标签归档:PHP

纯 PHP 实现并支持 Keep-Alive 和并行抓取的新版 HttpClient

前段时间有抓取数据的需求,考虑到驻留长时抓取的性能需求,不可能一次一个 file_get_congents 调用,即便使用 curl 扩展可以解决并行抓取,但似乎也无法发挥出 Keep-Alive 的优势(即一次连接,多次请求)。

因此使用纯 PHP 代码开发了这个类库,是一个比较完整的 Http 客户端,主要特色:

* 1) 纯 PHP 代码实现,无需依赖任何扩展
* 2) 允许设置各种 HTTP 头,完整的支持 Cookie
* 3) 支持 301/302 重定向识别,可设置最多跳转的次数
* 4) 支持 Keep-Alive 连接,重用于同一主机下的其它请求
* 5) 支持 https 访问(需要 PHP 开启 ssl 扩展)
* 6) 支持 POST 表单的文件上传
* 7) 支持同时并行处理多个请求

其中TCP连接采用异步方式,并行处理采用 stream_select() 多路IO轮循实现,也支持回调函数处理HTTP响应结果。

最新源码:https://github.com/hightman/pspider/blob/master/lib/HttpClient.class.php

简要示范:

require 'HttpClient.class.php';

function test_cb($res, $req, $key)
{
   echo '[' . $key . '] url: ' . $req->getUrl() . ', ';
   echo 'time cost: ' . $res->timeCost . ', ';
   echo 'size: ' . number_format(strlen($res->body)) . "\n";
}

$http = new HttpClient('test_cb');

// 全部 URL 抓取完毕时一并返回,传入单个 URL 或数组组成的多个 URL
// 第一次请求可能因为域名解析等原因较慢
// 可以自行构造 HttpRequest 直接用 IP请求更快
$results = $http->get(array(
  'baidu' => 'http://www.baidu.com/',
  'sina' => 'http://news.sina.com.cn/',
  'google' => 'http://www.google.com.sg/',
  'qq' => 'http://www.qq.com/',
));

// 键名不变,值为 HttpResponse 对象
//print_r($results);
//您可以通过 HttpClient::debug('open'); 会详细打印很多信息。

scws-1.2.0 发布,支持 PHP5.4 新增用于多线程的 scws_fork()

2012-3-29: SCWS-1.2.0 Released.

1) 修改 php 扩展代码以兼容支持 php 5.4.x
2) 修正 php 扩展中 scws_get_tops 的 limit 参数不允许少于 10 的问题
3) libscws 增加 scws_fork() 从既有的 scws 实例产生分支并共享词典/规则集,主要用于多线程开发。
4) 新增部分版本的 win32 的 dll 扩展,详见下载页面

最新下载地址:http://www.xunsearch.com/scws/download.php
演示地址:http://www.xunsearch.com/scws/demo.php

[patch] php-scws 扩展在 5.4.x 下的编译兼容补丁

近期 php5.4.x 已经正式发布,已有网友在使用并汇报说 scws 的 PHP 扩展无法编译通过。

刚看了一下,因为 5.4.x 起 php 移除了 safe_mode 导致一些代码错误不通过编译,简单修改补丁如下,请大家先手动修改一下,稍后 scws-1.1.10 发布时会同步解决,并推出 5.4 的 win32 dll 文件。

Index: php_scws.c
===================================================================
RCS file: /home/cvsroot/scws/phpext/php_scws.c,v
retrieving revision 1.13
diff -c -r1.13 php_scws.c
*** php_scws.c 23 Dec 2011 07:05:26 -0000 1.13
--- php_scws.c 5 Mar 2012 03:32:46 -0000
***************
*** 359,368 ****
--- 359,370 ----
if (!(fullpath = expand_filepath(filepath, NULL TSRMLS_CC)))
RETURN_FALSE;

+ #if PHP_API_VERSION < 20100412
if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
efree(fullpath);
RETURN_FALSE;
}
+ #endif

if (php_check_open_basedir(fullpath TSRMLS_CC)) {
efree(fullpath);
***************
*** 408,417 ****
--- 410,421 ----
if (!(fullpath = expand_filepath(filepath, NULL TSRMLS_CC)))
RETURN_FALSE;

+ #if PHP_API_VERSION < 20100412
if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
efree(fullpath);
RETURN_FALSE;
}
+ #endif

if (php_check_open_basedir(fullpath TSRMLS_CC)) {
efree(fullpath);
***************
*** 456,465 ****
--- 460,471 ----
if (!(fullpath = expand_filepath(filepath, NULL TSRMLS_CC)))
RETURN_FALSE;

+ #if PHP_API_VERSION < 20100412
if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
efree(fullpath);
RETURN_FALSE;
}
+ #endif

