该网站是一个基于PHP技术的小型企业网站,MySQL作为后台数据库,Apache2.0作为Web服务器。通过该网站的设计,能够很好地展示企业的形象,能够很清晰的向用户展示企业的产品,企业管理人员能方便的更改网站对外展示的内容。对此企业网站的网络设备、网络技术、安全技术、网站管理与维护等整体规划与方案设计。
这个毕业设计主要研究方向是企业网站后台数据库的设计以及整体架构的设计与代码编写,在这个研究方向上,主要是对网站后台架构的设计,包括此企业网站的页面制作、后台数据缓存、模板分离、网站安全等
关键词:PHP;Mysql;Apache2.0;企业网站
The site is a base on PHP technology, small business web site, MySQL as a back-end database, Apache2.0 as a web server. Through the design of the site can display a good corporate image, can be very clear to the user display business products, business executives can easily change the external display the contents of the site. This corporate web site network equipment, network technology, security technology, website management and maintenance of the overall planning and program design.
The main research direction of graduate design company web site back-end database design and the overall framework for the design and coding, in this research, the main structure of the site background design, including the corporate Web page production, background data caching, templates separation, site security.
Key Words:PHP;MySQL;Apache2.0; Enterprise Website
目 录
摘 要... I
Abstract II
第一章 绪论... 1
1.1 世界互联网的发展... 1
1.2 目前的互联网现状... 1
1.3 企业电子商务的兴起... 2
1.4 企业为什么要建立网站... 2
第二章 LAMP架构与所用技术... 3
2.1 Linux起源、特性及应用领域... 3
2.2 Apache概述... 4
2.3 MySQL概述... 4
2.4 PHP概述... 4
2.5 smarty模板引擎... 5
2.6 Ajax概述... 5
第三章 需求分析... 6
3.1 技术可行性... 6
3.1.1 动态网站技术介绍... 6
3.1.2 市场可行性... 6
3.1.3 语言优势... 7
3.1.4 操作可行性... 7
3.2 软件可行性分析... 8
3.2.1 开发环境... 8
3.2.2 服务器环境... 8
3.3 系统可行性分析... 8
3.3.1 B/S模式介绍... 8
3.3.2 B/S模式的优点... 8
3.4 功能性需求... 9
3.4.1 网站的基本信息设置... 9
3.4.2 导航管理... 9
3.4.3 图片管理... 10
3.4.4 商品管理... 10
3.4.5 文章模块... 10
3.4.6 文件下载... 11
3.4.7 招聘信息... 11
3.4.8 用户管理... 11
3.4.9 留言模块... 11
3.4.10 网站公告... 11
3.4.11 友情链接... 11
3.5 非功能性需求... 12
3.5.1 后台界面... 12
3.5.2 前台页面... 12
第四章 概要设计... 13
4.1 数据库设计... 13
4.1.1 数据库设计概述... 13
4.1.2 数据库需求分析... 13
4.1.3 数据库逻辑结构设计... 14
4.1.4 数据库物理结构设计... 16
4.2 系统结构设计... 19
4.2.1 网站后台结构... 19
4.2.2 网站前台结构... 20
4.2.3 系统架构设计... 20
第五章 详细设计... 22
5.1 系统公共文件核心代码... 22
5.1.1 前台核心控制文件... 22
5.1.2 前台公用函数库... 24
5.1.3 数据库类... 26
5.1.4 验证码类... 27
5.1.4 后台控制文件... 29
5.2 网站管理后台... 31
5.2.1 后台总体界面... 31
5.2.2 管理员登录... 31
5.2.3 系统信息... 34
5.2.4 系统设置... 34
5.2.5 导航管理... 35
5.2.6 修改管理员密码... 37
5.2.7 图片管理... 37
5.2.8 图片展示... 40
5.2.9 商品展示... 43
5.2.10 单页分类... 43
5.2.11 单页管理... 49
5.2.12 文章分类... 51
5.2.13 文章管理... 54
5.2.14 附件管理... 57
5.2.15 下载管理... 61
5.2.16 招聘管理... 61
5.3 网站前台... 62
5.3.1 前台首页... 62
5.3.2 企业简介... 62
5.3.3 图片展示... 63
5.3.4 商品展示... 63
5.3.5 人才招聘... 64
5.4 系统关键技术... 65
5.4.1 smarty模板... 65
5.4.2 ajax异步传输... 66
第六章 系统测试... 69
6.1 测试的定义及目的... 69
6.2 测试的原则... 69
6.3 测试的方法... 69
6.3.1 界面测试... 69
6.3.2 功能测试... 70
6.3.3 需求测试... 71
6.3.4 性能测试... 71
总 结... 72
1 总结... 72
2 扩展... 72
致 谢... 74
参 考 文 献... 75
Internet的最早起源于美国国防部高级研究计划署DARPA(Defence Advanced Research Projects Agency)的前身ARPAnet,该网于1969年投入使用。由此,ARPAnet成为现代计算机网络诞生的标志。
从六十年代起,由ARPA提供经费,联合计算机公司和大学共同研制而发展起来的ARPAnet网络。最初,ARPAnet主要是用于军事研究目的,它主要是基于这样的指导思想:网络必须经受得住故障的考验而维持正常的工作,一旦发生战争,当网络的某一部分因遭受攻击而失去工作能力时,网络的其他部分应能维持正常的通信工作。ARPAnet在技术上的另一个重大贡献是TCP/IP协议簇的开发和利用。作为Internet的早期骨干网,ARPAnet的试验并奠定了Internet存在和发展的基础,较好地解决了异种机网络互联的一系列理论和技术问题。
1983年,ARPAnet分裂为两部分,ARPAnet和纯军事用的MILNET。同时,局域网和广域网的产生和逢勃发展对Internet的进一步发展起了重要的作用。其中最引人注目的是美国国家科学基金会ASF(National Science Foundation)建立的NSFnet。NSF在全美国建立了按地区划分的计算机广域网并将这些地区网络和超级计算机中心互联起来。NFSnet于1990年6月彻底取代了ARPAnet而成为Internet的主干网。
NSFnet对Internet的最大贡献是使Internet向全社会开放,而不象以前的那样仅供计算机研究人员和政府机构使用。1990年9月,由Merit,IBM和MCI公司联合建立了一个非盈利的组织―先进网络科学公司ANS(Advanced Network &Science Inc.)。ANS的目的是建立一个全美范围的T3级主干网,它能以45Mbps的速率传送数据。到1991年底,NSFnet的全部主干网都与ANS提供的T3级主干网相联通。
Internet的第二次飞跃归功于Internet的商业化,商业机构一踏入Internet这一陌生世界,很快发现了它在通信、资料检索、客户服务等方面的巨大潜力。于是世界各地的无数企业纷纷涌入Internet,带来了Internet发展史上的一个新的飞跃。
Internet正以当初人们始料不及的惊人速度向前发展,今天的Internet已经从各个方面逐渐改变人们的工作和生活方式。人们可以随时从网上了解当天最新的天气信息、新闻动态和旅游信息,可看到当天的报纸和最新杂志,可以足不出户在家里炒股、网上购物、收发电子邮件,享受远程医疗和远程教育等等。
Internet的意义并不在于它的规模,而在于它提供了一种全新的全球性的信息基础设施。当今世界正向知识经济时代迈进,信息产业已经发展成为世界发达国家的新的支柱产业,成为推动世界经济高速发展的新的源动力,并且广泛渗透到各个领域,特别是近几年来国际互联网络及其应用的发展,从根本上改变了人们的思想观念和生产生活方式,推动了各行各业的发展,并且成为知识经济时代的一个重要标志之一。
进入20世纪九十年代后,Internet在商业上的应用其发展速度令人瞠目结舌。这个覆盖全球的网络以其无可比拟的优势向人们暗示着巨大的和潜在的商业利益。与传统的商业行为相比,它可提供资源丰富、迅速及时的商业信息,它的客户与市场遍及世界上每个角落,使很不起眼的小企业可以一下子变成“跨国公司”。
成千上万的大小企业纷纷加入到Internet 这个神奇的淘金王国中。Internet正以惊人的速度发展,它的普及意味着企业网络时代的来临,意味着企业生存方式、组织方式、工作方式的变革。它正在为企业提供一种全新的市场概念,正在改写商业社会的规则,正在给各行各业的人们带来新的机会和挑战。未来的商业竞争就是信息的竞争,企业进入网络空间已是刻不容缓。
很多企业由于缺乏技术人员等原因无法建立自己的网站,导致了在新的竞争形势中的失利。是否拥有自己的网站已经成为衡量一个企业综合素质的重要标志
企业网站的具体作用:
A.通过网站展示企业风采、传播企业文化、树立企业形象、提高企业知明度。
B.通过网站可介绍企业的基本情况,使经销商和用户更多的知道您的存在。
C.通过网站可以宣传您的产品和服务的优势,让经销商和用户在比较中了解您、走近您、直到选择您。
D.通过网站您可以利用电子信箱经济而又快捷地与外界进行各种信息沟。
E.通过网站您可以寻求合资与合作。
LAMP是基于Linux,Apache,MySQL和PHP的开放资源网络开发平台,名字来源于每个程序的第一个字母。每个程序在所有权里都符合开放源代码标准:Linux是开放系统;Apache是最通用的网络服务器;MySQL是带有基于网络管理附加工具的关系数据库;PHP是流行的对象脚本语言,它包含了多数其它语言的优秀特征来使得它的网络开发更加有效。
虽然这些开放源代码程序本身并不是专门设计成同另外几个程序一起工作的,但由于它们都是影响较大的开源软件,拥有很多共同特点,这就导致了这些组件经常在一起使用。在过去的几年里,这些组件的兼容性不断完善,在一起的应用情形变得更加普遍。并且它们为了改善不同组件之间的协作,已经创建了某些扩展功能。目前,几乎在所有的Linux发布版中都默认包含了这些产品。Linux操作系统、Apache服务器、MySQL数据库和Perl、PHP或者 Python语言,这些产品共同组成了一个强大的Web应用程序平台。
越来越多的供应商、用户和企业投资者日益认识到,经过LAMP单个组件的开源软件组成的平台用来构建以及运行各种商业应用和协作构建各种网络应用程序变为一种可能和实践,变得更加具有竞争力,更加吸引客户。LAMP无论是性能、质量还是价格都将成为企业、政府信息化所必须考虑的平台。下面分别对LAMP黄金组合中的各个部件做一些简单的介绍。
Linux操作系统核心最早是由芬兰的Linus Torvalds 1991年8月在芬兰赫尔辛基大学上学时发布的,后来经过众多世界顶尖的软件工程师的不断修改和完善,Linux得以在全球普及开来,在服务器领域及个人桌面版得到越来越多的应用,在嵌入式开发方面更是具有其它操作系统无可比拟的优势,并以每年100%的用户递增数量显示了Linux强大的力量。
Linux的是一套免费的32位多人多工的操作系统,运行方式同UNIX系统很像,但Linux系统的稳定性、多工能力与网络功能已是许多商业操作系统无法比拟的,Linux还有一项最大的特色在于源代码完全公开,在符合GNU GPL(General Public License)的原则下,任何人皆可自由取得、散布、甚至修改源代码。
与其它操作系统相比,Linux还具有以下特色:
①采用阶层式目录结构,文件归类清楚、容易管理
②支持多种文件系统,如Ext2FS,ISOFS以及Windows的文件系统FAT16,FAT32,NTFS等
③具有可移植性,系统核心只有小于10%的源代码采用汇编语言编写,其余均是采用C语言编写,因此具备高度移植性
④可与其它的操作系统如Windows98/2000/xp等并存于同一台计算机上
Apache,一种开放源码的HTTP服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性(注1)被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,Perl/Python等解释器可被编译到服务器中。
纵观Apache,它为我们的网络管理员提供了丰富多彩的功能,包括目录索引、目录别名、内容协商、可配置的HTTP错误报告、CGI程序的SetUID执行、子进程资源管理、服务器端图象映射、重写URL、URL拼写检查以及联机手册man等。也就是说,如果您在Linux Server上成功安装配置了Apache之后,您的计算机也将随着Apache的生效而摇身一变,成为一台名副其实的Web Server,这种变化的确是激动人心的。伴随着自由软件发展的强大动力,我们有理由相信Apache的未来是一片光明的。
MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
PHP,一个嵌套的缩写名称,是英文超级文本预处理语言(PHP:Hypertext Preprocessor)的缩写。PHP 是一种 HTML 内嵌式的语言,PHP与微软的ASP颇有几分相似,都是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,现在被很多的网站编程人员广泛的运用。PHP 独特的语法混合了 C、Java、Perl 以及 PHP 自创新的语法。它可以比 CGI 或者 Perl 更快速的执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;与同样是嵌入HTML文档的脚本语言JavaScript相比,PHP在服务器端执行,充分利用了服务器的性能;PHP执行引擎还会将用户经常访问的PHP程序驻留在内存中,其他用户再一次访问这个程序时就不需要重新编译程序了,只要直接执行内存中的代码就可以了,这也是PHP高效率的体现之一。PHP具有非常强大的功能,所有的CGI或者JavaScript的功能PHP都能实现,而且支持几乎所有流行的数据库以及操作系统。
Smarty是一个使用PHP写出来的PHP模板解析类,是目前业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。简单的讲,目的就是要使用PHP程序员同美工分离,使用的程序员改变程序的逻辑内容不会影响到美工的页面设计,美工重新修改页面不会影响到程序的程序逻辑
Ajax是Asynchronous JavaScript and XML(异步JavaScript和XML)的缩写。Ajax用来描述一组技术,它使浏览器可以为用户提供更为自然的浏览体验。借助于Ajax,可以在用户单击按钮时,使用JavaScript和DHTML立即更新UI,并向服务器发出异步请求,以执行更新或查询数据库。当请求返回时,就可以使用JavaScript和CSS来相应地更新UI,而不是刷新整个页面。最重要的是,用户甚至不知道浏览器正在与服务器通信:Web站点看起来是即时响应的。
在开始写这个网站系统之前,我们需要对这个系统的可行性进行分析,如果确实可行才能继续实施,否则将会产生一些额外的损失。可行性分析的任务是从技术上、经济上、社会上、法律上分析需要解决的问题是否存在可行的解。同时也要对需要实现的功能性需求和非功能性需求做一个详细的计划,为以后的具体实施提供一个明确的方向和依据。
Internet起源于20世纪60年代的美国,它在近几年迅速风靡全球,其根本原因不仅在于她拥有卓越的国际通信功能,更在于它拥有巨大的信息资源。所谓的Internet是指由分布在全世界成千上万的计算机网络遵循一定的通讯协议,并相互联系在一起而形成的国际互连网络,也就是说,Internet是建立和使用这些网络的人群、群体、公司以及各种网络资源的集合体。
随着网络技术的不断发展,单纯的静态页面已经不能满足发展的需要,因为静态页面是用单纯的HTML语言组成的,它没有交互性。因此,为了满足实际的需要,许多网页文件扩展名不再只是"htm"、"html",出现了以"php"、"asp"、"jsp"、"shtml"等为后缀的网页文件,这些都是采用动态网页技术制作出来的。
以前,世界上许多公司都把PHP当作是一个“高度机密,严格保密”的电脑程序语言,但是现在它已经变成最为著名的,在Web, Internet, E-commerce以及 B2B等诸多项目上应用最广泛的面向对象的脚本语言。即使是在今天,仍有许多竞争性(competing)公司把PHP当作是高度机密的东西,决不向外界(竞争对手)透露半点。
PHP将如同暴风雨一般席卷整个世界,IT工业将为之震惊。PHP的力量在于它是跨平台的,可以运行在任何地方。如Linux,Windows 95/98/NT/2000/XP,Solaris,HPUX以及各种UNIX。PHP只需写一次,就可以配置在任何地方。PHP可以运行在Apache,Microsoft IIS等多种Web服务器上。
PHP比Java快5到20倍!实际的比较测试显示,PHP的运行速度是Java3.7倍左右。PHP太容易使用了,你可以用它在非常短的时间里,非常迅速的开发出非常复杂的web,e-commerce和一般的单机应用程序。(在将来,PHP将会模仿Java大多数的功能,相信Java程序员也会喜欢上它。PHP将包含Java中的关键字,如class,extends,interface, implements, public,protected, private 等。)
PHP具有面向对象特性,它吸收了Java, C++, PERL 和C的最优秀的部分。PHP可以说是所有脚本/编程语言中的宝石。不久,它就会成为全世界程序员的“麦加圣地”。PHP即可以运行在Window95/NT/2000/XP上,也可以运行在各种UNIX上。
我们将大吃一惊——PHP极有可能成为21世纪的电脑编程语言。
可以使用Zend Optimizer对PHP进行编译和优化,从而使它运行的更好更快,PHP4.0中已经集成了Zend Optimizer。 首先,你在开发、测试、除错过程中,用PHP脚本语言编写你的应用程序。一旦项目完成,你便可以用Zend编译器,将PHP文件编译成运行速度更快的可执行程序。
PHP的发展前景越来越好,越来越多的人会选择用PHP来设计网站,所以,PHP也许将来会是在网站界占据着领头作用。
使用PHP技术,Web页面开发人员可以使用HTML设计和格式化最终页面显示效果,使用PHP语言来生成页面上的动态内容,配合smarty模板引擎,将生成的内容存储在模板变量中,那么其他人,如Web管理人员和页面设计者,只需要编辑或修改模板文件就可以让网站有不同的显示效果。
PHP是开源软件,所有PHP的源代码每个人都可以看得到,代码在许多工程师手中进行了检测,同时它与Apache编绎在一起的方式也可以让它具有灵活的安全设定,PHP具有了公认的安全性能。
ASP比不上PHP的跨平台能力,PHP几乎支持所有的操作系统平台及数据库系统,正是它的这种能力让UNIX/Linux有了一种与ASP媲美的开发语言,并广为流行。
在流行的企业应用LAMP平台中,PHP、Linux、Apache、MySQL都是免费软件,降低了企业架设成本。
对于用户来说,本系统只要求使用者会打字并且能对文字做一些简单的编辑,经过仔细设计和测试之后的系统具有操作简单,方便灵活等优点,足可以满足各种用户的不同需求,同时也方便了公司的内部管理。管理人员及用户一定会在短时间内掌握并熟练使用。只要动一动鼠标键盘就可以达到想要的效果。
本系统采用B/S模式。
B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN,WAN,Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全。特别是在跨平台语言出现之后,B/S架构管理软件更是方便、快捷、高效。
维护和升级方式简单
目前,软件系统的改进和升级越来越频繁,B/S架构的产品明显体现着更为方便的特性。对一个稍微大一点单位来说,系统管理人员如果需要在几百甚至上千部电脑之间来回奔跑,效率和工作量是可想而知的,但B/S架构的软件只需要管理服务器就行了,所有的客户端只是浏览器,根本不需要做任何的维护。无论用户的规模有多大,有多少分支机构都不会增加任何维护升级的工作量,所有的操作只需要针对服务器进行;如果是异地,只需要把服务器连接专网即可,实现远程维护、升级和共享。所以客户机越来越“瘦”,而服务器越来越“胖”是将来信息化发展的主流方向。今后,软件升级和维护会越来越容易,而使用起来会越来越简单,这对用户人力、物力、时间、费用的节省是显而易见的、惊人的。因此,维护和升级革命的方式是“瘦”客户机,“胖”服务器。
成本降低、选择更多
大家都知道windows在桌面电脑上几乎一统天下,浏览器成为了标准配置,但在服务器操作系统上windows并不是处于绝对的统治地位。现在的趋势是凡使用B/S架构的应用管理软件,只需安装在Linux服务器上即可,而且安全性高,所以服务器操作系统的选择是很多的,不管选用那种操作系统都可以让大部分人使用windows作为桌面操作系统电脑不受影响,这就使的最流行免费的Linux操作系统快速发展起来,Linux除了操作系统是免费的以外,连数据库也是免费的,这种选择非常盛行。
文章模块不仅需要具有文章组,并且需要如企业简介一类的单页文章,同时能对文章内容进行实时的增、删、查、改以及其他一些操作。
可以在前台网页显示相关的文章信息,您还可以阅读到想要读到的文章,而此文章模块也有自己的功能:
(1) 在网页上显示相关的文章列表;
(2) 在网页上显示相关的文章的内容;
(3) 管理人员可以对文章进行一系列的管理,包括文章的编辑、添加、删除;
(4) 管理人员也可以对文章的属性进行修改和删除。
文件模块使管理者在后台能够更好的管理文件,在文件分类中可以对文件进行编辑、删除。还可以添加下载文件。使用户更广泛地选择需要的文件。
可以在前台网页上显示相关的文件信息,使用户能够很好的选择自己需要的文件。文件模块主要功能为:
(1) 在网页上显示相关文件的有关信息。
(2) 管理人员可以对文件进行管理,包括附件列表的管理和添加附件操作。
(3) 为用户提供文件下载任务,可以对下载文件进行分类管理,在文件分类中可以对文件的属性进行编辑、删除。
(4) 对下载进行一系列的管理。
(1) 招聘信息是以列表的形式体现。
(2) 如招聘信息有误,管理员可通过点击“编辑”进行修改。
(3) 添加招聘信息时,可以点击表单后面的选项方便的把值填入表单,如不满意以有选项,也可自己填写。
(1) 如有需要修改用户名和用户密码可以由管理员来修改。
(2) 管理员也可删除用户。
(3) 管理员可在添加用户界面上直接添加用户。
(1) 网站设有留言板,方便用户提出意见和咨询问题。
(2) 注册用户登陆后,可以通过留言板留言。
(3) 用户留言后,等待管理员回复。
(4) 任何人均可浏览留言内容。
(1) 管理员可以在此添加公告。
(2) 管理员可以自己填写数字,来确定其排列的顺序(按从小到大排列)。
(3) 管理员可以删除过期的公告,但删除后不可恢复。
(1) 管理员可在此添加友情链接。
(2) 添加链接是可输入连接名称、地址,上传链接图片。
(3) 友情链接在前台显示,点击图片就可以打开该链接的页面。
(1) 网站后台要求结构明了,能够很容易找到想要操作的地方。
(2) 后台所填选项要有清楚说明其作用、功能。
(3) 每次提交操作之后要给出明确的提示,操作是否成功。
概要设计是在需求分析的基础上由抽象到具体的过程。内容包括数据库设计和系统结构设计两大部分。主要目标是将系统分析阶段所提出的反映了信息需求的系统逻辑方案转换成可以实施的基于计算机与通信系统的物理(技术)方案,为下一阶段的详细编码提供必要的技术资料,应符合系统性、灵活性、可靠性、经济性的要求。
数据库是数据管理的最新技术。十多年来数据库管理系统已从专用的应用程序发展成为通用的系统软件。由于数据库具有数据结构化,最低冗余度,较高的程序与数据独立性,易于扩充,易于编制应用程序等优点,较大的信息系统都是建立在数据库设计之上的。因此不仅大型计算机及中小型计算机,甚至微型机都配有数据库管理系统。
数据库系统的出现使信息系统从以加工数据的程序为中心转向围绕共享的数据库为中心的新阶段。这样既便于数据的集中管理,又有利于应用程序的研制和维护,提高了数据的利用性和相容性,提高了决策的可靠性。目前,数据库已经成为现代信息系统不可分割的重要组成部分。数据库技术也是计算机领域中发展最快的技术之一。
数据库设计是把现实世界的实体模型与需求转换成数据库的模型的过程,它是建立数据库应用系统的核心问题。数据库及其应用的性能都建立在良好的数据库设计的基础之上,数据库的数据是一切操作的基础,如果数据库设计不好,那么其它一切用于提高数据库性能的方法收效都是有限的。数据库设计的关键是如何使设计的数据库能合理地存储用户的数据,方便用户进行数据处理。
设计数据库必须遵循一定的规则,在关系型数据库中,这种规则就是范式,范式是符合某一种级别的关系模式的集合。一般人们设计数据库遵循第三范式。即:数据库表中不包含已在其他表中包含的非主关键字信息。采用范式减少了数据冗余,节约了存储空间,同时加快了增、删、改的速度。
进行整个数据库设计必须准确了解与分析用户需求(包括数据和处理)。用户需求分析是整个设计过程的基础,是最困难、最耗费时间的一步。作为最基本的需求分析做得是否充分与准确,决定了在其构建数据库的速度和质量。
用户的需求具体体现在各种信息的提供、存储、更新和查询方面,这就要求数据库结构能充分满足各种信息的输出与输入。收集基本数据、数据结构及数据处理的流程,组成一份详尽的数据字典,为后面的具体设计打下基础。以上面的需求分析作为设计依据,该企业网站应该有以下几个基本数据表:
1、系统设置表:包括的网站的一些基本配置信息。
2、导航表:包括导航的编号、名字、存储路径等。
3、分类表:包括图片分类、文章分类、下载分类、商品分类等。
4、内容表:包括图片、文章、下载、商品等。
5、用户表:包括用户的基本信息。
6、管理员表:包括管理员的基本信息。
3、扩展表:包括一些扩展模块所使用的表等。
概念结构设计是数据库设计的核心。概念结构独立于数据库的逻辑结构,也独立与所使用的具体的数据库管理系统。概念模型(E-R模型)的组成元素有:实体、属性、联系,E-R模型用E-R图表示。实体是用户工作环境中所涉及的事务,属性是对实体特征的描述。
模型中的实体相当于一个实体集、一个表。实体用矩形框表示,实体名称标注在矩形框内。用菱形表示实体间的联系,菱形框内写上联系名,用无向边把菱形分别与有关实体相连接,在无向边旁标上联系的类型。
属性是实体的性质。用椭圆框表示,与实体之间用一条线相连,表的主码是关键属性,关键属性项加下划线。
各子系统模块中主键相同的字段之间存在着相互关联的关系。
在程序中实现对他们的完整性和一致性控制。
E-R模型的组成元素有:实体、属性、联系。E-R模型用E-R图来表示。实体是用户工作环境中所涉及的事物,属性是对实体特征的描述。
图4.1 导航E-R图
图4.1显示了导航的所有属性,其中链接和外部链接二者之选其一,外部链接有着更高的优先级,存在外部链接,本身的链接(内部链接)将不起效。
图4.2 图片E-R图
图4.2显示了图片的所有属性,hash名是图片在上传过程由程序自动设置的一个名字,这个名字保证了图片在网站中的唯一性。
图4.3 商品E-R图
图4.3显示了商品的所有属性,其中发布人一般是管理员,封面图片是单独上传的。
其他模块的E-R图跟商品E-R图类似,将不再叙述,下面是网站管理员管理网站的
E-R图:
图4.4 网站管理员E-R图
在实际设计的时候需要考虑到一些系统的性能、负载问题,所以数据库的设计要求更加细致,下面对每个表进行详细的设计与说明。
图4.5 系统基本设置表(settings)
图4.5 系统基本设置表只有两个字段,分别是variable和value,这个表存储的是网站的一些配置信息,比如存储网站名,在表中的存储格式为:variable:sitename,value:企业网站。
图4.6 导航表(navgation)
图4.6导航表中的target字段的长度为1,这个字段只存在2个值,分别是0和1。
图4.7 图片分类表(picturecategories)
图4.7 图片分类表利用父子id法进行无限分类,note是对分类的一些简单描述,只在后台显示。
图4.8 图片表(pictures)
图4.8 图片表存储的是图片展示中的所有图片和商品的封面图片,可以说网站的大部分图片都记录在图片表中统一管理。
图4.9 图片展示表(picturescontent)
图4.9 图片展示表,这个表中的coverpic和content存储的是一个经过php序列化之后的图片信息数组,在显示的时候再经过反序列化。
图4.10 商品分类表(producecategories)
图4.10 商品分类表跟图片分类表基本一样,采用父子id法进行无限分类。
图4.11 商品基本信息表(produces)
图4.11 商品基本信息表是考虑到系统的性能,把商品的一些基本信息写在一个表中,由于这个表中存储的数据量不大,可以提高查询速度。
图4.12 商品详细信息表(producecontent)
图4.12 商品详细信息表存储了商品的详细内容,由于商品的详细内容既有文字,又有图片,况且商品的前台的商品列表中不显示详细信息,所以把商品的详细信息单独制表,当游客查看商品的详细信息的时候才查询商品详细信息表。文章模块、下载模块的数据表跟商品展示的数据表类似,下面不再详细说明。
图4.13 友情链接表(friendlink)
图4.13 友情链接表存储了友情链接的所有属性,这种小型模块只有使用了一个表进行数据的存储,操作简单。网站公告、用户信息、管理员信息、人才招聘等都是只有使用一个单表进行存储,后面不再详细说明。
图4.14 网站后台结构图
网站的后台功能设计必须完全的符合前台功能模块的要求,现在很多的大型CMS系统可以提供功能强大的专业网站后台,做为小型企业这种后台的实用性却不是很大,因为专业的后台管理程序功能太复杂,不利于企业内部工作人员进行管理。因此,专门开发一个小型网站后台管理系统在小型企业网站的设计中是非常必须的。
图4.15 网站前台结构
前台有这么几大模块,其中友情链接和网站公告在首页显示,模块较小,暂不列出。
图4.16 整个系统的程序架构
从上图中可以清晰的看到整个程序的架构,本程序使用程序跟显示分离的技术,php动态页只负责处理数据和一些逻辑,把处理完的变量赋值给smarty,让smarty去把数据跟模板结合。并且程序对一些经常用到的数据做了简单的缓存。
图4.17 模板引擎工作原理图
系统详细设计就是按照前面进行的种种分析,把各种需求使用程序语言实现的过程。这部分将会对某些关键技术做出详细的描述,包括代码段的讲解、运行原理的细述和显示效果的展示。
整个系统的前台几乎依赖于common.inc.php文件,这个文件对系统正常运行所需要的一些常量进行定义,对变量进行初始化,引入其他一些重要文件。
session_start();
set_magic_quotes_runtime(0);
define('IN_WEB', TRUE);
define('WEB_ROOT', str_replace("\\", '/', substr(dirname(__FILE__), 0, -7)));
define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
require_once WEB_ROOT.'include/global.fun.php';
这个文件最开始第一行使用了session_start函数开启了session,后面只要引用这个文件的页面都可以对session进行操作;紧接着后面的set_magic_quotes_runtime(0)是关闭php的自动转义,后面的数据使用自定义函数转义;后面的定义常量是为了页面的安全性和一些地方使用的方便性;同时这个文件还对主要的函数文件进行引入,统一调度。
$dbhost = $dbuser = $dbpass = $dbname = $pconnect = $dbprefix = $dbcharset = $charset = '';
$_CFG = array();
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value);
}
}
这一段最开始对一些需要使用的变量进行了初始化,防止一些非法注入,紧接着后面一段又对URL传值进行了过滤,这个过程是先判断php是否有自动过滤,如果有,直接返回,如果没有则对一些特殊字符进行转义,保证数据安全。
require_once WEB_ROOT.'config.inc.php';
require_once WEB_ROOT.'include/db_mysql.class.php';
$DB = new DB_MySQL();
$DB->connect($dbhost, $dbuser, $dbpass, $dbname, $pconnect);
unset($dbhost, $dbuser, $dbpass, $dbname, $pconnect);
$timestamp = gmtime();
$php_self = dhtmlspecialchars($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']);
$onlineip = getonlineip();
if (!@include(WEB_ROOT.'cache/settings.php')) {
require_once(WEB_ROOT.'include/cache.php');
recache();
exit('
caches created successfully , please refresh the page!
');}
if (!$_CFG['siteurl']) {
$_CFG['siteurl'] = 'http://'.$_SERVER['HTTP_HOST'].dirname($PHP_SELF).'/';
} else {
$_CFG['siteurl'] = str_replace(array('{host}','index.php'), array($_SERVER['HTTP_HOST'],''), $_CFG['siteurl']);
if (substr($_CFG['siteurl'], -1) != '/') {
$_CFG['siteurl'] = $_CFG['siteurl'].'/';
}
}
$css_root = $_CFG['siteurl'].'templates/default/';
$web_url = $_CFG['siteurl'];
这一段对以后页面经常使用的变量做了一定的操作之后进行了初始化赋值,后面的页面可以直接进行使用,提高代码利用率和程序的可读性。
require_once WEB_ROOT.'include/config.smarty.php';
include_once WEB_ROOT.'smarty/Smarty.class.php';
$template = new Smarty();
$template->caching = $tpl_caching;
$template->template_dir = WEB_ROOT.$tpl_template_dir;
$template->compile_dir = WEB_ROOT.$tpl_compile_dir;
$template->left_delimiter = $tpl_left_delimiter;
$template->right_delimiter = $tpl_right_delimiter;
这一段对smarty模板进行实例化,smarty模板在每个页面都会使用,这样做也是提高代码利用率。
总的来说,common.inc.php文件就是实例化一些几乎每个页面都会使用的对象,初始化一些经常使用的变量,聚合一些函数文件和类文件,相当于整个程序的控制中心,总体调度程序运行。
if(!defined('IN_WEB'))
{
exit('Access Denied');
}
页面最开始先判断是否存在IN_WEB常量,如果不存在就直接退出程序执行,这么做保证了文件的安全性,IN_WEB常量是在common.inc.php 文件中定义的,也就是说这个函数文件只能被common.inc.php文件引用。
function multi($num, $perpage, $curpage, $mpurl, $page = 10) {
$curpage = $curpage ? $curpage : 1;
$multipage = '';
$mpurl .= strpos($mpurl, '?') ? '&' : '?';
$pages = 1;//总页数
if($num > $perpage) {
$offset = $page - 1;
$pages = @ceil($num / $perpage);
if($page > $pages) {
$from = 1;
$to = $pages;
} else {
$from = $curpage - $offset;
$to = $from + $page - 1;
if($from < 1) {
$to = $page;//$curpage + 1 - $from;
$from = 1;
if($to - $from < $page) {
$to = $page;
}
} elseif($to > $pages) {
$from = $pages - $page + 1;
$to = $pages;
}
}
$curpage = $curpage <= $pages ? $curpage : $pages;
$multipage = ($curpage > 1 ? '
($curpage - $offset > 1 && $pages > $page ? '
($curpage > $page+1 ? '
for($i = $from; $i <= $to; $i++) {
$multipage .= $i == $curpage ? '
'
}
$multipage .= ($curpage < $pages-1 ? '
($to < $pages ? '
($curpage < $pages ? '
($pages > $page ? '
$multipage = $multipage ? '
}
return $multipage;
}
这个分页函数在使用的时候只需要传给它4个值,分别是:数据总数、每页显示数、当前页数、url地址,此时这个函数会输出一个分页的html代码,只用在程序中输出就可以,样式写在页面所使用的样式文件里。示例代码如下:
$allnum = 500;
$perpage = 25;
$curpage = (int)$_GET['page'];
$php_self;
$pages = multi($allnum, $perpage, $curpage, $php_self);
echo $pages;
?>
以上几行简单的代码(css样式文件省略)将可以产生一个如下图所示的分页。
图5.1 分页效果
class DB_MySQL {
var $querycount = 0;
……
// 连接数据库
function connect($dbhost, $dbuser, $dbpass, $dbname, $pconnect=0) {
if($pconnect) {
if(!@mysql_pconnect($dbhost, $dbuser, $dbpass)) {
$this->halt('数据库链接失败');
}
} else {
if(!@mysql_connect($dbhost, $dbuser, $dbpass)) {
$this->halt('数据库链接失败');
}
}
……
//定义 fetch_array 方法,此函数返回根据从结果集取得的行生成的数组,如果没有返回FALSE
function fetch_array($query, $result_type = MYSQL_ASSOC) {
return mysql_fetch_array($query, $result_type);
}
//定义 query 方法,用于执行一次 SQL 查询
function query($sql, $type = '') {
$func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?
'mysql_unbuffered_query' : 'mysql_query';
if(!($query = $func($sql)) && $type != 'SILENT') {
$this->halt('MySQL Query Error', $sql);
}
$this->querycount++;
return $query;
}
......
//直接执行一个 SQL 语句,并返回结果
function fetch_one_array($query) {
$result = $this->query($query);
$record = $this->fetch_array($result);
return $record;
}
// 返回结果集中行的数目
function num_rows($query) {
$query = mysql_num_rows($query);
return $query;
}
......
}
这个数据库类对MySQL数据库的一些方法做了简单的封装,简化在程序中操作数据库的过程,提高编码效率。
class captcha
{
var $folder = '../images';
var $img_type = 'png';
var $session_word = 'code_word';
……
// 生成图片并输出到浏览器
function generate_image($word = false) {
if (!$word) {
$word = $this->generate_word();
}
$this->record_word($word);
$letters = strlen($word);
mt_srand((double) microtime() * 1000000);
if (function_exists('imagecreatefromjpeg') && ((imagetypes() & IMG_JPG) > 0)) {
$theme = $this->themes_jpg[mt_rand(1, count($this->themes_jpg))];
} else {
$theme = $this->themes_gif[mt_rand(1, count($this->themes_gif))];
}
if (!file_exists($this->folder . $theme[0])) {
return false;
} else {
$img_bg = (function_exists('imagecreatefromjpeg') && ((imagetypes() & IMG_JPG) > 0)) ?
imagecreatefromjpeg($this->folder . $theme[0]) : imagecreatefromgif($this->folder . $theme[0]);
$bg_width = imagesx($img_bg);
$bg_height = imagesy($img_bg);
$img_org = ((function_exists('imagecreatetruecolor')) && PHP_VERSION >= '4.3') ?
imagecreatetruecolor($this->width, $this->height) : imagecreate($this->width, $this->height);
/* 将背景图象复制原始图象并调整大小 */
if (function_exists('imagecopyresampled') && PHP_VERSION >= '4.3') // GD 2.x
{
imagecopyresampled($img_org, $img_bg, 0, 0, 0, 0, $this->width, $this->height, $bg_width, $bg_height);
}
else // GD 1.x
{
imagecopyresized($img_org, $img_bg, 0, 0, 0, 0, $this->width, $this->height, $bg_width, $bg_height);
}
imagedestroy($img_bg);
$clr = imagecolorallocate($img_org, $theme[1], $theme[2], $theme[3]);
$x = ($this->width - (imagefontwidth(5) * $letters)) / 2;
$y = ($this->height - imagefontheight(5)) / 2;
imagestring($img_org, 5, $x, $y, $word, $clr);
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
header('Cache-Control: private, no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0, max-age=0', false);
header('Pragma: no-cache');
if ($this->img_type == 'jpeg' && function_exists('imagecreatefromjpeg')) {
header('Content-type: image/jpeg');
imageinterlace($img_org, 1);
imagejpeg($img_org, false, 95);
} else {
header('Content-type: image/png');
imagepng($img_org);
}
imagedestroy($img_org);
return true;
}
}
……
}
验证码类根据实例化时的传值,动态的生成验证码图片,并且把验证码的值写入session中,整个网站的程序页面都可以使用,判断验证码是否正确使用了验证码类中的一个比较函数,如果返回为假,则说明验证码不正确。
后台控制文件的逻辑跟前台控制文件的逻辑大体一致,唯一不同的是:后台控制文件在后半部分进行了管理员身份验证,而后台的每个文件在一开始都对global.php进行引用,这样就保证了后台的所有操作都是在管理员登录的情况下进行的。下面是管理员身份验证的核心代码。
/*-- 验证管理员身份 --*/
if ((!isset($_SESSION['admin_id']) || intval($_SESSION['admin_id']) <= 0) &&
$_REQUEST['act'] != 'login' && $_REQUEST['act'] != 'signin' )
{
/* session 不存在,检查cookie */
if (!empty($_COOKIE['WEB']['admin_id']) && !empty($_COOKIE['WEB']['admin_pass']))
{
/* 找到了cookie, 验证cookie信息 */
$sql = "SELECT id, adminname, password, ip, lastlogin FROM {$dbprefix}admin WHERE id = '" . intval($_COOKIE['WEB']['admin_id']) . "'";
$row = $DB->fetch_one_array($sql);
if (!$row) {
/* 没有找到这个记录 */
setcookie($_COOKIE['WEB']['admin_id'], '', 1);
setcookie($_COOKIE['WEB']['admin_pass'], '', 1);
showmsg("您还没登陆,请先登录!","privilege.php?act=login");
} else {
/* 检查密码是否正确 */
if (md5($row['password'].$_CFG['hash_code']) == $_COOKIE['WEB']['admin_pass']) {
!isset($row['lastlogin']) && $row['lastlogin'] = '';
set_admin_session($row['id'], $row['adminname'], $row['password'], $row['lastlogin']);
/* 更新最后登录时间和IP */
$DB->query("UPDATE {$dbprefix}admin SET lastlogin = '" .$timestamp. "', ip = '" .getonlineip(). "' WHERE id = '" . $_SESSION['admin_id'] . "'");
} else {
setcookie($_COOKIE['WEB']['admin_id'], '', 1);
setcookie($_COOKIE['WEB']['admin_pass'], '', 1);
showmsg("您还没登陆,请先登录!","privilege.php?act=login");
}
}
} else {
showmsg("您还没登陆,请先登录!","privilege.php?act=login");
}
}
以上是对管理员身份的验证,先判断session是否存在,如果存在就生成管理员信息cookie,如果不存在则验证cookie,存在cookie则验证cookie中的数据,失败则跳到登录页面,正确则更新数据库中的登录时间。
/*-- 判断 URL 是否正确,不正确则跳到登录页面 --*/
if ($_REQUEST['act'] != 'login' )
{
$admin_path = preg_replace('/:\d+/', '', $phpweb->url()) . 'admin';
if (!empty($_SERVER['HTTP_REFERER']) &&
strpos(preg_replace('/:\d+/', '', $_SERVER['HTTP_REFERER']), $admin_path) === false)
{
showmsg("您还没登陆,请先登录!","privilege.php?act=login");
}
}
这一段是判断在访问后台页面的时候路径是否正确,如果url路径不含有admin,则说明这个url路径是非法访问,把页面跳转到登陆页。
图5.2 后台全局图
图5.3 管理员登陆界面
后台管理员登陆启用了验证码技术,减少一些恶意程序对后台进行恶意登录尝试,由于验证码的存在,每次都需要验证提交的验证码是否与动态产生的session里的值一致,如不一致将直接不判断用户名和密码,返回登录界面。
下面是一些具体实现这个功能的代码:
if (!empty($_SESSION['code_word'])) {
include_once(WEB_ROOT . 'include/code.php');
$validator = new captcha();
if(!empty($_POST['login_code']) && !$validator->check_word($_POST['login_code']))
{
showmsg("验证码不正确,请准确填写","privilege.php?act=login");
}
if (empty($_POST['login_code'])) {
showmsg("请填写验证码","privilege.php?act=login");
}
}
以上一段就是对验证码进行判断,判断只要是$_SESSION['code_word']就代表验证码已经启用,这时引入验证码文件,实例化一个验证码对象,通过验证码类中的check_word方法判断接收的验证码是否跟之前产生的验证码一致,如果不一致就提示验证码不正确,然后返回登录页。
$_POST['username'] = isset($_POST['username']) ? trim($_POST['username']) : '';
$_POST['password'] = isset($_POST['password']) ? trim($_POST['password']) : '';
$sql = "SELECT id, adminname, password, ip, lastlogin FROM {$dbprefix}admin
WHERE adminname = '" . $_POST['username']. "' AND password = '" . md5($_POST['password']) . "'";
$row = $DB->fetch_one_array($sql);
if ($row) {
set_admin_session($row['id'],$row['adminname'],$row['password'],
$row['lastlogin']);
$DB->query("UPDATE {$dbprefix}admin SET ip= '".getonlineip()."',lastlogin='".$timestamp."' WHERE id='$_SESSION[admin_id]'");
showmsg("登录成功,页面在2秒后跳转","index.php");
} else {
showmsg("用户名或密码不正确,请重新输入","privilege.php?act=login");
}
验证码通过验证之后就开始对用户名和密码进行验证,验证的大概流程是:先接收表单传递来的值,如果不为空,则去除左右两边的空格,防止管理员由于多敲了一个空格导致无法正常登陆;根据接收到的用户名查询管理员表,如果查到了数据就证明用户名是正确的,然后判断提交的密码是否跟数据库查询出来的一致,如果一致,证明登录成功,更新最后登录时间和IP,否则提示错误,跳转回登录页。
下面是登陆的整体流程图:
图5.4 后台管理员登录流程图
图5.5 系统信息界面
这个界面就是对一些系统的基本信息和服务器环境信息做简单的显示,代码部分只有涉及到查询。
图5.6 后台系统设置
这里既是显示,同时也可以修改,如果需要对系统的某个设置进行更改只用更改之后点击提交就可以了。考虑到一些人性化的因素,在每条设置的后面都给了简单说明,并且在修改的时候只对改变的选项进行修改。
在处理动作页面主要是通过url传递的act值进行处理的,代码如下:
if (empty($_REQUEST['act'])) {
$_REQUEST['act'] = 'show';
} else {
$_REQUEST['act'] = trim($_REQUEST['act']);
}
当act为show时,进行显示,点击提交之后传递的act值是edit,此时程序对传递的数据做判断,如果某个选项跟原来的不一样,就更新这个选项,最后调用缓存管理文件重新生成缓存。
图5.7 后台导航管理
导航列表对导航做了很详细的显示,对自定义链接也清晰的给以标注,导航按照排列顺序的从小到大排列。
图5.8 导航链接地址
在添加或修改导航的时候,链接地址栏都完整显示网站的所有分类,只用选择自己想要的分类,程序就会自动将分类名转化成url地址,具体实现代码如下:
<{section name=cates loop=$catelist}>
<{/section}>
可以看到在进行smarty遍历输出下拉选项的时候,分类名的value值是分类对应的
url地址,这个对应的url地址是在php页面构造的,构造url的代码如下:
$sql = "SELECT id,title FROM {$dbprefix}singlepage";
$query = $DB->query($sql);
while ($row = $DB->fetch_array($query)) {
$list['url'] = "about.php?id=".$row['id'];
$list['name'] = $row['title'];
$catelist[] = $list;
}
……
使用这种方法查询了所有分类表,并且都按照分类id构造了相应的url地址,在模板页进行smarty遍历的时候可以方便的获得其对应值。
图5.9 修改管理员密码
出于安全性的考虑,在修改管理员密码的时候需要输入旧密码,如果旧密码错误是不能修改新密码的。
图5.10 图片管理列表
图片管理列表做了分页处理,这里不仅可以删除单张图片,而且也可以对图片进行批量删除,列表显示了图片的存储路径,上传时间,图片名等信息。批量删除的核心代码如下:
这一段JavaScript代码的工作是当点击提交之后,把多选框的值组合成一个字符串赋值给一个隐藏域文本框
后面的动作就是表单提交的过程,表单把数据提交到php页面,php首先对delid的值进行分割,然后一条一条的删除数据。代码如下:
$delid = isset($_REQUEST['delid']) ? $_REQUEST['delid'] : '';
$list = array();
$list = explode('/',$delid); //把delid的值使用'/'分割为一个数组
for ($i=0;$i ... 这里是删除图片和删除数据记录的动作 ... } showmsg("删除成功","picmanage.php?act=show"); 图5.11 上传图片 上传图片可以批量上传,每选择一张,下面就自动增加一条上传队列,并且显示出文件名,理论上可以上传任何格式的文件,但是出于实际运用的考虑,这里只允许上传常见的图片格式。如果需要取消某张图片的上传,单击前面对应的小叉就可以把图片删除上传队列。 在上传图片的时候使用的简单的面向对象原理,通过实例化上传类和缩略图类来简化上传操作,具体代码如下: require_once( WEB_ROOT."admin/include/admin_upload.class.php"); require_once( WEB_ROOT."admin/include/admin_miniature.class.php"); /*-- 初始化变量,实例化上传类 --*/ $file = $_FILES['pic']; $upload_path='../attachments/picture'; $allow_type=array('jpg','bmp','png','gif','jpeg'); $max_size=2048000; $upload=new upFiles($file, $upload_path, $max_size, $allow_type); $picnum = $upload->upload(); $pic = $upload->getSaveFileInfo(); /*-- 缩略图 --*/ $m=new Miniature(); for ($i=0;$i<$picnum;$i++) { $str_file = $_CFG['url'].substr($pic[$i]['file'],2); $m->ReadImage($str_file); $m->ResizeImage(200,200); $m->ImageType=4; $thumb_name=$pic[$i]['basename']."_thumb"; $m->SaveImage($pic[$i]['path']."/",$thumb_name);/ $m->DestroyImage(); $sql = "INSERT INTO {$dbprefix}pictures (id,temname,filename,filepath,thumbpath,uploadtime) VALUE ('','".$pic[$i]['savename']."','".$pic[$i]['name']."','".$pic[$i]['path']."','".$pic[$i]['path']."','".$timestamp."')"; $query = $DB->query($sql); } require_once()函数会先检查目标文件的内容是不是在之前就已经导入过了,如果是的话,便不会再次重复导入同样的内容。 $_FILES[]是PHP内置的超全局函数,这个函数专门用来接收文件域的数据,它会根据上传的文件生成一个数组,这个数组包括文件名、文件类型、文件大小、扩展名、内存中的临时名称。 upFiles类需要4个参数,分别是文件信息、存储路径、允许上传的大小、允许上传的扩展名。通过调用upload方法,文件上传之后会返回一个数组,通过getSaveFileInfo方法取得上传类返回的数组。 Miniature()是图片缩略图类,这个类里面封装了许多方法,如:ReadImage()是读取图片,需要的参数是图片的完整路径和图片名,通过ReadImage()方法可以获取的图片的一些信息。ResizeImage()是生成缩略图的方法,其中的两个参数分别是长和宽,在生成缩略图的时候是按照最小的那个值计算,按比例缩放。 图5.12 编辑图片展示 在图片展示栏可以对图片展示再进行编辑,编辑的内容包括图片组名称、分类、封面图片、图片组中的图片,在这里删除某一张图片的时候使用的是ajax技术,整个页面在不刷新的情况下进行图片的删除,适当的ajax充分的提高的用户的体验效果。 Ajax的静态页代码: 用户点击删除,此时调用了delOnePic函数,传递给函数2个参数,一个是图片图片基本名,一个是图片的扩展名。 jQuery的$.post(url, params, callback)有三个参数,分别是: url (String): 装入页面的URL地址。 params (Map): (可选)发送到服务端的键/值对参数。 callback (Function): (可选) 当数据装入完成时执行的函数。 以上代码中定义了删除图片的处理页面是picture.php,同时传递了4个值给picture.php,它们是动作:delonepic,图片名:picname,扩展名:ext,图片组id。 Ajax的动态页代码: $prid = $_REQUEST['prid']; $picname = $_REQUEST['picname']; $ext = $_REQUEST['ext']; $sql = $row = $query = ''; $sql = "SELECT * FROM {$dbprefix}picturecontent WHERE prid = $prid"; $row = $DB->fetch_one_array($sql); /*-- 删除图片 --*/ ...... /*-- 删除缩略图 --*/ ...... /*-- 处理数据表里面的序列串 --*/ $html = ''; for ($i=0;$i /*-- if 循环去除数组中删除的图片信息 --*/ if ($row['content'][$i] != $picname.$ext) { $newrow['content'][] = $row['content'][$i]; $basename = basename($row['content'][$i],$ext); $thumbname = $basename.'_thumb'.$ext; /*-- 开始重新生成 html 传回页面显示 --*/ $html .= " 删除"; } } /*-- 更新数据库 --*/ ...... echo $html; 动态页根据ajax传递来的参数删除图片,然后把数据表中的数据反序列化之后重新整理,构造一个html串传回静态页显示,最后更新数据库信息。 图5.12 在线编辑器 商品展示栏目中使用了网页在线编辑器xheditor,它能够在网页上实现许多桌面编辑软件(如:Word)所具有的强大可视编辑功能。WEB开发人员可以用它把传统的多行文本输入框 此模块实现对单页进行分类和管理。单页列表如图5.13所示: 图5.13 单页列表 (2)单击添加分类将会进入分类的详细属性页面。 单页分类有如下要求: 单页在前台按分类显示。 如果如 企业简介,企业文化一类需要在一起显示的请分为同一分类。 如果如 联系我们只显示一个页面,请单独建立分类。 在单页分类设置中每一项属性都有所规定: 例如:分类转向URL即为点击分类将进入转向设置的URL。 自定义模板,若管理者设置了自定义模板,则点击该分类的时候将显示该模板,系统默认模板不再生效。如果是封面模板就应事先放到模板所在目录,如不存在,将显示系统默认模板。 分类说明将显示于名称的后面,提供对本分类的简短描述,建议字数不超过20个。 如图5.14所示,显示了单页分类的一系列的相关操作和属性: 图5.14 增加单页分类操作 (3)单击编辑可以编辑分类 在SQL数据库中查询已经存在的数据,查询出来之后才可以对原有的数据进行编辑。 编辑分类提交后,系统必须每一项属性都更新,如果每一项数据都顺利更新则表示编辑分类成功,也就在页面上显示分类修改成功,然后自动转到单页列表页面。如果编辑分类失败则显示分类修改失败再回到单页列表页面。 (4)单击删除可以删除分类 删除分类成功后会在页面上显示删除成功。注:此删除操作不可恢复,所以谨慎决定后,再进行删除操作。 单页分类代码及分析: 显示分类:下面代码实现显示分类作用。 if ($_REQUEST['act'] == 'show') { $cates = tree("singlecategories",0); $smarty->assign("cates",$cates); $smarty->assign("css_root",$css_root); $smarty->display("single_cate.html"); } if ($_REQUEST['act'] == 'remove') { $id = $_REQUEST['pid']; delcate("singlecategories",$id); showmsg("删除分类成功","single_cate.php?act=show"); } 上述代码执行了显示单页分类页面操作,如果对已经添加的分类觉得不需要,可以删除分类,上述代码实现了删除分类的功能: 首先找到要删除的单页分类的id,然后执行删除操作,删除分类成功后则在页面上显示“删除分类成功”,如果删除不成功则显示“删除分类指失败”, single_cate.php?为执行删除操作后显示的页面。 主要用到的一些函数如下: Smarty的一些特点: •非常非常的快; •用php分析器干这个苦差事是有效的; •不需要多余的模板语法解析,仅仅是编译一次; •仅对修改过的模板文件进行重新编译; •可以编辑'自定义函数'和自定义'变量',因此这种模板语言完全可以扩展; •可以自行设置模板定界符,所以你可以使用{}, {{}}, , 等等; •诸如 if/elseif/else/endif 语句可以被传递到php语法解析器,所以 {if ...} 表达式是简单的或者是复合的,随自己喜欢; •如果允许的话,section之间可以无限嵌套; •引擎是可以定制的.可以内嵌php代码到你的模板文件中,虽然这可能并不需要(不推荐); •内建缓存支持; •独立模板文件; •可自定义缓存处理函数; •插件体系结构。 assign:用于在模板被执行时为模板变量赋值。 Display:显示模板,需要指定一个合法的模板资源的类型和路径。你还可以通过第二个可选参数指定一个缓存号,相关的信息可以查看缓存。 添加分类代码如下: if ($_REQUEST['act'] == 'add') { $id = $_REQUEST['pid']; $smarty->assign("pid",$id); $smarty->assign("css_root",$css_root); $smarty->display("single_cate_add.html"); } if ($_REQUEST['act'] == 'addok') { $cate = $_REQUEST['cate']; $sql = $query = ''; $sql = "INSERT INTO {$dbprefix}singlecategories (catid,parentid,name,note,template,url,displayorder) VALUE ('','".$cate['pid']."','".$cate['name']."','".$cate['note']."','".$cate['template']."','".$cate['url']."','".$cate['displayorder']."')"; $query = $DB->query($sql); if ($query) { showmsg("分类添加成功","single_cate.php?act=show"); } else { showmsg("分类添加失败","single_cate.php?act=show"); } } 上述代码为执行增加分类操作。转到添加分类页面,执行添加操作: INSERT INTO 表名(a1,a2)VALUES ('aaa','bbbb') INSERT INTO 语句用于向数据库表添加新纪录,向singlecategories表中添加分类的每一个字段信息。 调用$DB对象的query方法,-> 就是用来引用类的属性和方法的。 编辑分类代码如下: if ($_REQUEST['act'] == 'edit') { $catid = $_REQUEST['pid']; $sql = ''; $sql = "SELECT * FROM {$dbprefix}singlecategories WHERE catid = $catid"; $cate = $DB->fetch_one_array($sql); print_r($parentcate); $smarty->assign("css_root",$css_root); $smarty->assign("catid",$catid); $smarty->assign("cate_name",$cate['name']); $smarty->assign("cate_parentid",$cate['parentid']); $smarty->assign("cate_url",$cate['url']); $smarty->assign("cate_template",$cate['template']); $smarty->assign("cate_note",$cate['note']); $smarty->assign("cate_displayorder",$cate['displayorder']); $smarty->display("single_cate_edit.html"); } if ($_REQUEST['act'] == 'editok') { $cate = $_REQUEST['cate']; $sql = ''; $sql = "UPDATE {$dbprefix}singlecategories SET parentid = '".$cate['parentid']."', name = '".$cate['name']."', url = '".$cate['url']."', template = '".$cate['template']."', note = '".$cate['note']."', displayorder = '".$cate['displayorder']."' WHERE catid = ".$cate['catid']; $query = $DB->query($sql); if ($query) { showmsg("分类修改成功","single_cate.php?act=show"); } else { showmsg("分类修改失败","single_cate.php?act=show"); } } 上述代码是为实现编辑单页分类,首先执行查询出要编辑的分类的所在表和所在表中所处的分类id,从而显示出父级分类,显示出每一项该分类的属性,然后选中要编辑的属性编辑,编辑好之后,数据表提交后,需要更新该分类的每一项属性后,提交到数据表后,才能确认是否编辑成功,如果编辑成功则显示“分类修改成功”,否则显示“分类修改失败”。 在数据查询中,经常涉及到提取两个或多个表的数据,这就需要使用表的连接来实现若干个表数据的联合查询。上面代码中出现有关数据查询语句,下面对出现的一些语句做一些讲解: SELECT 列名1,列名2,… FROM 表1,表2,… WHERE 连接条件 SELECT查询语句中,FROM子句指定了SELECT语句中字段的来源。FROM子句后面是包含一个或多个的表达式(由逗号分开),其中的表达式可为单一表名称、已保存的查询或由 INNER JOIN、LEFT JOIN 或 RIGHT JOIN 得到的复合结果。 WHERE后面子句为指定查询条件 1 比较运算符 = 等于、> 大于、< 小于、>= 大于等于、<= 小于等于、<> 不等于、 !> 不大于、!< 不小于 更新查询语法: UPDATE 表名 SET 新值 WHERE 准则 UPDATE子句可以同时更改一个或多个表中的数据.它也可以同时更改多个字段的值。 UPDATE 把当前的单页分类属性更新到单页列表,按照分类id的顺序显示在列表当中。 Showmsg ()提示信息函数在用户进行一些操作后显示应该提示的信息页面,使管理者知道自己的操作情况。 显示单页的id、单页名称、所属分类、是否外链、打开方式、显示顺序,还可以对这些属性进行编辑和删除。如图5.15所示: 图5.15 单页列表 (1)单页列表 显示单页的名称、所属分类、单页是否外链、单页打开方式以及显示顺序。 (2)添加单页 点击添加单页跳转到添加单页的模块页面,添加单页。 添加单页包括单页名称、所属分类、自定义模板、链接地址、是否在新窗口中打开、显示顺序,还有最主要的单页内容。在输入单页内容的时候可以对其进行一系列的编辑。例如最简单的复制、粘贴、剪切等。这些功能都是由文章编辑器来实现的(此文章编辑器可以到网上下载)。如图5.16所示: 图5.16 单页在线编辑器 (3)单页管理代码及分析 显示单页列表代码如下: if ($_REQUEST['act'] == 'show') { $sql = $query = $singlist = ''; $sql="SELECT s.id,s.catid,s.title,s.url,s.target,s.displayorder,c.catid,c.name FROM {$dbprefix}singlepage s LEFT JOIN {$dbprefix}singlecategories c ON s.catid = c.catid ORDER BY s.displayorder"; $sql = "SELECT * FROM {$dbprefix}singlepage ORDER BY displayorder"; $query = $DB->query($sql); while ($row = $DB->fetch_array($query)) { $row['target'] = $row['target'] ? "原窗口" : "新窗口"; $row['url'] = $row['url'] ? "是" : "否"; $singlist[] = $row; } print_r($singlist); $smarty->assign("css_root", $css_root); $smarty->assign("web_url", $web_url); $smarty->assign("singlist", $singlist); $smarty->display("single.html"); } 上述代码应用到了数据查询、连接、排序,分析如下: SELECT* FROM table LEFT JOIN table2 ON table1.field1 comparision table.field2 用左连接来建立外部连接,在表达式的左边的表会显示其所有的数据。 右连接与左连接的差别在于:不管左侧表里有没有匹配的记录,它都从左侧表中返回所有记录。 空值不会相互匹配,可以通过外连接才能测试被连接的某个表的字段是否有空值。 通过在SELECT命令中加入ORDER BY子句可控制选择行的显示顺序。ORDER BY子句可以按升序(默认或ASC)、降序(DESC)排列各行,也可以按多个列表排序。 增加单页、编辑单页、删除单页与这些单页操作是否成功都与单页的添加、编辑、删除相类似,所以在此就不做详细说明了。 (1)文章分类操作 点击添加一级分类,将添加一个相对于网站根分类的子分类;点击添加二级分类,将添加一个相对于该一级分类的子分类;点击分类后面的小“+”,将添加相对于该分类的子分类。如图(15)所示。 注:为了避免太多级分类造成的烦恼,在这里只设了三级分类。例如要把一个已经是三级分类的归属给另一个三级分类,那么在编辑文章分类模块里,父级分类中将没有你要归属的分类名称。 例如要把管理类放到技术类的子分类中是不允许的。如图6-5和图6-6所示在父级分类中是没有技术类存在的。因为管理类和技术类同属于三级分类。 图5.17 显示添加分类 图5.18 父级分类 在后台进行文章分类,这样使用户更加方便更容易地找到自己想要看到的文章。页随着后台的修改更新,前台文章分类也有所更新,更新后的显示如图5.19和图5.20所示: 图5.19 新闻分类显示 图5.20 国内新闻分类显示图 (2)文章分类代码及分析 if ($_REQUEST['act'] == 'show') { $sql = $query = $cates = ''; $temcates = tree("articlecategories",0); $k = 0; for ($i = 0; $i { if ($temcates[$i]['parentid'] == 0) { $temcates[$i]['children'] = ''; $cates[$k] = $temcates[$i]; $m = 0; for ($j = 0; $j { if ($temcates[$j]['parentid'] != 0 && $temcates[$j]['parentid'] == $temcates[$i]['catid']) { $temcates[$j]['children'] = ''; $cates[$k]['children'][$m] = $temcates[$j]; for ($n = 0; $n { if ($temcates[$n]['parentid'] != 0 && $temcates[$n]['parentid'] == $temcates[$j]['catid']) { $temcates[$n]['children'] = ''; $cates[$k]['children'][$m]['children'][] = $temcates[$n]; } } $m++; } } $k++; } } if…else 循环 if…else 循环有三种结构 第一种是只有用到 if 条件,当作单纯的判断。解释成 "若发生了某事则怎样处理"。语法如下: if (expr) { statement } 其中的 expr 为判断的条件,通常都是用逻辑运算符号 (logical operators) 当判断的条件。而 statement 为符合条件的执行部分程序,若程序只有一行,可以省略大括号 {}。 第二种是除了 if 之外,加上了 else 的条件,可解释成 "若发生了某事则怎样处理,否则该如何解决"。语法如下 if (expr) { statement1 } else { statement2 } 第三种就是递归的 if…else 循环,通常用在多种决策判断时。它将数个 if…else 拿来合并运用处理。 for 循环 for循环就单纯只有一种,没有变化,它的语法如下: for(expr1; expr2; expr3) { statement } 其中的expr1为条件的初始值。expr2为判断的条件,通常都是用逻辑运算符号(logical operators) 当判断的条件。expr3为执行statement后要执行的部份,用来改变条件,供下次的循环判断,如加一..等等。而statement为符合条件的执行部分程序,若程序只有一行,可以省略大括号{}。 单击编辑可以修改文章内容、标题或所属分类;还可以删除文章。 (1)文章列表设计 后台显示文章的标题、所属分类、发布人信息、发布时间以及点击数。如图5.21所示: 图5.21 文章列表显示 在后台添加文章后,用户访问该网站时,前台的文章也会随之更新,页面在前台首页显示如图5.22所示。 图5.22 文章首页显示 在自己的模块中显示文章的更新日期和用户点击次数。如图5.23所示: 图5.23 文章更新时间和点击次数 (2)添加文章设计 单击添加文章,将跳转到添加文章模块,写明添加文章的标题、所属分类,将文章内容输入到文字编辑器中,可以对文章进行一系列的编辑。还可以添加图片、flash文件等更多的多媒体文件,实现这些功能跟前面的添加单页是一样的原理。源代码也跟上面的相差不大。文章写好之后,点击提交便可以在前台看到添加的文章了。如果觉得有怀疑,还可以先预览,再点击提交。如图5.24所示就是添加文章时候的模块。 图5.24 添加文章编辑器 (3)文章管理代码及分析 显示文章列表: if ($_REQUEST['act'] == 'show') { $sql = $query = $artlist = ''; $sql = "SELECT * FROM {$dbprefix}articles"; $query = $DB->query($sql); $allnum = $DB->num_rows($query); $perpage = 20; $curpage = isset($_GET['page']) ? intval($_GET['page']) : 1; $php_self = "articles.php?act=show"; $pages = multi($allnum, $perpage, $curpage, $php_self, 10); if (($curpage-1) >= 0) { $step = $curpage-1; } else { $step = 0; } $startpage = $perpage * $step; $sql="SELECT a.aid,a.catid,a.title,a.username,a.dateline,a.viewnum,c.catid,c.name FROM {$dbprefix}articles a LEFT JOIN {$dbprefix}articlecategories c ON a.catid = c.catid LIMIT $startpage,$perpage"; $query = $DB->query($sql); while ($row = $DB->fetch_array($query)) { $row['dateline'] = formatdate($_CFG['format_type'],$row['dateline']); $artlist[] = $row; } print_r($artlist); $smarty->assign("css_root", $css_root); $smarty->assign("pages",$pages); $smarty->assign("artlist", $artlist); $smarty->display("article.html"); } if ($_REQUEST['act'] == 'remove') { $aid = $_REQUEST['aid']; $sql = $query = ''; $sql = "DELETE FROM {$dbprefix}articles WHERE aid = $aid"; $query = $DB->query($sql); $sql = "DELETE FROM {$dbprefix}articlecontent WHERE aid = $aid"; $query = $DB->query($sql); web_header("location:article.php?act=show\n"); exit(); } 先用SQL语句查询出总共有多少条数据,然后初始化变量来实例化分页。后面的SQL语句是根据分页数查询出该页的数据,接着把每一条数据的时间格式化,最后就是smarty的赋值和调用模板。 multi是分页函数,传递给他的4个变量,它会自动生成一段分页的html代码。 LIMIT $startpage,$perpage是sql语句中的用法,从$startpage开始查询,查询$perpage条数据。代码中便是实现:限制每页显示20条,那么第二页的数据就是从第20条数据开始,往后查询20条数据。 $dbprefix是数据表前缀,在mysql语句中出现数据表的地方都要加上该前缀。 do..while 循环 do..while是重复叙述的循环,可以分成两种模式。 最单纯的就是只有while的循环。用来在指定的条件内,不断地重覆指定的步骤。语法如下 while(expr){ statement } 其中的expr为判断的条件,通常都是用逻辑运算符号(logical operators)当判断的条件。而statement为符合条件的执行部分程序,若程序只有一行,可以省略大括号{}。 while 可以不用大括号来包住执行部分,而使用冒号加上endwhile。 另外一种do..while循环则先执行,再判断是否要继续执行,也就是说循环至少执行一次,有点像是先斩后奏的方法。这种的循环,和单用while是不同的(单用while是先判断再处理)。 do..whilte 的语法如下: do{ statement }while(expr); 图5.14 附件管理 (1)附件管理 即对文件的管理,可以对文件进行删除操作。也可以添加文件,即添加附件。为用户提供更多的可下载文件。 (2)附件列表 附件列表主要呈现出附件的相关信息和可以进行的相关操作。 此栏目的删除操作不可恢复,所以敬请谨慎操作。 有的时候可能会需要到批量删除,如果用到批量删除,请选择需要删除的文件,然后点击提交即可达到批量删除效果。 如果需要删除单个文件,请直接单击该文件后面的删除即可达到删除单个文件效果。 如果需要全部删除,则选择全选,再单击提交即可把全部都删除。 以上操作如图5.24所示: 图5.24 上传文件列表 在附件列表显示了附件名称、附件类型、还有管理员上传该附件时的所在目录、附件大小、用户下载次数。 (3)添加附件 添加附件其实就是我们通常所说的上传文件。 这个添加附件可以一次上传多个文件,但每一个文件都需要单独选择。点击浏览可以选择文件,如图5.25所示: 图5.25 添加下载文件 所选择的文件将按选择顺序排列添加附件选择框下面,当选择好之后就可以点击上传便可以上传了。如果上传成功的话便会在页面上显示文件上传成功,如果上传失败的话,则显示文件上传失败。 上传文件成功后,附件列表随之更新上传的文件,各项属性也随之更新 (4)文件管理代码及分析 主要代码分析: if ($_REQUEST['act'] == 'addok') { require_once( WEB_ROOT."admin/include/admin_upload_file.class.php"); $file = $_FILES['file']; $upload_path='../attachments/upload'; $allow_type=array('jpg','bmp','png','gif','jpeg','rar','zip','pdf'); $max_size=2048000; $upload=new upFiles($file, $upload_path, $max_size, $allow_type); $picnum = $upload->upload(); $pic = $upload->getSaveFileInfo(); for ($i=0;$i<$picnum;$i++){ $sql = "INSERT INTO {$dbprefix}attachments (id,filename,temname,attachtype,size,filepath,downloads) VALUE ('','".$pic[$i]['name']."','".$pic[$i]['savename']."','".$pic[$i]['type']."','".$pic[$i]['size']."','".$pic[$i]['path']."',0)"; $query = $DB->query($sql); } if ($query) { showmsg("文件上传成功","attachment.php?act=show"); } else { showmsg("文件上传失败"); } } 打开附件目录: $dir = opendir($filepath); $file = $filepath.'/'.$row['temname']; if (is_file($file)) { @unlink($file); } closedir($dir); $sql = "DELETE FROM {$dbprefix}attachments WHERE id = $id"; $query = $DB->query($sql); if ($query) { showmsg("文件删除成功","attachment.php?act=show"); } else { showmsg("文件删除失败"); } } 首先初始化变量,实例化上传类, 上传文件格式限制 上传文件大小限制 上传文件、上传文件路径、上传文件大小、允许格式 PHP 默认的上传限定的最大值是 2 M ,如果上传的文件大小超过此设定值,需要调整PHP的一些参数。 (1) file-uploads :是否允许通过 HTTP上传文件的开关,默认为ON。 (2) upload –tmp-dir :用来说明 PHP 上传的文件放置的临时目录,要想上传文件,必须保证服务器没有关闭临时文件和对文件夹的写权限,如果未指定则PHP使用系统默认值。 (3) upload-max-filesize :允许上传文件大小的最大值 ,默认为 2 M。 (4) post-max-size :在采用POST方法进行一次表单提交中PHP所能接收的最大数据量。如果使用PHP文件上传功能,则需要将此值调整为大于 upload -max -filesize的值。 图5.26 添加下载 在添加下载页面,只用单击选择按钮,就会弹出一个文件选择窗口,窗口中列出了网站中所有的附件,我们只用单击某个附件就可以把附件信息加到文本框中,大大提高了用户体验。 图5.27 添加招聘 添加招聘信息时如果后面的备选信息符合要求,只用单击就可以把对应的值填入文本框中,如果没有合适选项才用手工填写。 其他几个栏目的操作跟以上已经列举出的选项大体相同,后面将不再细述。 图5.28 前台首页 图5.29 企业简介 企业简介使用的是单页模块,文章按照分类显示,在后台设置了关于企业和企业文化属于同一模块,则在前台显示的时候,左侧的分类栏里面关于企业和企业文化都是在一起的。 图5.30 图片展示 图5.31 商品展示 图5.32 人才招聘 人才招聘栏目没有制作在线应聘功能,浏览者只能查看了应聘信息之后根据内容中留的联系方式跟公司联系。 为了使系统有更好的结构,本系统把程序与显示进行了分离,程序仅仅只负责处理页面,把页面的显示效果交给了模板去处理,要把程序跟模板结合起来就需要一个第三方的工具,这时我们使用smarty模板引擎。 Smarty模板有两个方法:assign、display,assign方法负责把需要在模板中显示的变量赋值给smarty,display方法调用显示模板,模板被调用之后,smarty就把赋值给它的变量与模板结合起来,构成一个html与php混编的页面存到模板缓存里面。在浏览器接收到数据请求之后,smarty就调用相应的模板给以显示。下面看一下smarty的具体实例:
require_once './include/common.inc.php'; $name = "这是一个测试页面"; $template->assign("name",$name); $template->display("test.html"); ?> $template这个对象是在common.inc.php中实例化smarty类之后生成的,这里使用smarty的assign方法对模板中的name变量进行赋值,然后调用test.html模板进行显示。 HTML页面(test.html) <{$name}> 可以看到在模板中使用了<{$name}>来进行模板的显示,此时在浏览器中访问test.php页面时,显示的效果如下图: 图5.21 smarty显示效果 Smarty不仅能显示单个变量,而且还能显示数组,在使用assign赋值的时候只用赋值整个数组,在模板中可以使用section语句把数组遍历显示出来,这里不再细述。 Ajax是有机地利用了一系列交互式网页应用相关的技术所形成的结合体。它能在不刷新整个页面的前提下更新数据,这使得Web应用程序能更为迅速地回应用户的操作。 本系统中在后台删除图片和前台用户注册时都是用了ajax技术,下面详细讲解用户注册时的动态验证。 HTMl页面 //
$(function(){ ...... //文本框失去焦点后 $('form :input').blur(function(){ var $parent = $(this).parent(); $parent.find(".formtips").remove(); //验证用户名 if( $(this).is('#username') ){ if( this.value=="" || this.value.length < 6 ){ var errorMsg = '请输入至少6位的用户名.'; $parent.append(''+errorMsg+''); }else{ $.post("ajaxreg.php", { username: $('#username').val() }, function (data, textStatus){ $parent.append(data); }) } /*}else{ var okMsg = '输入正确.'; $parent.append(''+okMsg+''); }*/ } ......[中间部分省略] }) //]]> 可以看到页面的js脚本对文本框的值做了判断,当文本框的值小于6位的时候都给出提示,当满足条件之后就是用ajax把值传递到ajaxreg.php页面,当数据返回成功时,把返回的数据添加到文本框后面,下面看ajaxreg.php的处理脚本: require_once './include/common.inc.php'; $username = isset($_REQUEST['username']) ? $_REQUEST['username'] : ''; if ($username) { $sql = "SELECT * FROM {$dbprefix}members WHERE username = '".$username."'"; $member = $DB->fetch_one_array($sql); if ($member) { $msg = '该用户已存在'; } else { $msg = '该用户名可以注册'; } } echo $msg; Ajaxreg.php页面接收了前端传来的用户名,使用改用户名查询数据库,如果存在数据,说明此用户名已经被注册,如果不存在数据说明用户名没被注册,两种情况下都产生一段html,最后使用echo 返回给前端页面,前端页面接收到返回的html就把该段html动态的插入到文本框后面,实现了实时验证。效果如下图: 图5.22 实时验证 在完成了程序的编写工作后,接下来将进行软件的测试,这里说的软件,并不单单是指程序本身,还包括其他方面.测试和开发一样,也是一项技术性很强的工作,有着很多的技巧。软件测试是软件质量保证的主要活动之一,因此,测试的质量直接影响软件的质量。 软件测试就是在软件投入运行前,对软件的需求分析,设计规格说明和编码的最终复审,是保证软件质量的关键步骤.如果要给软件测试下定义,可以这样将,软件测试是为了发现错误而执行程序的过程. 测试的目的在于将软件设计时设计者与程序开发者之间理解不一致的地方,功能与需求不一致的地方,不符合逻辑思维的情况都反映给质量控制部门,由质量控制部门调配需求部门统一作出一个明确解答,再由开发人员进行修改和补充, 测试的目标是以最少的时间和人力找出软件中潜在的各种错误和缺陷。 对于相对复杂的产品或系统来说,Zero-Bug是一种理想,Good-Enough是我们的原则。Good-Enough原则就是一种权衡投入/产出比的原则;不充分的测试是不负责任的;过分的测试是一种资源的浪费,同样也是一种不负责任的表现。我们操作的困难在于,如何界定什么样的测试是不充分的,什么样的测试是过分的。目前状况唯一可用的答案是:制定最低通过标准和测试内容,然后具体问题具体分析。 依据前面所说的测试对象,我们把测试划分为几个方面来进行测试。 界面测试是测试过程中比较简单直观的一种测试方法,只要细心地按界面要求核对就行了。可这快往往是程序开发人员容易忽视和遗漏的地方,也是常常出Bug的地方。下面是界面测试中经常出现的几种Bug: (1) 错别字,即界面中的标题或者文本内容中出现了错别字。这种Bug如果测试人员不细心,和难找出来,可能会出现在提示信息或界面中。 (2) 出现了一些根本读不懂的内容,一般多出现在程序的提示信息和一些较长的文本中。这种情况基本上出现在拼起来显示的提示中,页面的简单陈述是通过变量拼组起来的,通过程序将字一个一个地输出出来。通常是因为程序中的控制错误或是程序开发人员对程序没有进行认真的自测,导致出现这种Bug。 (3) 程序员自创的词语,虽然意思对,但不符合界面的标准及需求。这种情况基本上是由于开发人员使用一些专业术语,并且混杂着自己的理解出现Bug,主要是由于开发过程中团队合作没又明确的分工,没有统一的规范用语。 (4) 页面类似的内容中,明显有字体,字号不同的情况,使界面整体风格看上去不一致,这种情况只出现在没有CSS定义的情况下,或是已经定义的CSS,开发人员在开发过程中没有调用。 (5) 标题相近的程序及模块,把标题弄混。这种情况多是因为业务方面的定义名称很相似或很类似,并且业务实体方面也很类似,开发人员在开发过程中忽略了开发名称和模块,只单独地实现其功能。 顾名思义,功能测试主要是测试程序模块是否实现了设计中所有要求的功能。功能测试中需要注意的有: 针对需求测试,是测试中很重要的一个环节。因为需求是在软件设计,开发乃至软件测试中重要的依据。要针对需求测试,首先就要对项目的需求和业务有一定的了解。这些需求很多时候是在实现增,删,查,改这些基本功能之上,针对项目和相关业务所作的一些逻辑上的控制。这就要求程序员在设计和编码的时候要去充分理解考虑需求。 性能测试在软件的质量保证中起着重要的作用。通常我们把性能指标全部归结到硬件,操作系统和开发环境上,而忽略了代码本身性能上的考虑。性能需求指标中,稳定性,并访支撑能力以及安全性都很重要,作为程序员需要评估该模块在系统运营中所处的环境,将要受到的负荷压力以及各种潜在的危险和恶意攻击的可能性。 1.快速入题。拿到毕设题目要尽快把自己的蓝图勾画出来,不能走一步算一步,必须把整体把握好。 2.频繁与导师讨论。有问题多问导师,应该经常与指导老师沟通交流,让老师帮助我们更好的完善毕业设计,不能自己一直闷着头做,方向偏了也不知道,多把自己的想法和思路告诉老师。 3.软件的学习。一定要边做边学软件,千万不能在做毕业设计期间,拿着本软件教程从第一页开始看,这样效率最低了,最好是根据已有论文资料中提到的软件用途,有针对性的学。包括毕业设计前期读文献资料,也不能闷头读,要与毕业设计紧密联系起来,最好是边做边读,有针对性的读。 4.越挫越勇。做毕业设计,常常感觉到这句话:“山重水复疑无路,柳暗花明又一村。”通常,一定是有解决的办法,只是由于文献查的不够,或是少了那点灵感。 5.不能脱离实际。做的毕业设计要有创意,不能浮在上面,要让自己满意。 6.越来越紧的状态,尤其是最后的那几天。毕业设计越到最后阶段,越要有毅力和状态,不能前紧后松,觉得前面做了不少,后面可以放松了。论文提交的前几天,要不厌其烦的检查论文,包括内容,格式等。最好是一项一项的检查:图、表、公式、字体、行距、对齐。整体上一项一项检查,确保万无一失。 7.通过毕业写毕业论文,也学会了书写论文的一些基本格式和方法,WORD的强大功能还需要我们不断的努力去学习和发现。 首先我们了解一下我们的php程序是怎样执行的,首先他被编译为中间代码,然后中间代码被送入执行引擎执行,然后销毁。每个请求的中间代码在执行完之后被销毁,这样的好处在于他完全隔离了不同的请求,使内存使用率降低。但是这样的缺点也显而易见,因为他需要再重复请求一个界面的时候对一个代码连续编译两次,编译的中间代码没有一点复用性。 (1) 自动优化,也就是我们的zend optimizer提供的功能,他可以对中间代码进行优化,这些优化是语言方面的,将效率低的转化为效率高的,但他的优化目标只限定在中间代码,因此不会影响你编写的源代码。这个能提高20%左右的性能。 (2) 代码编译缓存,就是使中间代码更有复用性。因为他会把中间代码进行缓存,下次使用的时候就不需要编译了,这个有50%到300%的性能提升。 (3) 动态内容缓存,也就是把php代码执行完之后生成的内容进行缓存,这个适用于幂等的请求,而且请求不会对服务器端的数据造成修改,而只是get数据内容。这个提升效果最大,但对于个性化的界面不太适合,您可以选择使用部分缓存的方式,但明显提高了复杂度。 (4) 内容压缩:他主要是提高HTTP的传输效率,使传输量减少90%左右,但他也有牺牲,就是增加了两端(c/s)的计算量。但ZPS使用对压缩文件也进行缓存的方式来减少压缩所带来的性能影响。 有3种方法可以加快MYSQL服务器的运行速度,效率从低到高依次为: 替换有问题的硬件。对MYSQL进程的设置进行调优。对查询进行优化。 替换有问题的硬件通常是我们的第一考虑,主要原因是数据库会占用大量资源。不过这种解决方案也就仅限于此了。实际上,您通常可以让中央处理器(CPU)或磁盘速度加倍,也可以让内存增大4到8倍。 第二种方法是对 MYSQL 服务器(也称为mysqld)进行调优。对这个进程进行调优意味着适当地分配内存,并让mysqld了解将会承受何种类型的负载。加快磁盘运行速度不如减少所需的磁盘访问次数。类似地,确保 MYSQL 进程正确操作就意味着它花费在服务查询上的时间要多于花费在处理后台任务(如处理临时磁盘表或打开和关闭文件)上的时间。对mysqld 进行调优是本文的重点。 最好的方法是确保查询已经进行了优化。这意味着对表应用了适当的索引,查询是按照可以充分利用MYSQL功能的方式来编写的。尽管本文并没有包含查询调优方面的内容(很多著作中已经针对这个主题进行了探讨),不过它会配置mysqld来报告可能需要进行调优的查询。 虽然已经为这些任务指派了次序,但是仍然要注意硬件和 mysqld 的设置以利于适当地调优查询。机器速度慢也就罢了,我曾经见过速度很快的机器在运行设计良好的查询时由于负载过重而失败,因为 mysqld 被大量繁忙的工作所占用而不能服务查询。 经过了三个月的努力,我们使用Ajax、Smarty等PHP相关技术在Appserv的集成环境下,使用Aend Studio这个优秀的IDE工具在合作中完成题目为:基于PHP技术的小型企业网站开发的毕业设计。 本次设计能够顺利完成,我们首先要感谢Zend公司,是他们的努力使得PHP发展的如此之好,并且提供如Zend Studio一类的优秀PHP编辑器,MySQL和Apache开源组织,是他们免费向全球用户提供了稳定的、优秀的软件促进php的发展。 其次,我们要感谢我的指导老师冯立波,冯老师一直从开题报告、中期检查以及最后作品都有多次询问我们的研究进程,并为我们指出不足,让我们能把作品完成的更加完善。对的设计中每一个计划,每一项安排都提出了至关重要的建议,使我们节省了大量的时间,并且能不厌其烦地指导技术上的问题,使我们的系统更加完善和符合企业网站的要求。在毕业设计及毕业论文过程中,冯老师对自己的严格要求,对我们也是一样,他严谨求实的态度,踏踏实实的精神,让我在以后的工作当中能更好的知道自己该怎么去为人为事。 感谢四年来传授知识的老师们,你们细心指导才使我们能够在今年顺利毕业。 另外,我还要感谢PHPChina的那些网上的朋友,他们毫不吝啬的将自己所掌握的知识拿出来资源共享,并且热心的对我所提出的一些问题给予解答,才使我顺利完成毕业设计,谢谢他们。 再一次,我们向多方面支持和帮助过我的人表示由衷的感谢! [1] 杨长春, 王叶荟. 基于PHP的新闻发布系统[J]. 江苏工业学院学报, 2003, (04). [2] 王志明. 基于LAMP的本科毕业论文管理系统的设计[J]. 电脑知识与技术, 2008, (25). [3] 程楠. 基于PHP的医学动态信息网站设计[J]. 河南职工医学院学报, 2007,(04) . [4] 伍孝金. 基于PHP的新闻发布系统的研究与实现[J]. 计算机应用与软件, 2006,(10) . [5] 周启海, 刘云强. 基于PHP、MYSQL、Apache的人事管理系统的设计与实现[J]. 计算机时代 , 2004,(08) [6] 石志钢. 基于PHP & MySQL的企业科协网站的技术解决方案[J]. 中国科技信息, 2009,(01) [7] 赵鹤芹. 设计动态网站的最佳方案:Apache+PHP+MySQL[J]. 计算机工程与设计, 2007,(04) . [8] 宋健. 基于PHP模块引擎SmartTemplate高校图书管理系统[J]. 科技广场, 2009, (01). [9] 周明俊. 基于PHP大文件上传的研究和设计[J]. 福建电脑, 2009, (04). [10] 刘鑑澄. 基于PHP技术的动态企业网站的研究与实现[J]. 电脑开发与应用, 2009, (02). [11] 苏厚雄. 基于PHP+MySql+Ajax的分页技术方案[J]. 科技信息(学术研究), 2008, (34). [12] 张建臣. 基于PHP技术的院系图书管理系统的设计与实现[J]. 中国教育信息化, 2007,(15) . [13] 高彦卿. 基于PHP&MySQL的就业网站的设计与实现[J]. 荆门职业技术学院学报, 2007,(06) . [14] 穆荣军,. 基于Apache+MySQL+PHP的关键技术分析[J]. . 中国电化教育, 2002,(02) . [15] 谷和启 ,马丽萍. 构建网站软件组合系列讲解——用PHP+MySQL+LINUX+APACHE构建网站[J]. . 电脑编程技巧与维护, 2002,(02) . [16] 白彦峰,刘雷. 用PHP & MySQL架构图书馆网站[J]. . 情报杂志, 2004,(05) . [17] 高彦卿. 用Smarty实现基于MVC模式的Web应用程序开发[J]. 电脑知识与技术(学术交流), 2007,(14) . [18] 宋尚平,李兴保. PHP模板引擎Smarty的安装配置及应用实现[J]. 现代教育技术, 2007,(09) . [19] 李季. 基于Php+Mysql的内容管理系统设计方案[J]. 硅谷, 2009, (09). [20] 王志淋, 李艺. 中小企业Internet网站构建方案[J]. 装备指挥技术学院学报 , 2001,(06) [21] 张艳喜. 基于PHP技术的数字媒体E-Learning系统的研究与实现[D]. 广东工业大学, 2006 [22] 申建芳. 基于Xml的协同Web数据库研究与实现[D]. 广东工业大学, 2003 [23] 刘宏亮. WEB数据库的研究与应用[D]. 中国农业大学, 2000 [24] 茅文静. 山塑集团电子商务平台设计与实现[D]. 山东大学, 2005 [25] 汤朝霞. ASP技术在Web数据库开发中的应用研究[D]. 山东师范大学, 2004 [26] 胡祖奎. 基于Web数据库的集件系统[D]. 西南师范大学, 2002 [27] 韩坚华. 基于Internet/Intranet的计算机应用系统关键技术的研究与应用[D]. 广东工业大学, 2003 [28] 王吉成. 院系管理信息系统(CMIS)的开发与应用研究[D]. 西北农林科技大学, 2005 [29] 周洪雷. 基于Web的学院管理信息系统的设计与实现[D]. 吉林大学, 2006 [30] 吕昊. 基于WEB的防雷办公管理信息系统的设计[D]. 吉林大学, 2006 [31] 周寅. 基于PHP的幼儿园信息管理系统的设计与实现[D]. 苏州大学, 2005 [32] 徐燕. 基于PHP的学习信息处理系统的研究与实现[D]. 华中师范大学, 2006 [33] 刘洁. 网上书店系统的研究与设计[D]. 吉林大学, 2004 [34] 李红娟. B2B电子商务系统的研究与实现[D]. 大庆石油学院, 2004 [35] 荣秋生. 网络管理系统中数据库的设计与实现[D]. 华中师范大学, 2001 [36] 戴琰. 基于网络数据库的汽车牌照自动识别系统[D]. 浙江大学, 2002 [37] 李炜. 基于WEB的高校电子政务与办公自动化系统的设计与实现[D]. 重庆大学, 2005 [38] 杨德友. 学生综合管理信息系统研究与实现[D]. 西南交通大学, 2006 [39] 官福山. 基于网络数据库的教学/学习系统[D]. 大连海事大学, 2000 [40] 韩坚华. 基于Internet/Intranet的计算机应用系统关键技术的研究与应用[D]. 广东工业大学, 2003 [41] 叶新伟.PHP+Ajax Web2.0编程技术与项目开发大全[M].北京:电子工业出版社,2008. [42] Luke Welling, Laura Thomson. PHP和MySQL Web开发[M]. 武欣译. 北京:机械工程出版社, 2009. [43] Michael Moncur. JavaScript入门经典[M]. 王军译. 北京:人民邮电出版社, 2007. [44] Christian Heilmann. 深入浅出JavaScript[M]. 牛海彬译. 北京:人民邮电出版社, 2008. [45] W.Jason Gilmore. PHP与MySQL程序设计[M]. 朱涛江译. 北京:人民邮电出版社, 2009. [46] Andy Budd, Cameron Moll, Simon Collison. CSS Mastery Advanced Web Standards Solutions[M]. friends of ED (February 13, 2006) [47] Lynn Beighley, Michael Morrison. Head First PHP & MySQL [M]. O'Reilly Media, Inc. (December 30, 2008) [48] Timothy Boronczyk, Elizabeth Naramore, Jason Gerner, Yann Le Scouarnec, [49] Jonathan Chaffer, Karl Swedberg. jQuery基础教程[M]. 李松峰,李炜译.北京:人民邮电出版社, 2008 [50] 陈向辉. 即用即查PHP函数参考手册[M]. 北京:人民邮电出版社, 20085.2.8 图片展示
5.2.9 商品展示
5.2.10 单页分类
5.2.11 单页管理
5.2.12 文章分类
5.2.13 文章管理
5.2.14 附件管理
5.2.15 下载管理
5.2.16 招聘管理
5.3 网站前台
5.3.1 前台首页
5.3.2 企业简介
5.3.3 图片展示
5.3.4 商品展示
5.3.5 人才招聘
5.4 系统关键技术
5.4.1 smarty模板
5.4.2 ajax异步传输
第六章 系统测试
6.1 测试的定义及目的
6.2 测试的原则
6.3 测试的方法
6.3.1 界面测试
6.3.2 功能测试
6.3.3 需求测试
6.3.4 性能测试
总 结
1 总结
2 扩展
致 谢
参 考 文 献
Jeremy Stolz, Michael K. Glass. Beginning PHP6, Apache, MySQL Web Development [M]. Wrox (January 27, 2009)