Installing PHP 7 on macOS 12 Monterey
macOS 12 (Monterey) removed PHP7 in Apple’s ongoing effort to remove scripting languages from macOS. Any applications that required PHP 7 broke. MDS, our macOS deployment tool, hosts MunkiReport, which depends on the apache PHP module to function. macOS still includes Apache, but not PHP. In order to get MunkiReport to work, PHP 7 need to be installed
Considered Homebrew
The most obvious way to solve this is to use the macOS package manager Homebrew. However, this has some challenges. It required anyone using MDS to install PHP via Homebrew, which requires the Xcode command line tools. Even worse, after installing via Homebrew, it still did not work due to the new Apache requirements to only allow signed modules to be loaded:
No code signing authority for module at libexec/libphp7.so specified in LoadModule directive. Code signing absent - not loading module at: libexec/libphp7.so
Compiling and Signing
To resolve this issues, PHP 7 needs to be compiled, signed, and distributed with MDS. PHP links to many external libraries
libphp7.so: libaprutil-1.0.dylib libexpat.1.dylib libiconv.2.dylib libapr-1.0.dylib libSystem.B.dylib libtidy.58.dylib libargon2.1.dylib libresolv.9.dylib libncurses.5.4.dylib libaspell.15.dylib libpspell.15.dylib libpq.5.dylib libsybdb.5.dylib libldap.2.dylib liblber.2.dylib libc++.1.dylib libgmp.10.dylib libintl.8.dylib libbz2.1.0.dylib libxml2.2.dylib libgssapi_krb5.2.2.dylib libkrb5.3.3.dylib libk5crypto.3.1.dylib libcom_err.3.0.dylib libssl.1.1.dylib libcrypto.1.1.dylib libpcre2-8.0.dylib libsqlite3.0.dylib libz.1.dylib libcurl.4.dylib libffi.8.dylib libgd.3.dylib libicuio.69.dylib libicui18n.69.dylib libicuuc.69.dylib libicudata.69.dylib libonig.5.dylib libodbc.2.dylib libedit.3.dylib libsodium.23.dylib libxslt.1.dylib libicucore.A.dylib libexslt.0.dylib libzip.5.dylib
To compile PHP, most of these libraries would need to be included since most are not included with macOS. It also required the Apache plug in system to build. To make this easier, homebrew was used to install PHP 7 and the libraries in a temporary location and then all the libraries we collected to a single folder for easy deployment. For this to work, all the references in PHP and linked libraries need to be updated to point to the new folder.
Building with Homebrew in Non-Standard Location
To build PHP in a non standard location, Homebrew needs to be installed in target folder and then all the software will then be installed in that location:
git clone https://github.com/Homebrew/brew.git
Any brew commands can then run and the packages will be installed in that location. There seems to be a missing dependency on curl so that had to be installed separately.
#!/bin/sh -x PHP_BUILD_FOLDER="php_build" if [ ! -e "${PHP_BUILD_FOLDER}" ]; then mkdir -p "${PHP_BUILD_FOLDER}" fi pushd ${PHP_BUILD_FOLDER} if [ ! -e "brew" ]; then echo "cloning brew" git clone https://github.com/Homebrew/brew.git fi cd brew echo "updating brew" bin/brew update echo "installing curl otherwise php install will fail" bin/brew install curl echo "setting tap" bin/brew tap shivammathur/php echo "installing php7.4" bin/brew install shivammathur/php/php@7.4 echo "make relocatable" cd .. if [ ! -e "mds-php" ]; then mkdir -p mds-php/bin mkdir -p mds-php/lib fi cp -f brew/Cellar/php@7.4/7.4.27/bin/php mds-php/bin/ ./php_script.py brew/Cellar/php@7.4/7.4.27/lib/httpd/modules/libphp7.so ./php_script.py mds-php/bin/php echo "done"
When the script is run, PHP 7 will be installed in the custom brew folder. The libraries required by the libphp7.so module and the php binary are send to a great script by Andy Duplain that looks at all the linked libraries, collects them up into a single folder, and updates the link references.
Once that script is run, the destination folder (“mds-php”) contains a bin and lib folder containing the php binary, the apache module (libphp7.so), and all required libraries.
The script originally updated the libraries to use relative links (rpath) so that the folder could be moved around on the destination and it would still work. However, apache does not allow rpath unless SIP is disabled. The python relocate script was then updated to hardcode the path to where the destination php would be installed. Instead of including the install files inside the app, it is installed into /usr/local/mds-php7 and all libraries are linked to the lib folder in that location.
Universal Binaries
Since MDS runs on both macOS on Intel and Apple Silicon, this same process was repeated on Apple Silicon. Homebrew does not cross compile packages easily, so the script was run on an M1 mac and the resulting binaries were combined using lipo. The files were also signed and hardened so both Apache and notarization would accept them
#!/bin/bash if [ ! -e "mds-php-universal/lib" ]; then mkdir -p mds-php-universal/lib fi if [ ! -e "mds-php-universal/bin" ]; then mkdir -p mds-php-universal/bin fi cd "mds-php/lib" for file in *; do if [ -f "$file" ]; then echo "combining $file with lipo" lipo -create -output ../../mds-php-universal/lib/"$file" "$file" ../../mds-php-arm/lib/"$file" echo "signing $file" codesign -v --force -o runtime --sign "Developer ID Application: Twocanoes Software, Inc. (UXP6YEHSPW)" ../../mds-php-universal/lib/"$file" fi done cd ../bin if [ -e "php" ]; then echo "combining $file with lipo" lipo -create -output ../../mds-php-universal/bin/php "php" ../../mds-php-arm/bin/php codesign -v --force -o runtime --sign "Developer ID Application: Twocanoes Software, Inc. (UXP6YEHSPW)" ../../mds-php-universal/bin/php fi
The resulting folder (“mds-php-universal”) was then packaged up and the files in that folder were installed to /usr/local/mds-php with the MDS package installer.
Using the PHP Apache module
Using the Apache PHP module requires updating the apache config file to reference the new module. The common name of the certificate that signed it must be specified as well.
LoadModule php7_module "/usr/local/mds-php/lib/libphp7.so" "Developer ID Application: Twocanoes Software, Inc. (UXP6YEHSPW)"
Result
The resulting package can then be installed on any macOS system and doesn’t require Homebrew to be installed and doesn’t have any external dependencies. It uses the built-in Apache on macOS, doesn’t require SIP to be disabled, and uses codesigning to validate the loaded modules for Apache. MDS builds as of 48054 now includes PHP 7 installed into /usr/local/mds-php.
Smart Card Utility Beta
Sign up to receive information about Smart Card Utility Beta and related news. Once you confirm your subscription, a link will be sent to download the current beta via TestFlight.