Skip to content

Instantly share code, notes, and snippets.

@rizalp
Last active March 21, 2023 11:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save rizalp/b5cc046bf271a2561339bea50b3505f5 to your computer and use it in GitHub Desktop.
Save rizalp/b5cc046bf271a2561339bea50b3505f5 to your computer and use it in GitHub Desktop.
[Build PHP 8] Minimal Build PHP 8.2.4, linked with sqlite3 from source on Ubuntu 22.04 And Macos #php #sqlite3 #ubuntu22.04

Why?

  • Minimal PHP system needed to run CRUD symfony app
  • Better understanding of PHP configurations
  • Newer sqlite support, like window functions and JSON1 extension

Adapted from

Install build tools & PHP Core dependencies

Ubuntu

sudo apt-get install build-essential \
pkg-config \
autoconf \
libtool \
bison \
re2c \
libxml2-dev \
libonig-dev \
libssl-dev \
libargon2-0-dev \
libsodium-dev \
libcurl4-openssl-dev \
libreadline-dev \
libyaml-dev \
libgmp-dev \
libzip-dev \
libpng-dev \
libjpeg-dev \
libwebp-dev \
libxpm-dev \
libicu-dev \
libfreetype6-dev \
libxslt-dev \
libldb-dev \
libtidy-dev \
libvips-dev

Download sqlite3 from https://www.sqlite.org/download.html. Download the source code with -autoconf file which contains the configure scripts. Extract and cd into the extracted directory

./configure --prefix=$HOME/package/sqlite-3.41.1 

make

make install

Configure And Compile PHP

Download PHP https://www.php.net/distributions/php-8.2.4.tar.xz, then adjusting the sqlite pkg-config and ldflags as needed

PKG_CONFIG_PATH="$HOME/package/sqlite-3.41.1/lib/pkgconfig" \
LDFLAGS="-L/$HOME/package/sqlite-3.41.1/lib" \
./configure \
--prefix=$HOME/package/php-8.2.4 \
--enable-bcmath \
--enable-calendar \
--enable-opcache \
--enable-mbstring \
--enable-intl \
--enable-mysqlnd \
--enable-fpm \
--enable-gd \
--enable-exif \
--with-fpm-user=$USER \
--with-fpm-group=$USER \
--with-readline \
--with-zlib \
--with-curl \
--with-openssl \
--with-password-argon2 \
--with-sodium \
--with-pear \
--with-gmp \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-zip \
--with-xsl \
--with-jpeg \
--with-png \
--with-webp \
--with-tidy

make -j $(nproc)

# run test (optional)
mysql -u root -e 'CREATE SCHEMA test;'
make TEST_PHP_ARGS=-j$(nproc) test
# for specific test only make TEST_PHP_ARGS=-j$(nproc) TESTS=ext/pdo_sqlite/ test

make install

./libtool --finish $HOME/source/php-8.2.4/libs

Optionally, you could test the binary using make TEST_PHP_ARGS=-j$(nproc) test or make TEST_PHP_ARGS=-j$(nproc) TESTS=ext/pdo_sqlite/ test to test only specific extension . To test mysql connection, don't forget to create schema mysql -u root -e 'CREATE SCHEMA test;'

copy default php-fpm config, otherwise php-fpm cannot be started

cp $HOME/package/php-8.2.4/etc/php-fpm.conf.default $HOME/package/php-8.2.4/etc/php-fpm.conf
cp $HOME/package/php-8.2.4/etc/php-fpm.d/www.conf.default $HOME/package/php-8.2.4/etc/php-fpm.d/www.conf

configure to running in the foreground, for easy debugging. Edit $HOME/package/php-8.2.4/etc/php-fpm.conf

daemonize = no

configure it to listen to unix socket, edit $HOME/package/php-8.2.4/etc/php-fpm.d/www.conf

listen = /tmp/php-fpm.sock

