续集:加强服务器安全性保护WordPress

自上次写过WordPress被黑之后,虽然安装了Wordfence,但发现依然不够,Wordfence能反复扫描出各种被黑的PHP木马。

没想到WordPress的安全性如此成问题,看来安全性还是必须从系统入手,不能光依赖WordPress本身。

一、禁用PHP的系统相关函数

首先经过检查,发现虽然篡改了PHP文件,甚至在tmp下面跑了一个进程,但似乎并没有渗透到系统级别,没有获得root权限,所以我立即在php.ini里面禁用了一些系统相关的函数,以防止被获得系统的权限


disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexi
ted,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_ws
topsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pc
ntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriorit
y,pcntl_setpriority,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,cu
rl_multi_exec,parse_ini_file,show_source

二、将WordPress目录下的文件权限改为root

为了防止PHP文件被插入恶意脚本,我将PHP文件都设置为只读,虽然这样会导致WordPress无法自动更新或者是自动安装插件,但要好过被篡改。然而uploads目录是必须要可以写入的,没有这个功能无法上传图片。


# chown -R root .
# chown -R www-data wp-content/uploads

三、禁止 uploads 目录中执行任何 PHP 脚本

在做了前两步之后,我发现依然有黑客可以上传脚本到 uploads 目录下,并通过远程请求调用执行,所以必须要禁止这个目录下的PHP脚本的运行。我在nginx中增加了一下配置


server {
listen 80;
server_name shiningray.cn *.shiningray.cn ;
root /var/www/shiningray;
index index.html index.htm index.php;
include /etc/nginx/php_params;
location ~* /(?:uploads|files)/.*.php$ {
deny all;
}

}

四、配置防火墙

当我还没配置第三步的时候,我通过 netstat 和 lsof 等指令调试系统的时候,发现PHP进程会连接到很多邮件服务器的25(smtp)端口,我想起来之前Linode客服所说的经常能发现我的服务器在投递垃圾邮件,原来是拿我当肉鸡发垃圾邮件。所以我觉得直接堵死smtp端口的连接,就可以断了他们的念想。

我使用Ubuntu的ufw来配置了端口的访问:

表示拒绝任何从本地发起到外部25端口的连接,使用 deny 替换掉 reject 也可以,但是 deny 是丢弃掉链接上发出去的包,而 reject 是直接断开链接。由于木马往往会反复不停的尝试,如果只是deny的话,可能会导致进程被堵死,所以最后选择了 reject

至此之后,再也没有感染过PHP的恶意脚本了。

php shell

本文要讲的php shell并非是使用php来写shell脚本,而是讲一个php的REPL的交互式shell。所谓REPL,也就是read-eval-print-loop,也就是说,shell读入一个指令,计算,然后输出结果,常见的有Python、Ruby的IRB等。

对于PHP,我们常常会写一个test.php,然后放入一些自己的代码,再打开浏览器检验一下,如果不对,又要重新修改代码,非常麻烦。交互式shell的好处就可以体现出来了,输入指令之后可以立刻看到执行代码的结果,所以非常适合用来检验代码片段(snippets)的正确性以及进行一些试验。

PHP本身自带一个交互式的shell,在命令行中输入php -i,便可以交互式运行,但要先输入一个php脚本的起始标签,但是该shell遇到异常的时候会直接退出,非常不方便。那么我找到一个非常接近于REPL的交互式shell便是php-shell


1. 安装

php-shell要求php 5.0以上版本

下载PHP_Shell-0.3.1.tgz

运行pear install PHP_Shell-0.3.1.tgz

如果确保pear已经安装,并在你的PATH路径中

2. 使用方法

在命令行下输入php-shell(Linux为php-shell.sh)进入交互式命令行:

这时候我们可以输入我们所需的表达式了,在php-shell中直接输入变量名,它也可以将内容直接打印出来:

当出现异常时,php-shell也会打印出异常的内容。
你可以使用exit退出。

3. Tab补全

php-shell一个强大的功能是支持补全,以下内容可以被补全:

  • new 类名()
  • 类名::方法名()
  • 类名::常量名
  • $变量名
  • 函数名()
  • $object->方法名()

请先输入第一个字符然后按TAB按钮。如果只有一种匹配,它便会直接补全名称,否则,再按一次TAB会列出所有的可能性。

如果你想查看所有已声明的类,你可以使用 getdeclaredclasses():

4. 总结

如果是php新手,希望php-shell能帮你快速掌握php。老手也可以用其来检验代码段。

除此之外,也可以尝试一下基于Web页面的php shell,如http://phpshell.sf.net/

PHP的二进制位移操作

PHP主要是设计于文本操作的,其实PHP不适合做数学运算,效率也不高,不过因为这次的项目中有个东西必须使用到二进制位移操作,在PHP上面遇到了一些麻烦。

因为PHP只有32位有符号整数,没有64位长整型,也没有无符号整数。其整型的范围是-231-1~231,超出这个范围的,将被解释为浮点数。因此,0xFFFFFFFF,直接打印,显示的是4294967295,及232

而在32位有符号整型中,0xFFFFFFFF应表示-1:

而PHP不支持浮点数的二进制位移操作,如果要进行,会先转换为整型,最后的结果,也将按照整型来返回:

同时PHP的向右位移操作,高位会填充符号位,而且PHP没有提供类似Java的>>>来强制填充0:

如何解决这个问题呢,我考虑过使用BCMath数学函数库,直接处理字符串表示的整数,或者是GMP/BigInt扩展等。不过我想既然使用字符串,那么我可以字符串地彻底一些,把数字转换成32个二进制的字符串,再手工填充0,最后转换回来。

不知道哪位有更好的方法,请告诉我。

代码如下:
直接下载代码:shift.php
(另外,其实代码可以扩展为任意位2进制的位移操作,这里我没有做)

Nginx的WordPress配置

WordPress是一个非常流行的Blog系统,它可以利用Apache的mod_rewrite来实现URL的静态化。安装好的WordPress在配置了持久链接之后,会在网站的根目录下(如果可写)生成一个.htaccess文件,这个文件可以指示Apache如何进行URL重写(如果服务器配置为允许使用htaccess的指令的话),它的内容如下:

这个文件的意思就是,如果当请求的文件不存在,那么把请求内部重定向到/index.php。WordPress会自己分析请求的URL,来判断显示哪个页面。

在上次配置了Nginx+PHP之后,由于Nginx不支持Apache的.htaccess文件,要实现持久连接静态化,我们必须手工配置Nginx的文件。首先找到Nginx的配置文件,默认编译后的配置文件在/usr/local/nginx/conf/nginx.conf;Ubuntu通过包安装的配置文件位于/etc/nginx/nginx.conf,也可以编辑vhost的配置文件,放在了/etc/nginx/sites-available下。

以下是基本的配置(Ubuntu下的范例):

还可以有很多种不同配置方式,例如不改写所有包含wp-的url等。此配置考虑了目录下的索引文件index.html和index.php。-f指令表示测试文件是否存在(不考虑文件和目录的区别),!-f则表示不存在。注意在重写url到index.html后面有个break,而重写到index.php后没有break。因为html文件不需要任何额外工作可以直接发送到客户端,所以重写规则在这里终止,下面就直接让nginx发送文件。而.php文件需要进一步发送到fastcgi进程来运行,Nginx会继续判断该文件符合第二个部分location ~ .*\.php$的规则,并进行FastCGI的转发。

大家可以将以上内容保存为wordpress.conf,然后在自己的vhost配置,即server节中应用该配置文件,例如(以下为Ubuntu进行的配置):

接下来让Nginx重新载入配置文件,便可使用WordPress的持久链接了。

Linux 上配置 Nginx + PHP5 FastCGI

Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。其拥有匹配Lighttpd的性能,同时还没有Lighttpd的内存泄漏问题,而且Lighttpd的mod_proxy也有一些问题并且很久没有更新。

因此我打算用其替代Apache应用于Linux服务器上。但是Nginx并不支持cgi方式运行,原因是可以减少因此带来的一些程序上的漏洞。那么我们必须使用FastCGI方式来执行PHP程序。

下面是我成功地配置Nginx + PHP5 FastCGI的过程

继续阅读“Linux 上配置 Nginx + PHP5 FastCGI”

PHP4.4.6和Mysql 5.0兼容性

这次有台Windows服务器拿到手中,需要装AMP,我一激进,装了Apache2.2.4 + Php5.2.1 + mysql-5.0.37。事后发现,网站程序用PHP4写的,和PHP5.2.1有点兼容性问题,于是乎换装PHP4,发现PHP4没有Apache2.2的模块,只好用CGI方式安装。接下来程序运行报错数据库无法连接,猜测是php4的mysql扩展不兼容mysql5。在网上找了半天,发现有老外自己编译了一个php4.4.6的补丁,下载覆盖了原来的dll文件,然后便成功了,特此备忘。

Paypal IPN接口开发小结

最近终于搞定了该死的Paypal ipn,特地在此留下点东西备忘。
所谓paypal ipn(Instant Payment Notification),就是Paypal开发的一种能主动通知第三方卖家系统交易状态的一种机制。IPN的原理很简单,就是当产生了一个交易之后,交易状态发生变化时,如用户已经付款、或者退款、撤销时,Paypal利用常用的HTTP POST方式,将交易的一些变量提交给网站的某个页面(称之为IPN Handler),当这个页面接受到请求时候,将这些数据原封不动加上一个指示验证的cmd=_notify-validate,POST回Paypal的接口地址,如果数据正确,那么Paypal返回字符串VERIFIED,否则为INVALID,如果结果为VERIFIED,那么你的程序就可以使用这些数据进行操作。
但代码的调试是一件很痛苦的事情,因为作为第三方开发人员,不可能开两个帐号,每次测试还要之间交易一些钱,所以Paypal专门开发了Sandbox给开发人员进行开发,首先到https://developer.paypal.com/ 注册一个开发帐号,好了之后再进入Sandbox建立测试用的Paypal虚拟帐号(至少应该建立一个Business的和一个Personal的),这种账号注册方法和Paypal的流程一样,信息可以是假的,包括银行帐号、信用卡(其实Paypal Sandbox会自动生成一些随机的号码)。接下来需要激活Paypal Sandbox的虚拟帐号,注意,这里不管你在Paypal Sanbox注册时填什么邮件地址,有任何发送到虚拟帐号所填邮箱的邮件都存会在开发帐号的管理界面中的Email页(导航栏上有)中。登录Sandbox的虚拟Paypal环境,还需要验证虚拟帐号的银行,这里可以随便填,然后通过Add Funds来给账户充值(想填多少填多少)。然后,还需要激活IPN的选项,在Business的那个账户的Profile设置页面中,点击,然后点击Edit按钮,打开IPN,这里如果你使用的是固定的IPN Handle,可以直接将地址填入。
接下来,我们测试的时候,应该将Paypal接口的地址设置为https://www.sandbox.paypal.com/cgi-bin/webscr
最后基本的流程为:

  • 用户在我们的网站上选择商品、放入购物车,然后检查准备支付
  • 网站根据购物车中的商品,生成Paypal的支付表单(也是提交到上面IPN用的Paypal接口地址),包含了此次交易的一些信息(下次会专门找机会解释一下)。并在自己的数据库中生成一张订单记录。
  • Paypal在Session中记录下这些交易信息
  • 用户用Paypal账户登录Paypal(Sandbox用Sandbox的虚拟帐号),复查明细,点击Pay按钮
  • Paypal进行交易处理,如果我们的Paypal收款帐号在接受帐款上没有什么问题(没有特别的需要在界面上“Accept”的地方),交易完成,那么Paypal会发送一个IPN,并发送提示邮件。
  • 我们IPN Handler接受到信息,首先向Paypal进行校验,如果信息正确,然后根据信息和自己数据库中进行比对,如果无误,可以将支付信息保存,并修改订单状态。
  • 然后Paypal会显示一个界面表示交易完成,此时如果用户点击“Return”按钮,Paypal会将用户送回我们网站指定地点。
  • 我们网站迎接用户回来,向用户表示感谢,并进行提醒,给出订单号等等。

