Skip to content

Instantly share code, notes, and snippets.

@dirx
Last active January 6, 2020 18:10
Show Gist options
  • Save dirx/257c5262d8a58ef54e23a6e8edb31105 to your computer and use it in GitHub Desktop.
Save dirx/257c5262d8a58ef54e23a6e8edb31105 to your computer and use it in GitHub Desktop.
PHP 7.4 FFI and function pointers via dlopen & dlsym & shared library
<?php
// requires https://github.com/edenhill/librdkafka installed
declare(strict_types=1);
const RTLD_LAZY = 0x00001;/* Lazy function call binding. */
const RTLD_NOW = 0x00002;/* Immediate function call binding. */
const RTLD_BINDING_MASK = 0x3;/* Mask of binding time value. */
const RTLD_NOLOAD = 0x00004;/* Do not load the object. */
const RTLD_DEEPBIND = 0x00008;/* Use deep binding. */
const RTLD_GLOBAL = 0x00100;
const RTLD_LOCAL = 0;
$ffi = FFI::cdef(
"
void *dlopen(const char *filename, int flags);
int dlclose(void *handle);
void *dlsym(void *handle, const char *symbol);
char *dlerror(void);
"
);
// load lib via dlopen like php https://github.com/php/php-src/blob/1c4ad17cc1e483201a36b027f20aab1f91d19628/Zend/zend_portability.h#L148
$handle = $ffi->dlopen('/usr/local/lib/librdkafka.so', RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND);
$err = $ffi->dlerror();
if ($err !== null) {
var_dump(FFI::string($err));
}
// or load lib via ffi (internally via dlopen)
//$handle = null;
//$librdkafka = FFI::cdef('', '/usr/local/lib/librdkafka.so');
// get function pointer
$pointer = $ffi->dlsym($handle, 'rd_kafka_version_str');
$err = $ffi->dlerror();
if ($err !== null) {
var_dump(FFI::string($err));
}
$rd_kafka_version_str = FFI::new('void*(*)(...)'); // generic function pointer
//$rd_kafka_version_str = FFI::new('char*(*)(...)'); // function pointer returning string ...
//$rd_kafka_version_str = $librdkafka->new('char*(*)(...)'); // function pointer ... in case of special librdkafka type
FFI::memcpy(
FFI::addr($rd_kafka_version_str),
FFI::addr($pointer), // pointer to the function pointer
FFI::sizeof($rd_kafka_version_str)
);
$version = $rd_kafka_version_str();
print_r($version);
var_dump(FFI::string(FFI::cast('char*', $version))); // cast with generic function pointer
//var_dump(FFI::string($version));
//var_dump(FFI::string($librdkafka->cast('char*', $version))); // cast with generic function pointer ... in case of special librdkafka type
if ($handle !== null) {
$ffi->dlclose($handle);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment