PHP 9

Page 1

封面

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

1/127


卷首语

《PHPer》

卷首语

CMS 驱动 Web2.0 Web2.0 的快速发展离不开开源内容管理系统的支持,当前流行的 Blog、Wiki 等系统都 或多或少的采用了开源 CMS 系统,甚至有人认为是开源 CMS 系统导致了 Web 2.0 的产生并 快速发展。同时,开源 CMS 系统也随着 Web 2.0 逐渐发展壮大,已经在开源社区形成了一股 不可忽视的力量。Web2.0 只是一个符号,它表明的是正在变化中的互联网,这些变化相辅相 成,彼此联系在一起,才促使互联网出现今天的模样,才让社会性、用户、参与和创作浮到 表面成为互联网文化的中坚力量并表征了未来。Web1.0 到 Web2.0 的转变,具体的说,从模 式上是单纯的“读”向“写”、“共同建设”发展,由被动地接收互联网信息向主动创造互联 网信息迈进!Web2.0 能建站吗,不能!因为它只是一种存在模式,一个不断进步的概念。 内容管理系统是一个很宽泛的概念:从商业门户网站的新闻系统到个人的 Weblog 都可以 称为内容管理系统。CMS 系统大致可分为框架型和应用型两大类,一种是框架型,本身不包 含任何应用实现,只是提供了底层框架,具体应用需要二次开发;另外一种是应用型,即本 身是一个面向具体类型的应用实现,已经包含了新闻、评论、管理、投票、论坛和 Wiki 等一 些子系统。 目前开源内容管理系统多是追求大而全,期望一套系统可以解决所有问题,而实际上这 种想法是不太可能实现的。客户要求千差万别,不可能有一种内容管理系统会放之四海而皆 准。所以今后的开源内容管理系统将会同时向专业化和通用化两个方向发展,向通用化发展, 即现在成熟内容管理系统继续完善、扩展功能;向专业化方向发展,即出现新的专用内容管 理系统,或原来内容管理系统出现 fork 分支,使得每种内容管理系统都有其擅长、专攻的应 用范围,这也是社会分工的必然结果。 内容管理是定制性很强的领域,市场也相当广泛,在这个市场里,开源内容管理系统已 取得相当成就,很多原有商业内容管理系统也因为开源系统的竞争而不断调整策略,最终也 投身开源的怀抱。 开源内容管理系统现在可以说是群雄并起,这些开源项目都将经过市场的检验,它们中 的很多可能不适合发展需要将成为历史,但开源内容管理系统整体将不断前行、不断发展。 开源内容管理系统将朝着更加人性化、更加智能化、更加专业化的方向发展。随着开源 CMS 系统的不断发展,新的开源商业模式也将随之出现,好的商业模式将促进开源 CMS 系统的更 加繁荣。

刘昊

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

2/127


PHPer 贡献者名单

《PHPer》

PHPer 贡献者名单 2008 年 4 月 1 日

第 9 期

主管:PHPChina.com 主办:PHPChina网站会员 网址:http://www.phpchina.com 总编:PHPChina 副总编:廖宇雷 卷首语:刘 昊 新闻:PHPChina 活动:雷 锋 就业:肥同小可 PHP推广活动:肥同小可 招聘:王志军 应

新手乐园:乔 聪 代码分析:傻大猫 / isno 企业解决方案:PHP168团队 模版和引擎:曾瑶合 安全与优化:胡俊鹏 / 刘 昊 开源项目介绍:stven / polo 知识库 LAMP大讲堂:高洛峰 教程连载:stven / polo / CodeIgniter中国 PHP百家谈:SUP LAMP新书推荐:PHPChina

校验排版:Richard 后期制作:风吹过的夏天 另外,欢迎广大PHP程序员踊跃投稿! 请将稿件发送至 phper@phpchina.com 请注明所投栏目,并附上作者简介。 PHP中国开源社区感谢您的参与!

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

3/127


目录

《PHPer》

目录 封面......................................................................................................................................................1 卷首语..................................................................................................................................................2 PHPER 贡献者名单 ...........................................................................................................................3 目录......................................................................................................................................................4 PHP 新闻.............................................................................................................................................6 2008 第三届互联网站长年会即将登场 ....................................................................................................................... 6

PHP 就业.............................................................................................................................................8 从火箭连胜看团队素养 ................................................................................................................................................ 8 一、自私--关心只在五伦之内 ......................................................... 9 二、自我--别人的问题与我无关 ...................................................... 11 三、自大――我的想法就是答案 ........................................................ 12

PHP 推广活动...................................................................................................................................14 2008 年 PHPCHINA 全国高校巡讲 ............................................................................................................................. 14

PHP 企业招聘...................................................................................................................................16 环球时报-环球网 ........................................................................................................................................................ 16 欧洲软件公司 BYSOFT ................................................................................................................................................ 17 深圳金蝶软件有限公司 .............................................................................................................................................. 19

PEA 活动...........................................................................................................................................20 PEA 的 2008 在沉默?................................................................................................................................................ 20

行业展望............................................................................................................................................24 CMS 大全..................................................................................................................................................................... 24 国内主流的 CMS 系统 .................................................................. 24 国外的一些主流 CMS 系统 .............................................................. 25

新手乐园............................................................................................................................................27 使用 SIMPLEXML 处理 XML 文件............................................................................................................................. 27 1 SimpleXML 简介 .................................................................... 27 2 SimpleXML 入门示例 ................................................................ 27 3 实例:XML 文件与数据库之间进行数据交互............................................. 29

代码分析............................................................................................................................................32 PHP 缓存的实践.......................................................................................................................................................... 32 前言 ................................................................................ 32 简介 ................................................................................ 32 代码分析 ............................................................................ 33 DISCUZ!浅析之登录篇 .............................................................................................................................................. 36 1 前台表单部分 ...................................................................... 36 2 处理登录部分 ...................................................................... 37 3 验证登录部分 ...................................................................... 39 4 自己动手写 Discuz!登录验证 ....................................................... 41

安全优化............................................................................................................................................43 基于 RBAC 的安全管理系统的设计与实现.............................................................................................................. 43 引言 ................................................................................ 43 分析说明 ............................................................................ 43 系统设计 ............................................................................ 45 结论 ................................................................................ 48 参考文献 ............................................................................ 48 浅谈 CMS 系统的 SEO 优化 ...................................................................................................................................... 50

PHP 企业解决方案...........................................................................................................................52 PHP168 整站架构分析+企业解决方案 ...................................................................................................................... 52

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

4/127


目录

《PHPer》

模板和引擎技术 ...............................................................................................................................55 使用 PEAR 类库和 SMARTY 模板引擎来做项目....................................................................................................... 55 使用 PEAR 和 Smarty 开发项目的好处 .................................................... 55 再来看看 Smarty 模板在 CMS 项目里的应用 ............................................... 57 综述 ................................................................................ 59

开源项目介绍....................................................................................................................................61 SYMFONY FRAMEWORK 安装及初级使用................................................................................................................... 61 1 Symfony FrameWork 安装 ............................................................ 61 2 使用 Symfony 创建立首个基于 PHP 的 MVC 框架项目(MyFirstSymfony) .................... 62 3 建立 Symfony 程序模块与简单 MVC 开发–helloworld 模块的建立与开发..................... 68

LAMP 大讲堂...................................................................................................................................78 会话控制 ...................................................................................................................................................................... 78 1 什么是会话控制 .................................................................... 78 2 会话控制的基本应用 ................................................................ 79 3 传递会话 ID ....................................................................... 91

教程连载............................................................................................................................................92 使用 SYMFONY 制作简单留言板(一) .................................................................................................................... 92 1 环境 .............................................................................. 92 2 留言板 Application 文件结构(如图 1)............................................... 92 3 留言板页面图像跳转及 UseCase 情况(UML) ........................................... 92 4 留言板数据库与数据表构建 .......................................................... 95 5 创建 GuestBook 程序 ................................................................ 95 6 使用 Symfony 特有的 scaffolding 功能自动创建数据库 module 与 model 等 ................. 96 7 根据 schema.yml 生成数据库对象模型(object-model)与 CRUD(ORM).................... 98 8 调整自动生成的逻辑结构与显示方式 ................................................. 100 9 补充说明,调整 Symfony 路由跳转规则,不使用 dev 方式显示模块 ....................... 106 10 总结 ............................................................................ 107 CODEIGNITER 详解(一) ......................................................................................................................................... 109 第一章 对 CodeIgniter 的介绍 ........................................................ 109 第二章 2 分钟建立一个 CodeIgniter 网站 .............................................. 117 关于【CodeIgniter 中国】开发团队 ................................................... 121

PHP 百家谈.....................................................................................................................................122 李国德访谈录 ............................................................................................................................................................ 122

LAMP 新书推荐.............................................................................................................................124 《构建可扩展的 WEB 站点》................................................................................................................................... 124 《LINUX 系统与网络服务管理技术大全》 ............................................................................................................. 126

封底..................................................................................................................................................127

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

5/127


PHP 新闻:2008 第三届互联网站长年会即将登场

《PHPer》

PHP 新闻

2008 第三届互联网站长年会即将登场 2008 年,是中国奥运之年,也是中国互联网发展的腾飞之年,中国网民突破 2 亿大关, 互联网应用更深的进入了人们的社会生活,中国互联网站长在 2008 年应该考虑什么、立足什 么、做些什么、怎么去做且做好?这是每一个站长都应该思考的问题。 在过去的 2006、2007 年第一届、第二届中国互联网站长论坛上,也就是 Comsenz 和落 伍者的 5 周年、6 周年聚会上,我们曾经有过很多行业焦点话题的思考、也做过大量具体经 营问题的探讨,甚至,还针对风险投资等新机会的把握和应对做过很多经验的分享。 2006、2007 那两年,确实也是激情燃烧的岁月之年。Web2.0 很热、融资很易、IPO 很多, 人也很浮躁。 2008 年,如中国股市一样,牛市行情转向“熊”的一面。互联网行业与任何行业一样, 都有面临巅峰和进入低谷的现实可能。哪些网站和站长能够最终赢得未来?什么才是赢得未 来的最重要根本?是背景、资源、资本、技术还是各种诱人的机会?都是也都不像是。

走出一切繁杂的经验,返回自然万物的本真,我们对于“最重要根本”的理解是:信念, “用信念去战斗”。 《士兵突击》是一个很好的信念教材,对于我们经营互联网事业的人来说,它不仅仅是 一个军旅题材的励志电视剧,却更象是一部浓缩版的引导心灵修炼的情景演义: “不抛弃,不放弃。” “每天都要做有意义的事。” “好好的活,就是做有意义的事。做有意义的事,就是好好的活。” “想到和得到中间还有两个字,那就是做到,只有做到才能得到。” “信念这玩意不是说出来的,是做出来的。” “人不是做出来的,是活出来的!” “人不能过得太舒服,太舒服就会出问题。” “只要今天比昨天好,这不就是希望嘛。” …… 坚持信念本身远比讲出信念、理解信念难得多,能够生存、发展、壮大的事业,往往首 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

6/127


PHP 新闻:2008 第三届互联网站长年会即将登场

《PHPer》

先有了坚贞的信念、以及更具体的维系信念的一件件有意义的事。 2008 年 4 月 19 日,康盛创想公司和落伍者社区合作发起第三届中国互联网站长年会, 将在总结过去、挑战现在、面向未来的基础上,发出“用信念去战斗”的新呼唤。从 2001— 2008, 这一年,也是双方成立 7 周年的日子。7 年之痒,印证“用信念去战斗”的具体行动是: 很傻很努力; 不抛弃,不放弃。 做小、做专,再做大; 开放、共赢,夺未来!

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

7/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

PHP 就业

从火箭连胜看团队素养 ―― 也谈程序员的团队精神 作者:肥同小可 动笔写这篇文章时,火箭已经被凯尔特人终止了连胜,辉煌的记录已然成为往事。 围棋大师聂卫平直言作为球迷“火箭 22 连胜纯属瞎蒙”,也是球迷的我对此实在不能苟 同,我同意大师开玩笑的说“中国足球要进步,请我当主教练还差不多”,因为那帮不争气的 家伙确实没什么值得国人期待的,但要说火箭是蒙到 NBA 联盟第二的连胜记录,实在有些过 于牵强和片面。诚如湖人队的科比在与火箭对战之前所言“火箭是让人尊敬的,在 NBA,创 造记录从来都没有偶然”。 什么是火箭连胜的秘诀,当家球星麦蒂给出了答案: “火箭是依靠团队的力量,不是靠某 一个人赢得比赛”。巴蒂尔也说:“我们连胜的秘诀就在于我们是个无比团结的团队,打法系 统和相互信任,这就是两大因素。” 还记得 2006 年 1 月 23 日,科比带领着湖人以 122-104 战胜多伦多猛龙,单场砍下 81 分, 当科比下场时,斯台普斯中心球馆的球迷全体站立鼓掌欢呼,连现场解说员也变得语无伦次, 媒体更以“最接近神的男人”大肆报道,这是何等荣耀……可是没有人留意湖人的主教练, 拥有九个 NBA 冠军戒指的杰克逊,赛后在激动之余他认为这样的比赛对球队本身没有太大的 帮助,因为“这不是一支球队要赢得比赛胜利所应该采用的方法”。杰克逊是对的,孤胆英雄 不能成就大业,不能带领湖人走得更远,直到这个赛季加索尔加盟湖人后,我们才看到了真 正强大的湖人,那是一个完整的团队,是一个强大的集体。 “最接近神的男人”,这里所说的“神”,就是乔丹, 科比是湖人的球队领袖和精神支柱,可惜还欠缺些乔丹的 王者之风,少了乔丹统帅群雄的能力。乔丹非凡的才能成 就了公牛王朝,至今仍记得高中时看公牛比赛的疯狂,即 便是面临高考的压力也无法阻挡我们看球的热情。 1997 年总决赛第五场公牛对爵士,乔丹患了重感冒, 肠炎也犯了,两天没有吃饭,一直在打点滴,但乔丹还是 带病上场 44 分钟砍下 38 分,带领公牛在落后 16 分时奋起 直追,直至最后翻盘。赛后的乔丹已无力走动,他虚弱的 倒在了皮蓬怀里,留下了感人至深的一幕。这让我想起近 期 NBA 一个公益宣传片的口号——“无兄弟,不篮球”, 如果没有皮蓬,没有罗德曼,没有库科奇……仅凭乔丹一 人之力能够缔造公牛王朝吗?也许我们只要看一看过去孤掌难鸣的科比就能找到答案。 从 NBA 球场反思职场,一个人在企业中,应该如何培养和建立自己的团队素养,如何融 入团队,在团队中发挥作用,进而获得团队及个人的成功,这对于程序员是个问题。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

8/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

程序员,这个职业,有一定的特殊性(至少外界这么认为)。程序员普遍给人的形象是性 格内向、生活邋遢、工作狂人、缺少情趣、难以沟通……总之,相比非程序员的人类来说, 个性十足,诚如业内的大牛,如谢顶的 Rod Johnson(Spring 的创始人)、大胡子的 James Gosling (Java 之父)、头发乱七八糟的 Guido van Rossum(Python 创始人)…… 在软件行业,个人英雄主义能走多远,这不好说,战场上能有几个兰博呢?我们看到现 在的软件巨擘,无论是微软还是甲骨文都“不是一个人在战斗”。作为一个程序员如何看待和 对待团队的问题,是每个程序员能否走向成功的关键。在这个行业混了多年,自己经历过, 也见别人经历过或正经历着,个人粗浅的认为,程序员如果想实现自我,可以有朝一日作为 项目经理带领一个团队,或者主持开发一个软件产品,甚至自己创办一个软件公司,至少要 解决的三个问题:自私、自我、自大。 本文无意去讨论什么是团队,团队的特征或者团 队应具备的条件,也不想把话题跑得太远扯得太大, 只希望可以给出作为程序员在团队中要克服的常犯错 误,若能给各位同僚一点借鉴,就不胜荣幸了。 中国人讲“众人拾柴火焰高”,“团结就是力量”, 可是我们也讲“一个和尚挑水吃,两个和尚抬水吃, 三个和尚没水吃” “龙多了旱,人多了乱”……如果说 团队是一艘大船,那么每一名队员就像船上舵手,大 家手中的船桨都向着一个方向使劲,船才会全速前进, 是否每个队员都能全力以赴齐心协力,决定了大船能 否乘风破浪全速航行。可惜,总有队员是背靠大树好 乘凉想偷懒省力的,总有队员会不断的抱怨天气寒凉 面包不够消极怠工的,总有队员畏惧艰苦临阵脱逃, 总有队员朝三暮四身在曹营心在汉……然后我们就看 到了一艘又一艘的大船沉没,也看到了一个又一个的 队员掉队…… 火箭能取得 22 连胜,又何尝不是如此呢,一个好的球队,要有人任劳任怨的干脏活累活, 要有人在局面被动时挺身而出,有人打前锋有人做后卫,有人部署战略有人经营球队…… 问题是我们如何处理个人和团队的关系,如果把握个人在团队中的位置和发挥应有的作 用。 程序员在一个团队中有三个常犯的错误:自私、自我、自大,仅代表个人观点,也许对 也许不对,只是希望各位看官看过之后有则改之无则加勉就好。

一、自私--关心只在五伦之内 自私,只顾自己的利益,不顾团队(公司)和别人的利益,关心的范围只在五伦(君臣、 父子、夫妇、兄弟、朋友)之内。古人讲父子有亲、君臣有义、夫妇有别、长幼有序、朋友 有信,现在当然没有了君臣,但是我们发现员工和老板之间好像很难有义…… 以前曾经听过不止一位同事或朋友讲这样一句话“给多少钱干多少活”,我相信看官您也 一定听说过甚至说过吧,问题是多少活等于多少钱呢?这个标准是我们自己定的,合不合理 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

9/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

就和老板和上司没啥关系了……全凭咱自己的感觉。结果我们就发现了,有的程序员不能接 受加班,甭管公司忙不忙产品赶不赶,我不能受委屈,即便留下来也是一百个不愿意;有的 程序员得过且过,能少做就少做,能不做就不做;有的程序员从来都是自己闷头做新人会不 会做有没有问题与我无关…… 我不是要替老板说话,不向着咱程序员,我想讲的是:一个人在企业里面工作,我们要 获得的是什么?如果你回答只是金钱,OK,你没有错。可是我在想,一个人如果只是为了钱 在工作,是多么的可悲。我总觉得一个人的工作,应该是有兴趣和有乐趣的,因为工作是生 活中一个重要的组成部分,如果只是为钱而忙,为钱而编程,我想这份工作也许很难让你获 得快乐。 我总觉得,一个人在职场,在一个团队里面,除了谋生计,我们 可能还要追求更多的东西,比如成就感、比如朋友、比如与团队一起 的成长和成功。就像马云在阿里巴巴上市后员工大会上讲的,阿里巴 巴创业初期,处境艰难,受不了苦的走了,嫌赚钱少的走了,剩下的 都是一心希望跟着阿里巴巴成功的人,结果现在当初留下来的人很多 都变成了百万甚至千万富翁。 曾认识很多程序员,不愿意带徒弟,团队中的新人,不愿意花精 力去教他,真应了那句老话“教会了徒弟饿死了师傅”,可是真是这样 吗,难道做技术就都需要这样?我总觉得帮助别人成长自己才能更快 的进步,而且在这个过程中你会收获更多的兄弟和朋友,这些可能都 是你未来可能成就事业的基础。可是……我们看到太多太多“自私”的案例。 如果一个球队的球星太“独”,总是无论机会好不好都自己出手,而不愿意与队员分享或 者留意团队合作,这个球队是不可能成为一流的,毕竟,篮球是五个人的事。听说乔丹当年 对每个公牛的队员都要求严格,训练有素,且自己带头做最多的训练,每个人在这样的氛围 下,都得到了迅速的成长,这样才成就了公牛王朝。 一个人再强,毕竟有限,曾经看一场 NBA 的比赛,评论员在评价科比的完美表现时,不 惜使用了“人中吕布,马中赤兔”的赞美,可是,团队整体不强的湖人,还是无法再现辉煌。 一个人的强要变成整个团队的强,团队的成功也是个人 的成功,如果太在意自我得失,什么事情都斤斤计较, 你会变得小气,会变得自私。只有一个人能努力的在团 队中工作,你会逐渐积累自己的能力、人脉,当你配合 或者带领团队取得成功的时候,如果你期望的金钱还没 有如期而至,我想即便你有些沮丧,不过你也可以自豪 得带着你的作品(你参与或主持开发的软件或者项目) 转投明主,甚至你会发现因为你的“不自私”,会有很 多老朋友老同事在他们现在公司需要人的时候,第一个 想到你,只因你曾是他们的兄弟,他们的朋友。 正如《道德经》所说“既以与人己愈有,既以予人己愈多。”说的通俗点,就是你给别人 的越多你将会获得的越多,比如友情、比如信任、比如尊重…… 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

10/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

二、自我--别人的问题与我无关 每天做地铁上班的时候我都会留意观察,总会有人一坐到座位上不管人多不多就翘起了 二郎腿;总会有人不管空间大不大就摊开了报纸;总会有人毫不顾忌的高谈阔论……这种心 态就是一种自我。 在公司工作,我们自己的工作做完以后,会去主动帮助别人吗,大多数程序员我看都是 自己做完了没事看到人家忙得要死还在旁边偷笑“笨蛋,做这么久都做不完”。其实,你主动 帮助别人人家很感激你的。工作做完了,主动问你的主管还有什么工作啊,你的主管会觉得 你做事很主动的,要升职也是升你这种人啊,那种勉强干完了自己的事其他什么都不愿意做 的家伙,你看看,有几个后来得到重用升了职加了薪的,即便有,我想十有八九也是用人的 主管瞎了眼睛看错了人。 自我,是我们经常犯的一种错误,不能够换位思考,站在别人的角度考虑问题,凡事以 自己为中心,不考虑别人的感受,都是一种自我的表现。市场学里面经常讲一句话“穿着别 人的鞋走路”,可是,很多人嘴上都是讲“我是为你好啊”,实际呢,都是自己的鞋还没脱就 扑哧一下踩到别人的鞋里了,那个内心还是自己的想法,只是表面上好像站在了对方的立场 上而已。 接触大多程序员的哥们,都是能完成自己的工作就好,然后上上网扯扯淡,总之即使闲 得再无聊也不会主动请缨,就像你很少见到有同事主动找主管或老板讲“头,我手头负责的 事情做完了,您看还有什么需要做的?”,这样的人,我没见过几个,多数都把安排的工作能 按时按质按量做完就烧高香了。 NBA 球场上我们也经常看到这种自我,那些大牌球星,大多有些自我为中心,就像当年 湖人的奥尼尔和科比,即便今天的火箭姚麦组合也是时传不合,这种过于自我也导致了太多 的球队众星云集却成绩不如人意。开发团队又何尝不是如此 呢,如果除了项目经理之外,每个人都各扫门前雪,我想这 个团队不会是一个具有较强战斗力和效率的团队。 战争大片在展现赛场的惨烈之前,都会着相当的笔墨来 描写战士间的友情、互相理解和帮助、朝夕相处以及他们共 同吃喝、一起休息的细节。为什么要这样做呢?彼此了解、 相互尊敬— — 才是让团队成员彼此间产生战斗力的基础和 必备条件。你能想象一个除了比赛,在训练场、更衣室一言 不发的球队会在比赛的关键时刻心有灵犀么?多体谅别人的 难处,多关心别人的不便,勇于承担责任,敢于面对问题, 你才有可能成为团队中让大家信赖的人。 这里,说一个小事情,我认识的一个朋友,一个公司的 项目经理,和我讲过这样的一件事情,希望每个做主管的朋 友可以引以为戒。有一天,他早晨到了公司,负责的项目进 度落后,可是有一个程序员居然在这关键时刻,上午十点才 到公司,他就很生气的质问这位迟到的同事:“你为什么这么晚才来,我需要你的解释!”结 果……那个同事是因为母亲突然病重赶往医院所以迟到了,不久以后,这个程序员就离职了。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

11/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

这个项目经理追悔莫及,失去了这样一位优秀的程序员。这种就是想法过于自我没有考虑对 方是否有难处,所以现在他对待下属有人迟到,每次都会问: “怎么迟到了?有什么需要我帮 助吗?”,如果是昨晚喝酒喝多了迟到的,他就会愧疚,你这样问几次以后你不说他,他都不 好意思迟到……换一种方式,多为对方考虑,你会发现,团队的沟通没有那么困难。 “己所不欲,勿施予人”,切记,切记。

三、自大――我的想法就是答案 我发现一个很有意思的现象,我们中国人表面上都非常谦虚,可是骨子里却又非常好胜, 尤其是程序员,表面相处时多会夸赞对方能力好技术强本领高,可是私下里又会拆对方的台 说对方的不是,会不服气。这是一种自大。 毛主席老人家告诉我们:谦虚使人进步,骄傲使人落后。问题是我们是真的谦虚吗?我 个人认为,狂要有狂的资本,只要有资本狂一点倒也是没什么,可是我往往见到的,都是一 瓶子不满半瓶子晃荡的程序员在狂妄……我过去的一个老同事,是一个很牛的程序员,香港 人,技术暴强(只所以这么形容,是以为他是我迄今为止见过最牛的程序员),可是却特别谦 虚,有的时候我问了他问题看他认真详细讲解不让你明白不罢休的样子,我真是感慨啊…… 正所谓人应学水,小溪小河哗啦啦,大江大海无声响。 每个人都有值得我们学习的地方,每个人都有他的优点,可惜我们往往看到团队中其他 的成员都是先看到对方的缺点,都是先拿自己的优点去和对方的缺点比较…… 夜郎自大,让人厌恶还是其次,会失去更多朋友和信任,才是更可悲的事情。 一个人在一个团队中,真正能够让人记住的,往往都是他娴熟的技术和谦虚的品德,如 果你是做一个主管,更要谨记,千万不要总是认为自己的想法就是答案,不要觉得自己是技 术专家,常常自以为是。 多听取别人的意见,多借鉴别人的观点,既然是一个团 队,就是要互补,就是要团结,不要一有不同的声音就表达 我们的不满,即便表面上同意内心里面也不接受,这往往会 造成整个计划执行的失败。 “海纳百川,有容乃大”,还记得吗,火箭连败时,许多 人质疑麦蒂的敬业精神;火箭连败时,许多人质疑阿尔德曼 的执教能力;火箭连败时,许多人质疑经理莫雷的交易策略。 但是,他们选择了沉默。这个时候,沉默就是一种力量。火 箭 22 连胜,还有人质疑阿尔德曼的战术吗?还有人麦蒂的领 袖气质么?还有人质疑莫雷的球员交易么?— — 事实胜于雄 辩。 胜利不是争吵得来的,胜利也不是抱怨可以获得的,胜 利更不是勾心斗角可以换取的;胜利需要靠真正的实力,胜 利需要靠整体的团队,胜利需要我们摒弃自大虚心向上。 如果今天你还是一个程序员,不自大是你能够成为团队领袖的基础;今天如果你是一个 项目经理,不自大是你能够带领团队的前提;今天如果你是一个老板,不自大是你能够看清 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

12/127


PHP 就业:从火箭连胜看团队素养

《PHPer》

自我的镜子……一个人有能力或有成就也许不难,难就难在具有了以后能够不自大,古人讲 “小时了了大未必佳”,说的就是这个事情。现在太多的年轻人,年纪不大,就当了主管甚至 做了老板,你能否带领一个团队?想一想刚愎自用的项羽和从善如流的刘邦吧。 自私、自我、自大,如果我们都能够不断的自我历练,不断的修炼自己,相信不管你在 任何一个团队中,都能够找到自己的位置,都能够成就团队也成就自我,团队和个人不是一 个矛盾体,而是相辅相成共荣共生的,个人的成长离不开团队,而团队的进步会带动个人的 发展,意识到这个关系,相信如果你有以上的问题,大概都可以有所意识并尝试改进了吧…… 生活不会总是一帆风顺,人生和职场就像篮球赛,困难和麻烦不是终止我们连胜的原因, 不要把这场比赛中的表现带到下一场比赛当中— — 无论是积极的表现还是消极的表现。如果 我们培养出了一种团体责任感和荣誉感,那么当失败或错误发生的时候,我们就不是一个人 在战斗,我们能更容易的同舟共济,并以一种积极的态度去继续下一场比赛,但愿我们每一 个人都是胜利者。 NBA 有句口号:“I love this game! ”,希望你的职场也如赛场,是你所热爱的。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

13/127


PHP 推广活动:2008 年 PHPChina 全国巡讲

《PHPer》

PHP 推广活动

2008 年 PHPChina 全国高校巡讲 作者:肥同小可 2007 年,《第一届 PHP 中国开源发展及人才状况调查》结果显示,国内 PHP 人才缺乏, 其中两个主要原因分别是:“大学教育体系限制”和“人才对 PHP 技术认知程度肤浅”,这 直接导致了大学生对 PHP 技术的了解匮乏,从事 PHP 开发工作人员数量减少,也直接限制 了国内基于 PHP 技术的应用发展。 为在全国各个大学推广 PHP 技术,让更多的大学生了解 PHP 技术、学习 PHP 技术、使 用 PHP 技术,并可以此求职或创业,PHPChina 开源社区决定开展全国范围内的 PHP 技术大 学校园巡讲,希望籍此可以为国内的 PHP 技术发展尽一份力。 活动自 2008 年 3 月 15 日开始,所有国内的大学院校都可以联系参与,讲座主讲嘉宾由 PHP 领域的资深程序员、项目经理、软件开发者等担任,由 PHPChina 根据地域、受众等情 况统一来协调安排。关注此次巡讲请留意活动页面:http://www.phpchina.com/activity2008, 各地大学讲座活动信息将在 PHPChina 论坛 PEA 版块发布,欢迎有兴趣的同学关注并参加交 流。 也欢迎各个大学院校与我们共同进行 PHP 技术普及,在大学里推广 PHP 技术、LAMP 技术、开源技术,拓宽大学生的视野,增加大学生的就业方向,推动国内开源技术发展。

成都理工大学

北京联合大学

大连海事大学

济南职业技术学院

天津大学

怀化学院

过去的一年,我们走过了很多的大学,可惜这也只是冰山一角,希望可以籍此活动抛砖 引玉,让更多的 PHP 爱好者、更多的大学、更多的企业参与进来,在我们共同的努力下,让 PHP 技术得以更好的推广和普及。万里长征总要走出第一步,就如同 Linux 在中国走过的历 程,我们期望开源软件可以在中国得到更好的发展,更广泛的应用。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

14/127


PHP 推广活动:2008 年 PHPChina 全国巡讲

《PHPer》

我们热诚的欢迎更多的 PHP 技术高手可以参与进来,为推动 PHP 技术共同努力,让大 学生可以学习到最新的技术,可以了解未来如何面对就业和看待创业,分享我们的经验和心 得,讲授我们的技术和理念,如果您也有意加入我们的团队请联系我们,虽然我们不能收获 鲜花与金钱,但是我们可以拥有掌声与尊重,推动中国开源事业的发展,是信仰更是实践, 期待您的加入。

SupeV 创始人骆超

康盛创想 CEO 戴志康

PHPChina 创始人耿志军

ShopNC 创始人白菜

感谢过去及现在一直在为推广 PHP 技术、推广开源技术而做出努力的每一个人,也盼望 更多的人成为我们这个团队的一员。 一个社区的力量,总是有限的,众人拾柴火焰高,要在国内更好的推广 PHP 技术,需要 更多的组织和个人加入进来,无论是可以为我们的大学生传授知识和经验,还是可以进行活 动的组织,或者可以合作推广,甚至是可以为大学生提供些小奖品,我们都期望您的加入。 特别鸣谢以下合作推广企业: 深圳市浪点科技有限公司(http://www.redphp.cn) 电子工业出版社(http://www.phei.com.cn) 康盛创想(北京)科技有限公司(http://www.comsenz.com) “PHPChina 中国开源之路”,是理想更是目标,路很长,夜很黑,可是,没有比人更 高的山,没有比脚更长的路,只要我们在努力,理想与目标就会离我们越来越近…… 联系我们: 电话:010-51657885-831

网站:http://www.phpchina.com

邮件:liming#phpchina.com(发送邮件时请把#改为@)

投稿:phper@phpchina.com

《PHPer》

15/127


PHP 企业招聘:环球时报-环球网

《PHPer》

PHP 企业招聘

环球时报-环球网 招聘信息 工作地点:北京 招聘人数:4 人 要求学历:大专 薪水待遇:4000-8000(RMB) 招聘职位及要求: 3 年以上的 PHP 开发经验; 2 年以上的 MySQL 的使用经验; 对 PHP API 基本了解; 对 PHP 系统测试和 Debug 工具有相对了解; 有使用 PHP 搭架构的经验; 对 Apache 内部架构了解者优先; 对*nix 系统非常了解; 有编写过高效率大网站代码者优先; 精力充沛,有团队精神; 优良的处事和沟通能力,能够和各级别的员工进行沟通。 联系方式: 联系人:PHPChina 伯乐 QQ:752719295 电话:13146612015 公司介绍 环球网(www.huanqiu.com)是经人民日报社批准,由环球时报社全资主办的一家以国际 资讯为主的新闻网站。作为环球时报的网络平台,环球网继承了环球时报的一贯风格,继续 专注于中国人视角下的国际新闻报到,不断向世界传达中国人的声音,立志成为世界与中国 互相了解的桥梁。因事业发展需要,现诚聘热爱网络媒体事业,有强烈事业心、较强创新能 力和良好团队协作意识、身体健康的人士加盟。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

16/127


PHP 企业招聘:欧洲软件公司 Bysoft

《PHPer》

欧洲软件公司 Bysoft 招聘信息 工作地点:广州 招收人数:3人 要求学历:本科 薪酬待遇:5000-10000(RMB) 职责范围: 1、网站和程序设计和开发; 2、为程序开发准备文档; 3、提供应用系统支持; 4、履行与IT有关的项目。 职位要求: 本科毕业、主修计算机科学、信息技术或与信息技术相关的学科; 2年左右使用HTML、PHP、Java进行网站开发的经验; 有SQL数据库的实际经验,并有SQL的技术能力; 有使用Dreamweaver或PhotoShop的经验更佳; 有使用Java和J2EE的经验更好; CET4以上,能进行流利的听、读、写; 良好的团队合作精神和沟通能力; 良好的学习能力、分析能力和活跃的思维能力,并愿意接受新挑战; 能承受工作压力; 准备在一个国际公司工作。 联系方式: 联系人:PHPChina 伯乐 QQ:752719295 电话:13146612015 公司介绍 Bysoft 是一家领先的法国网络技术公司,总部设在法国(巴黎),并在中国(广州)设 有办事处。我们专注于有关网站建设、互联网软件、网络应用,等有关互联网应用的开发。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

17/127


PHP 企业招聘:欧洲软件公司 Bysoft

《PHPer》

Bysoft 创建于 1991 年,在电子商务领域已拥有 16 年以上的经验。在过去几年里,我们专注 于电子商务的解决方案的领域,现已成为法国著名的 osCommerce 开发商。我们利用开放源 代码解决方案建立的网上商店,具有无可比拟的灵活性、可伸缩性以及安全性。现在,我们 的客户正在不断地品尝到胜利的果实,他们的在网上的销售额已超过 2000 万美元。今天,我 们继续在互联网的领域拓展服务,提供多样的网络应用方案、让客户体验快捷的服务以及网 上咨询等业务。 业务范围:网上商店的建立、内容管理系统(CMS)、门户网站的建立、多样的互联网 应用 Ajax、Flash、Flex、电子商务互联网软件、CRM、商务关系管理系统、网页设计、用户 界面设计、Flash 动画制作、互联网方案策略、网上营销与网上度量、技术或非技术的咨询。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

18/127


PHP 企业招聘:深圳金蝶软件有限公司

《PHPer》

深圳金蝶软件有限公司 招聘信息 工作地点:深圳 招收人数:3人 要求学历:本科 薪酬待遇:10000(RMB) 职位描述:Web应用系统架构架构、设计、开发和优化; 任职资格: 1、计算机相关专业大学本科以上学历,具有扎实的计算机基础理论知识; 2、三年以上业界工作经验,具有大型互联网应用设计、开发经验; 3、精通PHP语言,精通Web标准和HTTP等互联网协议; 4、熟练掌握HTML语言、JavaScript脚本语言; 5、熟悉Unix/Linux操作系统和开发环境,能够熟练配置Apache服务器; 6、具有一种以上关系型数据库应用开发经验,熟练MySQL。 联系方式: 联系人:PHPChina 伯乐 QQ:752719295 电话:13146612015 公司介绍 金蝶国际软件集团有限公司总部位于中国深圳,始创于 1993 年 8 月,于 2005 年 7 月 20 日在香港联合交易所主板成功上市。 金蝶国际软件集团有限公司是中国第一个 Windows 版财务软件及小企业管理软件— 金蝶 KIS、第一个纯 Java 中间件软件— 金蝶 Apusic 和金蝶 BOS、第一个基于互联网平台的三层结 构的 ERP 系统— 金蝶 K/3 的缔造者,其中金蝶 KIS 和 K/3 是中国中小型企业市场中占有率最 高的企业管理软件。2003 年 3 月,金蝶正式对外发布了第三代产品— 金蝶 EAS (KINGDEE ENTERPRISE APPLICATION SUITE)。金蝶 EAS 构建于金蝶自主研发的商业操作系统— 金蝶 BOS 之上,面向中大型企业,采用最新的 ERPⅡ管理思想和一体化设计,有超过 50 个应用 模块高度集成,涵盖企业内部资源管理、供应链管理、客户关系管理、知识管理、商业智能 等,并能实现企业间的商务协作和电子商务的应用集成。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

19/127


PEA 活动:PEA 的 2008 在沉默?

《PHPer》

PEA 活动

PEA 的 2008 在沉默? 写这个主题,主要是为了提醒我们不要停止我们前进的步伐,同时也是在鞭策自己。从 2008 年 1 月份以来全国 PEA 活动寥寥无几,基本上只有北京和上海有活动,重庆和成都有一 次活动,虽然正在筹备的地方无数,但是发起来活动的却几乎没有。为什么会这样呢?总结 一下有以下几点: 1、 我自己的问题:做为 PEA 的会长,我自己因为 2008 年开始公司的事情比较多,投入了 更多的时间和精力做销售的工作。这是我的问题,虽然公司产品销售是我的任务,但是 PEA 的发展也同样是我的任务,以后就算工作忙,也需要投入更大一部分时间和精力来 组织协调全国的 PEA 活动,给予地方 PEA 更多的支持。 2、 各地方常委的问题:可能由于地方常委个人技术的提升,职位也在提升,工作任务也在 增加,所以投入到 PEA 的时间和精力减少。但是个人感觉这些都是相对的,如果说没有 全国 PHP 的发展,没有 PEA 的推动,或许大家都不会得到重用,不会得到重用,那么 你的工作还会忙吗?每个人都不希望停止不前,每个人都不希望从此以后人脉冻结,因 此,还是需要多花一点时间和精力在 PEA 上面,因为只有 PEA 发展了,你的提升空间 才会更大,你的人脉才会更广,那么你自己也就会更加进步。 3、 各地资源和信息封闭的问题:在 PEA 建设初期,由于各地方本身没有联系在一起,没 有形成一个交流圈,所以很想互相认识、互相交流,但是等到有了一定的群体之后,就 认为已经可以不需要全国性的交流就可以独立成长。其实并非这么容易的,如果我们不 是做互联网的这么想还可以理解,但是我们都是做互联网的,怎么可能狭隘在一个地 方?并且除了上海和北京,很多地方的技术还是比较薄弱的,如果大家都封闭在一个地 方交流,那么你的技术能进步吗?进步能快吗?居然处于 PHP 顶端的城市北京和上海都 在努力的交流学习,为什么反而不在顶端的其他城市地方交流却少了呢? 4、 没有好好利用 PEA 这个平台:如果要是说在 PEA 建立初期,各地方的呼声少,我还可 以理解,但是恰恰相反,初期呼声很高,到现在发展有起色了,却反而大家没有激情了。 为什么平台大了,成员越来越多了,交流的机会越来越好了,反而大家不去利用这么大 的一个平台了?是的,PEA 本地化很重要,但是光本地化,没有互相之间的联合,那怎 么能让本地成长呢?希望各地能更好的利用这个平台,互相之间协作交流,共同发展, 齐头并进,将全国各地 PEA 都能够像北京上海一样,带动整个 PHP 行业的发展,只有 整个行业发展了,你— — PHPer 才能得到发展! 5、 PEA 总会的支持问题:PHPChina 作为 PEA 总部,与 Comsenz 合作,有了资金,有了自 己的盈利模式,就会有更多的能力来支持 PEA 地方。但是如果各地方并没有做出成绩, 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

20/127


PEA 活动:PEA 的 2008 在沉默?

《PHPer》

并没有发展,那么怎么来支持地方呢?各地方活动我们提供礼品、提供虚拟空间、提供 资源,可能在资金方面提供的少,但是我们说过,如果地方活动组织的好,我们会给与 地方部分基金的支持,包括场地资源的支持。当然我们不能给地方常委发工资,我们要 清楚本来 PEA 就是公益的,我们本身并不是盈利的,作为常委和会员在活动中得到了主 要是知识和人脉,如果是以作活动盈利为目的,那么就偏离了我们的宗旨。我们地方的 盈利不会是 PEA 直接给的,而是通过知识、人脉、名气,得到当地企业的认可,间接的 收益。各个地方的常委和会员可以思考一下,如果没有 PEA,你们的发展能这么快吗? PEA 的 2008 在沉默?我们不能沉默,我们离沉默还早呢,我们现在就沉默,那么我们就 停滞不前。我想没有一个人希望自己停滞不前吧,水往低处流,人往高处走,哪个人不希望 自己进步,哪个人不希望自己拿高薪,哪个人不希望自己有事业,哪个人不希望自己有外快? 我们只有继续向前进,只有更加的努力,只有更多的付出,才能得到更多的回报。 2008 是我们中国的 2008,我们 PEA 也应该在 2008 登上新的高峰,希望 PEA 全国所有 成员都能够与 PEA 一起在 2008 共同发展,共创 PHP 的辉煌!

最后附上 2008 年以来几个精彩的 PEA 活动: 北京 PEA “引领 Web 2.0 技术— PHP+MySQL 开发与就业前景”讲座

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

21/127


PEA 活动:PEA 的 2008 在沉默?

《PHPer》

PEA 重庆

PEA 重庆第四次聚会

PEA 济南

PEA 济南走进 Eorid 公司技术交流活动

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

22/127


PEA 活动:PEA 的 2008 在沉默?

《PHPer》

PEA 北京 北京 08 年 3 月份 PEA 活动总结

PEA 上海

上海 08 年 1 月“国际技术活动”总结

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

23/127


行业展望:CMS 大全

《PHPer》

行业展望

CMS 大全 作者:Samsung 对国内和国外使用 PHP 开发的 CMS 系统做一个简单的介绍,便于大家对各种 CMS 系统 的认识和了解。

国内主流的 CMS 系统 ※ HBcms 一个以 PHP 官方推荐的 PEAR+Smarty 技术架构的 CMS,2006 年才推出,完全符合 CMS 的发展趋势,简单、易用、美观。我本地测试了一下,很容易上手,特别适合没经验的新人 做网站。起码不会被复杂的功能吓倒。当然,它同样有各种复杂的功能,只是看你是否需要 用到了。使用 PHP 官方推荐的 PEAR+Smarty 技术,是这个 CMS 能持续发展的一个重要的特 点,很多功能都直接使用 PEAR 的类库完成。安装一步到位,默认附带了一些模板,值得推 荐。值得注意的是,官方网站宣称以后要开源,如果真这样,熟悉 PEAR 的 PHP 程序员就容 易上手了。 中文版官方:http://www.hbcms.com/ ※ PHPCMS 一个综合的网站管理系统,由 PHP+MySQL 构架全站生成 HTML,能够快速高效地应用 于 Linux 和 Windows 服务器平台,是目前中国 Linux 环境下最佳的网站管理应用解决方案之 一。 官方:http://www.phpcms.cn/ ※ PHP168 PHP168 整站系统,代码全部开源,可方便的进行二次开发,功能模块可以自由安装与删 除,个人用户免费使用。 官方:http://www.php168.com ※ 帝国网站管理系统 Ecms 全称为“帝国网站管理系统”,英文译为“Empire CMS”,简称“Ecms”。Ecms 是 基于 B/S 结构,且功能强大而易用的网站管理系统。 官方:http://www.phome.net ※ DEDE 这是一套令人爱憎分明的系统,首先它是国内一款开源的系统,2.x 的时候功能都已经令 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

24/127


行业展望:CMS 大全

《PHPer》

它的 fans 为之疯狂,非常灵活的定制、强大的功能、简洁的操作,但 2.x 的瓶颈问题:大数 据处理,到 3.0 的时候可能会解决,但 3.0 的一直跳票,迟迟不见发布,另很多人都非常失望, 希望能在 3.0 的时候看到一个全新的 Dedecms,当然也支持开源产品。 官方:http://www.dedecms.com ※ SupSite 一款将论坛资源自动转换成门户网站的 PHP 程序系统,使用 SupeSite 并利用你现有的论 坛,你将自动拥有一个功能完备的资源丰富的站点系统;由论坛变成网站,一切都是自动完 成,你不需要任何干涉,让你轻轻松松实现建立网站的目的。 官方:http://www.supsite.net ※ PHPArtile 这个算是国内 phpCms 的祖宗了,PA 由 PHP 语言开发,使用 MySQL 数据库保存数据, 为中小型网站发表文章、存放资料、新闻发布提供一个完美的解决方案。做了好几年了,3.0 迟迟还在开发中,今年出了 2.1 火了一阵又熄灭了,以前用的人挺多的,现在基本上没落了。 官方:http://www.21ds.net/ ※ 随易全站系统(Cmsez) Cmsez 集成了丰富的功能模块,包括用户管理、新闻发布、信息发布、产品展示、图片 管理、附件管理、在线商店、资料下载、多媒体浏览/播放等。 官方:http://www.cmsez.com ※ CMSware 一个非常不错的 CMS 系统,比较看好的他的后台操作简介,一些新技术,比如 Ajax 的 应用、Wap 的功能、还有它的 PSN 的发布、节点和模块的定制、自定义模型、数据库字段, 率先引进的工作流的概念,更多的发布自由度,非常强大的模板体系,确实处处体现了自由 的思想,让您体验自由管理的非凡感受。 官方:http://www.cmsware.com/ ※ 风讯网站内容管理系统(FoosunCMS) 风讯公司积多年经验、通过设计师们精心设计的符合国际要求的网站信息管理系统。 官方:http://www.foosun.cn

国外的一些主流 CMS 系统 ※ 曼波-MAMBO 一个国外的 CMS 系统,功能很强大,支持添加很多组件,模块;拥有丰富的模板。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

25/127


行业展望:CMS 大全

《PHPer》

官方:http://www.mamboserver.com ※ 凌波-Limbo(Lite Mambo) 顾名思义,是从 Mambo 演化而来。其目的是在继承 Mambo 一些强大的功能和特性的同 时,对原 Mambo 系统进行简化,使之变得更加轻便小巧。同时,Limbo 支持三种安装方式: TXT、Mysql、SQLite。 官方:http://www.limbo-cms.com ※ toenda 有德式的严谨,支持 PostgreSQL 和 SQLite,小型网站应用够了。 官方:http://www.toenda.com/ ※ Joomla 最火爆的 CMS,模板众多,人气很旺,发展空间大。预计 1.1 版开始提供数据库抽象层, 支持 PostgreSQL。 官方:http://www.joomla.org/ ※ Typo3 典型的德式产品,真正以内容为中心的管理系统,精细的控制,扩展库规模巨大,很难 相信会有这样大型的 Open Source 软件。有数据抽象层扩展,间接支持 PostgreSQL。 官方:http://www.typo3.org

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

26/127


新手乐园:使用 SimpleXML 处理 XML 文件

《PHPer》

新手乐园

使用 SimpleXML 处理 XML 文件 作者:乔聪

1 SimpleXML 简介 要处理 XML 文件,有两种传统的处理思路:SAX 和 DOM。SAX 基于事件触发机制, 对 XML 文件进行一次扫描,完成要进行的处理;DOM 则将整个 XML 文件构造为一棵 DOM 树,通过对 DOM 树的遍历完成处理。这两种方法各有优缺点,SAX 的处理思路相对抽象, DOM 的处理过程相对烦琐,都不很适合新手的入门。 PHP5 推出了一套新的 XML 处理函数,即 SimpleXML。名如其实,SimpleXML 本身小 巧精干,只提供了少量的几个方法函数,但用它处理起 XML 文件功能却非常强大,操作也 非常的简单。 首先,它提供有简单的函数可以从 XML 文档、字符串、或 DOM 对象上直接构造出 SimpleXMLElement 对象;其次,SimpleXMLElement 提供有简单的方法可以进行属性、子节 点、和 XPath 的操作;然而,SimpleXML 最简单的地方是,它提供有使用标准对象的属性和 对象迭代器进行节点操作的方法,这一处理思路使得用 PHP 对 XML 文档的处理得到了极大 的简化。

2 SimpleXML 入门示例 下面我们通过一些小的代码片段,稍微了解一下 SimpleXML 的强大和简洁。为举例方便, 我们使用一个 Messages.xml 文件,里面包含这样一段 XML 代码: Messages.xml <?xml version='1.0' standalone='yes'?> <Messages> <msg id='1'> <title>This is Title</title> <content>Here is Content</content> <time>2008-03-20 21:50:23</time> <reply id='11'>reply 1</reply> <reply id='12'>reply 2</reply> </msg> </Messages>

这是一篇保存有留言信息的 XML 文档,每条信息包括属性 id,子节点 title、content、time 以及若干条对于它的回复信息,每条回复包括属性 id 及回复的内容。 用 SimpleXML 处理并输出此 XML 文档内容的过程以及方法如下。 (1) 构造 SimpleXMLElement 对象 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

27/127


新手乐园:使用 SimpleXML 处理 XML 文件

《PHPer》

代码片断 $xml = simplexml_load_file('Messages.xml');

如果这段 xml 已经被读入到一个字符串$messages 中,则可以使用如下语句: 代码片断 $xml = simplexml_load_string('Messages.xml'); (2)输出留言 1 的标题 代码片断 //可以使用属性的方式访问子节点,通过节点的标签名可直接得到节点的内容 echo $xml->msg->title;

(3)输出留言 1 的第一条回复信息 代码片断 //同级别的多个同名节点自动成为数组,可以通过索引下标访问其内容 echo $xml->msg->reply[0];

(4)输出留言的 id 代码片断 //节点的属性与值被封装成为关联数组的键与值 echo $xml->msg['id'];

(5)输出第二条回复的 id 代码片断 //成为二维数组,第一维表示节点,第二维表示属性 echo $xml->msg->reply[1][ 'id'];

(6)依次输出所有回复的 id 代码片断 //使用 foreach 对同名节点进行遍历 foreach ($xml->msg->reply as $reply){ echo $reply['id']; }

(7)使用 XPath 检索所有的回复信息 代码片断 //xpath 方法直接检索定位(//表示任意深度) foreach ($xml->xpath('//reply') as $reply){ echo $reply.'<br>'; } 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

28/127


新手乐园:使用 SimpleXML 处理 XML 文件

《PHPer》

(8)遍历留言 1 所有的子节点 代码片断 //children 方法得到所有子节点 foreach ($xml->msg->children() as $field){ echo $field.'<br>'; }

(9)重新设置留言 1 的发布时间 代码片断 //直接设置属性 $xml->msg->time = '2008-03-21 00:53:12';

(10)设置回复 2 的 id 属性 代码片断 //设置管理数组的值 $xml->msg->reply[1]['id'] = '222';

(11)新增一个描述消息作者的字段 代码片断 //直接设置属性 $xml->msg->author = 'zhangsan';

(12)将消息的作者保存为属性 代码片断 //设置关联数组的 key $xml->msg['author'] = 'zhangsan';

(13)重新保存对象到文件 代码片断 //保存 $xml->asXML('MessagesNew.xml');

应该可以看出 SimpleXML 有多简单了吧!

3 实例:XML 文件与数据库之间进行数据交互 下面提供一个相对完整的实例,将留言信息从 MySQL 数据库中查询出来,保存成为一 个如上例所示的 XML 文件。留言信息和回复信息独立保存在两张表中,使用 MySQL 函数包 可以非常简单地实现如下: 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

29/127


新手乐园:使用 SimpleXML 处理 XML 文件

《PHPer》

代码如下: <?php //cong work at Wed Mar 20 19:59:04 CST 2008 //将数据从 MySQL 数据库中保存到 XML 文件中 //可以使用如下几种方式构造初始的 SimpleXMLElement 对象 //1、从 DOM 对象中构造 //$dom = new DOMDocument(); //$dom->loadXML("<rows></rows>"); //$xml = simplexml_import_dom($dom); //2、从仅包含根标签的 xml 文件中构造 //$xml = simplexml_load_file('messages.xml'); //3、直接写根标签字符串构造 //$xml = simplexml_load_string("<Messages></Messages>"); //4、使用 SimpleXMLElement 类的构造器构造 $xml = new SimpleXMLElement('<Messages></Messages>'); //连接数据库 mysql_connect('localhost','root','root'); mysql_select_db('test'); mysql_query('set names utf8'); //查询消息 $rs = mysql_query("select * from messages"); $i = 0;

//用做多条消息的数组索引下标

while($row = mysql_fetch_assoc($rs)){ $xml->message[$i] = '';

//… … … … … … … … … … … … ①

$xml->message[$i]['id'] = $row['id']; $xml->message[$i]->title = $row['title']; $xml->message[$i]->content = $row['content']; $xml->message[$i]->time = $row['time']; //根据消息 id 查询它相关的回复信息 $rsReply = mysql_query("select * from replies where mid={$row['id']}"); $j = 0;

//用于做多条回复的索引下标

while($rowReply = mysql_fetch_assoc($rsReply)){ $xml->message[$i]->reply[$j] = $rowReply['reply']; $xml->message[$i]->reply[$j]['id'] = $rowReply['id']; $j++; } $i++; } $xml->asXML('messages.xml'); ?>

上述代码唯一值得一提的地方就是标志①的那行。当我们要向一个 SimpleXML 对象中新 增一个节点或属性时,必须保证它的父节点是存在的,否则会报一个致命错误,提示信息是: Objects used as arrays in post/pre increment/decrement must return values by reference。希望大家 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

30/127


新手乐园:使用 SimpleXML 处理 XML 文件

《PHPer》

不要被这段不知所云的提示所迷惑。 相信读者能通过对上述代码的了解,对等地写出一个从 XML 文件到 MySQL 的代码出来。 作者介绍: 乔聪,PHPChina 济南培训中心教学总监 QQ:23750125 博客:http://www.Road2Lamp.com/blog

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

31/127


代码分析:PHP 缓存的实践

《PHPer》

代码分析

PHP 缓存的实践 作者:傻大猫

前言 本篇的代码是产品 SupeV 中的一部分,用于管理该产品的数据缓存。SupeV 是 Comsenz 公司开发的一套视频播客系统,基本上囊括了现阶段主流视频网站所拥有的全部功能,如视 频的上传、播放、分享等应用,此外还包括用户的博客空间、个人专辑、最新最热关注等增 加用户体验的细节功能。此外,SupeV 还采用了独特的站外引用机制、高性能模板机制、搜 索引擎完美收录技术、Ajax 技术等。开发小组程序员有 langwan、侠客、傻大猫等。

简介 Web 服务器端程序开发的一个重要问题:就是大负载情况下的访问速度问题;对于流量 很高,数据量很大的网站,就是让用户访问这个网站的感觉与单一用户访问一个静态页面时 的感觉一样。 很多时候,瓶颈出现在数据库的连接与 SQL 执行环节。使用缓存是解决问题的一个方法, 缓存能改进脚本执行时间和资源需求。对于不同的数据,不同的情况,当然要采取不同的缓 存方式;让用户不会感觉有交互延时,又能快速流畅地访问网站。 大家都知道使用缓存有很大的好处了,下面介绍笔者实现的一个简单的缓存系统;希望 能起到抛砖引玉的作用,使初学者了解一些东西;也希望高手们指出不足。 这个缓存系统可以根据需要自行设定缓存类型,每个缓存类型又可以灵活的选取各自不 同的缓存容器(这里的缓存容器是指缓存数据被保存的地方)。目前实现了三种缓存容器供选 用'file'、'db'、'ea';如果有兴趣,您可以自行添加其他容器(例如 APC 、Sqlite、Memcached 等),如图 1。

图1 网站:http://www.phpchina.com

cache 结构

投稿:phper@phpchina.com

《PHPer》

32/127


代码分析:PHP 缓存的实践

《PHPer》

代码分析 配置文件 config.php 中的设定: config.php <?php /* 缓存设置 添加缓存类型时,更新此数组 键值代表缓存容器可选 'file' 'db' 'ea' file - 使用文件存储缓存,缓存文件路径要可写入的 db - 使用数据库存储缓存,需要设置数据库连接,并创建缓存表(SQL 语句在文件 cache.sql 中) ea - 使用 eAccelerator 存储缓存,需要 php 的 eAccelerator 扩展 */ $type_arr['system'] = 'file';

//缓存系统设置等

$type_arr['other'] = 'file';

//缓存其他信息

$type_arr['block'] = 'file';

//缓存区块缓存

define('CACHE_PATH', './cache_data/'); //文件缓存路径设定,可写入 // 数据库设置 $dbhost = 'localhost';

//数据库地址

$dbuser = 'root';

//数据库账户名

$dbpw = 'root';

//数据库密码

$dbname = 'supev'; $tablepre = 'sv_';

//数据库名称 //表前缀

// 连接,选择数据库 $db = mysql_connect($dbhost, $dbuser, $dbpw) or die('Could not connect: ' . mysql_error()); mysql_select_db($dbname, $db) or die('Could not select database'); ?>

缓存系统函数文件 cache.php 中有 5 个主要的函数,作为接口: writecache // 写入缓存 readcache // 读取缓存 remove // 更新一个缓存 garbagecollection // 批量清理某类型的过期缓存 cache_flush // 批量清理某类型的全部缓存 其中参数的意义: $key // 缓存的键名 $data // 缓存数据 $expired // 过期时间-1 代表缓存失效;0 代表无限时间缓存,慎用 $cache_type // 缓存类型 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

33/127


代码分析:PHP 缓存的实践

《PHPer》

$depth // 是否使用深度分层缓存文件夹,视被缓存内容而定 $maxlifetime // 最大过期时间,用于清理过期缓存 下面看看应用的例子文件 example.php example.php <?php include('config.php'); include('cache.php'); $test_content = array('缓存测试', 'test', 1);

//测试数据

$cache_content = readcache('test_cache_key', 'other', false);

//读取缓存

if($cache_content == -1 || empty($cache_content)) { //读取失败打印源数据,并更新缓存 cache_flush('other'); writecache('test_cache_key', $test_content, 900, 'other', false); echo "print from source :\n"; print_r($test_content); } else { //读取成功,打印缓存数据 echo "print from cache :\n"; print_r($cache_content); } //关闭数据库连接 mysql_close($db); ?>

主要文件 cache.php,本部分内容较长,代码注释比较详细,在此功能函数不全部列出, 此文件位于附件相应目录下,感兴趣的朋友可以直接查看源文件。 cache.php 片断 <?php if (!isset($CACHE_INCLUDED)) { define('INFINITY_EXPIRED', 630720000); //无限缓存时间 用 20 年代替 define('MAX_FILE_TIME', 2592000); //默认删除 30 天没用过的缓存文件 $timestamp = time(); /** * validate and get container of cache * * @param string $cache_container * @return bool */ function _cache_container_validate($cache_type = 'other') { global $type_arr; if(!_cache_type_validate($cache_type)) { return false; } 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

34/127


代码分析:PHP 缓存的实践

《PHPer》

$cache_container = $type_arr[$cache_type]; $container_arr = array('file', 'db', 'ea');

//目前实现了三种缓存容器,如果有兴趣,您可以自行添

加其他容器 if(in_array($cache_container, $container_arr)) { return $cache_container; } else { return 'file'; } } /** * validate type of cache * * @param string $cache_type * @return bool */ function _cache_type_validate($cache_type = 'other') { global $type_arr; //添加缓存类型时,在 config.php 文件中更新此数组 return (array_key_exists($cache_type, $type_arr)); } 略...

注:文中涉及到例子的代码在附件/PHP 缓存实践/中。 作者介绍 徐强,99 年毕业于四川大学;2002 年毕业于清华大学。毕业后,一直在北京工作,先后 在 SOHU、联众、Comsenz 等公司做技术方面的工作。主要从事 PHP 相关的 Web 开发。 网名:傻大猫 邮箱:xuqiang76@163.com

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

35/127


代码分析:Discuz!浅析之登录篇

《PHPer》

Discuz!浅析之登录篇 作者:isno Discuz!相信我不用再作介绍了,众所周知的是 Discuz!在统计用户时间 Cookie 和 Session 方面做的很有特色,此文没有多少难点,旨在通过分析它的登录验证部分对大家以后设计系 统有所帮助。

1 前台表单部分 代码如下: <form method="post" name="login" action="logging.php?action=login&"> <!--formhash 是防止伪造表单而生成的一段随即字符串; 生成方法可以看 include 下 global.func.php 文件 formhash 函数,详细的我就不再多作解释了--> <input type="hidden" name="formhash" value="68db8fde" /> <!-- referer 是登录后要跳转的页面--> <input type="hidden" name="referer" value="index.php" /> <!--loginfield 是用户名方式 可以选择 username 和 uid--> <input class="radio" type="radio" name="loginfield" value="username" tabindex="2" checked="checked" />用户名 <input class="radio" type="radio" name="loginfield" value="uid" tabindex="3" />UID <!--用户密码--> <input type="password" id="password" name="password" size="25" tabindex="5" /> <!--questionid 论坛安全提问--> <select id="questionid" name="questionid" tabindex="6"> <option value="0">无安全提问</option> <option value="1">母亲的名字</option> <option value="2">爷爷的名字</option> <option value="3">父亲出生的城市</option> <option value="4">您其中一位老师的名字</option> <option value="5">您个人计算机的型号</option> <option value="6">您最喜欢的餐馆名称</option> <option value="7">驾驶执照的最后四位数字</option> </select> <!--answer 论坛安全提问回答--> <input type="text" id="answer" name="answer" size="25" tabindex="7" /> <!--cookietime 是默认时间--> <label><input class="radio" type="radio" name="cookietime" value="315360000" tabindex="8" /> 永久</label> <label><input class="radio" type="radio" name="cookietime" value="2592000" tabindex="9" checked="checked" /> 一个月</label> <label><input class="radio" type="radio" name="cookietime" value="86400" tabindex="10" /> 一天</label> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

36/127


代码分析:Discuz!浅析之登录篇

《PHPer》

<label><input class="radio" type="radio" name="cookietime" value="3600" tabindex="11" /> 一小时</label> <label><input class="radio" type="radio" name="cookietime" value="0" tabindex="12" /> 浏览器进程</label> <!--loginmode 登录方式--> <select id="loginmode" name="loginmode" tabindex="13"> <option value="">- 使用默认 -</option> <option value="normal"> 正常模式</option> <option value="invisible"> 隐身模式</option> </select> <!--我用的是 Discuz!6.0 版本 所以还有一个 styleid--> <select id="styleid" name="styleid" tabindex="14"> <option value="">- 使用默认 -</option> <option value="1">默认风格</option> <option value="2">喝彩奥运</option> <option value="3">深邃永恒</option> <option value="4">粉妆精灵</option> <option value="5">诗意田园</option> <option value="6">春意盎然</option> </select> </form>

以上这些就是 Discuz!6.0 登录表单所有的信息。如果我们自己写扩展来登录,只需要 username 和 password 即可。

2 处理登录部分 下面我们再看一下 Discuz!是怎么处理登录的。 PHP 页面是论坛根目录下的 logging.php 文件。 从 logging.php 第 40 行开始。 logging.php 片断 <? 略.... }elseif($action == 'login') { //这里面呢 就是处理登录的 /** * $discuz_uid 是登录后的一个标志,果为真就表示用户已经登录 * 如果已经登录,出现提示,你已经登录,后跳向$indexname 页 */ if($discuz_uid) { showmessage('login_succeed', $indexname); } 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

37/127


代码分析:Discuz!浅析之登录篇

《PHPer》

//$field 取得登录用户名方式 $field = $loginfield == 'uid' ? 'uid' : 'username'; /** * 下面则是判断登录验证是否开启 * $seccodestatus 具体可查看 forumdata/cache/cache_settings.ph 文件,当值 2 的时候 登录验证则开启 */ $seccodecheck = substr(sprintf('%05b', $seccodestatus), -2, 1); //loginfailedcount 用户登录失败 3 次后显示验证码 if($seccodecheck && $seccodedata['loginfailedcount']) { //取集,用户登录三次失败后$seccodecheck 为真 $seccodecheck = $db->result($db->query("SELECT count(*) FROM {$tablepre}failedlogins WHERE ip='$onlineip' AND count>='$seccodedata[loginfailedcount]' AND $timestamp-lastupdate<=900"), 0); } //下面这段是检测登录表单是否正确,正确的话显示登录页 $seccodemiss = !empty($loginsubmit) && $seccodecheck && !$seccodeverify ? TRUE : FALSE; if(!submitcheck('loginsubmit', 1, $seccodemiss ? FALSE : $seccodecheck)) { $discuz_action = 6; $referer = dreferer(); $thetimenow = '(GMT '.($timeoffset > 0 ? '+' : '').$timeoffset.') '. gmdate("$dateformat $timeformat", $timestamp + $timeoffset * 3600). $styleselect = ''; $query = $db->query("SELECT styleid, name FROM {$tablepre}styles WHERE available='1'"); while($styleinfo = $db->fetch_array($query)) { $styleselect .= "<option value=\"$styleinfo[styleid]\">$styleinfo[name]</option>\n"; } $_DCOOKIE['cookietime'] = isset($_DCOOKIE['cookietime']) ? $_DCOOKIE['cookietime'] :2592000; $cookietimecheck = array((isset($_DCOOKIE['cookietime']) ? intval($_DCOOKIE['cookietime']) : 2592000) => 'checked="checked"'); if($seccodecheck) { $seccode = random(6, 1) + $seccode{0} * 1000000; } include template('login'); } //我们继续看下下面的 else { //初始化参数 $discuz_uid = 0; $discuz_user = $discuz_pw = $discuz_secques = $md5_password = ''; $member = array(); $loginperm = logincheck(); if(!$loginperm) { showmessage('login_strike'); } 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

38/127


代码分析:Discuz!浅析之登录篇

《PHPer》

//得到$secques $secques = quescrypt($questionid, $answer); //判断是否存在 loginauth 如果有则从它里面取 password if(isset($loginauth)) { $field = 'username'; $password = 'VERIFIED'; list($username, $md5_password) = daddslashes(explode("\t", authcode($loginauth, 'DECODE')), 1); } else { $md5_password = md5($password); $password = preg_replace("/^(.{".round(strlen($password) / 4)."})(.+?)(.{" .round(strlen($password) / 6)."})$/s", "\\1***\\3", $password); } //下面就是比较简单的查询数据库然后判断了 $query = $db->query("SELECT m.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques, m.adminid, m.groupid, m.styleid AS styleidmem, m.lastvisit, m.lastpost, u.allowinvisible FROM {$tablepre}members m LEFT JOIN {$tablepre}usergroups u USING (groupid) WHERE m.$field='$username'"); $member = $db->fetch_array($query); if($member['discuz_uid'] && $member['discuz_pw'] == $md5_password) { if($member['discuz_secques'] == $secques && !$seccodemiss) { extract($member); $discuz_userss = $discuz_user; $discuz_user = addslashes($discuz_user); if(($allowinvisible && $loginmode == 'invisible') || $loginmode == 'normal') { $db->query("UPDATE {$tablepre}members SET invisible='".($loginmode == 'invisible' ? 1 : 0)."' WHERE uid='$member[discuz_uid]'", 'UNBUFFERED'); } $styleid = intval(empty($_POST['styleid']) ? ($styleidmem ? $styleidmem : $_DCACHE['settings']['styleid']) : $_POST['styleid']); $cookietime = intval(isset($_POST['cookietime']) ? $_POST['cookietime'] : ($_DCOOKIE['cookietime'] ? $_DCOOKIE['cookietime'] : 0)); //下面生成 cookietime 和 auth COOKIE dsetcookie('cookietime', $cookietime, 31536000); dsetcookie('auth', authcode("$discuz_pw\t$discuz_secques\t$discuz_uid", 'ENCODE'), $cookietime); //showmessage(xx) 提示登录成功并执行 updatesession 函数,session 入库在 893 行 sid 在 common.inc.php174 行生成 }

3 验证登录部分 限于篇幅,下面就简单谈一下 Discuz!怎么验证登录状态的。 从 common.inc.php 第 123 行开始。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

39/127


代码分析:Discuz!浅析之登录篇

《PHPer》

common.inc.php 片断 <?php //得到 sid $sid = daddslashes(($transsidstatus || CURSCRIPT == 'wap') && (isset($_GET['sid']) || isset($_POST['sid'])) ?(isset($_GET['sid']) ? $_GET['sid'] : $_POST['sid']) : (isset($_DCOOKIE['sid']) ? $_DCOOKIE['sid'] : '')); $discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']); //解开解密字符串,得到密码、安全提问和用户 id list($discuz_pw, $discuz_secques, $discuz_uid) = empty($_DCOOKIE['auth']) ? array('', '', 0) : daddslashes(explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')),1); $newpm = $newpmexists = $sessionexists = $seccode = $bloguid = 0; $membertablefields = 'm.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques, m.adminid, m.groupid, m.groupexpiry, m.extgroupids, m.email, m.timeoffset, m.tpp, m.ppp, m.posts, m.digestposts,m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5,m.extcredits6, m.extcredits7, m.extcredits8, m.timeformat, m.dateformat, m.pmsound, m.sigstatus, m.invisible, m.lastvisit, m.lastactivity, m.lastpost, m.newpm, m.accessmasks, m.xspacestatus, m.editormode, m.customshow'; //如果 sid 存在的话进行下面的操作 if($sid) { //如果 uid 是正确的则用 members 表内查询信息,否则的话从 sessions 内查询 if($discuz_uid) { $query = $db->query("SELECT s.sid, s.styleid, s.groupid='6' AS ipbanned, s.pageviews AS spageviews, s.lastolupdate, s.seccode, $membertablefields FROM {$tablepre}sessions s, {$tablepre}members m WHERE m.uid=s.uid AND s.sid='$sid' AND CONCAT_WS ('.',s.ip1,s.ip2,s.ip3,s.ip4)='$onlineip' AND m.uid='$discuz_uid' AND m.password='$discuz_pw' AND m.secques='$discuz_secques'"); } else { $query = $db->query("SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate, seccode FROM {$tablepre}sessions WHERE sid='$sid' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='$onlineip'"); } if($_DSESSION = $db->fetch_array($query)) { //用户信息是正确的 $sessionexists = 1; if(!empty($_DSESSION['sessionuid'])) { $query = $db->query("SELECT $membertablefields FROM {$tablepre}members m WHERE uid='$_DSESSION[sessionuid]'"); $_DSESSION = array_merge($_DSESSION, $db->fetch_array($query)); } } else { // 查询结果为假的话 清除所有 COOKIE 并设$sessionexists 为真,不在执行下面的操作 $query = $db->query("SELECT sid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate, seccode FROM {$tablepre}sessions WHERE sid='$sid' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='$onlineip'"); if($_DSESSION = $db->fetch_array($query)) { 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

40/127


代码分析:Discuz!浅析之登录篇

《PHPer》

clearcookies(); $sessionexists = 1; } } } // $sessionexists 为假的话,$discuz_uid 为真,执行下面操作 if(!$sessionexists) { if($discuz_uid) { $query = $db->query("SELECT $membertablefields, m.styleid FROM {$tablepre}members m WHERE m.uid='$discuz_uid' AND m.password='$discuz_pw' AND m.secques='$discuz_secques'"); if(!($_DSESSION = $db->fetch_array($query))) { clearcookies(); } } } ?>