整个流程基本如下,不过其中有很多要注意的地方:

  1. 我们看到了,接口地址是https开头的,也就是要求使用SSL进行连接,其实Paypal Sandbox可以使用http,但是最后实际的Paypal接口,不支持http协议,所以如果你用PHP写IPN Handler脚本的话,在验证信息的代码部分,如果简简单单使用fopen、HTTP_Request之类的工具是没用的,PHP的socks库不支持SSL,应该使用curl,有两种方法,一个是使用PHP扩展中的libcurl,Paypal官方发布的SDK中便是使用的这个方法,但Paypal的SDK非常复杂,如果想自己写,可以使用Snoopy,一个简单实用的PHP请求库(它自己说是模拟了浏览器的行为),而它使用的是Curl的可执行文件,通过管道获得结果,而非php的libcurl,所以自己cURL的主页上下载一个支持SSL的编译版本,可能还需要安装OpenSSL,不过对于Linux系统,可能应该会都带。
  2. 在支付表单中,可以自己设置notify_url字段,来指定此次交易的信息应该发送到哪个地方,这样就可以覆盖在Profile中我们的设置,另外,这个字段要进行urlencode
  3. 我们得到的IPN信息中,status对应的便是交易状态,如Complete表示完成,首字母大写,而验证结果则是VERIFIEY或者INVALID,全部大写,具体的内容,可以查看Paypal官方的文档订单管理整合指南

Cache_Lite的检测缓存失效

PEAR组件Cache_Lite是一个很实用的文件缓存组件,我在PHP编程中常常用到,现在我常需要检测某个id的缓存是否已经失效了,而Cache_Lite本身并未提供这样的功能,因此我写了这样一个函数:

使用也很简单,应该一眼就能看明白。当然也可以通过继承Cache_Lite,并添加一个方法来完成。

Zend Framework 指南

作者:Chris Shiflett
翻译:ShiningRay

我们邀请了PHP安全专家——兼最新发布的Zend Framework的贡献者——Chris Shiflett来为我们写一篇关于ZF主要特点的文章。

这份完整的、按部就班的教程通过向你展示如何应用框架写出一个简单的新闻管理系统,为你提供了构建实际应用的独特视角。

Zend Framework终于掀开了其神秘的面纱!尽管它尚处于开发过程的早期阶段,但本文将现在所能用的中最好的部分特别呈现给读者,并通过构建一个简单的应用这个过程引导你了解这个框架。

Zend很早就发布了框架并引入社区运作。写本指南只能针对框架今天的情况来列出其特点。因为本指南是在线发布的,所以我会在框架发生变化的时候及时更新本文,这样就能尽可能保持一致。

要求

Zend Framework 要求使用 PHP 5。为了能完全利用本指南中展示的代码,你还需要Apache Web服务器,因为范例应用(一个新闻管理系统)用到了mod_rewrite。

本指南中的代码可以自由下载,所以你可以亲自尝试一下。可以从Brain Bulb的网站上下载到:http://brainbulb.com/zend-framework-tutorial.tar.gz.

下载框架

在开始阅读本指南之前,你还需要先下载一份框架的预览发布版。可以用浏览器察看 http://framework.zend.com/download 并选择 tar.gz 或者 zip 文件手工下载,也可以使用下面的命令行:

清单1

注意

Zend已经计划提供一个独立的PEAR通道来方便下载。

下载了预览发布版之后,将这个库的目录放到一个方便的地方。在本教程中,我将库的目录名改称了lib,以便提供一个简单干净的目录结构:

清单2

www 目录是文档根目录,controllers和views目录为空,是将来要用的,lib目录是来自于下载的预览版。

入门

我第一个要向你展示的组件是Zend_Controller。在很多情况下,它为要开发的应用提供了一个基础,同时它也是令Zend Framework超越了组件集合的一个部分。不过在使用它之前,需要将所有进入的请求引导到某个PHP脚本中。本教程将使用mod_rewrite来完成这个目的。

如何用好mod_rewrite确实是一门艺术,不过还好本文中这个特殊的任务十分简单。如果你对mod_rewrite或者是Apache的一般配置还不是很熟悉的话,可以在文档根目录下创建一个.htaccess文件,并加入一下指令:

清单3

Zend_Controller目前的任务之一就是去掉对mod_rewrite的依赖。为了提供一个预览版可以使用的例子,本教程便使用了mod_rewrite。