if (php_check_open_basedir(fullpath TSRMLS_CC)) {
efree(fullpath);

[分享] PHP命令行程序无缓冲从标准输入读取每一个输入字节的方法

标题的描述可能不是非常清楚,先罗嗦重新解释一下。

通常在命令行里运行PHP脚本时,从标准输入读取数据时是有缓冲的,在终端敲回车前所输入的字符是没有真正发送到服务端的。

某种情况下,我们在做交互程序时,希望用户每键入一个字符就能被脚本检测到并触发相应的功能(实现类似SHELL里上下键可以翻页历史指令)。

这些状况在 TELNET 协议里都有相关的描述,是按回车时传送数据还是一键一传,是否回显用户的输入都是双方协商而定的。

在SSH/TELNET到服务端时会有一个初始协定,如果您想改变它可以调用 stty 指令。PHP的示例代码如下:

system("stty -echo -icanon"); // 告诉终端不要回显和一键一传
$stdin = fopen("php://stdin", "rb");
while ($char = fread($stdin, 1))
{
  echo "you input: $char (ascii=" . ord($char) . ")\n";
}

xunsearch-1.0.0 正式版 (基于xapian/scws/php的开源中文全文搜索引擎)

经过 2 周如火如荼的测试和修正,很高兴如期发布 xunsearch-1.0.0 正式稳定版,这也是 xunsearch 的第一个正式版本。

Xunsearch 是免费开源的专业全文检索解决方案,旨在帮助一般开发者针对既有的海量数据,快速而方便地建立自己的全文搜索引擎。全文检索可以帮助您降低服务器搜索负荷、极大程度的提高搜索速度和用户体验。

高性能:后端是采用 C/C++ 开发多线程服务端,索引设计基于 Xapian 和 scws 中文分词。单库最多支持 40 亿条数据,在 5 亿网页大约 1.5TB 的数据中检索时间不超过 1 秒(非缓存)。

简单易用:前端是使用脚本语言编写的开发工具 (SDK),目前仅支持 PHP 语言。API 简单清晰,开发难度极低,提供全中文的示例代码、文档、辅助脚本工具等。

全功能:除支持基础的自定义分词、字段检索、布尔搜索外,还直接支持用户急需的相关搜索、拼音搜索、搜索建议等专业功能。

官方网站:http://www.xunsearch.com/
下载地址:http://www.xunsearch.com/download/xunsearch-full-latest.tar.bz2
代码仓库:https://github.com/hightman/xunsearch
修改日志:https://github.com/hightman/xunsearch/commits/1.0.0

[分享] PHP-fpm/cgi 搭配 APC或xcache碰到死锁的解决办法!!

手上有一台机器一直跑 PHP 5.3.x (fpm或fastcgi方式),常常不定时发生死锁现象。

表现为 FCGI 服务连不上,NGINX报告 502 bad gateway,这时系统里的 php 进程其实都还在,但都卡在 futex() 这一系统调用上,很明显发生死锁了。

查了一些资料,发现这个BUG早在2年前就有人提交过了,至今似乎没有妥善的解决办法,原因在于锁住资源时如果发生脚本超时,则时PHP内部通过 longjmp 跳转来关闭请求,导致锁无法正确释放。参见:http://pecl.php.net/bugs/bug.php?id=17589http://bugs.php.net/bug.php?id=46025

目前在PHP5.3可以在 php.ini 中增加 exit_on_timeout = On 来解决,意思是当发生超时就索性把进程杀死,以便让系统回收这类锁资源,避免死锁。

php解析cookie名称的问题

今天才发现 php 在解析 cookie 时会把名称中包含的.(点)转换成_(下划线),翻遍手册没发现有任何标注,特意去翻RFC也没找到相应的约定,看来应该是PHP自己的发明。(所以:当你设置了一个包含.或空格作名字的cookie,再读取时记得自行转换名字,否则就读不到)

php源码中的 main/php_variables.c 大约 98 行起有以下部分:

 /* ensure that we don't have spaces or dots ... */
 for (p = var; *p; p++) {
 if (*p == ' ' || *p == '.') {
 *p='_';
 } else if (*p == '[') {

看上去可能是为了兼容早期的 register_globals,从而不让名称中包含 . 或空格

正则替换时的一个潜在问题,几乎折服所有新老手!

通常正则替换(preg_replace)会用 $1 或 \1 来作反向引用,如下:

‘$1′ . $string . ‘$2′ 或 ‘\1′ . $string . ‘\2′ 原意是在它们之间插入 $string

这本身也没什么问题,但当 $string 的值以数字开头时?比如 string = “4fabc” 那么,此时的 $1 直接连接了 string 将被正则引擎当作 $14 而不是 $1 了,所以不仅 $1 消失了,连 string 中的 ‘4’ 也被吃掉了~~

解决办法就是改用 ${1}, ${2} ….

这是实战过程碰到的问题,分享给大家了!