通过上面的简单分析,我们已经知道了 Discuz!登录和验证的方式。简单的说就是,把 用户密码、安全提问、用户 id 加密成一个名为 auth 的 Cookie;验证部分就是拆解此 Cookie 并结合 Session 来判断用户登录状态。

4 自己动手写 Discuz!登录验证 看到论坛里经常有人问怎么实现论坛和 CMS 的同步登录,通过上面的分析我们就知道了 只要一个 auth 即可。 代码如下: <?php /** * 加载 discuz 的入口文件,当然你也可以不加,不过你得提出几个必要的函数 */ require_once './include/comon.inc.php'; $formUsername = trim($username); // 接受 POST 传来的$username $formPassword = trim($password); // 接受 POST 传来的$password /** * 说下下面的 secques * secques 是论坛里的安全回答经过编码后提取的一段字符虽然我们登陆的时候不会用到它 * 但是生成 COOKIE 呢,它还是不可或缺的滴 */ $query = $db->query("SELECT uid,password,secques FROM cdb_members WHERE username='$for mUsername'"); $member = $db->fetch_array($query); // 验证用户密码是否匹配 if($member['password'] == md5($formPassword)) { // 已经验证用户密码都是匹配的,下面比较关键的就是生成 cookie 了 可要仔细看好了 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

41/127


代码分析:Discuz!浅析之登录篇

《PHPer》

/* 先说下 dsetcookie 函数,这是一个 Discuz!置 cookie 的函数,可以在 include/global.func.php 里查 看通常只需要三个参数即可 第一个为 cookie 键,第二个为键值 第三个为 cookie 有效时间 这里我 就随便设置一个,再说 authcode 此为加密函数 俺一直用这个函数,很强大很难破解,有兴趣的朋友 也可在 include/global.func.php 里找到改函数 研究一下 */ dsetcookie('sid','',-2423234234); // 注销掉 sid 如果不注销 Discuz!将通过查询 member 和 sessions 表获取用户信息 但是 sessions 表内并没有用户的记录 所以要注销掉 sid dsetcookie('auth', authcode("$formPassword\t$$member['secques']\t$member['uid']", 'ENCODE'), '1234243'); // O,关键步骤 我们都已经完成了,下面就由你写一个 header 跳转到论坛首页看是否登陆了, 我本地测试可以,你有问题的话那可就是 // RPWT 了 header("location:/index.php"); } else { // 我们这里返回一个错误信息,告诉那个用户密码错误 } ?>

文章到此就结束了,虽然写的没头绪虽然内容比较长,但是都比较简单,相信有点基础 的 PHPer 都能看懂。 如果文章有欠缺之处,还请多多指教。 作者介绍: 作者:isno,上海某公司 PHPer Email:isno@yahoo.cn 网站:www.isno.cn

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

42/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

安全优化

基于 RBAC 的安全管理系统的设计与实现 Design and Implementation A Safety Management System Based on RBAC 作者:胡俊鹏 Hu,Junpeng 摘要:本文在RBAC模型基础上提出了一种基于角色的安全保护策略,并制定了一些整个系 统通用的安全准则,应用这种策略和准则设计了一个基于角色的安全管理系统,实现了系统 开发过程中的职责分离,程序员在开发时就可以不要过多的考虑程序安全性的问题,只需要 遵守系统的安全准则即可,这样就可以把主要精力花费在系统的业务功能上。 关键词:角色;权限;访问控制 中图分类号:TP3 文献标识码:A Abstract: In this paper,role-based access control based on a role-based security strategy develop a common safety standards throughout the system. Design criteria for the application of this strategy and a role-based security management system. a system development process of separation of duties, programmers in the development process would not be excessive considering the issue of security, need only Compliance with the safety criteria can be, we can focus his energy on the system's operational functions. Keywords : Role;Permission;Access Control

引言 访问控制往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“Who 对 What(Which)进行 How 的操作”的逻辑表达式是否为真。针对不同的应用,需要根据项目 的实际情况和具体架构,在维护性、灵活性、完整性等 N 多个方案之间比较权衡,选择符合 的方案。基于角色的访问控制方法[1,2]是目前公认的解决大型企业的统一资源访问控制的有 效方法。 在基于角色的访问控制模型 RBAC 出现之前,自主访问控制 DAC[3,4]和强制访问控制 MAC 已经提出了二十多年并且在诸多应用领域取得了巨大的成功。访问控制已经成为计算机 安全产品中必不可少的组成部分之一。本文在 RBAC 的基础上通过分析设计了一个基于角色 的安全管理系统。

分析说明 角色与用户的分析 角色由用户自选定义,根据业务岗位不同可以定义多个角色。角色是用户权限的基础, 用户可以扮演多个角色。每个用户在系统中由一个唯一的 USERID 标识。用户通过系统登录 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

43/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

界面登录系统,系统通过加密算法验证用户身份和判断用户是否已经登录系统。 1)

角色由用户根据自己设想的组织机构进行添加设置,提供一个专门的模块用来设置组

织机构,用户通过组织机构方便地进行角色管理。 2)

每个角色在系统中也是由一个唯一角色编号来标识,同时必须保存用户所设置的机构

信息,一般来说每个角色只需要保存自己所在机构的代码即可。 菜单控制分析 1) 由业务功能模块列表和用户菜单定制共同组成。每个用户可以拥有自己的菜单,也可 以直接采用角色缺省菜单。 2) 为了方便用户进行权限组织管理,需要在系统中建立一张业务功能模块列表,在用户 界面上表示为树状分层结构。 3) 业务功能模块以用户定制菜单来体现,仍然采用编号分层方式,编号的每两位为一个 层次。对每个业务模块设置它的对象控制、记录增删改控制和记录集控制。 4) 当用户同时充当多个角色并且权限重复时,重复的权限仅一次有效,用户拥有他充当 的所有角色的权限的并集。 对象控制分析 对象是指应用系统窗口中的可视对象,如菜单项、按钮、下拉列表框、数据编辑控件及 数据编辑控件的字段等。对象控制通过角色与用户授权来实现。 1) 将每个业务模块可进行属性设置的对象由程序员事先设定或由技术支持工程师指导 用户加入。 2)

在系统管理员或授权用户进行设置业务模块的每种权限时,设置用户在拥有该业务模