如果你直接在httpd.conf中添加这些指令,还必须重新启动Web服务。但是,如果使用.htaccess文件,就不用了,而且这样更好。你可以随便在index.php中写点东西,然后任意请求某些路径来测试一下,比如/foo/bar。例如,如果你的主机是example.org,那么就请求URL http://example.org/foo/bar。

可能你还想在 include_path 中包含框架库的路径。你可以直接在php.ini中配置,或者可以将以下指令放入.htaccess文件中:

清单4

Zend

Zend 类包含了一系列十分通用也十分有用的静态方法。这是唯一一个需要手工进行包含的类:

清单5

一旦引用了Zend.php,就可以访问Zend类中的所有方法了。使用loadClass()方法,载入其他类也变得简单了。例如载入Zend_Controller_Front类:

清单6

loadClass()方法会考虑到include_path,同时它还知道框架的目录组织结构。我就使用它来载入所有其他的类。

Zend_Controller

这个控制器的使用还是比较直观的。实际上,我写这份指南的时候可没有官方文档可用!

现在ZF网站上已经有官方文档了。

首先讲Zend_Controller_Front,这是一个前端控制器。你可以将下面的代码放入index.php中来理解它是如何工作的:

清单7

如果你更希望使用对象链方式,可以如下改写:

清单8

现在,当进行/foo/bar的请求时,就会出现一个错误。这很好!它至少能告诉你有动作了。主要的问题是未发现IndexController.php

在创建这个文件之前,最好首先了解框架组织东西的方式。框架会将一个请求分解成几个部分,在这个例子中,请求/foo/bar,foo是控制器,bar是动作。两者的默认值都是index。

当foo作为控制器时,框架首先在控制器目录中查找名叫FooController.php的文件。因为不存在这个文件,于是框架退一步查找IndexController.php。如果还是没有发现,就报告错误。

下面,在controllers目录(可以使用setControllerDirectory()自己设置)中创建IndexController.php

清单9

IndexController类处理控制器为index的请求或者指定的控制器不存在的请求,就像刚才所说的。indexAction()方法将处理动作为index的请求。记住无论是控制器还是动作,默认的值都是index,前面也说过了。如果尝试请求/、/index或者/index/index,都会执行indexAction()方法(结尾的斜杠不会改变这种行为)。对任何其他资源的请求都可能会产生错误。

继续之前还要为IndexController添加一个很有用的方法noRouteAction()。一旦请求某个控制器且其不存在时便调用noRouteAction()方法。例如,请求/foo/bar时,如果FooController.php不存在,那么就会执行noRouteAction()。不过,/index/foo的请求还是会产生错误,因为这里foo是一个动作,而非控制器。

在IndexController中添加 noRouteAction() :

清单10

这个例子使用了 $this->_redirect(‘/’) 来描述可以在noRouteAction()中一般可能出现的动作。这可令对不存在的控制器的请求被重定向到根文档(首页)。

现在来创建 FooController.php:

清单11

如果你再请求 /foo/bar,就应该看到执行了barAction(),因为请求的动作是bar。这样不仅可以支持友好的URL,同时也可以用极少的代码就可以很好得进行组织。酷啊!

还可以创建一个__call()方法来处理未定义的动作的请求,如 /foo/baz:

清单12

现在只需几行代码就可以很优雅地处理进入的请求了,让我们继续。

Zend_View

Zend_View是一个可以协助你组织视图逻辑的类。它并不使用特定的模版系统,为了简便起见,在本例中我也不会使用模版系统。然而,你可以随意使用你喜欢的。

记住所有进入的请求都是由前端控制器来处理的。因此,既然应用程序的框架已经这样存在了,那么以后的天价都必须适应它。为了演示Zend_View最基本的用法,我们将IndexController.php中的代码修改成这样:

清单13

在视图目录(这里是views)创建一个叫做example.php的文件:

清单14 –

现在,当请求网站的根的资源时,应该可以看到example.php的内容。虽然现在这还不是很有用,不过记住你的工作目标是按照一个结构化、有组织的方法来开发Web应用。

为了更清楚地利用Zend_View,将模版(example.php)修改一下,包含一些数据:

清单15

