记一次生产升级事件(php)

背景

咸鱼君所在公司的安全部门, 扫描出项目的生产服务安全漏洞,并且很负责任的提供了两份扫描文档,

一份针对nginx(1.1.6),
一份针对php(7.1.3),

并限期一周内改善完!

咸鱼君粗略一扫,全都是服务软件的漏洞,

于是乎, 两个选择摆在眼前:

1.根据文档,按图索骥, 一个补丁一个补丁的“劳模打补丁”;
2.直接升级软件到最新版, 当然, 得确保服务的代码必须要适配!

于是咸鱼君“认真”考虑了一下(实在是懒,补丁太多,当然,也是觉得升级了对应用代码影响不大), 决定升级服务软件来解决漏洞!

下面,详细介绍咸鱼君的升级过程~

评估升级风险!

有相似需求的朋友一定要认真评估“直接升级服务软件版本”方案是否适合自己的业务, 因为服务软件的版本每次升级都会有些变化, 比如php就会舍弃一些函数, 万一项目代码用到了, 结果你直接升级了php
, 最后导致生产的服务代码跑不起来,那就悲剧了!!

评估升级风险的方式,咸鱼君采用的是本地升级服务软件,测试项目代码是否正常~

有条件的也可以搞台克隆生产环境的服务器, 而后测试升级操作~

备份备份备份!

先找到php 的安装目录
whereis php
查看当前版本(7.1.3)
/usr/local/php/bin/php -v 
查看当前configure编译参数.这个要保存下,编译新php时要用!
php -i | grep configure 

这里列出来的数据格式不对,需要处理一下,建议小伙伴保存在txt中,然后将单引号“ ’ ”替换为空值即可

 ./configure  
--prefix=/usr/local/php
 --with-config-file-
path=/usr/local/php/etc 
--enable-fpm 
--with-mcrypt 
--enable-mbstring 
--enable-pdo 
--with-curl 
--disable-debug 
--disable-rpath 
--enable-inline-optimization 
--with-bz2 
--with-zlib 
--enable-sockets 
--enable-sysvsem 
--enable-sysvshm 
--enable-pcntl 
--enable-mbregex 
--with-mhash 
--enable-zip 
--with-pcre-regex 
--with-mysqli 
--with-gd 
--with-jpeg-dir 
--with-freetype-dir 
--enable-calendar 
--with-openssl 
--with-png-dir 
--with-zlib-dir 
--enable-gd-native-ttf 
--with-xsl 
--with-gettext 
--with-pdo-mysql
备份旧版的php文件夹
sudo cp -r /usr/local/php  /usr/local/php_7.1_bac 

php升级

接下来我们去 https://www.php.net/downloads.php找到合适的稳定的php版本来下载, 记得一定要详细看change log,来决定要不要升级! 否则生产的服务代码因为版本问题挂了,那就悲剧了!! 咸鱼君考察后,选择了 php7.4.4稳定版,粗略一看,应该没问题(事实上后面发现了个小问题!险些悲剧!)
下载
//切换会用户目录(下载文件时先切换自己的目录,这是个好习惯!)
cd ~ 
wget https://www.php.net/distributions/php-7.4.4.tar.gz 
解压
tar -zxvf php-7.4.4.tar.gz
配置编译参数 (注意, 这里有很多问题, 为了流程的连贯性, 建议先往下看,读完全文, 最后再执行, 咸鱼君实力踩坑!)
cd php-7.4.4
//这里的***代表之前保存的编译参数
//但是php7.4.4和之前的有些许不同,所以需要大家先转换!!!!
//务必先不要执行,看完全文再执行,免得踩坑~
./configure  --prefix=*** 
编译
sudo make
安装
sudo make install
恢复配置
cd /usr/local/php_7.1_bac/
sudo cp etc/php.ini  /usr/local/php/etc/php.ini
sudo cp etc/php-fpm.conf /usr/local/php/etc/php-fpm.conf
sudo cp etc/php-fpm.d/www.conf /usr/local/php/etc/php-fpm.d/
切换新版php
//平滑重启
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

//当然,有时候急于等待结果的话,可以杀死再重启(不建议)
//咸鱼君为了快速验证,所以采用杀死再重启的方式,小伙伴们视实际情况而定
cd /usr/local/php/sbin/
sudo killall php-fpm
sudo ./php-fpm
最后,确认服务正常,去访问下生产的服务,是不是正常,如果发现不对,立刻执行以下命令恢复旧php
cd /usr/local
sudo killall php-fpm
sudo rm -r php
sudo cp -r php_7.1_bac/  php
sudo /php/sbin/php-fpm

如果真像上面罗列的升级过程一样简单就好了,事实上,咸鱼君升级php7.4.4的过程中碰到了很多的,并且有些问题是网上找不到明确解答的!, 接下来听咸鱼君细细道来~

php编译期间缺包问题

No package ‘*******’ found

碰到这问题很好解决,缺啥装啥即可!
这里咸鱼君碰到了如下的包缺失问题, 要是你碰到的和我不一样,没关系, 网上这类的问题解决贴一大把,主要因系统环境而异!

No package ‘libjpeg’ found
sudo yum install libjpeg libjpeg-devel
No package ‘libxml-2.0’ found
sudo yum -y install libxml2
sudo yum -y install libxml2-devel
No package ‘sqlite3’ found
sudo yum install sqlite-devel
No package ‘oniguruma’ found
sudo yum install oniguruma oniguruma-devel
No package ‘libpng’ found
sudo yum install libpng-devel

以上包都很好解决,下面这个包有点“意思”,

No package ‘libzip’ found

Please reinstall the libzip distributio 或 configure: error: system libzip must be upgraded to version >= 0.11
这个包比较特别, 不知道是不是php7.4.4的适配问题, 咸鱼君发现 yum install 安装的版本比较低,并且下载的1.2.1这个包安装上还是识别不了,只有1.2.0可以用!!!
yum remove libzip libzip-devel     //卸载yum安装的低版本
wget https://nih.at/libzip/libzip-1.2.0.tar.gz
tar -xvf libzip-1.2.0.tar.gz
cd libzip-1.2.0
./configure
make
这句一定要执行,不然编译安装php还是报错找不到!!
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/"   
sudo ldconfig
sudo make install

php执行时加载“.so”扩展失败问题

咸鱼君安装完各种包,兴冲冲的执行

cd /usr/local/php/sbin/
sudo killall php-fpm
sudo ./php-fpm

时,发现,报错

PHP Warning: PHP Startup: Unable to load dynamic library “******.so”

好吧, 折腾呗!
根本原因就是, 原来编译安装的扩展, 比如“redis”这类的,只适用于当时的php, 所以我们要想继续使用, 则必须得用新的php重新编译这些扩展,重新安装!

这里注意的时,有些扩展在php的安装包里就有,所以不用额外去下载~

Unable to load dynamic library “ bcmath.so”
cd php-7.4.4/ext/bcmath 
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
sudo make
sudo make install
Unable to load dynamic library “redis.so”
wget https://pecl.php.net/get/redis-5.2.1.tgz
tar -axvf redis-5.2.1.tgz
cd redis-5.2.1
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
sudo make
sudo make install

咸鱼君就碰到这两个, 安装完后

cd /usr/local/php/sbin/
sudo killall php-fpm
sudo ./php-fpm

好吧,再次报错, 原来是新的扩展打上后, 扩展路径和以前不一样了,所以需要修改php.ini, 注意, 安装扩展时,有返回一个安装路径, extension_dir这填充这个路径即可

sudo vim /usr/local/php/etc/php.ini

修改

extension_dir = "/usr/local/php/lib/php/extensions/no-debug-non-zts-20190902/"

最后

cd /usr/local/php/sbin/
sudo killall php-fpm
sudo ./php-fpm

好的,好像没问题了!!(剧透, 接下来有两个大坑!!!)

检查服务正常阶段

看似nginx和php都升级成功了,也不曾有报错了!
接下来我们来到最后阶段, 访问下项目, 看下是不是正常运行!!

大坑一: 验证码不显示!

咸鱼君项目采用的是Laravel5.6 + captcha做的验证码展示, 结果升级后发现,验证码显示不出来, 图片请求全是500错误, 打开Laravel Debug模式,看到报错

Symfony\Component\Debug\Exception\FatalThrowableError: Call to undefined function Intervention\Image\Gd\imagettfbbox()

一看, php的gd扩展有问题啊!!!
赶紧去ssh生产,查看gd扩展是不是正常安装的

php -m | grep gd

发现, gd扩展是有的!
这就奇怪了, 随后网上搜索下, 发现了各种“大佬”帖子的“解决方案”
大致方案如下

  1. php重新编译gd扩展
  2. 独立下载gd扩展编译安装
    ………………
    好吧, 咸鱼君尝试了, 并没什么用!
    这里就不发出这类的“解决方案”了,免得小伙伴们和我一样走“歪路”!

下面是重点了, 解决方案如下

问题原因

其实这个问题的确和 gd 扩展有关系, 主要是和gd扩展的子扩展freetype有关系!
你需要先判断生产环境是不是安装了freetype

//查看freetype安装目录
find / -name freetype  

要是安装了, 则编写一个小php脚本来判断有没有正确加载
gdtest.php

<?php

if(extension_loaded(gd)){
echo "can use gd<br>";
foreach(gd_info() as $cate=>$value)
echo "$cate: $value<br>";
}else
echo "can not use gd";
?>

执行

php test.php

结果:

can use gd
GD Version: bundled (2.0.34 compatible)
FreeType Support:                            #这里冒号后面没有值,说明gd不支持freetype
T1Lib Support:
GIF Read Support: 1
GIF Create Support: 1
JPEG Support: 1
PNG Support: 1
WBMP Support: 1
XPM Support:
XBM Support: 1
JIS-mapped Japanese Font Support:

若“FreeType Support: ”后为空不为“1”则说明,gd库没有freetype支持!

问题似乎陷入了循环,明明安装了freetype, 但是gd扩展却显示不支持!!! 搜遍互联网,咸鱼君得到的全都是“重装freetype”,“重装gd扩展”,甚至“重装php”的“解决方案”!

最后,咸鱼君无疑中看到一篇帖子,关于介绍php7.4.4的configure编译配置参数的变化的! 如下

--with-gd                   改为 --enable-gd
--with-freetype-dir     改为 --with-freetype
--with-jpeg-dir           改为 --with-jpeg
--with-webp-dir         改为 --with-webp
--with-xpm-dir           改为 --with-xpm
--with-libxml-dir         改为  --with-libxml 
--enable-zip              改为 --with-zip
--enable-zlib-dir        改为 --with-zlib

大家看到

--with-freetype-dir     改为 --with-freetype

有没有眼前一亮?!! 是的,真相如此简单, 还记得我们之前

php -i | grep configure

查出的那一堆配置参数么, 我们只需要按图索骥, 把对应的旧版参数替换成新版参数, 然后重新

./configure  --prefix=***
make 
sudo make install

即可!!!

真是坑爹!

另外,咸鱼君罗列的可能不全, 大家可以自行查看新版的参数

 //**代表你需要的扩展参数的关键字,来查看对应的配置方式
./configure -h  | grep **   

最后编译配置php7.4.4的命令为

./configure  
--prefix=/usr/local/php 
--with-config-file-path=/usr/local/php/etc 
--with-php-config=/usr/local/php/bin/php-configure 
--enable-fpm 
--enable-bcmath 
--with-mcrypt 
--enable-mbstring 
--enable-pdo 
--with-curl 
--disable-debug 
--disable-rpath 
--enable-inline-optimization 
--with-bz2 
--with-zlib 
--enable-sockets 
--enable-sysvsem 
--enable-sysvshm 
--enable-pcntl 
--enable-mbregex 
--with-mhash 
--with-zip 
--with-pcre-regex 
--with-mysqli 
--enable-gd 
--with-jpeg 
--with-freetype 
--enable-calendar 
--with-openssl 
--with-png 
--with-zlib 
--with-gd-native-ttf 
--with-xsl 
--with-gettext 
--with-pdo-mysql

大坑二: php7.4.4数组严格验证

满心关系的解决完验证码问题, 登入了项目web后台,却突然发现报错

Trying to access array offset on value of type null

当时, 吓得咸鱼君一身冷汗, 迅速ssh上生产, 先恢复了旧php!

之后,排查得到报错原因

######原来php7.4.4移除了很多notice报错,也就是可能老版的php只是warning,notice级别的报错,在新版里全部以error抛出!

Trying to access array offset on value of type null

就是其中的一种, php7.4.4不允许对值为null的数组不进行判空操作直接使用!

举个例子

$arr = //api返回;
$name = $arr['name'];

这样的操作就会抛出异常,所以我们需要先判断

if(isset($arr['name'])){
    $name = $arr['name'];
}

可以看出,php也在进行一些类型的严格规范了!

修改了这个问题, php就不抛错了, 咸鱼君再次上线了新版php~~

至此, 顺利从php7.1.3升级至7.4.4!!

希望咸鱼君的升级笔记能够帮到需要的小伙伴~

##升级需评估 ,否则要背锅~~

请关注我的订阅号

订阅号.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值