手记

关于编译PHP的一点思考

问题的引出

    总是有人反复问我php在CentOS等Linux系统下的安装问题,甚至同是一个人,几个月内安装PHP数次竟问我几十个相关问题,但是我保证:他每一次问的问题都不重样。这让我不禁停下来思考“无数次”的原因是什么? 我初步总结两点: 

1、未对linux原理进行系统学习 

2、Linux太灵活 

    由于安装php的人目的不同,我们不能要求每个人都如此这般精通Linux再去安装php,特别是有些php程序员仅仅是想搭建一个完整的php环境,然后就要迅速转入编程工作,自然对linux环境无需关心,甚至不甚熟悉。所以本文的目的就是想从菜鸟理解问题的角度(特别是面向windows下的Php程序员)阐述linux下安装php环境遇到的种种问题的缘故和解决思路.


基础知识

    开始之前,普及一些必要的Linux安装软件的知识,一般来说: 

1、不管任何linux系统,只要软件代码开源, 都可以通过tar.gz源码包方式安装软件,即源码编译安装。 
2、如果你基于某个Linux发行版工作,那么现代版的Linux套件都提供便捷的工具来安装软件。如CentOS使用yum,Ubuntu使用apg-get. 
    回到php安装上来: php通常都是用来做web应用,所以安装php也意味着安装Apache和MySQL。 既然我们使用CentOS套件,不妨先体验一把CentOS的yum工具如何便捷地安装软件. 
    假设此时CentOS主机已经装好,能够SSH登录上去,那么开始安装Apache,PHP, Mysql(认为以下有些只是点初学者能容易通过其他渠道掌握的省略),安装不必顺序进行: 

12345678910111213141). 安装Apache # sudo yum install httpd mod_ssl  2). 安装php # sudo yum install php php-common php-gd php-mcrypt php-pear php-pecl-memcache php-mhash php-mysql php-xml  3). 安装mysql # sudo yum install mysql-server  4). 启动mysql, # sudo service mysqld start  5). 启动apache # sudo service httpd start

    在浏览器中访问 http://your-ip/,  看看apache欢迎页是不是出来了。接下来写一个php脚本,链接数据操作,放到apache主目录下,看看能否访问。 


    一般来说,到这一步很多人都是可以做到的。即便遇到一点问题也都可以通过google找到资料解决,让人对Linux学习充满信心。那么,真正的问题在于:你无法安于yum工具默认为你做的设置, yum傻瓜式帮你把软件装好,一旦你需要任何对软件、特别是对服务器软件的定制时,你发现你都必须面对Yum下面的复杂性! 

案例1: 我发现默认装好的php是5.1.6,但是我想升级到5.2.10,但是yum服务器没有提供package怎么办? 
对于真正专业的PHP开发人员,了解如何针对他们的操作系统编译安装PHP是比较重要的。

看看前面提到的源码tar包方式,现在是面对的时刻了,去网站下载php源代码,在本地编译. 
tar.gz 包安装软件基本分三步走: 

123# configure   # make   # make install

注:这里的前提是apache、mysql已经安装在你的机器上了。那么升级之前是否要卸载当前的php5.1.6呢? 当然要删(不要手工删除,yum安装的就用yum删除),执行yum remove php 即可. 

现在解压缩php源码到 php目录,进入该目录执行

12# ./configure --prefix=/usr/local/php# make && make install

    这是一个最简化的安装步骤,如果不出意外,你的php所有相关的文件都被安装在/usr/local/php目录下。源码安装方式的有点在于,你能控制一个软件安装后所有的文件在一个相关目录下,缺点是你必须手工地配置它和apache与mysql的关联.。
    /usr/local/php/bin/php 就是php程序,在httpd.conf中配置其以CGI方式运行(google容易搜到不赘述)。重新启动apache, 运行一个Php脚本,现在应该已经可以执行了.。
    运行一个数据库连接的php脚本,通过浏览器运行,结果如何? 很遗憾,他可能告诉你mysql_connect找不到. 想想这个结果蛮合理的,apache和php通过前面的设置绑定好了,但是好像从来没设置过php和mysql的绑定啊? 

    还曾记得当我们使用C语言操作MySQL的时候,到mysql官方网站下载 MySQL Connector/C; 使用java连接数据库需要导入 mysql-connector-java-version-bin.jar 包(JDBC)。 总结一下:就是当我们需要编写程序去操作“X软件”时,我们必须参考“X软件”提供的API 或者 SDK,如果开放性很好,那么通常会提供大量API(比如:C语言、C++, JAVA, PYTHON等等)。相当于提供一个中间层(X软件的驱动程序)


其实,这里我们可以引申出一个基本概念: php如何使用第三方软件! 
本例是: php(mysql_connect()函数)使用mysql(第三方软件). 

观察上图,php能使用大量的第三方非php库(典型性是C语言写库), 为了达到此目的,你必须具备两个条件: 

  • 条件1    必须安装第三方库(软件)

  • 条件2    安装该软件的php扩展(接口,API)

    前面的情况是: mysql装了,满足条件I,但是条件II不满足, 为了满足条件二, 我们需要了解php安装扩展的知识. 