块这种权限时的对象属性。 记录集控制分析 记录集的控制是通过条件设置来实现,因此,需要控制记录集的数据库表设置专门的记 录集筛选字段,而筛选条件由用户根据岗位自行定义,建立过滤表,统一管理。 1) 在对用户设置业务模块权限时,同时在过滤表中设置本模块的数据编辑控件的数据筛 选条件,筛选条件是组成 SQL 语句的 WHERE 条件子句,使当前访问的模块根据筛选条件对 数据编辑控件的 SQL 语句进行重组,并检索数据。 2) 当存在需要从数据库中的多个表取数据的情况时,过滤表中存在多条记录,每一条记 录记录一个数据编辑控件取数的筛选条件。 3) SQL 语句的 WHERE 子句的生成与校验可以通过系统提供的 SQL 语法分析服务,利 用对象所提供的函数分析 SQL 语句,截取 WHERE 条件子句,校验新组合的 SQL 语句的合 法性。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

44/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

系统设计 安全保护策略 安全保护策略是设计安全可靠系统的准则,通常涉及下列几个方面: 1)区分安全策略与安全机构。 策略是信息安全的高级指导,策略出自对用户要求、设备环境、机构规则、法律约束等 方面的详细研究。策略重要性在于指导作用。而机构是实现和执行各种策略的功能的集合。 完善的机构是实施正确安全策略的物质基础。 2)安全策略设计。 RBAC 的特点是通过分配和取消角色来完成用户权限的授予和取消,并且提供了角色分 配规则和操作检查规则。整个访问控制过程分成两个部分,即访问权限与角色相关联,角色 再与用户关联,从而实现了用户与访问权限的逻辑分离[5]。 3)安全保护机构设计。 本系统的安全保护机构基本上是与上面的安全策略相互适应的,系统保护的总体结构如 图 1。 主体

各种访 问者

天灾,人 祸,故障

操作

物理

破坏途径

外部世界

安全保护

对 象

系统

图1

系统保护的总体结构示意图

主体、访问类型、对象是保护机构主要成分,保护机构应负责阻止一切物理破坏和用户 可能的操作破坏,后者归结为主体可用何种方式访问哪些对象。 安全管理机构 安全管理机构内部结构如图 2。 对象定义工具与权限定义工具 1)对象定义工具 对象是指系统中各种功能模块、数据、界面元素(包括菜单、按钮等各种界面上能控制 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

45/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

的控件)等,它们是主体能访问的各种对象。对象定义通常包括功能模块定义,界面元素控 制,数据信息控制三个步骤。 软件构件

对象定义工具

系统控制数据 可控制系统对象

可控制系统对象 定义

使用数据 权限定义工具 用户定义

角色集 使用数据 权限配置

定义

产生 权限数据

产生 配权角色

定义 用户组

登录用户 使用数据

用户委派 产生 动态产生主体能力表

权限审查

用户组定义

使用数据 用户加入到组

重新委派

没有通过

通过审查 动态产生最终主体能力表

收回部分权限

重新委派 保存授权信息

图2

动态产生修改后主体能力表

安全管理机构内部结构示意图

对象定义工具与权限定义工具 1)对象定义工具 对象是指系统中各种功能模块、数据、界面元素(包括菜单、按钮等各种界面上能控制 的控件)等,它们是主体能访问的各种对象。对象定义通常包括功能模块定义,界面元素控 制,数据信息控制三个步骤。 2)权限定义工具 定义权限就是定义对象访问控制和数据访问控制。为了表述方便我们对权限用一个三元 组符号来表示 P(o,t,p) ,其中 o 表示访问对象;t 表示访问类型;p 表示谓词。表示在谓词 p 为真时对于对象 o 可进行 t 类型的访问。只有给各种对象定义好访问的权限,才能给角色配 置权限,基于角色管理才能成为可能。 角色定义与权限配置 1)角色定义 角色之间有相应继承的关系,当一个角色 r1 继承另一个角色 r2 时,r1 就自动拥有了 r2 的访问权限(表示 r1->r2)。角色继承关系提供了对已有角色的扩充和分类的手段,使定义新 的角色可以在已有角色的基础上进行。另外还允许多继承,即一个角色继承多个父角色,多 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

46/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

继承体现对角色的综合能力。 2)权限配置 角色是一组访问权限的集合,一个用户可以是很多角色的成员,一个角色也可以有很多 个权限,而一个权限也可以重复配置于多个角色。权限配置工作是组织角色权限工作的步骤 之一,只有角色具有相应的权限后用户委派才能具有实际意义。 用户鉴别机构 安全保护的首要问题是鉴别用户身份。目前有三种方法可用:第一,利用用户的物理特 征(声波、指纹、相貌、签名)。这在理论是最可靠的,但由于物理特征可能随时间变化且记 录尚欠成熟等原因,使该方法未能广泛应用。第二,利用用户特有的证件,如身份证、机器 可读卡片,其缺点是证件可能被别人复制或冒用。第三,利用用户知道的某件能证明其身份 的约定(如口令)。这是当前较为常用的方法。本系统采用第三种方法。 表1

用户鉴别机构登记表

用户名称

标识

Hjp … …

其它情况

hello … …

… … … …

如表 1 所示是用户鉴别机构保存的一张登记有每个用户名称、标识和有关情况的表,表 中的用户名通常是公开的,标识则是保密的,当用户要访问系统时,须首先把自已的名称和 标识登记到系统中(即出示证件)。这时用户鉴别系统机构检查用户的标识是否与用表中的标 识一致,如果是,则认为用户身份己经得到证实,否则认为是假冒,系统将拒绝用户要求执 行的操作。口令是最常用的一种标识,通常由若干字母、数字组合而成。系统只允许用户连 续两次或三次登记口令,如果都不对则要等待一段较长的时间才能重新登记,这种延长时间 的方法能够有效的防止冒名者猜测口令的可能。 访问控制机构 杜绝对系统非法访问主要方法是访问控制,用户系统的访问控制可以用访问规则表示, 根据安全策略用访问规则给 o 用户授权。访问控制就是要处理怎样表达和核对访问规则的问 题。从形式上来说,一条访问规则可以写成四元组的形式(u,o,t,p),可对已有权限表示形式 重新表示为(u,p)。系统的访问控制分为模块级控制和界面元素级控制。 考虑到运行速度,根据系统中角色、权限配置、用户委派等关系动态地的组成一张用户 能力表保存在系统中。能力表(也称 C 表)是存贮和核对访问规则的一种有效形式。能力表 是面向主体的,用以说明主体能对哪个访问对象执行何种操作。基本形式如表 2 表2 Si

J

(oi1,ti1,pi1)

能力表 ……

(oij,tij,pij)

其中 Si 表示第 i 个主体;j 为 Si 可访问的数据对象的个数; (oi1,ti1,pi1)为访问权限,全 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

47/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

部主体的能力表的集合即为系统的全部访问规则。当某个访问请求需进行生效检查时,则按 访问请求的主体找到能力表逐项核对以决定其是否有效。 安全管理控制核心 安全管理控制核心是系统安全管理的核心控制部分,它在系统中控制整个系统的安全控 制工作,由它决定系统是否启动安全管理,在什么情况下调用访问控制机构等。可以根据情 况编写不同的访问规则,也可以将已有的访问规则应用于各种不同的数据控制和对象控制等。

结论 本系统核心思想是在基于角色控制思想的基础上提取改进而来的,实现了系统开发过程 中的职责分离。安全管理考虑了访问权限不是静态,而是动态的情况,所有对象的权限均用 三元组来表示 P(o,t,p),主体在系统中的访问规则用四元组来表示(s,o,t,p)。可通过安全管 理控制核心的接口,重新为系统编写访问规则,动态修改主体能力表,动态分配用户完成当 前工作流环节所需的权限。 应用本文的研究,WeCMS 已经成功的应用了基于角色的安全管理系统,并在实践建站 中取得了很好的效果。

参考文献 [1]栗松涛、李春文、孙政顺。一种新的B/S系统权限控制方法[J]。计算机工程与应用、2002、 38(1):99-101 [2]杨赞国、高敬惠,基于C/S模式的网络信息管理系统设计与实现[J]。微计算机信息,2005-73:27- 29 [3]叶锡君,许勇,吴国新。基于角色的访问控制在Web中的实现技术[J]。计算机工程,2002-1: 167~169 [4]Sun Software White Papers: RBAC in the Solaris Operating Environment, 2001 [5]钟华,冯玉琳,姜洪安。扩充角色层次关系模型及其应用。软件学报[J],2000,11(6):779~784 作者简介: 胡俊鹏(1978年 ),男,湖北钟祥人,汉族,硕士,助教,主要研究方向为计算机软件,计算机 网络与安全。 E- mail:hujunpeng@wephp.com Author brief introduction:HU Jun-peng (1978-), male, Hubei ZhongXiang, Han nationality, a master's degree in reading, teaching assistants,research direction for computer software, Computer network security,E-mail:hujunpeng@wephp.com 通讯地址:(445000 湖北民族学院计算机科学与技术系)胡俊鹏 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

48/127


安全优化:基于 RBAC 的安全管理系统的设计与实现

《PHPer》

团队介绍: WePHP团队多年来致力于WeCMS的研究与开发,侧重系统架构与安全,不断更新升级, 打造了许多政府机关、门户网站、企业网站等,经受了时间与技术的考验,也曾在华军软件 园和天空下载站有过发布。官方网站:http://www.wephp.com,随后可以访问我们的CMS站点 http://cms.wephp.com(正在更新中),有问题也可以到我们的论坛http://bbs.wephp.com进行交 流。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

49/127


安全优化:浅谈 CMS 系统的 SEO

《PHPer》

浅谈 CMS 系统的 SEO 作者:刘昊 CMS 系统促进着 Web2.0 的发展,根据权威机构的调查,一个网站 80%左右的流量都是 来源于搜索引擎的,所以一个网站到底做的好与坏不在于网站建设者的认知,而是在于相关 关键词在搜索引擎中的排名和被搜索引擎收录的网页数量,以此来衡量网站的价值。在这个 网络信息成爆炸式增长的时代,搜索引擎成为了人们查找信息的主要来源之一,而 CMS 作为 一个内容发布和管理的系统,就更应注重其文章或内容在 SEO 方面的特性,从而提升网站的 价值。 从开发语言的选择来说,用 Asp 开发的 CMS 有:动易、风讯等,用 PHP 开发的 CMS 有:DedeCms、SupeSite、帝国 CMS 等。开发语言及运行平台的选择非常重要,因为我们要 考虑到网站运行的安全性、负载能力、易用性、可扩展性等等,在这里我只从 SEO 角度探索 下优秀 CMS 系统应该具备的一些元素,而非从系统的设计、表现、功能等方面进行评价,因 为每一款 CMS 系统都有其自身的特点和应用的领域。 我大致的总结了一下 CMS 系统的 SEO 主要集中在以下 5 个方面: 1、实现全站 URL 的静态化 虽然目前搜索引擎的能力已经有了很大的提升,动态参数小于 3 的动态网页,蜘蛛都可 以顺利抓取,但是我们还是应该尽可能的为搜索引擎提供更好的搜索环境。目前 CMS 系统实 现 URL 静态化的方法可以使用 MVC 三层架构,通过 Rewrite 技术实现了 URL 伪静态。在这 方面 PHP 开发的各 CMS 系统都已经做的非常好了,但是希望可以实现自定义 URL 生成规则, 甚至包括后缀名,这样将更能在 URL 中突出 Keyword,提高网页的权重。 2、采用 CSS+DIV 对网站页面进行重构 采用了 CSS+DIV 的网页在搜索引擎优化方面的优势要强于传统采用 Table 编写的网页 (当然,这里并不是说明采用 Table 编写的网页就不能获得好的排名)。但是对于以内容为主 的 CMS 系统来说采用 CSS+DIV 的模式可以将文章的内容放到更加靠前的位置,便于蜘蛛更 快的找到它所需的内容。而且从网页浏览速度上考虑,采用 CSS+DIV 重构的页面容量要比 Table 编码的页面文件容量小得多,前者一般只有后者的 1/2 大小。遗憾的是目前还不是所有 的 CMS 系统都采用了这种模式。 3、网站根据频道的不同设置各自的<MATE>内容 网站首页、频道页、栏目页、内容页都可以自定义<MATE>或者通过设定好的系统参数 实现自定义<MATE>的内容规则。针对不同的二级频道分别在<MATE>中设置相应的内容, 可以体现二级频道的分类性。目前国内大多数的 CMS 系统对于这一块的实现都比较差,在他 们的二级频道中 Keyword 与 Description 都是相同的,这是严重违背 SEO 原则的。希望今后 可以得到开发团队的重视。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

50/127


安全优化:浅谈 CMS 系统的 SEO

《PHPer》

4、对文章页面的 Keyword 与 Description 内容进行完善 这里提到的 Keyword 与 Description 与第三条是不同的,这里我主要指的是文章页面的 Keyword 与 Description。最好的办法是根据文章发布时生成的 TAG 来自动生成关键词,所以 Keyword 部分就可以直接调用具体文章的关键词即刻。而描述可以自动截取每篇文章正文的 前 100 个汉字放入 Description 中。这样一来文章无论是 Keyword 还是 Description 都能很好的 结合起来,大大提高的内容的相关度。 5、加强搜索引擎对论坛页面的索引效率,使网站实现立体化 就是在每个话题的具体帖子下面出现了一个与之内容相关的帖子导航。也可以为文章建 立多个关键词(即 TAG),并在文章内容下面列出,当用户点击这些关键词,自动进入该关 键词的搜索页面;还可以在文章内容下面提供相关文章列表(自定义规则显示规则,譬如, 按哪个关键词、是按相关度来展示还是按时间展示等)。在内容页中显示本类下的 TOP10、推 荐文章,并建立一个随机内容区域,用来展示本类下的文章。 还有一些其他需要注意的地方,比如:应该根据整站的逻辑结构来设定面包屑导航,URL 指向相应目录而非文件;按整站、频道、分类甚至文章提供 RSS 源;系统自动根据设定的栏 目名称、URL 根据逻辑结构生成 HTML 格式、XML 格式的网站地图,并可以时实更新,XML 地图自动提交给 Google Sitemap。 相信随着市场竞争的越趋激烈,以及站长们对 SEO 的关注,只有将 SEO 做的更好、更 到位的 CMS 系统才会有更好的远景,更大的市场。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

51/127


PHP 企业解决方案:PHP168 整站架构分析+企业解决方案

《PHPer》

PHP 企业解决方案

PHP168 整站架构分析+企业解决方案 作者:PHP168 团队 PHP168 整站系统的与众不同之处在于“一个核心+多模块”以满足企业不同的需求。以 往的整站程序把所有的功能都集合在一起,这就给企业带来了诸多的不便,因为很多企业并 不需要全部的功能,全部功能给它的话,不仅仅是一种累赘,而且在操作上也带来太多的干 扰与诸多的不便。虽然有的整站系统推出了不同的版本,诸如:企业版、个人版、单位版等 等。但这也并不是解决问题的出路,虽然有了版本的区别,把企业与个人区分开来了,但是 还忽略了一个问题,就企业这个行业而言,他们的需求就各不相同。所以这也不能从根本上 解决问题。 考虑到以上种种情况,为了给企业、个人、单位等等,带来更多的方便,PHP168 整站开 发小组凭借着多年来的开发经验,最后想出一个非常有效的解决方案,那就是现在的:一个 核心+多个模块。可以非常灵活的满足不同的企业、单位、个人的不同需求。核心是必须安装 的,因为里边包括了网站最基本的功能,比如用户权限控制、数据备份等等。而多模块呢? 大家可以自由选择安装自己需要的模块。安装以后,某一天不需要了,也可以很方便的自由 删除。这就非常的灵活,扩展性也就非常的强,按需搭建自己的网站。就像搭建积木那么轻 松自如。 以上所讲的,是对 PHP168 整站系统的一个总体概述。下面再来跟大家分享一下我们这 个整站当中的一些比较具有特色的自定义功能函数,因为这些函数就像一座大厦的钢筋水泥 柱子一样,没有它们,就很难搭建整个大厦。所以我们就从最基本的功能跟大家讲起,以下 就抽取了几个比较有代表性的功能函数跟大家谈谈。 数据表字段信息处理函数 function table_field($table,$field=''){ global $db; $query=$db->query(" SELECT * FROM $table limit 1"); $num=mysql_num_fields($query); for($i=0;$i<$num;$i++){ $f_db=mysql_fetch_field($query,$i); $showdb[]=$f_db->name; } if($field){ if(in_array($field,$showdb) ){ return 1; }else{ return 0; } }else{ 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

52/127


PHP 企业解决方案:PHP168 整站架构分析+企业解决方案

《PHPer》

return $showdb; } }

以上这段代码,是一个 MySQL 数据表的处理函数,它可以实现两个非常重要的功能, 第一个功能就是可以判断某个表当中是否存在某个字段。看似很平凡的功能,实际用起来是 很多的。比如当版本升级的时候,就要判断用户的旧数据库是否存在某些字段,如果不存在 的话,就要往这个表中添加字段。其中上面的$table 参数就是数据表,而$field 参数就是字段 名。另一个重要的功能,就是获取某个表的所有字段,然后以数组的方式返回。这个功能的 实用性也很强,比如有些用户自定义的表单,用户自字义添加字段后,当添加数据的时候, 程序处理数据之前,就需要把那个表的字段获取到,因为里边的字段是变动的,用户可以随 便的添加或删除。 删除文件函数: function del_file($path){ if (file_exists($path)){ if(is_file($path)){ if( !@unlink($path) ){ $show.="$path,"; } } else{ $handle = opendir($path); while (($file = readdir($handle))!='') { if (($file!=".") && ($file!="..") && ($file!="")){ if (is_dir("$path/$file")){ $show.=del_file("$path/$file"); } else{ if( !@unlink("$path/$file") ){ $show.="$path/$file,"; } } } } closedir($handle); if(!@rmdir($path)){ $show.="$path,"; } } } return $show; }

上面这个是删除文件的函数,使用频率也是很高的,大家都知道,使用系统自身的函数 只能是删除单个文件,而无法递归的删除多级目录与文件,而这个函数正好解决了这个问题, 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

53/127


PHP 企业解决方案:PHP168 整站架构分析+企业解决方案

《PHPer》

不仅仅可以删除单个文件,也可以删除多级目录。比如整站数据生成静态后,就会生成很多 文件与很多目录。使用这个函数的话,就可以轻易的把某个目录下的所有文件一下子全部删 除。 大家想了解更多的信息,或者想亲自体验一下的,不烦登录 PHP168 官方网站: http://www.php168.com。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

54/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

模板和引擎技术

使用 PEAR 类库和 Smarty 模板引擎来做项目 作者:曾瑶合 以 CMS(网站内容管理系统)项目为例,项目核心就是底层类库和模板,而在国内流行 的 CMS 里面,PHP 类库和模板引擎代码大多都是开发 CMS 项目的程序员自己写的。我们暂 且不论程序性能和安全性,从代码重复利用的角度上来说,效率是相当低的。一个新的 PHP 程序员,要接手老程序员的代码,无疑必须重新研读几遍旧程序的代码,修改和扩展起来十 分吃力。 为什么要把精力花在重复的 Coding 上?难道没有通用的类库和通用的模板可以使用 吗?有!PHP 官方网站就有推荐,PEAR 类库和 Smarty 模板引擎。 PEAR 的基本目标是发展成为 PHP 扩展和库代码的知识库,而这个项目最有雄心的目标 就是试图定义一种标准,这种标准将帮助开发者编写可移植、可重用的代码。 “不要重复发明 轮子!”PEAR 是为 PHP 代码的重用而开发的。使用 PEAR 可以大大提高 PHP 程序的开发效 率。前人已经完成的工作,我们可以直接使用,不需要重复开发,更可以保证开发代码的质 量。 Smarty 则是 PHP 官方推荐的模板引擎,是目前业界最著名的 PHP 模板引擎之一。它分 离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与 HTML 代码 混杂在一起 PHP 代码逻辑分离。简单的讲,目的就是要使用 PHP 程序员同美工分离,使用 的程序员改变程序的逻辑内容不会影响到美工的页面设计,美工重新修改页面不会影响到程 序的程序逻辑,这在多人合作的项目中显的尤为重要。

使用 PEAR 和 Smarty 开发项目的好处 在国内 PHP 程序开发的免费 CMS 当中,宏博 CMS(以下简称 HBcms)整个核心全部由 PEAR 和 Smarty 组成,下面我们以它为例,来说明 PEAR 和 Smarty 的好处。 首先我们解压最新的 HBcms 源码包,在 include 目录下发现有 PEAR 和 Smarty 两个目录, 这可以说明,HBcms 程序默认会使用自带的 PEAR 和 Smarty 了,服务器上不再需要另外安 装了。从这一点也可以看出,很多程序员认为 PEAR 和 Smarty 的安装会很复杂,认为服务器 需要特别配置才能支持 PEAR 和 Smarty,这是错误的观点,您的项目本身就可以将它们包含 进去,服务器上无需另设置就可以直接使用了。 其实,直接在程序里调用自带的 PEAR 和 Smarty 类库是十分简单的,您只需要在程序里 设定好 include_path 就 OK 了。 代码如下: ini_set('include_path', $CFG['root'] . '/include/PEAR' . PATH_SEPARATOR . $CFG['root'] . '/include/Smarty' . PATH_SEPARATOR . ini_get('include_path')); 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

55/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

以后的使用就和官方教材里的一模一样了,请看, 代码如下: require_once("HTML/QuickForm.PHP"); require_once('XML/Unserializer.PHP'); require_once("File/Archive.PHP"); require_once("Config.PHP"); require_once('Smarty.class.PHP');

使用 PEAR 开发项目,代码到底有多通用,多简单呢?下面我们来看一个 HBcms 会员登 录表单的代码: 代码如下: include_once ("HTML/QuickForm.PHP"); $form =& new HTML_Quickform('login_form', 'post'); $form->addElement('text', 'login_name', '登录名'); $form->addElement('password', 'login_pass', '密码'); $form->addElement('submit', 'btnSubmit', '提交'); $form->display();

