{"id":20209854,"url":"https://github.com/rask/php-libload","last_synced_at":"2026-03-04T18:04:13.721Z","repository":{"id":57046737,"uuid":"240384235","full_name":"rask/php-libload","owner":"rask","description":"A small library to help in loading FFI libraries in a straight-forward manner.","archived":false,"fork":false,"pushed_at":"2020-02-17T22:56:59.000Z","size":67,"stargazers_count":7,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T13:35:51.374Z","etag":null,"topics":["ffi","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rask.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-13T22:57:51.000Z","updated_at":"2024-07-26T04:56:30.000Z","dependencies_parsed_at":"2022-08-24T03:40:37.444Z","dependency_job_id":null,"html_url":"https://github.com/rask/php-libload","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/rask/php-libload","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rask%2Fphp-libload","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rask%2Fphp-libload/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rask%2Fphp-libload/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rask%2Fphp-libload/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rask","download_url":"https://codeload.github.com/rask/php-libload/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rask%2Fphp-libload/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30088348,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T15:40:14.053Z","status":"ssl_error","status_checked_at":"2026-03-04T15:40:13.655Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","php"],"created_at":"2024-11-14T05:43:02.705Z","updated_at":"2026-03-04T18:04:13.702Z","avatar_url":"https://github.com/rask.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rask/libload\n\n[![Latest Stable Version](https://poser.pugx.org/rask/libload/v/stable)](https://packagist.org/packages/rask/libload) [![Infection MSI](https://badge.stryker-mutator.io/github.com/rask/php-libload/master)](https://infection.github.io)\n\nA small library to help in loading FFI libraries in a straight-forward manner.\n\n## Rationale\n\nThe vanilla methods of loading dynamic libraries via PHP FFI are simple and understandable:\n\n-   `\\FFI::cdef()` allows you to take in a library, and write the library header definition on the fly.\n-   `\\FFI::load()` allows you to take in a library header, inside which resides `FFI_LIB` that points to a dynamic library to load.\n\nThis is all fine and well, apart from one thing:\n\nYou're locked tight into the logic of `dlopen(3)`, which is a C function to load dynamic libraries. In essence this means the following:\n\n1.   You cannot use relative paths for `FFI_LIB`, as those operate on current working directory, which can be whatever\n2.   You cannot use absolute paths, as all software is runnable anywhere on any system in any path\n3.   You cannot rely on `LD_LIBRARY_PATH` as it cannot be altered at runtime, and you would require users of your code to set it up properly\n4.   You cannot use `/lib` or `/usr/lib`, as that would be senseless pollution on the user's system, not to speak of requiring admin privileges\n\nIn smaller projects with limited audiences these limitations might not matter. Or maybe the library you intend to use is a well-known and often preinstalled one (e.g. `libc`). But once you want to distribute public code that relies on a custom built FFI library, you're in trouble.\n\nSo, the only real reason this library exists is to bypass these limitations, and allow you to load a dynamic library in a few different ways.\n\n## Features\n\n-   Load libraries the `dlopen(3)` way\n-   Load libraries relative to the header file\n-   Load libraries relative to a custom path\n-   Load libraries by searching for them inside a directory tree\n\n## Example\n\n```php\n\u003c?php\n\nuse rask\\Libload\\Loader;\nuse rask\\Libload\\LoaderException;\nuse rask\\Libload\\Parsing\\ParseException;\n\n$loader = new Loader();\n\ntry {\n    $ffi = $loader-\u003erelativeTo('/path/to/libs')-\u003eload(__DIR__ . '/libs/my_lib.h');\n} catch (LoaderException | ParseException $e) {\n    // log it or something\n}\n\nassert($ffi instanceof \\FFI);\n```\n\nWhere `my_lib.h` contains\n\n```h\n#define FFI_LIB \"my_lib.so\"\n\n... definitions here ...\n```\n\nThe example above instantiates a new `Loader`, and then we instruct it to load a header file with the relative lookup mode.\n\nSo, if a dynamic library exists in `/path/to/libs/my_lib.so` it should get loaded and return a regular PHP `\\FFI` instance for us.\n\n## How it works\n\nIn a nutshell:\n\nThe loader reads your header file, parses the `FFI_LIB` definitions, and then just uses `\\FFI::cdef()` with the header file and a proper path to the library you actually want to load.\n\nA little hacky, yes.\n\n## Installation\n\n    $ composer require rask/libload\n\n## Usage\n\n### Using PHP default logic\n\nTo use the default `\\FFI::load()` logic (aka `dlopen(3)` logic), you can use the loader as follows:\n\n```php\n\u003c?php\n\n// ... setup autoloads etc ...\n\n$loader = new \\rask\\Libload\\Loader();\n\n$ffi = $loader-\u003eload('./path/to/header.h');\n\nassert($ffi instanceof \\FFI);\n```\n\n### Loading a library relative to header\n\nIf your header file defines an `FFI_LIB` that is located relative to the header file itself, you can use\n\n```php\n\u003c?php\n\n// ... setup autoloads etc ...\n\n$loader = new \\rask\\Libload\\Loader();\n\n$ffi = $loader-\u003erelativeToHeader()-\u003eload('./path/to/header.h');\n\nassert($ffi instanceof \\FFI);\n```\n\nYou header file might contain\n\n```h\n#define FFI_LIB \"./subdir/lib.so\"\n```\n\nSo `$loader` would look for the library in `./path/to/header/subdir/lib.so`.\n\nUsing this method fails if the `FFI_LIB` definition contains an absolute path.\n\nThis method disables the default `dlopen(3)` logic.\n\n### Loading a library relative to a custom path\n\nIf your library is located in a specific directory, you can load it using\n\n```php\n\u003c?php\n\n// ... setup autoloads etc ...\n\n$loader = new \\rask\\Libload\\Loader();\n\n$ffi = $loader-\u003erelativeTo('/my/awesome/libs')-\u003eload('./path/to/header.h');\n\nassert($ffi instanceof \\FFI);\n```\n\nYou header file might contain\n\n```h\n#define FFI_LIB \"./subdir/lib.so\"\n```\n\nSo `$loader` would look for the library in `/my/awesome/libs/subdir/lib.so`.\n\nUsing this method fails if the `FFI_LIB` definition contains an absolute path.\n\nThis method disables the default `dlopen(3)` logic.\n\n### Loading a library by searching inside a directory\n\nIf you have a directory tree with an arbritary structure but know the name of the library, you can search for it using\n\n```php\n\u003c?php\n\n// ... setup autoloads etc ...\n\n$loader = new \\rask\\Libload\\Loader();\n\n$ffi = $loader-\u003efromDirectory('/my/awesome/libs')-\u003eload('./path/to/header.h');\n\nassert($ffi instanceof \\FFI);\n```\n\nAnd if your directory tree is as follows\n\n```txt\n/\n    my/\n        awesome/\n            libs/\n                subdir1/\n                    subdir2/\n                        lib5.so\n                    lib3.so\n                    lib4.so\n                lib1.so\n                lib2.so\n```\n\nAnd if your header defines\n\n```h\n#define FFI_LIB \"lib4.so\"\n```\n\nThen `$loader` will find `/my/awesome/libs/subdir1/lib4.so`. The search will be slower in larger directories.\n\nThis method disables the default `dlopen(3)` logic.\n\n### Multiple library loading and resetting the loader\n\nIf you want to use the same loader instance for all kinds of loading needs across your application, you may need to reset it depending on how you want to load various libraries.\n\nYou can use resetting as such:\n\n```php\n\u003c?php\n\n// ... setup autoloads etc ...\n\n$loader = new \\rask\\Libload\\Loader();\n\n// Load using default logic\n$ffi1 = $loader-\u003eload('mylib1.h');\n\n// Load using relative to header\n$ffi2 = $loader-\u003ereset()-\u003erelativeToHeader()-\u003eload('mylib2.h');\n\n// Search a directory for the last one\n$ffi3 = $loader-\u003ereset()-\u003efromDirectory('/my/directory/path')-\u003eload('mylib3.h');\n```\n\nIf you have loads of variance in loading types, you can configure the instance to reset after each load:\n\n```php\n\u003c?php\n\n$loader = new \\rask\\Libload\\Loader();\n\n$loader-\u003eenableAutoReset();\n\nassert($loader-\u003eisAutoResetting() === true);\n\n// Now the instance will reset after each call to `load()`\n\n$loader-\u003edisableAutoReset();\n\nassert($loader-\u003eisAutoResetting() === false);\n\n// Returned to normal manual operation for resetting\n```\n\nIf you don't use resetting, you can keep using the same loading method for multiple libraries:\n\n```php\n\u003c?php\n\n$loader = new \\rask\\Libload\\Loader();\n\n$loader = $loader-\u003erelativeTo('/my/libs');\n\n$ffi1 = $loader-\u003eload('lib1.h');\n$ffi2 = $loader-\u003eload('lib2.h');\n$ffi3 = $loader-\u003eload('lib3.h');\n```\n\n## Todo\n\n-   More ways to load libraries?\n-   Make it work with headers that provide `FFI_SCOPE` (i.e. make it work with preloading)\n-   Make this package useless, by pestering PHP core devs to add this functionality to the PHP core FFI implementation\n\n## Notes\n\nThis package might be useless if you do not intend to write FFI code that is to be distributed as a package or something. Also this might be overkill if you can load your FFI instances using pure `\\FFI::cdef()` instead.\n\nCurrently FFI library loading in opcache preloading contexts is confusingly documented, so this package waits for confirmations on how to actually preload FFI libraries in production before making commitments towards preloading-compatibility. Use this for CLI apps for now.\n\n## Contributing\n\nDevelopment requirements apart from a PHP CLI installation that supports FFI, you need to have `gcc` and `make` available, and being able to compile on a system that produces Linux shared object binaries (`*.so`). This means you probably cannot run tests on Windows or Mac right now. Some tests require you to have `/lib/x86_64-linux-gnu/libc.so.6` available in your system.\n\nWe need `gcc` and `make` so we can build a shared library for testing purposes when running PHPUnit.\n\nBefore sending code as a pull request:\n\n-   Try to add tests for your changes (`composer test`), or ask for help from the maintainers with it\n-   Run linting and static analysis against your code before commiting (`composer lint` and `composer stan`)\n\nIf you have problems using the package, you can raise issues. Documentation and cleanup contributions very welcome. Feature requests are OK as long as they're not too far from the core purpose of this package: making loading FFI libraries a little simpler/easier/saner/etc.\n\nIf you have any questions about how to contribute, you can create an issue and ask for pointers.\n\n## License\n\nMIT License, see [LICENSE.md](./LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frask%2Fphp-libload","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frask%2Fphp-libload","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frask%2Fphp-libload/lists"}