Skip to content

Instantly share code, notes, and snippets.

@Muffinman
Last active June 13, 2024 08:57
Show Gist options
  • Save Muffinman/9075b659a06e8799f3672ee7d803ba9f to your computer and use it in GitHub Desktop.
Save Muffinman/9075b659a06e8799f3672ee7d803ba9f to your computer and use it in GitHub Desktop.
MacOS 14 PHP
From 272da51bfd562f5b9847c1b41eaa5d7018058490 Mon Sep 17 00:00:00 2001
From: Manuel Kress <[email protected]>
Date: Fri, 1 Mar 2024 17:47:21 +0100
Subject: [PATCH] Use ITIMER_REAL for timeout handling on MacOS / Apple Silicon
system
setitimer(ITIMER_PROF) fires too early on MacOS 14 when running on Apple
Silicon. See https://openradar.appspot.com/radar?id=5583058442911744.
Fixes GH-12814
Closes GH-13567
---
NEWS | 2 ++
Zend/zend_execute_API.c | 6 ++++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index c7f814138d00d..fa126f959b3ed 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1533,7 +1533,9 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
t_r.it_value.tv_sec = seconds;
t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
-# if defined(__CYGWIN__) || defined(__PASE__)
+# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
+ // ITIMER_PROF is broken in Apple Silicon system with MacOS >= 14
+ // See https://openradar.appspot.com/radar?id=5583058442911744.
setitimer(ITIMER_REAL, &t_r, NULL);
}
signo = SIGALRM;
@@ -1597,7 +1599,7 @@ void zend_unset_timeout(void) /* {{{ */
no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0;
-# if defined(__CYGWIN__) || defined(__PASE__)
+# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
setitimer(ITIMER_REAL, &no_timeout, NULL);
# else
setitimer(ITIMER_PROF, &no_timeout, NULL);
#!/usr/bin/env bash
# Download formula
curl https://gist.github.com/Muffinman/9075b659a06e8799f3672ee7d803ba9f/raw/e31e42baa88db21b0764a46dc17e8f87dacb0872/php.rb
# Install custom formula
brew install --build-from-source ./php.rb
class Php < Formula
desc "General-purpose scripting language"
homepage "https://www.php.net/"
# Should only be updated if the new version is announced on the homepage, https://www.php.net/
url "https://www.php.net/distributions/php-8.3.8.tar.xz"
mirror "https://fossies.org/linux/www/php-8.3.8.tar.xz"
sha256 "aea358b56186f943c2bbd350c9005b9359133d47e954cfc561385319ae5bb8d7"
license "PHP-3.01"
revision 1
livecheck do
url "https://www.php.net/downloads"
regex(/href=.*?php[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
bottle do
root_url "https://ghcr.io/v2/shivammathur/php"
sha256 arm64_sonoma: "d3615ea3b58564334a00d447d3d4f33770e56c74d041b69258d81c592b582e27"
sha256 arm64_ventura: "eca3ddde0ca92364e5996a65fafeb7429a0faf8eacccc9efd5487d5eb0dd1680"
sha256 arm64_monterey: "7fe7b1d0f6972cc5d34194ff7077dc11c2bb36beff0527a63fc795a192738ce9"
sha256 ventura: "27a80fa5e1f71b21f84b8b89604f5c40ac3345f1fd0c76e449579eb9772873f1"
sha256 monterey: "0c8e979d1000c87e017aac7eae1eae9a357dae35eef8db0f6a6419e921ac12e5"
sha256 x86_64_linux: "3f158d3a3f2d86088e53763fdb7516684ae8ce4f48f1f7c9701f9df492a3201e"
end
head do
url "https://github.com/php/php-src.git", branch: "master"
depends_on "bison" => :build # bison >= 3.0.0 required to generate parsers
depends_on "re2c" => :build # required to generate PHP lexers
end
depends_on "httpd" => [:build, :test]
depends_on "pkg-config" => :build
depends_on "apr"
depends_on "apr-util"
depends_on "argon2"
depends_on "aspell"
depends_on "autoconf"
depends_on "curl"
depends_on "freetds"
depends_on "gd"
depends_on "gettext"
depends_on "gmp"
depends_on "icu4c"
depends_on "krb5"
depends_on "libpq"
depends_on "libsodium"
depends_on "libzip"
depends_on "oniguruma"
depends_on "openldap"
depends_on "openssl@3"
depends_on "pcre2"
depends_on "sqlite"
depends_on "tidy-html5"
depends_on "unixodbc"
uses_from_macos "xz" => :build
uses_from_macos "bzip2"
uses_from_macos "libedit"
uses_from_macos "libffi", since: :catalina
uses_from_macos "libxml2"
uses_from_macos "libxslt"
uses_from_macos "zlib"
on_macos do
# PHP build system incorrectly links system libraries
patch :DATA
end
# Remove with 8.3.9
patch do
url "https://raw.githubusercontent.com/shivammathur/php-builder/595dc3f/config/patches/8.3/0045-method-visibility-issue.patch?full_index=1"
sha256 "2947d7ad1a54af20c935ec7d804bb45aec8d9e66b7f6a693a26b1ce0f2ed0a35"
end
# Remove with 8.3.9
patch do
url "https://gist.github.com/Muffinman/9075b659a06e8799f3672ee7d803ba9f/raw/41d68c0b95ba0f9e4d012308e8666ecc36c139ed/fix-macos-ITIMER_PROF-php8.3.patch"
sha256 "1174e6e55329595cb8ceb4d7aa737378da0bf1420b7d1fac4f5ac6a773f4070d"
end
def install
# buildconf required due to system library linking bug patch
system "./buildconf", "--force"
inreplace "configure" do |s|
s.gsub! "APACHE_THREADED_MPM=`$APXS_HTTPD -V 2>/dev/null | grep 'threaded:.*yes'`",
"APACHE_THREADED_MPM="
s.gsub! "APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR`",
"APXS_LIBEXECDIR='$(INSTALL_ROOT)#{lib}/httpd/modules'"
s.gsub! "-z `$APXS -q SYSCONFDIR`",
"-z ''"
end
# Update error message in apache sapi to better explain the requirements
# of using Apache http in combination with php if the non-compatible MPM
# has been selected. Homebrew has chosen not to support being able to
# compile a thread safe version of PHP and therefore it is not
# possible to recompile as suggested in the original message
inreplace "sapi/apache2handler/sapi_apache2.c",
"You need to recompile PHP.",
"Homebrew PHP does not support a thread-safe php binary. " \
"To use the PHP apache sapi please change " \
"your httpd config to use the prefork MPM"
inreplace "sapi/fpm/php-fpm.conf.in", ";daemonize = yes", "daemonize = no"
config_path = etc/"php/#{version.major_minor}"
# Prevent system pear config from inhibiting pear install
(config_path/"pear.conf").delete if (config_path/"pear.conf").exist?
# Prevent homebrew from hardcoding path to sed shim in phpize script
ENV["lt_cv_path_SED"] = "sed"
# system pkg-config missing
ENV["KERBEROS_CFLAGS"] = " "
if OS.mac?
ENV["SASL_CFLAGS"] = "-I#{MacOS.sdk_path_if_needed}/usr/include/sasl"
ENV["SASL_LIBS"] = "-lsasl2"
else
ENV["SQLITE_CFLAGS"] = "-I#{Formula["sqlite"].opt_include}"
ENV["SQLITE_LIBS"] = "-lsqlite3"
ENV["BZIP_DIR"] = Formula["bzip2"].opt_prefix
end
# Each extension that is built on Mojave needs a direct reference to the
# sdk path or it won't find the headers
headers_path = "=#{MacOS.sdk_path_if_needed}/usr" if OS.mac?
# `_www` only exists on macOS.
fpm_user = OS.mac? ? "_www" : "www-data"
fpm_group = OS.mac? ? "_www" : "www-data"
args = %W[
--prefix=#{prefix}
--localstatedir=#{var}
--sysconfdir=#{config_path}
--with-config-file-path=#{config_path}
--with-config-file-scan-dir=#{config_path}/conf.d
--with-pear=#{pkgshare}/pear
--enable-bcmath
--enable-calendar
--enable-dba
--enable-exif
--enable-ftp
--enable-fpm
--enable-gd
--enable-intl
--enable-mbregex
--enable-mbstring
--enable-mysqlnd
--enable-pcntl
--enable-phpdbg
--enable-phpdbg-readline
--enable-shmop
--enable-soap
--enable-sockets
--enable-sysvmsg
--enable-sysvsem
--enable-sysvshm
--with-apxs2=#{Formula["httpd"].opt_bin}/apxs
--with-bz2#{headers_path}
--with-curl
--with-external-gd
--with-external-pcre
--with-ffi
--with-fpm-user=#{fpm_user}
--with-fpm-group=#{fpm_group}
--with-gettext=#{Formula["gettext"].opt_prefix}
--with-gmp=#{Formula["gmp"].opt_prefix}
--with-iconv#{headers_path}
--with-kerberos
--with-layout=GNU
--with-ldap=#{Formula["openldap"].opt_prefix}
--with-libxml
--with-libedit
--with-mhash#{headers_path}
--with-mysql-sock=/tmp/mysql.sock
--with-mysqli=mysqlnd
--with-ndbm#{headers_path}
--with-openssl
--with-password-argon2
--with-pdo-dblib=#{Formula["freetds"].opt_prefix}
--with-pdo-mysql=mysqlnd
--with-pdo-odbc=unixODBC,#{Formula["unixodbc"].opt_prefix}
--with-pdo-pgsql=#{Formula["libpq"].opt_prefix}
--with-pdo-sqlite
--with-pgsql=#{Formula["libpq"].opt_prefix}
--with-pic
--with-pspell=#{Formula["aspell"].opt_prefix}
--with-sodium
--with-sqlite3
--with-tidy=#{Formula["tidy-html5"].opt_prefix}
--with-unixODBC
--with-xsl
--with-zip
--with-zlib
]
if OS.mac?
args << "--enable-dtrace"
args << "--with-ldap-sasl"
args << "--with-os-sdkpath=#{MacOS.sdk_path_if_needed}"
else
args << "--disable-dtrace"
args << "--without-ldap-sasl"
args << "--without-ndbm"
args << "--without-gdbm"
end
system "./configure", *args
system "make"
system "make", "install"
# Allow pecl to install outside of Cellar
extension_dir = Utils.safe_popen_read("#{bin}/php-config", "--extension-dir").chomp
orig_ext_dir = File.basename(extension_dir)
inreplace bin/"php-config", lib/"php", prefix/"pecl"
%w[development production].each do |mode|
inreplace "php.ini-#{mode}", %r{; ?extension_dir = "\./"},
"extension_dir = \"#{HOMEBREW_PREFIX}/lib/php/pecl/#{orig_ext_dir}\""
end
# Use OpenSSL cert bundle
openssl = Formula["openssl@3"]
%w[development production].each do |mode|
inreplace "php.ini-#{mode}", /; ?openssl\.cafile=/,
"openssl.cafile = \"#{openssl.pkgetc}/cert.pem\""
inreplace "php.ini-#{mode}", /; ?openssl\.capath=/,
"openssl.capath = \"#{openssl.pkgetc}/certs\""
end
config_files = {
"php.ini-development" => "php.ini",
"php.ini-production" => "php.ini-production",
"sapi/fpm/php-fpm.conf" => "php-fpm.conf",
"sapi/fpm/www.conf" => "php-fpm.d/www.conf",
}
config_files.each_value do |dst|
dst_default = config_path/"#{dst}.default"
rm dst_default if dst_default.exist?
end
config_path.install config_files
unless (var/"log/php-fpm.log").exist?
(var/"log").mkpath
touch var/"log/php-fpm.log"
end
end
def post_install
pear_prefix = pkgshare/"pear"
pear_files = %W[
#{pear_prefix}/.depdblock
#{pear_prefix}/.filemap
#{pear_prefix}/.depdb
#{pear_prefix}/.lock
]
%W[
#{pear_prefix}/.channels
#{pear_prefix}/.channels/.alias
].each do |f|
chmod 0755, f
pear_files.concat(Dir["#{f}/*"])
end
chmod 0644, pear_files
# Custom location for extensions installed via pecl
pecl_path = HOMEBREW_PREFIX/"lib/php/pecl"
pecl_path.mkpath
ln_s pecl_path, prefix/"pecl" unless (prefix/"pecl").exist?
extension_dir = Utils.safe_popen_read("#{bin}/php-config", "--extension-dir").chomp
php_basename = File.basename(extension_dir)
php_ext_dir = opt_prefix/"lib/php"/php_basename
# fix pear config to install outside cellar
pear_path = HOMEBREW_PREFIX/"share/pear"
cp_r pkgshare/"pear/.", pear_path
{
"php_ini" => etc/"php/#{version.major_minor}/php.ini",
"php_dir" => pear_path,
"doc_dir" => pear_path/"doc",
"ext_dir" => pecl_path/php_basename,
"bin_dir" => opt_bin,
"data_dir" => pear_path/"data",
"cfg_dir" => pear_path/"cfg",
"www_dir" => pear_path/"htdocs",
"man_dir" => HOMEBREW_PREFIX/"share/man",
"test_dir" => pear_path/"test",
"php_bin" => opt_bin/"php",
}.each do |key, value|
value.mkpath if /(?<!bin|man)_dir$/.match?(key)
system bin/"pear", "config-set", key, value, "system"
end
system bin/"pear", "update-channels"
%w[
opcache
].each do |e|
ext_config_path = etc/"php/#{version.major_minor}/conf.d/ext-#{e}.ini"
extension_type = (e == "opcache") ? "zend_extension" : "extension"
if ext_config_path.exist?
inreplace ext_config_path,
/#{extension_type}=.*$/, "#{extension_type}=#{php_ext_dir}/#{e}.so"
else
ext_config_path.write <<~EOS
[#{e}]
#{extension_type}="#{php_ext_dir}/#{e}.so"
EOS
end
end
end
def caveats
<<~EOS
To enable PHP in Apache add the following to httpd.conf and restart Apache:
LoadModule php_module #{opt_lib}/httpd/modules/libphp.so
<FilesMatch \\.php$>
SetHandler application/x-httpd-php
</FilesMatch>
Finally, check DirectoryIndex includes index.php
DirectoryIndex index.php index.html
The php.ini and php-fpm.ini file can be found in:
#{etc}/php/#{version.major_minor}/
EOS
end
service do
run [opt_sbin/"php-fpm", "--nodaemonize"]
run_type :immediate
keep_alive true
error_log_path var/"log/php-fpm.log"
working_dir var
end
test do
assert_match(/^Zend OPcache$/, shell_output("#{bin}/php -i"),
"Zend OPCache extension not loaded")
# Test related to libxml2 and
# https://github.com/Homebrew/homebrew-core/issues/28398
assert_includes (bin/"php").dynamically_linked_libraries,
(Formula["libpq"].opt_lib/shared_library("libpq", 5)).to_s
system "#{sbin}/php-fpm", "-t"
system "#{bin}/phpdbg", "-V"
system "#{bin}/php-cgi", "-m"
# Prevent SNMP extension to be added
refute_match(/^snmp$/, shell_output("#{bin}/php -m"),
"SNMP extension doesn't work reliably with Homebrew on High Sierra")
begin
port = free_port
port_fpm = free_port
expected_output = /^Hello world!$/
(testpath/"index.php").write <<~EOS
<?php
echo 'Hello world!' . PHP_EOL;
var_dump(ldap_connect());
EOS
main_config = <<~EOS
Listen #{port}
ServerName localhost:#{port}
DocumentRoot "#{testpath}"
ErrorLog "#{testpath}/httpd-error.log"
ServerRoot "#{Formula["httpd"].opt_prefix}"
PidFile "#{testpath}/httpd.pid"
LoadModule authz_core_module lib/httpd/modules/mod_authz_core.so
LoadModule unixd_module lib/httpd/modules/mod_unixd.so
LoadModule dir_module lib/httpd/modules/mod_dir.so
DirectoryIndex index.php
EOS
(testpath/"httpd.conf").write <<~EOS
#{main_config}
LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so
LoadModule php_module #{lib}/httpd/modules/libphp.so
<FilesMatch \\.(php|phar)$>
SetHandler application/x-httpd-php
</FilesMatch>
EOS
(testpath/"fpm.conf").write <<~EOS
[global]
daemonize=no
[www]
listen = 127.0.0.1:#{port_fpm}
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOS
(testpath/"httpd-fpm.conf").write <<~EOS
#{main_config}
LoadModule mpm_event_module lib/httpd/modules/mod_mpm_event.so
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_fcgi_module lib/httpd/modules/mod_proxy_fcgi.so
<FilesMatch \\.(php|phar)$>
SetHandler "proxy:fcgi://127.0.0.1:#{port_fpm}"
</FilesMatch>
EOS
pid = fork do
exec Formula["httpd"].opt_bin/"httpd", "-X", "-f", "#{testpath}/httpd.conf"
end
sleep 3
assert_match expected_output, shell_output("curl -s 127.0.0.1:#{port}")
Process.kill("TERM", pid)
Process.wait(pid)
fpm_pid = fork do
exec sbin/"php-fpm", "-y", "fpm.conf"
end
pid = fork do
exec Formula["httpd"].opt_bin/"httpd", "-X", "-f", "#{testpath}/httpd-fpm.conf"
end
sleep 3
assert_match expected_output, shell_output("curl -s 127.0.0.1:#{port}")
ensure
if pid
Process.kill("TERM", pid)
Process.wait(pid)
end
if fpm_pid
Process.kill("TERM", fpm_pid)
Process.wait(fpm_pid)
end
end
end
end
__END__
diff --git a/build/php.m4 b/build/php.m4
index 3624a33a8e..d17a635c2c 100644
--- a/build/php.m4
+++ b/build/php.m4
@@ -425,7 +425,7 @@ dnl
dnl Adds a path to linkpath/runpath (LDFLAGS).
dnl
AC_DEFUN([PHP_ADD_LIBPATH],[
- if test "$1" != "/usr/$PHP_LIBDIR" && test "$1" != "/usr/lib"; then
+ if test "$1" != "$PHP_OS_SDKPATH/usr/$PHP_LIBDIR" && test "$1" != "/usr/lib"; then
PHP_EXPAND_PATH($1, ai_p)
ifelse([$2],,[
_PHP_ADD_LIBPATH_GLOBAL([$ai_p])
@@ -470,7 +470,7 @@ dnl
dnl Add an include path. If before is 1, add in the beginning of INCLUDES.
dnl
AC_DEFUN([PHP_ADD_INCLUDE],[
- if test "$1" != "/usr/include"; then
+ if test "$1" != "$PHP_OS_SDKPATH/usr/include"; then
PHP_EXPAND_PATH($1, ai_p)
PHP_RUN_ONCE(INCLUDEPATH, $ai_p, [
if test "$2"; then
diff --git a/configure.ac b/configure.ac
index 36c6e5e3e2..71b1a16607 100644
--- a/configure.ac
+++ b/configure.ac
@@ -190,6 +190,14 @@ PHP_ARG_WITH([libdir],
[lib],
[no])
+dnl Support systems with system libraries/includes in e.g. /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk.
+PHP_ARG_WITH([os-sdkpath],
+ [for system SDK directory],
+ [AS_HELP_STRING([--with-os-sdkpath=NAME],
+ [Ignore system libraries and includes in NAME rather than /])],
+ [],
+ [no])
+
PHP_ARG_ENABLE([rpath],
[whether to enable runpaths],
[AS_HELP_STRING([--disable-rpath],
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment