iEFdev

Code, Computers & Random Junk

My PHP7 Install

I’ve installed and added PHP7 to my local server, so here are a few notes on that. As before… This is not a tutorial or a HowTo …more of a conceptual overview. You might want/have to fill in the missing parts your self.

Notes

I finished the 4 blog posts on my server installation the other day (first part here). After that I have installed PHP7, and added it to my server setup. I’m still using PHP 5.6 as the main version, but as a complement, just like I have 5.4 for old(er) scripts, I’ve added PHP7 to test/try and eventually - move over to that one later. It’s still very new and not all extensions are working. I never got Suhosin to install. Though, there is a suhosin7 in progress, but it looks just initiated and nothing more. So, I’ll have to wait.

When you download PHP7 and extract it. Read the --help and look through the options etc. You’ll see ther are a few differences compared to previous version(s).

cd php-7.0.1
./configure --help > ../php7_help.txt
  • One is --enable-opcache, which is enabled by default now.
  • Same thing with --enable-ipv6.
  • You can also skip --with-t1lib=/usr/local/lib. It’s not in there.
  • Two other ones gone are: --with-mysql and --with-mssql.

But, I’ll put down my code changes/additions here and you’ll have to refer to the previous posts.

Apache and Macros

I have changed and added Macros in Apache, and of course added a few lines in httpd.conf and httpd-vhosts.conf

httpd.conf

The “Listen” parts:

# Mainly php-5.6 (php-fpm)
# if not specified in vhost
Listen 0.0.0.0:80
Listen [::]:80

# php-7.0 (php-fpm)
Listen 0.0.0.0:81
Listen [::]:81

# php-5.4 (mod_php)
Listen 0.0.0.0:82
Listen [::]:82

# SSL
Listen 0.0.0.0:443
Listen [::]:443

Old port for 5.4 is now :82 and :81 will be used for PHP7. Not all the time, just the option to.

The other part is about undefining the Macros:

# Undefine Macros
UndefMacro FastPHP
UndefMacro FastPHP7
UndefMacro ModPHP
UndefMacro AddFastExt
UndefMacro AddPhpExt
UndefMacro NoExt
UndefMacro to443

The new Macro is FastPHP7.

other/httpd-macros.conf

To start from the end… I’ve changed the Macro AddFastExt:

<Macro AddFastExt $ext>
    AddType application/x-httpd-php56 $ext
</Macro>

…into:

<Macro AddFastExt $ext>
    AddType application/x-httpd-phpfcgi $ext
</Macro>

Just to make more sense instead of making another with “php70”. So, that one is used for both versions (5.6 and 7.0)

That change also makes the Macro FastPHP a little bit different, and there’a also a new FastPHP7

other/httpd-macros.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#
# Macros - for use in vHosts
#

# === PHP56 :: FPM/FastCGI =====================================
# === pool: [$sockname] (eg [foobar.dev])
<Macro FastPHP $sockname>
  <IfModule fastcgi_module>
      AddType application/x-httpd-phpfcgi .php
      Action application/x-httpd-phpfcgi /.php-fpm

      <IfModule alias_module>
          Alias /.php-fpm /srv/http/.php56-fpm/$sockname
      </IfModule>
      FastCGIExternalServer /srv/http/.php56-fpm/$sockname -socket /var/php56/fpm.d/$sockname.sock

      # Sock folder
      <LocationMatch "^\/?\.php\-fpm">
          Require all denied
          Require env REDIRECT_STATUS
      </LocationMatch>
      <Directory /srv/http/.php56-fpm>
          Require all denied
          Require env REDIRECT_STATUS
          <Files "$sockname">
              Require all denied
          </Files>
      </Directory>
  </IfModule>
</Macro>

# Example:
#Use FastPHP foobar.dev
#UndefMacro FastPHP


# === PHP70 :: FPM/FastCGI =====================================
# === pool: [$sockname] (eg [foobar.dev])
<Macro FastPHP7 $sockname>
  <IfModule fastcgi_module>
      AddType application/x-httpd-phpfcgi .php
      Action application/x-httpd-phpfcgi /.php-fpm

      <IfModule alias_module>
          Alias /.php-fpm /srv/http/.php70-fpm/$sockname
      </IfModule>
      FastCGIExternalServer /srv/http/.php70-fpm/$sockname -socket /var/php70/fpm.d/$sockname.sock

      # Sock folder
      <LocationMatch "^\/?\.php\-fpm">
          Require all denied
          Require env REDIRECT_STATUS
      </LocationMatch>
      <Directory /srv/http/.php70-fpm>
          Require all denied
          Require env REDIRECT_STATUS
          <Files "$sockname">
              Require all denied
          </Files>
      </Directory>
  </IfModule>
</Macro>

# Example:
#Use FastPHP7 foobar.dev
#UndefMacro FastPHP7


// ... //

extra/httpd-vhost.conf

In the Vhost file… I didn’t follow the previous setup/layout, so I made a separate vhost as the default PHP7 site, and in ~/Sites I can use it on port :81 or if I set it as the running version on any other vhost-site.

In extra/httpd-vhost.conf, after the first default site, I have this:

extra/httpd-vhost.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#===============================================
# DocumentRoot /srv/www/php7.dev/public_html
#===============================================
<VirtualHost *:80>
  Define vhost_srv php7.dev

  ServerName ${vhost_srv}
  ServerAlias www.${vhost_srv} localhost70
  ServerAdmin admin@${vhost_srv}

    DocumentRoot /srv/www/${vhost_srv}/public_html

  <IfModule alias_module>
      #Alias /pma /srv/www/_phpMyAdmin/public_html
      ScriptAlias /cgi-bin/ "/srv/www/${vhost_srv}/cgi-bin/"
  </IfModule>

  <Directory "/srv/www/${vhost_srv}/public_html">
      Options -Indexes -FollowSymLinks +SymLinksIfOwnerMatch
      Require host localhost
      Require ip ::1
      #Require all granted

      Use AddFastExt srv

      Use NoExt srv
      Use NoExt php
  </Directory>

  # Choose PHP Version
  # ==================
  Use FastPHP7 70-default
  #Use ModPHP
</VirtualHost>

Don’t forget to add to /etc/hosts:

127.0.0.1   php7.dev www.php7.dev localhost70

Folders

Created some folders, and set permissions.

sudo mkdir -p /etc/php70/fpm/pool.d{-available}
sudo mkdir -p /var/php70/{fpm.d,log,run,sessions}
sudo chown -R _www:_www /var/php70

sudo mkdir /srv/http/.php70-fpm
sudo chown _www:_www /srv/http/.php70-fpm

For the default site I also made these ones:

sudo mkdir -p php7.dev/{backups,cgi-bin,logs,misc_files,public_html,tmp}
sudo chown -R $USER:staff php7.dev

Aliases

We keep 5.6 in PATH, and like before 5.4 and now 7.0 are accessed with aliases.

In ~/.bash_aliases it now looks like:

# PHP 5.4, 7.0 (5.6 is in PATH)
alias php54='/usr/local/php54/bin/php'
alias phpize54='/usr/local/php54/bin/phpize'
alias pear54='/usr/local/php54/bin/pear'
alias pecl54='/usr/local/php54/bin/pecl'

alias php70='/usr/local/php70/bin/php'
alias phpize70='/usr/local/php70/bin/phpize'
alias pear70='/usr/local/php70/bin/pear'
alias pecl70='/usr/local/php70/bin/pecl'
alias fpmctl70='/usr/local/php70/sbin/fpmctl'

There’s an xtra alias for fpmctl70 since it’s running as “FPM/FastCGI”.

Install

The configure I used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#
# PHP 7.0.1-efd
# 2015-12-25
#
../php-7.0.1/configure \
--prefix=/usr/local/php70 \
--localstatedir=/var/php70 \
--libdir=/usr/lib/php70 \
--includedir=/usr/include/php70 \
--datarootdir=/usr/share/php70 \
--mandir=/usr/share/php70/man \
--sysconfdir=/etc/php70 \
--with-config-file-path=/etc/php70 \
--with-config-file-scan-dir=/etc/php70/conf.d \
--with-bz2=/usr \
--with-curl=/usr/local \
--with-fpm-user=_www \
--with-fpm-group=_www \
--with-freetype-dir=/usr/local \
--with-gd \
--with-gettext=/usr/local \
--with-gmp=/usr/local \
--with-iconv-dir=/usr/local \
--with-icu-dir=/usr/local \
--with-imap=/usr/local/imap-2007 \
--with-imap-ssl=/usr/local \
--with-iodbc=/usr \
--with-jpeg-dir=/usr/local \
--with-kerberos=/usr \
--with-ldap=/usr \
--with-ldap-sasl=/usr \
--with-libedit=/usr \
--with-libxml-dir=/usr/local \
--with-mcrypt \
--with-mhash \
--with-mysqli=mysqlnd \
--with-mysql-sock=/var/mysql/mysql.sock \
--with-ndbm=/usr \
--with-openssl=/usr/local \
--with-openssl-dir=/usr/local \
--with-pcre-dir=/usr/local \
--with-pcre-regex=/usr/local \
--with-pdo-mysql=mysqlnd \
--with-pdo-pgsql=/usr/local \
--with-pear=/usr/lib/php70/pear \
--with-pgsql=/usr/local \
--with-pic \
--with-png-dir=/usr/local \
--with-readline=/usr/local \
--with-snmp=/usr \
--with-tidy \
--with-xmlrpc \
--with-xsl=/usr/local \
--with-zlib=/usr/local \
--with-zlib-dir=/usr/local \
--disable-short-tags \
--disable-rpath \
--enable-bcmath \
--enable-calendar \
--enable-cli \
--enable-dba \
--enable-exif \
--enable-fpm \
--enable-ftp \
--enable-gd-native-ttf \
--enable-inline-optimization \
--enable-mbregex \
--enable-mbstring \
--enable-mysqlnd \
--enable-pcntl \
--enable-pdo \
--enable-sigchild \
--enable-shmop \
--enable-soap \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-wddx \
--enable-zip

Pretty much the same as before…

Extensions

I have added the same extensions as before, except Suhosin that isn’t ready, yet. And for some I hade to use a couple of other versions.

  • APCu: To get the tag and branch it, use: git checkout tags/v5.1.2 -b v5.1.2.
  • GeoIP: You must get the “svn” version: svn checkout http://svn.php.net/repository/pecl/geoip/trunk/ geoip.
  • Intl: I used phpize70 on the bundled. Forgot to test before if it would install. Previous versions have failed for me on OS X. Since this one worked, perhaps I should try to include it in the configure line next time.
  • Imagick: I used the 3.4.0RC4 PECL version.

LaunchDaemon

A new LaunchDaemon: /System/Library/LaunchDaemons/net.php.php7-fpm.plist, to run it (on start).

/System/Library/LaunchDaemons/net.php.php7-fpm.plist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>KeepAlive</key>
  <false/>
  <key>Label</key>
  <string>net.php.php7-fpm</string>
  <key>LaunchOnlyOnce</key>
  <true/>
  <key>ProgramArguments</key>
  <array>
      <string>/usr/local/php70/sbin/php-fpm</string>
      <string>--fpm-config</string>
      <string>/etc/php70/php-fpm.conf</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>Debug</key>
  <false/>
  <key>ServiceDescription</key>
  <string>PHP 7.0 :: FPM/FastCGI</string>
  <key>StandardErrorPath</key>
  <string>/var/php70/log/php-fpm.log</string>
</dict>
</plist>

You can also find it on Github: srv-files/LaunchDaemons/net.php.php7-fpm.plist

fpmctl70

A new version of fpmctl is made as well, like the one here.

/usr/local/php70/sbin/fpmctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/bin/sh
#
# fpmctl
#
# Description: Custom script based on the OS X version of `apachectl`
# to (un)load php-fpm when using launchtl
#
ARGV="$@"
#
# |||||||||||||||||||| START CONFIGURATION SECTION  ||||||||||||||||||||
# --------------------                              --------------------
#
# the path to your httpd binary, including options if necessary
PHPFPM='/usr/local/php70/sbin/php-fpm'
#
# Config file (if needed)
PHPFPMCONF='/etc/php70/php-fpm.conf'
#
# Using Links or Lynx?
LYNX="links -dump"
#
# Using `open` here (for now). It'll use the default browser
# To specify - add "-a browser" (eg. open -a Firefox)
BROWSER="open"
#
# the URL to php-fpm's status page.  If you do not
# have one, then status and fullstatus will not work.
# Add your settings to httpd-info.conf
STATUSURL="http://localhost/p70/status"
#
# --------------------                              --------------------
# ||||||||||||||||||||   END CONFIGURATION SECTION  ||||||||||||||||||||