可以看到,表单核心的代码都被封装在 QuickForm 类库里了,而这个 QuickForm 类库, 是由 PHP 业界顶尖的程序员领导开发的,更是由全球各地的 PHP 程序员进行检测的,安全 性,高效性和扩展性都十分的不错。最难得的一点是,这个类库会不断的进行升级,做 BUG 修复。而 CMS 项目本身要做的事情就是去使用它,必要的时候做一下类库升级即可。 为了进一步了解使用 PEAR 的方便性,下面我们看看 HBcms 把会员注册的信息写入数据 库的代码: 代码如下: require_once 'LiveUser/Admin.PHP'; $LUA =& LiveUser_Admin::factory($LIVEUSER_CONF); $LUA->init(); $user_data = array('handle' => 'HBcms_login_name', 'passwd' => 'HBcms_login_pass', 'perm_type'

=> 0, // 会员类型

'email' => 'hbcms@email.com', 'is_active' => 1 // 会员是否有效 ); $userId = $LUA->addUser($user_data);

上面的代码用到了 LiveUser 类库,它是一个用户认证与权限管理的框架。使用起来的代 码也是十分方便的。 再例如,我们要用它来判断会员是否已经登录,只要下面的简单代码就可以做到了。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

56/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

代码如下: if ( !$LU->isLoggedIn() ) { header("HTTP/1.1 301 Moved Permanently"); header("location:login.PHP"); exit(); }

程序员只要集中精力根据业务的不同需求,把项目表现层面的功能实现即可,节省了大 量繁琐的底层代码开发时间。 PEAR 经过几年的发展,成熟的类库越来越多,使用它的程序员也越来越多。但是在中 国,因为中文教程稀少,用的人还是很少。不过,在一些国内大网络公司的 PHP 程序员招聘 信息里,已经越来越多的看到熟练掌握 PEAR 类库优先的条件了。我们相信,在 PHP 官方的 推动下,PEAR 一定会更加的流行起来的。

再来看看 Smarty 模板在 CMS 项目里的应用 首先不得不说的是,PHP 官方推荐的 Smarty 模板,已经成为了 PHP 业界最流行的模板 语言,从各大招聘网站公布的信息来看,绝大多数 PHP 程序员和 Web 美工人员,只要掌握了 Smarty 模板引擎的编程,找工作是轻而易举的事。 从 CMS 项目的长远发展来说,PHP 程序员不可避免的要会经常更换,为什么不使用很 多人都会用的 Smarty 模板引擎呢? HBcms 的 Smarty 模板结构介绍: 在 HBcms 的 template 目录里,你会发现 Smarty 模板是成套出现的,一个目录就是一套 模板。一套模板里面,有多个模板文件,对应网站首页、栏目列表页、文章页、会员页等。 文件结构如图 1,

图1

文件结构

1. 一套模板,分 2 个目录存储相关的文件。 一个目录存储模板结构文件(TPL 文件,在 template 目录下)。 模板文件说明: 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

57/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

index.tpl.html,首页模板 article_list.tpl.html,列表页面模板 article_detail.tpl.html,文章内容页面模板 article_index.tpl.html,封面模板 user_index.tpl.html,会员模板 2. 另一个目录存储图片、CSS、JS 等文件(在 template/image 目录下)。 大体目录结构如图 2,

图2

目录结构

提示:图片目录可以和 TPL 目录名称不同。 将图片、CSS 目录和 TPL 模板结构文件目 录分开的好处是,网友查看网站的网页源代码,不会知道原始 TPL 文件的路径。可以防止别 人轻易盗用模板。 3. 各套模板互不相关。您可以非常容易的更换模板。 修改网站的模板,如图 3,

图3

修改网站的模板

修改栏目的模板,如图 4,

如图 4 网站:http://www.phpchina.com

修改栏目的模板

投稿:phper@phpchina.com

《PHPer》

58/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

打开一个 index.tpl.html 模板文件,会看到如下代码: 代码如下: <title><{$web.name}>:<{$web.desc}></title>

这里的模板定界符是“<{”和“}>” 。很容易理解,上面代码就是将$web 数组变量的 name 元素和 DESC 元素的值输出,显示在网页的<title>里。 在 CMS 模板里,用到最多的语法就是将一个数组的内容,通过一个循环显示出来。在 Smarty 模板引擎里,是如何实现的呢?我们来看看代码: 代码片断: <{foreach name=new_article_data item=item_info from=$new_article}> <A HREF="<{$item_info.url}>"><{$item_info.title}></A> <br> <{/foreach}>

上面的代码就是将数组$new_article 里的文章,把标题$item_info.title 一行一个的显示出 来,并加上了链接$item_info.url。代码看起来很像 PHP 程序,也许会吓到不少完全没有编程 经验的人,但是,这样的语法的确非常的具有扩展性,熟练掌握后,可以十分方便的对输出 加以修饰和控制。如添加表格、加 CSS 控制、设置最长标题字数、添加图片等等。 和其他 CMS 的模板语法比较而言,HBcms 的 Smarty 模板里主要是直接使用 PHP 程序直 接传递过来的数组变量的,如果没有传递变量,就必须要直接读取数据库的内容了。这个过 程就需要在模板里直接写 PHP 代码了,或许这就是其他 CMS 的模板没有采用 Smarty 引擎的 原因之一吧。 我们来看看在 Smarty 模板里直接读取数据库的代码: 代码片断: <{PHP}> $mdb = mdbConnection(); $sql = "SELECT * FROM HBcms_action_history ORDER BY id DESC LIMIT 0,20"; $my_data = $mdb->queryAll($sql); foreach ($my_data as $k => $v) { echo $v['user_id'] . ' - ' . date("H:i",$v['add_date']) . '<br>'; } <{/PHP}>

不过,从模板的灵活性来看,能够在模板里直接写 PHP 代码,这对于懂得 PHP 编程的 程序员来说,无疑是有非常大的灵活性和扩展性的。

综述 对于大部分中小型 PHP 项目而言,PEAR 和 Smarty 已经有它足够的优势了,学习它们, 掌握它们,对于 PHP 程序员来说,或许要多花你不少时间,但是这对一个程序员的前途来说, 是非常有含金量的。试一试,对你没有坏处。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

59/127


模板和引擎技术:使用 PEAR 类库和 Smarty 模板引擎来做项目

《PHPer》

参考资料: PEAR 官方网站:http://PEAR.PHP.net/ Smarty 官方网站:http://Smarty.PHP.net/ 宏博 CMS 官方网站:http://www.HBcms.com/ Smarty 中文教程:http://www.HBcms.com/main/Smarty/ PEAR 中文手册:http://www.PHPChina.com/batch.viewlink.PHP?itemid=27916 PEAR 中文社区:http://www.pearchina.com/ 作者介绍: 曾瑶合,宏博 CMS(HBcms)技术负责人之一。 网站:http://www.HBcms.com/

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

60/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

开源项目介绍

Symfony FrameWork 安装及初级使用 作者:stven,polo

1 Symfony FrameWork 安装 1.1 环境 Windows XP PHP5.2.5 Apache 2.0.55 Symfony 1.0.11 1.2 Symfony 介绍 Symfony 是当前基于 PHP5 的几款主流的 MVC 框架集之一。由于采用了之前 Mojavi、 MVC 框架的功能,结合 Ruby 语言构建而成。具有较高的稳定性与安全性,并支持当前多种 较流行的 Web2.0 技术,且支持 CRUD 数据库代码自动生成系统因此,被广泛的应用于大型 项目的开发中,如:Yahoo 的 Bookmarks 项目,及 del.icio.us 网站(Yahoo 旗下世界最大 Bookmark 网站),由于本人从事对日工作,Symfony 被日本方面所重视,也是本人学习的动 力与基础。 1.2.1 缺点 Symfony 最大的问题便是运行速度,以 CakePHP 与 ZendFramework 相比,Symfony 属于 最慢的了。 1.2.2 优点 面向大规模企业级开发与 CRUD 生成与插件技术。 1.3 Symfony 得到与安装(通过 PEAR 安装) 1.3.1 使用 Windows 命令行方式(“开始”->“运行”->“cmd”) 1.3.2 进入 PHP5.2.5 的目录,找到 pear.bat 文件。 1.3.3 追加 PEAR 频道输入命令:“pear channel-discover pear.symfony-project.com”。 1.3.4 得到并安装 Symfony,输入命令:“pear install symfony/symfony”。 1.3.5 提示安装成功后,退出命令行方式。 安装成功后,会在 PHP 目录中建立一个 symfony.bat 文件(如图 1),之后需要使用该命 令创建工程,工程结构如图 2。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

61/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图1

symfony.bat 文件

《PHPer》

图2

创建的 Symfony 工程结构

1.4 调整 Apache rewrite_module 模式 1.4.1 打开 httpd.conf 文件,加入 LoadModule rewrite_module modules/mod_rewrite.so 。 1.4.2 重启 Apache 。 参考资料: http://www.symfony-project.org/ http://www.phppro.jp/article/framework/symfony.php http://www.phppro.jp/article/framework/comparison.php

2 使用 Symfony 创建立首个基于 PHP 的 MVC 框架项目(MyFirstSymfony) 2.1 环境 Windows XP SP2 PHP5.2.5 Apache 2.0.55 PEAR MySQL 6.1 Symfony 1.0.11 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

62/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

2.1 使用 Symfony 的项目结构 Symfony 的项目结构主要由 Project 与 Application 组成,分别使用“symfony init-project” 与“symfony init-app”命令建立。各个 application 中包含的 Module。(如图 3)

图 3 Symfony 项目结构 2.2 建立首个项目 MyFirstSymfony 2.2.1 进入 Apache 所指定的 Web-root 目录下,建立名为“myfirstsymfony”的目录。 2.2.2 进入 Windows 的命令方式,进入刚才建立的目录,“C:/LocalWeb/myfirstsymfony/” 键入“symfony init-project myfirstsymfony”(如图 4),这时 Symfony 会自动建立工程所需的 相关文件及目录(见图 5)。 PS:若看不到键入的命令时,请在环境变量中追加 symfony.bat 所在的目录即可。 2.2.3 在 myfirstsymfony 项目下建立一个 Application(如图 7),继续在刚才的目录 “C:/LocalWeb/myfirstsymfony/”输入如下命令“symfony init-app myfirstapp”(如图 6)。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

63/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图4

《PHPer》

Symfony 建立工程

图 5 Symfony 自动创建的文件及目录

图6 网站:http://www.phpchina.com

Symfony 建立 Application 投稿:phper@phpchina.com

《PHPer》

64/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图7

《PHPer》

Symfony 建立的 Application 文件及目录

PS:这时会在主项目的 web 目录内(myfirstsymfony/web/)自动建立一个 index.php 的文 件。 对于项目内的“index.php”文件,但当 MVC 中的控制层。接受所有来自 Web 的访问及 临时目录(template)与模块(module)程序的调用,这之后会讲解“master-URL”也是作为 控制层。对于由 Symfony 被自动建立的文件一般不需要进行变更调整。 2.2.4 设置 Apache 的 httpd.conf 文件,将 Symfony 所需使用的文件包入并调整。 由于我的 Apache 中还有其他项目,则按照自己的配置方式进行了配置,如果默认安装, 则请按下面图中说明进行配置,配置后,重启 Apache(如图 8、图 9) 。

图8

httpd.conf 文件设置 1

2.2.5 运行 Symfony 项目管理及配置文件 完成以上工作后,试着运行一下之前“web”目录中的 index.php 文件,这时会看到配置 成功的信息(如图 10)。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

65/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图9

《PHPer》

httpd.conf 文件设置 2

图 10

配置成功信息

若看不到,请按以下排错方式进行处理。(包括图片是否能正常显示) (1)查看 httpd.conf 配置文件是否配置正确(若图片不能显示,多数情况是由 sf 文件夹 配置不正确造成)。 (2)若仍不能看到,则修改 php.ini 文件中的 magic_quotes_gpc=Off。 运行,web 目录下的“myfirstapp_dev.php”文件,这时会在之前显示运行成功的页面右 上角追加一个调试与 LOG 的工具栏。(如图 11) 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

66/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图 11

《PHPer》

myfirstapp_dev.php 运行效果

分别查看“vars & config”、“logs & msgs”、“time”。(如图 12、13)

图 12 网站:http://www.phpchina.com

vars & config 显示

投稿:phper@phpchina.com

《PHPer》

67/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图 13

《PHPer》

logs&msgs 显示

完成以上步骤后,一个 Symfony 的项目就被建立起来了,请看下讲,“建立 Symfony 程 序模块与简单 MVC 开发––helloworld 模块的建立与开发”。 参考资料: http://codezine.jp/a/article/aid/704.aspx?p=1

3 建立 Symfony 程序模块与简单 MVC 开发–helloworld 模块的建立与开发 3.1 在Application中建立模块(module) 这次要建立的是在Symfony下运行,模块名为“helloword”,在之前“myfirstapp”中建立。 3.1.1 在“myfirstapp”中建立“helloworld”模块。 在命令行中,运行“symfony init-module myfirstapp helloworld”命令(如图14)。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

68/127


开源项目介绍:Symfony FrameWork 安装及初级使用

图14

《PHPer》

运行“symfony init-module myfirstapp helloworld”命令

这时会在“myfirstapp”的“modules”目录中建立“helloworld”目录,该目录即为所新 建立的模块(如图15)。

图15

“helloworld”目录

该目录主要结构如下: 目录结构 myfirstsymfony/---------项目目录 apps/--------------------程序目录 myfirstapp/-----------myfirstapp 程序目录 modules/-----------myfirstapp 程序的模块目录 helloworld/------被建立的 myfirstapp 下的 helloworld 模块 actions/--------动作用目录 config/---------模块设置目录 lib/-------------模块用类及类库目录(class&library) templates/-----模块用临时文件目录 validate/-------验证设置文件存放目录 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

69/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

3.1.2 查看模块是否正常 在浏览器中,输入之前建立的模块名,查看模块是否已被加入到 Symfony 框架中。浏览 器中输入 http://localhost:8080/myfirstapp_dev.php/helloworld 显示如图 16 所示。 PS:我们从这里可以看出,对于 Symfony 调用模块的方式是通过 myfirstapp_dev.php 与 index.php 文件动态调用的,在这里面,大多数实例都采用 index.php 进行处理,有很多时候 是访问不到的,但是通过“dev”的方式可以处理。

图 16

查看建立模块是否已被加入

在 helloworld 模块中,该目录下的“templates/indexSuccess.php”是被作为“View 层”进 行处理的,当编辑这个文件时,模块的相应显示设计将会执行。这个文件名实际是按照以下 规则“<Action 名><执行结果>.php”被命名的。这个命名规范,被 Symfony 严格执行,当在 “action.class.php”中定义了默认的 Action 名“index”的时候,Symfony 会按照该文件名去 查找并调用相应的 view 层文件。 3.2 对 helloworld 模块进行调整,根据 Symfony 框架思想,构建一个简单的提交程序 3.2.1 “indexSuccess.php”--Code 的编辑 indexSuccess.php 代码片断: <p>Hello,World!</p> <?php echo form_tag("helloworld/formtestaction") ?> <?php echo label_for('name', 'What is your name?') ?> <?php echo input_tag('name') ?> <?php $ary_temp = array( "VISA"=>"VISA", "MASTER"=>"MASTER","DISC"=>"DISC"); 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

70/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

echo select_tag("cctype", options_for_select($ary_temp, "DISC")); ?> <?php echo submit_tag('Ok') ?> </ form>

对于以上代码中, “<?php ?>”部分为 Symfony 的标签,使用该标签可以很方便的实现复 杂代码的简化编码工作。如上面三行在实际开发过程中的 HTML 代码见表 1。 表1

Symfony 的标签

Symfony 标签 form_tag('helloworld/formtestaction')

转为 HTML 代码时 <form method="post" action="http://localhost/myfirstapp_dev.php /helloworld/formtestaction">

label_for('name', 'What is your name?')

<label for="name">What is your name?</label>

input_tag('name')

<input type="text" name="name" id="name" value="" />

select_tag("cc_type", options_for_select($ ary_temp, "DISC"))

submit_tag('OK')

<select name="cc_type" id="cc_type"> <option value="VISA">VISA</option> <option value="MASTER">MASTER</option> <option value="DISC" selected="selected">DISC</option> </select> <input type="submit" name="commit" value="Ok" />

3.2.2 通用配置调用文件 layout.php 与通用配置文件 view.yml 的编辑 对于每个模板文件,大多情况下只是编写<body>中的内容,对于<head>部分一般都为通 用部分,以于这部分通用的配置文件,我们可以在模块中建立“templates/layout.php”文件, 将标头及 keywords 等具体信息内容,进行定义,这时我们可以在模块中建立“config /view.yml” 文件,将相应的信息进行定义,对于 layout.php 则是起到将 view.yml 设定的内容进行显示的 作用。 templates/layout.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xht ml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <?php echo include_http_metas() ?> <!--view.yml 的 http_metas:部分--> <?php echo include_metas() ?>

<!--view.yml 的 metas:部分-->

<?php echo include_title() ?>

<!--标题(可以在 Action 或 view.yml 中进行定义)-->

<link rel="shortcut icon" href="/favicon.ico" /> </head> <body> <?php echo $sf_data->getRaw('sf_content') ?> <!--在这次将各个 template 被调用--> </body> </html> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

71/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

conifig/view.yml default: http_metas: (http-metas 设置部分。「http-equiv:content」) content-type: text/html; charset=utf-8 metas: (meta 标签各部分。「name:content」) title: HelloWorld!!! robots: index, follow description: symfony project keywords: symfony, project language: en stylesheets: [main] (CSS 调用,这时调用的是<项目目录>/web/css/main.css 文件) javascripts: [ ] (Javascript 文件调用,如果写入,则调用的是<项目目录>/web/js 目录中的文件) has_layout: on (是否使用 layout 配置 on/off) layout: layout (layout 的文件名称,全文查找该文件(扩展名省略,一般为.php))

3.2.3 action 文件的编辑 actions/actions.class.php <?php /** * helloworld actions. * * @package myfirstsymfony * @subpackage helloworld * @author Suil * @version SVN: $Id: actions.class.php 2692 2006-11-15 21:03:55Z fabien $ */ class helloworldActions extends sfActions { /*(1)*/ /** * Executes index action * */ public function executeIndex() { /*(2)*/ /* $this->forward('default', 'module');*/ /*(3)*/ } /** * Executes formtest action * */ public function executeFormtestaction(){

/*(4)*/

print(htmlspecialchars($this->getRequestParameter('name'))."さん、こんにちは!"); /*(5)*/ return sfView::NONE ;

/*(6)*/

} } ?> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

72/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

说明: (1)所有的 Action 都要继承 sfActions 基类(就像是 Servlet 都要继承 HttpServlet 基类 一样,如 request 与 response 等信息); (2)运行 Index 的方法,Index 为默认的 Action,定义为对应 IndexSuccess.php 文件。 Symfony 中 Action 命名规范为。“execute<module 名或 View 名>”; (3)新建立 module 时所建立的方法,被指向默认的模块名,在调用 View 时被首先调 用。类似于 Servlet 中的 init 方法; ( 4 ) 在 View(indexSuccess.php) 中 定 义 的 提 交 Action 名 称 所 建 立 的 执 行 函 数 。 executeFormtestaction 方法; (5)对于 formtestaction 方法所需处理的动作,该动作从 view 提交的 form 中通过 request 方法获得指定为“name”的变量并将其显示到页面上; (6)对于 formtestaction 方法返回处理的页面情况,本次设为 none,即当前页面,如不 设置将会跳到 formtestactionSuccess.php 页面中(该页面需要处理),将在之后进行说明。 3.2.4 以上 MVC 运行步骤及结果如下: (1)在浏览器中运行“http://localhost:8080/myfirstapp_dev.php/helloworld”(如图 17);

图 17 MVC 运行步骤 1 (2)输入,选择相应值(如图 18);

图 18 MVC 运行步骤 2 (3)点击“OK”,提交,得到如下结果(如图 19);

图 19 MVC 运行步骤 3 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

73/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

PS:对于页面中的错误报告是由于采用 dev 的显示方式,不必理会。 3.2.5 对于 executeFormtestaction 函数返回值的调整,新建 formtestactionSuccess.php 文件 (1)调整 executeFormtestaction 函数内容; 现在我们将之前的 executeFormtestaction 函数中的代码进行下调整,如下。 代码如下: public function executeFormtestaction(){ /*print(htmlspecialchars($this->getRequestParameter('name'))."さん、こんにちは!"); return sfView::NONE ;*/ $this->name = $this->getRequestParameter("name"); $this->cctype = $this->getRequestParameter("cctype"); }

(2)再次运行程序 再次试着运行,刚才 3.2.4 的各步骤; 这时,我们便会看到 Symfony 报出“formtestactionSuccess.php”文件不存在的错误信息。 (如图 20)

图 20

运行结果

这时,我们便会看到 Symfony 报出“formtestactionSuccess.php”文件不存在的错误信息。 (3)新建 formtestactionSuccess.php 文件; 我们试着按照 Symfony 提示的信息,建立 formtestactionSuccess.php 文件,代码如下。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

74/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

formtestactionSuccess.php <p><?php echo $sf_params->get('name') ?> !</p><p></p> <?php echo "your selected!".$sf_params->get("cctype");?>

(4)再次运行程序,得到结果如图 21。

图 21

运行结果

通过这里我们可以了解到,对于 Symfony 框架默认的显示方式是按照 execute 所处理的 <ActionName>去找相应的 View 层。 3.3 Symfony 的 MVC 运行方式(如图 22)

图 22 网站:http://www.phpchina.com

Symfony 的 MVC 运行方式 投稿:phper@phpchina.com

《PHPer》

75/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

3.4 补充说明 sfView 较常用的几个 Action 返回值的说明,见表 2 表2

sfView 较常用的几个 Action 返回值

返回值设定

说明

sfView::SUCCESS;

结果,返回默认 View 文件(XXXSuccess.php)

'MyResult' ;

结果,返回非默认 View 文件(XXMyResult.php)

sfView::ERROR;

结果,返回错误文件(XXXError.php) ,即调用错误页面。

sfView::NONE;

结果,不返回 View(即,在当前默认 Action 的 view 层)

sfView::HEADER_ONLY;

结果,只返回 View 的 Header 值(X-JSON 的 Header 时使用)

sfView::VAR;

结果,不返回,只是返回变量(一般为单体测试时使用)

3.5 对于 Symfony 中项目/程序/模块执行顺序的定义 对于 Symfony 中,我们之前所采用的“http://loalhost/<模块名>/<Action 名>”,并不是死 规定,对于 module 与 action 调用的组合是由 MVC 中的“C”负责的。对于这部分的调用在 “<项目目录>/<程序目录>/conf/routing.yml”文件中被定义。 (包括,是否对 index.php 或 dev.php 文件进行解析等)。 config/routing.yml # default rules homepage: ([/]使用 url 指定的时候,Control 解释器,默认 module 的 Action 方法为 index) url: / param: { module: default, action: index } (对于[/symfony/<Action 名>/*]的时候,调用 default,module。) default_symfony: url: /symfony/:action/* param: { module: default } (对于[/<module 名>]的时候,Action 为 Index) default_index: url: /:module param: { action: index } (基本的 URL 按照[/<module 名>/<action 名>/*]进行解释) default: url: /:module/:action/*

3.6 Symfony 阶段总结 经过这几天的学习,对 Symfony 基本有所了解,再加上对其它框架(如 ZF、ThinkPHP) 的了解,我选择 Symfony 有以下原因: (1)通过 Symfony 的命令方式可以很快的建立多个模块,适合当前多数企业的快速开 发; 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

76/127


开源项目介绍:Symfony FrameWork 安装及初级使用

《PHPer》

(2)Web2.0 支持(Ajax 等); (3)依据 YMAL 语言,有着较好的数据为模型支持 ORM; (4)多数大型网站应用(如:Yahoo BookMarks 等); (5)成熟的 MVC 结构,与 JSP、Servlet、Structs 十分相似; (6)强大的插件支持; (7)被日本多数 PHP 企业所接纳并用于实际项目开发。(上海、北京等地待遇优厚) 经过我这几天的学习,已经开始十分喜欢上了 Symfony,同时也坚信 Symfony 的发展之 路将会更好,对于该框架的了解及应用,现在也只是在初学中,希望学习 Symfony 的同志们 能够多多沟通,让我们共同支持 Symfony 的发展。 参考资料: http://codezine.jp/a/article/aid/704.aspx?p=4 作者: 网 名:stven,polo 邮 件:stvsui@hotmail.com 个人博客:http://stvsui.spaces.live.com/

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

77/127


LAMP 大讲堂:会话控制

《PHPer》

LAMP 大讲堂

会话控制 作者:高洛峰

1 什么是会话控制 要学习会话控制我们就先来理解一下“会话”,“会话”在我们生活中就好比你去一家商 场,从你一开始进去,直到你从这家商场走出来,这之间的整个购物的过程就可以理解为“会 话”;当我们上网的时候会话是无处不在的,例如我们使用的 Email 系统,当我们使用 URL 登录网站开始,到你退出这个网站,这之间的查看邮件、收信、发信等过程就是一个会话。 我们为什么要使用会话控制?因为我们上网使用的是“HTTP 协议”,而“HTTP 协议” 是无状态协议,就是说 HTTP 协议没有一个内建机制来维护两个事务之间的状态。当一个用 户在请求一个页面后再请求另外一个页面时,HTTP 协议不能告诉我们这两个请求是来自同 一个用户。 浏 览 器

客户机端

网页五

网页四

网页三

网页二

网页一

Web 服务器端

图1

HTTP 请求简图

如图 1 所示,某网站的用户通过客户机的浏览器上面的地址栏输入 Web 服务器的 URL 访问“网页一”,使用用户资料登入网站,这样“网页一”的全部内容都被下载到客户机的浏 览器中,因为我们是使用“HTTP 协议”来请求访问 Web 服务器,它是无状态协议,这时一 旦服务器响应完客户端的请求后就断开会话的连接,当用户使用“网页一”中的链接或直接 在地址栏中输入 Web 服务器 URL 来浏览网站中其它网页时,这位使用者的相关资料,并不 会传递到下一个程序之中。所以除非他在每浏览一个网页时,重复执行登入的动作,否则服 务器无法了解到底是哪位用户在浏览这个网页。 会话控制的思想是指能够在网站中根据一个会话来跟踪用户,这样我们就可以很容易做 到用户登录的支持。而不是在每浏览一个网页时,重复执行登入的动作。所以会话控制允许 服务器跟踪同一个客户端做出的连续请求。会话跟踪技术使得服务器应用程序可以保持客户 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

78/127


LAMP 大讲堂:会话控制

《PHPer》

应用的相关信息。也就是在处理同一个网站多个页面之间数据相互传递的问题。

2 会话控制的基本应用 目前会话跟踪常用的方法有这么几中方式,利用超链接URL参数或是header()函数以及其 它重定向的转向方式,传送用户资料给其它的PHP程序;通过网页中的各种隐藏式表单来储 存使用者资料,并传递给服务器中的PHP程序使用;使用Cookie将使用者的状态资料存放在 客户端电脑之中,让其它程序能透过存取用户电脑中的Cookie,来存取目前的使用者资料; 使用Session将使用者的状态资料存放于Web服务器中,让其它程序能透过服务器中的档案或 资料库,来存取使用者的资料。 在上面四种网页间的资料的传递方法之中,使用 URL 或隐藏式表单方式,主要是用来处 理参数的传递或者多笔资料的输入;Cookie 用来储存一些可在客户端执行的程序或使用者状 态资讯;而 Session 则主要是用来建立用户对于服务器程序处理的必要资料,例如使用者登录 资料、使用者权限信息等等。 2.1 使用 URL 和隐藏式表单进行参数传递 会话控制是控制用户在浏览同一个网站中的不同页面时,可以进行一个页面和另一个页 面之间的资料传递,而在浏览网站时,从一个页面转向到另一个页面是通过下面方式中任意 一种方式来实现的; 1. 直接在浏览器的地址栏中输入 URL; 2. 在 HTML 中“a”链接标签的“href”属性加入 URL,例如: 示例 <a href=“URL”>网页名称</a>

3. 利用重定向的方式实现页面跳转,可以使用 PHP 自己的函数 header()来实现页面跳 转,也可以在 PHP 中嵌入 JavaScript 代码来帮我们实现。 示例 header("Location: URL"); 或 echo “<script> window.location=’URL’</script>”; 或 echo “<script> window.location.replace(‘URL’)”; 或 echo “<script> window.navigate(‘URL’) </script>”;

4. 在表单提交中,也是把页面转到另一个页面,例如: 示例 <?<form action=”URL”> <input type=”submit”value=”送出”> </form> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

79/127


LAMP 大讲堂:会话控制

《PHPer》

上面几种方式都是使用URL进行页面跳转,所以除了表单提交的方式外,我们都可以利 用URL把数据资料从一个页面传递到另外一个服务器端页面,URL的使用语法格式为: http://连接网址/网页文件?资料栏位1=资料内容&资料栏位2=资料内容&… 其中“?”字元代表声明后面附加的第一个参数资料,而资料与资料之间以“&”连接, 资料要以属性名和属性值的形式存在,中间使用“=”号相连,但是请注意一点,参数列表中 不允许有空白字元存在,例如 http://www.lampuser.com/login.php?username=lampteacher&password=123456&… 虽然我们可以使用 URL 进行资料传递,但在 form 表单中的 action 属性值的 URL,它是 不能使用上面 URL 附加参数的形式进行资料传递的,因为表单在提交的时候,将<form>标签 里面所有<input>标签的 name 属性值和其对应的 value 属性值形成参数,并替换原有<form> 标签中 action 属性 URL 的所有参数,形成一个新的 URL,并把表单内容传递到下一个页面。 所以我们在提交表单转向另一个页面时,只有通过表单里的<input>标签来帮我们完成。通常 的表单会显示在用户的浏览器中,以提示用户输入相关的资料。但是表单用于程序与程序之 间相互传递信息时,就必须使用隐藏式表单栏。我们采用<input>标签的 type 属性为“hidden” 的隐藏表单。 示例 <input type="hidden" name="栏位名称" value="内容资料">

数据资料通过URL传递过来之后,将URL所传递过来的资料,转存成数组形态;我们可 以使用外部变量数组$_GET["资料栏位"]和$_REQUEST["资料栏位"]来接收资料,如果使用表 单的方式,我们还可以将<form>标签method属性的默认“get”值改为“post”方法传递,这 样我们就可以使用$_POST数组来接收传递过来的资料内容。 发送页面 send.php,显示如图 2 send.php <form action="revice.php" method="get"> <!-表单数据 ...... --> <input type="hidden" name="username" value="lampteacher"> <input type="hidden" name="password" value="123456"> <input type="submit" value="点击转到接收页面"> </form> <br> <a href="revice.php?username=lampteacher&password=123456">点击转到接收页面</a> <br> <div onclick="window.location='revice.php?username=lampteacher&password=123456'"> 点击转到接收页面 </div> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

80/127


LAMP 大讲堂:会话控制

《PHPer》

图2

GET 传递数据

接收页面 revice.php,显示如图 3 revice.php <?php $username=$_GET["username"]; $password=$_GET["password"]; echo "接收到的用户名:".$username."<br>"; echo "接收到的密码为:".$password."<br>"; ?>

图3

GET 接收数据

Cookie 的应用 当我们使用 URL 和隐藏表单的形式进行 PHP 页面程序的数据传递时,如果需要传递的 数据比较多,页面传递的次数比较频繁,或者是需要传递数组时,这种办法就有些烦琐。特 别是在项目中跟踪一个用户时,要为不同权限的用户提供不同的动态页面,就需要每个页面 都知道现在的用户是谁,所以就需要每个页面都能够获得这个用户相关信息。如果是使用 URL 的方式,我们要在每个页面转向的 URL 上都加上同样的用户信息,这样就给项目开发人员带 来很大的工作困难。所以对于这种情况我们通常选用 Cookie 和 Session 技术。 PHP 透明地支持 HTTP Cookie。Cookie 是一种在远程浏览器端储存数据并以此来跟踪和 识别用户的机制。Cookie 的英文的意思是“小甜饼”,是 Web 服务器端给客户端的,但是这 个“小甜饼”并不是服务器白给客户端的,需要客户端使用 Cookie 为服务器记录一些信息。 Cookie 技术就好比你第一次去超市买东西,超市给你提供的一张会员卡,这样你每次去这家 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

81/127


LAMP 大讲堂:会话控制

《PHPer》

超市买东西时,只要提供你保存的这张会员卡,都会享受到会员打折的待遇。Cookie 这种技 术让 Web 服务器能将一些只须存放于客户端,或者可以在客户端进行运算的资料,存放于用 户的电脑系统之中。如此就不需要在连接服务器时,再透过网路传输、处理这些资料,进而 提高网页处理的效率,降低服务器的负担。 [COOKIE] Username=”高洛峰” Password=”123456”

浏 览 器

客户机端

网页五

网页四

网页三

网页二

网页一

Web 服务器端

图4

Cookie 工作示意

Cookie 是用来将使用者资料记录在客户端的技术;例如图 4 所示,某网站的用户通过客 户机的浏览器上面的地址栏输入 Web 服务器的 URL 访问“网页一”,使用用户名“sky”和 密码为“123”等用户资料登入网站时,在“网页一”中把用户名“sky”和密码“123”等用 户资料,设置到客户端电脑的 Cookie 中,当这个用户再次使用这个浏览器去访问同一个服务 器的其它网页时,服务器的其它页面就可以从客户端电脑的 Cookie 中获取到登录时输入的用 户资料信息。 设置 Cookie Cookie 的建立十分简单,只要用户的浏览器支持 Cookie 功能,就可以使用 PHP 内建的 setcookie()函数或 setrawcookie()函数来新增建立一个 Cookie。Cookie 是 HTTP 标头的一部分, 因此 setcookie()函数必须在其它信息被输出到浏览器前调用,这是 Cookie 的限制,而不是 PHP。所以你必须在任何<html>或是<head>标签之前调用此函数。即使是空格或空行都不要 在 PHP 程序中使用 setcookie()函数前输出,这和对 header()函数的限制类似。但可以使用“输 出缓冲函数”来延迟脚本的输出,直到按需要设置好了所有的 Cookie 或者其它 HTTP 标头。 setcookie 语法格式: setcookie(string name, string value, int expire, string path,string domain, int secure) 它的所有参数是对应 HTTP 标头 Cookie 资料的属性,其代表意义分别如下: name:Cookie 的识别名称; value:Cookie 的值,可以为数值或字符串型态; expire:Cookie 的生存期限; 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

82/127


LAMP 大讲堂:会话控制

《PHPer》

path:Cookie 在服务器端的指定路径,当设定此值时,服务器中只有指定路径下的网 页或程序可以存取此 Cookie。 domain:指定此 Cookie 所属服务器的网址名称,预设是建立此 Cookie 服务器的网址。 secure:Cookie 的安全识别常数,如果设定此值代表只有在某种情况下,才能在客户 端与服务器之间传递。 虽然 setcookie 函数的导入参数看起来不少,但除了参数 name 之外,其它都是非必需的。 如果只有 name 这一个参数,则客户端原有此名称的 Cookie 将会被删除,你也可以使用空字 符串(" ")来略过此参数,参数 expire 和 secure 是个整数,你可以使用 0 来略过参数,而不是 使用空字符串。参数 expire 是一个正规的 Unix 时间整数,由 time()和 mktime()传回。参数 secure 指出此 Cookie 将只有在安全的 HTTPS 连结时传送。在实际建立 Cookie 时通常仅使用前面三 项参数。例如下面 Cookie 的声明叙述:setcookie("username",$username,$date);上面叙述代表 建立一个识别名称为 username 的 Cookie,其内容值为变量$username,而有效期限则由变量 $date 控制。 login.php <html> <head><title>用户登录</title></head> <body> <table align="center" border="1" widht="200"> <caption><h3>用户登录</h3></caption> <form action="login_pro.php" method="post"> <tr> <td>用户名</td> <td> <input type="text" name="username"> </td> </tr> <tr> <td>密 码</td> <td> <input type="password" name="password"> </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="登录"> <input type="reset" value="重置"> </td> </tr> </form> </table> </body> </html> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

83/127


LAMP 大讲堂:会话控制

《PHPer》

图5

用户登录界面

通过 login.php 页面的表单输入用户名和密码,点击“登录”按钮然后提交到 login_pro.php 页面设置 Cookie,把用户名和密码加到 Cookie 中去。 login_pro.php <?php $username=$_POST["username"]; $password=$_POST["password"]; setCookie("username", $username, time()+60*60*24*7); setCookie("password", $password, time()+60*60*24*7); echo “<center> 登录成功</center><br>”; ?> <a href="page1">第一个页面</a><br> <a href="page2">第二个页面</a><br> <a href="page3">第三个页面</a><br>

上面程序中我们使用了 setCookie()函数设置了 HTTP 的 Cookie 的标头,其中 Cookie 的 识别名称是“username”和“password”,对应的值是从表单传递过来的值,Cookie 的生存期 限是 time()+60*60*24*7,为一周的时间,我们可以从客户端的电脑目录“C:\Documents and Settings\Administrator\Cookies”中找到 Cookie 的文件 administrator@localhost[2].txt,内容如下: administrator@localhost[2].txt username %B8%DF%C2%E5%B7%E5 localhost/ 1024 2382891392 29919823 1699974160 29918415 * password 123456 localhost/ 1024 2382891392 29919823 1700074160 29918415 * 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

84/127


LAMP 大讲堂:会话控制

《PHPer》

读取 Cookie 资料内容 如果 Cookie 在客户端设置成功,客户端就拥有了 Cookie 档案,被存放在“C:\Documents and Settings\ 用 户 名 \Cookies 目 录 ” 下 , 当 客 户 再 次 访 问 该 网 站 时 , 浏 览 器 会 自 动 把 “C:\Documents and Settings\用户名\Cookies 目录”下与该站点对应的 Cookie 发送到服务器, 在 PHP5 中任何从客户端发送的 Cookie 都会被服务器自动包括进$_COOKIE 全局数组。 $_COOKIE 是 PHP 系统中内建读取 Cookie 资料内容的结合数组变量,它会储存所有透过 HTTP 传递的 Cookie 资料内容,并以 Cookie 的识别名称为索引值、内容值为元素,转存为数 组型态,$_COOKIE 的用法和我们读取表单所使用的外部变量数组$_GET 和$_POST 以及 $_REQUEST 的用法一样。 page.php <?php //检查 Cookie 是否存在 if (isset($_COOKIE["username"])){ //Cookie 存在即读取栏位内容 $Account = $_COOKIE["username"]; echo "识别名称为 username 的 Cookie 内容值: ".$Account; }else{ echo "客户端系统中无对应 Cookie 存在!!"; } ?>

输出结果如图 6,

图6

输出结果

除了使用$_COOKIE 结合数组变量外,系统会将客户端电脑中的所有 Cookies 及其内容 值,存放到内建的环境变量$HTTP_COOKIE_VARS 数组之中,使用方法和$_COOKIE 是一样 的。 数组型态 Cookie 应用 Cookie 可以利用数组状态,来将多个内容值储存在相同 Cookie 名称下,但不能直接使用 setCookie()函数将数组变量插入到第二个参数作为 Cookie 的值,因为 setCookie()函数的第二 个参数必须传一个字符串的值,但我们可以利用 Cookie 数组状态,使用 setCookie()函数中第 一个参数来设置关联数组和索引数组,例如, 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

85/127


LAMP 大讲堂:会话控制

《PHPer》

代码如下: setcookie(“user[username]”, “高洛峰”); setcookie(“user[password]”, “123456”); setcookie(“user[email]”, "lampteacher@gmail.com“);

在上面一段的程序中,建立了一个名为 user 的 Cookie,其中包含了三个资料栏位,这样 就形成了 Cookie 的关联数组形态,设置成功之后,PHP 服务器端就可以在程序中使用两种方 法获得客户端的 Cookie 的值,一种是使用$_COOKIE 的数组方式,但现在$_COOKIE 不是单 纯的一维数组了,已经变成了一个二维数组了;另一种就是在 PHP 服务器程序中,通过客户 端发回来的 Cookie 形成了$user 的数组,所以使用 foreach()函数就可以遍历所有传到服务器 端的 Cookie 的所有内容了,例如: 代码如下: //遍历$_COOKIE[“user”]数组 foreach($_COOKIE["user"] as $key => $value){ echo $key.":".$value."<br>"; } //遍历$user 数组 foreach($user as $key => $value){ echo $key.":".$value."<br>"; }

输出结果 username:高洛峰 password:123456 email:lampteacher@gmail.com

我们也可以使用 Cookie 的索引数组形态,例如: 代码如下: setcookie(“user[0]”, “高洛峰”); setcookie(“user[1]”, "123456”); setcookie(“user[2]”, "lampteacher@gmail.com“);

上面的程序代码段也会形成$_COOKIE[“user”]和$user 的数组。所以使用 Cookie 的数组 形态就和我们直接在 PHP 程序中声明数组非常的相似。只不过是我们把数组保存到了客端的 电脑中,然后在服务器端获取到数组的值。 删除 Cookie 如果用户想退出你的网站,不再需要使用 Cookie,这时就需要删除客户端的 Cookie,对 于删除 Cookie 的动作,共有两种方法,这两种方法都可以通过使用 setcookie()函数来进行删 除的动作。第一种方式,可以省略 setcookie()函数的所有参数列,仅导入第一个参数 Cookie 识别名称参数,来删除指定名称的 Cookie 资料;第二种方式,利用 setcookie()函数,把目标 Cookie 设定为“已过期”状态,Cookie 的有效期限参数的含义指当超过设定时间时,系统会 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

86/127


LAMP 大讲堂:会话控制

《PHPer》

自动删除客户端的 Cookie 程序,例如: 代码如下: setcookie(“Account”); //或 setcookie(“Account”, $ID, time()-10);

第二种方式中,Cookie 程序在当前时间之前已经过期,因此系统会自动将客户端识别名 称为“Account”的 Cookie 档案删除。例如: delcookie.php <?php //检查 Cookie 是否存在 if(isset($_COOKIE["username"])){ //Cookie 存在即删除,仅导入名称参数 setcookie("username"); ?>

2.2 Session 的应用 Session 与 Cookie 相似,都是用来储存使用者相关资料,但最大不同之处在于 Cookie 是 存放于客户端电脑之中,而是存放于服务器系统之下。在 Web 技术发展史上,Cookie 技术的 出现是一个重大的变革。最先是 Netscape 在它的 Netscape Navigator 浏览器中引入了 Cookie 技术,因为 Cookie 是在客户端的电脑保存资料,所以引起了一个争议,后来 W3C 协会开始 支持 Cookie 标准。以后又经过微软的大力推广,即在微软的 Internet Explorer 浏览器中完全 支持 Cookie 技术。到现在,绝大多数的浏览器都支持 Cookie 技术,或者至少兼容 Cookie 技 术的使用,既然 Cookie 是使用客户端的电脑保存信息,所以用户可以通过浏览器停止 Cookie 的使用,这样一来,Web 服务器就无法通过 Cookie 来跟踪用户信息;而 Session 技术是将使 用者相关的资料存放在服务器的系统之下,所以使用者无法停止掉 Session 的使用。 上一节我们把 Cookie 比喻成去超市买商品时办的会员卡,这张会员卡是用户自己保存的, 但如果用户去超市时忘记带卡了,或者是把卡弄丢了,这样用户就不能享受会员卡打折的待 遇了,如果超市为用户保存这张卡,用户就不用每天都把卡放在身上,但超市的会员特别多, 用户每次来,超市怎么就知道这个顾客是会员呢?所以在用户办卡的时候,超市会把会员卡 独有的卡号提供给这个用户,下次这个用户再来时,只要把自己记住的卡号提供给超市,超 市就可以通过这个卡号查询到这个会员的信息,给予打折优惠的待遇。Session 也是这个原理, 用户在第一次登录到服务器时,就为客户端提供一个独有的 Session ID,相当于前面我们提到 的会员卡卡号,如果用户没有在浏览器中停止使用 Cookie,这个 Session ID 就会保存在客户 端电脑的 Cookie 中;然后把用户的资料存放到服务器端,这样当用户切换页面时,只要在其 它页面提供出客户端 Cookie 中所存储的 Session ID,就可以从服务器中提取出这个用户的资 料,用来跟踪用户。所以也可以把 Session 中存储的数据当成是这个用户的全局变量,这个用 户在这个服务器的每个页面都可以访问到这些 Session 中存储的全局变量。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

87/127


LAMP 大讲堂:会话控制 客户机端

《PHPer》 浏 览 器

[COOKIE] Sessionid= cffaebaf1db68ca551270ee5b4e638e5

网页五

网页四

网页三

网页二

网页一

Web 服务器 端 [SESSION]

username=“高洛峰”password=“123456”

图7

会话应用

当使用者登入一个具有 Session 功能的网站时,系统会给予该使用者一个独有的 Session ID,用来在服务器中建立新的 Session 来储存使用者资料提供网站中各个网页与程序存取。因 为 Session 是存放于服务器之中,为了避免对服务器系统造成过大的负荷,因此 Session 并不 像 Cookie 是一种半永久性的存在。Session 会因为下面两种状况而自然消失,第一种状况, 当使用者关闭浏览器,也就是说失去与服务器之间的连结之后,Session 即会自动消失。而当 使用者下次登入网站时,再另行配置一个 Session 使用。第二种状况,Session 指定的有效期 限到期:一般而言 PHP 系统中对于 Session 的生存时间并无定义,也就是说预设值为零。但 PHP 开发人员可以通过修改 php.ini 配置文件中有关“session.cookie.lift_time”项目,来设定 Session 的有效期限。session.cookie_lifetime 以秒数指定了发送到浏览器的 Cookie 的生命周期。 值为 0 表示“直到关闭浏览器”。默认为 0。当系统赋予 Session 有效期限后,不管浏览器是 否开启,Session 都会自动消失。 Session 的声明与使用 Session 的使用不同于 Cookie,必须先启动,在 PHP 中必须调用 session_start()函数,以 便让 PHP 核心程序 Session 相关的内建环境变量,预先载入至内存中。这个 session_start()的 呼叫动作,就是 Session 的启动,语法格式:session_start(); 函数 Session_start()有两个作用,一是开始一个会话,二是返回已经存在的会话。这个函 数没有参数,且返回值均为 true。如果你使用基于 Cookie 的 Session,在使用 Session_start() 开启 Session 之前,浏览器不能有任何输出,因为基于 Cookie 的 Session 是在开启的时候,这 个函数会产生一个独有的 Session ID 保存到客户端电脑的 Cookie 中,和 setCookie()函数一样, 前面不能有任何的输出,输出空格或空行都不行。如果用户登录第一个页面时已经开启了 Session,并把独有的 Session ID 设置到了客户端电脑的 Cookie 中,用户在切换其它页面时, 其它页面程序中的 Session_start()的函数就不会再分配一个新的 Session ID,而是利用客户端 Cookie 中发过来的 Session ID 来返回已经存在的会话,所以同一个用户在同一个网站上的所 有页面中只有一个 Session ID,我们可以使用这个 Session ID 来跟踪一个用户。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

88/127


LAMP 大讲堂:会话控制

《PHPer》

如果你不想让每个页面都使用 Session_start()函数来开启 Session,可以在 php.ini 里启动 session.auto_start=1,但启用该选项也有一些限制,如果确实启用了 session.auto_start,则不能 将对象放入会话中,因为类定义必须在启动会话之前加载,以在会话中重建对象,也不可以 做 Session 持久化的工作。因为要开启已经存在的 Session,就必须要在 Session 开启前使用 Session_id()函数传入已经存在的 Session ID。所以不建议使用 php.ini 中的 session.auto_start 属性来开启 Session。 注册一个会话变量和读取 Session 在 PHP 之中使用 Session 变量,除了必须要启动之外,还要经过注册的手续。目前我们 注册一个 Session 使用$_SESSION 数组,自 PHP 4.1.0 起,$_SESSION 如同$_POST、$_GET、 $_REQUEST、$_COOKIE 等一样成为全局数组。与$HTTP_SESSION_VARS 不同,$_SESSION 总是具有全局范围。因此不要对$_SESSION 使用 global 关键字。如果倾向后者,可以将 $HTTP_SESSION_VARS 都替换成$_SESSION。此外注意必须在使用$_SESSION 之前先用 session_start()启动会话。在$_SESSION 关联数组中的键名具有和 PHP 中普通变量名相同的规 则,即不能以数字开头,必须以字母或下划线开头。如果 register_globals 被禁用,则只有全 局关联数组$_SESSION 中的成员可以被注册为会话变量。被恢复的会话变量也只存在于 $_SESSION 数组中。为提高安全性和代码的可读性,建议使用$_SESSION(或在 PHP4.0.6 或 更 低 版 本 中 用 $HTTP_SESSION_VARS )。 使 用 了 $_SESSION , 就 没 有 必 要 使 用 session_register()、session_unregister()、session_is_registered()函数。访问会话变量就和其它变 量一样,因此读取 Session 我们也使用$_SESSION 关联数组。例如: 代码如下: <?php //开启 Session 会话 session_start(); //注册 Session 变量 $_SESSION["username"]="高洛峰"; $_SESSION["password"]="123456"; ?>

或者, 代码如下: <?php //开启 Session 会话 session_start(); //读取 Session 变量 $username=$_SESSION["username"]; $password=$_SESSION["password"]; echo "用户名:".$username."<br>"; echo "密码是:".$password."<br>"; ?> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

89/127


LAMP 大讲堂:会话控制

《PHPer》

取消注册与关闭 Session 既然 Session 有启动、注册的动作,自然也有关闭与取消注册的内建函数,如果用户想退 出网站,把他的所有信息在服务器中销毁,就需要给这个用户提供一个注销的功能。如果将 目前 Session 关联的所有的资料全部销毁,可以使用 session_destroy()结束当前的会话,并清 空会话中的所有资源,session_destroy()销毁函数,相对于 session_start 函数,用来关闭 Session 的运作,但该函数并不会释放和当前 Session 相关的全局变量,也不会删除客户端的 Cookie。 此函数成功则传回 true,销毁 Session 资料失败则传回 false。例如:session_destroy(); 因为$_SESSION 的变量就和其它变量一样,所以我们可以使用 unset()这个函数来释放单 个 Session 变量。例如: 代码如下: //删除$_SESSION[“username”] unset($_SESSION[“username”]); //删除$_SESSION[“password”] unset($_SESSION[“passwrod”]);

一定要注意,不要用 unset($_SESSION)取消了整个$_SESSION 数组,这样将不能再通过 $_SESSION 超全局数组注册变量了。但如果想把所有的 Session 变量都删除,直接将全局数 组变量$_SESSION 赋上一个空数组。例如:$_SESSION=array(); PHP 默认的 Session 是基于 Cookie 的,Session ID 存储在客户端的 Cookie 中,如果要删 除 Cookie 的话,必须借助 setCookie()函数。但使用 setCookie()函数删除 Session ID 就必须知 道这个函数的第一个参数--Session Id 所对应的 Cookie 标识名。我们可以使用 session_name() 函数得到 Session 名称,Session 名称和 Cookies 及 URL 中的 Session ID 相关联。例如: 代码如下: if (isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time()-10); }

所以做一个注销的过程来取消注册与关闭 Session 具体的步骤如下; 代码如下: <?php // 初始化 session. session_start(); // 删除所有的 session 变量..也可用 unset($_SESSION[xxx])逐个删除. $_SESSION = array(); //删除 sessin id.由于 session 默认是基于 cookie 的,所以使用 setcookie 删除包含 session id 的 cookie. if (isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time()-10); } // 最后彻底销毁 session. session_destroy(); ?> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

90/127


LAMP 大讲堂:会话控制

《PHPer》

3 传递会话 ID 会话模块支持这两种方法传递一个会话 ID,第一种方法是基于 Cookie 的方式传递会话 ID,第二种方法是使用 URL 参数进行会话 ID 的传递。基于 Cookie 的方法更优化,但由于不 能总是可用,因为用户端可以屏蔽 Cookie;第二种方法直接将会话 ID 嵌入到 URL 中间去。 PHP 可以透明地转换链接。除非是使用 PHP4.2 或更新版本,需要手工在编译 PHP 时激活。 在 Unix 下,用--enable-trans-sid 配置选项。如果此配置选项和运行时选项 session.use_trans_sid 都被激活,相对 URL 将被自动修改为包含会话 ID。此外,可以用常量 SID,在会话启动时 被 定 义 。 如 果 客 户 端 没 有 发 送 适 当 的 会 话 Cookie 的 话 , 则 SID 的 格 式 为 session_name=session_id,否则就为一个空字符串。因此可以无条件将其嵌入到 URL 中去。 下面例子演示了怎样注册一个变量,以及怎样用 SID 正确连接到另一个页面。 代码如下: <?php session_start(); ?> <a href="http://www.uselib.com/index.php?<?php echo SID ?>">来博网</a>

如果把客户端电脑的 Cookie 停用,点击“来博网”的链接出现下面的结果,在地址栏里 会把 Session ID 以 session_name=session_id 的格式添加到 URL 上。如图 8

图8

以 Session 传递会话 ID

如果不停用客户端电脑的 Cookie,就会把 Session 保存到用户电脑的 Cookie 里,而 SID 为一个空字符串,点击“来博网”的链接出现下面的结果,如图 9

图9

以 Cookie 传递会话 ID

如果编译 PHP 时指定了--enable-trans-sid,就不需要像上例那样输出 SID 了,相对 URL 将被自动修改为包含会话 ID,这是我们使用 Linux 服务器常用的方法,但要注意,非相对的 URL 被假定为指向外部站点,因此没有附加 SID,因为这可能是个安全隐患将 SID 泄露给不 同的服务器。 讲师介绍: 高洛峰,北京易第优教育发展有限公司教学主管,毕业于 首都经贸大学计算机系,拥有多年软件开发经验,曾先后任大 连科特软件公司高级软件工程师,香港即时集团教学管理部总 经理、北京校区副校长,东软长春办事处高级技术讲师,具有 扎实的技术功底和丰富的教学经验。精通多种操作系统、嵌入 式开发、C\C++、J2EE、J2ME、J2SE、LAMP开发及Oracle数据 库等技术。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

91/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

教程连载

使用 Symfony 制作简单留言板(一) 作者:stven,polo

1 环境 Windows XP PHP5.2.5 Apache 2.0.55 Symfony 1.0.11。

2 留言板 Application 文件结构(如图 1)

图1

留言板 Application 文件结构

3 留言板页面图像跳转及 UseCase 情况(UML) 3.1 UseCase 与画面跳转情况 3.1.1 留言板 UseCase(如图 2) 。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

92/127


教程连载:使用 Symfony 制作留言板(一)

图2

《PHPer》

留言板 UseCase

3.1.2 留言板画面跳转情况(如图 3)。 跳转说明: (1)从“浏览画面”处点击“管理页面”并取得认证后进入“管理画面”; (2)从“管理画面”点击“Logout”后,返回“浏览画面”; (3)从“浏览画面”处点击“搜索”后进入“搜索画面”; (4)从“搜索画面”处点击“浏览表示”后进入“浏览画面”; (5)从“浏览画面”点击“新建留言”或“评论”后,进入“新建留言画面”; (6)从“新建留言画面”点击“保存留言” (或点击“取消”)登录记录后,回到“浏览 画面”; (7)从“搜索画面”找到符合条件的留言后点击“新建留言”或“评论”后进入“新建 留言画面”; (8)当一条留言被删除后,返回“浏览画面”。 3.2 程序功能说明 一个简单的留言板。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

93/127


教程连载:使用 Symfony 制作留言板(一)

图3

《PHPer》

留言板页面跳转情况

3.3 业务说明 3.3.1 “用户”与“管理员”两个用户。 3.3.2 所有用户访问 GuestBook,显示“浏览留言”页面。 3.3.3 所有用户通过“浏览留言”页面,可以进入“新建留言”与“查询”页面,点击单 条留言进入“查看留言”页面显示该留言全部信息,“用户”输入正确密码后在“浏览留言” 页面中可对自己的留言进行“编辑”、“删除”操作,“管理员”可对所有留言进行管理“编 辑”、“删除”操作。 3.3.4 在“查看留言”页面,如果输入正确密码,可进行“编辑”与“删除”操作,对于 “管理员”也可进行。 3.3.5 通过“查询”链接进入“查询”页面,通过“关键字查询”、“用户查询”、“日 期查询”条件进行查询,并将结果显示在“查询”页面下方。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

94/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

4 留言板数据库与数据表构建 4.1 数库名:symfonydb 4.2 数据表名:tab_guestbook(见表 1) 表1 字段

tab_guestbook 结构

类型

说明

Id

Int

ID(主键,自增长,1)

Title

Varchar(30)

标题

Author

Varchar(30)

用户名

Mail

Text

邮件地址

url

Text

个人主页

Body

Text

正文

Password

Varchar(15)

删除密码

Parent_id

Int

默认为“0” ,记录评论留言父 ID

Created_at

Timestamp

留言时间

4.3 在 MySQL 中创建上面所说的数据库与数据表。

5 创建 GuestBook 程序 项目名称:myfirstsymfony(使用即有的 Symfony 项目) 程序名称:guestbook 5.1 打开 Windows 的命行行方式 5.2 使用 DOS 命令进入 Symfony 项目所在目录(如图 4)

图4

进入 Symfony 的 DOS 命令

5.3 输入创建程序命令“symfony init-app guestbook”(如图 5),创建 guestbook, Application(如图 6)

图5 网站:http://www.phpchina.com

创建程序命令

投稿:phper@phpchina.com

《PHPer》

95/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

图 6 guesttbook 目录结构

6 使用 Symfony 特有的 scaffolding 功能自动创建数据库 module 与 model 等 6.1 编辑 databases.yml 文件,配置数据库信息 打开“<项目目录>/<config>/databases.yml”文件,编辑数据库信息,如下代码: database.yml all:(任意数据库连接名。对应生成“schemal.yml”文件的开头属性) propel: (数据库驱动类文件,sfPropelDatabase.class.php,对于 Propel 来说该项不需要调整) class:sfPropelDatabase param: phptype: mysql(数据库系统名称,共他数据库如:SQLServer、Pgsql、Sqlite、Oracle 都可以) host: localhost (主机名) database: symfonydb (数据库名) username: root (连接用户名) password: 123456 (连接密码)

PS:该文件不可以使用“TAB”分隔,“级别一次要对”,否则到后面测试是否成功建 立 CRUD 时会报错(报错信息如图 7)。

图7

报错信息

6.2 生成数据库定义文件(schema.yml) schema.yml 文件里是为了生成数据库 model(模型)所记录的 Table(数据表)结构的文 件。这个文件是用来记录“自然” (实体)的描述,通常在建立完程序后可以从即有的数据表 中自动生成,被 Propel 所生成。在 Symfony 里的 ORM 便是使用 Propel 实现的。 创 建 数 据 库 连 接 描 述 : 打 开 “ < 项 目 目 录 >/<config>/propel.ini ” 文 件 , 调 整 其 中 的 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

96/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

“propel.database.ini”项。 将 propel.database.url = mysql://root@localhost/myfirstsymfony 调整为 propel.database.url = mysql://root:123456@localhost/symfonydb 。 PS:定义的数据库 URL 格式为“mysql://<连接数据库用户名>:<连接密码>@<主机名>/< 数据库名>”。 6.3 使用 Symfony 命令创建数据库模型(Schema)定义文件 输入命令“symfony propel-build-schema”,这时 Symfony 会指定数据库中所有数据表的 描述信息定义到“<项目目录>/<config>/schema.yml”文件中(如图 8)。

图8

创建数据库模型

生成后的文件如下: schema.yml --propel: (databases.yml 对应的数据库连接名) tab_guestbook: (数据表名) _attributes: (数据表的属性如下面的 idMethod) idMethod: native (DBMS 特有的用来表示分配 ID 情况,若为“none”时不使用自动分配。) id: (数据列名) type: INTEGER (BOOLEAN/INTEGER/FLOAT/DATE/VARCHAR/TIMESTAMP 等类型) required: true (是否为必输项) autoIncrement: true (是否为自增长) primaryKey: true (是否为主键) title: type: VARCHAR size: 50 …… 略 created_at: type: TIMESTAMP required: true (该项设置 table 时错误) default: CURRENT_TIMESTAMP (该项设置 table 时错误,在运行构建数据库对象模型时会 出现错误) 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

97/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

6.4 从 schema.yml 从生成数据表定义 SQL 文件 生成完上面的 schema.yml 文件后,我们使用“symfony propel-build-sql”来创建数据表定 义的 SQL 文件,用来保存项目相关资料。 生成后目录:“<项目目录>/data/sql/lib.model.schema.sql”。

7 根据 schema.yml 生成数据库对象模型(object-model)与 CRUD(ORM) 7.1 生成数据库对象模型 根据上面所生成的 schema.yml 文件,通过 Symfony 命令生成数据库对象模型。 “symfony propel-build-model”。 成功后会在“<项目目录>/lib/model/”建立“OM”与“MAP”目录与相关文件。 目录结构 myfirstsymfony /lib/model/TabGuestbookPeer.php ----(子类,继承于 BaseTabGuestbookPeer 用于处理指定数据表 CRUD 操作类,该类方法可以在 symfony 中自动被建立后,按照要求调整) /lib/model/TabGuestbook.php ----(子类,继承于 BaseTabGuestbook 用于每条数据的封装及显示处 理) /lib/model/map/TabGuestbookMapBuilder.php ----(实时数据表映射类,为数据访问类调用服务) /lib/model/om/BaseTabGuestbook.php ----(抽象类,数据访问,数据封装,get/set 动作集类,被 TabGuestbook 所继承) /lib/model/om/BaseTabGuestbookPeer.php ----(抽象类,多用于执行 CRUD 操作,被 TabGuestbookPeer 所继承)

PS:对于每个实体数据表对应除 MapBuilder 以外的四个类文件。 7.2 使用 scaffolding 功能,基于现有模型类自动生成 CRUD 数据库访问 建立 CRUD 的目的:使用命令方式快速建立基于某 ORM 下的带有 CRUD 功能的 Module 及 Action 。 在命令行输入命令:“symfony propel-generate-crud guestbook guestbook TabGuestbook”, 生成的数据模型类所在目录如图 8 和图 9。

图8 网站:http://www.phpchina.com

程序名 投稿:phper@phpchina.com

图9

数据模型类名 《PHPer》

98/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

PS:使用该命令时需要注意以下格式。 “Symfony propel-generate-crud<ApplicationName>< 要建立的模块名><已建立的数据库模型类名>”创建后会在“<工程目录>/guestbook/modules/” 目录下创建“guestbook”模块,且在“web”目录下自动创建“guestbook.php” (如图 10)与 “guestbook_dev.php”(如图 11)文件。

图 10 guestbook.php 所在目录

图 11

guestbook_dev.php 所在目录

打 开 浏 览 器 , 输 入 : http://localhost:8080/guestbook_dev.php/guestbook 后 便 会 看 到 GuestBook 调用“listSuccess.php”后的结果(如图 12)。 7.3 使用 scaffolding 功能自动生成文件及方法说明 完成以上操作后,我们便完成了对一个数据库中表的 ORM 与 CRUD 的自动建立,现在 我们对自动建立出的 CRUD 的 Action 及各文件进行说明。

图 12

调用 listSuccess.php 显示效果

7.3.1 自动建立的 Action 方法说明(见表 2)。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

99/127


教程连载:使用 Symfony 制作留言板(一)

表2

《PHPer》

actions.class.php 中 Action 方法说明

Action 名

Action 处理说明

executeIndex

跳接到 guestbook 的 list 的 Action 中

executeList

显示所有数据

executeShow

显示单一数据

executeEdit

数据编辑

executeUpdate

数据更新

executeDelete

数据删除

executeCreate

新建数据

7.3.2 自动建立的 Templates 说明(见表 3) 表3

Templates 说明

Template 名

Template 处理说明

editSuccess.php

数据编辑 Form 表 Template

listSuccess.php

显示所有数据的 Template

showSuccess.php

显示单个数据的 Template

创建完以上步骤后,一个带有 CRUD 的 GuestBook 的雏形就基本建立完毕了,试着对自 动生成的 CRUD 进行下操作,添加几条数据(如图 13)。

图 13

guestbook 显示效果

8 调整自动生成的逻辑结构与显示方式 8.1 调整 List-Action 方法中的结果变量,以便方便编码(了解 Symfony 数据读取及传值 方式) 8.1.1 打开“actions.class.php”文件,调整其中的 executeList 方法,调整代码为: actions.class.php 的 executeList 方法 public function executeList(){ //$this->tab_guestbooks = TabGuestbookPeer::doSelect(new Criteria()); $c = new Criteria(); // (1) $c->addDescendingOrderByColumn(TabGuestbookPeer::ID); // (2) $this->gbdatas = TabGuestbookPeer::doSelect($c); // (3) }

我们来解读一下上面的代码: 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

100/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

(1)取出 LIST 的 Action 中使用了 Criteria 对象,这个类中包括了许多对数据库操作的方 法,该类一般被 Propel 的 Beer 所服务 (例如,之前使用 Propel 生成的 tabGuestbookpeer 类); (2)使用 Criteria 对象的 addDescendingOrderByColumn(TabGuestbookPeer::ID)方法, 在取数据时按照指定数据表的列进行排序,这里采用 TabGuestbook 表的 ID 作为排序; (3)使用 Peer 对象的 doSelect()方法将数据按照指定 ID 为排序取出数据,并存放 gbdatas 变量中,这时 gbdatas 变量为 BaseTabGuestbook 对象数且,对于 gbdatas 可以认为是 Symfony 的内存。 在设置完上述后,我们还需要对 listSuccess.php 的 Template 进行调整,因为对于该方法, 没有使用 sfView 转接,因此会在执行后,自动调用模板中 listSuccess.php 文件并进行显示处 理。 8.1.2 打开“listSuccess.php”文件,根据 executeList 的 Action 中传值情况调整该文件中 的 foreach 部分,将之前采用$tab_guestbooks 改为 executeList 中的 gbdatas。调整后该部分代 码为: 调整后代码 <?php foreach ($gbdatas as $gbdata): ?> <tr> <td><?php echo link_to($gbdata->getId(), 'guestbook/show?id='.$gbdata->getId()) ?> </td> <td><?php echo $gbdata->getTitle() ?> </td> <td><?php echo $gbdata->getAuthor() ?> </td> …… 略

8.2 调整 Update-Action 方法,对需要更新的数据进行简单的处理。 去除“正文”中的换行与回车符“\r\n”这样做是为了防止有些用户通过 XSS 方式,对 服务器进行攻击的处理,调整代码如下: 调整后代码 <?php public function executeUpdate() { 略… … //$tab_guestbook->setBody($this->getRequestParameter('body')); $body = $this->getRequestParameter("body"); $body = str_replace("\r\n", "\n", $body); $body = str_replace("\r", "\n", $body); $tab_guestbook->setBody($body); ……略 return $this->redirect('guestbook/show?id='.$tab_guestbook->getId()); } ?>

PS:XSS(Cross Site Scripting) ,指通过浏览器向服务器写入带有攻击性的 JavaScrip 等 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

101/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

Web 代码,对服务器进行的攻击。这种一般用在“留言版、论坛”的正文中被增加。当服务 器在取出数据显示时被执行。 (如 PHP 使用“htmlspecialchars”函数)这种攻击可以使“Cookie” 数据被盗取,若被应用于商品网站,则会被注入假的商品信息,并造成经济损失的一种脚本 攻击方式,为了防止这种情况的发生,最简单的方式,但是去掉正文中所有换行与回车符。 在 executeUpdate 的 Action 方法中,通过 BaseTabGuestbook 类的 save()、delete()等方法 来处理对数据的保存,通过 getXX()、setXX()方法得到数据与设置数据,对于 getXX()与 setXX() 方法中有一个很有趣的设置便函是 created_at 我们在查看这两个方法时会发现 propel 对这个 列自动建立了时间的验证。这便是 propel 中的特殊列。这列还包括:created_at、updated_at 等。 8.3 根据 Symofny 的 TAG 调整 listSuccess.php(模板) 打开“listSuccess.php”文件,做以下调整: (1)调整显示方式; (2)显示留言者姓名,并对该项增加 mailto 的链接; (3)显示留言者的 URL 并建立链接; (4)建立“回复”按钮,并将回复提交给 Create 的 Action。 (5)增加“新建留言”的 Submit 按钮。 调整后显示如图 14。 主要调整代码如下: 代码如下: 略… … <?php foreach ($gbdatas as $gbdata): ?> <tr> <td><big><?php echo $gbdata->getTitle() ?> </big></td> <td><?php mail_to($gbdata->getMail(), $gbdata->getAuthor())?></td> <td><small><?php echo $gbdata->getCreatedAt() ?> </small></td> <td><?php echo link_to("URL", $gbdata->getUrl())?></td> <td><div align="right"> <?php echo form_tag("guestbook/create"); echo input_hidden_tag("father_id", $gbdata->getId()); echo input_hidden_tag("father_title", $gbdata->getTitle()); echo input_hidden_tag("father_body", $gbdata->getBody()); echo submit_tag("Replay"); ?> </form> </div></td> </tr> <tr><td><?php echo $gbdata->getBody() ?> </td></tr> 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

102/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

<?php endforeach; ?> </tbody> </table> <!--<?php echo link_to ('create', 'guestbook/create') ?>--> <?php echo form_tag("guestbook/create")?> <?php echo input_hidden_tag("father_id", 0)?> <?php echo submit_tag("New GuestBook")?> </form> ……略

图 14

修改后 guestbook 显示效果

PS:调整时可以参考《Symfony Book》中第 10 章内容,查看各 form 标签作用,这里便 不再说明,之后如果有时间会再总结《Symfony 常用标签说明》的文章。 8.4 根据 Symfony 标签,调整“editSuccess.php”模板 (1)追加从 listSuccess.php 中传入的对 father_id 的判断,当存在 father_id 时表示为“回 复”否则为“编辑”; (2)调整其他标签。 调整后显示如图 15。 主要调整代码如下: 代码如下: 略… … <?php if($sf_params->get("father_id")){ echo input_tag("title", "RE:". $sf_params->get("father_title"), array("size"=>30)); } else { echo object_input_tag($tab_guestbook, "getTitle", array("size"=>50)); 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

103/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

} ?> … … 略… … <?php if($sf_params->get("father_body")){ echo textarea_tag("body",">>".str_replace("\n", "\n>", $sf_params->get("father_body")), array("size"=>"30x3")); } else { echo object_textarea_tag($tab_guestbook, 'getBody', array ('size' => '30x3')); } ?> 略… … <td><?php echo object_input_tag($tab_guestbook, 'getPassword', array ( 'size' => 20,"type"=>"password")) ?> </td> <td><?php echo input_hidden_tag("parent_id", $sf_params->get("father_id"))?></td> ……略 <?php if($sf_params->has("father_id") and $sf_params->get("father_id") != 0){ echo submit_tag('OK,Reply'); } else { echo submit_tag("OK,Save"); } ?> ……略

图 15

修改后 editSuccess.php 显示效果

8.4 根据 Symfony 标签,调整“showSuccess.php”模板 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

104/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

(1)增加“回复”按钮与传递相应的值; (2)调整其它标签。 调整后显示如图 16。 主要调整代码如下: 代码如下: 略… … <div align="right"> <?php echo form_tag("guestbook/create"); echo input_hidden_tag("father_id", $tab_guestbook->getId()); echo input_hidden_tag("father_title", $tab_guestbook->getTitle()); echo input_hidden_tag("father_body", $tab_guestbook->getBody()); echo submit_tag("OK,Replay"); ?> </form> </div> ……略

图 16

showSuccess.php 模板调整后显示效果

8.5 再次调整 listSuccess.php 增加对回复信息的显示 (1)executeList 的 Action 方法,对数据进行判断(使用 Criteria) ; “executeList”代码如下: executeList <?php public function executeList() { 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

105/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

//$this->tab_guestbooks = TabGuestbookPeer::doSelect(new Criteria()); $c = new Criteria(); $c->add(TabGuestbookPeer::ID ,0); $c->addDescendingOrderByColumn(TabGuestbookPeer::ID); $this->gbdatas = TabGuestbookPeer::doSelect($c); $father = null; foreach ($this->gbdatas as $father){ $c_reply = new Criteria(); $c_reply->add(TabGuestbookPeer::PARENT_ID , $father->getId()); $c_reply->addDescendingOrderByColumn(TabGuestbookPeer::ID ); $no = "threads".$father->getId(); $this->{$no} = TabGuestbookPeer::doSelect($c_reply); } } ?>

(2)调整 listSuccess.php 显示代码,增加对回复的显示。 “listSuccess.php”代码调整如下: listSuccess.php 略… … <?php $th = "threads".$gbdata->getId(); foreach ($$th as $reply):?> <div style="margin-left: 20px"> <table> <tr> <td><?php echo $reply->getTitle() ?> </td> <td><?php mail_to($reply->getMail(), $reply->getAuthor())?></td> <td><small><?php echo $reply->getCreatedAt() ?> </small></td> <td><?php echo link_to("URL", $reply->getUrl())?></td> <td><?php echo $reply->getBody();?></td> </tr> </table> </div> <? endforeach; ?> ……略

最后显示结果如图 17。

9 补充说明,调整 Symfony 路由跳转规则,不使用 dev 方式显示模块 对于不想使用 dev 进行显示的时候,处理如下: (1)打开“<项目目录>/apps/guestbook/config/routing.yml”文件,调整其中的“homepage” 项将其调整为“guestbook”,这样在处理时会调用 guestbook.php 作为处理; (2)调整 Apache 的 httpd.conf 文件,将“DirectoryIndex”项改为“guestbook.php”,这 样默认情况下系统会先调用“guestbook.php”作为默认页; 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

106/127


教程连载:使用 Symfony 制作留言板(一)

图 17

《PHPer》

调整 listSuccess.php 后 guestbook 效果

(3)调整“<项目目录>/web/.htaccess”文件,将之前的“RewriteRule”项进行调整为 “RewriteRule ^(.*)$ guestbook.php [QSA,L]”; (4)清除 Symfony 的缓存,进入“命令行”方式,在 Symfony 项目目录下运行“symfony cc”命令,清除所有缓存; (5)重启 Apache 服务器。 这时我们再在浏览器中输入:http://localhost:8080/guestbook ,显示效果如图 18。

10 总结 这样一个基本的 Symfony 留言板就被建立起来了,虽然不是很好看,但总算有点留言板 的功能了。这次所建立的留言板让我们学到了以下知识:

图 18 网站:http://www.phpchina.com

guestbook 最终显示效果 投稿:phper@phpchina.com

《PHPer》

107/127


教程连载:使用 Symfony 制作留言板(一)

《PHPer》

(1)使用 Symfony 命令动态创建程序(Applicateion); (2)使用 Symfony 命令动态创建 ORM(数据库映射模型); (3)使用 Symfony 命令动态创建数据表的 CRUD 动作(Action); (4)使用 Symfony 命令从 schema.yml 文件中建立数据表 SQL 文档; (5)Symfony 中对于变量是如何传递的; (6)Symfony 中对于对象是如何传递与取值的(object_XXXX 等标签); (7)Symfony 中 Propel 数据库是如何应用的(Criteria 类是什么); (8)Symfony 中各标签的灵活运用; (9)Symfony 中不使用 dev 方式显示时应如何设置 http://localhost:8080/guestbook 方式。 (10)《Symfony Book》与《Symfony API》参考书是如何使用的(BOOK 为标签及命令, API 为 symfony 功能类说明); (11)扩展知识,了解什么是 XSS(Cross Site Scriping)。 注:文中涉及到完整代码在附件/FrameWork 应用篇/中。 请看下篇:PHP-FrameWork 应用篇---使用 Symfony 制作简单留言板(二) 参考资料: http://codezine.jp/a/article/aid/837.aspx?p=1 作者: 网 名:stven,polo 邮 件:stvsui@hotmail.com 个人博客:http://stvsui.spaces.live.com/

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

108/127


教程连载:CodeIgniter 详解(一)

《PHPer》

CodeIgniter 详解(一) 作者:David Upton 翻译:CodeIgniter 中国

第一章 对 CodeIgniter 的介绍 大多数 PHPer 都想写出运行状态良好的应用程序,而且希望尽可能做得简单且不费事。 这篇文章是有关 CodeIgniter 的(以下简称 CI),CI 是一个可以达成以上目的的框架。 如果你只是要达成一个最终的结果,而把中间所有的编码细节和复杂统统丢给一个框架, CI 是你最好的朋友。 CI 有很多优点:免费、轻量级、容易安装,它能使你的编程生涯变得很轻松。这一章我 们会告诉你:  CI 能为你做什么?  什么是“框架”?CI 为什么能被称为框架?  “开源”商业模式。  CI 的某些不足(是的,它不完美)。 CodeIgniter 能为你做什么? 如果你已经是一位 PHPer,开发过 PHP 应用,CodeIgniter 将会帮助你做得更好、更容易 达成目标。CI 会减少你的代码数量。你的脚本可读性也会更好、更容易升级。它会使你的网 站结构更紧凑、代码更强健,如果没有很好地研究 CI 的源代码的话,你可能还无法察觉到它 的强健。 对大多数兄弟来讲,你可能已经花了不少时间,系统地学习了 PHP、HTML 和 CSS,当 然还有 MySQL 什么的,不过如果使用 CI,你只需要一些基本的 LAMP(WAMP)知识,你 没有必要先成为一个专家才能使用 CI。你完全可以先借助于 CI 或别的什么框架软件,成为 一个有生产力的 PHP 程序员,拿着高薪然后优雅地进一步学习 PHP 的中高级知识,直至成 为一位真正的 PHP 骨灰级的人物。 下述情形,你最好不要使用 CI:  你没有一点 PHP 和 HTML 的基本知识。  你想用最少的代码,快速简便的写一个基本的内容管理系统(CMS)(可以看看 Expression Engine)。  你想写一个只有几个标准特性的简单的网站。 节约时间 CI 学习周期短,见效快。让我们试着评估一下相关的要素: 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

109/127


教程连载:CodeIgniter 详解(一)

《PHPer》

CI 如何减少代码量? 你真的可以减少很多工作量:敲击键盘的次数减少了、代码错误减少了,你只需要较少 的时间调试代码。代码量减少还意味着你只需要较少的空间来存放应用程序。 举二个例子(稍后它们会被进一步分析,因此不用担心如何了解它们的工作原理!) 想象你正在写一个 MySQL 数据库查询。可能的代码如下: 代码如下: $connection = mysql_connect("localhost","fred","12345"); mysql_select_db("websites", $connection); $result = mysql_query("SELECT * FROM sites", $connection); while ($row = mysql_fetch_array($result, MYSQL_NUM)) { foreach ($row as $attribute) { print "{$attribute[1]} "; } }

现在看看 CI 如何处理同一个问题: 代码如下: $this->load->database('websites'); $query = $this->db->get('sites'); foreach ($query->result() as $row) { print $row->url; }

比较字符数:前者 336,后者 112。 第二个例子,现在让我们想象你正在用 HTML 写一个数据输入窗口,你想要一个下拉框。 下拉框中有三个选项。代码如下: 代码如下: <select name="type"> <option value="1">www.this.com</option> <option value="2">www.that.com</option> <option value="3" selected>www.theother.com</option> </select>

CI 的写法和前例一样,因为它把相关内容放入一个数组,更容易由 PHP 进行处理: 代码如下: $urlarray = array( '1' => 'www.this.com', '2' => 'www.that.com', '3' => 'www.theother.com' ); $variable .= form_dropdown('url', $urlarray, '1'); 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

110/127


教程连载:CodeIgniter 详解(一)

《PHPer》

在 HTML 中,你需要输入 154 个字符;在 CI 中,只需要 128 个字符。 使你的网站更安全 你不需要写很多代码,是因为 CI 提供了许多标准的功能,这些经过仔细推敲的框架内的 代码,对安全性和输入进行了有效的校验和过虑。初学者往往没有足够的能力全面兼顾功能 和安全(这也是中高级程序员与新手之间能力差异的一个方面)。 确保你的链接自动更新 设想你正在写一个菜单页,有许多超链接可重定向到其他页。它们全部以传统的 HTML 格式编写: 代码如下: <a href="http://www.mysite.com/index.php/start/hello/fred">Hello World</a>

然后,你决定改变这个链接地址。这意味你必须仔细地去查找并修改代码中的每一处地 址,否则它们将无法正常工作。 CI 给你一个简单的函数,可以这样编写超链接: 代码如下: echo anchor('start/hello/fred', 'Say hello to Fred');

CI 推荐你把你的 URL 放入一个 config 文件供你的脚本读取。CI 的 anchor 函数会自动从 config 文件中提取相关 URL。因此,当你修改一个 URL 时,你只需要修改 config 文件中的对 应链接,就一次那么简单。 防止对数据库的攻击:对录入数据进行校验和处理 数据输入可能引发许多问题。因为 HTML 和数据库的限制,数据中总包含特定的符号, 举例来说,省略符号和引号,可能导致你的数据库遭到攻击,最终得到你无法预料的结果。 解决方案是在把这些数据存入数据库前对这些数据进行相关处理。这样做会浪费一些系 统时间,增加一些额外编码。 CI 的表单辅助函数会自动地完成这些工作。因此,当你编写一个输入框时: 代码如下: echo form_input(‘username’, ‘johndoe’);

CI 也隐式地执行下列校验函数: 代码如下: Function form_prep($str=’’) { { if ($str===’’) { return ‘’; 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

111/127


教程连载:CodeIgniter 详解(一)

《PHPer》

} $temp = ‘__ TEMP_AMPERSANDS__’; // 将录入内容放入临时变量进行处理以便 // htmlspecialchars 不破坏原数据 $str = preg_replace;(“/&#(\d+);/”, “$temp\\1;”,$str); $str = preg_replace;(“/&(\w+);/”, “$temp\\1;”,$str); $str = htmlspecialchars($str); // htmlspecialchars 函数会造成对一些符号的错误处理 $str = str_replace(array(“’”,’”’),array(“’”, “& quot;”), $str); // 把临时变量还原到输入变量中 $str = preg_replace;(“/$temp (\d+);/”,”&#\\1;”,$str); $str = preg_replace;(“/$temp (\w+);/”,”&\\1;”,$str); return $str; }

上述函数捕获像“&”这样的特殊字符,以便在你的页面提交时不会造成混乱。你应该 知道,有些字符会引起问题。 并不是所有的用户都会中规中矩的输入符合要求的信息,你也不可能知道使用浏览器输 入信息的是什么人,他们在想什么,做什么。你可以使用 CI 来防止输入不符合要求的信息。 当然,你大可不必知道 CI 是如何在幕后为你做到这一切的,你只需要简单地输入如下代码: 代码如下: echo form_input('username', 'johndoe');

增强你的代码 CI 使你写代码更容易了。不像有些类库,如 PEAR 等,集成比较困难(有时候你会找不 到支持 PEAR 的空间),CI 很容易集成,只要把它放入一个目录,它就能很好地工作。CI 所 有的代码可读性好,也很健壮,推出前经过社区用户的认真测试,所以在你可以使用时,这 些代码已经经历了很多考验。 让我们看两个例子。 发送 Email 和附件很简单 传统的发送 Email 功能实现起来比较复杂。CI 提供的功能使这件事变得很简单: 代码如下: $this->load->library('email'); $this->email->from('your@your-site.com', 'Your Name'); $this->email->subject('Email Text'); $this->email->message('Testing the eamil class.'); $this->email->send();

实现发送 Email 功能中有一些不容易解决的技术问题:比如文本封装和发送附件功能, 标准的 PHP 实现起来比较复杂,CI 简化了这些工作,它的 Email 类使得发送附件很简单: 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

112/127


教程连载:CodeIgniter 详解(一)

《PHPer》

代码如下: $this->email->attach('/path/to/photo1.jpg');

CI 把内部的复杂部分悄悄地完成了,举例来说,实现了列举近百种不同的附件的 MIME 类型的功能。所以它知道你的相片 photo1.jpg 是一个“image/jpeg”MIME 类型。因此它在你 附件的适当位置填写必要的限制符号,它细致地封装你的文本,使你方便地设置需要标记的 文本。 压缩用户要下载的文件以加快下载速度 为了加快下载速度,常见的做法是在下载之前压缩下载文件。你可能不知道如何处理。 但 CI 可以方便地让你用四行代码完成此功能: 代码如下: $name = 'mydata1.txt'; $data = 'the contents of my file......'; $this->zip->add_data($name, $data); $this->zip->archive('c:/my_backup.zip');

运行这些代码,你会在你的 C 盘根目录下找到一个压缩文件,解压后即为原始文件。 你网站的用户并不清楚你是如何容易地实现这个功能的,但他们能体会到你的网站下载 速度很快,而你只用了数分钟(而不是数小时)就实现了这个功能。 CodeIgniter 是什么?框架又是什么? 三百六十行中新增编程这一行不久,人们注意到它牵涉了许多重复的工作。你或者其他 人也许不久以后就要用到几乎同样的功能,但是你必须花很长的时间来修改它。于是,人们 就发明了使用函数库的方法来重用代码。使用 PHP 的兄弟们也会使用函数库,并按用途分类 保存到不同的文件中,在编程时用 require 或 include 来使用它们。同样的,框架是为重用而 发明的,放在与你的代码分开的目录中,用来减少重复的劳动。 上面例子中连接数据库和写 HTML 页面的编程工作都可以调用相关的 CI 函数来进行简 化。 有很多种方法实现同样的功能,大多数的框架会让你按照它实现的方法来做,一般来说, 框架的作者很有经验,并且作了精心的设计,你可以在几乎所有的场合下使用。 好的框架设计能实现需要的功能,而且尽可能地不互相牵连。一个好框架为你做出各种 功能的实现,并且给你提供一步一步的编程指导。 提到框架时,就不能不提到有名的框架,“Ruby on Rail” 。 Rails 做得相当成功,因为它籍由最小量的编码,明显地提供简便快捷的网站开发。本质 上,它是一个结构和一组工具,专为使用 Ruby 语言的用户开发,允许你快速建立 Ruby 系统 原型。它不是 Ruby 语言中唯一的框架,但是它一定是最有开发效率和最有名的。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

113/127


教程连载:CodeIgniter 详解(一)

《PHPer》

为 PHP 开发的框架有好多个,CI 只是大约 40 个中的一个。其它的还包括 Zend Framework、 Cake 、 Trax 和 其 它 。 下 列 网 址 可 以 找 到 一 个 针 对 十 来 种 框 架 的 简 明 的 图 表 分 析 : http://www.phpit.net/article/ten-different-php-frameworks/。 如果你访问上述网址中相关产品的官方网站,你将会注意到,每个论坛都有一个共同的 热点,就是到底哪一个框架是最好的?事实上似乎是每个都有它的长处,而且又都有自己的 弱点。我的评估标准是:我很忙,因此框架应该节约我的时间,从中选择一个后,就坚持使 用下去,因此就有了这篇介绍 CI 框架的文章。 关于开发者 Rick Ellis 开发了 CI,他曾经是一个摇滚音 乐 家 , 现 在 是 一 个 软 件 设 计 师 。 Rick 还 是 pMachine 公司的 CEO,该公司还有一个著名的 CMS 产品叫做 Expression Engine。2006 年 1 月, 他在 Blog 中写道(http://www.ellislab.com): “我花了数星期时间搜索和安装 PHP 框 架,也被它们中的许多打击了一把,令我惊讶 的是:我发现大多数框架存在以下问题:  文档不全或质量很差。  他们假定你水平很高,希望你能很容易地掌握使用方法。  他们是为那些有超级用户权限,或者有权修改服务器设置的人写的。  他们假定你偏爱命令行操作,事实上许多人无此爱好。  偏爱使用 PEAR 类库或其它开源类库。  模板语法过于复杂。  有的太笨重,有的又太简单。  大多数框架只能在 PHP5 中运行,只有 5% 的使用率。 我还没有找到一个简单的 PHP 框架,健壮、易于使用、文档完整,包含建立一个完整应 用需要的所有工具,并且有一个以浏览器为基础的接口,使用普通用户权限就能安装。没有 别的原因,就是“市场需要”这个单一的原因促使我想开发这样一个框架产品。……” 结果是 CI 诞生了,作为一个业余时间开发的作品,Rick 慷慨地决定使它成为开源作品。 在跑生意间隙,他保持经常更新 CI。他也创建了一个优秀的论坛,CI 使用者能提出问题并且 分享开发心得。所有这些资源可从下列网址获得:http://www.codeigniter.com/。 他能实现自己的设计目标吗?相信你使用后会得出自己的结论…… 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

114/127


教程连载:CodeIgniter 详解(一)

《PHPer》

“开源”商业模式 这类软件可能会有一些让人感到困惑的地方。如果你喜欢你的软件与昂贵的支持合同和 “大公司”联系起来的话,那么 CI 不适合你。 (但是,你使用 PHP 能做什么呢?PHP 的用户 都知道,支持和 PHP 软件的开发,一定程度上依赖于“社区”数百或数千用户的义务劳动) 社区支持也存在一些问题。一致性和高质量不是“有保证的”,任何人都可以发表到论坛 上,有时这些发表的内容是完全错误的。 (注意:如果你去看一下一些昂贵的商业软件的授权 细则,也是不对产品质量做出保证的。)但是对于“开源”产品而言,则必须仔细推敲,而不 能一味的相信论坛上的表象言论。如果你对研究新事物饶有兴致,那么 CI 非常的适合你! 然而,所有明智的开发者都想知道把时间和精力投入到“一个人的团队”的产品中是否 明智。Rick Ellis 利用业余时间编写这个项目,并从他在 pMachine 的同事 Paul Burdick 那得到 了一些帮助。它是免费的,他不对维护或开发它做出任何承诺。他可能回去继续做一个摇滚 音乐家。 另一方面,下载它之后,您下载的版本将继续工作。您不必依赖升级和修补程序。Rick 的代码写的非常好,只有几个严重的 Bug。如果证明可行,你便没有理由不继续工作。到目 前为止,我只发现了 2 个导致我的代码出错的情况,是这个框架而不是我自己的代码上的 Bug。 (这两个 Bug 已被修复。) CI 的网站是社区和论坛的门户(如图 1)。

图1 网站:http://www.phpchina.com

CI 网站

投稿:phper@phpchina.com

《PHPer》

115/127


教程连载:CodeIgniter 详解(一)

《PHPer》

CI 不能做什么 CI 有它本身的缺点。Rick 把 CI 定义为小的和“轻量级”的框架。 (1.5 版压缩后只有 737 KB 可以在几秒种内下载完毕。Zend Framework 是 10 MB)CI 不能解决你所有的问题。但是 它能够:  使 PHP 编程更容易;  帮助你架构网站或使你更容易地设计架构。 作为“轻量级”框架的一个结果是:它没有它的对手所具有的许多特征。像 Rails 因为它 包含“脚手架(scaffolding)”和“代码生成器”,因此可以为你编写一些基本的脚本代码。因 此,举例来说,一旦你建立了一个数据库,Rails 能自动生成简单的 CRUD 脚本(创建、读取、 更新和删除)。 除此之外,Rails 还能让你编写“代码生成器”,自动地写其他的简单脚本代码。Rails 社 区中有许多这样的例子,因此你可以做很多智能化的东西。 CI 不这样做。 (有基本的“脚手架(scaffolding)”功能—在 CI 中,脚手架只给开发者使 用。就像在线手册描述的一样: “脚手架安全性不够……如要使用脚手架的话要确保在使用后 立即关闭这个功能。在实际运行的网站上不要让脚手架处在工作状态。”说得很明确了吧?) 相反地 CI 专注于使基本的东西更容易。它处理的一些事物是:  Session 管理和 Cookie。(见第 6 章)  数据库访问和查询。(见第 4 章)  创建 HTML 相关内容,如页面和表单,并检验输入内容。(见第 5 章)  测试。(见第 8 章)  Internet 通信,使用 FTP 或 XMLRPC。(见第 9 章) 很熟悉吧?这些全部是基本的处理,如果你正在创建一个动态网站,你一定会做这些工 作。CI 使这些工作更容易,而且使你的代码尽可能更好地工作。 许可协议 如果你正在构建一个商业应用程序,那么使用的任何软件的许可协议都将是至关重要的。 (如果你要筹集风险投资,那么让 VC 的律师去对其进行详述)CI 没有这方面的问题。CI 的 许可协议非常宽松,许可协议文件随 CI 一起在下载回来的压缩包里。 不像我所知道的某些商业软件,CI 的许可协议一屏就可以显示出来(如图 2)。 总结 如果你已经掌握了 PHP 的基本知识,并且想“聪明”地编写动态网站脚本,CodeIgniter 框架会使你的工作更容易,它帮助你:  节约时间。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

116/127


教程连载:CodeIgniter 详解(一)

《PHPer》

图2

CI 的许可协议

 使你的网站更健壮。  帮助你编写更复杂的系统。 它使你更好地享受编程乐趣,而不是一个干苦活的体力工。 有相当多的框架,还有很多是为其它语言开发的。他们都能减少编码的重复工作,使编 写复杂程序变得更容易,并且建立一个合理的系统架构。 这篇文章不是制造框架大战。文章中已经解释了选择 CI 理由,让它为你节约更多的时间 用在学习工作和生活中吧,请享用它!

第二章 2 分钟建立一个 CodeIgniter 网站 用 CI 建一个网站很容易。这一章很短,解释了用 CI 制作网站时发生了些什么,哪些文 件被创建,让我们来瞧一瞧:  创建网站需要什么软件?  安装 CI 文件:一个简单的下载和解压缩操作。  CI 的基本设置:有哪些文件夹及它们是如何组织的。  CI 安装时默认的控制器和视图。  一些简单的修改来演示 CI 如何运作。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

117/127


教程连载:CodeIgniter 详解(一)

《PHPer》

准备知识 CodeIgniter 有较好的版本兼容性。它工作在 PHP4.3.2 及以上版本或 PHP5。由于大多数 ISP 还不支持 PHP5,支持 PHP4 版本是有用的。 你还需要一个数据库。CI 的在线手册说: “已支持的数据库是 MySQL、MySQLi、MSSQL、 Postgre、Oracle、SQLite 和 ODBC。” 为了要开发并测试一个动态的网站,你需要一个 Web 服务器。通常,你会在本地服务器 上开发并测试你的网站,也就是说,这些软件可以运行在你自己的机器上(127.0.0.1 或 localhost),一般来讲,开发环境不会建立在远程服务器上。 如果你不熟悉如何分别建立本地开发环境,可以选择一个套装软件,像是 Xampplite,安 装 Apache、PHP 和 MySQL 几乎不需要修改配置文件。Xampplite 是免费的,有简单易懂的安 装指南。或者某些版本的 Windows 附带自己的 Web 服务器。 你还需要一个称心的 PHP 编辑器。所有的编码工作都可以在文本编辑器中完成。提供语 法加亮特性和自动补齐功能的编辑器会更理想一些,因为它可以帮助一般水平的程序员节约 时间。 一旦你做好了这些准备工作,我担保你在 2 分钟内就可以搞定 CI 安装工作。 安装 CodeIgniter 再次声明,CI 是完全免费的! 建立好开发环境后,访问 CodeIgniter 网站:http://www.codeigniter.com/并下载最新版的 框架。1.5.3 版是最新版(译注:编写此书时的最新版是 1.5.3),是一个只有 737KB 的压缩文 件,几秒种就可以下载完成。 解压缩这个文件,把它释放到网站根目录中。如果你正在使用 Xampplite,通常在 Xampplite 文件夹里面的 htdocs 文件夹中。 CodeIgniter 的 index.php 文 件 应 该 在 根 目 录 中 。 这 时 , 如 果 你 在 浏 览 器 上 打 开 http://127.0.0.1 你也就实际打开了此文件。我们用 1-2 分钟的时间来建立一个可运行的网站! 和 CI 包含在一起是一个简单易懂的用户手册(在 user_guide 文件夹中),你将会经常用 到它。它的内容很详细,细过这篇文章,所以需要时请经常查阅它。 当这些文件保存在你的机器上的时候,有两个方法来访问它们:  通过 URL,http://127.0.0.1  经过正常的目录路径:举例来说,C:/xampplite/htdocs/index.php 你应该通过浏览器访问 CI 的默认首页。真是简单!默认首页传递给你一个信息:你将看 到的内容由两个文件组成:视图和控制器。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

118/127


教程连载:CodeIgniter 详解(一)

《PHPer》

分析文件结构 安装 CI 文件后,我们来看一下目录结构(见图 3)。 你的根文件夹现在应该看起来有点像下面的图表。如果你曾经看过 Rails,这个结构将会 看起来非常熟悉。 你能把这些文件夹分为三个小组:  application 是你自己的项目存放文件的目录(举例来说,控制器、模型和视图,全部 在 application 文件夹中)。除了你刚才见到的默认视图和控制器,这些文件夹都是空 的。  在 system 文件夹中的文件是 CI 本身的代码。(system/libraries、system/codeigniter、 system/drivers 等)。如果你愿意,你可以研读它们,或者改变它们,不过要等到你了 解了 CI 是如何工作的才能这么做。而且如果你改变了框架内的代码,记住,当你下 载了 CodeIgniter 新版本时备份它们,否则新的版本会覆盖它们。当然,你也可能不 需要自己修改代码而直接使用 CI 本身的代码,Rick 写的代码应该是很不错的。  还有一些文件夹中已包含了文件,但是可能需要增加或修改(如:language、config、 errors)。这些文件夹被设置为默认的,但你可以修改它们。

图3

CI 安装目录结构

配置文件 还记得我们要花 2 分钟建立我们的网站吗?第 2 分钟要用来做一些基本的设置。 config 文件夹包含了一些为你的网站设定基本配置的文件。打开 config/config.php 文件告 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

119/127


教程连载:CodeIgniter 详解(一)

《PHPer》

诉网站应该在哪里找到它自己的结构和配置信息。文件的第一行一般是这样的: 代码如下: /* |-----------------------------------------------| Base Site URL |----------------------------------------------| URL to your Code Igniter root. Typically this | will be your base URL, WITH a trailing slash: | [url]http://www.your-site.com/[/url] */ $config['base_url'] = " [url]http://127.0.0.1/[/url]";

注意,CI 的注释多详尽啊! 修改引号中的数据以匹配你网站的根目录。如有疑问,请查询在线手册以得到详细指导。 作为一项基本的原则,使用 config.php 文件储存关于你网站的信息好过把这些信息散布 在你项目的不同文件中。这样做有几个好处:首先,更新比较容易;其次,当你把项目从开 发服务器转移到实际存放的服务器时,修改配置较容易;最后,许多 CI 函数会首先在配置文 件中寻找需要的信息。 还有其他的 config 文件存放在 config 文件夹中,但是目前你可以放心地使用它们而不用 修改它们的默认值。 这就是 2 分钟内运行 CI 所需要做的第二件事儿。在这一章的余下部分,我们将会上我们 刚做好的网站去逛逛。 它能工作吗? 验证网站能否正常工作的一个简单方法就是打开你的浏览器。假定你正在本地服务器的 根文件夹中运行它,在地址栏输入:http://127.0.0.1,你能看到网站的默认页面(如图 4)

图4 网站:http://www.phpchina.com

CI 测试页面

投稿:phper@phpchina.com

《PHPer》

120/127


教程连载:CodeIgniter 详解(一)

《PHPer》

看到默认页面意味着你的网站正常运行了。不需要 2 分钟,对吗? 总结 在本章节中,我们已经见到,安装 CI 是多么容易。一旦建立好你的开发环境,你所需要 做的是下载 CI 框架文件、解压并复制到一个目录而已。 随后,我们快速浏览了 CI 的目录结构。 这一章节非常短,因为 CI 容易安装,不需要太长的篇幅。其实其它章节也不长,因为 CI 的确很简单易懂、节约时间。

关于【CodeIgniter 中国】开发团队 CI 中国成立于 2007 年 10 月,由 Hex 一手建立而成。其后由本人代表 CI 中国与 CI 官方 取得联系,得到了官方的支持。但是这里要申明一点,有些新来的朋友可能不了解,CodeIgniter 是 EllisLab (http://www.ellislab.com/)的程序,虽然可以免费使用,但并非传统意义上的开源软 件,CI 使用的是 EllisLab 自己定制的授权。CI 中国与 CI 官方并无直接挂钩关系。CI 中国今 后开发的开源产品,会回馈给整个 CI 乃至 PHP 社区,但是产品本身与 CI 官方并无直接关联。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

121/127


PHP 百家谈:李国德访谈录

《PHPer》

PHP 百家谈

李国德访谈录 《PHPer》:首先,请李国德向大家简单介绍一下自己。 李国德:PHPer 读者,大家好,我是 SUP,目前负责 Comsenz 公司的产品研发工作。 《PHPer》:你个人网站上的一些案例都是 基于 PHP 开发的吗?都是你自己的作品 吗? 李国德:是的,我是 PHP 的 Fans。都是自 己根据需求开发的。 《PHPer》:你从什么时候开始接触 PHP 的?当时用 PHP 开发的第一个产品是什 么? 李国德:上大二的时候,2000 年吧。当时 特别喜欢 WDB 文本论坛,就研究了起来, 并学会了 PHP,开发了一个学生成绩录入、 显示的小程序。 《PHPer》:你认为 PHP 都可以用来做些什 么呢?或者说 PHP 适合做什么类型的产 品? 李国德:作为一种 Web 语言,PHP 以它快 速、高效、语法自由的特点,十分胜任做 Web 产品。 《PHPer》:你认为 PHP 语言本身有什么缺点呢?它不适合来做什么? 李国德:系统层次的东西,PHP 实现起来有点吃力。 《PHPer》:你这么多年来学习的理由是什么? 李国德:一个是兴趣,自己喜欢 PHP,喜欢去学习新鲜的东西;还有一个,是压力,现在互 联网的变化每天都有很大的变化,干我们这一行的,就得每天都要学习,否则就要落伍了。 《PHPer》:你认为做程序可以活一生吗? 李国德:做什么都可以活一生的,但我自己觉得,人生不应该只做一个,我们应该学会在专 注的同时,也融入一下其他领域,丰富自己的人生。 《PHPer》:你认为哪个产品最成功?请概要阐述一下这个产品。 李国德:UCenter Home 这个产品。UCenter Home 是一套采用 PHP+MySQL 构建的社会化网 络软件(Social Network Software,简称 SNS)。 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

122/127


PHP 百家谈:李国德访谈录

《PHPer》

通过 UCenter Home,建站者可以轻松构建一个以好友关系为核心的交流网络,让站点用 户可以用迷你博客一句话记录生活中的点点滴滴;方便快捷地发布日志、上传图片;更可以 十分方便的与其好友们一起分享信息、讨论感兴趣的话题;轻松快捷的了解好友最新动态。 《PHPer》:你认为除了掌握 PHP 还需要掌握什么其他语言呢? 李国德:我自己用过 VB、VBA,VC、Java 等工具和语言,感觉所有的编程语言都是一个机 械化的东西,精通一个就足够了。或者,根据自己的现实需求,决定自己用哪一个。编程语 言,都有规则在那里,很容易入手。当然,成为高手还得费些功夫,但千万别钻牛角尖,让 自己成为语言的奴隶,而是让语言成为自己的奴隶。 《PHPer》:对于刚刚跨入 PHP 大门的新人,你有什么建议? 李国德:我觉得新人一定要抱着求知的欲望,多研究一下别人的程序,先学会读程序,再尝 试写程序。 《PHPer》:好的,谢谢李国德,与我们分享了这么多关于程序开发方面观点。也为我们的初 学者提了不少有用的建议,希望能对正在学习 PHP 的朋友提供帮助。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

123/127


LAMP 新书推荐:《构建可扩展的 Web 站点》

《PHPer》

LAMP 新书推荐

《构建可扩展的 Web 站点》 电子工业出版社 作者:「美」Cal Henderson 译者:徐宁 掌握建立和架构可快速扩展应用程序的窍门——不再为昂贵的价格头痛不已,也无需与 企业应用程序服务器、专有编程产品及数据 库产品签订服务级别的协议。来自 flickr.com 主力开发人员的杰作——《构建可扩展的 Web 站点》,为 Web 开发人员提供了种种简 单实用的技巧,以建立一个访问者喜爱的快 速响应的 Web 站点。 建立一个流行的站点不仅需要运转快速 的硬件设备、大量内存和硬盘空间,还要考 虑怎样让站点随着时间推移而不断发展;怎 样让有不同期望的访问者访问到同样的资 源;怎样建立一个大家共同工作的开发团队, 同时保证不会给站点访问者带来新问题,也 不会造成相互之间的干扰等问题。 不管你是基于 PHP 脚本开始建立一个新 的站点,还是正在维护一个已有的站点,这 本书都能在以下几个方面给你提供帮助: • 设计应用程序底层的软件体系结构 • 选择使用一个让开发人员、设计人员和访问者都感到愉快的软件开发环境 • 保持应用程序数据的纯净和安全 • 呈现信息给来自全世界的访问者 • 整合电子邮件到你的应用程序中 • 规划硬件的购买和主机服务选项,恰到好处地满足你的需求,又避免掏空你的钱包 • 分区数据库,建立分布式数据库以支持大型数据集和并发事件 • 监测你的应用程序,发现并消除瓶颈 • 提供公开的 API,利用其他提供者的服务提升站点的影响和功能 不管你是正在建立一个希望将来发展壮大的小型 Web 站点,还是早已拥有一个需要维护 网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

124/127


LAMP 新书推荐:《构建可扩展的 Web 站点》

《PHPer》

的大型系统,《构建可扩展的 Web 站点》都可谓一个灵感之源,会带给你很多让事情简单运 作的方法和技巧。 Cal Henderson 来自英格兰,是照片共享服务 Flickr 的工程经理,目前在美国加州森尼维 耳市的 Yahoo!公司工作。在创建 Flickr 应用程序之前,Cal Henderson 在英国一家媒体公司 Emap 担任一个特殊 Web 项目的技术主管。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

125/127


LAMP 新书推荐:Linux 系统与网络服务管理技术大全

《PHPer》

《Linux 系统与网络服务管理技术大全》 电子工业出版社 作者:杨明华 谭励 于重重 等 Linux 是一个非常优秀的操作系统,经过十几年的发展,已经拥有了大量用户群,其在各 个领域的应用也日益广泛。如今学习和掌握 Linux 已经成为了一种潮流,是软件工程师之路 不可缺少的一块基石。为了满足众多 Linux 爱好者、初学者以及专业人员的使用需要,笔者 在多年从事 Linux 研究、教学及开发工作的基础 上精心编著了本书。该书就 Linux 的系统配置、 服务器的架设做了全面细致的讲解,将知识点结 合于实例当中,在实例当中又进一步拓展了知识 点。全书共分 25 章,尽可以多地涉及到了 Linux 的方方面面。可以说,书中凝聚了笔者的心血和 期望,虽然该书仅是一本工程应用类图书,但希 望通过此书能够为读者更快捷地走上 Linux 之路 带来便利。 本书从实用角度出发,对 Red Hat Enterprise Linux 5 平台下的系统管理及网络服务做了全面、 系统的介绍。既便于读者了解 Red Hat Enterprise Linux 5 强大的功能,又有利于帮助 Linux 用户在 较 短 的 时 间 内 快 速 地 学 习 和 掌 握 Red Hat Enterprise Linux 5。全书分上、下两篇,共 25 章, 内容涵盖了 Linux 系统概述、Red Hat Enterprise Linux 5 系统安装及相关配置、图形桌面管理、用户和用户组管理、磁盘管理、文件和目录管 理、终端常用命令、系统监测与维护、常用应用软件、网络基础、DNS 服务的配置与管理、 WWW 服务的配置与管理、FTP 服务的配置与管理、打印服务的配置与管理、NFS 服务的配 置与管理、Samba 服务的配置与管理、DHCP 服务的配置与管理、电子邮件服务的配置与管 理、NAT 服务的配置与管理、MySQL 数据库的配置与管理、代理服务的配置与管理、LDAP 服务的配置与管理、VPN 服务的配置与管理、Webmin 管理工具,以及网络安全与病毒防护。 本书内容丰富、语言通俗易懂、叙述深入浅出,非常适合于初、中级 Linux 用户,既可 以作为各类院校相关专业的教材及 Linux 培训班的教材,也可以作为广大 Linux 爱好者的专 业参考书。

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

126/127


封底

代码如下:

文件说明如下:

网站:http://www.phpchina.com

投稿:phper@phpchina.com

《PHPer》

127/127


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.