安装php, 大的方面还可以分为两种方式: 

  • 方式1. 静态编译    将扩展编译到php 

  • 方式2. 动态编译    将扩展单独编译成动态连接库so文件

方式1的优点是运行速度快,但是为了一个扩展需要重新安装整个php;

方式2灵活,但是运行速度稍慢. windows平台下的php程序员大多只熟悉方式2,因为方式2是windows下安装Php扩展的唯一方式. 

    这里,我想教大家熟悉一方式1. 因为之前不是安装php了吗? 如果没有删除php目录,重新进入该目录, 那么此时重新编译运行将采用增量方式,实际上比方式2还更方便些.仍然3步走: 

12# ./configure --prefix=/usr/local/php --with-mysql# make && make install

    和第一次安装php有什么差别? 是不是仅仅多了一个--with-mysql? 没错,php源码包包括了大量的Php扩展,也包括mysql的php扩展,只要加一个--with-mysql指示符, 编译的Php就支持mysql访问了 
    不幸的是,,很多人加了--with-mysql 参数后出项提示找不到头文件(*.h)文件,这是为什么呢? .h文件属于c语言知识范畴了。不过,一个基本知识是: X软件的php扩展的源代码在编译时必然可能依赖X软件的某些东西,好比mysql的php扩展源代码编译时不仅仅要求你安装mysql sever, 而一定要它的开发包相关文件(.h文件)。因此一般的思路就是: 下载mysql开发包并安装, 不过不要担心, 不到非必要,我们都尽可能使用yum工具来安装所有能安装的东西。通常有个命名管理,就是xx软件的开发包,往往相应的yum包名都是xx-devel。 不例外地,安装mysql开发包的命令则是: yum install mysql-devel。一路yes安装完毕,重新运行--with-mysql的configure, 现在应该顺利重装了php, 而且数据库连接也应该正常工作了。 


    有人质疑: 我安装mysql sdk,./configure命令一个--with-mysql就知道我安装的目录,还是有点神奇,难道他全硬盘搜索.h文件? 不是, 如果你用yum方式安装sdk,那么LD_LIBRARY_PATH系统变量就指示了该sdk相关信息 ,如果你使用源码(tar)安装mysql sdk,你的--with-mysql参数不得不像这样: --with-mysql=/your_mysql_sdk_dir/ 


案例2: (基于案例I)我发现5.2.10默认已经支持了很多扩展如果dom, iconv等,根据客户要求,现需要安装如下的扩展: 
curl, gettext, bz2, mysql,  calendar,pspell, shmop, ftp, openssl, zlib, exif,gmp,sysvmsg,sockets,wddx, gd, mysqli, pdo_mysql, mcrypt, mime_magic, xsl
 

正像案例1描述安装mysql扩展的过程一样, 这些扩展全都可参照依法炮制.configure配置命令如下: 

1# ./configure --prefix=/usr/local/php --with-curl --with-gettext --with-bz2 --with-mysql -enable-shmop --enable-calendar --with-openssl --with-pspell --enable-ftp --with-openssl --with-zlib --enable-exif --with-gmp --enable-sysvmsg --enable-sockets --enable-wddx --with-xsl --with-mcrypt --with-mysqli --with-mime_magic --with-pdo-mysql --with-gd --with-apxs2=/usr/local/apache/bin/apxs --without-sqlite --enable-so

我怎么知道这些参数的含义? 打开./configure脚本,参照官方php文档学习这些参数的含义是正宗的方法

    特别注意--with-apxs2=/usr/local/apache/bin/apxs的用法,此参数假设了apache已经预先安装带有apxs,这样apache的php模块文件会自动添加到httpd.conf文件中,如果是通过yum方式安装的apxs(如:yum -y install httpd-devel),则--with-apxs2参数不要加=后面的路径。也请参考另篇文章http://koda.iteye.com/blog/233412 

    安装过程中一定存在可能X软件还没安装,导致X软件的php扩展不能通过configure检查,那么我们通过yum 安装相应的软件包以及开发包即可。


假设yum包中不包含该软件怎么办? 采用终极方法:tar包安装,参照另文描述. 
安装之后,php.ini默认不存在。如果需要设置php.ini选项,通过phpinfo()函数查看php.ini默认存放路径,将php源码路径下的php.ini-recommended复制到其目录下更名为php.ini 


案例3: (基于案例I)我看yum默认安装的php都是以apache模块方式安装的,我能否也这样做? 
可以,apache的php模块so文件是php源代码包编译出来的./configure加一个参数: 
--with-apxs2=/usr/sbin/apxs 
这是什么? --with-apxs2所指向的 /usr/sbin/apxs是apache安装的一个Perl脚本,它知道所有apache软件的信息, 这样编译出来的apache的Php模块文件(名字可能是libphp5.so)将被复制到合适的目录,并且修改httpd.conf装载该文件. 
如果你的apache是源码方式安装的,那意味着apache软件所有相关文件都在某个目录下,如果/usr/apache,那么你也可以不用--with-apxs2而直接使用--with-apache=/usr/apache. 