also, uncomment out the listen.owner, listen.group, & listen.mode variables

php-fpm can be started by executing $HOME/package/php-8.2.4/sbin/php-fpm

Macos

This macos guide kind of outdated, since I rarely use Mac, please check the following for more updated approach:

brew install icu4c \
oniguruma \
openssl@1.1 \
libsodium \
argon2 \
libiconv \
readline \
libyaml \
gmp \
pkg-config \
libpng \
libzip \
autoconf \
tidy

Configure And Compile PHP

Finally, install php-8.2.4, adjusting the sqlite pkg-config and ldflags as needed

export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$HOME/package/sqlite-3.41.1/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libxml2/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libpng/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libwebp/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libzip/lib/pkgconfig"

./configure \
--prefix=$HOME/package/php-8.2.4 \
--enable-bcmath \
--enable-calendar \
--enable-opcache \
--enable-mbstring \
--enable-intl \
--enable-mysqlnd \
--enable-fpm \
--enable-gd \
--enable-exif \
--with-fpm-user=$USER \
--with-fpm-group=$USER \
--with-readline=$(brew --prefix readline) \
--with-iconv=$(brew --prefix libiconv) \
--with-zlib \
--with-curl \
--with-openssl \
--with-password-argon2 \
--with-sodium \
--with-pear \
--with-gmp \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-zip \
--with-xsl \
--with-jpeg \
--with-png \
--with-webp \
--with-tidy

make -j$(sysctl -n hw.logicalcpu)

# run test (optional)
mysql -u root -e 'CREATE SCHEMA test;'
make TEST_PHP_ARGS=-j$(sysctl -n hw.logicalcpu) test
# for specific test only make TEST_PHP_ARGS=-j$(sysctl -n hw.logicalcpu) TESTS=ext/pdo_sqlite/ test

make install

./libtool --finish $HOME/source/php-8.2.4/libs

Add To Path And Test

Then, add the $HOME/package/php-8.2.4/bin to your PATH

Finally:

rizalp@desktop:~$ symfony check:requirements

Symfony Requirements Checker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

> PHP is using the following php.ini file:
/home/rizalp/package/php-8.2.4/lib/php.ini

> Checking Symfony requirements:

.............................

                                              
 [OK]                                         
 Your system is ready to run Symfony projects 
                                              
@rizalp
Copy link
Author

rizalp commented Jan 20, 2020

php.ini

In $HOME/package/php-7.4.16/lib add new file php.ini. The default path are found from ./php --ini

short_open_tag=0
mysqli.default_socket=/var/run/mysqld/mysqld.sock
zend_extension=opcache.so

@rizalp
Copy link
Author

rizalp commented Jan 20, 2020

pear clear-cache
pear update-channels
pear upgrade --force

TODO

  • openssl
  • bcmath
  • gmp
  • calendar
  • mysql client
  • xdebug : pecl install xdebug, then add zend_extension=xdebug.so
  • exif
  • imagemagick : apt install libmagickwand-dev imagemagick, pecl install imagick, then add extension=imagick
  • apache integration (most shared host is still using .htaccess).
  • mysqlnd
  • yaml : pecl install yaml then add extension=yaml
  • uuid : pecl install uuid
  • timezonedb : pecl install timezonedb
  • vips : apt install libvips-dev then pecl install vips then add extension=vips

More options can be seen in the ./configure --help

@rizalp
Copy link
Author

rizalp commented Feb 4, 2020

Apache2 From Source

Previously i tried to use the apache2 from Ubuntu repo. --with--apxs2 flag configure successfully detect the libs. Unfortunately, when doing make install, it tried to put mod_php into the apache2 dir which requires root access, which failed.

I'd like to make it installed on non-root directory. to avoid messing up with system files.

Dependencies for apache2:

sudo apt install libapr1-dev libaprutil1-dev libpcre3-dev

