<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
 <channel>
  <title>西花厅</title>
  <link>http://lds2008.blogbus.com</link>
  <description><![CDATA[三日坊主]]></description>
  <generator> by blogbus.com </generator>
  <lastBuildDate>Sat, 05 May 2012 15:55:02 +0800</lastBuildDate>
  <image>
									<url>http://public.blogbus.com/profile/2/8/7/1984782/avatar_1984782_96.jpg</url>
									<title>西花厅</title>
									<link>http://lds2008.blogbus.com</link>
								</image>  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/lds" /><feedburner:info uri="lds" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
   <title>饭否图片上传按钮</title>
   <description><![CDATA[<p>"饭否图片上传" 按钮.&nbsp;</p>
<p><a class="fanBtn" style="color:#444" href="javascript:void((function(){var n=navigator.userAgent.toLowerCase();ie=n.indexOf('msie')!=-1?1:0;if(document.documentMode)ie=0;charset='';if(ie)charset=document.charset;src=ie&amp;&amp;charset=='utf-8'?'https://github.com/sandin/fanfouPic/raw/master/src/fanfoupic.js':'https://github.com/sandin/fanfouPic/raw/master/src/fanfoupic.js';element=document.createElement('script');element.setAttribute('src',src);document.body.appendChild(element);})())">FanfouPic</a></p>
<p>将链接添加为书签, 使用时点击该书签按钮即可.</p>
<p>截图:</p>
<p><img src="http://filer.blogbus.com/1984782/1984782_1305044301l.gif" border="0" alt="" /></p>
<p>&nbsp;</p>
<p>=== 使用方法 ===</p>
<p>.方法 1</p>
<p>将按钮拖到书签工具栏, 使用时点击该书签即可.</p>
<p>&nbsp;</p>
<p>.方法 2</p>
<p>鼠标右键按钮, 选择"添加到收藏夹"即可.</p>
<p>&nbsp;</p>
<p>.方法 3</p>
<p>鼠标右键按钮，选择右键菜单中的&ldquo;复制链接地址&rdquo;，然后手动添加书签：名称填写"启用搜狗云输入法"，地址粘帖复制的内容。或者，直接将下面的搜狗云输入法按钮拖到浏览器的书签栏。</p>
<p>&nbsp;</p>
<p>源代码:&nbsp;<a title="GitHub" href="https://github.com/sandin/fanfouPic">github</a></p><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/6fqI_CThyog/127379674.html</link>
   <author>三日坊主</author>
   <pubDate>Wed, 11 May 2011 00:14:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/127379674.html</feedburner:origLink></item>
  <item>
   <title>Crontab使用方法</title>
   <description><![CDATA[<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>每个系统有一个全局 crontab 文件, 位于 /etc/crontab.</p>
</div>
<div class="paragraph">
<p>每个用户可以有自己独立的 crontab 文件, 位于 /var/spool/cron/crontabs , 但该文件并不设计为手动编辑的, 正确的方法是使用 <tt>crontab -e</tt> 来编辑自己的 crontab 文件.</p>
</div>
<div class="paragraph">
<p>编辑自己用户的 crontab 文件</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>crontab -e</tt></pre>
</div>
</div>
<div class="paragraph">
<p>格式是:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt># m h dom mon dow command
  * *  *   *   *  curl http://yiriji.com/admin/cron</tt></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>
m, 分钟
</p>
</li>
<li>
<p>
h, 小时
</p>
</li>
<li>
<p>
dom, day of month, 日期
</p>
</li>
<li>
<p>
mon, month, 月份
</p>
</li>
<li>
<p>
dow, day of week, 星期
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>和全局的 crontab 不同的是, 没有用户名这一列</p>
</div>
<div class="paragraph">
<p>如果因书写错误, 则可以到 <tt>/var/mail/用户名</tt> 文件中查看到错误信息.</p>
</div>
<div class="listingblock">
<div class="title">Ubuntu中命令</div>
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>/etc/init<span style="color: #990000">.</span>d/cron start
/etc/init<span style="color: #990000">.</span>d/cron stop
/etc/init<span style="color: #990000">.</span>d/cron restart</tt></pre>
</div>
</div>
<div class="listingblock">
<div class="title">Ubuntu中的全局crontab文件示范:</div>
<div class="content">
<pre><tt># m h dom mon dow user  command

# 每天每个小时的第17分执行 /etc/cron.hourly 文件下的所有可执行程序或脚本
17 *    * * *   root    cd / &amp;&amp; run-parts --report /etc/cron.hourly

# 每天6点25分执行
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / &amp;&amp; run-parts --report /etc/cron.daily )

# 每个星期天的6点47分执行
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / &amp;&amp; run-parts --report /etc/cron.weekly )

# 每月1号6点52分执行
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / &amp;&amp; run-parts --report /etc/cron.monthly )</tt></pre>
</div>
</div>
<div class="paragraph">
<p>run-parts 的意思就是执行该文件夹下所有可执行程序或脚本.</p>
</div>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/ExEZlspsIc0/124297064.html</link>
   <author>三日坊主</author>
   <pubDate>Sat, 30 Apr 2011 12:18:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/124297064.html</feedburner:origLink></item>
  <item>
   <title>在.htaccess中设置expires头</title>
   <description><![CDATA[<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>在Apache下设置 Expires Header , 使得图片,CSS, JS得以被浏览器缓存, 以加快页面载入速度.</p>
</div>
<div class="paragraph">
<p>首先确定apache加载了 <tt>mod_expires</tt> .</p>
</div>
<div class="paragraph">
<div class="title">错误示范</div>
<p>网上提供在 <tt>.htaccess</tt> 里面使用 expires 的方法都是:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>ExpiresActive On
ExpiresDefault A0
ExpiresByType image/gif A2592000
ExpiresByType image/png A2592000
ExpiresByType image/jpg A2592000
ExpiresByType image/jpeg A2592000
ExpiresByType image/ico A2592000
ExpiresByType text/css A2592000
ExpiresByType text/javascript A2592000
ExpiresByType text/html M604800</tt></pre>
</div>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">以上设置只会缓存图片, image/* .</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<p><strong>但是</strong> 实验证明将它们写入 <tt>.htaccess</tt> 后，会只有image/* , text/css 会被加上 expires　头，而javascript和ico都 <strong>不会</strong> 被长期缓存.</p>
</div>
<div class="paragraph">
<p>原因是因为apache的 <tt>expiresByType</tt> 是根据浏览器请求头中 <tt>Accept</tt> 来决定的, 浏览器在请求图片的时候会自动在请求头上根据图片类型加上:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>Accept:  image/png, image/*;q=0.8, */*;q=0.5</tt></pre>
</div>
</div>
<div class="paragraph">
<p>而在请求javascript脚本的时候只会发送</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>Accept: */*</tt></pre>
</div>
</div>
<div class="paragraph">
<p>浏览器并不会指明请求类型为 <tt>text/javascript</tt> , 所以apache的 <tt>ExpiresByType</tt> 就捕捉不到该类型, 也就不会加上 expires 头.</p>
</div>
<div class="paragraph">
<div class="title">正确方法</div>
<p>因此正确的替代方法是使用 FilesMatch 来替代 ExpiresByType, 例如:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>
    ExpiresActive On
    ExpiresDefault "access plus 1 year"
</tt></pre>
</div>
</div>
<div class="paragraph">
<p>同样可以加入到 .htaccess 里使用.</p>
</div>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/X6phB1jBqHE/123951710.html</link>
   <author>三日坊主</author>
   <pubDate>Fri, 29 Apr 2011 09:50:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/123951710.html</feedburner:origLink></item>
  <item>
   <title>利用Patch文件进行FTP同步</title>
   <description><![CDATA[<div>
<h1>Git-Diff-Fileset</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>本工具利用Git等代码仓库生成的 <tt>diff</tt> (patch)文件, 复制得到一份两次提交之间的差异文件集. (保留目录结果, 文件信息).</p>
</div>
<div class="paragraph">
<p>该工具意在用于网站程序上线后, 在本地进行了多次代码更新, 需要使用FTP等工具本地将修改的文件集批量上传到服务器, 得到服务器和本地代码同步.</p>
</div>
</div>
</div>
<h2 id="_">1. 用例</h2>
<div class="sectionbody">
<div class="paragraph">
<p>假设你已经将整个应用程序的代码上传到服务器, 然后在本地进行了功能扩展, 修改或增加了一部分文件, 而在本地测试完毕后需要将它们上传到服务器. 在上一次与服务器同步之后, 你在本地进行了一次代码提交. 例如你的 commit log :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>commit 2 5b6a52ea652eec20871c6285e00a03bef785edcc
Date:   Thu Apr 28 12:35:31 2011 +0800

commit 1 e4ef18425c6c49aefa92bb46c847be16b2de019e
Date:   Thu Apr 28 11:34:05 2011 +0800</tt></pre>
</div>
</div>
<div class="paragraph">
<p>commit 1 的文件和服务器是同步的, 你只需要将 commit 2 的修改集上传到服务器.在在commit 2中你一共修改了三个文件:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>M /css/style.css
M /js/script.js
M /index.php</tt></pre>
</div>
</div>
<h3 id="_patch">1.1. 生成Patch文件</h3>
<div class="paragraph">
<p>利用git diff命令生成补丁文件.</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>git diff master^ &gt; change.diff</tt></pre>
</div>
</div>
<h3 id="__2">1.2. 得到修改集文件拷贝</h3>
<div class="paragraph">
<p>使用本工具得到一个修改集, 并保留目录结构和基本文件信息(最后修改时间等).</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>java --jar git-diff.jar -dir /path/to/your/project change.diff</tt></pre>
</div>
</div>
<div class="paragraph">
<p>其中dir参数为你的代码跟目录, 即 .git 文件夹的所在; change.diff 为上一步生成的补丁文件.</p>
</div>
<div class="paragraph">
<p>之后便得到一个拷贝目录, 将包含此次提交的所有修改文件:</p>
</div>
<div class="listingblock">
<div class="content">
<pre><tt>/copy/
/copy/index.php
/copy/css/style.css
/copy/js/script.js</tt></pre>
</div>
</div>
<h3 id="_ftp">1.3. 使用FTP上传到服务器</h3>
<div class="paragraph">
<p>你只需使用喜欢的FTP客户端, 把这个目录上传到服务器上相对应的目录即可.</p>
</div>
<div class="paragraph">
<p>然后可以冲杯茶, 让代码飞一会.</p>
<p>&nbsp;</p>
<p>下载地址:&nbsp;<a title="Github" href="https://github.com/sandin/diff-fileset">源代码</a></p>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/nKPp5Az-fgM/123941328.html</link>
   <author>三日坊主</author>
   <pubDate>Fri, 29 Apr 2011 09:28:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/123941328.html</feedburner:origLink></item>
  <item>
   <title>Zend Framework - 生成HTML缓存</title>
   <description><![CDATA[<div>
<h1><span style="font-size: 14px; font-weight: normal;">Table of Contents</span></h1>
<div id="toc">
  <noscript>
<p><strong>JavaScript must be enabled in your browser to display the table of contents.</strong></p>
</noscript>
<div class="toclevel1"><a href="#_php_html">1. PHP生成HTML缓存</a></div>
<div class="toclevel1"><a href="#_zend_cache_backend_static">2. Zend_Cache_Backend_Static</a></div>
<div class="toclevel2"><a href="#_">2.1. 内部实现</a></div>
<div class="toclevel1"><a href="#_zend_controller_action_helper_cache">3. Zend_Controller_Action_Helper_Cache</a></div>
<div class="toclevel2"><a href="#_1">3.1. 步骤1: 配置文件</a></div>
<div class="toclevel2"><a href="#_2_init">3.2. 步骤2: init()</a></div>
<div class="toclevel2"><a href="#_3_htaccess">3.3. 步骤3: .htaccess</a></div>
<div class="toclevel2"><a href="#__2">3.4. 内部实现</a></div>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>使用HTML缓存可以使得一些对动态要求不高的页面请求更快,也缓解了服务器压力, 比如一些固定的文章页.</p>
</div>
<div class="paragraph">
<p>而使用Zend Framework构建的应用程序将 <strong>非常简单</strong> 的可以把服务器输出的内容缓存为html文件, 再之后的请求中, 完全就没有PHP和Zend Frameword什么事了, 只是简单的请求html文件即可, 快速而高效.</p>
</div>
<div class="paragraph">
<p>但是可惜的是介绍相关内容的资料非常之少, 就连官方手册中也只是对该功能提了一下, 并没有给出完成的用例说明.</p>
</div>
<div class="paragraph">
<p>这里不仅是介绍如何使用 <tt>Zend_Cache</tt> 将Zend Framework生成的页面缓存为HTML的方法, 也对其实现方法和原理进行了一些分析, 可不局限与ZF框架, 对PHP生成HTML静态缓存技术有进一步的了解, 同时也研究了ZF是如何利用这些基本缓存技术来实现对整个ZF应用生成的内容进行缓存.</p>
</div>
</div>
</div>
<h2 id="_php_html">1. PHP生成HTML缓存</h2>
<div class="sectionbody">
<div class="paragraph">
<p>首先简单将一些PHP生成HTML缓存的原理, 这有助于我们理解Zend_Cache是如何缓存整个页面的.</p>
</div>
<div class="paragraph">
<p>首先我们大概都知道 <tt>ob_start</tt> 函数, 虽然可能很少用过, 但一定见过, 在一般情况下, 我们需要截获PHP输出内容, 一般会使用到这个函数, 例如:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// 开始缓存输出</span></span>
<span style="font-weight: bold"><span style="color: #000000">ob_start</span></span><span style="color: #990000">();</span>

<span style="font-style: italic"><span style="color: #9A1900">// 模拟读取数据库之类等耗时操作</span></span>
<span style="color: #009900">$foo</span> <span style="color: #990000">=</span> <span style="color: #009900">$db</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">fetchAll</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"SELECT * FROM {node}"</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// 模拟向客户端输出内容</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #009900">$foo</span><span style="color: #990000">;</span>

<span style="font-style: italic"><span style="color: #9A1900">// 因为之前调用了ob_start(), 所以这里并不会立刻输出到客户端</span></span>

<span style="font-style: italic"><span style="color: #9A1900">// 而我们可以截获到输出内容</span></span>
<span style="color: #009900">$buffer</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">ob_get_contents</span></span><span style="color: #990000">();</span>

<span style="font-style: italic"><span style="color: #9A1900">// 将输出内容缓存到文件</span></span>
<span style="font-weight: bold"><span style="color: #000000">file_put_contents</span></span><span style="color: #990000">(</span><span style="color: #009900">$buffer</span><span style="color: #990000">,</span> <span style="color: #FF0000">'/tmp/cache.html'</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// 将之前的ob缓存释放到客户端</span></span>
<span style="font-weight: bold"><span style="color: #000000">ob_end_clean</span></span><span style="color: #990000">();</span>
</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>而 <tt>ob_start</tt> 是提供另一种形式的, 就是 <tt>ob_start(callback)</tt> , 其中 <tt>callback</tt> 为指定的回调函数名, 该回调函数可能会在如下情况下被调用:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>
调用 <tt>ob_flush()</tt> , 部分输出内容发送到客户端.
</p>
</li>
<li>
<p>
调用 <tt>ob_clean()</tt> , 输出内容发送到客户端.
</p>
</li>
<li>
<p>
该请求终止时, 输出内容自动发送到客户端.
</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">例子</div>
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">myCallback</span></span><span style="color: #990000">(</span><span style="color: #009900">$buffer</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
    <span style="font-weight: bold"><span style="color: #000000">file_put_contens</span></span><span style="color: #990000">(</span><span style="color: #009900">$buffer</span><span style="color: #990000">,</span> <span style="color: #FF0000">'/tmp/cache.html'</span><span style="color: #990000">);</span>
<span style="color: #FF0000">}</span>


<span style="font-weight: bold"><span style="color: #000000">ob_start</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'myCallback'</span><span style="color: #990000">);</span>

<span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">''</span><span style="color: #990000">;</span>

<span style="font-weight: bold"><span style="color: #000000">ob_end_flush</span></span><span style="color: #990000">();</span>
</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>这里我们就基本了解了PHP生成HTML的原理, 接下来我们再来看Zend Framework这种具有比较复杂的系统如何来利用该原理实现HTML静态化的.</p>
</div>
</div>
<h2 id="_zend_cache_backend_static">2. Zend_Cache_Backend_Static</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Zend Frameword 中内置的实现HTML静态化的组件就是 <tt>Zend_Cache_Backend_Static</tt> , 其属于 <tt>Zend_Cache</tt> 模块. 因此在了解它之前, 你必须了解 <tt>Zend_Cache</tt> 的原理和使用方法, 这里并不简介, 可以查看手册 <a href="http://framework.zend.com/manual/en/zend.cache.html">Zend_Cache</a> .</p>
</div>
<div class="paragraph">
<p><tt>Zend_Cache_Backend_Static</tt> 作为cache backend, 其必须和cache frontend中的 <tt>Zend_Cache_Frontend_Capture</tt> 配合使用.</p>
</div>
<h3 id="_">2.1. 内部实现</h3>
<div class="paragraph">
<p>这里先讲解一下 <tt>Zend_Cache_Backend_Static</tt> 这个类, 在使用HTML静态化时可以不需要了解这个部分, Zend framework 提供了封住好的 <tt>helper</tt> 类, 不需要了解实现细节的可以跳过该小节.</p>
</div>
<div class="paragraph">
<p><tt>Zend_Cache_Backend_Static</tt> 的内部实现使用的其实只 <tt>Core, File</tt> 组合的一个 <tt>innerCache</tt> , 这里其实也很好理解, 因为它的功能就是将内容输出到文件, 所以就直接使用了 <tt>Zend_Cache_Backend_File</tt> 作为缓存到文件的功能, 当然这里并不需要去完全理解它, 除非你想要去自己实现 <tt>innerCache</tt> , 通过设置 <tt>Zend_Cache_Backend_Static</tt> 的 <tt>tag_cache</tt> 可以指定自己的 <tt>innerCache</tt> , 也可以调用 <tt>setInnerCache()</tt> 来完成.</p>
</div>
<div class="paragraph">
<p><tt>Zend_Cache_Backend_Static</tt> 基本上只有一个外部接口是最值得关注的, 就是 <tt>save</tt> 方法:
<tt>boolean save (string $data, string $id, [array $tags = array()], [int $specificLifetime = false])</tt></p>
</div>
<div class="ulist">
<div class="title">参数:</div>
<ul>
<li>
<p>
<tt>$data</tt> , 是需要缓存的内容.
</p>
</li>
<li>
<p>
<tt>$id</tt> , 是缓存的ID.
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>例如调用:
<tt>$cache-&gt;save("bar : data to cache", bin2hex("/bar"));</tt></p>
</div>
<div class="paragraph">
<p>将会把 "bar : data to cache" 作为文件缓存到 "public/bar.html" (默认设置情况下).</p>
</div>
<div class="paragraph">
<p>这里也就了解了ZF将会如何去缓存输出到HTML了, 基本上就是通过截获 ob_start 储存起来的输出缓存, 然后把该缓存作为 <tt>save</tt> 中 <tt>$data</tt> 参数即可.</p>
</div>
</div>
<h2 id="_zend_controller_action_helper_cache">3. Zend_Controller_Action_Helper_Cache</h2>
<div class="sectionbody">
<div class="paragraph">
<p>该 <tt>action helper</tt> 则是ZF为我们提供的一个封装好的帮助类, 使用它, 我们基本不需要做任何额外的操作就可以把整个action页缓存成html文件.</p>
</div>
<div class="paragraph">
<p>既然是 <tt>action helper</tt> , 那么也就是说ZF提供 <tt>Zend_Cache_Backend_Static</tt> 这种缓存技术和其他的几个缓存组件并不一定, 它是属于 <tt>Controller</tt> 级别的缓存, 旨在将某几个 <tt>action</tt> 页面进行整体缓存, 使用方法也是在 <tt>Controller_Action#init</tt> 中进行使用的.</p>
</div>
<div class="paragraph">
<p>这里先讲准备功能, 就是提供少数几个推荐提供给 <tt>Zend_Cache_Backend_Static</tt> 的参数:</p>
</div>
<h3 id="_1">3.1. 步骤1: 配置文件</h3>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">;</span> Cache <span style="color: #990000">-</span> static
<span style="color: #009900">resources.cachemanager.page.backend.options.public_dir </span><span style="color: #990000">=</span> APPLICATION_PATH <span style="color: #FF0000">"/../public/cached"</span>
<span style="color: #009900">resources.cachemanager.pagetag.backend.options.cache_dir </span><span style="color: #990000">=</span> APPLICATION_PATH <span style="color: #FF0000">"/data/cache/tags"</span>
<span style="color: #009900">resources.frontController.params.disableOutputBuffering </span><span style="color: #990000">=</span> true</tt></pre>
</div>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">注意大小写, <tt>cachemanager</tt> 的 <tt>m</tt> 是小写, 而 <tt>frontController</tt> 的 <tt>C</tt> 是大写, 因为这个大小写的原因害我浪费了一天的时间.</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<div class="title">public_dir</div>
<p>一个是 <tt>public_dir</tt> , 默认的是 <tt>../public</tt> , 而有时我们需要把静态文件放置到统一的文件夹中, 如果指定了该文件夹, 并且该文件夹不存在, 就必须确保PHP有 <tt>mkdir</tt> 此文件夹的权限, 如果该文件夹你创建好了, 那么就必须确保PHP有读写的权限. 我的建议是把这个文件夹创建好, 然后给个比较大的权限 0777 之类的做测试用, 已排除是文件权限导致的静态化失败, 特别是linux系统.</p>
</div>
<div class="paragraph">
<p>这个文件夹的制定很重要, 手册上推荐的是使用绝对路径(可以使用APPLICATION_PATH). 而且必须保存该文件夹可写, 而且创建HTML文件时就会失败.</p>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">需要给linux系统的某些用户提醒下就是, PHP生成的HTML文件所有者会是 www-data 之类的apache用户, 而且缓存文件的权限可能只有所有者可读, 你可能会永远看都是空文件夹, 因为你可能没有权限查看该文件夹下的内容 可能ZF已经为你生成了缓存的HTML文件到缓存目录, 而你查看文件夹时会发现总是空, 这是权限问题, 如果你用su用户查看, 就会发现HTML文件已经在那里了.</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<div class="title">disableOutputBuffering</div>
<p>手册上也明确写出了如果要使用该静态缓存功能, 就必须将 <tt>disableOutputBuffering</tt> 设置为 <tt>true</tt> , 该选项的功能是关闭 frontController的 outputBufering, 因为默认情况下, 在frontController里面是会使用到 <tt>ob_start</tt> 的, 而这里我们需要关闭它, 使得我们可以在 <tt>Zend_Cache_Backend_Static</tt> 中来调用 <tt>ob_start(callback)</tt> 来缓存所有内容.</p>
</div>
<h3 id="_2_init">3.2. 步骤2: init()</h3>
<div class="paragraph">
<p>唯一需要做的就是在 <tt>init()</tt> 内部利用cache helper来制定哪几个action是需要被缓存的即可.</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Node_IndexController <span style="font-weight: bold"><span style="color: #0000FF">extends</span></span> Zend_Controller_Action
<span style="color: #FF0000">{</span>

    public <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">init</span></span><span style="color: #990000">()</span>
    <span style="color: #FF0000">{</span>
        <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_helper<span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">cache</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'index'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'page'</span><span style="color: #990000">),</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'allentries'</span><span style="color: #990000">));</span>
    <span style="color: #FF0000">}</span>

    public <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">indexAction</span></span><span style="color: #990000">()</span>
    <span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"index action cache"</span><span style="color: #990000">;</span>
    <span style="color: #FF0000">}</span>

    public <span style="font-weight: bold"><span style="color: #0000FF">function</span></span> <span style="font-weight: bold"><span style="color: #000000">pageAction</span></span><span style="color: #990000">()</span>
    <span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">"page action cache"</span><span style="color: #990000">;</span>
    <span style="color: #FF0000">}</span>

<span style="color: #FF0000">}</span></span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>这时你访问 <tt>/node/index/index</tt> 就会发现你指定的缓存目录下会出现 <tt>/node/index/index.html</tt> 文件了. 比如你访问 <tt>/node</tt> 那么就会在缓存目录下直接生成 <tt>/node.html</tt> , 都是请求路径和缓存目录的路径一一对应的.</p>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">cache helper是支持 <tt>Zend_Layout</tt> 的, 生成的内容会包含layout.</td>
</tr>
</tbody>
</table>
</div>
<h3 id="_3_htaccess">3.3. 步骤3: .htaccess</h3>
<div class="paragraph">
<p>修改 .htaccess 重写规则可以使得你的静态页面路径和不使用静态缓存的url一样, 比如在不使用缓存的情况下, 你的url是 <tt>/node/get/</tt> , 而使用缓存后, 假如缓存的HTML文件储存在 <tt>public/cached/node/get.html</tt> 下, 那么使用重写规则就可以使得用户继续使用 <tt>/node/get/</tt> 这个url来访问它, 此时用户访问的就不再是PHP页面, 而是被重写到了 <tt>public/cached/node/get.html</tt> 这个静态页面. url依然保持一致.</p>
</div>
<div class="paragraph">
<p>重写规则可以参考手册上的 <a href="http://framework.zend.com/manual/en/zend.cache.backends.html#Zend_Cache_Backend_Static">Zend_Cache_Backend_Static</a> , 这里抄录一份:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>AddType application<span style="color: #990000">/</span>rss<span style="color: #990000">+</span>xml <span style="color: #990000">.</span>xml
AddType application<span style="color: #990000">/</span>atom<span style="color: #990000">+</span>xml <span style="color: #990000">.</span>xml

RewriteEngine On

RewriteCond <span style="color: #990000">%</span>{REQUEST_URI} feed<span style="color: #990000">/</span>rss$
RewriteCond <span style="color: #990000">%</span>{DOCUMENT_ROOT}<span style="color: #990000">/</span>cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.</span>xml <span style="color: #990000">-</span>f
RewriteRule <span style="color: #990000">.*</span> cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.</span>xml <span style="font-weight: bold"><span style="color: #000000">[L,T=application/rss+xml]</span></span>

RewriteCond <span style="color: #990000">%</span>{REQUEST_URI} feed<span style="color: #990000">/</span>atom$
RewriteCond <span style="color: #990000">%</span>{DOCUMENT_ROOT}<span style="color: #990000">/</span>cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.</span>xml <span style="color: #990000">-</span>f
RewriteRule <span style="color: #990000">.*</span> cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.</span>xml <span style="font-weight: bold"><span style="color: #000000">[L,T=application/atom+xml]</span></span>

RewriteCond <span style="color: #990000">%</span>{DOCUMENT_ROOT}<span style="color: #990000">/</span>cached<span style="color: #990000">/</span>index<span style="color: #990000">.</span>html <span style="color: #990000">-</span>f
RewriteRule <span style="color: #990000">^/*</span>$ cached<span style="color: #990000">/</span>index<span style="color: #990000">.</span>html <span style="font-weight: bold"><span style="color: #000000">[L]</span></span>
RewriteCond <span style="color: #990000">%</span>{DOCUMENT_ROOT}<span style="color: #990000">/</span>cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.(</span>html<span style="color: #990000">|</span>xml<span style="color: #990000">|</span>json<span style="color: #990000">|</span>opml<span style="color: #990000">|</span>svg<span style="color: #990000">)</span> <span style="color: #990000">-</span>f
RewriteRule <span style="color: #990000">.*</span> cached<span style="color: #990000">/%</span>{REQUEST_URI}<span style="color: #990000">.%</span><span style="color: #993399">1</span> <span style="font-weight: bold"><span style="color: #000000">[L]</span></span>

RewriteCond <span style="color: #990000">%</span>{REQUEST_FILENAME} <span style="color: #990000">-</span>s <span style="font-weight: bold"><span style="color: #000000">[OR]</span></span>
RewriteCond <span style="color: #990000">%</span>{REQUEST_FILENAME} <span style="color: #990000">-</span>l <span style="font-weight: bold"><span style="color: #000000">[OR]</span></span>
RewriteCond <span style="color: #990000">%</span>{REQUEST_FILENAME} <span style="color: #990000">-</span>d
RewriteRule <span style="color: #990000">^.*</span>$ <span style="color: #990000">-</span> <span style="font-weight: bold"><span style="color: #000000">[NC,L]</span></span>

RewriteRule <span style="color: #990000">^.*</span>$ index<span style="color: #990000">.</span>php <span style="font-weight: bold"><span style="color: #000000">[NC,L]</span></span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>我测试出来是此重写规则在某些情况下是会失效的, 比如apache设置的virtualhost里会可能会出现问题(有些配置下), 原因是 <tt>%{REQUEST_URI}</tt> , 在有时候它会带前置的 <tt>/</tt> , 比如我请求 <tt>http://www.eriji.com/node</tt> , 按照重写规则,  <tt>%{REQUEST_URI}</tt> 应该被解析为 <tt>node</tt> , 而有些设置下它是会被设置为 <tt>/node</tt> 的, 多一个 <tt>/</tt> , 使得重写失败, apache将不会重写到我们的缓存文件, 如果你确认的ZF生成了HTML文件到文件系统, 但是因为重定向的问题导致缓存没有被读取, 可以开启 mod_rewrite 的 <tt>rewriteLog</tt> , 查看具体重定向日志, 检查重写规则是否命中.</p>
</div>
<h3 id="__2">3.4. 内部实现</h3>
<div class="paragraph">
<p>其实在了解了 <tt>ob_start(callback)</tt> 这个原理后, 我们自己都可以去实现HTML静态化,  但是在ZF里面, 唯一的问题是, 我们什么时候应该开启 <tt>ob_start</tt> , 而又到什么时候ZF才会把响应的内容(包括layout等)准备完毕, 也就是说什么时候使用 <tt>ob_end_lean</tt> ,特别是这个时机问题很重要, <tt>clean</tt> 早了可能缓存里面什么都没有, 也可能在使用了layout的情况下, 缓存里面只有action提供的view内容, 而没有 layout 部分.</p>
</div>
<div class="paragraph">
<p>我们可以细致的研究下ZF的分发过程, 并且在其中观察 <tt>Zend_Controller_Action_Helper_Cache</tt> 是怎么来完成这个工作的, 从中可以了解到ZF的分发系统.</p>
</div>
<div class="paragraph">
<p>首先我们从Controller_Action#init开始追踪, 因此我们在这一步里开始使用了cache helper.</p>
</div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
<tt>Controller_Action#init()</tt> , $this&rarr;_helper&rarr;cache(array(<em>index</em>), ..
</p>
</li>
<li>
<p>
<tt>HelperBroker</tt>, 注册cache helper, Zend_Constroller_Action_Helper/Cache#direct
</p>
</li>
<li>
<p>
<tt>Controller_Action#init()</tt>, 执行init()剩余部分
</p>
</li>
<li>
<p>
<tt>Controller_Dispatcher()</tt>,  一系列分发
</p>
</li>
<li>
<p>
<tt>Controller_Dispatcher_Standard#dispatch</tt>, 如果 <tt>disableOutputBuffering</tt> 没有指定则会调用 <tt>ob_start()</tt> 我们使用静态缓存的时候就必须关闭它.
</p>
</li>
<li>
<p>
<tt>Controller_Action#dispatch()</tt>, action分发
</p>
</li>
<li>
<p>
<tt>Controller_Action_Helper()</tt>, 分发到注册的action helper
</p>
</li>
<li>
<p>
<tt>Constoller_Action_Helper_Cache()#preDispatch</tt>, 进入cache helper
</p>
</li>
<li>
<p>
<tt>Zend_Cache_Frontend_Capture-&gt;start()</tt>, 调用 <span style="color:red;">ob_start(array(this, "_flush"))</span>
</p>
</li>
<li>
<p>
<tt>Constoller_Front</tt>, 调用所有插件的postDispatch, $this&rarr;_plugins&rarr;postDispatch($this&rarr;_request)
</p>
</li>
<li>
<p>
<tt>Zend_Layout_Controller_Plugin_Layout</tt> , layout插件对response&rarr;body进行处理, 目前的response&rarr;body中只有 action的view内容, 如果使用了layout, 这一步才会把layout的内容添加进来. 准确的说是把action view塞到layout里面去, 然后一起作为response&rarr;body.
</p>
</li>
<li>
<p>
<tt>Zend_Cache_Frontend_Captrue#_flush($data)</tt> , 得到response&rarr;body, 将其作为data参数, 调用 Zend_Cache_Backend_Static#save($data, $id, $tag)
</p>
</li>
<li>
<p>
<tt>Zend_Cache_Backend_Static#save</tt>, 调用 file_put_content 将响应内容输出到文件.
</p>
</li>
<li>
<p>
请求结束.
</p>
</li>
</ol></div>
<div class="paragraph">
<p>其中关键的就是 <tt>9</tt> 和 <tt>12</tt> , 都是 <tt>Zend_Cache_Frontend_Captrue</tt> 进行的操作, 使用的就是 <tt>ob_start(callback)</tt> 原理, 其中callback函数指定的是自己的 <tt>_flush</tt> 方法, 而在该方法里, 利用了 <tt>Zend_Cache_Backend_Static#save</tt> 来将缓存内容生成HTML文件.</p>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2011-04-26 11:40:25 CST
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/IQpkYoUz4ls/122973893.html</link>
   <author>三日坊主</author>
   <pubDate>Tue, 26 Apr 2011 11:29:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/122973893.html</feedburner:origLink></item>
  <item>
   <title>OAuth - 进行认证</title>
   <description><![CDATA[<div id="toc">
<div id="toctitle"><span style="font-size: 21px; font-weight: bold;">1. 简介</span></div>
</div>
<div id="content">
<div class="sectionbody">
<div class="paragraph">
<p>首先确认你对OAuth认证有基本了解,知道大概流程是怎样的及其主要的一些概念, 如果不清楚, 可以先看 <a href="http://lds2008.blogbus.com/logs/120393356.html">OAuth 基本概念</a> .</p>
</div>
<div class="paragraph">
<p>本文主要通过实例代码来演示如果在PHP中进行OAuth认证, OAuth客户端使用的是 <a href="http://framework.zend.com/manual/zh/zend.oauth.html">Zend_Oauth</a> .</p>
</div>
</div>
<h2 id="_request_token">2. 获得request token / 请求用户授权</h2>
<div class="sectionbody">
<div class="olist arabic">
<div class="title">这里我们这同一个页面实现两步:</div>
<ol class="arabic">
<li>
<p>
向服务器请求一个 request token.
</p>
</li>
<li>
<p>
将用户重定向到服务器的认证授权页面.
</p>
</li>
</ol></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// 你的API KEY/secret</span></span>
<span style="color: #009900">$key</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"3c2d81228736786e5e846fa51900067404daaaa25"</span><span style="color: #990000">;</span>
<span style="color: #009900">$secret</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"f6996b1591ef009dcea225629a77abf4"</span><span style="color: #990000">;</span>


<span style="font-style: italic"><span style="color: #9A1900">// 参数</span></span>
<span style="color: #009900">$config</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
    <span style="color: #FF0000">'callbackUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://localhost/callback'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'siteUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://yiriji.com/oauth'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerKey'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_key<span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerSecret'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_secret
<span style="color: #990000">);</span>
<span style="color: #009900">$consumer</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">new</span></span> <span style="font-weight: bold"><span style="color: #000000">Zend_Oauth_Consumer</span></span><span style="color: #990000">(</span><span style="color: #009900">$config</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// 向服务器请求一个request token</span></span>
<span style="color: #009900">$token</span> <span style="color: #990000">=</span> <span style="color: #009900">$consumer</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">getRequestToken</span></span><span style="color: #990000">();</span>

 <span style="font-style: italic"><span style="color: #9A1900">// persist the token to storage</span></span>
<span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">serialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// redirect the server authorize page</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(!</span> <span style="font-weight: bold"><span style="color: #0000FF">empty</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">))</span> <span style="color: #FF0000">{</span>
    <span style="color: #009900">$consumer</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">redirect</span></span><span style="color: #990000">();</span>
<span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="color: #FF0000">{</span>
    <span style="font-weight: bold"><span style="color: #0000FF">echo</span></span> <span style="color: #FF0000">'服务器没有返回 request token'</span><span style="color: #990000">;</span>
<span style="color: #FF0000">}</span></span></tt></pre>
</div>
</div>
<div class="paragraph">
<p><tt>$consumer-&gt;getRequestToken();</tt> 这里获得的$token即为 <tt>request token</tt> . 我们在获得它后已经将它临时储存起来, 用于下一次请求,</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// persist the token to storage</span></span>
<span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">serialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">);</span></span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>然后便可以把用户 <strong>重定向</strong> 到服务器的授权页面, 然用户确认给我们的这个token进行授权.</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// redirect the server authorize page</span></span>
<span style="color: #009900">$consumer</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">redirect</span></span><span style="color: #990000">();</span></span></tt></pre>
</div>
</div>
<div class="dlist">
<div class="title">参数解释:</div>
<dl>
<dt class="hdlist1">
callbackUrl
</dt>
<dd>
<p>
    即 <tt>oauth_callback</tt> , 客户端的回调页面.
</p>
</dd>
<dt class="hdlist1">
siteUrl
</dt>
<dd>
<p>
    服务器提供OAuth认证的根路径.
</p>
</dd>
</dl></div>
<div class="paragraph">
<div class="title">说明:</div>
<p>Zend_Oauth 默认的是使用 twitter 风格的网址来进行认证的, 比如 <tt>getRequestToken</tt> 方法请求的则是 <tt>/request_token</tt> , 根据我们例子中设置的 <tt>siteUrl</tt> 为 <tt>http://yiriji.com/oauth</tt> , 所以这里我们请求的网址完整路径则为 <tt>http://yiriji.com/oauth/request_token</tt> .</p>
</div>
<div class="paragraph">
<p>三个主要服务器网址默认为:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>
<tt>/request_token</tt> ,请求request token网址
</p>
</li>
<li>
<p>
<tt>/authorize</tt> , 请求用户授权网址
</p>
</li>
<li>
<p>
<tt>/access_token</tt> , 交换access token网址
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>这三个网址的命名方式, 基本上大多数提供OAuth认证网站都适用, 但如果需要自定义, 可以使用 <tt>setRequestTokenUrl()</tt> , <tt>setAccessTokenUrl()</tt> , 和 <tt>setAuthorizeUrl()</tt> .</p>
</div>
</div>
<h2 id="_access_token">3. 交换得到access token</h2>
<div class="sectionbody">
<div class="paragraph">
<p>在上一步中我们将用户重定向到了 <strong>服务器</strong> 的认证页面, 此时服务器会去对用户身份进行认证并且询问是否确认授权, 如果用户确认了, 则会向我们之前提供的 <tt>callback</tt> 页面发送一个请求以通知我们刚才的那个 <tt>request token</tt> 已经被用户授权了, 按照OAuth标准, 服务器将会发送几个参数 <tt>oauth_token</tt> , <tt>oauth_verifier</tt> 给客户端(我们).</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// 你的API KEY/secret</span></span>
<span style="color: #009900">$key</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"3c2d81228736786e5e846fa51900067404daaaa25"</span><span style="color: #990000">;</span>
<span style="color: #009900">$secret</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"f6996b1591ef009dcea225629a77abf4"</span><span style="color: #990000">;</span>


<span style="font-style: italic"><span style="color: #9A1900">// 参数</span></span>
<span style="color: #009900">$config</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
    <span style="color: #FF0000">'callbackUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://localhost/callback'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'siteUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://yiriji.com/oauth'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerKey'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_key<span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerSecret'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_secret
<span style="color: #990000">);</span>

<span style="color: #009900">$consumer</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">new</span></span> <span style="font-weight: bold"><span style="color: #000000">Zend_Oauth_Consumer</span></span><span style="color: #990000">(</span><span style="color: #009900">$config</span><span style="color: #990000">);</span>

<span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(!</span><span style="font-weight: bold"><span style="color: #0000FF">empty</span></span><span style="color: #990000">(</span><span style="color: #009900">$_GET</span><span style="color: #990000">)</span> <span style="color: #990000">&amp;&amp;</span> <span style="font-weight: bold"><span style="color: #0000FF">isset</span></span><span style="color: #990000">(</span><span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">]))</span> <span style="color: #FF0000">{</span>
    <span style="color: #009900">$token</span> <span style="color: #990000">=</span> <span style="color: #009900">$consumer</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">getAccessToken</span></span><span style="color: #990000">(</span><span style="color: #009900">$_GET</span><span style="color: #990000">,</span>
        <span style="font-weight: bold"><span style="color: #000000">unserialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">])</span>
    <span style="color: #990000">);</span>
    <span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_ACCESS_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">serialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">);</span>
    <span style="font-weight: bold"><span style="color: #000000">var_dump</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">);</span>

    <span style="font-style: italic"><span style="color: #9A1900">// Now that we have an Access Token, we can discard the Request Token</span></span>
    <span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">null</span></span><span style="color: #990000">;</span>
<span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="color: #FF0000">{</span>
    <span style="font-style: italic"><span style="color: #9A1900">// Mistaken request? Some malfeasant trying something?</span></span>
    <span style="font-weight: bold"><span style="color: #0000FF">exit</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Invalid callback request. Oops. Sorry.'</span><span style="color: #990000">);</span>
<span style="color: #FF0000">}</span>
</span></tt></pre>
</div>
</div>
<div class="ulist">
<div class="title">说明:</div>
<ul>
<li>
<p>
这里的 <tt>$config</tt> 参数和请求request token的时候是完全一样的.
</p>
</li>
<li>
<p>
此时我们准备接受的是服务器发来的一个 <tt>GET</tt> 请求, <tt>auth_token</tt> 包含在GET参数里面.
</p>
</li>
<li>
<p>
<tt>$_SESSION["TWITTER_REQUEST_TOKEN"]</tt> 则是我们在请求request token后储存起来.
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>我们利用服务器传来的 <tt>$_GET</tt> 和之前储存在本地的 <tt>request token</tt> (为 <tt>Zend_OAuth_Token_Request</tt> 实例), 即可向服务器交换token, 利用:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

 <span style="color: #009900">$token</span> <span style="color: #990000">=</span> <span style="color: #009900">$consumer</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">getAccessToken</span></span><span style="color: #990000">(</span><span style="color: #009900">$_GET</span><span style="color: #990000">,</span>
                <span style="font-weight: bold"><span style="color: #000000">unserialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">])</span>
            <span style="color: #990000">);</span></span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>这里实际是在请求服务器的 <tt>access_token</tt> 页面, 我们这里的例子中的完整网址为: <tt>http://yiriji.com/oauth/access_token</tt> , 该页面提供OAuth交换token功能, 可以利用我们已被用户授权的 <tt>request token</tt> , 交换得到一个 <tt>access token</tt> .</p>
</div>
<div class="paragraph">
<p>按照OAuth标准, 服务器此时会返回一个 <tt>oauth_token</tt> 参数, 该参数则是我们所需要的 <tt>access token</tt> ,我们必须将它储存起来, 这里的例子里我们将它储存到SESSION中, 并且为了使用方便, 我们存入的是 <tt>Zend_Oauth_Token_Access</tt> 实例, 之后我们做API请求的时候则会用到它.</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="font-style: italic"><span style="color: #9A1900">// 储存 access token</span></span>
<span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_ACCESS_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">serialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$token</span><span style="color: #990000">);</span>

<span style="font-style: italic"><span style="color: #9A1900">// 因为我们已经获得到了 access token</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// 所以 request token已经没有用了, 可以销毁掉</span></span>
<span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_REQUEST_TOKEN'</span><span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">null</span></span><span style="color: #990000">;</span></span></tt></pre>
</div>
</div>
</div>
<h2 id="_api">4. 使用服务器的API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>鉴于我们已经拥有了一个被授权的 <tt>access token</tt> , 所以我们有权去访问服务器上受保护资源, 使用其需要进行身份认证的API服务.</p>
</div>
<div class="paragraph">
<p>这里我们演示的是 <a href="http://www.eriji.com">宜日记</a> 所提供的一个 <strong>新建一篇日记</strong> 的API.</p>
</div>
<div class="paragraph">
<p>该API是一个REST风格的API:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>
新建日记 : <strong>POST</strong>  <tt>http://www.eriji.com/api/diarys</tt>
</p>
</li>
<li>
<p>
删除日记 : <strong>DELETE</strong>  <tt>http://www.eriji.com/api/diarys</tt>
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>新建日记API接受的参数为:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>
<tt>content</tt> : 日记内容
</p>
</li>
<li>
<p>
<tt>title</tt> : 日记标题
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>因为该API需要OAuth身份认证, 而我们前两步已经完成了一个认证, 并且在已经储存了一个有效的 <tt>access token</tt> , 这里我们就利用它来使用该API服务:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000"><!--?php</span-->

<span style="color: #009900">$config</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">array</span></span><span style="color: #990000">(</span>
    <span style="color: #FF0000">'callbackUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://localhost/callback'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'siteUrl'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'http://yiriji.com/oauth/'</span><span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerKey'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_key<span style="color: #990000">,</span>
    <span style="color: #FF0000">'consumerSecret'</span> <span style="color: #990000">=&gt;</span> <span style="color: #009900">$this</span><span style="color: #990000">-&gt;</span>_secret<span style="color: #990000">,</span>
    <span style="color: #FF0000">'signatureMethod'</span> <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">"Plaintext"</span>
<span style="color: #990000">);</span>

<span style="color: #009900">$content</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'I\'m posting to Diary using Zend_Oauth!'</span><span style="color: #990000">;</span>
<span style="color: #009900">$title</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'title'</span><span style="color: #990000">;</span>

<span style="font-style: italic"><span style="color: #9A1900">// 取出我们的access token</span></span>
<span style="color: #009900">$token</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">unserialize</span></span><span style="color: #990000">(</span><span style="color: #009900">$_SESSION</span><span style="color: #990000">[</span><span style="color: #FF0000">'TWITTER_ACCESS_TOKEN'</span><span style="color: #990000">]);</span>

<span style="color: #009900">$client</span> <span style="color: #990000">=</span> <span style="color: #009900">$token</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">getHttpClient</span></span><span style="color: #990000">(</span><span style="color: #009900">$config</span><span style="color: #990000">);</span>
<span style="color: #009900">$client</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">setUri</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'http://yiriji.com/api/diarys'</span><span style="color: #990000">);</span> <span style="font-style: italic"><span style="color: #9A1900">// 设置API地址</span></span>
<span style="color: #009900">$client</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">setMethod</span></span><span style="color: #990000">(</span>Zend_Http_Client<span style="color: #990000">::</span>POST<span style="color: #990000">);</span>
<span style="color: #009900">$client</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">setParameterPost</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'content'</span><span style="color: #990000">,</span> <span style="color: #009900">$content</span><span style="color: #990000">);</span> <span style="font-style: italic"><span style="color: #9A1900">// 设置请求参数</span></span>
<span style="color: #009900">$client</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">setParameterPost</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'title'</span><span style="color: #990000">,</span> <span style="color: #009900">$title</span><span style="color: #990000">);</span>
<span style="color: #009900">$response</span> <span style="color: #990000">=</span> <span style="color: #009900">$client</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">request</span></span><span style="color: #990000">();</span> <span style="font-style: italic"><span style="color: #9A1900">// 请求服务器API</span></span>

<span style="font-style: italic"><span style="color: #9A1900">// 得到服务器响应, 这里我们的服务器返回的是JSON格式的数据</span></span>
<span style="color: #009900">$data</span> <span style="color: #990000">=</span> Zend_Json<span style="color: #990000">::</span><span style="font-weight: bold"><span style="color: #000000">decode</span></span><span style="color: #990000">(</span><span style="color: #009900">$response</span><span style="color: #990000">-&gt;</span><span style="font-weight: bold"><span style="color: #000000">getBody</span></span><span style="color: #990000">());</span>

<span style="font-style: italic"><span style="color: #9A1900">// 服务器返回我们刚创建的日记数据, 如下:</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// array(</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//    'diary' =&gt; array(</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//        'content' =&gt; 'I\'m posting to Diary using Zend_Oauth!',</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//        'title'   =&gt; 'title'</span></span>
<span style="font-style: italic"><span style="color: #9A1900">//     )</span></span>
<span style="font-style: italic"><span style="color: #9A1900">// )</span></span>
</span></tt></pre>
</div>
</div>
</div>
<h2 id="__2">5. 注意事项</h2>
<div class="sectionbody">
<div class="paragraph">
<p>这里我们就完整的演示了一遍如何在PHP中进行OAuth认证, 需要注意的几个地方是:</p>
</div>
<div class="paragraph">
<div class="title">签名方式:</div>
<p><em>signatureMethod</em> , 一般的提供OAuth认证服务器都会支持OAuth的常用签名方法, 但还是需要注意我们请求的签名方式是被服务器所支持的. 这里我测试到 <tt>Zend_Oauth</tt> 和 <tt>oauth-php</tt> 两个库所提供的 <tt>HMAC-SHA1</tt> 算法并不一致, 原因未知, 如果在认证时出现 <strong>签名错误</strong> , 并且你确定你的其他信息都是正确而有效的, 那么可以试试先换个签名方式进行调试, 已排除是服务器不支持签名方法或签名算法出现问题.</p>
</div>
<div class="paragraph">
<div class="title">网址问题:</div>
<p>应该确认 <tt>/request_token</tt> , <tt>/authorize</tt> , <tt>/access_token</tt> 这三个服务提供的网址是准确的, 并且确认他们接受和返回的参数都是符合OAuth标准的.</p>
</div>
<div class="paragraph">
<div class="title">OAuth标准:</div>
<p>一般情况下提供OAuth服务的网站都是按照OAuth标准来做的, 但是因为各种实现OAuth的方法并不完全相同, 比如有人是自己实现的, 有人是使用各种版本各种语言的第三方库来实现的, 如果都按照标准来做就没有什么问题, 但你不能够百分之百确定他们的实现方法是完全符合标准的, 就算是完全符合标准, 其中也还是有些小地方是不同的, 因为标准中还是有些内容不是强制要求的, 而各自的库都使用了一些默认值, 比如 <strong>网址</strong> , <strong>参数</strong> 等, 所以你需要注意的是你使用的OAuth客户端和网站使用的OAuth服务端是兼容的, 如果不兼容, 你则需要去根据 <strong>服务器</strong> 的API <strong>说明</strong> 来调整自己的OAuth客户端参数.</p>
</div>
</div>
<h2 id="_oauth">6. 提供OAuth服务</h2>
<div class="sectionbody">
<div class="paragraph">
<p>最后需要说的是, <tt>Zend_Oauth</tt> 目前只提供OAuth客户端, 即 <tt>Zend_Oauth_Client</tt> , 在Zend framework的版本库中存在一个未完整的 <tt>Zend_Oauth_Server</tt> , 但它还没有实现并且也没有加入到发布的版本代码中, 如果你需要提供OAuth认证服务, 那么就必须去使用其他的库了, <a href="http://oauth.net/code/">OAuth官方</a> 上提供了许多语言和版本的库, 你都可以使用.</p>
</div>
<div class="paragraph">
<p>这里我推荐的是如果你不介意自己去实现OAuth认证数据信息的数据库储存, 那么可以更为轻量的 <a href="http://term.ie/">Andy Smith</a> 提供的 <a href="http://oauth.googlecode.com/svn/code/php/">a basic php library for OAuth</a> .</p>
</div>
<div class="paragraph">
<p>而如果你想直接使用一个功能全面的并有数据库支持的库, 则可以使用 <a href="http://code.google.com/p/oauth-php/">oauth-php</a> , 它提供了 MySQL/MySQLi, Postgresql, PDO 和 Oracle stores 数据库实现方法.</p>
</div>
<div class="paragraph">
<p>当然这里我推荐的两个库都是纯PHP库, 至于PHP官网上的 <a href="http://php.net/oauth">PECL版本</a> 的库我还没有使用过, 所以并不知道它好不好用, 如果在可以使用 <tt>PECL</tt> 的提前下, 应该也可以尝试尝试, 毕竟它肯定要比纯PHP库更快一些.</p>
</div>
</div>
<h2 id="__3">7. 结束语</h2>
<div class="sectionbody">
<div class="paragraph">
<p>之后的OAuth系列, 我将介绍一下如何在服务器上提供OAuth的认证服务, 这样就可以使得我们开发的网站可以实现需要OAuth认证的API服务.</p>
</div>
</div>
</div>
<div id="footnotes">
<hr />
</div>
<div id="footer">
<div id="footer-text">
Last updated 2011-04-18 09:21:54 CST
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/7e0WmKZ1zLc/120676562.html</link>
   <author>三日坊主</author>
   <pubDate>Mon, 18 Apr 2011 09:22:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/120676562.html</feedburner:origLink></item>
  <item>
   <title>OAuth -  具体流程</title>
   <description><![CDATA[<div class="paragraph">
<div class="title">具体例子说明:</div>
<p>假设某用户, 在一个提供图片储存服务的网站上储存了些只有自己可以访问的私密图片, 而现在需要授权另一个提供图片打印服务的网站去访问这些私密图片, 并把他们打印出来.</p>
</div>
<div class="ulist">
<div class="title">名称及角色:</div>
<ul>
<li>
<p>
用户A, 资源所有者, 私密图片的所有者, 具有访问这些图片的权利, 并具有授权第三方服务去访问它们的权利.
</p>
</li>
<li>
<p>
服务器A, <a href="http://photos.com">http://photos.com</a> 图片服务网站. 用户A在该网站储存了些私密图片.
</p>
</li>
<li>
<p>
客户端A, <a href="http://printer.com">http://printer.com</a> 打印服务网站, 需要在用户A授权后有权限访问在其储存 <a href="http://photos.com">http://photos.com</a> 上的私密图片, 并打印出来.
</p>
</li>
<li>
<p>
受保护资源, 用户A在服务器A上储存的私密图片.
</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>首先, 服务器A得给客户端A预先提供一对允许其使用其API接口的 <tt>API key</tt> 和 <tt>secret</tt> .  例如:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="dlist"><dl>
<dt class="hdlist1">
API KEY
</dt>
<dd>
<p>
    dpf43f3p2l4k3l03
</p>
</dd>
<dt class="hdlist1">
Secret
</dt>
<dd>
<p>
    kd94hf93k423kf44
</p>
</dd>
</dl></div>
</div>
</div>
<div class="paragraph">
<p>然后, 客户端A利用该 <tt>API KEY</tt> 和 <tt>secret</tt> 向服务器A请求一个 <tt>request token</tt> , 网址为 <tt>http://photos.com/oauth/request_token</tt> ,如下:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="literalblock">
<div class="content">
<pre><tt>POST /request_token HTTP/1.1
    Host: photos.com
    Authorization: OAuth realm="Photos",
       oauth_consumer_key="dpf43f3p2l4k3l03",
       oauth_signature_method="HMAC-SHA1",
       oauth_timestamp="137131200",
       oauth_nonce="wIjqoS",
       oauth_callback="http%3A%2F%2Fprinter.example.com%2Fcallback",
       oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D"</tt></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>服务器A对该请求中的信息进行认证, 如果信息验证成功(即检查key, secret), 则返回给客户端A返回一个 <tt>request token</tt> ,如下:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="literalblock">
<div class="content">
<pre><tt>HTTP/1.1 200 OK
  Content-Type: application/x-www-form-urlencoded</tt></pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre><tt>oauth_token=hh5s93j4hdidpola&amp;oauth_token_secret=hdhd0244k9j7ao03&amp;
oauth_callback_confirmed=true</tt></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>此时客户端A将服务器A返回的 <tt>request token</tt> 储存起来待用(比如存入SESSION), 并将用户浏览器重定向到服务器A的认证授权页面, 让用户对该 <tt>request token</tt> 进行授权. 网址为: <tt>http://photos.com/authorize</tt> , 如下:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="paragraph">
<p><a href="https://photos.com/authorize?oauth_token=hh5s93j4hdidpola">https://photos.com/authorize?oauth_token=hh5s93j4hdidpola</a></p>
</div>
</div>
</div>
<div class="paragraph">
<p>在服务器A的认证授权页面, 服务器A对用户身份进行认证, 比如提供一个登录框(输入用户名/密码), 如果当前用户已处于登录状态(比如服务器上已经存在SESSION的持久身份信息或刚才在登录框中输入的用户马/密码正确), 则向用户询问是否授权允许客户端A访问受保护资源.</p>
</div>
<div class="paragraph">
<p>如果用户确认授权, 服务器A则将该 <tt>request token</tt> 标记为 <strong>已授权</strong> (比如在数据库中更新), 然后将用户重定向回客户端A的callback页面(利用客户端请求中的 <tt>oauth_callback</tt> 参数), 并返回给客户端A <tt>oauth_token</tt> 参数以表明该 <tt>request token</tt> 已被用户授权, 返回网址如下:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="paragraph">
<p><a href="https://printer.com/callback?oauth_token=hh5s93j4hdidpola&amp;oauth_verifier=hfdp7dh39dks9884">https://printer.com/callback?oauth_token=hh5s93j4hdidpola&amp;oauth_verifier=hfdp7dh39dks9884</a></p>
</div>
</div>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">注意此时返回的 <tt>oauth_token</tt> 依然是客户端请求给服务器的那个 <tt>request token</tt> .</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<p>然后, 客户端A需要利用这个 <tt>request token</tt> 向服务器A交换得到一个真正的 <tt>access token</tt> , 例如网址: <tt>http://photos.com/access_token</tt> :</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="literalblock">
<div class="content">
<pre><tt>POST /access_token HTTP/1.1
Host: photos.com
Authorization: OAuth realm="Photos",
   oauth_consumer_key="dpf43f3p2l4k3l03",
   oauth_token="hh5s93j4hdidpola",
   oauth_signature_method="HMAC-SHA1",
   oauth_timestamp="137131201",
   oauth_nonce="walatlh",
   oauth_verifier="hfdp7dh39dks9884",
   oauth_signature="gKgrFCywp7rO0OXSjdot%2FIHF7IU%3D"</tt></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>此时, 服务器A对发送来的数据进行验证, 如果发送来的信息无误并且该 <tt>request token</tt> 确实已被用户授权(查看数据库中的 token 记录) , 则利用该 <tt>request token</tt> 生成一个 <tt>access token</tt> , 并将其发送给客户端A, 如下:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="literalblock">
<div class="content">
<pre><tt>HTTP/1.1 200 OK
    Content-Type: application/x-www-form-urlencoded</tt></pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre><tt>oauth_token=nnch734d00sl2jdk&amp;oauth_token_secret=pfkkdhi9sl3r4s00</tt></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>这里服务器A返回的 <tt>oauth_token</tt> 就是 <tt>access token</tt> , 这个token才是客户端A真正的目的所在, 利用该 <tt>access token</tt> , 客户端A才有权限去向服务器A访问用户A的收保护资源, 所以需要将该 <tt>access token</tt> 储存起来(比如存入SESSION). 而之前的那个 <tt>request token</tt> 在此时已经没有用了, 可以销毁.</p>
</div>
<div class="paragraph">
<p>客户端利用得到的 <tt>access token</tt> 去访问服务器A上用户A的那些私密图片, 比如获得 <tt>vacation.jpg</tt> 图片, 该图片在服务器A上的 <tt>http://photos.com/photos/vacation.jpg</tt> , 那么则请求:</p>
</div>
<div class="sidebarblock">
<div class="sidebar-content">
<div class="literalblock">
<div class="content">
<pre><tt>GET /photos?file=vacation.jpg HTTP/1.1
Host: photos.com
Authorization: OAuth realm="Photos",
   oauth_consumer_key="dpf43f3p2l4k3l03",
   oauth_token="nnch734d00sl2jdk",
   oauth_signature_method="HMAC-SHA1",
   oauth_timestamp="137131202",
   oauth_nonce="chapoH",
   oauth_signature="MdpQcU8iPSUjWoN%2FUDMsK2sui9I%3D"</tt></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>此处请求中的 <tt>oauth_token</tt> 就是刚才得到的那个 <tt>access token</tt> ,在该token未过期或未被销毁的前提下, 客户端A可以反复利用该token去访问服务器A上用户A的那么图片, 而不需要重新进行认证.</p>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/wohIUQPlOyo/120434438.html</link>
   <author>三日坊主</author>
   <pubDate>Sun, 17 Apr 2011 13:29:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/120434438.html</feedburner:origLink></item>
  <item>
   <title>OAuth - 基本概念</title>
   <description><![CDATA[<div id="content">
<h2 id="_">1. 基本概念</h2>
<div class="sectionbody">
<h3 id="__2">1.1. 词汇表</h3>
<div class="paragraph">
<div class="title">Client</div>
<p>HTTP客户端, 具有发送OAuth-authenticated请求能力的HTTP客户端</p>
</div>
<div class="paragraph">
<div class="title">Server</div>
<p>HTTP服务器, 具有接收OAuth-authenticated请求能力的HTTP服务器.</p>
</div>
<div class="paragraph">
<div class="title">protected resource</div>
<p>受保护的资源, 在获得了OAuth认证后能访问的资源.</p>
</div>
<div class="paragraph">
<div class="title">resource owner</div>
<p>资源所有者, 具有访问和控制资源的所有者, 并能够通过OAuth认证后将访问权利授权给某客户端.</p>
</div>
<div class="paragraph">
<div class="title">credentials</div>
<p>&nbsp;</p>
<ul>
<li>client credentials: consumer key and secret.</li>
<li>temporary credentials: request token and secret.</li>
<li>Token credentialss: Access Token and secret</li>
</ul>
<p>&nbsp;</p>
</div>
<div class="ulist">
<div class="title">token</div>
<ul>
<li>
<p>
request token
</p>
</li>
<li>
<p>
access token
</p>
</li>
</ul>
</div>
<div class="paragraph">
<div class="title">Consumer</div>
<p>客户端程序, 需要进行OAuth认证的客户端程序, 通常包含一对key/secret, 相当于普通登录的username, password.
在客户端(client)用key, secrect向提供OAuth认证API(OAuth-enabled API)的服务器(OAuth Server)进行认证.</p>
</div>
<div class="paragraph">
<div class="title">Server Provider</div>
<p>服务器程序, 提供OAuth认证.</p>
</div>
<div class="paragraph">
<div class="title">User</div>
<p>资源所有者.</p>
</div>
<h3 id="__3">1.2. 基本流程</h3>
<div class="olist arabic">
<div class="title">例子:</div>
<ol class="arabic">
<li>
<p>
server提供给client一对 <tt>key</tt> 和 <tt>secret</tt>.
</p>
</li>
<li>
<p>
客户端利用 <tt>key</tt> 和 <tt>secret</tt> 及其他参数向服务器请求得到一个 <tt>request token</tt> ,例如请求网址: <tt>http://server/oauth/request_token</tt> .
</p>
</li>
<li>
<p>
要求用户对 <tt>request token</tt> 进行授权.例如网址: <tt>http://server/oauth/authorize</tt> . 一般性操作为:.
</p>
<div class="ulist">
<ul>
<li>
<p>
server提供认证页面进行用户认证, 类似于普通登录页面, 以确定用户身份, 身份认证成功后转入询问用户是否确定授权页面, 例如: <tt>http://server/oauth/confirm</tt>
</p>
</li>
<li>
<p>
server询问用户是否授权该 <tt>request token</tt> , 即允许该client访问受保护资源.
</p>
</li>
<li>
<p>
用户确定允许访问, 则该 <tt>request token</tt> 被server标记为已授权, 然后将用户重定向到client之前提供的 <tt>oauth_callback</tt> 页面, 并将 <tt>oauth_token</tt> 值传回客户端以表示该 <tt>request token</tt> 已被用户授权. ( <tt>oauth_token</tt> 等于 <tt>request token</tt> .
</p>
</li>
</ul>
</div>
</li>
<li>
<p>
client此时可利用已被用户授权的 <tt>request token</tt> 向server交换得到一个 <tt>access token</tt> , 拥有该 <tt>access token</tt> , client则可以访问受保护资源, 并且在该 <tt>access token</tt> 过期以前反复使用它. 例如请求网址: <tt>http://server/oauth/access_token</tt>
</p>
</li>
</ol></div>
<h3 id="__4">1.3. 页面及其参数</h3>
<h4 id="_request_token">1.3.1. /request_token</h4>
<div class="tableblock">
<table border="0" cellspacing="0" cellpadding="4" width="60%" frame="border" rules="all">
<caption class="title">Table 1. 请求参数:</caption>
<colgroup><col width="50%"></col>
<col width="50%"></col>
</colgroup>
<tbody>
<tr>
<td align="left" valign="top">
<p class="table">参数</p>
</td>
<td align="left" valign="top">
<p class="table">意义</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_consumer_key</p>
</td>
<td align="left" valign="top">
<p class="table"><tt>API key</tt></p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_onoce</p>
</td>
<td align="left" valign="top">
<p class="table">单次值, 随机字符串</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_signature</p>
</td>
<td align="left" valign="top">
<p class="table">签名值, 利用某种算法对 <tt>secret</tt> 生成的签名.</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_signature_method</p>
</td>
<td align="left" valign="top">
<p class="table">签名方法</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_timestamp</p>
</td>
<td align="left" valign="top">
<p class="table">时间戳</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_version</p>
</td>
<td align="left" valign="top">
<p class="table">可选, 但必须为 <em>1.0</em></p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<div class="title">返回参数:</div>
<p>无</p>
</div>
<h4 id="_authorize">1.3.2. /authorize</h4>
<div class="tableblock">
<table border="0" cellspacing="0" cellpadding="4" width="60%" frame="border" rules="all">
<caption class="title">Table 2. 请求参数</caption>
<colgroup><col width="50%"></col>
<col width="50%"></col>
</colgroup>
<tbody>
<tr>
<td align="left" valign="top">
<p class="table">参数</p>
</td>
<td align="left" valign="top">
<p class="table">意义</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_token</p>
</td>
<td align="left" valign="top">
<p class="table">之前的 <tt>Request Token</tt></p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_callback</p>
</td>
<td align="left" valign="top">
<p class="table">认证后重定向回客户端的url.</p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="tableblock">
<table border="0" cellspacing="0" cellpadding="4" width="60%" frame="border" rules="all">
<caption class="title">Table 3. 返回参数</caption>
<colgroup><col width="50%"></col>
<col width="50%"></col>
</colgroup>
<tbody>
<tr>
<td align="left" valign="top">
<p class="table">参数</p>
</td>
<td align="left" valign="top">
<p class="table">意义</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_token</p>
</td>
<td align="left" valign="top">
<p class="table">已被授权的<tt>Request Token</tt></p>
</td>
</tr>
</tbody>
</table>
</div>
<h4 id="_access_token">1.3.3. /access_token</h4>
<div class="tableblock">
<table border="0" cellspacing="0" cellpadding="4" width="60%" frame="border" rules="all">
<caption class="title">Table 4. 请求参数</caption>
<colgroup><col width="50%"></col>
<col width="50%"></col>
</colgroup>
<tbody>
<tr>
<td align="left" valign="top">
<p class="table">参数</p>
</td>
<td align="left" valign="top">
<p class="table">意义</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_consumer_key</p>
</td>
<td align="left" valign="top">
<p class="table"><tt>API Key</tt> .</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_token</p>
</td>
<td align="left" valign="top">
<p class="table">已被授权的 <tt>request token</tt> .</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_signature</p>
</td>
<td align="left" valign="top">
<p class="table">签名值.</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_signature_method</p>
</td>
<td align="left" valign="top">
<p class="table">签名方法.</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_timesramp</p>
</td>
<td align="left" valign="top">
<p class="table">时间戳.</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_nonce</p>
</td>
<td align="left" valign="top">
<p class="table">单次值.</p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="tableblock">
<table border="0" cellspacing="0" cellpadding="4" width="60%" frame="border" rules="all">
<caption class="title">Table 5. 返回参数</caption>
<colgroup><col width="50%"></col>
<col width="50%"></col>
</colgroup>
<tbody>
<tr>
<td align="left" valign="top">
<p class="table">参数</p>
</td>
<td align="left" valign="top">
<p class="table">意义</p>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p class="table">oauth_token</p>
</td>
<td align="left" valign="top">
<p class="table">已被授权的 <tt>access token</tt></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/Njo2497HNSg/120393356.html</link>
   <author>三日坊主</author>
   <pubDate>Sun, 17 Apr 2011 10:02:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/120393356.html</feedburner:origLink></item>
  <item>
   <title>Javascript 模块式开发</title>
   <description><![CDATA[<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>众所周知关于Javascript中最基本的常识就是 <strong>全局变量都是魔鬼</strong> ,因此我们必须时刻注意不要随便去添加全局变量, 我的看法是你的程序一般只有一个全局变量做为你的命名空间即可, 然后在这个命名空间下, 你还可以进行模块式的开发. 这里我介绍一种关于模块开发的例子:</p>
</div>
<div class="paragraph">
<p>我这里使用了过去设计的一种模块/命名空间机制, 可以作为例子来探讨一下, 首先把代码贴出来, 有个全局性的印象:</p>
</div>
<div class="paragraph">
<p>我们这里使用 <tt>window.Ediary</tt> 作为应用程序统一使用全局性的唯一命名空间, 所有组件都必须储存在此命名空间下.</p>
</div>
<div class="listingblock">
<div class="title">代码:</div>
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>$<span style="color: #990000">,</span> win<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>

 <span style="font-style: italic"><span style="color: #9A1900">// Application</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">var</span></span> Ediary <span style="color: #990000">=</span> <span style="color: #FF0000">{</span>

    debug<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span><span style="color: #990000">,</span>

    <span style="font-style: italic"><span style="color: #9A1900">// default options</span></span>
    options<span style="color: #990000">:</span> <span style="color: #FF0000">{</span>
        autoLoad <span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span>             <span style="font-style: italic"><span style="color: #9A1900">// auto load module immediately</span></span>
    <span style="color: #FF0000">}</span><span style="color: #990000">,</span>

    <span style="font-style: italic"><span style="color: #9A1900">// modules list</span></span>
    modules<span style="color: #990000">:</span> <span style="color: #FF0000">{}</span><span style="color: #990000">,</span>

    <span style="font-style: italic"><span style="color: #9A1900">/**</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * Registers a module</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> String module name</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> mixed module:</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *          Object:   如果提供一个对象, 就被直接附加到命名空间下</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *          Function: 如果提供一个函数, 则被会视作模块代码块, 该函数会在加载模块时执行.</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> Object options:</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *          autoLoad: 如果为false, 则模块中的代码不会被立即执行, 而是储存在modules list中</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     */</span></span>
    extend<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>name<span style="color: #990000">,</span> object<span style="color: #990000">,</span> options<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>modules<span style="color: #990000">[</span>name<span style="color: #990000">]</span> <span style="color: #990000">!==</span> <span style="color: #FF0000">'undefined'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            console<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">error</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"Duplication Module, The "</span> <span style="color: #990000">+</span> name <span style="color: #990000">+</span> <span style="color: #FF0000">" module is exsits."</span><span style="color: #990000">);</span>
            <span style="font-weight: bold"><span style="color: #0000FF">return</span></span><span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span>

        <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> o <span style="color: #990000">=</span> $<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">extend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">{}</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>options<span style="color: #990000">,</span> options<span style="color: #990000">);</span>

        <span style="font-weight: bold"><span style="color: #0000FF">switch</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> object<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="color: #FF0000">'object'</span><span style="color: #990000">:</span>
                <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">[</span>name<span style="color: #990000">]</span> <span style="color: #990000">=</span> object<span style="color: #990000">;</span>
                <span style="font-weight: bold"><span style="color: #0000FF">break</span></span><span style="color: #990000">;</span>
            <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="color: #FF0000">'function'</span><span style="color: #990000">:</span>
                <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span>o<span style="color: #990000">.</span>autoLoad<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
                    <span style="font-style: italic"><span style="color: #9A1900">// load immediately</span></span>
                    <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">loadModule</span></span><span style="color: #990000">(</span>object<span style="color: #990000">,</span> options<span style="color: #990000">);</span>
                <span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="color: #FF0000">{</span>
                    <span style="font-style: italic"><span style="color: #9A1900">// Save it into this modules list</span></span>
                    <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>modules<span style="color: #990000">[</span>name<span style="color: #990000">]</span> <span style="color: #990000">=</span> <span style="color: #FF0000">{</span>origin<span style="color: #990000">:</span> object<span style="color: #990000">,</span> load<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span><span style="color: #FF0000">}</span><span style="color: #990000">;</span>
                <span style="color: #FF0000">}</span>
                <span style="font-weight: bold"><span style="color: #0000FF">break</span></span><span style="color: #990000">;</span>
            <span style="font-weight: bold"><span style="color: #0000FF">default</span></span><span style="color: #990000">:</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span><span style="color: #990000">;</span> <span style="font-style: italic"><span style="color: #9A1900">//do nothing</span></span>
        <span style="color: #FF0000">}</span>
    <span style="color: #FF0000">}</span><span style="color: #990000">,</span>

    <span style="font-style: italic"><span style="color: #9A1900">/**</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * Load a module</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> mixed module name</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *           Function: 如果提供一个匿名函数, 则被立即执行</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     *           String:   如果提供一个模块名称, 则会去调用之前注册时存储在模块列表中的模块代码</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> Object options</span></span>
<span style="font-style: italic"><span style="color: #9A1900">     */</span></span>
    loadModule<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>module<span style="color: #990000">,</span> options<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
        <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> fn<span style="color: #990000">;</span>

        <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> module <span style="color: #990000">==</span> <span style="color: #FF0000">'function'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            <span style="font-style: italic"><span style="color: #9A1900">// Got a Function</span></span>
            fn <span style="color: #990000">=</span> module<span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> module <span style="color: #990000">==</span> <span style="color: #FF0000">'string'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            <span style="font-style: italic"><span style="color: #9A1900">// Got a Module Name</span></span>
            <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> mod <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>modules<span style="color: #990000">[</span>module<span style="color: #990000">];</span>

            <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> mod <span style="color: #990000">!==</span> <span style="color: #FF0000">'undefined'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
                fn <span style="color: #990000">=</span> mod<span style="color: #990000">[</span><span style="color: #FF0000">'origin'</span><span style="color: #990000">];</span>
                mod<span style="color: #990000">.</span>load <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span><span style="color: #990000">;</span>
            <span style="color: #FF0000">}</span> <span style="font-weight: bold"><span style="color: #0000FF">else</span></span> <span style="color: #FF0000">{</span>
                console<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">warn</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"The Module %s is not exsits."</span><span style="color: #990000">,</span> module<span style="color: #990000">);</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span><span style="color: #990000">;</span>
            <span style="color: #FF0000">}</span>
        <span style="color: #FF0000">}</span>

        fn<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">call</span></span><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">,</span> options<span style="color: #990000">);</span> <span style="font-style: italic"><span style="color: #9A1900">// inside Function 'this' point Ediary</span></span>
    <span style="color: #FF0000">}</span><span style="color: #990000">,</span>

    destroy<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{</span>
    <span style="color: #FF0000">}</span>