添加了两个额外的特性。$this->escape()方法必须用在所有的输出上。即便你要自己创建输出(例如这个例子中的),也要将所有的输出进行转义,这种好习惯可以防止出现跨站脚本(XSS)。

$this->title$this->body特性在这里是用于演示动态数据的。它们应该在控制器中定义,所以让我们修改IndexController.php来给他们赋值:

清单16

现在你再浏览网站,应该看到了模版所使用的这些值。在模版中使用$this的原因是模版是在Zend_View的实例的范围内执行的。

记住example.php仅仅是一个普通的PHP脚本,所以你可以在其中做任意你想做的事情。最好还是尽量遵守规则,仅仅在模版中进行显示数据的工作。控制器(或者是控制器进行分配的模块)则应该承担所有的业务逻辑。

在继续讲之前,我要最后对Zend_View做一个补充。在每个控制器的方法中实例化$view对象会要额外输入很多东西,而我们的主要目标是更简单、更快速地进行开发。而且,如果模版都存放在同一个目录下的话,每次都要调用setScriptPath()也是一件麻烦事。

幸好,Zend类包含了一个注册表,它可以帮助我们消除这种反复的工作。你可以使用register()方法将$view对象存放在注册表中:

清单17

可以使用registry()方法来获取它:

清单18

从今往后,本教程就会使用注册表了。

Zend_InputFilter

The last component this tutorial covers is Zend_InputFilter. This class provides a simple but rigid approach to input filtering. You instantiate it by passing an array of data to be filtered:

清单19

他会把数组($_POST)设置为NULL,这样就不可能再直接进行访问了。Zend_InputFilter提供了一些根据特定条件筛选数据的方法。例如,如果你需要$_POST['name']都是字母,可以使用getAlpha()方法:

清单20

传给每一个筛选方法的参数是对应要进行筛选的数组元素的键。该对象(在这个例子中是$filterPost)是一个包含了有错误的数据的保护笼,这使得对数据的访问更加可控和一致。因此,当要访问输入数据的时候,应该使用Zend_InputFilter

Zend_Filter提供了一些静态的过滤方法,这些方法和Zend_InputFilter的方法遵循同样的规则。

创建一个新闻管理系统

尽管预览版还包含了很多组件(甚至还有更多的正在进行开发),但是只需要使用前面讨论过的组件就可以构建简单的应用了。在构建应用的过程中,你就会对框架的基本结构和设计有一个更加清晰的理解。

每个人开发应用的方式都有所不同,所以Zend Framework尽可能地尝试包容这些差异。同样,本教程是根据我的偏好写的,所以你可以将它们调整为适合自己口味的方式。

当我开始开发某个应用时,我是先从界面开始的。这并不是说我喜欢做表面文章,花大量功夫在样式、图片上,其实我是站在一个用户的角度来透视问题。这样,我将一个应用看作是一系列页面的集合,每个页面对应一个唯一的URL。这个新闻管理系统有以下一些URL组成:

清单21

马上开始根据控制器考虑这些URL。IndexController显示新闻、AddController处理新闻和评论的添加,AdminController处理诸如审批新闻之类的管理工作,以及ViewController用于查看指定的新闻条目和相应的评论。

首先,如果有FooController.php,先将其删除,并修改IndexController.php并添加合适的动作,并加入一些关于业务逻辑的注释放着:

清单22

下面,创建AddController.php:

清单23

注意AddControllerindexAction()不应被调用。只有当请求的路径是/add时才会调用这个方法。因为用户也许会手工输入URL,还是有可能会被调用的,所以这时应该将用户重定向到首页、显示一个错误或者你觉得合适的动作。

下面,创建AdminController.php:

清单24 –

最后,创建ViewController.php:

清单25

AddController中的一样,index()方法应该是不可能会被调用的,所以可以在其中安排任何动作。ViewController和其他的有些不同,因为还不知道什么是有效的动作。为了能支持类似/view/23这样的URL,必须使用__call()来支持动态动作。

与数据库进行交互

因为Zend Framework的数据库组件相对还不太稳定,同时我又希望例子更容易使用,所以我使用了SQLite的类来存储和获取新闻条目以及评论:

清单26

