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

<channel>
	<title>睡到25点 &#187; discuz</title>
	<atom:link href="http://www.voidman.com/tag/discuz/feed" rel="self" type="application/rss+xml" />
	<link>http://www.voidman.com</link>
	<description>个人博客，记录与分享。</description>
	<lastBuildDate>Thu, 12 Jan 2012 14:00:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>在 Discuz 中应用 MogileFS 分布式文件存储系统</title>
		<link>http://www.voidman.com/2009/05/mogilefs-for-discuz.html</link>
		<comments>http://www.voidman.com/2009/05/mogilefs-for-discuz.html#comments</comments>
		<pubDate>Sun, 10 May 2009 06:38:51 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[discuz]]></category>
		<category><![CDATA[mogilefs]]></category>

		<guid isPermaLink="false">http://www.voidman.com/?p=286</guid>
		<description><![CDATA[本文讨论内容基于 Discuz 7, Red Hat Enterprise Linux AS 4, MogileFs Server 2.17, MogileFS Client 1.08, MogileFS Utils 2.14 MogileFS 安装和配置 安装 基本安装顺序是 mogilefs-server（服务端）， MogileFS-Client（客户端）， MogileFS-Utils（工具包）。安装 MogileFS 其实并不复杂，但有些耗时，因为大多数据时间都被用在安装依赖包上了。在安装 MogileFS 之前有几个包是必需的： Sys-Syscall-0.22.tar.gz Danga-Socket-1.56.tar.gz String-CRC32-1.4.tar.gz Gearman-1.07.tar.gz Gearman-Client-Async-0.93 Net-Netmask-1.9015.tar.tar Perlbal-1.70.tar.tar 若在安装过程中还提示其它包不存在，可以根据提示到search.cpan.org搜索相应的包装上。具体安装步骤可以参考这里或这里。 安装成功后，会提示安装了以下文件，在下文的 MogileF S配置部分中会提到。 &#8230; <a href="http://www.voidman.com/2009/05/mogilefs-for-discuz.html">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>
本文讨论内容基于 Discuz 7, Red Hat Enterprise Linux AS 4, MogileFs Server 2.17, MogileFS Client 1.08, MogileFS Utils 2.14
</p></blockquote>
<h3>MogileFS 安装和配置</h3>
<p><strong>安装</strong><br />
基本安装顺序是 <a href="http://search.cpan.org/~bradfitz/mogilefs-server/">mogilefs-server</a>（服务端）， <a href="http://search.cpan.org/~bradfitz/MogileFS-Client-1.08/">MogileFS-Client</a>（客户端）， <a href="http://search.cpan.org/CPAN/authors/id/D/DO/DORMANDO/MogileFS-Utils-2.14.tar.gz">MogileFS-Utils</a>（工具包）。安装 MogileFS 其实并不复杂，但有些耗时，因为大多数据时间都被用在安装依赖包上了。在安装 MogileFS 之前有几个包是必需的：</p>

<div class="wp_syntax"><pre class="ini">Sys-Syscall<span style="">-0.22</span>.tar.gz
Danga-Socket<span style="">-1.56</span>.tar.gz
String-CRC32<span style="">-1.4</span>.tar.gz
Gearman<span style="">-1.07</span>.tar.gz
Gearman-Client-Async<span style="">-0.93</span>
Net-Netmask<span style="">-1.9015</span>.tar.tar 
Perlbal<span style="">-1.70</span>.tar.tar</pre></div>

<p>若在安装过程中还提示其它包不存在，可以根据提示到<a href="search.cpan.org">search.cpan.org</a>搜索相应的包装上。具体安装步骤可以参考<a href="http://mogilefs.pbworks.com/HowTo">这里</a>或<a href="http://durrett.net/mogilefs_setup.html">这里</a>。<br />
<span id="more-286"></span><br />
安装成功后，会提示安装了以下文件，在下文的 MogileF S配置部分中会提到。</p>

<div class="wp_syntax"><pre class="bash">/usr/bin/mogilefsd
/usr/bin/mogstored
/usr/bin/mogdbsetup
/usr/bin/mogautomount
/usr/bin/mogtool
/usr/bin/mogadm</pre></div>

<p><strong>数据库配置</strong><br />
MogileFS 通过数据库来维护文件的存储节点和存储份数等相关属性。 创建一个数据库命名为 mogilefs，创建一个用户 mogile，设置密码为 mogile</p>

<div class="wp_syntax"><pre class="mysql"><span style="color: #008200; font-style: italic;"># mysql</span>
mysql&gt; <span style="color: #0000FF; ">CREATE DATABASE</span> mogilefs;
mysql&gt; <span style="color: #0000FF; ">GRANT</span> ALL ON mogilefs.* TO <span style="color: #FF00FF;">'mogile'</span>@<span style="color: #FF00FF;">'%'</span>;
mysql&gt; <span style="color: #0000FF; ">SET</span> PASSWORD FOR <span style="color: #FF00FF;">'mogile'</span>@<span style="color: #FF00FF;">'%'</span> = PASSWORD<span style="color: #000;">&#40;</span><span style="color: #FF00FF;">'mogile'</span><span style="color: #000;">&#41;</span>;
mysql&gt; FLUSH <span style="color: #0000FF; ">PRIVILEGES</span>;
mysql&gt; quit</pre></div>

<p>然后通过 MogileFs 自带的工具创建表</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># /usr/bin/mogdbsetup --dbhost=db.yourdomain.com --dbname=mogilefs --dbuser=mogile --dbpassword=mogile</span></pre></div>

<p><strong>tracker 配置</strong><br />
编辑 /etc/mogilefs/mogilefsd.conf</p>

<div class="wp_syntax"><pre class="ini">db_dsn DBI:mysql:mogilefs
db_user mogile 
db_pass mogile 
conf_port <span style="">6001</span> 
listener_jobs <span style="">5</span></pre></div>

<p><strong>存储节点配置</strong></p>
<ul>
<li>
<p>先编辑配置文件 /etc/moiglefs/mogstored.conf</p>

<div class="wp_syntax"><pre class="ini"><span style="color: #000099;">httplisten</span>=<span style="color: #660066;"><span style="">192.168</span><span style="">.0</span><span style="">.7</span>:<span style="">7500</span> </span>
<span style="color: #000099;">mgmtlisten</span>=<span style="color: #660066;"><span style="">192.168</span><span style="">.0</span><span style="">.7</span>:<span style="">7501</span> </span>
<span style="color: #000099;">docroot</span>=<span style="color: #660066;">/var/mogdata</span></pre></div>

</li>
<li>
<p>向系统添加存储节点主机，并查看是否添加成功。这里我们添加的主机名称是 file.yourdomain.com，IP为192.168.0.7</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 host add file.yourdomain.com --ip=192.168.0.7 --port=7500 --status=alive</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 host list</span></pre></div>

</li>
<li>
<p>向系统添加存储节点设备，并查看是否添加成功</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># mkdir /var/mogdata/dev1</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 device add file.yourdomain.com 1</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 device list</span></pre></div>

<p>这里的 1 代表 file.yourdomain.com 主机下的存储设备编号，对应存储目录为 /var/mogdata/dev1</p>
</li>
<li>
<p>添加存储域。在 MogileFs 中，文件通过 KEY 来引用，KEY 在某个存储域下是唯一的。我们添加一个 bbs.yourdomain.com 域，论坛里的附件都存储到该域下。</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 domain add bbs.yourdomain.com</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 domain list</span></pre></div>

</li>
<li>
<p>添加存储类别。在 MogileFs 中可以设置不同的存储类别存储不同份数的文件副本。我们添加一个 attach 类，每个文件至少存储 2 份</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 class add bbs.yourdomain.com attach --mindevcount=2</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 class list</span></pre></div>

</li>
</ul>
<p>最后在防火墙配置上述几个端口访问规则。现在可以启动 MogileFs，并查看进程与服务状态。</p>

<div class="wp_syntax"><pre class="bash"><span style="color: #666666; font-style: italic;"># /usr/bin/mogstored --daemon</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogilefsd -c /etc/mogilefs/mogilefsd.conf --daemon</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># ps -fe |grep mogstored</span>
<span style="color: #666666; font-style: italic;"># ps -fe |grep mogilefsd</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 check</span>
<span style="color: #666666; font-style: italic;"># /usr/bin/mogadm --trackers=192.168.0.7:6001 stats</span></pre></div>

<p>注：上述配置例子基于tracker，存储节点均在同一台主机，而实际使用上需要将存储节点分配到不同主机上才是真正意义上的分布式存储。甚至于  tracker 也可以是多个。</p>
<h3>安装 MogileFS PHP 扩展</h3>
<p>从 <a href="http://svn.usrportage.de/php-mogilefs/trunk/">http://svn.usrportage.de/php-mogilefs/trunk/</a> 获取源代码编译安装：</p>

<div class="wp_syntax"><pre class="bash">$ phpize
$ ./configure
$ <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span></pre></div>

<p>将生成的 php-mogilefs.so 复制到 PHP 扩展目录，在 php.ini 添加一行扩展配置：</p>

<div class="wp_syntax"><pre class="ini"><span style="color: #000099;">extension</span>=<span style="color: #660066;">php-mogilefs.so</span></pre></div>

<p>重启 WEB 服务，用 phpinfo() 函数测试，如果显示结果如下图显示则表示安装成功<br />
<a href="http://img.voidman.com/wp/2009/05/mogilefs.png"><img src="http://img.voidman.com/wp/2009/05/mogilefs.png" alt="mogilefs" title="mogilefs" width="541" height="104" class="grayborder alignnone size-full wp-image-289" /></a><br />
该扩展提供的<a href="http://svn.usrportage.de/php-mogilefs/trunk/README">方法和函数</a>可以直接使用，不过为了方便维护，可以对之进行一下简单的封装。</p>
<h3>改造 Discuz 的附件系统</h3>
<blockquote><p>
接下来会应用到 WordPress 的 Hook 机制，详见<a href="http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html">WordPress 的 Hook 机制在 Discuz 二次开发中的应用</a>
</p></blockquote>
<p><strong>附件上传</strong></p>
<p>在 Discuz 7 中附件的上传由<code>include/post.func.php</code>文件里的<code>attach_upload()</code>函数处理，我们在其中增加将附件添加到 MogileFS 的处理。由于 Discuz 7 支持远程上传附件到 FTP，并且可以设置成只上传到远程 FTP，这会删除上传到 WEB 服务器的原始附件，所以要在这之前处理。</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008000; font-style: italic;">// begin of hack</span>
dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_upload'</span>, <span style="color: #008080;">$attach</span>, <span style="color: #008080;">$target</span><span style="color: #800000;">&#41;</span>;
<span style="color: #008000; font-style: italic;">// end of hack</span>
&nbsp;
<span style="color: #008000; font-style: italic;">// 找到以下这行代码，在这之前添加以上代码</span>
<span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'remote'</span><span style="color: #800000;">&#93;</span> = !<span style="color: #008080;">$swfupload</span> ? ftpupload<span style="color: #800000;">&#40;</span><span style="color: #008080;">$target</span>, <span style="color: #008080;">$attach</span><span style="color: #800000;">&#41;</span> : <span style="color: #800080;">0</span>;</pre></div>

<p>mogilefs_attachment_upload 函数用来处理往 MoigleFs 添加附件。在前面提到，MogileFs 通过 KEY 来引用文件，我采用的 KEY 的规则是：</p>

<div class="wp_syntax"><pre class="ini">attach_<span style="">&#123;</span>attachment_md5<span style="">&#125;</span>_<span style="">&#123;</span>ext<span style="">&#125;</span>
attach_<span style="">&#123;</span>attachment_md5<span style="">&#125;</span>_thumb_jpg</pre></div>

<p>{md5} 是 Discuz 附件表 attachment 字段的 MD5 值，{ext} 是附件的扩展名。注意，Discuz 存储文件时会把部分可能不安全附件的后缀名更改为 attach。Discuz 中图片附件的缩略图均为 JPG 格式，所以 thumb_jpg 表示 JPG 格式缩略图的意思。</p>
<p>mogilefs_attachment_upload() 函数的处理流程:</p>
<ol>
<li>判断 MogileFs 扩展是否加载，否则退出处理</li>
<li>获取 MogileFs 单个操作实例</li>
<li>根据传入的附件信息（$target, $attach）生成 attach_key，然后往 MogileFs 提交文件</li>
<li>如果附件是图片，检查图片的缩略图是否存在，如果存在，则生成 thumb_key ，然后往 MogileFs 提交缩略图文件</li>
</ol>
<p><strong>附件删除</strong></p>
<p>Discuz 7 中附件文件的删除由<code>include/global.func.php</code>文件里的<code>dunlink()</code>函数处理，我们在该函数结束之前添加 MogileFs 的文件删除处理：</p>

<div class="wp_syntax"><pre class="php">dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_delete'</span>, <span style="color: #008080;">$filename</span>, <span style="color: #008080;">$havethumb</span><span style="color: #800000;">&#41;</span>;</pre></div>

<p>mogilefs_attachment_delete() 函数的处理流程:</p>
<ol>
<li>判断 MogileFs 扩展是否加载，否则退出处理</li>
<li>获取 MogileFs 单个操作实例</li>
<li>根据传入的附件路径 $filename 生成 attach_key，然后通过 MogileFs 提供的方法删除文件</li>
<li>根据 $havethumb 判断是否存在缩略图，若存在则生成 thumb_key，然后通过 MogileFs 提供的方法删除文件</li>
</ol>
<p>由于附件的上传中可能出现错误，Discuz 7 会做回滚处理删除本次上传出现错误之前已经正常上传的附件，而这些文件同样已经被上传到 MogileFs，故也要做删除处理：<br />
修改<code>include/post.func.php</code>文件里的<code>upload_error()</code>函数和<code>ftpupload_error()</code>：</p>

<div class="wp_syntax"><pre class="php"><span style="color: blue;">function</span> upload_error<span style="color: #800000;">&#40;</span><span style="color: #008080;">$message</span>, <span style="color: #008080;">$attacharray</span> = <span style="color: blue;">array</span><span style="color: #800000;">&#40;</span><span style="color: #800000;">&#41;</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
  <span style="color: blue;">if</span><span style="color: #800000;">&#40;</span>!<span style="color: blue;">empty</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$attacharray</span><span style="color: #800000;">&#41;</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
    <span style="color: blue;">foreach</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$attacharray</span> <span style="color: blue;">as</span> <span style="color: #008080;">$attach</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
      @<span style="color: #ff0000;">unlink</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$GLOBALS</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'attachdir'</span><span style="color: #800000;">&#93;</span>.<span style="color: #ff00ff;">'/'</span>.<span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'attachment'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#41;</span>;
      <span style="color: #008000; font-style: italic;">// begin of hack</span>
      dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_delete'</span>, <span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'attachment'</span><span style="color: #800000;">&#93;</span>, <span style="color: blue;">true</span><span style="color: #800000;">&#41;</span>;
      <span style="color: #008000; font-style: italic;">// end of hack</span>
    <span style="color: #800000;">&#125;</span>
  <span style="color: #800000;">&#125;</span>
  showmessage<span style="color: #800000;">&#40;</span><span style="color: #008080;">$message</span><span style="color: #800000;">&#41;</span>;
<span style="color: #800000;">&#125;</span>
&nbsp;
<span style="color: blue;">function</span> ftpupload_error<span style="color: #800000;">&#40;</span><span style="color: #008080;">$source</span>, <span style="color: #008080;">$attach</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
  @<span style="color: #ff0000;">unlink</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$source</span><span style="color: #800000;">&#41;</span>;
  <span style="color: blue;">if</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'thumb'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
    @<span style="color: #ff0000;">unlink</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$source</span>.<span style="color: #ff00ff;">'.thumb.jpg'</span><span style="color: #800000;">&#41;</span>;
  <span style="color: #800000;">&#125;</span>
  <span style="color: #008000; font-style: italic;">// begin of hack</span>
  dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_delete'</span>, <span style="color: #008080;">$source</span>, <span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'thumb'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#41;</span>;
  <span style="color: #008000; font-style: italic;">// end of hack</span>
  showmessage<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'post_attachment_remote_save_error'</span><span style="color: #800000;">&#41;</span>;
<span style="color: #800000;">&#125;</span></pre></div>

<p><strong>附件读取</strong><br />
附件的读取需要在 Discuz 后台打开“下载附件来路检查”选项，因为附件的读取操作是 hook 在<code>attachment.php</code>文件上的。</p>
<ul>
<li>
<p>缩略图处理</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008000; font-style: italic;">// begin of hack</span>
dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_fetch'</span>, <span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'attachment'</span><span style="color: #800000;">&#93;</span>, <span style="color: blue;">true</span><span style="color: #800000;">&#41;</span>;
<span style="color: #008000; font-style: italic;">// end of hack</span>
&nbsp;
<span style="color: #008000; font-style: italic;">//找到下面这行代码，在此之前添加上述代码</span>
getlocalfile<span style="color: #800000;">&#40;</span><span style="color: #008080;">$attachdir</span>.<span style="color: #ff00ff;">'/'</span>.<span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'attachment'</span><span style="color: #800000;">&#93;</span>.<span style="color: #ff00ff;">'.thumb.jpg'</span><span style="color: #800000;">&#41;</span>;</pre></div>

</li>
<li>
<p>其他附件处理<br />
    先删除<code>attachment.php</code>中的以下代码</p>

<div class="wp_syntax"><pre class="php"><span style="color: blue;">if</span><span style="color: #800000;">&#40;</span>!<span style="color: #008080;">$attach</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'remote'</span><span style="color: #800000;">&#93;</span> &amp;&amp; !<span style="color: #ff0000;">is_readable</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$filename</span><span style="color: #800000;">&#41;</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
  showmessage<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'attachment_nonexistence'</span><span style="color: #800000;">&#41;</span>;
<span style="color: #800000;">&#125;</span></pre></div>

<p>然后将以下代码添加到<code>getlocalfile()</code>函数的起始处，接管该函数读取本地附件的处理。</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008000; font-style: italic;">// begin of hack</span>
dz_do_action<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'mogilefs_attachment_fetch'</span>, <span style="color: #008080;">$filename</span><span style="color: #800000;">&#41;</span>;
<span style="color: #008000; font-style: italic;">// end of hack</span></pre></div>

</li>
</ul>
<p>mogilefs_attachment_fetch() 的处理流程</p>
<ol>
<li>判断 MogileFs 扩展是否加载，否则退出处理</li>
<li>获取 MogileFs 单个操作实例</li>
<li>根据传入参数判断读取的是缩略图还是原附件，生成 thumb_key 或 attach_key</li>
<li>通过 MogileFs 扩展提供的方法读取文件内容</li>
<li>输出</li>
</ol>
<p>当然，此外还有一些细节处理，如文件大小，文件头响应输出等，不再赘述。</p>
<h4>Related Posts</h4><ul class="related_post"><li><a href="http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html" title="WordPress 的 Hook 机制在 Discuz 二次开发中的应用">WordPress 的 Hook 机制在 Discuz 二次开发中的应用</a></li></ul><hr /><a href="http://www.voidman.com">Voidman.com</a> | Link: <a href="http://www.voidman.com/2009/05/mogilefs-for-discuz.html">http://www.voidman.com/2009/05/mogilefs-for-discuz.html</a><br /><img alt="linezing" width="1" height="1" src="http://img.tongji.linezing.com/288120/tongji.gif" />]]></content:encoded>
			<wfw:commentRss>http://www.voidman.com/2009/05/mogilefs-for-discuz.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>WordPress 的 Hook 机制在 Discuz 二次开发中的应用</title>
		<link>http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html</link>
		<comments>http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html#comments</comments>
		<pubDate>Fri, 01 May 2009 16:41:30 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[discuz]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.voidman.com/?p=285</guid>
		<description><![CDATA[最近工作需要对 Discuz 做二次开发，本着最小化改动方便以后升级的原则，我引入了 WordPress 的 Hook 机制（即 Plugin API）来降低二次开发代码与 Discuz 原生代码的耦合度。 WordPress 内部提供了许多 Hook（钩子），以便插件可以将相应的 action 或 filter 挂接上去接管或改进 WordPress 的默认处理来达到自己期望的目的，在处理完毕后将控制权重新交给 WordPress。而我们所要做的就是将这种机制移植到 Discuz 中，所幸的是，WordPress 的 Hook 机制并没有过多地依赖于它的其它核心程序，所以基本不需要做多少修改就可以拿来使用。 基本步骤 在 Discuz 安装目录新建一个文件夹，命名为extra，复制 WordPress 的wp-includes/plugin.php文件到此文件夹。为了符合 Discuz 名命名规范，将文件重命名为plugin.func.php 为了避免潜在的函数命名冲突，可以将plugin.func.php文件里的函数名称都加上前缀，例如do_action()修改成dz_do_action()；另外 plugin_basename(), register_activation_hook(), register_deactivation_hook(), register_uninstall_hook() 等函数可以删除。 &#8230; <a href="http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近工作需要对 Discuz 做二次开发，本着最小化改动方便以后升级的原则，我引入了 WordPress 的 Hook 机制（即 Plugin API）来降低二次开发代码与 Discuz 原生代码的耦合度。</p>
<p>WordPress 内部提供了许多 Hook（钩子），以便插件可以将相应的 action 或 filter 挂接上去接管或改进 WordPress 的默认处理来达到自己期望的目的，在处理完毕后将控制权重新交给 WordPress。而我们所要做的就是将这种机制移植到 Discuz 中，所幸的是，WordPress 的 Hook 机制并没有过多地依赖于它的其它核心程序，所以基本不需要做多少修改就可以拿来使用。<br />
<span id="more-285"></span><br />
<strong>基本步骤</strong></p>
<ol>
<li>在 Discuz 安装目录新建一个文件夹，命名为<code>extra</code>，复制 WordPress 的<code>wp-includes/plugin.php</code>文件到此文件夹。为了符合 Discuz 名命名规范，将文件重命名为<code>plugin.func.php</code></li>
<li>为了避免潜在的函数命名冲突，可以将<code>plugin.func.php</code>文件里的函数名称都加上前缀，例如<code>do_action()</code>修改成<code>dz_do_action()</code>；另外 <code>plugin_basename()</code>, <code>register_activation_hook()</code>, <code>register_deactivation_hook()</code>, <code>register_uninstall_hook()</code> 等函数可以删除。</li>
<li>在<code>extra</code>文件夹新建一个php文件，命名为<code>hooks.inc.php</code>，这里放置绝大部分 filter 和 action，将它们放在该文件中的一个最大的好处是方便集中维护。</li>
<li>载入相关文件。打开<code>include/common.inc.php</code>文件，找到

<div class="wp_syntax"><pre class="php"><span style="color: blue;">require_once</span> DISCUZ_ROOT.<span style="color: #ff00ff;">'./config.inc.php'</span>;</pre></div>

<p>在该行代码下面添加</p>

<div class="wp_syntax"><pre class="php"><span style="color: blue;">require_once</span> DISCUZ_ROOT.<span style="color: #ff00ff;">'./extra/plugin.func.php'</span>;
<span style="color: blue;">require_once</span> DISCUZ_ROOT.<span style="color: #ff00ff;">'./extra/hooks.inc.php'</span>;</pre></div>

<p>至此，基本的 Hook 机制已经建立
</li>
</ol>
<p><strong>实际应用示例</strong></p>
<p>接下来我们就可以开始添加自己的代码了。举个例子，Discuz 中<code>$discuz_auth_key</code>是这样定义的：</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008080;">$discuz_auth_key</span> = <span style="color: #ff0000;">md5</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$_DCACHE</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'settings'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'authkey'</span><span style="color: #800000;">&#93;</span>.<span style="color: #008080;">$_SERVER</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'HTTP_USER_AGENT'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#41;</span>;</pre></div>

<p>如果想将<code>$discuz_auth_key</code>的定义修改为<code>md5(authkey+user_agent+ip)</code>这样的形式，我们可以通过 filter 来实现。在<code>$discuz_auth_key</code>的定义代码下一行添加：</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008000; font-style: italic;">// 生成一个名为 discuz_auth_key 的钩子</span>
<span style="color: #008080;">$discuz_auth_key</span> = dz_apply_filters<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'discuz_auth_key'</span>, <span style="color: #008080;">$discuz_auth_key</span>, <span style="color: #008080;">$_DCACHE</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'settings'</span><span style="color: #800000;">&#93;</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'authkey'</span><span style="color: #800000;">&#93;</span>, <span style="color: #008080;">$_SERVER</span><span style="color: #800000;">&#91;</span><span style="color: #ff00ff;">'HTTP_USER_AGENT'</span><span style="color: #800000;">&#93;</span>, <span style="color: #008080;">$onlineip</span><span style="color: #800000;">&#41;</span>;</pre></div>

<p>然后打开<code>hooks.inc.php</code>文件，添加以下代码</p>

<div class="wp_syntax"><pre class="php"><span style="color: #008000; font-style: italic;">// 为了方便维护，所有 filter 类 hook 都以 filter_ 为前缀</span>
<span style="color: blue;">function</span> filter_discuz_auth_key<span style="color: #800000;">&#40;</span><span style="color: #008080;">$discuz_auth_key</span>, <span style="color: #008080;">$authkey</span>, <span style="color: #008080;">$ua</span>, <span style="color: #008080;">$ip</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
  <span style="color: #008000; font-style: italic;">// 符合自己设定的条件时才重新定义 authkey</span>
  <span style="color: #008000; font-style: italic;">// 否则返回 Discuz 定义的 discuz_auth_key 原值</span>
  <span style="color: blue;">if</span> <span style="color: #800000;">&#40;</span><span style="color: #008080;">$authkey</span> &amp;&amp; <span style="color: #008080;">$ua</span> &amp;&amp; <span style="color: #008080;">$ip</span><span style="color: #800000;">&#41;</span> <span style="color: #800000;">&#123;</span>
    <span style="color: #008080;">$discuz_auth_key</span> = <span style="color: #ff0000;">md5</span><span style="color: #800000;">&#40;</span><span style="color: #008080;">$authkey</span> . <span style="color: #008080;">$ua</span> . <span style="color: #008080;">$ip</span><span style="color: #800000;">&#41;</span>;
  <span style="color: #800000;">&#125;</span>
  <span style="color: blue;">return</span> <span style="color: #008080;">$discuz_auth_key</span>;
<span style="color: #800000;">&#125;</span>
&nbsp;
<span style="color: #008000; font-style: italic;">// 将 filter 函数 filter_discuz_auth_key 挂接到 discuz_auth_key 钩子上</span>
<span style="color: #008000; font-style: italic;">// 第三个参数的值 10 代表执行优先级，因为一个钩子上可以挂接多个callback函数</span>
<span style="color: #008000; font-style: italic;">// 第四个参数的值 4 代表允许 filter_discuz_auth_key 函数接收的参数个数</span>
add_filter<span style="color: #800000;">&#40;</span><span style="color: #ff00ff;">'discuz_auth_key'</span>, <span style="color: #ff00ff;">'filter_discuz_auth_key'</span>, <span style="color: #800080;">10</span>, <span style="color: #800080;">4</span><span style="color: #800000;">&#41;</span>;</pre></div>

<p>这样便达到我们所要的效果了。当然有些情况下还是无法避免了二次开发代码与原代码的夹杂在一起，不过由于有了 Hook 机制，这种情形已经可以大大减少了。</p>
<p><strong>相关阅读</strong><br />
<a href="http://codex.wordpress.org/Plugin_API">WordPress Plugin API</a></p>
<h4>Related Posts</h4><ul class="related_post"><li><a href="http://www.voidman.com/2009/11/media-temple-hacked.html" title="Media Temple Hacked">Media Temple Hacked</a></li><li><a href="http://www.voidman.com/2009/05/mogilefs-for-discuz.html" title="在 Discuz 中应用 MogileFS 分布式文件存储系统">在 Discuz 中应用 MogileFS 分布式文件存储系统</a></li><li><a href="http://www.voidman.com/2009/04/at-reply-mail-notification-1-release.html" title="At Reply Mail Notification 1.0 Release">At Reply Mail Notification 1.0 Release</a></li><li><a href="http://www.voidman.com/2009/03/lbs-to-wordpress.html" title="LBS 转 WordPress 不完全记录">LBS 转 WordPress 不完全记录</a></li><li><a href="http://www.voidman.com/2009/01/wordpress-is-using-a-bad-way-to-detect-duplicate-comment.html" title="Wordpress 糟糕的重复评论检测方式">Wordpress 糟糕的重复评论检测方式</a></li><li><a href="http://www.voidman.com/2009/01/at-reply-mail-notification-test.html" title="At Reply Mail Notification 测试贴">At Reply Mail Notification 测试贴</a></li><li><a href="http://www.voidman.com/2008/11/automatically-delete-post-revisions.html" title="让 Wordpress 自动删除 Post Revisions">让 Wordpress 自动删除 Post Revisions</a></li><li><a href="http://www.voidman.com/2008/11/google-xml-sitemaps-ignore-the-specified-categories.html" title="让 Google Sitemaps Generator 可以忽略指定的日志分类">让 Google Sitemaps Generator 可以忽略指定的日志分类</a></li><li><a href="http://www.voidman.com/2008/11/the-better-solution-for-static-paged-post.html" title="Wordpress 分页文章静态化的更优解决方案">Wordpress 分页文章静态化的更优解决方案</a></li><li><a href="http://www.voidman.com/2008/07/upgraded-to-wordpress-v26.html" title="升级到 WordPress 2.6">升级到 WordPress 2.6</a></li></ul><hr /><a href="http://www.voidman.com">Voidman.com</a> | Link: <a href="http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html">http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html</a><br /><img alt="linezing" width="1" height="1" src="http://img.tongji.linezing.com/288120/tongji.gif" />]]></content:encoded>
			<wfw:commentRss>http://www.voidman.com/2009/05/using-wordpress-plugin-api-hack-discuz.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