<span style="color: #FF0000">}</span><span style="color: #990000">;</span>
win<span style="color: #990000">.</span>Ediary <span style="color: #990000">=</span> Ediary<span style="color: #990000">;</span>

<span style="color: #FF0000">}</span><span style="color: #990000">)(</span>jQuery<span style="color: #990000">,</span> window<span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="paragraph">
<div class="title">新建一个模块</div>
<p>我们可以先来看看如何新建模块先, 这是一个标准模块的例子:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>Ediary<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">extend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'moduleName'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>E<span style="color: #990000">)</span><span style="color: #FF0000">{</span>

    <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> YourModule <span style="color: #990000">=</span> <span style="color: #FF0000">{</span>
        name<span style="color: #990000">:</span> <span style="color: #FF0000">'lds'</span><span style="color: #990000">,</span>
        init<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{</span>
        <span style="color: #FF0000">}</span><span style="color: #990000">,</span>
        getName<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{</span>
        <span style="color: #FF0000">}</span>
    <span style="color: #FF0000">}</span><span style="color: #990000">;</span>

    <span style="font-style: italic"><span style="color: #9A1900">// 在命名空间中注册</span></span>
    E<span style="color: #990000">.</span>YourModule <span style="color: #990000">=</span> YourModule<span style="color: #990000">;</span>


<span style="color: #FF0000">}</span><span style="color: #990000">,</span> options<span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">在这个匿名函数内部 <tt>this</tt> 指向的 <tt>Ediary</tt> 这个对象, 但不建议使用 <tt>this</tt> 关键词来引用 <tt>Ediary</tt> 对象, 而应该用 <tt>E</tt> 来引用.</td>
</tr>
</tbody>
</table>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">如果扩展模块的moduleName已经存在, 将会抛出错误.</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<div class="title">延迟加载模块</div>
<p>对于有些模块, 需要使用外部库, 或需要等待DOM解析完毕等情况,需要延迟加载模块,而非注册模块时立即加载,则可以使用 <tt>autoLoad</tt> 参数来实现:
<tt>options: {autoLoad: false}</tt></p>
</div>
<div class="paragraph">
<p>例子:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>Ediary<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">extend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'moduleName'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>E<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
    <span style="font-style: italic"><span style="color: #9A1900">// your module code</span></span>
