<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Some reminiscences, some memories &#187; PHP</title>
	<atom:link href="http://www.mikespook.com/index.php/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mikespook.com</link>
	<description>Just another boring day</description>
	<lastBuildDate>Tue, 10 Jan 2012 03:14:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>关于 QQ OAuth 封装出现 T_PAAMAYIM_NEKUDOTAYIM 的解决办法</title>
		<link>http://www.mikespook.com/2011/01/%e5%85%b3%e4%ba%8e-oauth-%e5%b0%81%e8%a3%85%e5%87%ba%e7%8e%b0-t_paamayim_nekudotayim-%e7%9a%84%e4%b8%80%e4%ba%9b%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/</link>
		<comments>http://www.mikespook.com/2011/01/%e5%85%b3%e4%ba%8e-oauth-%e5%b0%81%e8%a3%85%e5%87%ba%e7%8e%b0-t_paamayim_nekudotayim-%e7%9a%84%e4%b8%80%e4%ba%9b%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 06:16:15 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[OAuth]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=832</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
许多网友在使用我的 OAuth 的腾讯微博封装（腾讯微博开放平台的PECL的OAuth封装）时都遇到了 T_PAAMAYIM_NEKUDOTAYIM 的错误。为了方便大家，干脆这里统一说明一下吧。

这个错误的责任在我。

由于我使用的开发和部署环境都是 Ubuntu 环境，PHP 版本 5.3.3。我在编码的时候使用了一个 5.2.x 不支持的特性。在 XY/QQ/Store.php 的 28 行：

