以前都是靠各种一键脚本来安装 PHP,今天我尝试一下从源码手动编译安装 PHP,这里记录一下过程,有不足之处欢迎指正。废话不多说,直接开始。

系统环境

[root@hwc ~]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

环境需要

  • 安装 PHP 需要libxml2-developenssl-develcurl-devellibpnglibpng-devellibicu-develgcc-c++libmcrypt-devellibtidy-develunixODBC-develpostgresql-devel
    yum -y install libxml2 libxml2-devel openssl openssl-devel curl curl-devel libpng libpng-devel libicu-devel gcc-c++ libmcrypt-devel libtidy-devel unixODBC-devel postgresql-devel
    
  • 手动安装unixODBC/usr/local/unixODBC 首先从官网下载最新的unixODBC包并解压(如果感觉速度慢,可以使用备用下载)
    cd /usr/local
    wget http://ftp.unixodbc.org/unixODBC-2.3.7.tar.gz
    tar -zxvf unixODBC-2.3.7.tar.gz
    

    进入解压出来的文件夹内,配置安装目录,并编译安装。这里-prefix一定要为/usr/local/unixODBC,否则后面配置 PHP 时会报错

    cd unixODBC-2.3.7
    ./configure --prefix=/usr/local/unixODBC
    make && make install
    

以上是我配置的时候遇到的缺少的包,具体每个人配置的时候缺少的可能不一样,报错时请安装相应的包

安装