<span style="color: #FF0000">}</span><span style="color: #990000">,</span> <span style="color: #FF0000">{</span>autoLoad<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span><span style="color: #FF0000">}</span><span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>这样进行注册的模块不会立即被加载到命名空间中(此模块的匿名函数不会被立即执行), 而是被存储到一个模块列表中去 ( <tt>Ediary.modules = []</tt> ), 你模块中的代码只有在手动的加载它时才会被执行, 因此得到了延时加载的目的:</p>
</div>
<div class="listingblock">
<div class="title">手动加载模块:</div>
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>Ediary<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">loadModule</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'moduleName'</span><span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>此时应用程序将会执行储存在modules list中的注册此模块时提供的匿名函数.</p>
</div>
<div class="admonitionblock">
<table border="0">
<tbody>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">如果加载一个尚未注册过的模块,会不被允许并抛出提示.</td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<div class="title">拓展分析</div>
<p>使用这样一个简单的结构对你的代码进行模块式的分割, 可以得到你的代码不断的可以扩展和复用, 而完全不用担心会影响其他模块,  它比只使用一个匿名函数包裹着你的代码来避免破坏全局变量的好处就是, 你可以在外部去访问他们. 比如我们常常是这样来写一段代码的:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{</span>
    <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> Class <span style="color: #990000">=</span> <span style="color: #FF0000">{</span>
        init<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{}</span>
    <span style="color: #FF0000">}</span><span style="color: #990000">;</span>
<span style="color: #FF0000">}</span><span style="color: #990000">)();</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>这样是一个很好的习惯, 但导致了你在外部后将会完全不能去访问这个匿名函数中定义的内容了, 这样是完全的隔离, 我们使用一个唯一的全局变量来作为两个世界之间的桥梁, 这里在任何都去访问他们就比较灵活了.</p>
</div>
<div class="paragraph">
<p>我的看法是把一个模块看作一个命名空间, 你再里面可以做任何的事情, 处理任何的逻辑, 然后丢出一个访问接口即可, 这样外部也可以使用你模块中的内容, 也不用担心不影响别人, 这应该是一种习惯.</p>
</div>
<div class="paragraph">
<p>最后就贴出一个使用该结构的模块, 该模块设计是用来给每个模块提供 <tt>i18n</tt> 的多语言支持:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-style: italic"><span style="color: #9A1900">// i18n module</span></span>
Ediary<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">extend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'i18n'</span><span style="color: #990000">,</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>E<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
    <span style="font-weight: bold"><span style="color: #0000FF">var</span></span> i18n <span style="color: #990000">=</span> <span style="color: #FF0000">{</span>

        languages<span style="color: #990000">:</span> <span style="color: #FF0000">{}</span><span style="color: #990000">,</span>

        <span style="font-style: italic"><span style="color: #9A1900">/**</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> String key language package name</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         * </span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> Object value language package object, like { NAME : '中文翻译'}</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         */</span></span>
        extend<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>key<span style="color: #990000">,</span> value<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>languages<span style="color: #990000">[</span>key<span style="color: #990000">]</span> <span style="color: #990000">==</span> <span style="color: #FF0000">'undefined'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
                <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>languages<span style="color: #990000">[</span>key<span style="color: #990000">]</span> <span style="color: #990000">=</span> value<span style="color: #990000">;</span>
            <span style="color: #FF0000">}</span>
            <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> value<span style="color: #990000">;</span>
        <span style="color: #FF0000">}</span><span style="color: #990000">,</span>

        <span style="font-style: italic"><span style="color: #9A1900">/**</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         *</span></span><span style="color: #009900">@param</span><span style="font-style: italic"><span style="color: #9A1900"> String key language package name</span></span>
<span style="font-style: italic"><span style="color: #9A1900">         */</span></span>
        get<span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">function</span></span><span style="color: #990000">(</span>key<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
            <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> <span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">typeof</span></span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>languages<span style="color: #990000">[</span>key<span style="color: #990000">]</span> <span style="color: #990000">!==</span> <span style="color: #FF0000">'undefined'</span><span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
                <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="font-weight: bold"><span style="color: #0000FF">this</span></span><span style="color: #990000">.</span>languages<span style="color: #990000">[</span>key<span style="color: #990000">];</span>
            <span style="color: #FF0000">}</span>
        <span style="color: #FF0000">}</span>
    <span style="color: #FF0000">}</span><span style="color: #990000">;</span>
    E<span style="color: #990000">.</span>i18n <span style="color: #990000">=</span> i18n<span style="color: #990000">;</span>
<span style="color: #FF0000">}</span><span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="listingblock">
<div class="title">这样就可以在模块中定义自己的语言:</div>
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>E<span style="color: #990000">.</span>i18n<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">extend</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Editor'</span><span style="color: #990000">,</span> <span style="color: #FF0000">{</span>
    SAVE_SUCCESS <span style="color: #990000">:</span> <span style="color: #FF0000">'保存成功.'</span><span style="color: #990000">,</span>
    SAVE_FAIL <span style="color: #990000">:</span> <span style="color: #FF0000">'保存失败.'</span><span style="color: #990000">,</span>
    SAVING <span style="color: #990000">:</span> <span style="color: #FF0000">'正在保存...'</span><span style="color: #990000">,</span>
    JSON_PARSE_ERROR <span style="color: #990000">:</span> <span style="color: #FF0000">'无法解析服务器返回的数据'</span><span style="color: #990000">,</span>
    NOT_SAVED<span style="color: #990000">:</span> <span style="color: #FF0000">'日记没有保存, 确定离开?'</span><span style="color: #990000">,</span>
    GETING_DIARYS <span style="color: #990000">:</span> <span style="color: #FF0000">'正在获取日记.'</span><span style="color: #990000">,</span>
    SUCCESS<span style="color: #990000">:</span> <span style="color: #FF0000">'成功'</span>