<span class="readmore"><a href="http://www.mikespook.com/2011/01/%e5%85%b3%e4%ba%8e-oauth-%e5%b0%81%e8%a3%85%e5%87%ba%e7%8e%b0-t_paamayim_nekudotayim-%e7%9a%84%e4%b8%80%e4%ba%9b%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/" title="关于 QQ OAuth 封装出现 T_PAAMAYIM_NEKUDOTAYIM 的解决办法">阅读全文——共380字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>许多网友在使用我的 OAuth 的腾讯微博封装（<a href="http://www.mikespook.com/index.php/archives/813">腾讯微博开放平台的PECL的OAuth封装</a>）时都遇到了 T_PAAMAYIM_NEKUDOTAYIM 的错误。为了方便大家，干脆这里统一说明一下吧。</p>
<p>这个错误的责任在我。<br />
由于我使用的开发和部署环境都是 Ubuntu 环境，PHP 版本 5.3.3。我在编码的时候使用了一个 5.2.x 不支持的特性。在 XY/QQ/Store.php 的 28 行：</p>
<pre class="brush: php; title: ; notranslate">
$class::setParams($params);
</pre>
<p>经不完全验证在 5.2.x 及以下版本会报  T_PAAMAYIM_NEKUDOTAYIM 错误。</p>
<p>解决办法其实很简单，将 28 行代码替换为：</p>
<pre class="brush: php; title: ; notranslate">
call_user_func(array($class, 'setParams'), $params);
</pre>
<p>仅此即可。</p>
<p>真是抱歉了！同时感谢 <a href="http://52q.net/" target="_blank">ahu</a>、<a href="http://sjolzy.cn/" target="_blank">sjolzy</a> 提供的关键信息！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2011/01/%e5%85%b3%e4%ba%8e-oauth-%e5%b0%81%e8%a3%85%e5%87%ba%e7%8e%b0-t_paamayim_nekudotayim-%e7%9a%84%e4%b8%80%e4%ba%9b%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>使用 PECL 的 OAuth 库访问 QQ 微博 API</title>
		<link>http://www.mikespook.com/2010/12/%e4%bd%bf%e7%94%a8-pecl-%e7%9a%84-oauth-%e5%ba%93%e8%ae%bf%e9%97%ae-qq-%e5%be%ae%e5%8d%9a-api/</link>
		<comments>http://www.mikespook.com/2010/12/%e4%bd%bf%e7%94%a8-pecl-%e7%9a%84-oauth-%e5%ba%93%e8%ae%bf%e9%97%ae-qq-%e5%be%ae%e5%8d%9a-api/#comments</comments>
		<pubDate>Tue, 28 Dec 2010 14:28:49 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[PECL]]></category>
		<category><![CDATA[QQ]]></category>
		<category><![CDATA[微博]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=798</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
大势所趋，QQ 也在自家门上开了个小洞让诸位看客过过瘾。不过 API 文档不给力，疏漏多、讲得粗，没有 SDK，没有 Step by step，关键细节交代不清……幸而，摸索两日，总算是探得一个靠谱的办法——PECL 的 OAuth 库访问。

特别记录于此，供众玩家观赏。



<span class="readmore"><a href="http://www.mikespook.com/2010/12/%e4%bd%bf%e7%94%a8-pecl-%e7%9a%84-oauth-%e5%ba%93%e8%ae%bf%e9%97%ae-qq-%e5%be%ae%e5%8d%9a-api/" title="使用 PECL 的 OAuth 库访问 QQ 微博 API">阅读全文——共3506字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>大势所趋，QQ 也在自家门上开了个小洞让诸位看客过过瘾。不过 API 文档不给力，疏漏多、讲得粗，没有 SDK，没有 Step by step，关键细节交代不清……幸而，摸索两日，总算是探得一个靠谱的办法——PECL 的 OAuth 库访问。</p>
<p>特别记录于此，供众玩家观赏。<br />
<span id="more-798"></span></p>
<p>在使用 <a href="http://pecl.php.net/package/oauth" target="_blank">PECL 的 OAuth</a> 库之前，尝试过包括 <a href="http://code.google.com/p/oauth-php/" target="_blank">oauth-php</a> 在内的一些第三方库。有些跟 QQ 的 API 不兼容（不要信什么大家都是严格按照 RFC 实现之类的浮云）；有些自己正常运行都有问题；还有些我觉得作为一个 API 调用界面，本身设计的用法就太过复杂，封装层次太高……本想用熟悉的 <a href="http://framework.zend.com/manual/en/zend.oauth.html" target="_blank">Zend_OAuth</a>，但是想到 Zend 的那个大块头……幸有 PECL！</p>
<p>不过 PECL 也不是人人都能用的，毕竟这个玩意是个要额外安装的家伙。大家酌情选择吧……</p>
<p>先讲讲我的运行环境。我使用的是 <a href="http://www.linode.com/?r=ca32e7b3df04fe291d4ce354dcf3b2f8f4ce93ef" target="_blank">linode 的 VPS</a> 主机，最便宜的那种。装的是 Ubuntu 10.4，Apache2、PHP5 这些都是 apt 装的。个人觉得，我投入的那点精力优化出来的编译参数不一定会比 ubuntu 的团队做得更好。</p>
<p>所以 OAuth 扩展的安装是非常的简单，首先安装 php 的编译依赖和 pear 包。libpcre3 是 OAuth 编译依赖的一个包，主要用来支持正则表达式：</p>
<pre class="brush: bash; title: ; notranslate">
sudo apt-get install php5-dev php-pear libpcre3-dev
</pre>
<p>使用 pecl 安装 OAuth：</p>
<pre class="brush: bash; title: ; notranslate">
sudo pecl install oauth
</pre>
<p>在 /etc/php5/apache2/conf.d/ 下建立文件 oauth.ini，加内容：</p>
<pre class="brush: bash; title: ; notranslate">
extension=oauth.so
</pre>
<p>重启 web 服务器：</p>
<pre class="brush: bash; title: ; notranslate">
sudo apache2ctl restart
</pre>
<p>好了，OAuth 扩展加载完成。</p>
<p>在演示中，只做两件事情：1、利用 OAuth 完成身份验证。2、取得身份验证后获取大厅消息。</p>
<p>下面是代码，不罗嗦了，注释里说明。</p>
<p>define.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
define('OAUTH_KEY', '应用信息里的 App Key');
define('OAUTH_SECRET', '应用信息里的 App Secret');

define('REQUEST_TOKEN', 'https://open.t.qq.com/cgi-bin/request_token');
define('AUTHORIZE', 'https://open.t.qq.com/cgi-bin/authorize');
define('ACCESS_TOKEN', 'https://open.t.qq.com/cgi-bin/access_token');

define('CALLBACK', 'http://xxiyy.com/qqt/callback.php');

session_id('XY');
session_start();
</pre>
<p>index.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
include('define.php');
try {
    $oauth = new OAuth(OAUTH_KEY, OAUTH_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
    $oauth-&gt;enableDebug();
    // 很重要！！！在 OAuth 标准里是没有规定 nonce 的长度的，但是 QQ 对 nonce 的长度做了要求——32 字节长。如果不设置一下，会返回 400 错误。我为此纠结了一天。
    $oauth-&gt;setNonce(md5(rand()));
    // CALLBACK 一定要设置，OAuth 扩展的文档上是没设置的，但是 QQ 这里不设会报错
    $requestTokenInfo = $oauth-&gt;getRequestToken(REQUEST_TOKEN, CALLBACK);
    $_SESSION['oauth_token_secret'] = $requestTokenInfo['oauth_token_secret'];
    // header(&quot;Location: ……&quot;) 亦可
    echo &quot;&lt;p&gt;&lt;a href='&quot; . AUTHORIZE . &quot;?oauth_token=&quot; . $requestTokenInfo['oauth_token'] . &quot;'&gt;authorize&lt;/a&gt;&lt;/p&gt;&quot;;
} catch (OAuthException $e) {
    var_dump($e);
}
</pre>
<p>callback.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
include('define.php');
try {
    $oauth = new OAuth(OAUTH_KEY, OAUTH_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
    $oauth-&gt;enableDebug();
    // 很重要！！！如果不设置一下，会返回 401 错误。
    $oauth-&gt;setNonce(md5(rand()));
    $oauth-&gt;setToken($_GET['oauth_token'], $_SESSION['oauth_token_secret']);
    $accessTokenInfo = $oauth-&gt;getAccessToken(ACCESS_TOKEN, null, $_GET['oauth_verifier']);
    $_SESSION['access_token'] = $accessTokenInfo['oauth_token'];
    $_SESSION['access_secret'] = $accessTokenInfo['oauth_token_secret'];
    header('Location: room.php');
} catch (OAuthException $e) {
    var_dump($e);
}
</pre>
<p>room.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
include('define.php');
try {
    $url = &quot;http://open.t.qq.com/api/statuses/public_timeline?format=json&amp;pos=0&amp;reqnum=10&quot;;

    $oauth = new OAuth(OAUTH_KEY, OAUTH_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
    $oauth-&gt;enableDebug();
    $oauth-&gt;setToken($_SESSION['access_token'], $_SESSION['access_secret']);
    $oauth-&gt;fetch($url);
    $json = json_decode($oauth-&gt;getLastResponse());
    var_dump($json);
} catch (OAuthException $e) {
    var_dump($e);
}
</pre>
<p>完整代码：<a href='http://www.mikespook.com/wp-content/uploads/2010/12/qqt.zip'>下载</a></p>
<p>PS：多说两句。今天微博上看到关于 QQ 开放的 API 有一些讨论，似乎认可度不高。不过，虽然腾讯这次开放的微博 API 还有很多不足，尤其是开发者支持和文档方面。但说句公道话，还远未达到“令人畏惧”的程度（你们想看看更“令人畏惧”的吗？）。按照腾讯一贯的风格：持续迭代、快速改进，应该很快会有新的支持。</p>
<p>尝试一下这个：<br />
<a href="javascript:void(0)" onclick="postToWb();" class="tmblog"><img src="http://v.t.qq.com/share/images/s/b32.png"></a><script type="text/javascript">
	function postToWb(){
		var _t = encodeURI(document.title);
		var _url = encodeURIComponent(document.location);
		var _appkey = encodeURI("appkey");//你从腾讯获得的appkey
		var _pic = encodeURI('');//（例如：var _pic='图片url1|图片url2|图片url3....）
		var _site = 'http://www.mikespook.com';//你的网站地址
		var _u = 'http://v.t.qq.com/share/share.php?title='+_t+'&#038;url='+_url+'&#038;appkey='+_appkey+'&#038;site='+_site+'&#038;pic='+_pic;
		window.open( _u,'', 'width=700, height=680, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no' );
	}
</script><br />
貌似有问题，带不上地址呢？我又搞错什么了？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/12/%e4%bd%bf%e7%94%a8-pecl-%e7%9a%84-oauth-%e5%ba%93%e8%ae%bf%e9%97%ae-qq-%e5%be%ae%e5%8d%9a-api/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Web编程异步模型的 Gearman 实现（残）</title>
		<link>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84-gearman-%e5%ae%9e%e7%8e%b0%ef%bc%88%e6%ae%8b%ef%bc%89/</link>
		<comments>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84-gearman-%e5%ae%9e%e7%8e%b0%ef%bc%88%e6%ae%8b%ef%bc%89/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 02:34:35 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Stardy & Research]]></category>
		<category><![CDATA[Gearman]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[异步]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=597</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
写了 PHP 原生的二段式异步模型的实现，我就想着用 Gearman 实现一个 callback 方式的异步。还没准备好怎么去写，就看到了靓文一篇《Gearman 心得》。

看过之后，甚感压力：好文！！于是，弃笔不写，洗洗睡罢了……

补充一下，在“心得”文中仅仅说明了不阻塞的后台作业。对于异步获取数据并未说明。所以我这里罗嗦一下……

<span class="readmore"><a href="http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84-gearman-%e5%ae%9e%e7%8e%b0%ef%bc%88%e6%ae%8b%ef%bc%89/" title="Web编程异步模型的 Gearman 实现（残）">阅读全文——共373字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>写了 PHP 原生的二段式异步模型的实现，我就想着用 Gearman 实现一个 callback 方式的异步。还没准备好怎么去写，就看到了靓文一篇<a href="http://www.jaceju.net/blog/?p=1211" target="_blank">《Gearman 心得》</a>。</p>
<p>看过之后，甚感压力：<strong>好文！！</strong>于是，弃笔不写，洗洗睡罢了……</p>
<p>补充一下，在“心得”文中仅仅说明了不阻塞的后台作业。对于异步获取数据并未说明。所以我这里罗嗦一下……</p>
<p>worker 如果用 php 来实现，并且不用<a href="http://www.mikespook.com/index.php/archives/587" target="_blank">《Web编程异步模型的PHP 原生实现》</a>中的异步方式，是无法实现 php 的 client 的异步的。比较好的实现方式是 worker 不使用 php，用 python、perl 或者 c，实现一个线程池来执行 job。当然，私下觉得用 stackless python 可能是更好的选择。</p>
<p>2010年07月18日补充：<br />
好吧，终于有人撰文，正好可以补充完整这个异步思路：<br />
<a href="http://blog.ez2learn.com/2010/07/17/talk-about-coroutine-and-gevent/" target="_blank">淺談coroutine與gevent</a><br />
就他了，太棒了！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84-gearman-%e5%ae%9e%e7%8e%b0%ef%bc%88%e6%ae%8b%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Web编程异步模型的PHP原生实现</title>
		<link>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84php%e5%8e%9f%e7%94%9f%e5%ae%9e%e7%8e%b0/</link>
		<comments>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84php%e5%8e%9f%e7%94%9f%e5%ae%9e%e7%8e%b0/#comments</comments>
		<pubDate>Sat, 05 Jun 2010 03:01:31 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[异步]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=587</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
这是基于上一篇随笔：关于Web编程异步模型的白日梦的实现。这一思路我记得在 05 年还是 07 年的时候就在 ChinaUnix 上有高人所讨论，只是自己当时愚钝未能明晰本质，纠结于 PHP 的多线程之中……

这个实现写好有段时间了，最近琐碎的事情很多，一直没有整理出来。今日得闲记录下来。

利用PHP自带的 stream_select 函数实现异步，利用这个函数使得 PHP 原生支持的异步调用实现，无须第三方服务或库。不过只能实现二段式异步调用，就是说会有明显的 Begin 和 End 两个阶段。

<span class="readmore"><a href="http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84php%e5%8e%9f%e7%94%9f%e5%ae%9e%e7%8e%b0/" title="Web编程异步模型的PHP原生实现">阅读全文——共2511字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>这是基于上一篇随笔：<a href="http://www.mikespook.com/index.php/archives/580" target="_blank">关于Web编程异步模型的白日梦</a>的实现。这一思路我记得在 05 年还是 07 年的时候就在 ChinaUnix 上有高人所讨论，只是自己当时愚钝未能明晰本质，纠结于 PHP 的多线程之中……</p>
<p>这个实现写好有段时间了，最近琐碎的事情很多，一直没有整理出来。今日得闲记录下来。</p>
<p>利用PHP自带的 stream_select 函数实现异步，利用这个函数使得 PHP 原生支持的异步调用实现，无须第三方服务或库。不过只能实现二段式异步调用，就是说会有明显的 Begin 和 End 两个阶段。<br />
<span id="more-587"></span><br />
代码比较容易理解，大家自己看吧。</p>
<p>先看看，封装好的方法，如何异步调用：</p>
<pre class="brush: php; title: ; notranslate">
/**
 * DEMO
 */

/**
 * 请求集合
 */
$requestSet = array(
    'foobar' =&gt; array(
        'stream'    =&gt;  '127.0.0.1:80',
        'path'      =&gt;  '/api.php',
        'params'    =&gt;  array('a'=&gt;1),
        'callback'  =&gt;  'echoArray',
    ),
    'foo-bar' =&gt; array(
        'stream'    =&gt;  '127.0.0.1:80',
        'path'      =&gt;  '/api.php',
        'params'    =&gt;  array('method'=&gt;'get', 'table'=&gt;'user', 'id'=&gt;1),
        'callback'  =&gt;  'echoArray',
    ),
    'another' =&gt; array(
        'stream'    =&gt;  '127.0.0.1:80',
        'path'      =&gt;  '/api.php',
        'params'    =&gt;  array(),
        'callback'  =&gt;  'echoArray',
    ),
);

/**
 * 演示处理函数，这里只作打印
 * @param $a array 输入数组
 */
function echoArray($a) {
    var_dump($a);
}

/**
 * 二段异步调用
 */

/**
 * 第一阶段，发起请求
 */
$fps = beginRequest($requestSet);
/**
 * 第二阶段，处理返回
 */
endReponse($requestSet, $fps);
</pre>
<p>封装的异步函数：</p>
<pre class="brush: php; title: ; notranslate">
/**
 * 发起一个请求
 * @param $stream string 主机、端口
 * @param $path string api路径
 * @param $params array 参数
 * @return resource 文件描述符
 */
function request($stream, $path, $params) {
    $fp = stream_socket_client(&quot;tcp://{$stream}&quot;, $errno, $errstr, 30);
    if (!$fp) {
        throw new Exception($errstr, $errno);
    } else {
        $params = http_build_query($params);
        $host = explode(':', $stream);
        $str = &quot;GET {$path}?{$params} HTTP/1.0\r\nHost: {$host[0]}\r\nAccept: */*\r\n\r\n&quot;;
        fwrite($fp, $str);
    }
    return $fp;
}

/**
 * 获取请求的返回
 * @param $fp resource 文件描述符
 * @return array 取得的返回值
 */
function response($fp) {
    $r = stream_get_contents($fp);
    // 简陋的 HTTP 协议解析
    $r = explode(&quot;\n&quot;, $r);
    return json_decode($r[count($r) - 1]);
}

/**
 * 发起请求
 * @param $requestSet array 请求队列数组
 * @return array 文件描述符数组
 */
function beginRequest($requestSet) {
    $fps = array();
    foreach($requestSet as $key =&gt; $request) {
        try {
            $fps[$key] = request($request['stream'], $request['path'], $request['params']);
        } catch (Exception $e) {
            echo $e;
        }
    }
    return $fps;
}

/**
 * 处理返回
 * @param $requestSet array 请求队列数组
 * @param $fps array 文件描述符数组
 */
function endReponse($requestSet, $fps) {
    $r = $fps;

    while(count($fps) &gt; 0) {
        // 这里是重点，stream_select 保证了先返回的先处理。
        $n = stream_select($r, $w, $e, 0);
        if ($n === false) {
            echo $e;
    	    continue;
        }
        if ($n &gt; 0) {
            foreach($r as $socket) {
                // 读取返回值，并调用回调
                $r = response($socket);
                $key = array_search($socket, $fps);
                $callback = $requestSet[$key]['callback'];
                $callback($r);
                fclose($socket);
	        unset($fps[$key]);
	    }
        }
        $r = $fps;
    }
}
</pre>
<p>api.php 接口：</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$a = array(
    'hello' =&gt; 'world',
    'foobar' =&gt; array(0,1,2,3,4),
    'GET'   =&gt;  $_GET,
    );
echo json_encode($a);
</pre>
<p>为了演示的需要剔除了面向对象、异常处理的一些内容。同时硬性规定 api 接口使用 json 通过 http 协议传递数据。<br />
实际上，由于 php 的 stream 的功能可以处理包括 udp 协议在内的I/O。可利用其他协议和开销更小的报文格式，以便能获得更好的性能。</p>
<p>由于模型的限制，callback 异步无法直接实现，可将存在数据读取依赖关系的数据读取过程拆解为若干个二段异步调用。</p>
<p>PS：这里只是一个实现方法的演示，并不涉及该方法是否在真实环境可用。也就是说，虽然实现了PHP的异步调用，但是实际运行可能并不比顺序阻塞读取的性能高。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/06/web%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84php%e5%8e%9f%e7%94%9f%e5%ae%9e%e7%8e%b0/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>关于Web编程异步模型的白日梦</title>
		<link>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8eweb%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84%e7%99%bd%e6%97%a5%e6%a2%a6/</link>
		<comments>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8eweb%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84%e7%99%bd%e6%97%a5%e6%a2%a6/#comments</comments>
		<pubDate>Thu, 27 May 2010 03:04:26 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Stardy & Research]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[异步]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=580</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
早上刷牙，处于半睡状态。突然想起昨天晚上看到的那个 go-lang 的 MVC 框架，若使用 go func() 方式异步获取数据，应当是不错的。窃喜……梦醒……

在地铁上被前前后后那些特种男女逼到车角，无奈。又想起早上那个白日梦，遂上网搜索了一番。得老赵的佳作一篇《F# 与ASP.NET（1）：基于事件的异步模式与异步Action》。之前看过，由于对微软无爱，未能细品。今日一读，如醍醐灌顶，豁然开朗。

遂整理思路如下，以待后用。

<span class="readmore"><a href="http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8eweb%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84%e7%99%bd%e6%97%a5%e6%a2%a6/" title="关于Web编程异步模型的白日梦">阅读全文——共1987字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>早上刷牙，处于半睡状态。突然想起昨天晚上看到的那个 go-lang 的 MVC 框架，若使用 go func() 方式异步获取数据，应当是不错的。窃喜……梦醒……</p>
<p>在地铁上被前前后后那些特种男女逼到车角，无奈。又想起早上那个白日梦，遂上网搜索了一番。得老赵的佳作一篇<a href="http://blog.zhaojie.me/2010/04/fsharp-for-asp-net-1-event-based-asynchronous-pattern-and-async-action.html" target="_blank">《F# 与ASP.NET（1）：基于事件的异步模式与异步Action》</a>。之前看过，由于对微软无爱，未能细品。今日一读，如醍醐灌顶，豁然开朗。</p>
<p>遂整理思路如下，以待后用。<br />
<span id="more-580"></span></p>
<p>在说异步模型之前，先说说最常见的同步模型吧。例如下面的 PHP 代码：</p>
<pre class="brush: php; title: ; notranslate">
// 获取数据
$userInfo = getUserInfo();
$newsList = getNewsList();
$topRateNewsList = getNewsList('DESC `rate`');
// 创建模板，绑定变量
$tmp = CreateTemplate();
$tmp-&gt;bind('userInfo', $userInfo);
$tmp-&gt;bind('newsList', $newsList);
$tmp-&gt;bind('topRateNewsList', $topRateNewsList);
// 渲染模板，输出
$tmp-&gt;render();
echo $tmp;
</pre>
<p>在这段代码中，所有调用都是顺序的。也就是说，如果 getUserInfo($userId) 没有返回用户信息的话，getNewsList(5) 永远都不会被调用。实际情况，可能是用户信息是从用户库取数据，新闻是从新闻库取数据。假设新闻库运行良好，而由于某种原因用户库宕机了，那么这次请求也就废掉了。故障也从一个库的宕机扩散到整个站点。</p>
<p>现在，我白日做梦的创建一种新语言 go-php，引入 go-lang 的关键字 go 到 php 中：</p>
<pre class="brush: php; title: ; notranslate">
// 创建一个数据通道
$chan = CreateChan();
// 获取数据，并放到数据通道上去
go getUserInfo($chan);
go getNewsList($chan);
$params = array('DESC `rate`');
go getNewsList($chan, $params);
// 创建模板
$tmp = CreateTemplate();
// 从通道上取数据
while($d = $chan-&gt;read()) {
    if ($d['error']) {
        // 数据有错误 ……处理一下吧
    } else {
        $tmp-&gt;bind($d['key'], $d['data']);
    }
}
// 渲染模板，输出
$tmp-&gt;render();
echo $tmp;
</pre>
<p>好了，这其实不是什么新奇创造，这只是一个<strong>二段式异步调用（Begin/End）</strong>。这有点像大宗采购，采购商并不一件一件的商品进行采购，而是拿着清单说：“好了，兄弟，这是我要的货，你们帮我找齐，放到码头406号仓库去……”，然后他就在 406 号仓库等着点货了。这段代码还可以改进，就像采购清单一样，将这个清单推到数据层，数据层把数据返回到数据通道上去。恩，应该不少人在自己的应用中使用 MQ，Memcache 甚至 pipe 实现了这种异步了吧。</p>
<p>再来看另外一段 go-php 代码：</p>
<pre class="brush: php; title: ; notranslate">
/**
 * 回调函数
 * @param $tmp 模板
 * @param $d 返回的数据
 */
function callbackBind($tmp, $d) {
    if ($d['error']) {
        // 数据有错误 ……处理一下吧
    } else {
        $tmp-&gt;bind($d['key'], $d['data']);
    }
}
// 创建模板
$tmp = CreateTemplate();
// 获取数据，并设置数据回调
go getUserInfo(callbackBind, $tmp);
go getNewsList(callbackBind, $tmp);
$params = array('DESC `rate`');
go getNewsList(callbackBind, $tmp, $params);
// 如果不是所有数据都回调了，则阻塞
$tmp-&gt;wait();
// 渲染模板，输出
$tmp-&gt;render();
echo $tmp;
</pre>
<p>这就是老赵的<strong>事件回调</strong>的异步处理的 go-php 版本。这有点像渠道商订货（或者淘宝上的无货代理？）：“我需要XXXX，你帮我送到XXXX去”。然后坐等，所有的内容都送到了，就收钱走人。</p>
<p>对于数据读取的错误，只要处理得当也不是致命的。最多在渲染页面的时候，少某块数据，用户只会奇怪：“这次怎么打开没有新闻那部分的内容了呢……刷新一下看看……”。而不会说：“烂网站，又打不开了……”用户体验直线上升啊！</p>
<p>好了，梦就做到这里。相信这两种方式其实已经有实际案例了。我比较孤陋寡闻一些，了解的不多。而且有的东西，未经许可也不好多说……大家私下打听吧。</p>
<p>总之呢，两种异步模型各自有各自的好处。并行的数据存取，提高 I/O 利用率是其本质。王道啊……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8eweb%e7%bc%96%e7%a8%8b%e5%bc%82%e6%ad%a5%e6%a8%a1%e5%9e%8b%e7%9a%84%e7%99%bd%e6%97%a5%e6%a2%a6/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>关于昨日爆出的 Nginx + PHP CGI 漏洞的一点点补充</title>
		<link>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8e%e6%98%a8%e6%97%a5%e7%88%86%e5%87%ba%e7%9a%84-nginx-php-cgi-%e6%bc%8f%e6%b4%9e%e7%9a%84%e4%b8%80%e7%82%b9%e7%82%b9%e8%a1%a5%e5%85%85/</link>
		<comments>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8e%e6%98%a8%e6%97%a5%e7%88%86%e5%87%ba%e7%9a%84-nginx-php-cgi-%e6%bc%8f%e6%b4%9e%e7%9a%84%e4%b8%80%e7%82%b9%e7%82%b9%e8%a1%a5%e5%85%85/#comments</comments>
		<pubDate>Fri, 21 May 2010 06:14:52 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cgi]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[漏洞]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=575</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
我第一次看到这个漏洞是在 Laruence 的博客。看完之后，我赶紧评估了一下我们正在开发的产品出现这个漏洞的可能性。还不错，在我们当前架构下，这个漏洞被成功利用的可能性为 0 ……

结果，今天在大嘴巴 cnbeta 看到了这篇很标题党的新闻《80后发现nginx 0day漏洞，上传图片可入侵100万服务器》。然后引用的出处是这里。

好了，我认为我提供的背景资料足够详细了。现在说说为什么我们的产品不会出现这个被利用的可能吧。

<span class="readmore"><a href="http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8e%e6%98%a8%e6%97%a5%e7%88%86%e5%87%ba%e7%9a%84-nginx-php-cgi-%e6%bc%8f%e6%b4%9e%e7%9a%84%e4%b8%80%e7%82%b9%e7%82%b9%e8%a1%a5%e5%85%85/" title="关于昨日爆出的 Nginx + PHP CGI 漏洞的一点点补充">阅读全文——共484字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>我第一次看到这个漏洞是在 <a href="http://www.laruence.com/2010/05/20/1495.html" target="_blank">Laruence 的博客</a>。看完之后，我赶紧评估了一下我们正在开发的产品出现这个漏洞的可能性。还不错，在我们当前架构下，这个漏洞被成功利用的可能性为 0 ……</p>
<p>结果，今天在大嘴巴 cnbeta 看到了这篇很标题党的新闻<a href="http://www.cnbeta.com/articles/111711.htm" target="_blank">《80后发现nginx 0day漏洞，上传图片可入侵100万服务器》</a>。然后引用的出处是<a href="http://www.80sec.com/nginx-securit.html" target="_blank">这里</a>。</p>
<p>好了，我认为我提供的背景资料足够详细了。现在说说为什么我们的产品不会出现这个被利用的可能吧。</p>
<p>其实很简单，将资源文件和 php 脚本文件放在不同的域名下面。然后将资源文件（含产品自身的和用户贡献的）的访问限于只作文件传输，不作任何的脚本解析。</p>
<p>例如 PHP 脚本执行的主机名是 www.mikespook.com。而上传文件和图像、js、css 等放在 static.mikespook.com 主机名下。</p>
<p>其实，就是这么简单的一个隔离措施，就避免了出现这种上传并解析的漏洞。</p>
<p>即使想用同一个域名，通过对 nginx 的配置禁止资源文件目录下的文件被当作脚本解析也是很容易的。</p>
<p>这个故事教育我们：细节是基石，架构是王道！！！</p>
<p>另，根据来自高春辉的可靠消息，手机之家也不存在此问题……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/05/%e5%85%b3%e4%ba%8e%e6%98%a8%e6%97%a5%e7%88%86%e5%87%ba%e7%9a%84-nginx-php-cgi-%e6%bc%8f%e6%b4%9e%e7%9a%84%e4%b8%80%e7%82%b9%e7%82%b9%e8%a1%a5%e5%85%85/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]MongoDB：PHP开发者应该知道的关于 MongoDB 的 5 件事儿</title>
		<link>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/</link>
		<comments>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 04:04:52 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=524</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
原文：http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb

感觉这篇文章说了一些 MongoDB 的要点，适合 MongoDB 扫盲使用。所以翻译出来，造福于民。虽然文章是针对 PHP 开发者写的，但实际上 python、ruby 或者其他 web 开发人员也可借鉴。

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-这里是译文分隔线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;

<span class="readmore"><a href="http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/" title="[翻译]MongoDB：PHP开发者应该知道的关于 MongoDB 的 5 件事儿">阅读全文——共2223字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>原文：<a href="http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb" target="_blank">http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb</a></p>
<p>感觉这篇文章说了一些 MongoDB 的要点，适合 MongoDB 扫盲使用。所以翻译出来，造福于民。虽然文章是针对 PHP 开发者写的，但实际上 python、ruby 或者其他 web 开发人员也可借鉴。<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-这里是译文分隔线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<span id="more-524"></span></p>
<p>2010年将被记住，因为这一年 SQL 死了；这一年关系数据库从一线退下；这一年开发人员发现他们没必要为了持久化数据，将每个对象转化为表格结构。</p>
<p>2010年是文档数据库的一年。尽管一直在稳步发展势头，通过过去七年多的发展，现在有各种稳定的文档数据库——从基于亚马逊和谷歌的云，到各种开放源码工具，尤其是 <a href="http://couchdb.apache.org/" target="_blank">CouchDB</a> 和 <a href="http://www.mongodb.org/display/DOCS/Home" target="_blank">MongoDB</a>。</p>
<p>那么，MongoDB 是什么？这里的五件事是每个 PHP 开发人员应该知道的：</p>
<p><strong>1、MongoDB 是一个独立的服务器<br />
2、它是基于文档的，而不是基于表格的<br />
3、它是非结构化的<br />
4、不必去学习另一种查询语言<br />
5、它具有强大的 PHP 支持</strong></p>
<p>阅读下文，可以了解关于这些的详细内容。</p>
<p><strong>1、MongoDB 是一个独立的服务器</strong></p>
<p>如 MySQL 或 PostgreSQL 一样，MongoDB 侦听端口以便接入。它提供了用于查询，创建，更新和删除的工具。从理论上讲，你使用它的工作方式与你使用 MySQL 或 PostgreSQL 的工作方式相同：连接，执行任务，并关闭连接。<br />
<strong><br />
2、跟行和表格说再见，向文档和集合说你好</strong></p>
<p>MongoDB 存储整个文档，代替了存储在表的行数据中。如果有一个含有标题、多位作者、内容和标签的“文章”数据，该数据基本上看起来像这样：</p>
<pre class="brush: php; title: ; notranslate">
&lt;? php
array(
    'title' =&gt; 'Hello World',
    'authors' =&gt; array('John', 'Sally', 'Jim'),
    'body' =&gt; 'Hello world',
    'tags' =&gt; array('tag1', 'tag2', 'tag3')
);
?&gt;
</pre>
<p>要注意的关键，上面的例子是一个记录——一个文档——实际上是像文档一样存储，并支持同一字段有多个值的情况。没有必要将数据转化为通常意义上的表中，因为，根本没有表。</p>
<p>现在，作为将文档存储在表中的替代方案，它们存储在一个集合里，这可以认为是一个大的文档列表。</p>
<p><strong>3、MongoDB 是非结构化的</strong></p>
<p>MongoDB 没有结构化语言。如果你想创建一个新的文档类型，你不用做任何事来告诉数据库关于这些数据的结构，而仅仅是存到数据库中即可。</p>
<p>在第 2 点中，我虚构了一个文档。现在，如果我想在这些字段上定义文章类型，我所要做的仅仅是存储对象到数据库如果我想定义它与这些领域的文章类型，首先，我需要做的就是写入数据库中的对象。日后，如果我决定增加一些什么，例如，一个日期？我只是从数据库中获得文章，添加日期字段，并保存它。</p>
<p>相关的数据类型是什么？简单的说，MongoDB 使用类似 JavaScript 或 PHP 的类型处理方式。也就是说，数据库是灵活的弱类型。</p>
<p>虽然有一些数据是有限制条件的（大块的数据可能需要一些明确的处理），但在大多数情况下，你可以像写 PHP 代码一样编写你的 MongoDB 代码。</p>
<p><strong>4、不必去学习另一种查询语言！</strong></p>
<p>还记得这些你写的数据库抽象层吗？还记得那些你处理过的 ORM 层吗？现在，你可以将它们全部丢弃。在 Mongo 中你不需要他们。</p>
<p>MongoDB（当使用 PHP 驱动）没有很多查询语句。在大多数情况下，只需给它一个数组指定你想要的信息，然后它会给你返回文档的数组。</p>
<p>如果你想运行一些非常复杂的查询（如Map-Reduce操作），可以向MongoDB 传递 JavaScript，其内部的 JavaScript 引擎可以解析这个脚本。</p>
<p><strong>5、PHP 和 MongoDB 是上天注定的一对搭档</strong></p>
<p>PHP 已经有很好的 MongoDB 支持。Mongo 驱动可以通过 PECL 扩展安装到 PHP，这意味着运行 pecl 安装 mongo 非常简单。（早些时候我写了一篇短文，详细介绍了<a href="http://technosophos.com/content/os-x-installing-mongodb-and-php-mongo-driver" target="_blank">安装过程</a>）</p>
<p>然后，你可以立即使用<a href="http://us2.php.net/manual/en/book.mongo.php" target="_blank"> Mongo 的 API</a> 开始工作。复杂性，站在 PDO 的阵营中。它不够简单，<del datetime="2010-03-24T01:00:36+00:00">but there should be nothing foreign about it for anyone who has done database development before.（注：不知道怎么翻译，不是关键，大家自悟吧）</del>但是这对于之前做过数据库开发的人来说，不会很陌生。</p>
<p>API 文档（上面有连接）包括了指引和许多例子，所以你应该能够在一个很短的时间里学会。这里有一些你需要注意的：</p>
<p>* MongoDB 是神速的<br />
* 开发时间也短，因为没有结构需要管理，和很少（如果有的话）的数据映射。<br />
* 学习曲线很平滑，因为没有新的查询语言学习。<br />
* 代码是简洁的。毕竟，无须任何其他 ORM，封装可以非常简单。<br />
* 你的代码是未来的保证。向你的对象增加更多的字段是很轻松的——甚至复杂的字段。因此，需求变化了，你可以很快修改代码以便适应。</p>
<p>我用 MongoDB 开发只有一段时间，但这足以让我意识到它有改变游戏规则的潜力。这也是让我主张使用新一代的文档数据库代替基于 SQL 的关系数据库的原因。将关系数据库留在尘土里——或者，更可能的是让它们做它们能做好的事情：存数属于行和表的数据。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>脚本语言的配置文件</title>
		<link>http://www.mikespook.com/2009/09/%e8%84%9a%e6%9c%ac%e8%af%ad%e8%a8%80%e7%9a%84%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6/</link>
		<comments>http://www.mikespook.com/2009/09/%e8%84%9a%e6%9c%ac%e8%af%ad%e8%a8%80%e7%9a%84%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 02:30:26 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[配置文件]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=405</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
关于配置文件，在 PHP 的 Zend Framework 中我做过一些简单的关于性能的测试：http://www.mikespook.com/index.php/archives/36。将 ninnypro 的配置文件从 ini 修改为 xml ，并且声称能提高传说中的性能。

最近被调到另外一个在用 python 的组帮忙，阅读了他们的实现服务器端的 python 代码之，配置文件近二十余个，全是 xml 文件。为了使用着些配置文件，从 XMLFile 继承，实现了二十余个 Config 类。

<span class="readmore"><a href="http://www.mikespook.com/2009/09/%e8%84%9a%e6%9c%ac%e8%af%ad%e8%a8%80%e7%9a%84%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6/" title="脚本语言的配置文件">阅读全文——共1350字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>关于配置文件，在 PHP 的 Zend Framework 中我做过一些简单的关于性能的测试：<a href="http://www.mikespook.com/index.php/archives/36" target="_blank">http://www.mikespook.com/index.php/archives/36</a>。将 ninnypro 的配置文件从 ini 修改为 xml ，并且声称能提高传说中的性能。</p>
<p>最近被调到另外一个在用 python 的组帮忙，阅读了他们的实现服务器端的 python 代码之，配置文件近二十余个，全是 xml 文件。为了使用着些配置文件，从 XMLFile 继承，实现了二十余个 Config 类。</p>
<p><strong>这看起来似乎没什么问题。<span id="more-405"></span></strong></p>
<p>是的，一点问题也没有。</p>
<ol>
<li>XML是高度结构化的描述方式。</li>
<li>XML有大量丰富的包、库支持。</li>
<li>XML的跨语言能力也是相当优异。你可以轻松的用市面上常见的所有语言轻松的掌控 XML。</li>
</ol>
<p>这些都决定了 XML 作为配置文件，肯定是比 ini 或者自定义结构的配置文件更加优异的结构。同时，大量的实践也证明 XML 的优异性。例如 j2ee 的实践、SOA的实现、Jabber 的应用都说明 XML: is the lord of the configuration。</p>
<p><strong>但是真得一点问题都没有么？</strong></p>
<p>首先，来看一下 Zend Framework 的 Zend_Config。由于 PHP 自身的数据结构特点，Zend_Config_Xml 和 Zend_Config_Ini 两个类都会加载相应的配置文件，解析后作为数组传递到 Zend_Config 类中。也就是说，最终殊途同归，所有的配置都变成了 PHP 的数组。</p>
<p>然后，再来看一下那个项目中的配置文件。结构化的 XML 被 XMLFile 读取，然后转化为 XMLFile 对象。再统一放入 ConfigManagement 中，经过转换，将部分结构转为 dict 使用。</p>
<p>使用配置文件的原因，我猜测是因为以前，编译语言开发的程序经过编译后，不具有动态改变参数的能力。虽然可以从命令行通过传参来在每次运行时修改配置，但是无论是谁需要通过命令行传递成百上千的参数，都会疯掉。而且，命令行传参，不具有结构化的特征。在一些场景下，需要快速修改部分配置，就变得极为困难。</p>
<p>于是聪明的程序员发明了对人友好的、结构化的配置文件，通过读取配置文件来改变程序内部参数的使用。</p>
<p>这一习惯一直沿用至今。伴随 XML 的问世，配置文件的地位再次上升。更有甚者，在开发中不做编码，只写配置。</p>
<p><strong>看出问题了么？</strong></p>
<p>如果还是没有想法的话，那就再来看看脚本语言：</p>
<ol>
<li>脚本语言具有动态性。</li>
<li>脚本语言自身就是结构化的。</li>
<li>脚本语言可以增强编译语言的动态能力。</li>
</ol>
<p>在各个脚本语言应用 XML 作为配置文件的实践中，不论是 PHP 的 array，还是 Python 的 dict，无一例外的将配置文件转换为了脚本语言内部的一种数据结构。在多数情况下，这也是 XML 作为脚本语言配置文件唯一的解决方案。</p>
<p>再来看一个问题：在项目中使用 XML 作为配置文件的时候，是否有使用 DTD 作为 XML 的效验工具？</p>
<p>如果答案是否定的，那么 XML作为脚本语言就没有任何优势。没有应用 DTD 的 XML 就如同 PHP 的 array，Python 的 dict 一样。</p>
<p>那又何必要苦苦的追随 XML，不用脚本语言的数据结构来直接编写配置文件呢？</p>
<p>本来，早就像对这个话题写点什么。星期六（2009-09-19）的时候参加了广州技术沙龙，听了朱童鞋的 nginx 代码剖析后，突然有所顿悟：<strong></strong></p>
<p><strong>成功在于细节，性能在于细节。</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2009/09/%e8%84%9a%e6%9c%ac%e8%af%ad%e8%a8%80%e7%9a%84%e9%85%8d%e7%bd%ae%e6%96%87%e4%bb%b6/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>［翻译］PHP的命名空间真这么糟糕么？</title>
		<link>http://www.mikespook.com/2009/09/%ef%bc%bb%e7%bf%bb%e8%af%91%ef%bc%bdphp%e7%9a%84%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e7%9c%9f%e8%bf%99%e4%b9%88%e7%b3%9f%e7%b3%95%e4%b9%88%ef%bc%9f/</link>
		<comments>http://www.mikespook.com/2009/09/%ef%bc%bb%e7%bf%bb%e8%af%91%ef%bc%bdphp%e7%9a%84%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e7%9c%9f%e8%bf%99%e4%b9%88%e7%b3%9f%e7%b3%95%e4%b9%88%ef%bc%9f/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 02:27:11 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[命名空间]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=394</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
几年前（大约应该在02-03年之间，也就是php5刚出来那会）曾经跟朋友讨论过一次关于php的命名空间的问题。当时觉得，php要是能有命名空间，那是多完美的事情啊。

如今，php5.3已经包含了命名空间。但是似乎并没有当年的那种感慨了。大约是旧的系统要迁移，新的系统要重新设计，这个名字空间都有点鸡肋的感觉。看来还要习惯一下才好。

看到这篇文章，觉得说得是有点对的。也不长，就随手翻译出来。翻译后的感觉：作者 超级喜欢使用“However”。

<span class="readmore"><a href="http://www.mikespook.com/2009/09/%ef%bc%bb%e7%bf%bb%e8%af%91%ef%bc%bdphp%e7%9a%84%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e7%9c%9f%e8%bf%99%e4%b9%88%e7%b3%9f%e7%b3%95%e4%b9%88%ef%bc%9f/" title="［翻译］PHP的命名空间真这么糟糕么？">阅读全文——共1630字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>几年前（大约应该在02-03年之间，也就是php5刚出来那会）曾经跟朋友讨论过一次关于php的命名空间的问题。当时觉得，php要是能有命名空间，那是多完美的事情啊。<br />
如今，php5.3已经包含了命名空间。但是似乎并没有当年的那种感慨了。大约是旧的系统要迁移，新的系统要重新设计，这个名字空间都有点鸡肋的感觉。看来还要习惯一下才好。<br />
看到这篇文章，觉得说得是有点对的。也不长，就随手翻译出来。翻译后的感觉：作者 超级喜欢使用“However”。<br />
能说明两个问题：</p>
<ol>
<li> php本身为什么是这样</li>
<li> php的名字空间为什么是这样</li>
</ol>
<p>作者：<a title="Craig Buckler's Author Bio" rel="nofollow" href="http://www.sitepoint.com/articlelist/560">Craig Buckler</a><br />
原文：<a href="http://www.sitepoint.com/blogs/2009/08/13/are-php-namespaces-bad/" target="_blank">http://www.sitepoint.com/blogs/2009/08/13/are-php-namespaces-bad/</a><span id="more-394"></span><br />
<img class="alignright" title="PHP namespaces" src="http://www.mikespook.com/wp-content/uploads/2009/12/0414_php-namespaces1.png" alt="PHP namespaces" width="240" height="240" /></p>
<p>PHP开发者对于PHP中命名空间的实现，已经变得异常的<a href="http://www.petitiononline.com/phpns/petition.html">渴望</a>。当PHP应用开始变得巨大，并且更加复杂的时候，命名空间是解决代码冲突的必要手段。<br />
我最近的一些<a href="http://www.sitepoint.com/blogs/2009/07/13/php-53-namespaces-basics/">指南</a>收到了大量关于PHP的命名空间实现的评论。问题主要集中在语法和反斜杠上面。在解决这些问题之前，让我们先来快速回顾一下PHP的历史。</p>
<h2>混乱的PHP</h2>
<p>像C#和Java这些语言，是被设计和遵循严格的语法标准的。PHP是<em>演化</em>的。最早的版本发布于1995年，版本号3，是面向过程的语言。版本4包含了最基本的面向对象，而版本5提供了合适的标准OOP模型。命名空间在版本5.3被加入其中。</p>
<p>PHP批评者声明说这个语言是混乱的。函数名不一致（例如strpos，str_split，substr），对象处理是无用的，还有一些语法同其他语言相比，不是极其怪诞，就是异乎寻常。</p>
<p>然而，PHP仍然保持着使用最广泛的服务器端开发语言的头把交椅。它的才华主要在下面的长处：</p>
<ul>
<li>初学者可以从简单的面向过程编程开始。他们无须触及OOP技术仍然可以有所见数。</li>
<li>10年前为PHP 3编写的代码仍然可以运行在PHP 5.3下。可能需要一些微小的调整，但是很少需要大量重写。</li>
</ul>
<p>PHP代码可能并不总是可爱的、有逻辑的或者优雅的，但是相比其他选择它的开发总是快捷和容易被理解的。</p>
<h2>PHP命名空间的实现</h2>
<p>不像C#和Java，PHP不得不保持没有名字空间代码的兼容性。这个已经被实现，你可以选择使用或者不使用命名空间。然而，如果你使用PHP 5.3或更高版本，我推荐使用命名空间，即使你在项目中只使用相同的名字。</p>
<p>使用<code>namespace</code>和<code>use</code>作为命名空间操作符看起来很有逻辑。一些开发者可能不同意，但是在这种情况下它们如何命名其实并不重要。</p>
<p>最后，回到反斜杠的问题上。多数批评者人为这是丑陋的，难以阅读，并且在Mac上难以输入。即便如此，我仍然认为它比曾经提议过的两个冒号要好。例如下面的静态方法调用：</p>
<pre lang="PHP">// PHP 5.3 beta版静态方法调用
echo ::App::Lib1::MyClass::WhoAmI();
// PHP 5.3正式版静态方法调用
echo \App\Lib1\MyClass::WhoAmI();</pre>
<p>第二行可以被快速录入，更少的错误可能，容易阅读，并且容易理解。如果你在字符串之外看到反斜杠，你就知道那一定存在命名空间。</p>
<p>当然，如果PHP使用“.”作为公共方法、静态方法和命名空间会更好。这样可以同Java、C#、JavaScript、Python和许多其他语言一致起来。不幸的是PHP的历史和向下兼容让这一切难以实现。</p>
<p>没有语言是完美的，而PHP更加不会是完美语言中的一员。无论如何，命名空间已经被很好的实现，特别是考虑到它可能产生的限制和问题。我相信你一定会学习并且着迷那个反斜杠的。</p>
<p>相关阅读：</p>
<ul>
<li><a href="http://www.sitepoint.com/blogs/2009/07/13/php-53-namespaces-basics/">How to Use PHP Namespaces, Part 1: The Basics</a></li>
<li><a href="http://www.sitepoint.com/blogs/2009/07/14/php-namespaces-import-alias-resolution/">How to Use PHP Namespaces, Part 2: Importing, Aliases, and Name Resolution</a></li>
<li><a href="http://www.sitepoint.com/blogs/2009/07/15/how-to-use-php-namespaces-part-3-keywords-and-autoloading/">How to Use PHP Namespaces, Part 3: Keywords and Autoloading</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2009/09/%ef%bc%bb%e7%bf%bb%e8%af%91%ef%bc%bdphp%e7%9a%84%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e7%9c%9f%e8%bf%99%e4%b9%88%e7%b3%9f%e7%b3%95%e4%b9%88%ef%bc%9f/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>mb_ereg(i)_replace() 执行任意代码的漏洞</title>
		<link>http://www.mikespook.com/2009/05/mb_eregi_replace-%e6%89%a7%e8%a1%8c%e4%bb%bb%e6%84%8f%e4%bb%a3%e7%a0%81%e7%9a%84%e6%bc%8f%e6%b4%9e/</link>
		<comments>http://www.mikespook.com/2009/05/mb_eregi_replace-%e6%89%a7%e8%a1%8c%e4%bb%bb%e6%84%8f%e4%bb%a3%e7%a0%81%e7%9a%84%e6%bc%8f%e6%b4%9e/#comments</comments>
		<pubDate>Fri, 08 May 2009 14:24:13 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[漏洞]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=309</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
这个漏洞说大也大，说小也小。大是因为真得可以通过注入的方式让漏洞代码执行任意代码。小是因为产生漏洞的环境还是比较苛刻的。

来源于此：http://milw0rm.com/exploits/8641

当最后一个参数设置为“e”，也就是将替换的内容作为 PHP 代码执行的时候，漏洞就产生了。

<span class="readmore"><a href="http://www.mikespook.com/2009/05/mb_eregi_replace-%e6%89%a7%e8%a1%8c%e4%bb%bb%e6%84%8f%e4%bb%a3%e7%a0%81%e7%9a%84%e6%bc%8f%e6%b4%9e/" title="mb_ereg(i)_replace() 执行任意代码的漏洞">阅读全文——共432字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>这个漏洞说大也大，说小也小。大是因为真得可以通过注入的方式让漏洞代码执行任意代码。小是因为产生漏洞的环境还是比较苛刻的。</p>
<p>来源于此：<a href="http://milw0rm.com/exploits/8641" target="_blank">http://milw0rm.com/exploits/8641</a></p>
<p>当最后一个参数设置为“e”，也就是将替换的内容作为 PHP 代码执行的时候，漏洞就产生了。<br />
例如：</p>
<pre lang="PHP">function hi80vul() {}

$str = '\', phpinfo(), \'';
mb_ereg_replace('^(.*)$', 'hi80vul(\'\1\')', $str, 'e');</pre>
<p>又例如：</p>
<pre lang="PHP">function hi80vul() {}

$str = '\', var_dump(get_loaded_extensions()), \'';
mb_ereg_replace('^(.*)$', 'hi80vul(\'\1\')', $str, 'e');</pre>
<p>如果有在代码中使用过 mb_ereg_replace 和 mb_eregi_replace，以及参数“e”，那就赶紧检查一下是否有这样的安全隐患吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2009/05/mb_eregi_replace-%e6%89%a7%e8%a1%8c%e4%bb%bb%e6%84%8f%e4%bb%a3%e7%a0%81%e7%9a%84%e6%bc%8f%e6%b4%9e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

