引子:
因为Bo-Blog2WordPress时丢失了200多篇文章,所以重转一次试试,这时表前缀设置为wp2_ ; 仍然时候BoWP.php 来转, 虽然内容确实写到了wp2_ 为前缀的表中,但是管理后台却无法登录,查了一通,发现在usermeta表中的”wp_user_level” 中的wp_ 应该和表前缀相同,修改为 wp2_user_level 后,问题解决。
修改后的转换程序: BoWP.php
DevOps
引子:
因为Bo-Blog2WordPress时丢失了200多篇文章,所以重转一次试试,这时表前缀设置为wp2_ ; 仍然时候BoWP.php 来转, 虽然内容确实写到了wp2_ 为前缀的表中,但是管理后台却无法登录,查了一通,发现在usermeta表中的”wp_user_level” 中的wp_ 应该和表前缀相同,修改为 wp2_user_level 后,问题解决。
修改后的转换程序: BoWP.php
Bug描述:
在使用file_get_contents($ur);请求一个$url 时,如果server在http请求头还没有完全输出时就意外关闭了连接,则file_get_contents($ur)将因无法读取完整的数据而陷入死循环,这时,进程占用cpu约 100%
影响版本:
本次故障出现在PHP-5.3.3 ,相信此前的版本中应该也存在;以后的版本就不得而知了
Bug重现方法:
server.php
|
1 2 3 4 5 6 7 |
<?php $str = "HTTP/1.1 200 OK Date: Sat, 07 Jul 2012 07:46:29 GMT"; fgets(STDIN); echo $str; exit; ?> |
client.php
|
1 2 3 4 |
<?php echo file_get_contents("http://localhost:9090/"); exit; ?> |
在A终端模拟server端:
|
1 2 |
#mkfifo /tmp/fifo #nc -l localhost -p 9090 </tmp/fifo | php server.php >/tmp/fifo |
在B终端执行client.php
|
1 |
#php client.php |
在C终端观察client.php 的执行情况
使用gstack查看堆栈状况:
使用gdb分析,参看脚本: php-5.3.3/ext/standard/http_fopen_wrapper.c
可以通过: https://svn.php.net/repository/php/php-src/tags/ 直接查看,在php5.4中还没有修复该bug
提交bug 到 php.net, bug地址: https://bugs.php.net/bug.php?id=63338
通常在一个终端执行一个耗时很长的程序时,我们使用nohup来执行,避免终端关闭时程序退出; 程序退出多半是程序需要输出,而输出终端已经不存在了,导致IO错误。
下面观察了一下test.php 的程序在终端执行的情况:
<?php
while(1) {
echo "hello world\n";
sleep(5);
}
————————————–
在一个终端启动程序:
php test.php
# ltrace -p 19197
write(1, "hello world\n", 12) = 12
fflush(0x8515c0) = 0
sleep(5) = 0
write(1, "hello world\n", 12) = 12
…
在另一个终端使用gdb调试该进程,当前一个终端关闭时,程序因写失败而进入函数php_handle_aborted_connection ; 这里将连接状态设置为abort,然后检查是否忽略连接abort,因为我设置为不忽略,所以程序退出了。修改程序,添加 ignore_user_abort(true); 这样的话,终端退出后,进程也不会退出了。但是,我们就又发现另外一个现象,这时候使用ltrace跟踪时,write调用没有了,因为php使用函数:php_ub_body_write_no_header 输出时,检查了变量output_globals.disable_output, 而该变量在发现连接断开时被置为 1 , 所以再也看不到输出了。
奇怪的是,使用ltrace跟踪的使用,命名是使用write系统调用输出的,gdb调试时,给write函数设置断点,居然不能拦住????
PTR (Pointer Recore),指针记录,是电子邮件系统中的一种数据类型,被互联网标准文件RFC1035所定义。与其相对应的是A记录、地址记录。二者组成邮件交换记录。
A记录解析名字到地址,而PTR记录解析地址到名字。地址是指一个客户端的IP地址,名字是指一个客户的完全合格域名。
PTR记录被用于电子邮件发送过程中的反向地址解析。当正向域名解析完成后,还应当向您的线路接入商(ISP)申请做反向地址解析,以减少被国外机构退信的可能性。
因为反向地址解析是需要“钱”的,所以除了用于发邮件的IP做反向地址解析,提供web服务的IP一般是不做反向地址解析的,所以很难根据IP地址反向解析到域名
实例:
提供邮件服务的IP的反向地址解析:
提供web服务的IP的反向地址解析:
1. 借助工具看进程状态
2. 查看各种日志,程序级别的、系统级别的等等
form表单的enctype属性可以设置表单提交时表单内容的编码方式,可用的编码方式有:
enctypemethod attribute is post, this attribute is the MIME type of content that is used to submit the form to the server. Possible values are:
<input> element with the type attribute set to "file".其中, text/plain 很少使用,其编码方式如下:
引子:
PHP的popen可以并发调起多个进程吗?
我们做如下测试:
测试1:
分析1:
我们发现,这里只输出了"a", 没有输出"b",说明sleep 100;执行了, sleep 200; 没有立即执行
测试2:
分析2:
这里a、b都输出了,说明两条命令都被调起执行了;同时,我们也发现,主进程并没有立即退出,而是在等待所有子进程执行完毕,如果使用 "&" 将启动的命令推倒后台,主进程也就不等待了。
测试3:
分析3:
这里a没有输出,说明如果不将popen赋值给一个变量,则进程阻塞,如果使用 "&" 将启动的命令推倒后台,则亦不阻塞。
使用Tokyotrant有相当一段时间了,确实有几次莫名的退出,今天再次出现,查了一下系统日志,报错如下:
$grep ttserver /var/log/messages
Jun 18 22:00:42 localhost kernel: [2463228.773583] ttserver[32282] general protection rip:2b6557922dcb rsp:4a0b2c08 error:0
又出现一次;
Jul 18 07:00:21 localhost kernel: [11461817.641400] ttserver[612]: segfault at 000000001ffc2000 rip 0000003f5407c08f rsp 000000004732ec08 error 4
定义方法1:
—– conf.php ——
引用配置文件:
—– test.php ——
———————
分析:
如果代码就这么简单,我们发现程序工作的很好,但是:
1. 如果$conf文件很大,每次都include势必浪费很多时间
2. 如果把include修改为include_once,则情况就会变得怪异了; 如果外部不小心include的了一次conf.php ,则test中不再执行conf.php,则test() 不能正常工作; 如果保证外面没有include("conf.php"); 则test() 第一次可以工作正常,第二次就无法正常工作,因为第二次执行test()函数并没有执行conf.php,也就没有$conf变量
3. conf.php 中 $conf 变量的作用域是不固定的,依赖于conf.php 的执行环境,所以简单地把 $conf看做是global的,更是容易犯错误的
结论: 这样写配置文件很容易犯错误,所以不要这样定义配置文件
定义方法2:
——- conf.php —–
引用配置文件:
——- test.php ——-
分析:
1. 配置文件包含进来之后,将一直占用内存空间,所以配置文件不宜太大,不过一般都不太太大
2. 为了提高效率,这里最好使用include_once, 而不是include
3. 这种写法不管怎么调用都不会有问题
4. 需要注意一点的是: 如果配置文件确实很大,解析该配置文件需要10毫秒, 而且不是每次请求都会用到大部分配置,或许整个请求之间只用到了其中1/10的配置,但是还是不得不耗费10ms来解析整个配置文件; 如果确实这这种情况,不妨考虑第三种配置方法
定义方法3:
——- conf.php ——
引用配置文件:
——- test.php ——-
分析:
1. 这种办法似乎规避了前两种写法的所有缺点
2. 我们还可以在配置文件中添加一些逻辑,避免代码的重复