<span style="color: #FF0000">}</span><span style="color: #990000">;</span></tt></pre>
</div>
</div>
<div class="paragraph">
<p>当你需要使用的直接:</p>
</div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.4
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">var</span></span> i18n <span style="color: #990000">=</span> E<span style="color: #990000">.</span>i18n<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">get</span></span><span style="color: #990000">(</span><span style="color: #FF0000">'Editor'</span><span style="color: #990000">);</span>

<span style="font-weight: bold"><span style="color: #000000">alert</span></span><span style="color: #990000">(</span>i18n<span style="color: #990000">.</span>SAVE_SUCCESS<span style="color: #990000">);</span></tt></pre>
</div>
</div>
<div class="paragraph">
<div class="title">结束语</div>
<p>你可以使用这个结构, 也可以不使用, 但是使用 <strong>唯一</strong> 的全局变量作为 <strong>命名空间</strong> 的理念是每个人都应该拥有的, 永远不去破坏全局环境是没有 <tt>namespace</tt> 语言使用者的基本准则, 如果你不需要延时载入模块等复杂功能,  也可以只使用这种概念来书写自己的代码. 如果每个人都以这样的一种分功能的模块式来书写Javascript代码, 最后Javascript也会出现更多的可复用的第三方库资源. 到时就不需要每个人都重复在那里造轮子玩了.</p>
</div>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/XpOrcB_76cI/115928187.html</link>
   <author>三日坊主</author>
   <pubDate>Thu, 07 Apr 2011 17:13:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/115928187.html</feedburner:origLink></item>
  <item>
   <title>PHPCMS 重新生成搜索索引</title>
   <description><![CDATA[<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>我实在想不出来为什么PHPCMS的搜索模块不提供一个按钮来刷新所有搜索结果并更新所有搜索的索引数据.</p>
</div>
<div class="paragraph">
<p>如果你提供缓存机制, 那么就必须要提供一个强制缓存的方法, 而PHPCMS的搜索提供了两层缓存, 一是 <tt>phpcms_search</tt> 这个表来提供索引缓存, 然后在数据库缓存的基础上又提供了文件缓存机制, <tt>search/data/</tt> 文件夹下的都是文件缓存, 但是后台管理里面居然一个清空缓存的选项都没有, 必须手动去清除.</p>
</div>
<div class="paragraph">
<p>我是真不知道这样设计是怎么想的, 如果URL规则变了, 同样的文章名出现, 文章被删除了, 此搜索都会出问题, 搜索出来的全部都是旧结果, 不存在的文章, 而你想刷新缓存? 没门.</p>
</div>
<div class="paragraph">
<p>查到的资料, 手动清空刷新搜索缓存的办法是.</p>
</div>
<div class="olist arabic">
<div class="title">步骤:</div>
<ol class="arabic">
<li>
<p>
<strong>清空文件缓存</strong> : <tt>/search/data/</tt> 下的所有文件和文件夹.
</p>
</li>
<li>
<p>
<strong>清空数据库数据</strong> : 执行SQL命令 <tt>truncate phpcms_search</tt> .
</p>
</li>
<li>
<p>
<strong>将所有文章都标记为未索引</strong> : 执行 <tt>update phpcms_content set searchid='0'</tt> , 很明显它给每篇文章设置了索引值, 只有在该ID为0时, 下次才会对这篇文章重新生成索引ID.
</p>
</li>
<li>
<p>
<strong>重新生成索引</strong> : 这里可以用 [生成HTML]-[更新URL] 的操作达到这个目的, 它在更新URL的时候会去读刚才设置的 <tt>searchid</tt> . 而且即使你没有使用HTML缓存机制这个操作也是一样可以帮你重新生成索引的.
</p>
</li>
</ol></div>
<div class="paragraph">
<p>关于为什么一件很简单的事情会变得这么麻烦, 我就不吐槽了, 最后说下我用的PHPCMS版本是 <tt>2008 sp4</tt> .</p>
</div>
</div>
</div>
</div><!--sp--><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://feedproxy.google.com/~r/lds/~3/uEW4qidXKaY/115912061.html</link>
   <author>三日坊主</author>
   <pubDate>Thu, 07 Apr 2011 16:25:00 +0800</pubDate>
  <feedburner:origLink>http://lds2008.blogbus.com/logs/115912061.html</feedburner:origLink></item>
 </channel>
</rss>

