<?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>某人的栖息地 &#187; php</title>
	<atom:link href="http://www.ooso.net/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ooso.net</link>
	<description>Linux + Apache + Mysql + Php + Flash</description>
	<lastBuildDate>Thu, 19 Jan 2012 01:21:44 +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>php的异步http请求类</title>
		<link>http://www.ooso.net/archives/597</link>
		<comments>http://www.ooso.net/archives/597#comments</comments>
		<pubDate>Thu, 10 Nov 2011 08:24:07 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=597</guid>
		<description><![CDATA[基于上次写的关于php的libevent扩展的应用，我实现了一个异步的http请求类。
代码在github上：https://github.com/volca/AsyncHttpClient
使用示例
如下，在request的时候能够定义请求完成之后的callback函数。

				<span class="readmore"><a href="http://www.ooso.net/archives/597" title="php的异步http请求类">阅读全文（134字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>基于上次写的<a href="http://www.ooso.net/archives/607" title="关于php的libevent扩展的应用">关于php的libevent扩展的应用</a>，我实现了一个异步的http请求类。</p>
<p>代码在github上：<a href="https://github.com/volca/AsyncHttpClient">https://github.com/volca/AsyncHttpClient</a></p>
<h2>使用示例</h2>
<p>如下，在request的时候能够定义请求完成之后的callback函数。</p>
<pre><code>&lt;?php
$base = event_base_new();

$uri = "http://www.baidu.com/";
$config = array(
    'eventbase' =&gt; $base
);

for($i = 0; $i &lt; 10; $i++) {
    $client = new AsyncHttpClient($uri, $config);
    $client-&gt;request(function($result) {
        echo "Result len:";
        echo strlen($result['response']);
        // parse response with Zend_Http_Response
        $response = Zend_Http_Response::fromString($result['response']);
        echo $response-&gt;getBody();
        echo "\n";
    });
}

event_base_loop($base);
echo "done\n";</code></pre>
<p>目前的实现比较初级，只做了get方法的封装，如果需要http上传或者post，还需要另外实现。另外这个类也需要<a href="http://pecl.php.net/libevent">php的libevent扩展</a>。</p>
<h2>Update 2011.11.17</h2>
<p>将这个类修改为继承自Zend_Http_Client，这样我可以少写一些代码，顺带也实现了文件http上传以及post（未经测试）,代码中的使用示例也已经更新。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/597/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>关于php的libevent扩展的应用</title>
		<link>http://www.ooso.net/archives/607</link>
		<comments>http://www.ooso.net/archives/607#comments</comments>
		<pubDate>Tue, 25 Oct 2011 14:58:04 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[libevent]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=607</guid>
		<description><![CDATA[php有个libevent扩展，在一年前我曾经拿它实现了一个thrift socket server，虽然我没有把它放在正式的场合来使用，但是我觉得这个扩展应该可以有更广泛的用途，比如：

phpDaemon — 一个异步的服务器端开发框架.
tail &#8211; 用php实现类似unix下的tail命令行

				<span class="readmore"><a href="http://www.ooso.net/archives/607" title="关于php的libevent扩展的应用">阅读全文（1038字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>php有个libevent扩展，在一年前我曾经拿它<a href="http://www.ooso.net/archives/537">实现了一个thrift socket server</a>，虽然我没有把它放在正式的场合来使用，但是我觉得这个扩展应该可以有更广泛的用途，比如：</p>
<ul>
<li><a href="http://phpdaemon.net/">phpDaemon</a> — 一个异步的服务器端开发框架.</li>
<li><a href="http://abhinavsingh.com/blog/2009/11/writing-a-custom-unix-style-tail-in-php-using-libevent-api-on-mac-os-x-10-5-x-and-other-platforms">tail</a> &#8211; 用php实现类似unix下的tail命令行</li>
<li><a href="http://toys.lerdorf.com/archives/57-ZeroMQ-+-libevent-in-PHP.html">ZeroMQ + libevent in PHP</a> &#8211; 用php和ZeroMQ实现的一个事件驱动服务器端</li>
</ul>
<p>我所想到的一个比较实用的使用场景是，在页面中利用libevent请求多个http接口来获得数据。若是在从前，一个可行的办法是利用curl_multi_exec来同时请求好几个接口，但是这个办法需要用一个do &#8230; while循环来完成请求，很是坑爹。那么看看采用libevent的例子:</p>
<h2>代码实例 http.php</h2>
<pre><code>&lt;?php
$base_fd = event_base_new();
$times = 0;
$limit = 10;
$index = array();

function httpGet($host, $base_fd) {
    global $index;

    $fd = stream_socket_client("$host:80", $errno, $errstr, 3, STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT);
    $index[$fd] = 0;
    $event_fd = event_new();
    event_set($event_fd, $fd, EV_WRITE | EV_PERSIST, function($fd, $events, $arg) use($host) {
        global $times, $limit, $index;

        if(!$index[$fd]) {
            $index[$fd] = 1;
            $out = "GET / HTTP/1.1\r\n";
            $out .= "Host: $host\r\n";
            $out .= "Connection: Close\r\n\r\n";
            fwrite($fd, $out);
        } else {
            echo fread($fd, 4096);
            if(feof($fd)) {
                fclose($fd);
                $times++;
                echo "done\n";

                if($times == $limit - 1) {
                    event_base_loopexit($arg[1]);
                }
            }
        }
    }, array($event_fd, $base_fd));

    event_base_set($event_fd, $base_fd);
    event_add($event_fd);
}

for($i = 0; $i &lt; $limit; $i++) {
    echo "$i\n";
    httpGet($argv[1], $base_fd);
        //echo file_get_contents("http://$argv[1]");
}

event_base_loop($base_fd);
?&gt;</code></pre>
<p>为了省事，这个php脚本仅仅是重复抓取一个网页5次，并且回调的逻辑我没怎么做处理，仅仅是echo出来而已，可以通过下面命令行来运行这个例子:</p>
<pre><code>php http.php "www.baidu.com"</code></pre>
<p>代码中的http_get($argv[1])这行虽然是靠一个命令行顺序执行，但是不会阻塞后面的代码，直接就进行下一次请求了。而且我们看看回调方法部分是不是很像用javascript调用ajax写的回调方法？这都是php 5.3中闭包的功劳。</p>
<pre><code>event_set($event_fd, $fd, EV_WRITE | EV_PERSIST, function($fd, $events, $arg) {
    //回调方法，后续处理随意
    echo fread($fd, 4096);
    if(feof($fd)) {
        fclose($fd);
	event_base_loopexit($arg[1]);
	echo "done";
    }
}, array($event_fd, $base_fd));</code></pre>
<h2>想到更多</h2>
<p>在mysqlnd，memcached&#8230;这些php扩展中，都已经有delay回调的实现，如果能好好利用，对性能提升岂不是有莫大的帮助？或者在libevent扩展的基础上，实现一个事件驱动的开发框架，也是可行的。</p>
<h2>Update 2011.11.10</h2>
<p>在这个代码的基础上实现了一个<a href="http://www.ooso.net/archives/597" title="php的异步http请求类">异步http请求的客户端</a></p>
<h2>Update 2011.10.28</h2>
<p>event_base_loop是会阻塞后续代码执行的，所以我调整了示例代码，使用同一个event_base，并且用stream_socket_client来进行异步连接，另外在/etc/hosts指定域名的ip会对执行速度有帮助。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/607/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>php文档更新</title>
		<link>http://www.ooso.net/archives/548</link>
		<comments>http://www.ooso.net/archives/548#comments</comments>
		<pubDate>Sun, 26 Jun 2011 09:18:31 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[pear]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=548</guid>
		<description><![CDATA[php.net最近更新了php文档，比较有用的是新增的pman工具。pman是一个命令行小工具，方便查看php函数的本地帮助文档，但是不包含php.net的评论数据。简单的试用心得如下:
安装pman
使用传说中的pear来安装pman
sudo pear install doc.php.net/pman

				<span class="readmore"><a href="http://www.ooso.net/archives/548" title="php文档更新">阅读全文（1075字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>php.net最近更新了<a href="/tag/php">php</a>文档，比较有用的是新增的pman工具。pman是一个命令行小工具，方便查看php函数的本地帮助文档，但是不包含php.net的评论数据。简单的试用心得如下:</p>
<h2>安装pman</h2>
<p>使用传说中的pear来安装pman</p>
<pre><code>sudo pear install doc.php.net/pman</code></pre>
<p>如果pear版本比较老，需要先升级pear才可以继续</p>
<pre><code>sudo pear upgrade pear</code></pre>
<h2>pman使用方法</h2>
<p>pman的使用方法很傻瓜，比如我们想查看strlen的帮助信息:</p>
<pre><code>pman strlen</code></pre>
<p>帮助文本的内容是彩色的，能和chm版本的php帮助文档媲美。pman的详细使用帮助如下</p>
<pre><code>#pman --help
man, version 1.6c

usage: man [-adfhktwW] [section] [-M path] [-P pager] [-S list]
	[-m system] [-p string] name ...

  a : find all matching entries
  c : do not use cat file
  d : print gobs of debugging information
  D : as for -d, but also display the pages
  f : same as whatis(1)
  h : print this help message
  k : same as apropos(1)
  K : search for a string in all pages
  t : use troff to format pages for printing
  w : print location of man page(s) that would be displayed
      (if no name given: print directories that would be searched)
  W : as for -w, but display filenames only

  C file   : use `file' as configuration file
  M path   : set search path for manual pages to `path'
  P pager  : use program `pager' to display pages
  S list   : colon separated section list
  m system : search for alternate system's man pages
  p string : string tells which preprocessors to run
               e - [n]eqn(1)   p - pic(1)    t - tbl(1)
               g - grap(1)     r - refer(1)  v - vgrind(1)</code></pre>
<p>还有一个好处是在vim里查看php帮助信息更方便了，结合完美</p>
<pre><code>:!pman strlen</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/548/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>用git部署php站点</title>
		<link>http://www.ooso.net/archives/596</link>
		<comments>http://www.ooso.net/archives/596#comments</comments>
		<pubDate>Tue, 29 Mar 2011 03:26:42 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=596</guid>
		<description><![CDATA[在小站点上，直接用git来部署php代码相当方便，你的远程站点以及本地版本库都有一个版本控制，追踪问题或者回滚是很轻松的事情。下面介绍用git部署时的设置步骤
在远程服务器的设置
假定你需要部署的代码在/var/www/yoursite
cd /var/www/yoursite

				<span class="readmore"><a href="http://www.ooso.net/archives/596" title="用git部署php站点">阅读全文（488字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>在小站点上，直接用git来部署php代码相当方便，你的远程站点以及本地版本库都有一个版本控制，追踪问题或者回滚是很轻松的事情。下面介绍用git部署时的设置步骤</p>
<h2>在远程服务器的设置</h2>
<p>假定你需要部署的代码在/var/www/yoursite</p>
<pre><code>cd /var/www/yoursite
git init .
git config receive.denyCurrentBranch ignore
git config --bool receive.denyNonFastForwards false
cd .git/hooks
wget http://utsl.gen.nz/git/post-update
chmod +x post-update</code></pre>
<h2>在本地git库中新增配置</h2>
<pre><code>[remote "prod"]
        url = your-ssh-username@your-host:/var/www/yoursite/</code></pre>
<p>这样就算设置完成了。</p>
<p>如果你想把本地的代码推送到远程服务器，下面简单的步骤就可以做到</p>
<pre><code>git pull
git push prod</code></pre>
<h2>注意事项</h2>
<p>如果远程服务器上git的配置目录.git暴露在外部可访问的位置，请在web服务器上设置这个目录不可见。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/596/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>防止伪造跨站请求的小招式</title>
		<link>http://www.ooso.net/archives/581</link>
		<comments>http://www.ooso.net/archives/581#comments</comments>
		<pubDate>Mon, 17 Jan 2011 02:34:52 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=581</guid>
		<description><![CDATA[伪造跨站请求介绍
伪造跨站请求比较难以防范，而且危害巨大，攻击者可以通过这种方式恶作剧，发spam信息，删除数据等等。这种攻击常见的表现形式有：

伪造链接，引诱用户点击，或是让用户在不知情的情况下访问

				<span class="readmore"><a href="http://www.ooso.net/archives/581" title="防止伪造跨站请求的小招式">阅读全文（357字）</a></span>]]></description>
			<content:encoded><![CDATA[<h2>伪造跨站请求介绍</h2>
<p>伪造跨站请求比较难以防范，而且危害巨大，攻击者可以通过这种方式恶作剧，发spam信息，删除数据等等。这种攻击常见的表现形式有：</p>
<ul>
<li>伪造链接，引诱用户点击，或是让用户在不知情的情况下访问</li>
<li>伪造表单，引诱用户提交。表单可以是隐藏的，用图片或链接的形式伪装。</li>
</ul>
<p>比较常见而且也很廉价的防范手段是在所有可能涉及用户写操作的表单中加入一个随机且变换频繁的字符串，然后在处理表单的时候对这个字符串进行检查。这个随机字符串如果和当前用户身份相关联的话，那么攻击者伪造请求会比较麻烦。</p>
<p>yahoo对付伪造跨站请求的办法是在表单里加入一个叫<strong>.crumb</strong>的随机串；而facebook也有类似的解决办法，它的表单里常常会有<strong>post_form_id</strong>和<strong>fb_dtsg</strong>。</p>
<h2>随机串代码实现</h2>
<p>咱们按照这个思路，山寨一个crumb的实现，代码如下：</p>
<pre><code>&lt;?php
class Crumb {                                                                                                  

    CONST SALT = "your-secret-salt";                                                         

    static $ttl = 7200;                                                                                           

    static public function challenge($data) {
        return hash_hmac('md5', $data, self::SALT);
    }                                                                                                             

    static public function issueCrumb($uid, $action = -1) {
        $i = ceil(time() / self::$ttl);
        return substr(self::challenge($i . $action . $uid), -12, 10);
    }                                                                                                             

    static public function verifyCrumb($uid, $crumb, $action = -1) {
        $i = ceil(time() / self::$ttl);                                                                           

        if(substr(self::challenge($i . $action . $uid), -12, 10) == $crumb ||
            substr(self::challenge(($i - 1) . $action . $uid), -12, 10) == $crumb)
            return true;                                                                                          

        return false;
    }                                                                                                             

}</code></pre>
<p>代码中的$uid表示用户唯一标识，而$ttl表示这个随机串的有效时间。</p>
<h2>应用示例</h2>
<p><strong>构造表单</strong><br />
在表单中插入一个隐藏的随机串crumb</p>
<pre><code>&lt;form method="post" action="demo.php"&gt;
&lt;input type="hidden" name="crumb" value="&lt;?php echo Crumb::issueCrumb($uid)?&gt;"&gt;
&lt;input type="text" name="content"&gt;
&lt;input type="submit"&gt;
&lt;/form&gt;</code></pre>
<p><strong>处理表单 demo.php</strong><br />
对crumb进行检查</p>
<pre><code>&lt;?php
if(Crumb::verifyCrumb($uid, $_POST['crumb'])) {
    //按照正常流程处理表单
} else {
    //crumb校验失败，错误提示流程
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/581/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>php实现的thrift socket server</title>
		<link>http://www.ooso.net/archives/537</link>
		<comments>http://www.ooso.net/archives/537#comments</comments>
		<pubDate>Fri, 25 Jun 2010 08:03:31 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[thrift]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=537</guid>
		<description><![CDATA[这些天用php写了个thrift的socket server，因为原来thrift的源码里php部分只有基于apache的服务器端代码，再加上前些日子看到php也能直接使用libevent构建web服务器，所以才会想到写这个玩玩。
php-thrift-server源码
代码直接从apache的thrift项目clone过来，托管在github上：
http://github.com/volca/thrift

				<span class="readmore"><a href="http://www.ooso.net/archives/537" title="php实现的thrift socket server">阅读全文（2531字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>这些天用php写了个thrift的socket server，因为原来thrift的源码里php部分只有基于apache的服务器端代码，再加上前些日子看到<a href="/tag/php">php</a>也能直接使用libevent构建web服务器，所以才会想到写这个玩玩。</p>
<h2>php-thrift-server源码</h2>
<p>代码直接从apache的thrift项目clone过来，托管在github上：</p>
<p><a href="http://github.com/volca/thrift">http://github.com/volca/thrift</a></p>
<p>新增或改动的代码如下:</p>
<ol>
<pre>
lib/php/
`-- src
    |-- server
    |   |-- TNonblockingServer.php
    |   `-- TServer.php
    `-- transport
        |-- TNonblockingServerSocket.php
        |-- TNonblockingSocket.php
        |-- TServerSocket.php
        |-- TServerTransport.php
test/php
|-- TestClient.php
|-- TestNonblockingServer.php
</pre>
</ol>
<h2>使用示例</h2>
<p>获取thrift的源码，并编译出thrift工具，编译过程请搜索</p>
<pre><code>git clone git://github.com/volca/thrift.git</code></pre>
<p>安装php,以及apc, libevent扩展:</p>
<pre><code>pecl install apc
#需要先libevent-devel之类的包包
pecl install libevent</code></pre>
<p>运行php的socket服务器，我直接从thrift的test代码中修改了一个独立运行的php server，见thrift/test/php/TestNonblockingServer.php，这里也包含一个测试业务代码的实现。</p>
<pre><code>cd thrift/test/php
#用thrift命令行工具生成php的测试类库
make
#启动thrift服务，会监听本机的9090端口
php TestNonblockingServer.php</code></pre>
<p>客户端的代码也一并提供，对各种数据类型比如int, float, string, list等等进行测试。</p>
<pre><code>php TestClient.php</code></pre>
<h2>性能测试</h2>
<p>apache + php的测试结果</p>
<pre><code>testVoid() = void
testString("Test") = "Test"
testByte(1) = 1
testI32(-1) = -1
testI64(-34359738368) = -34359738368
testDouble(-852.234234234) = -852.234234234
testStruct({"Zero", 1, -3, -5}) = {"Zero", 1, -3, -5}
testNest({1, {"Zero", 1, -3, -5}), 5} = {1, {"Zero", 1, -3, -5}, 5}
testMap({0 =&gt; -10, 1 =&gt; -9, 2 =&gt; -8, 3 =&gt; -7, 4 =&gt; -6}) = {0 =&gt; -10, 1 =&gt; -9, 2 =&gt; -8, 3 =&gt; -7, 4 =&gt; -6}
testSet({-2, -1, 0, 1, 2}) = {1, 1, 1, 1, 1}
testList({-2, -1, 0, 1, 2}) = {-2, -1, 0, 1, 2}
testEnum(ONE) = 1
testEnum(TWO) = 2
testEnum(THREE) = 3
testEnum(FIVE) = 5
testEnum(EIGHT) = 8
testTypedef(309858235082523) = 309858235082523
Total time: 41 ms</code></pre>
<p>php + libevent的socket server测试结果</p>
<pre><code>testVoid() = void
testString("Test") = "Test"
testByte(1) = 1
testI32(-1) = -1
testI64(-34359738368) = -34359738368
testDouble(-852.234234234) = -852.234234234
testStruct({"Zero", 1, -3, -5}) = {"Zero", 1, -3, -5}
testNest({1, {"Zero", 1, -3, -5}), 5} = {1, {"Zero", 1, -3, -5}, 5}
testMap({0 =&gt; -10, 1 =&gt; -9, 2 =&gt; -8, 3 =&gt; -7, 4 =&gt; -6}) = {0 =&gt; -10, 1 =&gt; -9, 2 =&gt; -8, 3 =&gt; -7, 4 =&gt; -6}
testSet({-2, -1, 0, 1, 2}) = {1, 1, 1, 1, 1}
testList({-2, -1, 0, 1, 2}) = {-2, -1, 0, 1, 2}
testEnum(ONE) = 1
testEnum(TWO) = 2
testEnum(THREE) = 3
testEnum(FIVE) = 5
testEnum(EIGHT) = 8
testTypedef(309858235082523) = 309858235082523
Total time: 8 ms</code></pre>
<p>这个测试中，没有耗时很长的请求，处理逻辑完全一样，php socket server耗时仅为apache + php的五分之一。</p>
<h2>thrift是什么？</h2>
<p>thrift流传的似乎不是太广泛，而且有被别的技术替代的趋势，所以下面还是引用一下别的文章的介绍：</p>
<blockquote><p>Thrift由一个软件库和一系列的代码生成工具组成，由 Facebook开发。目的是为了加快软件开发和实现高效和可扩展的后台服务。主要目标是不同程序开语言之间实现高效和可靠的通信，这需要将不同语言之间抽象出一个通用层，然后由不同语言来实现这个通用层。在这里要特别指出的是，Thrift允许开发人员定义数据类型和服务接口（定义在一个中性语言文件里），并通过这个文件生成构建RPC客户端和服务端所需的代码。</p>
<p>简单分析其机理，Thrift就是实现C/S模式，通过代码生成工具将接口定义文件生成服务器端和客户端代码（可以为不同语言），从而实现服务端和客户端跨语言的支持。</p>
<p>Thrift可以分为传输层和协议层：</p>
<p>传输层定义了数据的传输方式，可以为TCP/IP传输，内存共享或者文件共享等形式；<br />
协议层定义了数据的传输格式，可以为二进制流或者XML等形式。<br />
当服务器端使用socket协议时，可以用simple|thread-pool|threaded|nonblocking等方式运行，从而获得更好的性能。
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/537/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>php的filter扩展小技巧</title>
		<link>http://www.ooso.net/archives/559</link>
		<comments>http://www.ooso.net/archives/559#comments</comments>
		<pubDate>Fri, 30 Apr 2010 11:29:26 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=559</guid>
		<description><![CDATA[做为一个合格的web开发人员，一定会牢记一个原则——永远不能相信用户输入的数据，行走江湖，安全第一是很重要的。用户通过表单或url传过来的数据，一定要仔细检查过了，才往后台数据库里存进去。在一个成熟的开发团队里，贯彻这个原则不成问题；但是如果在一个新人老手混搭的小team里，很容易就忽视了这个问题，那么各种安全漏洞比如跨站攻击，sql注入等等真是防不胜防。
实际上，用php 5自带的filter扩展能够较好的解决这个问题。我在从前的blog里记录了filter扩展的常规用法——直接利用filter来校验数据，这样有不少额外的代码量，所以我得介绍一个比较偷懒的办法——自动对所有输入变量进行过滤，这只需要对php.ini增加一行配置，然后重启apache或fastcgi让php配置生效。

				<span class="readmore"><a href="http://www.ooso.net/archives/559" title="php的filter扩展小技巧">阅读全文（868字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>做为一个合格的web开发人员，一定会牢记一个原则——永远不能相信用户输入的数据，行走江湖，安全第一是很重要的。用户通过表单或url传过来的数据，一定要仔细检查过了，才往后台数据库里存进去。在一个成熟的开发团队里，贯彻这个原则不成问题；但是如果在一个新人老手混搭的小team里，很容易就忽视了这个问题，那么各种安全漏洞比如跨站攻击，sql注入等等真是防不胜防。</p>
<p>实际上，用php 5自带的filter扩展能够较好的解决这个问题。我在<a href="http://www.ooso.net/archives/204">从前的blog里记录了filter扩展的常规用法</a>——直接利用filter来校验数据，这样有不少额外的代码量，所以我得介绍一个比较偷懒的办法——自动对所有输入变量进行过滤，这只需要对php.ini增加一行配置，然后重启apache或fastcgi让php配置生效。</p>
<blockquote><p>filter.default=&#8221;special_chars&#8221;</p></blockquote>
<p>开启了这项配置后，会自动使用<a href="http://php.net/filter_input">filter_input</a>方法对$_GET, $_POST, $_COOKIE, $_REQUEST以及$_SERVER变量进行过滤转义。配置中special_chars是常量FILTER_SANITIZE_SPECIAL_CHARS的缩写，它能自动转义大部分危险字符例如： <strong>&#39;&quot;&lt;&gt;</strong>。而php手册对它的解释是：</p>
<blockquote><p>HTML-escape &#8216;&#8221;<>&#038; and characters with ASCII value less than 32, optionally strip or encode other special characters. </p></blockquote>
<p>在这个情况下，新人们写出这样的代码我也不会太担心:</p>
<pre><code>$foo = $_GET['foo'];
echo $foo;</code></pre>
<p>在部分场合，我们可能还是需要未转义的变量，比如某个ajax接受的参数是一段json串，用这段代码即可获得原始数据：</p>
<pre><code>$foo = filter_input (INPUT_GET, 'foo',  FILTER_UNSAFE_RAW);</code></pre>
<p>fitler扩展与yahoo使用的yiv如出一辙，印象里似乎就是yahoo对yiv做了些修改贡献给php社区，但是暂时没找到出处。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/559/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>关于“facebook的memcached实战”小记</title>
		<link>http://www.ooso.net/archives/558</link>
		<comments>http://www.ooso.net/archives/558#comments</comments>
		<pubDate>Thu, 29 Apr 2010 16:38:07 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[memcache]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=558</guid>
		<description><![CDATA[上周挤到QCon的会场里，听了两场 —— Facebook的Memcached实战，以及Twitter 的可伸缩性数据架构。当时对facebook超大规模使用memcached印象很深刻，只可惜到现在也没见到这个的ppt。平时用php比较多，因此听闻同样使着php的facebook讲memcached，有些小小的感触，记录下来。
更高效的序列化函数
php有两个memcache扩展，默认都是使用php自带的序列化函数serialize来存储数组或对象。但是serialize最为人诟病的就是速度慢，序列化之后占用空间大。由于facebook已经在memcached里保存了200T字节的数据，因此序列化函数即便作出的百分之一的优化对它来说都是个不小的收益。他们发粪涂墙在thrift的binary协议基础上搞出了一个fb_serialize，据称这个序列化方法能快上3倍，快倒算了，还能节省30%空间， 200T字节的数据能节省出30%，简直就是传说中的银弹啊，这让php官方的开发人员们情何以堪？

				<span class="readmore"><a href="http://www.ooso.net/archives/558" title="关于“facebook的memcached实战”小记">阅读全文（1275字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>上周挤到QCon的会场里，听了两场 —— Facebook的<a href="/tag/memcache">Memcached</a>实战，以及Twitter 的可伸缩性数据架构。当时对facebook超大规模使用memcached印象很深刻，只可惜到现在也没见到这个的ppt。平时用php比较多，因此听闻同样使着php的facebook讲memcached，有些小小的感触，记录下来。</p>
<h2>更高效的序列化函数</h2>
<p>php有两个memcache扩展，默认都是使用php自带的序列化函数serialize来存储数组或对象。但是serialize最为人诟病的就是速度慢，序列化之后占用空间大。由于facebook已经在memcached里保存了200T字节的数据，因此序列化函数即便作出的百分之一的优化对它来说都是个不小的收益。他们发粪涂墙在thrift的binary协议基础上搞出了一个fb_serialize，据称这个序列化方法能快上3倍，快倒算了，还能节省30%空间， 200T字节的数据能节省出30%，简直就是传说中的银弹啊，这让php官方的开发人员们情何以堪？</p>
<p>facebook目前已经开源了thrift，其中自带了一个thrift协议的php扩展，但是这些代码里没有找到传说中的fb_serialize，我倒是从最近他们放出来<a href="http://github.com/facebook/hiphop-php">hiphop-php</a>里找到了这部分代码，哪位大侠去扒拉扒拉弄出来做成php扩展造福广大群众？</p>
<p>作为备选方案，我推荐<a href="/archives/538">igbinary</a>，这也是一个binary的序列化方法。在上次的测试结果中，它甚至能节约50%的存储空间，速度也是稳超php原生的序列化方法，搞不好facebook换了这个序列化方法能省下更多的内存来？</p>
<p>节约每个item的存储空间有什么好处？我个人认为一个是省钱，另外一个就是能够带来速度上的提升。我们平常碰到稍大一点的item都得用gzip压的妥妥贴贴的才送到memcached里，网络传输的开销小了，这是实实在在的性能提升。何乐而不为？</p>
<h2>mcproxy</h2>
<p>mcproxy = memcached + proxy。facebook的机房遍布各洲，利用mcproxy来进行跨机房的同步或分发，全球制霸，指着太阳就能等到那天了。一般的互联网企业还真用不上这玩意，规模还没上去的时候，这些乱七八糟的只会拖后腿。facebook还没开源mcproxy，但是我找到两个替代品：</p>
<ol>
<ul>
<li><a href="http://code.google.com/p/memagent/">memagent</a> is a simple but useful proxy program for memcached servers. </li>
<li><a href="http://code.google.com/p/moxi/">moxi</a> = memcached + integrated proxy</li>
</ul>
</ol>
<p>从项目描述来看，moxi最接近facebook介绍的mcproxy，成熟度也比较高。</p>
<h2>数据的一致性</h2>
<p>Marc Kwiatkowski在会场上用大篇幅的ppt和大量的动画来阐述这个问题，他们用了很多额外的手段来解决在跨机房情况下因为延时问题造成的脏数据。这一段看着挺晕，但是我们联想到facebook用到的多级cache技术: 本地全局变量 + apc + memcache，不难理解这样做颇有些道理，这相当于用memcache实现了一个版本控制系统。</p>
<p>我还是很晕这段ppt。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/558/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>关于改善xhprof使用情况的设想</title>
		<link>http://www.ooso.net/archives/557</link>
		<comments>http://www.ooso.net/archives/557#comments</comments>
		<pubDate>Fri, 23 Apr 2010 00:58:29 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=557</guid>
		<description><![CDATA[自从去年将xhprof用在生产环境以来，对生产环境的程序调试，性能优化都带来很多便利。但是在使用过程中，还是有一些细节需要改善。
问题



				<span class="readmore"><a href="http://www.ooso.net/archives/557" title="关于改善xhprof使用情况的设想">阅读全文（963字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>自从去年<a href="http://www.ooso.net/archives/522">将xhprof用在生产环境</a>以来，对生产环境的程序调试，性能优化都带来很多便利。但是在使用过程中，还是有一些细节需要改善。</p>
<h2>问题</h2>
<ol>
<ul>
<li>xhprof的profile日志直接以文件形式保存在生产服务器上，需要定时清理，或者收集起来移动到查看日志的工具机上。</li>
<li>由于xhprof生成的profile是一个大数组，所以保存到文件时使用了标准的php serialize，日志文件偏大，一个不留神就容易占用很多服务器磁盘空间。</li>
<li>查看日志列表时，一个个点开查看比较费劲。</li>
</ul>
</ol>
<p>针对这几个问题，我有一些小小的设想。</p>
<h2>日志存放</h2>
<p>部署一个中央日志服务器，采用facebook的<a href="http://github.com/facebook/scribe">scribe</a>来收集日志。生产环境的服务器产生的xhprof日志，都写入到scribe的客户端，由客户端自动同步到中央日志服务器的scribe上，不占用本地的存储空间。在代码上的改动也比较小，只要基于iXHProfRuns接口实现一个XhprofRuns类，调整save_run方法的存储方式即可。</p>
<h2>更换序列化方法</h2>
<p>xhprof默认是将profile信息用php原生的序列化方法处理后进行保存，而我在前两天比较过<a href="http://www.ooso.net/archives/538">igbinary vs serialize vs json_encode</a>的性能和占用字节数，这个测试里igbinary在各方面都有一定优势，尤其是占用存储空间会大幅度减小，所以我只要更换序列化方法为igbinary_serialize即可获得改善。</p>
<h2>优化列表展示</h2>
<p>我已经厌倦挨个查看profile日志的大图，费时费力还没有针对性。所以我现在的做法是，在profile日志的列表中将前1000个日志的总体执行时间直接输出到列表中，并且将执行时间过长的日志用红色粗体标识。做了这个小小的改动之后，当我想要去视察一下运行情况时，就把日志列表中那些红通通的链接点开看看就行了，真正的省时省力。</p>
<p>如何从xhprof日志文件中获取执行时间？简单的代码如下</p>
<pre><code>/**
 * 由xhprof日志获得执行时间
 *
 * @param string $log xhprof日志的文件路径
 * @return int 执行时间
 */
function getSpentTime($log) {
  $profile = unserialize(file_get_contents($log));
  return $profile['main()']['wt'] / 1000;
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/557/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>igbinary vs serialize vs json_encode</title>
		<link>http://www.ooso.net/archives/538</link>
		<comments>http://www.ooso.net/archives/538#comments</comments>
		<pubDate>Sun, 18 Apr 2010 15:01:58 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[memcache]]></category>

		<guid isPermaLink="false">http://www.ooso.net/archives/538</guid>
		<description><![CDATA[最近看到memcached扩展支持额外的序列化方式 &#8212; igbinary，这是一个未收录到pecl的php扩展，它提供的两个主要方法：


igbinary_serialize

				<span class="readmore"><a href="http://www.ooso.net/archives/538" title="igbinary vs serialize vs json_encode">阅读全文（1557字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>最近看到<a href="http://pecl.php.net/memcached">memcached</a>扩展支持额外的序列化方式 &#8212; <a href="http://github.com/phadej/igbinary">igbinary</a>，这是一个未收录到pecl的php扩展，它提供的两个主要方法：
<ol>
<ul>
<li>igbinary_serialize</li>
<li>igbinary_unserialize</li>
</ul>
</ol>
<p>据称可以用它来代替php自带的序列化函数serialize，性能更好，而且占用的字节数也更少。下面我就 igbinary ，serialize ，json_encode三者的性能做了一个简单的测试。</p>
<h2>测试</h2>
<p>以一个包含1000000个元素的数组做为原始数据，分别以json, serialize, igbinary进行序列化和反向操作。</p>
<pre><code>&lt;?php
ini_set('memory_limit', '512m');
$array = array_fill(0, 1000000, rand(1, 9999));

$start = microtime(true);
$export = json_encode($array);
$end = microtime(true);
$duration = $end - $start;
print('JSON Encode: ' . $duration . PHP_EOL);

$start = microtime(true);
$import = json_decode($export);
$end = microtime(true);
$duration = $end - $start;
print('JSON Decode: ' . $duration . PHP_EOL);

$start = microtime(true);
$export = serialize($array);
$end = microtime(true);
$duration = $end - $start;
print('Serialize: ' . $duration . PHP_EOL);

$start = microtime(true);
$import = unserialize($export);
$end = microtime(true);
$duration = $end - $start;
print('Serialize: ' . $duration . PHP_EOL);

$start = microtime(true);
$export = igbinary_serialize($array);
$end = microtime(true);
$duration = $end - $start;
print('Igbinary Serialize: ' . $duration . PHP_EOL);

$start = microtime(true);
$import = igbinary_unserialize($export);
$end = microtime(true);
$duration = $end - $start;
print('Igbinary Serialize: ' . $duration . PHP_EOL);
?&gt;</code></pre>
<h2>测试结果</h2>
<blockquote><p>JSON Encode: 0.084825992584229<br />
JSON Decode: 0.34976410865784<br />
Serialize: 0.38241410255432<br />
Serialize: 7.7904229164124<br />
Igbinary Serialize: 0.046916007995605<br />
Igbinary Serialize: 0.23396801948547</p></blockquote>
<p>从测试结果来看，速度方面优先级排列为 igbinary > json > serialize。同时我们也可以看到，<a href="/tag/php">php</a>原生的serialize在对大对象进行反向操作时，速度真是掉队一大截了。</p>
<p>占用字节数对比</p>
<ol>
<ul>
<li>json: 5000001</li>
<li>serialize: 15888902</li>
<li>igbinary: 7868681</li>
</ul>
</ol>
<p>在没有中文字符的情况下，json胜出，igbinary次之，serialize又被甩了几条街。</p>
<h2>一图顶千言</h2>
<p>柱状图越矮小的性能越好<br />
<img src="http://chart.apis.google.com/chart?cht=bvg&#038;chdl=json|serialize|igbinary&#038;chco=ff0000%2C00ff00%2C0000ff&#038;chs=600x300&#038;chxl=0%3A|Export|Import|1%3A|0|1|2|3|4|5|6|7|8|9|10&#038;chxt=x%2Cy&#038;chbh=25%2C1%2C25&#038;chds=0%2C10%2C0%2C10%2C0%2C10&#038;chd=t%3A0.084%2C0.349|0.382%2C7.79|0.047%2C0.234" alt="igbinary vs serialize vs json_encode 速度比较" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/538/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>试着开源LiteCloud项目</title>
		<link>http://www.ooso.net/archives/554</link>
		<comments>http://www.ooso.net/archives/554#comments</comments>
		<pubDate>Mon, 15 Mar 2010 15:47:32 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[litecloud]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[tokyocabinet]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=554</guid>
		<description><![CDATA[所谓LiteCloud，无非就是前些天提到的LightCloud的php版本实现。这个和原来的python版本有一些区别，会造成不兼容，如下：


把Consistent Hashing算法换成了ketama，在pecl的memcached扩展里有简单方法可以实现，效率比单纯的php好很多，能快个10倍吧。没有重复造轮子，因此我很是得意。

				<span class="readmore"><a href="http://www.ooso.net/archives/554" title="试着开源LiteCloud项目">阅读全文（1844字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>所谓LiteCloud，无非就是<a href="http://www.ooso.net/archives/549">前些天提到的LightCloud</a>的php版本实现。这个和原来的python版本有一些区别，会造成不兼容，如下：</p>
<ul>
<ol>
<li>把Consistent Hashing算法换成了ketama，在pecl的memcached扩展里有简单方法可以实现，效率比单纯的php好很多，能快个10倍吧。没有重复造轮子，因此我很是得意。</li>
<li>静态方法调用时，不再支持原来的system参数，原版是用这个来支持多个LiteCloud集群。</li>
<li>第一个版本，利用memcached扩展来读取tokyo tyrant，所以目前仅支持简单的操作比如get, set, delete, increment。其实再努力一下，也可以支持更多的功能，比如redis。</li>
<li>去掉了原版的local_cache功能，我觉得这个功能完全可以放在外面，更灵活。</li>
</ol>
</ul>
<h2>项目主页</h2>
<p>目前托管在github上 —— <a href="http://github.com/volca/litecloud">LiteCloud</a> ，使用<a href="/tag/git">git</a>以及github的时间不太长，但是很喜欢，欢迎fork。</p>
<h2>使用示例</h2>
<p>用静态方法调用:</p>
<pre><code>require 'LiteCloud.php';

$config = array(
    'lookup1_A' =&gt; '127.0.0.1:41201',
    'lookup1_B' =&gt; '127.0.0.1:51201',

    'storage1_A' =&gt; '127.0.0.1:44201',
    'storage1_B' =&gt; '127.0.0.1:54201',
);

list($lookupNodes, $storageNodes) = LiteCloud::generateNodes($config);
LiteCloud::init($lookupNodes, $storageNodes);

LiteCloud::set('hello', 'world');
print LiteCloud::get("hello"); # =&gt; world
LiteCloud::delete("hello");

print LiteCloud::get("hello"); # =&gt; nil</code></pre>
<p>或者采用实例化的方式调用，这种方式能够支持多个LightCloud集群</p>
<pre><code>require 'LiteCloud.php';

$config = array(
    'lookup1_A' =&gt; '127.0.0.1:41201',
    'lookup1_B' =&gt; '127.0.0.1:51201',

    'storage1_A' =&gt; '127.0.0.1:44201',
    'storage1_B' =&gt; '127.0.0.1:54201',
);

$cloud = new LiteCloud($config);

$cloud-&gt;set('hello', 'world');
print $cloud-&gt;get("hello"); # =&gt; world
$cloud-&gt;delete("hello");

print $cloud-&gt;get("hello"); # =&gt; nil</code></pre>
<p>看上去和python版本差不多，对吧？</p>
<h2>性能测试</h2>
<p>这个部分是个重点，之前找到的lightcloud的php版本，性能比原版要慢一个数量级，我可不想在这个地方丢了份。</p>
<p>暂时做了个最简单的性能测试，测试脚本在test目录下。测试条件如下:</p>
<ul>
<ol>
<li>底层采用tokyo tyrant作为存储。</li>
<li>单个进程重复操作一万次，比如写一万次hello => world，这个测试条件和python版本完全一致</li>
<li>关闭了local_cache</li>
</ol>
</ul>
<h3>python版本的测试结果</h3>
<pre><code>Finished "Tyrant set" 10000 times in 2.50 sec [4002.0 operations pr.sec]
Finished "Tyrant get" 10000 times in 1.04 sec [9583.7 operations pr.sec]
Finished "Tyrant delete" 10000 times in 7.39 sec [1352.4 operations pr.sec]</code></pre>
<h3>LiteCloud的测试结果</h3>
<pre><code>Using 1.8229308128357 time to set 10000 values. QPS:5485.67
Using 0.71097207069397 time to get 10000 values. QPS:14065.25
Using 2.1550960540771 time to delete 10000 values. QPS:4640.16</code></pre>
<p>看上去还比较乐观，尤其是delete的性能翻了好几番，几乎要怀疑我在代码实现部分出了差错，在其它方面的表现也是全面超出，因为python版在hash_ring的实现上拖了后腿。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/554/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>使用nginx做为hiphop-php的前端服务器</title>
		<link>http://www.ooso.net/archives/545</link>
		<comments>http://www.ooso.net/archives/545#comments</comments>
		<pubDate>Sat, 27 Feb 2010 23:55:30 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[nginx]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=545</guid>
		<description><![CDATA[在邮件组里看到有人问能不能把多个hiphop-php编译后的程序跑在同一个端口上，想想也是合理的要求。如果一个服务器上跑了多个站点，那肯定都得用80端口，当大家共同租用服务器的时候，这个需求更为强烈。当时我所想到的解决办法是在前面搭个nginx之类的做代理，实际编译后的程序跑在别的端口，然后没过几天就看到了这份wiki &#8211; Using nginx as front server to HipHop。
简单的nginx配置示例
/etc/nginx/conf.d/ooso.conf:

				<span class="readmore"><a href="http://www.ooso.net/archives/545" title="使用nginx做为hiphop-php的前端服务器">阅读全文（813字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>在邮件组里看到有人问能不能把多个hiphop-php编译后的程序跑在同一个端口上，想想也是合理的要求。如果一个服务器上跑了多个站点，那肯定都得用80端口，当大家共同租用服务器的时候，这个需求更为强烈。当时我所想到的解决办法是在前面搭个<a href="/?tag=nginx">nginx</a>之类的做代理，实际编译后的程序跑在别的端口，然后没过几天就看到了这份wiki &#8211; <a href="http://wiki.github.com/facebook/hiphop-php/using-nginx-as-front-server-to-hiphop">Using nginx as front server to HipHop</a>。</p>
<h2>简单的nginx配置示例</h2>
<p>/etc/nginx/conf.d/ooso.conf:</p>
<pre><code>server {
        listen *:80;
        server_name *.ooso.net ooso.net;

       location / {
           root   __SERVER_ROOT__;
           index  index.html index.php index.htm;
       }

       location ~ \.php$ {
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header Host www.ooso.net;
        proxy_pass   http://localhost:4247;
      }
}</code></pre>
<p>把hiphop-php编译后的代码跑在4247端口，然后通过nginx把所有对php的请求转发到这个端口，看上去就像我们平常配置的php fastcgi，不是吗？</p>
<h2>这样做有什么好处</h2>
<ul>
<li>支持负载均衡</li>
<li>支持ssl</li>
<li>支持gzip压缩</li>
<li>用nginx来挡住DoS攻击</li>
<li>因为我们的代码需要经过编译才能上线，代码多起来这个时间还真不短，不能像之前单纯的php那样爽快覆盖就完事。把经过编译的最新代码部署在别的端口上，用nginx快速切换，应该是一个比较实际的用法。</li>
</ul>
<h2>额外的技巧</h2>
<p>看wiki学到的额外技巧。以下配置段可以防止某些人把别的垃圾域名指向你的主机，结果被搜索引擎认为你用多个域名搞了一堆重复的内容建设，降低搜索权重。</p>
<pre><code>server {
    listen *:80;
    server_name _;

	location / {
		deny all;
	}
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/545/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>快速安装hiphop-php的捷径</title>
		<link>http://www.ooso.net/archives/543</link>
		<comments>http://www.ooso.net/archives/543#comments</comments>
		<pubDate>Sun, 21 Feb 2010 10:55:15 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[rpm]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=543</guid>
		<description><![CDATA[不得不说，现在安装hiphop-php实在是太麻烦了，如果有rpm包一次搞定那该多好？就说周边那些零散的依赖库，也有不少安装比较繁琐的硬骨头。
Centos用户的好消息
Update: 在centos 64位机上完全通过rpm安装hiphop-php的步骤也已经提供了。
在邮件组上看到有人提供了centos下安装hiphop相关的rpm列表，把这些rpm装好，再按照wiki上专心编译hiphop即可。也许再过一阵，就会有人直接提供hiphop的rpm包，那就彻底方便了。

				<span class="readmore"><a href="http://www.ooso.net/archives/543" title="快速安装hiphop-php的捷径">阅读全文（818字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>不得不说，现在安装hiphop-php实在是太麻烦了，如果有rpm包一次搞定那该多好？就说周边那些零散的依赖库，也有不少安装比较繁琐的硬骨头。</p>
<h2>Centos用户的好消息</h2>
<p><strong>Update</strong>: <a href="http://wiki.github.com/facebook/hiphop-php/installing-or-building-hiphop-php-via-rpm-on-centos-5">在centos 64位机上完全通过rpm安装hiphop-php的步骤</a>也已经提供了。</p>
<p>在邮件组上看到有人提供了<a href="http://github.com/johnwyles/hiphop-rpm-centos/downloads">centos下安装hiphop相关的rpm列表</a>，把这些<a href="/?tag=rpm">rpm</a>装好，再按照wiki上专心编译hiphop即可。也许再过一阵，就会有人直接提供hiphop的rpm包，那就彻底方便了。</p>
<p>rpm列表</p>
<ol>
<ul>
<li>libicu42-4.2.1-1.x86_64.rpm</li>
<li>libicu-devel-4.2.1-1.x86_64.rpm </li>
<li>icu-debuginfo-4.2.1-1.x86_64.rpm </li>
<li>icu-4.2.1-1.x86_64.rpm 		</li>
<li>libcurl4-devel-7.20.0-1.x86_64.rpm </li>
<li>libcurl4-7.20.0-1.x86_64.rpm 	</li>
<li>curl-debuginfo-7.20.0-1.x86_64.rpm</li>
<li>curl-7.20.0-1.x86_64.rpm 	</li>
<li>libevent-1.4.13-1.x86_64.rpm 	</li>
<li>boost-devel-1_37_0-1.x86_64.rpm </li>
<li>boost-debuginfo-1_37_0-1.x86_64.rpm</li>
<li>boost-1_37_0-1.x86_64.rpm 	</li>
<li>cmake-2.6.4-7.el5.x86_64.rpm</li>
</ul>
</ol>
<h2>Ubuntu 9.10用户的安装指南</h2>
<p><a href="http://wiki.github.com/facebook/hiphop-php/building-and-installing-on-ubuntu-910">Building and Installing on Ubuntu 9.10</a></p>
<p>看起来还是ubuntu用户最清爽。</p>
<p><strong>注：如果使用了32bit的ubuntu，请使用<a href="http://github.com/metagoto/hiphop-php">patch过的hiphop-php</a>进行编译。</strong></p>
<h2>Fedora用户的编译步骤</h2>
<p><a href="http://www.ioncannon.net/programming/918/building-hiphop-php-for-fedora-12-on-64-bit-and-32-bit-systems/">Building HipHop PHP for Fedora 12 on 64 bit and 32 bit Systems</a></p>
<p><del datetime="2010-02-24T13:02:52+00:00">BTW: 目前hiphop-php仅支持64位操作系统。</del></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/543/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>初次体验hiphop-php</title>
		<link>http://www.ooso.net/archives/541</link>
		<comments>http://www.ooso.net/archives/541#comments</comments>
		<pubDate>Sun, 21 Feb 2010 02:19:22 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[facebook]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=541</guid>
		<description><![CDATA[昨天facebook在github上发布了hiphop-php的源代码。之前听说这玩意能把php代码翻译成c++代码，然后带来巨大的性能提升，所以第一时间编译了一份hiphop-php。
我的机器环境是

Centos 5.3 x86_64

				<span class="readmore"><a href="http://www.ooso.net/archives/541" title="初次体验hiphop-php">阅读全文（1052字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>昨天facebook在<a href="http://github.com/facebook/hiphop-php">github</a>上发布了hiphop-php的源代码。之前听说这玩意能把php代码翻译成c++代码，然后带来巨大的性能提升，所以第一时间编译了一份hiphop-php。</p>
<h2>我的机器环境是</h2>
<ul>
<li>Centos 5.3 x86_64</li>
<li>8G内存</li>
<li>Intel(R) Xeon(R) CPU E5420  @ 2.50GHz</li>
</ul>
<h2>安装注意事项</h2>
<p>编译的时候碰到的问题很多，但是基本上都是按照<a href="http://wiki.github.com/facebook/hiphop-php/building-and-installing">wiki上的步骤</a>进行的。我觉得比较重要的几点：</p>
<ul>
<li>wiki上的Required Packages包包列表都要检查一遍，比如版本号，是否安装过，像binutils-dev这种就很容易忽略</li>
<li>版本符合的话，直接用yum安装这些包就可以了</li>
<li>wiki上有类似Boost 1.37 is the minimum version字样，说明开发者可能就是在这个版本下开发的，我试了下最新版本的boost，编译到后来反而出错</li>
<li>如果yum上没有符合版本的lib库，可以手动编译，但是编译时建议就放在自己的home下，比如：
<pre><code>./configure --prefix=/home/user</code></pre>
</li>
<li>tbb Intel’s Thread Building Blocks这个包有些麻烦，记得按照wiki上说的步骤安装</li>
</ul>
<h2>测试hiphop-php</h2>
<p>安装完成之后，时间也不是太多，所以我仅仅是简单的测试了一个<a href="/?tag=php">php</a>文件，代码如下：</p>
<pre><code>&lt;?php
$i = 0;
for($j = 0; $j &lt; 1000000; $j++)
        $i += $j;

echo $i, "\n";
?&gt;</code></pre>
<p>用hphp进行编译:</p>
<pre><code>hphp/hphp test.php --keep-tempdir=1 --log=3</code></pre>
<p>提示生成新的可执行文件</p>
<pre><code>/tmp/hphp_c9sbnG/program</code></pre>
<p>做一下运行时间对比：</p>
<pre><code>$ time php test.php
499999500000

real    0m0.307s
user    0m0.299s
sys     0m0.007s

$ time /tmp/hphp_c9sbnG/program
499999500000

real    0m0.259s
user    0m0.194s
sys     0m0.008s</code></pre>
<p>没看出来编译成c++代码之后有太大的性能提升，估计是俺的使用手法问题？在邮件组里观察几天再说。</p>
<h2>Update</h2>
<p>facebook将优化之后的编译参数提交到了github，于是我重新编译并测试一遍这段相同的代码：</p>
<pre><code>$ time /tmp/hphp_c9sbnG/program
499999500000

real    0m0.140s
user    0m0.076s
sys     0m0.006s</code></pre>
<p>可以看到，经hiphop编译后的php，执行时间几乎快了一倍。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/541/feed</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>快速创建pear/pecl的rpm</title>
		<link>http://www.ooso.net/archives/535</link>
		<comments>http://www.ooso.net/archives/535#comments</comments>
		<pubDate>Mon, 04 Jan 2010 04:32:41 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[rpm]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=535</guid>
		<description><![CDATA[目前使用的服务器为centos，使用yum以及rpm来维护系统好处多多：


安装卸载，升级rpm软件包只需一条命令即可

				<span class="readmore"><a href="http://www.ooso.net/archives/535" title="快速创建pear/pecl的rpm">阅读全文（535字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>目前使用的服务器为centos，使用yum以及rpm来维护系统好处多多：</p>
<ol>
<ul>
<li>安装卸载，升级rpm软件包只需一条命令即可</li>
<li>统一部署，便于维护</li>
<li>比手工编译的方式要快</li>
</ul>
</ol>
<p>于是我需要把日常使用到的一些php扩展做成rpm包，但是手工写spec文件比较繁琐，因此<a href="/?tag=pear">pear</a>的这个小工具<a href="http://pear.php.net/package/PEAR_Command_Packaging">PEAR_Command_Packaging</a>帮了不少忙。它会给pear工具新增一个选项：</p>
<pre><code>pear make-rpm-spec [options] &lt;package-file&gt;</code></pre>
<p>这个命令行将会创建一个rpm的.spec文件，包含指定pear包的定义，而且也适用于<a href="http://pecl.php.net">pecl</a>的php扩展。</p>
<h2>创建pear rpm包的例子</h2>
<pre><code>$ cd /path/to/rpm-build-tree/SPECS
$ pear make-rpm-spec ../SOURCES/Net_Socket-1.0.tgz
Wrote RPM spec file PEAR::Net_Socket-1.0.spec
$ rpm -bb PEAR::Net_Socket-1.0.spec
...
Wrote: /path/to/rpm-build-tree/RPMS/noarch/PEAR::Net_Socket-1.0-1.noarch.rpm</code></pre>
<h2>关于make-rpm-spec的帮助</h2>
<pre><code>pear help make-rpm-spec</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/535/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>memcache连接慢又一例</title>
		<link>http://www.ooso.net/archives/524</link>
		<comments>http://www.ooso.net/archives/524#comments</comments>
		<pubDate>Tue, 22 Dec 2009 13:56:53 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[memcache]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=524</guid>
		<description><![CDATA[继上次解决memcache连接慢问题以来，好长一段时间没在这个问题上翻过跟头。这一次我又在生产环境观察到php和memcache的连接时间经常会在50ms以上。
作为一个cache，占用了这么长的执行时间，天理何在？
实际的运行环境如下：


				<span class="readmore"><a href="http://www.ooso.net/archives/524" title="memcache连接慢又一例">阅读全文（699字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>继<a href="http://www.ooso.net/archives/479">上次解决memcache连接慢问题</a>以来，好长一段时间没在这个问题上翻过跟头。这一次我又在生产环境观察到php和memcache的连接时间经常会在50ms以上。</p>
<p>作为一个cache，占用了这么长的执行时间，天理何在？</p>
<p>实际的运行环境如下：</p>
<ol>
<ul>
<li>apache + mod_php</li>
<li><a href="http://pecl.php.net/memcache">php-memcache扩展</a>版本为2.2.5</li>
<li>memcache的并发连接数在400左右，相当少</li>
</ul>
</ol>
<p>这次memcache扩展用的是最新的稳定版，无可挑剔。所以刚开始我认为是网络环境的问题，于是直接采用telnet工具直连<a href="/?tag=memcache">memcache</a>进行测试，发现速度飞快！一点便秘感都没有！所以把目光仍然放回到memcache扩展上来，集中对比较慢的addServer方法各项参数进行排查。</p>
<h2>Memcache::addServer方法</h2>
<pre><code>bool Memcache::addServer  ( string $host  [, int $port = 11211  [, bool $persistent  [, int $weight  [, int $timeout  [, int $retry_interval  [, bool $status  [, callback $failure_callback  [, int $timeoutms  ]]]]]]]] )</code></pre>
<p>比对结果表明，$weight参数对memcache的连接时间有显著的影响，$weight的默认值为1，一旦设置为别的数值，连接时间便会由毫秒级变成50ms左右，立竿见影。</p>
<p>鉴于php-memcache扩展一贯恶劣的表现，俺不得不痛下决心迁移到新的<a href="http://pecl.php.net/memcached">memcached扩展</a>上。memcached扩展基于libmemcached开发，而且提供了丰富的接口方法，应该是更好的选择。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/524/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>php的echo为什么这么慢</title>
		<link>http://www.ooso.net/archives/517</link>
		<comments>http://www.ooso.net/archives/517#comments</comments>
		<pubDate>Tue, 15 Dec 2009 13:38:09 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=517</guid>
		<description><![CDATA[作为一个行走江湖多年的老中医，今天受命去解决一例前端页面展现缓慢的问题。问题页的情况如下：


apache + php

				<span class="readmore"><a href="http://www.ooso.net/archives/517" title="php的echo为什么这么慢">阅读全文（820字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>作为一个行走江湖多年的老中医，今天受命去解决一例前端页面展现缓慢的问题。问题页的情况如下：</p>
<ol>
<ul>
<li>apache + php</li>
<li>使用smarty模板输出内容</li>
<li>页面最终输出内容较大，80k+</li>
<li>页面执行时间在500ms以上</li>
</ul>
</ol>
<p>祭出法宝<a href="/archives/522">xhprof</a>对问题页面做了细致检查，发现页面的瓶颈竟然是模板（编译后的）中的一个echo语句，这个echo语句输出的字符串比较大，大概是50k+字节，花费时间为400多毫秒，占整个页面执行时间的80%。这样的echo输出在站点首页中其实是很常见的事情，没有数据库操作，按道理执行时间不应该这么长。</p>
<p>于是猛力使用搜索技能，最终在<a href="http://www.php.net/manual/en/function.echo.php#28843" href="_blank">php手册的echo部分</a>找到了一些蛛丝马迹，早在2003年就有前辈认为通过echo输出大字符串到客户端会引起服务器的性能问题，据我测试，在这个场景下使用print其实也是一样的慢。建议的解决办法是把字符串切割成更小的字符串输出，展现速度会有提升，输出函数如下：</p>
<pre><code>&lt;?php
function echobig($string, $bufferSize = 8192) {
    $splitString = str_split($string, $bufferSize);
    foreach($splitString as $chunk)
        echo $chunk;
}
?&gt;</code></pre>
<p>但是上面的处方不太对症，整个echobig的输出时间仍然在400毫秒左右，没有太大改善。</p>
<p>考虑到是输出大量内容到客户端比较慢，于是检查了apache的配置，原来还没打开deflate进行压缩，遂启用之。再次使用xhprof进行检查，这条echo的输出时间降低到5ms左右。</p>
<p>400ms到5ms，一个配置问题会产生80倍的差距，还真是省老钱了。这个故事告诉我们，<strong>压缩输出真的很重要。</strong></p>
<h2>Update</h2>
<p>实际上这个问题也可以通过调整webserver的output buffer来解决一部分，参考：</p>
<ul>
<li><a href="http://fplanque.com/dev/linux/why-echo-is-slow-in-php-how-to-make-it-really-fast">Why echo is slow in PHP and how to make it really fast</a></li>
<li><a href="http://www.laruence.com/2011/02/13/1870.html">加速PHP的ECHO</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/517/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>在生产环境中使用php性能测试工具xhprof</title>
		<link>http://www.ooso.net/archives/522</link>
		<comments>http://www.ooso.net/archives/522#comments</comments>
		<pubDate>Wed, 05 Aug 2009 14:01:00 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=522</guid>
		<description><![CDATA[xhprof是facebook开源出来的一个php性能测试工具，也可以称之为profile工具，这个词不知道怎么翻译才比较达意。跟之前一直使用的xdebug相比，有很多类似之处。以前对xdebug有一些记录还可以供参考，但是它的缺点是对性能影响太大，即便是开启了profiler_enable_trigger参数，用在生产环境中也是惨不忍睹，cpu立刻就飙到high。
而xhprof就显得很轻量，是否记录profile可以由程序控制，因此，用在生产环境中也就成为一种可能。在它的文档上可以看到这样一种用法：

				<span class="readmore"><a href="http://www.ooso.net/archives/522" title="在生产环境中使用php性能测试工具xhprof">阅读全文（782字）</a></span>]]></description>
			<content:encoded><![CDATA[<p><a href="http://mirror.facebook.net/facebook/xhprof/doc.html">xhprof</a>是facebook开源出来的一个php性能测试工具，也可以称之为profile工具，这个词不知道怎么翻译才比较达意。跟之前一直使用的xdebug相比，有很多类似之处。以前<a href="http://www.ooso.net/archives/359">对xdebug有一些记录还可以供参考</a>，但是它的缺点是对性能影响太大，即便是开启了profiler_enable_trigger参数，用在生产环境中也是惨不忍睹，cpu立刻就飙到high。</p>
<p>而xhprof就显得很轻量，是否记录profile可以由程序控制，因此，用在生产环境中也就成为一种可能。在它的文档上可以看到这样一种用法：</p>
<p>以万分之一的几率启用xhprof，平时悄悄的不打枪。</p>
<pre><code>if (mt_rand(1, 10000) == 1) {
 xhprof_enable(XHPROF_FLAGS_MEMORY);
 $xhprof_on = true;
}</code></pre>
<p>在程序结尾处调用方法保存profile</p>
<pre><code>if ($xhprof_on) {
 // stop profiler
 $xhprof_data = xhprof_disable();

 // save $xhprof_data somewhere (say a central DB)
 ...
}</code></pre>
<p>也可以用register_shutdown_function方法指定在程序结束时保存xhprof信息，这样就免去了结尾处判断，给个改写的不完整例子：</p>
<pre><code>if (mt_rand(1, 10000) == 1) {
 xhprof_enable(XHPROF_FLAGS_MEMORY);
 register_shutdown_function(create_funcion('', "$xhprof_data = xhprof_disable(); save $xhprof_data;"));
}</code></pre>
<p>至于日志，我暂时用的是最土的文件形式保存，定期清除即可。</p>
<p>BTW:xhprof生成的图形方式profile真是酷毙了，哪段代码成为瓶颈，一目了然。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/522/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>启用memcached压缩注意事项</title>
		<link>http://www.ooso.net/archives/475</link>
		<comments>http://www.ooso.net/archives/475#comments</comments>
		<pubDate>Wed, 13 May 2009 23:56:05 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[memcache]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=475</guid>
		<description><![CDATA[在php开发中，开启memcache的数据压缩存储是一件很简单的事情。在多数情况下，压缩数据不仅不会降低程序的执行效率，反倒会因为网络传输的开销降低，带来速度提升。看看最常用的Memcache::set方法:
bool Memcache::set  ( string $key  , mixed $var  [, int $flag  [, int $expire  ]] )
在这个方法中，将$flag设置为MEMCACHE_COMPRESSED即可启用memcache压缩存储。
这样做有什么弊端？

				<span class="readmore"><a href="http://www.ooso.net/archives/475" title="启用memcached压缩注意事项">阅读全文（1146字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>在php开发中，开启<a href="/?tag=memcache">memcache</a>的数据压缩存储是一件很简单的事情。在多数情况下，压缩数据不仅不会降低程序的执行效率，反倒会因为网络传输的开销降低，带来速度提升。看看最常用的Memcache::set方法:</p>
<pre><code>bool Memcache::set  ( string $key  , mixed $var  [, int $flag  [, int $expire  ]] )</code></pre>
<p>在这个方法中，将$flag设置为MEMCACHE_COMPRESSED即可启用memcache压缩存储。</p>
<h3>这样做有什么弊端？</h3>
<p>如果没有做额外判断，每一次写入memcache都会启用压缩，不管数据的大小。对应的，每次获得数据都需要做一次解压缩的操作，这是典型的一刀切手法。实际上在数据很小的情况下，不需要压缩，在这个基础上压缩省不了多少空间。</p>
<h3>更好的压缩策略？</h3>
<p>好了，我的想法是在数据超过一定大小（比如2k）的情况下，才开启压缩。这个好办，捋起袖子就干，在调用Memcache::set方法之前，首先判断一下数据的大小，一个strlen就搞定了，再简单不过了。</p>
<pre><code>$memcache = new Memcache;
$memcache-&gt;connect('localhost', 11211);
$flag = strlen($data) &gt; 2048 ? MEMCACHE_COMPRESSED : 0;
$memcache-&gt;set('mykey', $data, $flag);</code></pre>
<p>有人可能会问了，array和object怎么办，这玩意可不能用strlen判断长度。</p>
<p>这还真能难住我一阵子，要知道把array/object写入memcache的时候，php会自动做serialize，再把它当作字符串插入memcache。</p>
<pre><code>$flag = strlen(serialize($data)) &gt; 2048 ? MEMCACHE_COMPRESSED : 0;</code></pre>
<p>谁会采用这段代码？看起来非常山寨，而且serialize也不快，赔本买卖。</p>
<h3>更好的办法！</h3>
<p>上面的文字都是废话，直接看这段就好。<a href="http://cn2.php.net/manual/en/function.memcache-setcompressthreshold.php">Memcache::setCompressThreshold方法</a>可以包办之前所有的逻辑。</p>
<blockquote><p>Memcache::setCompressThreshold — Enable automatic compression of large values</p></blockquote>
<pre><code>bool Memcache::setCompressThreshold  ( int $threshold  [, float $min_savings  ] )</code></pre>
<p>举个例子，下面这段会自动启用压缩策略，当数据大于2k时，以0.2的压缩比进行zlib。</p>
<pre><code>$memcache-&gt;setCompressThreshold(2000, 0.2);</code></pre>
<p>根据我的测试结果，<strong>setCompressThreshold方法会忽略Memcache::set的flag参数</strong>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/475/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>apache的RewriteMap使用心得</title>
		<link>http://www.ooso.net/archives/493</link>
		<comments>http://www.ooso.net/archives/493#comments</comments>
		<pubDate>Thu, 02 Apr 2009 13:57:47 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[apache]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=493</guid>
		<description><![CDATA[在apache的环境下，rewrite还真是生活之友啊，时不时就得用上。前些日子有个需求，要将url重新转一转。
什么情况？
原来的url
http://www.xxx.com/demo/oldpage.php?param1=1&#038;param2=2

				<span class="readmore"><a href="http://www.ooso.net/archives/493" title="apache的RewriteMap使用心得">阅读全文（1311字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>在apache的环境下，rewrite还真是生活之友啊，时不时就得用上。前些日子有个需求，要将url重新转一转。</p>
<h2>什么情况？</h2>
<p>原来的url</p>
<p>http://www.xxx.com<b>/demo/oldpage.php?param1=1&#038;param2=2</b></p>
<p>转换后的url</p>
<p>http://www.xxx.com/newpage.php?url=<b>%2Fdemo%2Fmypage.php%3Fparam1%3D1&#038;param2%3D2</b></p>
<p>需要把粗体部分的url进行urlencode，能看出上面的字符&#8221;?&#038;=&#8221;都分别转义过，作为参数发给另外一个url。那么这时候请出rewrite还真是最合适不过了。</p>
<h2>坎坷的Rewrite经历</h2>
<p>查查rewrite手册，俺这才知道，转义这活，非得派出<a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#mapfunc">RewriteMap的map function</a>才能做的比较漂亮。现在只有四个内部map function可供差遣： </p>
<ul>
<li>toupper: Converts the key to all upper case.</li>
<li>tolower: Converts the key to all lower case.</li>
<li>escape: Translates special characters in the key to hex-encodings.</li>
<li>unescape: Translates hex-encodings in the key back to special characters.</li>
</ul>
<p>那么很快就有了第一个rewrite出现：</p>
<pre><code>RewriteMap escape int:escape
RewriteRule ^/([^/]*)$ /newpage.php?mi_url_suffix=${escape:$1?%{QUERY_STRING}} [L,PT]</code></pre>
<p>注：这里的int不是intger的意思，它是internal的缩写，表示调用内部函数。</p>
<p>看上去非常简单，跑起来貌似也正&#8230;.常？且慢，俺打开RewriteLog一瞅，形式不容乐观啊，&#8221;&#038;&#8221;字符通通没有转义。看来是失败了，爬到狗狗上翻了一下，貌似escape对&#8221;?=&#8221;之类的特殊字符是不做转义的，晕。</p>
<h2>RewriteMap到底</h2>
<p>接着细看apache的rewrite手册，发现RewriteMap还支持自定义脚本，那么还得使出俺的看家绝技——php了。首先弄一个能转义的php，必须非常简单，复杂了apache容易挂掉，写出来发现想复杂都挺难啊：</p>
<p>/usr/local/bin/escape.php</p>
<pre><code>#!/usr/bin/php -f
&lt;?php
while($in = trim(fgets(STDIN)))
        fputs(STDOUT, urlencode($in) . "\r\n");
?&gt;</code></pre>
<p>在这个脚本里可别使用php:://stdin之类的，具体原因查<a href="/category/php">php</a>手册。相应的，rewrite规则如下：</p>
<pre><code>RewriteMap escape prg:/usr/local/bin/escape.php
RewriteRule ^/([^/]*)$ /newpage.php?mi_url_suffix=${escape:$1?%{QUERY_STRING}} [L,PT]</code></pre>
<p>rewrite规则没有太大的改变，prg表示使用自定义脚本。现在这个版本总算正常运作了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/493/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>131个字符的php framework</title>
		<link>http://www.ooso.net/archives/415</link>
		<comments>http://www.ooso.net/archives/415#comments</comments>
		<pubDate>Tue, 10 Mar 2009 06:40:03 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[framework]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=415</guid>
		<description><![CDATA[在friendfeed上看到这个链接 —— The 140 Characters Webapp Challenge!，这个比赛要求用140个字符的代码造就一个web应用。
里头有36个程序可供投票，基本上全是脚本语言大杂烩：php,perl,ruby,javascript。实现的应用也是五花八门，有相册，类twitter，小游戏，甚至还有php代码框架？摘录如下：
require __DIR__.'/c.php';
if (!is_callable($c = @$_GET['c'] ?: function() { echo 'Woah!'; }))

				<span class="readmore"><a href="http://www.ooso.net/archives/415" title="131个字符的php framework">阅读全文（606字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>在<a href="https://friendfeed.com">friendfeed</a>上看到这个链接 —— <a href="http://f055.net/article/final-wrap-up-of-the-140-characters-webapp-challenge/">The 140 Characters Webapp Challenge!</a>，这个比赛要求用140个字符的代码造就一个web应用。</p>
<p>里头有36个程序可供投票，基本上全是脚本语言大杂烩：php,perl,ruby,javascript。实现的应用也是五花八门，有相册，类twitter，小游戏，甚至还有php代码框架？摘录如下：</p>
<pre><code>require __DIR__.'/c.php';
if (!is_callable($c = @$_GET['c'] ?: function() { echo 'Woah!'; }))
        throw new Exception('Error');
$c();</code></pre>
<p>这段代码利用了php5.3的一些新特性：</p>
<ul>
<li>__DIR__</li>
<li>Anonymous functions</li>
<li>?:运算符</li>
</ul>
<p>代码只有131个字符，由于代码极为简陋，安全性也是没得保障的，只能算一个程序的统一入口罢了。</p>
<p>如果用php 5.2来写这段代码，大概就是：</p>
<pre><code>require dirname(__FILE__).'/c.php';
if (!is_callable($c = @$_GET['c'] ? $_GET['c'] : create_function('', "echo 'Woah!';")))
        throw new Exception('Error');
$c();</code></pre>
<p>如果要让这段代码变得实用点，可以在$c前面加上一个前缀，这样安全性会有进一步提升，代码也会相应的增加若干字节。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/415/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>关于smarty3的一些说明</title>
		<link>http://www.ooso.net/archives/476</link>
		<comments>http://www.ooso.net/archives/476#comments</comments>
		<pubDate>Sun, 01 Feb 2009 10:10:16 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://www.ooso.net/?p=476</guid>
		<description><![CDATA[这些天看到了smarty 3 alpha冒头了，于是花时间做了个走访调查。下面的文字基本上来自其readme：
基本文件文件结构

index.php

				<span class="readmore"><a href="http://www.ooso.net/archives/476" title="关于smarty3的一些说明">阅读全文（794字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>这些天看到了<a href="http://www.smarty.net">smarty 3 alpha</a>冒头了，于是花时间做了个走访调查。下面的文字基本上来自其readme：</p>
<h2>基本文件文件结构</h2>
<pre>
index.php
/libs/
  Smarty.class.php 		#主文件
/libs/sysplugins/		#内部plugin
  internal.*
/plugins/			#外部plugin,可自由扩充
  function.mailto.php
  modifier.escape.php
/templates/			#模板，可以是纯php或传统的smarty模板
  index.tpl
  index_view.php
</pre>
<h2>一个经典的smarty调用</h2>
<pre><code>require('Smarty.class.php');
$smarty = new Smarty;
$smarty-&gt;assign('foo','bar');
$smarty-&gt;display('index.tpl');</code></pre>
<p>和之前的版本似乎没什么差别</p>
<h2>SINGLETON</h2>
<p>这个有意义吗？</p>
<pre><code>$smarty = Smarty::instance();</code></pre>
<h2>模板</h2>
<p>之前的smarty模板，相当于重新定义了一套标签语言，那么smarty3提供了一种新的模板形式，直接支持<a href="/?tag=php">php</a>语法的模板。</p>
<p>但是问题就出来了，我们还有必要用模板吗？</p>
<p>引用php类型模板的一个例子：</p>
<pre><code>$smarty-&gt;display('php:mytemplate.tpl');</code></pre>
<p>模板中可以直接使用熟悉的语法： &lt;?=$foo?&gt; &lt;?=$bar?&gt;</p>
<p>使用php类型模板的话，安全问题需要自己解决。但这个对成熟的团队来说不是问题。</p>
<p>除此之外，新支持字符串类型的模板，感觉比较生猛，离模板之路也是渐行渐远：</p>
<pre><code>$smarty-&gt;display('string:This is my template, {$foo}!');</code></pre>
<h2>smarty3的相关链接</h2>
<ul>
<li><a href="http://smarty-php.googlecode.com/svn/branches/Smarty3Alpha/ ">Smarty 3 Alpha with SVN</a> &#8212; 选择googlecode提供的svn服务还是蛮省钱的</li>
<li><a href="http://groups.google.com/group/smarty-developers">smarty 3开发者邮件组</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/476/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>在CentOS / Red Hat下安装PHP 5.x PECL Filter Extension</title>
		<link>http://www.ooso.net/archives/473</link>
		<comments>http://www.ooso.net/archives/473#comments</comments>
		<pubDate>Mon, 27 Oct 2008 08:22:30 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.ooso.net/index.php/archives/473</guid>
		<description><![CDATA[php 5.2之后，默认会装有filter extension，这个扩展可以帮助php开发者过滤用户输入的内容，由php的创始人之一Rasmus Lerdorf提供，可以见我早期的文章介绍。
Q. How do I install filter extension for safely dealing with input parameters supplied via a web form using filter_var()?
A. This extension is part of PHP Core version 5.20 and above. Unfortunately, RHEL / CentOS comes with PHP version 5.1.6. So you need to install this extension by typing the following commands.

				<span class="readmore"><a href="http://www.ooso.net/archives/473" title="在CentOS / Red Hat下安装PHP 5.x PECL Filter Extension">阅读全文（1164字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>php 5.2之后，默认会装有filter extension，这个扩展可以帮助php开发者过滤用户输入的内容，由php的创始人之一Rasmus Lerdorf提供，可以见我<a href="/index.php/archives/202">早期的文章介绍</a>。</p>
<blockquote><p>Q. How do I install filter extension for safely dealing with input parameters supplied via a web form using filter_var()?<br />
A. This extension is part of PHP Core version 5.20 and above. Unfortunately, RHEL / CentOS comes with PHP version 5.1.6. So you need to install this extension by typing the following commands.</p></blockquote>
<p>由于RHEL / CentOS自带的php版本是5.1.6，那么只好手工安装filter扩展。安装过程：</p>
<h2>安装php-devel</h2>
<p>为了编译php extensions，需要安装php-devel包:</p>
<pre><code># yum install php-devel</code></pre>
<h2>下载php的源码</h2>
<p>php 5.1.6的源码树中没有包含php_pcre.h header文件, 所以需要另行下载一个php源码. 从php.net下载最新版本的源码并放到/opt目录:</p>
<pre><code># cd /opt
# elinks http://cn2.php.net/get/php-5.2.6.tar.bz2/from/cn.php.net/mirror</code></pre>
<p>保存之后解压:</p>
<pre><code># tar -jxvf php-5.2.6.tar.bz2</code></pre>
<h2>下载filter extension</h2>
<p>在<a href="http://pecl.php.net">pecl</a>上找到最新的filter源码:</p>
<pre><code># cd /opt
# wget http://pecl.php.net/get/filter-0.11.0.tgz</code></pre>
<h2>安装filter extension</h2>
<p>解压文件:</p>
<pre><code># tar -jxvf filter-0.11.0.tgz
# cd filter-0.11.0</code></pre>
<p>打开logical_filters.c文件:</p>
<pre><code># vi logical_filters.c</code></pre>
<p>找到下面的代码行:</p>
<pre><code>#include "ext/pcre/php_pcre.h"</code></pre>
<p>修改成 (php_pcre.h的绝对路径):</p>
<pre><code>#include "/opt/php-5.2.6/ext/pcre/php_pcre.h"</code></pre>
<p>保存并关闭文件. 最后输入下面命令来编译filter扩展:</p>
<pre><code># phpize
# ./configure
# make install</code></pre>
<h2>配置Filter Extension</h2>
<p>输入下列命令:</p>
<pre><code># echo 'extension=filter.so' &gt; /etc/php.d/filter.ini</code></pre>
<p>然后重启web server即可。</p>
<p>原文: <a href="http://www.cyberciti.biz/faq/rhel-cento-linux-install-php-pecl-filter/">CentOS / Red Hat Linux Install PHP 5.x PECL Filter Extension</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/473/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>php 5.3带来了什么(三)</title>
		<link>http://www.ooso.net/archives/472</link>
		<comments>http://www.ooso.net/archives/472#comments</comments>
		<pubDate>Wed, 24 Sep 2008 08:50:01 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.ooso.net/index.php/archives/472</guid>
		<description><![CDATA[之前介绍的php 5.3的新特性，都是方便开发人员的东东。下面介绍个很讨虚拟主机提供商喜欢的特性。
增强的ini文件支持

CGI/ FastCGI支持类似.htaccess的INI配置

				<span class="readmore"><a href="http://www.ooso.net/archives/472" title="php 5.3带来了什么(三)">阅读全文（593字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>之前介绍的php 5.3的新特性，都是方便开发人员的东东。下面介绍个很讨虚拟主机提供商喜欢的特性。</p>
<h2>增强的ini文件支持</h2>
<ul>
<li>CGI/ FastCGI支持类似<b>.htaccess</b>的INI配置</li>
<li>每个目录下都可以有INI设置，ini的文件名取决于php.ini的配置，但是[PATH=/var/www/domain.com], [HOST=www.domain.com]段落的设置用户不能修改。</li>
<li>增强的error handling</li>
<li>允许在ini文件中定义变量和常量，可以在程序中直接调用。</li>
</ul>
<p>附上一段ini文件的例子</p>
<pre><code>#用户自定义的php.ini文件名 (.htaccess). 默认是".user.ini"
user_ini.filename = ".user.ini"

#如果要禁用这个特性，设置为空值即可
user_ini.filename =

#用户自定义的php.ini文件TTL时长(time-to-live)，单位为秒，我理解为缓存过期时间。默认为300秒
user_ini.cache_ttl = 300

[PATH=/var/www/domain.com]
variables_order = GPC
safe_mode = 1

[my variables]
somevar = “1234”
anothervar = ${somevar} ; anothervar == somevar

[ini arrays]
foo[bar] = 1
foo[123] = 2
foo[] = 3</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/472/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>php 5.3带来了什么(二)</title>
		<link>http://www.ooso.net/archives/470</link>
		<comments>http://www.ooso.net/archives/470#comments</comments>
		<pubDate>Sun, 21 Sep 2008 06:44:53 +0000</pubDate>
		<dc:creator>Volcano</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.ooso.net/index.php/archives/470</guid>
		<description><![CDATA[接上文
性能提升
php 5.3的总体性能提升了5 &#8211; 15%


				<span class="readmore"><a href="http://www.ooso.net/archives/470" title="php 5.3带来了什么(二)">阅读全文（1217字）</a></span>]]></description>
			<content:encoded><![CDATA[<p>接上文</p>
<h2>性能提升</h2>
<p>php 5.3的总体性能提升了5 &#8211; 15%</p>
<ul>
<li>md5()快了10-15%</li>
<li>Better stack implementation in the engine</li>
<li>Constants移到read-only内存里</li>
<li>exception处理过程改进(简化，opcodes更少)</li>
<li>(require/include)_once改进，去掉重复open</li>
<li>Smaller binary size &#038; startup size with gcc4</li>
</ul>
<h2>新语言特性</h2>
<h3>__DIR__</h3>
<p>在5.3以前，为了获得当前脚本的目录，需要一次函数调用</p>
<pre><code>echo dirname(__FILE__); // &lt; PHP 5.3</code></pre>
<p>在5.3，只需要一个魔术常量__DIR__就解决了。</p>
<pre><code>echo __DIR__; // &gt;= PHP 5.3</code></pre>
<h3>?:操作符</h3>
<p>便捷的<b>?:</b>操作符，可以从两个值/表达式中快速取得非空值。</p>
<pre><code>$a = true ?: false; // true
$a = false ?: true; // true
$a = "" ?: 1; // 1
$a = 0 ?: 2; // 2
$a = array() ?: array(1); // array(1);
$a = strlen("") ?: strlen("a"); // 1</code></pre>
<h3>__callStatic()</h3>
<p>新增了魔术方法__callStatic，功能和__call类似，但是仅对static方法有效。</p>
<pre><code>class helper {
        static function __callStatic($name, $args) {
                echo $name.'('.implode(',', $args).')';
        }
}
helper::test("foo","bar"); // test(foo,bar)</code></pre>
<h3>动态调用static方法</h3>
<p>动态的调用静态方法？动静结合。</p>
<pre><code>class helper {
        static function foo() { echo __METHOD__; }
}
$a = "helper";
$b = "foo";
$a::$b(); // helper::foo</code></pre>
<h3>Late Static Binding</h3>
<p>不知道怎么译，可能留个原文更容易理解。静态方法的事件处理时机有变化，以前是在编译期处理，现在是执行期间处理。</p>
<p>在php 5.3之前，下面的代码会输出一个A，但是这不是咱们要的，whoami方法已经在class B中重新定义，它本该输出B才符合咱们想当然的思维。</p>
<pre><code>class A {
   public static function whoami() {
      echo __CLASS__;
   }
   public static function identity() {
     self::whoami();
   }
}
class B extends A {
   public static function whoami() {
      echo __CLASS__;
   }
}
B::identity(); // A &lt;-- PHP &lt; 5.3</code></pre>
<p>下面代码中使用了<b>static::whoami()</b>来调用静态方法。php 5.3之后，由于__CLASS__是在执行期被处理，那么这个例子中能顺利抓到class B。</p>
<pre><code>class A {
   public static function whoami() {
      echo __CLASS__;
   }
   public static function identity() {
      static::whoami();
   }
}
class B extends A {
   public static function whoami() {
      echo __CLASS__;
   }
}
B::identity(); // B &lt;-- &gt;= PHP 5.3</code></pre>
<h2>mysqlnd</h2>
<p>见<a href="http://www.ooso.net/index.php/archives/464">mysqlnd成为php 5.3中的默认mysql驱动</a></p>
<p>但是PDO_MySQL暂时还不支持mysqlnd，目前只有mysql(i)扩展可以用到</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ooso.net/archives/470/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