首先下载 PHP 安装包,这里我下载的是php-7.1.33,下载到/usr/local(如果下载速度过慢,可以使用备用下载

cd /usr/local
wget https://www.php.net/distributions/php-7.1.33.tar.gz
tar -zxvf php-7.1.33.tar.gz

然后配置安装选项

cd /usr/local/php-7.1.33
./configure  --enable-fpm --enable-mysqlnd --enable-opcache --enable-pcntl --enable-mbstring --enable-soap --enable-zip --enable-calendar --enable-bcmath --enable-exif --enable-ftp --enable-intl --with-mysqli --with-pdo-mysql --with-pdo-odbc=unixODBC --with-pdo-pgsql --with-openssl --with-curl --with-gd --with-gettext --with-mhash --with-openssl --with-mcrypt --with-tidy --enable-wddx --with-xmlrpc

上面的配置参数开启了很多 PHP 扩展,某些扩展需要特定的包,如果没有的话,请自行安装,或酌情删除某些参数 关于配置的可选参数及作用,请参考核心配置选项列表

配置成功会出现下面这样的输出。希望你能一次成功,但是如果你的系统比较干净,在执行完上一步安装了那些包后仍然可能缺少一些包,缺少包的话配置就会报错。看见报错别怕,根据报错内容去安装对应的包就可以

Thank you for using PHP.

config.status: creating php7.spec
config.status: creating main/build-defs.h
config.status: creating scripts/phpize
config.status: creating scripts/man1/phpize.1
config.status: creating scripts/php-config
config.status: creating scripts/man1/php-config.1
config.status: creating sapi/cli/php.1
config.status: creating sapi/fpm/php-fpm.conf
config.status: creating sapi/fpm/www.conf
config.status: creating sapi/fpm/init.d.php-fpm
config.status: creating sapi/fpm/php-fpm.service
config.status: creating sapi/fpm/php-fpm.8
config.status: creating sapi/fpm/status.html
config.status: creating sapi/phpdbg/phpdbg.1
config.status: creating sapi/cgi/php-cgi.1
config.status: creating ext/phar/phar.1
config.status: creating ext/phar/phar.phar.1
config.status: creating main/php_config.h
config.status: executing default commands

配置成功之后编译测试并安装,测试环节不要少

make && make test
make install

测试环节可能会失败,可能会遇到一些bug,把错误信息根据提示发送给 PHP 官方就好,你也可以选择不发送,这都没关系。只要编译成功,就可以执行安装。 安装之后,查看是否安装成功

[root@hwc ~]# php -v
PHP 7.1.33 (cli) (built: Jan 11 2020 17:34:26) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

配置php.ini

查看php.ini应该放置的目录

[root@hwc ~]# php --ini
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File:         (none)
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

Configuration File (php.ini) Path: /usr/local/lib可以看到php.ini应该放到/usr/local/lib目录内,然后Loaded Configuration File: (none)表示在/usr/local/lib目录内并未加载到php.ini,我们需要把php.ini文件放到那里

先去 PHP 安装包目录,然后拷贝php.ini-development/usr/local/lib/php.ini

cp /usr/local/php-7.1.33/php.ini-development /usr/local/lib/php.ini

请注意如有需要,请将路径替换成你的正确的路径 拷贝过去之后再查看一下

[root@hwc ~]# php --ini
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File:         /usr/local/lib/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

可以看到php.ini文件已经加载到

如果你想更改php.ini文件的加载路径,你可以在编译安装前通过配置参数--with-config-file-path=来配置

配置php-fpm.conf

php-fpm是一个FastCGI程序,是用来管理CGI进程(例如:php-cgi,PHP解释器)的。 执行配置文件测试命令以查看测试文件情况

[root@hwc ~]# php-fpm -t
[11-Jan-2020 18:25:22] ERROR: failed to open configuration file '/usr/local/etc/php-fpm.conf': No such file or directory (2)
[11-Jan-2020 18:25:22] ERROR: failed to load configuration file '/usr/local/etc/php-fpm.conf'
[11-Jan-2020 18:25:22] ERROR: FPM initialization failed

可以看到系统并未加载到/usr/local/etc/php-fpm.conf。它当然加载不到,因为还没配置。

进入到/usr/local/etc目录下,可以看到有个php-fpm.conf.default,拷贝出来一份重命名为php-fpm.conf,然后还有一个文件是/usr/local/etc/php-fpm.d/www.conf.default,这里也要做一下相同处理。

cp /usr/local/etc/php-fpm.conf.default /usr/local/etc/php-fpm.conf
cp /usr/local/etc/php-fpm.d/www.conf.default /usr/local/etc/php-fpm.d/www.conf

改好名后再测试一下

[root@hwc ~]# php-fpm -t
[11-Jan-2020 18:54:18] ERROR: Unable to globalize '/usr/local/NONE/etc/php-fpm.d/*.conf' (ret=2) from /usr/local/etc/php-fpm.conf at line 125.
[11-Jan-2020 18:54:18] ERROR: failed to load configuration file '/usr/local/etc/php-fpm.conf'
[11-Jan-2020 18:54:18] ERROR: FPM initialization failed

还是失败,怎么回事?查看失败记录,很容易看到php-fpm.conf第125行出了错误,而且是路径书写错误。好了,那改吧。

vim /usr/local/etc/php-fpm.conf

来到vim编辑界面输入:set number以显示行号,让我们更快地找到第125行

来到第125行,可以看到第125行写的是

include=NONE/etc/php-fpm.d/*.conf

NONE修改成绝对路径试试,修改后如下

include=/usr/local/etc/php-fpm.d/*.conf

保存并退出后,再次测试

[root@hwc ~]# php-fpm -t
[11-Jan-2020 19:02:39] NOTICE: configuration file /usr/local/etc/php-fpm.conf test is successful

OK,成功了。

在启动服务之前,需要修改www.conf配置文件,确保 php-fpm 模块使用 www 用户和 www 用户组的身份运行

vim /usr/local/etc/php-fpm.d/www.conf

找到如下部分并进行如下修改

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = www
group = www

然后启动php-fpmphp-fpm的可执行文件路径由 PHP 配置时的--prefix=决定,prefix默认是/usr/local。而php-fpm的可执行文件在prefix/sbin目录下,所以默认是在/usr/local/sbin目录下 启动php-fpm

[root@hwc ~]# /usr/local/sbin/php-fpm 
[11-Jan-2020 19:31:56] ERROR: [pool www] cannot get uid for user 'www'
[11-Jan-2020 19:31:56] ERROR: FPM initialization failed

启动失败,没有www用户,那就创建

groupadd www
useradd -g www -s /sbin/nologin www

再次启动

[root@hwc ~]# /usr/local/sbin/php-fpm

没有报错,经如下检查,说明启动成功

[root@hwc ~]# ps -ef | grep php-fpm
root     19159     1  0 19:35 ?        00:00:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
www      19160 19159  0 19:35 ?        00:00:00 php-fpm: pool www
www      19161 19159  0 19:35 ?        00:00:00 php-fpm: pool www
root     19170  8731  0 19:40 pts/0    00:00:00 grep --color=auto php-fpm

php-fpm启动与停止

为了能够更加方便地启动与停止 php-fpm ,我们需要编写一个服务

vim /usr/lib/systemd/system/php-fpm.service

添加以下内容,请把路径换成自己的php-fpm路径

[Unit]
Description=php-fpm
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/sbin/php-fpm

[Install]
WantedBy=multi-user.target

之后就可以使用systemctl方便地管理php-fpm服务了

# 设置开机自动启动
systemctl enable php-fpm

# 设置禁止开机自动启动
systemctl disable php-fpm

# 启动服务
systemctl start php-fpm

# 停止服务
systemctl stop php-fpm

# 查看服务状态
systemctl status php-fpm

错误处理

  • 关于启动php-fpm报错,显示127.0.0.1:9000端口已被占用 报错内容如下
    ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (98)
    

    查看一下是谁在占用端口

    [root@hwc php-7.1.33]# netstat -lntup | grep 9000
    tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      25688/php-fpm: mast
    

    你会发现就是它自己在占用这个端口。执行下面命令关闭其进程,然后再次启动php-fpm就好了。

    killall php-fpm