PHP Velho Oeste 2024

Utilisation basique de FFI

Avant de plonger dans les détails de l'API FFI, jetons un coup d'œil à quelques exemples démontrant la simplicité d'utilisation de l'API FFI pour les tâches courantes.

Note:

Certains de ces exemples requièrent libc.so.6 et ne fonctionneront donc pas sur les systèmes où cette bibliothèque n'est pas disponible.

Exemple #1 Appel d'une fonction à partir d'une bibliothèque partagée

<?php
// crée un objet FFI, en chargeant la libc et en exportant la fonction printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // Declaration C régulière
"libc.so.6");
// appele la fonction printf() de C
$ffi->printf("Hello %s!\n", "world");
?>

L'exemple ci-dessus va afficher :

Hello world!

Note:

Notez que certaines fonctions C nécessitent des conventions d'appel spécifiques, par exemple __fastcall, __stdcall ou ,__vectorcall.

Exemple #2 Appel d'une fonction, retournant une structure par l'intermédiaire d'un argument

<?php
// crée la liaison gettimeofday()
$ffi = FFI::cdef("
typedef unsigned int time_t;
typedef unsigned int suseconds_t;

struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};

struct timezone {
int tz_minuteswest;
int tz_dsttime;
};

int gettimeofday(struct timeval *tv, struct timezone *tz);
"
, "libc.so.6");
// crée les structures de données C
$tv = $ffi->new("struct timeval");
$tz = $ffi->new("struct timezone");
// appelle la fonction gettimeofday() de C
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
// accède au champs de la structure de données C
var_dump($tv->tv_sec);
// imprime toute la structure de données C
var_dump($tz);
?>

Résultat de l'exemple ci-dessus est similaire à :

int(0)
int(1555946835)
object(FFI\CData:struct timezone)#3 (2) {
  ["tz_minuteswest"]=>
  int(0)
  ["tz_dsttime"]=>
  int(0)
}

Exemple #3 Accès aux variables C existantes

<?php
// crée un objet FFI, en chargeant la libc et en exportant la variable errno
$ffi = FFI::cdef(
"int errno;", // Declaration C régulière
"libc.so.6");
// imprime la valeur errno de C
var_dump($ffi->errno);
?>

L'exemple ci-dessus va afficher :

int(0)

Exemple #4 Création et modification de variables C

<?php
// crée une nouvelle variable C de type int
$x = FFI::new("int");
var_dump($x->cdata);

// affectation simple
$x->cdata = 5;
var_dump($x->cdata);

// affectation composée
$x->cdata += 2;
var_dump($x->cdata);
?>

L'exemple ci-dessus va afficher :

int(0)
int(5)
int(7)

Exemple #5 Travailler avec des tableaux C

<?php
// crée une structure de données en C
$a = FFI::new("long[1024]");
// modification de la structure comme avec un tableau PHP normal
for ($i = 0; $i < count($a); $i++) {
$a[$i] = $i;
}
var_dump($a[25]);
$sum = 0;
foreach (
$a as $n) {
$sum += $n;
}
var_dump($sum);
var_dump(count($a));
var_dump(FFI::sizeof($a));
?>

L'exemple ci-dessus va afficher :

int(25)
int(523776)
int(1024)
int(8192)

Exemple #6 Travailler avec des enums en C

<?php
$a
= FFI::cdef('typedef enum _zend_ffi_symbol_kind {
ZEND_FFI_SYM_TYPE,
ZEND_FFI_SYM_CONST = 2,
ZEND_FFI_SYM_VAR,
ZEND_FFI_SYM_FUNC
} zend_ffi_symbol_kind;
'
);
var_dump($a->ZEND_FFI_SYM_TYPE);
var_dump($a->ZEND_FFI_SYM_CONST);
var_dump($a->ZEND_FFI_SYM_VAR);
?>

L'exemple ci-dessus va afficher :

int(0)
int(2)
int(3)

add a note add a note

User Contributed Notes 1 note

up
1
wowabbs+php at gmail dot com
3 years ago
<?
 
if(!dl("ffi")) // Load the extension
     
throw new Exception('Cound not load the FFI extension.');

  function
setWindowsDesktop($bmpFilePath)
  {
   
define('SPI_SETDESKWALLPAPER'  , 0x14);
   
define('SPIF_UPDATEINIFILE'    0x1);
   
define('SPIF_SENDWININICHANGE' 0x2);
   
assert(File_Exists($bmpFilePath));
   
   
// declare the Win32 API function used to change desktop settings.
   
$User32 = FFI::cdef(<<<'IDL'
      int SystemParametersInfoA(int uAction, int uParam, char *lpvParam, int fuWinIni);
    IDL, 'User32.dll');
    $Kernel32 = FFI::cdef(<<<'IDL'
      int GetLastError();
    IDL, 'Kernel32.dll');
    // call the Windows API to update the desktop background.
    $Ret = $User32->SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, $bmpFilePath, SPIF_UPDATEINIFILE || SPIF_SENDWININICHANGE);
    if ($Ret == 0)
    {
      $Error = $Kernel32->GetLastError();
      throw new Exception("The call to the Windows API failed (error {$Error}).");
    }
  }
 
  $Url='https://www.php.net//images/news/phpkonf_2015.png';
  $Img=File_Get_Contents($Url);
  File_Put_Contents($File=basename($Url), $Img);
  setWindowsDesktop(realpath($File));
?>
To Top