指定了--with-apxs2=/usr/local/apache/bin/apxs以后,就不要再激活--enable-fpm和--enable-fastCGI,apxs是以php module的模式加载PHP的。

Mysql在编译了Mysql开发library以后,可以不用指定mysql的路径。

PHP编译存在基础的依赖的关系,编译PHP首先需要安装XML扩展,因为php5核心默认打开了XML的支持,其他的基础库,相应需要:

GD -> zlib, Png, Jpg, 如果需要支持其他,仍需要根据实际情况编译扩展库,ttf库需要freetype库的支持。

--enable-magic-quotes,是一个极其不推荐的参数,当然,如果你需要PHP为你做这些底下的工作,实际上他也没有很彻底的解决问题。

--with-openssl,需要openssl库。

mysqli是MySQL团队提供的MySQL驱动,具有很多实用的功能和典型特征。不过他不是MySQL于PHP平台最好的选择,PDO被证实,是一个简易、高并发性,而且易于创建和回收的标准接口。不过PDO也经历了5.3以前的内存溢出的问题,在5.3以后,在读取Oracle的LOB资源时,若不对内存进行限制,仍会内存溢出。

如果是产品模式,好像pear、shmop、ftp等,都不推荐使用,他们要做的事情,用C/C++,用Java,甚至其他脚本语言,都有很好很快速的选择,无需局限于使用PHP去实现。不熟悉的类库和不常用的库,也不推荐使用。magic-quote、session.auto_start、PHP服务器信息、PHP报错信息等在编译完成后,应该第一时间关闭,避免暴露服务器信息。

PHP对应的Web Server模式,Module、fastcgi、fpm只需要一种即可,服务器不是你的试验田。fastcgi可以选择Nginx和lighttpd,其实Nginx也是使用lighttpd的spwan-fcgi进行fcgi进程管理的。fpm是使用PHP自身去管理多进程,有点类似一个后端代理。无论什么模式,在发布产品服务器,都应该做进程和线程调优,做足够多的压力测试,找出最好的进程数组合。

选好一种PHP OPCode cache的扩展,这个也是很重要的,linux 2.6核心下,fcgi下,xcache有较好的实践经验,其他的在并发数增加以后,性能衰减严重。

如果真的想体验,宁可编译多几个PHP版本,也不要针对一个版本的PHP集合各种扩展,适应各种环境,这会让把你自己逼进窘境的。


F.A.Q 
Q1: make install出现警告 
Warning: Cannot use a scalar value as an array in phar://install-pear-nozlib.phar/PEAR/ChannelFile.php on line 1400 
不影响系统运行。但是为什么呢? 

Q2: 我的主机上有多个ini文件,怎样知道那个php.ini才是我当前有效的ini文件? 
A: 运行phpinfo()的php脚本,它会告诉你 

Q3: 我想做一些php的设置,但是我不想改php.ini,怎么办? 
A: php做./configure时,加参数 --with-config-file-scan-dir=/etc/php.d ,那么安装好的php运行时会自动检查/etc/php.d/下所有.ini文件。你可以把你的配置信息写到这里。 

Q4: 启动apachce出现错误:libphp5.so: cannot restore segment prot after relock: Permission Denied 
A: 临时禁用SELinux.执行命令setenforce 0. 永久生效可以执行setup命令,更改防火墙设置。 

Q5: 启动apache出现错误: 
Starting httpd: httpd: Syntax error on line 206 of /etc/httpd/conf/httpd.conf: Cannot load /usr/lib/httpd/modules/libphp5.so into server: /usr/lib/httpd/modules/libphp5.so: undefined symbol: sqlite3SrcListShiftJoinType 

A: php做./configure是时使用参数--without-sqlite。当然这是回避问题,我还没具体研究这个问题的确切原因:) 

Q5:按照你的./configure在32位机器上运行好好的,到了64位机器就不工作了,提示mysql什么的找不到 
A: ./configure增加参数 -–libdir=/usr/lib64 –-with-libdir=lib64 

下面是我在64bit主机上安装php的配置参数 

1./configure --prefix=/usr/php --with-apxs2=/usr/sbin/apxs --with-config-file-path=/etc/ --with-config-file-scan-dir=/etc/php.d --without-sqlite --enable-mbstring --with-curl --with-gettext --with-bz2 --with-mysql -enable-shmop --enable-calendar --with-openssl --with-pspell --enable-ftp --with-openssl --with-zlib --enable-exif --with-gmp --enable-sysvmsg --enable-sockets --enable-wddx --with-xsl --with-mcrypt --with-mysqli --with-mime_magic --with-pdo-mysql --libdir=/usr/lib64 --with-libdir=lib64 --with-gd --with-jpeg-dir=/usr/lib64 --with-png-dir=/usr/lib64 --with-freetype-dir=/usr/lib64

    执行./configure之前,如果php已经make过,最好make clean以保证configure指示的参数能够正确被编译. 



http://blog.renhao.org/2011/09/centos-6-x64-compile-lnmp-environment/

http://www.cnblogs.com/kootao/p/3245484.html




0人推荐
随时随地看视频
慕课网APP