# Program and path to LaunchDaemon
LAUNCHCTL="/bin/launchctl"
LAUNCHD_JOB="/System/Library/LaunchDaemons/net.php.php7-fpm.plist"

run_launchctl() {
    if [ $UID != 0 ]; then
        echo This operation requires root.
        exit 1
    fi

    $LAUNCHCTL $@
}

ERROR=0

if [ "x$ARGV" = "x" ] ; then
    ARGV="-h"
fi

# Modified from apachectl in OS X
case $ARGV in
start)
    run_launchctl load -w $LAUNCHD_JOB
    ERROR=$?
    ;;

stop)
    run_launchctl unload -w $LAUNCHD_JOB
    ERROR=$?
    ;;

restart|graceful)
    run_launchctl unload -w $LAUNCHD_JOB 2> /dev/null
    run_launchctl load -w $LAUNCHD_JOB
    ERROR=$?
    ;;

# Test FPM configuration and exit
configtest)
    $PHPFPM -y $PHPFPMCONF -t
    ERROR=$?
    ;;

# PHP information
info)
    $PHPFPM -i
    ERROR=$?
    ;;

status-cli)
    $LYNX $STATUSURL
    ;;

status-web)
  $BROWSER $STATUSURL
  ;;

*)
    $PHPFPM "$@"
    ERROR=$?
esac

exit $ERROR

You can also find it on Github: srv-files/PHP/fpmctl70

Note: You must rename it to fpmctl. The name on Github is just to keep them apart.

/usr/local/php70/sbin/fpmctl

Pools

Without the comments/commented lines… Refer to the generated files.

The global pool: /etc/php70/php-fpm.conf

/etc/php70/php-fpm.conf
1
2
3
4
5
6
7
8
9
10
11
[global]

pid = run/php-fpm.pid

error_log = log/php-fpm.log

log_level = notice

daemonize = no

include=/etc/php70/fpm/pool.d/*.conf

The default pool: /etc/php70/fpm/pool.d/70-default.conf (not symlinked).

‘/etc/php70/fpm/pool.d/70-default.conf’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[www]

; When not set, the global prefix (or /usr/local/php70) applies instead.

user = _www
group = _www

listen = /var/php70/fpm.d/70-default.sock

listen.backlog = 65535

pm = ondemand

pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

pm.status_path = /p70/status
ping.path = /p70/ping
ping.response = pong

access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
slowlog = log/70-default.log.slow

catch_workers_output = yes

security.limit_extensions = .php .srv


;;; Mail
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i
;php_admin_value[mail.log] = /srv/http/logs/70-default-php_mail_log
php_admin_value[mail.log] = /srv/www/php7.dev/70-default-php_mail_log

;;; Errors
php_flag[display_errors] = on
php_admin_value[error_log] = /srv/www/php7.dev/70-default-php_errors_log
php_admin_flag[log_errors] = on

;;; Mem
;php_admin_value[memory_limit] = 128M
php_admin_value[memory_limit] = 32M

;; Session
php_admin_value[session.gc_maxlifetime] = 3600
php_admin_value[session.save_path] = /var/php70/var/session

;;; Dirs
;php_admin_value[open_basedir] = /srv/http/public_html
php_admin_value[upload_tmp_dir] = /srv/www/php7.dev/tmp

Post notes

You can of course add to ~/Sites to run it on port :81 etc.

To add/mix versions are a bit tricky, but keep notes of all your edits and just let it take the time it needs.

When all is done you’ll have 3 PHP versions running on the same Apache server.

My setup now is:

  • Apache 2.4.18, MPM Event
    • php-5.4.45 - (Apache 2.0 Handler).
    • php-5.6.16 - (FPM/FastCGI, main version).
    • php-7.0.1 - (FPM/FastCGI).

And I can start/stop/restart the server with:

  • apachectl (in PATH).
  • fpmctl (in PATH).
  • fpmctl70 (aliased to: /usr/local/php70/sbin/fpmctl).

Screenshot

(Full size)


Happy hacking…

/Eric

Comments