当然,你可以用自己的解决方案来替换这个类。包含它只为了提供一个完整的例子,并不是给出一个推荐的实现。

这个类的构造器需要获得SQLite数据库的完整路径和文件名,数据库必须事先创建好:

清单27

这只需要运行一次,然后就只要将完整的路径和文件名传给Database类就行了:

清单28

整合

为了能将所有的东西放到一起,先在lib目录中创建Database.php,这样loadClass()就能找到它了。而index.php文件现在要实例化$view$db并将它们存储在注册表中。也可以创建一个叫做__autoload()的函数来自动加载所有需要用到的类:

清单29

下面,在视图目录中创建一些简单的模版。index.php文件可以用于显示index视图:

清单30 –

view.php 模版可以用于显示特定的新闻条目:

清单31

最后,admin.php模版可以用于审批新闻条目:

清单32

为了简单起见,就使用一个带密码的表单作为访问控制机制。

放好了这些模版之后,就只要将原来放在控制器中占着位置的注释替换成几行代码。例如,IndexController.php就变成了:

清单33

组织好所有的东西之后,应用的首页的完整的业务逻辑就被减至四行代码。AddController.php还要再处理一下,需要更多的代码:

清单34

因为用户在提交了一个表单之后被重定向了,所以在这个控制器里面不需要视图。

AdminController.php中,要处理两个动作,显示管理界面和审批新闻:

清单35

最后是ViewController.php:

清单36

这段代码提供了一个功能完整——虽然非常简单的——的新闻共享和评论的应用。最好的地方就是借助于框架优雅的设计,添加更多的功能十分简单,同时随着Zend Framework的逐渐程序,各方面都会变得更好。

更多资料

本指南仅仅是讲解了一些皮毛,还有一些其他的资源可以参考。除了官方手册之外,Rob Allen提供了一些他对于Zend Framework的详细感受,Richard Thomas也给出了一些有用的注释。如果你有自己的看法,可以在本页上留下留言说出自己的想法。

结语

不过还是能发现这个预览版有些粗糙,我自己写这个教程的时候,遇到过一些挫折。不过整体上来说,我认为Zend Framework兑现了大部分承诺,同时所有的参数者依然在继续努力改进它。Chris Shiflett 是 Brain Bulb——一个专于PHP开发和安全性的咨询公司—— 的主席,你可以阅读一下Chris的Blog或者访问Brain Bulb的网站

什么是 Cake?

Cake 是一个针对PHP的,使用了诸如ActiveRecord、Association Data Mapping、Front Controller和MVC等知名设计模式的快速开发框架。我们的主要目标是提供一个可以令各种层次的PHP用户快速地开发出健壮的Web应用,而又不失弹性。

为什么使用 Cake?

  1. 灵活的许可证MIT License
  2. 完全自主的知识产权:每一行代码都是由CakePHP开发小组写出来的。
  3. 极其简洁:只要看看名字就知道了……
  4. 快速开发:开发之迅速史无前例。(看看zZine的文章
  5. 最佳实践:Cake很容易理解,而且已经把工业标准设置在了安全性、会话处理和其他的东西中。
  6. 面向对象: 无论你是一个老练的OO程序员还是一个初学者,都可以感到十分轻松。
  7. 无需配置:只要安装好数据库,好戏就开场了。

厌倦了不断重复?总是Ctrl-C然后Ctrl-V代码?想让你的应用更快速地转化成产品?请选择Cake!看看Wiki立刻上手。

关键特性

  • 兼容 PHP4 和 PHP5
  • 提供了集成的数据库 CRUD 和简化了的查询
  • 请求分配器,和美观的、可自定义URL。
  • 快速、灵活的模版机制(使用PHP语法和助手方法)
  • 可以从任何网站的子目录中运行,只需要少量甚至无需改动Apache的配置。

立刻加入

我们一直在寻找人手来帮助我们写指导、进行测试和书写文档。参与的最佳地点就是IRC。我们正在完善一些针对希望对这个项目编写代码的贡献者指导方针。当然,任何人都可以提出您宝贵的意见和建议。
#cakephp at irc.freenode.net ? CakePHP Wiki ? CakePHP Google Group ? CakeTRAC (development site)

指南