Базовая Ρ€Π°Π±ΠΎΡ‚Π° с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ FFI

ΠŸΠ΅Ρ€Π΅Π΄ ΠΏΠΎΠ³Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π² Π΄Π΅Ρ‚Π°Π»ΠΈ API-интСрфСйса модуля FFI, Π΄Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим нСсколько ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² ΡƒΠΏΡ€ΠΎΡ‰Ρ‘Π½Π½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹ API модуля FFI Π² стандартных Π·Π°Π΄Π°Ρ‡Π°Ρ….

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: Для ряда этих ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² потрСбуСтся Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° libc.so.6. Они Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² систСмах, Π³Π΄Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° нСдоступна.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 Π’Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· ΠΎΠ±Ρ‰Π΅ΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ

<?php

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ FFI, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ libc ΠΈ экспортируСм Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // Π­Ρ‚ΠΎ стандартная дСкларация Π² языкС C
"libc.so.6"
);

// Π’Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ printf()
$ffi->printf("ΠŸΡ€ΠΈΠ²Π΅Ρ‚, %s!\n", "ΠΌΠΈΡ€");

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

ΠŸΡ€ΠΈΠ²Π΅Ρ‚, ΠΌΠΈΡ€!

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ для ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ языка C Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ соглашСния ΠΎ Π²Ρ‹Π·ΠΎΠ²Π°Ρ…, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€: __fastcall, __stdcall ΠΈΠ»ΠΈ ,__vectorcall.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 Π’Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ структуры Ρ‡Π΅Ρ€Π΅Π· Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚

<?php

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ привязку 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"
);

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ структуры Π΄Π°Π½Π½Ρ‹Ρ… языка C
$tv = $ffi->new("struct timeval");
$tz = $ffi->new("struct timezone");

// Π’Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ gettimeofday()
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));

// ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ доступ ΠΊ полю структуры Π΄Π°Π½Π½Ρ‹Ρ… языка C
var_dump($tv->tv_sec);

// Π’Ρ‹Π²ΠΎΠ΄ΠΈΠΌ структуру Π΄Π°Π½Π½Ρ‹Ρ…
var_dump($tz);

?>

Π’Ρ‹Π²ΠΎΠ΄ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΡ…ΠΎΠΆ Π½Π°:

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

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #3 Доступ ΠΊ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ C

<?php

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ FFI-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ libc ΠΈ экспортируСм ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ errno
$ffi = FFI::cdef(
"int errno;", // Π­Ρ‚ΠΎ стандартная дСкларация Π² языкС C
"libc.so.6"
);

// Π’Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ errno
var_dump($ffi->errno);

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

int(0)

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #4 Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈ модификация C-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ

<?php

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ языка C с Ρ‚ΠΈΠΏΠΎΠΌ int
$x = FFI::new("int");
var_dump($x->cdata);

// ΠŸΡ€ΠΎΡΡ‚ΠΎΠ΅ присваиваниС
$x->cdata = 5;
var_dump($x->cdata);

// НСпростоС присваиваниС
$x->cdata += 2;
var_dump($x->cdata);

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

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

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #5 Π Π°Π±ΠΎΡ‚Π° с массивами языка C

<?php

// Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ структуру Π΄Π°Π½Π½Ρ‹Ρ…
$a = FFI::new("long[1024]");

// Π Π°Π±ΠΎΡ‚Π°Π΅ΠΌ с Π½Π΅ΠΉ ΠΊΠ°ΠΊ с ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌ PHP-массивом
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));

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

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

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #6 Π Π°Π±ΠΎΡ‚Π° с пСрСчислСниями языка 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);

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

int(0)
int(2)
int(3)
οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 1 note

up
5
wowabbs+php at gmail dot com ΒΆ
5 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));
?>