Then simply follow the http://httpd.apache.org/docs/current/install.html, using this configure script, with only minimal mods required, and using mpm_prefork (because mod_php is not thread safe).

PREFIX=$HOME/package/httpd-2.4.46
./configure --prefix=$PREFIX --enable-mods-shared='few rewrite proxy proxy_fcgi' --enable-mpms-shared='prefork event' --enable-nonportable-atomics=yes
make -j4
make install

And then, rebuild php using configuration above, with new flag: --with-apxs2=$HOME/package/httpd-2.4.46/bin/apxs

Apache2 Configuration

Make backup of the default configuration

mv $PREFIX/conf/httpd.conf $PREFIX/conf/httpd.conf.bak 

Then, use the following $PREFIX/conf/httpd.conf.

In $PREFIX/conf/httpd.conf, make sure the following is applied. This will make apache2 listen to 127.0.1.1:8000, enabling mpm_event and rewrite (most php frameworks / cms have extensive use of .htaccess), and specify directory for vhost conf and files.

Define httpd_root "${HOME}/package/httpd-2.4.46"
ServerRoot "${httpd_root}"
Listen 8000

LoadModule rewrite_module modules/mod_rewrite.so

# These three are needed for mpm_event + php_fpm
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

# These two embedd php7 into the apache, hence need to use prefork as 
# php extension are not thread safe
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
#LoadModule php7_module        modules/libphp7.so

LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so

ServerAdmin you@example.com
ServerName 127.0.1.1:8000

<Directory />
    AllowOverride none
    Require all denied
</Directory>

DocumentRoot "${httpd_root}/htdocs"
<Directory "${httpd_root}/htdocs">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<Directory "${httpd_root}/domains">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

<IfModule unixd_module>
    User ${USER}
    Group ${USER}
</IfModule>

<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

Include conf/domains/*.conf

<Files ".ht*">
    Require all denied
</Files>

ErrorLog "logs/error_log"
LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    CustomLog "logs/access_log" common
</IfModule>

<IfModule headers_module>
    RequestHeader unset Proxy early
</IfModule>

<IfModule mime_module>
    TypesConfig conf/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
</IfModule>

# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
#       starting without SSL on platforms with no /dev/random equivalent
#       but a statically compiled-in mod_ssl.
#
<IfModule ssl_module>
    SSLRandomSeed startup builtin
    SSLRandomSeed connect builtin
</IfModule>

Then mkdir -p $PREFIX/conf/domains && nano $PREFIX/conf/domains/demo.local.conf, and add the minimal virtualhost needed to proxy all .php files into php-fpm:

<VirtualHost demo.local>
    ServerName demo.local
    ServerAlias www.demo.local
    DocumentRoot ${httpd_root}/domains/demo.local

    <IfModule proxy_fcgi_module>
        SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
        <FilesMatch \.php$>
            SetHandler proxy:unix:/tmp/php-fpm.sock|fcgi://dummy
        </FilesMatch>
    </IfModule>

    <IfModule php7_module>
        <FilesMatch \.php$>
            SetHandler application/x-httpd-php
        </FilesMatch>
    </IfModule>

    ErrorLog ${httpd_root}/logs/demo.local/error.log
    CustomLog ${httpd_root}/logs/demo.local/access.log combined
</VirtualHost>

Then add files virtualhost sites directory mkdir -p $PREFIX/domains/demo.local && nano $PREFIX/domains/demo.local/index.php

<?php

phpinfo();

Or you could symlink public directory that contains front controller index.php of your project. For example symfony project has this front controller public that store index.php front controller and many static assets. The static assets will be served by apache with mpm_event, and the index.php is forwarded to php_fpm

Create log directory mkdir -p $PREFIX/logs/demo.local

Finally, register demo.local as the valid domain in your computer, by sudo nano /etc/hosts, and add / append

127.0.1.1                demo.local

finally start bin/apachectl -k start. Alternatively you could do start | stop | restart | graceful | graceful-stop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment