场景如下:

  1. Linux环境,PHP5.3版本,用的ThinkPHP3.1框架(老项目的源码亲喷)。
  2. 一顿编译安装之后,发现少转了GD库,就又手动从源码包里拉了GD包出来,单独编译了一遍,最后phpinfo();查看GD库安装上了。
  3. 满心欢喜,一顿刷新,操,验证码还是没出来,然后开始了百度一顿搜索,最终总结出以下几种可能性:

一、关于PHP用不了imagepng函数,导致Nginx 502 的问题

查看phpinfo()里的GD库,是不是安装上了libpng项,--with-png-dir=/usr/local/libpng.1.6.19,然后看看php的依赖库,用这个:

  1. ldd /usr/local/php/bin/php | grep libpng

具体的PHP安装路径根据自己的实际情况

我的看到是这样:

  1. libpng12.so.0 => /usr/lib/x86_64-linux-gnu/libpng12.so.0 (0x00007fa6dbbe2000)
  2. libpng12.so.0,其实就是说用的libpng的版本是1.2.x

很明显libpng.1.6.19libpng.1.2.x是对不上的,问题就在这里,解决的办法是:

  1. 1. 把/usr/lib/x86_64-linux-gnu/libpng12.so.0里的libpng12版本升级到libpng16,用apt-get install -y libpng16-dev,再重新编译PHP
  2. 2. 把原来的/usr/local/libpng.1.6.19删了,重新编译安装libpng,要用1.2.x的版本,这里就不赘述libpng的安装了,将路径写到--with-png-dir=里就可以了,再重新编译PHP

不过可惜,公司并不是这种情况。

二、不重新编译php,扩展gd库,导致nginx出现502错误,php-fpm出现exited with code 127错误

通过使用命令,批量跟踪php-fpm进程

  1. ps -ef | grep fpm | awk '{print "-p " $2}' | xargs strace

刷新在浏览器刷新验证码页面,然后切回XShell,发现最终问题出在PHP调用GD库时报错undefined symbol: gdJpegGetVersionString

【解决方法】

修改源代码:

  1. vim /softs/php-5.6.9/ext/gd/gd.c

下面两行放在首部:

  1. #include "/softs/libpng-1.6.23/png.h"
  2. #include "/softs/jpeg-9b/jpeglib.h"

尾部增加:

  1. const char * gdJpegGetVersionString()
  2. {
  3. switch(JPEG_LIB_VERSION) {
  4. case 62:
  5. return "6b";
  6. break;
  7. default:
  8. return "unknown";
  9. }
  10. }
  11. const char * gdPngGetVersionString()
  12. {
  13. return PNG_LIBPNG_VER_STRING;
  14. }

然后保存gd.c,重新整合php & gd,重启php-fpmnginx,就OK了。

但公司还是不是这个问题,找到这里差点崩溃。

三、php gd freetype libjpeg support 不支持

打开phpinfo()有时候你会发现自己装上了jpegpnggif、但却少了个freetype,这个主要是字体引擎相关的依赖。

先在linux运行

  1. find / -name freetype2

一遍都会得到

  1. /usr/include/freetype2

找到正确的依赖地址,然后重新编译GD库时,加上--with-freetype-dir=/usr/include/freetype2安装成功,重启php-fpm后,在phpinfo()里就能看到安装上了。

但这时候我崩溃,具体这个也不是,TMD。

突然内心一哭,难道是框架的问题?这老东西不知道靠不靠谱,直接开源码一顿梭哈再说。

打开验证码类,发现:

  1. php
  2. static function output($im, $type='png', $filename='') {
  3. header("Content-type: image/" . $type);
  4. $ImageFun = 'image' . $type;
  5. if (empty($filename)) {
  6. $ImageFun($im);
  7. } else {
  8. $ImageFun($im, $filename);
  9. }
  10. imagedestroy($im);
  11. }

这老代码原来是根据不同图片类型,自动选择使用哪个image函数库的,默认是png

虽然看着没问题,但由于神笔马良的探索精神,我还是直接断点一波,尝试改成jpg类型,一顿操作之后,发现验证码居然出来了,难道是imagepng()函数库的问题?之后function_exists('imagepng')如我所料,得出结果是false,又尝试换成imagegif(),验证码还是能出来,这时候基本就可以确定是png函数库的问题了。

逛了一波Google,有人说是PHP在编译时没有安装GD库,又或者时安装GD库时没有依赖到PNG,之后再单独编译GD库时,PNG函数库还是会无法使用,只有重新编译PHP,同时编译GD-PNG才能解决这个问题。

反正是新机器,重装PHP问题也不大,就让公司运维重新编译了一次。

重启,按下F5,果然验证码出来了,顿时心中一万只草泥马奔腾而过,只能说一句:PHP牛逼!