本文为实战操作过程的全程记录,采用一台新创建的linode vps(512M内存)环境,操作系统采用centos 6.2,以从源码编译的方式安装配置nginx, php(fast-cgi模式)web环境。
我们的目标:配置一台高性能、安全的web服务器。
本文为实战操作过程的全程记录,采用一台新创建的linode vps(512M内存)环境,操作系统采用centos 6.2,以从源码编译的方式安装配置nginx, php(fast-cgi模式)web环境。
我们的目标:配置一台高性能、安全的web服务器。
centos6本身不带mcrypt库的支持,手工编译php时,还需要先安装该库,这里有两个途径
1. 使用第三方源实现yum安装,推荐使用RPMforge,在centos下配置该yum源,配置后即可尝试yum install libmcrypt, yum install libmcrypt-devel, yum install mcrypt-devel 安装该库。本人没有实际操作,不确定具体该包的包名。因为如果使用该库,就没必要手工编译php了,直接yum安装好了。配置RPMforge如下
rpm -ivh http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.i686.rpm yum clean all yum makecache
请参看RPMforge, 很不错的centos RPM/yum源
2. 手工编译安装mcrypt库的支持。
这才是本文主要针对的,手工编译。按php官方的说明 http://www.php.net/manual/en/mcrypt.requirements.php
These functions work using » mcrypt. To use it, download libmcrypt-x.x.tar.gz from» http://mcrypt.sourceforge.net/ and follow the included installation instructions
但是http://mcrypt.sourceforge.net/并没有libmcrypt,而是应该到sourceforge上下载,http://sourceforge.net/projects/mcrypt/files/Libmcrypt/2.5.8/
下载,解压,./configure, make,make install, 很常规的步骤。注意libmcrypt需要c++编译器,请保证安装过gcc-c++, 否则请yum install gcc-c++装之
centos 6下,安装fedoraproject的epel-release源,即可以安装php的mssql模块。
注:epel是fedora开发组为centos开发的附加软件yum源,可以弥补centos上游redhat里缺少的软件包。epel的质量还是相当之高的。
[root@c12 html]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm
[root@c12 html]# rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
[root@c12 html]# yum install php-mssql
[root@c12 html]# /etc/init.d/httpd graceful
完成。
phpinfo中可以看到mssql的信息
mssql模块实际还是FreeTDS,其功能主要是在Liunx下能够访问Sybase及MS SQL,官方网站是:http://www.freetds.org/ 。当然也可以手工编译mssql模块到php中,不过通过yum更简单一点。
关于epel源,参看这里 http://fedoraproject.org/wiki/EPEL/zh-cn
本方法来源于centOS 6更新yum以便可裝php-mssql (http://blog.hubin411.com/2011/10/13/centos-6%e6%9b%b4%e6%96%b0yum%e4%bb%a5%e4%be%bf%e5%8f%af%e8%a3%9dphp-mssql/) 阅读该页面请自备梯子。或参看如下转录的核心部分:
tep 1:
# wget http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm //取得rpm檔案
step 2:
# rpm -ivh epel-release-6-5.noarch.rpm //安裝取得的rpm檔案
step 3:
# yum update //更新yum的資源庫
step 4:
# yum install php-mssql //安裝php-mssql
step 5:
# service httpd restart //重啟apache伺服器
使用php写的web程序,从mssql 2005读取一个文章列表,要读取出文章内容,在列表页面里显示出一部分,起先使用:
SELECT top 20 [id],[title],[content], FROM [news] where xxx
这是很自然直接的写法,但是发现运行速度非常的慢,浏览器访问经常要花费好几秒到几十秒才打开页面,慢的时候还会php脚本执行的超时;该表建有必要的索引,数据量只有几万条而已。通过定时追踪发现问题就出在这个语句上,改成如下的形式:
$sql="SELECT top $pagesize * from ( SELECT top $top [id],[title] ,convert(varchar(30),[updatetime],120) as [updatetime] ,[keyword] ,[picture],convert(varchar(500),content) as concent FROM [news] "; $sql = $sql.$sql_where." order by updatetime desc ) as bb order by updatetime asc";
目的是方便分页,不读取出没用的记录。但事实上并没有起色,还是非常慢(这个写法读出来的记录集其实是倒序的,要在读出到数组里后使用array_reverse来反转一下)。而当把sql语句里的content字段去掉不读,就会快如飞一般。就算是改换$sql_where 里的条件也一样的快(这样mssql就不会使用其内部缓存,方便比较语句效率)。
这么看,text型字段实在是mssql里sql语句效率的杀手;可悲的是,这个内容字段是一定要读取的,这是web系统的功能要求,使用缓存是一个方法,但就算使用缓存,在生成缓存时,也一样会非常慢,甚至超时。
几乎是异想天开的念头:拆成多个语句,先读出不带text字段的记录集,再通过php程序遍历id号,然后一条一条的读出text字段,并拼到结果数组里,没想到,居然速度快多了,打开速度维持在0.5秒内,虽然并不够理想。
实在是无法想像,无法理解为什么是这样子!
代码大致如下:
function get_content($id)
{
global $conn;
$content='';
$sql='select convert(varchar(max),content) as content FROM [news] where id='.(int)$id;
$rs=mssql_query($sql,$conn);
if($row=mssql_fetch_assoc($rs)){
$content=$row['content'];
}
$content=substr(strip_tags($content),0,500);
return $content;
}
$top=($page +1)*$pagesize ;
$sql="SELECT top $pagesize * from (SELECT top $top [id],[title] ,convert(varchar(30),[updatetime],120) as [updatetime] ,[keyword],[picture] FROM [news] "; $sql = $sql.$sql_where." order by updatetime desc) as bb order by updatetime asc";
$rs=mssql_query($sql,$conn) or die($sql);
$data=array();
while($row=mssql_fetch_assoc($rs)){
$row=$row+array(
'content' => get_content($row['id'])
);
$data[]=$row;
}
$data=array_reverse($data);
已于2012-01-16更新:对于元素为数组的,也以表格输出(否则将数组子元素显示为array)
直接上代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>以表格形式输出二维数组</title> </head> <body> <?php $comment[100]=array('id'=>100,'parent'=>0,'content'=>'AAAAAAAAAA'); $comment[101]=array('id'=>101,'parent'=>100,'content'=>'BBBBBBBBB'); $comment[102]=array('id'=>102,'parent'=>100,'content'=>'CCCCCCCCCC'); $comment[103]=array('id'=>103,'parent'=>0,'content'=>'DDDDDDDDDDd'); $comment[104]=array('id'=>104,'parent'=>102,'content'=>'EEEEEEEE'); $comment[105]=array('id'=>105,'parent'=>101,'content'=>'FFFFFFFFF'); $comment[106]=array('id'=>106,'parent'=>0,'content'=>'GGGGGGGG'); $comment[107]=array('id'=>107,'parent'=>0,'content'=>'HHHHHHHHH'); $comment[108]=array('id'=>108,'parent'=>101,'content'=>'IIIIIIIIIIII'); $comment[109]=array('id'=>109,'parent'=>105,'content'=>'JJJJJJJJJJ'); $comment[110]=array('id'=>110,'parent'=>103,'content'=>'KKKKKKKKKK'); $comment[111]=array('id'=>111,'parent'=>108,'content'=>'LLLLLLLLL'); $comment[112]=array('id'=>112,'parent'=>105,'content'=>'MMMMMMMMMM'); $data=$comment; array_table_view($data); function array_table_view($data) { ?> <table width="95%" border="1" cellspacing="0" cellpadding="4"><?php if(!sizeof($data)){ ?> <tr> <td>empty array.</td> </tr><?php }else{ foreach($data as $item){ ?> <tr><?php foreach($item as $key => $val){ ?> <th><?php echo $key; ?></th><?php } ?> </tr> <?php break; } foreach($data as $item){ ?> <tr><?php foreach($item as $key => $val){ ?> <td><?php if(is_array($val)){ array_table_view($val); }else{ echo $val; } ?></td><?php } ?> </tr> <?php } } ?> </table> <?php } ?> </body> </html>
代码下载 array_table_view
代码下载 (请“复制-粘贴-保存”以上代码)
php开发环境里,安装了xdebug模块后,var_dump()输出的结果将比较易于查看,但默认情况下,var_dump() 输出的结果将有所变化:过多的数组元素不再显示,字符串变量将只显示前N个字符,较深的数组元素也被显示成省略号。这点会带来一些不便,我们修改配置文件,设置这些。
在php.ini里的xdebug节点中,加入如下
xdebug.var_display_max_children=128
xdebug.var_display_max_data=512
xdebug.var_display_max_depth=5
含义从名字上看就可看懂。
其实这里有三条配置,正好与本文上述的三点“变化”一一对应嘀 ^..^
从phpinfo()里的xdebug节点里可以看到更多的配置变量,多半也是可以通过php.ini修改的
这是对一种错误表述的评论,错误见文后部分
"windows系统是直接输入文件的绝对路径需要这种方式"e:\\aaa.txt",注意是两个反斜杠,一个反斜杠的话就错了"这个说法是误导,或有 误导之嫌。windows系统表示文件路径时,使用一个反斜杠,而反斜杠在很多语言里表示转义之用,所以要用两个反斜杠;路径的字符串在程序运行过程中 (内存里),实际还是一个。
如果在php里,这样的用单引号括起路径字符串,如下这样是这完全正确的 readfile('e:\Downloads\t.txt'); 而readfile("e:\Downloads\t.txt");这样写就错了。不过事实上,在win32版的php里,这样写也是对的 readfile("e:\Downloads\z.txt"); 可能是反斜杠后是一个非转义字符,php把此\解析为常规反斜杠。
php里,用单引号括起路径字符串,readfile('e:\Downloads\t.txt');是这完全正确的,而readfile("e: \Downloads\t.txt");这样写就错了。不过事实上,在win32版的php里,这样写也是对的 readfile("e:\Downloads\z.txt"); 可能是反斜杠后是一个非转义字符,php把此\解析为常规反斜杠(但反对这样使用)。
——以上是对新浪微博里的一条微博做的回复,该条微博如下:http://weibo.com/1767100271/xDUCLyFYM【fopen函数的使用的几种方式】 //第一种使用fopen的方式,windows系统是直接输入文件的绝对路径需要这种方式"e:\\aaa.txt",注意是两个反斜杠,一个反斜杠的话就错了 //
原发微者没有回应,那就这管他了,把该条回复转到这里。
不知道什么时候,fedora 14上的php读取http远程文件时就报错,像下面这样
Warning: file_get_contents() [function.file-get-contents]: php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/lib/www/html/myworks/dn2ip/dn2ip.php on line 27
file(),fopen()等函数也有类似情况,如果直接指定ip地址连接是没有问题的,使用php cli也是正常的。另外gethostbyname函数也有问题,$ip = gethostbyname('www.baidu.com'); var_dump($ip);
执行结果是浏览器上输出 www.baidu.com,根本没有解析域名,而只把参数传出来,也没有报错,包括warning级别的错误也没有。
多方查找都没有找到原因,包括在英文站点上搜索也没找到可以解决问题的方案。网上大体有这些方案:检查命令行执行wget 等是否正常执行,检查主机dns服务器设置,重启apache等,但我的fedora是笔记本上的系统,不知道重启了多少次!
实在是很郁闷。想起完全卸载php,甚至连apache也卸载,然后清理一下相关残留文件,再重启重新安装试试。
yum erase php后,重启还有如下一些php包没的卸载,
[root@fsc ~]# rpm -qa |grep php
php-cli-5.3.6-1.fc14.i686
php-gd-5.3.6-1.fc14.i686
php-pdo-5.3.6-1.fc14.i686
php-mbstring-5.3.6-1.fc14.i686
php-xml-5.3.6-1.fc14.i686
php-mysql-5.3.6-1.fc14.i686
php-common-5.3.6-1.fc14.i686
[root@fsc ~]# rpm -ev php-cli php-gd php-pdo php-mbstring php-xml php-mysql php-common
warning: /etc/php.ini saved as /etc/php.ini.rpmsave
php配置文件曾经修改过,与rpm包里的原始版本不一致,所以被rpm自动备份下来了,重新安装php时很有参考价值的。
没有重启httpd,执行刚才的测试文件,发现居然可以解析域名了!那就不用重启再安装php了,直接yum install php,再安装另外几个包,yum install php-mbstring php-xml php-gd ,重启apache,完成!
这个非常怪异的问题,困扰了好些天,这次又莫名其妙的好了。原因不清楚。
-------------错误消息文本记录-------------------------------------
执行如下代码
$host="ip138.com";
var_dump(gethostbyname($host));
$url="http://www.baidu.com/";
$html=file_get_contents($url);
完整的错误消息,供参考(使用了xdebug,输出比php默认的消息更友好一点)
string 'ip138.com' (length=9)
( ! ) Warning: file_get_contents() [function.file-get-contents]: php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/lib/www/html/myworks/dn2ip/dn2ip.php on line 27 | ||||
---|---|---|---|---|
Call Stack | ||||
# | Time | Memory | Function | Location |
1 | 0.0015 | 331060 | {main}( ) | ../dn2ip.php:0 |
2 | 0.0105 | 331556 | file_get_contents ( ) | ../dn2ip.php:27 |
( ! ) Warning: file_get_contents(http://www.baidu.com/) [function.file-get-contents]: failed to open stream: php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/lib/www/html/myworks/dn2ip/dn2ip.php on line 27 | ||||
---|---|---|---|---|
Call Stack | ||||
# | Time | Memory | Function | Location |
1 | 0.0015 | 331060 | {main}( ) | ../dn2ip.php:0 |
2 | 0.0105 | 331556 | file_get_contents ( ) | ../dn2ip.php:27 |
string 'http://www.baidu.com/' (length=21)
一个朋友的网站,换web服务器,要我帮忙。朋友的网站原本在我的虚拟主机空间上,但嫌网通访问速度慢,自己买了个比较快一点的。要换的也还是虚拟主机,而且是超简单的那种,只有一个基于web的简单后台,文件管理都很不完善,连zip压缩解压缩的功能没有,也没有直接下载远程文件并解压的功能,更不用说ssh了。对于这样的虚拟主机最怕就是ftp服务器再有问题。
然而最怕的事情还是来了。
经常在虚拟主机上见到微软的msftp,那个烂啊,都没有可以形容的词了。上传或下载文件的过程中,会莫名其妙的连接中断,要重新连接,而且更可恶的是服务器在断开连接时,连个消息都不给,直接断掉了,ftp客户端还在等待服务器上回应,结果是超时,然后客户端才知道是连接断掉了。有时在上传或者下载一个队列时,上传了一个文件,在进行下一个时,提示消息“传输失败”,然后客户会跳过进行再下一下,再下一个......当然也传问是失败。这个最令人无法忍受的事情,只能强制断开ftp客户端,再重新传输队列。十分的没有效率,而且影响心情。这次的问题跟这个类似,但似乎这个服务器不是windows的,它使用的ftp服务器消息中声称是ProFTPD,看来应该是linux,而虚拟主机服务器的管理员能把linux也搞成这样,实在对不起linux. 以前还从来没有见过配置得这么烂的linux + ftpd!
然而骂归骂,事情还是得做。这次迁移的其实一个很小的网站,只有一千多个文件,跟一个mysql数据库。使用filezilla传输,已经设置文件覆盖规则,以免传输一半被服务器单方面断开、而导致文件重传时的“文件覆盖提醒”。但还是实在无法忍受,传了半个小时才传上了200多个文件,失败的队列文件数目已经涨到300多个,看来照这样的速度,要传不知道多久了,还得多次重置失败队列。于 是想需要用另外的方法来实现,而不能使用ftp了。最简单的php,它本身有文件管理的功能,网上有很多基于php的文件管理工具,下载了几个试用,要么功能太差,没有zip功能,或者文件太多,比朋友的这个小网站文件还多。 因为之前搞过一次php写的zip文件解压缩脚本,不过是使用别人写的。而php本身有从外部站点上下载文件的功能,像fopen, file_get_contents等函数都可以很容易实现。那与其找php文件管理工具,还不如写个简单的程序在目标主机上运行。程序非常简单:
<?php
$foo=__FILE__;
$bar=pathinfo($foo);
$file_path=$bar['dirname'].'/xxx.zip';
$data=file_get_contents("http://xxx.path8.net/xxx/xxx.zip");
$foo=file_put_contents($file_path,$data);
var_dump($foo);
?>
我的虚拟主机好歹有个ssh,可以很方便的压缩所有文件,并通过http访问。上面这段php脚本就可以实现从我的网站上通过http访问,并把整站的压缩文件下载到目标主机上(这里要注意目标主机上不否有写入权限,可以把目录设置777,迁移完成后再改回去)。然后,再使用一个zip解压工具,当然也要是php脚本编写的,网上有这个一个,有简单的页面设计,还比较直观,使用也较简单(附于本文后)。把这个工具也传到目标主机上,跟整站zip压缩包放在同一目录下,使用它解压缩zip,非常快,几秒钟就完成了,如果是使用ftp传输,那真不知道还要几个小时才能完成。
核心内容:
笔者曾写过一篇fedora linux apache/php下安装配置xdebug,记录了fedora13下安装xdebug 2.1.0的过程。当时在编译的二进制.so模块可以直接在fedora14下使用,如不想自己编译、且信得过笔者的同学们,请直接下载本文件,或者参考上文自行编译:
下载安装文件xdebug-module-linux-fedora13-14
安装方法:
1. 复制文件xdebug.so到 /usr/lib/php/modules/
2. 复制文件xdebug.ini 到 /etc/php.d/
3. 重启apache
___________以下是个人安装过程,仅供参考________________
笔者曾写过一篇
当时是在fedora13下参考xdebug官方的说明文档自行编译,然后把编译过程记下来的。现在fedora14已经发布几个月,当然是覆盖安装了。今天需要写个小东西,php自带的调试消息实在比较简陋,于是想起安装个xdebug,首先想到的yum里找不到,于上网上搜索怎么yum安装,结果发现打开的是这篇自己几个月前写的文章。
难道又要重新编译吗?太没效率了!
于是想是否不用重新编译、而是直接使用以前编译的.so模块呢?试试,不行再编译。
参看文章中之前的记录,还要安装两个工具:phpize与php-config,从它们文件名看,应该是编译过程上用的,现在不用编译,不安装试试。
安装过程:把编译目录里./moduls/xdebug.so复制到/usr/lib/php/modules/, 再写入xdebug配置信息上到文件/etc/php.d/xdebug.ini
[root@fsc prx]# echo 'zend_extension=/usr/lib/php/modules/xdebug.so > [Xdebug] > xdebug.profiler_enable=on > /etc/php.d/xdebug.ini' >/etc/php.d/xdebug.ini
重启apache,结果没有html格式的php消息。运行<?php phpinof();?> 发现xdebug是成功加载了,经验判断是没有打开php的html格式错误显示所致。看之前写文章里,有这一点 的,只是写在后面,看来这篇文章的“读者体验”(从“用户体验”生造来的词~~)不怎么好,连自己看都感觉到不方便! 有必要修改一下。
运行下面代码,把html_errors打开。
[root@fsc prx]# echo 'html_errors=on'>>/etc/php.d/xdebug.ini
再次重启apache,完成。
抓个图来纪念一下: