编译安装php7.4的一些踩坑和探索
周六进行服务器数据迁移时踩的坑。浅浅记录一下探索过程,以防未来再度踩坑。
事情是这样的。
先前的云服务器快到期了,由于续费很贵,于是我换了一家服务商,最近在断断续续利用闲暇时间做数据迁移。
在这个服务器上我有一个dokuwiki的页面,平时用来存放一些笔记和日记的内容,但是迁移到新机器以后,我发现dokuwiki的页面显示出了些问题,所有页面元素渲染全部不正确。查看控制台日志发现在进行 GET http://125.122.22.249/doku/dokuwiki/lib/exe/css.php?t=dokuwiki&tseed=f690c2922e3bb08ba4733d36a34533de
时收到了500 Internal Server Error错误。进一步排查日志,怀疑是php的问题。
原先那台机器上的php版本为7.4,新机器的系统是Ubuntu 22.04.5,能够用apt安装到的只有php8以上的版本,而dokuwiki的框架是以php7的语法编写的,因此存在一些兼容性的问题(例如, PHP Fatal error: Array and string offset access syntax with curly braces is no longer supported in /var/www/html/doku/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php on line 761
)。
要解决这个问题,有两种策略:①升级dokuwiki到支持php8的版本;②降级php到php7的版本。
经过一些并不严谨的搜索,我以为dokuwiki依然没有提供php8支持(但后来发现,好像只要升级到最新版就能支持php8),于是采取了第二种策略,降级php到php7。以下是详细步骤:
一、准备工作
使用apt移除已有的php版本
1 | sudo apt autoremove php |
然后下载php-7的源代码包,将其解压至 /opt
目录,并进入这一目录。
1 | cd /opt |
二、编译、测试与运行
编译前,需要安装下面几个工具库。(这一块的内容可能有所不同,取决于 ./configure
阶段会发生什么样的报错。简单来说,./configure
阶段说缺乏哪个工具,就安装那个工具)
1 | sudo apt install pkg-config |
进行make前的configuration:
1 | sudo ./configure --enable-fpm # 启动fpm模块的编译 |
这里额外补充一点知识:当服务器上的httpd是由apache2控制时,php有两种不同的工作模式。
- 第一种方式:Mod-PHP(Apache PHP 模块),即PHP 直接嵌入 Apache,并通过
libphp
模块执行 PHP 代码。这种模式是apt install php
安装的默认工作模式,只需要apt install libapache2-mod-php
就可以工作。 - 第二种方式:FastCGI(php-fpm 进程),即PHP 以
php-fpm
服务的形式,运行在单独的进程池中,Apache 通过mod_proxy_fcgi
与php-fpm
进程通信。
我们现在编译安装php,要选择的工作模式是FastCGI(php-fpm 进程)模式,这种模式编译比较简单(不需要生成so文件然后去apache2那边再做配置),且进程独立,比较好控制。
完成configuration以后,我们进行编译与安装的步骤:
1 | sudo make |
编译过程大约需要十多分钟,在此期间我们可以稍作休息。编译完成之后运行 make install
,则php的相关文件就会被复制到相应的系统路径下(如上图),其中包括 /usr/local/bin/,/usr/local/sbin/
等。
保险起见,我们此时最好编辑一下 /etc/profile
文件,将上述路径写入环境变量PATH当中(如下图, PATH=$PATH:/usr/local/bin/:/usr/local/lib/:/usr/local/sbin/
)
三、配置php自身的配置文件
编译安装好的php,其配置文件路径在 /usr/local/etc
目录下,主要包括 /usr/local/etc/php-fpm.conf
和 /usr/local/etc/php-fpm.d/www.conf
,前者用于php本身的配置,后者用于工作池(pool)的配置。两个以 .default
结尾的文件是配置文件模板,如果配置文件不存在,可以使用cp指令从模板文件创建新的配置文件。
1 | cyclin@vm:/usr/local/etc$ tree |
第一个配置文件 /usr/local/etc/php-fpm.conf
:
1 | [global] |
第二个配置文件 /usr/local/etc/php-fpm.d/www.conf
:
1 | [www] |
这里的 listen
字段指定了php进程和apache2进程之间的通信方式。 listen = /run/php/php7.4-fpm.sock
即通过 /run/php/php7.4-fpm.sock
套接字文件进行通信。另一种通信方式是 listen = 127.0.0.1:9000
,通过9000网络端口进行通信。相比之下,sock套接字文件的通信效率高一点,因此我们也采取这种方法进行配置。
可以使用 php-fpm -t
检测配置文件是否编写正确。如果输出 ”test is successful“(如下代码块),则表明一切正常。
1 | cyclin@vm:/usr/local/etc/php-fpm.d$ sudo php-fpm -t |
四、将php-fpm设置为系统服务
现代Linux系统使用systemctl管理系统服务,其配置文件全部存放在 /etc/systemd/system/
目录下。我们在这里创建一个文件 php7.4-fpm.service
,即可创建相关服务(服务的名称就是 php7.4-fpm
)
1 | cd /etc/systemd/system/ |
在这个文件中,写入以下内容:
1 | [Unit] |
解释一下 ExecStartPre
字段的意思:这里设置的是每次启动服务前需要执行的操作。对于php-fpm的服务来说,我们需要提前执行的操作有两个,分别是 /bin/mkdir -p /run/php
和 /bin/chown www-data:www-data /run/php
,即创建 /run/php
目录并赋予www-data
访问权限。因为php服务需要在这个目录下创建套接字文件,但是php服务本身的权限不足以创建和修改这个目录,因此我们在这里使用root用户的身份进行提前创建和赋权。
完成上述配置以后,我们启动php-fpm服务,并查看服务状态:
1 | sudo systemctl daemon-reload #重新加载所有系统服务 |
如果服务运行正常,我们可以看到类似下面这样的输出:
如果服务运行不正常,则 sudo systemctl status php7.4-fpm
会输出错误状态,此时我们也可以使用 sudo journalctl -u php7.4-fpm --no-pager | tail -30
查看更详细的报错信息,以便排查错误。
五、配置apache2方面的配置文件
当我们在浏览器中访问一个php页面时(例如 xxx.com/index.php
),apache2会去查询服务器上的 /var/www/html/index.php
这个文件,然后调用php进行php代码的执行,随后将执行完代码的html版本的页面返回给浏览器。因此,apache2与php的进程间通信很重要。使用apt安装的apache2默认没有开启与php的进程间通信,我们需要手动开启。
首先,我们创建配置文件 /etc/apache2/conf-available/php7.4-fpm.conf
,在这个文件中写入下面的内容:
1 | <IfModule mod_proxy_fcgi.c> |
随后,通过下面的指令启动php支持并重启apache2的服务:
1 | sudo apt install libapache2-mod-fcgid # 安装apache2的相关功能模块 |
完结撒花!
要测试php的效果,可以使用下面的指令创建一个phpinfo文件:
1 | echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php |
如果一切顺利,当我们使用浏览器访问这一页面时,将会看到如下图的内容:
以上。