17.06.2015 Views

封面

封面

封面

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

封 面<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 1/111


卷 首 语<br />

《PHPer》<br />

卷 首 语<br />

Zend Framework 全 接 触<br />

PHP 的 发 展 也 不 是 一 帆 风 顺 : 从 2000 年 左 右 PHP3.0 的 风 行 , 到 2005 年 PHP 一<br />

度 陷 入 低 谷 , 再 到 现 在 PHP 的 再 度 崛 起 ,PHP 走 过 了 一 条 曲 折 的 道 路 。PHP 从 5.0 开<br />

始 , 面 向 对 象 的 功 能 趋 于 完 善 , 然 后 是 Zend Framework 的 发 布 , 由 此 我 们 能 够 看 出<br />

Zend 公 司 向 企 业 开 发 市 场 进 军 的 意 图 和 雄 心 。<br />

PHP 在 4.0 之 前 , 主 要 以 面 向 过 程 的 开 发 为 主 , 代 码 中 包 含 着 大 量 的 系 统 函 数 和<br />

用 户 自 定 义 函 数 。 但 是 即 使 PHP5.0 之 后 充 分 考 虑 了 对 类 和 对 象 的 支 持 , 但 是 大 多 数<br />

程 序 员 的 代 码 中 真 正 应 用 对 象 的 时 候 并 不 多 , 程 序 员 还 是 习 惯 像 ASP 一 样 书 写 结 构 化<br />

的 面 向 过 程 的 代 码 。 面 向 对 象 的 好 处 并 没 有 被 大 家 充 分 挖 掘 出 来 。<br />

每 种 语 言 几 乎 都 有 若 干 个 框 架 可 用 。 选 择 刚 好 满 足 业 务 需 求 的 框 架 可 能 有 点 为 难 ,<br />

但 是 选 择 框 架 时 应 当 要 求 其 节 省 的 时 间 和 精 力 越 多 越 好 。 如 果 一 个 框 架 工 作 得 很 好 但<br />

是 耗 费 大 量 的 支 持 成 本 ; 或 者 即 使 易 于 支 持 , 但 是 起 到 的 反 作 用 大 于 正 面 辅 助 开 发 作<br />

用 , 那 也 不 是 一 个 好 的 框 架 。 如 果 一 个 框 架 十 分 “ 优 雅 ”, 但 是 在 支 持 和 开 发 中 问 题 频<br />

发 , 那 么 这 个 框 架 也 是 没 有 任 何 用 处 的 。<br />

目 前 流 行 和 比 较 流 行 的 PHP 框 架 已 经 不 少 , 例 如 Zend 框 架 ,FleaPHP,CodeIgniter,<br />

ThinkPHP,CakePHP 等 。 选 择 学 习 一 个 框 架 可 能 全 凭 个 人 爱 好 。Zend Framework 大<br />

量 应 用 了 PHP5 中 面 向 对 象 的 新 特 征 : 接 口 、 异 常 、 抽 象 类 、SPL 等 等 。 这 些 东 西 的<br />

应 用 让 Zend Framework 具 有 高 度 的 模 块 化 和 灵 活 性 。 同 时 , 因 为 严 格 遵 循 “ 针 对 接 口<br />

编 程 ” 和 “ 单 一 对 象 职 责 ” 等 原 则 , 让 Zend Framework 很 有 希 望 成 为 一 个 出 色 的 企 业 应<br />

用 开 发 框 架 。 但 同 时 也 有 批 评 者 指 出 Zend Framework 虽 然 大 量 应 用 PHP5 的 新 特 征 ,<br />

但 却 没 有 将 这 些 相 对 于 PHP4 的 优 势 转 化 为 能 够 为 开 发 者 提 供 帮 助 的 东 西 。 对 于 简 单<br />

和 小 型 的 项 目 来 说 ,Zend Framework 不 但 不 能 提 高 开 发 效 率 。 反 而 因 为 在 框 架 中 应 用<br />

了 大 量 面 向 对 象 设 计 和 PHP5 的 新 特 征 , 对 开 发 者 提 出 了 更 高 的 要 求 , 间 接 增 加 了 项<br />

目 的 开 发 成 本 。 而 对 于 较 大 的 项 目 和 企 业 应 用 ,Zend Framework 倒 是 一 个 不 错 的 基<br />

础 。 但 要 创 建 一 个 成 功 的 应 用 , 仍 然 需 要 付 出 不 小 的 努 力 。 并 且 要 时 刻 注 意 Zend<br />

Framework 的 性 能 问 题 。<br />

至 于 Zend Framework 到 底 是 好 是 坏 , 只 能 说 仁 者 见 仁 , 智 者 见 智 。 本 期 杂 志 中<br />

我 们 发 布 了 Zend Framework 团 队 的 力 作 , 对 于 Zend 框 架 从 介 绍 到 应 用 进 行 了 详 细 的<br />

阐 述 。 希 望 对 于 Zend 框 架 感 兴 趣 的 phper 们 可 以 从 中 有 所 收 获 , 也 希 望 Zend 框 架 可<br />

以 更 好 的 应 用 到 各 类 实 际 的 应 用 到 中 去 , 真 正 的 在 项 目 开 发 中 得 到 普 及 。<br />

刘 昊<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 2/111


PHPer 贡 献 者 名 单<br />

《PHPer》<br />

PHPer 贡 献 者 名 单<br />

2009 年 6 月 1 日 第 20 期<br />

主 管 :PHPChina.com<br />

主 办 :PHPChina 网 站 会 员<br />

网 址 :http://www.phpchina.com<br />

总 编 :PHPChina<br />

副 总 编 : 廖 宇 雷<br />

编 辑 :leehui1983 casual0402<br />

卷 首 语 : 刘 昊<br />

应 用<br />

知 识 库<br />

招 聘 : 王 志 军<br />

新 手 乐 园 : 于 安<br />

扩 展 与 框 架 : 廖 宇 雷 、ZendFramework 团 队<br />

企 业 解 决 方 案 :ZendFramework 团 队<br />

高 级 应 用 :ZendFramework 团 队<br />

项 目 管 理 : 李 桂 杰<br />

安 全 优 化 : 机 械 工 业 出 版 社<br />

LAMP 大 讲 堂 :Richard Petersen<br />

校 验 排 版 :PHPChina<br />

后 期 制 作 : 兔 石 尾<br />

另 外 , 欢 迎 广 大 PHP 程 序 员 踊 跃 投 稿 !<br />

请 将 稿 件 发 送 至<br />

phper@phpchina.com<br />

请 注 明 所 投 栏 目 , 并 附 上 作 者 简 介 。<br />

PHP 中 国 开 源 社 区 感 谢 您 的 参 与 !<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 3/111


目 录<br />

《PHPer》<br />

目 录<br />

封 面 ........................................................................................................................................1<br />

卷 首 语 ....................................................................................................................................2<br />

PHPER 贡 献 者 名 单 ..............................................................................................................3<br />

目 录 ......................................................................................................................................4<br />

PHP 新 闻 ...............................................................................................................................7<br />

2009 年 7 月 的 编 程 语 言 排 行 榜 ........................................................................................7<br />

PHP 5.3.0 正 式 发 布 ...........................................................................................................9<br />

提 速 与 MySQL 的 连 接 ........................................................... 9<br />

E_DEPRECATED 标 记 将 被 废 弃 的 功 能 ............................................... 9<br />

PHP 企 业 招 聘 ..................................................................................................................... 11<br />

新 手 乐 园 ..............................................................................................................................14<br />

实 例 命 令 行 模 式 的 管 理 应 用 ..........................................................................................14<br />

扩 展 与 框 架 ..........................................................................................................................19<br />

ZEND 框 架 简 介 ................................................................................................................19<br />

1 设 置 Zend 框 架 ............................................................ 19<br />

1.1 安 装 Zend 框 架 .......................................................... 19<br />

1.2 创 建 一 个 虚 拟 主 机 ....................................................... 20<br />

1.3 引 导 文 件 ............................................................... 20<br />

2 创 建 控 制 器 、 视 图 和 模 型 ................................................... 22<br />

2.1 添 加 索 引 控 制 器 ......................................................... 22<br />

2.2 添 加 视 图 ............................................................... 23<br />

2.3 定 义 模 型 ............................................................... 23<br />

3 添 加 功 能 ................................................................. 25<br />

3.1 使 用 request 和 response 对 象 ............................................ 26<br />

3.2 使 用 内 置 的 操 作 辅 助 类 ................................................... 27<br />

3.3 使 用 内 置 的 视 图 辅 助 类 ................................................... 28<br />

3.4 验 证 输 入 信 息 ........................................................... 29<br />

4 小 结 ..................................................................... 32<br />

QEEPHP 快 速 入 门 ( 五 )—— 实 现 用 户 功 能 ..............................................................33<br />

1 实 现 用 户 注 册 ( 用 户 界 面 ) ................................................. 33<br />

1.1 创 建 视 图 ............................................................... 33<br />

1.2 url() 函 数 .............................................................. 34<br />

1.3 视 图 的 继 承 ............................................................. 34<br />

1.4 完 成 视 图 ............................................................... 36<br />

1.5 指 定 要 继 承 的 视 图 ....................................................... 36<br />

1.6 通 过 定 义 区 块 来 覆 盖 父 模 板 中 的 内 容 ....................................... 36<br />

2 实 现 用 户 注 册 ( 功 能 实 现 ) ................................................. 37<br />

2.1 丑 陋 的 表 单 提 交 处 理 代 码 ................................................. 37<br />

2.2 完 善 模 型 定 义 ........................................................... 38<br />

2.3 完 善 模 型 的 属 性 ......................................................... 38<br />

2.4 行 为 插 件 ............................................................... 40<br />

2.5 完 善 模 型 的 行 为 和 关 系 ................................................... 40<br />

2.6 实 现 用 户 注 册 表 单 ....................................................... 41<br />

2.7 创 建 表 单 对 象 ........................................................... 41<br />

2.8 准 备 表 单 视 图 ........................................................... 42<br />

2.9 实 现 用 户 登 录 ........................................................... 43<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 4/111


目 录<br />

《PHPer》<br />

3 用 户 登 录 和 注 销 ........................................................... 45<br />

3.1 实 现 登 录 ............................................................... 45<br />

3.2 调 用 行 为 插 件 的 方 法 ..................................................... 46<br />

3.3 记 住 用 户 的 登 录 状 态 ..................................................... 46<br />

3.4 添 加 登 录 需 要 的 视 图 ..................................................... 46<br />

3.5 实 现 注 销 ............................................................... 47<br />

3.6 在 用 户 界 面 上 显 示 登 录 状 态 ............................................... 47<br />

3.7 用 户 界 面 组 件 化 ......................................................... 48<br />

4 修 改 密 码 ................................................................. 50<br />

4.1 建 立 表 单 ............................................................... 50<br />

4.2 添 加 控 制 器 动 作 ......................................................... 51<br />

企 业 解 决 方 案 ......................................................................................................................54<br />

ZEND 框 架 高 级 功 能 ........................................................................................................54<br />

1 管 理 配 置 文 件 ............................................................. 54<br />

1.1 使 用 数 组 的 方 法 ......................................................... 54<br />

1.2 INI 方 法 ................................................................ 54<br />

1.3 XML 方 法 ................................................................ 55<br />

2 设 置 站 点 级 别 的 视 图 变 量 ................................................... 56<br />

3 共 享 对 象 ................................................................. 56<br />

4 错 误 处 理 ................................................................. 56<br />

5 应 用 程 序 日 志 记 录 ......................................................... 57<br />

6 缓 存 ..................................................................... 59<br />

6.1 缓 存 功 能 在 安 全 性 上 的 考 虑 ............................................... 59<br />

6.2 缓 存 技 术 ............................................................... 59<br />

7 验 证 用 户 ................................................................. 61<br />

8 在 PHP 语 言 中 使 用 JSON ..................................................... 64<br />

9 自 定 义 路 由 ............................................................... 65<br />

10 管 理 会 话 ................................................................ 67<br />

11 发 送 邮 件 ................................................................ 68<br />

12 创 建 PDF 文 件 ............................................................ 68<br />

12.1 创 建 新 的 PDF 页 面 ...................................................... 69<br />

12.2 在 PDF 页 面 上 绘 图 ...................................................... 69<br />

13 与 Web 服 务 相 集 成 ........................................................ 71<br />

14 小 结 .................................................................... 72<br />

项 目 管 理 ..............................................................................................................................73<br />

为 什 么 领 导 力 以 信 任 为 基 础 ( 一 ) ..............................................................................73<br />

建 立 和 失 去 信 任 .............................................................. 73<br />

信 任 通 过 承 诺 而 建 立 .......................................................... 74<br />

信 任 因 为 不 一 致 的 行 为 而 失 去 .................................................. 74<br />

明 确 信 任 ( 挂 起 绿 灯 ) ........................................................ 75<br />

不 同 类 型 的 权 力 .............................................................. 76<br />

不 要 依 赖 授 予 型 权 力 .......................................................... 76<br />

高 级 应 用 ..............................................................................................................................78<br />

应 用 ZEND 框 架 ..................................................................................................................78<br />

1 模 块 和 模 型 设 置 ........................................................... 78<br />

1.1 常 规 的 模 块 化 的 目 录 结 构 ................................................. 78<br />

1.2 模 型 库 和 Zend_Loader .................................................... 79<br />

2 请 求 生 命 周 期 ............................................................. 80<br />

3 创 建 插 件 ................................................................. 80<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 5/111


目 录<br />

《PHPer》<br />

4 创 建 辅 助 类 ............................................................... 81<br />

4.1 编 写 操 作 辅 助 类 ......................................................... 81<br />

4.2 编 写 视 图 辅 助 类 ......................................................... 82<br />

5 实 现 访 问 控 制 功 能 ......................................................... 83<br />

6 使 用 两 步 视 图 ............................................................. 85<br />

6.1 创 建 一 个 主 布 局 ......................................................... 85<br />

6.2 使 用 占 位 符 ............................................................. 86<br />

7 小 结 ..................................................................... 87<br />

安 全 优 化 ..............................................................................................................................88<br />

WINDOWS 安 全 ( 一 ) .....................................................................................................88<br />

1 Windows 安 全 概 述 .......................................................... 88<br />

1.1 安 全 标 识 符 .............................................................. 89<br />

1.2 访 问 控 制 列 表 ............................................................ 90<br />

1.3 安 全 描 述 符 .............................................................. 91<br />

1.4 访 问 令 牌 ............................................................... 94<br />

2 安 全 信 息 来 源 ............................................................. 96<br />

2.1 访 问 令 牌 ................................................................ 96<br />

2.2 安 全 描 述 符 ............................................................. 97<br />

LAMP 大 讲 堂 ...................................................................................................................101<br />

WEB 服 务 器 ( 一 ) .......................................................................................................101<br />

1 Tux .................................................................... 101<br />

2 其 他 Web 服 务 器 ......................................................... 102<br />

3 Apache Web 服 务 器 ....................................................... 102<br />

3.1 Java:Apache Jakarta 项 目 .............................................. 103<br />

3.2 安 装 Linux Apache ...................................................... 103<br />

3.3 Apache 多 处 理 模 块 :MPM ................................................. 104<br />

3.4 启 动 和 停 止 Web 服 务 器 .................................................. 104<br />

4 Apache 配 置 文 件 .......................................................... 105<br />

职 场 人 生 ............................................................................................................................106<br />

大 学 生 求 职 七 大 昏 招 —— 说 谎 ( 四 ) ........................................................................106<br />

技 巧 —— 如 何 诚 实 的 描 述 自 己 的 “ 问 题 ” ....................................... 106<br />

LAMP 新 书 .......................................................................................................................108<br />

《LINUX 服 务 器 安 全 策 略 详 解 》 .................................................................................108<br />

《C 标 准 库 》 .................................................................................................................109<br />

《PYTHON 开 发 技 术 详 解 》 .......................................................................................... 110<br />

封 底 .................................................................................................................................... 111<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 6/111


目 录<br />

《PHPer》<br />

PHP 新 闻<br />

2009 年 7 月 的 编 程 语 言 排 行 榜<br />

PHPChina<br />

Tiobe 近 日 发 布 了 最 新 一 期 的 编 程 语 言 排 行 榜 , 在 前 十 名 的 榜 单 中 , 除 C # 上 升 一<br />

位 与 上 期 排 名 第 六 的 Python 交 换 位 置 外 , 其 他 排 名 无 明 显 变 化 。 本 期 榜 单 , 我 们 关 注<br />

Java 的 持 续 下 滑 。<br />

编 程 语 言 排 名 前 20:<br />

排 行 榜 上 前 十 名 编 程 语 言 的 长 期 趋 势 图 如 下 :<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 7/111


目 录<br />

《PHPer》<br />

排 名 21 到 50 的 编 程 语 言 :<br />

编 程 语 言 类 别 走 势 :<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 8/111


目 录<br />

PHP 5.3.0 正 式 发 布<br />

PHPChina<br />

《PHPer》<br />

随 着 PHP 5.3 的 发 布 , 这 个 开 源 动 态 语 言 迎 来 了 近 两 年 来 的 最 重 要 更 新 , 新 版 PHP<br />

具 有 一 长 串 新 功 能 , 性 能 得 到 大 大 改 进 。<br />

应 该 说 ,PHP 5.3 版 是 一 个 大 于 开 发 者 预 期 的 重 大 版 本 , 加 入 了 最 初 计 划 在 PHP 6<br />

中 出 现 的 一 些 功 能 。 新 版 PHP 将 继 续 扮 演 与 Ruby、Java 和 .net 等 多 种 技 术 相 竞 争 的<br />

开 源 语 言 角 色 。<br />

PHP 核 心 开 发 人 员 Ilia Alshanetsky 表 示 ,“ 在 新 特 点 和 功 能 方 面 ,PHP 5.3 可 以<br />

说 比 任 何 人 预 想 的 都 要 更 全 面 , 这 主 要 因 为 PHP 6 推 迟 发 布 的 原 因 。 因 此 尽 管 它 发 布<br />

的 时 间 间 隔 有 些 长 , 但 是 我 认 为 这 种 等 待 是 值 得 的 ,PHP 5.3 是 一 个 汇 聚 众 多 开 发 者<br />

心 血 的 优 秀 作 品 。”<br />

Alshanetsky 表 示 , 与 多 数 重 要 版 本 PHP 一 样 , 这 个 版 本 的 PHP 引 入 了 众 多 改 进 ,<br />

可 以 让 开 发 者 更 简 单 的 使 用 它 。<br />

PHP 5.3 简 化 应 用 程 序 部 署 的 方 式 之 一 是 它 支 持 新 命 名 空 间 , 这 是 封 装 类 和 其 它<br />

PHP 对 象 的 方 式 之 一 。<br />

Alshanetsky 表 示 , 对 PHP 开 发 者 来 说 , 命 名 空 间 可 以 带 来 更 清 晰 的 代 码 和 更 简<br />

单 的 名 称 约 定 。<br />

“ 目 前 , 多 数 程 序 库 作 者 被 迫 在 他 们 的 类 和 函 数 名 称 前 加 上 库 名 作 为 前 缀 , 以 避<br />

免 命 名 冲 突 问 题 , 有 些 时 候 这 种 做 法 会 带 来 相 当 难 用 的 名 称 ,”Alshanetsky 表 示 。“ 该<br />

功 能 还 会 简 化 单 一 应 用 程 序 中 多 程 序 库 的 利 用 , 这 些 库 并 不 一 定 必 须 遵 循 详 细 的 命 名<br />

约 定 , 例 如 在 其 类 / 函 数 名 称 前 加 前 缀 等 。”<br />

提 速 与 M ySQL 的 连 接<br />

PHP 经 常 被 与 开 源 数 据 库 MySQL 配 合 使 用 来 开 发 Web 应 用 , 它 们 在 开 源 开 发 工 具<br />

组 合 LAMP 中 是 非 常 重 要 的 一 部 分 。 在 PHP 5.3 中 增 加 了 一 个 名 为 MySQLInd 的 新 功 能 ,<br />

取 代 了 以 前 的 libmysql 库 , 用 来 连 接 PHP 和 MySQL, 并 拥 有 优 化 MySQL 性 能 和 内 存 利<br />

用 率 的 可 能 。<br />

Alshanetsky 表 示 ,“ 当 说 到 数 据 库 时 , 多 数 情 况 下 主 要 的 瓶 颈 并 非 数 据 库 接 口 的<br />

速 度 , 而 是 数 据 库 的 操 作 。 使 用 MySQLInd 来 取 代 标 准 的 libmysql, 肯 定 会 带 来 速 度<br />

的 改 善 , 不 过 我 不 认 为 它 会 让 所 有 应 用 都 提 高 运 行 速 度 。 换 句 话 说 , 使 用 高 度 调 优<br />

MySQL 应 用 的 人 将 会 看 到 新 版 PHP 中 更 快 速 、 更 专 用 的 接 口 所 带 来 的 速 度 提 升 。”<br />

总 体 来 说 ,Alshanetsky 预 计 , 通 过 从 目 前 的 PHP5.2 转 向 PHP 5.3, 用 户 应 该 会<br />

看 到 多 数 工 作 流 程 的 性 能 将 提 高 5% 到 15%, 某 些 特 定 工 作 流 程 甚 至 可 能 看 到 更 高 的 收<br />

益 。<br />

E_DEPRECATED 标 记 将 被 废 弃 的 功 能<br />

尽 管 增 加 新 功 能 是 任 何 新 技 术 发 布 的 一 个 关 键 部 分 , 除 此 之 外 PHP 5.3 还 有 自 己<br />

的 特 别 之 处 —— 它 明 确 了 哪 个 功 能 可 能 会 被 取 消 。<br />

该 版 本 提 供 了 一 个 名 为 E_DEPRECATED 的 新 错 误 代 码 , 让 开 发 者 知 道 哪 些 特 定 功 能<br />

即 将 从 该 语 言 中 消 失 。<br />

Alshanetsky 表 示 ,“ 以 前 我 们 曾 碰 到 过 这 样 的 问 题 , 我 们 没 有 一 个 明 确 的 错 误 代<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 9/111


目 录<br />

《PHPer》<br />

码 来 表 示 已 经 不 支 持 的 功 能 , 人 们 很 难 在 错 误 代 码 层 次 上 来 判 断 什 么 功 能 可 能 最 后 被<br />

移 除 。”<br />

通 过 创 建 一 个 专 用 错 误 代 码 来 解 决 这 个 问 题 , 开 发 者 可 以 通 过 使 用 PHP 的 错 误 记<br />

录 工 具 来 识 别 自 己 代 码 库 中 的 哪 一 部 分 还 在 使 用 将 被 移 除 的 功 能 , 因 此 开 发 者 可 以 进<br />

行 相 应 的 调 整 。<br />

据 Alshanetsky 表 示 ,PHP 开 发 团 队 存 在 一 个 共 识 , 目 前 被 标 记 为 E_DEPRECATED<br />

的 功 能 将 在 PHP 6 中 移 除 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 10/111


PHP 企 业 招 聘<br />

《PHPer》<br />

PHP 企 业 招 聘<br />

PHP 工 程 师<br />

招 聘 信 息<br />

公 司 名 称 : 新 浪 网<br />

招 聘 人 数 : 若 干 名<br />

工 作 地 点 : 北 京<br />

薪 水 待 遇 :5k++ / month<br />

职 位 描 述 :<br />

1、 负 责 无 线 业 务 相 关 CMS 平 台 的 设 计 、 建 设 及 日 常 维 护 、 开 发 、 测 试 。<br />

2、 负 责 管 理 数 据 库 的 数 据 维 护 及 统 计 。<br />

3、 负 责 实 时 平 台 网 站 运 行 状 况 , 保 证 网 站 安 全 性 。<br />

4、 根 据 产 品 需 求 , 负 责 开 发 新 的 无 线 增 值 业 务 。<br />

任 职 资 格 :<br />

1 、 大 学 本 科 毕 业 ,4 级 英 语 水 平 , 能 熟 练 阅 读 相 关 英 文 技 术 文 档 ;<br />

2 、 熟 悉 Unix/Linux/FreeBSD 开 发 环 境 ;<br />

3 、 至 少 2 年 以 上 的 PHP/MySQL 开 发 经 验 , 熟 悉 面 向 对 象 的 软 件 设 计 方 法 ,<br />

4 、 具 备 数 据 库 应 用 系 统 的 规 划 及 设 计 能 力 ;<br />

5 、 熟 悉 HTTP 协 议 , 熟 悉 HTML/CSS/XML 等 Web 开 发 基 本 技 术 ;<br />

6 、 具 备 良 好 的 代 码 编 程 习 惯 及 较 强 的 文 档 编 写 能 力 ;<br />

7 、 具 备 强 烈 的 进 取 心 、 求 知 欲 及 团 队 合 作 精 神 ;<br />

8 、 能 够 承 受 适 当 压 力 , 独 当 一 面 ;<br />

9 、 具 有 SMS/MMS 等 无 线 增 值 应 用 开 发 经 验 者 优 先 考 虑 。<br />

10、 具 有 大 中 型 网 站 的 系 统 构 架 设 计 和 程 序 开 发 经 验 者 优 先 考 虑 。<br />

联 系 方 式 :<br />

公 司 介 绍<br />

联 系 人 :PH PC hina 伯 乐<br />

电 子 邮 箱 :wangzhijun@comsenz.com<br />

联 系 电 话 :13146612015<br />

QQ: 752719295<br />

新 浪 (NASDAQ: SINA) 是 一 家 服 务 于 中 国 大 陆 及 全 球 华 人 社 群 的 领 先 在 线 媒 体 及 增<br />

值 资 讯 娱 乐 服 务 提 供 商 。 新 浪 拥 有 十 五 家 地 区 性 网 站 , 以 服 务 大 中 华 地 区 与 海 外 华 人<br />

为 己 任 , 通 过 旗 下 三 大 业 务 主 线 即 提 供 网 络 媒 体 及 娱 乐 服 务 的 新 浪 网 (SINA.com)、<br />

提 供 用 户 付 费 在 线 及 无 线 增 值 服 务 的 新 浪 无 线 (SINA Online) 以 及 向 中 小 型 企 业 提 供<br />

增 值 服 务 的 新 浪 企 业 服 务 (SINA.net), 提 供 包 括 门 户 网 站 、 收 费 邮 箱 、 无 线 短 信 、 虚<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 11/111


PHP 企 业 招 聘<br />

《PHPer》<br />

拟 ISP、 搜 索 引 擎 、 分 类 信 息 、 在 线 游 戏 、 电 子 商 务 、 网 络 教 学 、 企 业 电 子 解 决 方 案<br />

在 内 的 一 系 列 服 务 。<br />

新 浪 在 全 球 范 围 内 拥 有 超 过 8328 万 注 册 用 户 , 各 种 付 费 服 务 的 常 用 用 户 超 过 1000<br />

万 , 是 中 国 大 陆 及 全 球 华 人 社 群 中 最 受 推 崇 的 互 联 网 品 牌 。<br />

新 浪 将 业 务 重 点 放 在 中 国 大 陆 , 其 营 业 收 入 的 96% 即 来 自 这 一 地 区 。 据 中 国 互 联<br />

网 络 信 息 中 心 (CNNIC) 公 布 的 中 国 互 联 网 络 发 展 状 况 显 示 , 中 国 目 前 拥 有 6800 万 互 联<br />

网 用 户 , 居 世 界 第 二 位 。 同 1997 年 10 月 第 一 次 调 查 结 果 62 万 上 网 用 户 人 数 相 比 ,<br />

现 在 的 上 网 用 户 人 数 已 是 当 初 的 109.7 倍 。 随 着 中 国 经 济 的 迅 猛 发 展 , 作 为 中 国 最 大<br />

的 网 络 媒 体 公 司 , 新 浪 将 直 接 受 惠 于 这 一 巨 大 的 成 长 空 间 。<br />

新 浪 网 称 雄 中 国 线 上 广 告 市 场<br />

通 过 与 国 内 外 六 百 余 家 内 容 供 应 商 达 成 合 作 关 系 , 新 浪 设 在 中 国 大 陆 的 各 家 网 站<br />

提 供 了 三 十 多 个 在 线 内 容 频 道 。 新 浪 及 时 全 面 的 报 导 涵 盖 了 国 内 外 突 发 新 闻 、 体 坛 赛<br />

事 、 娱 乐 时 尚 、 财 经 及 IT 产 业 资 讯 , 成 为 数 以 百 万 计 中 国 互 联 网 用 户 生 活 中 不 可 或<br />

缺 的 部 分 。 新 浪 免 费 电 子 邮 件 系 统 拥 有 两 千 多 万 活 跃 用 户 , 仅 次 于 Hotmail、 雅 虎 和<br />

美 国 在 线 , 居 世 界 第 四 位 。 新 浪 综 合 搜 索 引 擎 也 一 直 在 国 内 名 列 前 茅 。<br />

新 浪 无 线 - 中 国 领 先 的 用 户 付 费 增 值 服 务 提 供 商<br />

新 浪 于 2002 年 4 月 正 式 推 出 新 浪 无 线 业 务 , 以 打 造 中 国 的 用 户 付 费 增 值 服 务 平 台 ,<br />

提 供 无 线 增 值 服 务 、 虚 拟 ISP、 收 费 邮 箱 服 务 和 在 线 游 戏 等 。 中 国 拥 有 超 过 2 亿 的 手<br />

机 用 户 , 是 全 球 最 大 的 移 动 电 话 市 场 , 从 而 为 无 线 内 容 服 务 提 供 了 巨 大 的 商 机 。 作 为<br />

领 先 的 线 上 内 容 整 合 商 , 新 浪 在 无 线 增 值 服 务 领 域 亦 居 领 导 地 位 , 为 数 以 百 万 计 的 付<br />

费 用 户 提 供 短 信 服 务 。 新 浪 是 国 内 最 受 欢 迎 的 无 线 应 用 协 议 (WAP) 门 户 之 一<br />

新 浪 企 业 服 务 - 中 国 领 先 的 中 小 型 企 业 增 值 服 务 提 供 商<br />

新 浪 是 国 内 最 受 信 赖 的 互 联 网 品 牌 。 为 充 分 发 掘 这 一 品 牌 的 价 值 , 新 浪 于 2002<br />

年 2 月 推 出 了 新 浪 企 业 服 务 (SINA.net), 将 服 务 领 域 延 伸 至 国 内 的 中 小 企 业 。 新 浪 的<br />

企 业 服 务 项 目 包 括 企 业 邮 箱 、 企 业 黄 页 、 分 类 信 息 、 网 络 营 销 和 电 子 商 务 。 目 前 , 新<br />

浪 已 发 展 了 20 多 万 个 中 小 型 企 业 客 户 , 且 客 户 数 量 仍 在 快 速 增 长 。<br />

新 浪 - 通 往 中 国 的 门 户<br />

新 浪 凭 借 自 己 在 全 球 范 围 的 影 响 力 , 已 成 为 引 导 众 多 跨 国 企 业 进 入 中 国 、 开 发 这<br />

个 全 球 最 大 、 成 长 最 快 的 市 场 的 领 路 人 。 当 戴 尔 、 欧 莱 雅 、 强 生 、 耐 克 等 国 际 著 名 企<br />

业 决 心 在 中 国 实 施 网 络 营 销 策 略 时 , 他 们 均 选 择 新 浪 作 为 其 网 络 合 作 伙 伴 。 跨 国 企 业<br />

已 经 并 将 继 续 成 为 新 浪 客 户 基 础 的 一 个 重 要 组 成 部 分 。<br />

新 浪 的 前 景<br />

新 浪 旨 在 通 过 互 联 网 及 无 线 网 络 等 多 种 平 台 , 向 中 国 及 全 球 华 人 社 群 的 个 人 与 公<br />

司 用 户 提 供 高 质 量 的 增 值 信 息 服 务 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 12/111


PHP 企 业 招 聘<br />

《PHPer》<br />

PHP 高 级 工 程 师<br />

招 聘 信 息<br />

公 司 名 称 : 北 京 智 博<br />

招 聘 人 数 :3 名<br />

工 作 地 点 : 北 京<br />

薪 水 待 遇 :6k++ / month<br />

职 位 描 述 :<br />

1 、 负 责 电 子 商 务 网 站 的 建 设 及 日 常 维 护 、 开 发 、 测 试 。<br />

任 职 资 格 :<br />

1 、 一 年 以 上 网 站 开 发 经 验<br />

2 、 工 作 认 真 细 致 负 责 , 勇 于 接 受 挑 战 , 具 有 良 好 的 团 队 协 作 精 神 ;<br />

3 、 精 通 PHP+MySQL 开 发 , 熟 悉 JavaScript、HTML;<br />

4 、 精 通 DIV+CSS 网 站 架 构 ;<br />

5 、 熟 悉 PHP 的 常 用 函 数 库 以 及 熟 悉 PHP 的 类 的 用 法 , 具 有 良 好 的 编 程 风<br />

格 、 习 惯 ;<br />

6 、 精 通 关 系 数 据 库 MySQL, 熟 悉 SQL 语 言 ;<br />

7 、 有 一 定 的 前 台 能 力 设 计 者 优 先 ;<br />

8 、 有 大 、 中 型 网 站 开 发 经 验 者 优 。<br />

联 系 方 式 :<br />

公 司 介 绍<br />

联 系 人 :PH PC hina 伯 乐<br />

电 子 邮 箱 :wangzhijun@comsenz.com<br />

联 系 电 话 :13146612015<br />

QQ: 752719295<br />

体 彩 导 刊 、 彩 民 周 刊 官 网 。 国 内 彩 票 行 业 主 流 媒 体 之 一 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 13/111


PHP 企 业 招 聘<br />

《PHPer》<br />

新 手 乐 园<br />

实 例 命 令 行 模 式 的 管 理 应 用<br />

于 安<br />

在 上 一 期 杂 志 中 , 我 发 表 了 一 篇 < 偏 向 于 命 令 行 模 式 的 管 理 应 用 > 这 篇 主 题 简 单 讲<br />

了 如 何 用 命 令 行 来 管 理 , 如 何 来 快 速 高 效 地 应 用 起 来 . 由 于 只 是 初 型 , 所 以 没 有 做 上<br />

实 例 . 经 过 长 久 的 思 考 , 现 在 终 于 有 了 眉 目 , 现 在 我 补 上 一 篇 .<br />

在 实 现 此 应 用 前 , 我 要 先 考 虑<br />

• 命 令 行 在 什 么 地 方 输 入 ?<br />

• 输 入 的 结 果 如 何 返 回 ?<br />

• 还 有 就 是 如 何 模 拟 出 DOS 的 界 面 ?<br />

首 先 , 为 了 方 便 , 建 议 使 用 jquery 1.32 min 发 行 版 本 , 加 载 到 html 中 。 接 着 我<br />

们 来 分 析 html (dos.html);<br />

代 码 片 段<br />

<br />

<br />

<br />

<br />

DOS 执 行 命 令 <br />

<br />

<br />

<br />

// 缓 期 需 要 ;<br />

var int =0;<br />

$(function (){<br />

focus_(); // 为 每 一 次 固 定 焦 点 ;<br />

})<br />

function focus_(){<br />

$('textarea').focus();<br />

$('textarea').val($('textarea').val());<br />

setTimeout_(); // 为 滚 动 条 设 置 函 数 , 就 是 总 是 固 定 在 底 部 .<br />

}<br />

// 回 车 点 击 后 , 因 为 用 户 最 喜 欢 回 车<br />

function noNumbers(e){<br />

var keynum;<br />

var keychar;<br />

var numcheck;<br />

if(window.event){ // IE<br />

keynum = e.keyCode;<br />

} else if(e.which){ // Netscape/Firefox/Opera<br />

keynum = e.which;<br />

}<br />

if(keynum===13){ // 如 果 回 车 , 这 是 关 键 ;<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 14/111


PHP 企 业 招 聘<br />

《PHPer》<br />

var mess = $('textarea:last').val();<br />

var array = mess.split('\n'); // 一 行 一 行 , 是 以 \n 为 结 束 ; 切 割 ;<br />

for (s in array){<br />

if(array[s].indexOf('PHP>')!=-1) // 查 找 最 后 一 个 PH P> 后 面 .<br />

mess2 = array[s]; // 将 值 赋 出 , 简 单 来 讲 , 就 是 将 当 前 行 赋 出 .<br />

}<br />

// 判 断 一 下 PHP> 是 否 存 在 , 这 标 识 不 要 删 除 , 否 则 难 看 了<br />

if(mess2.indexOf('PHP>')!=-1){<br />

mess2 = mess2.replace('PHP>',''); // 新 变 量 记 录 实 质 的 命 令 行 .<br />

var len = mess2.length; // 判 断 一 个 命 令 行 长 度 ;<br />

// 判 断 一 下 有 没 有 结 尾 ;<br />

if(len>2 && mess2.substr(len-1,len)!==';') // 如 果 没 有 结 尾 , 就 禁 止 回 车 .<br />

return false;<br />

// 判 断 是 否 直 接 回 车 , 禁 止 两 个 字 符 的 命 令 ;<br />

if(len


PHP 企 业 招 聘<br />

《PHPer》<br />

}<br />

});<br />

// 假 如 返 回 信 息 是 javascript:XX 模 式 , 表 示 要 直 接 运 行 ;<br />

if(msg.indexOf('javascript:')!=-1){<br />

msg = msg.replace('javascript:',''); // 先 把 javascript: 去 掉<br />

eval_(msg); //EVAL 运 行 它 ;<br />

}<br />

}<br />

focus_(); // 又 是 焦 点 函 数 ;<br />

// 自 动 运 行 返 回 的 JS, 为 了 更 可 观 , 所 以 增 加 了 缓 期 执 行 ;<br />

function eval_(msg){<br />

if(int


PHP 企 业 招 聘<br />

《PHPer》<br />


PHP 企 业 招 聘<br />

《PHPer》<br />

刷 新 或 者 输 入 clear, 将 使 界 面 恢 复 到 初 始 状 态 ;<br />

为 了 测 试 功 能 , 我 写 了 数 学 算 法 功 能 ;<br />

现 在 功 能 实 现 了 , 基 本 上 与 DOS 有 如 下 类 似 功 能 :<br />

• 禁 止 非 结 尾 为 ”;” 的 命 令 提 交 , 这 点 是 学 习 mysql 的 ;<br />

• 结 果 显 示 效 果 与 DOS 一 样 , 甚 至 好 过 DOS;<br />

• 清 屏 功 能 ;<br />

• 命 令 安 全 输 入 功 能 ;<br />

• 速 度 更 快 , 更 直 观 。<br />

本 程 序 在 IE6 IE7 IE8 FF 浏 览 器 下 测 试 成 功 。 演 示 :<br />

http://www.fenanr.com/show.php?action=dos;<br />

作 者 简 介 :<br />

姓 名 : 冯 . 于 安<br />

Email: Yua n-e@qq.com<br />

分 享 工 作 室 :http://www.fenanr.com;<br />

现 居 : 广 州<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 18/111


扩 展 与 框 架 :<br />

《PHPer》<br />

扩 展 与 框 架<br />

Zend 框 架 简 介<br />

ZendFramework 团 队<br />

为 了 开 发 用 于 PHP 的 标 准 化 的 MVC 框 架 , 社 区 成 员 付 出 了 很 大 努 力 , 最 终 形 成<br />

了 Zend 框 架 。 它 是 真 正 的 开 源 项 目 , 它 的 授 权 是 基 于 BSD 授 权 协 议 的 , 这 确 保 了 所<br />

有 人 都 有 权 利 适 当 地 使 用 它 。<br />

Zend 框 架 遵 循 MVC 架 构 , 但 它 的 实 现 质 量 要 高 得 多 , 并 且 也 很 成 熟 。 它 为 大 多<br />

数 Web 开 发 任 务 提 供 了 相 应 的 功 能 , 而 且 操 作 也 很 灵 活 。<br />

本 文 介 绍 了 Zend 框 架 , 并 且 演 示 了 使 用 这 个 框 架 进 行 开 发 的 一 种 方 法 。 使 用 Zend<br />

框 架 并 不 是 仅 仅 只 有 这 一 种 方 法 , 这 是 因 为 Zend 框 架 的 整 体 目 标 是 创 建 一 个 适 合 大<br />

量 不 同 的 开 发 人 员 的 灵 活 的 开 发 环 境 。<br />

1 设 置 Zend 框 架<br />

Zend 框 架 的 入 门 是 非 常 简 单 的 。 你 需 要 下 载 并 安 装 它 , 然 后 为 这 一 框 架 配 置 Web<br />

服 务 器 环 境 即 可 。<br />

1.1 安 装 Zend 框 架<br />

首 先 需 要 访 问 http://framework.zend.com 并 下 载 最 新 的 稳 定 版 本 。 编 写 此 书 时 , 最<br />

新 的 版 本 是 1.0.3。<br />

> wget http://framework.zend.com/releases/ZendFramework-1.0.3/ ➥<br />

ZendFramework-1.0.3.tar.gz<br />

需 要 挑 选 一 个 保 存 框 架 库 的 公 共 位 置 , 这 取 决 于 你 如 何 组 织 服 务 器 。 这 里 使 用 以<br />

下 路 径 。<br />

> mkdir /usr/share/php/ZendFramework<br />

不 过 , 使 用 哪 个 目 录 完 全 取 决 于 你 自 己 , 你 所 需 做 的 事 情 就 是 记 住 保 存 框 架 文 件<br />

的 位 置 。<br />

下 一 步 , 将 框 架 解 压 缩 到 这 个 目 录 中 。<br />

> tar xzf ZendFramework-1.0.3.tar.gz<br />

现 在 就 获 得 了 以 下 的 一 个 目 录 。<br />

> drwx------ 7 1005 513 ZendFramework-1.0.3<br />

这 将 使 得 框 架 的 完 整 路 径 为 /usr/share/php/ZendFramework/ZendFramework-1.0.3/。<br />

不 过 , 你 也 许 已 经 注 意 到 , 文 件 的 权 限 分 配 不 是 很 理 想 。 在 这 里 , 你 有 几 种 选 择 , 可<br />

以 让 Web 服 务 拥 有 这 些 文 件 , 另 外 , 为 了 使 文 件 不 易 被 修 改 , 也 可 以 保 护 这 些 文 件 。<br />

推 荐 使 用 后 者 。<br />

> cd ZendFramework-1.0.3<br />

> chown root:root . –R<br />

现 在 , 已 经 获 得 了 root 用 户 拥 有 的 所 有 框 架 文 件 了 , 但 是 Web 服 务 器 还 不 能 读 取<br />

这 些 文 件 。 需 要 将 目 录 的 权 限 设 置 为 chmod755(drwxr-xr-x), 将 文 件 的 权 限 设 置 为<br />

644(-rw-r--r--)。 最 简 单 的 方 法 是 使 用 find 命 令 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 19/111


扩 展 与 框 架 :<br />

《PHPer》<br />

> find -type d -exec chmod 755 {} \;<br />

> find -type f -exec chmod 644 {} \;<br />

权 限 设 置 正 确 并 且 框 架 配 置 完 成 之 后 , 只 有 root 用 户 才 可 以 修 改 框 架 文 件 。 这 应<br />

该 可 以 提 供 更 多 的 安 全 保 障 , 从 而 防 止 框 架 库 在 主 原 始 位 置 之 外 的 地 方 被 修 改 。<br />

从 这 里 开 始 , 你 就 不 能 再 通 过 替 换 现 存 文 件 来 升 级 到 新 版 本 了 。 相 反 , 应 该 遵 循 这 一<br />

过 程 , 每 次 都 创 建 一 个 新 的 目 录 。<br />

1.2 创 建 一 个 虚 拟 主 机<br />

框 架 安 装 完 成 以 后 , 需 要 创 建 一 个 虚 拟 主 机 。 这 一 过 程 在 前 一 章 已 经 做 过 说 明 。<br />

Zend 框 架 使 用 一 种 非 常 相 似 的 目 录 结 构 。<br />

> cd /usr/local/www/yourdomain.com<br />

> mkdir –p document_root/images document_root/styles<br />

> mkdir –p application/models application/views/scripts/index \<br />

> application/controllers<br />

> find<br />

代 码 片 段<br />

.<br />

./document_root<br />

./document_root/images<br />

./document_root/styles<br />

./application<br />

./application/models<br />

./application/views<br />

./application/views/scripts<br />

./application/views/scripts/index<br />

1.3 引 导 文 件<br />

引 导 文 件 将 Web 服 务 器 环 境 和 Zend 框 架 集 成 在 一 起 。 它 是 Web 服 务 器 向 站 点 发<br />

送 所 有 请 求 的 地 方 , 它 将 处 理 应 用 程 序 的 分 派 工 作 。<br />

第 一 步 是 在 document_root 目 录 中 创 建 index.php 文 件 ( 引 导 文 件 ) 和 .htaccess 文 件 。<br />

document_root.<br />

> cd document_root<br />

> pico –w index.php<br />

代 码 片 段<br />

<br />

> pico –w .htaccess<br />

RewriteEngine On<br />

RewriteCond %{REQUEST_FILENAME} -s [OR]<br />

RewriteCond %{REQUEST_FILENAME} -l [OR]<br />

RewriteCond %{REQUEST_FILENAME} –d<br />

RewriteRule ^.*$ - [NC,L]<br />

RewriteRule ^.*$ /index.php [NC,L]<br />

这 一 脚 本 会 将 所 有 请 求 重 定 向 到 index.php, 从 而 避 免 发 生 404 文 件 未 找 到 HTTP<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 20/111


扩 展 与 框 架 :<br />

《PHPer》<br />

的 错 误 。 严 格 说 来 , 它 会 检 查 请 求 是 否 能 找 到 对 应 的 文 件 、 符 号 链 接 或 者 目 录 , 然 后<br />

在 所 有 这 些 条 件 都 不 满 足 的 情 况 下 执 行 重 定 向 操 作 。<br />

要 测 试 输 出 结 果 , 可 以 访 问 http://yoursite.com/asdf 并 确 保 看 到 “Rewrite working.”<br />

字 样 。 如 果 看 不 到 这 一 结 果 , 你 将 需 要 解 决 mod_rewrite 的 问 题 ( 要 找 到 关 于 mod_rewrite<br />

的 文 档 , 可 参 见 http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)。<br />

假 设 一 切 正 常 , 下 一 步 骤 就 应 该 是 开 始 编 写 真 实 的 index.php 文 件 。 先 清 除 旧 文 件 中<br />

的 内 容 。<br />

> echo > index.php<br />

然 后 创 建 一 个 新 的 index.php 文 件 , 并 且 包 含 主 要 的 Zend 平 台 include 文 件 。<br />

> pico –w index.php<br />

代 码 片 段<br />


扩 展 与 框 架 :<br />

《PHPer》<br />

代 码 片 段<br />


扩 展 与 框 架 :<br />

《PHPer》<br />

2.2 添 加 视 图<br />

在 前 面 , 通 过 创 建 视 图 对 象 , 给 它 设 置 变 量 , 并 调 用 render() 方 法 , 你 手 工 输 出 了<br />

视 图 。Zend 框 架 有 一 个 被 称 为 视 图 输 出 器 的 默 认 组 件 , 它 为 你 处 理 了 其 中 两 个 步 骤 :<br />

自 动 创 建 视 图 实 例 以 及 输 出 视 图 脚 本 。 视 图 实 例 被 保 存 在 控 制 器 的 实 例 的 $this->view<br />

变 量 中 。<br />

对 应 用 程 序 来 说 , 第 一 个 视 图 模 板 将 是 application/views/scripts/index/index.phtml,<br />

如 代 码 清 单 1-3 所 示 。 目 录 index 代 表 了 控 制 器 名 称 , 而 index.phtml 文 件 则 代 表 去 掉<br />

了 Action 后 缀 的 方 法 名 称 。<br />

代 码 清 单 1-3 示 例 视 图 (application/views/scripts/index/index.phtml)<br />

代 码 片 段<br />

<br />

<br />

Welcome: <br />

<br />

<br />

这 个 模 板 非 常 简 单 。 现 在 , 要 使 用 这 个 模 板 , 需 要 重 构 IndexController.php 文 件 中<br />

的 indexAction 方 法 , 并 设 置 name 变 量 的 值 , 如 代 码 清 单 1-4 所 示 。<br />

代 码 清 单 1-4 一 个 启 用 了 视 图 的 操 作 ( 在 IndexController.php 中 )<br />

代 码 片 段<br />

public function indexAction() {<br />

$this->view->name = 'Kevin';<br />

}<br />

如 果 重 新 加 载 页 面 , 应 该 会 看 到 “Welcome: Kevin.” 的 字 样 。 现 在 , 你 已 经 完 成 了<br />

一 个 可 以 运 行 的 Zend 框 架 应 用 程 序 。<br />

2.3 定 义 模 型<br />

下 一 步 是 创 建 数 据 模 型 , 这 一 模 型 可 以 为 应 用 程 序 提 供 一 些 有 意 义 的 数 据 。Zend<br />

框 架 包 含 了 大 量 有 价 值 的 类 , 这 些 类 可 用 来 作 用 于 数 据 库 。 你 将 使 用 这 些 基 类 创 建 数<br />

据 模 型 , 但 首 先 需 要 一 个 数 据 库 。<br />

1. 设 置 数 据 库<br />

使 用 哪 种 数 据 库 完 全 取 决 于 你 自 己 。 本 章 的 例 子 中 使 用 的 是 PostgreSQL 数 据 库 ,<br />

这 是 因 为 在 Debian Linux 发 行 版 上 , 它 可 以 从 包 管 理 器 安 装 。 对 于 特 定 系 统 来 说 , 用<br />

到 的 二 进 制 程 序 的 位 置 可 能 不 在 路 径 上 , 并 且 pg_hba.conf 文 件 所 在 的 位 置 也 可 能 与<br />

这 里 显 示 的 位 置 不 同 。<br />

首 先 , 需 要 创 建 一 个 PostgreSQL 用 户 作 为 数 据 库 的 拥 有 者 , 还 要 将 应 用 程 序 访 问<br />

的 数 据 库 与 已 经 在 主 机 上 运 行 的 其 他 数 据 库 分 隔 开 。 这 是 一 个 交 互 式 命 令 , 应 该 作 为<br />

postgres 用 户 来 运 行 。 确 保 为 数 据 库 使 用 自 定 义 的 密 码 。<br />

> createuser –P<br />

然 后 , 创 建 一 个 由 demouser 用 户 拥 有 的 数 据 库 , 这 个 数 据 库 是 UTF-8 编 码 格 式 的 ,<br />

名 称 为 demodb。<br />

> createdb -O demouser -E utf-8 demodb<br />

下 一 步 , 要 启 用 对 新 数 据 库 的 访 问 , 需 要 编 辑 PostgreSQL 基 于 主 机 的 验 证 配 置 文<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 23/111


扩 展 与 框 架 :<br />

《PHPer》<br />

件 (pg_hba.conf), 以 便 让 新 用 户 有 权 限 连 接 到 数 据 库 。 以 下 的 配 置 行 将 demodb 的 本<br />

地 (UNIX 套 接 字 ) 访 问 权 限 授 权 给 使 用 MD5 散 列 密 码 的 demouser 用 户 。<br />

> pico -w /etc/postgresql/8.1/main/pg_hba.conf<br />

local demodb demouser md5<br />

下 一 步 , 需 要 重 新 加 载 postgresql 守 护 进 程 , 可 以 使 用 初 始 化 脚 本 或 者 pg_ctl 二<br />

进 制 程 序 。<br />

> /etc/init.d/postgresql reload<br />

现 在 , 应 该 可 以 连 接 到 数 据 库 了 。<br />

> psql -U demouser -W demodb<br />

下 一 步 , 创 建 一 个 表 。 创 建 的 第 一 个 表 可 能 用 来 保 存 客 户 的 信 息 。<br />

demodb=> create table customers(customer_id serial, name varchar);<br />

然 后 可 以 在 这 个 表 中 创 建 一 条 记 录 。<br />

demodb=> INSERT INTO customers (name) VALUES ('Kevin');<br />

最 后 , 使 用 \q 命 令 退 出 。<br />

demodb=> \q<br />

拥 有 了 数 据 库 之 后 , 便 可 以 为 customers 表 创 建 一 个 模 型 , 但 首 先 必 须 配 置 Zend<br />

框 架 , 以 便 使 用 这 个 数 据 库 。<br />

2. 配 置 框 架 以 使 用 数 据 库<br />

要 让 Zend 框 架 可 以 使 用 你 的 数 据 库 , 你 需 要 编 辑 引 导 文 件 index.php。<br />

> pico –w document_root/index.php<br />

在 这 个 文 件 中 包 含 Zend_Controller_Front::run 的 代 码 行 之 前 添 加 代 码 清 单 15-5 中<br />

显 示 的 代 码 。<br />

Zend_Controller_Front::run.<br />

代 码 清 单 1-5 用 于 引 导 的 数 据 库 连 接 信 息 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

$params = array (<br />

'username' => 'demouser',<br />

'password' => 'demopass',<br />

'dbname' => 'demodb'<br />

);<br />

$db = Zend_Db::factory('PDO_PGSQL', $params);<br />

Zend_Db_Table::setDefaultAdapter($db);<br />

setDefaultAdapter() 函 数 的 调 用 确 保 了 一 种 情 况 , 即 之 后 所 有 不 使 用 显 式 连 接 信 息<br />

连 接 数 据 库 的 代 码 都 将 使 用 这 个 连 接 信 息 。 这 使 所 有 的 Zend_Db_Table 实 例 只 需 要 关<br />

注 表 的 结 构 , 而 不 用 关 注 要 连 接 的 数 据 库 的 位 置 。 它 还 提 供 了 一 个 方 便 并 且 集 中 的 配<br />

置 点 。<br />

3. 创 建 Customers 的 模 型 、 控 制 器 和 视 图<br />

现 在 你 可 以 创 建 一 个 从 Zend_Db_Table 派 生 的 模 型 类 , 这 个 模 型 将 与 数 据 库 表 相<br />

互 作 用 。<br />

> pico application/models/Customers.php<br />

添 加 代 码 清 单 1-6 中 显 示 的 代 码 。<br />

代 码 清 单 1-6 Customers 模 型 类 (application/models/Customers.php)<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 24/111


扩 展 与 框 架 :<br />

《PHPer》<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

重 新 加 载 页 面 , 将 会 生 成 customers 表 的 带 样 式 列 表 。<br />

现 在 , 你 已 经 完 成 并 激 活 了 Zend 框 架 , 但 是 , 还 没 有 处 理 过 任 何 数 据 输 入 , 或 者 执 行 任 何 交<br />

互 式 操 作 。<br />

3 添 加 功 能<br />

Zend 框 架 提 供 了 一 个 功 能 集 , 它 们 可 以 被 用 来 创 建 表 格 并 且 使 处 理 输 入 数 据 的 工<br />

作 更 加 简 单 。 这 个 功 能 包 含 了 三 个 主 要 的 部 分 :<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 25/111


扩 展 与 框 架 :<br />

《PHPer》<br />

• request 和 response 对 象 ;<br />

• 操 作 辅 助 类 和 视 图 辅 助 类 ;<br />

• 输 入 校 验 功 能 。<br />

3.1 使 用 request 和 response 对 象<br />

request 对 象 封 装 了 所 有 你 希 望 用 到 的 HTTP 数 据 , 其 中 包 含 了 所 有 的 GET 数 据 ( 查<br />

询 ) 、 POST 数 据 和 cookie 数 据 。 它 还 提 供 了 从 请 求 URI 中 解 析 出 的 信 息 , 例 如 控 制<br />

器 和 操 作 名 称 等 信 息 。 另 外 , 还 提 供 了 一 种 特 殊 类 型 的 数 据 , 它 被 称 为 参 数 , 参 数 可<br />

以 通 过 URL 来 设 置 , 与 使 用 查 询 变 量 相 比 , 这 种 设 置 使 站 点 对 搜 索 引 擎 更 加 友 好 。<br />

为 了 补 充 request 对 象 ,response 对 象 提 供 了 封 装 好 的 用 于 处 理 输 出 流 的 一 种 方 式 。<br />

1.request 对 象<br />

以 下 五 个 请 求 对 象 方 法 的 用 法 都 是 相 同 的 , 它 们 允 许 你 与 标 准 的 输 入 流 打 交 道 。<br />

• getQuery($key = null, $default = null)<br />

• getPost($key = null, $default = null)<br />

• getCookie($key = null, $default = null)<br />

• getServer($key = null, $default = null)<br />

• getEnv($key = null, $default = null)<br />

如 果 为 key 参 数 传 入 null 值 , 将 获 得 信 息 的 一 个 完 整 数 组 。 如 果 传 入 一 个 键 值 ,<br />

将 只 获 得 那 个 键 值 对 应 的 数 据 。 还 可 以 传 入 一 个 默 认 值 , 这 使 得 它 们 在 没 有 找 到 匹 配<br />

的 键 值 时 可 以 返 回 这 个 默 认 值 。 如 果 没 有 找 到 匹 配 的 键 值 并 且 也 没 有 传 入 默 认 值 , 将<br />

返 回 null 值 。<br />

如 果 需 要 访 问 HTTP 请 求 头 信 息 , 将 需 要 使 用 getHeader() 方 法 , 并 传 入 头 信 息 的<br />

名 称 。 需 要 注 意 的 是 HTTP 头 信 息 是 区 分 大 小 写 的 。<br />

getHeader($header)<br />

在 所 有 MVC 实 现 框 架 中 参 数 都 是 最 关 键 的 一 个 部 分 。 它 们 是 get 变 量 的 替 换 方 法 ,<br />

而 且 它 们 会 使 站 点 对 搜 索 引 擎 更 加 具 有 吸 引 力 。 为 了 在 Zend 框 架 应 用 程 序 中 使 用 参<br />

数 ,URL 将 被 分 隔 为 以 下 的 部 分 。<br />

http://example.com/controller/action/key1/value1/key2/value2 . . .<br />

通 过 使 用 参 数 , 不 需 要 使 用 get 信 息 , 就 可 以 将 关 键 的 查 询 信 息 传 入 脚 本 中 , 例<br />

如 顾 客 的 ID 信 息 。 使 用 参 数 是 最 佳 的 方 法 之 一 , 它 确 保 了 搜 索 引 擎 爬 虫 可 以 获 取 到<br />

动 态 内 容 , 这 是 因 为 大 多 数 爬 虫 程 序 都 会 忽 略 查 询 变 量 。<br />

如 果 在 URL 参 数 中 没 有 找 到 请 求 的 键 值 ,getParam() 方 法 也 会 访 问 query 和 post 信 息 。<br />

getParam($key, $default = null)<br />

getParams() 方 法 会 返 回 包 含 所 有 参 数 、query 和 post 信 息 的 一 个 数 组 。<br />

要 确 定 当 前 的 HTTP 请 求 方 法 , 如 GET、POST、HEAD 等 , 可 以 使 用 以 下 方 法 :<br />

getMethod()。<br />

另 外 , 还 可 以 使 用 以 is 开 头 的 一 些 方 便 的 函 数 :isPost()。<br />

2.response 对 象<br />

response 对 象 包 含 了 允 许 设 置 头 信 息 和 分 配 响 应 内 容 的 方 法 。 代 码 清 单 15-9 演 示<br />

了 如 何 设 置 一 个 Content-Type 头 信 息 , 以 及 如 何 在 一 个 JSON(JavaScript Object<br />

Notation,JavaScript 对 象 标 志 ) 操 作 的 场 景 中 设 置 响 应 内 容 。<br />

代 码 清 单 1-9 JSON 返 回 操 作<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 26/111


扩 展 与 框 架 :<br />

《PHPer》<br />

public function jsonAction() {<br />

// 不 输 出 模 板<br />

$this->getHelper('ViewRenderer')->setNoRender();<br />

// 设 置 response 对 象 中 的 内 容 类 型 头 信 息<br />

$this->getResponse()->setHeader('Content-Type', 'application/json');<br />

}<br />

// 手 工 设 置 响 应 内 容 , 而 不 是 输 出 模 板<br />

$json = '{"Name":"Kevin"}';<br />

$this->getResponse()->setBody($json);<br />

此 外 , 你 还 可 能 会 使 用 setHttpResponseCode() 方 法 来 设 置 状 态 码 , 例 如 在 你 希 望<br />

创 建 404 错 误 或 者 503 错 误 页 面 时 。<br />

3.2 使 用 内 置 的 操 作 辅 助 类<br />

操 作 辅 助 类 是 一 种 可 重 用 的 类 , 可 以 向 控 制 器 添 加 功 能 , 通 常 这 种 功 能 不 应 该 被<br />

当 作 程 序 逻 辑 功 能 。 例 如 , 在 Zend 框 架 中 , 将 用 户 重 定 向 到 另 外 一 个 页 面 的 能 力 是<br />

作 为 辅 助 类 来 实 现 的 。<br />

在 第 17 章 你 将 学 到 如 何 创 建 自 己 的 操 作 辅 助 类 。 现 在 , 我 们 介 绍 一 些 内 置 的 操 作 辅<br />

助 类 。<br />

1.Redirector 辅 助 类<br />

Redirector 辅 助 类 执 行 的 操 作 和 它 的 名 称 的 含 义 一 样 , 允 许 将 用 户 重 定 向 到 一 个 新<br />

的 页 面 。 它 提 供 了 几 种 方 法 , 但 最 关 键 的 一 个 是 goto() 方 法 。<br />

void goto($action, $controller=null, $module=null, $params=array())<br />

goto() 方 法 执 行 重 定 向 操 作 , 并 且 允 许 重 定 向 到 一 个 特 定 的 操 作 。 应 该 优 先 使 用 提<br />

供 的 API, 而 不 是 直 接 使 用 头 信 息 , 这 是 因 为 有 几 种 因 素 会 在 执 行 过 程 中 影 响 Zend<br />

框 架 应 用 程 序 的 URL 布 局 功 能 。<br />

为 了 将 用 户 重 定 向 到 一 个 新 页 面 , 需 要 向 customers 控 制 器 添 加 一 个 操 作 方 法 , 如<br />

代 码 清 单 1-10 所 示 。<br />

代 码 清 单 1-10 使 用 Redirector 辅 助 类 ( 在 CustomersController.php 文 件 中 )<br />

代 码 片 段<br />

public function redirectAction() {<br />

$this->getHelper('redirector')->goto('index');<br />

}<br />

当 访 问 /customers/redirecct 时 , 应 该 会 将 你 的 动 作 转 发 到 index 动 作 。<br />

可 以 使 用 Zend_Controller_Action 类 的 getHelper() 方 法 , 通 过 辅 助 名 称 来 访 问 所 有 的 辅<br />

助 类 。<br />

2.FlashMessenger 辅 助 类<br />

FlashMessenger 辅 助 类 的 作 用 在 于 将 一 个 请 求 的 消 息 保 存 到 下 一 个 页 面 。 它 允 许<br />

添 加 一 个 将 要 显 示 在 下 一 页 面 的 消 息 , 它 将 处 理 关 于 会 话 的 所 有 问 题 , 其 中 包 括 在 显<br />

示 完 成 之 后 将 这 个 消 息 从 会 话 中 删 除 。<br />

FlashMessenger 辅 助 类 的 用 法 将 在 代 码 清 单 1-11 和 代 码 清 单 1-12 中 演 示 。<br />

代 码 清 单 1-11 使 用 FlashMessenger 辅 助 类 ( 在 CustomersController.php 文 件 中 )<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 27/111


扩 展 与 框 架 :<br />

《PHPer》<br />

代 码 片 段<br />

public function redirectAction() {<br />

$this->getHelper('FlashMessenger')<br />

->addMessage("This was set at the redirector");<br />

$this->getHelper('redirector')->goto('show');<br />

}<br />

}<br />

public function showAction() {<br />

$this->view->messages = $this->getHelper('FlashMessenger')->getMessages();<br />

代 码 片 段<br />

代 码 清 单 1-12 消 息 视 图 (application/view/scripts/customers/show.phtml)<br />

<br />

<br />

<br />

如 果 访 问 /customers/redirect, 将 被 重 定 向 到 /customers/show 上 , 而 且 还 会 看 到 消 息 。<br />

然 后 , 如 果 重 新 加 载 页 面 , 将 看 不 到 这 个 消 息 , 因 为 在 它 被 显 示 出 来 之 后 它 就 被 从 会<br />

话 中 删 除 了 。<br />

3.3 使 用 内 置 的 视 图 辅 助 类<br />

视 图 辅 助 类 与 操 作 辅 助 类 遵 循 相 同 的 逻 辑 , 这 允 许 为 视 图 创 建 可 重 用 的 组 件 。 在<br />

后 面 你 将 学 到 如 何 创 建 视 图 辅 助 类 。 现 在 , 我 们 来 看 一 下 内 置 的 辅 助 类 。<br />

许 多 内 置 的 视 图 辅 助 类 协 助 创 建 表 单 并 将 表 单 绑 定 到 视 图 上 。 用 辅 助 类 创 建 表 单<br />

使 用 的 代 码 较 多 。 不 过 , 它 们 实 现 了 一 些 有 用 的 操 作 , 如 输 出 转 义 , 并 且 使 从 一 个 数<br />

组 来 创 建 选 择 下 拉 列 表 更 加 容 易 。 另 外 , 它 们 还 有 助 于 提 供 更 加 一 致 的 最 终 输 出 结 果 。<br />

因 为 customers 表 只 有 一 个 列 , 所 以 使 用 视 图 辅 助 类 将 非 常 容 易 。 创 建 一 个 如 代 码 清<br />

单 1-13 所 示 的 新 视 图 , 并 将 它 保 存 为 /application/views/scripts/customers/add.phtml。<br />

代 码 清 单 1-13 使 用 视 图 辅 助 类 (application/views/scripts/customers/add.phtml)<br />

代 码 片 段<br />

<br />

<br />

<br />

<br />

这 段 代 码 调 用 了 两 个 视 图 辅 助 类 :formText 和 formSubmit。 解 析 这 些 视 图 将 生 成<br />

以 下 输 出 HTML。<br />

下 一 步 , 向 CustomersController.php 文 件 中 的 控 制 器 类 添 加 一 个 空 的 操 作 方 法 , 如<br />

代 码 清 单 1-14 所 示 。 即 使 没 有 方 法 实 现 体 , 这 个 方 法 的 存 在 也 提 供 了 输 出<br />

customers/add.phtml 视 图 的 功 能 。<br />

代 码 清 单 1-14 添 加 一 个 操 作 方 法 ( 在 CustomersController.php 文 件 中 )<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 28/111


扩 展 与 框 架 :<br />

《PHPer》<br />

public function addAction() {}<br />

下 一 步 , 访 问 http://example.com/customers/add, 便 可 以 看 到 表 单 了 。<br />

在 开 始 处 理 任 何 特 定 的 表 单 之 前 , 提 交 一 些 有 效 的 数 据 并 确 保 它 们 能 够 让 你 的 应<br />

用 程 序 正 确 运 行 通 常 是 很 有 用 的 。 一 般 来 说 , 你 可 能 会 使 用 var_dump($_POST) 方 法<br />

或 者 一 些 类 似 的 方 法 来 输 出 所 有 的 表 单 数 据 。 不 过 , 在 Zend 框 架 中 , 你 希 望 确 保 数<br />

据 能 够 正 确 地 被 所 有 的 API 理 解 。 要 实 现 这 一 点 , 你 将 使 用 Zend_Debug 以 显 示 由<br />

Zend_Request 对 象 解 析 的 post 信 息 。 修 改 addAction() 方 法 , 如 代 码 清 单 1-15 所 示 。<br />

代 码 清 单 1-15 使 用 Zend_Debug::dump( 在 CustomersController.php 文 件 中 )<br />

代 码 片 段<br />

public function addAction() {<br />

Zend_Debug::dump($this->getRequest()->getPost());<br />

}<br />

到 目 前 为 止 , 你 知 道 输 入 的 数 据 是 有 效 的 , 并 且 post 操 作 也 是 正 确 的 。 现 在 便 可<br />

以 开 始 处 理 表 单 了 。<br />

3.4 验 证 输 入 信 息<br />

在 将 post 信 息 提 交 给 数 据 库 之 前 , 必 须 确 保 信 息 有 效 , 以 便 使 数 据 库 中 的 数 据 保<br />

持 一 致 。Zend_Db 基 础 架 构 将 提 供 对 SQL 注 入 的 保 护 , 所 以 这 个 校 验 层 主 要 是 为 了<br />

确 保 数 据 是 合 理 的 , 并 且 可 以 安 全 地 显 示 在 其 他 页 面 中 。<br />

在 Zend 框 架 应 用 程 序 中 接 受 用 户 的 输 入 数 据 包 含 两 个 部 分 。<br />

• 过 滤 , 这 一 部 分 包 括 了 修 改 数 据 操 作 , 例 如 去 掉 字 符 串 末 尾 的 空 格 或 者 删 除<br />

HTML 标 签 等 操 作 。<br />

• 验 证 , 这 一 部 分 在 过 滤 之 后 发 生 , 它 可 以 确 保 数 据 是 合 理 的 , 以 保 证 它 不 会<br />

导 致 如 跨 站 点 脚 本 攻 击 这 样 的 问 题 。<br />

这 些 操 作 分 别 通 过 Zend_Filter 类 和 Zend_Validate 类 来 实 现 。 不 过 , 它 们 更 多 的 是<br />

通 过 Zend_Filter_Input 类 在 一 起 使 用 的 , 这 个 类 的 作 用 在 于 过 滤 信 息 数 组 , 例 如 整 个<br />

表 单 或 者 URL 参 数 集 合 。<br />

1. 使 用 Zend_Filter_Input 类<br />

要 使 用 Zend_Filter_Input 类 , 首 先 需 要 定 义 两 个 关 联 数 组 , 一 个 用 于 过 滤 器 , 另<br />

外 一 个 用 于 验 证 器 。 这 些 数 组 中 的 键 值 指 向 你 希 望 验 证 的 字 段 , 而 相 对 应 的 数 值 定 义<br />

了 要 应 用 的 规 则 。 代 码 清 单 1-16 显 示 了 如 何 验 证 customers 表 单 。<br />

代 码 清 单 1-16 验 证 表 单 ( 在 CustomersController.php 文 件 中 )<br />

代 码 片 段<br />

public function addAction() {<br />

$request = $this->getRequest();<br />

// 确 定 是 否 正 在 处 理 post 请 求<br />

if($request->isPost()) {<br />

// 过 滤 掉 name 字 段 的 标 签<br />

$filters = array(<br />

'name' => 'StripTags'<br />

);<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 29/111


扩 展 与 框 架 :<br />

《PHPer》<br />

// 验 证 名 称 不 少 于 1 个 字 符 并 且 不 多 于 64 个 字 符<br />

$validation = array(<br />

'name' => array (<br />

array('StringLength', 1, 64)<br />

)<br />

);<br />

// 初 始 化 Zend_Filter_Input(ZFI), 并 向 它 传 递 整 个 getPost() 数 组<br />

$zfi = new Zend_Filter_Input($filters, $validation, $request->getPost());<br />

// 如 果 验 证 通 过 , 这 个 值 应 该 为 true<br />

if ($zfi->isValid()) {<br />

// 直 接 从 zfi 获 取 数 据 并 且 为 Zend_Db 类 创 建 一 个 数 组<br />

$clean = array();<br />

$clean['name'] = $zfi->name;<br />

// 创 建 customers 表 的 一 个 实 例 并 插 入 $clean 行<br />

$customers = new Customers();<br />

$customers->insert($clean);<br />

// 在 添 加 完 数 据 之 后 重 定 向 到 显 示 页 面<br />

$this->getHelper('redirector')->goto('index');<br />

} else {<br />

// 表 单 没 有 通 过 验 证 , 从 ZFI 获 得 信 息<br />

foreach($zfi->getMessages() as $field=>$messages) {<br />

// 将 每 个 ZFI 消 息 放 在 FlashMessenger 中 , 让 它 在 表 单 上 显 示 这 些 信 息<br />

foreach($messages as $message) {<br />

$this->getHelper('FlashMessenger')<br />

->addMessage($field . ' : '. $message);<br />

}<br />

}<br />

// 重 定 向 回 输 入 表 单 , 但 这 次 包 括 了 信 息 数 据<br />

$this->getHelper('redirector')->goto('add');<br />

}<br />

}<br />

// 不 是 post 请 求 , 检 查 flash 信 息 并 显 示 到 视 图 上<br />

if($this->getHelper('FlashMessenger')->hasMessages()) {<br />

$this->view->messages = $this->getHelper('FlashMessenger')->getMessages();<br />

}<br />

// 视 图 显 示 器 会 自 动 地 输 出 add.phtml 模 板<br />

}<br />

还 需 要 修 改 add.phtml 模 板 。 在 文 件 顶 部 添 加 代 码 清 单 1-17 所 示 的 代 码 。<br />

代 码 清 单 1-17 修 改 Add 视 图 ( 在 add.phtml 文 件 中 )<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 30/111


扩 展 与 框 架 :<br />

《PHPer》<br />

代 码 片 段<br />

<br />

<br />

<br />

<br />

<br />

当 提 交 一 个 空 值 时 , 它 会 验 证 失 败 。 如 果 输 入 一 个 HTML 标 签 , 它 应 该 被 过 滤 掉 。<br />

验 证 器 和 过 滤 器 的 数 组 是 用 来 实 现 这 一 功 能 的 。 在 之 前 的 代 码 清 单 中 演 示 的 值 非 常 简<br />

单 , 但 可 以 使 用 一 些 非 常 复 杂 的 验 证 规 则 。 对 于 验 证 器 来 说 , 可 以 提 供 一 个 数 组 , 将<br />

多 个 验 证 器 应 用 到 一 个 字 段 上 。 例 如 , 如 果 要 求 姓 名 中 只 包 含 字 符 , 可 以 添 加 Alpha<br />

过 滤 器 , 如 代 码 清 单 1-18 所 示 。<br />

代 码 清 单 1-18 使 用 多 个 验 证 器<br />

代 码 片 段<br />

$validation = array(<br />

'name' => array (<br />

array('StringLength', 1, 64),<br />

'Alpha'<br />

)<br />

);<br />

你 会 留 意 到 这 里 只 使 用 了 验 证 器 的 名 称 , 而 不 是 数 组 。 这 是 因 为 并 非 所 有 的 验 证<br />

器 都 需 要 参 数 。 第 一 种 格 式 将 数 值 作 为 构 造 函 数 参 数 在 验 证 器 名 称 后 面 传 给 验 证 类 。<br />

第 二 种 格 式 不 需 要 参 数 。<br />

要 找 到 所 有 内 置 验 证 类 的 清 单 , 可 以 在 Zend 框 架 库 的 安 装 目 录 中 查 找 以 下 的 路 径 :<br />

/ZendFramework-1.0.3/library/Zend/Validate<br />

在 这 里 , 你 将 找 到 包 含 了 验 证 类 的 文 件 集 合 , 你 可 以 直 接 使 用 这 些 验 证 类 。 它 们<br />

接 受 的 参 数 是 由 每 个 类 的 __construct() 方 法 定 义 的 。<br />

与 验 证 器 类 似 , 过 滤 器 也 可 以 串 在 一 起 。 以 下 是 查 找 过 滤 器 信 息 的 路 径 :<br />

ZendFramework-1.0.3/library/Zend/Filter<br />

对 于 StripTags 过 滤 器 , 你 将 留 意 到 它 接 受 多 个 参 数 , 而 不 仅 仅 是 允 许 使 用 的 标 签<br />

的 一 个 列 表 。 建 议 试 验 多 种 过 滤 器 和 验 证 器 的 组 合 , 从 而 找 到 一 个 适 合 表 格 的 混 合 体 。<br />

还 应 该 注 意 到 , 当 某 个 字 段 没 有 通 过 验 证 时 显 示 出 来 的 错 误 信 息 很 简 洁 , 你 可 能 希 望<br />

修 改 默 认 信 息 。<br />

2. 使 用 元 命 令<br />

可 以 通 过 一 种 名 为 元 命 令 的 特 殊 机 制 来 修 改 验 证 错 误 信 息 。 在 验 证 或 者 过 滤 记 录<br />

中 元 命 令 被 当 作 另 外 一 个 值 使 用 。 这 些 值 是 特 殊 的 保 留 字 , 或 者 是 执 行 一 些 附 加 功 能<br />

的 类 常 量 , 如 设 置 错 误 信 息 等 。 例 如 , 要 设 置 name 字 段 的 验 证 信 息 , 将 使 用 MESSAGES<br />

元 命 令 和 一 个 验 证 数 组 , 如 代 码 清 单 1-19 所 示 。<br />

代 码 清 单 1-19 控 制 错 误 信 息<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 31/111


扩 展 与 框 架 :<br />

《PHPer》<br />

$validation = array(<br />

'name' => array (<br />

array('StringLength', 1, 64),<br />

Zend_Filter_Input::MESSAGES => array(<br />

array(<br />

Zend_Validate_StringLength::TOO_SHORT => 'Name cannot be blank',<br />

Zend_Validate_StringLength::TOO_LONG => 'Name field is too long'<br />

)<br />

)<br />

)<br />

);<br />

ALLOW_EMPTY 元 命 令 允 许 一 个 字 段 提 交 空 值 。 这 个 字 段 仍 然 需 要 出 现 在 输 入<br />

数 据 数 组 中 , 这 被 称 为 presence, 但 它 的 值 可 能 是 "。 你 可 以 认 为 在 Zend 框 架 中 presence<br />

和 empty 的 区 别 与 PHP 中 null 和 " 的 区 别 是 一 样 的 。 代 码 清 单 1-20 演 示 了<br />

ALLOW_EMPTY 元 命 令 的 用 法 。<br />

代 码 清 单 1-20 允 许 为 空 的 字 段<br />

代 码 片 段<br />

$validation = array(<br />

'name' => array (<br />

'Alpha',<br />

Zend_Filter_Input::ALLOW_EMPTY => true<br />

)<br />

);<br />

这 个 字 段 现 在 可 以 包 含 零 个 或 多 个 字 母 字 符 。<br />

你 还 可 能 会 用 到 另 外 几 个 元 命 令 。<br />

• PRESENCE。 要 求 某 个 键 值 出 现 在 输 入 数 组 中 (Boolean)。<br />

• FIELDS。 不 使 用 输 入 键 值 作 为 字 段 名 称 , 重 写 并 使 用 这 个 值 作 为 替 代 。<br />

• DEFAULT。 如 果 某 个 字 段 不 存 在 , 就 为 这 个 字 段 设 置 一 个 默 认 值 。<br />

• BREAK_CHAIN。 在 验 证 某 个 字 段 时 碰 到 第 一 个 验 证 失 败 就 停 止 , 而 不 是 在<br />

它 上 面 应 用 所 有 的 验 证 器 。<br />

4 小 结<br />

在 本 文 中 , 我 们 介 绍 了 Zend 框 架 的 内 容 , 其 中 包 括 设 置 和 引 导 过 程 。 需 要 下 载 包 、<br />

设 置 权 限 , 通 常 还 要 为 Zend 框 架 配 置 Web 服 务 器 环 境 。 然 后 , 介 绍 了 MVC 模 式 中<br />

的 元 素 在 Zend 框 架 中 是 如 何 应 用 的 。<br />

本 文 中 的 示 例 项 目 演 示 了 一 个 非 常 基 本 的 视 图 , 介 绍 了 Zend 框 架 是 如 何 与 开 发 过<br />

程 一 起 工 作 的 。 在 下 一 章 , 你 将 学 到 如 何 使 用 其 他 的 一 些 Zend 框 架 特 性 , 其 中 包 括<br />

模 块 支 持 功 能 和 几 种 内 置 组 件 的 功 能 , 用 来 控 制 应 用 程 序 的 访 问 、 发 送 邮 件 、 使 用 会<br />

话 、 记 录 错 误 以 及 与 Web 服 务 交 互 等 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 32/111


扩 展 与 框 架 :<br />

《PHPer》<br />

QeePHP 快 速 入 门 ( 五 )—— 实 现 用 户 功 能<br />

1 实 现 用 户 注 册 ( 用 户 界 面 )<br />

廖 宇 雷<br />

根 据 我 们 最 开 始 的 分 析 ,todo 应 用 应 该 允 许 用 户 注 册 、 登 录 , 然 后 创 建 自 己 的 任<br />

务 列 表 。 用 户 注 册 这 个 功 能 流 程 很 简 单 , 用 流 程 图 表 示 如 下 :<br />

用 户 注 册 的 流 程<br />

这 个 功 能 我 们 使 用 users 控 制 器 的 register 动 作 来 完 成 , 所 以 首 先 通 过 WebSetup<br />

创 建 users 控 制 器 。 并 在 users 控 制 器 中 添 加 如 下 代 码 :<br />

代 码 片 段<br />

function actionRegister()<br />

{<br />

}<br />

现 在 通 过 浏 览 器 访<br />

问 http://localhost/todo/public/index.php?controller=users&action=register 还 只 能 看 到 一<br />

片 空 白 , 因 为 我 们 还 没 有 为 register 动 作 方 法 提 供 对 应 的 视 图 文 件 。<br />

1.1 创 建 视 图<br />

在 QeePHP 应 用 程 序 中 , 视 图 的 功 能 就 如 其 名 称 暗 示 的 一 样 , 是 用 来 显 示 给 用 户<br />

看 的 。 大 多 数 情 况 下 , 视 图 都 是 包 含 大 量 HTML 代 码 的 PHP 文 件 。 我 们 可 以 在 视 图<br />

中 输 出 变 量 内 容 , 以 便 将 操 作 结 果 展 示 给 用 户 。<br />

register 动 作 的 操 作 结 果 就 是 显 示 一 个 “ 用 户 注 册 ” 表 单 。 因 此 创 建<br />

app/view/users/register.php 文 件 , 内 容 如 下 :<br />

代 码 片 段<br />


扩 展 与 框 架 :<br />

《PHPer》<br />

<br />

<br />

<br />

<br />

<br />

现 在 刷 新 浏 览 器 , 就 可 以 看 到 注 册 表 单 了 。 但 是 我 们 会 发 现 浏 览 器 中 的 HTML 源<br />

代 码 是 不 合 法 的 。 因 为 连 head、body 等 基 本 元 素 都 没 有 。<br />

1.2 url() 函 数<br />

在 视 图 中 , 我 们 使 用 了 url() 函 数 。 这 个 函 数 在 QeePHP 框 架 中 承 担 着 非 常 重 要<br />

的 职 责 : 生 成 有 效 的 URL 地 址 。<br />

在 Web 应 用 程 序 中 ,URL 地 址 的 重 要 性 无 论 如 何 强 调 都 不 过 分 。 而 在 QeePHP<br />

中 ,URL 中 特 定 参 数 将 被 MVC 模 式 用 于 访 问 特 定 控 制 器 和 动 作 。 为 了 能 够 生 成 有<br />

效 的 URL 地 址 ,QeePHP 框 架 提 供 了 url() 函 数 。<br />

url() 函 数 有 多 种 用 法 , 但 最 常 用 的 用 法 只 需 要 两 个 参 数 :<br />

参 数<br />

用 途<br />

$udi<br />

指 定 URL 地 址 对 应 的 UDI<br />

$args<br />

要 在 URL 中 传 递 的 附 加 参 数<br />

这 里 提 到 的 UDI 是 统 一 目 的 地 标 识 符 (Uniform Destination Identifier) 的 缩 写 。<br />

UDI 由 控 制 器 、 动 作 、 名 字 空 间 以 及 模 块 名 组 成 , 采 用 如 下 的 格 式 :<br />

代 码 片 段<br />

namespace::controller/action@module<br />

UDI 字 符 串 中 , 每 一 个 部 分 都 是 可 选 的 。 如 果 没 有 提 供 控 制 器 和 动 作 名 , 则 使 用<br />

默 认 的 控 制 器 (default) 和 动 作 名 (index) 代 替 。<br />

UDI 字 符 串 写 法 示 例 :<br />

代 码 片 段<br />

controller<br />

controller/action<br />

/action<br />

controller@module<br />

controller/action@module<br />

namespace::controller<br />

namespace::controller/action<br />

namespace::controller@module<br />

namespace::controller/action@module<br />

@module<br />

namespace::@module<br />

由 于 本 教 程 没 有 用 到 名 字 空 间 和 模 块 , 所 以 整 篇 教 程 中 出 现 的 UDI 都 是<br />

“tasks/create”、“users/login” 这 样 的 形 式 。<br />

1.3 视 图 的 继 承<br />

在 传 统 开 发 模 式 中 , 视 图 是 个 不 被 人 重 视 的 地 方 。 配 合 Smarty 之 类 的 模 板 引 擎 ,<br />

将 页 面 分 割 成 多 个 子 模 板 就 算 不 错 了 。 但 是 随 着 现 代 Web 应 用 的 复 杂 度 越 来 越 高 ,<br />

对 用 户 界 面 的 要 求 也 变 得 更 严 格 , 传 统 做 法 的 工 作 量 和 灵 活 性 都 很 不 理 想 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 34/111


扩 展 与 框 架 :<br />

《PHPer》<br />

参 考 下 面 的 示 意 图 , 可 以 看 到 一 个 页 面 中 , 除 了 中 间 的 内 容 部 分 外 , 页 头 、 侧 边 栏 、<br />

页 脚 在 其 他 页 面 中 都 是 可 以 重 复 使 用 。 那 么 我 们 为 什 么 不 能 引 入 面 向 对 象 中 的 继 承 思<br />

想 , 让 视 图 也 可 以 继 承 呢 ?<br />

典 型 的 视 图 布 局<br />

使 用 模 板 继 承 后 , 我 们 把 整 个 页 面 作 为 一 个 父 模 板 , 而 各 个 页 面 对 应 的 模 板 做 成<br />

子 模 板 , 子 模 板 从 父 模 板 继 承 。<br />

多 个 子 模 板 从 父 模 板 继 承<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 35/111


扩 展 与 框 架 :<br />

《PHPer》<br />

1.4 完 成 视 图<br />

虽 然 没 有 特 别 要 求 , 但 惯 例 上 将 包 含 页 面 整 体 结 构 的 视 图 称 为 “ 布 局 视 图 ”。 在 todo<br />

应 用 中 , 为 了 简 单 起 见 , 我 们 就 不 制 作 新 的 布 局 视 图 了 , 直 接 沿 用 生 成 应 用 时 自 动 创<br />

建 的 布 局 视 图 。<br />

修 改 register.php 文 件 , 顶 部 加 入 下 列 代 码 :<br />

代 码 片 段<br />

// 指 示 该 视 图 从 _layouts/default_layout 继 承<br />

<br />

// 定 义 一 个 名 为 contents 的 区 块<br />

<br />

在 register.php 文 件 底 部 加 入 :<br />

代 码 片 段<br />

// 区 块 定 义 结 束<br />

<br />

修 改 完 成 后 刷 新 浏 览 器 , 可 以 看 到 现 在 的 页 面 不 但 有 register.php 中 添 加 的 表 单<br />

内 容 , 还 有 完 整 的 页 头 、 侧 边 栏 和 页 脚 。<br />

1.5 指 定 要 继 承 的 视 图<br />

从 布 局 视 图 继 承 后 获 得 的 完 整 页 面<br />

新 增 的 代 码 中 , _extends() 方 法 表 示 当 前 视 图 从 哪 一 个 视 图 继 承 。 打 开<br />

_layouts/default_layout.php 可 以 看 到 这 里 定 义 了 完 整 的 页 面 结 构 。 注 意 _extends() 方<br />

法 指 定 的 视 图 名 字 不 需 要 包 含 扩 展 名 。 因 为 QeePHP 支 持 多 种 模 板 引 擎 , 而 每 种 模 板<br />

引 擎 使 用 的 文 件 扩 展 名 都 有 所 不 同 。<br />

1.6 通 过 定 义 区 块 来 覆 盖 父 模 板 中 的 内 容<br />

在 新 增 代 码 中 , 出 现 了 _block() 和 _endblock() 两 个 方 法 。 这 两 个 方 法 总 是 成 对<br />

出 现 的 , 用 来 定 义 一 个 “ 区 块 ”。 每 一 个 区 块 都 有 名 称 , 因 此 _block() 方 法 需 要 提 供 区<br />

块 名 称 作 为 参 数 。 在 子 模 板 中 定 义 的 区 块 , 区 块 的 内 容 会 替 换 掉 父 模 板 中 同 名 区 块 的<br />

内 容 。<br />

打 开 _layouts/default_layout.php 父 模 板 可 以 看 到 如 下 代 码 :<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 36/111


扩 展 与 框 架 :<br />

《PHPer》<br />

<br />

<br />

这 里 定 义 了 一 个 名 为 “contents” 的 区 块 。 由 于 子 模 板 中 也 定 义 了 同 名 区 块 , 所 以 子<br />

模 板 中 的 内 容 就 将 父 模 板 的 “contents” 区 块 内 容 替 换 掉 了 , 最 终 获 得 了 完 整 的 输 出 内 容 。<br />

利 用 这 个 特 性 , 我 们 可 以 实 现 非 常 灵 活 的 视 图 。 例 如 在 文 章 显 示 页 面 , 将 文 章 标 题 添<br />

加 到 页 面 的 title 标 签 中 :<br />

代 码 片 段<br />

// 父 模 板<br />

这 是 我 的 网 站 - 欢 迎 <br />

// 子 模 板<br />

<br />

当 显 示 文 章 页 面 时 , 文 章 页 面 视 图 中 定 义 的 “title” 区 块 就 会 替 换 掉 父 模 板 中 的 内 容 。<br />

从 而 页 面 标 题 就 变 成 了 “ 这 是 我 的 网 站 – 文 章 的 标 题 ”。 而 在 没 有 定 义 “title” 区 块 的 子<br />

模 板 中 , 父 模 板 “title” 区 块 的 内 容 则 会 被 保 留 。<br />

除 了 继 承 和 区 块 ,QeePHP 的 视 图 还 提 供 了 其 他 非 常 有 使 用 价 值 的 特 征 。 我 们 会<br />

在 教 程 接 下 来 的 内 容 中 为 大 家 逐 步 呈 现 。<br />

2 实 现 用 户 注 册 ( 功 能 实 现 )<br />

在 前 面 的 小 结 中 , 我 们 主 要 学 习 了 怎 么 使 用 视 图 。 现 在 我 们 来 解 决 表 单 提 交 , 以<br />

及 模 型 的 创 建 问 题 。<br />

2.1 丑 陋 的 表 单 提 交 处 理 代 码<br />

修 改 controller/users.php 文 件 , 加 入 以 下 代 码 :<br />

代 码 片 段<br />

function actionRegister()<br />

{<br />

// 从 POST 中 提 取 用 户 名 和 密 码<br />

$username = trim(strtolower(isset($_POST['username']) ? $_POST['username'] : ''));<br />

$password = isset($_POST['password']) ? $_POST['password'] : '';<br />

// 对 输 入 数 据 进 行 验 证<br />

$errors = array();<br />

if (strlen($username) < 5)<br />

{<br />

$errors['username'][] = ' 用 户 名 不 能 少 于 5 个 字 符 ';<br />

}<br />

if (strlen($username) > 15)<br />

{<br />

$errors['username'][] = ' 用 户 名 不 能 超 过 15 个 字 符 ';<br />

}<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 37/111


扩 展 与 框 架 :<br />

《PHPer》<br />

}<br />

if (strlen($password) < 6)<br />

{<br />

$errors['password'][] = ' 密 码 不 能 少 于 6 个 字 符 ';<br />

}<br />

..... 更 多 的 验 证 代 码<br />

..... 检 查 用 户 名 是 否 重 复<br />

..... 检 查 保 存 是 否 成 功<br />

..... 如 果 失 败 , 将 错 误 信 息 存 入 视 图<br />

..... 如 果 失 败 , 将 POST 信 息 存 入 视 图 , 以 便 在 表 单 中 重 新 显 示 提 交 的 内 容<br />

上 述 代 码 可 能 和 过 去 的 做 法 类 似 , 但 是 这 些 代 码 看 着 不 恶 心 吗 ?<br />

QeePHP 为 表 单 提 供 了 全 面 支 持 , 并 且 允 许 开 发 者 将 表 单 和 模 型 结 合 起 来 使 用 。<br />

这 样 一 来 , 表 单 数 据 的 过 滤 、 验 证 , 以 及 错 误 处 理 都 可 以 自 动 完 成 , 不 需 要 开 发 者 手<br />

工 编 码 实 现 。 关 于 如 何 使 用 表 单 , 有 专 门 的 章 节 详 细 阐 述 。 这 里 我 们 只 简 单 的 展 示 一<br />

下 使 用 QeePHP 表 单 模 型 带 来 的 优 势 。<br />

2.2 完 善 模 型 定 义<br />

时 刻 记 住 一 点 ,QeePHP 是 一 个 遵 循 “ 领 域 驱 动 开 发 ” 思 想 的 框 架 。 而 领 域 驱 动 中 ,<br />

最 重 要 的 就 是 模 型 。 而 我 们 的 大 多 数 表 单 都 是 和 模 型 有 关 的 , 所 以 在 处 理 表 单 之 前 ,<br />

首 先 要 完 善 模 型 的 定 义 。 因 为 这 些 定 义 可 以 直 接 套 入 表 单 对 象 中 , 避 免 我 们 在 不 同 的<br />

地 方 编 写 同 样 的 逻 辑 , 这 就 是 DRY 原 则 的 最 佳 实 践 。<br />

先 前 创 建 的 User 模 型 只 是 半 成 品 , 现 在 我 们 需 要 对 其 进 行 完 善 。 一 个 模 型 由 几<br />

个 方 面 组 成 :<br />

• 属 性 : 定 义 模 型 有 哪 些 属 性 、 属 性 的 类 型 以 及 属 性 的 行 为 和 验 证 规 则 等<br />

• 行 为 : 添 加 实 现 业 务 逻 辑 需 要 的 方 法 , 让 模 型 逐 步 逼 近 实 际 的 需 求<br />

• 数 据 : 由 属 性 和 存 储 模 型 属 性 的 数 据 表 组 成 , 但 属 性 不 一 定 要 和 数 据 表 一 一<br />

对 应<br />

• 关 系 : 模 型 需 要 互 相 配 合 来 实 现 业 务 需 求 , 因 此 关 系 也 是 模 型 的 一 部 分<br />

2.3 完 善 模 型 的 属 性<br />

打 开 模 型 的 定 义 文 件 , 在 __define() 方 法 中 可 以 找 到 模 型 的 详 细 定 义 。 这 些 定 义<br />

分 为 几 个 部 分 :<br />

• 指 定 存 储 模 型 使 用 的 数 据 表<br />

• 属 性 和 关 联 的 定 义 , 例 如 只 读 属 性 、 虚 拟 属 性 、 关 联 等<br />

• 对 属 性 的 验 证 规 则<br />

• 安 全 性 方 面 的 定 义<br />

• 行 为 插 件 的 定 义<br />

在 QeePHP 的 模 型 中 , 属 性 本 身 具 有 多 种 特 性 :<br />

• 是 否 是 只 读 属 性<br />

• 是 否 是 虚 拟 属 性<br />

• 是 否 有 getter 或 setter 方 法<br />

• 类 型<br />

• 验 证 规 则<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 38/111


扩 展 与 框 架 :<br />

《PHPer》<br />

对 于 todo 这 样 的 简 单 应 用 , 我 们 用 不 到 这 么 多 高 级 特 性 , 所 以 上 述 内 容 了 解 一 下<br />

就 行 了 。<br />

todo 应 用 中 ,user 模 型 只 有 两 个 主 要 属 性 : 用 户 名 和 密 码 。 根 据 需 求 , 这 两 个 属<br />

性 有 下 列 要 求 :<br />

• 用 户 名 应 该 是 唯 一 的<br />

• 用 户 一 旦 成 功 创 建 , 就 不 能 更 改 用 户 名 , 因 此 用 户 名 必 须 是 只 读 属 性<br />

• 用 户 名 不 能 少 于 5 个 字 符 , 不 能 多 于 15 个 字 符 , 并 且 只 能 使 用 字 母 和 数 字<br />

组 成<br />

• 密 码 不 能 少 于 6 个 字 符 , 不 能 多 于 20 个 字 符<br />

• 密 码 应 该 加 密 存 储<br />

现 在 我 们 一 步 步 来 实 现 这 些 要 求 。<br />

修 改 __define() 方 法 , 禁 止 更 新 用 户 名 :<br />

代 码 片 段<br />

'props' => array(<br />

.....<br />

// 指 定 username 属 性 为 只 读<br />

'username' => array('readonly' => true),<br />

.....<br />

),<br />

/**<br />

* 指 定 更 新 数 据 库 中 的 对 象 时 , 哪 些 属 性 的 值 不 允 许 由 外 部 提 供<br />

*/<br />

'update_reject' => 'username',<br />

继 续 :<br />

代 码 片 段<br />

'validations' => array<br />

(<br />

// 指 定 username 属 性 的 验 证 规 则<br />

'username' => array<br />

(<br />

array('not_empty', ' 用 户 名 不 能 为 空 '),<br />

array('min_length', 5, ' 用 户 名 不 能 少 于 5 个 字 符 '),<br />

array('max_length', 15, ' 用 户 名 不 能 超 过 15 个 字 符 '),<br />

array('is_alnum', ' 用 户 名 只 能 由 字 母 和 数 字 组 成 '),<br />

),<br />

// 指 定 password 属 性 的 验 证 规 则<br />

'password' => array<br />

(<br />

array('not_empty', ' 密 码 不 能 为 空 '),<br />

array('min_length', 6, ' 密 码 不 能 少 于 6 个 字 符 '),<br />

array('max_length', 20, ' 密 码 不 能 超 过 20 个 字 符 '),<br />

),<br />

),<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 39/111


扩 展 与 框 架 :<br />

《PHPer》<br />

经 过 简 单 的 设 置 , 大 部 分 要 求 都 可 以 由 QeePHP 来 处 理 了 , 剩 下 的 密 码 加 密 存 储<br />

则 可 以 借 助 现 成 的 acluser 行 为 插 件 来 实 现 。<br />

2.4 行 为 插 件<br />

虽 然 我 们 可 以 通 过 给 password 属 性 添 加 getter 和 setter 方 法 来 实 现 密 码 的 加 密 ,<br />

但 QeePHP 已 经 提 供 了 现 成 的 插 件 来 帮 助 我 们 完 成 类 似 工 作 , 并 且 提 供 了 更 丰 富 的 特<br />

性 。<br />

acluser 行 为 插 件 应 用 到 一 个 模 型 后 , 可 以 实 现 下 列 特 征 :<br />

• 密 码 属 性 的 自 动 加 密<br />

• 验 证 用 户 名 和 密 码 的 正 确 性<br />

• 验 证 用 户 名 的 唯 一 性<br />

• 查 询 用 户 的 基 本 属 性 和 角 色 信 息<br />

要 使 用 acluser 插 件 , 只 需 要 修 改 __define() 方 法 :<br />

代 码 片 段<br />

// 指 定 该 ActiveRecord 要 使 用 的 行 为 插 件<br />

'behaviors' => 'acluser',<br />

// 指 定 行 为 插 件 的 配 置<br />

'behaviors_settings' => array<br />

(<br />

# ' 插 件 名 ' => array(' 选 项 ' => 设 置 ),<br />

'acluser' => array(<br />

'acl_data_props' => 'username',<br />

),<br />

),<br />

acluser 插 件 的 详 细 文 档 请 参<br />

考 : http://qeephp.com/docs/qeephp-api/class-model-behavior-acluser<br />

指 定 好 acluser 插 件 后 , 我 们 的 user 模 型 在 属 性 方 面 就 完 善 了 。<br />

2.5 完 善 模 型 的 行 为 和 关 系<br />

根 据 前 面 的 需 求 分 析 ,user 模 型 具 有 下 列 行 为 :<br />

user 模 型 的 行 为<br />

validateLogin<br />

验 证 用 户 名 和 密 码<br />

createTask<br />

创 建 属 于 该 用 户 的 任 务<br />

loadTasks<br />

载 入 属 于 该 用 户 的 任 务<br />

由 于 acluser 插 件 已 经 提 供 了 验 证 用 户 名 和 密 码 的 方 法 ,validateLogin() 方 法 不 需<br />

要 我 们 自 己 实 现 了 。 下 面 来 实 现 createTask() 和 loadTasks() 方 法 。 修 改 user 模 型 的<br />

类 , 加 入 下 列 代 码 :<br />

代 码 片 段<br />

class User extends QDB_ActiveRecord_Abstract<br />

{<br />

/**<br />

* 创 建 属 于 当 前 用 户 的 任 务<br />

*<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 40/111


扩 展 与 框 架 :<br />

《PHPer》<br />

}<br />

* @return Task<br />

*/<br />

function createTask($subject, $description = null)<br />

{<br />

$task = new Task();<br />

$task->owner = $this;<br />

$task->subject = $subject;<br />

$task->description = $description;<br />

return $task;<br />

}<br />

.....<br />

而 loadTasks() 方 法 也 不 需 要 我 们 去 实 现 , 因 为 QeePHP 的 ORM 可 以 让 我 们 直<br />

接 通 过 属 性 访 问 一 个 模 型 关 联 的 其 他 模 型 。 所 以 我 们 只 需 要 修 改 __define() 方 法 , 加<br />

入 user 模 型 和 task 模 型 的 关 联 就 可 以 了 :<br />

代 码 片 段<br />

'props' => array(<br />

.....<br />

'tasks' => array(QDB::HAS_MANY => 'Task', 'target_key' => 'user_id'),<br />

.....<br />

),<br />

OK, 现 在 用 户 模 型 已 经 准 备 好 了 。<br />

2.6 实 现 用 户 注 册 表 单<br />

在 Web 应 用 中 , 表 单 需 要 完 成 下 面 的 主 要 任 务 :<br />

• 容 纳 从 客 户 端 提 交 的 数 据<br />

• 对 客 户 端 提 交 的 数 据 进 行 过 滤<br />

• 对 客 户 端 提 交 的 数 据 进 行 验 证<br />

• 导 出 过 滤 和 验 证 后 的 数 据<br />

• 构 造 出 在 浏 览 器 中 需 要 的 HTML 代 码<br />

为 了 提 供 更 好 的 灵 活 性 , 并 且 简 化 表 单 的 使 用 ,QeePHP 将 上 述 几 项 任 务 分 为 多<br />

个 不 同 的 部 分 :<br />

• QForm 负 责 构 造 表 单 元 素 容 器<br />

• 表 单 元 素 负 责 容 纳 数 据 , 并 数 据 进 行 过 滤 和 验 证<br />

• 通 过 QeePHP 的 用 户 界 面 控 件 构 造 表 单 HTML 代 码<br />

在 QeePHP 应 用 中 使 用 表 单 , 典 型 的 过 程 如 下 :<br />

• 创 建 表 单 , 定 义 表 单 需 要 容 纳 的 数 据 , 以 及 过 滤 和 验 证 规 则<br />

• 在 控 制 器 动 作 中 构 造 表 单 对 象 , 并 导 入 数 据 进 行 过 滤 和 验 证<br />

• 在 视 图 中 构 造 表 单 的 HTML 代 码 , 或 者 通 过 视 图 片 段 构 造 表 单 HTML 代 码<br />

搞 清 楚 了 基 本 概 念 , 我 们 就 来 一 步 步 实 现 用 户 注 册 表 单 。<br />

2.7 创 建 表 单 对 象<br />

新 建 文 件 app/form/userlogin.php, 内 容 如 下 :<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 41/111


扩 展 与 框 架 :<br />

《PHPer》<br />

代 码 片 段<br />

class Form_UserLogin extends QForm<br />

{<br />

function __construct($action)<br />

{<br />

// 调 用 父 类 的 构 造 函 数<br />

parent::__construct('form_userlogin', $action);<br />

}<br />

}<br />

// 从 配 置 文 件 载 入 表 单<br />

$filename = rtrim(dirname(__FILE__), '/\\') . DS . 'userlogin_form.yaml';<br />

$this->loadFromConfig(Helper_YAML::loadCached($filename));<br />

$this->addValidations(User::meta());<br />

再 新 建 文 件 app/form/userlogin_form.yaml:<br />

代 码 片 段<br />

# ~form 开 头 的 内 容 用 于 指 定 表 单 属 性<br />

~form:<br />

_subject: " 注 册 新 用 户 "<br />

# 指 定 字 段 及 过 滤 器 等 信 息<br />

username:<br />

_ui: textbox<br />

_filters: ['trim', 'strtolower']<br />

_label: " 用 户 名 "<br />

password:<br />

_ui: password<br />

_label: " 密 码 "<br />

虽 然 为 了 演 示 表 单 的 时 候 , 对 于 用 户 登 录 这 种 表 单 我 们 也 用 了 两 个 分 离 的 文 件 。<br />

但 对 于 一 些 复 杂 表 单 , 分 离 为 两 个 文 件 后 , 可 以 分 别 修 改 表 单 的 行 为 ( 表 单 对 象 文 件 )<br />

和 定 义 ( 配 置 文 件 ), 更 好 的 实 现 职 责 分 离 的 目 标 。<br />

2.8 准 备 表 单 视 图<br />

表 单 对 象 要 转 换 成 HTML 代 码 , 还 要 借 助 表 单 视 图 。 幸 运 的 是 表 单 视 图 是 一 个<br />

完 全 独 立 的 部 分 , 我 们 可 以 从 QeePHP 社 区 上 下 载 一 些 现 成 的 表 单 视 图 来 使 用 , 或<br />

者 以 其 为 基 础 修 改 。 这 样 大 大 的 减 少 了 工 作 量 。 这 里 使 用 的 是<br />

http://qeephp.com/projects/show/name/formview_simple 这 个 表 单 视 图 。<br />

记 得 将 表 单 视 图 的 样 式 表 合 并 到 public/css/style.css 文 件 中 。 按 照 说 明 准 备 好 文<br />

件 后 , 修 改 app/view/users/register.php 文 件 的 内 容 为 :<br />

代 码 片 段<br />

<br />

<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 42/111


扩 展 与 框 架 :<br />

《PHPer》<br />

<br />

<br />

相 比 以 前 手 工 编 写 的 表 单 , 代 码 量 大 大 减 少 , 而 且 还 具 有 更 多 的 功 能 。<br />

2.9 实 现 用 户 登 录<br />

修 改 users 控 制 器 的 actionRegister() 方 法 为 :<br />

代 码 片 段<br />

function actionRegister()<br />

{<br />

// 构 造 表 单 对 象<br />

$form = new Form_UserLogin(url('users/register'));<br />

if ($this->_context->isPOST() && $form->validate($_POST))<br />

{<br />

// 是 POST 提 交 , 并 且 表 单 验 证 通 过<br />

try<br />

{<br />

// 创 建 user 对 象 并 保 存<br />

$user = new User($form->values());<br />

$user->save();<br />

题<br />

}<br />

}<br />

// 成 功 后 输 出 新 建 用 户 对 象 的 信 息<br />

dump($user->username, ' 新 建 用 户 的 用 户 名 ');<br />

dump($user->password, ' 新 建 用 户 的 密 码 ');<br />

dump($user->id(), ' 新 建 用 户 的 ID');<br />

exit;<br />

}<br />

catch (AclUser_DuplicateUsernameException $ex)<br />

{<br />

// 捕 获 AclUser_DuplicateUsernameException 异 常 , 在 表 单 中 指 出 用 户 名 存 在 重 复 问<br />

}<br />

$form['username']->invalidate(" 您 要 注 册 用 户 名 {$user->username} 已 经 存 在 了 ");<br />

// 将 表 单 对 象 传 递 给 视 图<br />

$this->_view['form'] = $form;<br />

现 在 用 浏 览 器 访<br />

问 http://localhost/todo/public/index.php?controller=users&action=register , 然 后 不 输 入<br />

任 何 内 容 就 点 击 “ 提 交 ” 按 钮 , 将 可 以 看 到 如 下 界 面 :<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 43/111


扩 展 与 框 架 :<br />

《PHPer》<br />

对 验 证 信 息 的 反 馈<br />

现 在 输 入 用 户 名 为 :imphper, 密 码 为 123456, 提 交 后 会 看 到 如 下 内 容 :<br />

注 册 成 功 后 的 输 出 信 息<br />

通 过 phpMyAdmin 可 以 看 到 刚 刚 输 入 的 信 息 已 经 存 入 数 据 库 了 :<br />

保 存 到 数 据 库 中 的 用 户 信 息<br />

为 了 方 便 后 续 开 发 , 我 们 再 修 改 一 下 users 控 制 器 的 actionRegister() 方 法 :<br />

代 码 片 段<br />

// 成 功 后 输 出 新 建 用 户 对 象 的 信 息<br />

dump($user->username, ' 新 建 用 户 的 用 户 名 ');<br />

dump($user->password, ' 新 建 用 户 的 密 码 ');<br />

dump($user->id(), ' 新 建 用 户 的 ID');<br />

exit;<br />

改 为 :<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 44/111


扩 展 与 框 架 :<br />

《PHPer》<br />

// 登 录 成 功 后 , 重 定 向 浏 览 器<br />

return $this->_redirect(url('default/index'));<br />

现 在 读 者 朋 友 们 可 以 发 挥 自 己 的 想 象 力 , 尝 试 输 入 不 同 的 内 容 来 测 试 表 单 的 验 证<br />

规 则 、 过 滤 器 设 置 , 以 及 对 重 复 用 户 名 的 检 查 :)<br />

3 用 户 登 录 和 注 销<br />

通 过 前 面 实 现 用 户 注 册 功 能 , 我 们 了 解 了 如 何 完 善 模 型 及 创 建 表 单 。 这 一 个 小 节<br />

我 们 来 实 现 用 户 的 登 录 和 注 销 功 能 。<br />

3.1 实 现 登 录<br />

修 改 users 控 制 器 , 加 入 下 列 代 码 :<br />

代 码 片 段<br />

function actionLogin()<br />

{<br />

$form = new Form_UserLogin(url('users/login'));<br />

$form->_subject = ' 登 录 ';<br />

if ($this->_context->isPOST() && $form->validate($_POST))<br />

{<br />

try<br />

{<br />

// 使 用 acluser 插 件 的 validateLogin() 方 法 验 证 登 录 并 取 得 有 效 的 user 对 象<br />

$user = User::meta()->validateLogin($form['username']->value, $form['password']->value<br />

);<br />

}<br />

}<br />

// 将 登 录 用 户 的 信 息 存 入 SESSION, 以 便 应 用 程 序 记 住 用 户 的 登 录 状 态<br />

$this->_app->changeCurrentUser($user->aclData(), 'MEMBER');<br />

// 登 录 成 功 后 , 重 定 向 浏 览 器<br />

return $this->_redirect(url('default/index'));<br />

}<br />

catch (AclUser_UsernameNotFoundException $ex)<br />

{<br />

$form['username']->invalidate(" 您 输 入 的 用 户 名 {$form['username']->value} 不 存 在 ");<br />

}<br />

catch (AclUser_WrongPasswordException $ex)<br />

{<br />

$form['password']->invalidate(" 您 输 入 的 密 码 不 正 确 ");<br />

}<br />

$this->_view['form'] = $form;<br />

这 段 代 码 中 有 两 个 地 方 需 要 说 明 一 下 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 45/111


扩 展 与 框 架 :<br />

《PHPer》<br />

3.2 调 用 行 为 插 件 的 方 法<br />

acluser 行 为 插 件 为 模 型 扩 展 了 多 个 方 法 , 包 括 :<br />

方 法 名 用 途 类 型<br />

validateLogin() 验 证 用 户 登 录 并 返 回 用 户 对 象 类 方 法<br />

validateUsername() 验 证 用 户 名 类 方 法<br />

validatePassword() 验 证 用 户 名 和 密 码 类 方 法<br />

changePassword() 修 改 指 定 用 户 的 密 码 类 方 法<br />

checkPassword() 检 查 指 定 的 密 码 是 否 与 当 前 用 户 的 密 码 相 符 实 例 方 法<br />

changePassword() 修 改 当 前 用 户 的 密 码 实 例 方 法<br />

updateLogin() 更 新 用 户 的 登 录 信 息 实 例 方 法<br />

aclRoles() 获 得 包 含 用 户 所 有 角 色 名 的 数 组 实 例 方 法<br />

aclData() 获 得 用 户 的 ACL 数 据 实 例 方 法<br />

类 方 法 是 指 调 用 该 方 法 不 需 要 构 造 模 型 对 象 实 例 , 而 实 例 方 法 则 只 能 通 过 模 型 对<br />

象 实 例 来 调 用 。 要 调 用 一 个 类 方 法 :<br />

代 码 片 段<br />

User::meta()->validateLogin();<br />

调 用 一 个 实 例 方 法 则 是 :<br />

$user->changePassword();<br />

可 以 看 出 , 类 方 法 必 须 通 过 meta() 方 法 返 回 的 连 贯 接 口 来 调 用 。<br />

在 用 户 登 录 中 , 我 们 用 到 了 acluser 插 件 提 供 的 validateLogin() 类 方 法 , 所 以 调<br />

用 方 式 就 是 :<br />

代 码 片 段<br />

$user = User::meta()->validateLogin(<br />

$form['username']->value,<br />

$form['password']->value<br />

);<br />

validateLogin() 方 法 检 查 用 户 名 和 密 码 的 正 确 性 , 如 果 检 查 通 过 就 返 回 有 效 的 用<br />

户 对 象 , 否 则 抛 出 不 同 的 异 常 。 通 过 拦 截 异 常 我 们 就 可 以 给 用 户 反 馈 合 适 的 错 误 信 息 。<br />

3.3 记 住 用 户 的 登 录 状 态<br />

登 录 成 功 , 我 们 必 须 让 应 用 程 序 记 住 用 户 的 登 录 状 态 , 不 然 用 户 一 刷 新 页 面 , 又<br />

变 成 未 登 录 了 。 在 QeePHP 自 动 生 成 的 应 用 程 序 对 象 中 , 已 经 提 供 了 一 系 列 方 法 来 完<br />

成 这 项 工 作 :<br />

方 法 名<br />

用 途<br />

changeCurrentUser<br />

将 用 户 数 据 保 存 到 session 中<br />

currentUser()<br />

获 取 保 存 在 session 中 的 用 户 数 据<br />

currentUserRoles()<br />

获 取 session 中 用 户 信 息 包 含 的 角 色<br />

cleanCurrentUser()<br />

从 session 中 清 除 用 户 数 据<br />

所 以 要 让 应 用 程 序 记 住 用 户 的 登 录 状 态 , 调 用 changeCurrentUser() 方 法 就 可 以 了 。<br />

3.4 添 加 登 录 需 要 的 视 图<br />

我 们 还 没 有 添 加 登 录 页 面 需 要 的 视 图 , 不 过 由 于 登 录 和 注 册 的 页 面 内 容 完 全 一 样 ,<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 46/111


扩 展 与 框 架 :<br />

《PHPer》<br />

所 以 我 们 直 接 重 用 注 册 的 视 图 即 可 。 在 actionLogin() 方 法 最 后 添 加 一 行 代 码 :<br />

$this->_viewname = 'register';<br />

这 行 代 码 告 诉 QeePHP 使 用 register 动 作 的 视 图 。 修 改 好 后 , 访 问<br />

http://localhost/todo/public/index.php?controller=users&action=login 测 试 一 下 登 录 功 能<br />

吧 。<br />

3.5 实 现 注 销<br />

登 录 验<br />

既 然 有 登 录 , 就 有 注 销 , 在 users 控 制 器 新 增 方 法 actionLogout():<br />

代 码 片 段<br />

function actionLogout()<br />

{<br />

// 清 除 当 前 用 户 的 登 录 信 息<br />

$this->_app->cleanCurrentUser();<br />

}<br />

// 重 定 向 浏 览 器<br />

return $this->_redirect(url('default/index'));<br />

3.6 在 用 户 界 面 上 显 示 登 录 状 态<br />

现 在 注 册 、 登 录 和 注 销 功 能 都 做 好 了 , 但 是 用 户 界 面 上 还 没 有 相 应 的 链 接 , 而 且<br />

也 没 有 显 示 出 用 户 的 登 录 状 态 。<br />

在 编 码 之 前 , 我 们 可 以 打 开 app/view/_layouts/default_layout.php 文 件 来 看 看 。 可<br />

以 看 到 其 中 有 一 行 :<br />

代 码 片 段<br />

<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 47/111


扩 展 与 框 架 :<br />

《PHPer》<br />

侧 边 栏 视 图 片 段<br />

在 视 图 中 , 可 以 用 “$this->_element( 片 段 名 )” 来 载 入 一 个 视 图 片 段 , 该 视 图 片 段 存<br />

储 为 “app/view /_elements/ 片 段 名 _element.php” 文 件 。 例 如 “sidebar” 视 图 片 段 对 应 的 文<br />

件 名 就 是 “app/view/_elements /sidebar_element.php”。<br />

视 图 片 段 通 常 用 于 一 些 在 各 个 页 面 都 会 重 复 出 现 的 内 容 , 例 如 页 头 、 页 脚 等 。 合<br />

理 使 用 视 图 片 段 可 以 极 大 减 少 视 图 中 存 在 的 重 复 代 码 。 不 过 视 图 片 段 并 不 能 够 处 理 自<br />

己 需 要 的 数 据 , 所 以 像 显 示 当 前 用 户 登 录 信 息 这 样 的 需 求 , 我 们 需 要 使 用 用 户 界 面 控<br />

件 。<br />

3.7 用 户 界 面 组 件 化<br />

在 前 面 的 章 节 中 , 看 到 如 何 通 过 视 图 的 继 承 和 区 块 来 分 拆 用 户 界 面 , 最 终 获 得 各<br />

个 可 以 重 用 的 部 分 。 而 用 户 界 面 控 件 就 是 一 种 更 强 大 的 手 段 , 可 以 将 用 户 界 面 上 的 一<br />

个 独 立 区 域 封 装 起 来 。<br />

这 个 区 域 不 但 有 自 己 的 表 现 , 还 可 以 有 自 己 的 数 据 。 例 如 “ 最 新 10 个 回 复 ” 这 个 控<br />

件 可 以 自 己 查 询 最 新 的 10 个 回 复 数 据 , 然 后 载 入 自 己 的 视 图 来 构 造 HTML 代 码 。<br />

而 在 传 统 开 发 模 式 中 , 如 果 某 个 页 面 需 要 “ 最 新 10 个 回 复 ” 这 个 区 域 , 就 必 须 在 该 页 面<br />

对 应 的 控 制 器 动 作 中 查 询 需 要 的 数 据 。 最 终 , 各 个 控 制 器 动 作 中 都 重 复 着 相 同 的 代 码 。<br />

QeePHP 利 用 用 户 界 面 控 件 机 制 , 彻 底 解 决 了 这 个 问 题 , 完 全 符 合 DRY 原 则 。 现 在<br />

我 们 来 把 sidebar 这 个 视 图 片 段 转 换 为 一 个 用 户 界 面 控 件 。<br />

用 户 界 面 通 常 由 控 件 类 和 控 件 视 图 两 部 分 组 成 。 控 件 类 都 放 置 在 app/control/ 目<br />

录 中 。 我 们 现 在 新 建 文 件 app/control/sidebar.php 文 件 , 内 容 如 下 :<br />

代 码 片 段<br />

class Control_Sidebar extends QUI_Control_Abstract<br />

{<br />

function render()<br />

{<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 48/111


扩 展 与 框 架 :<br />

《PHPer》<br />

// 从 对 象 注 册 表 中 查 询 app 对 象<br />

$app = Q::registry('app');<br />

// 取 得 当 前 用 户 的 信 息<br />

$this->_view['current_user'] = $app->currentUser();<br />

}<br />

}<br />

// 渲 染 视 图 并 返 回 结 果<br />

return $this->_fetchView(dirname(__FILE__) . '/sidebar_view');<br />

然 后 将 文 件 app/view/_elements/sidebar_element.php 移 动 到 app/control/ 目 录 , 并<br />

改 名 为 sidebar_view.php。 打 开 该 文 件 , 在 适 当 位 置 添 加 如 下 内 容 :<br />

代 码 片 段<br />

<br />

<br />

用 户 登 录 <br />

<br />


扩 展 与 框 架 :<br />

《PHPer》<br />

未 登 录 状 态 的 侧 边 栏<br />

4 修 改 密 码<br />

登 录 状 态 的 侧 边 栏<br />

通 常 , 用 户 登 录 后 修 改 自 己 的 密 码 时 都 要 求 输 入 正 在 使 用 的 密 码 。 因 此 这 次 我 们<br />

不 能 重 用 刚 刚 的 Form_UserLogin 表 单 了 , 需 要 单 独 建 立 一 个 。<br />

4.1 建 立 表 单<br />

创 建 文 件 app/form/changepasswd.php, 内 容 为 :<br />

代 码 片 段<br />

class Form_ChangePasswd extends QForm<br />

{<br />

function __construct($action)<br />

{<br />

// 调 用 父 类 的 构 造 函 数<br />

parent::__construct('form_changepasswd', $action);<br />

// 从 配 置 文 件 载 入 表 单<br />

$filename = rtrim(dirname(__FILE__), '/\\') . DS . 'changepasswd_form.yaml';<br />

$this->loadFromConfig(Helper_YAML::loadCached($filename));<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 50/111


扩 展 与 框 架 :<br />

《PHPer》<br />

// 三 个 密 码 字 段 按 照 User 模 型 的 password 属 性 来 验 证<br />

$this['old_password']->addValidations(User::meta(), 'password');<br />

$this['new_password']->addValidations(User::meta(), 'password');<br />

// 但 new_password2 字 段 还 有 一 个 额 外 的 验 证 规 则 ,<br />

// 通 过 Form_ChangePasswd 对 象 的 checkNewPassword() 方 法 进 行 验 证<br />

$this['new_password2']->addValidations(User::meta(), 'password')<br />

->addValidations(array($this, 'checkNewPassword'), ' 两 次 输 入 的 密 码 必 须 一<br />

致 ');<br />

}<br />

}<br />

/**<br />

* 检 查 两 次 输 入 的 新 密 码 是 否 一 致<br />

*/<br />

function checkNewPassword($new_password)<br />

{<br />

return ($this['new_password2']->value == $this['new_password']->value);<br />

}<br />

这 次 的 表 单 对 象 复 杂 了 许 多 。 除 了 要 为 三 个 密 码 输 入 字 段 指 定 验 证 规 则 外 , 还 特<br />

别 增 加 一 个 额 外 的 验 证 规 则 。checkNewPassword() 这 个 方 法 被 用 于 对 new_password2<br />

字 段 的 验 证 。 这 样 可 以 检 查 两 次 输 入 的 新 密 码 是 否 一 致 。<br />

对 于 复 杂 表 单 的 自 定 义 验 证 规 则 , 都 可 以 采 用 上 述 方 式 实 现 。 创 建 修 改 密 码 表 单<br />

的 配 置 文 件 app/form/changepasswd_form.yaml:<br />

代 码 片 段<br />

# ~form 开 头 的 内 容 用 于 指 定 表 单 属 性<br />

~form:<br />

"_subject": " 修 改 密 码 "<br />

old_password:<br />

_ui: password<br />

_label: " 现 在 使 用 的 密 码 "<br />

new_password:<br />

_ui: password<br />

_label: " 新 密 码 "<br />

new_password2:<br />

_ui: password<br />

_label: " 再 次 输 入 新 密 码 "<br />

4.2 添 加 控 制 器 动 作<br />

修 改 users 控 制 器 , 加 入 下 列 代 码 :<br />

代 码 片 段<br />

function actionChangePasswd()<br />

{<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 51/111


扩 展 与 框 架 :<br />

《PHPer》<br />

}<br />

$form = new Form_ChangePasswd(url('users/changepasswd'));<br />

if ($this->_context->isPOST() && $form->validate($_POST))<br />

{<br />

try<br />

{<br />

// 取 得 当 前 用 户 的 信 息<br />

$current_user = $this->_app->currentUser();<br />

}<br />

// 修 改 密 码<br />

User::meta()->changePassword(<br />

$current_user['username'],<br />

$form['new_password']->value,<br />

$form['old_password']->value<br />

);<br />

// 重 定 向 浏 览 器<br />

return $this->_redirectMessage(<br />

' 修 改 密 码 成 功 ',<br />

' 您 的 登 录 密 码 已 经 成 功 修 改 , 下 次 登 录 请 使 用 新 密 码 。',<br />

url('default/index'));<br />

}<br />

catch (AclUser_WrongPasswordException $ex)<br />

{<br />

$form['old_password']->invalidate(' 您 输 入 的 现 用 密 码 不 正 确 ');<br />

}<br />

$this->_view['form'] = $form;<br />

$this->_viewname = 'register';<br />

这 里 我 们 继 续 沿 用 了 register 动 作 的 视 图 :)<br />

actionChangePasswd() 中 , 我 们 使 用 acluser 的 changePassword() 方 法 来 修 改 密<br />

码 。 如 果 现 有 密 码 出 错 , 将 抛 出 异 常 。 只 要 捕 获 异 常 就 可 以 在 界 面 提 示 用 户 输 入 出 错<br />

了 。<br />

输 入 了 错 误 的 密 码<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 52/111


扩 展 与 框 架 :<br />

《PHPer》<br />

注 意 这 次 在 重 定 向 浏 览 器 时 调 用 的 是 _redirectMessage() 方 法 。 这 个 方 法 会 通 过<br />

redirect_message 视 图 来 显 示 提 示 信 息 , 能 够 让 用 户 注 意 到 操 作 的 结 果 。 如 果 有 必 要 ,<br />

可 以 将 注 册 、 登 录 等 方 法 的 重 定 向 操 作 也 改 为 使 用 带 提 示 信 息 的 重 定 向 。<br />

成 功 修 改 密 码 后 的 提 示 信 息<br />

现 在 用 户 方 面 的 功 能 就 基 本 上 实 现 完 了 。 下 一 节 开 始 , 我 们 将 实 现 任 务 的 管 理 功<br />

能 。<br />

框 架 介 绍<br />

QeePHP 是 新 一 代 敏 捷 开 发 框 架<br />

QeePHP 是 全 球 第 一 个 遵 循 “ 领 域 驱<br />

动 ­ 开 发 ” 思 想 设 计 和 实 现 的 PHP 开 发<br />

框 架 。 在 保 持 易 学 易 用 、­ 快 速 稳 定 的 同<br />

时 ,QeePHP 为 创 建 具 有 复 杂 内 在 逻 辑 的<br />

Web 应 用 提 供 了 全 方 位 的 支 持 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 53/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

企 业 解 决 方 案<br />

Zend 框 架 高 级 功 能<br />

Zend Framework 团 队<br />

如 果 你 开 发 并 且 运 行 了 一 个 非 常 基 本 的 Zend 框 架 应 用 程 序 。 它 允 许 我 们 给 数 据 库<br />

建 模 、 创 建 表 单 以 及 验 证 数 据 。Zend 框 架 还 提 供 了 更 多 功 能 。<br />

本 文 提 供 了 关 于 Zend 框 架 实 际 运 作 的 细 节 , 并 介 绍 了 一 些 高 级 特 性 。 你 将 学 到 如<br />

何 使 用 这 些 特 性 完 成 配 置 、 调 试 、 路 由 、 缓 存 、 发 送 E-mail、 创 建 PD F 文 档 以 及 操 作<br />

多 个 Web 服 务 等 功 能 。<br />

1 管 理 配 置 文 件<br />

任 何 具 有 一 定 复 杂 度 的 应 用 程 序 都 需 要 一 套 配 置 文 件 。 这 些 文 件 将 保 存 一 些 配 置<br />

信 息 , 如 站 点 所 操 作 的 数 据 库 的 登 录 信 息 、 域 配 置 数 据 以 及 其 他 与 环 境 相 关 的 设 置 。<br />

通 过 Zend_Config 类 ,Zend 框 架 提 供 了 写 入 配 置 数 据 的 几 种 方 法 。 这 里 , 我 们 将 介 绍<br />

以 下 几 种 方 法 。<br />

• 在 引 导 文 件 中 创 建 一 个 具 有 层 次 结 构 的 数 组 。<br />

• 创 建 一 个 INI 文 件 。 在 处 理 INI 文 件 时 , 框 架 甚 至 允 许 扩 展 配 置 节 并 重 写 键<br />

值 。<br />

• 使 用 XML 文 件 。<br />

1.1 使 用 数 组 的 方 法<br />

要 在 引 导 文 件 中 添 加 一 个 配 置 数 组 , 只 需 创 建 一 个 具 有 键 值 / 数 值 结 构 的 数 组 。<br />

还 可 以 嵌 套 数 组 以 创 建 具 有 多 个 层 次 的 结 构 。 当 Zend_Config 类 通 过 数 组 来 初 始 化 时<br />

, 将 把 数 组 的 键 值 转 换 成 属 性 , 从 而 提 供 了 一 个 非 常 清 晰 的 接 口 。 如 代 码 清 单 1-1 显<br />

示 了 一 个 使 用 数 组 方 法 的 例 子 。<br />

代 码 清 单 1-1 在 引 导 文 件 中 使 用 数 组 来 配 置 系 统 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

$configArray = (<br />

'domain' => 'some.com',<br />

'database' => array(<br />

'name' => 'dbname',<br />

'password' => 'password'<br />

)<br />

);<br />

$config = new Zend_Config($configArray);<br />

echo $config->database->name;<br />

1.2 INI 方 法<br />

INI 方 法 和 数 组 方 法 的 主 要 区 别 在 于 IN I 文 件 可 以 定 义 重 写 的 数 据 , 这 一 特 性 可 以<br />

被 用 在 特 定 的 情 况 下 , 例 如 在 测 试 服 务 器 上 运 行 时 , 或 者 在 生 产 服 务 器 上 运 行 时 。<br />

这 提 供 了 一 定 程 度 的 灵 活 性 , 但 也 会 导 致 了 很 多 重 复 , 因 此 ,Zend 框 架 的 IN I 格 式 也<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 54/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

提 供 了 配 置 节 级 别 的 扩 展 。 代 码 清 单 1-2 显 示 了 一 个 INI 文 件 , 其 中 包 含 了 正 式 的 配 置<br />

数 据 和 测 试 用 的 配 置 数 据 。<br />

代 码 清 单 1-2 使 用 INI 文 件 配 置 系 统 ( Config.INI)<br />

代 码 片 段<br />

[production]<br />

domain = some.com<br />

database.name = dbname<br />

database.password = password<br />

[staging : production]<br />

domain = beta.some.com<br />

database.name = stagingdb<br />

在 这 个 例 子 中 , 测 试 用 的 配 置 数 据 扩 展 了 正 式 产 品 的 配 置 数 据 并 重 写 了 两 个 键 值<br />

, 但 没 有 改 变 第 三 个 键 值 password。<br />

为 了 使 Zend_Config 类 知 道 使 用 哪 一 种 设 置 , 需 要 使 用 以 下 代 码 来 实 例 化 Zend_Co<br />

nfig_ Ini 类 。<br />

代 码 片 段<br />

$config = new Zend_Config_Ini('config.ini','staging');<br />

echo $config->database->password;<br />

第 一 个 参 数 指 向 INI 文 件 , 第 二 个 参 数 表 示 使 用 的 配 置 节 。<br />

1.3 XML 方 法<br />

使 用 XM L 方 法 配 置 系 统 提 供 了 INI 方 法 的 所 有 功 能 , 并 且 使 应 用 程 序 之 间 具 有 更<br />

强 的 移 植 性 。 不 过 , 它 也 带 来 了 解 析 X M L 文 件 所 需 的 开 销 。 代 码 清 单 1-3 显 示 了 一 个<br />

XML 配 置 文 件 的 示 例 。<br />

代 码 清 单 1-3 使 用 XM L 文 件 配 置 系 统 ( Config.xml)<br />

代 码 片 段<br />

<br />

<br />

<br />

some.com<br />

<br />

dbname<br />

password<br />

<br />

<br />

<br />

beta.some.com<br />

<br />

dbname<br />

<br />

<br />

访 问 X M L 配 置 数 据 的 方 法 与 使 用 IN I 文 件 配 置 系 统 时 的 访 问 方 法 是 相 同 的 。<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 55/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

$config = new Zend_Config_Xml('config.xml', 'staging');<br />

echo $config->database->password;<br />

这 里 不 推 荐 使 用 XML 作 为 配 置 数 据 , 这 是 因 为 解 析 XML 文 档 带 来 的 开 销 实 际 上 是<br />

非 常 高 的 。 不 过 , 可 以 使 用 缓 存 功 能 来 抵 消 这 个 问 题 , 本 文 将 会 讨 论 到 缓 存 技 术 。<br />

2 设 置 站 点 级 别 的 视 图 变 量<br />

默 认 情 况 下 , 框 架 会 创 建 一 个 新 的 Zend_View 实 例 并 自 动 将 它 注 册 到 视 图 输 出 类<br />

上 。 然 而 , 在 某 些 情 况 下 , 你 可 能 希 望 自 定 义 这 个 视 图 。 自 定 义 视 图 实 例 时 , 允 许 设<br />

置 默 认 的 应 用 程 序 级 别 的 变 量 , 修 改 默 认 的 路 径 结 构 , 以 及 设 置 几 种 不 同 的 选 项 。 代<br />

码 清 单 1-4 显 示 了 注 册 自 定 义 视 图 的 一 个 例 子 。<br />

代 码 清 单 1-4 将 一 个 自 定 义 视 图 注 册 到 视 图 输 出 类 上<br />

代 码 片 段<br />

$view = new Zend_View();<br />

$view -> siteWideProperty = 'value';<br />

$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');<br />

$viewRenderer -> setView($view);<br />

这 个 方 法 非 常 简 单 , 可 以 在 引 导 过 程 中 执 行 它 。 现 在 , 每 个 视 图 脚 本 都 可 以 访 问<br />

$this-> siteWideProperty 的 值 , 这 一 功 能 在 设 置 公 共 位 置 的 路 径 方 面 非 常 有 用 , 例<br />

如 在 设 置 图 像 、JavaScript 和 CSS 文 件 的 路 径 时 。<br />

3 共 享 对 象<br />

Zend_Registry 组 件 的 作 用 在 于 允 许 创 建 可 在 不 同 框 架 类 之 间 共 享 的 对 象 。 这 一<br />

方 法 与 使 用 全 局 变 量 类 似 , 但 不 会 与 你 可 能 正 在 和 框 架 一 起 使 用 的 其 他 库 发 生 冲 突 。<br />

要 在 Zend_Registry 类 中 存 储 一 个 对 象 实 例 , 只 需 调 用 set() 方 法 并 且 为 这 个 项 定 义<br />

一 个 名 称 即 可 。<br />

Zend_Registry::set('handle', $instance);<br />

之 后 , 如 果 需 要 获 取 这 个 对 象 , 只 需 调 用 get() 方 法 就 可 以 了 。<br />

$instance = Zend_Registry::get('handle');<br />

4 错 误 处 理<br />

在 前 面 你 创 建 了 一 个 会 抛 出 异 常 的 框 架 引 导 程 序 。 这 并 不 是 默 认 行 为 , 需 要 通 过<br />

调 用 前 端 控 制 器 实 例 上 的 throwExceptions(true) 方 法 来 激 活 它 。<br />

默 认 情 况 下 , 框 架 会 在 发 生 问 题 时 查 找 一 个 名 为 ErrorController 的 控 制 器 , 而<br />

不 是 直 接 抛 出 异 常 。 框 架 还 在 request 对 象 上 设 置 了 一 个 名 为 error_handler 的 请 求<br />

参 数 , 这 个 参 数 包 含 了 错 误 条 件 的 细 节 。<br />

为 了 在 示 例 应 用 程 序 中 正 确 地 处 理 错 误 , 需 要 创 建 一 个 名 为 ErrorController 的<br />

新 控 制 器 , 并 将 它 和 其 他 控 制 器 放 在 一 起 。 在 这 个 控 制 器 中 , 你 需 要 创 建 一 个 名 为<br />

errorAction 的 方 法 , 这 个 方 法 在 错 误 条 件 发 生 时 会 被 框 架 所 调 用 。<br />

现 在 , 你 应 该 拥 有 一 个 类 似 以 下 代 码 的 控 制 器 了 。<br />

代 码 片 段<br />


企 业 解 决 方 案 :<br />

《PHPer》<br />

}<br />

public function errorAction() {<br />

}<br />

还 需 要 创 建 一 个 名 为 error.phtml 的 视 图 , 并 将 它 放 在 一 个 名 为 error 的 目 录 中 。<br />

视 图 的 内 容 本 身 并 不 是 特 别 重 要 。<br />

下 一 步 , 需 要 获 得 异 常 抛 出 的 原 因 。 错 误 信 息 包 含 在 请 求 参 数 error_handler 中 ,<br />

可 以 使 用 代 码 清 单 1-5 中 显 示 的 代 码 来 获 得 这 个 信 息 。<br />

代 码 清 单 1-5 获 取 错 误 信 息 (ErrorC ontroller.php)<br />

代 码 片 段<br />


企 业 解 决 方 案 :<br />

《PHPer》<br />

与 添 加 到 引 导 文 件 中 的 所 有 其 他 附 加 功 能 的 位 置 是 一 样 的 。<br />

代 码 清 单 1-6 创 建 一 个 日 志 记 录 器 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

// 创 建 一 个 Log 对 象<br />

$log = new Zend_Log();<br />

// 过 滤 掉 干 扰 项 ( 可 选 操 作 )<br />

$log->addFilter(new Zend_Log_Filter_Priority(Zend_Log::ERR));<br />

// 创 建 一 个 W riter 对 象<br />

$logWriter = new Zend_Log_Writer_Stream(APP_PATH . '/application.log');<br />

// 创 建 一 个 Form atter 对 象 ( 可 选 操 作 )<br />

$logFormat = '%timestamp% %priorityName% %message%' . "\n";<br />

$logWriter->setFormatter(new Zend_Log_Formatter_Simple($logFormat));<br />

// 将 W riter 对 象 添 加 到 Log 对 象 中<br />

$log->addWriter($logWriter);<br />

// 将 Log 对 象 保 存 到 注 册 表 中 以 便 访 问<br />

Zend_Registry::set('log', $log);<br />

代 码 清 单 1-6 在 应 用 程 序 根 目 录 中 创 建 了 一 个 名 为 application.log 的 文 件 。 为<br />

使 操 作 顺 利 执 行 , 这 个 目 录 对 Web 服 务 器 用 户 必 须 是 可 写 的 , 可 能 是 www-data、nobody<br />

或 者 apache2, 这 取 决 于 你 的 操 作 系 统 的 发 布 版 本 , 日 志 记 录 器 会 过 滤 掉 优 先 级 低 于<br />

ERR 的 所 有 消 息 , 并 将 错 误 消 息 格 式 化 为 人 类 可 读 的 格 式 。 格 式 化 和 过 滤 都 是 可 选 步<br />

骤 。<br />

现 在 , 日 志 记 录 器 对 象 已 经 设 置 完 成 了 , 但 还 没 有 记 录 任 何 消 息 。 代 码 清 单 1-7<br />

演 示 了 ErrorController 和 这 个 日 志 记 录 器 对 象 之 间 的 一 种 可 能 的 集 成 方 法 。<br />

代 码 清 单 1-7 在 ErrorController 中 记 录 日 志 (ErrorController.php)<br />

代 码 片 段<br />

class ErrorController extends Zend_Controller_Action {<br />

public function errorAction() {<br />

$request = $this->getRequest();<br />

$errorHandler = $request->getParam('error_handler');<br />

// 获 得 Log 对 象 实 例<br />

$log = Zend_Registry::get('log');<br />

// 记 录 包 含 了 抛 出 的 异 常 信 息 的 一 条 紧 急 消 息<br />

$log->emerg($errorHandler['exception']->__toString());<br />

}<br />

}<br />

这 段 集 成 代 码 将 异 常 记 录 到 一 个 文 件 中 , 而 不 是 将 这 些 信 息 显 示 给 用 户 。 这 将 允<br />

许 为 用 户 创 建 自 定 义 的 错 误 页 面 , 同 时 不 会 丢 失 任 何 关 键 的 调 试 错 误 细 节 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 58/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

6 缓 存<br />

缓 存 是 所 有 具 有 一 定 复 杂 度 的 应 用 程 序 的 一 个 关 键 部 分 。 不 管 是 缓 存 静 态 页 面 还<br />

是 SQL 查 询 结 果 , 充 分 利 用 缓 存 功 能 对 应 用 程 序 的 性 能 来 说 都 是 至 关 重 要 的 。<br />

Zend 框 架 提 供 了 块 级 别 的 部 分 缓 存 功 能 和 整 页 面 的 缓 存 功 能 。 决 定 何 时 使 用 哪 种<br />

缓 存 是 非 常 重 要 的 , 这 是 因 为 缓 存 特 定 请 求 有 可 能 导 致 难 以 解 决 的 问 题 , 以 及 非 常 严<br />

重 的 安 全 问 题 。<br />

6.1 缓 存 功 能 在 安 全 性 上 的 考 虑<br />

以 下 是 安 全 使 用 缓 存 功 能 的 一 些 原 则 。<br />

• 在 生 成 页 面 时 , 如 果 请 求 的 数 据 将 导 致 相 同 的 输 出 , 则 缓 存 这 些 数 据 。 例 如 ,<br />

首 页 就 很 有 可 能 需 要 缓 存 功 能 。<br />

• 如 果 是 包 含 个 人 信 息 的 输 入 产 生 的 页 面 , 则 不 要 缓 存 任 何 数 据 。 它 可 能 会 被<br />

用 来 创 建 跨 域 访 问 场 景 , 这 可 能 会 侵 犯 到 用 户 的 隐 私 , 从 而 会 对 业 务 产 生 严<br />

重 影 响 。<br />

• 确 保 缓 存 页 面 输 出 不 会 避 开 安 全 模 型 , 不 会 允 许 其 他 用 户 读 取 为 某 个 特 定 用<br />

户 缓 存 的 页 面 。 在 缓 存 需 要 某 种 形 式 的 验 证 才 能 访 问 的 页 面 时 , 要 非 常 谨 慎 ,<br />

这 是 因 为 绕 开 验 证 的 可 能 性 大 大 提 高 了 。<br />

为 了 更 好 地 理 解 缓 存 的 安 全 问 题 , 我 们 设 想 一 个 包 含 了 信 息 展 示 版 面 的 会 员 区 域<br />

的 网 站 。 可 以 设 想 一 个 场 景 , 当 用 户 登 录 时 , 她 的 信 息 展 示 版 面 将 会 被 缓 存 起 来 。 当<br />

下 一 个 用 户 登 录 时 , 可 以 看 到 这 个 已 被 缓 存 的 页 面 。 问 题 在 于 这 个 缓 存 是 第 一 个 用 户<br />

登 录 时 产 生 的 页 面 结 果 , 而 你 正 好 将 第 一 个 用 户 的 个 人 信 息 展 现 给 了 另 外 一 个 用 户 。<br />

这 样 的 缓 存 场 景 很 常 见 , 并 且 已 经 导 致 一 些 重 要 机 构 遇 到 了 非 常 严 重 的 问 题 。<br />

我 已 经 说 过 缓 存 会 产 生 一 些 问 题 , 那 么 缓 存 能 实 现 什 么 功 能 呢 ? 简 单 来 讲 , 它 可<br />

以 做 任 何 事 情 。Zend 框 架 有 非 常 好 的 缓 存 解 决 方 案 , 这 是 因 为 它 不 仅 允 许 缓 存 整 个 页<br />

面 , 而 且 还 允 许 缓 存 部 分 页 面 , 甚 至 是 SQL 查 询 结 果 。<br />

6.2 缓 存 技 术<br />

缓 存 组 件 有 两 个 重 要 部 分 : 前 端 和 后 端 。 前 端 负 责 决 定 缓 存 什 么 以 及 如 何 缓 存 ,<br />

后 端 负 责 已 缓 存 信 息 的 存 储 。 表 1-1 列 出 了 可 用 的 前 端 , 表 1-2 列 出 了 后 端 。<br />

表 1-1 Zend_Cache 前 端<br />

前 端 说 明<br />

Zend_Cache_Frontend_Core 包 含 了 load($handle) 和 save($data) 方 法 的 通<br />

用 的 缓 存 前 端 。 这 一 前 端 定 义 了 所 有 其 他 前 端 的 基 类 ,<br />

而 且 定 义 了 几 个 有 用 的 缓 存 选 项 , 其 中 包 含 caching(<br />

bool)、 lifetime(int<br />

seconds)、 logging(bool log to<br />

Zend_Log)、 write_control、 automatic_seri<br />

alization<br />

和 automatic_cleaning_factor 等 。 从 字<br />

面 上 便 可 以 理 解 它 们 的 含 义 。 关 于 这 些 选 项 的 更 多 细 节<br />

, 参 见 Zend 框 架 参 考 文 档<br />

Zend_Cache_Frontend_Output 捕 捉 $cache->start() 和 $cache->end() 之 间 所<br />

有 输 出 的 前 端 。 在 缓 存 整 个 页 面 不 太 合 适 的 情 况 下 , 对<br />

于 缓 存 输 出 的 部 分 块 来 说 , 它 很 有 用<br />

Zend_Cache_Frontend_Functi 函 数 缓 存 前 端 允 许 你 保 存 函 数 的 结 果 以 及 它 可 能 直 接 输<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 59/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

on<br />

出 的 任 何 内 容 。 它 只 有 一 个 call(callback$function,<br />

array$params) 函 数<br />

Zend_Cache_Frontend_Class 类 缓 存 前 端 允 许 你 缓 存 需 要 在 加 载 过 程 之 间 保 留 状 态<br />

的 类 。 它 可 以 被 用 来 序 列 化 或 反 序 列 化 对 象 , 使 你 可 以<br />

不 用 再 回 头 访 问 数 据 库 或 者 配 置 文 件 就 可 以 实 例 化 一 个<br />

类 。 要 使 用 这 一 前 端 ,'cachedEntity' 选 项 必 须 设 置 为 类<br />

的 名 称 或 者 实 例 。 要 调 用 缓 存 的 方 法 , 调 用<br />

$cache->method- Name(...) 即 可<br />

Zend_Cache_Frontend_File 这 一 前 端 和 核 心 前 端 相 同 , 但 通 过 这 一 扩 展 , 缓 存 会<br />

在 文 件 被 修 改 的 情 况 下 过 期 。 这 允 许 永 久 缓 存 一 些 项 目<br />

, 如 XM L 文 件 的 解 析 过 程 , 直 到 底 层 的 文 件 被 修 改 了<br />

。 要 使 用 这 一 前 端 , 需 要 提 供 'master_file'=>'<br />

/path/to/file' 选 项<br />

Zend_Cache_Frontend_Page 这 一 前 端 缓 存 整 个 页 面 , 用 起 来 也 非 常 简 单 。 需 要 提<br />

供 一 个 regexps 选 项 , 这 是 一 个 数 组 的 数 组 , 它 声 明<br />

了 将 被 缓 存 的 页 面 。 这 一 前 端 的 用 法 将 在 代 码 清 单 16-8<br />

中 演 示<br />

最 容 易 实 现 的 缓 存 类 型 是 全 页 面 缓 存 。 它 非 常 简 单 , 这 是 因 为 它 不 需 要 输 入 数 据 ,<br />

并 且 它 的 内 容 通 常 是 静 态 的 。 为 了 实 现 这 种 类 型 的 缓 存 , 需 要 在 应 用 程 序 路 径 中 创 建<br />

一 个 名 为 cache 的 可 写 目 录 , 并 且 遵 循 代 码 清 单 1-8 中 的 例 子 。<br />

代 码 清 单 1-8 缓 存 首 页 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

$cacheBackendOptions = array(<br />

'cache_dir' => APP_PATH . '/cache'<br />

);<br />

$cacheFrontendOptions = array(<br />

'regexps' => array(<br />

'^/$' => array() // 在 首 页 中 使 用 默 认 的 缓 存 选 项<br />

)<br />

);<br />

$cache = Zend_Cache::factory(<br />

'Page', // 使 用 Page 前 端<br />

'File', // 使 用 File 后 端<br />

$cacheFrontendOptions,<br />

$cacheBackendOptions<br />

);<br />

$cache->start();<br />

表 1-2 Zend_Cache 后 端<br />

后 端 说 明<br />

Zend_Cache_Backend_File<br />

这 一 基 本 后 端 将 缓 存 的 对 象 保 存 到 文 件 中 。 可 以<br />

使 用 后 端 选 项 'cache_dir' 来 设 置 缓 存 文 件 目 录 。<br />

这 一 缓 存 目 录 必 须 是 W eb 服 务 器 用 户 可 写 的<br />

Zend_Cache_Backend_Sqlite 这 一 后 端 将 缓 存 项 保 存 到 一 个 SQ Lite 数 据 库 文 件<br />

中 。 使 用 后 端 选 项 'cache_db_complete_path'<br />

=>'/path/to/sqlitefile' 可 以 指 定 数 据 库<br />

Zend_Cache_Backend_Memcached 这 一 后 端 将 缓 存 保 存 到 一 个 memcached 守 护 程 序<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 60/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

中 。 要 激 活 这 一 后 端 , 必 须 提 供 servers 后 端 选 项 ,<br />

这 是 一 个 数 组 的 数 组 , 其 中 包 含 键 值 host、port 和<br />

persistent 等 。 还 可 以 通 过 将 compression 后 端 选 项 设<br />

置 为 布 尔 值 true 激 活 即 时 的 压 缩 功 能<br />

Zend_Cache_Backend_Apc<br />

APC 缓 存 后 端 允 许 使 用 APC 扩 展 来 存 储 缓 存 数<br />

据 。 将 需 要 APC 扩 展 , 在 PHP 安 装 程 序 上 它 通 常 不<br />

是 标 准 的 扩 展 。 这 一 后 端 不 需 要 其 他 附 加 的 选 项<br />

Zend_Cache_Backend_ZendPlatf 还 可 以 使 用 Zend 平 台 来 缓 存 数 据 。 这 一 后 端 不 需<br />

orm<br />

要 其 他 附 加 的 选 项<br />

代 码 清 单 1-8 中 的 示 例 使 用 了 Page 前 端 和 File 后 端 来 缓 存 页 面 的 整 个 输 出 。Page<br />

前 端 接 受 一 个 数 组 , 其 中 包 含 了 用 于 指 定 需 要 缓 存 的 页 面 的 正 则 表 达 式 。 这 里 , 你 可<br />

以 使 用 默 认 的 缓 存 选 项 , 它 不 会 缓 存 带 有 变 量 信 息 的 请 求 , 请 求 的 类 型 包 括 get、post、<br />

cookie、session 等 。<br />

为 了 确 保 缓 存 能 在 变 量 存 在 时 创 建 , 可 以 使 用 几 种 类 型 的<br />

cach_with_*_variables 和 make_id_with_*_variables 选 项 。 例 如 , 如 果 希 望 缓 存<br />

GET 请 求 的 结 果 , 将 需 要 使 用 cache- FrontendOptions 数 组 , 如 代 码 清 单 1-9 所 示 。<br />

代 码 清 单 1-9 缓 存 GET 请 求<br />

代 码 片 段<br />

$cacheFrontendOptions = array(<br />

'debug_header' => true,<br />

'regexps' => array(<br />

'^/$' => array(<br />

'cache_with_get_variables' => true,<br />

'make_id_with_get_variables' => true<br />

)<br />

)<br />

);<br />

cache_with_get_variables 选 项 表 示 缓 存 功 能 可 以 缓 存 包 含 get 变 量 的 页 面 。<br />

make_id_ with_get_variables 选 项 表 示 所 有 页 面 输 入 都 必 须 单 独 地 缓 存 页 面 。 也 就<br />

是 说 , 同 一 get 变 量 的 两 个 值 会 导 致 两 个 不 同 的 缓 存 文 件 。<br />

在 代 码 清 单 1-9 中 , 你 还 将 注 意 到 debug_header 选 项 被 设 置 为 true。 这 个 选 项<br />

使 缓 存 页 面 输 出 一 个 头 信 息 , 以 表 明 它 是 一 个 已 缓 存 的 页 面 , 这 样 就 可 以 知 道 页 面 被<br />

缓 存 的 时 间 , 还 可 以 帮 助 调 试 页 面 。<br />

将 get 替 换 为 post、cookie、session 或 者 files, 将 会 导 致 不 同 的 缓 存 场 景 。<br />

不 过 , 只 有 在 相 同 输 入 参 数 总 是 产 生 相 同 页 面 输 出 的 情 况 下 , 这 种 缓 存 类 型 才 是 适 用<br />

的 。<br />

7 验 证 用 户<br />

Zend_Auth 组 件 允 许 确 认 访 问 者 的 身 份 。 这 个 组 件 结 合 会 话 和 数 据 访 问 的 功 能 创<br />

建 了 一 个 稳 定 的 身 份 验 证 系 统 。 为 了 了 解 Zend_Auth 的 机 制 , 我 们 来 看 一 个 完 整 的 例<br />

子 。<br />

代 码 清 单 1-10 显 示 了 一 个 完 整 的 验 证 解 决 方 案 , 其 中 集 成 了 表 格 处 理 、<br />

FlashMessenger 和 数 据 库 。 这 个 例 子 的 前 提 条 件 是 需 要 一 个 名 为 users 的 数 据 库 表 ,<br />

其 中 包 含 了 名 为 email、password 和 name 的 字 段 。 创 建 如 代 码 清 单 1-10 所 示 的<br />

IndexController.php 文 件 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 61/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

代 码 片 段<br />

代 码 清 单 1-10 一 个 完 整 的 Zend_Auth 示 例 程 序 (IndexController.php)<br />

// 这 一 示 例 是 在 H ello: name 示 例 程 序 的 基 础 上 创 建 的<br />

public function indexAction() {<br />

// 获 得 Zend_A uth 类 的 一 个 引 用<br />

$auth = Zend_Auth::getInstance();<br />

// 检 查 用 户 是 否 已 登 录<br />

if($auth->hasIdentity()) {<br />

// 获 得 用 户 的 身 份 并 且 将 视 图 变 量 设 置 为 用 户 姓 名<br />

$identity = $auth->getIdentity();<br />

$this->view->name = $identity->name;<br />

} else {<br />

// 无 法 获 得 身 份 的 用 W elcom e: unknown 来 表 示<br />

$this->view->name = 'unknown';<br />

}<br />

}<br />

public function loginAction() {<br />

if($this->getRequest()->isPost()) {<br />

// 过 滤 掉 字 段 中 的 标 签<br />

$filters = array(<br />

'email' => 'StringTrim',<br />

'password' => 'StringTrim'<br />

);<br />

$validation = array(<br />

'email'=>array('emailAddress'),<br />

'password' => array (<br />

array('StringLength', 1, 64)<br />

)<br />

);<br />

/*<br />

初 始 化 Zend_ Filter_ Input, 并 向 它 传 递 整 个 getPost() 数 组<br />

*/<br />

$zfi = new Zend_Filter_Input(<br />

$filters,<br />

$validation,<br />

$this->getRequest()->getPost()<br />

);<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 62/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

// 如 果 通 过 了 验 证 , 这 个 值 将 为 true<br />

if ($zfi->isValid()) {<br />

$dbconfig = array(<br />

'host' => 'localhost',<br />

'username' => 'user',<br />

'password' => 'password',<br />

'dbname' => 'demo'<br />

);<br />

$db = Zend_Db::factory('PDO_PGSQL', $dbconfig);<br />

// 创 建 一 个 新 的 Zend_A uth_A dapter 对 象<br />

$adapter = new Zend_Auth_Adapter_DbTable(<br />

$db,<br />

'users', // 表 的 名 称<br />

'email', // identity 字 段 的 名 称<br />

'password', // credential 字 段 的 名 称<br />

'md5(?)' // 应 用 的 SQ L 函 数 ( 可 选 )<br />

);<br />

// 将 identity 和 credential 字 段 设 置 为 经 过 验 证 的 值<br />

$adapter->setIdentity($zfi->email)<br />

->setCredential($zfi->password);<br />

/*<br />

使 用 适 配 器 获 得 Zend_A uth 类 的 实 例 和 authenticate() 方 法<br />

*/<br />

$auth = Zend_Auth::getInstance();<br />

$result = $auth->authenticate($adapter);<br />

// 检 查 验 证 是 否 成 功<br />

if ($result->isValid()) {<br />

/*<br />

下 一 行 代 码 将 整 个 数 据 库 行 保 存 到 用 户 的 Zend_A uth 身 份 数 据 中 。<br />

通 常 只 有 identity 列 会 被 保 存 为 字 符 串 , 在 这 个 例 子 中 是 e-mail 列 。<br />

通 过 保 存 整 个 记 录 , 可 以 同 时 访 问 用 户 的 nam e 和 ID 。<br />

*/<br />

$auth->getStorage()->write($adapter->getResultRowObject());<br />

// 成 功 登 录 后 重 定 向 到 /index/index 中<br />

$this->getHelper('redirector')->goto('index','index');<br />

} else {<br />

// 到 了 这 里 说 明 验 证 失 败 了 。<br />

$this->getHelper('FlashMessenger')<br />

->addMessage(<br />

"The login credentials provided are not valid."<br />

);<br />

$this->getHelper('redirector')->goto('login');<br />

}<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 63/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

}<br />

} else {<br />

foreach($zfi->getMessages() as $field=>$messages) {<br />

foreach($messages as $message) {<br />

$this->getHelper('FlashMessenger')<br />

->addMessage($field . ' : '. $message);<br />

}<br />

}<br />

$this->getHelper('redirector')->goto('login');<br />

}<br />

}<br />

$this->view->messages = $this->getHelper('FlashMessenger')<br />

->getMessages();<br />

还 需 要 一 个 位 于 /views/scripts/index/ 中 的 login.phtml 视 图 , 如 代 码 清 单 1-11<br />

所 示 。<br />

代 码 清 单 1-11 Login 视 图 (login.phtml)<br />

代 码 片 段<br />

<br />

<br />

ERROR: <br />

<br />

<br />

<br />

<br />

<br />

Email Address:<br />

<br />

<br />

Password:<br />

<br />

<br />

<br />

<br />

<br />

<br />

要 访 问 这 个 登 录 表 单 , 直 接 访 问 http://example.com/index/login 即 可 。<br />

8 在 PH P 语 言 中 使 用 JSON<br />

Zend_Json 提 供 了 一 个 简 单 的 编 码 器 / 解 码 器 机 制 , 将 变 量 在 JSON 和 PHP 之 间 转<br />

换 。 这 个 组 件 非 常 容 易 理 解 , 代 码 清 单 1-12 演 示 了 如 何 在 JSON 操 作 场 景 中 运 行 这 个<br />

组 件 。<br />

代 码 清 单 1-12 使 用 Zend_Json 类<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 64/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

public function jsonAction() {<br />

$this->getHelper('ViewRenderer')->setNoRender();<br />

// 模 拟 一 个 JSON 输 入 值<br />

$jsonInput = '[0,1,2,3]';<br />

// 将 JSON 值 解 码 到 一 个 PHP 数 组 中<br />

$phpArray = Zend_Json::decode($jsonInput);<br />

// 执 行 PH P 操 作<br />

shuffle($phpArray);<br />

// 编 码 用 于 输 出 的 数 据<br />

$jsonOutput = Zend_Json::encode($phpArray);<br />

// 获 得 response 对 象 并 设 置 内 容 类 型 HTTP 头 信 息<br />

$response = $this->getResponse();<br />

$response->setHeader('Content-Type', 'application/json');<br />

// 确 保 只 输 出 JSON 数 据<br />

$response->clearBody();<br />

// 将 response 对 象 中 的 内 容 设 置 为 JSON 代 码<br />

$response->setBody($jsonOutput);<br />

}<br />

PHP 中 JSON 解 码 的 一 般 操 作 是 将 JSON 对 象 转 换 为 关 联 数 组 。 因 为 我 们 有 时 不 希<br />

望 有 这 个 操 作 ,Zend 框 架 提 供 了 另 外 一 种 解 码 语 法 。<br />

$phpObject = Zend_Json::decode('{"x":1}', Zend_Json::TYPE_OBJECT);<br />

这 句 代 码 会 产 生 一 个 stdClass 对 象 , 其 中 有 一 个 名 为 x 的 属 性 。<br />

9 自 定 义 路 由<br />

前 面 介 绍 了 Zend 框 架 的 前 端 控 制 器 。 在 控 制 路 由 的 URL 格 式 方 面 , 这 个 控 制 器 相<br />

当 严 格 。 不 过 ,Zend 框 架 的 设 计 者 们 认 识 到 , 有 些 情 况 下 和 这 一 典 型 结 构 有 所 不 同 是<br />

有 必 要 的 。 例 如 , 移 植 一 个 具 有 一 定 结 构 的 应 用 程 序 时 , 或 者 创 建 一 个 多 语 言 站 点 时 。<br />

通 过 使 用 rewrite 路 由 程 序 , 可 以 向 默 认 规 则 中 添 加 路 由 规 则 , 或 者 甚 至 完 全 覆<br />

盖 原 有 的 路 由 规 则 。 代 码 清 单 1-13 显 示 了 如 何 将 rewrite 路 由 程 序 与 应 用 程 序 集 成<br />

在 一 起 , 并 且 不 用 改 变 任 何 功 能 。 将 上 一 章 编 写 的 引 导 文 件 中 的 代 码<br />

代 码 片 段<br />

$front = Zend_Controller_Front::getInstance();<br />

$front->throwExceptions(true);<br />

$front->run(APP_PATH . '/application/controllers');<br />

替 换 为 代 码 清 单 1-13 所 示 的 代 码 。<br />

代 码 清 单 1-13 引 导 rewrite 路 由 程 序 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

$router = new Zend_Controller_Router_Rewrite();<br />

$front = Zend_Controller_Front::getInstance();<br />

$front->setRouter($router);<br />

$front->run(APP_PATH . '/application/controllers');<br />

现 在 , 已 经 启 用 了 rewrite 路 由 程 序 , 但 没 有 重 写 任 何 功 能 。 调 用<br />

$router->addRoute() 方 法 将 重 写 功 能 添 加 到 默 认 路 由 上 。 路 由 的 格 式 是 通 过<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 65/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

Zend_Controller_Router_Route 类 实 例 化 的 , 并 且 其 用 法 非 常 简 单 。 代 码 清 单 1-14<br />

演 示 了 如 何 将 /product/view/productId/1 路 由 转 换 到 /product/view/1。<br />

代 码 清 单 1-14 rewrite 路 由 信 息<br />

代 码 片 段<br />

$route = new Zend_Controller_Router_Route(<br />

'/product/view/:productId, array(<br />

'controller' => 'product',<br />

'action' => 'view',<br />

'productId' => false<br />

)<br />

);<br />

$router->addRoute('viewproduct, $route);<br />

在 这 个 例 子 中 , 控 制 器 和 动 作 是 硬 编 码 的 ,productId 参 数 是 可 选 的 并 且 默 认 值<br />

是 取 值 为 false 的 一 个 布 尔 值 。 从 操 作 控 制 器 的 角 度 看 ,productId 值 仍 然 是 一 个 参<br />

数 , 并 且 可 以 用 以 前 讨 论 过 的 方 法 访 问 它 。 只 有 URL 发 生 了 变 化 。<br />

注 意 到 这 种 做 法 并 没 有 替 换 默 认 的 路 由 规 则 也 是 很 重 要 的 。 如 果 希 望 定 义 一 个 将 默 认<br />

规 则 全 部 替 换 了 的 路 由 系 统 , 框 架 为 此 提 供 了 removeDefaultRoutes() 方 法 。<br />

实 例 化 路 由 格 式 的 类 具 有 以 下 形 式 。<br />

Zend_Controller_Router_Route($route, $defaults, $format)<br />

其 中 包 含 了 以 下 参 数 。<br />

• $route。 以 冒 号 为 前 缀 的 符 号 表 示 一 个 变 量 , 如 果 是 以 斜 线 结 束 的 , 它 就 不<br />

是 变 量 。 有 三 个 保 留 字 变 量 ::module、:controller 和 :action。 这 些 变 量 允<br />

许 指 定 应 该 调 用 哪 一 个 模 块 、 控 制 器 和 操 作 的 映 射 关 系 。<br />

• $defaults。 第 二 个 参 数 是 默 认 值 的 一 个 数 组 。 当 希 望 使 用 静 态 URL, 但 仍 然<br />

需 要 将 它 映 射 到 控 制 器 和 操 作 时 , 这 个 参 数 就 很 有 用 。 默 认 参 数 值 为 false<br />

表 示 这 些 数 值 是 可 选 的 , 在 这 种 情 况 下 , 它 也 是 很 有 用 的 。<br />

• $format。 如 果 一 个 参 数 不 是 可 选 的 , 最 后 的 格 式 数 组 可 以 被 用 来 提 供 附 加 路<br />

由 。 格 式 是 键 / 值 数 组 , 这 里 的 键 是 参 数 名 称 , 而 值 是 一 个 为 匹 配 路 由 参 数 必<br />

须 传 递 的 正 则 表 达 式 。 这 不 是 用 来 验 证 数 据 的 , 否 则 就 会 导 致 系 统 使 用 不 适<br />

当 的 默 认 路 由 。 相 反 , 这 一 参 数 允 许 区 分 两 个 相 似 但 不 同 的 路 由 。<br />

我 们 来 看 一 下 /product/view/ProPHP 路 由 和 /product/view/1 路 由 。 应 该 如 何 编 写<br />

一 个 路 由 , 将 这 两 个 路 由 分 别 映 射 到 viewByName 和 viewById 操 作 呢 ?format 参 数 提<br />

供 了 这 一 功 能 。 前 面 那 个 路 由 需 要 在 后 面 添 加 , 这 是 因 为 框 架 中 的 路 由 采 用 了 先 匹 配<br />

先 使 用 的 方 法 。 代 码 清 单 1-15 显 示 了 这 一 路 由 。<br />

代 码 清 单 1-15 格 式 匹 配 路 由<br />

代 码 片 段<br />

$route1 = new Zend_Controller_Router_Route(<br />

'/product/view/:productId',<br />

array(<br />

'controller'=>'product',<br />

'action'=>'viewById'<br />

),<br />

array(<br />

'name' => '/[0-9]+/';<br />

)<br />

);<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 66/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

只 有 在 productId 为 数 字 的 情 况 下 这 个 路 由 才 会 匹 配 成 功 , 所 以 如 果 productId 实<br />

际 上 是 一 个 名 称 , 路 由 逻 辑 会 直 接 跳 到 下 一 个 路 由 中 。 然 后 , 为 了 捕 捉 目 标 为<br />

viewByName 的 请 求 , 需 要 添 加 一 个 如 代 码 清 单 1-16 所 示 的 路 由 。<br />

代 码 清 单 1-16 用 于 名 称 的 路 由<br />

代 码 片 段<br />

$route2 = new Zend_Controller_Router_Route(<br />

'/product/view/:name',<br />

array(<br />

'controller'=>'product',<br />

'action'=>'viewByName',<br />

'name'=>false<br />

),<br />

);<br />

你 会 注 意 到 这 一 catchall 路 由 并 没 有 格 式 , 默 认 的 参 数 值 为 false。 由 于 第 一 个 路<br />

由 捕 获 了 所 有 的 ID, 剩 下 的 肯 定 是 名 称 , 所 以 应 该 路 由 到 viewByName。 如 果 希 望 添<br />

加 一 个 判 断 格 式 的 正 则 表 达 式 , 没 有 成 功 匹 配 的 值 将 不 会 被 正 确 路 由 。<br />

10 管 理 会 话<br />

大 多 数 读 者 都 习 惯 于 通 过 session_start() 方 法 和 使 用 $_SESSION 对 象 的 做 法 来 处 理<br />

会 话 。Zend 框 架 提 供 了 一 个 新 的 Zend_Session 类 , 这 使 得 大 家 可 以 更 加 容 易 地 处 理<br />

会 话 数 据 。<br />

Zend_Session 将 为 你 启 动 会 话 , 所 以 不 再 需 要 调 用 session_start() 方 法 。 它 还 提 供<br />

了 一 个 命 名 空 间 选 项 , 这 一 特 性 允 许 你 基 于 处 理 会 话 变 量 的 组 件 来 隔 离 所 有 会 话 变 量 。<br />

这 可 以 保 持 变 量 名 称 的 简 单 性 , 但 仍 然 可 以 确 保 它 们 不 会 与 应 用 程 序 的 其 他 部 分 冲 突 。<br />

最 后 , 框 架 还 可 以 将 会 话 过 期 时 间 设 置 为 以 “ 跳 ” 为 单 位 的 数 字 ,“ 跳 ” 是 指 会 话 启 动 的<br />

次 数 。 例 如 , 如 果 要 将 某 个 页 面 的 数 据 传 递 、 重 定 向 并 加 载 到 下 一 页 面 , 可 以 将 它 设<br />

置 为 单 个 “ 跳 ” 之 内 有 效 , 并 且 , 当 信 息 被 下 一 页 面 读 取 之 后 , 便 会 自 动 从 会 话 中 删 除 。<br />

代 码 清 单 1-17 演 示 了 Zend_Session 类 的 用 法 。<br />

代 码 片 段<br />

public function OneAction() {<br />

$session = new Zend_Session_Namespace('AUniqueNamespace');<br />

$session->setExpirationHops(1);<br />

$session->key = 'value';<br />

$this->getHelper('redirector')->goto('two');<br />

}<br />

public function TwoAction() {<br />

$session = new Zend_Session_Namespace('AUniqueNamespace');<br />

$this->view->key = $session->key;<br />

}<br />

如 果 访 问 your/session/one 操 作 , 它 将 会 设 置 会 话 变 量 并 转 到 /session/two 位 置 。 如<br />

果 重 新 加 载 /session/two, 这 个 值 将 会 变 为 未 定 义 的 值 , 这 是 因 为 已 经 达 到 了 过 期 “ 跳 ”<br />

的 次 数 。<br />

定 期 重 新 生 成 会 话 ID 也 是 一 种 常 见 需 求 。 这 有 助 于 减 少 会 话 被 第 三 方 劫 持 的 可 能<br />

性 。 对 于 这 一 需 求 ,Zend_Session 类 提 供 了 一 个 静 态 的 regenerateId() 方 法 , 这 个 方 法<br />

将 重 新 创 建 一 个 新 的 会 话 ID, 并 将 它 与 客 户 端 相 关 联 。 通 过 在 引 导 文 件 中 添 加 以 下 代<br />

码 行 , 可 以 确 保 每 个 页 面 加 载 都 会 导 致 一 个 新 的 会 话 ID 被 生 成 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 67/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

Zend_Session::regenerateId();<br />

在 会 话 不 存 在 的 情 况 下 , 框 架 不 会 重 新 生 成 会 话 ID, 并 且 调 用 这 个 方 法 不 会 启 动<br />

一 个 用 其 他 方 法 没 有 被 启 动 的 会 话 。<br />

11 发 送 邮 件<br />

大 多 数 具 有 一 定 复 杂 度 的 Web 应 用 程 序 都 需 要 生 成 各 种 类 型 的 E-mail, 例 如 , 发<br />

送 邮 包 或 者 产 品 订 单 的 通 知 , 或 者 仅 仅 是 一 个 每 日 报 告 。Zend 框 架 提 供 了 强 大 的 邮 件<br />

发 送 API。<br />

最 简 单 的 实 现 就 是 通 过 本 地 邮 件 代 理 给 收 件 人 发 送 一 封 包 含 普 通 文 本 的 E-mail。<br />

代 码 清 单 1-18 演 示 了 发 送 一 封 单 行 E-mail 消 息 的 方 法 。<br />

代 码 清 单 1-18 通 过 本 地 代 理 发 送 普 通 文 本 的 E-mail<br />

代 码 片 段<br />

$mail = new Zend_Mail();<br />

$mail->addTo('user@example.com', 'Firstname Lastname');<br />

$mail->setFrom('noreply@example.com', 'example.com messaging system');<br />

$mail->setSubject('The subject');<br />

$mail->setBodyText('The content');<br />

$mail->send();<br />

下 一 步 是 将 E-mail 的 内 容 从 普 通 文 本 升 级 到 HTML 格 式 。 实 现 这 一 点 , 有 两 种 选<br />

择 。<br />

• 如 果 要 发 送 一 封 多 部 件 邮 件 ( 包 含 普 通 文 本 和 HTML), 可 以 添 加 代 码 调 用<br />

setBody- Html($html) 方 法 。<br />

• 如 果 要 发 送 一 个 单 部 件 文 本 /HTML 消 息 , 可 以 替 换 对 setBodyText() 方 法 的 调<br />

用 。<br />

如 果 没 有 本 地 邮 件 服 务 器 或 者 邮 件 代 理 , 希 望 通 过 简 单 邮 件 传 输 协 议 (SMTP)<br />

来 发 送 邮 件 , 框 架 为 这 个 协 议 提 供 了 一 个 接 口 。 代 码 清 单 1-19 显 示 了 一 个 例 子 。<br />

代 码 清 单 16-19 通 过 SMTP 发 送 邮 件<br />

代 码 片 段<br />

$transport = new Zend_Mail_Transport_Smtp(<br />

'mail.domain.com',<br />

array(<br />

'auth' => 'login',<br />

'username' => 'myusername',<br />

'password' => 'password'<br />

)<br />

);<br />

auth 参 数 控 制 了 如 何 将 验 证 信 息 传 递 给 SMTP。 它 可 以 是 plain、login 或 者<br />

cram-md5。 要 将 这 个 发 送 过 程 和 前 一 例 子 集 成 在 一 起 , 需 要 将 代 码 清 单 16-18 中 最 后<br />

的 send() 调 用 替 换 为 send($transport) 调 用 。<br />

当 需 要 向 与 sendmail 相 兼 容 的 邮 件 发 送 程 序 传 递 更 多 选 项 时 , 还 可 以 使 用<br />

Zend_Mail_ Transport_Sendmail 类 。 当 通 过 sendmail 接 口 发 送 E-mail 时 , 添 加 一 个 -f<br />

选 项 对 于 正 确 地 传 送 头 信 息 来 说 通 常 是 非 常 关 键 的 。<br />

12 创 建 PDF 文 件<br />

Zend_Pdf 组 件 允 许 在 PHP 代 码 中 创 建 或 者 修 改 PDF 文 件 。 它 支 持 几 种 不 同 的 图<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 68/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

像 格 式 、 字 体 以 及 一 些 基 本 的 绘 图 功 能 。<br />

从 头 开 始 创 建 PDF 文 件 非 常 简 单 。 只 需 创 建 Zend_Pdf 类 的 一 个 新 实 例 即 可 。<br />

$pdf = new Zend_Pdf();<br />

如 果 希 望 修 改 一 个 PDF 文 件 , 只 需 使 用 静 态 的 load 函 数 即 可 。<br />

$pdf = Zend_Pdf::load('/path/to/load/file.pdf');<br />

要 保 存 一 个 PDF 文 件 , 不 管 这 个 文 件 是 新 的 还 是 修 改 过 的 , 都 可 以 调 用 save() 方<br />

法 。<br />

$pdf->save('/path/to/save/file.pdf');<br />

要 返 回 一 个 包 含 了 二 进 制 数 据 的 字 符 串 , 例 如 直 接 输 出 到 浏 览 器 中 , 可 以 调 用<br />

render() 方 法 。<br />

$pdf->render();<br />

所 有 的 PDF 文 档 都 包 含 了 页 面 。 你 可 以 获 取 页 面 、 创 建 新 页 面 , 在 页 面 上 绘 制 形<br />

状 、 字 体 以 及 图 像 。 当 加 载 一 个 现 存 的 PDF 文 件 时 , 一 个 名 为 pages 的 集 合 属 性 将 会<br />

被 创 建 和 填 充 , 其 中 包 含 了 通 过 数 字 索 引 访 问 的 Zend_Pdf_Page 对 象 , 数 字 索 引 号 0<br />

表 示 的 是 第 一 页 。<br />

12.1 创 建 新 的 PDF 页 面<br />

可 以 通 过 两 种 方 式 创 建 新 页 面 。<br />

• 创 建 Zend_Pdf_Page 的 一 个 新 实 例 。 这 会 创 建 一 个 独 立 于 文 档 的 页 面 。<br />

• 使 用 $pdf->newPage() 方 法 。 这 会 创 建 一 个 已 挂 接 的 页 面 。<br />

独 立 页 面 和 已 挂 接 页 面 之 间 的 区 别 在 于 内 部 。 这 与 在 同 一 文 档 中 多 个 页 面 之 间 共<br />

享 资 源 相 关 联 , 如 字 体 。<br />

框 架 提 供 了 4 个 默 认 的 页 面 大 小 :SIZE_A4、A4_LANDSCAPE、LETTER 和<br />

LETTER_LANDSCAPE。 代 码 清 单 1-20 演 示 了 向 一 个 PDF 实 例 添 加 新 页 面 的 方 法 。<br />

代 码 清 单 1-20 向 一 个 PDF 实 例 添 加 新 页 面<br />

代 码 片 段<br />

$pdf->pages[] = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_LETTER);<br />

// 其 他 可 选 的 方 法<br />

$pdf->pages[] = $pdf->newPage(Zend_Pdf_Page::SIZE_LETTER);<br />

// 复 制 第 一 页 的 内 容 并 将 它 添 加 到 PDF 中<br />

$pdf->pages[] = new Zend_Pdf_Page($pdf->pages[0]);<br />

如 果 希 望 删 除 一 个 页 面 , 只 需 重 置 pages 集 合 中 相 应 的 数 组 索 引 即 可 。<br />

12.2 在 PDF 页 面 上 绘 图<br />

下 一 步 是 在 页 面 上 绘 图 。 在 PDF 中 , 绘 图 坐 标 (0,0) 从 左 下 角 开 始 , 而 不 是 像<br />

Web 开 发 人 员 所 期 望 的 那 样 从 左 上 角 开 始 。 在 PDF 页 面 上 的 y 坐 标 轴 上 绘 图 时 , 需 要<br />

将 正 数 想 象 成 负 数 并 且 将 0 想 象 为 底 部 。<br />

可 以 绘 制 形 状 和 线 条 , 以 及 字 体 和 图 像 。 所 有 的 绘 图 系 统 都 是 基 于 制 图 风 格 的 系<br />

统 操 作 的 , 这 种 风 格 的 系 统 允 许 设 置 线 条 和 填 充 颜 色 、 宽 度 和 模 式 等 。 代 码 清 单 16-21<br />

显 示 了 PDF 绘 图 的 一 些 选 项 。<br />

代 码 清 单 1-21 在 PDF 中 绘 图 ( 在 IndexController.php 文 件 中 )<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 69/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

public function pdfAction() {<br />

// 禁 止 视 图 输 出 器<br />

$this->getHelper('ViewRenderer')->setNoRender();<br />

// 获 得 response 对 象 并 设 置 内 容 类 型 HTTP 头 信 息<br />

$response = $this->getResponse();<br />

$response->setHeader('Content-Type', 'application/pdf');<br />

// 创 建 一 个 新 的 PDF 文 档 , 并 添 加 一 个 大 小 为 letter 的 页 面<br />

$pdf = new Zend_Pdf();<br />

$pdf->pages[] = $pdf->newPage(Zend_Pdf_Page::SIZE_LETTER);<br />

// 获 得 页 面 的 一 个 引 用<br />

$page = $pdf->pages[0];<br />

// 创 建 图 形 样 式 并 设 置 选 项<br />

$style = new Zend_Pdf_Style();<br />

// 将 字 体 颜 色 设 置 为 黑 色<br />

$style->setLineColor(new Zend_Pdf_Color_Rgb(0,0,0));<br />

// 加 载 一 个 字 体 , 并 将 它 的 大 小 设 置 为 12<br />

$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES);<br />

$style->setFont($font, 12);<br />

// 应 用 这 一 样 式<br />

$page->setStyle($style);<br />

// 从 页 面 左 上 角 开 始 在 100×100 偏 移 量 位 置 上 绘 制 文 本<br />

$page->drawText('Your first dynamic PDF', 100, ($page->getHeight()-100));<br />

/*<br />

确 保 没 有 输 出 内 容 来 破 坏 PDF 输 出 信 息 。 在 输 出 二 进 制 数 据 时 , 需 要 一 个 空 的 输 出 缓 存 。<br />

*/<br />

$response->clearBody();<br />

// 输 出 PDF<br />

$response->setBody($pdf->render());<br />

}<br />

绘 制 图 像 的 工 作 要 稍 微 复 杂 一 些 。 由 于 PDF 是 打 印 格 式 ,PDF 文 档 采 用 的 1..72<br />

的 英 寸 .. 点 的 比 例 系 统 , 这 一 系 统 在 标 准 的 屏 幕 分 辨 率 图 形 上 使 用 1..1 的 比 例 转 换 。<br />

不 过 , 对 于 打 印 分 辨 率 的 图 形 来 说 , 在 绘 图 时 , 必 须 考 虑 图 像 每 英 寸 的 点 的 数 量 (DPI)。<br />

代 码 清 单 1-22 显 示 了 如 何 正 确 绘 制 一 个 基 于 DPI 设 置 的 图 像 。<br />

代 码 清 单 1-22 绘 制 具 有 指 定 DPI 的 图 像<br />

代 码 片 段<br />

// 创 建 一 个 image 对 象<br />

$imageFile = dirname(__FILE__) . '/test.jpg';<br />

$image = Zend_Pdf_Resource_ImageFactory::factory($imageFile);<br />

// 设 置 计 算 变 量<br />

$dpi = 300; // 图 像 的 DPI 很 重 要<br />

$pointsPerInch = 72; //PDF 标 准 的 点 阵 大 小 为 每 英 寸 72 点<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 70/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

// 以 宽 和 高 的 点 数 计 算 图 像 大 小<br />

$imageWidth = ($image->getPixelWidth() / $dpi) * $pointsPerInch;<br />

$imageHeight = ($image->getPixelHeight() / $dpi) * $pointsPerInch;<br />

// 设 置 绘 图 偏 移 量<br />

$x = 100;<br />

$y = ($page->getHeight()-150); // 找 到 页 面 顶 端 , 并 向 下 偏 移 150 点<br />

// 在 PDF (x1,y1,x2,y2) 偏 移 量 位 置 上 绘 制 图 形 ( 左 下 角 坐 标 系 统 )<br />

$page->drawImage($image, $x, ($y - $imageHeight), ($x + $imageWidth), $y);<br />

13 与 Web 服 务 相 集 成<br />

Zend 框 架 内 置 了 多 个 模 型 类 用 于 快 速 而 且 简 单 地 与 几 种 Web 服 务 集 成 。 当 前 , 它<br />

包 括 了 与 Akismet、Amazon、Flickr 和 Yahoo API 等 Web 服 务 相 集 成 的 内 置 机 制 。<br />

作 为 示 例 , 我 们 来 看 一 下 Akismet 服 务 , 它 是 用 来 确 定 对 某 个 Web 站 点 的 评 论 是 有 害<br />

的 还 是 合 理 的 。 你 将 需 要 一 个 来 自 WordPress.com 的 API 键 值 以 便 使 用 这 个 Web 服 务 。<br />

一 旦 获 得 了 键 值 , 实 例 化 这 个 服 务 就 非 常 简 单 了 。<br />

$akismet = new Zend_Service_Akismet($apiKey, 'http://your.com');<br />

在 获 取 了 一 个 Akismet 对 象 之 后 , 可 以 检 查 一 个 评 论 是 否 是 垃 圾 邮 件 , 当 它 被 过<br />

滤 掉 时 , 应 该 将 它 当 成 一 个 有 害 信 息 , 而 当 它 被 错 误 地 标 记 为 有 害 信 息 时 , 应 该 把 它<br />

当 成 是 一 个 好 的 评 论 。<br />

为 了 检 查 某 个 评 论 是 否 是 有 害 信 息 , 需 要 向 Akismet 传 递 关 于 评 论 者 的 特 定 数 量<br />

的 数 据 。 这 包 括 了 HTTP 头 信 息 , 如 浏 览 器 用 户 代 理 程 序 、IP 地 址 等 信 息 。 这 一 信 息<br />

将 和 过 滤 器 一 起 使 用 以 判 断 评 论 是 否 是 有 害 的 。 传 递 的 数 据 越 多 , 获 得 的 关 于 有 害 信<br />

息 的 预 测 也 就 越 可 靠 。<br />

这 一 信 息 使 用 的 是 key=>value 数 组 的 形 式 。 表 1-3 显 示 了 Akismet 支 持 的 键 值 。<br />

表 1-3 Akismet 键 值<br />

键 值 数 据 是 否 必 需<br />

user_agent $_SERVER['HTTP_USER_AGENT'] 是<br />

user_ip $_SERVER['REMOTE_ADDR'] 是<br />

blog 首 页 的 URL 不 是<br />

comment_author 姓 名 不 是<br />

comment_author_ema<br />

il<br />

user@example.com<br />

不 是<br />

comment_author_url 评 论 者 的 URL 不 是<br />

comment_content 实 际 的 评 论 数 据 不 是<br />

comment_type<br />

所 提 供 的 数 据 的 类 型 , 其 中 包 含 comment、 不 是<br />

trackback、pingback 或 者 任 何 其 他 的 字<br />

符 串<br />

permalink 表 单 页 面 的 URL, 而 不 是 首 页 的 URL 不 是<br />

referrer $_SERVER['HTTP_REFERER'] 不 是<br />

* 应 该 提 供 的 所 有 其 他 信 息 不 是<br />

创 建 了 数 据 数 组 之 后 , 就 可 以 调 用 isSpame() 方 法 。<br />

if( ! $akismet->isSpam($data)) { // 数 据 是 空 的 }<br />

如 果 过 滤 器 没 有 获 得 数 据 , 还 可 以 调 用 submitSpam($data) 方 法 , 以 便 让 过 滤 器 知<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 71/111


企 业 解 决 方 案 :<br />

《PHPer》<br />

道 以 后 如 何 截 获 相 似 的 请 求 。 如 果 过 滤 器 捕 获 了 一 些 它 不 应 该 捕 获 的 信 息 并 且 返 回 了<br />

错 误 的 负 面 评 论 , 可 以 调 用 submitHam($data) 方 法 以 帮 助 过 滤 器 知 道 以 后 不 要 截 获 这<br />

样 的 信 息 。 这 两 个 方 法 都 不 会 返 回 任 何 值 。<br />

14 小 结<br />

本 文 介 绍 了 Zend 框 架 必 须 提 供 的 几 个 更 加 高 级 的 机 制 , 总 结 如 下 。<br />

• Zend_Config 允 许 管 理 配 置 文 件 。<br />

• 使 用 Zend_View, 可 以 设 置 站 点 级 别 的 视 图 变 量 。<br />

• Zend_Resigtry 类 允 许 在 组 件 之 间 共 享 对 象 。<br />

• 使 用 ErrorController 类 , 可 以 创 建 一 个 可 以 打 印 出 大 量 调 试 信 息 的 错 误 处 理 程<br />

序 。 还 可 以 将 这 一 错 误 信 息 集 成 到 一 个 自 定 义 的 Zend_Log 日 志 文 件 中 。<br />

• 使 用 Zend_Cache 类 , 可 以 通 过 应 用 有 效 的 缓 存 功 能 来 提 升 应 用 程 序 的 性 能 。<br />

在 选 择 如 何 实 现 缓 存 时 , 必 须 非 常 谨 慎 , 因 为 使 用 缓 存 功 能 是 比 较 危 险 的 。<br />

• 使 用 Zend_Auth 并 将 它 和 登 录 控 制 器 集 成 在 一 起 , 可 以 创 建 验 证 系 统 。<br />

• 使 用 Zend_Json 类 , 可 以 创 建 一 个 发 送 JSON 数 据 的 操 作 。<br />

• Zend_Controller_Router_Rewrite 允 许 应 用 自 定 义 路 由 规 则 , 从 而 使 得 URL 更<br />

加 简 短 , 并 且 更 具 有 针 对 性 。<br />

• 可 以 创 建 一 个 Zend_Session_Namespace 类 , 并 且 让 数 据 在 特 定 数 量 的 “ 跳 ” 之<br />

后 过 期 。 为 了 防 止 会 话 数 据 被 劫 持 , 可 以 使 用 regenerateId() 方 法 。<br />

• 可 以 使 用 Zend_Mail 来 发 送 E-mail。<br />

• Zend_PDF 允 许 创 建 PDF 文 件 。<br />

• 使 用 Zend_Service, 可 以 与 几 种 Web 服 务 集 成 。 例 如 , 通 过<br />

Zend_Service_Akismet, 可 以 使 用 Akismet 服 务 检 查 博 客 的 评 论 是 否 是 有 害 的 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 72/111


项 目 管 理<br />

《PHPer》<br />

项 目 管 理<br />

为 什 么 领 导 力 以 信 任 为 基 础 ( 一 )<br />

著 :Berkun.S<br />

译 : 李 桂 杰<br />

我 曾 遇 到 过 十 几 个 经 理 。 其 中 多 数 人 很 容 易 就 被 忘 掉 了 , 但 是 有 些 人 却 是 非 常 令<br />

人 害 怕 。 但 是 , 那 些 我 很 欣 赏 的 人 需 要 时 间 才 能 赢 得 我 的 信 任 。 他 们 希 望 我 的 工 作 出<br />

色 圆 满 , 但 他 们 也 知 道 , 只 有 我 每 天 都 能 依 靠 他 们 , 我 才 你 达 到 这 样 的 工 作 状 态 , 否<br />

则 根 本 不 可 能 。 但 是 , 这 并 不 意 味 着 , 他 们 只 做 我 所 要 求 的 任 何 事 情 , 或 者 只 屈 从 于<br />

我 的 建 议 。 然 而 , 这 的 确 说 明 他 们 的 行 为 是 可 以 预 期 的 。 他 们 时 常 来 到 我 面 前 , 跟 我<br />

谈 论 他 们 的 职 责 、 动 机 和 期 望 。 我 知 道 我 的 立 场 , 也 清 楚 我 的 角 色 和 他 们 的 角 色 , 更<br />

明 白 对 于 所 要 的 事 情 , 我 能 从 他 们 那 里 得 到 多 大 的 支 持 。<br />

身 为 团 队 的 领 导 , 所 有 的 事 情 都 依 赖 于 每 个 成 员 能 够 对 你 做 出 何 种 假 设 。 当 你 说 :<br />

“ 我 明 天 会 把 它 完 成 ” 或 者 “ 我 会 和 Sally 谈 , 让 她 同 意 这 一 点 。” 其 他 人 心 里 就 会<br />

打 起 小 算 盘 , 看 看 你 所 说 的 话 能 够 成 功 的 几 率 到 底 有 多 少 。 渐 渐 地 , 如 果 你 对 团 队 管<br />

理 得 很 好 , 这 种 成 功 的 几 率 就 会 很 高 。 他 们 就 会 开 始 听 从 你 所 说 的 , 并 且 非 常 信 任 你 。<br />

虽 然 电 影 把 领 导 力 描 述 成 高 度 戏 剧 化 的 活 动 —— 让 英 雄 冲 进 燃 烧 的 大 楼 中 , 或 者 孤 身<br />

一 人 勇 敢 地 对 抗 成 群 的 敌 人 —— 而 真 正 的 领 导 力 其 实 是 非 常 简 单 而 实 际 的 事 情 。 做 你<br />

所 说 的 , 说 你 所 想 的 , 当 你 做 错 的 时 就 认 错 。 做 决 策 前 , 征 求 那 些 受 影 响 者 的 意 见 和<br />

建 议 。 如 果 你 能 经 常 做 到 这 些 , 你 就 会 赢 得 和 你 一 起 工 作 的 同 事 们 的 信 任 。 当 你 必 须<br />

要 求 他 们 做 一 些 他 们 不 愿 意 做 , 或 者 他 们 并 不 同 意 那 样 做 的 事 情 时 , 对 你 信 任 就 会 使<br />

你 的 领 导 力 发 挥 作 用 。<br />

这 说 明 , 要 想 成 为 一 名 出 色 的 领 导 , 你 并 不 需 要 成 为 最 好 的 程 序 员 、 计 划 者 、 架<br />

构 师 、 沟 通 者 、 能 说 笑 话 者 、 设 计 师 或 者 其 他 任 何 角 色 。 你 所 要 做 的 事 情 就 是 , 把 信<br />

任 当 成 一 件 重 要 的 事 情 去 培 养 , 并 且 刻 意 和 你 身 边 的 人 共 同 分 享 。 因 此 , 要 成 为 一 名<br />

好 领 导 , 你 就 要 学 会 如 何 发 现 、 建 立 、 赢 得 信 任 和 信 任 他 人 —— 同 时 你 也 要 学 会 培 养<br />

信 任 自 己 。<br />

建 立 和 失 去 信 任<br />

信 任 (Trust): 名 词 , 对 某 人 的 正 直 、 能 力 和 品 质 非 常 有 信 心 。<br />

“ 信 任 是 所 有 有 意 义 的 人 际 关 系 的 核 心 。 没 有 信 任 , 就 没 有 付 出 、 结 盟 和 风 险 承 担 。”<br />

——Terry Mizrahi, 社 区 组 织 教 育 中 心 主 任 (Education Center for Community<br />

Organizations) 在 一 次 试 验 中 , 我 把 一 些 熟 人 作 为 样 本 , 询 问 他 们 在 当 前 的 工 作 场 所 信<br />

任 谁 , 为 什 信 任 他 ? 他 们 的 回 答 大 致 都 相 同 : 信 任 是 由 这 样 的 人 赢 得 的 , 他 们 努 力 做<br />

好 自 己 的 工 作 , 对 项 目 的 的 目 标 尽 职 尽 责 , 公 平 地 对 待 每 个 人 , 在 艰 难 的 时 刻 表 现 也<br />

始 终 如 一 。 没 有 一 个 人 谈 到 , 他 们 是 否 喜 欢 这 样 的 人 , 或 者 愿 意 邀 请 他 们 共 进 晚 餐 。<br />

看 上 去 , 信 任 是 某 种 穿 透 其 它 人 格 优 点 的 东 西 。 人 们 可 以 信 任 那 些 他 们 根 本 不 喜 欢 ,<br />

或 者 不 愿 意 花 时 间 相 处 的 人 。<br />

不 同 于 其 他 的 人 类 特 征 , 信 任 和 个 人 喜 好 没 有 多 少 联 系 。 人 们 不 会 基 于 肤 浅 的 事<br />

情 去 选 择 相 信 谁 。 相 反 , 对 于 可 以 依 赖 谁 这 个 问 题 , 我 们 总 会 做 出 深 入 的 思 考 。 如 果<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 73/111


项 目 管 理<br />

《PHPer》<br />

我 问 你 , 在 一 种 危 险 的 情 况 下 , 你 相 信 谁 会 挽 救 你 ? 你 所 选 的 人 , 和 我 问 你 愿 意 和 谁<br />

一 起 看 电 影 所 选 的 人 一 定 不 同 。 无 论 如 何 , 个 人 感 情 和 可 靠 性 之 间 没 有 必 然 连 接 的 关<br />

系 。<br />

但 是 , 要 在 一 个 项 目 环 境 中 检 验 信 任 , 我 们 需 要 把 概 念 分 成 可 以 利 用 的 各 个 部 分 。<br />

信 任 的 其 中 一 个 简 单 的 单 位 , 就 是 承 诺 。 承 诺 , 或 者 叫 允 诺 , 就 是 针 对 双 方 达 成 一 致<br />

意 见 的 事 情 , 所 签 订 的 最 简 单 的 合 同 。<br />

信 任 通 过 承 诺 而 建 立<br />

你 结 交 了 一 个 新 朋 友 , 当 他 告 诉 你 会 在 哪 里 和 你 见 面 时 , 你 相 信 他 会 出 现 在 他 所<br />

说 的 地 方 。 但 是 , 如 果 连 续 两 、 三 次 , 他 都 让 没 有 守 约 , 最 后 , 你 一 个 人 看 了 电 影 或<br />

者 呆 在 俱 乐 部 里 , 你 对 他 的 信 任 就 会 大 打 折 扣 。 实 际 上 , 你 没 有 遵 守 对 你 的 承 诺 。 如<br />

果 这 种 事 情 继 续 发 生 , 你 的 看 法 就 会 改 变 。 你 将 不 再 信 任 他 , 在 重 要 的 事 情 面 前 , 你<br />

会 怀 疑 你 对 他 的 信 任 。<br />

根 据 Watts S. Humphrey 所 著 《 管 理 软 件 开 发 过 程 》( Managing the Software Process,<br />

Addison-Wesley 出 版 ,1989 年 ), 合 理 管 理 项 目 的 核 心 元 素 之 一 , 就 是 领 导 者 对 工 作<br />

作 出 承 诺 , 并 且 努 力 完 成 承 诺 的 能 力 。Humphrey 认 为 这 一 能 力 非 常 重 要 , 因 此 他 详<br />

细 地 定 义 了 有 效 承 诺 的 元 素 。 他 列 出 了 一 下 几 点 , 并 且 做 了 一 些 修 正 。<br />

有 效 承 诺 的 元 素<br />

1. 做 出 承 诺 的 人 非 常 愿 意 这 样 做 。<br />

2. 承 诺 不 是 轻 易 做 出 的 , 这 就 是 说 , 承 诺 是 在 充 分 地 考 虑 了 工 作 、 资 源 和 进 度<br />

的 情 况 下 做 出 的 。<br />

3. 双 方 对 做 什 么 , 由 谁 来 做 , 以 及 什 么 时 候 去 做 , 达 成 一 致 意 见 。<br />

4. 公 开 且 坦 诚 地 做 出 承 诺 。<br />

5. 即 使 需 要 帮 助 , 责 任 人 也 要 尽 力 实 现 承 诺 。<br />

6. 在 承 诺 兑 现 之 前 , 如 果 有 任 何 影 响 其 中 一 方 履 行 承 诺 的 事 情 发 生 , 都 要 提 前<br />

通 知 对 方 , 并 且 重 新 做 出 承 诺 。<br />

这 里 , 有 两 件 非 常 有 意 思 的 事 情 。 第 一 , 承 诺 在 双 方 生 效 。 相 关 的 两 方 互 相 承 诺 。<br />

如 果 Cornelius 对 Rupert 承 诺 , 当 Rupert 外 出 时 , 他 会 帮 他 遛 狗 , 那 么 双 方 都 会 尊 重<br />

彼 此 的 利 益 。Cornelius 绝 不 会 在 穿 过 25 个 街 区 , 来 到 Rupert 公 寓 , 想 要 带 Rover 去<br />

中 央 公 园 散 步 的 时 候 , 却 发 现 Rupert 正 躺 在 沙 发 上 看 着 电 视 (“ 哦 , 对 不 起 。 我 本 来<br />

想 昨 天 给 你 打 电 话 来 着 —— 我 的 行 程 取 消 了 。”)。 双 方 交 换 彼 此 的 信 任 , 同 时 希 望 对<br />

方 尊 重 彼 此 的 信 任 —— 而 不 是 亵 渎 或 者 遗 忘 。 让 对 方 浪 费 时 间 或 者 金 钱 , 就 是 在 破 坏<br />

这 种 信 任 。<br />

第 二 , 我 们 经 常 做 出 承 诺 。 在 每 一 次 的 谈 话 中 , 我 们 都 会 要 求 或 者 被 要 求 做 些 什<br />

么 , 并 且 对 此 达 成 某 个 期 限 , 这 样 , 我 们 就 是 在 做 着 某 种 承 诺 。 其 中 包 括 某 些 简 单 的<br />

陈 述 , 例 如 ,“ 嗨 , 晚 餐 后 我 会 打 电 话 给 你 ” 或 者 “ 明 天 我 会 读 那 份 草 稿 ”。 对 于 承 诺 有<br />

多 认 真 , 双 方 想 法 可 能 各 不 相 同 , 但 是 , 几 乎 没 有 人 会 怀 疑 已 经 做 出 了 某 种 承 诺 。 我<br />

们 对 待 别 人 的 承 诺 越 不 尽 心 , 别 人 对 我 们 的 信 任 就 越 会 下 降 。 承 诺 有 不 同 的 等 级 ( 例<br />

如 , 如 果 你 忘 记 了 某 天 下 午 给 你 妻 子 打 电 话 , 她 不 会 把 这 看 成 是 因 为 你 要 和 她 离 婚 的<br />

表 现 ), 但 是 , 这 些 承 诺 对 于 我 们 理 解 其 他 人 是 否 值 得 信 任 都 是 相 关 联 和 有 作 用 的 。<br />

信 任 因 为 不 一 致 的 行 为 而 失 去<br />

回 到 项 目 上 来 , 当 人 们 的 行 为 难 以 预 料 时 , 就 会 破 坏 信 任 。 当 某 人 采 取 的 行 动 一<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 74/111


项 目 管 理<br />

《PHPer》<br />

直 和 他 的 承 诺 毫 无 关 系 , 就 会 产 生 影 响 团 队 的 波 动 情 绪 。 那 些 和 他 一 起 工 作 ( 或 竞 争 )<br />

的 人 的 精 力 就 会 被 消 耗 。 他 们 现 在 要 花 费 精 力 去 考 虑 他 是 否 会 按 照 他 所 说 的 去 做 , 而<br />

不 是 把 精 力 放 在 完 成 工 作 上 。 他 们 必 须 要 制 定 一 些 应 变 的 计 划 , 同 时 各 种 程 度 的 压 力<br />

和 怀 疑 都 会 增 加 (“ 如 果 Marla 今 天 不 能 签 入 那 些 代 码 , 我 们 就 完 了 。”)。 越 是 有 人 对<br />

他 的 工 作 不 负 责 任 , 就 越 会 引 起 团 队 的 情 绪 波 动 。<br />

我 来 讲 个 有 趣 的 ( 虽 然 令 人 感 到 痛 苦 ) 关 于 失 去 信 任 的 故 事 , 这 个 故 事 和 我 以 前<br />

的 一 个 经 理 有 关 。 我 那 时 是 一 名 程 序 经 理 , 下 面 有 五 个 程 序 员 和 测 试 员 , 而 且 我 们 相<br />

处 十 分 融 洽 。Jake 是 团 队 的 领 导 , 也 是 我 的 经 理 , 他 的 手 下 除 了 我 还 有 其 他 几 个 项 目<br />

经 理 。 问 题 出 在 Jake 喜 欢 改 变 想 法 的 习 惯 上 。 例 如 , 他 和 我 一 起 讨 论 我 要 做 出 的 重 要<br />

决 定 , 而 这 些 需 要 他 的 支 持 。 我 们 很 快 就 对 最 佳 方 法 达 成 一 致 意 见 。 但 是 , 一 旦 我 们<br />

开 始 开 会 , 会 上 出 现 个 性 强 硬 的 人 , 资 历 和 他 相 同 或 者 比 他 还 高 的 人 不 同 意 他 的 观 点 ,<br />

那 么 ,Jake 就 会 以 喜 剧 性 的 方 式 屈 服 ( 有 三 分 之 一 的 时 间 , 他 会 这 么 做 , 而 我 总 是 不<br />

知 道 是 哪 三 分 之 一 )。 他 会 改 用 其 它 方 法 , 赞 成 任 何 受 欢 迎 的 决 策 。<br />

我 还 记 得 在 会 上 , 我 站 在 白 板 前 讲 解 我 的 A 计 划 , 刚 讲 到 一 半 , 他 就 同 意 别 人 的<br />

意 见 而 采 取 B 计 划 。 我 停 下 来 , 盯 着 他 , 非 常 惊 讶 , 他 竟 然 可 以 泰 然 处 之 地 做 出 这 种<br />

事 情 。 难 道 他 真 的 忘 了 吗 ? 他 真 的 是 那 种 爱 拍 马 屁 的 人 吗 ? 他 对 我 所 做 的 一 切 竟 然 毫<br />

无 知 觉 吗 ? 或 者 他 那 风 向 标 一 样 的 行 为 ( 跟 着 房 间 里 的 方 向 转 ), 真 的 不 在 他 的 控 制<br />

范 围 内 吗 ? 我 那 时 还 没 有 能 力 处 理 这 样 的 事 情 , 而 且 也 不 知 道 和 别 人 讲 讲 我 所 经 历 的<br />

遭 遇 , 所 以 我 只 有 忍 耐 。 而 我 去 体 育 馆 健 身 时 , 却 从 来 也 没 有 像 这 样 有 忍 耐 力 。<br />

最 后 , 我 开 始 和 他 讨 论 他 的 这 种 做 法 。 而 且 , 只 要 我 们 做 出 决 定 , 我 就 把 它 写 成<br />

文 件 ( 电 子 邮 件 对 此 非 常 有 用 ), 作 为 日 后 的 参 照 。 我 甚 至 还 让 他 在 开 会 前 做 好 准 备 。<br />

但 是 , 所 有 这 些 努 力 只 是 对 他 之 前 的 行 为 得 到 有 限 的 改 善 ( 他 把 不 支 持 B 计 划 , 改 成<br />

不 参 与 讨 论 , 不 帮 助 推 进 A 计 划 了 )。 我 很 快 发 现 , 我 已 经 绕 开 他 做 事 了 。 我 故 意 在<br />

他 没 有 出 席 会 议 的 时 候 做 出 决 定 。 与 他 参 会 相 比 , 这 样 做 不 但 减 少 工 作 , 而 且 还 更 加<br />

有 效 。 虽 然 这 样 , 对 我 的 团 队 会 造 成 其 他 的 问 题 ( 也 会 对 我 和 Jake 之 间 的 关 系 不 利 ),<br />

但 是 我 却 可 以 管 好 我 这 一 摊 儿 , 把 事 情 做 好 。<br />

糟 糕 的 是 ,Jake 很 精 明 , 和 他 共 事 很 有 趣 。 但 是 , 因 为 我 不 信 任 他 , 这 些 也 就 变<br />

得 无 所 谓 了 。 作 为 经 理 , 如 果 他 再 笨 点 , 而 值 得 信 任 的 程 度 再 增 加 一 倍 , 那 么 他 将 非<br />

常 有 所 作 为 。 当 然 , 我 们 就 会 做 出 更 好 的 产 品 , 我 就 不 用 花 费 太 多 的 精 力 来 对 付 他 ,<br />

而 是 把 更 多 的 精 力 放 在 协 助 团 队 上 。<br />

明 确 信 任 ( 挂 起 绿 灯 )<br />

我 碰 到 的 优 秀 的 经 理 , 都 会 把 信 任 感 表 现 出 来 。 他 们 明 确 地 告 诉 我 , 我 有 权 对 我<br />

所 负 责 的 事 情 做 出 决 策 , 只 要 我 能 得 到 团 队 的 支 持 就 行 。 他 们 ( 我 的 经 理 ) 可 能 会 检<br />

查 一 些 他 们 所 关 注 的 特 别 事 项 , 要 求 我 和 他 们 一 起 核 实 这 些 问 题 。 而 且 , 他 们 会 指 引<br />

我 把 重 点 放 在 实 现 事 情 上 , 而 不 是 寻 求 别 人 的 认 可 上 。 给 予 信 任 , 是 授 权 的 真 实 意 义 ,<br />

是 强 而 有 力 的 东 西 。 有 些 运 动 对 这 种 授 权 有 特 殊 的 行 话 —— 例 如 , 在 篮 球 场 上 是 说 或<br />

者 “ 绿 灯 (green light)”。<br />

多 年 以 前 , 我 在 高 中 打 篮 球 , 加 入 Rob Elkins 1 教 练 的 篮 球 队 , 就 在 纽 约 市 道 格 拉<br />

斯 顿 的 塞 缪 尔 Y 体 育 场 。 有 一 天 训 练 时 , 他 把 我 拉 到 一 边 , 这 通 常 是 指 他 要 开 始 训 斥<br />

你 了 。 我 在 练 习 时 一 直 犯 错 , 把 其 他 运 动 员 的 短 裤 拉 扯 下 来 , 害 得 他 们 无 法 进 行 防 守 。<br />

当 我 坐 下 时 , 把 头 下 , 准 备 好 挨 骂 了 。 但 是 , 他 什 么 也 没 说 。 我 们 做 了 很 久 , 看 着 场<br />

上 其 他 队 员 的 混 战 。 最 后 , 他 说 :“Scott, 你 有 绿 灯 了 。” 我 看 着 他 , 问 道 :“ 绿 灯 ?”<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 75/111


项 目 管 理<br />

《PHPer》<br />

他 笑 着 回 答 道 “ 是 的 ”, 但 却 连 看 都 没 看 我 。 我 说 “ 好 吧 , 教 练 ”, 然 后 就 跑 回 场 上 。 尽<br />

管 很 少 有 人 听 过 这 话 , 但 是 不 知 怎 么 , 所 有 队 员 都 知 道 这 话 什 么 意 思 。 一 般 情 况 下 ,<br />

球 员 是 否 有 义 务 射 篮 , 必 须 要 看 教 练 的 战 术 安 排 , 但 是 绿 灯 除 外 。 我 可 以 随 时 射 篮 ,<br />

只 要 我 觉 得 合 适 —— 当 我 认 为 必 要 时 , 我 可 以 接 替 任 何 打 法 和 练 习 权 限 。<br />

注 释 1: 纽 约 市 道 格 拉 斯 顿 的 塞 缪 尔 Y 体 育 场 的 Rob 和 Eric, 教 了 我 很 多 关 于 教<br />

练 和 管 理 的 知 识 , 他 们 所 教 的 内 容 比 我 后 来 高 中 和 大 学 的 篮 球 队 教 练 教 的 内 容 要 多 的<br />

多 。 如 果 你 认 识 他 们 , 请 告 诉 他 们 和 我 联 系 。<br />

告 诉 一 个 球 员 这 样 的 话 , 就 是 给 予 他 非 常 的 信 任 , 这 恰 恰 是 为 什 么 大 多 数 球 员 在<br />

其 整 个 职 业 生 涯 中 都 没 有 听 说 过 这 事 ( 我 高 中 一 直 打 篮 球 , 后 来 还 在 第 三 级 大 学 队 里<br />

打 , 但 是 我 再 也 没 有 听 过 这 样 的 话 , 而 且 之 前 也 从 未 听 说 )。 教 练 通 常 害 怕 放 弃 职 权 ,<br />

就 像 经 理 们 那 样 , 他 们 认 为 自 己 的 权 力 非 常 脆 弱 。 站 在 边 上 ( 或 者 一 个 人 坐 在 角 落 的<br />

办 公 室 ) 是 非 常 容 易 受 到 攻 击 的 地 方 。 很 多 经 理 和 教 练 们 担 心 , 如 果 给 他 们 的 团 队 额<br />

外 的 自 由 , 就 会 出 现 什 么 状 况 。 他 们 忘 了 自 己 可 以 随 时 调 整 信 任 度 , 如 果 我 滥 用 Elkins<br />

教 练 给 我 的 信 任 , 那 么 没 有 什 么 可 以 阻 止 他 收 回 他 对 我 的 信 任 ( 把 绿 灯 变 成 黄 灯 )。<br />

更 重 要 的 是 , 或 许 , 经 理 们 害 怕 给 予 的 信 任 程 度 , 正 好 就 是 团 队 实 际 所 需 的 跟 随 他 们<br />

的 领 导 的 程 度 。<br />

可 以 说 , 我 在 Elkins 教 练 带 下 表 现 得 比 其 他 教 练 带 领 时 都 更 加 努 力 。 我 本 能 地 认<br />

为 我 要 实 现 更 高 的 目 标 ( 虽 然 有 场 比 赛 , 我 十 五 分 钟 内 射 了 7 次 篮 , 结 果 一 次 也 没 射<br />

中 , 我 确 信 这 种 射 篮 成 绩 可 以 称 得 上 是 某 种 俱 乐 部 记 录 了 )。 对 那 些 给 予 我 相 似 信 任<br />

感 的 经 理 , 我 也 会 尽 力 和 他 们 工 作 , 而 对 于 那 些 没 有 这 么 做 的 经 理 , 我 工 作 起 来 就 不<br />

那 么 尽 力 。 这 并 不 是 因 为 我 喜 欢 他 们 ( 虽 然 这 有 所 帮 助 ), 而 是 因 为 我 有 了 更 可 以 努<br />

力 工 作 的 空 间 。 信 任 的 传 达 才 产 生 真 正 的 授 权 , 因 为 这 会 给 人 空 间 , 使 人 能 够 在 他 们<br />

的 颠 覆 状 态 下 工 作 。<br />

如 果 获 得 最 大 可 能 的 成 功 就 是 你 的 目 标 , 那 么 你 就 要 寻 找 各 种 办 法 , 给 别 人 绿 灯 。<br />

经 理 人 的 工 作 , 就 是 给 他 的 团 队 创 造 机 会 , 同 时 还 要 协 助 团 队 有 能 力 和 做 好 准 备 去 抓<br />

住 这 些 机 会 。<br />

不 同 类 型 的 权 力<br />

在 本 文 中 , 我 会 使 用 两 种 权 力 模 型 。 在 后 面 的 第 十 六 章 中 , 会 介 绍 高 级 模 型 。 现<br />

在 开 始 , 我 会 专 注 介 绍 简 单 而 有 效 的 职 能 性 权 力 。<br />

职 能 性 权 力 有 两 种 : 授 予 的 和 自 己 争 取 得 来 的 。 授 予 的 权 力 来 自 积 极 体 制 或 者 工<br />

作 头 衔 ( 有 时 , 被 称 为 职 权 )。 例 如 , 篮 球 队 教 练 有 权 决 定 哪 个 队 员 可 以 上 场 , 哪 个<br />

队 员 要 做 冷 板 凳 。 小 规 模 营 销 办 公 室 领 导 有 权 聘 用 和 开 除 任 何 人 。 但 是 , 这 种 权 力 和<br />

人 们 对 他 们 有 多 少 尊 重 无 关 , 甚 至 于 和 人 们 认 为 他 们 有 多 少 技 能 和 知 识 也 无 关 。 相 反 ,<br />

自 己 争 取 的 权 力 , 是 必 须 经 过 表 现 和 行 为 的 不 断 进 取 而 获 得 的 。 获 取 的 权 力 , 或 者 是<br />

获 取 的 授 权 , 就 是 那 种 人 们 出 于 领 导 的 英 明 和 有 所 帮 助 , 而 不 是 因 为 他 的 权 限 , 而 选<br />

择 去 听 从 的 那 种 权 力 。<br />

不 要 依 赖 授 予 型 权 力<br />

“ 我 不 相 信 任 何 体 系 的 组 织 者 , 而 且 会 避 开 他 们 : 对 体 系 的 渴 望 , 就 是 因 为 自 身 不<br />

完 整 。”<br />

——Nietzsche<br />

如 果 领 导 以 授 予 型 权 力 作 为 主 要 的 影 响 力 , 那 么 就 会 限 制 人 际 关 系 。 它 排 除 了 交<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 76/111


项 目 管 理<br />

《PHPer》<br />

换 想 法 的 可 能 , 把 重 点 放 在 了 如 何 使 用 这 些 影 响 力 , 而 不 是 如 何 调 用 那 些 聪 明 人 上 。<br />

虽 然 在 某 些 情 况 下 , 必 须 使 用 独 裁 专 制 的 权 力 , 但 是 , 优 秀 的 领 导 尽 可 能 地 把 剑 插 在<br />

剑 鞘 中 。 一 旦 你 拔 剑 , 就 没 有 人 听 你 说 什 么 了 —— 他 们 都 听 剑 的 了 。 更 糟 糕 的 的 是 ,<br />

你 身 边 的 每 个 人 都 会 拔 出 自 己 的 剑 去 回 应 你 的 剑 ( 他 们 的 剑 可 能 比 你 的 剑 还 要 好 )。<br />

他 们 不 会 和 你 解 释 为 什 么 你 做 错 了 , 他 们 只 会 利 用 自 己 的 授 予 型 权 力 去 挑 战 你 的 力 量 。<br />

这 就 导 致 了 各 种 力 量 的 竞 争 , 这 种 竞 争 和 智 慧 无 关 , 也 不 会 去 寻 找 最 佳 的 解 决 方 法 。<br />

授 予 型 权 力 ( 就 像 力 量 的 黑 暗 面 ) 是 临 时 的 , 因 为 它 很 容 易 获 得 : 你 无 需 努 力 , 就 可<br />

以 得 到 你 想 要 的 。<br />

我 曾 遇 到 这 样 的 情 况 , 把 我 推 到 授 予 的 权 力 和 争 取 得 到 的 权 力 的 十 字 路 口 。 那 时<br />

在 开 发 IE2.0, 那 是 我 第 一 项 重 大 的 程 序 管 理 任 务 。 第 一 天 , 我 被 介 绍 给 两 位 我 要 共<br />

事 的 程 序 员 ,Bill 和 Jay。Jay 非 常 友 好 , 而 Bill 则 比 较 沉 默 和 吓 人 。 他 在 组 织 中 也 是<br />

一 位 资 力 很 高 的 人 ( 以 微 软 的 行 话 来 说 是 13 级 , 这 意 味 着 , 他 是 程 序 员 中 可 能 的 最<br />

高 级 别 的 人 )。 我 还 记 得 坐 在 他 的 办 公 室 里 , 隔 着 桌 子 看 着 他 。 我 谈 了 有 10 分 钟 , 而<br />

他 几 乎 什 么 都 没 说 。 他 就 是 那 样 斜 靠 在 椅 子 里 , 盯 着 我 。<br />

我 试 着 走 到 白 板 前 , 看 看 那 样 能 够 让 他 谈 点 什 么 , 但 是 没 有 生 效 。 他 只 会 说 些 讽<br />

刺 或 者 含 糊 不 清 的 事 , 例 如 ,“ 哦 , 真 的 是 那 样 吗 ?” 以 及 “ 哇 …… 真 有 趣 , 你 竟 然 你 那<br />

样 想 。” 他 只 是 在 玩 弄 我 , 就 像 猫 在 玩 一 只 半 死 的 老 鼠 一 样 。 要 知 道 , 我 那 时 只 是 个<br />

狂 妄 自 大 的 23 岁 的 年 轻 人 , 我 对 我 所 做 的 事 情 根 本 不 清 楚 , 尽 管 我 不 断 让 自 己 相 信 ,<br />

我 可 以 装 懂 。 另 一 方 面 ,Bill 是 经 验 丰 富 的 专 家 , 他 前 有 几 十 次 碰 到 过 这 样 的 程 序 。<br />

事 实 上 , 我 确 定 他 脑 海 中 只 有 两 个 想 法 :“ 我 怎 么 能 跟 着 这 样 一 个 年 轻 的 新 人 ?” 以 及<br />

“ 他 是 不 是 我 碰 到 过 的 最 蠢 或 者 第 二 蠢 的 人 ?” 见 面 结 束 , 我 用 一 种 “ 直 接 从 HR 训 练 录<br />

像 ” 里 学 来 的 方 式 , 胡 乱 说 道 , 将 和 你 一 起 工 作 多 么 好 啊 。( 我 坚 信 , 这 一 点 让 他 确 信 ,<br />

我 事 实 上 是 那 个 最 蠢 的 家 伙 。)<br />

那 时 , 一 个 好 朋 友 ( 另 一 位 PM) 给 了 这 样 的 建 议 : 按 规 矩 办 事 。 我 应 该 告 诉 Bill,<br />

因 为 我 是 PM, 他 是 程 序 员 , 在 一 些 高 层 次 的 决 定 上 , 他 应 该 按 我 说 的 去 做 。 这 点 与<br />

我 曾 听 说 的 微 软 PM 神 话 (“ 谁 挡 了 我 的 路 , 我 就 杀 谁 ”) 不 谋 而 合 , 于 是 , 我 重 新 鼓<br />

起 勇 气 , 去 尝 试 和 实 践 这 句 话 。 但 是 , 在 我 拔 剑 准 备 往 前 冲 时 , 我 找 我 的 经 理 谈 话 。<br />

就 在 温 和 的 笑 声 中 , 他 告 诉 我 不 要 贸 然 行 事 。 他 提 醒 我 ,Bill 在 他 的 领 域 内 , 非 常 聪<br />

明 且 知 识 渊 博 , 我 应 该 想 办 法 如 何 利 用 他 这 一 点 。 他 还 补 充 道 , 和 Bill 一 起 工 作 , 就<br />

像 他 提 过 的 那 样 ,“ 对 我 有 好 处 ”。 尽 管 他 在 笑 , 但 我 还 是 相 信 他 。 我 把 剑 放 到 了 一 边 ,<br />

开 始 从 尽 量 让 Bill 发 挥 作 用 的 角 度 出 来 去 解 决 问 题 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 77/111


高 级 应 用 :<br />

《PHPer》<br />

高 级 应 用<br />

应 用 Zend 框 架<br />

Zend Framework 团 队<br />

在 之 前 的 文 章 中 , 你 已 经 初 步 了 解 了 一 些 Zend 框 架 组 件 , 以 及 如 何 在 应 用 程 序 中<br />

使 用 它 们 。 在 本 章 中 , 你 将 更 好 地 了 解 Zend 框 架 的 架 构 、 分 派 循 环 以 及 插 件 架 构 。<br />

还 将 学 到 如 何 创 建 你 自 己 的 可 重 用 库 , 并 将 它 们 与 Zend_Loader 集 成 。<br />

在 接 近 本 章 末 尾 的 地 方 , 你 将 应 用 已 学 知 识 去 创 建 一 个 完 全 集 成 的 验 证 程 序 和 访<br />

问 控 制 系 统 。 最 后 , 将 介 绍 关 于 Zend_Layout 组 件 的 内 容 , 这 个 组 件 允 许 创 建 一 个 在<br />

整 个 站 点 范 围 内 具 有 公 共 外 观 的 站 点 。 阅 读 完 本 章 之 后 , 你 对 Zend 框 架 的 运 行 机 制<br />

应 该 有 一 个 系 统 的 了 解 。<br />

1 模 块 和 模 型 设 置<br />

在 前 面 , 你 已 经 创 建 了 遵 循 单 一 控 制 器 / 操 作 层 次 结 构 的 Zend 框 架 站 点 。 这 通 常<br />

是 所 需 要 的 全 部 功 能 , 但 是 如 果 有 一 个 复 杂 的 站 点 , 也 可 以 添 加 第 三 个 层 次 , 它 被 称<br />

为 模 块 , 允 许 创 建 遵 循 /module/controller/action 格 式 的 URL。<br />

1.1 常 规 的 模 块 化 的 目 录 结 构<br />

这 个 URL 结 构 和 它 底 层 的 框 架 布 局 结 构 通 常 被 称 为 常 规 的 模 块 化 的 目 录 结 构 。 在<br />

使 用 模 块 化 设 置 时 , 目 录 结 构 应 如 代 码 清 单 1-1 所 示 , 这 一 示 例 假 设 你 拥 有 两 个 模 块<br />

default 和 admin。<br />

代 码 清 单 1-1 模 块 化 目 录 结 构<br />

代 码 片 段<br />

.<br />

./application<br />

./application/modules<br />

./application/modules/default<br />

./application/modules/default/controllers<br />

./application/modules/default/views<br />

./application/modules/default/views/scripts<br />

./application/modules/default/views/scripts/index<br />

./application/modules/default/views/scripts/error<br />

./application/modules/default/models<br />

./application/modules/admin<br />

./application/modules/admin/views<br />

./application/modules/admin/views/scripts<br />

./application/modules/admin/views/scripts/index<br />

./application/modules/admin/models<br />

./application/modules/admin/controllers<br />

./document_root<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 78/111


高 级 应 用 :<br />

《PHPer》<br />

要 激 活 模 块 化 的 用 法 , 只 需 在 引 导 文 件 中 将 前 端 控 制 器 指 向 modules 目 录 即 可 。<br />

$front->addModuleDirectory(APP_PATH . '/application/modules');<br />

index 模 块 被 称 为 default, 对 / 的 请 求 将 会 被 转 发 到 /default/index/index 上 。 要 使 用<br />

框 架 提 供 的 模 块 化 设 置 , 做 到 这 些 事 就 可 以 了 。<br />

1.2 模 型 库 和 Zend_Loader<br />

你 应 该 会 注 意 到 在 常 规 设 置 中 模 块 之 间 不 会 共 享 models 目 录 。 这 有 助 于 隔 离 组 件<br />

逻 辑 , 并 且 使 模 块 更 容 易 在 应 用 程 序 之 间 共 享 。 但 也 会 导 致 代 码 重 复 。<br />

许 多 框 架 开 发 人 员 发 现 , 保 持 一 个 可 重 用 的 组 件 库 , 并 和 框 架 自 身 打 包 的 方 法 类<br />

似 的 方 法 打 包 , 是 很 有 价 值 的 。 与 应 用 程 序 级 别 的 模 型 相 比 , 这 一 方 法 的 优 点 在 于 可<br />

以 在 应 用 程 序 之 间 以 及 模 块 之 间 共 享 这 个 组 件 库 。 缺 点 在 于 不 再 可 以 对 应 用 程 序 的 环<br />

境 设 置 假 设 条 件 , 例 如 注 册 表 对 象 或 者 引 导 设 置 等 环 境 因 素 。 希 望 绑 定 的 这 种 类 型 的<br />

任 何 设 置 都 必 须 在 引 导 库 时 显 式 地 传 递 给 它 。<br />

要 添 加 一 个 模 型 库 , 首 先 需 要 在 全 局 位 置 创 建 一 个 名 为 library 的 目 录 , 例 如<br />

/usr/share/ php/YourPrefix。 这 个 library 目 录 将 作 为 包 含 路 径 在 引 导 过 程 中 传 递 给 框 架 。<br />

下 一 部 分 的 内 容 与 命 名 规 范 非 常 接 近 。 类 名 称 应 该 全 部 以 一 个 公 共 的 前 缀 开 头 , 然 后<br />

遵 循 驼 峰 匹 配 原 则 , 在 希 望 用 目 录 分 隔 的 地 方 用 下 划 线 (_) 隔 开 。 例 如 ,<br />

YourPrefix_Tax_Calculator 将 被 保 存 在 library/YourPrefix/Tax/Calculator.php 中 。 因 为 我<br />

们 可 能 希 望 对 现 存 的 库 进 行 集 成 , 所 以 不 想 使 用 这 一 命 名 规 范 , 这 样 将 不 能 通 过 标 准<br />

的 Zend_Loader 自 动 加 载 机 制 访 问 库 了 。<br />

代 码 清 单 1-2 显 示 了 如 何 创 建 库 模 型 。<br />

代 码 片 段<br />


高 级 应 用 :<br />

《PHPer》<br />

set_include_path(implode(PATH_SEPARATOR, $paths));<br />

require_once('Zend/Loader.php');<br />

Zend_Loader::registerAutoload();<br />

$tax = YourPrefix_Tax_Calculator::calculate(1);<br />

这 一 方 法 是 否 可 行 完 全 取 决 于 遵 循 Zend 框 架 标 准 的 类 名 命 名 规 范 的 程 度 。 如 果 希<br />

望 加 载 一 个 没 有 前 缀 或 者 下 划 线 的 类 , 如 TaxCalculator, 将 需 要 编 写 你 自 己 的 加 载 程<br />

序 。 如 第 9 章 所 讨 论 过 的 , 通 过 扩 展 Zend_Loader 或 者 注 册 一 个 附 加 的 spl_autoload<br />

函 数 , 你 也 可 以 实 现 这 一 功 能 。<br />

2 请 求 生 命 周 期<br />

现 在 , 你 已 经 了 解 了 模 块 和 模 型 , 下 面 将 介 绍 Zend 框 架 的 核 心 , 并 真 正 理 解 路 由<br />

和 分 派 应 用 程 序 时 框 架 运 行 的 步 骤 。 图 17-1 演 示 了 Zend 框 架 应 用 程 序 的 完 整 流 程 。<br />

图 1-1 Zend 框 架 应 用 程 序 流 程<br />

你 会 留 意 到 的 第 一 件 事 就 是 在 接 收 到 一 个 请 求 之 后 , 路 由 就 开 始 了 。( 暂 时 忽 略 插<br />

件 和 辅 助 代 理 类 , 它 们 的 含 义 将 在 下 一 节 讨 论 。) 路 由 是 指 框 架 接 收 到 请 求 URL, 并<br />

将 它 与 路 由 器 规 定 的 规 则 列 表 相 匹 配 的 过 程 。 这 些 规 则 将 URL 分 解 成 模 块 、 控 制 器 、<br />

操 作 以 及 任 意 数 量 的 已 定 义 参 数 。 然 后 , 所 有 这 些 信 息 都 会 被 存 储 到 Zend_Request<br />

对 象 中 , 并 且 传 递 给 分 派 循 环 。<br />

分 派 过 程 是 以 循 环 形 式 运 行 的 , 它 允 许 几 种 不 同 的 机 制 重 置 应 用 程 序 并 将 它 发 送<br />

回 分 派 起 点 , 例 如 将 一 个 未 授 权 的 用 户 转 发 到 登 录 屏 幕 中 。 这 一 分 派 过 程 默 认 是 由<br />

Zend_Controller_ Dispatcher_Standard 来 处 理 的 , 它 会 实 例 化 操 作 控 制 器 , 并 且 调 用 控<br />

制 器 的 init() 方 法 。 然 后 , 它 会 调 用 操 作 控 制 器 上 的 dispatch() 方 法 。<br />

3 创 建 插 件<br />

你 可 能 会 留 意 到 , 框 架 拥 有 PluginBroker 类 激 发 的 几 个 事 件 , 严 格 来 讲 , 这 个 类<br />

的 名 称 为 Zend_Controller_Plugin_Broker, 这 是 一 个 基 本 的 注 册 和 通 知 类 。 这 些 事 件 提<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 80/111


高 级 应 用 :<br />

《PHPer》<br />

供 了 影 响 和 中 断 分 派 过 程 的 机 会 。 通 常 , 这 一 中 断 过 程 是 以 修 改 Zend_Request 对 象 的<br />

值 的 形 式 进 行 的 , 从 而 对 后 面 的 流 程 产 生 影 响 。<br />

例 如 , 一 个 转 发 插 件 在 routeShutdown 事 件 中 可 以 设 置 控 制 器 和 操 作 等 请 求 参 数 ,<br />

这 将 会 导 致 完 全 不 同 的 分 派 过 程 。 另 一 种 插 件 可 能 会 在 dispatchLoopShutdown 事 件 中<br />

添 加 或 者 删 除 应 答 内 容 。<br />

编 写 插 件 非 常 简 单 。 首 先 , 所 有 插 件 都 必 须 从 Zend_Controller_Plugin_Abstract 类<br />

继 承 , 并 且 实 现 图 1-1 所 示 的 任 何 PluginBroker 方 法 。 除 了 dispatchLoopShutdown 事<br />

件 之 外 , 所 有 的 方 法 都 将 传 入 当 前 的 Zend_Request 对 象 作 为 它 们 唯 一 的 参 数 。<br />

要 了 解 这 一 机 制 是 如 何 工 作 的 , 我 们 来 看 一 个 简 单 的 例 子 。 在 库 中 创 建 一 个 名 为<br />

YourPrefix_Controller_Plugin_Statistics 的 类 , 这 个 类 将 会 在 routeStartup 事 件 中 将 每 个<br />

请 求 的 URL 记 录 到 数 据 库 中 。 这 个 插 件 的 内 容 如 代 码 清 单 1-4 所 示 。 这 个 插 件 假 设 已<br />

经 有 一 个 名 为 stats 的 表 , 并 且 表 中 有 一 个 名 为 uri 的 列 。<br />

代 码 清 单 1-4 stats 日 志 记 录 插 件 (YourPrefix_Controller_Plugin_Statistics)<br />

代 码 片 段<br />

class YourPrefix_Controller_Plugin_Statistics extends<br />

Zend_Controller_Plugin_Abstract {<br />

public function routeStartup($request) {<br />

$uri = $request->getRequestUri();<br />

$dbconfig = array(<br />

'host' => 'localhost',<br />

'username' => 'user',<br />

'password' => 'password',<br />

'dbname' => 'demo'<br />

);<br />

$db = Zend_Db::factory('PDO_PGSQL', $dbconfig);<br />

$data = array(<br />

'uri' => $uri<br />

);<br />

$db->insert('stats', $data);<br />

}<br />

}<br />

要 注 册 插 件 , 需 要 调 用 前 端 控 制 器 上 的 registerPlugin() 方 法 :<br />

$front->registerPlugin(new YourPrefix_Controller_Plugin_Statistics());<br />

通 过 使 用 插 件 , 可 以 在 站 点 范 围 内 收 集 关 于 应 用 程 序 的 所 有 类 型 的 信 息 。<br />

4 创 建 辅 助 类<br />

辅 助 类 是 专 门 用 来 为 MVC 组 件 增 加 和 集 成 功 能 的 类 。 有 两 种 主 要 的 辅 助 类 类 型 ,<br />

它 们 分 别 是 操 作 辅 助 类 和 视 图 辅 助 类 。<br />

4.1 编 写 操 作 辅 助 类<br />

回 头 参 考 图 1-1, 你 将 会 留 意 到 HelperBroker 操 作 上 有 另 外 两 个 事 件 将 会 被 调 用 ,<br />

即 notifyPreDispatch() 和 notifyPostDispatch()。 这 两 个 方 法 在 操 作 辅 助 类 上 被 简 单 地 转<br />

换 为 preDispatch() 和 postDispatch() 方 法 , 它 们 提 供 了 处 理 操 作 控 制 器 特 定 事 件 的 功 能 ,<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 81/111


高 级 应 用 :<br />

《PHPer》<br />

并 且 不 用 注 册 一 个 站 点 级 别 的 插 件 。 这 可 以 实 现 即 用 即 加 载 的 场 景 , 如 果 拥 有 大 量 辅<br />

助 类 , 这 种 做 法 将 会 更 加 有 效 。<br />

视 图 输 出 器 是 框 架 内 置 功 能 作 为 操 作 辅 助 类 部 署 的 一 个 好 的 示 例 。 它 使 用<br />

Zend_Request:: getActionName() 方 法 以 及 postDispatch() 事 件 来 确 定 和 输 出 专 门 为 操 作<br />

设 计 的 模 板 。<br />

重 定 向 辅 助 类 没 有 实 现 这 些 事 件 , 但 是 用 到 了 辅 助 类 集 成 以 便 为 重 定 向 功 能 提 供<br />

一 个 方 便 的 接 口 。<br />

如 果 希 望 编 写 操 作 辅 助 类 , 只 需 继 承 Zend_Controller_Action_Helper_Abstract, 并<br />

实 现 认 为 有 价 值 的 那 些 方 法 。 为 了 注 册 操 作 辅 助 类 , 可 以 调 用 HelperBroker 上 的<br />

addHelper() 方 法 。<br />

Zend_Controller_Action_HelperBroker::addHelper(new YoorHelperClass());<br />

另 外 , 还 可 以 使 用 addPath() 方 法 设 置 一 个 路 径 , 在 这 个 路 径 中 HelperBroker 可 以<br />

找 到 所 有 的 辅 助 类 。 例 如 , 把 所 有 辅 助 类 添 加 到 以 类 前 缀 YourPrefix 开 头 的 路 径 中 。<br />

Zend_Controller_Action_HelperBroker::addPath('/path/to/helpers', 'YourPrefix');<br />

为 了 访 问 操 作 的 辅 助 类 , 可 以 调 用 $this->getHelper('YourHelperClass') 方 法 , 正 如<br />

之 前 示 例 中 使 用 FlashMessenger、Redirector 和 ViewRenderer 这 些 类 时 你 所 做 的 那 样 。<br />

4.2 编 写 视 图 辅 助 类<br />

还 可 以 创 建 你 自 己 的 视 图 辅 助 类 , 但 在 确 定 某 个 辅 助 类 是 否 合 适 时 , 要 非 常 谨 慎 。<br />

理 想 情 况 下 , 视 图 辅 助 类 应 该 用 在 重 复 任 务 上 , 并 且 只 应 该 被 当 成 在 处 理 公 共 视 图 数<br />

据 时 获 得 便 利 的 一 种 方 法 。 它 们 不 能 用 来 避 开 操 作 的 处 理 逻 辑 , 因 为 这 样 , 会 极 大 地<br />

减 少 使 用 MVC 框 架 带 来 的 好 处 , 并 且 模 糊 了 控 制 器 和 视 图 的 界 限 。<br />

为 了 创 建 视 图 辅 助 类 , 应 该 创 建 一 个 名 称 带 有 Zend_View_Helper 前 缀 的 类 , 并 将<br />

它 放 在 ./views/helpers 目 录 中 。 代 码 清 单 1-5 显 示 了 如 何 创 建 一 个 返 回 当 前 日 期 的 视 图<br />

辅 助 类 。<br />

代 码 清 单 1-5 简 单 的 视 图 辅 助 类<br />

代 码 片 段<br />


高 级 应 用 :<br />

《PHPer》<br />

5 实 现 访 问 控 制 功 能<br />

现 在 , 你 已 经 了 解 了 插 件 、 辅 助 类 以 及 请 求 周 期 的 不 同 部 分 , 可 以 开 始 讨 论 访 问<br />

控 制 功 能 。Zend_Acl 是 一 个 强 大 的 并 且 复 杂 的 组 件 , 它 允 许 定 义 网 站 中 允 许 用 户 访 问<br />

的 操 作 。<br />

虽 然 Zend_Acl 可 以 独 立 于 插 件 和 辅 助 类 使 用 , 但 将 它 们 作 为 一 个 完 整 的 解 决 方 案<br />

来 使 用 时 , 其 功 能 要 强 大 得 多 。 它 是 一 个 高 质 量 的 访 问 系 统 , 其 中 包 含 了 可 继 承 的 角<br />

色 在 资 源 级 别 控 制 和 权 限 级 别 控 制 等 方 面 的 设 置 功 能 。 这 里 , 为 简 单 起 见 , 我 们 将 完<br />

整 地 介 绍 资 源 级 别 控 制 。<br />

在 这 个 例 子 中 , 你 将 创 建 一 个 基 本 的 订 户 区 域 类 型 的 Web 站 点 , 其 中 特 定 控 制 器<br />

对 访 客 是 限 制 访 问 的 , 但 会 员 是 可 以 访 问 的 。 这 个 控 制 器 将 把 未 授 权 的 用 户 转 发 到 登<br />

录 页 面 。 为 了 实 现 这 个 功 能 , 你 将 需 要 一 个 如 代 码 清 单 1-7 所 示 的 基 本 的 ACL(Access<br />

Control List, 访 问 控 制 列 表 )。<br />

代 码 清 单 1-7 ACL 启 动 (index.php)<br />

代 码 片 段<br />

$acl = new Zend_Acl();<br />

// 创 建 guest 角 色<br />

$acl->addRole(new Zend_Acl_Role('guest'));<br />

// 创 建 members 角 色 , 它 继 承 自 guest 角 色<br />

$acl->addRole(new Zend_Acl_Role('member'), 'guest');<br />

// 为 index 控 制 器 添 加 资 源<br />

$acl->add(new Zend_Acl_Resource('index'));<br />

// 为 articles 控 制 器 添 加 资 源<br />

$acl->add(new Zend_Acl_Resource('articles'));<br />

// 允 许 guest 访 问 index 控 制 器<br />

$acl->allow('guest', 'index');<br />

// 禁 止 guest 访 问 article 控 制 器 , 但 允 许 members 访 问<br />

$acl->deny('guest', 'articles');<br />

$acl->allow('member', 'articles');<br />

下 一 步 , 需 要 创 建 一 个 articles 控 制 器 以 及 与 之 对 应 的 视 图 , 如 代 码 清 单 1-8 和 代<br />

码 清 单 1-9 所 示 。<br />

代 码 清 单 1-8 articles 控 制 器 (ArticlesController.php)<br />

代 码 片 段<br />


高 级 应 用 :<br />

《PHPer》<br />

This is secret<br />

在 库 中 , 需 要 创 建 一 个 名 为 YourPrefix_Controller_Plugin_Security 的 插 件 , 并 将 它<br />

放 在 /usr/share/php/YourPrefix/library/YourPrefix/Controller/Plugin/Security.php 文 件 中 ,<br />

这 个 插 件 如 代 码 清 单 1-10 所 示 。<br />

代 码 清 单 1-10 ACL 和 Auth 相 结 合 的 插 件<br />

代 码 片 段<br />

class YourPrefix_Controller_Plugin_Security<br />

extends Zend_Controller_Plugin_Abstract<br />

{<br />

protected $_acl;<br />

// 在 注 册 插 件 时 获 得 启 动 的 ACL<br />

public function __construct($acl) {<br />

$this->_acl = $acl;<br />

}<br />

// 响 应 dispatchLoopStartup 事 件<br />

public function dispatchLoopStartup($request) {<br />

// 获 得 Zend_Auth 的 一 个 实 例 并 将 默 认 角 色 设 置 为 guest。<br />

$auth = Zend_Auth::getInstance();<br />

$role = 'guest';<br />

// 如 果 用 户 已 登 录 , 从 数 据 库 行 中 获 得 角 色 标 识 符<br />

if($auth->hasIdentity()) {<br />

$role = $auth->getIdentity()->role;<br />

}<br />

// 资 源 名 称 就 是 控 制 器 名 称<br />

$resource = $request->getControllerName();<br />

// 如 果 控 制 器 不 处 在 ACL 控 制 之 下 , 就 忽 略 访 问 控 制<br />

if($this->_acl->has($resource)) {<br />

// 检 查 当 前 角 色 是 否 有 权 限 访 问 资 源<br />

if( ! $this->_acl->isAllowed($role, $resource) ) {<br />

// 不 能 访 问<br />

// 备 份 原 始 的 请 求 URI<br />

$session = new Zend_Session_Namespace('ACLSecurity');<br />

$session->originalRequestUri = $request->getRequestUri();<br />

// 覆 盖 分 派 器 将 会 使 用 的 控 制 器 和 操 作<br />

$request->setControllerName('index');<br />

$request->setActionName('login');<br />

}<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 84/111


高 级 应 用 :<br />

《PHPer》<br />

}<br />

}<br />

}<br />

// else { 可 以 访 问 , 正 常 分 派 }<br />

下 一 步 就 是 与 前 一 章 中 的 验 证 示 例 集 成 在 一 起 。 为 了 做 到 这 一 点 , 需 要 在 数 据 库<br />

users 表 中 添 加 一 个 名 为 role 的 列 , 并 将 role 列 的 值 设 为 member。 然 后 在<br />

IndexController.php 文 件 中 的 loginAction 中 找 到 以 下 代 码 。<br />

$this->getHelper('redirector')->goto('index','index');<br />

并 将 这 行 代 码 修 改 为 :<br />

代 码 片 段<br />

// 试 图 将 用 户 转 发 到 他 们 曾 试 图 访 问 的 地 方<br />

$session = new Zend_Session_Namespace('ACLSecurity');<br />

if(isset($session->originalRequestUri)) {<br />

$this ->getHelper('redirector')<br />

->gotoUrl($session->originalRequestUri);<br />

} else {<br />

$this->getHelper('redirector')->goto('index','index');<br />

}<br />

这 使 得 当 重 定 向 的 用 户 成 功 登 录 后 , 他 们 将 被 带 到 原 来 试 图 访 问 的 原 始 URL 上 。<br />

最 后 , 将 这 个 插 件 注 册 到 前 端 控 制 器 中 。<br />

$front->registerPlugin(new YourPrefix_Controller_Plugin_Security($acl));<br />

现 在 可 以 尝 试 访 问 /articles 控 制 器 了 。 应 该 会 被 转 送 到 /index/login 中 。 一 旦 成 功 登<br />

录 , 将 被 重 新 带 回 /articles 中 。 现 在 你 拥 有 了 一 个 基 本 的 ACL 和 验 证 集 成 的 插 件 解 决<br />

方 案 。<br />

6 使 用 两 步 视 图<br />

Zend_Layout 组 件 的 作 用 在 于 满 足 一 种 常 见 需 求 , 即 创 建 站 点 时 站 点 中 页 面 应 具<br />

有 相 似 的 外 观 。 这 一 组 件 通 常 被 称 为 站 点 级 模 板 、 两 步 视 图 或 者 布 局 。<br />

布 局 的 概 念 是 避 免 使 用 在 前 面 添 加 的 模 板 和 在 后 面 添 加 的 模 板 。 相 反 , 使 用<br />

Zend_View_ Helper_Placeholder 来 指 定 控 制 器 — 操 作 分 派 过 程 创 建 的 内 容 应 该 放 在 最<br />

终 输 出 结 果 中 的 位 置 。 这 允 许 你 使 用 一 个 布 局 文 件 来 表 达 最 终 页 面 的 结 构 , 在 同 一 文<br />

件 中 同 时 包 含 了 和 。<br />

6.1 创 建 一 个 主 布 局<br />

为 了 使 用 Zend_Layout 组 件 , 需 要 向 引 导 文 件 添 加 如 代 码 清 单 1-11 所 示 的 代 码 。<br />

代 码 清 单 1-11 引 导 Zend_Layout 组 件 ( 在 index.php 文 件 中 )<br />

代 码 片 段<br />

Zend_Layout::startMvc(<br />

array(<br />

'layoutPath' => APP_PATH . '/application/layouts/',<br />

'layout' => 'index'<br />

)<br />

);<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 85/111


高 级 应 用 :<br />

《PHPer》<br />

这 一 引 导 过 程 定 义 了 布 局 脚 本 文 件 所 在 的 位 置 以 及 默 认 布 局 的 名 称 。 在 这 个 例 子<br />

中 , 为 了 演 示 可 用 的 选 项 , 我 们 将 默 认 的 名 称 layout 重 写 成 了 index。<br />

下 一 步 , 创 建 如 代 码 清 单 1-12 所 示 的 布 局 文 件 index.phtml。<br />

代 码 清 单 1-12 主 布 局 文 件 (./application/layouts/index.phtml)<br />

代 码 片 段<br />

<br />

<br />

<br />

<br />

<br />

激 活 了 Zend_Layout 组 件 之 后 , 操 作 的 所 有 输 出 内 容 都 会 被 放 在<br />

Zend_Layout->content 占 位 符 中 。 如 代 码 清 单 1-12 所 示 , 这 一 占 位 符 可 以 通 过 布 局 辅<br />

助 类 ($this->layout()) 来 访 问 。<br />

在 控 制 器 和 操 作 层 面 , 可 以 通 过 在 init() 方 法 或 者 操 作 中 调 用 setLayout() 方 法 来 选<br />

择 可 替 换 的 布 局 。<br />

$this->_helper->layout()->setLayout('alternative');<br />

要 使 得 某 个 操 作 不 使 用 布 局 , 可 以 调 用 disableLayout() 方 法 。<br />

$this->_helper->layout()->disableLayout();<br />

6.2 使 用 占 位 符<br />

除 了 保 存 操 作 的 输 出 内 容 之 外 , 占 位 符 也 可 以 用 于 将 内 容 放 在 布 局 中 预 定 义 的 位<br />

置 上 。 一 个 常 见 的 用 法 就 是 在 菜 单 中 放 置 一 个 菜 单 项 , 但 却 在 视 图 脚 本 中 配 置 这 个 菜<br />

单 项 。<br />

要 创 建 一 个 具 有 菜 单 系 统 的 布 局 , 需 要 使 用 自 定 义 键 值 menu, 在 Zend_Layout 名<br />

称 下 定 义 一 个 占 位 符 。 代 码 清 单 1-13 演 示 了 如 何 创 建 一 个 基 本 的 布 局 模 板 。<br />

代 码 清 单 1-13 包 含 条 件 判 断 占 位 符 的 布 局 脚 本<br />

代 码 片 段<br />

<br />

<br />

<br />

<br />

<br />

<br />

当 希 望 将 一 个 菜 单 项 放 在 这 个 占 位 符 中 时 , 在 视 图 脚 本 场 景 中 , 你 只 需 捕 获 一 些<br />

内 容 即 可 , 如 代 码 清 单 1-14 所 示 。<br />

代 码 清 单 1-14 捕 获 输 出 到 占 位 符 中 的 内 容 ( 视 图 场 景 )<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 86/111


高 级 应 用 :<br />

《PHPer》<br />

代 码 片 段<br />

<br />

New Menu Item<br />

<br />

当 布 局 被 输 出 时 , 这 一 内 容 将 被 放 在 文 档 中 合 适 的 位 置 。 这 将 允 许 创 建 一 些 将 代<br />

码 注 入 到 文 档 不 同 部 分 的 高 级 视 图 效 果 。<br />

7 小 结<br />

在 本 文 中 , 你 学 习 了 关 于 Zend 框 架 的 内 部 操 作 以 及 如 何 创 建 模 块 、 模 型 库 、 插 件 、<br />

辅 助 类 以 及 布 局 等 。<br />

常 规 的 模 块 化 目 录 结 构 提 供 了 使 用 模 块 的 功 能 。 你 还 可 以 创 建 自 定 义 的 组 件 库 并<br />

将 其 添 加 到 引 导 文 件 中 , 以 便 框 架 可 以 自 动 加 载 你 的 类 。<br />

框 架 的 请 求 周 期 包 含 了 几 个 路 由 和 分 派 事 件 。 你 可 以 创 建 自 定 义 的 控 制 器 插 件 、<br />

操 作 辅 助 类 和 视 图 辅 助 类 。<br />

Zend_Layout 组 件 允 许 创 建 具 有 公 共 外 观 的 站 点 。<br />

如 果 您 还 要 继 续 学 习 Zend 框 架 , 可 以 阅 读 框 架 指 南 文 档 和 邮 件 列 表 存 档 。 如 果 对<br />

使 用 Zend 框 架 来 开 发 应 用 程 序 感 兴 趣 , 可 以 参 见 irc.freenode.net 上 的 #zftalk 频 道 , 或<br />

者 位 于 http://framework.zend.com 的 官 方 邮 件 列 表 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 87/111


安 全 优 化 :<br />

《PHPer》<br />

安 全 优 化<br />

Windows 安 全 ( 一 )<br />

机 械 工 业 出 版 社<br />

几 乎 在 很 短 的 时 间 里 , 人 们 对 安 全 的 态 度 发 生 了 巨 大 的 转 变 , 无 论 是 开 发 人 员 还<br />

是 终 端 用 户 。 几 年 前 , 大 多 数 计 算 机 都 是 未 联 网 的 设 备 , 计 算 机 安 全 问 题 的 主 要 来 源<br />

也 只 是 一 些 离 线 媒 介 , 例 如 软 盘 。 在 当 时 , 最 大 的 安 全 问 题 就 是 病 毒 。 现 在 , 随 着 网<br />

络 连 接 率 日 益 增 加 , 几 乎 所 有 计 算 机 都 可 以 被 远 程 攻 击 。<br />

在 一 些 老 的 操 作 系 统 中 , 例 如 Windows 95, 并 不 支 持 本 地 计 算 机 上 的 安 全 对 象 。<br />

Windows NT 的 出 现 为 用 户 带 来 了 符 合 C2 级 安 全 标 准 的 内 核 。 今 天 ,Windows 操 作 系<br />

统 的 客 户 端 版 本 ( 即 Windows XP 家 庭 版 和 Windows Vista 家 庭 版 ) 能 够 控 制 对 每 个<br />

对 象 的 访 问 , 因 此 发 生 拒 绝 访 问 故 障 (Access Denied Failure) 的 概 率 也 就 越 大 。 另 一<br />

种 推 动 力 是 来 自 安 全 社 区 , 他 们 在 运 行 进 程 时 通 常 使 用 最 低 的 用 户 权 限 。 这 样 可 以 将<br />

主 机 和 程 序 中 的 安 全 漏 洞 分 离 开 来 。 那 么 , 如 果 以 非 管 理 员 权 限 来 运 行 程 序 , 那 么 在<br />

实 际 情 况 中 会 有 多 大 的 可 行 性 ? 可 能 只 有 一 些 在 设 计 时 考 虑 了 安 全 因 素 的 程 序 才 能<br />

运 行 , 而 大 多 数 程 序 将 无 法 运 行 , 因 为 它 们 仍 然 需 要 访 问 一 些 只 有 管 理 员 才 可 以 访 问<br />

的 注 册 表 位 置 或 者 文 件 系 统 位 置 。<br />

对 象 安 全 性 是 开 发 一 流 软 件 的 基 础 要 素 。 本 章 将 介 绍 如 何 分 析 和 修 复 软 件 中 的 安<br />

全 问 题 。 本 文 将 重 点 介 绍 当 合 法 操 作 遇 到 一 系 列 故 障 时 所 应 采 取 的 步 骤 , 而 并 不 会 介<br />

绍 由 于 代 码 缺 陷 所 导 致 的 一 些 未 预 期 行 为 ( 例 如 缓 冲 区 溢 出 、 整 数 溢 出 等 ), 这 些 缺<br />

陷 通 常 会 被 病 毒 利 用 , 在 其 他 的 参 考 书 中 已 经 给 出 了 详 尽 的 介 绍 。 在 本 章 中 , 我 们 将<br />

讨 论 以 下 内 容 :<br />

• Windows 安 全 的 基 本 知 识 以 及 工 作 机 制 。 我 们 将 给 出 在 分 析 与 安 全 相 关 的 问<br />

题 时 需 要 具 备 的 基 础 知 识 。<br />

• 如 何 通 过 调 试 扩 展 功 能 来 分 析 各 种 安 全 组 件 。 本 节 将 介 绍 一 些 对 调 试 安 全 性<br />

问 题 来 说 非 常 重 要 的 扩 展 命 令 。<br />

• 如 何 将 一 些 现 有 的 技 术 与 本 书 给 出 的 信 息 结 合 起 来 , 以 解 决 由 于 未 预 期 的 安<br />

全 限 制 所 导 致 的 问 题 。<br />

1 Windows 安 全 概 述<br />

任 何 一 个 Windows 安 全 对 象 都 可 以 用 句 柄 来 表 示 , 在 这 些 安 全 对 象 中 包 含 了 一 些<br />

安 全 信 息 , 并 且 受 到 Windows 安 全 机 制 的 保 护 。Windows 安 全 模 型 使 用 了 三 个 安 全 概<br />

念 :<br />

• 自 主 访 问 控 制 列 表 (Discretionary Access Control List,DACL): 描 述 的<br />

是 哪 些 主 体 (Principal) 可 以 使 用 这 个 对 象 以 及 如 何 使 用 。<br />

• 用 户 的 标 识 : 也 称 为 主 体 。<br />

• 安 全 引 用 监 视 器 (Security Reference Monitor,SRM): 通 过 一 些 的 信 息 来<br />

限 制 对 它 所 保 护 的 对 象 进 行 访 问 。<br />

与 Windows 安 全 对 象 相 关 的 DACL 是 由 对 象 创 建 者 本 身 来 管 理 的 。DACL 是 另 一 个<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 88/111


安 全 优 化 :<br />

《PHPer》<br />

结 构 — 安 全 描 述 符 (Security Descriptor) 中 的 成 员 , 安 全 描 述 符 是 一 组 与 对 象 相<br />

关 的 信 息 , 保 存 在 安 全 的 存 储 位 置 中 。 每 当 一 个 新 的 主 体 访 问 对 象 时 , 都 会 从 这 个 安<br />

全 的 存 储 位 置 中 抽 取 出 对 象 的 安 全 描 述 符 。 例 如 , 文 件 的 安 全 描 述 符 是 保 存 在 NTFS<br />

文 件 系 统 中 , 注 册 表 项 的 安 全 描 述 符 是 保 存 在 注 册 表 中 , 而 内 核 对 象 的 安 全 描 述 符 则<br />

是 保 存 在 内 核 地 址 空 间 中 。<br />

Windows SRM 运 行 在 内 核 地 址 空 间 中 , 它 与 用 户 态 代 码 是 分 离 的 。 大 多 数 安 全 对<br />

象 都 是 由 内 核 组 件 创 建 的 , 内 核 组 件 通 过 地 址 的 独 立 性 来 保 护 与 用 户 态 组 件 相 关 的 安<br />

全 描 述 符 。 由 于 用 户 态 组 件 不 能 通 过 内 核 来 实 现 自 己 的 安 全 对 象 代 理 (Object Broker),<br />

因 此 Windows 中 的 一 些 组 件 是 通 过 类 似 于 Windows 安 全 机 制 的 思 想 来 实 现 定 制 的 安 全<br />

模 型 。<br />

定 制 的 安 全 对 象 代 理 必 须 增 强 对 象 的 访 问 机 制 。 换 句 话 说 , 在 设 计 安 全 对 象 代 理<br />

时 , 你 必 须 确 保 这 个 对 象 不 能 通 过 其 他 任 何 机 制 来 访 问 。 在 这 些 情 况 中 , 对 象 代 理 将<br />

扮 演 SRM 角 色 , 并 且 按 照 它 自 己 的 方 式 来 管 理 对 象 安 全 描 述 符 。 为 了 确 保 与 操 作 系 统<br />

保 持 兼 容 , 并 且 在 安 全 设 置 中 使 用 相 同 的 用 户 接 口 , 对 象 代 理 很 可 能 使 用 与 Windows<br />

SRM 一 样 的 数 据 结 构 。<br />

在 访 问 控 制 中 的 另 一 个 重 要 组 件 就 是 安 全 主 体 , 它 是 由 操 作 系 统 来 创 建 和 验 证 的 。<br />

安 全 主 体 保 存 在 访 问 令 牌 (Access Token) 中 。 这 个 访 问 令 牌 包 含 了 安 全 主 体 所 在 的<br />

用 户 组 、 一 组 由 操 作 系 统 赋 予 的 特 殊 权 限 , 以 及 由 系 统 其 他 组 件 使 用 的 一 些 信 息 。<br />

对 象 访 问 权 限 是 通 过 一 组 位 表 示 的 , 每 一 位 表 示 一 项 能 否 被 赋 予 某 个 主 体 的 权 限 ( 特<br />

定 于 对 象 的 属 性 )。<br />

下 面 将 介 绍 与 调 试 Windows 程 序 相 关 的 所 有 安 全 结 构 , 以 及 用 于 查 看 这 些 结 构 的<br />

各 种 方 法 。 熟 悉 这 些 概 念 的 读 者 可 以 跳 过 这 一 节 。 本 章 的 示 例 使 用 了 三 个 新 的 扩 展 命<br />

令 :!sd、!token 以 及 !sid, 这 三 个 命 令 是 在 调 试 器 默 认 加 载 的 扩 展 模 块 中 实 现 的 。<br />

本 章 将 使 用 07sample.exe 程 序 , 这 个 程 序 的 源 代 码 文 件 和 二 进 制 文 件 分 别 位 于 以 下<br />

文 件 夹 中 :<br />

源 代 码 文 件 :C:\AWD\Chapter7<br />

二 进 制 文 件 :C:\AWDBIN\WinXP.x86.chk\07sample.exe<br />

由 于 在 分 布 式 程 序 中 经 常 会 发 生 安 全 性 错 误 , 因 此 本 章 还 将 使 用 第 8 章 的 一 些 示<br />

例 , 包 括 一 个 客 户 端 程 序 08cli.exe, 一 个 包 含 代 理 存 根 (Proxy Stub) 的 动 态 库<br />

08comps.dll, 以 及 一 个 服 务 器 程 序 08comsrv.exe。 我 们 必 须 通 过 命 令 行 08comsrv.exe<br />

/RegServer 来 注 册 08comsrv.exe, 并 且 通 过 命 令 行 regsvr32 08comps.dll 来 注 册<br />

08comps.dll。 这 些 程 序 的 源 代 码 文 件 和 二 进 制 文 件 位 于 以 下 文 件 夹 中 :<br />

源 代 码 文 件 :C:\AWD\Chapter8<br />

二 进 制 文 件 :C:\AWDBIN\WinXP.x86.chk\08cli.exe、08comps.dll 以 及<br />

08comsrv.exe<br />

1.1 安 全 标 识 符<br />

安 全 标 识 符 , 也 被 称 之 为 SID, 是 在 Windows 安 全 机 制 中 使 用 的 基 本 概 念 之 一 。<br />

SID 表 示 一 个 主 体 或 者 一 个 属 性 , 并 且 这 个 主 体 或 者 属 性 在 SID 所 在 的 操 作 系 统 中 是<br />

惟 一 的 。SID 通 过 一 个 简 单 的 结 构 来 表 示 , 这 个 结 构 定 义 在 头 文 件 winnt.h 中 , 如 清 单<br />

1 所 示 。<br />

清 单 1 SID 结 构 定 义<br />

typedef struct _SID_IDENTIFIER_AUTHORITY {<br />

BYTE Value[6];<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 89/111


安 全 优 化 :<br />

《PHPer》<br />

} SID_IDENTIFIER_AUTHORITY;<br />

typedef struct _SID {<br />

BYTE Revision;<br />

BYTE SubAuthorityCount;<br />

SID_IDENTIFIER_AUTHORITY IdentifierAuthority;<br />

DWORD SubAuthority[1];<br />

} SID;<br />

SID 结 构 是 变 长 的 , 其 中 包 含 了 变 长 数 量 的 SubAuthority 项 , 可 以 表 示 任 何 主 体 。<br />

SID 是 根 据 IdentifierAuthority 来 分 组 的 。SID 的 内 存 布 局 是 非 常 简 单 的 , 计 算 机<br />

很 容 易 理 解 , 但 对 于 人 来 说 却 是 很 难 理 解 的 。 在 一 些 技 术 文 档 中 ,SID 被 表 示 为 一 个<br />

字 符 串 , 形 如 S-R-I-S-S-S-⋯-S, 其 中 R 表 示 修 订 级 别 (Revison Level), I 表 示 控<br />

制 这 个 SID 的 授 权 (Authority), S 是 由 这 个 授 权 所 管 理 的 子 授 权 (Subauthority)。<br />

Windows SID 的 Revision 域 被 设 置 为 1, 并 且 可 以 拥 有 多 达 6 个 子 授 权 。 在 Windows<br />

中 ,IdentifierAuthority 等 于 5:{0,0,0,0,0,5}。 例 如 , 本 地 系 统 (Local System)<br />

在 内 存 中 被 表 示 为 一 系 列 的 字 节 ,S-1-5-18, 如 果 下 面 的 清 单 所 示 ( 这 些 字 节 被 分 散<br />

在 多 行 , 每 行 对 应 一 个 SID 组 件 )<br />

0:000> db 000840c8 Lc<br />

000840c8 01<br />

01<br />

00 00 00 00 00 05-<br />

12 00 00 00 ............<br />

第 一 行 表 示 SID 的 修 订 号 , 第 二 行 是 SID 中 子 授 权 的 数 量 , 接 下 来 是 Windows 授 权 标<br />

识 符 , 最 后 一 行<br />

是 子 授 权 的 值 。 通 过 扩 展 命 令 !sid 可 以 将 这 个 数 据 结 构 输 出 为 形 如 “S-⋯” 的 字 符 串<br />

格 式 , 如 下 所 示 :<br />

0:000> !sid 000840c8<br />

SID is: S-1-5-18<br />

1.2 访 问 控 制 列 表<br />

在 调 试 Windows 安 全 性 问 题 时 , 另 一 个 重 要 的 结 构 就 是 访 问 控 制 项 (Access<br />

Control Entry,ACE)。 ACE 表 示 , 在 由 这 个 ACE 保 护 的 对 象 上 , 有 哪 些 权 限 可 以 被 赋<br />

予 由 SID 表 示 的 主 体 。 一 组 有 序 的 ACE 就 构 成 了 一 个 访 问 控 制 列 表 (ACL), 它 将 控 制<br />

所 有 主 体 在 它 所 保 护 对 象 上 的 权 限 。<br />

从 结 构 上 来 看 , 每 个 ACE 都 有 一 个 ACE_HEADER, 随 后 是 特 定 于 ACE 的 数 据 , 这 是<br />

实 现 对 象 多 态 性 的 一 种 古 老 的 “C” 技 术 。 在 MSDN 以 及 winnt.h 头 文 件 中 对 所 有 的 ACE<br />

类 型 都 给 出 了 非 常 详 尽 的 描 述 。 本 节 将 只 介 绍 ACCESS_ALLOWED_ACE, 因 为 这 是 最 常 使<br />

用 的 结 构 。 其 他 类 型 的 ACE 都 是 类 似 的 , 都 可 以 在 头 文 件 winnt.h 中 找 到 。ACE 结 构<br />

的 头 部 如 下 所 示 :<br />

typedef struct _ACE_HEADER {<br />

BYTE AceType;<br />

BYTE AceFlags;<br />

WORD AceSize;<br />

} ACE_HEADER;<br />

typedef struct _ACCESS_ALLOWED_ACE {<br />

ACE_HEADER Header;<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 90/111


安 全 优 化 :<br />

《PHPer》<br />

ACCESS_MASK Mask;<br />

DWORD SidStart;<br />

} ACCESS_ALLOWED_ACE;<br />

AceType 域 表 示 在 ACE_HEADER 后 面 的 结 构 类 型 。 通 常 的 做 法 是 , 根 据 AceType 域<br />

中 的 值 将 ACE_HEADER 结 构 转 换 为 具 体 的 ACE 类 型 , 例 如 ACCESS_ALLOWED_ACE。Mask<br />

域 是 一 个 DWORD 类 型 的 值 , 其 中 包 含 了 这 个 ACE 允 许 的 所 有 权 限 。 表 1 给 出 了 每 一 位<br />

的 含 义 。<br />

表 1 访 问 掩 码 中 所 有 位 的 含 义<br />

在 头 文 件 winnt.h 中 定 义 了 ACL 结 构 , 如 下 所 示 :<br />

typedef struct _ACL {<br />

BYTE AclRevision;<br />

BYTE Sbz1;<br />

WORD AclSize;<br />

WORD AceCount;<br />

WORD Sbz2;<br />

} ACL;<br />

在 ACL 中 , 位 于 这 个 结 构 之 后 的 是 一 组 ACE( 数 量 为 AceCount), 并 且 使 用 了 一 块<br />

大 小 为 AclSize 字 节 的 连 续 内 存 。 当 前 , 在 Windows 中 使 用 的 所 有 ACL 的 Revision<br />

域 都 等 于 2。 通 过 扩 展 命 令 !acl 很 容 易 将 ACL 解 析 出 来 , 如 下 所 示 :<br />

0:000> !acl 000840ac<br />

ACL is:<br />

ACL is: -> AclRevision :0x2<br />

ACL is: ->Sbz1 :0x0<br />

ACL is: -> AclSize :0x1c<br />

ACL is: -> AceCount :0x1<br />

ACL is: ->Sbz2 : 0x0<br />

ACL is: ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE<br />

ACL is: ->Ace[0]: ->AceFlags: 0x0<br />

ACL is: ->Ace[0]: ->AceSize: 0x14<br />

ACL is: ->Ace[0]: ->Mask : 0x00120089<br />

ACL is: ->Ace[0]: ->SID: S-1-1-0<br />

1.3 安 全 描 述 符<br />

到 目 前 为 止 , 我 们 看 到 的 所 有 结 构 都 包 含 在 安 全 描 述 符 (Security Descriptor,<br />

SD) 结 构 中 , 这 个 结 构 是 定 义 在 头 文 件 winnt.h 中 , 如 下 所 示 :<br />

typedef WORD SECURITY_DESCRIPTOR_CONTROL;<br />

typedef struct _SECURITY_DESCRIPTOR {<br />

BYTE Revision;<br />

BYTE Sbz1;<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 91/111


安 全 优 化 :<br />

《PHPer》<br />

SECURITY_DESCRIPTOR_CONTROL Control ;<br />

PSID Owner;<br />

PSID Group;<br />

PACL Sacl;<br />

PACL Dacl;<br />

} SECURITY_DESCRIPTOR;<br />

在 Windows 操 作 系 统 中 Revision 域 被 设 置 为 1。Control 域 表 示 安 全 描 述 符 的 内<br />

容 , 例 如 表 示 在 安 全 描 述 符 中 包 含 的 是 一 个 DACL( 当 设 置 了 SE_DACL_PRESENT 标 志 时 )<br />

还 是 SACL 等 。 如 果 在 Control 域 中 设 置 了 SE_SELF_RELATIVE 位 , 那 么 安 全 描 述 符 中<br />

的 所 有 指 针 都 应 该 被 视 作 为 相 对 于 安 全 描 述 符 基 地 址 的 偏 移 ; 否 则 , 这 些 地 址 都 是 绝<br />

对 地 址 。<br />

为 了 理 解 这 些 结 构 在 内 存 中 的 布 局 , 我 们 将 使 用 07sample.exe, 并 且 选 择 选 项 ‘0’,<br />

这 个 选 项 表 示 执 行 与 安 全 描 述 符 相 关 的 函 数 。 清 单 7-2 的 源 代 码 将 通 过 一 个 基 于 安 全<br />

描 述 符 定 义 语 言 (Security Descriptor Definition Language,SDDL) 的 字 符 串 来<br />

创 建 安 全 描 述 符 。 我 们 可 以 通 过 advapi32!AccessCheck 来 获 得 由 这 个 安 全 描 述 符 保<br />

护 的 对 象 的 用 户 访 问 权 限 。<br />

清 单 2 执 行 AccessCheck 函 数 的 示 例 代 码<br />

代 码 片 段<br />

void Sample0()<br />

{<br />

LPWSTR stringSD = L"O:SYG:BAD:(A;;FR;;;S-1-1-0)";<br />

PSECURITY_DESCRIPTOR sd = NULL;<br />

...<br />

if (FALSE == ConvertStringSecurityDescriptorToSecurityDescriptor(<br />

stringSD, SDDL_REVISION_1, &sd, NULL))<br />

{ ... }<br />

ImpersonateSelf(SecurityIdentification);<br />

STOP_ON_DEBUGGER;<br />

HANDLE hToken=NULL;<br />

if (!OpenThreadToken(<br />

GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))<br />

{ ... }<br />

RevertToSelf();<br />

...<br />

if (FALSE == AccessCheck(<br />

sd,<br />

hToken,<br />

MAXIMUM_ALLOWED,<br />

&rightsMapping,<br />

privileges,&privilegesSize ,<br />

&grantedAccess,<br />

&grantedAccessStatus))<br />

{<br />

TRACE(L"AccessCheck failed ");<br />

}<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 92/111


安 全 优 化 :<br />

《PHPer》<br />

...<br />

}<br />

下 面 是 安 全 描 述 符 的 来 源 介 绍 。 在 私 有 符 号 库 中 通 常 会 包 含 安 全 描 述 符 的 地 址 。<br />

当 不 存 在 私 有 符 号 时 , 我 们 可 以 发 现 advapi32!AccessCheck 的 第 一 个 参 数 就 是 用 于<br />

访 问 检 查 的 安 全 描 述 符 。 下 一 节 将 解 释 栈 中 参 数 的 含 义 。 这 个 函 数 的 声 明 如 下 所 示 :<br />

WINADVAPI BOOL WINAPI AccessCheck (<br />

IN PSECURITY_DESCRIPTOR pSecurityDescriptor,<br />

IN HANDLE ClientToken,<br />

IN DWORD DesiredAccess,<br />

IN PGENERIC_MAPPING GenericMapping,<br />

OUT PPRIVILEGE_SET PrivilegeSet,<br />

IN LPDWORD PrivilegeSetLength,<br />

OUT LPDWORD GrantedAccess,<br />

OUT LPBOOL AccessStatus );<br />

我 们 在 用 户 态 调 试 器 ( 例 如 windbg.exe) 下 启 动 07sample.exe, 并 且 在<br />

AccessCheck 地 址 处 设 置 一 个 断 点 。 然 后 , 以 字 节 形 式 将 安 全 描 述 符 显 示 出 来 , 如 清<br />

单 3 所 示 。<br />

清 单 3 安 全 描 述 符 的 二 进 制 表 示<br />

0:000> k2<br />

ChildEBP RetAddr<br />

0006fe9c 0100204e ADVAPI32!AccessCheck<br />

0006ff00 01001f33 07sample!Sample0+0x10e<br />

0:000> dc @esp L4<br />

0006fea0 0100204e 00084098 000007bc 02000000 N ...@..........<br />

0:000> db 00084098 L4c<br />

00084098 01 00 04 80 30 00 00 00-3c 00 00 00 00 00 00 00 ....0... !sd 00084098<br />

->Revision : 0x1<br />

->Sbz1 : 0x0<br />

->Control : 0x8004<br />

SE_DACL_PRESENT<br />

SE_SELF_RELATIVE<br />

->Owner : S-1-5-18<br />

->Group : S-1-5-32-544<br />

->Dacl :<br />

->Dacl : ->AclRevision: 0x2<br />

->Dacl : ->Sbz1 : 0x0<br />

->Dacl : ->AclSize : 0x1c<br />

->Dacl : ->AceCount : 0x1<br />

->Dacl : ->Sbz2 : 0x0<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 93/111


安 全 优 化 :<br />

《PHPer》<br />

->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE<br />

->Dacl : ->Ace[0]: ->AceFlags: 0x0<br />

->Dacl : ->Ace[0]: ->AceSize: 0x14<br />

->Dacl : ->Ace[0]: ->Mask : 0x00120089<br />

->Dacl : ->Ace[0]: ->SID: S-1-1-0<br />

->Sacl : is NULL<br />

在 前 面 中 介 绍 的 SID 和 ACL 都 属 于 安 全 描 述 符 的 一 部 分 。 这 些 结 构 的 地 址 都 是 基<br />

于 安 全 描 述 符 的 相 对 地 址 , 即 使 扩 展 命 令 由 于 符 号 不 匹 配 而 无 法 正 常 工 作 时 , 也 可 以<br />

很 容 易 地 将 这 些 信 息 抽 取 出 来 。<br />

1.4 访 问 令 牌<br />

只 有 当 主 体 请 求 访 问 由 这 个 安 全 描 述 符 保 护 的 安 全 对 象 时 , 安 全 描 述 符 才 是 有 用<br />

的 。 主 体 的 标 识 , 以 及 被 赋 予 的 权 限 , 都 被 封 装 到 一 个 内 核 结 构 中 , 这 个 结 构 叫 做 访<br />

问 令 牌 (Access Token)。 用 户 态 的 组 件 可 以 通 过 句 柄 来 使 用 访 问 令 牌 。 我 们 可 以 通<br />

过 扩 展 命 令 !token 来 查 看 这 些 访 问 令 牌 , 这 个 命 令 的 参 数 既 可 以 是 访 问 令 牌 的 地 址<br />

( 例 如 在 内 核 态 调 试 器 中 ), 也 可 以 是 一 个 指 向 令 牌 的 句 柄 ( 例 如 在 用 户 态 调 试 器 中<br />

使 用 )。 如 果 在 使 用 这 个 扩 展 命 令 时 没 有 指 定 参 数 , 那 么 当 存 在 线 程 模 拟 访 问 令 牌<br />

(Thread Impersonation Access Token) 时 , 它 将 显 示 这 个 令 牌 ; 否 则 , 它 将 显 示<br />

进 程 令 牌 。<br />

在 清 单 5 中 , 我 们 使 用 了 在 清 单 7-3 中 传 递 给 advapi32!AccessCheck 函 数 的 令 牌 。<br />

由 于 使 用 了 -n 选 项 , 因 此 这 个 扩 展 命 令 将 解 析 与 每 个 SID 相 关 的 名 字 ( 显 示 在 SID<br />

后 面 的 括 号 中 )。<br />

清 单 5 在 调 试 器 中 通 过 扩 展 命 令 !token 来 显 示 令 牌<br />

0:000> * 显 示 句 柄 为 0x7bc 的 令 牌 的 信 息<br />

0:000> !token 7bc -n<br />

TS Session ID: 0<br />

User: S-1-5-21-1060284298-2111687655-1957994488-1003 (User:<br />

XP-SP2\TestAdmin)<br />

Groups:<br />

00 S-1-5-21-1060284298-2111687655-1957994488-513 (Group: XP-SP2\None)<br />

Attributes - Mandatory Default Enabled<br />

01 S-1-1-0 (Well Known Group: localhost\Everyone)<br />

Attributes - Mandatory Default Enabled<br />

02 S-1-5-32-544 (Alias: BUILTIN\Administrators)<br />

Attributes - Mandatory Default Enabled Owner<br />

03 S-1-5-32-545 (Alias: BUILTIN\Users)<br />

Attributes - Mandatory Default Enabled<br />

04 S-1-5-4 (Well Known Group: NT AUTHORITY\INTERACTIVE)<br />

Attributes - Mandatory Default Enabled<br />

05 S-1-5-11 (Well Known Group: NT AUTHORITY\Authenticated Users)<br />

Attributes - Mandatory Default Enabled<br />

06 S-1-5-5-0-35778 (no name mapped)<br />

Attributes - Mandatory Default Enabled LogonId<br />

07 S-1-2-0 (Well Known Group: localhost\LOCAL)<br />

Attributes - Mandatory Default Enabled<br />

Primary Group: S-1-5-21-1060284298-2111687655-1957994488-513 (Group:<br />

XP-SP2\None)<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 94/111


安 全 优 化 :<br />

《PHPer》<br />

Privs:<br />

00 0x000000017 SeChangeNotifyPrivilege Attributes - Enabled Default<br />

01 0x000000008 SeSecurityPrivilege Attributes -<br />

...<br />

17 0x000000009 SeTakeOwnershipPrivilege Attributes -<br />

18 0x00000001e SeCreateGlobalPrivilege Attributes - Enabled Default<br />

19 0x00000001d SeImpersonatePrivilege Attributes - Enabled Default<br />

Auth ID: 0:1c3a8<br />

Impersonation Level: Identification<br />

TokenType: Impersonation<br />

仔 细 地 观 察 这 个 令 牌 中 的 所 有 SID, 我 们 可 以 将 它 们 分 为 安 全 组 主 体 (Security<br />

Group Principal)、 用 户 主 体 (User Principal) 以 及 标 识 , 例 如 LogonId。SID 概<br />

念 非 常 灵 活 , 因 为 它 只 是 一 个 用 来 表 示 不 同 实 体 的 惟 一 标 识 , 例 如 在 表 2 中 给 出 了 一<br />

些 标 识 。<br />

表 2 SID 类 型 及 示 例<br />

有 些 SID 被 用 作 为 属 性 或 者 组 的 成 员 , 几 乎 在 任 何 地 方 都 可 以 看 到 这 些 SID, 因<br />

此 它 们 也 叫 做 已 知 SID(Well-Known SID)。 表 3 包 含 了 一 组 最 为 常 见 的 SID。 作 为 权<br />

威 的 信 息 来 源 , MSDN 包 含 了 一 组 在 Windows 操 作 系 统 中 使 用 已 知 SID。<br />

表 3 已 知 SID<br />

这 个 扩 展 命 令 将 显 示 一 组 SID, 分 别 表 示 令 牌 主 体 的 标 识 以 及 这 个 主 体 所 属 的 安<br />

全 组 。 之 后 , 扩 展 命 令 还 将 显 示 一 组 赋 予 给 用 户 的 权 限 , 其 中 一 些 权 限 已 经 被 启 用 了 。<br />

每 当 用 户 登 录 系 统 时 都 将 建 立 这 个 令 牌 信 息 , 并 且 在 登 录 会 话 期 间 将 保 持 不 变 。 这 些<br />

权 限 可 以 通 过 程 序 来 启 用 或 者 禁 止 , 也 可 以 从 令 牌 中 删 除 , 但 却 不 能 增 加 到 令 牌 中 。<br />

同 一 个 主 体 在 不 同 的 系 统 上 进 行 认 证 时 将 获 得 不 同 的 令 牌 信 息 , 组 成 员 属 性 , 或 者 被<br />

赋 予 的 权 限 。<br />

我 们 可 以 通 过 比 喻 的 方 式 来 说 明 这 些 概 念 之 间 的 关 系 。 访 问 令 牌 好 比 是 旅 行 者 ( 也<br />

就 是 主 体 ) 的 护 照 , 用 来 在 不 同 的 国 界 上 标 识 他 们 自 己 。 安 全 描 述 符 表 示 移 民 法 , 由<br />

入 境 国 的 移 民 局 官 员 使 用 , 根 据 申 请 人 的 来 源 国 描 述 旅 行 者 的 权 力 和 要 求 。 在 护 照 中<br />

的 所 有 信 息 , 例 如 来 源 国 或 者 从 不 同 领 事 馆 中 获 得 的 签 证 , 可 以 被 比 作 不 同 的 令 牌 组<br />

成 员 关 系 和 权 力 。 移 民 局 , 相 当 于 执 行 访 问 检 查 的 代 码 , 将 信 任 护 照 的 颁 发 者 ( 在 这<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 95/111


安 全 优 化 :<br />

《PHPer》<br />

里 相 当 于 操 作 系 统 ) 并 且 确 信 护 照 不 是 伪 造 的 ( 这 在 真 实 世 界 中 很 难 实 现 )。 根 据 移<br />

民 法 ( 安 全 描 述 符 ), 旅 行 者 将 被 允 许 或 者 拒 绝 进 入 入 境 国 ( 访 问 对 象 )。<br />

在 现 实 生 活 中 , 任 何 一 个 国 家 都 会 有 自 己 的 移 民 政 策 , 这 就 好 比 软 件 至 少 都 是 安<br />

全 的 ; 每 个 对 象 都 被 一 个 安 全 描 述 符 保 护 起 来 。 为 了 在 Windows 系 统 中 实 现 同 样 级 别<br />

的 信 任 , 访 问 令 牌 是 通 过 可 信 计 算 基 (Trusted Computing Base) 组 件 来 管 理 的 , 可<br />

信 计 算 基 也 称 为 TCB。 在 TCB 中 运 行 的 每 个 组 件 对 于 操 作 系 统 以 及 安 全 系 统 中 的 每 个<br />

用 户 来 说 都 是 可 信 的 。<br />

本 文 的 剩 余 内 容 将 使 用 前 面 介 绍 的 信 息 来 分 析 或 者 解 决 各 种 与 安 全 性 相 关 的 问 题 。<br />

2 安 全 信 息 来 源<br />

为 了 能 够 在 不 同 的 安 全 领 域 工 作 , 工 程 师 们 需 要 知 道 在 什 么 位 置 查 找 安 全 信 息 以<br />

及 所 找 到 的 安 全 信 息 应 该 是 什 么 。<br />

2.1 访 问 令 牌<br />

访 问 令 牌 保 存 在 什 么 地 方 , 以 及 如 何 找 到 它 们 ?Windows 操 作 系 统 为 系 统 中 的 每<br />

个 进 程 都 创 建 了 一 个 主 访 问 令 牌 (Primary Access Token)。 这 个 令 牌 表 示 创 建 这 个<br />

进 程 的 主 体 , 并 在 默 认 情 况 下 将 被 用 于 所 有 的 对 象 访 问 。 主 访 问 令 牌 的 地 址 包 含 在 每<br />

个 进 程 的 nt!PROCESS 结 构 中 。 在 用 户 态 调 试 器 和 内 核 态 调 试 器 中 , 可 以 通 过 扩 展 命<br />

令 !token 来 显 示 进 程 的 访 问 令 牌 。<br />

在 用 户 态 调 试 器 中 , 如 果 当 前 的 线 程 不 是 处 于 模 拟 状 态 , 那 么 扩 展 命 令 !token 将<br />

自 动 显 示 主 访 问 令 牌 。 在 内 核 态 调 试 器 中 , 主 访 问 令 牌 地 址 是 进 程 基 本 信 息 的 一 部<br />

分 , 可 以 通 过 扩 展 命 令 !process 来 显 示 进 程 的 基 本 信 息 , 如 清 单 7-6 所 示 。 这 个 清<br />

单 假 设 示 例 进 程 正 在 系 统 中 运 行 。<br />

清 单 7-6 获 得 进 程 访 问 令 牌<br />

kd> * 选 项 1 将 显 示 进 程 的 基 本 信 息 ( 例 如 令 牌 等 )<br />

kd> !process 0 1 07sample.exe<br />

PROCESS 81136930 SessionId: 0 Cid: 045c Peb: 7ffd8000 ParentCid: 030c<br />

DirBase: 0ae64000 ObjectTable: e13e5d38 HandleCount: 18.<br />

Image: 07sample.exe<br />

VadRoot 811eaa90 Vads 24 Clone 0 Private 50. Modified 0. Locked 0.<br />

DeviceMap e164c948<br />

Token e1424030<br />

ElapsedTime 00:46:16.327<br />

...<br />

kd> *Token field contains the address of the primary access token<br />

在 客 户 端 / 服 务 器 ( C l i e n t - S e r v e r ) 程 序 中 ,Wi n d o w s 操<br />

作 系 统 非 常 依 赖 身 份 模 拟 (Impersonation) 机 制 。 身 份 模 拟 是 一 种 非 常 灵 活 的 机 制 ,<br />

在 这 种 机 制 中 , 线 程 可 以 使 用 一 个 不 同 于 主 访 问 令 牌 的 其 他 访 问 令 牌 来 访 问 对 象 。 在<br />

nt!ETHREAD 结 构 表 示 线 程 对 象 中 , 包 含 一 个 指 向 模 拟 访 问 令 牌 的 引 用 。 当 线 程 处 于 模<br />

拟 状 态 时 , 通 过 扩 展 命 令 !thread 可 以 显 示 模 拟 令 牌 和 模 拟 级 别 等 信 息 。 清 单 7 在<br />

ImpersonateSelf 函 数 之 后 立 即 使 用 了 07sample.exe 的 主 线 程 。<br />

清 单 7 显 示 线 程 模 拟 令 牌<br />

在 内 核 态 调 试 器 中<br />

kd> * 显 示 由 内 核 线 程 对 象 表 示 的 线 程<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 96/111


安 全 优 化 :<br />

《PHPer》<br />

kd> !thread ffad3020<br />

THREAD ffad3020 Cid 045c.03f0 Teb: 7ffdf000 Win32Thread: 00000000<br />

RUNNING on<br />

processor 0<br />

Impersonation token:e1424568 (Level Identification)<br />

...<br />

kd> * 在 Token 域 中 包 含 了 模 拟 令 牌 的 地 址 在 用 户 态 调 试 器 中<br />

0:000> !token –n<br />

TS Session ID: 0<br />

User: S-1-5-21-1060284298-2111687655-1957994488-1003 (User:<br />

XP-SP1\TestAdmin)<br />

...<br />

当 线 程 没 有 处 于 模 拟 状 态 时 , 清 单 8 的 转 储 信 息 将 给 出 模 拟 状 态 。 系 统 中 的 所 有<br />

线 程 在 起 始 时 都 是 处 于 这 种 状 态 , 而 并 不 考 虑 这 些 线 程 的 父 线 程 是 否 处 于 模 拟 状 态 。<br />

清 单 8 显 示 线 程 没 有 处 于 模 拟 状 态<br />

在 内 核 态 调 试 器 中<br />

kd> !thread ffad3020<br />

THREAD ffad3020 Cid 045c.03f0 Teb: 7ffdf000 Win32Thread: 00000000<br />

RUNNING on<br />

processor 0<br />

Not impersonating<br />

...<br />

kd> * 没 有 Token 域 。 表 示 线 程 没 有 处 于 模 拟 状 态<br />

在 用 户 态 调 试 器 中<br />

214 第 二 部 分 调 试 实 践<br />

0:000> !token<br />

Thread is not impersonating.Using process token<br />

...<br />

最 后 , 在 许 多 创 建 令 牌 或 者 返 回 令 牌 句 柄 的 函 数 中 都 可 以 获 得 令 牌 。 在 获 得 了 令<br />

牌 的 句 柄 值 后 , 无 论 是 从 函 数 中 返 回 的 还 是 通 过 其 他 方 法 获 得 的 , 都 可 以 查 看 这 些 访<br />

问 令 牌 , 如 清 单 5 所 示 。<br />

当 线 程 模 拟 访 问 令 牌 时 , 每 个 系 统 函 数 都 将 使 用 这 个 标 识 来 执 行 必 要 的 访 问 检 查 。<br />

如 果 在 线 程 中 没 有 进 行 模 拟 , 那 么 每 次 访 问 检 查 中 将 使 用 进 程 访 问 令 牌 , 不 过 有 一 个<br />

值 得 注 意 的 例 外 情 况 。 在 advapi32!OpenThreadToken 中 , 开 发 人 员 可 以 通 过 参 数<br />

OpenAsSelf 来 选 择 是 使 用 主 访 问 令 牌 还 是 使 用 模 拟 访 问 令 牌 。 然 而 , 我 们 认 为 任 何 访<br />

问 令 牌 对 于 它 所 在 的 进 程 来 说 都 是 可 访 问 的 。<br />

用 户 态 程 序 可 以 通 过 调 用 advapi32!OpenThreadToken 或 者<br />

advapi32!OpenProcessToken 来 获 得 在 安 全 引 用 监 视 器 (Security Reference Monitor)<br />

中 使 用 的 访 问 令 牌 。 用 户 态 扩 展 模 块 exts.dll 在 实 现 扩 展 命 令 !token 时 也 使 用 了 相<br />

同 的 函 数 。 如 果 在 用 户 态 调 试 器 下 扩 展 命 令 !token 没 有 显 示 某 个 线 程 的 模 拟 状 态 , 那<br />

么 要 对 这 个 输 出 结 果 持 怀 疑 态 度 。 当 这 个 扩 展 命 令 无 法 获 得 身 份 模 拟 信 息 时 , 将 是 会<br />

使 用 主 令 牌 , 我 们 在 随 后 的 章 节 中 将 进 行 介 绍 。<br />

2.2 安 全 描 述 符<br />

安 全 描 述 符 保 存 在 什 么 地 方 ? 我 们 知 道 所 有 的 对 象 都 是 由 存 储 在 特 定 位 置 上 的 安<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 97/111


安 全 优 化 :<br />

《PHPer》<br />

全 描 述 符 来 保 护 的 。 所 有 的 内 核 对 象 都 包 含 了 一 个 相 同 的 头 结 构 , 这 个 结 构 位 于 对 象<br />

内 存 地 址 的 起 始 位 置 上 。 头 结 构 _OBJECT_HEADER 包 含 了 一 个 指 针 指 向 保 护 这 个 对 象 的<br />

安 全 描 述 符 , 此 外 还 包 含 了 引 用 计 数 和 对 象 的 类 型 。 在 清 单 9 中 , 我 们 再 次 使 用 了<br />

07sample.exe。 我 们 首 先 获 得 进 程 对 象 的 对 象 头 , 在 对 象 头 中 包 含 了 一 个 指 针 指 向 保<br />

护 这 个 对 象 的 安 全 描 述 符 。<br />

清 单 9 从 内 核 对 象 中 获 得 对 象 头<br />

kd> !process 0 0 07sample.exe<br />

PROCESS ffbbc818 SessionId: 0 Cid: 01c4 Peb: 7ffde000 ParentCid: 00ac<br />

DirBase: 0232e000 ObjectTable: e1112e10 HandleCount: 8.<br />

Image: 07sample.exe<br />

kd> !object ffbbc818<br />

Object: ffbbc818 Type: (812ee900) Process<br />

ObjectHeader: ffbbc800<br />

HandleCount: 2 PointerCount: 7<br />

kd> dt _OBJECT_HEADER ffbbc800<br />

+0x000 PointerCount : 7<br />

+0x004 HandleCount : 2<br />

+0x004 NextToFree : 0x00000002<br />

+0x008 Type : 0x812ee900 _OBJECT_TYPE<br />

+0x00c NameInfoOffset : 0 ‘’<br />

+0x00d HandleInfoOffset : 0 ‘’<br />

+0x00e QuotaInfoOffset : 0 ‘’<br />

+0x00f Flags : 0x20 ‘ ‘<br />

+0x010 ObjectCreateInfo : 0x812ca8e8 _OBJECT_CREATE_INFORMATION<br />

+0x010 QuotaBlockCharged : 0x812ca8e8<br />

+0x014 SecurityDescriptor : 0xe198bb92<br />

+0x018 Body : _QUAD<br />

在 对 象 头 中 包 含 了 一 个 指 向 对 象 安 全 描 述 符 的 伪 指 针 。 这 个 伪 指 针 使 用 了 后 三 位<br />

来 存 储 与 安 全 描 述 符 地 址 无 关 的 状 态 信 息 。 这 是 可 能 的 , 因 为 在 安 全 描 述 符 中 使 用 了<br />

内 存 对 齐 。 在 屏 蔽 了 一 些 不 重 要 的 位 后 , 可 以 通 过 扩 展 命 令 !sd 来 显 示 包 含 有 效 安 全<br />

描 述 符 的 地 址 , 如 清 单 10 所 示 。<br />

清 单 10 获 得 内 核 对 象 的 安 全 描 述 符<br />

kd> !sd 0xe198bb92 &0xFFFFFFF8<br />

->Revision : 0x1<br />

->Sbz1 : 0x0<br />

->Control : 0x8004<br />

SE_DACL_PRESENT<br />

SE_SELF_RELATIVE<br />

->Owner : S-1-5-21-1060284298-2111687655-1957994488-1003<br />

->Group : S-1-5-21-1060284298-2111687655-1957994488-513<br />

->Dacl :<br />

->Dacl : ->AclRevision : 0x2<br />

->Dacl : ->Sbz1 : 0x0<br />

->Dacl : ->AclSize : 0x40<br />

->Dacl : ->AceCount : 0x2<br />

->Dacl : ->Sbz2 : 0x0<br />

->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE<br />

->Dacl : ->Ace[0]: ->AceFlags: 0x0<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 98/111


安 全 优 化 :<br />

《PHPer》<br />

->Dacl : ->Ace[0]: ->AceSize: 0x24<br />

->Dacl : ->Ace[0]: ->Mask : 0x001f0fff<br />

->Dacl : ->Ace[0]: ->SID: S-1-5-21-1060284298-2111687655-1957994488- 1003<br />

->Dacl : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE<br />

->Dacl : ->Ace[1]: ->AceFlags: 0x0<br />

->Dacl : ->Ace[1]: ->AceSize: 0x14<br />

->Dacl : ->Ace[1]: ->Mask : 0x001f0fff<br />

->Dacl : ->Ace[1]: ->SID: S-1-5-18<br />

->Sacl : is NULL<br />

由 于 安 全 描 述 符 的 地 址 刚 好 是 在 对 象 地 址 之 后 , 为 了 简 化 获 得 对 象 安 全 描 述 符 的<br />

操 作 , 可 以 将 获 取 安 全 描 述 符 地 址 的 所 有 步 骤 都 放 在 一 行 中 , 如 下 所 示 :<br />

!sd poi(-4) & FFFFFFF8<br />

在 内 核 内 存 中 , 并 非 所 有 的 对 象 都 有 一 个 安 全 描 述 符 可 以 通 过 在 清 单 10 中 给 出 的<br />

方 法 来 访 问 。 持 久 化 的 内 核 对 象 , 例 如 文 件 或 者 注 册 表 项 值 , 将 把 安 全 描 述 符 保 存 在<br />

次 级 存 储 中 , 并 且 通 过 它 们 私 有 的 机 制 来 管 理 安 全 访 问 。 如 果 查 看 一 个 注 册 表 项 对 象 ,<br />

我 们 可 以 看 到 它 的 安 全 描 述 符 为 NULL, 这 表 示 不 允 许 查 看 安 全 描 述 符 。 为 了 说 明 这 种<br />

情 况 , 我 们 可 以 在 示 例 中 选 择 选 项 ‘4’, 在 这 个 选 项 中 将 打 开 一 些 注 册 表 项 。<br />

清 单 11 分 析 注 册 表 项 的 对 象 头<br />

kd> k4<br />

ChildEBP RetAddr<br />

0006ff00 01001f33 07sample!Sample4Get+0x45<br />

0006ff18 01001e48 07sample!AppInfo::Loop+0xb3<br />

0006ff7c 01002aa6 07sample!wmain+0xa8<br />

0006ffc0 7c816fd7 07sample!__wmainCRTStartup+0x102<br />

kd> dv *key<br />

softwareKey = 0x000007f4<br />

bookKey = 0x77c2ed0e<br />

kd> !handle 7f4<br />

processor number 0, process ffbbc818<br />

PROCESS ffbbc818 SessionId: 0 Cid: 01c4 Peb: 7ffde000 ParentCid: 00ac<br />

DirBase: 0232e000 ObjectTable: e1112e10 HandleCount: 9.<br />

Image: 07sample.exe<br />

Handle table at e122f000 with 9 Entries in use<br />

07f4: Object: e18cce60 GrantedAccess: 00020019 Entry: e122ffe8<br />

Object: e18cce60 Type: (812e4e70) Key<br />

ObjectHeader: e18cce48<br />

HandleCount: 1 PointerCount: 1<br />

Directory Object: 00000000 Name: \REGISTRY\MACHINE\SOFTWARE<br />

kd> dt _OBJECT_HEADER e18cce48<br />

+0x000 PointerCount : 1<br />

+0x004 HandleCount : 1<br />

+0x004 NextToFree : 0x00000001<br />

+0x008 Type : 0x812e4e70 _OBJECT_TYPE<br />

+0x00c NameInfoOffset : 0 ‘’<br />

+0x00d HandleInfoOffset : 0 ‘’<br />

+0x00e QuotaInfoOffset : 0 ‘’<br />

+0x00f Flags : 0 ‘’<br />

+0x010 ObjectCreateInfo : 0x812ca8e8 _OBJECT_CREATE_INFORMATION<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 99/111


安 全 优 化 :<br />

《PHPer》<br />

+0x010 QuotaBlockCharged : 0x812ca8e8<br />

+0x014 SecurityDescriptor : (null)<br />

+0x018 Body : _QUAD<br />

当 无 法 轻 易 地 查 看 安 全 描 述 符 时 , 我 们 可 以 在 对 象 代 理 执 行 访 问 检 查 时 验 证 它 的<br />

值 。 在 其 他 一 些 用 户 态 组 件 中 也 暴 露 了 一 些 不 由 内 核 ( 例 如 服 务 控 制 管 理 器 [Service<br />

Control Manager]) 管 理 的 对 象 , 这 些 用 户 态 组 件 同 样 使 用 了 它 们 自 己 的 机 制 来 管 理<br />

安 全 描 述 符 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 100/111


LAMP 大 讲 堂 :<br />

《PHPer》<br />

LAMP 大 讲 堂<br />

Web 服 务 器 ( 一 )<br />

Richard Petersen<br />

Linux 发 布 提 供 多 种 Web 服 务 器 。 主 要 的 Web 服 务 器 是 Apache, 该 服 务 器 几 乎 成<br />

为 Linux 发 布 的 标 准 Web 服 务 器 。 这 个 Web 服 务 器 系 统 功 能 非 常 强 大 , 性 能 比 较 稳 定 ,<br />

配 置 还 算 简 单 。 除 它 之 外 还 可 能 附 带 其 他 Web 服 务 器 , 例 如 Tux, 这 个 Web 服 务 器 体<br />

积 较 小 , 在 处 理 不 变 Web 数 据 的 时 候 非 常 快 速 和 高 效 。Linux 发 布 为 Web 服 务 器 提 供<br />

默 认 的 配 置 , 从 而 使 得 它 们 一 旦 安 装 便 可 使 用 。<br />

Apache 可 使 用 OpenSSL 方 便 地 支 持 全 部 的 安 全 套 接 层 (Secure Socket Layer)<br />

特 性 。 也 有 一 些 私 有 的 加 密 产 品 可 用 , 只 不 过 它 们 要 收 取 许 可 证 费 用 。 无 需 直 接 获 取<br />

许 可 授 权 , 只 需 购 买 包 含 Stronghold 和 Raven(covalent.net) 许 可 证 的 商 业 版 Apache<br />

即 可 。 以 前 ,RSA 技 术 被 限 制 只 能 在 美 国 本 土 使 用 , 那 个 时 候 它 受 专 利 的 保 护 。 目 前<br />

RSA 专 利 已 经 过 期 ,RSA 可 用 于 免 费 发 布 的 产 品 , 如 OpenSSL。<br />

1 Tux<br />

Tux,Red Hat 内 容 加 速 器 (Red HatContent Accelerator), 是 一 个 静 态 内 容 的 Web<br />

服 务 器 , 它 被 设 计 成 可 在 Linux 内 核 中 高 速 运 行 。 实 际 上 , 它 运 行 在 内 核 空 间 , 这 使<br />

得 它 的 响 应 时 间 远 少 于 标 准 用 户 空 间 Web 服 务 器 , 如 Apache。 作 为 内 核 空 间 服 务 器 ,<br />

Tux 可 以 非 常 高 效 地 处 理 图 片 等 静 态 内 容 。 与 此 同 时 , 它 可 以 与 用 户 空 间 的 Web 服 务<br />

器 , 如 Apache, 协 同 工 作 , 提 供 动 态 内 容 , 例 如 CGI 程 序 。Tux 甚 至 可 利 用 缓 存 来<br />

保 存 之 前 生 成 的 动 态 内 容 , 然 后 像 使 用 静 态 内 容 一 样 使 用 它 。Tux 可 与 用 户 空 间 Web<br />

服 务 器 协 同 工 作 的 能 力 使 得 它 可 以 成 为 主 要 的 Web 服 务 器 。 任 何 Tux 不 能 处 理 的 内<br />

容 交 给 用 户 空 间 Web 服 务 器 处 理 。<br />

注 意 Tux 在 GNU 公 共 许 可 证 下 可 自 由 发 布 , 许 多 Linux 发 布 包 含 Tux。<br />

Tux 配 置 文 件 位 于 /proc/sys/net/tux。 其 中 可 输 入 serverport,max_doc_size,logfile<br />

等 参 数 ( 查 阅 redhat.com/docs/manuals/tux 上 Tux 参 考 手 册 以 获 取 更 详 细 的 参 数 列 表 )。<br />

默 认 的 参 数 已 经 存 在 ;serverport、clientport, 以 及 documentroot 是 必 须 设 置 的 参 数 。<br />

serverport 是 Tux 使 用 的 端 口 , 如 果 是 主 要 Web 服 务 器 , 则 使 用 80 端 口 。clientport<br />

是 与 Tux 协 作 的 用 户 空 间 Web 服 务 器 ( 如 Apache) 使 用 的 端 口 。documentroot 用 于<br />

指 定 Web 文 档 的 根 目 录 ( 在 Red Hat 和 Fedora 上 是 /var/www/html 目 录 )。<br />

理 想 情 况 是 ,Tux 作 为 主 要 Web 服 务 器 运 行 ,Apache 作 为 从 属 Web 服 务 器 运 行 。<br />

为 了 配 置 Apache 和 Tux 一 起 运 行 ,Apache 配 置 文 件 httpd.conf 中 的 端 口 项 需 要 从 80<br />

改 成 8080。<br />

Port 8080<br />

有 些 参 数 , 如 DOCROOT, 可 作 为 Tux 命 令 的 参 数 来 指 定 。 可 以 在 /etc/sysconfig/tux<br />

文 件 中 进 一 步 编 辑 这 些 参 数 。<br />

注 意 也 可 以 将 Tux 作 为 FTP 服 务 器 运 行 。 在 /proc/sys/net/tux 目 录 下 , 修 改 配 置<br />

文 件 的 内 容 , 把 serverport 修 改 成 21,application_protocol 修 改 成 1,nonagle 修 改 成 0,<br />

然 后 重 新 启 动 Tux。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 101/111


LAMP 大 讲 堂 :<br />

《PHPer》<br />

在 文 档 根 目 录 下 使 用 generatetuxlist 命 令 可 生 成 FTP 目 录 列 表 。<br />

2 其 他 Web 服 务 器<br />

Linux 上 其 他 可 用 的 Web 服 务 器 包 括 Stronghold 企 业 服 务 器 以 及 Apache-SSL 服<br />

务 器 。 下 面 给 出 了<br />

一 个 列 表 :<br />

• Apache-SSL(apache-ssl.org) 是 一 个 基 于 Apache 和 OpenSSL(openssl.org)<br />

的 加 密 Web 服 务 器 。<br />

• lighttpd(lighttpd.net) 是 一 个 小 型 的 , 速 度 非 常 快 的 Web 服 务 器 。<br />

• Sun Java 系 统 Web 服 务 器 (sun.com) 具 有 Java 开 发 支 持 和 安 全 特 性 。<br />

• Zope 应 用 服 务 器 (zope.org) 是 一 个 开 源 的 Web 服 务 器 , 具 有 集 成 的 安 全 ,<br />

基 于 Web 的 管 理 和<br />

• 开 发 , 数 据 库 接 口 等 特 性 。 由 Zope 公 司 开 发 , 该 公 司 开 发 了 Python 编 程 语<br />

言 。<br />

• Stronghold 企 业 服 务 器 (redhat.com/software/stronghold) 是 Apache Web<br />

服 务 器 的 商 业 版 本 ,<br />

• 具 有 改 进 的 安 全 和 管 理 工 具 。<br />

• Netscape 企 业 服 务 器 (enterprise.netscape.com), 作 为 Netscape 安 全 解 决<br />

方 案 的 一 部 分 , 具 有<br />

• 高 性 能 的 开 放 标 准 。<br />

• 也 可 以 使 用 最 初 的 NCSA Web 服 务 器 , 虽 然 目 前 已 不 再 开 发 和 支 持<br />

(hoohoo.ncsa.uiuc.edu)。<br />

3 Apache Web 服 务 器<br />

Apache Web 服 务 器 是 一 个 特 性 齐 全 , 免 费 的 HTTP(Web) 服 务 器 , 由 Apache 服 务<br />

器 项 目 负 责 开 发 和 维 护 。 这 个 项 目 的 目 的 是 提 供 可 靠 的 , 高 效 的 , 以 及 方 便 扩 展 的 Web<br />

服 务 器 , 它 的 源 码 在 自 己 的 Apache 软 件 许 可 证 (Apache Softuare License) 下 是 免<br />

费 和 开 放 的 。 这 个 服 务 器 软 件 包 括 服 务 器 守 护 进 程 、 配 置 文 件 、 管 理 工 具 , 以 及 文 档 。<br />

Apache 服 务 器 项 目 由 程 序 员 志 愿 者 组 成 的 核 心 组 负 责 维 护 , 由 世 界 各 地 大 量 的 贡 献 者<br />

提 供 支 持 。Apache 服 务 器 项 目 是 Apache 软 件 基 金 会 (Apache SoftwareFoundation<br />

过 去 叫 做 Apache 组 ) 目 前 支 持 的 几 个 项 目 之 一 。 这 个 非 营 利 组 织 为 各 种 各 样 的 Apache<br />

开 源 软 件 项 目 , 包 括 Apache HTTPD 服 务 器 、Java Apache、Jakarta, 以 及 XML-Apache,<br />

提 供 财 务 、 法 律 , 以 及 组 织 的 支 持 。Apache 软 件 基 金 会 的 网 站 是 apache.org。 表 23-1<br />

列 出 了 Apache 相 关 的 各 种 站 点 。<br />

Apache 最 初 是 基 于 伊 利 诺 斯 大 学 厄 本 那 香 槟 分 校 (University of Illinols,<br />

UrbanaChampaign) 的 国 家 超 级 计 算 应 用 中 心 (National Center for Supercomputing<br />

Applications) 所 开 发 的 NCSA Web 服 务 器 。 目 前 Apache 凭 自 己 的 能 力 已 经 发 展 成 独<br />

立 的 服 务 器 , 并 成 为 最 受 欢 迎 的 Web 服 务 器 之 一 。 虽 然 最 初 是 为 Linux 和 UNIX 系 统<br />

开 发 的 ,Apache 已 成 为 跨 平 台 的 应 用 程 序 , 可 运 行 于 Windows 和 OS/2 等 操 作 系 统 。<br />

它 的 站 点 httpd.apache.org 提 供 有 关 这 个 Web 服 务 器 的 在 线 支 持 和 文 档 。 服 务 器 安<br />

装 的 时 候 还 会 提 供 基 于 HTML 的 手 册 。Apache 配 置 工 具 可 帮 助 用 户 方 便 地 配 置 Apache<br />

服 务 器 。 它 可 运 行 于 任 何 X Window 系 统 窗 口 管 理 器 上 , 包 括 GNOME 和 KDE。 另 外 , 也<br />

可 以 使 用 Comanche 配 置 工 具 。Webmin conf 也 提 供 对 Apache 的 配 置 支 持 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 102/111


LAMP 大 讲 堂 :<br />

《PHPer》<br />

3.1 Java:Apache Jakarta 项 目<br />

Apache Jakarta 项 目 支 持 开 源 Java 软 件 的 开 发 ; 它 的 网 站 地 址 是 jakarta.apache.org。<br />

目 前 ,Jakarta 支 持 大 量 的 项 目 , 包 括 库 、 工 具 、 框 架 、 引 擎 , 以 及 服 务 器 应 用 程 序 。<br />

Tomcat 是 Java Servlet 和 JavaServer Pages 规 范 的 开 源 实 现 。Tomcat 设 计 用 于 Apache<br />

服 务 器 。JMeter 是 一 个 Java 开 发 工 具 , 用 于 测 试 服 务 器 资 源 , 例 如 servlet 和 CGI 脚<br />

本 的 性 能 。Velocity 是 模 板 引 擎 , 它 提 供 对 Java 对 象 的 简 单 访 问 。Watchdog 是 一 个 用<br />

于 检 测 servlet 容 器 兼 容 性 的 工 具 。Structs,Cactus, 以 及 Tapestry 都 是 已 建 立 的 Java<br />

框 架 , 用 于 开 发 Java Web 应 用 程 序 。<br />

表 1 Apache 相 关 的 网 站<br />

3.2 安 装 Linux Apache<br />

在 初 始 安 装 Linux 系 统 的 时 候 ,Linux 发 布 通 常 会 允 许 你 选 择 是 否 安 装 Apache Web<br />

服 务 器 。 所 有 必 须 的 目 录 和 配 置 文 件 将 自 动 生 成 。 这 样 , 每 当 运 行 Linux 的 时 候 , 系<br />

统 就 已 经 是 一 个 功 能 完 整 的 网 站 。 每 次 启 动 系 统 ,Web 服 务 器 也 会 自 动 启 动 , 并 持 续<br />

运 行 。 在 大 多 数 Linux 发 布 中 , 用 于 存 放 网 站 数 据 文 件 的 目 录 是 /var/www/html。 可<br />

以 将 网 页 放 置 到 这 个 目 录 , 或 者 放 置 到 其 中 的 任 何 子 目 录 。 你 的 系 统 已 经 被 配 置 成 Web<br />

服 务 器 运 行 。 所 需 要 做 的 是 执 行 必 需 的 网 络 服 务 器 配 置 , 接 着 指 定 开 发 给 远 端 用 户 的<br />

文 件 和 目 录 。 无 需 做 其 他 的 事 情 。 一 旦 网 站 连 接 到 网 络 , 远 端 用 户 就 可 以 访 问 它 。<br />

Web 服 务 器 通 常 会 在 /var/www 目 录 中 建 立 网 站 。 它 还 会 建 立 几 个 目 录 用 于 管 理 这<br />

个 站 点 。/var/www/cgi-bin 目 录 用 于 存 放 CGI 脚 本 ,/var/www/html/manual 用 于 存<br />

放 HTML 格 式 的 Apache 手 册 。 可 以 使 用 浏 览 器 来 查 看 它 。 网 站 被 放 置 在 /var/www/html<br />

目 录 下 。 把 网 站 主 页 放 在 这 里 。 配 置 文 件 放 置 在 另 一 个 目 录 /etc/httpd/conf。 表 2<br />

列 出 Apache 服 务 器 使 用 的 不 同 目 录 和 配 置 文 件 。<br />

表 2 Apache Web 服 务 器 的 文 件 和 目 录 (RPM 安 装 )<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 103/111


LAMP 大 讲 堂 :<br />

《PHPer》<br />

3.3 Apache 多 处 理 模 块 :MPM<br />

Apache 目 前 采 用 具 有 多 处 理 模 块 (MPM, multiprocessing modules) 的 新 的 体 系<br />

结 构 , 这 种 结 构 设 计 用 于 为 不 同 的 操 作 系 统 定 制 Apache, 以 及 处 理 某 些 多 进 程 操 作 。<br />

就 主 要 的 MPM 而 言 ,Linux 系 统 使 用 prefork 或 者 worker MPM, 而 Windows 使 用<br />

mpm_winnt MPM。prefork 是 标 准 的 MPM 模 块 , 被 设 计 成 与 较 老 的 UNIX 和 Linux 系 统<br />

兼 容 , 特 别 是 与 那 些 不 支 持 线 程 的 系 统 兼 容 。 可 以 在 Apache 配 置 文 件 /etc/httpd/<br />

conf/httpd.conf 中 为 这 两 种 模 式 配 置 工 作 负 荷 。<br />

许 多 曾 经 驻 留 在 Apache 核 心 的 指 示 符 现 在 被 放 置 到 各 个 模 块 和 MPM 中 。 采 用 这 种<br />

模 块 化 的 设 计 , 有 些 指 示 符 已 经 被 删 除 , 例 如 ServerType。 这 些 模 块 的 配 置 文 件 位 于<br />

/etc/httpd/conf.d 目 录 中 。<br />

3.4 启 动 和 停 止 Web 服 务 器<br />

在 大 多 数 系 统 中 ,Apache 作 为 独 立 运 行 的 服 务 器 安 装 , 然 后 持 续 地 运 行 。 在 初 始<br />

化 脚 本 中 , 系 统 会 自 动 启 动 这 个 Web 服 务 器 守 护 进 程 , 每 当 系 统 启 动 时 调 用 它 。<br />

在 Red Hat、Fedora、SUSE, 以 及 类 似 的 Linux 发 布 中 , 可 以 使 用 chkconfig 命<br />

令 设 置 这 个 httpd 服 务 器 在 哪 个 运 行 级 别 启 动 , 并 在 适 当 的 运 行 级 别 目 录 创 建 链 接 。<br />

下 面 的 命 令 会 设 置 Web 服 务 器 (httpd) 在 运 行 级 别 3 和 5 启 动 。<br />

chkconfig --level 35 httpd on<br />

在 Debian、Ubuntu, 以 及 类 似 的 Linux 发 布 中 , 可 以 使 用 rrconf 或 sysv-rc-conf<br />

工 具 来 完 成 类 似 的 设 置 。 在 使 用 GNOME 的 Linux 发 布 中 , 可 以 使 用 services-admin<br />

工 具 。<br />

注 意 这 个 Web 服 务 器 的 服 务 脚 本 httpd( 在 Debian 中 被 称 作 apache2) 位 于<br />

/etc/rc.d/init.d 目 录 中 。 可 以 使 用 service 命 令 手 动 地 启 动 和 停 止 httpd 服 务 器 :<br />

service httpd start。<br />

Apache 还 提 供 名 为 apachectl(Apache 控 制 ) 的 控 制 工 具 用 于 管 理 Web 服 务 器 。<br />

使 用 apachectl, 可 以 从 命 令 行 启 动 、 关 闭 , 以 及 重 启 动 服 务 器 。apachectl 命 令 接<br />

收 几 个 参 数 :start( 用 于 启 动 服 务 器 )、stop( 用 于 关 闭 服 务 器 )、restart( 用 于 关<br />

闭 并 重 新 启 动 服 务 器 )、graceful( 用 于 关 闭 并 优 雅 地 重 新 启 动 服 务 器 )。 另 外 , 可 以<br />

使 用 apachectl 命 令 带 上 config 参 数 检 查 配 置 文 件 的 语 法 。 也 可 以 将 apachectl 作<br />

为 服 务 器 在 /etc/rc.d 目 录 中 的 系 统 服 务 文 件 使 用 。<br />

可 以 直 接 使 用 守 护 进 程 的 完 整 路 径 名 来 调 用 它 。 这 个 守 护 进 程 有 若 个 选 项 。-d 选<br />

项 为 httpd 程 序 指 定 与 默 认 目 录 不 同 的 目 录 。-f 选 项 用 于 指 定 与 httpd.conf 不 同 的<br />

配 置 文 件 。-v 选 项 显 示 版 本 信 息 。<br />

/usr/sbin/httpd -v<br />

若 要 检 查 Web 服 务 器 , 可 启 动 Web 浏 览 器 , 输 入 系 统 的 因 特 网 域 名 地 址 。 对 于<br />

域 名 为 trutle.mytrek.com 的 系 统 , 用 户 需 输 入 http://turtle.mytrek.com。 这 样 将<br />

会 显 示 放 置 在 Web 根 目 录 的 主 页 。 最 简 单 的 实 现 方 法 是 使 用 Lynx, 这 是 一 个 命 令 行 的<br />

Web 浏 览 器 。 启 动 Lynx, 并 敲 入 g 会 打 开 一 个 行 供 用 户 输 入 的 系 统 URL。Lynx 会 显 示<br />

该 网 站 的 主 页 。 务 必 确 保 首 先 要 把 index.html 文 件 放 到 /var/www/html 目 录 下 。<br />

一 旦 服 务 运 行 起 来 , 可 以 使 用 ab 基 准 测 试 工 具 测 试 它 的 性 能 , 这 个 工 具 也 是 由<br />

Apache 提 供 :ab 工 具 能 够 显 示 服 务 器 一 次 能 够 处 理 多 少 个 请 求 。 它 有 多 个 选 项 :-v<br />

控 制 详 细 显 示 的 级 别 ;-n 指 定 处 理 请 求 数 量 ( 默 认 是 1); -t 指 定 时 间 限 制 。<br />

注 意 目 前 不 支 持 在 xinetd 下 运 行 Apache。 在 Apache 2 中 , 为 实 现 这 种 支 持 ,<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 104/111


LAMP 大 讲 堂 :<br />

《PHPer》<br />

通 常 选 择 被 设 计 用 于 在 xinetd 的 MPM 模 式 。<br />

4 Apache 配 置 文 件<br />

配 置 指 示 符 存 在 于 httpd.conf 配 置 文 件 中 。 被 整 理 过 的 httpd.conf 文 件 自 动 安<br />

装 在 /etc/httpd/conf 目 录 下 。 强 烈 建 议 你 查 阅 自 己 系 统 中 的 这 个 文 件 。 它 包 含 Apache<br />

各 种 指 示 符 的 详 细 描 述 和 默 认 的 配 置 项 。<br />

主 配 置 文 件 中 的 任 何 指 示 符 可 以 在 单 个 目 录 的 基 础 上 被 该 目 录 中 的 .htaccess 文<br />

件 覆 盖 。 虽 然 最 初 仅 是 设 计 用 于 访 问 指 示 符 ,.htaccess 文 件 也 可 以 保 存 任 何 的 资 源<br />

指 示 符 , 从 而 使 得 用 户 可 以 定 制 特 定 目 录 中 网 页 的 显 示 方 式 。 在 httpd.conf 文 件 中<br />

可 配 置 对 .htaccess 文 件 的 访 问 。<br />

另 外 ,Apache 的 许 多 模 块 都 有 自 己 的 配 置 文 件 。 它 们 被 放 置 在 /etc/httpd/conf.d<br />

目 录 中 。<br />

作 者 简 介 :<br />

Richard Petersen 是 著 名 的 Linux 专 家 , 也 是 一 位 Linux/Unix 教 育 专 家 , 所 出 版 的<br />

很 多 专 著 都 非 常 畅 销 ,《Linux 完 全 参 考 手 册 ( 原 书 第 6 版 )》 是 他 的 代 表 作 , 目 前 最<br />

新 版 本 是 第 6 版 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 105/111


职 场 人 生 :<br />

《PHPer》<br />

职 场 人 生<br />

1<br />

大 学 生 求 职 七 大 昏 招 —— 说 谎 ( 四 )<br />

张 大 志<br />

故 事 四 : 该 诚 实 的 时 候 必 须 诚 实<br />

应 聘 编 辑 的 应 届 生 黄 宇 来 新 潮 公 司 是 第 三 次 , 之 前 部 门 的 负 责 人 对 黄 宇 的 能 力 和<br />

潜 力 给 予 很 高 的 评 价 , 按 惯 例 如 果 薪 水 能 谈 拢 , 那 就 可 以 确 定 入 职 了 。<br />

高 方 玄 :“ 由 于 你 面 试 中 已 充 分 展 示 了 自 己 自 己 的 能 力 , 我 们 相 信 你 能 比 较 好 的<br />

胜 任 公 司 的 工 作 , 所 以 , 公 司 给 你 定 的 薪 水 高 于 其 它 应 届 毕 业 生 。 试 用 2000 元 , 转<br />

正 后 2500 元 。 你 认 为 可 以 吗 ?”<br />

黄 宇 :“ 好 的 , 谢 谢 , 我 想 回 去 再 考 虑 一 下 。”<br />

高 方 玄 送 走 黄 宇 的 5 分 钟 之 后 电 话 响 起 。<br />

黄 宇 :“ 高 经 理 , 我 是 黄 宇 。”<br />

高 方 玄 :“ 哦 。”<br />

黄 宇 :“ 感 谢 公 司 对 我 的 认 可 和 给 出 的 薪 水 。”<br />

高 方 玄 有 种 不 好 的 预 感 , 通 常 这 么 开 头 的 电 话 最 后 都 是 候 选 人 因 薪 水 或 其 它 什 么<br />

原 因 拒 绝 公 司 的 机 会 。<br />

高 方 玄 :“ 嗯 , 然 后 呢 ?”<br />

黄 宇 :“ 在 接 受 工 作 机 会 之 前 , 有 件 事 我 想 说 明 一 下 。 我 虽 然 今 年 毕 业 , 但 没 有<br />

拿 到 学 位 证 书 。”<br />

“ 原 因 呢 ?” 高 方 玄 心 里 一 块 石 头 总 算 落 了 地 。 这 个 问 题 对 于 快 速 发 展 中 的 公 司 来<br />

说 虽 然 重 要 , 但 其 实 领 导 还 是 更 看 重 工 作 实 力 、 以 及 对 工 作 的 热 情 , 其 它 的 都 可 以<br />

根 据 实 际 情 况 再 商 榷 。<br />

黄 宇 :“ 有 一 门 课 没 有 通 过 , 通 知 补 考 时 , 我 在 北 京 实 习 , 知 道 消 息 的 时 候 已 经<br />

是 要 考 试 的 头 一 天 晚 上 了 , 来 不 及 回 去 了 , 所 以 ……”<br />

高 方 玄 :“ 哦 。”<br />

黄 宇 :“ 因 为 之 前 我 对 自 己 能 否 成 功 应 聘 没 把 握 , 不 希 望 因 为 这 个 影 响 到 公 司 对<br />

我 的 评 价 。 同 时 , 我 希 望 在 进 入 公 司 之 前 , 公 司 能 了 解 我 的 真 实 情 况 。 至 于 您 刚 才<br />

提 出 的 薪 水 , 我 完 全 可 以 接 受 。”<br />

高 方 玄 :“ 好 的 。 我 会 与 部 门 沟 通 一 下 , 尽 快 通 知 你 结 果 。”<br />

……<br />

部 门 经 理 听 到 这 个 消 息 后 , 只 考 虑 了 两 分 钟 , 立 即 同 意 黄 玄 入 职 。 他 给 出 的 理 由<br />

很 简 单 :“ 这 位 同 学 能 力 胜 任 , 而 且 诚 实 , 谈 到 这 个 问 题 的 时 间 拿 捏 准 确 , 说 明 性<br />

格 比 较 成 熟 , 我 很 看 好 他 。”<br />

两 天 后 , 黄 宇 顺 利 入 职 , 现 在 工 作 得 非 常 开 心 , 已 经 成 为 部 门 骨 干 。<br />

技 巧 —— 如 何 诚 实 的 描 述 自 己 的 “ 问 题 ”<br />

应 该 说 , 是 黄 宇 的 真 诚 和 智 慧 为 自 己 赢 得 了 这 次 工 作 机 会 。<br />

首 先 , 黄 宇 没 有 选 择 说 谎 或 者 更 拙 劣 的 办 法 去 掩 盖 自 己 的 这 个 问 题 。 虽 然 即 将 从<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 106/111


职 场 人 生 :<br />

《PHPer》<br />

事 的 工 作 黄 宇 非 常 喜 欢 , 也 有 相 对 高 的 待 遇 , 应 该 说 机 会 很 难 得 。 但 黄 宇 没 有 选 择<br />

去 办 个 假 证 , 实 在 是 明 智 之 举 。 我 们 曾 经 见 过 一 些 候 选 人 因 为 不 能 提 供 相 应 的 资 料<br />

而 在 面 试 中 落 马 , 也 曾 经 见 过 提 供 了 虚 假 资 料 被 公 司 发 现 后 开 除 的 员 工 。<br />

其 次 , 黄 宇 还 把 握 了 正 确 的 时 机 , 在 得 到 公 司 对 自 己 的 认 可 后 说 出 了 自 己 没 拿 到<br />

毕 业 证 的 事 实 。 这 个 时 候 , 通 过 人 力 资 源 部 的 两 次 面 试 和 业 务 部 门 的 面 试 , 公 司 招<br />

聘 方 对 黄 宇 的 工 作 能 力 有 了 一 定 的 认 识 和 了 解 , 也 向 他 申 出 了 “ 橄 榄 枝 ”, 毕 业 证<br />

做 为 一 个 细 节 影 响 不 会 太 大 , 而 且 , 不 对 公 司 隐 瞒 自 己 的 真 实 情 况 让 他 更 被 信 任 。<br />

每 个 面 试 者 , 在 描 述 自 己 或 多 或 少 存 在 的 问 题 时 , 都 应 该 秉 承 一 个 原 则 ——“ 诚 实<br />

而 不 鲁 莽 , 坦 率 而 有 策 略 。” 说 谎 固 然 是 要 不 得 的 , 但 毫 无 技 巧 的 直 接 把 自 己 存 在<br />

的 问 题 讲 出 来 , 也 不 见 的 是 件 好 事 情 。 试 想 一 下 , 如 果 一 开 始 黄 宇 就 告 诉 新 潮 公 司<br />

, 他 是 一 个 没 有 拿 到 学 位 证 书 的 应 届 毕 业 生 , 部 门 经 理 对 他 的 评 价 还 会 是 这 样 吗 ?<br />

作 者 简 介 :<br />

真 名 : 张 大 志<br />

网 名 :LEO(jobchanceleo)<br />

CSDN 十 大 明 星 博 主 ,2009CSDN MVB,ITCAST 特 约 讲 师 、IT168 特 邀 职 业 发 展 顾 问 ,<br />

主 持 “IBM 软 件 技 术 精 英 职 业 规 划 讲 堂 ”, 主 持 “CD2.0 大 会 职 业 规 划 论 坛 - 后 金 融 风<br />

暴 时 代 的 软 件 人 员 素 质 要 求 ”, 为 Zed-3、CSDN 等 知 名 国 内 外 企 业 提 供 咨 询 和 培 训 ,<br />

内 容 包 括 :HR 战 略 管 理 、 员 工 招 聘 与 培 训 , 职 业 生 涯 管 理 等 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 107/111


LAMP 新 书<br />

《PHPer》<br />

LAMP 新 书<br />

《Linux 服 务 器 安 全 策 略 详 解 》<br />

出 版 社 : 电 子 工 业 出 版 社<br />

作 者 : 曹 江 华<br />

出 版 日 期 :2009 年 6 月<br />

图 书 介 绍 :<br />

“Linux 就 是 服 务 器 , 或 者 换 句 话 说 , 是 服<br />

务 器 成 就 了 Linux。” 相 信 读 者 对 于 这 样 的 判 断<br />

肯 定 会 有 不 同 意 见 。 这 里 不 是 以 偏 概 全 , 只 为<br />

强 调 Linux 与 服 务 器 与 生 俱 来 的 天 然 联 系 。 实 际<br />

上 , 对 于 Linux 厂 商 而 言 , 约 90% 以 上 的 收 入 都<br />

来 自 服 务 器 应 用 市 场 。Linux 主 要 用 于 架 设 网 络<br />

服 务 器 。 如 今 关 于 服 务 器 和 网 站 被 黑 客 攻 击 的<br />

报 告 几 乎 每 天 都 可 以 见 到 , 而 且 随 着 网 络 应 用<br />

的 丰 富 多 样 , 攻 击 的 形 式 和 方 法 也 千 变 万 化 。<br />

如 何 增 强 Linux 服 务 器 的 安 全 性 是 Linux 系 统 管<br />

理 员 最 关 心 的 问 题 之 一 。<br />

本 书 共 28 章 和 1 个 附 录 。 概 括 而 言 , 实 质<br />

是 五 部 分 内 容 : 第 一 部 分 分 级 介 绍 对 Linux 服 务 器 的 攻 击 情 况 , 以 及 Linux 网 络 基 础 ;<br />

第 二 部 分 是 本 书 的 核 心 , 针 对 不 同 的 Linux 服 务 器 分 别 介 绍 各 自 的 安 全 策 略 ; 第 三 部<br />

分 介 绍 Linux 服 务 器 的 安 全 工 具 ; 第 四 部 分 是 Linux 下 开 源 数 据 库 安 全 以 及 Linux 下<br />

新 闻 组 服 务 器 构 建 、 网 络 钓 鱼 的 防 范 、Linux 无 线 网 络 构 建 及 其 安 全 策 略 、 使 用 Linux<br />

安 全 审 计 以 及 使 用 Selinux 保 护 Linux 服 务 器 的 方 法 ; 第 五 部 分 是 1 个 附 录 , 介 绍 Linux<br />

服 务 器 应 急 响 应 流 程 与 步 骤 。<br />

本 书 适 合 作 为 大 专 院 校 计 算 机 专 业 师 生 的 教 材 或 教 学 参 考 书 , 也 适 合 于 Linux 网<br />

络 管 理 员 和 系 统 管 理 员 , 以 及 对 安 全 方 面 感 兴 趣 的 读 者 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 108/111


LAMP 新 书<br />

《PHPer》<br />

出 版 社 : 人 民 邮 电 出 版 社<br />

原 书 名 :The Standard C Library<br />

原 出 版 社 :Prentice Hall PTR<br />

作 者 :( 美 )P.J.Plauger<br />

译 者 : 卢 红 星 徐 明 亮 霍 建 同<br />

出 版 日 期 :2009 年 7 月<br />

《C 标 准 库 》<br />

图 书 介 绍 :<br />

本 书 将 告 诉 你 如 何 使 用 符 合 C<br />

语 言 的 ANSI/ISO<br />

标 准 的 库 函 数 。 因 为 已 经 有 很 多 书 出 色 地 讲 解 了<br />

C<br />

语 言 本 身 , 所 以 本 书 只 专 注 于 “ 库 ” 这 个 话 题 。 本<br />

书 还 会 告 诉 你 C 标 准 库 是 如 何 实 现 的 。 本 书 提 供 了 大 约 9 000<br />

行 测 试 过 的 可 实 际 工 作 的 代 码 。 我 相 信 , 看 了 C<br />

标 准 库 的 实 现 细 节 后 你 能 更 好 地 理 解 如 何 使 用 它 。<br />

库 函 数 的 实 现 代 码 尽 可 能 地 使 用 标 准 C , 这 样 做 有 3<br />

个 设 计 目 的 : 首 先 , 它 使 代 码 具 有 可 读 性 和 示 范 性 ; 其 次 , 它 使 代 码 在 各 种 计 算 机<br />

体 系 结 构 间 具 有 高 度 可 移 植 性 ; 最 后 , 它 能 使 编 写 的 代 码 兼 顾 正 确 性 、 性 能 和 规 模<br />

各 方 面 。<br />

教 你 如 何 编 写 C 程 序 并 不 是 本 书 的 目 的 。 本 书 假 定 你 能 读 懂 简 单 的 C<br />

程 序 , 对 于 那 些 稍 有 难 度 的 代 码 , 我 会 向 你 解 释 其 中 的 难 点 和 技 巧 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 109/111


LAMP 新 书<br />

《PHPer》<br />

出 版 社 : 人 民 邮 电 出 版 社<br />

原 书 名 :The Standard C Library<br />

原 出 版 社 :Prentice Hall PTR<br />

作 者 :( 美 )P.J.Plauger<br />

译 者 : 卢 红 星 徐 明 亮 霍 建 同<br />

出 版 日 期 :2009 年 7 月<br />

《Python 开 发 技 术 详 解 》<br />

图 书 介 绍 :<br />

本 书 将 告 诉 你 如 何 使 用 符 合 C<br />

语 言 的 ANSI/ISO<br />

标 准 的 库 函 数 。 因 为 已 经 有 很 多 书 出 色 地 讲 解 了<br />

C<br />

语 言 本 身 , 所 以 本 书 只 专 注 于 “ 库 ” 这 个 话 题 。 本<br />

书 还 会 告 诉 你 C<br />

标 准 库 是 如 何 实 现 的 。 本 书 提 供 了 大 约 9 000<br />

行 测 试 过 的 可 实 际 工 作 的 代 码 。 我 相 信 , 看 了 C<br />

标 准 库 的 实 现 细 节 后 你 能 更 好 地 理 解 如 何 使 用 它 。<br />

库 函 数 的 实 现 代 码 尽 可 能 地 使 用 标 准 C , 这 样 做 有 3<br />

个 设 计 目 的 : 首 先 , 它 使 代 码 具 有 可 读 性 和 示 范 性 ; 其 次 , 它 使 代 码 在 各 种 计 算 机<br />

体 系 结 构 间 具 有 高 度 可 移 植 性 ; 最 后 , 它 能 使 编 写 的 代 码 兼 顾 正 确 性 、 性 能 和 规 模<br />

各 方 面 。<br />

教 你 如 何 编 写 C 程 序 并 不 是 本 书 的 目 的 。 本 书 假 定 你 能 读 懂 简 单 的 C<br />

程 序 , 对 于 那 些 稍 有 难 度 的 代 码 , 我 会 向 你 解 释 其 中 的 难 点 和 技 巧 。<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 110/111


封 底<br />

代 码 片 段<br />

网 站 :http://www.phpchina.com 投 稿 :phper@phpchina.com 《PHPer》 111/111

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!