15

I need to run a php script on a system with a somewhat broken PHP install. Rather than trying to workaround the issues I want to just package my code with it's own PHP binary (I can execute an executable). I want to just have a simple php binary that has all the modules I need compiled in. My general process is:

./configure --enable-static --enable-cli --disable-all

This gives me a php binary with no extensions. From here I can add the extensions I need. For example to add curl and json support

./configure --enable-static --enable-cli --disable-all --with-curl --enable-json

This seems to work well generally. My script needs libxml support for interacting with AWS. So I added --enable-libxml --enable-simplexml to the configure command. When I copy the binary to the remote machine it gets an error when trying to use the XML library that looks like:

/usr/lib/x86_64-linux-gnu/libxml2.so.2: version `LIBXML2_2.9.0' not found

Obviously it is dynamically linking to libxml2. I take this to mean that while the PHP extension is statically compiled into PHP, the library that the PHP extension is using is not. Running ldd confirms this:

$ ldd sapi/cli/php
linux-vdso.so.1 =>  (0x00007fff05cf3000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f3c69f82000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f3c69d68000)
libcurl.so.4 => /lib64/libcurl.so.4 (0x00007f3c69afc000)
librt.so.1 => /lib64/librt.so.1 (0x00007f3c698f4000)
libm.so.6 => /lib64/libm.so.6 (0x00007f3c695ed000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f3c693e8000)
libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f3c691cf000)
libxml2.so.2 => /lib64/libxml2.so.2 (0x00007f3c68e66000)
libz.so.1 => /lib64/libz.so.1 (0x00007f3c68c4f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3c68890000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007f3c6860f000)
libidn.so.11 => /lib64/libidn.so.11 (0x00007f3c683db000)
libssh2.so.1 => /lib64/libssh2.so.1 (0x00007f3c681b1000)
libssl3.so => /lib64/libssl3.so (0x00007f3c67f72000)
libsmime3.so => /lib64/libsmime3.so (0x00007f3c67d44000)
libnss3.so => /lib64/libnss3.so (0x00007f3c679fc000)
libnssutil3.so => /lib64/libnssutil3.so (0x00007f3c677d0000)
libplds4.so => /lib64/libplds4.so (0x00007f3c675cb000)
libplc4.so => /lib64/libplc4.so (0x00007f3c673c6000)
libnspr4.so => /lib64/libnspr4.so (0x00007f3c67188000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3c66f6a000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f3c66d20000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f3c66a40000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f3c6680a000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f3c66606000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f3c663f7000)
libldap-2.4.so.2 => /lib64/libldap-2.4.so.2 (0x00007f3c661a4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3c6a1d7000)
liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f3c65f7f000)
libssl.so.10 => /lib64/libssl.so.10 (0x00007f3c65d12000)
libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007f3c6592b000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f3c6571c000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f3c65518000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f3c652fa000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f3c650d6000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f3c64e6f000)

As you can see there are many libraries that are dynamically linked to my php binary. I am guessing it was generally working because my target system had a lot of these same libraries but not the libxml library.

So my question is, how do I make a completely static binary with no dependencies on shared libraries. I realize this will make my executable bigger but it would also mean I can package my php executable with the code and it will work on any 64-bit linux machine.

Eric Anderson
  • 3,692
  • 4
  • 31
  • 34

2 Answers2

5

I have found a solution although it's a bit messier than I would like. I am leaving the libxml as a shared object and just including it with my code package and using the LD_LIBRARY_PATH environment variable so that it loads my shared library objects instead of the ones installed on the system.

Ideally I would like just a single binary file but this solution works. It also has the slight advantage of using the system libraries if those are suitable (i.e. my code package doesn't have to include all the shared libraries). But I would still be interested in knowing if there is a way to compile a completely static php binary.

Eric Anderson
  • 3,692
  • 4
  • 31
  • 34
  • Hi Erick, did you figure out any better way to do this? I have a full fledged web based hospital system developed in php, jquery, HTML, MySQL, JavaScript and HTML that the hospital has asked me to help them compile it in one executable. It runs on an RPM Linux based server and several other branches of the hospital in different geographical regions connect to it too. – Joseph Nov 26 '16 at 10:29
  • 1
    Not a single binary. I ended up using the LD_LIBRARY_PATH described for a while. Later that project migrated to Docker allowing me to better control the version of PHP regardless of what the environment natively supported. – Eric Anderson Nov 28 '16 at 14:24
0

It was suggested to me a long time ago to try out http://statifier.sf.net/ or http://magicErmine.com

They make a static binary out of any executable.

I think that's how the folks over at magento made that php 5.2 binary.

txyoji
  • 6,680
  • 1
  • 44
  • 46
  • Statifier is an almost dead project, it doesn't support memory randomization. Ermine is too expensive. – Viktor Joras May 16 '18 at 21:39
  • https://appimage.org is also a thing now. Not a "static" binary but a package with all dependencies similar to how mac-os applications work. – txyoji Mar 24 '22 at 15:36
  • A new project for php > 7.4 to build static binary's - https://github.com/crazywhalecc/static-php-cli – txyoji Jul 24 '23 at 15:53