零基础学编程

零基础学PHP+MySQL

郑海生　著

ISBN：978-7-111-26331-9

本书纸版由机械工业出版社于2009年出版，电子版由华章分社（北京华章图文信息有限公司）全球范围内制作与发行。

版权所有，侵权必究

客服热线：+ 86-10-68995265

客服信箱：service@bbbvip.com

官方网址：www.hzmedia.com.cn

新浪微博 @研发书局

腾讯微博 @yanfabook

目录

写给未来的程序员

学习编程需要注意的几点

丛书书目

丛书特点

完善的售后服务

前言

本书特点

本书内容

本书适合的读者

本书的作者

第一篇 PHP入门基础

第1章 初识PHP

1.1 了解PHP

1.2 PHP的地位及优势

1.3 PHP的学习和工作原理

1.4 初识PHP程序

1.5 小结

第2章 搭建PHP环境

2.1 Windows下的IIS与PHP

2.2 Windows下的Apache配置

2.3 小结

第3章 网页基础速成：静态及动态技术

3.1 认识HTML

3.2 文字与段落标记

3.3 插入图像

3.4 表格的使用

3.5 表单的使用

3.6 网页的美化CSS

3.7 JavaScript基础

3.8 小结

第4章 PHP基础

4.1 基本语法

4.2 文件引用

4.3 数据类型

4.4 基本变量

4.5 小结

第5章 运算符

5.1 算术运算

5.2 比较运算与逻辑运算

5.3 位运算

5.4 字符串运算

5.5 赋值运算

5.6 表达式

5.7 递增递减运算

5.8 掌握运算符的优先级

5.9 小结

第6章 流程控制结构

6.1 选择分支结构

6.2 循环语句

6.3 利用循环控制流程

6.4 其他流程控制语句

6.5 小结

第7章 函数和对象的基本知识

7.1 函数

7.2 一个函数的开发实例—上传文件系统

7.3 对象

7.4 一个对象的开发实例

7.5 小结

第二篇 PHP的常用函数库

第8章 PHP的常用函数库

8.1 字符串处理函数

8.2 数组处理函数

8.3 数学运算函数

8.4 日期与时间函数

8.5 目录与文件函数

8.6 PHP实践—无数据库留言板

8.7 小结

第9章 MySQL数据库

9.1 认识并安装MySQL数据库

9.2 MySQL的基本操作

9.3 MySQL数据库的数据类型

9.4 小结

第10章 MySQL简单管理及MySQL操作

10.1 进入MySQL设置管理员密码

10.2 增加用户并设置密码及用户权限

10.3 取消权限及删除用户

10.4 备份和复制数据库

10.5 MySQL数据库定义

10.6 SQL数据操作

10.7 小结

第三篇 数据库

第11章 使用phpMyAdmin管理MySQL数据库

11.1 phpMyAdmin的安装和配置

11.2 用phpMyAdmin进行MySQL权限管理

11.3 用phpMyAdmin进行数据库及表的管理

11.4 小结

第12章 PHP中使用MySQL数据库

12.1 MySQL数据库函数在PHP中的应用

12.2 用PHP进行数据查询

12.3 用PHP进行数据表的修改

12.4 PHP操作MySQL实例—学生信息管理系统

12.5 小结

第四篇 PHP的高级开发

第13章 PHP的面向对象编程

13.1 PHP中的类应用

13.2 PHP模板的应用

13.3 小结

第14章 PHP与Ajax

14.1 什么是Ajax

14.2 Ajax的实现原理和工作流程

14.3 Ajax应用

14.4 Spry框架

14.5 小结

第15章 PHP与正则表达式

15.1 了解正则表达式

15.2 正则表达式的语法

15.3 PHP中相关正则表达式的使用

15.4 常用的正则表达式

15.5 正则表达式实例

15.6 小结

第16章 PHP与XML

16.1 XML快速入门

16.2 深入XML文档

16.3 用PHP函数处理XML文档

16.4 使用DOM库处理XML文档

16.5 小结

第五篇 PHP综合实例

第17章 PHP留言板实例

17.1 数据库设计

17.2 共用页面部分

17.3 UBBCode转换为HTML

17.4 留言列表页面

17.5 发表留言程序

17.6 管理员的登录

17.7 管理员的回复程序

17.8 设计首页

17.9 小结

第18章 新闻发布系统

18.1 数据库准备

18.2 添加新闻

18.3 修改新闻

18.4 删除新闻

18.5 浏览新闻

18.6 小结

第19章 PHP论坛

19.1 数据库准备

19.2 共用显示部分

19.3 用户注册

19.4 登录页面

19.5 发表文章程序部分

19.6 文章的显示页面及文章的回复程序

19.7 文章的锁定操作

19.8 文章的置顶操作

19.9 文章的删除及修改

19.10 论坛主页面

19.11 小结

附录

附录A 正则表达式参考

A.1 普通字符

A.2 元字符

A.3 转义字符

A.4 匹配多种字符的表达式

A.5 使用符号创建匹配多种字符的表达式

A.6 用来限定匹配次数的表达式

A.7 其他说明

附录B PHP代码编写的一般规则

B.1 标识符命名规范

B.2 代码编写规范

附录C PHP下的编码

C.1 我们面对的是纷繁复杂世界

C.2 浏览器的编码和解码

光盘内容

写给未来的程序员

很多初学者对编程心生恐惧，不知道从何学起。尤其是看了别人的经验，说要先学操作系统原理、数据结构、算法等，一大堆概念涌过来，让人不知所措。其实，编程没有那么复杂，跟我们来吧，“零基础”系列正是为不会编程的你准备的！

学习编程需要注意的几点

❑不要死记语法：很多初学者试图把各种语法背下来，其实这是极其错误的，程序开发的语法、规范特别多，不可能都记得下来，你只要知道有这么一个功能就可以了，需要的时候翻阅书籍，或者查找帮助文件，这样省时省力。

❑多动手，多练习：只知道死啃书本的人，是不会成为开发高手的，只有多上机编写程序，才能在实践中提高对编程的认识。

❑遇到问题，首先尝试自己解决：自己先用一天的时间，尽力解决，实在不行再去找人帮助，千万不要遇到问题立刻找人帮忙，这样永远也不会提高。

❑多用Google、Baidu：网络是一个大知识库，是最好的老师，你遇到的问题，别人也遇到过，多去搜索一下吧。

❑多阅读别人的源代码：要看懂别人的设计思想，不断地融为己用。

丛书书目

《零基础学Ajax》

《零基础学PHP+MySQL》

《零基础学JavaScript》

《零基础学C++》

《零基础学PHP》

《零基础学HTML+CSS》

《零基础学Java》

《零基础学C#3.0》

《零基础学Java Web开发》

《零基础学Excel VBA》

《零基础学Visual C++》

《零基础学Visual Basic》

《零基础学Visual Basic+SQL Server》

《零基础学Visual C#2005》

《零基础学ASP.NET 3.5》

《零基础学SQL Server 2005》

《零基础学Dreamweaver CS3+ASP》

丛书特点

本丛书考虑了初学者的认知特点，在讲解的过程中遵循如下原则：

·从基本的环境配置讲起，告诉你如何搭建开发环境。

·细致讲解第一个例子，让你在第一个例子中学会程序开发的基本步骤。

·强调动手实践，对每个知识点都有相应的代码段，让你在操作中领会编程的真谛。

·注释极为详尽，方便读者阅读代码，理解其中的含义。

完善的售后服务

我们提供了论坛：http://www.rzchina.net，读者可以在上面提问交流，另外我们还会在论坛上定期发布一些小的教程、视频动画，以提高读者的学习效率。

最后送给各位读者一句话：“天下事有难易乎？为之，则难者亦易矣；不为，则易者亦难矣。”还等什么，现在就动手学习吧！

前言

PHP是一种目前比较流行的非客户端Web程序开发语言之一。其主要的特点是语法简单、学习容易、功能强大。对于初学者来说容易接受且容易上手。在结合了一些最新编程语言的最佳特性后，PHP、MySQL和Apache的组合已经成为Web服务器的一种配置标准。学习PHP是十分轻松、令人感觉愉悦的；开发PHP程序的过程也是比较简单、快捷的。可以说，PHP已经成为Web脚本技术的先驱，并且会继续引领Web技术的潮流。

笔者精心编写了本书，目的是帮助想要学习PHP的人员，掌握PHP程序开发的知识，尤其是为PHP新手进入PHP开发行业提供一个开发知识的阶梯。笔者结合自己多年的开发经验和团队管理经验，为广大开发人员介绍了各种领先的开发技术和开发理念，作为开发人员提高自己的技术水平、完善自己的知识结构、扩展自己的开发知识面的参考。

本书特点

本书由浅入深地讲解了PHP开发的理论和方法，以及目前流行的各种Web技术和常用的PHP开发工具。在每章的最后，笔者还给出了对读者学习本章的要求及比较重要的知识点。对初学者，笔者不但介绍了PHP的基础知识，而且介绍了PHP开发的高级阶段，使初学者可以一步到位。

本书基本涵盖了PHP开发Web程序的各个方面的知识，从开发设计到程序的开发，从开发的基本理论到程序开发的实用技术，讲述了各种常用的开发案例设计方法及开发流程，以及各种Web技术的使用方法。

本书的特点主要体现在以下几个方面。

❑本书的编排采用循序渐进的方式，适合初级、中级读者逐步掌握PHP程序开发的基本方法和程序的设计。

❑本书结合笔者的开发经验由浅入深地介绍PHP知识，在每章的最后指出了对读者学习本章的要求及比较重要的知识点。

❑本书在介绍各种Web开发方法和技术时，采用了浅显易懂的例子，在介绍PHP常用函数时使用了一个知识点配一个实例的方式，方便读者自己进行实践和演练。在本书的介绍中，提供了丰富完整的开发示例代码，读者可直接使用，或者根据自己的实际情况进行调整。本书的所有例子和源代码都附在随书光盘中，方便读者使用。

❑本书在体现基础的开发知识外，还适当地加入了目前Web开发领域的各种先进的前沿技术和理论，方便读者借鉴PHP程序开发的理念和技术。

本书内容

本书共分为五篇，共19章和3个附录，从PHP的基本概念讲起，再进一步介绍PHP程序开发过程所经历的各个阶段；然后结合目前PHP开发的各种实用技术和常用工具，讲解如何进行各种类型的程序开发；最后结合笔者的经验讲解如何养成一个良好的程序开发习惯，让开发人员的水平得以不断提高。

第一篇（第1章～第7章）PHP入门基础。

讲述了PHP的基础知识，包括初识PHP、搭建PHP环境、网页基础速成：静态及动态技术、PHP基础、常量和变量、运算符、流程控制结构、函数和对象的基本认识。

第二篇（第8章～第10章）PHP的常用函数库。

讲述了PHP常用函数知识，包括PHP的常用函数库及PHP实践程序无数据库留言板，使PHP开发人员了解PHP常用的函数库及使用方法。

第三篇（第11章～第12章）数据库。

具体讲述了MySQL数据库，包括MySQL数据库的介绍、MySQL简单管理及MySQL操作、使用phpMyAdmin对MySQL数据库进行管理、PHP中使用MySQL数据库，使PHP初学者了解MySQL数据库及对数据库的操作。本篇也介绍了如何使用PHP管理工具phpMyAdmin，更加方便初学者的学习。

第四篇（第13章～第16章）PHP的高级开发。

主要介绍PHP的高级开发阶段，包括PHP的面向对象编程、PHP与Ajax、PHP与正则表达式、PHP与XML，为PHP中级学者提供一些提高开发技术水平的知识。学习这4章内容，可以使开发人员思路清晰，更加快捷地实现程序开发。

第五篇（第17章～第19章）PHP的综合实例。

主要介绍PHP的综合实例，包括留言板、新闻发布系统、PHP论坛，为PHP学习者提供一些开发案例，方便PHP学习者进一步研究。

本书由浅入深，从理论到实践，尤其适合初级读者逐步学习及完善自己的知识结构。

本书适合的读者

❑希望学习PHP程序开发的新手。

❑迫切想要提高个人PHP程序开发技能和水平的初级人员。

❑具备一定的PHP开发理论知识，但是缺乏实践的程序开发人员。

❑希望学习PHP最新开发技术的程序员。

❑希望了解大型Web程序的开发思想和开发技巧的人员。

❑目前正在考虑在PHP程序开发中使用Ajax、XML等技术的人员。

❑Web开发入门人员。

本书的作者

本书主要由郑海生编著，其他参与编著和资料整理的人员有冯华君、刘博、刘燕、叶青、张军、张立娟、张艺、彭涛、徐磊、戎伟、朱毅、李佳、李玉涵、杨利润、杨春娇、武鹏、潘中强、王丹、王宁、王西莉、石淑珍、程彩红、邵毅、郑丹丹、郑海平、顾旭光。

编者

第一篇　PHP入门基础

第1章　初识PHP

本章将介绍PHP,PHP是一种工作在服务器端的脚本语言。它的基础语法是Perl语言，提取了C、ASP、Shell和JavaScript脚本语言的优点，是一种和ASP相似的技术。PHP是一种嵌入式脚本语言，与HTML语言结合，实现与用户的交互以及对数据库的访问。

PHP的全名是超文本预处理器（Professional Hypertext Preprocessor）。它是HTML中内嵌的脚本语言，拥有比其他脚本语言更快的执行效率。而且最吸引开发人员的一点是，它完全是免费的。PHP、MySQL（一个免费的数据库）和Apache（也是一个免费的服务器）相互配合工作，已经被大多数网站设计员所采用。

1.1　了解PHP

PHP语言是怎么出现的，它能为Web程序带来什么发展，它都包括哪些方面，这就是本节要介绍的主要内容。

1.1.1　PHP能做什么

PHP主要用在服务器端的脚本程序，它可以完成其他任何类似于ASP技术所能完成的工作，例如收集表单数据、生成动态网页等。但PHP的功能不止这些。PHP脚本语言主要用于以下3个方面。

❑服务器端的脚本语言。其是PHP最主要的方面，能够搭建PHP运行平台。读者在运行Web服务器时，通过Web浏览器来访问PHP程序的输出内容，也就是客户端的PHP页面。

❑命令行格式的脚本语言。读者可以编写一段PHP脚本程序，只需要使用PHP解析器来执行，就可以得到想要的内容。

❑编写客户端的图形界面应用程序。对基于窗口模式的应用程序，或许PHP不是最好的程序语言，但是如果读者特别精通PHP语言，而且还希望在客户端应用程序中使用PHP的一些高级特性，那么读者就可以利用PHP-GT来编写客户端应用程序。PHP程序语言具有跨平台的特性，读者也可以通过PHP-GTK编写跨平台的应用程序。PHP-GTK是PHP包中的一个扩展包，在通常发布的PHP包中并不包含此包。

PHP的功能不止上述几方面，还有其他方面。PHP也具有平台无关性，它不仅可以在Windows中使用，还可以在Linux、UNIX中使用。

PHP还有一个显著的特性，就是可以支持多种数据库。读者将会慢慢地发现PHP与大多数数据库相配合工作的网页是多么的简单。现在PHP所支持的数据库如图1.1所示。

图　1.1　数据库名表

1.1.2　PHP的发展

1994年，Rasmus Lerdorf设计出了第1个PHP，但是今天人们使用的PHP和最初的版本有很大的不同。现在PHP的最新版本是PHP 5.0。下面就是PHP从PHP 1.0到PHP 5.0的一个发展过程。

（1）最初PHP只是一套简单的Perl脚本，用来跟踪访问其主页的人们的信息。这一套脚本的名字为Personal Home Page Tools。随着更多功能需求的增加，Rasmus使用C语言写了一个更大的、可以访问数据库、可以让用户开发简单的动态Web程序。Rasmus发布了PHP/FI的源代码，以便每个人都可以使用，同时也可以让程序爱好者们修正源码中的Bug，从而改进源代码。

PHP/FI是一个专为个人主页/表单提供解释程序的程序，已经包含了今天PHP的一些基本功能。有着Perl样式的变量，自动解释表单变量，并可以嵌入HTML。语法本身与Perl很相似，但是它很有限、很简单，还稍微有些不协调。

（2）一直到1997年，PHP/FI 2.0，也就是使用C语言实现的第2版，在全世界的用户和众多域名上被安装。

PHP/FI 2.0在经历了诸多个beta版本的发布后，于1997年11月发布了官方正式版本。不久，PHP 3.0第1个alpha版本发布，PHP从此走向了成功。

（3）PHP 3.0是类似于当今PHP语法结构的第1个版本。Andi Gutmans和Zeev Suraski在为一所大学的项目中开发电子商务程序时，发现PHP/FI 2.0功能明显不足，于是Andi Gutmans和Zeev Suraski重写了代码，也就是PHP 3.0。经过Andi、Rasmus和Zeev一系列的努力，考虑到PHP/FI已存在的用户群，于是决定联合发布PHP 3.0作为PHP/FI 2.0的官方后继版本。

PHP 3.0一个最强大的功能是可扩展性。除了给最终用户提供数据库、协议和API的基础结构，PHP 3.0的可扩展性还吸引了大量的开发人员提交新的模块。后来证实，这是PHP 3.0取得巨大成功的关键。PHP 3.0中的其他关键功能包括面向对象的支持，以及更强大和协调的语法结构。

（4）1998年的冬天，PHP 3.0官方发布不久，Andi Gutmans和Zeev Suraski开始重新编写PHP代码。设计目标是增强复杂程序运行时的性能，以及PHP自身代码的模块性。PHP 3.0的新功能、广泛的第3方数据库，API的支持以及使得这样程序的编写成为可能，但是PHP 3.0没有高效处理如此复杂程序的能力。

新的被称为Zend Engine的引擎，也就是Zeev和Andi的缩写。它成功地实现了设计目标，并在1999年中期首次引入PHP。基于该引擎并结合了更多新功能的PHP 4.0，在PHP 3.0发布两年后，于2000年5月发布了官方正式版本。除了更高的性能以外，PHP 4.0还包含了其他一些关键功能，例如支持更多的Web服务器、HTTP Sessions支持、输出缓存、更安全地处理用户输入的方法以及一些新的语言结构。

（5）PHP 5.0是当前PHP的最新版本。PHP的开发小组有很多优秀的开发人员，同时还有大量的优秀人才在进行着PHP相关工程的开发工作，如PEAR和PHP文档的工程。

PHP 5.0的更多关于该引擎的信息，请访问PHP的官方网站。

1.2　PHP的地位及优势

上面介绍了PHP能做什么及PHP是如何发展的。正是因为它的优势，现在将介绍PHP在互联网中的地位及它的优势。

1.2.1　PHP所具有的优点及其在互联网中的地位

PHP之所以能有这样的发展，显然是跟它的一些优点是分不开的。下面就来看看PHP有哪些优点。

❑简单性：简单就是比较好学，容易入手。PHP借用了C、Perl、Shell及JavaScript等一些好的语法框架。对于初学者来说，很快就可以掌握。

❑速度快：PHP比传统的解释执行方式的语言速度快好几倍。

❑跨平台性：PHP可以在Windows、Linux、Unix系统下运行。将Windows下的PHP程序拿到Linux、UNIX系统下，不需要对PHP代码进行修改，就可以使用。

❑强大的数据库支持：PHP有很多可被支持的数据库，如图1.1所示。

❑PHP的开放源代码：开放源代码指的不单是PHP应用程序的源代码，而且还有PHP本身的源代码。也就是说，可以在PHP的官方网上找到PHP源代码进行编译和执行，以得到最终的运行程序，如果有必要也可以做出修改。

❑基于服务器端：也就是说PHP是运行在Web服务器端。PHP程序可能很大、很复杂，但是它的运行速度只和服务器的速度有关，发送到客户端只是程序运行的结果，对客户端的执行速度不会产生直接的影响。

❑执行的效率高：和其他的CGI语言比较，PHP语言不但占用的系统资源比较小，而且运行的速度比较快，所以它的执行效率较高。

正因为PHP具有上述这些优点，所以它在互联网中的地位很高，被非常广泛地应用。读者可以在google.cn或baidu.com中输入PHP，结果是什么样的呢？下面就以PHP在google.cn中查询为例，看看是什么结果，如图1.2所示。

图　1.2　查询PHP的结果图

由图可见全世界有多少人在使用PHP，这也足可以证明读者的选择是正确的。虽然数据并不是那么准确，但也可以表明PHP在全世界范围内应用的广泛性。

1.2.2　PHP的优势

PHP语言的优势如下。

❑良好的安全性：PHP的代码是开源，所有PHP的源代码每个人都可以看得到。代码在许多工程师手中进行了检测，同时它与Apache编辑在一起的方式也可以让它具有灵活的安全设定，因此PHP具有了公认的安全性能。

❑跨平台特性：ASP比不上PHP的跨平台能力，PHP几乎支持所有的操作系统平台及数据库系统，正是它的这种能力让UNIX和Linux有了一种与ASP媲美的开发语言，并广为流行。

❑易学性：PHP嵌入在HTML语言中，且坚持以脚本语言为主。与Java、C等语言不同，PHP语法简单、书写容易，方便学习和掌握。

❑执行速度快：占用系统资源少，代码执行速度快。

❑免费：在流行的企业应用LAMP平台中，PHP、Linux、Apache、MySQL都是免费软件，降低了企业架设成本。

❑目前互联网上众多动态网页都采用PHP语言编写。

1.3　PHP的学习和工作原理

通过上面的介绍，读者对PHP有了初步的认识。本节将介绍PHP是如何工作的，以及如何才能学好PHP。PHP工作流程的总结如下。

❑产生对PHP脚本的HTTP请求。

❑Apache将请求传递给PHP引擎。

❑PHP引擎分析扩展名为.php的脚本，并用特定的标记来启用PHP模式。

❑PHP引擎在服务器上执行脚本。

❑利用PHP扩展或PEAR数据库抽象库，来进行数据库交互或与LDAP源代码、cron作业等进行的交互。

❑处理结果。

❑将数据转换成HTML代码。

❑将响应发送至客户端浏览器进行显示。

1.3.1　PHP的工作原理

PHP是一种开放源代码的脚本语言，是主要应用于Web服务器的服务端的应用程序，用于动态网页的设计。PHP在功用上也可以替代微软的ASP、ASP.NET、VBScript、JScript体系、Sun公司的JSP、Java体系等。它是一种嵌入HTML页面的脚本语言。

PHP在Web服务器上运行。当PHP脚本被客户端请求时，被请求的PHP程序就开始运行，而且也会把运行的结果返回到客户端的浏览器。不过发送到客户端浏览器的内容只是普通的HTML文本，没有包含PHP代码。这也是与嵌入HTML的客户端脚本的最重要的区别。下面来看PHP的工作流程，如图1.3所示。

图　1.3　PHP工作流程图

1.3.2　如何学好PHP

从自己向别人问怎么学PHP开始，到现在不少人又来问笔者怎么学PHP，不管是新手，还是老手，似乎总是感觉摸不出一条清晰的脉络来。不过，笔者既然对PHP有了一定水平的理解，那么笔者总结的学习思路应该可以给初学者一个参考。

这里先把学习PHP的过程做一下概括，如下所述。

❑熟悉HTML、CSS、JS等网页基本元素，完成阶段可自行制作完整的网页，对元素属性达到熟悉程度。

❑理解动态语言的概念、运作机制，熟悉PHP语法。

❑学习如何将PHP与HTML结合起来完成简单动态页面。

❑接触MySQL，开始设计数据库程序。

❑不断巩固，摸透大部分PHP的常用函数，并理解OOP、MySQL优化以及模板的概念。

完成一个功能齐全的动态站点，是一个循序渐进的学习过程，不过新手不要看到上面的概括就以为学习蛮简单的，在此不得不对您稍微泼一下冷水，任何东西其实都不简单，所以读者在学习过程中要认真、坚持，坚持、再坚持，只有这样才能取得成功。

这里先解释一下学习思路，如下所述。

（1）在理解网站这一概念之后不难看出，任何网站都是由网页组成的，也就是说想完成网站，必须先学会做网页。因此必须要掌握了HTML，才能为今后制作网站打下基础。

（2）在学习HTML时，边学边做是最有效的方式，这一方式对于学习PHP同样是最有效的。HTML中的任何元素都要亲自实践，只有明白了什么元素会起到什么效果之后，才会记忆深刻，而一味地啃书，绝对是不行的。笔者认为大部分新手之所以觉得概念难学，大部分是因为一个字“懒”，懒是阻止进步的最大敌人，所以克服掉懒的习惯，才能更快地学好一样东西。

（3）掌握静态网页的制作技术是学习开发网站的先决条件，这一点就讲到这里。

（4）等到读者发奋努力地学会了用PHP成功地插入、删除、更新数据的时候，距离成功就指日可待了。这就是要学习MySQL数据库。

（5）接下来就是巩固知识，熟悉了PHP和MySQL开发的要领之后，再回头看之前写的那个留言本，也许会怀疑那真的是自己写的吗？当然是自己写的。这个时候，留言本应该增加一些模块，如注册、分页、数据查询等功能。完成之后，便会感觉特有成就感。

（6）学东西永远不可能有速成这一说，只有通过自己的不断努力，日积月累，知识才会慢慢地增加。在学习语法时，每个人都有各自不同的方式，但笔者认为借鉴别人成功的代码，绝对是有益无害。因此多看那些经过千锤百炼出来的经典代码，是进阶的最好方法。

1.4　初识PHP程序

在上一节中，介绍了PHP的工作原理及如何学习PHP，相信大家都有完成自己的程序的梦想。下面将介绍第1个PHP程序，及PHP与其他脚本语言的比较。

1.4.1　第1个PHP程序

通过前面的介绍，读者知道了PHP有那么多的优点，下面就看看第1个PHP程序，如代码1.1所示。

代码1.1　第1个PHP程序：1-1.php

＜html＞

＜!程序名称：1-1.html＞

＜!程序功能：输出"hello"。＞

＜head＞＜!--头部标记的开始标记--＞

＜title＞第一个PHP程序＜/title＞＜!--标题标记--＞

＜/head＞＜!--头部标记的结束标记--＞

＜body＞＜!--页面内容标记的开始标记--＞

＜?php//PHP标记

echo"hello!!!!!!!!!!!";//输出语句

?＞

＜/body＞

＜/html＞

注意　PHP每个语句是以“；”结尾，所以在"echo"末尾必须要有“；”。

作用　这个程序是一个测试程序，是大多数初学者见到的第1个PHP程序。大多数程序都会把"hello"作为第1个程序显示给初学者认识。

上面的代码必须保存成".php"为后缀名的文件。PHP的标记是以＜?php开始，以?＞结束。上面的程序在配置好PHP运行环境服务器后，在地址栏中输入http://localhost/1-1.php，就可以在浏览器中看到"hello!!!!!!!!!!!"字符串。程序运行结果如图1.4所示。

图　1.4　第1个PHP程序的运行效果图

读者也可以在浏览器中查看此程序在客户端的源文件。查看结果如代码1.2所示。

代码1.2　客户端显示程序：1-2.html

＜html＞

＜!程序名称：1-2.html＞

＜!程序功能：输出"hello"。＞

＜head＞

＜title＞第1个PHP程序＜/title＞

＜/head＞

＜body＞

＜!—

＜?PHP

echo"";

?＞

上面的代码并没有在输出的页面中出现

--＞

hello!!!!!!!!!!!

＜/body＞

＜/html＞

注意　PHP程序执行后，发给客户端的只是HTML文件，这样更加安全。

作用　笔者给出这个对比程序，是为了让初学者更好地去认识PHP，更好地掌握客户端与服务器端是如何工作的，为以后的学习打下基础。通过对比也可以知道哪些代码是在服务器端执行，哪些在客户端运行。学习好这部分内容，在以后的开发中，也可以增加程序的安全性。

从上面的例子中可以清楚地看出PHP的工作原理。PHP程序都是在服务器端解释执行，而执行的结果转化成HTML语言的格式输出到客户端。因此查看程序源文件时，PHP程序是看不到的，显示的只是PHP执行的结果。

1.4.2　PHP与ASP、JSP的比较

PHP是一种CGI语言，写CGI的方式多种多样，PHP只是其中的一种。传统的方法有C、Visual Basic，编写时虽然效率高，但是比较烦琐，不容易维护，所以现在应用的范围并不广。目前比较流行的除PHP外，还有与其类似的微软的ASP、Sun公司的JSP。JSP与Java能紧密结合，目前很多的Java程序都能非常容易地改编成JSP程序，它也有着平台无关性，相信会有越来越多的人尝试用JSP编写动态网页。在这里笔者并无意断言孰优孰劣，只是客观展示它们的性能特点。对PHP、ASP、JSP三种语言的比较如表1.1所示。

从表1.1中可以看出，ASP与平台和服务器无关性最差，只有在微软的Windows系统IIS上才能把功能完整地体现出来。PHP适用多种操作系统和几乎所有的网络服务器，JSP的平台无关性最好。

在稳定性上，PHP有良好的口碑，很多应用PHP架设的网站，长时间运作都不会出现问题。而ASP有时会使系统不稳定，需要重新启动操作系统，不过这有可能是因为有些ASP用户使用的是Windows 9x操作系统的缘故，ASP在WindowsNT/2000上的稳定性还是不错的。由于JSP推出时间较短，还没有大规模地应用，因此不太好断言。但JSP是秉承Java的，从Java的稳定性来看，JSP稳定性应该不错。

总而言之，一种语言要达到各方面性能都非常优秀，几乎是不可能的，但是PHP正处于各种性能的平衡点，完全可以满足在设计动态网页时各方面的要求。

1.5　小结

通过对本章的学习，读者可以了解到PHP有简单性、速度快、平台无关性、强大的数据库支持、开放源代码、基于服务器端、执行效率高等优点。

PHP的工作原理是当PHP脚本被客户端请求时，被请求的PHP程序就开始运行，而且会把运行的结果返回到客户端的浏览器。返回到客户端浏览器的内容只是普通的HTML文本。这样就使得程序占用空间比较少，运行速度得到保障。

第2章　搭建PHP环境

在了解了PHP众多的优秀特点后，接下来要做的是架设一个PHP运行环境，本章要介绍如何安装和设置PHP。PHP可以在IIS上运行，也可以在Apache服务器上运行。PHP也可以在不同的平台上运行，如Windows操作系统、Linux操作系统等。

在不同的平台上，安装和设置PHP是有一定差异的。鉴于多数读者所使用的环境，本章将对Windows平台下PHP的安装和设置进行详细介绍。在Windows平台下运行PHP环境，可以是IIS服务器，也可以是Apache服务器。

2.1　Windows下的IIS与PHP

Windows系统内置的Internet信息服务IIS对ASP具有良好的支持，因此在IIS中调试ASP网页是非常方便的。但有些朋友的网页采用PHP编程技术，默认情况下IIS是不支持PHP开发的，本节将介绍如何使IIS与PHP进行天衣无缝的合作。

2.1.1　IIS的安装

如果要运行PHP程序，就得有一个能执行PHP的平台。下面就介绍在Windows下的IIS上运行PHP程序。如何得到IIS？读者可以在网上下载，也可以使用Windows系统盘。在这里只介绍用系统盘在Windows 2003上安装IIS。

（1）先准备好一张Windows 2003系统盘，把它放入光驱，然后单击控制面板中的“添加/删除程序”图标，弹出图2.1所示的对话框。

图　2.1　“添加或删除程序”对话框

（2）在弹出的对话框中，单击“添加/删除Windows组件”图标，弹出图2.2所示的对话框。在组件下拉列表中选择“添加/删除程序”项，然后单击“下一步”按钮，弹出图2.3所示的对话框。现在已经开始安装了，稍等片刻会弹出图2.4所示的对话框。

注意　选中“添加/删除程序”后，也可单击“详细信息”按钮，对安装的主件进行选择。

图　2.2　“Windows组件向导”对话框

图　2.3　安装组件

图　2.4　完成组件安装

（3）单击“完成”按钮，此时IIS就安装完成了。运行代码2.1查看IIS是否安装成功。打开IE浏览器，在地址栏中输入http://localhost/2-1.html，如果成功，运行结果如图2.5所示。

图　2.5　测试页运行效果图

代码2.1　测试IIS安装是否成功程序：2-1.html

＜html＞

＜!程序名称：2-1.html＞

＜!程序功能：测试IIS安装是否成功.＞

＜head＞

＜title＞测试页面＜/title＞

＜/head＞

＜body＞

＜!—页面中的内容--＞

现在又5点了，很晚了.

＜br＞＜!—换行符--＞

想睡觉了，可是还得努力啊！

＜/body＞

＜/html＞

注意　IIS的默认端口号是“80”，不能被其他程序占用，如果被其他程序占用，IIS就无法启动。可以修改IIS端口号。

2.1.2　PHP的安装及配置

在Windows系统下安装PHP是大多数读者的选择。它相对于Linux/UNIX系统下的安装比较简单。下面具体介绍Windows下安装PHP的步骤。

（1）下载PHP 5.0 for Windows的安装程序。读者可以到http://www.php.net下载。下载完成后，双击PHP 5.0安装包，会弹出图2.6所示的对话框，单击Next按钮，弹出图2.7所示的对话框。

图　2.6　PHP 5.0安装图

图　2.7　PHP 5.0安装图

（2）在该对话框中勾选I accept the terms in the License Agreement复选框，Next按钮将变成黑色，单击该按钮，弹出图2.8所示的对话框。

图　2.8　选择安装目录对话框

（3）在该对话框中，可以通过单击Browse按钮，选择PHP 5.0的安装目录。这里按照PHP 5.0默认的目录安装，单击Next按钮，弹出图2.9所示的对话框。

图　2.9　服务器设置选项对话框

（4）这个对话框是服务器设置选项对话框，因为笔者用的是IIS，所以选择IIS ISAPI module，单击Next按钮，弹出图2.10所示的对话框。

图　2.10　选择项目设置对话框

（5）在该对话框中对项目进行设置，单击Extensions和Extras两项，在下拉列表中选择第2个选项，如图2.11所示。然后单击Next按钮，弹出图2.12所示的对话框。单击Install按钮，开始安装PHP 5.0，安装完成后弹出对话框，如图2.13所示。

图　2.11　项目设置完成图

图　2.12　PHP 5.0设置完成图

图　2.13　PHP 5.0安装完成图

（6）单击Finish按钮完成PHP 5.0的安装。接下来对PHP进行设置。打开"pnp.ini"文件，首先找到extension_dir，修改成extension_dir="C:\Program Files\PHP\ext"。然后再找到extension=msql.dll，把前面的“；”去掉。接着将php5isapi.dll和msql.dll这两个文件复制到"WINDOWS\system32\"，然后在IIS里添加".php"后缀，操作如图2.14所示。单击图2.14中所示的的“配置（G）...”按钮，弹出图2.15所示的对话框。

图　2.14　IIS中添加后缀

图　2.15　配置后缀

（7）单击图2.15中所示的“添加（D）...”按钮，弹出图2.16所示的对话框。在“可执行文件”文本框中输入"C:\Program Files\PHP\php5isapi.dll"，在“扩展名”文本框中输入".php"，然后单击“确定”按钮。重新启动IIS,PHP 5.0设置完成。下面就写个程序来测试一下，如代码2.2所示。

图　2.16　添加后缀对话框

代码2.2　测试PHP的安装是否成功程序：2-2.php

＜?php

//程序名称：2-2.php

//程序功能：测试PHP的安装是否成功.

/*只做简单的输出操作.

Php输出的标记是"echo"

*/

echo"你成功地安装了PHP！";

?＞

在地址栏中输入"http://localhost/"，运行效果如图2.17所示，这样就表明PHP 5.0安装成功了。

图　2.17　测试PHP 5.0安装是否成功

注意　安装IIS和PHP 5.0没有先后顺序。

2.1.3　下载并安装DevPHP3编辑器

程序运行需要一个平台，而代码的编写就需要一个编辑器。编辑器有很多种，如EngInSite PHP Editor、NuSphere PHPEd等，这里就不一一介绍了。下面来介绍一下DevPHP3编辑器。

（1）读者可以在网上下载这个编辑器，下载后双击该软件的安装文件，会弹出图2.18所示的对话框。

图　2.18　编辑器语言选项对话框

（2）在这个对话框中，可以选择喜欢的语言，不过这里没有简体中文。软件下载时会有一个简体中文语言文件，可以在安装之后进行设置。单击OK按钮，会弹出图2.19所示的对话框。在该对话框中直接单击"（N）"按钮，弹出图2.20所示的对话框。

图　2.19　编辑器安装对话框

图　2.20　编辑器的阅读协议对话框

（3）在该对话框中选中第1个选项，也就是同意协议书。然后单击"（N）"按钮，弹出图2.21所示的对话框。

图　2.21　选择安装路径对话框

（4）在这里可以选择适合的路径，然后单击"（I）"按钮，弹出图2.22所示的对话框。单击"（F）"按钮，这样就完成了编辑器的安装。

图　2.22　编辑器安装完成对话框

2.1.4　设置DevPHP 3编辑器

安装好DevPHP 3编辑器后，接下来学习如何设置编辑器。

（1）首先把chinese.lng文件复制到"\Dev-PHP\lang\"目录下，也就是编辑器的安装目录下的lang文件包里。然后打开编辑器，按Ctrl+N键新建一个PHP文件，如图2.23所示。

图　2.23　编辑器窗口

（2）编辑器新建PHP文件之后的窗口如图2.23所示，单击窗口中第4个菜单，弹出图2.24所示的对话框。

图　2.24　编辑器外观选项窗口

（3）在该对话框中选择从上到下的第6个选项，将会弹出设置语言的对话框，如图2.25所示。在该对话框第1栏的下拉菜单中选择Chinese选项，然后单击窗口下方有字的按钮，也就是窗口下方的第1个按钮，这样编辑器的语言设置就完成了。接下来需要设置编辑器环境，这样写好的PHP程序就可以在该编辑器中直接运行了。在编辑器中单击“外观”按钮，弹出图2.26所示的菜单项。

图　2.25　设置语言对话框

图　2.26　“外观”菜单

（4）选择“环境选项”菜单，弹出图2.27所示的对话框。选择对话框中的“编译器”选项卡，进行环境设置，如图2.28所示。

图　2.27　“环境选项”对话框

图　2.28　“编译器”选项卡

（5）在该对话框中，PHP编译器是指PHP执行文件的安装路径。笔者的安装路径为C:\PHP\php.exe。其他选项默认就可以了。现在测试一下，程序如代码2.3所示。

代码2.3　测试编辑器环境设置是否成功程序：2-3.php

＜?php

//程序名称：2-3.php

//程序功能：测试编辑器环境设置是否成功.

echo"测试成功！";

?＞

（6）执行程序，如果运行效果是乱码等，则说明设置没有成功；如果运行效果如图2.29所示，则证明编辑器的环境设置成功。

图　2.29　测试程序执行效果图

2.2　Windows下的Apache配置

Apache是什么呢？Apache就是一个应用服务器，类似微软的IIS。Apache的安装比较简单，这里不做详细介绍。需介绍的是安装完成后，怎样对Apache进行设置，才能使Apache更好地工作。

注意　在安装Apache前，机器的“80”或“8000”端口不能被占用。如果被其他程序占用，安装Apache时会报告错误。

2.2.1　使Apache识别PHP程序

怎样可以在Apache里能正常地显示简体中文？在Apache安装目录中打开配置文件httpd.conf，找到AddDefaultCharset ISO-8859-1这行，将其改为AddDefaultCharset GB2312，也就是让默认语言编码为简体中文。

为了在Apache下可以识别到PHP程序，需进行下面的设置。打开Apache的配置文件，找到AddType application/x-gzip.gz.tgz这行，如果没有如下所示的几行代码，就加入如下代码；如果有如下所示的代码，就把代码前面的“；”去掉，这样Apache就可以识别到PHP程序了。

ScriptAlias/php/"c:/php/"

AddType application/x-httpd-php.php

Action application/x-httpd-php"/php/php-cgi.exe"

怎样将Apache的默认Web目录修改成读者喜欢的浏览目录？同样也要打开Apache的配置文件httpd.conf，找到"DocumentRoot"D：/Apache2/htdocs""这行代码，将其改为读者所喜欢的Web目录，如笔者的为"DocumentRoot"D：/www""。如果读者不想修改，也可以不修改。

对于Apache的服务器配置有很多技巧，本书将在下面简要地介绍最常用的Apache的配置技巧。

2.2.2　设置请求等待时间

在Apache的安装目录下，打开conf文件夹下的httpd.conf Apache配置文件，找到TimeOut n，其中的n表示以秒为单位的整数。修改此项可以有以下方法：通过获得一个get请求的总时间；也可以通过获得一个post和put请求的TCP包间的时间差；最后是TCP包传输中响应的时间间隔。

2.2.3　修改Apache监听的端口

打开Apache的配置文件，找到Listen的选项。例如，要修改Apache监听的端口为8000，则需要修改Listen选项为"Listen 8000"，这样Apache的监听端口就为8000了。

注意　如果要同时监听给定的端口和地址，就可以修改为Listen 192.168.60.188:8000。

现在测试一下Apache服务器，程序如代码2.4所示。

代码2.4　测试Apache服务器设置是否成功程序：2-4.php

＜?php

//程序名称：2-4.php

//程序功能：测试Apache服务器设置是否成功.

echo"测试成功！";

?＞

如果运行效果如图2.30所示，说明Apache安装成功；如果没有正常显示，则需要再详细地查看配置文件，找到出现问题的原因，将其解决。

图　2.30　测试程序2-4.php的运行效果图

2.3　小结

本章学习了PHP在Windows下的环境的搭建，有IIS的安装、PHP的安装及配置、编辑器的安装并设置、Apache的安装配置。

❑在IIS里添加PHP的后缀，是为了使PHP程序在IIS中解释执行。

❑PHP的配置，是为了在运行PHP程序时，不出现MySQL等模块没有正确加载。

❑对编辑器的设置，可以使PHP程序能在编辑器中直接执行。

❑Apache的配置，是为了可以正常地执行PHP程序，以及Apache服务器如何设置等待时间和监听端口。

第3章　网页基础速成：静态及动态技术

本章要为读者介绍页面的基础知识。实现网页最基本的语言就是HTML语言。虽然现在有好多新的技术（XML等），但是网页中最常用的还是HTML语言。本章将为读者介绍如何使用样式，使网页变得更加美观。

本章还将介绍JavaScript的基础知识，以及如何使用JavaScript进行表单的检验等，这些知识涉及一些基本的网页动态操作，希望读者能好好掌握。

3.1　认识HTML

HTML是一种超文本标识语言，用来描述WWW上的超文本文件。它主要是在原来文本文件的基础上，加一系列的标识符号描述其格式，形成网络文件。当用户使用浏览器下载文件时，就把这些标识解释成它应有的含义，按照一定的格式，将这些被标识的文件显示在屏幕上。而HTML的标识符号并不显示在屏幕上。

3.1.1　HTML介绍

HyperText Markup Language的缩写是HTML，简称超文本标记语言。它是现在最常见的网页制作语言，也是网页的基础语言。不管使用哪种技术开发Web，最终反应在用户浏览器上的总是HTML代码。

❑HTML具有跨平台兼容特性。它可以在所有安装浏览器的计算机上浏览HTML文档。

❑HTML 4.0的推出，改进了语言环境、设备环境和显示环境的特性，完善了一些功能，样式支持、脚本等方面得到了提高。

❑学习HTML，主要是了解网页是如何工作的。了解HTML的基础知识，就可以灵活地制作出读者喜欢的网页效果，也可以使PHP与HTML更好地结合。

3.1.2　HTML基本标记介绍

HTML是由标记和属性构成的。标记是用于告诉浏览器怎么显示文档。属性是标记的一个选项，起到修饰作用，如高度、宽度、对齐方式和颜色等。标记的构成是由一对尖括号（＜＞）括起来的元素，尖括号之间的内容就是HTML命令。标记的格式如下：

＜html＞

标记大多数是成对出现，称为起始标记和结束标记。如＜html＞＜/html＞，但是也有少量的不是配对出现的标记。起始标记和结束标记样子很相似，唯一不同的就是结束标记有一个斜杠号。也就是在起始标记中加一个斜杠号，放在尖括号内的首部，就是结束标记。

标记的使用是，把需要标记的内容放入起始标记和结束标记之间，也就是起始标记要放在需要标记的内容前面，而结束标记要放在需要标记内容之后。下面通过一个例子来说明如何使用HTML标记，程序如代码3.1所示。

代码3.1　如何使用HTML标记程序：3-1.html

＜html＞

＜!程序名称：3-1.html＞

＜!程序功能：介绍如何使用HTML标记＞

＜head＞

＜!--＜title＞是起始标记，而＜/title＞是结束标记--＞

＜title＞标记的使用＜/title＞

＜/head＞

＜body＞

＜!—页面的正文部分--＞

＜!--＜b＞是段落的起始标记，＜/b＞是段落的结束标记--＞

＜b＞＜H1＞需要标记的内容＜H1＞＜/b＞

＜/body＞

＜/html＞

＜html＞＜/html＞是HTML标记，＜head＞＜/head＞是HTML头标记，它们之间是标题标记，即＜title＞＜/title＞，而＜body＞＜/body＞是网页主体标记。标记使用程序运行效果如图3.1所示。

图　3.1　标记使用程序运行效果

注意　输写代码时，标记要对齐，这样代码的可读性比较高。HTML语言的标记属性是不区分大小写的。

作用　在程序中使用了HTML的注释和HTML代码的对比，可以使用初学者明白在HTML中，被注释的部分是不会显示在页面中的。通过此程序，可以使初学者了解HTML基本标记的使用。

表3.1所示的是HTML的一部分标记符，还有很多的标记可以查看HTML手册。

注意　表中＜html＞＜/html＞是HTML最重要的标记。如果没有HTML文件标记，浏览器将无法识别该文件是否为网页，并会以纯文字文件处理。

＜head＞＜/head＞是网页文件头信息标记，设定网页的标题名称、指定背景音乐、作用语言等。＜title＞＜/title＞是网页的标题标记。读者常常会看到一些网站会有欢迎词，这些就是通过＜title＞＜/title＞来设定的。＜meta＞＜/meta＞是网页中的语言和其他相关设置标记。网页有自己默认的语言，通过这个标记可以设置读者喜欢的语言。接下来就把网页设置成为“简体中文”语言。格式如下。

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

上面的代码要放在＜head＞＜/head＞之间，通过这样的设置，网页可以正常地显示简体中文。下面测试代码3.2的显示情况。执行程序3-2.html，运行效果如图3.2所示。

图　3.2　网页语言设置效果图

代码3.2　在网页中显示简体中文的程序：3-2.html

＜html＞

＜!程序名称：3-2.html＞

＜!程序功能：网页显示简体中文＞

＜head＞

＜!—设置页面的编码部分--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜!—页面标题部分--＞

＜title＞网页语言设置＜/title＞

＜/head＞

＜body＞

＜!—页面的正文部分--＞

正常显示简体中文。

＜/body＞

＜/html＞

注意　如果网页不设置语言，就会使用默认语言。如果内容是简体中文，运行的结果是简体中文，部分会是乱码。

作用　通过对此程序的学习，读者可以对页面的编码进行设置，这样可以使页面采用读者自己需要的编码来显示。

＜body＞＜/body＞是网页主体标记。网页的内容如图片、文字等，要放在＜body＞＜/body＞之间，只有这样，网页的主体内容才能显示出来。＜bgsound＞是背景音乐标记。一个网站如果只有图和文字就太枯燥了，可以通过此标记给网页添加背景音乐，使网页更加活泼。

注意　＜bgsound＞标记不是成对出现的。

3.1.3　HTML基本标记演练

前面讲述了HTML的一些标记，下面通过实例来了解它们的功能，如代码3.3所示。

代码3.3　网页标记的使用程序：3-3.html

＜html＞

＜!程序名称：3-3.html＞

＜!程序功能：网页标记的使用。＞

＜head＞

＜!--

下面的代码＜meta＞是设置页面的编码方式

其中属性charset是设置页面的编码

--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜!—页面的标题部分--＞

＜title＞网页标记的使用＜/title＞

＜!—背景音乐--＞

＜bgsound src="11.midi"＞

＜/head＞

＜body＞

＜!—页面的正文部分--＞

网页使用背景音乐标记添加了背景音乐。

＜/body＞

＜/html＞

程序的运行效果如图3.3所示。

图　3.3　使用背景音乐等标记的运行效果图

作用　在网页中增加背景音乐可以使网页的内容更加丰富，让读者更好地浏览网页。

3.1.4　HTML注释符

注释用于在程序中插入描述语句时使用，而在程序执行时，不会被运行，在用户浏览时，这些描述性语句不会出现在Web页面中。它的格式如下所示。

＜!--注释内容--＞

它是以＜!--开始，以--＞结束，中间部分就是要描述的语句。下面通过一个实例来对比介绍。没有加注释的代码如代码3.4所示。

代码3.4　不加注释的程序：3-4.html

＜html＞

＜!程序名称：3-4.html＞

＜!程序功能：没有注释符的HTML文件＞

＜head＞

＜title＞无注释符＜/title＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜center＞

这是笔者喜爱的一些话！

＜br＞

生气是拿别人做错的事来惩罚自己

＜br＞

明天的希望，让我们忘了今天的痛苦

＜br＞

发光并非太阳的专利，你也可以发光

＜br＞

获得幸福的不二法则是珍视你所拥有的，遗忘你所没有的

＜br＞

你可以用爱得到全世界，你也可以用恨失去全世界

＜br＞

真正的爱，应该超越生命的长度，心灵的宽度，灵魂的深度

＜/center＞

＜/body＞

＜/html＞

程序3-4.html没有加注释符，运行效果如图3.4所示。

图　3.4　没有加注释符的运行效果图

注意　程序3-4.html中，＜br＞是换行标记，只在程序执行时运行，而不会显示在Web页面上。

没有加注释符，程序运行时会显示"body"中的所有内容，但是不包括标记。当在代码3.4中加入注释符时，运行效果如代码3.5所示。

代码3.5　有注释符的HTML程序：3-5.html

＜html＞

＜!程序名称：3-5.html＞

＜!程序功能：有注释符的HTML文件＞

＜head＞

＜!—页面的标题--＞

＜title＞有注释符＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜center＞

＜!--这是笔者喜爱的一些话！--＞

＜!—代码中的＜br＞是换行标记--＞

＜br＞

生气是拿别人做错的事来惩罚自己

＜br＞

明天的希望，让我们忘了今天的痛苦

＜br＞

发光并非太阳的专利，你也可以发光

＜br＞

＜!--获得幸福的不二法则是珍视你所拥有的，遗忘你所没有的--＞

＜br＞

＜!--你可以用爱得到全世界，你也可以用恨失去全世界--＞

＜br＞

＜!--真正的爱，应该超越生命的长度，心灵的宽度，灵魂的深度--＞

＜/center＞

＜/body＞

＜/html＞

在程序3-4.html的基础上，可将不想显示的内容加了注释。运行程序3-5.html，观看加上注释的内容是否还会显示。运行程序3-5.html的效果如图3.5所示。

图　3.5　加有注释符后的运行效果图

从图3.5可以看出，被加了注释符的内容没有显示在Web页面中。那么注释符的作用也就显而易见了。

3.2　文字与段落标记

文字也是网页的一大组成元素，对于文字的修饰，HTML语言提供了文字的标记和属性，这样会使网页看起来更加的美观与直观。

3.2.1　标题标记

标题标记，也叫标题字体。它可以分离大段文字，概括下文，所以HTML提供了6个等级的标题标记。标题标记如表3.2所示。

标题标记是从＜H1＞到＜H6＞，字体逐渐变小，即＜H1＞标记字体是最大的，而＜H6＞标记字体是最小的。下面以代码3.6为例，使读者了解标题标记的用法。

代码3.6　标题标记的使用程序：3-6.html

＜html＞

＜!程序名称：3-6.html＞

＜!程序功能：标题标记的使用＞

＜head＞

＜!—页面标题--＞

＜title＞标题标记的使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—标题标记H1的使用--＞

＜H1＞标题标记的字体逐渐变小＜/H1＞

＜!—标题标记H2的使用--＞

＜H2＞标题标记的字体逐渐变小＜/H2＞

＜!—标题标记H3的使用--＞

＜H3＞标题标记的字体逐渐变小＜/H3＞

＜!—标题标记H4的使用--＞

＜H4＞标题标记的字体逐渐变小＜/H4＞

＜!—标题标记H5的使用--＞

＜H5＞标题标记的字体逐渐变小＜/H5＞

＜!—标题标记H6的使用--＞

＜H6＞标题标记的字体逐渐变小＜/H6＞

＜/body＞

＜/html＞

程序3-6.html中，在相同的文字上使用了这6个等级的标题标记。显示效果如图3.6所示。

图　3.6　标题标记使用效果图

注意　在一行中不可以显示不同大小字体的标题，因为使用了标题标记，它会自动插入一个空行。

作用　读者通过此程序，可以了解到标题标记的几种形式。在以后的使用中，可以正确地使用这些标题标记。使页面更加美观。

从图3.6中可以看出，标题标记的字体是逐渐变小的。在程序3-6.html中可以看到，文字在网页显示中，全部是左对齐的。如果读者想让文字居中或右对齐该怎么办呢？下面表3.3罗列的是对齐方式属性表。

从表3.3可知，标题标记的属性有左对齐、居中和右对齐。现在将这些属性加入标题标记中，程序如代码3.7所示。

代码3.7　如何在标题标记中加入标题的属性程序：3-7.html

＜html＞

＜!程序名称：3-7.html＞

＜!程序功能：标题标记属性的使用＞

＜head＞

＜!—页面标题的设置--＞

＜title＞标题标记的使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—设置标题的对齐方式为左对齐--＞

＜H3 ALIGN=LEFT＞标题标记在同一行显示不同大小的字体＜/H3＞

＜!—设置标题的对齐方式为居中对齐--＞

＜H3 ALIGN=CENTER＞标题标记在同一行显示不同大小的字体＜/H3＞

＜!—设置标题的对齐方式为右对齐--＞

＜H3 ALIGN=RIGHT＞标题标记在同一行显示不同大小的字体＜/H3＞

＜/body＞

＜/html＞

在此程序中使用了标题标记及对齐方式，通过此代码，可以使页面中的内容更加直观，使页面中标题可以出现在理想的位置，并让页面更加美观、整洁。

标题标记的属性要放在标题标记的开始部分。如果读者想更好地理解标题标记的属性，可以试着把它放在标题的文字部分、标题标记的结束部分中或标题标记的结束部分，看看显示的效果。一定不会是程序3-7.html执行的运行效果图，程序3-7.html执行的运行效果如图3.7所示。

图　3.7　标题标记属性的使用效果图

注意　上面的所有标题标记的属性，在使用时必须放在标题标记的开始标记中，如＜h1 align=center＞。

3.2.2　基本文字标记及属性

基本文字的标记就是对单个文字及词组强记，如强调字的黑体、斜体、下画线等。基本文字标记符如表3.4所示。

为了使这些效果显示，必须把要强调的文字放在开始标记与结束标记之间。下边通过实例来了解基本文字标记的使用方法，程序如代码3.8所示。

代码3.8　基本文字标记的使用程序：3-8.html

＜html＞

＜!程序名称：3-8.html＞

＜!程序功能：基本文字标记＞

＜head＞

＜!—设置页面的标题--＞

＜title＞基本文字标记＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—字体的闪烁的使用--＞

＜B＞这是笔者喜爱的一些话！＜/B＞

＜!—换行符--＞

＜BR＞

＜!—设置文字为斜体--＞

＜I＞明天的希望，让我们忘了今天的痛苦＜/I＞

＜!—换行符--＞

＜BR＞

＜!—设置字体为黑体--＞

＜STRONG＞发光并非太阳的专利，你也可以发光＜/STRONG＞

＜!—换行符--＞

＜BR＞

＜!—显示为下角标--＞

n【SUB】2【/SUB】

＜!—换行符--＞

＜BR＞

＜!—显示上角标，一般为N的N次方--＞

3【SUP】n【/SUP】

＜!—换行符--＞

＜BR＞

＜!—下画线的使用--＞

＜U＞真正的爱，应该超越生命的长度，心灵的宽度，灵魂的深度＜/U＞

＜/body＞

＜/html＞

在此程序中使用的基本文字标记，可以使页面中的文字更醒目，使浏览页面的用户更快地看到网站突出的内容。使用此标记时要注意：把需要标记的文字放到标记符的中间，运行效果如图3.8所示。

图　3.8　基本文字标记使用效果图

3.2.3　基本段落标记及属性

代码3.9　段落标记的使用程序：3-9.html

＜html＞

＜!程序名称：3-9.html＞

＜!程序功能：段落标记的使用＞

＜head＞

＜!—标题部分--＞

＜title＞段落标记的使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!--这个段落是用非配对的段落标记符--＞

在前面的章节中介绍了文字的标记，当文字多的时候，就会形成段落，下面就对段落标记进行介绍。段落标记是对一整段文字进行格式化。最常用的段落标记是，适合用于一般的文本文字。段落标记是非配对的标记，就是不需要成对出现。如果读者想成对出现也可以，把段落标记的开始标记符放在段落的首部，结束标记符放在段落的尾部，这样会更加方便地阅读代码。

＜p＞

＜!--下面的段落是用配对的段落标记符--＞

＜p＞

在前面的章节中介绍了文字的标记，当文字多的时候，就会形成段落，下面就对段落标记进行介绍。段落标记是对一整段文字进行格式化。最常用的段落标记是，适合用于一般的文本文字。段落标记是非配对的标记，就是不需要成对出现。如果读者想成对出现也可以，把段落标记的开始标记符放在段落的首部，结束标记符放在段落的尾部，这样会更加方便的地读代码。

＜/p＞

＜/body＞

＜/html＞

在实例3-9.html中，第1段使用的是非配对的段落标记符，而在第2段使用的是配对的段落标记符。使用配对的段落标记符可使代码的可读性更好，运行效果却是相同的。实例3-9.html运行结束如图3.9所示。

图　3.9　段落标记符使用的实例效果图

注意　如果使用非配对的段落标记符，则必须要把段落标记符放在段落的末尾，这样才能使段落标记符的前面文字是一个段落。

段落标记符使段落与段落之间有一行空格，如果读者想在没有这一行空格的前提下，新起一行文字该怎么办呢？下面就介绍一下"BR"换行符。换行标记符可以非常方便地在要换行的地方使用。如一首诗，在一行没有结束时需要新起行，这样比较美观。下边通过代码3.10来了解换行标记的作用。

代码3.10　换行标记的作用程序：3-10.html

＜html＞

＜!程序名称：3-10.html＞

＜!程序功能：换行标记的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞换行标记的使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—设置内容显示在页面的中间--＞

＜CENTER＞

望岳

＜!—换行--＞

＜BR＞

岱宗夫如何，齐鲁青未了。造化钟神秀，阴阳割昏晓。

＜!—换行--＞

＜BR＞

荡胸生层云，决眦入归鸟。会当凌绝顶，一览众山小。

＜!—换行--＞

＜BR＞

＜/CENTER＞

＜/body＞

＜/html＞

通过上面的实例可以看到，换行符使用在结束行的后边，新起行的前面。实例3-10.html的运行效果如图3.10所示。

图　3.10　换行标记符使用效果图

3.2.4　水平线

水平线标记用来分开大段文本水平线，用以分割页面中的不同部分。水平线的标记符是＜hr＞，在网页中加入此标记符，页面中的HTML代码会自动识别标记来生成水平线。水平标记符有3个属性，分别是size、widht和noshade。这此属性的作用如下所示。

❑size：表示水平线的宽度。

❑width：表示水平线的长，用占屏幕宽度的百分比或像素值来表示。

❑noshade：表示线段无阴影属性，为实心线段。

3.3　插入图像

读者在浏览普通的文本网页时，可能会觉得比较单调。如果在普通的文本网页中加上了图像，就会觉得比较生动，信息能实现到更好的沟通。但是在HTML中加入图像有利也有弊。为什么这样说呢？因为使用生动专业水平的图像可以使站点清晰、易用，这是对网站有利的一面。而造成网站弊端的是，图像越多，下载时间越长，就形成了网站打开速度比较慢的局面。

3.3.1　图像的格式和标记

图像文件中有信息和文件的存放方式，它们是由图像格式确定的。目前Web中用得比较多的，也是浏览器最为广泛接受的两种图像格式是GIF和JPG。还有一种新的格式是PNG，它结合了GIF和JPG格式的长处，但是现在用得不太多，相信不久会普及。

GIF是Graphics Interchange Format的缩写，简称图像交换格式。所有的浏览器都认识GIF格式，也有些浏览器只认识GIF格式。GIF图像的文件扩展名为.gif。

注意　图像文件扩展名是不区分大小写的。

插入图片是为了可以使网页更加美观、更加生动。图片的标记与属性如表3.5所示。

在HTML文档中加入图像时，要用一个引用图像的标记SRC，格式如下所示：

＜IMC SRC="图像位置"ALT="没有显示图像时显示的文字"HEIGHT=图像的高度WIDTH=图像的宽度

BORDER=图像边框的象数ALIGN=图像的对齐方式＞

上面的代码中的＜IMC＞是插入图像的标记，用来实现图像的插入。而ALT=""是在网页中的图片不能显示时，替换图片的文字，这个属性可用可不用。还有SRC=""是指定图片文件的位置；HEIGHT=n指定图片的高度；WIDTH=n指定图片的宽度；BORDER=n设置图片边框的像素；‘ALIGN=""是设置图片的对齐方式。下面就通过实例来介绍如何插入图像，程序如代码3.11所示。

代码3.11　插入图片标记的使用程序：3-11.html

＜html＞

＜!程序名称：3-11.html＞

＜!程序功能：插入图片标题标记的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞插入图片＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—标题标记h1的使用--＞

＜h1＞插入图片＜/h1＞

＜!--

插入图片标记的使用

其中也可以设置图的对齐方式

还有大小等

--＞

＜IMG SRC="111.jpg"align=left ALT="不能正常显示图片"HEIGHT=150 WIDTH=330

BORDER=0＞

＜/body＞

＜/html＞

程序中的＜IMG＞是插入图片的标记，ALIGN是设置图片的对齐方式。接下来就是设置图片的高和宽等，运行效果如图3.11所示。

图　3.11　插入图片标记使用效果图

注意　ALIGN在左对齐时可以不用加，默认是左对齐。

作用　在页面中使用了插入图片的标记，可以增加页面的美观，更加有说服力。

3.3.2　图像的超链接

图片链接有两个好处：网站上有了图片，可以使网站更生动，更加有说服力；一张图可代替许多文字，使读者更加明白。这样也使网站节省了许多空间。

想要在插入的图片上加入链接，就要在插入图片开始标记的前面加入图片开始标记＜A HREF=“链接的地址”＞，在插入图片结束标记的后边插入图片链接结束标记＜/A＞。下面通过实例来介绍图片链接标记的用法，如代码3.12所示。

代码3.12　图片链接标记的使用程序：3-12.html

＜html＞

＜!程序名称：3-12.html＞

＜!程序功能：图片链接标记的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞图片链接标记使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—页面的标题--＞

＜h1＞图片链接标记使用＜/h1＞

＜!—图片链接标记的使用--＞

＜A HREF="3-10.html"＞＜IMG SRC="111.jpg"align=left ALT="不能正常显示图片"

HEIGHT=150 WIDTH=130 BORDER=0＞

＜/A＞

＜/body＞

＜/html＞

本程序使用图片链接标记，并设置了图片在不能正常显示时，在插入图片处显示替换的文字，还有对齐方式、高和宽等。程序3-12运行效果如图3.12所示。当单击图片时，页面会自动跳转到链接所指向的页面。单击图片，显示效果如图3.13所示。

图　3.12　图片链接标记使用效果图

图　3.13　单击链接图片显示效果图

3.4　表格的使用

本节主要介绍HTML中的表格。表格是由行和列组成，而行和列组成一个单元格，在表格中可以插入文本，也可以插入图片。

3.4.1　表格的创建

表格是通过在HTML中插入表格的标记来创建的，然后再通过行和列标记来设置表格的行和列。表格的标记如表3.6所示。

注意　结束标记/TR、/TD和/TH是可选项，加上结束标记可以使标记的结构更加清楚。也可以增加与旧版本的浏览器兼容性。

＜TABLE＞＜/TABLE＞标记是识别HTML中的表格标记，可以使用它来创建表格；＜TR＞＜/TR＞标记是识别HTML中表格的行标记，使用它可以创建表格中的行；＜TD＞＜/TD＞标记是识别HTML中表格行中的一个单元；＜TH＞＜/TH＞标记是识别HTML中表格的列。通过前面的介绍读者已经了解了HTML中表格的标记，下面来介绍HTML中表格标记的格式。表格标记的格式如下所示：

＜table＞

＜tr＞＞

＜th＞＜/th＞

＜th＞＜/th＞

＜/tr＞

＜tr＞

＜td＞＜/td＞

＜td＞＜/td＞

＜/tr＞

＜/table＞

在上面的格式中，在表格要出现的地方加入＜table＞标记，在表格结束时加入＜/table＞标记，也可以不加；在表格的每一行前加入标记＜tr＞标记，在表格的行结束时加入＜/tr＞标记；＜th＞标记是表格的列标记符，在表格的列结束时加入＜/th＞标记。下面通过实例来介绍表格的创建，如代码3.13所示。

代码3.13　如何创建表格程序：3-13.html

＜html＞

＜!程序名称：3-13.html＞

＜!程序功能：如何创建表格＞

＜head＞

＜!—页面的标题--＞

＜title＞表格的创建＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—表格标记的使用部分--＞

＜TABLE＞

＜TR＞

＜TD＞

＜TH＞第一行第一列＜/TH＞

＜TH＞第一行第二列＜/TH＞

＜TH＞第一行第三列＜/TH＞

＜TH＞第一行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第二行第一列＜/TH＞

＜TH＞第二行第二列＜/TH＞

＜TH＞第二行第三列＜/TH＞

＜TH＞第二行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第三行第一列＜/TH＞

＜TH＞第三行第二列＜/TH＞

＜TH＞第三行第三列＜/TH＞

＜TH＞第三行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜/TABLE＞

＜/body＞

＜/html＞

在此程序中，使用了表格标记创建表格，使用表格的行和列标记实现表格单元的创建。代码3.13的运行效果如图3.14所示。

图　3.14　表格的创建程序运行效果图

注意　如果省略结束标记，将内容放在开始标记后和下一个标记前，浏览器识别到下一个标记时，默认当前标记结束。

3.4.2　表格的属性

表格的属性就是对表格的设置，如表格的边框、对齐方式等。边框是表格项目周围的直线，用于分开行、列和单元。默认情况下，大部分浏览器显示无边框的表格，但是使用表格边框更加美观。

表格边框用一个属性和边框宽度的像素数指定。大多数浏览器将边框显示为具有三维效果的直线。表格的边框属性如表3.7所示。

❑设置表格的边框的属性是BORDER，通过给表格边框属性赋值就可以实现表格边框的设置。

❑设置表格的边框颜色的属性是BORDERCOLOR，通过给表格边框颜色属性赋值就可以实现对表格边框颜色的设置。

3.4.3　设置表格的边框

下面通过实例来介绍如何使用表格的边框属性，实现更加美观的表格，如代码3.14所示。

代码3.14　表格的边框属性使用程序：3-14.html

＜html＞

＜!程序名称：3-14.html＞

＜!程序功能：表格的边框属性使用＞

＜head＞

＜!—页面的标题--＞

＜title＞表格的边框属性使用＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—表格中属性的使用--＞

＜TABLE border=2 bordercolor="#ff0000"＞

＜TR＞

＜TD＞

＜TH＞第一行第一列＜/TH＞

＜TH＞第一行第二列＜/TH＞

＜TH＞第一行第三列＜/TH＞

＜TH＞第一行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第二行第一列＜/TH＞

＜TH＞第二行第二列＜/TH＞

＜TH＞第二行第三列＜/TH＞

＜TH＞第二行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第三行第一列＜/TH＞

＜TH＞第三行第二列＜/TH＞

＜TH＞第三行第三列＜/TH＞

＜TH＞第三行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜/TABLE＞

＜/body＞

＜/html＞

在此程序中使用了表格标记及表格的行、列标记，实现表格的创建。通过在表格标记的开始标记中加入表格边框属性的使用，来设置表格的边框及表格边框的颜色，使表格变得更加美观。代码3.14的运行效果如图3.15所示。

图　3.15　表格边框属性的使用程序运行效果图

注意　表格边框属性的设置，必须放在表格标记的开始标记中。

当然也可以使用没有边框的表格。实现无边框的表格比较简单，只要给表格边框属性赋值为0，就可以实现。

3.4.4　表格的对齐

读者可使用表格对齐方式来设置表格的位置，也可以使用表格的宽度属性设置表格的宽度。表格的对齐方式属性及表格的宽度属性如表3.8所示。

读者可以使用这些标记创建想要的表格，下面通过实例来进一步介绍表格对齐、宽度属性的使用，程序如代码3.15所示。

代码3.15　表格对齐、宽度属性的使用程序：3-15.html

＜html＞

＜!程序名称：3-15.html＞

＜!程序功能：表格对齐、宽度属性的使用程序＞

＜head＞

＜!—页面的标题--＞

＜title＞表格对齐、宽度属性的使用程序＜/title＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜meta http-equiv="Content-Language"content="zh-tw"＞

＜/head＞

＜body＞

＜!—表格中对齐及宽度属性标记的使用--＞

＜TABLE border=2 bordercolor="#ff0000"width=600 align=left＞

＜TR＞

＜TD＞

＜TH＞第一行第一列＜/TH＞

＜TH＞第一行第二列＜/TH＞

＜TH＞第一行第三列＜/TH＞

＜TH＞第一行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第二行第一列＜/TH＞

＜TH＞第二行第二列＜/TH＞

＜TH＞第二行第三列＜/TH＞

＜TH＞第二行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜TR＞

＜TD＞

＜TH＞第三行第一列＜/TH＞

＜TH＞第三行第二列＜/TH＞

＜TH＞第三行第三列＜/TH＞

＜TH＞第三行第四列＜/TH＞

＜/TD＞

＜/TR＞

＜/TABLE＞

＜/body＞

＜/html＞

此程序在创建表格时使用了表格的边框属性、表格的边框颜色属性、表格的对齐方式属性、表格的宽度属性。在此程序中设置表格的对齐方式是LEFT，所以在浏览器中，表格是靠左显示的。代码程序3.15的运行结果如图3.16所示。

图　3.16　表格对齐、宽度属性的使用程序运行效果图

从图中可以看出，表格是显示在浏览器的左边的，所以读者还可以设置表格居中、左对齐。

注意　表格的属性标记的使用要放置在表格标记的开始标记中。

3.5　表单的使用

表单是Web页面与Web站点之间双向通信的唯一途径。表单是通过网员收集数据的工具。实际上表单也可以从访问者取得信息而不必让访问者有“填表”的感觉。现在的大多数网站上都使用了表单，如Web的聊天室、选择的下拉菜单等。

3.5.1　表单的创建

表单中看见的部分，也就是访问者填写的部分；看不到的部分就是指定服务如何处理信息的部分。表单包含的部件有提交和复位按钮，用于将表单的信息发送给服务器处理或返回表单的初始设置。其他部件功能如下。

❑文本字段用来输入少量文本的区域，用于字数不多的响应。

❑选择清单用来使访问者选择一个或几个项目的清单，用于列出有限的选项的清单。

❑复选框用来让访问者选择多个项目的清单，用于列出多行选项的清单。也就是单选按钮。

❑单选按钮是让访问者选择单个项目。

❑文本区是输入大段的文本区域。

创建表单的第1步就是插入＜form＞标记并加入提交和复位按钮。提交和复位按钮是表单的重要组件，访问者要通过提交按钮与复位按钮进行信息的提交和清除选项操作。尽管要加入其他的字段后表单才真正有作用，但提交按钮是让表单发生作用的关键。基本表单标记和提交与复位按钮的用法如表3.9所示。

以上就是基本表单标记和提交与复位按钮的用法。下面通过实例来介绍基本表单标记和提交与复位按钮是如何使用的，程序如代码3.16所示。

代码3.16　表单创建程序：3-16.html

＜html＞

＜!--程序名称：3-16.html--＞

＜!--程序功能：表单创建程序.--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—页面的标题--＞

＜title＞创建表单＜/title＞

＜/head＞

＜body＞

＜!—设置页面中的表单居中显示--＞

＜center＞

＜!—表单部分--＞

＜form method="post"＞

姓名：＜input type="text"name="name"size="20"＞＜br＞

年龄：＜input type="text"name="nage"size="20"＞＜br＞

班级：＜input type="text"name="phone"size="20"＞＜br＞

地址：＜input type="text"name="address"size="20"＞＜br＞

年级：＜input type="text"name="education"size="20"＞＜br＞

E-MAIL：＜input type="text"name="email"size="20"＞＜br＞

＜!—提交按钮部分--＞

＜input type="submit"value="提交"name="b1"＞＜input type="reset"value="重写"

name="b2"＞＜br＞

＜/form＞

＜center＞

＜/body＞

＜/html＞

在上面的程序中使用表单标记创建一个表单，通过属性method来设置表单的发送方式。然后输入表格，可以通过这些表来收集信息，最后是提交按钮和复位按钮。程序的运行效果如图3.17所示。

图　3.17　表单的创建程序运行效果图

3.5.2　表单中的单选按钮

单选按钮是让用户从清单中进行单项选择。之所以叫单选按钮，是因为一次只能选择一个项目。下面通过实例来介绍单选按钮的使用方法，程序如代码3.17所示。

代码3.17　单选按钮的使用程序：3-17.html

＜html＞

＜!--程序名称：3-17.html--＞

＜!--程序功能：单选按钮的使用程序.--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—页面的标题--＞

＜title＞单选按钮的使用程序＜/title＞

＜/head＞

＜body＞

＜!—设置表单居中显示--＞

＜center＞

＜!--表单--＞

＜form method="post""＞

姓名：＜input type="text"name="name"size="20"＞＜br＞

年龄：＜input type="text"name="nage"size="20"＞＜br＞

班级：＜input type="text"name="phone"size="20"＞＜br＞

地址：＜input type="text"name="address"size="20"＞＜br＞

年级：＜input type="text"name="education"size="20"＞＜br＞

E-mail：＜input type="text"name="email"size="20"＞＜br＞

＜p＞

＜!--单选框--＞

＜b＞你喜欢的程序语言是：＜/b＞＜br＞

＜input type="radio"name="name"＞Java语言

＜input type="radio"name="name"＞PHP语言

＜input type="radio"name="name"＞C语言

＜input type="radio"name="name"＞C++语言＜br＞

＜b＞你最常用的程序语言是：＜/b＞＜br＞

＜input type="radio"name="name1"＞Java语言

＜input type="radio"name="name1"＞PHP语言

＜input type="radio"name="name1"＞C语言

＜input type="radio"name="name1"＞C++语言＜br＞

＜!--提交按钮--＞

＜input type="submit"value="提交"name="b1"＞＜input type="reset"value="重写"

name="b2"＞＜br＞

＜/form＞

＜center＞

＜/body＞

＜/html＞

该程序中使用的是单选按钮，单选按钮表示在一个项目中只能选择一个答案。该程序是一个简单的调查问卷，运行结果如图3.18所示。

图　3.18　单选按钮的使用程序运行效果图

注意　一般应该把最常用的选项设置为默认选中，使访问者的工作量减小。

3.5.3　表单中的复选框

复选框是让用户可以用复选框来选择清单中的项目，为用户提供多项选择。每个复选框都是独立工作的，访问者可以对各个复选框进行选择和取消。复选框使用户可以进行多个答案的选择。使用type=checkbox属性将输入字段设置为复选框。使用name为设置属性标注项目。对于复选框，每一个项目要使用不同的标题，因为尽管复选框看上去像是一组，但是逻辑上每个项目是相互独立的。下面就通过实例来介绍复选框的使用方法，程序如代码3.18所示。

代码3.18　复选框的使用程序：3-18.html

＜html＞

＜!--程序名称：3-18.html--＞

＜!--程序功能：复选框的使用程序.--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—页面的标题--＞

＜title＞复选框的使用程序＜/title＞

＜/head＞

＜body＞

＜!—设置表单居中显示--＞

＜center＞

＜!--表单--＞

＜form method="post""＞

姓名：＜input type="text"name="name"size="20"＞＜br＞

年龄：＜input type="text"name="nage"size="20"＞＜br＞

班级：＜input type="text"name="phone"size="20"＞＜br＞

地址：＜input type="text"name="address"size="20"＞＜br＞

年级：＜input type="text"name="education"size="20"＞＜br＞

E-mall：＜input type="text"name="email"size="20"＞＜br＞

＜p＞

＜!--复选框--＞

＜b＞你喜欢的程序语言是：＜/b＞＜br＞

＜input type="checkbox"name="name"＞Java语言

＜input type="checkbox"name="name"＞PHP语言

＜input type="checkbox"name="name"＞C语言

＜input type="checkbox"name="name"＞C++语言＜br＞

＜b＞你常用的程序语言是：＜/b＞＜br＞

＜input type="checkbox"name="name1"＞Java语言

＜input type="checkbox"name="name1"＞PHP语言

＜input type="checkbox"name="name1"＞C语言

＜input type="checkbox"name="name1"＞C++语言＜br＞

＜!--提交按钮--＞

＜input type="checkbox"value="提交"name="b1"＞＜input type="reset"value="

重写"name="b2"＞＜br＞

＜/form＞

＜center＞

＜/body＞

＜/html＞

在该程序中使用了复选框，可以使读者回答多个问题，程序运行效果如图3.19所示。

图　3.19　复选框的使用程序运行效果图

3.5.4　下拉菜单的使用

下拉菜单是表单开发中最常用、最灵活的形式，可以让访问者选择一个进行响应。下拉菜单是让访问者从清单中选择，并没有输入。表3.10是下拉菜单中选择字段的标记和属性表。

在上表中列出了下拉菜单的标记和属性，下面通过实例来介绍这些标记和属性是如何使用的，程序如代码3.19所示。

代码3.19　下拉菜单的使用程序：3-19.html

＜html＞

＜!--程序名称：3-19.html--＞

＜!--程序功能：下拉菜单的使用程序.--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—页面的标题--＞

＜title＞下拉菜单的使用程序＜/title＞

＜/head＞

＜body＞

＜center＞

＜!--表单中的复选框--＞

＜form method="post"＞

姓名：＜input type="text"name="name"size="20"＞＜br＞

生日：

＜select name="referral"＞

＜option value="print"selected＞1985.04.10

＜option value="print1"＞1986.05.11

＜option value="print2"＞1987.06.12

＜option value="print3"＞1988.07.13

＜/select＞

＜br＞

年龄：＜input type="text"name="nage"size="20"＞＜br＞

班级：＜select name="class"＞

＜option value="print"selected＞1班

＜option value="print1"＞2班

＜option value="print2"＞3班

＜option value="print3"＞4班

＜/select＞＜br＞

地址：＜input type="text"name="address"size="20"＞＜br＞

年级：＜select name="class1"＞

＜option value="print"selected＞1年级

＜option value="print1"＞2年级

＜option value="print2"＞3年级

＜option value="print3"＞4年级

＜/select＞＜br＞

E-mail：＜input type="text"name="email"size="20"＞＜br＞

＜p＞

＜!—下接菜单部分--＞

＜b＞你喜欢的程序语言是：＜/b＞＜br＞

＜input type="checkbox"name="name"＞Java语言

＜input type="checkbox"name="name"＞PHP语言

＜input type="checkbox"name="name"＞C语言

＜input type="checkbox"name="name"＞C++语言＜br＞

＜b＞你常用的程序语言是：＜/b＞＜br＞

＜input type="checkbox"name="name1"＞Java语言

＜input type="checkbox"name="name1"＞PHP语言

＜input type="checkbox"name="name1"＞C语言

＜input type="checkbox"name="name1"＞C++语言＜br＞

＜input type="submit"value="提交"name="b1"＞＜input type="reset"value="重写"

name="b2"＞＜br＞

＜/form＞

＜center＞

＜/body＞

＜/html＞

该程序使用了下拉菜单，这样可以减少访问者的工作量，免去了输入的麻烦，现在访问者可以在下拉菜单中选择理想的答案就可以了。程序的运行效果如图3.20所示。

图　3.20　下拉菜单的使用程序运行效果图

注意　在下拉菜单的标记和属性中，每个下拉菜单都要有一个名字，并且每个下拉菜单的名字不能相同。

3.6　网页的美化CSS

网页的美化就是样式单（CSS）的作用，使用样式可以增加网页的美化效果。使用样式可以控制页面元素的样子、在哪里显示、颜色和大小，用什么字体等。这样就可以由读者确定页面的样子，而不是浏览器和访问者来控制。

除了对访问者看到的文档提供更多的控制外，样式比填写格式标记的方法能更好地管理HTML文档。将这些标记放在样式中时，文档会更加整洁。样式还可以减少开发和维护HTML文档所用的时间。与手工格式化的文本相比，读者可以只修改样式中的模式定义，这个定义就会作用在HTML文档的各个地方。

样式还提供了Web站点中文档间的灵活性。可以建立适用于站点中所有页面的样式，也可以建立单个样式作用于某个HTML文档，这个具体样式能覆盖全局模式。另外，还可以进一步调整各个样式以适应特殊的文本样式。下面就来介绍样式的标记及其属性，样式的标记及其属性如表3.11所示。

表3.11所示的是样式的标记和属性，可以通过使用这些标记和属性来创建样式。下面通过一个实例来介绍如何使用这些标记和属性，程序如代码3.20所示。

代码3.20　样式的使用程序：3-20.html

＜html＞

＜!--程序名称：3-20.html--＞

＜!--程序功能：样式的使用程序.--＞

＜head＞

＜!—页面的标题--＞

＜title＞样式的使用程序＜/title＞

＜!—样式部分--＞

＜style＞

＜!--

＜div＞

{width:200;filter blur(add=true,direction=135,strengh=20);

}--＞

＜/style＞

＜/head＞

＜body＞

＜!—使用样式部分--＞

＜div＞

＜p style="font-size:48;font-style:bold;

color:red;"＞PHP程序＜/p＞

＜/div＞

＜/body＞

＜/html＞

上面的这一段代码产生的效果如图3.21所示。而其中字体的模糊效果就是运用了CSS的滤镜功能。滤镜功能是CSS非常有趣、也非常吸引人的一个功能。

图　3.21　样式的使用程序运行效果图

注意　样式也可以是单独的文件，在使用时引入此样式表就可以了，引入样式的标记是@import url()。

3.7　JavaScript基础

JavaScript语言的前身叫Livescript。自从Sun公司推出著名的Java语言之后，Netscape公司引进了Sun公司有关Java的程序概念，将自己原有的Livescript重新设计，并改名为JavaScript。

3.7.1　JavaScript的特点

JavaScript是一种基于对象和事件驱动、并具有安全性能的脚本语言，有了JavaScript，可使网页变得生动。使用它的目的是与HTML超文本标识语言、Java脚本语言一起实现在一个网页中链接多个对象，与网络客户交互作用，从而可以开发客户端的应用程序。它是通过嵌入或调入在标准的HTML语言中实现的。JavaScript具有很多优点，如下所示。

1.简单性

JavaScript是一种脚本编写语言，它采用小程序段的方式实现编程。像其他脚本语言一样，JavaScript同样也是一种解释性语言，提供了一个简易的开发过程。它的基本结构形式与C、C++、VB、Delphi十分类似。但它不像这些语言一样需要先编译，而是在程序运行过程中被逐行地解释。它与HTML标识结合在一起，从而方便用户的使用操作。

2.动态性

JavaScript是动态的，它可以直接对用户或客户输入做出响应，无须经过Web服务程序。它对用户的反映响应，是采用事件驱动的方式进行的。所谓事件驱动，就是指在主页中执行了某种操作所产生的动作，就称为“事件”，如按下鼠标、移动窗口、选择菜单等都可以视为事件。当事件发生后，可能会引起相应的事件响应。

3.跨平台性

JavaScript依赖于浏览器本身，与操作环境无关，只要能运行浏览器的计算机，并支持JavaScript的浏览器就可以正确执行。

4.节省CGI的交互时间

随着WWW的迅速发展，有些WWW服务器提供的服务要与浏览者进行交流，以确认浏览者的身份、需服务的内容等，这项工作通常由CGI/PERL编写相应的接口程序与用户进行交互来完成。很显然，通过网络与用户的交互，一方面增大了网络的通信量，另一方面影响了服务器的服务性能。服务器为一个用户运行一个CGI时，需要一个进程为它服务，它要占用服务器的资源（如CPU服务、内存耗费等）。如果用户填表出现错误，交互服务占用的时间就会相应增加。被访问的热点主机与用户交互越多，服务器的性能影响就越大。

JavaScript是一种基于客户端浏览器的语言，用户在浏览中填表、验证的交互过程，只是通过浏览器对调入HTML文档中的JavaScript源代码进行解释执行来完成的。即使是必须调用CGI的部分，浏览器也只将用户输入验证后的信息提交给远程的服务器，大大减少了服务器的资源。

3.7.2　JavaScript可以做什么

用JavaScript可以做许多事情，使网页更具交互性，给站点的用户提供更好、更令人兴奋的体验。JavaScript使读者可以创建活跃的用户界面，当用户在页面间导航时向用户提供信息的反馈。例如，读者可能在一些站点上见过在鼠标指针停留时突出显示的按钮，这是用JavaScript实现的，使用了一种称为翻转器（rollover）的技术。

可以使用JavaScript确保用户在表单中输入有效的信息，这样可以节省用户的时间和开支。如果表单需要进行计算，那么可以在用户机器上的JavaScript中完成，而不需要任何服务器端处理。读者应该知道一种区分程序的方式：在用户机器上运行的程序称为客户端（client-side）程序，在服务器上运行的程序称为服务器端（server-side）程序。

可以使用JavaScript根据用户的操作即时创建定制的HTML页面。假设用户正在运行一个旅行指南站点，当单击夏威夷作为旅游目的地时，可以在一个新窗口中显示最新的夏威夷旅游指南。JavaScript可以控制浏览器，所以可以打开新窗口、显示警告框以及在浏览器窗口的状态栏中显示定制的消息。JavaScript有一套日期和时间特性，可以生成时钟、日历和时间戳文档。

JavaScript还可以处理表单、设置cookie、即时构建HTML页面，以及创建基于Web的应用程序。

3.7.3　网页中的JavaScript实例—图像动态浮动

在大多数的网站上，读者可以看到有一张张的广告图在页面中浮动，这样可以减少空间不足。下面就来介绍如何让图像动态地浮动，示例程序如代码3.21所示。

代码3.21　图像动态浮动的程序：3-21.html

＜html＞

＜!--程序名称：3-22.html--＞

＜!--程序功能：浮动图像显示.--＞

＜head＞

＜!—页面的标题--＞

＜title＞浮动图像显示＜/title＞

＜SCRIPT language=javascript＞

//定义浏览器检查变量

var navigator_ok=false;

//取得游览器的版本号第1个字母并转换为数字

var version_No=parseInt(navigator.appVersion.substring(0,1));

//取得浏览器的名称

var aname=navigator.appName;

//检查浏览器是否为IE 4.0以上的版本

function check_navigate(){

if(aname.indexOf("Internet Explorer")!=-1){

if(version_No＞=4)

navigator_ok=navigator.javaEnabled();

}

}

var delta_min=2;//定义移动增量的最小值

var delta_max=5;//定义移动增量的最大值

var delta_direction=2;//定义产生X、Y增量.随机调整大小幅度的变量

//定义一个记录浮动图像的对象。

function floater_obj(origin_x,origin_y,my_width,my_height){

this.delta_x=0;

this.delta_y=0;

this.width=my_width;

this.height=my_height;

this.x=origin_x;

this.y=origin_y;

}

//定义使图像产生浮动效果的执行函数

function floater_move(){

if(navigator_ok){

//取得文档在窗口内的X和Y方向的偏移量

pageX=window.document.body.scrollLeft;

pageY=window.document.body.scrollTop;

//取得当前窗口的宽度和高度的数值

pageW=window.document.body.offsetWidth;

pageH=window.document.body.offsetHeight;

//累计X、Y的增量值

floater.x+=floater.delta_x;

floater.y+=floater.delta_y;

//使X、Y的增量值随机地增加或减少

floater.delta_x+=delta_direction*(Math.random()-0.5);

floater.delta_y+=delta_direction*(Math.random()-0.5);

//限制X、Y的边界正、负增量值不超过最大限制

if(floater.delta_x＞(delta_max+delta_min))

floater.delta_x=(delta_max+delta_min)*2-floater.delta_x;

if(floater.delta_x＜(-delta_max-delta_min))

floater.delta_x=(-delta_max-delta_min)*2-floater.delta_x;

if(floater.delta_y＞(delta_max+delta_min))

floater.delta_y=(delta_max+delta_min)*2-floater.delta_y;

if(floater.delta_y＜(-delta_max-delta_min))

floater.delta_y=(-delta_max-delta_min)*2-floater.delta_y;

//如果移动到窗口的左边界，则产生一个正的增量值，使其向右移动

if(floater.x＜=pageX){

floater.x=pageX;

floater.delta_x=delta_min+delta_max*Math.random();

}

//如果移动到窗口的右边界，则产生一个负的增量值，使其向左移动

if(floater.x＞=pageX+pageW-floater.width){

floater.x=pageX+pageW-floater.width;

floater.delta_x=-delta_min-delta_max*Math.random();

}

//如果移动到窗口的上边界，则产生一个正的增量值，使其向下移动

if(floater.y＜=pageY){

floater.y=pageY;

floater.delta_y=delta_min+delta_max*Math.random();

}

//如果移动到窗口的下边界，则产生一个负的增量值，使其向上移动

if(floater.y＞=pageY+pageH-floater.height){

floater.y=pageY+pageH-floater.height;

floater.delta_y=-delta_min-delta_max*Math.random();

}

//使用计算完成的X、Y坐标值给定图像的移动位置

document.all.my_picture.style.pixelLeft=floater.x;

document.all.my_picture.style.pixelTop=floater.y;

}

}

//定义一个用于产生对象实例的全局变量

var floater;

//初始化函数(在＜body onload="ini()"＞中调用)

function ini(){

check_navigate();//调用检查浏览器函数

//如果浏览器符合要求，则执行图像的移动功能

if(navigator_ok){

//----------------------------------------------------------------

//生成一个记录移动位置的"对象实例"

//对象参数顺序为：对象在页面上出现的初始x坐标、y坐标，对象的宽度、高度

//----x、y坐标定义方法如下

//左上角定义为：(0,0)

//右上角定义为：(800,0)

//左下角定义为：(0,600)

//右下角定义为：(800,600)

//---------------------------------------

//如果被显示的图像为80X80的尺寸

//定义对象宽度为：80+20=100(考虑窗口水平滚动条宽度)

//定义对象高度为：80+20=100(考虑窗口垂直滚动条宽度)

//------------------------------------------------------------------

floater=new floater_obj(800,0,100,100);

window.setInterval("floater_move()",100);//定时执行图像移动函数(现为：100毫秒)

}

}

＜/SCRIPT＞

＜/head＞

＜body bgcolor="#FFFFFF"onload="ini()"＞

＜!—使用CSS样式--＞

＜div id=my_picture style="HEIGHT：88px;POSITION：absolute;WIDTH：80px;left：

185px;top：73px;z-index：10"＞＜a

href="http://www.sino8848.com"target=_blank＞＜img border=0 src="111.jpg"＞＜/a＞

＜/div＞

＜/body＞

＜/html＞

该程序是一个图像浮动显示效果页面，在此程序中，JavaScript是放在＜head＞与＜/head＞之间。首先通过定义浏览器检查变量，取得浏览器的版本号第1个字母并将其转换为数字，再获取浏览器的名称，然后定义移动增量的最小值与最大值。

通过定义使图像产生浮动效果的执行函数，执行图像的浮动。如果移动到窗口的左边界，则产生一个正的增量值，使其向右移动；如果移动到窗口的右边界，则产生一个负的增量值，使其向左移动；如果移动到窗口的上边界，则产生一个正的增量值，使其向下移动；如果移动到窗口的下边界，则产生一个负的增量值，使其向上移动。程序的运行效果如图3.22所示。

图　3.22　浮动图像显示程序的运行效果图

注意　此程序的JavaScript脚本语句是放在＜head＞…＜/head＞之间的。

3.7.4　使用JavaScript进行表单检验

表单的检验是使用JavaScript脚本语言，对表单进行检验。不管是动态网站，还是其他B/S结构的系统，都离不开表单，表单作为客户端向服务器提交数据的载体担当着相当重要的角色。这就引出了一个问题，提交的数据合法吗？摆在读者面前的问题就是验证这些数据，保证所提交的数据是合法的，所以需要写一个验证函数。下面通过一个实例来介绍如何实现表单的验证，程序如代码3.22所示。

代码3.22　表单非法关键词验证程序：3-22.html

＜!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞

＜html xmlns="http://www.w3.org/1999/xhtml"＞

＜!--程序名称：3-23.html--＞

＜!--程序功能：表单非法关键词验证.--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"/＞

＜!—页面的标题--＞

＜title＞表单非法关键词验证＜/title＞

＜/head＞

＜body＞

＜!--验证表单部分--＞

＜div id="key"＞＜/div＞

＜form action="http://bbs.blueidea.com/thread-2781039-1-16.html"method="

post"name="form1"target="_blank"id="form1"style="text-align:center;"

onsubmit="return check()"＞

＜textarea name="userText"cols="50"rows="15"id="userText"＞＜/textarea＞

＜br/＞

＜input type="submit"name="Submit"value="提交"/＞

＜/form＞

＜div id="info"align="center"＞＜/div＞

＜script type="text/javascript"＞

var keyStr="藏独|窃听||垃圾|人渣|女性";//你可以在这里增加限制关键词，词之间用英文半角"|"

function check(){

var rs_value=document.form1.userText.value;

if(rs_value==""){

alert("请录入待检测的内容！");

document.form1.userText.focus();

return false;

}

var keyArray=keyStr.split("|");

var re;

for(i=0;i＜keyArray.length;i++){

re=new RegExp(keyArray[i],"g");

if(re.exec(rs_value)!=null){

alert("含有非法关键词！");

document.form1.userText.focus();

return false;

}

}

}

window.onload=function(){

document.getElementById("key").innerHTML="＜strong＞现有非法关键字集:＜/strong＞"+keyStr;

}

＜/script＞

＜/body＞

＜/html＞

此程序使用JavaScript脚本语言验证用户输入的数据是否合法。如果合法，则提交到处理页面；如果不合法，会弹出警告框。程序运行效果如图3.23所示。在此页面中，如果用户输入上面的非法关键字，如藏独、窃听、垃圾、人渣、女性等，就会弹出警告框，提示用户输入的是非法的关键字。输入非法关键字后，单击提交按钮会弹出警告框如图3.24所示。

图　3.23　表单非法关键词验证程序运行效果图

图　3.24　警告框图

3.8　小结

本章首先介绍了网页中基础的HTML语言。主要内容如下。

❑HTML的介绍。

❑HTML标记和注释符。

❑文字与段落标记。

❑插入图像。

❑表格和表单的使用。

在本章中还介绍了网页的美化样式CSS，通过对页面的设置，使外观更加夺目。另外，本章还介绍了JavaScript基础知识，主要如下。

❑JavaScript可以做什么。

❑网页中JavaScript实例—图像动态浮动。

❑JavaScript进行表单检验。

相信读者在学习了本章的内容后会收获不小。通过本章的学习，读者应掌握HTML的使用、样式的使用、使用JavaScript进行表单检验等知识。

第4章　PHP基础

PHP与HTML类似，也提供一些封装好的标记。而且PHP是一门语言，具备语言的一些基本语法，这都是读者前期需要了解的知识。本章的重点如下。

❑PHP的标记有哪些，标记是如何使用的。

❑怎么样把文件引用在PHP的程序中，引用文件标记是如何使用的。

❑PHP数据类型有哪些。

❑PHP的变量。

本章主要介绍PHP的基本语法，还有如何引入已有的文件和PHP的数据类型。只有了解了PHP基本语法，才能在以后的使用中更加得心应手。

4.1　基本语法

PHP的语法和C语言的语法相似，但也有所不同。PHP的代码是嵌入到HTML代码中的，就是可以和HTML代码混合，但是要使用PHP开始和结束标记来表示PHP代码，这样编缉器才可以识别到PHP代码。下面介绍PHP的基本语法。

4.1.1　PHP的标记

PHP标记是指PHP的标识符号，也可这样理解，PHP的标记与控制解释程序行为的HTML标记相似。下面介绍这些标记是如何配合语言使用的。PHP的开始标记与结束标记分别是＜?php，?＞。在PHP程序执行时，编辑器将会寻找这种标识符，以便运行其内部的代码。PHP的基本标记语法如下所示：

＜?php

PHP程序.

?＞

这是PHP的默认标记符，它用来标识PHP代码的开始和结束。接下来通过一个实例来介绍PHP的基本标记。示例程序如代码4.1所示。

代码4.1　PHP基本标记符的使用程序：4-1.php

＜?php

//程序名称：4-1.php

//程序功能：PHP的基本标记符的使用程序

echo"欢迎使用PHP！";

?＞

该程序使用开始标记和结束标记，在开始标记和结束标记之间是要执行的代码。代码4.1的运行效果如图4.1所示。

注意　在PHP高版本中，PHP基本标记可以写成＜??＞。

图　4.1　PHP基本标记使用效果图

PHP的标记也可以写成脚本形式，它的格式如下所示：

＜script language="php"＞

代码

＜/script＞

此程序是使用脚本语言来实现的，通过代码4.2可以进一步地了解。

代码4.2　PHP嵌套的使用程序：4-2.php

＜html＞

＜!程序名称：4-2.php＞

＜!程序功能：PHP嵌套的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞＜/title＞

＜/head＞

＜body＞

＜!—设置页面使用的脚本语言--＞

＜script language="php"＞

echo"欢迎光临PHP！";

＜/script＞

＜/body＞

＜/html＞

如果以前接触过或者写过脚本程序，对于这样的表示方法就比较熟悉了。这样的表示方法与JavaScript脚本程序嵌入网页中类似，用标识符＜script language="php"＞来声明使用脚本语言的类型是PHP，用标识符＜/script＞来说明程序完成。程序的运行效果如图4.2所示。

图　4.2　PHP嵌套的使用效果图

4.1.2　PHP的注释符

现代的软件程序，程序的注释是必不可少的。如果程序没有注释，在维护时，是非常困难的，因为程序的可读性比较差，所以程序员要养成对程序做注释的习惯。这对程序员来说是比较重要的。PHP注释有单行注释和多行注释，注释符如表4.1所示。

下面对PHP注释符的使用进行举例，示例程序如代码4.3所示。

代码4.3　PHP注释符的使用程序：4-3.php

＜?php

//程序名称：4-3.php

//程序功能：PHP注释符的使用程序

//PHP单行注释符的使用

echo"PHP单行注释符！\n";

/*PHP

多行注释符

的使用！

*/

echo"PHP多行注释符！"\n;

?＞

在此程序中，注释符“//”为单行注释，当程序中的说明文字只需要注释一行时，在这行的首部加上这个标记就可以。注释符“/*注释部分*/”为多行注释，当程序中的说明文字需要注释多行时，把要注释的文字加在这个标记之间就可以。程序的运行效果如图4.3所示。

图　4.3　注释符使用程序运行效果图

注意　使用多行注释时，注释不能包含嵌套的注释，否则会引起错误。

4.2　文件引用

PHP的特点之一是引用文件，这也是PHP最吸引程序员的特色之一。用此方法可以把常用的功能写成函数，放在文件中，引用后就可以调用函数了。

4.2.1　在PHP程序最前面的引用文件的方法

在PHP程序最前面的引用文件的方法是require，这个方法的使用如下所示：

require("MyRequireFile.php");

PHP程序在执行前，先读入require所指定引入的文件，使其变成PHP程序的一部分。常用的函数也可以使用这种方法将其引入网页中。下面通过实例来进一步了解该方法，程序如代码4.4所示。

代码4.4　引入文件方法的使用：4-4.php

＜?php

//程序名称：4-4.php

//程序功能：引入文件方法的使用

require("aa.txt");//引入文件方法的使用

echo"引入文件方法的使用.";

?＞

此程序使用require方法，将"aa.txt"文件引用到PHP程序中，使其成为PHP程序的一部分。程序的运行效果如图4.4所示。

图　4.4　引入文件方法的使用程序运行效果图

注意　引入的文件不止是PHP文件，也可以是文本文件。

4.2.2　在流程控制片段中引用文件的方法

在流程控制片段中引用文件的方法是include，这个方法的使用方法如下所示：

include("引入的内容")

此函数一般放在流程控制的处理区段中。PHP程序在读取到include时，才将引入的文件读进来，这种方法可以把程序执行时的流程简单化。在流程控制片段中引用文件的方法代码如代码4.5所示。

代码4.5　引入文件方法的使用程序：4-5.php

＜?php

//程序名称：4-5.php

//程序功能：引入文件方法的使用

$a=5;

if($a＞2)//使用条件来判断引用文件

include("aa.txt");//引入文件方法的使用

else

include("bb.txt");//引入文件方法的使用

?＞

此程序用了条件判断，若条件成立，将引入"aa.txt"文件，否则引入"bb.txt"文件。程序的执行效果如图4.5所示。

图　4.5　引入文件方法的使用程序运行效果图

4.3　数据类型

对于计算机语言来说，数据类型是所有编程语言所共有的，PHP也一样。PHP的数据类型有：整数型、浮点型、字符串型。

4.3.1　整数型

整数型（integer），在32位的系统中，整数型的有效范围是-2147483648～+2147483647。整数常指没有小数的自然数，包括正数、负数和零。下面的实例是介绍整数型的使用，如代码4.6所示。

代码4.6　整数型数据的使用程序如：4-6.php

＜html＞

＜!程序名称：4-6.php＞

＜!程序功能：整数型数据的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞数据类型＜/title＞

＜/head＞

＜body＞

＜?php

$a=10000;

//给变量a设定一个值

echo$a;

//把变量的值在网页中显示出来

?＞

＜/body＞

＜/html＞

该程序是给变量设定一个值，然后把设定的值输出到网页上。程序运行结果如图4.6所示。

图　4.6　整数型数据的使用效果图

4.3.2　浮点型

浮点型就是"double"。在32位系统中，浮点型的有效范围是1.7E-308～1.7E+308。浮点数有的时候也称实数，是指有小数点的数据。浮点型与整数型的区别就是小数点的数据是否存在，即使小数点后面为0，也是浮点数。下面通过一个实例来介绍浮点型数据的使用，程序如代码4.7所示。

代码4.7　浮点型数据的使用程序如：4-7.php

＜html＞

＜!程序名称：4-7.php＞

＜!程序功能：浮点型数据的使用＞

＜head＞

＜!—页面的标题--＞

＜title＞数据类型＜/title＞

＜/head＞

＜body＞

＜?php

$a=0.32;

//给变量a设定一个值

echo"a=";

echo$a;

echo"＜br＞";

//把变量的值在网页中显示出来

$b=-0.32;

//给变量b设定一个值

echo"b=";

echo$b;

//把变量的值在网页中显示出来

?＞

＜/body＞

＜/html＞

此程序是给变量设定值，然后在把值输出到网页上，通过换行标记，使变量b的值在新的一行输出。程序运行效果如图4.7所示。

图　4.7　浮点型数据的使用效果图

注意　如果数据的小数点后面为0，也是浮点数。

4.3.3　字符串型

字符串型就是String，无论数据是单个字符还是多个字符的字符串，都属于字符串型。这就是与C语言的区别，在C语言中没有字符串型，只有字符型。字符串被理解成字符数组。PHP的字符串型不仅利于理解，还可以达到简化类型的目的。下面为字符串的使用实例，程序如代码4.8所示。

代码4.8　字符串的使用程序如：4-8.php

＜html＞

＜!程序名称：4-8.php＞

＜!程序功能：字符串的使用＞

＜head＞

＜title＞数据类型＜/title＞

＜/head＞

＜body＞

＜?php

//设定变量a是单引号字符串

$a="abcdefghi＜br＞";

//设定变量b是双引号字符串

$b='abcdefghi';

echo$a;

echo$b;

?＞

＜/body＞

＜/html＞

此程序使用了单引号字符串和双引号字符串。两者的使用方法很相似，但是彼此也有很大的区别。单引号字符串非常容易理解，只需要使用单引号把想要使用的文本括起来就可以了，例如下面的代码所示：

'单引号字符串的格式。'

如果在单引号中再使用单引号时，会变得有些复杂。怎么使用呢？解决的方法就是使用反斜杠“\”。反斜杠字符也称是转义字符，其作用就是告诉系统，它后面的单引号按一般的字符输出，其格式如下所示：

'php\'a book is highly enjoyable.\''

而双引号字符串类似于单引号字符串，但是双引号字符串更加复杂一点。双引号字符串不仅仅可以使用反斜杠在字符串中加入转移序列和转换字符，还可以使用变量替换。其格式如下所示：

"My name is See."

"See said,\"Gifts are great.\""

注意　其中的反斜杠用来改变双引号的功能。在双引号字符串中可以使用单引号。双引号字符串和单引号字符串的一个不同之处是，双引号字符串可以在字符串中加入特殊的转义序列。转义字符及其作用如表4.2所示。

4.4　基本变量

每一种编程语言都有自己的数据结构的定义和使用方法，PHP也一样，也有常量和变量。常量又分为常数和内置常量。常数是指常用的一些特定的数字。变量分为全局变量和局部变量。变量也有它的作用域，变量的作用域取决于它出现在什么位置。下面就为读者介绍PHP中的基本变量。

4.4.1　什么是常量

常量用来存储固定数据信息。由于系统不分配内存，所以只能被赋值一次。也有一些常量是PHP固有的，还有的可以用define函数生成。为了使这些常量与变量有所区别，在PHP中用大写字母命名常数。但这并不是语法规定的，只是为了使程序员养成良好的编程习惯。

常量是一个简单的标识符。在执行期间常量的值不能改变，常量标识符总是大写的。常量和其他的PHP标记遵循同样的命名规则。合法的常量名以字母或下划线开始，后边跟有任何字母、数字及下划线。正规的表达式如下所示：

A-Z_1-n

注意　在这里，字母是A～Z，以及从127～255的ASCII字符。

常量的范围是全局的，不用管作用域就可以在程序的任何地方访问常量。常量的定义可以用define()函数来定义。一个常量如果被定义，就不能改变，也不可以取消定义。

常量只能包含标量数据（如boolean,integer,float和srting）。可以简单地通过指定其名字来取得常量的值，不可以在常量前面加“$”符号。如果常量是动态的，可以用函数constant()来读取常量的值，也可以用get_defined_constants()来获取所有定义的常量列表。下面是一个定义常量的实例，程序如代码4.9所示。

代码4.9　常量的定义程序：4-9.php

＜html＞

＜!程序名称：4-9.php＞

＜!程序功能：常量的定义＞

＜head＞

＜!—页面的标题--＞

＜title＞常量的定义＜/title＞

＜/head＞

＜body＞

＜?php

define("MY_CONSTANT","定义常量是字符串");//定义常量MY_CONSTANT为字符串

define("C_2",99.9);//定义常量C_2为双精度数

echo"MY_CONSTANT:";//在浏览器上输出常量MY_CONSTANT的值

echo MY_CONSTANT;

echo"＜br＞";//换行

echo"C_2:";//在浏览器中输出常量C_2的值

echo C_2;

echo"＜br＞";

?＞

＜/body＞

＜/html＞

此程序使用define()函数，通过函数获取常量的值，然后把常量的值输出在网页中。常量是区分大小写的，这一点要注意，在获取常量时，不能把常量的大小写混淆了。程序的运行效果如图4.8所示。

图　4.8　常量的定义程序运行效果图

4.4.2　PHP自带常量有哪些

PHP向它的运行程序中提供了大量的内置常量，不过很多常量都是由不同的扩展库定义的，只有在加载了这些扩展库时才能出现，也可以是在动态加载后，还可以是在编译时已经包括在内的。这些特殊的常量是不区分大小写的，如表4.3所示。

❑内置常量"_LINE_"：这个内置常量是PHP脚本的行数。如果引用文件，则在引用文件内的该常量为被引用文件的行，而不是引用文件的文件的行。

❑内置常量"_FILE_"：这个内置常量是PHP脚本程序的名称。如果引用了文件，则在引用文件内的该常量为被引用的文件名，而不是引用这个文件的文件名。

❑内置常量"_FUNCTION_"：表示函数名称（PHP 4.3.0新加）。自PHP 5.0起，本常量返回该函数被定义时的名字（区分大小写）。在PHP 4.0中该值总是小写字母的。

❑内置常量"_CLASS_"：表示类的名称（PHP 4.3.0新加）。自PHP 5.0起，本常量返回该类被定义时的名字（区分大小写）。在PHP 4.0中该值总是小写字母的。

❑内置常量"_METHOD_"：表示类的方法名（PHP 4.0.0新加）。返回该方法被定义时的名字（区分大小写）。

4.4.3　什么是变量

PHP的变量是用一个美元符号（$）后面跟变量名来表示。变量是区分大小写的。变量名与PHP中其他的标记一样遵循相同的规则。一个有效的变量名由字母或下画线开头，后面跟任何数量的字母、数字及下画线。合法的变量名与不合法的变量名对比如表4.4所示。

注意　PHP的变量是区分大小写的。

4.4.4　变量的赋值

在PHP中，使用一个变量前不需要声明，这与其他语言不同。在C语言中，要求每一个变量与其类型一起声明，这是因为要事先分配好相应的内存。由于PHP不是编译语言，而是解释语言，所以没有以上的问题。在使用变量时，PHP可以根据所赋的数值类型来确定变量的类型。

等号用来给变量赋值。赋值的方法为，等号左边是待赋值的变量，右边是所要赋的值。最简单的赋值形式是利用常量表达式。常量表达式就是数字或由引号括起来的字符串。变量赋值的格式如下所示：

$a="This a text！"

等号左边的表达式，可以是简单的字符中常量，也可以是运算符、变量及常量的组合。下面通过实例介绍变量的赋值，如代码4.10所示。

代码4.10　变量的赋值程序：4-10.php

＜html＞

＜!程序名称：4-10.php＞

＜!程序功能：变量的赋值＞

＜head＞

＜!—页面的标题--＞

＜title＞变量的赋值＜/title＞

＜/head＞

＜body＞

＜?php

define("MY_CONSTANT",1);//定义常量MY_CONSTANT为1

//***************************************

//整数型

//***************************************

$a=1;

$b=1+1;

$c=$b+MY_CONSTANT;

echo"整数型：＜br＞";

echo"\$a=";

echo$a;

echo"＜br＞";

echo"\$b=";

echo$b;

echo"＜br＞";

echo"\$c=";

echo$c;

echo"＜br＞";

//**********************************

//浮点型

//**********************************

$d=0.1;

$e=0.1+0.1;

$f=$e+MY_CONSTANT;

echo"浮点型：＜br＞";

echo"\$d=";

echo$d;

echo"＜br＞";

echo"\$e=";

echo$e;

echo"＜br＞";

echo"\$f=";

echo$f;

echo"＜br＞";

//******************************

//字符型

//******************************

$a2="text";

$b2="text"."_text";

$c2=$b2+MY_CONSTANT;

echo"字符型：＜br＞";

echo"\$a2=";

echo$a2;

echo"＜br＞";

echo"\$b2=";

echo$b2;

echo"＜br＞";

echo"\$c2=";

echo$c2;

echo"＜br＞";

?＞

＜/body＞

＜/html＞

此程序是给变量赋值，然后通过变量的运算，把最后的结果输出到网页中。在程序中的输出语句中有“\”，它是为了说明程序在执行到这个标记时，标记后边的变量按字符串处理。程序的运行效果如图4.9所示。

图　4.9　变量的赋值程序运行效果图

从上面的例子中，可以看到整型、字符型与浮点型变量的各种赋值形式。如果等号两边的类型不同，则系统以右边的为准。如果出现的不是类型数据相加，则按如下规定变型。

依照优先权变型：浮点型＞整数型＞字符型。就是当整型与浮点型相加时，结果为浮点型；当字符型与整型相加时，结果为整型，字符部分被自动去掉。

4.4.5　变量的作用域

部分语言有全局变量与局部变量，PHP也存在相同的处理方法。

变量的作用域由第1次使用它的位置决定，即变量在何处是可见的。读者所定义的每个函数都有自己的变量空间。也就是说有些变量只对某函数有意义，在程序的其他地方，这些变量都是不可见的，这就是局部变量。

全局变量是在所有的函数之外创建的。在有些编程语言中全局变量在函数的内部是可见的。而在PHP中创建一个函数时，必须明确告诉PHP读者在该函数中要用某个全局变量。在PHP中，全局变量的有效范围限于主程序中，不会影响到函数中的同名的变量，即全局变量与局部变量相互不侵犯。如果使全局变量能通透到函数中，就要用到"global"命令。下面是一个使用全局变量的实例，程序如代码4.11所示。

代码4.11　全局变量的使用程序：4-11.php

＜html＞

＜!程序名称：4-11.php＞

＜!程序功能：全局变量的使用＞

＜head＞

＜title＞全局变量的使用＜/title＞

＜/head＞

＜body＞

＜?php

/*此处声明变量

表示变量为全局变量*/

$a1=1;

function a()

{

echo"未使用global命令：";

echo$a1;//此处变量为函数的内部变量

echo"＜br＞";

}

function b()

{

global$a1;//此处声明变量为全局变量

echo"使用global命令：";

echo$a1;

echo"＜br＞";

}

function c()

{

global$a2;//此处声明变量为全局变量

$a2=2;

}

echo"在函数体外：";

echo$a1;

echo"＜br＞";

/*函数部分

下面是函数的调用*/

a();

b();

c();

echo"在函数外使用函数体内的变量：";

echo$a2;

echo"＜br＞";

?＞

＜/body＞

＜/html＞

此程序使用了全局变量和局部变量，在函数外声明的变量为全局变量。可以使用global命令在函数体外使用函数体内的变量。程序的运行效果如图4.10所示。

图　4.10　全局变量的使用程序运行效果图

注意　全局变量与局部变量的区别就在于它的使用范围。

4.5　小结

在本章中首先学习了PHP的基本的语法，有PHP的标记、PHP嵌入方法、PHP的注释符。又学习了文件是如何引用的，分为两种：一种是在PHP程序最前面的引用文件；另一种是在流程控制片段中引用文件。最后介绍了PHP的数据类型，如整数型、浮点型、字符串型。

本章最后介绍了PHP的常量和变量。常量是用来存储固定数据信息的，由于系统不分配内存，所示只能被赋值一次。PHP的变量用一个美元符号（$）后面跟变量名来表示，变量是区分大小写的。赋值就是用等号给变量赋值，赋值的方法为，等号左边是待赋值的变量，右边是所要赋的值。变量是有作用域的，分为全局变量和局部变量。通过以上内容的学习，相信读者能够掌握常量和变量的基本知识及简单用法。

第5章　运算符

本章将介绍运算符，运算符就是用一些符号进行运算，使用PHP对其进行操作。运算符包括算术运算符、逻辑运算符、关系运算符、赋值运算符、字符运算符等。本章还将介绍位运算、递增递减运算、运算符的优先级、比较运算与逻辑运算。

运算符是一个表达式存在的基础，而一段程序又由多个表达式组成，表达式的组成缺少不了运算符。所以掌握本章的内容，学会如何组件一段良好的代码非常关键。

5.1　算术运算

提起算术运算，读者就会想起加、减、乘、除，这些都是数学运算的基础，任何一种编程语言都会有这些运算符。在PHP中，算术运算一般是针对整型或双精度型的变量或数值。如果在字符串中使用算术运算符，则先要把字符变成数字，这样会出现不可想象的结果。

5.1.1　PHP中的常见算术运算符

表5.1所示的就是PHP中的算术运算符。这些运算符遍布程序的每个角落，是最常用的运算符之一。它们的名称与我们小学时学习的一些算术符号相同，所以被称为算术运算符。

5.1.2　PHP算术运算符的使用

代码5.1　PHP算术运算符的使用程序：5-1.php

＜html＞

＜!程序名称：5-1.php＞

＜!程序功能：PHP算术运算符的使用＞

＜head＞

＜title＞PHP算术运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=3+5;//加法运算

$b=18-10;//减法运算

$c=3*6;//乘法运算

$d=18/3;//可以整除的运算

$e=10/3;//不可以整除的运算

$a1=8%7;//整数的求模运算

/*双精度型的求模运算

并把运算的结束输出到页面中*/

$a2=0.8%0.7;

echo"加法运算：3+5=";//加法运算的结果

echo$a;

echo"＜br＞";

echo"减法运算：18-10=";//减法运算的结果

echo$b;

echo"＜br＞";

echo"乘法运算：3*6=";//乘法运算的结果

echo$c;

echo"＜br＞";

echo"整数相除：18/3=";//整数相除的运算结果

echo$d;

echo"＜br＞";

echo"不能整除的运算：10/3=";//不能整除的运算结果

echo$e;

echo"＜br＞";

echo"整数的求模：8%7=";//求模运算的结果

echo$a1;

echo"＜br＞";

echo"双精度的求模：0.8%0.7=";//双精度求模的运算结果

echo$a2;

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序使用了加法运算、减法运算、乘法运算、除法运算以及求模运算。除法运算在不可以整除时，结果会是双精度型。而求模运算在两边均是双精度时，结果为0或空。程序的运行效果如图5.1所示。

图　5.1　PHP算术运算符的使用效果图

注意　求模运算在两边均是双精度时，结果为0或空。除法运算在不可以整除时，结果会是双精度型。

5.2　比较运算与逻辑运算

关系运算是逻辑运算中比较简单的一种，关系运算实际上就是比较运算，用于将两个值进行比较，以判断比较的结果是否符合条件。

5.2.1　PHP的关系运算符

PHP的关系运算符如表5.2所示。关系运算主要用来比较大小。要注意在程序中有些不是通过数字来比较大小的，如字符串也可以比较、对象也可以比较。

该表是关系运算符，主要用于判断语句。例如，一个变量$a＞3，这是一个关系表达式，大于号是一个关系运算符，如果变量$a的值为5，则满足给定的条件，返回的值为true；如果变量的值为2，则不能满足条件，返回的值为false。

5.2.2　关系运算符的应用

前面小节了解了PHP中都有哪些关系运算，下面通过一个实例来介绍关系运算符的使用，程序如代码5.2所示。

代码5.2　PHP关系运算符的使用程序：5-2.php

＜html＞

＜!程序名称：5-2.php＞

＜!程序功能：PHP关系运算符的使用＞

＜head＞

＜title＞PHP关系运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=3;//设置变量a等于3

$b=4;//设置变量b等于4

echo"\$a=$a＜br＞";//输出变量$a

echo"\$b=$b＜br＞";//输出变量$b

echo"比较的结果:＜br＞";

if($a＞$b)//条件变量a大于变量b

{

echo"(\$a＞\$b)即($(a)＞$(b))为真！";

echo"＜br＞";

}

else

{

echo"(\$a＞\$b)即($(a)＞$(b))为假";

echo"＜br＞";

}

?＞

＜/body＞

＜/html＞

此程序通过设置变量a和b，然后通过条件"$a＞$b"来判断，如果条件满足，就会输出“($a＞$b)即($(a)＞$(b))为真！”；如果没有满足条件，就会输出“($a＞$b)即($(a)＞$(b))为假”。程序的运行结果如图5.2所示。

图　5.2　PHP关系运算符的使用程序运行效果图

5.2.3　PHP的逻辑运算

逻辑运算符可以用于控制程序，通常用在if或while语句中，需要根据不同的条件来决定应该执行什么语句。每一个逻辑表达式都会得出一个真值或者假值。对于PHP提供的逻辑运算符如表5.3所示。

逻辑与（＆＆和and）是用于确定前后两个操作数是否都为真。如果为真，结果就为真；如果其中一个为假，最后的结果也就为假；如果两个操作数全为假，那么结果也为假。逻辑与的值的判断如表5.4所示。

与逻辑与相反的是逻辑或。逻辑或是如果操作数全为真时，结果也为真；如果其中有一个值为真，结果也为真。只有在两个操作数都为假时，结果才会为假。逻辑或的值的判断如表5.5所示。

逻辑与和逻辑或是双条件间断，用于确定最终的结果是真还是假，而逻辑非是只有一个条件来判断，如果值为真，结果就会为假；反之，当值为假时，结果却是真。逻辑非值的判断如表5.6所示。

5.3　位运算

位运算符是所有运算符中比较难的一种，使用时读者必需要先理解二进制。位运算符与逻辑运算符相似，但是逻辑运算符是在true和false的基础上进行运算的。对于逻辑运算符“1”和“10”都会被认为是真，而对于位运算符则是两个不同的数字。

5.3.1　PHP提供的位运算符

PHP提供的位运算符如表5.7所示。其中“位”后面的运算名称与逻辑运算比较相似，如“位与”、“位或”等。

5.3.2　演示位运算符的应用

位运算符是把操作数转换为二进制数进行的运算。下面通过一个实例来介绍位运算符，程序如代码5.3所示。

代码5.3　位运算符的使用程序：5-3.php

＜html＞

＜!程序名称：5-3.php＞

＜!程序功能：PHP位运算符的使用＞

＜head＞

＜title＞PHP位运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=3;//此处变量a等于3，如果逻辑运算值为真，则位运算就等于二进制数11

$b=6;//设置变量b等于6

$c=($a＆＆$b);//进行逻辑运算

$d=($a＆$b);//进行位运算

echo"\$a=$a";//在浏览器上输出a的值

echo"＜br＞";

echo"\$b=$b";//在浏览器上输出b的值

echo"＜br＞";

echo"变量a和b的逻辑与运算:\$a＆＆\$b=$c";//在浏览器上输出$a＆＆$b的值

echo"＜br＞";

echo"量a和b的位与运算:\$a＆\$b=$d";//在浏览器上输出$a＆$b的值

?＞

＜/body＞

＜/html＞

此程序是先设置了两个变量a和b，并给变量赋值。然后让变量a和b进行逻辑与运算，把运算的结果给变量c，并把运算结果输出到浏览器中。程序中变量d的值是通过变量a和b进行位与运算的结果，并被输出到浏览器中。程序5-3.php的运行结果如图5.3所示。

图　5.3　位运算符的使用程序运行效果图

5.3.3　轻松学习移位运算

PHP的移位运算是将一个数转换成二进制码，然后进行移位。左移位运算是把二进制码的每一位左移，移位补0；右移位运算是把二进制码的每一位右移，低位去掉。下面通过一个实例来介绍移位运算符的使用，程序如代码5.4所示。

代码5.4　PHP移位运算符的使用程序：5-4.php

＜html＞

＜!程序名称：5-4.php＞

＜!程序功能：PHP移位运算符的使用＞

＜head＞

＜title＞移PHP位运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=15;//此处变量a等于15，二进制码为1111

$b=$a＜＜3;//这里将变量左移3位

$c=$a＞＞3;//这里将变量右移3位

echo"输出原值:$a";//在浏览器上输出a的值

echo"＜br＞";

echo"二进制码为:".decbin($a);//在浏览器上输出二进制码

echo"＜br＞";

echo"左移三位:$b";//在浏览器上输出左移两位的值

echo"＜br＞";

echo"二进制码:".decbin($b);//在浏览器上输出b二进制码

echo"＜br＞";

echo"右移三位:$c";

?＞

＜/body＞

＜/html＞

注意　位运算中的移运算是将一个数转换成二进制码，左移位运算是把二进制码的每一位左移，移位补0；右移位运算是把二进制码的每一位右移，低位去掉。

此程序是把变量的值转换成二进制码，然后进行移位运算，并把最终的结果输出到浏览器中，程序的运行效果如图5.4所示。

图　5.4　PHP移位运算符的使用程序运行效果图

5.4　字符串运算

字符的运算比较简单，它的运算符只有一个，就是英文状态下的句号，也是字符串的连接运算符。它可以将字符串连接起来，合并成一个新的字符串。在处理特别是字符串变量时，会常用到这个运算符。下面就通过一个实例来介绍字符串运算符的使用，程序如代码5.5所示。

代码5.5　字符串运算符的使用程序：5-5.php

＜html＞

＜!程序名称：5-5.php＞

＜!程序功能：字符串运算符的使用。＞

＜head＞

＜title＞字符串运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a="abcd";//此处变量a等于字符串"abcd"

$b="efghl";//此处变量b等于字符串"efghl"

$c=$a.$b;

$d="$a"."不等于"."$b";

echo"输出原值:$a";//在浏览器上输出a的值

echo"＜br＞";

echo"输出原值:$b";//在浏览器上输出b

echo"＜br＞";

echo"\$c=$c";//在浏览器上输出c的值

echo"＜br＞";

echo"\$d=$d";//在浏览器上输出d

echo"＜br＞";

?＞

＜/body＞

＜/html＞

此程序是给变量设定值，然后通过字符串连接符把变量连接起来，并把结果赋给变量c。最后把计算结果输出到网页上。程序的运行效果如图5.5所示。

图　5.5　字符串运算符的使用程序运行效果图

注意　字符串连接符是英文状态下的句号，而不是在中文下的句号。

5.5　赋值运算

赋值运算符就是将符号右边的值或表达式赋给左边。基本的赋值运算符是“=”。这并不是读者认为的等于号，在PHP中的意思是把“=”右边的值赋左边。PHP还有其他的赋值运算符，如将等号右边的值加到左边的运算符“+=”、把等号右边的值减到左边的运算符“-=”、将等号左边的值乘以右边的运算符“*=”、把左边的值除以右边的运算符“/=”、将左边的值对右边取余数的运算符“%=”和把右边的字符串加到左边的运算符“.=”等。下面就通过一个实例来介绍赋值运算符的用法，程序如代码5.6所示。

代码5.6　运算符赋值的使用程序：5-6.php

＜html＞

＜!程序名称：5-6.php＞

＜!程序功能：运算符赋值的使用＞

＜head＞

＜title＞运算符赋值的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=5;//设置变量

echo"\$a=$a";//输出变量

echo"＜br＞";//换行

$c=$a+2;

$a+=2;//即$a=$a+2

$b="哇";

$b.="哈";//$b="哇哈";

$b.="哈";//$b="哇哈哈"

$d=4;

echo"\$d=$d";

echo"＜br＞";

$f=$d*2;

$d*=2;

$e=8;

echo"\$e=$e";

echo"＜br＞";

$g=$e/2;

$e/=2;

//******************************************

//输出上面变量的各种运算结果

//********************************************

echo"\$a+=$a";

echo"＜br＞";

echo"\$a+2=$c";

echo"＜br＞";

echo"\$b.=$b";

echo"＜br＞";

echo"\$d*2=$f";

echo"＜br＞";

echo"\$d*=$d";

echo"＜br＞";

echo"\$e/2=$g";

echo"＜br＞";

echo"\$e/=$e";

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序是通过运算符的对比形式来介绍赋值运算符，例如此程序中"$a=$a+2"与“$+=2”的结果是一样的。程序的运行效果如图5.6所示。

图　5.6　赋值运算符的使用程序的运行效果图

5.6　表达式

表达式是数据、变量、常量和运算符的组合。它的执行顺序一般是从左到右，也有从右到左的表达式，如使用等号“=”运算符的表达式。在一个表达式中通常会有多个运算符，这样读者就必须要了解运算符的运算等级。当不同的数据类型的数据混在一起运算时，读者必须了解数据类型是如何自动转换的。

在使用表达式进行运算时，要注意以下两点。

❑有些运算符只能使用某些类型数据，超出了范围将会造成错误或不可想象的结果。

❑如果运算中同时有整型和双精度型数据，则整型数据将被转换为双精度型数据。

许多运算符都用数字工作。如果试图加入数据，则整型数据将被转换成数字。字符串的内容决定了它将被转换成整型还是双精度型，PHP将把字符串转换成数字。下面就通过一个实例来介绍PHP中的表达式运算符，程序如代码5.7所示。

代码5.7　表达式的使用程序：5-7.php

＜html＞

＜!程序名称：5-7.php＞

＜!程序功能：表达式的使用＞

＜head＞

＜title＞表达式的使用＜/title＞

＜/head＞

＜body＞

＜?php

echo 1+"1";//输出数字与字符串的运算结果

echo"＜br＞";//换行

echo 1+"2";

echo"＜br＞";

echo 1+"3extra stuff";

echo"＜br＞";

echo 1+"4.5e6";//数字与进制数的运算

echo"＜br＞";

echo 1+"a7";

echo"＜br＞";

echo"1"+"a7";

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序是输出数字和字符串，程序的运行效果如图5.7所示。

图　5.7　表达式的使用程序的运行效果图

注意　当PHP输出字符串时，会把字符串转换成数字形式输出。它会去除开始的空白，并消去数字字符串后的所有字符。当PHP不能确定一个合理的数值时，会把字符串当作零。

5.7　递增递减运算

PHP中的自增、自减运算符“++”、“--”来自于C语言，它们的用法基本相同，惟一的区别就是PHP中自增、自减运算符除了可使用于数值类型外，还可以用于字符串。“++”和“--”不但可以用在变量前，也可以用在变量后，如"++$a"和"--$a"。使用在不同的位置会有不同的效果。

5.7.1　递增运算

PHP的递增运算有两种形式，如"++$a"和"$a++"。如果是"$a++"，表示程序中先使用了变量a的值，然后再执行递增运算，变量的值就会加1；如果是"++$a"，表示先执行变量递增运算，然后使用变量递增后的值在程序中运行。下面就通过一个实例来介绍递增运算的使用，程序如代码5.8所示。

代码5.8　递增运算符的使用程序：5-8.php

＜html＞

＜!程序名称：5-8.php＞

＜!程序功能：递增运算符的使用＞

＜head＞

＜title＞递增运算符的使用＜/title＞

＜/head＞

＜body＞

＜?php

$a=1;//设置变量

echo"\$a=$a";//输出变量

echo"＜br＞";//换行

$b=$a++;//递增运算

echo"\$a++=$b";//输出递增运算结果

echo"＜br＞";

echo"\$a++后的值:$a";

echo"＜br＞";

$c=++$a;//加法运算

echo"++\$a=$c";

?＞

＜/body＞

＜/html＞

该程序先设置了变量$a的值为1，然后通过先使用变量a的值，然后执行递增运算，变量的值就会加1。再通过先执行变量递增运算，然后使用变量递增后的值在程序中运行。运行效果如图5.8所示。

注意　两种递增的区别为，"$a++"是在程序中先使用了变量a的值，然后再执行递增运算，变量的值就会加1；“++$a”是会先执行变量递增运算，然后使用变量递增后的值在程序中运行。

图　5.8　递增运算符的使用程序运行效果图

5.7.2　递减运算

PHP的递减运算也有两种形式，如"--$a"和"$a--"。如果是"$a--"，就是在程序中先使用了变量a的值，然后执行递减运算，变量的值就会减1；如果是"--$a"，就会先执行变量递减运算，然后使用变量递增后的值在程序中运行。下面就通过一个实例来介绍递减运算符，如代码5.9所示。

代码5.9　递减运算符的使用程序：5-9.php

＜html＞

＜!程序名称：5-9.php＞

＜!程序功能：递减运算符的使用＞

＜head＞

＜title＞递减运算符的使用＜/title＞

＜/head＞

＜body＞＜?php

$a=10;//设置变量

$d=88;

echo"\$a=$a";//输出变量

echo"＜br＞";//换行

echo"\$d=$d";

echo"＜br＞";

$b=$a--;//递减运算

echo"\$a--=$b";

echo"＜br＞";

echo"\$a--后的值:$a";//输出递减运算结果

echo"＜br＞";

$c=--$d;

echo"--\$d=$c";

?＞

＜/body＞

＜/html＞

该程序首先设置了变量$a的值为1，和变量$d的值为88，通过先使用变量a的值，然后执行递减运算，变量的值就会减1。然后变量d通过先执行变量递减运算，最后把变量递减后的值在程序中运行。程序运行效果如图5.9所示。

图　5.9　递减运算符的使用程序运行效果图

5.8　掌握运算符的优先级

对于含有多种运算符的表达式来说，它的执行顺序不一定是从左到右，主要是依据运算符的执行等级。这样有利于程序表达式与一般的数学表达式相一致。

5.8.1　运算符的优先级列表

运算符的优先级如表5.8所示。该表是PHP运算符的优先级表，其中优先级相同的运算符按从左到右地顺序执行运算。表中从上到下的级别顺序是由高到低。

5.8.2　演示PHP运算符的优先级

下面就通过一个实例来介绍PHP运算符的优先级，程序如代码5.10所示。该程序除了从左到右的顺序外，运算符还有特定的优先级，如乘法运算符优先于加法运算符，也说明了括号的优先级高于乘法的优先级。

代码5.10　运算符的优先级程序5-10.php

＜html＞

＜!程序名称：5-10.php＞

＜!程序功能：PHP运算符的优先级＞

＜head＞

＜title＞PHP运算符的优先级＜/title＞

＜/head＞

＜body＞＜?php

/*PHP的运算符的优先级

乘、除＞加、减*/

echo"3+2*5=";

echo 3+2*5;//先乘后加

echo"＜br＞";//换行

echo"(3+2)*5=";

echo(3+2)*5;//先加后乘，因为有括号

echo"＜br＞";

?＞

＜/body＞

＜/html＞

注意　对于含有多种运算符的表达式来说，它的执行顺序不一定是从左到右，主要是依据运算符的执行等级。

5.9　小结

本章介绍了PHP的运算符，这些是PHP的编程基础，也是构成PHP脚本的基本元素。运算符包括算术运算符、逻辑运算符、关系运算符、赋值运算符、字符运算符等。本章还为读者介绍了位运算、递增递减运算、运算符的优先级、比较运算与逻辑运算。最后部分介绍了PHP的表达式、运算符的优先级。相信通过本章的学习，读者可以掌握运算符的使用方法。感兴趣的读者，也可以自己动手做一个计算器小实例，实践本章的学习情况。

第6章　流程控制结构

控制语句可以使指定的代码段在某种条件下执行，也可以使指定的代码重复使用，这样可以使脚本的流程更加简化，使脚本的流程更加有效。

由于PHP的大部分语法是承袭C语言的语法，所以在流程控制方面，也就有着与C语言非常类似的语句。PHP的流程控制语句可与ASP不同，ASP可以使用goto语句。而PHP就不可以，因为PHP是结构化的程序语言，在流程的设计上有一定的规定。

6.1　选择分支结构

PHP中具有真和假的概念，也就是true和false。false和0等价，其他数值就是true。真和假主要是用在控制语句中。如，if控制语句需要根据布尔表达式的值true或false来判断，所以给出的所有值都会被转换成true或false。if语句有3种形式，分别为if格式、if...else格式、if...elseif...else格式。

6.1.1　if格式

if格式只用到了if条件进行简单地判断。可以理解为“若学习PHP则就要做点东西出来”。也就是“如果发生了什么事，就得怎么样去解决”，其流程如图6.1所示。

图　6.1　if结构流程图

该图是简单的选择if结构流程图。程序运行到if结构时，进行条件判断，如果布尔类型值为true就会运行条件下边的语句；如果布尔类型值为假，则会跳出循环。if结构语法的格式如下：

if(条件语句)//括号中是条件部分

{

//循环中将要执行的代码部分

}

其中括号中的部分为条件部分，也就是“发生了什么事”。大括号里边为循环中将要执行的代码部分，就是条件符合后才去执行的部分。循环中将要执行的代码部分只有一行时，可以省去大括号。省去大括号的程序如代码6.1所示。

代码6.1　省去大括号程序：6-1.php

＜?php

//程序名称：6-1.php

//程序功能：循环中将要执行的代码部分只有一行时，可以省去大括号

$d=1;//给变量d进行赋值

If($d=1)//对变量进行判断

echo"星期天，可以去玩了";//条件符合就执行下面的代码

?＞

上面的程序是通过把1赋给变量d，然后"if"对变量进行判断。如果变量等于1，那么将输出“星期天，可以去玩了”；如果变量不等于1，那程序就不再向下执行。程序的运行结果如图6.2所示。

图　6.2　运行效果

注意　因为循环中将要执行的代码部分只有一行时，可以省去大括号。不过要是读者不怕麻烦，也可以加上，看看程序的运行结果。

下面的例子是循环中将要执行的代码部分有两行的，大括号就不可以省去了。程序如代码6.2所示。

代码6.2　大括号必须得加的程序：6-2.php

＜?php

//程序名称：6-2.php

//程序功能：循环中将要执行的代码部分有两行的，大括号不可以省去

$d=1;//给变量d进行赋值

if($d=1)//对变量进行判断

{

//条件符合就执行下面的代码

echo"星期天，上午去看书！\n";

echo"星期天，下午去吃饭！";

}

?＞

该程序的运行过程与代码6.1类似，唯一不同的是循环中将要执行的代码部分有两行，这样就不可以省去大括号。如果省去了大括号程序只会输出“星期天，上午去看书！”而不会输出“星期天，上午去看书！星期天，下午去吃饭！”。上面的程序运行结果如图6.3所示。

图　6.3　运行效果

读者可以试一下，去掉大括号，看看程序运行结果是什么。这样可以加深理解。

6.1.2　if...else格式

这种格式是在if语句中增加了一个else条件，可以理解成“若学习PHP则就要做点东西出来，否则就没有好好学习PHP”，其流程图如6.4所示。

图　6.4　if...else结构流程图

if...else多选择结构只有在条件为true时，才会运行某个操作；如果条件为false，就会跳过该操作。if...else多选择结构将使读者可以在条件为true或false时，分别指定执行不同的操作，其语法格式如下：

if(条件部分)

{

//程序语句;

}

else

{

//程序语句;

}

当条件判断语句的值为真时，将执行if后边的语句；如果为假，则执行else后边的语句。下面来看代码6.3的程序。

代码6.3　多选择的条件语句：6-3.php

＜?php

//程序名称：6-3.php

//程序功能：多选择的条件语句

$a=4;//给变量赋值

if($a＞6)//对变量进行判断

{

echo"a＞6";//如果条件语句判断值为真，就执行这里的语句

}

else

{

echo"a＜6"//否则条件语句判断值为假，执行这里的语句

}

?＞

该程序是先给定变量一个值4，然后用变量的值和6进行比较，如果变量的值比6大，程序就会向下执行，输出"a＞6"。如果变量的值小于6，程序将会执行else后面的语句。程序运行结果如图6.5所示。

图　6.5　运行效果

6.1.3　if...elseif...else格式

这种格式就是if...else的嵌套，它将多个if...else联合在一起使用，通常进行多种选择判断，其格式如下：

if(条件语句)

{

//程序语句;

}

elseif(条件语句)

{

//程序语句;

}

else

{

//程序语句;

}

作用　if...else的嵌套是为解决一些复杂的判断，比如说判断一个学生成绩是在哪个级别，小于60分为不及格；大于60而小于80为良；大于80而小于100为优。像这样的条件判断就可以使用if...else的嵌套。

技巧　在使用if...else的嵌套时，是以if开始一个条件，如果条件符合，将会执行if下面大括号“｛｝”内的程序语句；如果if条件不符合，将会跳过if下面大括号“｛｝”内的程序语句，去执行else后面的if条件。就这样依此类推。

6.1.4　身份和密码验证实例

假如一个网站的用户比较多，有高级用户和一般会员，那么怎样才能实现一些文件或一些区域只能是高级用户可以访问，而一般用户不可以访问呢？下面通过一个实例来实现这个问题。程序如代码6.4所示。

代码6.4　对用户身份和密码的验证程序：6-4.php

＜?php

//程序名称：6-4.php

//程序功能：对用户身份和密码的验证

/*身份和密码验证部分

*/

//给用户名和密码设定的值

$nameuser="admin";

$namepsw="admin";

$tijiao=$tijiao;

if($tijiao=="提交")

{

//获取表单的数据

$nameuser=$user;//给用户名变量传值

$namepsw=$psw;//给密码变量传值

if($nameuser==""||$namepsw="")//用户名与密码的比较

echo"用户名和密码不能为空！";

elseif($nameuser="admin"||$namepsw="admin")

echo"正在验证密码！";

else

echo"用户名和密码不符！"

?＞

//程序的表单部分

＜html＞

＜head＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"/＞

＜title＞身份和密码验证实例＜/title＞

＜/head＞

＜body＞

＜?php

}

else

{

?＞

//表单部分

＜form method="post"action="6-4.php"name="yz"＞//设置表单的提交对象

＜p＞＜tr＞

＜td align="center"＞

用户名：＜input type="text"size="20"name="user"value="admin"＞

＜/td＞

＜/tr＞＜p＞

＜tr＞

＜td align="center"＞

密码：＜input type="psw"size="20"name="psw"value="admin"＞

＜/td＞

＜/tr＞＜p＞

＜tr＞

＜td align="center"＞

＜input type="submit"value="提交"name="tijiao"/＞

＜input type="reset"value="重设"/＞

＜/td＞

＜/tr＞

＜?php

}

?＞

＜/body＞

＜/html＞

本实例是通过if...else的嵌套来对用户就进行判断的。用户提交后，判断用户名和密码是否符合条件。如果符合就可以访问，不符合就不可以访问。程序运行结果如图6.6所示。

图　6.6　运行效果图

用户输入符合条件的用户名和密码，提交后的运行结果如图6.7所示。如果用户输入的是不符合条件的用户名，提交后的运行结果是什么呢？读者可以去试一下。

图　6.7　提交效果图

作用　身份和密码验证程序是读者用来完成用户在浏览网站时，进行的验证。例如用户登录网站，使用一个唯一的帐号进行登录，读者就可使用此程序来进行用户账号和密码的验证，以保证网站的安全。

技巧　此身份和密码验证程序中，使用了if...else的嵌套对用户的账号进行判断。如果用户输入的账号通过了if...else的嵌套的判断，说明此账号是可以使用的。

6.1.5　switch多分支的选择语句

switch是在多个分支中，选择一个分支去执行。当然也可以使用if的嵌套，但是当把多个if嵌套在一起时，程序的可读性较差。PHP提供的多分支选择语句—switch。在switch语句中，可以根据表达式的值从多个选择中选择一个来执行，其流程如图6.8所示。

图　6.8　switch多分支选择结构流程

由图6.8可知，switch语句是当值为其中一个时，就会执行相应的操作语句；当运行遇到break时，就会跳出switch语句，其格式如下所示：

switch(表达式)

{

case 值 1：操作语句1;

break;

case 值 2：操作语句2;

break;

case 值 3：操作语句3;

break;

...

case 值 n：操作语句n;

break;

default：

语句n+1;

}

注意　switch语句的表达式中，数据类型的值可以是byte、char、short和int，但不允许是浮点型和long类型。

判断表达式的值与case语句后面的值一定是相等的。因为px决定程序需要执行的分支。

在每一个case语句的结束位置一定都要有一个"break；"关键字，因为它的作用是：当程序运行某个分支时，会执行相应的程序块，直到遇到"break；"关键字，才结束分支程序的执行；如果没有"break；"关键字，程序就会执行当前case语句后面的程序块，以及后面的每一个分支语句后才跳出switch语句。

switch语句中的"default："作用是：当表达式的值与任何一个case语句后边的值都不相符时，就会执行default语句后面的程序块，这个语句也可以省略。

下面用一个实例来看看switch是如何工作的。这个实例是对周几的判断，如代码6.5所示。

代码6.5　对周几的判断程序：6-5.php

＜?php

//程序名称：6-5.php

//程序功能：通过switch显示周几

//当前星期作为判断条件

switch(date("D"))

{

case"Mon"：//星期一的情况

echo"星期一";

break;

case"Tue"：//星期二的情况

echo"星期二";

break;

case"Wed"：//星期三的情况

echo"星期三";

break;

case"Thu"：//星期四的情况

echo"星期四";

break;

case"Fri"：//星期五的情况

echo"星期五";

break;

default：//除以上之外的其他情况

echo"过周末";

break;

}

?＞

本实例用了一个data()函数，先通过这个函数获取日期，再使用switch判断来实现。"default："只有上面的5种情况不符合，也就是只有是周末时，才会运行"default："后边的程序块。程序的运行效果如图6.9所示。

图　6.9　运行效果图

6.2　循环语句

循环结构可以用来控制在某种条件为true时，重复执行指定的一个操作。可以分为两种形式：一种是单while形式，另一种是do...while形式。

注意　虽然这两种都是循环语句，但是它们也存在异同点。相同的是它们都是重复某一个操作的循环语句；而不同点是它们前一个是先去判断再处理，后一个是先去执行语句再去做判断。

6.2.1　while格式

while是最简单的循环语句，通过在指定的条件内，指定重复的操作。其流程图如6.10所示。从图中可以看出，程序运行到条件语句时，就会去判断。如果值为true，就会运行指定的操作，完成指定的操作后就又会返回到条件语句，再做判断，直到条件语句的值为false为止。while语句的格式如下：

while(条件语句)

{

指定操作代码

}

图　6.10　while的流程图

其中小括号中的部分为条件部分，大括号中为指定的操作。如果指定操作部分只有一行，那么就可以省去大括号。和上节的单选if在这点上是相同的。下面是一个10字的例子，程序如代码6.6所示。

代码6.6　while循环是如何工作程序：6-6.php

＜?php

//程序名称：6-6.php

//程序功能：while循环是如何工作的

$a=1;//声明一个变量

while($a＜=10)//进行回圈循环

{

echo"这是第",$a,"个字＜br＞\n";//条件符合就运行下面的代码

$a++;

}

?＞

本程序是通过一个while的一个回圈来实现的。先给变量a设定一个初始值，然后将变量和10进行比较，如果条件语句的值为true，那么就开始回圈循环，直到条件语句为false为止。其中的"$a++"是当循环完一个回圈，变量的值就会加1。运行结果如图6.11所示。

图　6.11　运行效果图

作用　while循环是一个单个循环，如果条件成立，将会在次返回到条件语句，一直会执行到条件为不成立为止。

技巧　此while循环也可结合其他条件判断语句来使用，如if等。

6.2.2　do...while格式

do...while是先执行在判断的循环语句，也就是说代码至少执行一次。其流程如图6.12所示。do...while语句首先执行循环体语句，然后再对while语句括号中的条件进行判断。如果值为true，返回继续执行循环体；如果为false，则结束循环，其格式如下：

do

{

循环体

}while(条件);

图　6.12　do...while语句的流程图

下面是一个简单的do...while循环实例，通过该例读者可以更好地理解do...while是如何实现多次执行指定的代码。程序如代码6.7所示。

代码6.7　do...while是如何工作的程序：6-7.php

＜html＞

＜!--程序名称：6-7.php--＞

＜!--程序功能：do...while是如何工作的--＞

＜!--本程序是do...while在HTML中的嵌套--＞

＜head＞

＜title＞do...while循环＜/title＞

＜/head＞

＜body＞

＜?php

$a=1;//初始化变量

do

{//大括号中是指定操作的语句

echo$a;//输出变量的值

echo"＜br＞";//是一个换行符

$a++;

}

while($a＜=10)//条件判断语句

?＞

＜/body＞

＜html＞

上面的实例是在HTML中的嵌套。程序先执行do下面大括号里面的语句，然后才对条件进行判断，运行结果如图6.13所示。

图　6.13　do...while实例的运行效果

从图可以看出，程序先输出了变量的值1，然后才去判断，通过"$a++；"这个语句对变量循环一次加1，直到变量的值等于10为止。如果读者想更好地理解它是如何工作的，也可以把变量的值初始为11看看会显示什么。

6.3　利用循环控制流程

for语句在PHP中是最复杂的，功能也是最强大的，任何while和do...while都可以用for来实现。

6.3.1 for语句

for语句是比较频繁地执行一个循环语句，常用来处理计数器的控制循环，其流程图如图6.14所示。

图　6.14　for语句的流程图

由图中可以看出，首先给变量设定初始值，对条件进行判断，如果值为真，就会执行两个程序块。接着执行循环体语句和修改表达式，修改循环变量的值。然后返回条件进行判断，如果值还为真，重复上面的操作，这样就构成了一个程序往复循环。直到值为假时，就跳出循环体。其格式如下所示：

for(设定初始值;循环条件;修改表达式)

{

循环体

}

其中，设定初始值是给变量设定初始值；循环条件是判断循环是不是还可以继续执行的条件；修改表达式是指修改表达式的值，也就是变量的值。一个简单的for语句应用实例如代码6.8所示。

代码6.8　for语句的应用实例程序：6-8.php

＜?php

//程序名称：6-8.php

//程序功能：重复输出以后要好好学习PHP

/*设定初始值;

循环条件;

修改变量的值*/

for($i=1;$i＜10;$i++)

{

echo"$i.以后要好好学PHP＜br＞\n";//重复执行的程序

}

?＞

程序中变量设定的初始值为1，条件是变量不能大于10，"$i++"的作用是修改变量的值。当条件不符时，就会跳出循环。运行效果如图6.15所示。

图　6.15　运行效果图

注意

for语句括号内的表达式一个都不能省，必需用分号隔开。

for循环体可以为空，但是分号“；”必需有。

设定多个变量初始值和修改多个变量值时，可以用逗号隔开。

作用　for语句的作用就是实现计数的递增或递减。可以用在网站访问的统计等方面。

6.3.2　用PHP中的for语句实现九九乘法表

九九乘法表是什么样子，相信读者都还知道，但是应该怎么做呢？先想一下，应该用几个变量，这几个变量间有什么关系，两个循环之间应该怎么处理呢？九九乘法表的特点是有9行9列，但每一行的列数并不一样，第1行只有一列，而第9行则有9列，所以这两个循环之间其实有很明显的规律可以寻找。现在就以下面的程序为例来说明。程序如代码6.9所示。

代码6.9　通过双重for来实现九九乘法表程序：6-9.php

＜?php

//程序名称：6-9.php

//程序功能：通过双重for来实现九九乘法表

//设定变量初始值

$a=1;

$b=1;

/*循环条件部分

循环的初始值

循环的最大值

循环的递增*/

for($a=1;$a＜=9;$a++)

{

for($b=1;$b＜=9;$b++)//双重for语句

echo"$a*$b=".$a*$b."\t";

echo"\n";

}

?＞

上面的实例是通过设定两个变量，用双重的for循环来控制程序的运行。运行效果如图6.16所示。

图　6.16　运行效果图

6.4　其他流程控制语句

PHP中除了上面所讲的几种流程控制语句外，还有break、continue这两种流程控制语句。下面就为读者做具体介绍。

6.4.1　break跳转语句

在switch的程序中，已经使用了break语句结束循环体。除此break语句外，还可以结束for、do...while等语句的执行。

如果是单层循环，break语句的作用是跳出循环体。如果是双层循环，break语句就有两种情况了：如果出现在内循环的位置，break的作用是结果内循环体；如果出现在外循环位置，那么break的作用就是结果外循环体。下面是一个break、for和if结合应用的实例，该程序计算1+2+3+…一直加到大于1000为止。程序如代码6.10所示。

代码6.10　break、for和if的应用程序：6-10.php

＜?php

//程序名称：6-10.php

//程序功能：break、for和if的应用

$a=1;//设定变量

$sum=0;

/*循环体部分

增加变量$a的值

循环的初始值*/

for($a=1;$a++)

{

$sum+=$a;//计算变量$sum的值

if($sum＞1000)//判断变量的值是否大于1000

break;//如果变量的值大于1000就跳出循环

}

echo'$a=',$a;//输出变量$sum大于1000时变量$a的值

echo'$sum=',$sum;//输出跳出循环变量$sum的值

?＞

因为不知道程序要循环多少次，因此使用for循环语句时，就省去了判断循环条件表达式。使用if语句是对求和的结果进行判断，如果值大于1000就会执行break语句，结束循环；如果值不大于1000，就会一直循环下去。程序的运行效果如图6.17所示。

图　6.17　6-10.php运行效果图

6.4.2　continue语句

continue语句与break语句不同，break语句是终止当前的循环，而continue语句则不是这样。continue语句是不去执行continue语句后面的语句，结束本次循环，继续执行下一次循环。下面一个实例是输出1～5中除了3以外的数。程序如代码6.11所示。

代码6.11　不输出不想要的内容程序：6-11.php

＜?php

//程序名称：6-11.php

//程序功能：不输出不想要的内容

$i=1;//设定变量

for($i=1;$i＜=5;$i++)//循环范围

{

if($i==3)//判断变量是否等于3

continue;//结束本次循环

else

{

echo'$i=',$i,"＜br＞";

}

}

?＞

本程序是通过for让变量在循环条件范围内递增。通过if语句来判断变量的值是否为3，如果变量的值等于3，就会执行continue语句，结束本次循环。如果变量的值不等于3，就会输出循环变量的值。程序的运行效果如图6.18所示。

图　6.18　6-11.php运行效果图

6.5　小结

本章介绍了PHP中的流程控制结构，其中有分支结构的if语句和switch语句。if语句中又包括了if、if...else和if...else的嵌套结构。还有实现循环结构的for语句、while语句、do...while语句。读者在学习这些语句时要注意并掌握以下内容。

❑if选择结构只有条件为true时，才执行操作。

❑if...else选择结构是在条件为true或false时，执行指定的不同的操作。

❑switch语句是处理多个判断，其判断表达式是否为假定的值，执行不同的操作。

❑while是单循环语句，在指定的条件内，执行指定的操作。

❑do...while循环结构是在循环末尾判断循环条件，所以循环体至少执行一次。

❑for语句是比较频繁地执行一个循环语句，常用来处理计数器的控制循环。

第7章　函数和对象的基本知识

本章将介绍PHP的函数和对象的基本知识。通过对本章节的学习，读者应了解什么是函数，如何声明一个函数，如何建立自定义函数，找到这些答案就掌握了函数的应用。然后本章介绍对象的创建和应用，了解一个面向对象开发语言所需要掌握的技术。本章最后还提供了一个面向对象应用开发的案例，读者通过这个案例可掌握面向对象开发的流程。

7.1　函数

在PHP中，允许程序员将常用的流程或者变量等组件组织成一个固定的格式。也就是说程序员可以自己组合函数。

PHP中的函数（function）和C语言中的函数是一样的。包括有返回值和无返回值的函数，PHP中的函数与Pascal语言不同的是函数（function）和过程函数（procedure），它们并没有那么复杂。

7.1.1　什么是函数

函数就是在某变化过程中有两个变量A和B，变量B随着变量A一起变化，而且依赖于A，如果变量A取某个特定的值，B依确定的关系取相应的值，那么称B是A的函数。

在程序的编写过程中往往会有一些要反复使用的功能模块，如果每一次都重复嵌入这些代码，这样会使程序变得不但长而且复杂，维护起来比较困难。在这种情况下可以用到PHP中的函数，可以把这些功能模块写成一个函数，在需要使用时，通过调用此函数就可以了。

这样读者一次编写好函数，以后使用时不必关心其中的细节，要做功能修改时，只需要修改函数中的内容，则所有对这个函数的调用都会发生相应的变化，而不需要一个一个地去修改。使用函数还可以减少对系统资源的耗用，因为每一次调用函数结束后，系统都会释放调用函数所占用的资源。

对于PHP来说，在函数的名称上大小写的管制比较松散，可以在定义函数时写成大写，而在使用函数时写成小写。也就是说在PHP中，函数是不区分大小写的，只要注意函数的名称没有重复就可以了。

7.1.2　如何建立自定义函数

在定义一个函数时，要以function语句开头，接着是函数名称，函数名称后是括号，括号内是函数的参数列表。如果括号内有多个参数，那么参数与参数之间必须用逗号隔开。当然也可以没有参数。函数的使用格式如下所示：

function myfunc(参数1，参数2，参数n)

{

//要执行的动作

}

在此代码中，"myfunc"是函数的名称，在命名时可以是任何英文字母开头的字符串，但是开头不能是数字或下画线，可以在第1个字符串后加数字和下画线。在使用函数时，自定的函数名称前要加入function的保留字，表示这是定义程序员自定函数。下面就通过实例来介绍PHP中函数的使用，程序如代码7.1所示。

代码7.1　PHP中函数的使用程序：7-1.php

＜html＞

＜!程序名称：7-1.php＞

＜!程序功能：PHP中函数的定义＞

＜head＞

＜title＞PHP中函数的定义＜/title＞

＜/head＞

＜body＞＜?php

function my_func($inputText)//定义一个函数

{

echo"＜b＞".$inputText."＜/b＞";//输出函数的变量

}

echo"这是一个简单的函数！";

echo"＜br＞";

echo"这是一个自定义函数！.";

echo"＜br＞";

echo"＜h1＞读者的定义函数建立成功！＜/h1＞";

?＞

＜/body＞

＜/html＞

该程序中，"function"是函数的保留字，"my_func"是函数的名称，命名时不能以数字或下画线开头。括号中是函数的参数，这样一个函数就定义好了。程序的运行效果如图7.1所示。

图　7.1　PHP中函数的定义程序运行效果图

注意　函数的名称是不区分大小写的。

PHP中的任何一个函数都是具有全局域的，即可以在内部定义函数，在外部调用内部定义的函数；也可以在外部定义函数，在内部调用外部定义的函数。PHP不支持函数重载，不可以取消已经定义的函数，并且也不可以重新定义已经声明的函数。

7.1.3　函数的参数

函数的参数是指函数名称后括号中的内容。参数之间要使用逗号隔开。参数后的大括号“{}”包含的是内容，即为整个函数的区段。如果函数有返回值，使用return就可以将值返回。函数可以事先定义初始值或内定值。有定义内定值的参数在使用函数时可以省略，但是一定要放在没有设定内定值参数的后面，否则PHP在解析函数时，会出现错误。

参数的类型，只要参数是PHP支持的变量类型都可以使用，无论是数组、字符串、整数等。返回值也是一样的。

参数的值，通常使用传值的方式输入，但有时在特别的需求时，可以使用传址的方式，传入参数的指针。方法就是在参数前面加上“＆”符号就可以了。下面通过实例来介绍PHP中函数的参数，程序如代码7.2所示。

代码7.2　PHP中函数的参数程序：7-2.php

＜html＞

＜!程序名称：7-2.php＞

＜!程序功能：PHP中函数的参数＞

＜head＞

＜title＞PHP中函数的参数＜/title＞

＜/head＞

＜body＞

＜?php

function myfunc1($arg_1,$arg_2,$arg_3="这是内定字符串！")//可以省略内定参数

{

echo$arg_1+$arg_2;

echo$arg_3;

echo"＜br＞";

}

myfunc1(3,4);//参数$arg_3省略

myfunc1(6,6,"不用内定值");//输入参数$arg_3的值

function myfunc2(＆$argstr)//参数的传值

{

$argstr=ereg_replace("/","-",$argstr);

}

$today="2008/04/20"//给日期赋值

myfunc2($today);

echo$today;//输出指定的值

?＞

＜/body＞

＜/html＞

该程序是函数的某一个参数在定义时就给出了一个默认值，在调用过程中，如果该参数有返回值，则该参数采用这个值；如果该参数没有返回值，则该参数采用默认值。参数的传值，通常使用传值的方式输入，但有时在特别的需求时，可以使用传址的方式，传入参数的指针。程序的运行效果如图7.2所示。

图　7.2　PHP中函数的参数程序运行效果图

7.1.4　函数的返回值

函数的返回值就是函数的值通过可以选择的返回语句返回。对返回值的类型没有限制，可以是任何类型的值，也可以是列表和对象。当函数在某点结束时，就准备将控制权转给调用者，如果是执行到了函数代码段的末尾，则执行从该函数返回到调用它的地方。用return语句结束函数的执行。

一个函数可以有多个return语句，但是这样可能会降低代码的可读性。多个return语句对于理解执行的流程来说会是一个负担。一个入口和一个出口的函数是理想情况下的函数。在实践中，多个return语句是可能的。如果return语句后跟着表达式，那么表达式的值将被返回，如代码7.3所示。

代码7.3　return语句后表达式的返回值程序：7-3.php

＜html＞

＜!程序名称：7-3.php＞

＜!程序功能：返回表达式的值＞

＜head＞

＜title＞返回表达式的值＜/title＞

＜/head＞

＜body＞

＜?php

function my_func($InputText)//定义函数

{

$my="＜b＞";//变量设值

$my.=$InputText;

$my.="＜/b＞";

return($my);

}

echo"这不是一个自定义函数的返回值！";//输出

echo"＜br＞";//换行

echo my_func("这是一个自定义函数的返回值！");

echo"＜br＞";

echo"这也不是一个自定义函数的返回值！";

echo"＜br＞";

?＞

＜/body＞

＜/html＞

此程序通过建立自定义函数myfunc，在返回值语句后面是一个表达式，程序将返回表达式的值。运行效果如图7.3所示。

图　7.3　返回表达式的值的程序运行效果图

7.1.5　变量函数

变量函数也是动态函数。用函数的同名变量实现可变函数。PHP提供了可变函数的机制，可以方便地利用变量实现对函数的调用。在PHP的某个代码中，如果某一变量的值与一个函数同名时，则在该代码中可以使用该变量代替函数名来调用函数，调用方法是在变量名后加上括号及函数参数，如“（参数）”。变量函数的使用格式如下所示：

＜?php

function fun()//定义函数

{

echo"使用变量代替函数";

echo"＜br＞";

}

$var="fun";//给变量设置值是函数名

$var();//调用函数

?＞

此程序中，$var()就相当于调用函数fun()，$var()就是变量函数。变量函数与普通的函数调用时最大的区别就是在于变量函数前面的“$”符号，有此符号，系统就会认为是变量函数。变量函数的使用程序如代码7.4所示。

代码7.4　变量函数的使用程序：7-4.php

＜html＞

＜!程序名称：7-4.php＞

＜!程序功能：变量函数的使用＞

＜head＞

＜title＞变量函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

function a()//函数a

{

echo"In a()＜br＞\n";

}

function b($arg='')//函数b

{

echo"In b();argument was'$arg'.＜br＞\n";

}

function c($string)//函数c

{

echo$string;

}

$func='a';//给变量设置值为函数名

$func();//调用函数a

$func='b';//给变量设置值为函数名

$func('test');//给函数传参数

$func='c';//给变量设置值为函数名

$func('test');//给函数传参数

?＞

＜/body＞

＜/html＞

此程序通过定义3个函数，最终将用一个变量函数调用这3个函数，程序的运行效果如图7.4所示。

图　7.4　变量函数的使用程序运行效果图

注意　如果写成$var="fun()"，则$var只是一个普通的字符串而已，调用语句$var；不会实现fun()函数的功能。

7.2　一个函数的开发实例—上传文件系统

本节将为读者介绍如何使用PHP函数实现文件的上传，由于有时读者不清楚要上传几个文件，所以将介绍一个可以选择上传个数的上传文件系统。

7.2.1　上传系统的流程

本系统的流程如图7.5所示。从此流程图中可以看出，本实例是分成3个部分来完成的。首先是用户需要在网页中设置要上传的文件的个数，用户设置完成后，单击“提交”按钮，就会发送到第2个文件7-6.php，使用for循环来实现用户设置个数的文件上传框。用户选择好上传的文件后，单击“上传”按钮，此时发送到7-7.php处理上传文件的程序，实现文件的上传。

图　7.5　文件上传系统的流程图

7.2.2　用户设置上传文件个数的界面

下面就以一个实例来介绍用户设置文件上传个数的页面是如何实现的，程序如代码7.5所示。

代码7.5　用户设置上传文件的个数程序：7-5.html

＜html＞

＜!程序名称：7-5.php＞

＜!程序功能：用户设置上传文件的个数＞

＜head＞

＜title＞用户设置上传文件的个数＜/title＞

＜/head＞

＜body＞

＜!--表单--＞

＜form name="form1"method="post"action="7-14.php"＞

＜p＞请输入你要同时上传的文件的数目，最大值是9＜/p＞

＜p＞

＜!—设置上传文件个数的表单--＞

＜input name="uploadNeed"type="text"id="uploadNeed"maxlength="1"＞

＜/p＞

＜p＞

＜!—提交部分--＞

＜input type="submit"name="Submit"value="提交"＞

＜/p＞

＜/form＞

＜/body＞

＜/html＞

此程序是一个HTML表单，通过此表单，把用户设置的数据发送到7-6.php进行处理。程序的运行效果如图7.6所示。

图　7.6　用户设置上传文件的个数程序的运行效果图

7.2.3　实现用户设置上传文件个数的功能

用户设置的上传文件个数的信息发送到程序7-6.php，程序是如何把接收到的信息做处理的呢？下面来看代码7.6。

代码7.6　实现上传的窗口程序：7-6.php

＜html＞

＜!程序名称：7-6.php＞

＜!程序功能：实现上传的窗口＞

＜head＞

＜!—设置页面的标题--＞

＜title＞实现上传的窗口＜/title＞

＜/head＞

＜body＞

＜form name="form1"enctype="multipart/form-data"method="post"action="7-13.php"＞

＜?php

$uploadNeed=$_POST['uploadNeed'];//创建动态表单

for($x=0;$x＜$uploadNeed;$x++)//循环体部分

{

?＞

＜!—输出上传文件的表单--＞

＜input name="uploadFile＜?php echo$x;?＞"type="file"id="uploadFile＜?php echo$x;?＞"＞

＜?php

}//完成循环

?＞

＜input name="uploadNeed"type="hidden"value="＜?php echo$uploadNeed;?＞"＞

＜input type="submit"name="Submit"value="上传"＞

＜/form＞

＜/body＞

＜/html＞

此程序接收用户提交的信息，然后做出的处理。如果用户设置了上传文件个数为8，那么此程序会创建8个上传文件的窗口。程序的运行结果如图7.7所示。

图　7.7　实现上传的窗口程序的运行效果图

注意　本系统最大可设置上传文件的个数为9。所以用户在设置文件上传个数时不能大于9。

作用　此程序是实现用户选择上传文件路径的页面。先把用户要上传的文件获取到，然后通过上传处理文件实现文件的上传。

技巧　在此程序中使用了for语句来实现用户设置上传文件的个数。由于程序设置了最大上传个数为9所以用户只能在小于9的情况下完成上传。

7.2.4　处理上传的文件

在前面的程序中用户设置了上传文件的个数为8，当程序7-6.php接收到信息后，会创建出8个上传文件的窗口。当用户选择好需要上传的8个文件后，单击“上传”按钮，这时，用户的操作就交给了程序7-7.php来完成。下面来介绍处理上传文件的程序，如代码7.7所示。

代码7.7　处理上传文件程序：7-7.php

＜html＞

＜!程序名称：7-7.php＞

＜!程序功能：处理上传文件＞

＜head＞

＜title＞处理上传文件＜/title＞

＜/head＞

＜body＞

＜?php

$uploadNeed=$_POST['uploadNeed'];

for($x=0;$x＜$uploadNeed;$x++)//开始循环

{

$file_name=$_FILES['uploadFile'.$x]['name'];

$file_name=stripslashes($file_name);//去除文件名中的特殊字符

$file_name=str_replace("'","",$file_name);

$copy=copy($_FILES['uploadFile'.$x]['tmp_name'],$file_name);

if($copy)//检查是否复制成功

{

echo"$file_name上传成功＜br/＞";

}else{

echo"$file_name上传失败＜br/＞";}

}//结束循环

?＞

＜/body＞

＜/html＞

此程序是用来完成文件的上传处理工作的。如果上传成功，则此页面上会显示所上传的文件名和上传完成的状态。程序的运行效果如图7.8所示。

图　7.8　处理上传文件程序的运行效果图

这样一个简单的文件上传系统就完成了。

作用　此程序的作用是把用户需要上传的文件，通过判断，如果符合要求，就会把用户上传的文件上传到指定的位置。

技巧

在此程序中使用文件上传函数，通过此函数就可以把用户需要上传的文件上传到指定的位置。

其中调用了复制函数，来判断用户需要上传的文件是否复制成功。复制成功就进行上传操作。

7.3　对象

面向对象技术已经提出了很多年，如果读者熟悉ASP、Java等语言，那么一定对面向对象也很熟悉。PHP支持面向对象的编程技术，但相对于ASP而言，PHP几乎没有预先定义好的对象，因此使用时只能自行定义。面向对象的概念对于编程来说会有很大的帮助。

7.3.1　对象的概念

讲到对象，就必须涉及一个问题：什么是类，因为读者将要直接接触的就是类（class）这个概念。类是对象的抽象，也是变量和函数的组合，对象是类的实例化。

所谓对象，是一种将状态（数据）和行为（操作）合成到一起的软件构造，用来描述真实世界的一个（物理或概念性的）对象。也就是说使用计算机对人类的思维或可观事物进行一个模拟，对象中包含了一系列数据结构和相关的操作。对象本身可以为用户提供一系列的服务，而用户无须知道其中的细节。而类就是定义和描述对象的工具，也就是说类的实例化就是一个对象。

7.3.2　定义类

对象的建立需要先定义类，在定义类后，就可以在类的基础上创建对象。下面来介绍类的定义。在PHP中，使用class关键字可以实现类的定义。类定义的语法形式如下所示：

Class类名

{

类变量集与函数集

}

类的定义是以"class"开头，后面是类名，花括号中就是类的变量集与函数集。下面通过实例来介绍类的定义，如代码7.8所示。

代码7.8　类的定义程序：7-8.php

＜html＞

＜!程序名称：7-8.php＞

＜!程序功能：类的定义＞

＜head＞

＜title＞类的定义＜/title＞

＜/head＞

＜body＞

＜?php

class Point//定义类

{

var$x;//点的x坐标

var$y;//点的y坐标

function setx($px=0)//设置x坐标

{

$this-＞x=$px;

}

function sety($py=0)//设置y坐标

{

$this-＞y=$py;

}

function getx()//获取x的坐标值

{

return$this-＞x;

}

function gety()//获取y的坐标值

{

return$this-＞y;

}

}

?＞

＜/body＞

＜/html＞

其中定义了一个点的类，该类有两个成员变量，也就是点的两坐标。类中还提供了一系列存取函数，以得到或设置点的两坐标。

从程序中可以看出，类中成员变量的定义方法为“var变量名；”，成员函数与一般函数的定义方法相同。

注意　如果成员函数中要使用类中的成员变量或其他成员函数，不能直接引用，要用“$this-＞变量名”或“$this-＞函数名”。

7.3.3　创建对象

类定义好了，接下来就可以在类的基础上创建对象了。对象的创建是使用new关键字来生成一个类的对象。类的实例化后就是创建了一个对象。创建对象的格式如下所示：

$对象名=new类名

上面的格式也就是将类实例化的过程。下面通过实例来介绍对像是如何创建的，程序代码如代码7.9所示。

代码7.9　对象的创建程序：7-9.php

＜html＞

＜!程序名称：7-9.php＞

＜!程序功能：对象的创建＞

＜head＞

＜title＞对象的创建＜/title＞

＜/head＞

＜body＞

＜?php

class Point

{

var$x;//点的x坐标

var$y;//点的y坐标

function setx($px=0)//设置x坐标

{

$this-＞x=$px;

}

function sety($py=0)//设置y坐标

{

$this-＞y=$py;

}

function getx()//获取x的坐标值

{

return$this-＞x;

}

function gety()//获取y的坐标值

{

return$this-＞y;

}

}

$myPoint=new Point;

$myPoint-＞setx(10);

$myPoint-＞sety(10);

?＞

＜/body＞

＜/html＞

此程序是将定义的"Point"类实例化，创建出"Point"类的对象。程序中$myPoint=new Point是对象的创建语句。对象的名称为"myPoint"，对象中包含了类中的所有属性和方法。由于类的封装性，类中的属性是不让对象直接访问的，对象可以使用类中的方法达到操作类属性的目的。引用类中的方法可以使用“-＞”符号。例如要把myPoint点移动到点（10，10）这里，可以使用下面的语句来实现：

$myPoint-＞setx(10);

$myPoint-＞sety(10);

使用上面的语句，就会使myPoint点的x值和y值都变为10了。

注意　类中的属性不能由类的实例化对象直接访问，只能通过成员函数来访问。

作用　对象的使用，就是把程序分层的一个过程序，这样可以使程序更加安全、更好理解，具有更高的效率。

7.4　一个对象的开发实例

对象是通过类的实例化出来的，既然读者可以声明一个类，接下来就是实例化对象了。当定义好类后，使用"new"关键字来生成一个对象。类实例化对象的格式如下所示：

$对象名称=new类名称();

本实例分为4个部分，分别是定义一个类，然后把类进行实例化，产生一个对象，使用成员函数来访问类，程序如代码7.10所示。

代码7.10　一个对象开发实例程序：7-10.php

＜html＞

＜!程序名称：7-10.php＞

＜!程序功能：一个对象开发实例＞

＜head＞

＜title＞一个对象开发实例＜/title＞

＜/head＞

＜body＞

＜?php

class Person

{

/*下面是人的成员属性*/

var$name;//人的名字

var$sex;//人的性别

var$age;//人的年龄

/*下面是人的成员方法*/

function say()//这个人可以说话的方法

{

echo"这个人在唱歌";

echo"＜br＞";

}

function run()//这个人可以走路的方法

{

echo"这个人在跑步";

echo"＜br＞";

}

}

$p1=new Person();//创建实例对象$p1

$p2=new Person();//创建实例对象$p2

$p3=new Person();//创建实例对象$p3

/*下面三行是给$p1对象属性赋值*/

$p1-＞name="张大";

$p1-＞sex="男";

$p1-＞age=20;

/*下面三行是访问$p1对象的属性*/

echo"p1对象的名字是：".$p1-＞name."＜br＞";

echo"p1对象的性别是：".$p1-＞sex."＜br＞";

echo"p1对象的年龄是：".$p1-＞age."＜br＞";

/*下面两行访问$p1对象中的方法*/

$p1-＞say();

$p1-＞run();

/*下面三行是给$p2对象属性赋值*/

$p2-＞name="李四";

$p2-＞sex="女";

$p2-＞age=30;

/*下面三行是访问$p2对象的属性*/

echo"p2对象的名字是：".$p2-＞name."＜br＞";

echo"p2对象的性别是：".$p2-＞sex."＜br＞";

echo"p2对象的年龄是：".$p2-＞age."＜br＞";

/*下面两行访问$p2对象中的方法*/

$p2-＞say();

$p2-＞run();

/*下面三行是给$p3对象属性赋值*/

$p3-＞name="王小";

$p3-＞sex="男";

$p3-＞age=40;

/*下面三行是访问$p3对象的属性*/

echo"p3对象的名字是：".$p3-＞name."＜br＞";

echo"p3对象的性别是：".$p3-＞sex."＜br＞";

echo"p3对象的年龄是：".$p3-＞age."＜br＞";

/*下面两行访问$p3对象中的方法*/

$p3-＞say();

$p3-＞run();

?＞

＜/body＞

＜/html＞

代码7.10是通过类产生实例对象的过程，"$p1"就是实例出来的对象名称，同理，"$p2"、"$p3"也是实例出来的对象名称。一个类可以实例出多个对象，每个对象都是独立的。上面的代码相当于实例出来3个人，每个人之间是没有联系的，只能说明这3个对象都是人类，每个人都有各自的姓名、性别和年龄的属性，每个人都有唱歌和跑步的方法，只要是类里面体现出来的成员属性和成员方法，实例化出来的对象里面就包含了这些属性和方法。

对象在PHP里面和整型、浮点型一样，也是一种数据类，都是存储不同类型数据用的，在运行的时候都要加载到内存中去用。那么对象在内存里面是怎么体现的呢？内存从逻辑上大体分为4段，栈空间段、堆空间段、代码段、初始化静态段，程序里面不同的声明放在不同的内存段里，栈空间段是存储占用相同空间长度并且占用空间小的数据类型的地方。

每个在堆里的实例对象都是存储属性的。例如，现在堆里面的实例对象里都存有姓名、性别和年龄。每个属性又都有一个地址。$p1=new Person()；等号的右边$p1是一个引用变量，通过赋值运算符“=”把对象的首地址赋给$p1这个引用变量，所以$p1是存储对象首地址的变量。$p1放在栈内存里边，$p1相当于一个指针指向堆里面的对象，所以可以通过$p1这个引用变量来操作对象，通常也称对象引用为对象。

上面看到PHP对象中的成员有两种：一种是成员属性，另一种是成员方法。对象已经可以声明了，$p1=new Person()；怎么去使用对象的成员呢？要想访问对象中的成员就要使用一个特殊的操作符“-＞”来完成对象成员的访问。访问对象成员的格式如下所示：

对象-＞属性$p1-＞name;$p2-＞age;$p3-＞sex;

对象-＞方法$p1-＞say();$p2-＞run();

程序的运行效果如图7.9所示。

图　7.9　一个对象开发实例程序运行效果图

技巧　在使用类时，首先要定义类，然后再实例化类，来产生一个对象，最后就可以通过成员来访问对象了。就是实现一个对象的步骤。

7.5　小结

本章介绍了函数和对象：函数包括函数的概念、函数的定义、函数的参数、函数的返回值、变量函数；对象包括对象的概念、对象是如何创建的。

读者通过本章的学习，需要掌握什么是对象、对象是如何定义、如何使用，以及函数是什么、函数的创建及使用的方法。PHP是面向对象开发的语言，这就增加了程序的灵活性，建议读者掌握本章的内容并多加实践。

第二篇　PHP的常用函数库

第8章　PHP的常用函数库

本章将介绍PHP中的常用函数。PHP编程在很大程序上就是对函数的运用，这点和C语言类似。因为PHP提供了丰富的函数支持，才使得其功能非常强大。而对PHP中常用函数的使用熟练与否，直接关系到程序开发的速度。本章将要介绍的常用函数类型如下。

❑字符串处理函数。

❑数组处理函数。

❑数学运算函数。

❑变量处理函数。

❑日期与时间函数。

❑目录与文件函数。

8.1　字符串处理函数

在程序编写过程中，读者经常会用到字符串处理函数，如字符的查找、替换、格式化、分割等。PHP提供了很多处理字符串的函数，为编写程序带来了极大的方便。

8.1.1　拆分字符串方法

拆分字符串方法是把字符串拆分成几个子字符串，并返回一个子字符串。拆分字符串方法的格式如下所示：

String substr(string str,int start,int[length])

此函数返回字符串str中从位置start开始、长度为length的子字符串，其中参数start和length不但可以取正数，还可以取负数。下面通过实例来介绍拆分字符串函数的方法，程序如代码8.1所示。

代码8.1　拆分字符串函数的方法程序：8-1.php

＜html＞

＜!程序名称：8-1.php＞

＜!程序功能：拆分字符串函数的方法＞

＜head＞

＜title＞拆分字符串函数的方法＜/title＞

＜/head＞

＜body＞

＜?php

$str="0123456789";//给变量设值

echo"\$str=$str";//输出变量

echo"＜br＞";//换行

echo"substr(\$str,4)=".substr($str,4);//输出4后面的数

echo"＜br＞";

echo"substr(\$str,-4)=".substr($str,-4);//输出后4位数

echo"＜br＞";

echo"substr(\$str,4,2)=".substr($str,4,2);//输出4后的一位数，包括4

echo"＜br＞";

echo"substr(\$str,4,10)=".substr($str,4,10);//输出4后的10位数

echo"＜br＞";

echo"substr(\$str,4,-2)=".substr($str,4,-2);//输出4后面除去末尾的2位数

echo"＜br＞";

echo"substr(\$str,4,-10)=".substr($str,4,-10);//输出4后面除去从尾向前数的10位数

echo"＜br＞";

echo"substr(\$str,-4,2)=".substr($str,-4,2);

echo"＜br＞";

echo"substr(\$str,-4,10)=".substr($str,-4,10);

echo"＜br＞";

echo"substr(\$str,-4,-2)=".substr($str,-4,-2);

echo"＜br＞";

echo"substr(\$str,-4,-10)=".substr($str,-4,-10);

echo"＜br＞";

echo"substr(\$str,\"ab\")=".substr($str,"ab");

echo"＜br＞";

echo"substr(\$str,\"4ab\")=".substr($str,"4ab");

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序介绍了substr()函数的用法。从程序中可以看出，如果start或length为字符串，则先按字符串转整型的方式转换参数；如果start为正数，表示相对字符串str首字符的位置；如果start为负数，其绝对值表示相对str最末一个字符的位置，“-1”表示最后一个字符；如果start超出字符串的范围，则函数返回空值；如果length为正数，那么从start开始朝str末尾方向取length个字符返回。如果lenght为负数，那么从后面和第length个的绝对值字符就是末尾，返回从start到新末尾的字符串；如果length超出srart和字符串末尾所控制的范围，函数返回空值。程序的运行效果如图8.1所示。

图　8.1　拆分字符串函数的方法程序运行效果图

注意　函数的参数之间要用逗号隔开。如果是点号“.”，程序会认为是字符串的连接符。

作用　此程序中使用了substr()函数，它是用来实现获取指定字符串中某个字符。

8.1.2　特定字符的查找

PHP中提供了功能强大的字符串查找和替换函数，可以方便地进行字符串的查找和替换操作。这两个函数的作用是在字符串一中查找字符串二第1次出现的地方，如果找到，将返回字符串一中从字符串二开始剩余部分。字符串二也可以是一个整数，函数会先将此整数转换为ASCII码，然后进行查找。其不同点在于查找函数不区分大小写，而替换函数是区分大小写的。但是这两个查找函数的功能相同。查找函数的格式分别如下所示：

string stristr(string str1,string str2)

string strstr(string str1,string str2)

其中stristr和strstr是查找函数，str1和str2表示字符串一和字符串二。

1.strstr函数

下面通过实例来介绍字符串的查找的使用，实例程序如代码8.2所示。

代码8.2　字符串的查找：8-2.php

＜html＞

＜!程序名称：8-2.php＞

＜!程序功能：字符串的查找函数的使用＞

＜head＞

＜title＞字符串的查找函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

echo stristr("abcDefghi","def");//从第1个字符串中查找第2个字符串，并输出查找到的字符串后面的字符

echo"＜br＞";//输出换行

echo strstr("abcDefdefghi","def");//只输出第2个查找到的字符串后面的字符

echo"＜br＞";

echo strstr("abcDefdefghi",97);//输出查找到的字符串后面的97位字符

echo"＜br＞";

?＞

＜h1＞

＜/body＞

＜/html＞

该程序中使用了字符串查找函数stristr()和strstr()，函数的作用是在字符串一中查找字符串二第1次出现的地方，如果找到，将返回字符串一中从字符串二开始剩余部分。程序中的字符串也可能是整数，函数会先将此整数转换为ASCII码，然后进行查找。程序的运行效果如图8.2所示。

图　8.2　字符串的查找和替换函数的使用程序运行效果图

注意　字符串查找函数不区分大小写，而字符串替换函数是区分大小写的。但是查找函数与替换函数的功能相同。

作用　此程序是用来实现字符串或字符的查找及替换，如在一段文字中查找某个字符串或字符，进行替换。这样既可以节省时间，又减少了程序员的工作量。

2.strrchr函数

与上面的函数的查找作用不同，字符串查找函数是在字符串"str1"中查找最后一次出现字符串"str2"的首字符的地方，并返回首字符及剩余的字符串。同样"str2"也可以是整数。函数的格式如下所示：

String strrchr(string str1,string str2)

此格式中strrchr为字符串查找函数，参数中的"str1"和"str2"是原字符串和查找字符串。下面通过一个实例来介绍此函数的使用，程序如代码8.3所示。

代码8.3　字符串的查找函数的使用程序：8-3.php

＜html＞

＜!程序名称：8-3.php＞

＜!程序功能：字符串的查找函数的使用＞

＜head＞

＜title＞字符串的查找函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

echo strrchr("abcDefdrfghi","dab");//输出查找到字符串后面的字符

echo"＜br＞";

echo strrchr("abcDefdefghi",97);

echo"＜br＞";

?＞

＜h1＞

＜/body＞

＜/html＞

该程序中使用了字符串查找函数strrchr()，此字符串查找函数是在字符串"str1"中查找最后一次出现字符串"str2"的首字符的地方，并返回首字符及剩余的字符串。所以语句echo strrchr（"abcDefghi"，"dab"）；的输出结果是"drfghi"，就是没有输出内容。程序运行结果如图8.3所示。

图　8.3　字符串的查找函数的使用程序运行效果图

3.strrpos函数

除上面的查找函数外，PHP还提供了两个查找函数，这两个函数的作用是在"str1"中查找"str2"，并返回找到的位置。二者的区别在于strops()函数将比较整个字符串，而且返回字符串"str2"第1次出现的位置；而strrpos()函数只比较字符串的首字符，而且返回字符最后一次出现的位置。

在strops()函数中，如果"str2"不是一个字符串，那么先将其转换为整数，然后用整数所代表的ASCII字符进行查找。strops()函数中第3个参数offset是可选的，第3个参数是设定从字符串"str1"的哪个位置开始查找。

如果子串没有找到，这两个函数的返回值均为空值。函数的格式如下所示：

int strops(string str1,string str2,int[offset])

int strrpos(string str1,char str2)

在该格式中，strpos和strrpos为字符串查找函数，其中"str1"为被查找的字符串，"str2"为要查找的字符串，"offset"为设定从被查找字符串的哪个位置开始查找。下面通过一个实例来介绍这两个字符串查找函数的用法，程序如代码8.4所示。

代码8.4　字符串查找函数的程序：8-4.php

＜html＞

＜!程序名称：8-4.php＞

＜!程序功能：字符串的查找函数的使用＞

＜head＞

＜title＞字符串的查找函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$str="abcdeabcde";

echo strpos($str,"ab");//输出0

echo"＜br＞";

echo strrpos($str,"ab");//取最后一次出现的位置，输出5

echo"＜br＞";

echo strrpos($str,"ac");//取首字符

echo"＜br＞";

echo strpos($str,97);//97为字母a的ASCII码

echo"＜br＞";

echo strpos($str,"ab",1);//从第2个字符开始找

echo"＜br＞";

echo strpos($str,"ba");//没找到，返回空

echo"＜br＞";

echo empty($var);//$var为空，所以输出1

?＞

＜h1＞

＜/body＞

＜/html＞

该程序中使用字符查找函数，在"str1"中查找"str2"，并返回找到的位置。strops()函数将比较整个字符串，而且返回字符串"str2"第1次出现的位置。而strrpos()函数只比较字符串的首字符，而且返回字符最后一次出现的位置。程序的运行结果如图8.4所示。

图　8.4　字符串查找函数的使用程序运行效果图

注意　字符串查找函数如果没有找到子串，则这两个函数的返回值均为空值。

8.1.3　特定字符的替换

前面介绍了查找函数，接下来介绍替换函数。该函数的作用是将字符串"str"某些子字符串替换为另一个子字符串，然后将新的字符串返回。如果指定的子字符串在字符串中不存在，此函数将返回空值。函数的格式如下所示：

string str_replace(string substr,string newstr,string str)

在此格式中，str_replace为字符串替换函数，其中"substr"为指定的子字符串，"newstr"为要替换的字符串，"str"为字符串。下面通过实例来介绍PHP的字符串替换函数的使用。实例代码如代码8.5所示。

代码8.5　字符串的替换函数的使用程序：8-5.php

＜html＞

＜!程序名称：8-5.php＞

＜!程序功能：字符串的替换函数的使用＞

＜head＞

＜title＞字符串的替换函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$str="abcdeabcde";

echo str_replace("ab","ba",$str);//把字符串"ab"替换成字符串"ba"

echo"＜br＞";

echo str_replace("cd","dc",$str);//把字符串"cd"替换成字符串"dc"

?＞

＜h1＞

＜/body＞

＜/html＞

该程序中使用字符串替换函数str_replace()，把指定的子字符串替换成新的子字符串，最后把新的字符串返回。程序的运行结果如图8.5所示。

图　8.5　字符串替换函数的使用程序运行效果图

注意　字符串替换函数中如果指定的子字符串在字符串中不存在，此函数将返回空值。

8.1.4　比较字符串

字符串比较函数用于对字符串的大小进行比较以及字符串相似度比较等。如果"str1"＞"str2"则返回值为1；如果字符串"str1"＜"str2"则返回值为-1；如果两个字符串相等，则返回值就会是0，实现这样功能的函数是strcasecmp()、strcmp()。这两个函数的区别在于strcasecmp()函数是不区分大小写的，而strcmp()函数是区分大小写的。其格式如下所示：

int strcasecmp(string str1,string str2)

int strcmp(string str1,string str2)

其中，strcasecmp()和strcmp()是字符串的一种比较函数，strcasecmp()函数不区分大小写，而strcmp()函数是区分大小写的。下面就通过具体实例来介绍字符串比较函数的使用，程序如代码8.6所示。

代码8.6　字符串的比较函数的使用程序：8-6.php

＜html＞

＜!程序名称：8-6.php＞

＜!程序功能：字符串的比较函数的使用＞

＜head＞

＜title＞字符串的比较函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$str1="ab";//设置变量

$str2="abc";//设置变量

echo strcasecmp($str1,$str2);//变量的比较

echo"＜br＞";//换行

echo strcmp($str2,$str1);//变量的比较

echo"＜br＞";

echo strcasecmp("abc","ABC");//变量的比较

echo"＜br＞";

echo strcmp("abc","ABC");//变量的比较

echo"＜br＞";

?＞

＜h1＞

＜/body＞

＜/html＞

该程序中使用strcasecmp()和strcmp()两个字符串比较函数。字符串的比较函数用于比较两个字符串的大小。如果"str1"＞"str2"，则返回值为1；如果字符串"str1"＜"str2"，则返回值为“-1”；如果两个字符串相等，则返回值就会是0。程序的运行结果如图8.6所示。

图　8.6　字符串比较函数的使用程序运行效果图

注意　strcasecmp()函数是不区分大小写的，而strcmp()函数是区分大小写的。

作用　字符串比较函数，可以用来对两字符串的大小等就行判断，也可以用来实现如用户名及密码的判断。

与上面函数不同的是strcspn()和strspn()函数。strcspn()函数是返回从字符串一首部开始，完全由字符串二中任一字符的子字符串长度；而函数strspn()是返回从字符串一首部开始，完全由字符串二中字符所构成的子字符串的长度。函数的格式如下所示：

int strcspn(string str1,string str2)

int strspn(string str1,string str2)

其中，strcspn()和strspn()为字符串比较函数。其中的参数分别为字符串一和字符串二。下面通过实例来介绍PHP中的比较函数的使用，如代码8.7所示。

代码8.7　字符串的比较函数的使用程序：8-7.php

＜html＞

＜!程序名称：8-7.php＞

＜!程序功能：字符串的比较函数的使用＞

＜head＞

＜title＞字符串的比较函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$str1="student";//设置变量1的值

$str2="define";//设置变量2的值

$str3="final";//设置变量3的值

$str4="definef";//设置变量4的值

echo strcspn($str1,$str2);//比较变量1和变量2的值

echo"＜br＞";

echo strspn($str3,$str4);//比较变量3和变量4的值

echo"＜br＞";

?＞

＜h1＞

＜/body＞

＜/html＞

在程序中，变量1中共有d、e、f、i、n 5个字母，变量2的值student中第4个字符包含在变量1的值define中，所以返回值为3；变量3的值final中的f、i、n 3个字符皆包含在变量4的值dcfinef中，所以返回值为3。程序运行效果如图8.7所示。

图　8.7　字符串的比较函数的使用程序运行效果图

注意　字符串比较函数strcasecmp()和strcmp()二者的区别。

8.1.5　字符串类型转换

字符串类型的转换函数用于将一种数据类型转换为另一种数据类型。下面给出3种类型转换函数和一个通用转换函数。类型转换函数的格式如下所示：

double doubleval(mixed var)

int intval(mixed var,int[base])

string strval(mixed var)

int settype(mixed var,string type)

其中，"mixed var"代表简单数据类型，不包括数组和对象；函数intval()中的"int[base]"是可选参数，表示以何种进位制进行转换为整数；doubleval()函数会将变量强制转换为浮点型；intval()函数将变量强制转换为整型；strval()函数将变量强制转换为字符串。在通用的类型转换函数中，"string type"只能是以下值：integer、double、string、array及object。

该函数将变量var强制转换为string type参数中所指定的类型。如果返回成功，返回值为true，否则返回值为false。下面通过实例来介绍PHP中的类型转换函数的使用，实例程序如代码8.8所示。

代码8.8　字符串的类型转换函数的使用程序：8-8.php

＜html＞

＜!程序名称：8-8.php＞

＜!程序功能：字符串的类型转换函数的使用＞

＜head＞

＜title＞字符串的类型转换函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$var1="1.23e56abc";

$var2="12abc";

$var3="12z";

$var4=123;

$var5=123.56;

$var6="1.234e56abc";

echo doubleval($var1);//字符串转浮点型

echo"＜br＞";

echo intval($var2);//字符串转换整型

echo"＜br＞";

echo intval($var3,16);//先将字符串转换为数字，然后转换为十进制数

echo"＜br＞";

echo strval($var4);//整型转字符串

echo"＜br＞";

echo strval($var5);//浮点型转字符串

echo"＜br＞";

if(settype($var6,"double"))//判断变量

{

echo"$var6";

echo"＜br＞";

echo"type of\$svar is".gettype($var6);

echo"＜br＞";

}

?＞

＜h1＞

＜/body＞

＜/html＞

程序中使用了类型转换函数，把字符串转换成整型，以及把整型转换成字符串等操作。程序的运行效果如图8.8所示。

图　8.8　字符串类型转换函数的使用程序运行效果图

注意　在十六进制中，a～f和A～F也是合法的能充当数字的字符，例如intval（"12a"，16）将输出“298”，因为十六进制的"12a"也就是十进制的“298”。

作用　此函数的作用是把不是所需进制的字符转换成作者需要的进制码。

8.2　数组处理函数

数组就是将一系列的数值或字符串作为一单元来处理。它由两部分组成：数组名和下标。数组名是唯一的，下标表示了数组中数据的位置，其可以是数字也可以是字符。这个结构可以作为变量。读者可以赋值给数组，也可以把数组的值传给函数。在使用数组前不需要声明，与变量一样，数组的元素是动态生成的。

8.2.1　建立数组的方法

PHP中的数组可以是一维或者多维数组，其成员可以是整型、布尔型、浮点型和字符串。PHP也支持以数字为下标的数组和以字符串为下标的数组，二者没有区别。在PHP中可以list()函数或array()函数来创建数组，也可以直接给函数进行赋值。下面就使用函数arrat()来创建数组，程序如代码8.9所示。

代码8.9　函数的创建程序：8-9.php

＜html＞

＜!程序名称：8-9.php＞

＜!程序功能：数组的创建＞

＜head＞

＜title＞数组的创建＜/title＞

＜/head＞

＜body＞

＜?php

$myarr=array//设置数组

(

0=＞1,

2=＞1.111e2,

1=＞"php",

"str"=＞"string"

);

for($i=0;$i＜count($myarr);$i++)//通过循环输出

{

$Print=each($myarr);//把函数赋值给变量

echo"$Print[value]＜p＞";//输出数组值

}

?＞

＜/body＞

＜/html＞

程序中使用array()函数创建了一个数组，其中“=＞”符号用来向数组元素赋值，通过for循环输出整个数据。程序的运行结果如图8.9所示。

图　8.9　函数的创建程序运行效果图

注意　“=＞”符号用来向数组元素赋值，也可以直接给函数赋值。

PHP中数组的下标只是作为以后存取数组的一个标识，没有序号意义，而数组的排列顺序是以加入时的先后顺序为准。PHP也支持多维数组，多维数组与一维数组的区别是多维数组有两个或多个下标，但它们的用法基本一样。多维数组的实例如代码8.10所示。

代码8.10　多维数组的创建程序：8-10.php

＜html＞

＜!程序名称：8-10.php＞

＜!程序功能：多维数组的创建＞

＜head＞

＜title＞多维数组的创建＜/title＞

＜/head＞

＜body＞

＜?php

$myarr[0][0]=1;//设置多维数组值

$myarr[0][1]=1.111e2;//设置多维数组值

$myarr[1][0]="php";//设置多维数组值

$myarr[1]["str"]="string";//设置多维数组值

for($i=0;$i＜count($myarr);$i++)//通过循环控制数组

{

for($j=0;$j＜count($myarr[$i]);$j++)//双重循环

{

$Print=each($myarr[$i]);

echo"$Print[value]＜p＞";

}

}

?＞

＜/body＞

＜/html＞

程序中使用了多维数组并赋值，通过for循环的嵌套把整个多维数组输出，运行效果如图8.10所示。

图　8.10　多维数组的创建程序运行效果图

作用　可以使用在数据的存储过程中，例如从数据库中读取数据，把数据先放在数组中，然后在显示在页面中。

8.2.2　数组的创建与赋值函数

数组的创建与赋值函数有array range()和void list()两个函数，其作用是数组的创建和赋值，用于对一个数组进行初始化。

函数array range()的作用是给一组变量一次性赋值。函数void list()的作用是创建一个包含连续的整数的数组，返回的数组下标从0开始。函数的格式如下所示：

void list()

array range(int low,int high)

其中，low表示数组的赋值的开始值。high表示数组的赋值的结束值。该函数的使用程序如代码8.11所示。

代码8.11　数组函数的使用程序：8-11.php

＜html＞

＜!程序名称：8-11php＞

＜!程序功能：数组函数的使用＞

＜head＞

＜title＞数组函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

list($var1,$var2,$var3)=array("a","b","c");//通过函数给变量赋值

list($var4,$var5,$var6)=array(1=＞"a",3=＞"b","c");//通过函数给变量赋值

echo"$var1,$var2,$var3";//输出变量的值

echo"＜br＞\n";

echo"$var4,$var5,$var6";//输出变量的值

echo"＜br＞\n";

$arr=range(1,10);//通过函数给数组赋值

for($n=0;$n＜count($arr);$n++)//循环

{

echo"\$arr[$n]=$arr[$n];\n";//输出数组的值

}

?＞

＜/body＞

＜/html＞

程序中使用函数array range()给一组变量一次性赋值。使用函数void list()创建一个包含连续的整数的数组，并赋值。使用for循环把整个数组的返回值输出。运行效果如图8.11所示。

图　8.11　数组函数的使用程序运行效果图

8.2.3　对数组下标的操作函数

对数组下标的操作是通过数组的属性与遍历函数来实现的。数组的属性与遍历函数主要用于与数组下标相关的操作。

（1）函数count()用于计算变量中元素的个数。如果变量为空值，则会返回0；如果变量是普通数据类型，则返回的值是1；如果是数组，那么将会返回数组元素的个数。而函数sizeof()只能使用于数组，返回的值也是数组元素的个数。函数的格式如下所示。在PHP的数组中，系统会用一个指针指向当前处理的元素，在默认情况下该指针指向数组的第1个元素。

int count(mixed var)

int sizeof(array arr)

（2）函数prev()的作用是返回前一个元素的值，并且将指针前移；函数next()的作用是返回后一个元素的值，并且将指针后移。其函数的格式如下所示：

mixed current(array arr)

mixed prev(array arr)

mixed next(array arr)

（3）PHP中还提供将数组的指针移至最前或最后的函数reset()和函数end()。函数reset()的作用是将数组指针移至最前，并返回数组的第1个元素的值；函数end()的作用却是将数组的指针移至最后，并返回最后数组元素的最后一个元素的值。函数的格式如下所示：

mixed reset()

mixed end()

（4）PHP中也提供了返回数组下标值的函数和返回当前元素值的函数，它们分别是key()和pos()函数。函数key()的作用是将数组当前元素的下标值返回；而函数pos()的作用是返回当前元素的值。函数的格式如下所示：

mixed key(array arr)

mixed pos(array arr)

（5）函数each()的作用是将数组当前元素的下标和元素的值取出来，并将数组指针前移一位。其返回值是一个包含4个元素的数组，其数组中有0、1、key、value4个下标，0和key下标对应的是数组元素的下标值，1和value下标对应的是数组元素的值。如果指针越界，函数就会返回值false。此函数与for循环语句结合使用就可以实现数组的遍历。函数的格式如下所示：

array each(array arr)

上面介绍的是对数组下标的操作函数，下面通过一个实例来介绍这些函数是如何使用的，实例代码如代码8.12所示。

代码8.12　对数组下标的操作函数的使用程序：8-12.php

＜html＞

＜!程序名称：8-12.php＞

＜!程序功能：对数组下标的操作函数的使用＞

＜head＞

＜title＞对数组下标的操作函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$arr=array("one","two","three","four");//函数count()sizeof()的使用

echo count($arr);//输出元素的个数

echo"＜br＞";

echo sizeof($arr);//数组元素的个数

$arr1=array(0,1,2,3,4,5);//函数current()、prev()、next()的使用

for($i=0;$i＜3;$i++)//循环变量

echo($arr1);//输出数组1

echo current($arr1);//输出元素的个数

echo"＜br＞";

echo prev($arr1);//输出前一个元素的值

echo"＜br＞";

echo next($arr1);//输出下一个元素的值

echo"＜br＞";

$arr2=array(0,1,2,3,4,5);//函数reset()和end()的使用

echo end($arr2);//把数组的指针移到最后

echo"＜br＞";

echo reset($arr2);//把数组的指针移到最前

echo"＜br＞";

$arr3=array("a"=＞0,"b"=＞1,"c"=＞2,"d"=＞3);//函数key()和函数pos()的使用

next($arr3);//下一个元素

echo key($arr3)."=".pos($arr3);//输出数组的下标值和当前元素值

echo"＜br＞";

$arr4=array("a","b","c","f","e","d");//函数each()的使用

for($i=0;$i＜count($arr4);$i++)

{

$output=each($arr4);

echo"\$arr4[$output[key]]=$output[value];\n";

}

?＞

＜/body＞

＜/html＞

该程序通过对数组下标的操作函数的使用，返回数组中元素的下标值与数组元素的值。函数each()结合for循环使用，可以实现数组的遍历。程序的运行效果如图8.12所示。

图　8.12　对数组下标操作函数的使用程序运行效果图

注意　函数sizeof()只能使用于数组，返回的值也是数组元素的个数。

8.2.4　使用排序函数实现数组元素的排序

数组排序函数用于对一个数组中的所有元素进行排序，可以以下标为索引，也可以以值为索引，排序可以是顺序，也可以是逆序。

（1）PHP中提供了顺序排序函数和逆序排序函数，它们分别是asort()和arsort()函数。这两个函数都会对数组参数进行排序，不同的是assort()函数是顺序排序，而arsort()函数是逆序排序。这两个函数在使用后都不会改变数组索引与值之间的关联关系。函数的格式如下所示：

void assort(array arr)

void arsort(array arr)

（2）PHP还提供了使用函数后数组的索引和值不能是对应关系的函数，它们分别是sort()和rsort()函数。这两个函数与上面所介绍的函数使用法基本相同，惟一的区别在于使用此函数后数组的索引和值不是对应关系了。这两个函数的格式如下所示：

void sort(array arr)

void rsort(array arr)

（3）接下来介绍的函数ksort与上面所介绍函数不同的是，它是按数组索引进行的排序函数。其格式如下所示：

int ksort(array arr)

（4）下面介绍的这3个函数也是用于数组的排序，与前面的数组排序函数的不同处，就是它们是在用户指定的关键字比较函数compare_function()的基础上进行排序的。这3个函数之间的区别如下。

❑usort()函数按数组元素进行的排序，而且会改变数组下标与值的对应关系。

❑uasort()函数是按数组元素的值进行的排序，但是不会改变数组下标与值的对应关系。

❑uksort()函数按数组元素的下标进行排序，也不改变数组下标与值的对应关系。

下面通过实例来介绍PHP中的排序函数，如代码8.13所示。

代码8.13　使用排序实现数组元素的排序程序：8-13.php

＜html＞

＜!程序名称：8-13.php＞

＜!程序功能：使用排序实现数组元素的排序＞

＜head＞

＜title＞使用排序实现数组元素的排序＜/title＞

＜/head＞

＜body＞

＜?php

$arr1=array("a","b","c","f","e","d");//通过数组给变量赋值

arsort($arr1);//把数组1逆序排序

for($i=0;$i＜count($arr1);$i++)//循环

{

$output=each($arr1);//输出数组1

echo"\$arr1[$output[key]]=$output[value];\n";

}

echo"＜p＞";

asort($arr1);//对数组1进行排序

for($i=0;$i＜count($arr1);$i++)//循环变量

{

$output=each($arr1);//输出数组1

echo"\$arr1[$output[key]]=$output[value];\n";

}

$arr2=array("a","b","c","f","e","d");//sort()、rsort()的使用

rsort($arr2);//值不能是对应关系的函数

for($i=0;$i＜count($arr2);$i++)//循环变量，值在0到count($arr2)之间

{

echo"\$arr2[$i]=$arr2[$i];\n";//输出数组

}

echo"＜p＞";

sort($arr2);

for($i=0;$i＜count($arr2);$i++)

{

echo"\$arr2[$i]=$arr2[$i];\n";

}

$arr3=array("d"=＞"one","c"=＞"two","b"=＞"three","a"=＞"four");//ksort()的使用

ksort($arr3);

for($i=0;$i＜count($arr3);$i++)

{

$output=each($arr3);

echo"\$arr3[$output[key]]=$output[value];\n";

}

function cmp($arg1,$arg2)//usort()、uasort()、uksort()的使用

{

if($arg1==$arg2)return o;

return($arg1＞$arg2)?-1:1;

}

$arr4=array(3=＞"a",2=＞"b",1=＞"c",4=＞"d",0=＞"e");

usort($arr4,cmp);//按数组排序

while(list($key,$value)=each($arr4))

{

echo"\$arr4[$key]=$value;\n";//输出数组4

}

echo"＜br＞";

$arr5=array(3=＞"a",2=＞"b",1=＞"c",4=＞"d",5=＞"e");

uasort($arr5,cmp);//按数组的值排序

while(list($key,$value)=each($arr5))

{

echo"\$arr5[$key]=$value;\n";//输出数组5

}

echo"＜br＞";

$arr6=array(3=＞"a",2=＞"b",1=＞"c",4=＞"d",5=＞"e");

uksort($arr6,cmp);//按数组元素下标排序

while(list($key,$value)=each($arr6))

{

echo"\$arr6[$key]=$value;\n";//输出数组6

}

?＞

＜/body＞

＜/html＞

该程序使用了排序函数实现数组元素的排序。其中排序后的索引与值的对应关系没有发生变化的只有each()函数。函数cmp()的使用是自定义一个比较方案。程序运行效果如图8.13所示。

图　8.13　使用排序实现数组元素的排序程序运行效果图

注意　排序后的索引与值的对应关系没有发生变化的函数是each()。

8.2.5　使用动态操作函数实现数组动态扩充

数组动态操作函数用于数组的动态扩充，利用这些函数可以完成栈队列的功能。实现数组动态扩充功能的函数有：array_push()函数的作用是将一个或多个元素压入数组末尾，并将数组扩充，函数返回扩充后的数组中元素的个数；array_pop()函数的作用是从数组的末尾弹出一个元素返回，并将数组长度减1；array_unshift()函数的作用是将一个或多个元素压入数组头部，将数组扩充，函数返回扩充后的数组中元素的个数；array_shift()函数的作用是从数组头部弹出一个元素返回，并将数组的长度减1。函数的格式如下所示：

int array_push(array array,mixed var,[...])

mixed array_pop(array array)

int array_unshift(array array,mixed var,[...])

mixed array_shift(array array)

利用这些函数可以实现数据结构中栈和队列的功能。下面通过一个实例来介绍使用动态操作函数实现数组动态扩充，如代码8.14所示。

代码8.14　使用动态操作函数实现数组动态扩充程序：8-14.php

＜html＞

＜!程序名称：8-14.php＞

＜!程序功能：使用动态操作函数实现数组动态扩充＞

＜head＞

＜title＞使用动态操作函数实现数组动态扩充＜/title＞

＜/head＞

＜body＞

＜?php

$arr=array("a","b","c");//数组函数的使用

while(list($key,$value)=each($arr))

echo"\$arr[$key]=$value;";//输出结果

echo"＜br＞";

array_push($arr,1,2);//输出数末尾的值

echo"从数组末尾压入1\2:";

echo"＜br＞";//换行

reset($arr);

while(list($key,$value)=each($arr))

echo"\$arr[$key]=$value;";

echo"＜br＞";

echo"从数组末尾弹出:".array_pop($arr);

echo"＜br＞";

reset($arr);//设置变量

while(list($key,$value)=each($arr))

echo"\$arr[$key]=$value;";

echo"＜br＞";

array_unshift($arr,3,4);

echo"从数组头部压入3,4:＜br＞";

reset($arr);

while(list($key,$value)=each($arr))

echo"\$arr[$key]=$value;";

echo"＜br＞";

echo"从数组头部弹出:".array_shift($arr)."＜br＞";

reset($arr);

while(list($key,$value)=each($arr))

echo"\$arr[$key]=$value;";

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序使用动态操作函数实现数组动态扩充。利用程序中的这些函数可以实现数据结构中栈和队列的功能。程序的运行效果如图8.14所示。

图　8.14　使用动态操作函数实现数组动态扩充程序运行效果图

8.3　数学运算函数

PHP提供了大量数学运算函数来实现长整型和浮点型的各种运算，其返回结果也只限于这两种数据类型。如果要实现高精度的数学运算，就要使用BC高精度运算函数库了。这里介绍常用的数学运算函数，并没有涉及BC函数库。

8.3.1　常用数学运算函数

PHP中的常用数学运算函数有算术、幂指对函数、进位制函数、三角、反三角函数。下面介绍这些函数的使用语法。

（1）PHP提供的用来求一个数的绝对值的函数是mixed abs（mixed num），其格式如下所示。

mixed abs(mixed num)

（2）PHP还提供了3个取整函数，它们不同处是：floor()函数是将实数向下取整；而round()函数五舍六入取整；ceil()函数是向上取整。这3个函数的格式如下所示：

int floor(floar num)

int round(float num)

int ceil(float number)

（3）PHP也提供了指数幂的运算函数，exp()函数用于计算以"e"为底数，以"expe"为指数的幂运算。pow()函数用于计算以base为底数，以expe为指数的幂。函数的格式如下所示：

float exp(float expe)

float pow(folat base,float expe)

（4）PHP也提供了计算平方根的函数，sqrt()函数用于求一个数的平方根。其格式如下所示：

float sqrt(float num)

（5）PHP不仅仅于此，还提供了计算对数的函数，log()函数是计算以e为底的对数，log10()函数是计算以10为底的对数。其格式如下所示：

float log(float num)

float log10(float num)

（6）PHP也提供了两个用于取得参数中的最大值和最小值的函数。函数所接受的参数应该有两个或多个，而且这些参数应当是数值或字符串。函数返回值的类型与最大元素或最小元素的类型一致。函数在进行比较时，如果参数全是字符串，则按ASCII码值进行比较；如果参数全是数值类型，则按数值大小进行比较，其函数的格式如下所示：

mixed max(mixed arg1,mixed arg2,…mixed argn)

mixed min(mixed arg1,mixed arg2,…mixed argn)

（7）PHP提供的进位制转换函数是base_convert()，这是PHP通用的进位制转换函数，其格式如下所示：

string base_convert(string number,int frombase,int tobase)

其中，参数number是由字符组成的数字，参数frombase是原进位制，而参数tobase是要转换成的进位制。函数返回转换后的结果，如果有错误，就会返回0。

（8）PHP提供了3个函数用于三角型的计算函数，分别为正弦、余弦、正切函数，所接受的参数均为浮点型的弧度值，其格式如下所示：

float sin(floart arg)

float cos(floart arg)

float tan(floart arg)

PHP中提供了这些算术、幂指对函数、进位制函数、三角、反三角的函数，对这些函数的实例程序如代码8.15所示。

代码8.15　幂指对函数、进位制函数、三角、反三角函数的使用程序：8-15.php

＜html＞

＜!程序名称：8-15.php＞

＜!程序功能：幂指对函数、进位制函数、三角、反三角函数的使用＞

＜head＞

＜title＞幂指对函数、进位制函数、三角、反三角函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

/*幂指对函数的使用*/

echo abs(-10);

echo"＜br＞";

echo floor(23.45);

echo"＜br＞";

echo round(123.678);

echo"＜br＞";

echo ceil(23.45);

echo"＜br＞";

/*圆周率的输出*/

echo pi();

echo"＜br＞";

echo exp(8);

echo"＜br＞";

echo pow(8,2);

echo"＜br＞";

echo sqrt(16);

echo"＜br＞";

echo log(5);

echo"＜br＞";

echo log10(8);

echo"＜br＞";

/*最大，最小函数的使用*/

$max=max(2.1,"2.1");

echo"(2.1,\"2.1\")"."最大值$max,"."类型".gettype($max);

echo"＜br＞";

$min=min(2.1,"2.1");

echo"最小值$min,"."类型".gettype($min);

echo"＜br＞";

$max=max("al","2.1");

echo"(\"al\",\"2.1\")"."最大值$max"."类型".gettype($max);

echo"＜br＞";

$min=min(1,"al","2.1");

echo"最小值$min"."类型".gettype($min);

echo"＜br＞";

echo number_format(123456.89);

echo"＜br＞";

echo number_format(123456.89,7);

echo"＜br＞";

/*进位制函数的使用*/.

echo base_convert("35",10,2);

echo"＜br＞";

echo base_convert("35","10",16);

echo"＜br＞";

/*三角，反三角函数的使用*/

echo sin(M_PI/6);

echo"＜br＞";

echo cos(M_PI);

echo"＜br＞";

echo tan(M_PI/2);

?＞

＜/body＞

＜/html＞

其中常量M_PI代表圆周率，使用pi()可以返回圆周率的值。如果参数既有字符串类型又有数值类型，函数将参数的类型以第1个参数为准进行强制转换，然后进行大小比较。程序运行结果如图8.15所示。

图　8.15　幂指对函数、进位制函数、三角、反三角函数的使用程序运行效果图

注意　如果在大小比较函数中只输入了一个参数，PHP语法分析器会给出警告，函数的返回值为空。如果函数的参数是数组，程序将无法通过。

在浮点格式的输出函数中，参数dec_point和thousands_sep都只能包含一个字符，否则分隔符将使用默认分隔符。在三角、反三角函数中，如果运算结果超出浮点数所能表示的范围，将以系统所能显示的最大数或最小数为返回值。

8.3.2　随机数的设定与获取

随机数的设定与获取是用srand()函数给随机数产生器设置当前的时间，使用rand()函数在最小值和最大值间产生一个随机数，使用getrandmax()函数返回rand()函数所能产生的最大随机数。函数的格式如下所示：

void srand(int seed)

int rand([int min],[int max])

int getrandmax()

在此程序中，参数seed表示当前的时间，min和max是设置随机数的最小和最大值。下面通过实例来介绍随机函数，如代码8.16所示。

代码8.16　随机函数的使用程序：8-16.php

＜html＞

＜!程序名称：8-16.php＞

＜!程序功能：随机函数的使用＞

＜head＞

＜title＞随机函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

srand(time());//产生时间

echo rand(1,100);//产生最大的随机数

echo"＜br＞";

echo rand(1,1000);//产生1～1000的最大随机数

echo"＜br＞";

echo rand(10,90);

echo"＜br＞";

echo getrandmax();

echo"＜br＞";

?＞

＜/body＞

＜/html＞

该程序中给随机数产生器设置当前的时间，设置随机数从最小值和最大值间产生一个随机数，返回随机函数所能产生的最大随机数。程序的运行效果如图8.16所示。

图　8.16　随机函数的使用程序运行效果图

注意　使用getrandmax()函数返回rand()函数所能产生的最大随机数。一般输出“32767”。

8.4　日期与时间函数

PHP提供了时间和日期函数，时间和日期函数就是当前时间和日期的格式化输出。通常时间和日期函数是把系统的时间和日期输出到网页中。

8.4.1　时间、日期的输出格式

时间和日期的获取是通过data()函数和gmdata()函数来实现的。这两个函数的作用是将当前时间和日期的格式化输出。其格式如下所示：

string data(string format,int[timestamp])

string gmdata(string format,int timestamp)

其中，参数timestamp的中文名可翻译为“时戳”，通常表示从系统建立到当前时间的时间长度，一般以秒为单位；data()函数是输出本地的日期和时间，如果不指定timestamp的值，则其值为默认为本地当前的timestamp的值；gmdata()函数是输出格林尼治日期和时间；timestamp为必需参数；format表示指定日期和时间输出的格式。format的输出格式如表8.1所示。

此表为时间和日期的输出格式。下面通过一个实例来介绍时间函数和时间、日期的输出格式的使用，如代码8.17所示。

代码8.17　时间函数和时间、日期的输出格式的使用程序：8-17.php

＜html＞

＜!程序名称：8-17.php＞

＜!程序功能：时间函数和时间、日期的输出格式的使用＞

＜head＞

＜title＞时间函数和时间、日期的输出格式的使用＜/title＞

＜/head＞

＜body＞

＜?php

/*两种时间函数的使用*/

echo"本地时间：".date("Y年m月j日，I,H:i:s");//输出本地时间

echo"＜br＞";

echo"GMT时间：".gmdate("Y年m月j日，I,H:i:s",

mktime(date(H),date(i),date(s),date(n),date(j),date(Y)));//时间函数的使用

?＞

＜/body＞

＜/html＞

在程序中，使用时间和日期函数获取了本地时间和日期，然后通过固定的格式输出，其中"Y"是以3个数字显示年，"m"表示以两个数字表示月，"j"表示以两个数字表示日。程序的运行效果如图8.17所示。

图　8.17　时间函数和输出格式的效果图

8.4.2　检验输入的日期是否合法

PHP还提供了用于检验输入的日期是否合法的函数checkdate()，其格式如下所示：

int checkdate(int month,int day,int year)

其中，参数month表示月，其合法范围是1～12之间。参数day表示日，其合法范围是由参数月来决定的，系统会自动考虑到闰年；参数year表示的是年，合法的使用范围是0～32767。下面通过一个实例来介绍PHP中的检验日期函数的使用，如代码8.18所示。

代码8.18　PHP中的检验日期函数的使用程序：8-18.php

＜html＞

＜!程序名称：8-18.php＞

＜!程序功能：PHP中的检验日期函数的使用＞

＜head＞

＜title＞PHP中的检验日期函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

echo checkdate(4,23,2008);//返回值为1

echo"＜br＞";

echo checkdate(4,231,2008);//返回值为空

?＞

＜/body＞

＜/html＞

在此程序中使用了检验日期函数，是用于输入日期是否合法的检验。如果输入的日期是合法的，那么返回值为true，如果输入的日期不是合法日期，那么返回值为false。程序的运行效果如图8.18所示。

图　8.18　PHP中的检验日期函数的效果图

注意　PHP中对日期输入是否合法检验函数的参数，在使用时要注意它的合法范围。

8.5　目录与文件函数

PHP中提供了目录与文件的操作函数。目录操作函数是将目录读取、复位、关闭等操作；而文件函数是对文件进行打开、读取、写入、关闭等操作。对于文件函数来说，在网络编程中要用到两种类型的文件操作：一种是普通的文件操作，另一种是数据库文件操作。这里要讲述的是普通文件操作函数，而对于数据库文件的操作将在下面的章节进行介绍。

8.5.1　目录操作函数

目录函数用于实现目录的操作，包括目录的读取、复位、关闭等。下面对目录操作函数进行介绍。

（1）用于改变当前目录的操作函数是chdir()，如果操作成功，其返回值为true；如果操作不成功，其返回值为false。函数的格式如下所示。其中，参数directory是指要操作的目录名。如果操作成功就会返回1，否则返回0。

int chdir(string directory)

（2）PHP中实现把目录名转换成一个对象的函数是dir()，它是将输入的目录名转换成一个对象并返回。返回的对象中有两个属性和3个方法，如表8.2所示。

表中的3个方法与下面要介绍的函数readdir()、rewinddir()和closedir()的作用是相同的。这3个函数的格式如下所示：

string readdir(int dir_handle)

void rewinddir(int dir_handle)

void closedir(int dir_handle)

（3）函数readdir()的作用是读取目录中句柄指针当前所指的文件，并返回文件名；函数rewinddir()的作用是将目录句柄指针移到顶端，相当于把指针指向“.”目录；函数closedir()的作用就是关闭已经打开的目录；而打开目录的函数是opendir()，作用是将指定的目录打开，并返回目录的句柄。下面通过实例来介绍这些函数的使用，如代码8.19所示。

代码8.19　PHP中目录操作函数的使用程序：8-19.php

＜html＞

＜!程序名称：8-19.php＞

＜!程序功能：PHP中目录操作函数的使用＞

＜head＞

＜title＞PHP中目录操作函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$handle=opendir("C:\WINDOWS");//打开文件

rewinddir($handle);

while($filename=readdir($handle))//循环输出目录

{

echo$filename."\n";//输出文件名

}

closedir($handle);//关闭文件

?＞

＜/body＞

＜/html＞

在此程序中使用了目录打开函数打开"C:\WINDOWS"目录，然后通过函数rewinddir()把目录指针指向目录的顶端，使用读取函数读取出目录中的内容，最后关闭此目录。程序的运行结果如图8.19所示。

图　8.19　PHP中目录操作函数的使用程序运行效果图

注意　在使用目录操作函数时要注意，使用打开目录文件，在程序结束时，一定要记得把打开的目录文件关闭，避免系统资源的浪费。

8.5.2　文件打开与关闭操作

文件打开与关闭函数是用于创建和销毁与文件的链接。在进行文件操作前一般都要先打开文件，在文件操作完成后应该关闭文件。文件的打开和关闭函数的格式如下所示：

int fopen(string filename,string mode,int[use_include_path])

int fclose(int fp)

文件打开函数的功能是打开本地文件或一个由URL所指定的文件，并返回文件的指针，如果打开文件成功，返回值为true，否则返回值为false。参数use_include_path为可选参数。如果参数filename以"http://"开头就会找开一个与指定服务器的连接，并返回指向被请求文件的指针。由于此函数不处理HTTP重定向，所以必须在目录中包括斜杠。如果参数filename以"FTP://"开头就会打开一个与指定服务器的FTP连接，并返回指向被请求文件的指针，如果服务器不支持被动模式的FTP，此操作不成功。通过FTP可以将文件以读取或写入的方式打开，但是不能以读写的方式打开。

除上面的情况以外，参数filename都会认为是本地文件，函数将在本地文件系统中打开指定文件，并返回文件指针。参数mode表示打开文件的方式，可以是表8.3中所示的一个方式。

函数fclose()的作用是关闭已经打开的文件。参数fp是函数打开文件的指针。操作成功返回值为true，否则返回值为false。下面通过实例来介绍PHP中文件操作函数的使用，如代码8.20所示。

代码8.20　PHP中文件操作函数的使用程序：8-20.php

＜html＞

＜!程序名称：8-20.php＞

＜!程序功能：PHP中文件操作函数的使用＞

＜head＞

＜title＞PHP中文件操作函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$fp=fopen("E:\www\aa.txt","r+");//打开文件

fclose($fp);//关闭文件

?＞

＜/body＞

＜/html＞

此程序中，使用文件打开函数以读写方式打开"aa.txt"文件，然后通过关闭文件函数关闭此文件。因为没有做读取和写入操作，如果打开和关闭成功，程序运行结果是个空白页面；如果打开和关闭不成功，程序返回值为false。

注意　文件打开函数的参数filename以"http://"开头时。由于此函数不处理HTTP重定向，所以必须在目录中包括斜杠；如果以"FTP://"开头，通过FTP可以将文件以读取或写入的方式打开，但是不能以读写的方式打开。

8.5.3　文件信息获取函数

PHP中提供的文件信息获取函数，其作用是获取文件的保护模式、当前文件的链接数、所有者ID、字节数、最后一次访问的时间、最后一次修改时间等。获取文状态信息和符号链接状态的函数格式如下所示：

array stat(string filename)

array lstat(string filename)

stat()函数的作用是获取指定文件的状态信息。lstat()函数的作用是获取指定文件或符号链接的状态信息。这两个函数的用法相同，区别是如果参数filename是一个符号链接，此函数将会返回符号链接的状态，而不是符号链接所指向的文件的状态。

文件信息获取函数中判断文件是否存在、是否可读、是否可写、是否可执行的函数格式如下所示：

int file_exists(string filename)

bool is_readable(string filename)

bool is_writeable(string filename)

bool is_executable(string filename)

file_exists()函数的作用是判断指定文件是否存在，如果存在返回值为true，否则返回值false；is_readable()函数的作用是判断一个文件是否可以读取，如果此文件存在而且可读则返回值为true，否则返回值为false；is_writeable()函数的作用是判断一个文件是否可写，如果此文件存在而且是可写的，则返回值为true，否则返回值为false。参数也可以是一个目录，函数将判断目录是否可写。is_executable函数的作用是判断一个文件是否可执行，如果此文件存在而且是可执行的，则返回值为true，否则返回值为false；获取文件的权限的函数是fileperms()，此函数的作用是返回指定文件的权限，如果操作成功，返回值为true，否则返回值为false。下面通过实例来介绍PHP中文件信息获取函数的使用，代码如代码8.21所示。

代码8.21　PHP中获取文件信息函数的使用程序：8-21.php

＜html＞

＜!程序名称：8-21.php＞

＜!程序功能：PHP中获取文件信息函数的使用＞

＜head＞

＜title＞PHP中获取文件信息函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

echo"stat()的使用＜br＞";//stat()函数的使用

$arr1=stat("aa.txt");//文件名

for($i=0;$i＜count($arr1);$i++)

{

echo"\$arr1[$i]=$arr1[$i];";//输出变量

}

echo"＜br＞";

/*file_exists()等4函数的使用.*/

echo"判断文件是否存在、是否可读、是否可写、是否可执行的函数＜br＞";

echo file_exists("aa.txt")."＜br＞";

echo is_readable("aa.txt")."＜br＞";

echo is_writeable("aa.txt")."＜br＞";

echo is_executable("aa.txt")."＜br＞";

?＞

＜/body＞

＜/html＞

此程序中使用了获取文件状态信息的函数和判断文件是否存在、是否可读、是否可写、是否可执行的函数，进行对指定文件信息的获取。程序的运行效果如图8.20所示。

图　8.20　PHP中获取文件信息函数的使用程序运行效果图

注意　当lstat()函数的参数filename是一个符号链接时，此函数将返回符号链接的状态，而不是符号链接所指向的文件的状态。

8.5.4　如何对文件内容进行读和写

文件读写函数是文件夹类函数中最重要的一部分，PHP中的文件读写函数可以完成操作系统对文件所能完成的绝大部分功能。

（1）fgetc()函数的作用是取得文件指针处的字符并返回，如果当前指针在文件末尾，则返回值为false；fgetcsv()函数的作用是读取从文件指针处开始到行尾的内容，并用CSV方式进行分隔，将结果保存在一个数组中返回。如果文件指针在末尾，返回值为false。fgetss函数的作用是获取文件指针所在行的内容，与fgcts()函数不同的是，函数将去掉字符中的HTML及PHP。函数的格式如下所示：

string fgetc(int fp)

array fgetcsv(int fp,int length,string[delimiter])

string fgets(int fp,int length)

string fgetss(int fp,int length,string[allowable_tags])

（2）file()函数的作用是将指定文件读取到数组中，文件中的一行字符将对应数组中的一个元素，此函数将去掉字符中的HTML及PHP语言标记。函数的格式如下所示：

array file(string filename,int[use_include_path])

（3）readfile()函数的作用是读取一个文件至标准输出，返回值为从文件中读取的字节数。如果读取过程序中产生错误则返回false，同时显示错误信息。如果此函数用于@filename方式调用，则不显示错误信息。

（4）fpassthru()函数将当前文件指针所指处到文件末尾的所有数据输出，输出完成后关闭文件。如果成功，返回值为true，否则返回值为false。函数的格式如下所示：

int readfile(string filename,int[use_include_path])

int fpassthru(int fp)

（5）fread()函数作用是从文件指针"fp"所指处起，读取"length"字节长的数据并返回。当读取完成时，读取过程停止。函数的格式如下所示：

string fread(int fp,int length)

（6）fwrite()函数的作用是将字符串"string"中的内容写入指定文件中，如果指定了参数"length"，写入"length"字节后或到达"string"末尾后写入过程停止。fputs()函数与fwrite()函数的功能完全相同，写入成功，函数返回值为true，否则返回值为false。

下面通过实例来介绍PHP中文件的读写函数的使用，如代码8.22所示。

代码8.22　PHP中读写函数的使用程序：8-22.php

＜html＞

＜!程序名称：8-22.php＞

＜!程序功能：PHP中读写函数的使用＞

＜head＞

＜title＞PHP中读写函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$fp=fopen("aa.txt","r");//打开文件

for($i=1;$i＜15;$i++)//循环变量

{

echo fgetc($fp);//输出获取的文件信息

fseek($fp,$i);

}

echo"＜br＞".fgets($fp,1024)."＜p＞";

rewind($fp);//写入文件

while($arr=fgetcsv($fp,1024))

{

echo count($arr)."items:";

for($i=0;$i＜count($arr);$i++)

{

echo$arr[$i];

}

echo"＜br＞";

}

rewind($fp);

fgetss($fp,1024);

echo"＜br＞".fgetss($fp,1024)."＜br＞";

echo fgetss($fp,1024);

fclose($fp);

$fp1=fopen("aa.txt","r");//读取函数的使用

fseek($fp1,10);

echo fread($fp1,100)."＜p＞";

fclose($fp1);

$fp2=fopen("aa.txt","a");//写入函数的使用

$str="添加的内容\n";

fputs($fp2,$str);

fwrite($fp2,$str);

fclose($fp2);

?＞

＜/body＞

＜/html＞

此程序使用了文件操作函数，先把文件以只读取的方式打开然后进行读取操作，使用循环把读取到的内容输出到页面，接着进行写入操作，把指定的内容写入文件，最后关闭文件。程序的运行效果如图8.21所示。

图　8.21　PHP中读写函数的使用程序运行效果图

8.6　PHP实践—无数据库留言板

本节要设计一个留言板，是一个没有数据库的留言板。用户可以在留言板上输入用户信息和留言内容，并可以即时查看。由于处理少量数据的留言板简单易行，不使用数据库，因此读取硬盘就可以。要实现一个留言板，首先要规划好功能模块。一个简单的留言板至少包括以下两个文件。

❑留言板的处理脚本：读取留言文件，格式显示内容、写入模块、提供用户输入留言内容的表单。

❑留言内容存储文件：留言人姓名、留言的时间、E-mail地址、留言内容。规划流程图如图8.22所示。

图　8.22　留言板规划流程图

8.6.1　提交页面设计

提交页面就是一个信息提交的页面。需要用户输入用户名、E-mail地址和留言内容。信息输入完成后，单击“提交”按钮，把输入的信息提交给处理页面。提交页面的代码如代码8.23所示。

代码8.23　数据的提交页面程序：8-23.html

＜html＞

＜!程序名称：8-23.html＞

＜!程序功能：数据的提交页面＞

＜head＞

＜title＞留言板＜/title＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜/head＞

＜body＞

＜!—设置对齐方式--＞

＜div align="left"＞

＜p＞＆nbsp;＜/p＞

＜p＞

＜font size="5"＞我要发言＜/font＞

＜/P＞

＜!--表单--＞

＜form method="post"action="8-24.php"＞

＜p align="left"＞姓名：

＜input type="text"name="name"＞

＜/p＞

＜p align="left"＞EMAIL：

＜input type="text"name="email"＞

＜/p＞

＜p align="left"＞

留言内容：

＜/p＞

＜p align="left"＞

＜textarea name="nairong"cols="30"rows="5"＞

＜/textarea＞

＜/p＞

＜p align="left"＞

＜!--提交按钮--＞

＜input type="submit"name="submit"value="提交"＞

＜input type="reset"name="reset"value="重设"＞

＜/p＞

＜/from＞

＜p＞＆nbsp;＜/p＞

＜/div＞

＜/body＞

＜/html＞

注意　姓名、E-mail和留言内容类型的区别。姓名、E-mail是"text"类型，而留言内容是"textarea"类型，并要说明"rows"的值。

作用　此程序使用了表单，把用户输入的数据提交到处理页面，以此实现用户留言的发表。

上面的程序是一个简单的留言提交页面，如果读者觉得不够美观，可以修改此程序，使留言信息的提交页面更美观。程序的运行结果如图8.23所示。

图　8.23　提交页面的运行效果

8.6.2　对提交数据进行处理

图8.23所示的是提交数据的页面，那提交过来的数据会怎么处理呢？下面就看一下处理页面是怎么设计的。实例代码如8.24所示。

代码8.24　处理提交来的数据程序：8-24.php

＜?php

//程序名称：8-24.php

//程序功能：处理提交来的数据

if($name=="")//姓名不能为空

{

echo"姓名不能为空";//如果为空，则提示姓名不能为空

}

else

if($email=="")//判断E-mail是否为空

{

echo"Email不能为空";//如果为空，提示E-mail不能为空

}

else

if($nairong=="")//留言不能为空

{

echo"留言内容不能为空";

}

else

{

/*以可读写方式打开ly.txt文件用于存储留言，如果不存在新建一个*/

$fp=fopen("guestbook.dat","a++");

$t=date(Y年m月d日);//写入日期

$main="姓名:＜a href=\"mailto:$email\"＞//写入留言内容

$name＜/a＞:($t)＜br＞留言:$nairong＜br＞＜hr＞";

$write=fwrite($fp,$main);//写入文件

fclose($fp);

echo"留言成功";

}

?＞

本程序包括两方面：一方面是对姓名、E-mail、留言内容的判断，看是否为空；另一方面是对提交来的数据写入"guestbook.dat"。如果用户信息填写完成后，单击“提交”按钮，运行结果如图8.24所示；如果用户没有填姓名，提交后会出现“用户名不能为空”的提示；如果用户没有填写E-mail，提交后就会提示“E-mail不能为空”的提示。留言内容也是一样。

图　8.24　提交效果图

8.6.3　显示留言内容

一个留言板，不仅要把用户的留言写入数据文件，而且要把写入数据文件里的内容读出来，显示在页面上。下面就是显示留言内容的代码，如代码8.25所示。

代码8.25　显示留言内容程序：8-25.php

＜html＞

＜!程序名称：8-25.php＞

＜!程序功能：显示留言内容＞

＜head＞

＜title＞留言板＜/title＞

＜neta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜/head＞

＜div align="center"＞

＜table width="90%"border="0"＞

＜tr valign="top"＞

＜td height="395"＞

＜p align="center"＞留言簿：＜/p＞

＜p align="center"＞

＜?php

$f=fopen("guestbook.dat","a++");//打开文件

$msg=fread($f,filesize("guestbook.dat"));//读取文件

fclose($f);//关闭文件

echo"＜center＞$msg＜/center＞";//显示留言

?＞

……//省略部分代码

＜/html＞

注意　程序中打开文件进行读写操作，操作完成后要记住关闭文件。

作用　此程序是把数据从文件中读取出来，然后把数据显示在相应的位置。此程序也可以使用到新闻的发布等类似的读取文件中内容的程序中。

技巧　本程序中并没有使用数据库，是为了方便用户有不同的选择，在没有数据库的机器中也可以使用，因此把文件作为数据库来存储数据。使用文件操作函数打开文件，但要注意的是，使用此函数时，也要给定相应的权限。

该程序先是把要显示的内容从数据文件中读取出来，然后把读取出来的数据以一种指定的格式显示出来。下面就看看数据文件中用户的留言，结果如图8.25所示。从图中可以看出，留言薄的内容有用户的姓名、留言的时间、留言的内容。为了使每个用户留言的内容分开，在每两个用户留言的内容中间都会有一条横线。

图　8.25　读取留言内容的效果图

8.6.4　留言板的首页

前面把留言的每个模块都已做好了，现在就通过一个页面把前面的模块整合在一起，这样就可以使留言板显得不那么散乱了。程序如代码8.26所示。

代码8.26　留言板的首页程序：8-26.html

＜html＞

＜!程序名称：8-26.html＞

＜!程序功能：留言板的首页＞

＜head＞

＜!--页面标题--＞

＜title＞留言板＜/title＞

＜!--页面编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜/head＞

＜!--框架部分--＞

＜frameset cols="180,603*"frameborder="no"

border="0"framespacing="0"rows="*"＞

＜frame name="leftFrame"scrolling="no"noresize src="8-23.html"＞

＜frame name="mainFrame"src="8-25.php"＞

＜/frameset＞

＜noframes＞

＜body bgcolor="#ffffff"＞

＜/body＞

＜/noframes＞

＜/html＞

这样留言板就成功地设计完成了。程序运行结果如图8.26所示。这里的留言板首页是把前面的程序结合在一起的结果，这样无数据库留言板就实现了。

图　8.26　完整的留言板效果图

8.7　小结

本章介绍了PHP的常用函数，包括字符串处理函数、数组处理函数、数学运算函数、日期与时间函数和目录与文件函数。在字符串的处理函数中介绍了拆分字符串方法、字符串的查找和替换、比较字符串以及字符串类型转换。在数组处理函数中介绍了建立数组的方法、数组的创建与赋值函数、对数组下标的操作函数、使用排序实现数组元素的排序、使用动态操作实现数组动态扩充。在数学运算函数中介绍了数学运算函数、随机数的设定与获取等。通过本章的学习，相信读者对PHP的常用函数及其用法有了一定的了解。

本章最后学习了应用PHP实现无数据库的留言板，主要介绍了应用PHP怎么样去处理提交过来的留言内容，和对留言页面中用户信息，如姓名、E-mail、留言内容的验证。通过对本章的学习，读者可以清楚地知道，实现一个简单留言板的设计流程。首先设计留言信息的留言页面，再设计留言内容处理的页面，然后设计留言信息的显示页面，最后设计留言板的首页，也就是把留言信息页面和留言信息的显示页面结合起来。

第9章　MySQL数据库

本章将为读者介绍MySQL数据库。在网络编程中，数据库的应用是很广泛的。将大量信息存储在数据库中，可以方便地添加、删除，快速地检索、排序，只要是稍有规模的网站，都会使用到数据库。MySQL之所以流行，也是因为它是免费的数据库，使用它开发，会减少项目的成本。本章主要学习MySQL数据的一些基本操作，如果需要深入学习，则需要参考一些数据库的专业书籍。

9.1　认识并安装MySQL数据库

PHP支持众多数据库，而其中与MySQL的结合性最为完美。MySQL数据库是由瑞典TCX公司开发的，并随着Linux的普及逐渐获得了广泛的应用。MySQL是一个源码公开而且完全免费的产品，可用于大、中、小各种数据库应用场合。MySQL还适用于多种操作平台，而且支持多线程与多CPU。

9.1.1　认识MySQL数据库

MySQL数据库是多关系型数据库产品中的一个，相比其他数据库而言，MySQL数据库可以称为目前运行速度最快的SQL语言。除此外还具有许多其他数据库所不具有的功能和选择。MySQL数据库是一种完全免费的产品，用户可以从网上直接下载，用户可以是个人，也可是商业用户，都不用支付任何费用。MySQL数据库具有以下特点。

❑没有限制同时访问数据库的用户数量。

❑可以保存记录超过50 000 000条。

❑数据库系统的运行速度是目前所有产品中最快的。

❑可以简单、有效地进行用户权限的设置。

从MySQL数据库具有的以上特点可以看出，MySQL数据库是一个运行速度快、多线程、多用户和强大的SQL数据库服务器。MySQL可以运行在多种平台上，包括Windows NT、UNIX和Linux系统。MySQL是建立数据库驱动和动态网站的最佳数据库。PHP、MySQL和Apache是Linux平台网站的最佳组合。目前，国际上知名公司也开始把MySQL作为其数据库管理系统，这也充分证明了MySQL数据库的优越性能和广阔的发展前景。

9.1.2　安装数据库系统

如何得到MySQL数据库呢？维护MySQL的主要网站是http://www.MySQL.com，读者可以从这个网站下载MySQL数据库。在全球有许多MySQL数据库的镜像网站，可以选择一个就近的网站下载，这样可以比较快地得到MySQL数据库。中国用户可以从http://www.MySQL.cn/下载。得到了MySQL数据库后，接下来进行安装，笔者就以Windows 2003为例来进行介绍。首先要把下载的MySQL数据库压缩文件解压到指定目录。

（1）双击解压后的MySQL数据库文件中的"setup.exe"文件，会弹出MySQL数据库的安装窗口，如图9.1所示。在弹出的窗口中单击"Next"按钮，会弹出MySQL数据库安装类型设置窗口，如图9.2所示。

图　9.1　MySQL数据库的安装窗口

图　9.2　MySQL数据库安装类型设置窗口

（2）设置MySQL数据库的安装类型。在MySQL数据库安装类型设置窗口中有典型安装、完全安装和自定义安装。一般选择典型安装，既默认选项。然后单击"Next"按钮，会弹出MySQL数据库的准备安装程序窗口，如图9.3所示。

图　9.3　MySQL数据库的准备安装程序窗口

接下来单击"Install"按钮，弹出MySQL数据库的安装情况窗口和MySQL.com账户的创建窗口，如图9.4和图9.5所示。

图　9.4　MySQL数据库的安装情况窗口

图　9.5　MySQL.com账户的创建窗口

（3）MySQL. com账户的创建。在MySQL.com账户的创建窗口中有创建一个新账户、使用已有的账户、跳过此设置3个选项。在这里笔者选择了跳过此设置"Skip Sign-Up"选项，然后单击"Next"按钮，弹出完成安装向导窗口，如图9.6所示。

图　9.6　完成安装向导窗口

（4）MySQL数据库服务器的安装。单击"Finish"按钮，完成MySQL数据库的安装。此时会弹出MySQL数据库服务器的安装向导窗口，如图9.7所示。然后单击"Next"按钮，会弹出MySQL数据库服务器对象设置窗口，如图9.8所示。

图　9.7　MySQL数据库服务器的安装向导窗口

在图9.8所示的窗口中有详细配置和基本的配置，一般是默认选项"Detailed Configuration"。然后单击"Next"按钮会弹出MySQL数据库服务器选择种类窗口，如图9.9所示。

图　9.8　MySQL数据库服务器对象设置窗口

图　9.9　MySQL数据库服务器选择种类窗口

（5）在图9.9所示窗口中有3个选项，分别为开发者的机器、服务器、专业的MySQL数据库服务器。在此选择了开发者的机器"Developer Machine"选项。然后单击"Next"按钮，会弹出MySQL数据库用途选择窗口，如图9.10所示。

图　9.10　MySQL数据库用途选择窗口

在9.10所示的窗口中有3个选项，分别为多功能的数据库、唯一交易数据库、非唯一交易数据库。在这里笔者选择的是多功能的数据库"Multifunctional Database"选项，也就是默认选项。然后单击"Next"按钮，会弹出MySQL数据库的安装路径设置窗口，如图9.11所示。

图　9.11　MySQL数据库的安装路径设置窗口

（6）MySQL数据库的安装路径设置。在此窗口中可对MySQL数据库的安装路径进行设置，如果不修改，默认路径为C盘下。笔者选择的是D盘。然后单击"Next"按钮，会弹出MySQL数据库的连接用户的设置窗口，如图9.12所示。

图　9.12　MySQL数据库的连接用户的设置窗口

在图9.12所示的窗口中有3个选项，分别为决策支持系统、联机事务处理、手动设置连接数。在这里笔者选择的是决策支持系统"Decision Support（DSS）/OLAP"选项，也就是默认选项。然后单击"Next"按钮，会弹出MySQL数据库网络选项设置窗口，如图9.13所示。

图　9.13　MySQL数据库网络选项设置窗口

（7）在图9.13所示的窗口中使用默认就可以，不用修改。然后单击"Next"按钮，弹出MySQL数据库显示字体设置窗口，如图9.14所示。

图　9.14　MySQL数据库显示字体设置窗口

（8）在图9.14所示的窗口中，使用默认选项就可以。然后单击"Next"按钮，会弹出MySQL数据库操作模式的选择窗口，如图9.15所示。在图9.15所示的窗口中有两个选项，分别是"Install As Windows Service"和"Include Bin Directory in Windows PATH"选项，在这里使用默认选项。然后单击"Next"按钮，会弹出MySQL数据库密码设置窗口，如图9.16所示。

图　9.15　MySQL数据库操作模式的选择窗口

图　9.16　MySQL数据库密码设置窗口

（9）在图9.16所示的窗口中设置MySQL数据库密码，设置完后单击"Next"按钮，会弹出MySQL数据库准备执行操作窗口，如图9.17所示。在图9.17所示的窗口中，单击"Execute"按钮，会弹出MySQL数据库安装完成窗口，如图9.18所示。

图　9.17　MySQL数据库准备执行操作窗口

图　9.18　MySQL数据库安装完成

（10）在图9.18所示的窗口中单击"Finish"按钮，完成MySQL数据库的安装。

安装完MySQL数据库之后，现在进行MySQL数据库的配置。打开PHP5.0的配置文件"php.ini"，找到";extension=php_MySQL.dll"这一行，把这行前面的注释“;”去掉，成为"extension=php_MySQL.dll"，保存文件。重新启动Web服务器，MySQL数据库的配置工作就完成了。

9.2　MySQL的基本操作

下面介绍MySQL数据库的一些基本操作，包括如何与数据库建立连接，如何设置数据库，以及如何执行基本的命令等。

9.2.1　进入MySQL数据库命令窗口

如果是装有MySQL数据库的本地机器，可以打开MySQL数据库的命令窗口进行基本的操作，进入MySQL数据库命令窗口的操作如下所示。

单击“开始”＞“程序”＞"MySQL"＞"MySQL Server"＞"MySQL Command Line Client"命令。打开MySQL数据库的命令窗口，如图9.19所示。在该窗口中会提示用户输入密码，用户在此需要输入安装MySQL数据库时设置的密码，输入密码完成，按Enter键，这样就进入了MySQL数据库，窗口如图9.20所示。

图　9.19　MySQL数据库的命令窗口

图　9.20　进入MySQL数据库的命令窗口

9.2.2　连接远程数据库系统

一般在访问MySQL数据库时，如果连接远程数据库系统，首先要登录到远程数据库系统。MySQL数据库的连接命令如下所示：

MySQL-h hostname-u username-p[password]

其中，"hostname"表示安装有MySQL数据库系统的服务器名称，"username"和"password"分别表示用户的登录名称和密码。然后进入MySQL数据库。

在图9.20所示的窗口中有MySQL数据库的反馈信息，其中的"help"是MySQL数据库的帮助命令。如果读者在使用中忘了某命令，可以输入此命令来得到要使用的命令集。输入帮助命令会出现命令帮助信息，如图9.21所示。

图　9.21　MySQL数据库帮助信息窗口

注意　命令“？”和命令"help"的功能是一样的，都是用来显示系统的帮助信息。

在图9.21所示的窗口中，命令介绍如下。

"clear"命令用于清除屏幕内容，此命令的格式如下所示：

MySQL＞clear

"connect"命令用来重新连接服务器，有两个可选参数，分别为"dbname"和"hostname"；"exit"命令是用于退出MySQL数据库，使用与"quit"命令相同；"go"命令用于将命令传送到MySQL数据库；"print"命令用于打印当前命令；"status"命令用来显示服务器当前信息。"status"命令的执行效果如图9.22所示。

图　9.22　"status"命令的运行效果

"use"命令用来打开数据库，以数据库名称作为命令参数。显示数据表命令是"show tables"，此命令用来列出当前数据库下所有数据表。此命令的格式如下所示：

Show columns from tablename;

其中"show columns"用来列出"tablename"数据表中的所有字段和字段相关信息。

注意　MySQL数据库要求使用者在所有命令的结尾处使用“；”符号，作为命令的结束。

9.3　MySQL数据库的数据类型

从本质上说，数据库就是一种不断增长的、复杂的数据组织结构。在MySQL数据库中，用于保存数据记录的结构被称为数据表。而每一条数据记录则是由更加小的数据对象，即数据类型组成。总体来说，一个或多个数据类型组成了一条数据记录，一条或多条数据记录组成了一个数据表，一个或多个数据表组成一个数据库。

数据类型分为不同格式和大小，以方便数据设计人员创建最理想的数据结构。能否正确地选择恰当的数据类型对最终数据库的性能具有重要的影响，因此，读者必须首先对数据类型的有关概念进行比较详细的了解。MySQL数据库提供了多种数据类型，其中比较常用的有如下几种。

❑char（M）用于表示固定长度的字符串，它可以包含最多可达255个字符。其中的"M"代表字符串的长度。格式如下所示：

username char(10);

❑VARCHAR（M）：是一种比CHAR更加灵活的数据类型，同样用于表示字符数据，但是VARCHAR可以保存可变长度的字符串。其中"M"表示该数据类型允许保存的字符串的最大长度，只要长度小于该最大值的字符串都可以被保存在该数据类型中。因此，对于那些难以估计确切长度的数据对象来说，使用VARCHAR数据类型更加明智。VARCHAR数据类型所支持的最大长度也是255个字符。这里需要提醒读者注意的一点是，虽然VARCHAR使用起来较为灵活，但是从整个系统的性能角度来说，CHAR数据类型的处理速度更快，有时也许可以超出VARCHAR处理速度的50%。因此用户在设计数据库时应当综合考虑各方面的因素，以求达到最佳的平衡。

注意　虽然VARCHAR使用起来较为灵活，但是从整个系统的性能角度来说，CHAR数据类型的处理速度更快。

❑INT（M）：用于保存-2147483647～2147483648范围之间的任意整数数据。其格式如下所示：

userage int;

❑FLOAT[（M,D）]：用于表示数值较小的浮点数据，可以提供更加准确的数据精度。其中"M"代表浮点数据的长度，需要注意的是，浮点数据的长度是小数据点左右数据长度的总和。"D"表示浮点数据位于小数点右边的数值位数。此数据类型的格式如下所示：

income float(4,2);

按照上述数据类型的设置，12.34为有效数据，而123.45和1.45678则因为超出了数据长度限制或小数点右边位数大于规定值而成为无效数据。

❑"DATE"：用于保存日期数据，默认格式为YY-MM-DD。MySQL数据库提供了许多功能强大的日期格式化和操作命令。

❑"SET"：是多个数据值的组合，任何部分或全部数据值都是该数据类型的有效数据。SET数据类型最大可以包含64个指定数据值。

❑"NOT NULL"：指明这个数据值不能为空。根据上述数据类型的设置，chen、li和chen,li都可以成为"firstname"的有效值。

ENUM数据类型和SET基本是相同的，唯一的区别就在于ENUM只能选择一个有效数据值，格式如下所示：

gender ENUM("male","female")NOT NULL;

上面对用户在使用MySQL数据库的过程中经常用到的数据类型进行了简单的介绍。数据的记录是一组经过声明的数据类型，也就是字段。这些被声明的字段就可以组成一条记录。记录小到可以只包含一个数据变量，大到可以满足用户和各种复杂需求。多条记录组合在一起就构成了数据表的基本结构。

9.4　小结

本章主要介绍了MySQL数据库，讲解了MySQL数据库的安装和设置，还介绍了MySQL数据库的一些基本的操作命令，以及使用MySQL数据库存储数据时，数据的常用类型有哪些。

本章在介绍MySQL数据库的安装时，主要介绍了如何得到MySQL数据库、如何设置MySQL数据库。在介绍MySQL数据库的基本操作时，主要是介绍一些MySQL数据库常用的命令。在介绍MySQL数据库的数据类型时，主要介绍了MySQL数据库的数据类型有哪些以及数据类型的使用。读者应该对以上的知识点仔细理解、掌握。

第10章　MySQL简单管理及MySQL操作

本章将介绍MySQL数据库简单的管理及MySQL数据库的操作。读者在学习本章时，需要掌握以下内容。

❑进入MySQL设置管理员密码。

❑增加用户并设置密码。

❑设置用户权限。

❑取消权限及删除用户。

❑备份和复制数据库。

❑MySQL数据库定义。

❑SQL数据操作。

10.1　进入MySQL设置管理员密码

MySQL数据库的管理员应该知道如何设置管理员账号的密码，当用户忘记MySQL数据库管理员的密码时，或MySQL数据库系统的密码被其他人知道以及长时间使用一个密码，影响MySQL数据库系统的安全时，用户可以进入MySQL数据库对管理员密码进行修改。下面就介绍一下怎么样修改MySQL数据库管理员的密码，可以分为两种情况：一种是知道管理员的密码去修改，另一种是忘记了管理员的密码。

10.1.1　修改管理员密码

换掉MySQL数据库的旧密码。首先要运行"ms.dos"命令窗口，然后通过命令"cd C:\MySQL\bin"，进入MySQL数据库的bin目录下，如图10.1所示。

图　10.1　进行MySQL的bin目录图

在图10.1所示的窗口中可以看出，读者已进入MySQL的bin目录下，接下来就进行修改密码的操作。在光标闪的地方输入如下的命令：

mysqladmin-u root-p password mypassword

在此命令中，"password"后面跟的是读者要修改的新密码。也可以把管理员的名字修改为读者的名字。运行引命令后，会提示用户输入旧密码，这样保证了数据库的安全，如图10.2所示。

图　10.2　修改密码窗口图

在图10.2所示的窗口中，"enter password："是让用户输入MySQL数据库的旧密码，以验证是否是合法的用户在修改密码。输入MySQL数据库的旧密码后，新密码就生效了。

注意　如图用户进入到MySQL数据库的命令窗口中，此命令就不能使用了，MySQL数据库会认为是错误的语法。

10.1.2　重置管理员密码

如果用户忘记了MySQL数据库的密码，也可以通过以下操作来重新设置MySQL数据库的密码。

（1）首先要把MySQL数据库的所有进程结束，如果是Windows，直接调出进程管理器结束。

（2）然后以安全模式启动MySQL数据库。安全模式启动MySQL数据库的方法是运行"ms.dos"命令窗口，然后通过命令"cd C:\MySQL\bin"，进入MySQL数据库的bin目录下。

（3）无密码进入MySQL数据库，命令如下所示：

safe_mysqld--skip-grant-tables＆

此命令用于无密码进入MySQL数据库系统中。接下来进行重新设置管理员账号的密码。

（4）打开MySQL数据库，命令如下所示：

use mysql

（5）修改密码。修改密码的命令如下所示：

update user set password=password("new_pass")where user="root";

此命令中，"new_pass"是用户需要输入的密码。运行此命令后，还要更新MySQL数据库的权限表，命令如下所示：

flush privileges;

这样MySQL数据库管理员的密码就修改完成了。最后，以正常模式启动MySQL数据库，修改后的管理员的密码就生效了。

注意　命令输入的先后顺序，先输入"use mysql"命令，回车后输入修改密码命令，再回车输入更新MySQL数据库权限表的命令。

10.2　增加用户并设置密码及用户权限

MySQL数据库管理员应该知道如何设置MySQL用户账号，指出哪个用户可以连接服务器、从哪里连接以及连接后可以做什么。

10.2.1　设置用户权限的命令

MySQL现在的版本中，引入了两条语句，使得管理员的工作更容易完成，grant语句用于创建MySQL数据库中的用户并指定其权限，而revoke语句用来删除用户的权限。两条语句是为MySQL数据库系统的前端服务的，并提供与直接操作这些表的内容的不同方法。这两条语句影响MySQL数据库系统中的4个表，这4个表如表10.1所示。

注意　MySQL数据库中还有一个表是授权表host，但它不受这两个语句的影响。

当读者对一用户发出下一条grant语句时，在user表中便为此用户创建了一条记录。如果语句指定了任何全局权限，则这些也记录在user表中；如果用户指定了数据库、表和列级权限，就会分别记录在db、tables_priv和columns_priv表中。

10.2.2　数据库用户有哪些权限

下面介绍MySQL数据库中用户的权限。给用户设置权限就是告诉MySQL数据库此用户可以连接哪个数据库及数据表、连接数据库及数据表后可以做什么工作。MySQL数据库中用户的权限如表10.2所示。

注意　此表中的权限是通过"privileges"授予给用户的。

10.2.3　增加用户并赋予权限

本小节会演示一些权限方面的命令，为了便于读者阅读，通过编号形式展现每个命令和功能。

（1）增加一个用户，并赋予其权限及口令。MySQL数据库增加用户的命令格式如下：

grant select on数据库.*to用户名@登录主机identified by"密码"

笔者将在数据库中增加一个用户名为"test"的用户，密码为“123”，让此用户可以在任何主机上登录，并对所有数据库有查询、插入、修改、删除的权限。首先用root用户连入MySQL数据库系统，然后输入以下命令。运行此命令后，用户名为"test"、密码为“123”的新用户就创建成功，并赋予对所有数据库有查询、插入、修改、删除的权限。

grant select,insert,update,delete on*.*to test@"%"Identified by"123";

注意　进入MySQL数据库系统环境中的命令，后面都带一个分号作为命令结束符。

（2）创建一个只能在localhost上登录，并可以对数据库mydb进行查询、插入、修改、删除的操作。创建此用户的命令如下所示：

grant select,insert,update,delete on mydb.*to test1@localhost identified by"123";

因为上面创建的用户"test"影响到了MySQL数据库系统的安全，如某个人知道"test"的密码，那么此人就可以在Internet上的任何一台电脑上登录读者的MySQL数据库，并可以对读者的数据为所欲为。但是此次创建的用户就不同了，用户即使知道"test2"的密码，也无法从Internet上直接访问数据库，只能通过MySQL主机上的Web页来访问。如果读者不想让"test1"有密码，那么读者也可输入以下的命令把密码去掉。运行此命令后，用户"test1"的密码就被清除了。

grant select,insert,update,delete on mydb.*to test1@localhost identified by"";

注意　用户名、用户密码、数据库和表名在授予表记录中是区分大小写的，主机名和列名不区分大小写。

（3）把某个查询表的权限授予指定用户，此操作是如何实现的？下面就以数据表"table1"为例，把数据表"talbe1"的所有权限赋予给用户"test1"。实现此操作的命令如下所示。

grant select on table table1 to test1;

（4）把多个数据表的权限授予指定的几个用户，此操作是如何实现的？下面就以数据表"table1"、"table2"为例，把数据表"talbe1"和"table2"的所有权限赋予给用户"test1"和"test2"。实现此操作的命令如下所示：

grant all privileges on table table1,table2 to test1,.test2;

（5）如果想把某个数据表的查询权限授予所有用户，此操作是如何实现的呢？下面就以数据表"table1"为例，把数据表"talbe1"的所有权限赋予给所有用户。实现此操作的命令如下所示：

grant select on table table1 to public;

（6）如果想把某个查询表和修改用户名的权限授予指定用户，那么此操作该怎样完成呢？下面就以查询表"table1"为例，把查询表"talbe1"的查询表和修改用户名权限赋予给用户"test1"。实现此操作的命令如下所示：

grant update(username),select on table table1 to test1;

此命令实际上是把对表"table1"的查询权限和对属性列的名的修改权限赋予了用户"test1"。

（7）如果想把某个数据表的插入信息权限授予指定用户，此操作该如何实现呢？下面就以数据表"table1"为例，把数据表"talbe1"的插入信息权限赋予给指定用户。实现此操作的命令如下所示：

grant insert on table table1 to test1;

（8）如果想把某个数据库的创建数据表的权限授予指定用户，则此操作是怎样的呢？下面就以数据库database1为例，把数据表"database1"的创建数据表的权限赋予给用户"test1"。实现此操作的命令如下所示：

grant createtab on database database1 to test1;

从上面的实例可以得知，grant语句可以一次给一个用户授权，也可以一次给多个用户授权，还可以一次传播多个同类对象的权限。

10.3　取消权限及删除用户

取消MySQL数据库中一个用户的权限，并删除此用户。如果一个用户已经不使用此账号，MySQL数据库管理员就要对此用户进行取消权限并删除。这样可以保证MySQL数据库系统的安全，以免不法用户使用此账号对MySQL数据库系统进行破坏。

10.3.1　取消用户权限和删除用户

下面介绍如何取消用户权限和删除用户。取消用户的权限，可以使用revoke语句。此语句的语法与grant非常相似，不同处就是grant语句中的"to"用"from"来取代并且revoke语句中没有indetifed by和with grant option子句。取消用户权限的语句格式如下所示：

revoke privileges(columns)on what from user

此语句中，"user"部分必须与原来grant语句的读者想收回授权的用户的"user"部分匹配。"privileges"部分可以不匹配，读者可以使用grant语句给用户授权，然后使用revoke语句取消用户的部分权限。

revoke语句中只取消了用户的权限，并没有删除此用户。虽然读者取消了用户的所有权限，但是在"user"表中用户记录依然存在。这就说明用户仍然可以连接MySQL数据库服务器。如果想要完全删除一个用户，就必须要使用下一条delete语句，明确地从"user"表中删除用户的记录。删除用户的格式如下所示：

delete from user

where User="username"and host="hostname";

flush privileges;

此格式中，delete语句是把用户的记录从"user"表中删除，而flush语句是告诉服务器重新载入授权表。

注意　使用grant语句和revoke语句时，授权表自动重载，而直接修改授权表时不会自动重载。

10.3.2　实例演示删除用户的操作

下面用实例来进一步介绍如何取消用户的权限并删除此用户。如果读者想把用户"test1"的所有权限取消并删除此用户，操作步骤如下所示：

（1）取消用户"test1"的所有权限。取消用户所有权限的命令如下所示：

revoke select,insert,update,delete on*.*from test1;

（2）执行此命令后，用户"test1"的所有权限将被取消。然后把此用户的记录从"user"表中删除。命令如下所示：

DELETE FROM user WHERE User="test1"and Host="localhost";

（3）此命令执行完成后，用户被删除，但是读者并没有重新载入授权表。重新载入授权表的命令如下所示：

flush privileges;

这样一个已经存在的用户就被MySQL数据库管理员完全删除了。

10.4　备份和复制数据库

数据库的备份是很重要的，因为在数据库出现表丢失或损坏情况时，或者如果系统崩溃时，用户肯定希望数据库里的数据尽可能丢失最少的数据，最好是恢复到崩溃前的状态。如果用户对数据库做了备份，那么就不怕出现这一类的问题了，可以把数据库恢复到出现问题前的状态，这样就不会造成数据的丢失了。

备份数据库有两个主要的方法，使用mysqldump程序或直接复制数据库文件。但是每种方法都有其优点和缺点。

10.4.1　备份数据库

mysqldump备份数据库方法是与MySQL数据库服务器协同操作。直接复制方法是在服务器外部进行的。并且使用复制数据库的方法来备份数据库时，必须采取一定的措施以保证没有用户正修改或者将要复制数据库。如果用文件系统备份来备份数据库，也会发生同样的问题。如果数据库中数据表在文件系统备份过程中被修改，进行备份的数据表文件就会出现与原数据文件不一致的现象，对以后恢复数据表将会失去意义。文件系统备份与直接复制文件的区别是：直接复制数据库文件时，可以完全控制备份过程，这样能采取措施确保MySQL数据库服务器上的表不受干扰。

注意　使用mysqldump要比直接复制数据库文件慢。

下面介绍如何使用mysqldump程序备份数据库文件。采用mysqldump程序产生数据库备份文件时，文件内容包含创建正在转储的数据表的create语句和包含数据表中行数据的insert语句。也就是说mysqldump程序产生的输出可在以后用于MySQL的输入来重建数据库。

下面读者将一个数据库文件备份到一个文本文件中。命令如下所示：

mysqldump mydatabase＞f:\mydb.text

输出的文件如下所示：

mysql dump

host:localhost database:mydatabase

table structure for table'ab'

create table ab(

student_id int(10)unsigned default'0'not null,

date date default'0000-00-00'not null,

primary key(student_id,date)

);

dumping data for table'ab'

insert into ab values(3,'2008-04-30');

insert into ab values(3,'2008-05-01');

此程序由多个insert和create table语句组成。本程序只输出文件的开头部分。接下来的输出和上面类似。

10.4.2　数据库的破损恢复

数据库损坏的发生有很多原因，程度也不同。可能损坏一个数据表，也可能必须替换整个数据库。在某些情况下也需要恢复，如用户错误地删除了数据库。读者可以实施数据库的恢复。

恢复数据库有两种信息源，即数据库备份文件和更新日志。备份文件将表恢复到实施备份时的状态，然而一般数据表在备份与发生问题的时间内已经被修改，更新日志包含了用于进行这些修改的查询。读者可以使用日志文件作为MySQL数据库的输入来重复查询。这也是为什么启用更新日志的原因。注意读者在备份数据库文件前需要关闭MySQL数据库，然后重启MySQL数据库。

使用更新日志重复做备份以后，修改MySQL数据库中数据表的查询。对于任何可适用的更新日志，将其作为MySQL数据库的输入。指定"one database"选项使得MySQL数据库只执行读者所需要的数据库的查询。

如果读者正在实施恢复，且使用更新日志恢复由于一个错误的drop dtatbase,drop table语句造成丢失的信息，则在运行更新日志前，要保证从其中删除这些语句。

10.4.3　恢复单个表

下面介绍如何恢复单个表。恢复单个数据表较为复杂。如果读者用一个由mysqldump语句生成的备份文件，并且其不包含读者需要的数据，则需要从相关行中提取读者需要的数据，将其作为MySQL数据库的输入，这是容易的部分。难的部分是从只运用该数据表的更新日志中拉出一部分。mysql_find_rows实用程序对此很有帮助，它能够从更新日志中提取出多行查询。

另一个办法是使用另一台服务器恢复整个数据库，然后复制需要的数据表文件夹到原数据库中，这可能是一个简单的方法。不过，当读者将文件复制到原数据库目录中时，需要确保原数据库的服务器处于关闭状态。

10.5　MySQL数据库定义

MySQL数据库的定义就是MySQL数据库的命名规则和其创建语法。MySQL数据库的命名可以是字母、下画线和数字。创建一个新的MySQL数据库，可以使用create语句实现。

10.5.1　增加、删除及选择数据库

对MySQL数据库进行操作时，可以使用MySQL数据库中的命令来增加数据库及数据表、删除数据库和数据表以及选择数据库。下面对这些命令进行介绍。

（1）MySQL数据库是如何创建一个新的数据库的。MySQL数据库创建新的数据库时，使用create语句来实现。创建数据库的语法格式如下所示：

create database databasename;

执行此语句，就可以在MySQL数据库中创建一个新的数据库，下面笔者就来创建一个名为"mydb"的数据库，语法如下所示。

注意　此语法是在"mysql＞"提示符下执行的，语句的结束要用“；”。

mysql＞create database mydb;

执行此语句后，一个名为"mydb"的数据库就创建成功了。MySQL数据库系统会有提示信息，如图10.3所示。

图　10.3　创建数据库成功的提示信息

（2）当用户不需要一个数据库时，可以删除此数据库。删除数据库的语法格式如下所示：

drop database databasename;

此语句的格式与创建数据库语句格式类似。下面把上面创建的数据库mydb删除。删除语法格式如下所示：

drop database mydb;

执行此语句后，mydb数据库将会被删除。如果删除成功，MySQL数据库就会出现图10.4所示的提示信息。

图　10.4　成功地删除数据库的提示信息

如果需要删除的数据库不存在，MySQL数据库会提示错误的信息。上面已经把mydb数据库成功删除，接下来再进行一次删除操作，结果如图10.5所示。

图　10.5　删除不存在的数据库时提示的信息

注意　创建一个已经存在的数据库，系统也会出现与删除不存在的数据库的提示信息一样的提示。

（3）当用户需要选中一个数据库进行修改时，可以使用use语句来实现选中数据库，选中数据库的语句格式如下所示：

use database;

在此语句中，"database"是需要选中的数据库的名称。现在笔者将选中mydb数据库，语句格式如下所示：

use mydb;

执行此语句，如果选择数据库成功，MySQL数据库会出现图10.6所示的提示信息。如果读者使用此语句选择不存在的数据库，MySQL数据库会出现图10.7所示的提示信息。

图　10.6　选择数据库成功的提示信息

图　10.7　选择不存在的数据库的提示信息

注意　MySQL数据库的每一个语句的结束时都要以“；”符号结束。

10.5.2　数据表的组成及建立、索引和修改、删除数据表

在MySQL数据库中，用于保存数据记录的结构被称为数据表。而每一条数据记录则是由更加小的数据对象，即数据类型组成。因此，一个或多个数据类型组成了一条数据记录，一条或多条数据记录组成了一个数据表。

下面就来介绍如何创建用户存储数据的数据表。数据表中又分为好多个字段，在创建数据表时，这些字段也要被创建，并给这些字段设置数据类型用于存储不同类型的数据。创建数据表的语法格式如下所示：

create table tablename

(

字段名1 数据类型(大小),

字段名2 数据类型(大小),

字段名3 数据类型(大小)

);

在此语句的括号中设置字段时，字段间要使用逗号隔开。下面通过一个实例来介绍数据表是如何被创建的。笔者将要在数据库mydb中创建一个数据表"user"，在此数据表中包含了3个字段，分别为"id"、"username"和"password"。创建此数据表的步骤如下所示。

（1）首先要选择数据库。选择数据库的语句如下所示：

use mydb;

（2）创建数据表。选择数据库后，系统会提示选择数据库成功的信息，然后再输入如下所示的语句：

create table user

(

id int(4),

username char(10),

password chat(10)

);

此语句的作用是在mydb数据库中创建一个名为"user"的数据表，并在数据表中添加"id"、"username"和"password"3个字段，分别为整型和字符型，同时也设置了字段的长度。执行此语句，如果创建成功，提示如图10.8所示。

图　10.8　数据表创建成功的提示信息

注意　数据表的创建是在数据库中来实现的。当括号中设置字段时，字段间要使用逗号隔开。

（3）删除数据表。读者在不使用一个数据表时，管理员就会对此表进行删除，以保证系统的稳定。下面介绍如何实现删除一个数据表。删除数据表的语法格式如下所示：

drop table user;

此语句与创建数据表的语法类似，惟一不同的是删除数据表没有对字段的设置，即没有数据表名后面的括号部分。如果删除成功，系统会提示图10.9所示的信息。

图　10.9　成功地删除数据表的提示信息

（4）更改数据表。更改数据表可以使用alter table语句，此语句可以修改一个现有数据表的结构，例如可以添加、删除、命名字段，也可以创建或删除索引等。此语句虽然功能比较强，但是语法也比较复杂。如修改数据表"user"中的字段"password"，允许其为空。修改数据表的语法格式如下所示：

alter table user change password password char(10)null;

此语句是把数据表中字段名为"password"修改为可以为空值。

（5）数据表的索引的创建和删除。数据表的索引不但可以有序查找，另外数据库利用各种各样的快速定位技术能够大大提高查询效率。特别是当数据量非常大，查询涉及多个表时，使用索引往往能使查询速度加快成千上万倍。在执行CREATE TABLE语句时可以创建索引，也可以单独用CREATE INDEX或ALTER TABLE来为表增加索引。下面就介绍用ALTER TABLE来创建普通索引，格式如下所示：

ALTER TABLE table_name ADD INDEX index_name(column_list)

其中"table_name"是要增加索引的表名，"column_list"指出对哪些列进行索引，多列时各列之间用逗号分隔。索引名"index_name"可选，默认时，MySQL数据库将根据第1个索引列赋一个名称。另外，ALTER TABLE允许在单个语句中更改多个表，因此可以同时创建多个索引。

（6）可利用ALTER TABLE或DROP INDEX语句来删除索引。类似于CREATE INDEX语句，DROP INDEX可以在ALTER TABLE内部作为一条语句处理。格式如下所示：

DROP INDEX index_name ON talbe_name

此语句是删除"table_name"中的索引"index_name"。这样就可以通过此语句来实现删除一个数据表的索引。

注意　如果从表中删除了某列，则索引会受到影响。对于多列组合的索引，如果删除其中的某列，则该列也会从索引中删除；如果删除组成索引的所有列，则整个索引将被删除。

10.6　SQL数据操作

SQL数据操作是使用SQL语句对MySQL数据库进行增加"insert into"、修改"update"和删除"delete"数据表中的记录。

10.6.1　数据的增加

数据的增加，是使用SQL语句对MySQL数据库中数据表的记录进行添加。SQL中的"insert into"命令可以在现有的数据表的末尾增加一条新的记录。新记录包含了由"insert into"命令指定的数据。读者可以在命令中直接输入数据，也可以通过一个指定的数组或者内存变量来输入数据。SQL增加数据的命令的语法格式如下所示：

insert into(数据表名)

values((表达式)

);

在此语法的格式中，“into（数据表名）”子句是指定了准备在其中增加记录的数据表的名字。“数据表名”表示一个相应的数据表文件名的表达式。它可以是一个固定的数据表的文件名，也可以是一个表达式，通过这个表达式可以计算出最终数据表文件的名字。其中可以包含一个驱动器名及目录路径。如果指定的数据表未打开，就会以独占的模式在一个没有使用的工作区打开这个数据表。随后，记录将添加到数据表文件的末尾。此时，原来已经选定的工作区仍然保持选定的状态。打开新工作区并不意味着同时要选定这个工作区。如果指定的数据表已经打开，"insert into"命令就会直接将记录添加到数据表的末尾；如果表是在除当前选定工作区以外的另一个工作区里面打开的，那么在添加了记录以后，不会自动重新选定那个工作区，原来的“当前”工作区仍然会保持选定状态。

读者有选择地指定数据表中使用的一个字段列表，以便给新添加的记录赋值。字段列表可以按顺序排列。如果没有指定字段列表，表内的所有字段都会成为字段列表。"values"子句包含了一系列计算表达式的列表。

除了指定"values"子句这个方法以外，还可以用“from array（数组）”子句来指定一个数组，从而提供相应的字段值。（数组）部分代表一个现成数组的名字，其中包含了用于新增加记录的数据。数组里面存储的每个字段值都需要按照数据表的结构顺序排列。数据只会分配给拥有一个对应内存变量的字段。如果某个数据表字段没有对应的内存变量，字段就会置空。下面对数据表"table1"添加一条记录。记录的内容包含"id"、"username"和"password"3个字段。实现的SQL语句如下所示：

INSERT INTO'table1'('id','username','password')

VALUES(

NULL,'hai','000000'

);

在此语法中，把一个空值赋给了"id"，把用户名"hai"赋给了"username"，把密码“000000”赋给了"password"。

注意　数据表名后面括号中的数据类型要与"value"中的数据类型一一对应。如果不对应，添加记录将会失败。

10.6.2　数据的删除

数据的删除，是使用SQL语句对MySQL数据库中数据表的记录进行删除。SQL中的"delete"命令可以在现有的数据表中删除满足条件的数据记录。删除命令的语法格式如下所示：

delete from'数据表名'

where(条件语句)

其中"delete"是从指定的数据表中删除满足由"where"给出的条件的记录，并返回删除的记录的个数。

如果发出一个没有where子句的"delete"命令，数据表中的所有行都会被删除。MySQL数据库通过创建一个空表来完成，它比删除每行要快。在这种情况下，"delete"返回0作为受影响记录的个数。

注意　MySQL数据库不能返回实际上被删除的行数，因为进行再创建而不是打开数据文件。只要数据表定义文件“表名.frm”是有效的，数据表就能这样被再创建，即使数据或索引文件破坏了。

如果读者想知道在删除所有行时究竟有多少条记录被删除，可以使用这样格式的delete语句。命令格式如下所示：

delete from数据表名where 1＞0;

注意　这比没有where子句的“delete from＜数据表名＞”慢得多。因为一次只删除一行。

如果指定关键词"low_priority"，delete语句的执行将被推迟到没有其他客户读取指定数据表后。删除的记录以一个链接表维持，并且随后的"insert"操作再次使用老的记录位置。为了回收闲置的空间并减小文件大小，可以使用optimize table语句或myisamchk实用程序重新组织表。optimize table较容易，但是myisamchk更快。MySQL对delete特定的"limit rows"选项告诉服务器在控制被返回到客户之前，将要删除的最大行数，这样可以保证一个特定删除命令不会花费太多的时间。读者可以简单地重复删除命令，直到受影响的行数小于limit值。

下面就以实例来介绍删除命令的使用。笔者将删除数据表"table1"中的第3条记录，命令格式如下所示。

delete from'table1'

where(id='3');

运行此命令后数据表"table1"中的第3条记录就会被删除。

10.6.3　数据的修改

修改数据表中的内容是指数据表中的记录如果有不正确的，可以通过此语句来实现对数据记录的更正。修改数据表记录的一般格式如下所示：

update[low_priority]＜数据表名＞

set(属性1=表达式1,

属性2=表达式，

属性n=表达式n)

where(条件);

update用于新值更新现存数据表中的列；set子句指出哪个列要修改和应该被给定的值；where子句，如果给出，指定哪个行应该被更新，否则所有行被更新。

如果指定关键词"low_priority"，执行修改语句被推迟到没有其他客户正在读取表时。如果从一个表达式的表名存取列，修改语句使用列的当前值。例如，下列语句设置"age"为它的当前值加1：

update persondata set age=age+1;

如果设置列为其当前的值，MySQL数据库注意到了这点，并且不做更新操作。下面将用实例来介绍修改命令的使用。修改数据表"table1"中的第3条记录，命令格式如下所示：

UPDATE'table1'

SET'name'='hai',

'phone'='123456'WHERE'id'=3 LIMIT 1;

在此语句中，笔者修改了数据表"table1"中的"name"、"phone"的值。

10.7　小结

本章介绍了MySQL的简单管理及MySQL的操作。通过对本章的学习，读者可以掌握以下的内容。掌握了本章的知识后，读者对于一般的MySQL数据库的操作就比较容易下手了。

❑如何设置管理员密码。

❑怎么样增加用户并设置密码及设置用户权限。

❑如何取消权限及删除用户。

❑如何备份及复制数据库，两者的区别及共同点。

❑如何实现增加、删除及选择数据库。

❑数据表是由什么组成的及建立、索引和修改、删除数据表的方法。

❑如何在数据表中增加数据。

❑如何在数据表中删除数据。

❑如何在数据表中修改数据。

第三篇　数据库

第11章　使用phpMyAdmin管理MySQL数据库

本章将要介绍的是如何使用phpMyAdmin对MySQL数据库进行管理。因为MySQL数据库的操作界面是在msdos下进行，对于初学MySQL数据库的用户来说，操作起来不是很方便，所以使用phpMyAdmin对MySQL数据库进行管理。因为使用phpMyAdmin对MySQL数据库的操作更加简单、方便。本章将主要介绍如何使用phpMyAdmin数据库管理工具对MySQL数据库进行管理。通过对本章的学习，读者需要掌握的知识如下。

❑phpMyAdmin的安装和配置。

❑用phpMyAdmin进行MySQL权限管理。

❑用phpMyAdmin进行数据库及表的管理。

11.1　phpMyAdmin的安装和配置

本节将介绍phpMyAdmin的安装以及对phpMyAdmin的配置。要安装phpMyAdmin数据库管理工具，就要有一个phpMyAdmin的安装包。如何得到此安装包呢？读者可以到"www.google.cn"中去查找一下，然后进行下载。

11.1.1　phpMyAdmin的安装

下载phpMyAdmin后，可以直接单击安装文件，安装过程有一些注意事项，读者一定要仔细。步骤如下所示。

（1）phpMyAdmin的语言设置。得到此安装包后，双击此安装包，会弹出phpMyAdmin的语言设置窗口，如图11.1所示。

图　11.1　语言选择窗口

此窗口用来设置phpMyAdmin数据库管理工具的语言，这里选择"chinese（Simplified）"然后单击"OK"按钮，会弹出phpMyAdmin数据库的安装向导窗口，如图11.2所示。此窗口指引读者完成"PHP Setup for IIs"的安装进程，然后单击“下一步”按钮，弹出phpMyAdmin安装协议窗口，如图11.3所示。

图　11.2　phpMyAdmin数据库的安装向导窗口图

图　11.3　phpMyAdmin安装公司协议窗口图

（2）PHP与IIS的功能选择。在此窗口中是phpMyAdmin安装的协议，读者阅读后单击“我同意”按钮，会弹出PHP与IIS功能选择窗口，如图11.4所示。在此窗口中有PHP、IIS和MySQL的一些功能模块，供用户选择，这里一般全部选择。然后单击“下一步”按钮，会弹出选择MySQL服务的运行文件，如图11.5所示。

图　11.4　PHP与IIS功能选择窗口图

图　11.5　选择MySQL服务的运行文件图

（3）phpMyAdmin数据库管理工具安装目录的选择。在此窗口中，有两个MySQL数据库服务文件，一般选择默认文件，然后单击“下一步”，会弹出phpMyAdmin数据库管理工具安装目录的选择窗口，如图11.6所示。在此窗口中是phpMyAdmin数据库管理工具安装目录的选择，读者可以根据自己的需要安装在指定的目录中。选择好phpMyAdmin管理工具安装的目录后，单击“安装”按钮，会弹出phpMyAdmin数据库管理工具的安装完成窗口，如图11.7所示。

图　11.6　数据库管理工具安装位置窗口图

图　11.7　安装完成窗口图

此时phpMyAdmin数据库管理工具就安装完成了，如果安装成功，会弹出phpMyAdmin数据库管理工具的安装信息页面，如图11.8所示。

图　11.8　数据库管理工具的安装信息页面图

注意　在安装phpMyAdmin数据库管理工具时，计算机的系统中要安装了IIS，如果没有安装IIS的话，phpMyAdmin数据库管理工具就会安装不成功。

11.1.2　phpMyAdmin的配置

phpMyAdmin数据库管理工具安装完成后，下面就来介绍phpMyAdmin数据库管理工具是如何来配置的。

（1）首先需要打开phpMyAdmin数据库管理工具的安装目录下的"PHP.ini"配置文件。找到"$cfg['PmaAbsoluteUri']"代码，此代码是修改读者将上传到空间的phpMyAdmin的网址。可以修改为如下所示：

$cfg['PmaAbsoluteUri']='http://user.com/phpmyadmin/';

（2）接着找到"$cfg['Servers'][$i][‘host']='localhost';"代码，这里可以设定远程MySQL服务器IP地址，通常用默认，也有例外。

（3）再找到"$cfg['Servers'][$i]['auth_type']='config';"代码，此代码是连接MySQL服务器的方式，在本地计算机里调试用config，如果在远程调试就要修改成"cookie"。

（4）然后找到"$cfg['Servers'][$i]['user']='root';"代码，此代码是设置访问数据库的用户名，也就是"MySQL user"。本地计算机访问用"root"，如果是远程访问，要使用用户的ftp账户了。最后要找到"$cfg['Servers'][$i]['password']=‘’；"代码，此代码是设置访问数据库时的密码，也就是"MySQL password"。本地计算机访问时，可以设置，也可以不进行设置。这样就完成了phpMyAdmin数据库管理工具的配置。在地址栏中输入"http://localhost/phpMyAdmin/"，运行的结果如图11.9所示。

图　11.9　phpMyAdmin数据库管理工具登录窗口图

注意　在此页面中，可以选择显示的语言，简体中文要选择"Chinese simplified（zh-utf-8）"。

11.2　用phpMyAdmin进行MySQL权限管理

本节将介绍如何使用phpMyAdmin对MySQL数据库实行权限管理。MySQL数据库的权限管理是指对MySQL数据库中的用户的权限进行设置，使用户只能连接到指定的数据库，进行指定的操作，如只可以读操作，不可以写操作等。

本节还将介绍如何用phpMyAdmin数据库管理工具进行创建用户和删除用户，并对创建的用户进行权限的设置。

11.2.1　增加用户

增加用户是指在MySQL数据库中增加一个或多个用户，以达到需要连接数据库的用户，能够通过创建的账号连接到数据库中，进行合法地操作。使用phpMyAdmin数据库管理工具创建用户的步骤如下所示。

（1）首先读者需要进入phpMyAdmin数据库管理工具中，才能通过phpMyAdmin数据库管理工具的可示化操作界面，可以简单地实现用户的创建。登录的窗口如图11.10所示。在图11.10所示的窗口中，在登录前，要选择phpMyAdmin数据库管理工具显示的语言，输入用户名和密码。在此，因为是要创建一个用户，所以要使用有创建权限的用户来创建，也就是管理员账户。输入完成后，单击“登入”按钮，这样就进入了phpMyAdmin数据库管理工具，如图11.11所示。

图　11.10　phpMyAdmin数据库管理工具登录

图　11.11　进入了phpMyAdmin数据库管理工具的窗口图

使用phpMyAdmin数据库管理工具来创建用户，需要先单击图11.11所示的窗口中的权限，然后才可以进行增加用户操作，如图11.12所示。

图　11.12　phpMyAdmin数据库管理工具中的权限窗口图

（2）增加用户。在图11.12所示的窗口中，可以对用户进行权限设置，也可以增加新的用户。用户的权限设置将在下一节进行介绍。如果是增加新的用户，可以单击窗口中的“添加新用户”按钮，以增加用户，如图11.13所示。

图　11.13　“添加用户”窗口图

（3）在图11.13所示的窗口中，输入需要创建的用户名和密码，如笔者将要创建一个用户名为"haisheng"的账户，然后输入密码，选择主机。如果不选择主机，phpMyAdmin数据库管理工具会选择为默认的主机。输入完成后单击窗口下方的“执行”按钮，如图11.14所示。为了节省空间，笔者缩小了窗口，所以在图11.13中没有显示执行按钮。

图　11.14　添加用户操作完成图

这样一个用户就增加成功了，在此页面中还显示了增加用户所用的SQL语句，读者也可以通过这些SQL语句在MySQL数据库中实现增加用户操作。

注意　增加的用户名称不能和数据库中已经存在的用户名称一样，如果一样，此用户创建就不会成功。

前面为读者介绍了如何通过phpMyAdmin数据库管理工具实现增加一个新用户，下面将为读者介绍一下，如何通过phpMyAdmin数据库管理工具实现删除一个数据库中已经存在的用户。此操作与增加用户非常相似。首先进入到phpMyAdmin数据库管理工具中，单击“权限”按钮，在出现的窗口中选择要删除的用户名称，如图11.15所示。

图　11.15　用户一览窗口图

在图11.15所示的窗口中，从用户一览表中选择要进行删除的用户名称，然后选择删除的方式，单击“执行”按钮，就把要删除的用户从数据库中删除了。数据库中用户的删除方式有4种，第1种是只从权限数据库删除用户；第2种是收回用户的所有可用权限，然后删除用户；第3种是删除用户后并重新读取权限；第4种是删除与用户名称相同的数据库。那么笔者就以用户名称"haisheng"为例，从数据库中删除。先选中用户名"haisheng"，然后选择删除方式，笔者要收回该用户的权限后删除该用户。然后单击“执行”按钮，此用户就从数据库中删除了。

注意　选择用户的删除方式时，要注意的是，针对不同的目的，选择不同的删除方式，如果选择的删除方式不符合，就会产生不可想象的错误。

11.2.2　用户权限的设置

用户权限是指在MySQL中创建一个新的用户，并进行权限设置。也可以是一个已经存在的用户。设置权限就是用户在数据库中能做什么的设置。例如，读者想让一个用户可以创建数据库，则必须给用户设置创建数据库的权限。下面就来介绍一下MySQL数据库中提供的权限。

数据操作权限有"select"、"insert"、"update"和"delete"，是允许读者可以在数据库现有的表上实施的操作权限。"select"权限是只有用户从一个表中检索行时，才可以使用此权限；"insert"权限是在用户向数据表中增加记录时，会用到此权限；"update"权限是在用户修改数据表中的记录时，会用到此权限；"delete"权限是用在当用户删除数据表中的记录时使用此权限；"file"权限是用户执行读和写服务器上的文件时，所有被授予此权限的用户都可以读和写MySQL服务器中的文件。

结构表中的权限。"create"是创建操作权限，用户可以通过此权限进行创建数据库等操作；"alter"权限是修改现有表的结构，读者可以通过此权限进行增加、删除数据表中的列，也可以创造、取消数据表的索引，可以改变现有列的类型、重新命名列或表本身；"index"权限是表的索引，读者可以使用此权限进行数据的索引的创建等操作；"drop"权限删除操作，读者可以使用此权限进行一个或多个数据表的删除操作，此权限是所有表中数据和表的定义，所以使用操作时，要小心使用；"grant"权限是对权限的授予操作，读者可以把本身体所具有的权限授予其他用户；"reload"权限是权限拥有者允许执行的命令，使用可以通知服务器读入授权表；"shut down"权限通过终止服务器上读取被滥用完全拒绝为其他用户服务；"precess"权限能被用来察看当前执行的查询的普通文本，包括设定或修改口令查询。

下面介绍在phpMyAdmin中设置用户的权限，设置用户权限的窗口如图11.16所示。

图　11.16　设置用户权限窗口图

在图11.16所示的窗口中，如果创建一个与管理员的权限相同的用户，将此窗口中的所有权限全部选择就可以了，然后单击“执行”按钮，用户的权限就设置完成了。读者可以使用创建的用户登录，进行创建数据表等操作。

11.2.3　修改管理员权限和密码

本小节为读者介绍phpMyAdmin管理员的权限及密码设置。在前面介绍了phpMyAdmin数据库管理工具的权限可示化操作窗口，用户可以在这里进行管理员的权限的设置。管理员的权限需要有对数据库所有操作权限，也要有增加用户和删除用户的权限，还要有对数据表的操作等权限，一般管理员的权限为使用所有权限，所以读者要把权限表中所有权限选择。然后单击“执行”按钮，完成管理员的权限设置。

在管理员遇到密码被其他人知道、密码长时间没有修改，影响到系统的安全时，可以进行管理员密码的修改。下面介绍一下使用phpMyAdmin数据库管理工具进行管理员密码修改的操作。

打开修改管理员密码窗口。进入phpMyAdmin数据库管理工具，如图11.17所示。在图11.17所示的窗口中，通过单击“更改密码”按钮，可以进行管理员密码的修改，如图11.18所示。

图　11.17　进入phpMyAdmin数据库管理工具窗口图

图　11.18　修改管理员密码窗口图

在图11.18所示的窗口中可以修改成无密码，也可以修改为用户指定的密码，输入完成后单击“更改”按钮，完成管理员的密码修改。

注意　修改密码也可通过权限窗口，选择用户进行密码修改。

11.3　用phpMyAdmin进行数据库及表的管理

本节将介绍用phpMyAdmin数据库管理工具进行数据库及表的管理。通过本节的学习，读者可以知道如何使用phpMyAdmin数据库管理工具创建一个新的数据库及删除一个不使用的数据库，实现对数据表的创建及删除、修改等。还要知道如何使用phpMyAdmin数据库管理工具对数据表进行索引操作。

11.3.1　数据库建立和删除

数据库的创建，如果是在MySQL中创建，对于初学者来说比较麻烦，不利于操作。创建数据库命令的语法比较生，常会出现错误，而使用phpMyAdmin数据库管理工具进行创建，比较方便，也比较直观，因为phpMyAdmin数据库管理工具提供的是可示化操作窗口。接下来介绍如何使用phpMyAdmin数据库管理工具来创建数据库及删除数据库。

首先需要进入到phpMyAdmin数据库管理工具页面，进行MySQL数据库数据库管理工具phpMyAdmin的页面如图11.19所示。

图　11.19　创建数据库图

数据库的创建。在此页面中创建一个新的数据库并输入需要创建的数据库的名字，然后单击“创建”按钮，这样一个新闻发布系统的数据库就创建成功了，如图11.20所示。

图　11.20　创建数据表图

这样数据库就创建成功了，数据表的创建将在下一节介绍，下面介绍如何使用phpMyAdmin数据库管理工具删除一个已经存在的数据库，操作如下所示。

首先进入phpMyAdmin数据库管理工具页面，在此页面中单击数据，数据库管理工具会列出数据库中所有的数据库的名称，如图11.21所示。

图　11.21　数据库管理工具列出数据库窗口图

在图11.21所示的窗口中，读者可以单击需要删除的数据库名称，然后进入要删除的数据库中，如图11.22所示。图11.22所示的窗口是进入到需要删除的数据库中的界面，然后单击“删除”按钮，进行数据库的删除操作，如图11.23所示。

图　11.22　删除数据库的操作窗口图

图　11.23　删除数据库的提示图

图11.23所示的是删除数据库的提示窗口，因为数据库管理工具将要把这个数据库完全删除，为了用户的安全，提示用户是否真的要进行删除操作。如果真的要删除，单击“确定”按钮，就完成了对数据库的删除操作。

注意　在使用数据库的删除操作时，用户要小心，以免造成不必要的麻烦。

11.3.2　数据表的建立并对数据表增加字段

数据的创建是在指定的数据库中创建一个新数据表的操作，同时在数据表中增加用户所需的字段，用来存储用户的信息。

创建数据表的操作首先要进入phpMyAdmin数据库管理工具页面中，打开创建的数据表所属的数据库，再进行数据表的创建，如图11.24所示。在图11.24所示的窗口中，列出了数据库中所有表的名称，还有创建数据表的窗口，在创建一个新的数据表的表单中输入需要创建的数据表名称，在设置数据表中字段"number of fields"一项中输入数据表的字段个数。例如笔者创建“3”字段，然后单击“执行”按钮，如图11.25所示。

图　11.24　创建数据表窗口图

图　11.25　设置表中字段的窗口图

在图11.25所示的窗口中，可以设置字段的名称与字段的数据类型、字段的长度等。在这里设置字段名称为"id"、"title"和"info"，在字段一列中分别输入字段名称，接下来就是设置字段的数据类型。笔者设置字段"id"的数据类型为"int"，因为"id"是统计数据表记录的个数，是数字，为了节省存储空间，设置数据类型为"int"就可以满足需求了。设置"title"的数据类型为"varchar"型，长度为50，因为一个信息不可以超过50个字，所以设置为50就可以了。设置"info"的数据类型为"text"，因为用户要留言，使用的是文本格式，所以设置为"text"。在设置完成后单击“执行”按钮就完成了数据表中字段的设置。

注意　在设置字段的类型时，要使用适合的数据类型，否则会产生不可想象的结果。还要注意的是，设置类型的长度要合理，否则用户输入的数据超出了设置的长度，会造成数据的溢出。

11.3.3　对表数据的修改

对表数据的修改，就是对表中记录内容的修改，在用户增加的记录有错误时，可以通过此操作把记录的内容修改正确。下面就进行此操作的介绍。

（1）首先要进入到phpMyAdmin数据库管理工具页面中，选择需要修改的数据库中的数据表，如图11.26所示。

图　11.26　数据表中内容修改窗口图

（2）在图11.26所示的窗口中，可以进行数据表内容的修改。选择要进行修改的记录名称，然后单击需要进行修改记录对应的“一支笔”图标，进行记录的修改，如图11.27所示。

图　11.27　数据表中记录内容的修改图

（3）在图11.27所示的窗口中，进行错误信息的修改。笔者把那乱七八糟的内容修改一下，就在字段对应的表单中，输入法正确的数据后，单击“执行”按钮，就完成了记录内容的修改。

注意　在修改数据表中记录的内容时，如果数据表中没有记录，是不可以修改的，只可以执行插入操作，增加内容。

11.3.4　如何对表进行索引

索引用来快速地寻找那些具有特定值的记录，所有MySQL索引都以B-树的形式保存。如果没有索引，执行查询时MySQL必须从第1个记录开始扫描整个表的所有记录，直至找到符合要求的记录。表里面的记录数量越多，这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引，则MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录，那么通过索引查找记录至少要比顺序扫描记录快100倍。

1.普通索引

这是最基本的索引类型，而且它没有唯一性之类的限制。

2.唯一性索引

这种索引和前面的“普通索引”基本相同，但有一个区别：索引列的所有值都只能出现一次，即必须唯一。

3.唯一索引

主键是一种唯一性索引，但它必须指定为"PRIMARY KEY"。如果读者曾经用过AUTO_INCREMENT类型的列，可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定，但是用户也可以通过修改表的方式加入主键，例如“ALTER TABLE tablename ADD PRIMARY KEY（列的列表）；”。每个表只能有一个主键。

4.全文索引

MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中，全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。它可以通过CREATE TABLE命令创建，也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集，通过ALTER TABLE（或者CREATE INDEX）命令创建全文索引要比把记录插入带有全文索引的空表更快。

5.单列索引与多列索引

索引可以是单列索引，也可以是多列索引。单列索引是只在指定的那列进行扫描，而多列是在只指定的列中进行扫描。

下面使用phpMyAdmin数据库管理工具来创建数据表的索引。首先要先进入到phpMyAdmin数据库管理工具中页面，打开数据表，如图11.28所示。在图11.28所示的窗口中，在索引列表中输入列数，然后单击“执行”按钮，创建此列的索引，进行索引设置。如图11.29所示。

图　11.28　创建数据表的索引窗口图

图　11.29　索引设置窗口图

在图11.29所示的窗口中，需要设置索引的名称、索引的类型、索引的字段。在这里笔者设置索引名称为“留言”，设置索引的类型为"index"，也就是普通的索引。字段设置为"title"，设置完成后单击“保存”按钮，完成对索引的创建。

注意　对于简单的查询，不需要创建索引，因为简单的查询可以不要索引，如果创建了索引，则会使查询的速度更慢。

11.4　小结

本章介绍了如何安装phpMyAdmin数据库管理工具及phpMyAdmin数据库管理工具的配置；使用phpMyAdmin数据库管理工具添加数据库的新用户并对其进行权限及密码的设置；如何使用phpMyAdmin数据库管理工具对管理员账号进行设置；使用phpMyAdmin数据库管理工具创建数据库、数据表、增加数据表中的字段、数据表索引的创建操作等内容。

通过phpMyAdmin数据库管理工具这个可示化操作窗口，完成上述的操作比较简单，初学者容易接受。

第12章　PHP中使用MySQL数据库

在众多的CGI语言中，PHP对数据库的支持是最完善的。它不只支持二十多种数据库，跨越了各种操作平台，而且PHP对数据库的操作快捷而简单，的确是广大开发网络数据库程序的首选。通过对本章节的学习，读者可以掌握以下知识。

❑MySQL数据库函数在PHP中是如何应用的。

❑PHP是怎么样连接MySQL数据库的。

❑用PHP进行数据的查询。

❑用PHP进行数据表的修改。

❑如何实现一个学生信息管理系统。

12.1　MySQL数据库函数在PHP中的应用

用PHP操纵MySQL数据库比用其他语言操纵数据库要简便很多，这要得益于PHP中大量与MySQL数据库相关的函数，读者只需要调用其中一些函数就可以完成大部分数据库的操作。

12.1.1　PHP如何实现数据库的连接与关闭

数据库系统连接与关闭函数用于产生或取消一个与数据库相连的指针。

PHP中用来与MySQL数据库系统连接的函数有两个，分别是mysql_connect()函数和mysql_pconnect()函数。数据库关闭函数为mysql_close()，此外还有一个用于更改当前用户的函数。

那么在PHP中是如何使用这些函数，来完成相应的操作呢？下面笔者就来介绍一下这些函数在PHP是如何应用的。

（1）连接MySQL数据库的mysql_connect()函数和mysql_pconnect()函数。通过此函数向MySQL数据库发出连接的主机、用户名和密码。此函数的使用格式如下所示：

int mysql_connect(string[hostname][:port]),string[username],string[password])

int mysql_pconnect(string[hostname][:port]),string[username],string[password])

其中参数"hostname"为主机名，"port"为连接时使用的端口号，默认的主机名为"localhost"，默认的端口号为“80”。"username"为用户名，默认为"root"，而"password"就是密码，默认情况下为空。如果函数与数据库系统连接成功，将返回一个连接号；如果连接失败，则返回false。

这两个连接函数的区别就是，使用mysql_connect()函数进行数据库系统连接时，操作数据库结束后，会自动关闭此连接，除非在此前已经使用mysql_close()函数进行了强制关闭。而使用mysql_pconnect()函数进行连接时，会自动检查是否有使用同样的主机名、端口号、用户名和密码进行的连接操作。如果有，则直接使用原有连接号，而且使用mysql_pconnect()函数进行数据库的连接是建立了一种永久连接。即使使用mysql_close()函数也不会关闭此个连接，只有退出整个MySQL数据库系统时才会关闭此连接。

注意　这两个函数在使用时可以在前面加上“@”符号屏蔽系统错误提示，而由用户处理错误。

（2）关闭与MySQL数据库系统连接的函数是mysql_close()，是在必要时强制关闭与MySQL数据库的连接。其语法格式如下所示：

int mysql_close(int[linkid])

此函数用于关闭与MySQL数据库系统的连接。参数linkid是要关闭的连接标识，如果未定此参数，函数将关闭最近一次打开的数据库系统连接。如果连接关闭成功，函数返回值为true，如果连接关闭失败，函数将返回值为false。

注意　mysql_close()函数不会关闭由mysql_pconnect()函数创建的永久连接。

（3）用于改变当前与数据库系统相连接的用户的函数是mysql_change_user()，其格式如下所示：

int mysql_change_user(string user,string password,string[database],int[linkid])

其中参数user为用户名，参数password为用户密码。如果这两个参数不相符合，则不改变数据库系统当前用户。如果指定了数据库，则此数据库将作为新用户的默认数据库，参数linkid为数据库系统的连接标识，默认为最近一次创建的系统连接。

前面为读者介绍了PHP中用来与MySQL数据库系统连接的函数、数据库关闭函数与用于更改当前用户的函数。下面通过一个实例来进一步了解这些函数在PHP中的使用，程序如代码12.1所示。

代码12.1　PHP中使用连接数据库与关闭连接函数的使用程序：12-1.php

＜html＞

＜!--程序名称：12-1.php--＞

＜!--程序功能：连接函数与关闭函数的使用--＞

＜head＞

＜title＞连接函数与关闭函数的使用＜/title＞

＜body＞

＜?php

/*连接数据库部分*/

$mysqluser="root";//数据库用户名

$mysqlpass="123456";//数据库密码

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据库连接语句

echo$connect;

echo"＜br＞";

mysql_close();//关闭连接

$pconnect=mysql_pconnect("localhost",$mysqluser,$mysqlpass);//数据库连接语句

echo$pconnect;

?＞

＜/body＞

＜/html＞

此程序使用了PHP中用来与MySQL数据库系统连接的函数mysql_connect()和mysql_pconnect()函数，来实现数据库的连接。使用数据库关闭函数mysql_close()断开mysql_connect()函数的连接，因为mysql_pconnect()函数是建立的永久连接，使用关闭函数也不可以强制关闭连接。程序的运行效果如图12.1所示。

图　12.1　连接函数与关闭函数的使用程序运行效果图

注意　在执行这个实例前，要先启动MySQL数据库服务器，如果用户没有启动，将会出现无MySQL连接的警告。

作用　此程序的作用就是在用户需要连接数据库时，通过此代码进行数据库的连接，完成用户的操作。

技巧　程序的实现有很多种，可以根据读者的爱好或习惯来完成。笔者在这是把连接数据库的用户名、密码等信息以变量的形式给出，这样在今后的修改中，可以方便程序的修改。为程序减少工作量。

12.1.2　SQL语句执行函数

在PHP中有两个函数可以用于数据库记录查询，这两个函数分别为mysql_query()函数和mysql_db_query()函数。这两个函数可以执行标准的SQL查询语句，其格式如下所示：

int mysql_query(string query,int[linkid])

int mysql_db_query(string database,string query,int[linkid])

其中，参数query为一条SQL查询语句，参数linkid为数据库连接号。这两个函数的区别在于mysql_query()函数需要使用mysql_select_db()函数预先选择数据库，而mysql_db_query()函数的数据库选择在参数中实现。下面通过一个实例介绍此函数在PHP中是如何使用的，程序如代码12.2所示。

代码12.2　在PHP中使用SQL执行语句函数的程序：12-2.php

＜html＞

＜!--程序名称：12-2.php--＞

＜!--程序功能：SQL执行语句函数的使用--＞

＜head＞

＜title＞SQL执行语句函数的使用＜/title＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据库连接语句

mysql_select_db("$dbname");//查询语句

$result1=mysql_query("select*from$tablename");//通过函数查询数据表

$result2=mysql_db_query("$dbname","select*from$tablename");

echo$result1;//输出变量1

echo"＜br＞";

echo$result2;//输出变量2

mysql_close();//关闭连接

?＞

＜/body＞

＜/html＞

此程序中，如果参数query中的SQL语句为select语句，则函数会返回一个结果号，该结果号本身并没有什么实际意义，通常用于其他函数的参数，与其他函数配合起来使用。如果参数query中的SQL语句不是select语句，则返回值没有任何意义。程序的运行效果如图12.2所示。

图　12.2　SQL执行语句函数的使用程序运行效果图

作用　此程序的作用就是把数据库中的数据，通过数据库连接程序连接到数据库，再通过SQL语句把数据库中的内定读出或写入、修改。

12.1.3　获取字段信息函数

字段函数也是MySQL数据库中非常重要的一类函数，其提供了对数据表中字段操作的全部功能，包括获取字段的数据类型、长度等。将数据库记录集当前指针把指记录以对象的形式返回的函数是mysql_fetch_field()。记录集对象的属性如表12.1所示。

参数field_offset表示字段偏移量，如果没有指定，则默认为当前字段。函数执行完成后，会自动将字段指针向后移动，如果字段指针已经在末尾，则函数执行后将返回空。此函数的格式如下所示：

object mysql_fetch_field(int result,int[field_offset])

下面就通过一个实例来介绍此函数在PHP中是如何使用的，程序如代码12.3所示。

代码12.3　获取字段对象信息的函数使用程序：12-3.php

＜html＞

＜!--程序名称：12-3.php--＞

＜!--程序功能：字段信息获取函数使用--＞

＜head＞

＜title＞字段信息获取函数使用＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

$result=mysql_query("select*from$tablename");//查询结果给变量

echo"＜table border=1＞";//输出表格部分

echo"＜tr＞＜td＞name＜/td＞＜td＞table＜/td＞

＜td＞max_length＜/td＞＜td＞not_null＜/td＞

＜td＞primary_key＜/td＞＜td＞unique_key＜/td＞

＜td＞mutiple_key＜/td＞＜td＞numeric＜/td＞

＜td＞blob＜/td＞＜td＞type＜/td＞

＜td＞unsigned＜/td＞＜td＞zerofill＜/td＞＜/tr＞";

while($obj=mysql_fetch_field($result))//输出查询结果

{

echo"＜tr＞";

echo"＜td＞".$obj-＞name."＜/td＞";

echo"＜td＞".$obj-＞table."＜/td＞";

echo"＜td＞".$obj-＞max_length."＜/td＞";

echo"＜td＞".$obj-＞not_null."＜/td＞";

echo"＜td＞".$obj-＞primary_key."＜/td＞";

echo"＜td＞".$obj-＞unique_key."＜/td＞";

echo"＜td＞".$obj-＞multiple_key."＜/td＞";

echo"＜td＞".$obj-＞numeric."＜/td＞";

echo"＜td＞".$obj-＞blob."＜/td＞";

echo"＜td＞".$obj-＞type."＜/td＞";

echo"＜td＞".$obj-＞unsigned."＜/td＞";

echo"＜td＞".$obj-＞zerofill."＜/td＞";

echo"＜/tr＞";

}

echo"＜/table＞";

mysql_close();//关闭连接

?＞

＜/body＞

＜/html＞

此程序中，通过数据库连接函数连接数据库，然后使用获取字段对象信息的函数返回字段的信息，程序的运行结果如图12.3所示。

图　12.3　获取字段对象信息的函数使用程序的运行效果图

作用　此程序是获取数据库中特定的字段信息，完成用户特定的操作，可以得到用户在某种情况下获取数据库中指定的字段信息。

技巧　字段信息的获取是通过SQL语句来完成。首先连接数据库，然后通过SQL语句获取数据库中字段的信息，最后输出获取的信息。

12.1.4　获取字段长度的函数

与上一节函数不同的是mysql_fetch_lengths()函数。此函数的作用是获取查询结果中最后一行记录中各字段的长度，并以数组的形式返回，如果出错，此函数将返回一个空值。函数的格式如下所示：

array mysql_fetch_lengths(int result)

下面通过实例来介绍一下在PHP中如何使用此函数，程序如代码如12.4所示。

代码12.4　获取字段长度的函数使用程序：12-4.php

＜html＞

＜!--程序名称：12-4.php--＞

＜!--程序功能：获取字段长度的函数使用.--＞

＜head＞

＜title＞字获取字段长度的函数使用＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

$result=mysql_db_query("$dbname","select*from$tablename");//查询结果给变量

while(mysql_fetch_row($result))//条件判断

{

$arr=mysql_fetch_lengths($result);//字段长度

for($i=0;$i＜count($arr);$i++)//循环

{

echo$arr[$i]."";//输出结果

}

echo"＜br＞";

}

mysql_close();//关闭连接

?＞

＜/body＞

＜/html＞

此程序使用获取字段长度的函数mysql_fetch_lengths()来获取字段的长度。程序的运行结果如图12.4所示。

图　12.4　字获取字段长度的函数使用程序的运行效果图

注意　mysql_fetch_lengths()函数一般要与mysql_fetch_row()函数、mysql_fetch_array()函数或mysql_fetch_object()函数结合起来使用，以实现记录移动的功能，如果不使用这些函数，不会有输出。

12.1.5　查询结果集的一些其他函数

除了前面介绍的两个字段函数，还有一些常用的查询函数，本节简要介绍一下这些函数的用法。

（1）mysql_result()函数的作用是返回MySQL查询结果集中一个单元的内容，field参数为字段偏移量，或者字段的名称，或以点相隔的字段的表名和字段名。此函数的格式如下所示：

int mysql_fetch(int result,int row,mixed[field])

注意　当对大结果集进行操作时，建议使用功能更为强大的替代函数，如mysql_fetch_row()、mysql_fetch_array()和mysql_fetch_object()。

（2）mysql_field_seek()函数的作用是移动查询结果中的字段指针，参数field_offset指定了字段的偏移。函数的格式如下所示：

int mysql_field_seek(int result,int field_offset)

（3）mysql_field_table()函数的作用是获取指定字段所在表格的名称，参数field_offset为字段偏移量。函数的格式如下所示：

int mysql_field_table(int result,int field_offset)

（4）mysql_field_name()函数的作用是获取查询结果中指定字段的名称，参数"field_index"为字段序号。

（5）mysql_field_type()函数的作用是获取查询结果中指定字段的类型，参数field_offset为字段偏移量。函数返回值可以是int、real、string和blob等。这两个函数的格式如下所示：

string mysql_field_name(int result,int field_index)

string mysql_field_type(int result,int field_offset)

（6）mysql_field_flags()函数的作用是获取查询结果中与指定字段相关的标识，标识可以是一个或多个值的组合。参数field_offset为字段偏移量。函数的格式如下所示：

string mysql_field_flags(int result,int field_offset)

注意　如果标志为多个值的组合，各值字符串之间将以空格分隔，可以使用explode()将其分开。

下面通过一个实例来介绍字段函数在PHP中是如何使用的，程序如代码12.5所示。

代码12.5　字段函数使用程序：12-5.php

＜html＞

＜!--程序名称：12-5.php--＞

＜!--程序功能：字段函数使用--＞

＜head＞

＜title＞字段函数使用＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据库连接

mysql_select_db("$dbname");

$result=mysql_db_query("$dbname","select*from$tablename");

echo"＜table border=1";

echo"＜tr＞＜td＞name＜/td＞＜td＞type＜/td＞

＜td＞len＜/td＞＜td＞flags＜/td＞＜/tr＞";

for($i=0;$i＜mysql_num_fields($result);$i++)

{

echo"＜tr＞";

echo"＜td＞".mysql_field_name($result,$i)."＜/td＞";

echo"＜td＞".mysql_field_type($result,$i)."＜/td＞";

echo"＜td＞".mysql_field_len($result,$i)."＜/td＞";

echo"＜td＞".mysql_field_flags($result,$i)."＜/td＞";

echo"＜/tr＞";

}

echo"＜/table＞";

mysql_close();

?＞

＜/body＞

＜/html＞

此程序使用了字段函数进行字段的获取，然后将其输出到表格中，如图12.5所示。

图　12.5　字段函数使用程序运行效果图

注意　因为在建立news数据库中的"tnews"数据表时，并没有指定参数flags，所以函数得到的"flags"均为空值。

12.1.6　使用记录函数实现数据表记录操作

记录函数是MySQL数据库函数中非常重要的一类函数，提供了对数据表中记录操作的全部功能，包括记录的指针移动、记录值的返回等。

（1）mysql_affected_rows()函数用于返回MySQL服务器最近一次操作所影响的记录所在行号。如果没有指定参数link_id，则使用最近一次打开的连接。此函数的格式如下所示：

int mysql_affected_rows(int[link_id])

注意　此函数对查询语句无效，因为查询语句不会修改记录。记录的操作有插入、删除等，如果使用删除语句将所有的记录都删除了，此函数将会返回值为0。

（2）用于在数据库记录集中移动记录指针的是mysql_data_seek()函数。此函数的格式如下所示：

int mysql_data_seek(int result_identifier,int row_number)

在此函数中，参数row_number指定了要移动到的记录行。如果移动成功，则返回值为true；如果移动失败，则返回值为false；

（3）mysql_fetch_array()函数的作用是获取数据库当前行的记录，其返回结果为一个数组，数组以字段名及数值索引为下标，以字段内容为值，同时记录指针会自动下移一行。如果已经到了记录集的最后一行，函数将返回一个空数组。此函数的格式如下所示：

array mysql_fetch_array(int result,int[result_type])

此格式中，参数result_type为可选择常量，可以选择的值有mysql_assoc、mysql_num和mysql_both，可以是这些值的其中一个。

（4）与mysql_fetch_array()函数的作用相同的函数是mysql_fetch_row()，也是将当前记录以数组的形式返回。两个函数不同之处在于mysql_fetch_array()函数返回的数组只能以数值索引为下标，而mysql_fetch_row()函数返回的数组有两种下标。函数的格式如下所示：

array mysql_fetch_row(int result)

下面通一个过实例来介绍在PHP中如何实现数据表记录显示的，程序如代码12.6所示。

代码12.6　实现数据表记录显示程序：12-6.php

＜html＞

＜!--程序名称：12-6.php--＞

＜!--程序功能：实现数据表记录显示--＞

＜head＞

＜title＞实现数据表记录显示＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据库连接

mysql_select_db("$dbname");

$result=mysql_query("select*from$tablename");//查询数据

echo"＜table border=1＞";

echo"＜tr＞＜td＞name＜/td＞＜td＞address＜/td＞

＜td＞tel＜/td＞＜/tr＞";

while($arr=mysql_fetch_array($result))//条件判断

{

echo"＜tr＞";//输出表格

echo"＜td＞".$arr["name"]."＜/td＞";//输出名字

echo"＜td＞".$arr["id"]."＜/td＞";//输出ID

echo"＜td＞".$arr["tel"]."＜/td＞";//输出电话

echo"＜/tr＞";

}

echo"＜/table＞";

mysql_data_seek($result,0);

echo"＜table border=1＞";

echo"＜tr＞＜td＞name＜/td＞＜td＞address＜/td＞

＜td＞tel＜/td＞＜/tr＞";

while($arr=mysql_fetch_row($result))//判断

{

echo"＜tr＞";//输出表格

echo"＜td＞".$arr[0]."＜/td＞";//输出数组元素[0]

echo"＜td＞".$arr[1]."＜/td＞";//输出数组元素[1]

echo"＜td＞".$arr[2]."＜/td＞";//输出数组元素[2]

echo"＜/tr＞";

}

echo"＜/table＞";

mysql_close();

?＞

＜/body＞

＜/html＞

在此程序中，使用了数据表记录获取函数，把获取的数据以数组的形式返回，并且显示在指定的表格中。程序的运行效果如图12.6所示。

图　12.6　实现数据表记录显示程序运行效果图

mysql_fetch_object()函数的作用是将数据库记录集的当前指针所指记录，以对象的形式返回，同时将指针后移一位。此对象以记录的字段名为属性，函数格式如下所示：

object mysql_fetch_object(int result,int[result_type])

在此格式中，可选择参数result_type是一个常量。可以选择的常量有mysql_assoc、mysql_num和mysql_both。

作用　此程序的作用就是读取数据库中记录的条数，并将其显示出来。也就是数据库的遍历。

技巧　读取数据库的信息，输出到指定的表格中。数据的获取是通过数组，这样可以提高程序的效率。

12.1.7　其他函数

在PHP中使用查询时，查询结果会占用内存空间，当查询结束时，就要释放所占用的内存空间。那么在PHP中是如何把查询结果占用的空间释放的呢？下面就为读者来介绍一下怎样释放查询结果所占用的内存空间。

mysql_free_result()函数的作用是释放查询结果所占用的内存空间，内存释放成功，函数将返回值为true，如果内存空间释放失败，则返回值为false。此函数的格式如下所示：

int mysql_free_result(int result)

下面通过实例来介绍在PHP中如何使用此函数来释放内存，程序如代码12.7所示。

代码12.7　释放内存函数的使用程序：12-7.php

＜html＞

＜!--程序名称：12-7.php--＞

＜!--程序功能：释放内存函数的使用--＞

＜head＞

＜title＞释放内存函数的使用＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

$result=mysql_db_query("$dbname","select*from$tablename");

echo mysql_free_result($result);//输出结果

mysql_close();//关闭连接

?＞

＜/body＞

＜/html＞

在此程序中使用了内存释放函数，如果内存释放成功，程序的运行结果会显示1，如果不成功，则程序的运行结果是false，也就是空。程序的运行结果如图12.7所示。

图　12.7　释放内存函数的使用程序运行效果图

注意　在程序开始时打开了数据库，在程序运行结束时，要关闭数据库。

作用　此程序的作用是把不使用的内存释放出来，减少内存的浪费，使服务器不会崩溃。

技巧　此程序通过数据库关闭函数及时地将完成的数据库操作的连接关闭。

12.2　用PHP进行数据查询

PHP与MySQL数据库结合，PHP使用SQL语句对MySQL数据库进行查询，实现起来比较简单、容易。对于初学者来说，比较容易接受。本节将向读者介绍如何使用PHP对数据库进行操作。

12.2.1　从表中抓取数据并在页面上显示

从数据表中抓取数据并显示在页面中，就是使用select语句在数据表中查询需要的数据，然后通过输出语句显示在页面中。下面笔者将把数据库news的tnews数据表中的内容抓取出来，并显示在页面中，程序如代码12.8所示。

代码12.8　从表中抓取数据并在页面上显示程序：12-8.php

＜html＞

＜!--程序名称：12-8.php--＞

＜!--程序功能：从表中抓取数据并在页面上显示.--＞

＜head＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"＞

＜title＞从表中抓取数据并在页面上显示＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

mysql_query("set names'gb2312'");//设置编码

if($id=="")

{

if(mysql_num_rows(mysql_query("select*from$tablename"))!=0)

{

$get=mysql_query("select*from$tablename order by id desc");

while($stuff=mysql_fetch_array($get))

{

print"＜a href=\"12-8.php?id=$stuff[0]\"target=\"_blank\"＞

＜b＞$stuff[1]＜/b＞＜br＞＜/a＞";

}

}

else

{

echo"现在没有新闻";//输出结果

}

}

else

{

$getnews=mysql_query("select*from$tablename where id=$id");

$result=mysql_fetch_array($getnews);

echo"＜h1＞$result[1]＜/h1＞";

echo"$result[2]＜br＞\n";

}

?＞

＜/body＞

＜/html＞

此程序中使用了数据库连接函数进行连接数据库，连接后，通过SQL的查询语句查询数据表中的内容，然后通过PHP的输出语句把查询到的记录逐条显示在页面中。程序的运行效果如图12.8所示。该图显示的是程序从数据库中抓取出来的数据，在此页面只显示了数据的标题，当用户单击标题时，程序会从数据表中把此标题对应的数据从数据表中读取出来，并显示在页面上。运行效果如图12.9所示。

图　12.8　从表中抓取数据并在页面上显示

图　12.9　用户单击标题后的运行效果图

注意　查询数据表中的数据，使用返回值为数组的函数，然后通过循环语句把数据表中的记录逐条显示出来。

12.2.2　如何对数据有条件地选择

如何对数据有条件地选择就是使用查询数据表中用户所需要的数据。例如，用户只需要"id"从3～10的数据，还有就是用户需要学生信息表中所有的男学生等，这些都是通过使用查询数据对数据有条件的选择。下面通过一个实例来介绍如何实现对数据有条件的选择。笔者要从数据表"tnews"中查找"id"从2～5的记录信息，如代码12.9所示。

代码12.9　有条件地选择数据程序：12-9.php

＜html＞

＜!--程序名称：12-9.php--＞

＜!--程序功能：有条件地选择数据--＞

＜head＞

＜title＞＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";//设置页面显示的条数

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

mysql_query("set names'gb2312'");//设置页面编码

$get=mysql_query("select*from$tablename where id between'18'and'20'");

$result=mysql_fetch_array($get);

echo"＜h1＞$result[1]＜/h1＞";

echo"$result[2]＜br＞\n";

?＞

＜/body＞

＜/html＞

该程序是一个有选择性输出数据库中的记录程序。通过在select语句中添加适当的选择条件，就可以从数据表中只选择用户需要的数据记录。此程序中使用了查询语句中界于两个参数之间的选择语句，如between‘18’and‘20’。该语句是将数据库中的数据表的"id"，大于18并小于20的记录输出到页面中。程序的运行效果如图12.10所示。

图　12.10　有条件地选择数据程序运行效果图

注意　在使用有条件选择数据记录时，"between"是界于两个参数之间的数据记录。

12.2.3　查询特定的数据记录

当一个数据库中的记录有很多条时，用户不知道需要的数据在哪个"id"段，只知道标题是什么？这时就可以使用选择特定的数据记录来查询。如用户只知道标题是星期一，想要知道星期一做了什么，就可以使用这种查找语句。下面通过实例来介绍如何选择特定的数据记录，如代码12.10所示。

代码12.10　查询特定的数据记录程序：12-10.php

＜html＞

＜!--程序名称12-10.php--＞

＜!--程序功能：有条件的查询特定的数据记录程序

＜head＞

＜title＞查询特定的数据记录程序＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db("$dbname");//查询语句

mysql_query("set names'gb2312'");//设置页面编码

$get=mysql_query("select*from$tablename where title='星期一'");

$result=mysql_fetch_array($get);

echo"＜h1＞$result[1]＜/h1＞";

echo"$result[2]＜br＞\n";

?＞

＜/body＞

＜/html＞

在此程序中，使用特定数据的查询语句。这里只使用了标题做为查询的参数，读者也可以根据不同的需求去修改查询语句。这里只查找了标题为星期一的数据记录，程序的运行效果如图12.11所示。

图　12.11　查询特定的数据记录程序运行效果图

注意　因为MySQL数据库允许组合条件进行数据查询，所以有条件的查询语句有很多，读者可以试着多操作一些。

12.2.4　如何实现查询结果的分页显示

当一个页面从数据库中读取出许多数据时，读者不可能让网页读取出多少条记录，就在一页中显示多少条。这时就可以把读取出来的数据记录分批地显示在几个网页上，这样可以使读者的网页既美观，又有逻辑结构。下面通过实例来介绍如何实现查询结果的分页显示，如代码12.11所示。

代码12.11　查询结果的分页显示程序：12-11.php

＜html＞

＜!--程序名称12-11.php--＞

＜!--程序功能：查询结果的分页显示--＞

＜head＞

＜title＞查询结果的分页显示＜/title＞

＜/head＞

＜body＞

＜?

$pagesize=2;//每页显示2条记录

$server=mysql_pconnect("localhost","root","123456");//连接数据库语句

$db=mysql_select_db("news");

mysql_query("set names'gb2312'");//设置页面编码

$sql="select count(*)as total from tnews";//生成查询记录数的SQL语句

$rst=mysql_query($sql);//查询记录数

$row=mysql_fetch_array($rst);//取出一条记录

$rowcount=$row["total"];//取出记录数

mysql_free_result($rst);//释放result资源

$pagecount=bcdiv($rowcount+$pagesize-1,$pagesize,0);//算出总共有几页

//在没有设置pageno时，默认为显示第1页

if(!isset($pageno))$pageno=1;

//若pageno比1小，则把它设置为1

if($pageno＜1)$pageno=1;

//若pageno比总共的页数大，则把它设置为最后一页

if($pageno＞$pagecount)$pageno=$pagecount;

if($pageno＞0){

/*把$PHP_SELF转换为可以在URL上使用的字符串，这样的话就可以处理中文目录或中文文件名*/

$href=eregi_replace("%2f","/",urlencode($PHP_SELF));

if($pageno＞1)//显示上一页的链接

{

echo'＜a href="12-11.php'.$href.'?pageno='.

($pageno-1).'"＞上一页＜/a＞';

}

else{

echo'上一页';

}

for($i=1;$i＜$pageno;$i++){

echo'＜a href="12-11.php'.$href.'?pageno='.$i.'"＞'.$i.'＜/a＞';

}

echo$pageno.'';

for($i++;$i＜=$pagecount;$i++){

echo'＜a href="12-11.php'.$href.'?pageno='.$i.'"＞'.$i.'＜/a＞';

}

if($pageno＜$pagecount){//显示下一页的链接

echo'＜a href="12-11.php'.$href.'?pageno='.($pageno+1).'"＞下一页＜/a＞';

}

else{

echo'下一页';

}

//算出本页第一条记录在整个表中的位置(第一条记录为0)

$offset=($pageno-1)*$pagesize;

$sql="select*from tnews LIMIT$offset,$pagesize";//生成查询本页数据的SQL语句

$rst=mysql_query($sql);//查询本页数据

$num_fields=mysql_num_fields($rst);//取得字段总数

$i=0;

while($i＜$num_fields){

/*取得所有字段的名字*/

$fields[$i]=mysql_field_name($rst,$i);//取得第i+1个字段的名字

$i++;

}

echo'＜table border="1"cellspacing="0"cellpadding="0"＞';

/*开始输出表格*/

echo'＜tr＞';

reset($fields);

while(list(,$field_name)=each($fields)){

/*显示字段名称*/

echo"＜th＞$field_name＜/th＞";

}

echo'＜/tr＞';

while($row=mysql_fetch_array($rst)){

/*显示本页数据*/

echo'＜tr＞';

reset($fields);

while(list(,$field_name)=each($fields)){

/*显示每个字段的值*/

$field_value=$row[$field_name];

if($field_value=="")

{

echo'＜td＞＜/td＞';

}

else{

echo"＜td＞$field_value＜/td＞";

}

}

echo'＜/tr＞';

}

echo'＜/table＞';

/*表格输出结束*/

mysql_free_result($rst)or die("无法释放result资源！");//释放result资源

}

else{

echo"目前该表中没有任何数据！";

}

/*断开连接并释放资源*/

mysql_close($server);

?＞

＜/body＞

＜/html＞

在此程序中，使用$pagesize=2；语句设置一页显示多少条数据记录，然后通过查询语句得到数据库中数据记录的条数，再计算需要几页来显示。程序的运行效果如图12.12所示。在此页面中显示了两条数据记录，总共有3页，当用户单击“2”或者“下一页”时便会显示第2页的数据记录，如图12.13所示。

图　12.12　查询结果的分页显示程序运行效果图

图　12.13　第2页的数据记录图

作用　分页的作用就是指一个页面中可以设置固定的显示信息的条数，如果读取的数据条数大于设置的最大条数，将会根据读取的顺序显示到下一页面中，这样就可以避免页面中版面的变化。

技巧　数据的分页是通过条件判断来实现的，如果读取的条数大于页面显示的最大条数，就会把数据显示到下页中。

12.3　用PHP进行数据表的修改

本章将为读者介绍如何使用PHP对数据表进行操作，包括向数据表中添加记录、使用表单更新数据表中的记录以及删除数据表中的记录。通过对本章节的学习，读者可以了解以下操作。

❑如何使用PHP向数据表中添加记录。

❑怎样通过表单把数据表中的记录更新。

❑如何使用PHP删除数据表中的记录。

12.3.1　向数据表中插入新数据

向数据库中插入数据就是使用SQL的insert语句来实现数据的插入。SQL语句的语法规定比较严格，任何语法格式的错误，都会导致命令执行过程序的错误。在使用PHP操作SQL语句时，对插入语句后跟着的参数更加严格。所以，读者在使用PHP操作SQL语句时要注意，使用不正确的括号、逗号及从分号，都有可能导致操作的错误。下面通过一个实例来介绍SQL的插入语句在PHP中是如何使用的。首先要设计一个数据的提交页面，如代码12.12所示。

代码12.12　提交页面的程序：12-12.html

＜html＞

＜!--程序名称：12-12.html--＞

＜!--程序功能：提交页面的程序--＞

＜head＞

＜title＞提交页面的程序＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜!--居中对齐--＞

＜center＞

＜!--换行--＞

＜br＞＜br＞

＜!--表单部分--＞

＜form action="12-13.php"method="post"＞

＜input type="hidden"name="action"value="add"＞

标题：＜br＞

＜input type="text"name="title"size=50＞＜br＞＜br＞

内容：＜br＞

＜textarea rows=5 cols=50 name="text"＞

＜/textarea＞

＜br＞

＜input type="submit"value="添加"＞

＜/center＞

＜/body＞

＜/html＞

此程序是一个向数据库添加处理程序的提交页面。通过此页面把要添到数据表中的记录内容提交到处理程序，然后通过处理程序把记录添加到数据表中。程序的运行效果如图12.14所示。

图　12.14　提交页面的运行效果图

上面的程序是把添加的记录内容提交到处理页面，处理提交程序把获取的信息通过SQL语句的insert将记录内容添加到数据表中，如代码12.13所示。

代码12.13　插入记录的程序：12-13.php

＜html＞

＜!--程序名称：12-13.php--＞

＜!--程序功能：插入记录的程序--＞

＜head＞

＜title＞插入记录的程序＜/title＞

＜/head＞

＜body＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db($dbname);//查询语句

mysql_query("set names'gb2312'");//设置页面编码

$query="insert into$tablename(id,title,text)//插入语句

values(null,'$title','$text')";

echo$query;

echo"＜br＞";

mysql_query($query);

echo"你的新闻已经增加。";//输出结果

?＞

＜/body＞

＜/html＞

在此程序中，使用了SQL语句把获取的信息添加到数据表中，insert into语句的后面是数据表的名称，value的值要与前面的"（id,title,text）"括号中的字段相对应。下面将要插入标题为“地震危害”，内容为“我从五楼摇晃下去。”程序的运行效果如图12.15所示。

图　12.15　插入记录的程序运行效果图

注意　insert into语句后是数据表的名称，value的值要与前面的"（id,title,text）"括号中的字段对应。

12.3.2　如何更新数据表中的记录

数据表中记录的修改，是把数据表中旧的数据记录覆盖。在许多的网站中如果觉得发表的内容不合适，想要对其进行修改，就可以通过SQL语句中的update语句进行修改。下面通过以下实例来介绍如何实现更新数据表中的记录，如代码12.14所示。

代码12.14　更新数据表中的记录程序：12-14.php

＜html＞

＜!--程序名称：12-14.php--＞

＜!--程序功能：更新数据表中的记录程序--＞

＜head＞

＜title＞更新数据表中的记录程序＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";//显示的条数

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db($dbname);//查询语句

mysql_query("set names'gb2312'");//设置页面编码

if($action=="edit")

{

mysql_query("update$tablename set title='$title'where id='$id'");

mysql_query("update$tablename set text='$text'where id='$id'");

print"你的记录已经修改";

}

else if($action=="view")

{

$get=mysql_fetch_row(mysql_query("select*from$tablename where

ID='$id'"));

?＞

＜!—表单部分--＞

＜form action="12-12.php"method="post"＞

＜input type="hidden"name="action"value="edit"＞

＜input type="hidden"name="id"value="＜?php echo"$get[0]";?＞"＞

标题：＜br＞

＜input type="text"name="title"size=50 value="＜?php echo"$get[1]";?＞"＞

＜br＞＜br＞

内容：＜br＞

＜textarea rows=5 cols=50 name="text"＞＜?php echo"$get[2]";?＞

＜/textarea＞

＜input type="submit"value="编辑"＞

＜?php

}

else

{

?＞

＜form action="12-12.php"method="post"＞

＜input type="hidden"name="action"value="view"＞

＜select name="id"size=5＞

＜?php

$get=mysql_query("select*from$tablename");

while($stuff=mysql_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";//输出结果

}

?＞

＜/select＞

＜input type="submit"value="修改"＞

＜?php

}

?＞

＜/center＞

＜/body＞

＜/html＞

此程序中首先把数据表中的标题读取出来，读者可以选择需要修改的标题进行修改。此程序使用了HTML与PHP相结合的形式对数据表进行操作。程序的运行效果如图12.16所示。在此页面中读者可以选择需要修改的标题，然后单击“修改”按钮会出现修改页面，如图12.17所示。

图　12.16　更新数据表中的记录程序运行效果图

图　12.17　修改数据表中记录页面图

在此页面中修改完用户需要的内容后，单击“编辑”按钮，进行更新数据表中的记录操作。如果修改成功，程序的运行效果如图12.18所示。

图　12.18　成功修改数据表记录页面图

注意　程序中的HTML与PHP的放置位置，如果放置不合理，就会出现想象不到的错误。

作用　数据的修改就是用户使用此程序进行对数据库中的数据内容的使用，使用户及时地更新数据库中的信息。

12.3.3　删除指定的数据

删除指定的数据就是指删除用户需要删除的数据表中的记录。当一个网站存在好长时间以前的数据记录时，可以选择删除这些数据；或者用户的网站上出现不法的信息时，也可以使用删除操作来删除此不法数据。下面通过实例来介绍如何删除指定的数据记录。如代码12.15所示。

代码12.15　删除指定的数据程序：12-15.php

＜html＞

＜!--程序名称：12-15.php--＞

＜!--程序功能：删除指定的数据--＞

＜head＞

＜title＞删除指定的数据＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db($dbname);//查询语句

mysql_query("set names'gb2312'");//设置页面编码

if($action=="delete")

{

mysql_query("DELETE FROM$tablename WHERE id='$id'");

print"你的内容已经删除";

}

else

{

$script=getenv("SCRIPT_NAME");

?＞

＜!—表单部分--＞

＜form action="12-15.php"method="post"＞

＜input type="hidden"name="action"value="delete"＞

＜select name="id"size=5＞

＜?php

$get=mysql_query("select*from$tablename");

while($stuff=mysql_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";

}

?＞

＜/select＞

＜input type="submit"value="删除"＞

＜?php

}

?＞

＜table align=center border=0 width=776＞

＜tbody＞

＜tr＞

＜td align=middle＞

＜br＞

＜br＞

＜hr size="0"width="80%"＞

＜/td＞

＜/tr＞

＜tr align="center"＞

＜/tr＞

＜/tbody＞

＜/table＞

＜/body＞

＜/html＞

此程序也是采用HTML和PHP代码相结合的形式。首先用户选择需要删除的数据标题，单击“删除”按钮，程序通过SQL语句中的DELETE语句来完成删除指定数据的操作。程序的运行效果图12.19所示。在此页面中，用户选择需要删除的数据的标题，然后单击“删除”操作，这样用户指定的数据就被删除了，删除完的运行效果如图12.20所示。

图　12.19　删除数据时的浏览数据标题页面图

图　12.20　删除成功的运行效果图

注意　删除命令后是数据表的名称，跟着是需要删除数据的标题。如代码""DELETE FROM$tablename WHERE id='$id'""。

12.4　PHP操作MySQL实例—学生信息管理系统

学生信息管理系统是对学生信息的添加、修改和查询的功能。学生信息的添加就是录入学生的信息，修改指的是对学生信息的更新、查询，包括输入学生名字查询和输入学生信息的查询。本系统包括以下几个模块。

❑录入学生信息。

❑模糊查询学生信息。

❑精确查询学生的信息。

❑修改学生的信息。

❑删除学生信息的记录。

本系统的模块工作流程如图12.21所示，下面就介绍一下该流程图。

图　12.21　学生管理系统的流程图

❑录入学生的信息，通过录入提交表单程序12-16.html，把学生的信息提交到处理进入学生记录程序12-17.php，通过处理录入学生记录程序把学生的信息添加到数据库中。

❑模糊查询是通过模糊查询提交程序12-18.html，把查询的关键字提交到模糊查询处理程序12-19.php，模糊查询处理程序把查询的内容输出到此页面。

❑精确查询是通过精确查询提交程序12-20.html，把查询的关键字提交到精确查询处理程序12-21.php，精确查询处理程序把查询的内容输出到此页面。

❑删除学生的记录，通过删除学生记录程序12-22.php，把用户需要删除的学生记录从数据库中删除。

❑修改学生记录是通过修改学生记录程序12-23.php，把用户需要修改的学生记录从数据库中提取出来，并显示在此页面中的修改表单中，进行修改。

12.4.1　数据库设计

本系统通过录入学生的信息，并存入到MySQL数据库中，来实现学生信息的管理。下面来介绍数据库的设计，首先创建一个数据库mydb，然后在此数据库中创建一张数据表"user"，用来存储学生的信息记录。创建数据库的操作语句如下所示：

create database mydb;

进入MySQL数据库的命令窗口中，在"mysql＞"的提示中输入上面的语句，然后按Enter键，如果数据库创建成功，会出现创建成功提示，如图12.22所示。

图　12.22　创建数据库成功提示图

这样数据库就创建成功了，接下来在数据库中创始一张数据表"user"，数据表中包含有6个字段，分别为"id"、"name"、"age"、"phone"、"address"和"education"。创建数据表"user"的语句如下所示：

create table user

(

id int not null auto_increment,name varchar(20),

age int,

phone int,

address varchar(60),

education varchar(60),

primary key(id)

);

运行此语句后，数据表就创建成功了，现在数据库的设计就完成了，可以存储学生的记录了。

注意　在输入创建命令时，要注意语句的完整性，括号中的参数之间是要用逗号隔开的。语句结束时要以分号结束。

12.4.2　增加数据页

增加数据页就是录入表单页面，用户可以通过此表单向数据表"user"中添加新的学生信息记录，如代码12.16所示。

代码12.16　增加数据表单提交程序：12-16.html

＜html＞

＜!--程序名称：12-16.html--＞

＜!--程序功能：增加数据表单提交程序--＞

＜head＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜title＞增加数据表单提交程序＜/title＞

＜/head＞

＜body＞

＜!—居中对齐--＞

＜center＞

＜!—表单部分--＞

＜form method="post"action="12-17.php"＞

＜input type="hidden"name="action"value="add"＞

姓名：＜input type="text"name="name"size="20"＞＜br＞

年龄：＜input type="text"name="nage"size="20"＞＜br＞

班级：＜input type="text"name="phone"size="20"＞＜br＞

地址：＜input type="text"name="address"size="20"＞＜br＞

年级：＜input type="text"name="education"size="20"＞＜br＞

＜input type="submit"value="提交"name="b1"＞＜input type="reset"value="重写"

name="b2"＞＜br＞

＜/form＞

＜center＞

＜/body＞

＜/html＞

此程序中设计了与数据表"user"中字段对应的提交表，通过在此表彰中输入学生的信息，提交到添加学生信息处理页面。程序的运行效果如图12.23所示。

图　12.23　添加学生信息程序运行效果图

在此页面中，用户输入需要添加的学生信息后，单击“提交”按钮后，就把输入的学生信息提交到添加学生信息处理页面了。如果用户输入的学生信息有误，则需要重新输入，也可以单击“重写”按钮，来清空表单中已经存在的信息。现在添加学生信息的提交页面已经完了，接下来介绍如何将从提交表单程序中获取的信息添加到数据表中，如代码12.17所示。

代码12.17　添加学生信息处理程序：12-17.php

＜html＞

＜!--程序名称：12-17.php＞

＜!--程序功能：添加学生信息处理程序--＞

＜head＞

＜title＞添加学生信息处理程序＜/title＞

＜/head＞

＜body＞

＜?php

$formdata=array();//定义数组

if(count($http_post_vars))

{

while(list($key,$value)=each($http_post_vars))

{

$formdata[strtolower($key)]=$value;

}

}

$mysqluser="root";//用户名

$mysqlpass="123456";//数据库密码

$dbname="mydb";//数据库名

$tablename="user";//数据表名

$limit="5";//页面显示条数

?＞

＜!—表格部分--＞

＜table＞

＜tr＞＜td＞

＜?php

$name=$formdata['name'];//转换变量name

$age=$formdata['age'];//转换变量age

$phone=$formdata['phone'];//转换变量phone

$address=$formdata['address'];//转换变量address

$eduction=$formdata['education'];//转换变量education

echo"连接数据库";

$db_connect=mysql_connect('localhost',$mysqluser,$mysqlpass);//连接语句

mysql_select_db($dbname);//查询语句

mysql_query("set names'gb2312'");//设置编码

if(!$db_connect)

{

echo"数据库连接不成功！";

?＞

＜/td＞＜/tr＞

＜/table＞

＜?php

exit;//关闭连接

}

?＞

＜?php

$seldb=mysql_select_db($dbname,$db_connect);

if($action=="add")

{

$insertquery="INSERT INTO'user'('id','name','age','phone',

'address','education')

value(NULL,'$name','$age','$phone','$address','$education')";

echo"用户添加成功！";

}

else

{

echo"学生添加不成功.";

}

?＞

＜?php

$db_close=mysql_close($db_connect);

?＞

＜p＞关闭数据库！＜/p＞

＜/body＞

＜/html＞

此程序首先连接到数据库mydb，然后把从提交表单页面获取的信息通过SQL语句INSERT INTO'user'（'id'，'name'，'age'，'phone'，'address'，'education'）value（NULL，'$name'，'$age'，'$phone'，'$address'，'$education'）添加到数据表中，如果添加成功，运行效果如图12.24所示。

图　12.24　成功添加学生记录程序运行效果图

这样学生管理系统的添加学生记录的模块就完成了。数据的添加就是连接到数据库，把提交的信息添加到数据库中。

作用　此程序的作用就是用户把需要的信息增加到数据库中。向数据库中增加数据是通过SQL语句INSERTINTO()来完成的。

12.4.3　修改和删除数据页

修改数据记录就是用户通过此页面对需要修改的学生信息进行的一个更新。而删除页面就是用户通过此页面把不需要的学生信息进行删除。下面介绍如何修改数据表中已经存在的学生信息，如代码12.18所示。

代码12.18　修改学生信息程序：12-18.php

＜html＞

＜!--程序名称：12-18.php＞

＜!--程序功能：修改学生信息程序--＞

＜head＞

＜title＞修改学生信息程序＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";//设置页面显示条数

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db($dbname);//选择数据库

mysql_query("set names'gb2312'");//设置页面编码

if($action=="edit")

{

mysql_query("UPDATEuserSET name='$uname',age='$uage',phone='

$uphone',address='$uaddress',education='$ueducation'where id=$uid");//修改语句

print"学生信息改。";

}

else if($action=="view")

{

$get=mysql_fetch_row(mysql_query("select*from$tablename where

ID='$id'"));

echo$get;

?＞

＜!—表单部分--＞

＜form action="12-34.php"method="post"＞

＜input type="hidden"name="action"value="edit"＞

＜input type="hidden"name="id"value="＜?php echo$record-＞id?＞"＞

姓名：＜input type="text"name="name"size="20"value="＜?php echo"$get[1]";?＞"＞＜br＞

年龄：＜input type="text"name="age"size="20"value="

＜?php echo"$get[2]";?＞"＞＜br＞

电话：＜input type="text"name="phone"size="20"value="

＜?php echo"$get[3]";?＞"＞＜br＞

地址：＜input type="text"name="address"size="20"value="

＜?php echo$record-＞address?＞"＞＜br＞

年级：＜input type="text"name="education"size="20"value="

＜?php echo"$get[4]";?＞"＞

＜br＞

＜input type="submit"value="修改"name="edit"＞＜br＞

＜/form＞

＜?php

}

else

{

?＞

＜!—提交表单部分--＞

＜form action="12-34.php"method="post"＞

＜input type="hidden"name="action"value="view"＞

＜select name="id"size=5＞

＜?php

$get=mysql_query("select*from$tablename");

while($stuff=mysql_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";

}

?＞

＜/select＞

＜input type="submit"value="修改"＞

＜?php

}

?＞

＜/center＞

＜/body＞

＜/html＞

此程序首先从数据表"user"中把所有学生信息的"id"号和用户名取出，显示在一个下拉列表中，用户可以通过下拉列表选择需要修改的学生信息记录进行修改。程序的运行效果如图12.25所示。如图12.26所示的页面是把数据表中所有学生的名字取出，显示在一个下拉列表中，用户可以选择需要进行修改的学生姓名，然后单击“修改”按钮进行修改。

图　12.25　从数据表中取出信息图

图　12.26　修改学生信息图

在此页面中，可以对学生的信息进行修改，把需要更新的学生信息重新输入到表单中，当用户把学生的信息输入完成后，单击“修改”按钮，就完成了学生信息的更新，如图12.27所示。

图　12.27　完成学生信息修改图

注意　此程序是HTML与PHP混合使用的程序，如果两者放置不合理就不会出现理想的效果。

修改程序已经完成，下面介绍如何把数据表中已经存在的学生信息从数据表中删除。此程序中使用了SQL语句中的删除命令"delete"，通过此命令在给定参数的情况下进行删除操作。此程序与修改程序类似，都是从数据表"user"中把所有用户的"id"号和学生的名称取出，显示在一个下拉列表中，用户选择需要进行删除的学生名称就可以执行删除操作，如代码12.19所示。

代码12.19　删除学生记录的程序：12-19.php

＜html＞

＜!--程序名称：12-19.php--＞

＜!--程序功能：删除学生记录的程序--＞

＜head＞

＜title＞删除学生记录的程序＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$mysqluser="root";//用户

$mysqlpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//表名

$limit="5";//设置页面显示条数

$connect=mysql_connect("localhost",$mysqluser,$mysqlpass);//数据连接

mysql_select_db($dbname);//选择数据库

mysql_query("set names'gb2312'");//设置页面编码

if($action=="delete")//判断传来的值

{

mysql_query("DELETE FROM$tablename WHERE id='$id'");

print"学生的信息记录已经被删除。";

}

else

{

$script=getenv("SCRIPT_NAME");

?＞

＜!---表单部分-＞

＜form action="12-19.php"method="post"＞

＜input type="hidden"name="action"value="delete"＞

＜select name="id"size=5＞

＜?php

$get=mysql_query("select*from$tablename");//获取查询结果

while($stuff=mysql_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";//输出结果

}

?＞

＜/select＞

＜input type="submit"value="删除"＞

＜?php

}?＞

＜table align=center border=0 width=776＞

＜tbody＞

＜tr＞

＜td align=middle＞

＜br＞

＜br＞

＜hr size="0"width="80%"＞

＜/td＞

＜/tr＞

＜tr align="center"＞

＜/tr＞

＜/tbody＞

＜/table＞

＜/body＞

＜/html＞

此程序首先从数据表"user"中把所有学生信息的"id"号和用户名取出，显示在一个下拉列表中，用户可以通过下拉列表进行选择需要删除的学生信息记录进行删除。删除操作通过SQL语句中的删除命令进行删除。程序的运行效果如图12.28所示。在此页面中用户可以选择需要进行删除操作的学生姓名进行删除操作，当用户选择了需要删除的学生姓名后，单击“删除”按钮来完成删除操作，如图12.29所示。

图　12.28　选择删除学生信息图

图　12.29　完成删除学生信息操作图

注意　程序使用了数组把从数据表中查询的记录以数组的形式发送到页面中，然后以下拉列表的形式显示出来。

技巧　对数据库中信息的删除，是通过SQL语句中的删除语法来完成的。在此程序中首先对数据库中的信息做一次遍历，用户可以在数据库的遍历表中选择需要删除的信息进行删除。

12.4.4　数据显示页

数据显示页用来把数据表中所有的学生信息的记录显示在此页面中，本程序在数据记录过多时进行了分页显示。程序如代码12.20所示。

代码12.20　数据显示页程序：12-20.php

＜html＞

＜!--程序名称12-20.php

＜!--程序功能：数据显示页程序--＞

＜head＞

＜title＞数据显示页程序＜/title＞

＜/head＞

＜body＞

＜?

$pagesize=2;//每页显示2条记录

$server=mysql_pconnect("localhost","root","123456");//连接语句

$db=mysql_select_db("mydb");//选择数据库

mysql_query("set names'gb2312'");//设置页面编码

$sql="select count(*)as total from user";//生成查询记录数的SQL语句

$rst=mysql_query($sql);//查询记录数

$row=mysql_fetch_array($rst);//取出一条记录

$rowcount=$row["total"];//取出记录数

mysql_free_result($rst);//释放result资源

$pagecount=bcdiv($rowcount+$pagesize-1,$pagesize,0);//算出总共有几页

/*在没有设置pageno时，默认为显示第1页*/

if(!isset($pageno))$pageno=1;

/*若pageno比1小，则把它设置为1*/

if($pageno＜1)$pageno=1;

/*若pageno比总共的页数大，则把它设置为最后一页*/

if($pageno＞$pagecount)$pageno=$pagecount;

if($pageno＞0){

/*把$PHP_SELF转换为可以在URL上使用的字符串，

这样的话就可以处理中文目录或中文文件名*/

$href=eregi_replace("%2f","/",urlencode($PHP_SELF));

if($pageno＞1){//显示上一页的链接

echo'＜a href="12-20.php'.$href.'?pageno='.($pageno-1).'"＞上一页＜/a＞';

}

else{

echo'上一页';

}

for($i=1;$i＜$pageno;$i++){

echo'＜a href="12-20.php'.$href.'?pageno='.$i.'"＞'.$i.'＜/a＞';

}

echo$pageno.'';

for($i++;$i＜=$pagecount;$i++){

echo'＜a href="12-20.php'.$href.'?pageno='.$i.'"＞'.$i.'＜/a＞';

}

if($pageno＜$pagecount){//显示下一页的链接

echo'＜a href="12-20.php'.$href.'?pageno='.($pageno+1).'"＞下一页＜/a＞';

}

else{

echo'下一页';

}

/*算出本页第一条记录在整个表中的位置(第一条记录为0)*/

$offset=($pageno-1)*$pagesize;

$sql="select*from user LIMIT$offset,$pagesize";//生成查询本页数据的SQL语句

$rst=mysql_query($sql);//查询本页数据

$num_fields=mysql_num_fields($rst);//取得字段总数

$i=0;

while($i＜$num_fields){

/*取得所有字段的名字*/

$fields[$i]=mysql_field_name($rst,$i);//取得第i+1个字段的名字

$i++;

}

echo'＜table border="1"cellspacing="0"cellpadding="0"＞';

/*开始输出表格*/

echo'＜tr＞';

reset($fields);

while(list(,$field_name)=each($fields)){

/*显示字段名称*/

echo"＜th＞$field_name＜/th＞";

}

echo'＜/tr＞';

while($row=mysql_fetch_array($rst)){

/*显示本页数据*/

echo'＜tr＞';

reset($fields);

while(list(,$field_name)=each($fields)){

/*显示每个字段的值*/

$field_value=$row[$field_name];

if($field_value==""){

echo'＜td＞＜/td＞';

}

else{

echo"＜td＞$field_value＜/td＞";

}

}

echo'＜/tr＞';

}

echo'＜/table＞';

/*表格输出结束*/

mysql_free_result($rst)or die("无法释放result资源！");//释放result资源

}

else{

echo"目前该表中没有任何数据！";

}

/*断开连接并释放资源*/

mysql_close($server);

?＞

＜/body＞

＜/html＞

在此程序中，PHP程序操作SQL语句把数据表中的学生信息全部读取出来，然后通过输入语句把读取的信息显示在页面中，程序的运行效果如图12.30所示。

图　12.30　显示数据表中学生信息的程序图

在此页面中，如果在一页中显示的数据过多，会使用户读取不太方便，因此页面中加入了分页显示。分页显示查询记录的操作过程是：程序从数据表中读取将要显示的页面的初始记录，如果是第1次显示，则默认是第1页，使用语句控制生成的查询记录来显示记录数，然后把读取出来的数据分页显示在表格中。笔者设置了一页只显示两条记录，当用户单击“下一页”或者“2”时，会显示接下来的两条记录，如图12.31所示。

图　12.31　分页显示效果图

注意　在分页显示时，要对读取出来的数据进行计算，看分多少页，然后进行分页显示。

12.4.5　精确查询与模糊查询

精确查询与模糊查询区别是：精确查询是指用户知道需要查询的学生名称，可以准确地把此学生的信息查询出来；模糊查询是当用户只知道学生的不准确的信息，通过此信息来查询出需要的学生记录。下面来介绍一下精确查询，也是用户通常使用的，使用提交表单把查询的信息提交到查询处理页面进行查询操作。查询信息的提交页面代码如代码12.21所示。

代码12.21　查询信息的提交页面程序：12-21.html

＜html＞

＜!--程序名称：12-21.html＞

＜!--程序功能：查询信息的提交页面程序--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—标题部分--＞

＜title＞地址簿查询＜/title＞

＜/head＞

＜body＞

＜p align="center"＞＜b＞＜font size="5"＞地址簿查询＜/font＞＜/b＞＜/p＞

＜!—表单部分--＞

＜form method="post"action="12-22.php"＞

＜p align="center"＞请输入要查询的学生姓名：

＜input type="text"name="name"size="20"＞＜input type="submit"value="查询"name="b1"＞

＜input type="reset"value="重写"name="b2"＞＜/p＞

＜/form＞

＜/body＞

＜/html＞

＜/body＞

＜/html＞

此程序是一个用户输入查询信息，并且提交到查询处理页面的程序，程序的运行效果如图12.32所示。

图　12.32　查询提交页面程序图

在此页面中，用户需要在输入查询学生的姓名的表单中输入需要查询的学生姓名，然后单击“查询”按钮，来完成查询操作。如果用户想清空输入的学生姓名，也可以单击“重写”按钮来完成清空操作。当用户单击“查询”按钮时，程序就会把信息提交到处理程序中，处理查询信息的代码如代码12.22所示。

代码12.22　处理查询信息页面程序：12-22.php

＜!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞

＜html xmlns="http://www.w3.org/1999/xhtml"＞

＜!--程序名称：12-22.php--＞

＜!--程序功能：处理查询信息页面程序--＞

＜head＞

＜meta http-equiv="Content-Type"content="text/html;charset=gb2312"/＞

＜title＞处理查询信息页面程序＜/title＞

＜/head＞

＜body＞

＜?php

$formdata=array();//使用数组函数

if(count($http_post_vars))

{

while(list($key,$value)=each($http_post_vars))

{

$formdata[strtolower($key)]=$value;

}

}

$mysqluser="root";//用户名

$mysqlpass="123456";//数据库密码

$dbname="mydb";//数据库名

$tablename="user";//数据表名

$limit="5";//设置页面显示条数

?＞

＜?php

$name=$_POST['name'];//变量转换

echo$name;//输出提交的变量

$db_connect=mysql_connect('localhost',$mysqluser,$mysqlpass);//连接语句

mysql_query("set names'gbk'");//设置页面编码

if(!$db_connect)

{

?＞

＜table＞

＜tr＞＜td＞

数据库连接不成功

＜/td＞＜/tr＞

＜/table＞

＜?php

exit;//关闭连接

}

?＞

＜?php

$seldb=mysql_select_db($dbname,$db_connect);//连接语句

$sql="select*from'user'where'name'='$name'";//查询语句

echo$sql;//输出查询结果

$result=mysql_query($sql,$db_connect);

echo mysql_num_rows($result);

$rows=mysql_fetch_array($result)

?＞

＜!—表单部分--＞

＜table width="100%"border="1"cellspacing="1"cellpadding="1"＞

＜tr＞

＜td＞＜div align="center"＞id＜/div＞＜/td＞

＜td＞＜div align="center"＞姓名＜/div＞＜/td＞

＜td＞＜div align="center"＞年龄＜/div＞＜/td＞

＜td＞＜div align="center"＞电话＜/div＞＜/td＞

＜td＞＜div align="center"＞地址＜/div＞＜/td＞

＜td＞＜div align="center"＞班级＜/div＞＜/td＞

＜/tr＞

＜tr＞

＜!—把结果输出到表格中--＞

＜td＞＜div align="center"＞＜?php echo$rows['id'];?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$rows['name'];?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$rows['age'];?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$rows['phone'];?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$rows['address'];?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$rows['education'];?＞＜/div＞＜/td＞

＜/tr＞

＜/table＞

＜?php

echo"这就是你要查询的结果";

?＞

＜/body＞

＜/html＞

此程序是从查询表单提交表单中获取信息，用mysql_connect函数与数据库建立连接，用mysql_select_db函数选择需要操作的数据库，生成查询记录的SQL语句，再使用mysql_query函数执行SQL语句，把需要查询的信息从数据表中取出，并显示在指定的表格中。程序的运行效果如图12.33所示。

图　12.33　精确查询的程序图

注意　程序的编码要与数据库一致，读者可以通过mysql_query（"set names'gbk'"）；语句设置页面的编码。

作用　查询的作用是就为用户提供方便。使用户在网站中快速地找到需要的内容。可通过内容的关键字查询。

下面介绍一下模糊查询，如果用户想知道所有姓“王”或其他信息的学生，就可以通过此程序来实现。例如笔者现在想知道数据库中现有的所有姓“王”的学生信息，可以通过模糊查询的提交页面把信息提交到模糊查询的处理页面。模糊查询的提交页面代码如代码12.23所示。

代码12.23　模糊查询的提交页面程序：12-23.html

＜html＞

＜!--程序名称：12-23.html--＞

＜!--程序功能：模糊查询的提交页面程序--＞

＜head＞

＜!—设置页面编码--＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=GB2312"＞

＜!—标题部分--＞

＜title＞模糊查询的提交页面程序＜/title＞

＜/head＞

＜body＞

＜h1 align="center"＞关键字查询＜/h1＞

＜!—表单部分--＞

＜form method="post"action="12-24.php"＞

＜p align="center"＞＜b＞关键字：

＜/b＞＜input type="text"name="keyword"size="20"＞

＜input type="submit"value="查询"name="b1"＞

＜input type="reset"value="重写"name="b2"＞＜/p＞

＜/form＞

＜/body＞

＜/html＞

＜/body＞

＜/html＞

此页面是用户输入需要查询的信息页面，通过此页面可以把用户输入的信息提交到模糊查询的处理页面。程序的运行效果图如12.34所示。

图　12.34　查询的提交程序图

用户可以通过此页面输入需要查询的信息，进行查询。例如笔者想查询数据库中姓“王”的所有学生的信息，在此页面中的关键字表单中输入“王”，然后单击“查询”按钮就可以把信息提交到模糊查询的处理页面，模糊查询的处理页面代码如代码12.24所示。

代码12.24　模糊查询的处理页面程序：12-24.php

＜html＞

＜!--程序名称：12-24.php--＞

＜!--程序功能：模糊查询的处理页面程序--＞

＜head＞

＜title＞查询数据库＜/title＞

＜/head＞

＜body＞

＜?php

$formdata=array();//数的使用

if(count($http_post_vars))

{

while(list($key,$value)=each($http_post_vars))

{

$formdata[strtolower($key)]=$value;

}

}

$username='root';//用户名

$password='123456';//数据库密码

?＞

＜!—表单部分--＞

＜table＞

＜tr＞＜td＞

＜?php

$name=$_POST['keyword'];//变量的转换

echo$name;//输出变量

echo"连接数据库";//输出连接提示

$db_connect=@mysql_connect('localhost',$username,$password);//连接语句

mysql_query("set names'gbk'");//设置页面编码

if(!$db_connect)

{

echo"数据库连接不成功";

?＞

＜/td＞

＜/tr＞

＜/table＞professional like"%"＆strtemp＆"%"and

＜?php

exit;//关闭连接

}

?＞

＜?php

$seldb=@mysql_select_db('mydb',$db_connect);//连接语句

$selectquery="select*from user where name like'%$name%'or age like'%$name%'

or phone like'%$name%'or address like'%$name%'or education like'%$name%'order

by id desc";//查询语句

$selectdb=@mysql_query($selectquery,$db_connect);

if(!$selectquery)

{

echo"SQL执行不成功";//输出执行结果

}

$count=@mysql_num_rows($selectdb);

if($count＜0)

{

echo"没有记录";//输出查询结果

}

else

{

echo"有$count条记录";

}

?＞

＜!—表单部分--＞

＜table width="100%"border="1"cellspacing="1"cellpadding="1"＞

＜tr＞

＜td＞＜div align="center"＞id＜/div＞＜/td＞

＜td＞＜div align="center"＞姓名＜/div＞＜/td＞

＜td＞＜div align="center"＞年龄＜/div＞＜/td＞

＜td＞＜div align="center"＞电话＜/div＞＜/td＞

＜td＞＜div align="center"＞地址＜/div＞＜/td＞

＜td＞＜div align="center"＞班级＜/div＞＜/td＞

＜/tr＞

＜?php

for($i=0;$i＜$count;$i++)

{

$records=@mysql_fetch_object($selectdb);

?＞

＜tr＞

＜td＞＜div align="center"＞＜?php echo$records-＞id?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$records-＞name?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$records-＞age?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$records-＞phone?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$records-＞address?＞＜/div＞＜/td＞

＜td＞＜div align="center"＞＜?php echo$records-＞education?＞＜/div＞＜/td＞

＜/tr＞

＜?php

}

?＞

＜?php

$db_close=mysql_close($db_connect);//关闭连接

?＞

＜p＞关闭数据库！＜/p＞

＜/body＞

＜/html＞

此程序是从提交表单中获取数据，用mysql_connect函数与数据库建立连接，使用mysql_select_db函数选择需要操作的数据库，生成查询记录的SQL语句。在SQL语句中使用了"like"操作符与数据表的第1个字段进行匹配。通过mysql_query函数执行SQL语句，把查询到的数据显示在指定的表格中。程序的运行结果如图12.35所示。

图　12.35　模糊查询的运行结果图

注意　在此程序中使用了"like"操作符，与数据表中的每一个字段进行匹配。

12.5　小结

本章介绍了PHP与MySQL相结合使用，来完成PHP对MySQL数据库的增加、删除、修改、查询等操作，本章介绍的主要内容如下。

❑MySQL数据库函数在PHP中的应用，包括PHP如何实现数据库的连接与关闭、SQL语句执行函数、字段信息获取函数、使用记录函数实现数据表记录操作。

❑用PHP进行数据查询，其中包含从表中抓取数据并在页面上显示、如何对数据有条件的选择、查询特定的数据记录、如何实现查询结果的分页显示。

❑用PHP进行数据表的修改，包括向数据表中插入新数据、如何更新数据表中的记录、删除指定的数据。

通过上面的学习，读者要知道如何使用PHP函数来完成相应的操作。

第四篇　PHP的高级开发

第13章　PHP的面向对象编程

面向对象编程（OOP）是程序员编程的一项基本技能，PHP 5.0对OOP提供了良好的支持。如何使用OOP的思想进行PHP的高级编程，对于提高PHP编程能力和规划好Web开发构架来说都是非常有意义的。

通常在做一个有数据库后台的网站的时候，都会考虑到程序需要适用于不同的应用环境。和其他编程语言不同的是，在PHP中，操作数据库的是一系列的具体功能函数（如果不使用ODBC接口的话）。这样做虽然效率很高，但是封装不够。如果有一个统一的数据库接口，那么就可以不对程序做任何修改而适用于多种数据库，从而使程序的移植性和跨平台能力都大大提高。

13.1　PHP中的类应用

许多PHP的爱好者在学习过程中会感到对PHP中类的概念难以理解和掌握，虽然知道类既然存在就有其存在的道理，但是由于平时接触和使用的机会较少，也就一略而过。其实，只要读者理解变量和函数这些PHP基本概念的话，掌握类的含义就不成问题了。

所谓类就是指由变量和作用于变量的函数组成的集合。类提供了一种对现实世界中事物的描述方式。通过有效地使用类，读者可以将描述同一对象的多个变量和函数组合在一起，作为一个整体使用，从而使编写出来的程序更直观、更合理、更易于维护。

13.1.1　深入PHP中的类

当定义一个类时，实际上是声明了它的确切形式和属性，这是通过指定类所包含的数量和对数据进行操作的代码来实现的。也许有一些简单的类仅包含代码或数据，但是现实世界中的类都包含两者。类的声明是通过关键词"class"来声明的，其一般形式为：

class classname{

函数语句;

}

在PHP中面向对象编程是通过类来完成封装的。下面通过一个实例来介绍类是如何定义的，实例程序如代码13.1所示。

代码13.1　类的定义实例13-1.php

＜?php

//**************************************************************************

//名称：13-1.php

//功能：定义一个类实例

//**************************************************************************

class Something{//在OOP类中，通常第1个字符为大写

var$x;//定义变量

function setX($v)

{

/*方法开始为小写单词，然后使用大写字母来分隔单词，例如getValueOfArea()*/

$this-＞x=$v;

}

function getX()//获取变量

{

return$this-＞x;

}

}

?＞

当然读者可以按个人的喜好进行定义，但最好保持一种标准，这样会更有效。数据成员在类中使用"var"声明来定义，在给数据成员赋值之前，它们是没有类型的。一个数据成员可以是一个整数、一个数组、一个相关数组"associative array"或者是一个对象。方法在类中被定义成函数形式，在方法中访问类成员变量时，应该使用$this-＞name，否则对一个方法来说，它只能是局部变量。使用"new"操作符来创建一个对象，代码如下所示：

$obj=new Something;

在此代码中，使用"new"操作来创建对象，在"new"后面加上类名，就完成对象的创建。然后读者可以使用成员函数，代码如下所示：

$obj-＞setX(5);

$see=$obj-＞getX();

在这个例子中，setX成员函数将5赋值给对象的成员变量x（不是类的），然后getX返回它的值5。

13.1.2　类的继承

可以像上一小节演示$obj-＞x=6那样，通过类引用方式来存取数据成员，这不是一个很好的OOP习惯。所以强烈建议通过方法来存取成员变量。如果把成员变量看成是不可处理的，并且只通过对象句柄来使用方法，那么你将是一个好的OOP程序员。不幸的是，PHP不支持声明私有成员变量，所以不良代码在PHP中也是允许的。继承在PHP中很容易实现，只要使用"extend"关键字即可，实例代码如代码13.2所示。

代码13.2　类的继承程序：13-2.php

＜?php

//***************************************************************

//名称：13-2.php

//功能：类的继承

//***************************************************************

class Another extends Something{//定义继承类

var$y;//定义变量

function setY($v){//设置变量

$this-＞y=$v;

}

function getY(){

return$this-＞y;

}

}

"Another"类的对象现在拥有了父类（Something）全部的数据成员及方法，而且还加上了自己的数据成员和方法。读者也可以使用如下代码来创建对象中的方法：

$obj2=new Something;

$obj2-＞setX(6);

$obj2-＞setY(7);

PHP现在还不支持多重继承，所以读者不能从两个或两个以上类派生出新的类来。可以在派生类中重定义一个方法，如果在"Another"类中重定义了getX方法，就不能使用"Something"中的getX方法了。如果读者在派生类中声明了一个与基派同名的数据成员，那么当处理它时，它将“隐藏”基类的数据成员。

13.1.3　类的构造函数

读者可以在自己的类中定义构造函数。构造函数是一个与类名同名的方法，当读者创建一个类的对象时会被调用，例如代码13.3所示。

代码13.3　创建构造函数与类同名的方法：13-3.php

＜?php

//*****************************************************************

//名称：13-3.php

//功能：创建构造函数与类同名的方法

//****************************************************************

class Something{//定义类

var$x;//定义变量

function Something($y){//设置方法

$this-＞x=$y;

}

function setX($v){//设置方法

$this-＞x=$v;

}

Function getX(){

return$this-＞x;

}

}

?＞

所以可以创建一个对象，通过$obj=new Something（6）；构造函数会自动地把6赋值给数据变量x。构造函数和方法都是普通的PHP函数，所以读者可以使用默认参数。function Something（$x=“3”，$y=“5”）；$obj=new Something()；、$obj=new Something（8）；及"$obj=new Something（8，9）；"。默认参数使用C++的方式，所以读者不能忽略y的值，而给x一个默认参数，参数是从左到右赋值的，如果传入的参数少于要求的参数时，其作的将使用默认参数。

当一个派生类的对象被创建时，只有它的构造函数被调用，父类的构造函数没被调用，如果读者想调用基类的构造函数，必须要在派生类的构造函数中显示调用。这样做是因为在派生类中，所有父类的方法都是可用的，如代码13.4所示。

代码13.4　调用基类构造函数程序：13-4.php

＜?php

//**************************************************************

//名称：13-4.php

//功能：调用基类构造函数

//*************************************************************

function Another(){//定义类

$this-＞y=5;//设定指针

$this-＞Something();

/*显示调用基类构造函数*/

}

?＞

13.1.4　抽象类和重载

OOP的一个很好的机制是使用抽象类。抽象类不能实例化，只能提供给派生类一个接口。设计者通常使用抽象类来强迫程序员从基类派生，这样可以确保新的类包含一些期待的功能。在PHP中没有标准的方法，但是如果读者需要这个特性，可以通过定义基类，并在它的构造函数后加上die的调用，这样就可以保证基类是不可实例化的，现在在每一个方法接口后面加上die语句。所以如果一个程序员在派生类中没有覆盖方法，将引发一个错误。因为PHP是无类型的，读者可能需要确认一个对象是来自于自己的基类的派生类，那么在基类中增加一个方法来定义类的身份，也就是返回某种标识"id"，并且在读者接收到一个对象参数时校验这个值。当然，如果一个不好的程序员在派生类中覆盖了这个方法，这种方法就不起作用了，不过问题一般多发现在懒惰的程序员身上。

当然，能够让基类对程序员无法看到是很好的，只要将接口打印出来做程序的工作就可以了。注意，在PHP中没有析构函数。

重载与覆盖不同，重载在PHP中不支持。在OOP中，读者可以重载一个方法来实现两个或重多的方法具有相同的名字，但是有不同数量或类型的参数。PHP是一种松散类型的语言，所以通过类型重载不起作用，然而通过参数的个数不同来重载也不起作用。

有时在OOP中重载构造函数非常好，这样读者可以通过不同的方法创建对象并传递不同数量的参数。在PHP中实现它的技巧，如代码13.5所示。

代码13.5　重载在PHP中的使用程序：13-5.php

＜?php

//****************************************************

//名称：13-5.php

//功能：重载

//****************************************************

class Myclass{//定义类

function Myclass(){

$name="Myclass".func_num_args();

$this-＞$name();

/*注意$this-＞name()一般是错误的，但是在这里$name是一个将被调用方法的名字*/

}

function Myclass1($x){

code;

}

function Myclass2($x,$y){

code;

}

}

?＞

通过在类中的额外的处理，使用这个类对用户是透明的，"$obj1=new Myclass('1');"、"$obj2=new Myclass('1','2');"有时非常好用。

13.1.5　面向对象的多态

多态是对象的一种能力，它可以在运行时根据传递的对象参数，决定调用哪个对象的方法。例如，如果读者有一个"figure"的类，它定义了一个draw的方法。并且派生了circle和"rectangle"类，在派生类中读者覆盖了draw方法，读者可能还有一个函数，它希望使用一个参数x，并且可以调用"$x-＞draw()"。如果读者有多态性，调用哪个draw方法依赖于读者传递给这个函数的对象类型。

多态性在像PHP这样的解释语言中是非常容易和自然的，所以PHP当然支持多态性，如代码13.6所示。

代码13.6　多态在PHP中的应用程序：13-6.php

＜?php

//******************************************************

//名称：13-6.php

//功能：多态在php中的应用

//******************************************************

function niceDrawing($x){//定义方法

/*假设这是Board类的一个方法*/

$x-＞draw();

}

$obj=new Circle(3,187);//新建一个方法

$obj2=new Rectangle(4,5);//新建第2个方法

$board-＞niceDrawing($obj);//新建第2个方法

/*将调用Circle的draw方法*/

$board-＞niceDrawing($obj2);

?＞

注意　PHP是支持多态性的。PHP也是一种解释语言，所以非常容易和自然地支持多态性。

13.1.6　一个典型的数据库操作类

初学者甚至一些非初学者常常犯的错误，就是在开发应用程序的时候，缺乏对未来的考虑。如果有一天，读者的程序需要使用其他数据库，难道读者还需要重新写一篇针对于这个版本数据库的程序吗？这是程序常常会遇到的问题，尤其是当目前的数据库可能不适合读者当前需要的时候。但是当读者做这一切的时候会发现绝非是想像的那样容易，每一个DBMS都有不同的函数。例如，在MySQL中连接数据库的函数为mysql_connect()，而在MSSQL却是mssql_connect()。重新查看读者所有的代码，然后修改所有操作数据库的函数和查询语法，这绝不是一项简单的工作。程序会经常被捆绑到错误的数据库上，以至无法在运行时达到最优性能。数据库类库就是这样产生的，它允许读者通过同样的代码来操作不同的数据库。一个设计良好的数据库类库可以完美地改变这一切。它允许读者通过极小的修改，就能转接到其他数据库，无论读者要连接什么数据库管理系统，只要使用同一个的函数，和不同的参数即可。例如，在ADOdb中，只需简单地将$db=NewADOConnection（'access'）修改为$db=NewADOConnection（'mysql'），这样，读者就能轻松地把程序从Access数据库转移到MySQL数据库中。现在网络上已经有很多这样的数据库类库，如Pear、PHPlib，笔者已经在工作中使用到这些，也许读者也曾经用过。这里仅将重点放在读者所特别关注的ADOdb，只是对它做一个介绍，使读者能够马上运用它来开发自己的下一个项目。下面将介绍数据库操作类的实例程序，如代码13.7所示。

代码13.7　一个典型的数据库操作类程序：13-7.php

＜?

//****************************************************************

//名称：13-7.php

//功能：数据库操作类

//****************************************************************

class mysql//定义类

{

var$conn;//定义变量

function connect($dbhost,$dbuser,$dbpwd,$dbname)//定义方法

{

if(!$this-＞conn=@mysql_pconnect($dbhost,$dbuser,$dbpwd)){

$this-＞halt('Can not connect to MySQL server');

}else{

$this-＞select_db($dbname);

mysql_query("SET NAMES'utf8'");

}

}

/*选择数据库*/

function select_db($dbname){//定义查询方法

return mysql_select_db($dbname,$this-＞conn);

}

function query($sql){

$this-＞querycount++;

return mysql_query($sql);

}

function fetch_array($result){//数组

return mysql_fetch_array($result);

}

function fetch_field($result){//查询

return mysql_fetch_field($result);

}

function num_rows($records){

return mysql_num_rows($records);

}

function result($query,$row){

$query=@mysql_result($query,$row);

return$query;//调用方法

}

function halt($message=''){

exit($message);

}

/*关闭服务器连接*/

function close(){

return mysql_close($this-＞conn);

}

function geterror(){

return mysql_error();

}

}

?＞

使用数据库操作类的好处就是，不用把操作数据库的SQL语句写在每个程序的代码中，在修改时也不用对每个程序都进行修改，这样可以大大节省程序员的工作量，提高工作效率，也提高代码的可读性，同时提升了程序的执行速度。

13.1.7　用文件上传类轻松实现PHP文件上传

文件上传是Web开发中的一个重要内容。PHP可以支持多种浏览器上传文件。这样可以给用户带来极大的方便，从而也提高了网站的整体性能。使用PHP上传类可以大大提高程序的工作效率，减少程序员的工作量。因为当读者需要修改程序时，不需要每个页面都去修改，只需要修改PHP文件上传类就可以了，所以减少了程序员的工作量。PHP上传类的代码如代码13.8所示。

代码13.8　用文件上传类轻松实现PHP文件上传类程序：13-8.php

＜?

//**********************************************************************************

//名称：13-8.php

//功能：用文件上传类轻松实现PHP文件上传

//**********************************************************************************

class upload

{

/*构造类*

function construct($array){//定义方法

if(is_array($array)){

//设置最大值

$MaxSize=(array_key_exists('MaxSize',$array))?intval($array['MaxSize']):100;

$Mode=(array_key_exists('Mode',$array))?intval($array['Mode']):1;

//设置上传路径

$SavePath=(array_key_exists('SavePath',$array))?$array['SavePath']:'upload';

$FileType=(array_key_exists('FileType',$array))?$array['FileType']:'jpg/gif/png/bmp';

}else{

$MaxSize=100;//最大上传个数100

$SavePath='upload';

$FileType='jpg/gif';

$Mode=1;

}

if((!is_int($MaxSize))||($MaxSize＜0))$this-＞error(__FUNCTION__,$MaxSize.'

is not a positive integer!');

$this-＞MaxSize=$MaxSize;

$this-＞SavePath=$SavePath;

$this-＞FileType=$FileType;

$this-＞Mode=$Mode;

}

/*设置访问权限*/

function getFileType(){//获取文件类型方法

$type=strtolower(substr($this-＞FileName,strrpos($this-＞FileName,".")+1));

return$type;

}

/*验证上传文件的类型*/

function checkFileType(){

if($this-＞FileName==""){

return false;

}else{

$type=$this-＞getFileType();

if(strstr($this-＞FileType,$type)){

/*echo"＜script＞alert('".$this-＞FileType."------------".$type."');＜/script＞";*/

return true;

}else{

return false;

}

}

}

/*查验文件上传的目录*/

function check_dir(){

if(!is_dir($this-＞SavePath))$this-＞mkfolder();

if(is_writable($this-＞SavePath)){

return true;

}elseif(chmod($this-＞SavePath,0777)){

return true;

}else{

return false;

}

}

/*创建一个目录*/

function mkfolder(){

$arraydir=explode("/",$this-＞SavePath);

$dirname="";

for($i=0;$i＜=count($arraydir);$i++){

$dirname.=$arraydir[$i]."/";

if(!is_dir($dirname)){

mkdir($dirname,0777);

}

}

}

/*生成文件名*/

function random($Length){

$hash='';

$chars

'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';

$max=strlen($chars)-1;

mt_srand((double)microtime()*1000000);

for($i=0;$i＜$Length;$i++){

$hash.=$chars[mt_rand(0,$max)];

}

return$this-＞random=$hash;

}

/*重新命名文件*/

function nFileName(){

switch($this-＞Mode){

case'1':

/*设定时间*/

return$this-＞nFileName=date("Ymdhis").".".$this-＞getFileType();

break;

case'2':

/*随意的*/

return$this-＞nFileName=$this-＞random(32).".".$this-＞getFileType();

break;

case'3':

/*时间采用md5加密*/

return$this-＞nFileName=md5(date("Ymdhis")).".".$this-＞getFileType();

break;

case'4':

return

$this-＞nFileName=date("Ymdhis").$this-

＞random(6).".".$this-＞getFileType();

break;

default:

return$this-＞nFileName=date("Ymdhis").".".$this-＞getFileType();

break;

}

}

/*获取上传文件的大小*/

function GetFileSize(){

if($this-＞TempFile!=''){

return filesize($this-＞TempFile);

}else{

return false;

}

}

/*上传文件的路径*/

function upload_file(){

if($this-＞TempFile!=""){

if(($this-＞MaxSize*1024)＞$this-＞GetFileSize()){

if($this-＞check_dir()){

if($this-＞checkFileType()){

$this-＞FilePath=$this-＞SavePath.$this-

＞nFileName();

if(@copy($this-＞TempFile,$this-＞FilePath)||

(function_exists('move_uploaded_file')＆＆

@move_uploaded_file($this-＞TempFile,$this-＞FilePath)))

{

@unlink($this-＞TempFile);

return true;

}else{

return false;

}

}

}

}

}

}

function error($function,$errormsg)

{

exit('Error in file＜b＞'.__FILE__.'＜/b＞,Function＜b＞'.$function.'()＜/b＞:'.$errormsg);

}

?＞

在此文件上传类中首先使用数组构造一个上传函数，通过检验访问权限、上传文件的类型、文件上传的目录等，来做文件上传前的准备，然后再通过创建上传目录、上传文件的命名、获取上传文件的大小是否合法等的判断来实现文件的上传。上传的时间和日期通过"md5"加密技术进行加密。这样一个上传类就完成了。

注意　实现文件的上传类的使用是通过"post"把表单的数据提交上文件上传类程序中，然后通过判断来实现文件的上传。

作用　读者使用数据上传类来实现数据的上传，这样可以提高程序的效率，也提高程序的可读性。

技巧　使用数据上传类，是把分成几层，上传表单是一层，数据上传处理程序放在类中又是一层。在需要用户到数据上传处理程序时，再把数据上传处理程序引入到页面中，这样就提高了程序的效率。

13.2　PHP模板的应用

在多人开发大型PHP项目时，模板技术非常有用，它可以分开美工和程序员的工作，并且方便界面的修改和完善；不仅如此，利用模板技术，还可以简单、有效地定制或者修改站点。现在笔者将要讲述如何在PHP中应用模板技术。

PHP的模板技术又分为PHPLIB Template模板引擎、FastTemplate模板引擎、Smarty模板引擎。

13.2.1　什么是模板技术

什么是PHP的模板技术？PHP模板发展自Perl的Template。剥开神秘的面纱，模板技术的核心概念是非常简单的。要将读者的美工页面指定为模板文件，只需将页面中活动的内容如数据库输出、用户交互等部分定义为变量，放在模板文件中相应的位置，当用户浏览时，由PHP程序文件打开该模板文件，将模板文件中定义的变量进行替换，替换成对应的数据库输出或者用户交互等动态生成内容。

模板能够改善网站的结构，其特点如下。

❑可以在几秒钟改变整个站点的外观。

❑抽象程序设计，没有垃圾HTML代码。

❑设计人员不需要关心全部的“模糊”代码。

❑速度快。

现在PHP中应用最多的模板有3种，Smarty、Phplibtemplate和Fasttemplate，这3种模板作者虽然不同，但是在语法结构和函数定义上却有着惊人的相似之处。只要读者掌握了其中的一个，另一个相信读者也会很快地熟练运用。本章总括了使用模板的优点和优势，又分别介绍了Smarty、Phplibtemplate和Fasttemplate的使用方法和技巧，最后又对这两种模板的效率进行了对比。希望通过本章的介绍，能帮助那些想了解模板技术的读者用最快的速度去掌握它，并在以后的编程中去应用这项伟大的技术。

13.2.2　PHPLIB Template模板引擎的介绍和使用实例

如果读者正在设计一个交互式网站，一定会关注两个主要的问题，就是美工和程序。这也是一个网站在建设中抛开其内容之后最关键的要素。通常有两种方式来协调美工和程序之间的关系，如下所述。

❑先做好美工页面，然后由程序员直接在美工页面的HTML文件中嵌入ASP、JSP、PHP等程序代码。当然本书主要是介绍嵌入PHP程序代码。

❑美工和程序同时进行，但这时因为没有页面框架，程序只能做出一些关键代码，双方完成后再进行一次美工页面和程序代码的嵌入合成。

在实际的网站建设过程中，由于人员、进度等环境的限制，大家通常会混合地使用上面两种协调方式。然而这两种方法都有不足之处，如下所示。

❑效率不高。两者协调不好可能产生等待、重复代码调试步骤等现象。

❑调试不畅。由于程序代码最终需要嵌入在HTML页面中，代码的嵌入、调试、纠错都比较烦琐。

❑维护不便。一旦美工设计需要修改，如网站改版，那么所有程序和HTML代码混合页面都需要重写。

如果读者正在使用PHP程序建设网站，那么恭喜读者，PHP的模板技术会比较圆满地解决上述问题。

那么什么是PHP的模板技术？PHP模板即PHPLIB的Template技术，是PHPLIB程序库中的主要模块之一，发展自Perl的Template。而PHPLIB则是在PHP上的一个扩展，提供了很多类库，能够方便地实现一些基本功能、如用户认证，数据库封装等。读者可以在phplib.netuse.de上下载到其最新版本。要使用PHP模板，只需在PHPLIB的程序包中解开template.inc文件，并放到PHP程序能够调用的目录里就可以了。

剥开神秘的面纱，模板技术的核心概念非常简单。要将美工页面指定为模板文件，只需将页面中活动的内容如数据库输出、用户交互等部分定义成形式，为变量放在模板文件中相应的位置。当用户浏览时，由PHP程序文件打开该模板文件，将模板文件中定义的变量进行替换，替换成对应的数据库输出或者用户交互等动态生成内容。下面举例介绍PHP模板，定义模板文件代码如下所示：

＜html＞

.....

＜body＞

...

...

＜/body＞

＜/html＞

可以看到，事实上模板文件就是一个普通的HTML文件，它包含了读者所想要的版面、美工等要素，而内部的活动内容则以变量的形式存在，并等待被替换。显然，模板文件直接被浏览是毫无意义的，因为它不包含任何PHP程序，所有的内容都是“死”的。现在来看看，怎样调用模板，让它“活动”起来。

假设读者在一个PHP文件中使用了上述模板，当用户浏览此PHP文件时，此文件处理过程如代码13.9所示。

代码13.9　调用模板程序：13-9.php

＜?php

//*********************************************************************

//名称：13-9.php

//功能：调用模板程序

//*********************************************************************

mydate=date("Y年m月d日");//处理好变量的值

include("template.inc");//调入模板程序模块

mytemp=new Template("/你的模板文件所在目录/");

/*创建一个模板实例mytemp，如果模板就在当前目录，那么使用"."就可以*/

mytemp-＞set_file("MyFileHandle","MyTemplate.html");

/*设置MyFileHandle文件句柄指向我们所要调用的模板文件Mytemplate.html*/

mytemp-＞set_var("today",mydate);

/*调用模板的set_var方法，设置模板中的变量today值为$mydate*/

mytemp-＞parse("MyOutput","MyFileHandle");

/*调用模板的parse方法，对MyFileHandle文件句柄所指向的模板文件进行分析

替换其中相应变量

并把替换结果即完整的HTML文件内容保存在字串变量MyOutput中*/

mytemp-＞p("MyOutput");

/*打印输出结果字串变量MyOutput的值*/

?＞

就是这么简单，模板技术很轻松地把网站设计分离成了清晰的美工和程序两个方面，并把它们的成果简单、方便地结合了起来。一方面，如果美工设计需要修改，那么我们只要记住原模板中各个变量名，把变量名插入到新模板中对应位置就可以了，真的很轻松！另一方面，在PHP程序中基本没有了PHP脚本和HTML语法混合的现象，很大地提高了PHP系统的执行效率，而且如果是数据库等一些费时的操作，现在可以很及时地关闭数据库、释放资源，这样也在一定程度上提高了PHP和相关系统的资源使用效率。

13.2.3　FastTemplate模板引擎的介绍和使用实例

当读者在建立一个站点的时候，可能不得不面对以下现实，站点需要一名程序员来设计程序和一名网站设计者来组织页面。那么，是否有使两者很好地结合起来的方法呢？有的，就是使用模板FastTemplate技术，它将使你的工作更加轻松。下面解释一下使用模板的好处。

❑在很短的时间内可以替换整个站点的外观。

❑使程序员可以抽象编程，而无须接触HTML代码。

❑速度非常之快。

❑可以重复利用以前的模板。

模板的来历：FastTemplate来自于Perl软件包（在CPAN上可以找到）。它被移植到了PHP平台上。你只需要一个基础类文件"class.FastTemplate.php"。先介绍一下使用模板和使用echo或print命令建立HTML页面的区别。echo和print在编写短小的脚本时显得非常实用，但是做出来的脚本的组织性和可定制性不好，修改起来不太方便。模板在编写支持多国语种的站点时的效率则要高的多，如用echo和print时大大增加了程序员工作量。然而使用模板技术，把网站的程序部分和美工部分分的很清楚，加快了网站的建设速度，也减少了程序员的工作量，尤其是大工程时。

那么，怎么使用FastTemplate呢？第1步，只需使用函数＆amp;lt;?php$tpl=new FastTemplate("path");?＆amp;gt;，其中path指向template目录所在的路径。这句函数建立了一个$tpl对象，以后可以对它指定参数，进行处理或用来建立各种页面等。FastTemplate是建立在这么一种理论基础之上的，即假定一个Web页是由许多小的部分组成的，如Web页细分为TITLE、PAGE、FOOT等。整个页被赋予一个变量名，每一个小部分又被赋予一个变量名，最小的不可再分割的部分通常就是字符串了，它也被赋予一个变量名。具体处理的时候，是一层层的包含关系。被包含部分在上一层中以宏"{NAME}"的形式出现。最后经过一层层地向上输出，得到完整的页面。那么最底层的向字符串赋值的函数是什么呢，就是"＆amp;lt;?php$tpl-＆amp;gt;assign(NAME,"text");?＆amp;gt;"。通过这个功能，FastTemplate将字符串text赋予了变量NAME，在此层结束时，使用＜br＞跳到另一层执行。其他层与之类似。

替换宏"{NAME}"的内容为text。例如"$tpl-＆amp;gt；assign（NAME，"me"）；"，这就将变量NAME赋值了字符串"me"。第2步，$tpl需要知道其所调用的所有模板文件，即各个小部分。这个功能由define一个数组实现，即"＆amp;lt；?php$tpl-＆amp;gt；define()；?＆amp;gt；"，代码如下：

＆amp;lt;?php$tpl-＆amp;gt;define(array(foo=＆amp;gt;"foo.tpl",bar=＆amp;gt;"bar.tpl"));?＆amp;gt;

这说明总共包括了两个模板文件：foo.tpl和bar.tpl，并给它们指定了名字foo和bar。有了以上的知识以后，现在是否想试一试将模板文件中所包含的宏"{MACROS}"部分按照自己定义的变量替换呢？使用以下的命令即可实现：

＆amp;lt;?php$tpl-＆amp;gt;parse(PAGECONTENT,"foo");?＆amp;gt;

这条命令的具体意义是，首先已经用assign定义了FOO模板中包含的若干宏变量，然后根据这些变量对模板文件foo进行替换处理，并将替换后的模板文件赋予另一个变量名PAGECONTENT。完整的代码如下：

＆amp;lt;?php

$tpl-＆amp;gt;assign(NAME,"me");

$tpl-＆amp;gt;parse(PAGECONTENT,"foo");?＆amp;gt;

当然，还没有做完，因为"bar"模板文件才是Web的主输出部分，"bar"模板包含着"foo"模板，还包含着宏变量"{PAGETITLE}"和"{PAGECONTENT}"等待处理。PAGECONTENT经过对FOO的处理已经得到，PAGETITLE还未指定，所以还要指定PAGETITLE，并调用函数＆amp;lt;?php$tpl-＆amp;gt;parse（MAIN，"bar");?＆amp;gt;进行处理，并将处理后的结果赋予变量MAIN。如"＆amp;lt;?php$tpl-＆amp;gt;assign(PAGETITLE,"FooBar test");$tpl-＆amp;gt;parse(MAIN,"bar");?＆amp;gt;"。很简单吧，最后只需输出页面即可。

13.2.4　Smarty模板引擎的介绍和使用实例

smarty是一个使用PHP写出来的PHP模板引擎，它提供了逻辑与外在内容的分离。简单地讲，目的就是要使PHP程序员同美工分离，使程序员改变程序的逻辑内容不会影响到美工的页面设计，美工重新修改页面不会影响到程序的程序逻辑，这在多人合作的项目中显得尤为重要。smarty的优点有以下几方面。

❑速度：采用smarty编写的程序可以获得最大速度的提高，这一点是相对于其他的模板引擎技术而言的。

❑编译型：采用smarty编写的程序在运行时要编译成一个非模板技术的PHP文件，这个文件采用了PHP与HTML混合的方式，在下一次访问模板时将Web请求直接转换到这个文件中，而不再进行模板重新编译。在源程序没有改动的情况下。

❑缓存技术：smarty选用的一种缓存技术，它可以将用户最终看到的HTML文件缓存成一个静态的HTML页，当设定smarty的cache属性为true时，在smarty设定的cachetime期内将用户的Web请求直接转换到这个静态的HTML文件中来，这相当于调用一个静态的HTML文件。

❑插件技术：smarty可以自定义插件。插件实际就是一些自定义的函数。

❑模板中可以使用if...else等条件判断语句。在模板文件使用判断语句可以非常方便地对模板进行格式重排。

上面介绍的是smarty的优点，下面介绍不适合使用smarty的地方。

❑需要实时更新的内容。例如股票显示，它需要经常对数据进行更新，这类型的程序使用smarty会使模板处理速度变慢。

❑小项目：小项目因为项目简单而美工与程序员兼于一人的项目，使用smarty会丧失PHP开发迅速的优点。

了解了smarty模板后，下面就来介绍如何安装smarty类，安装smarty的环境是PHP版本4.06以上版本。安装smarty方法非常简单，从http://samrty.php.net中下载smarty将LIB中所有文件复制到comm目录下就完成了基本安装。本节将通过几个实例来讲一讲smarty的使用。smarty模板通常使用".tpl"来标识，有些人为了美工方便，将扩展名直接写成".html"也是可以的。本文中采用smarty标准写法，以".tpl"表示一个smarty模板。下面就先看个简单的实例，如代码13.10所示。

代码13.10　smarty模板页面程序：13-10.tpl

＜html＞

＜!--名字：13-10.tpl--!＞

＜!--功能：smarty模板--!＞

＜head＞

＜title＞smarty模板＜/title＞

＜/head＞

＜body＞

{*显示是smarty变量识符里的用*包含的文字为注释内容*}

{*页面头*}

＜{include file="13-11.tpl"}＞

大家好，我叫＜{$name}＞，欢迎大家阅读我的smarty学习材料。

{*页面尾*}

＜{include file="13-12.tpl"}＞

＜/body＞

＜/html＞

在此代码中，“{*……*}”是模板页的注释，它在smarty对模板进行解析时不进行任何输出，仅供模板设计师对模板进行注释。"＜{include file=”xxx.tpl”}＞"使用此句将一个模板文件包含到当前页面中，例子中将在网站中公用事的"head.tpl"与"foot.tpl"进行了包含，读者也可以理解为，使用这一句将"xxx.tpl"中的内容全部复制在当前语句处。当然，读者不使用这一句也可以，将"xxx.tpl"中的内容复制到当前语句处，也是完全可以的。"{$name}"模板变量是smarty中的核心组成，采用smarty定义的左边界符“{”与右边界符“}”包含着，以PHP变量形式给出，在smarty程序中将使用$smarty-＞assign（"name"，"某人名"）；将模板中的"$name"替换成“某人名”3个字。

下面介绍如何把模板页面中将要包含时去的文件，如代码13.11和代码13.12所示。

代码13.11　smarty模板程序：13-11.tpl

＜html＞

＜!--名字：13-11.tpl--!＞

＜!--功能：smarty模板--!＞

＜head＞

＜title＞smarty模板＜/title＞

＜/head＞

＜body＞

此代码显示模板的头部页面信息，也就是简单的HTML代码。下面介绍模板的尾部页面，如代码13.12所示。

代码13.12　smarty模板程序：13-12.tpl

＜!--名字：13-12.tpl--!＞

＜!--功能：smarty模板--!＞

＜hr＞

＜!—居中显示--＞

＜center＞CopyRight(C)by 2008＜/center＞

＜hr＞

＜/body＞

＜/html＞

此代码和模板的头部信息页面类似，都是简单的HTML代码。下面就来介绍一下处理模板的PHP程序，如代码13.13所示。

代码13.13　处理模板的PHP程序：13-13.php

＜?php

//××××××××××××××××××××××××××××××××××××××××××××××××××

//名称：13-13.php

//功能：处理模板的PHP程序

//××××××××××××××××××××××××××××××××××××××××××××××××××

include_once("../libs/Smarty.class.php");//包含smarty类文件

$smarty=new Smarty();//建立smarty实例对象

$smarty

$smarty-＞template_dir="./templates";//设置模板目录

$smarty-＞compile_dir="./templates_c";//设置编译目录

/*左右边界符，默认为{}，但实际应用当中容易与JavaScript

相冲突，所以建议设成＜{}＞或其他*/

$smarty-＞left_delimiter="＜{";

$smarty-＞right_delimiter="}＞";

$smarty-＞assign("name","某人名");//进行模板变量替换

$smarty-＞display("index.tpl");

?＞

在此程序中，首先要把smarty的类文件包含在PHP程序中，再建立smarty实例对像，指定模板目录，定义边界符，之后进行替换操作。程序的运行结果如图13.1所示。

图　13.1　smarty模板实例程序的运行效果图

注意　在使用smarty模板技术时，首先要把smarty模板的类文件包含到程序中。设置模板的目录时，路径一定要正确，否则程序不能运行。

作用　使用模板技术的作用就是把美工和程序做一次分工，这样可以提高开发周期，减少了开发的费用。使用模板的好处还有就是在以后的维护中，如果网站进行改版时，程序部分就不需要修改了，只需要修改模板即可。

13.3　小结

本章介绍了PHP的面向对象编程，包括PHP中的类定义、PHP中的类应用、PHP模板的应用。其中PHP中的类应用又包括一个典型的数据库操作类，用文件上传类轻松实现PHP文件上传。而PHP模板的应用中包括模板技术介绍、PHPLIB Template模板引擎介绍和使用实例、FastTemplate模板引擎介绍和使用实例、Smarty模板引擎介绍和使用实例。通过本章的学习，读者需要知道如何定义并使用类，了解在什么项目下可以使用模板技术。

第14章　PHP与Ajax

本章将介绍Ajax在PHP中的使用，Ajax是一个功能更加完备的Web应用技术。Ajax与PHP的结合，使PHP的功能和效果更加完善，更加受用户的欢迎。本章主要了解什么是Ajax，并学习Ajax的实现原理和工作流程，其中还穿插Ajax应用的案例。本章最后介绍了一个常见的Ajax框架：Spry框架。

14.1　什么是Ajax

Ajax是客户端脚本与Web服务器交换数据的Web应用程序的开发。Ajax的全称是Asynchronous JavaScript and XML，其中，Asynchronous是异步的意思，它有别于传统Web开发中采用的同步的方式。与其他技术不同的是，Ajax不用打断交互流程进行重新加载，就可以动态地更新信息。使用Ajax用户可以创建类似本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。

Ajax是客户希望得到一个功能更完备的应用，是用户的一个新的选择、新的工具，可以开发更加丰富的基于浏览器的应用程序。Ajax的主要组件是JavaScript脚本语言。Ajax的应用和测试框架，再加上更优秀的工具支持，减轻了开发人员的负担。

Ajax在大多数现代浏览器中都能使用，而且不需要任何专门的软件或硬件。实际上，这种方法的一大优势就是开发人员不需要学习一种新的语言，也不必完全丢掉原先掌握的服务器端技术。Ajax是一种客户端方法，可以与J2EE、.NET、PHP、Ruby和CGI脚本交互，它并不关心服务器是什么。尽管存在一些很小的安全限制，但读者还是可以从现在就开始使用Ajax，充分利用读者原有的知识。

下面将介绍使用Ajax时常犯几个的错误。首先，Ajax不同于IFRAME和隐藏框架，通过XHR做出的请求不会修改浏览器的历史栈。这点在许多情况下没有什么问题，如果用户确实想用后退按钮，就有问题了。与其他基于浏览器的方法不同，Ajax不会修改地址栏中显示的链接，这表明用户不能轻松地为一个页面建立书签，或者向朋友发送一个链接。对于许多用户来说，可能没有这个要求，但是如果你的网站专门为人提供行车路线之类的内容，就要针对这个问题提供一个解决方案了。

Ajax允许读者异步地完成操作，这是其最大的优点同时也是最突出的缺点。Web应用是以一种请求/响应模式完成操作的，用户也已经接受了这种思想。但是用了Ajax后，就不再有这个限制了。用户可以只修改页面的一部分，而如果用户没想到这一点，很可能会被搞糊涂。

什么时候应该使用Ajax技术，而什么时候不该用呢？其实从验证开始就很合适，但这里并没有限制读者的主动性。可以使用Ajax提交数据，但不能把它作为提交数据的主要方法。验证和表单填写就非常适合用Ajax来实现。

14.2　Ajax的实现原理和工作流程

为了学习Ajax，必须深刻地理解XMLHttpRequest对象，它是一个JavaScript对象。首先要创建该对象，其实很简单，如下面的代码所示：

var xmlHttp=new XMLHttpRequest();

Ajax基本上是把JavaScript技术和XMLHttpRequest对象放在Web表单和服务器之间。当用户填写表单时，数据发送给一些JavaScript代码而不是直接发送给服务器。相反，JavaScript代码捕获表单数据并向服务器发送请求。同时用户屏幕上的表单也不会闪烁、消失或延迟。换句话说，如果JavaScript代码在幕后发送请求，用户甚至不知道请求的发出。更好的是，请求是异步发送的，也就是说JavaScript代码（和用户）不用等待服务器的响应。因此用户可以继续输入数据、滚动屏幕和使用应用程序。

然后，服务器将数据返回JavaScript代码（仍然在Web表单中），后者决定如何处理这些数据，可以迅速更新表单数据，让人感觉应用程序是立即完成的，表单没有提交或刷新，而用户得到了新数据。JavaScript代码甚至可以对收到的数据执行某种计算，再发送另一个请求，完全不需要用户干预！这就是XMLHttpRequest的强大之处。它可以根据需要自行与服务器进行交互，用户甚至可以完全不知道幕后发生的一切。结果类似于桌面应用程序的动态、快速响应、高交互性的体验，但是背后又拥有互联网的全部强大力量。

14.3　Ajax应用

前面介绍了Ajax，接下来简单谈谈远程脚本。读者可能会想：“Ajax有什么大不了的？早就用IFRAME做过同样的事情。”实际上，笔者也曾用过这种方法。这在以前一般称为远程脚本（remote scripting），很多人认为这只是一种修修补补。不过，这确实提供了一种能避免页面刷新的机制。

14.3.1　如何建立远程连接对象

基本说来，远程脚本是一种远程过程调用类型。用户可以像正常的Web应用一样与服务器交互，但是不用刷新整个页面。与Ajax类似，读者可以调用任何服务器端技术来接收请求、处理请求并返回一个有意义的结果。正如在服务器端有很多选择，客户端同样有许多实现远程脚本的选择。读者也可以在应用中嵌入Flash动画、Java applet，或者ActiveX组件，甚至可以使用XML-RPC，但是这种方法过于复杂，因此除非读者使用这种技术很有经验，否则这种方法不太合适。实现远程脚本的通常做法包括将脚本与一个IFRAME（隐藏或不隐藏）结合，以及由服务器返回JavaScript，然后在浏览器中运行这个JavaScript。

Microsoft提供了自己的远程脚本解决方案，并称之为Microsoft远程脚本（Microsoft Remote Scripting,MSRS）。采用这种方法，可以像调用本地脚本一样调用服务器脚本。页面中嵌入Java applet，以便与服务器通信，ASP页面用于放置服务器端脚本，并用HTHL文件管理客户端的布局摆放。在Netscape和IE 4.0及更高版本中都可以使用Microsoft的这种解决方案，可以同步调用，也可以异步调用。不过，这种解决方案需要Java，这意味着可能还需要附加的安装例程，而且还需要Internet Information Services（IIS），因此会限制服务器端的选择。

Brent Ashley为远程脚本创建了两个免费的跨平台库。JSRS是一个客户端JavaScript库，它充分利用DHTML向服务器做远程调用。相当多的操作系统和浏览器上都能使用JSRS。如果采用一些常用的、流行的服务器端实现（如PHP、Python和Perl CGI），JSRS一般都能在网站上安装并运行。

如果觉得JSRS太过笨重，Ashley还创建了RSLite，这个库使用了cookie。RSLite仅限于少量数据和单一调用，不过大多数浏览器都能提供支持。

为了进行比较，下面将介绍如何使用IFRAME来实现类似Ajax的技术，如代码14.1所示。

代码14.1　建立远程连接对象程序：14-1.html

＜html＞

＜!--程序名称：14-1.html--＞

＜!--程序功能：建立远程连接对象程序.--＞

＜head＞

＜title＞建立远程连接对象程序＜/title＞

＜/head＞

＜script type="text/javascript"＞

function handleResponse(){

alert('this function is called from server.html');

}

＜/script＞

＜body＞

＜h1＞Remote Scripting with an IFRAME＜/h1＞

＜!—框架--＞

＜iframe id="beforexhr"

name="beforexhr"

style="width:0px;height:0px;border:0px"

src="blank.html"＞＜/iframe＞

＜a href="14-2.html"target="beforexhr"＞call the server＜/a＞

＜/body＞

＜/html＞

此程序是建立远程连接的程序，程序14.1.html的运行效果如图14.1所示。

图　14.1　建立远程连接的程序运行效果图

实现本实例还要有类似服务器响应的程序，下面就建立一个模拟服务器的响应程序，如代码14.2所示。

代码14.2　模拟服务器的响应程序：14-2.html

＜html＞

＜!--程序名称：14-2.html--＞

＜!--程序功能：模拟服务器的响应程序.--＞

＜head＞

＜title＞Microsoft Internet Explorer＜/title＞

＜/head＞

＜!—脚本部分--＞

＜script type="text/javascript"＞

window.parent.handleResponse();

＜/script＞

＜body＞

＜/body＞

＜/html＞

此程序用于处理连接程序的响应程序，当用户单击"call the server"时，模拟服务器的响应程序会处理此次操作。程序的运行效果如图14.2所示。

图　14.2　处理连接程序的响应程序运行效果图

注意　JavaScript的嵌入位置要正确，如果读者没有正确地嵌入脚本程序，会使网页出现错误。

14.3.2　异步发送请求

本小节将介绍如何使用XMLHttpRequest对象。前面已经向读者介绍过如何创建这个对象了，下面来看如何向服务器发送请求，以及如何处理服务器的响应。

最简单的请求是，不以查询参数或提交表单数据的形式向服务器发送任何信息。在实际中，往往都希望向服务器发送一些信息。

使用XMLHttpRequest对象发送请求的基本步骤如下。

（1）为得到XMLHttpRequest对象实例的一个引用，可以创建一个新的实例，也可以访问包含有XMLHttpRequest实例的一个变量。

（2）告诉XMLHttpRequest对象，哪个函数会处理XMLHttpRequest对象状态的改变，为此要把对象的onreadystatechange属性设置为指向JavaScript函数的指针。

（3）指定请求的属性。XMLHttpRequest对象的open()方法会指定将发出的请求。open()方法取3个参数：一个是指示所用方法（通常是GET或POST）的串；一个是表示目标资源URL的串；一个是Boolean值，指示请求是否是异步的。

（4）将请求发送给服务器。XMLHttpRequest对象的send()方法把请求发送到指定的目标资源。send()方法接受一个参数，通常是一个串或一个DOM对象。这个参数作为请求体的一部分被发送到目标URL。当向send()方法提供参数时，要确保open()中指定的方法是POST。如果没有数据作为请求体的一部分被发送，则使用null。

这些步骤很直观：读者需要XMLHttpRequest对象的一个实例，要告诉它如果状态有变化该怎么做，还要告诉它向哪里发送请求以及如何发送请求，最后还需要指导XMLHttpRequest发送请求。不过，除非读者对C或C++很了解，否则可能不明白函数指针（function pointer）是什么意思。

函数指针与任何其他变量类似，只不过它指向的不是像串、数字、甚至对象实例之类的数据，而是指向一个函数。在JavaScript中，所有函数在内存中都编有地址，可以使用函数名引用，这就提供了很大的灵活性。可以把函数指针作为参数传递给其他函数，或者在一个对象的属性中存储函数指针。

对于XMLHttpRequest对象，onreadystatechange属性存储了回调函数的指针。当XMLHttpRequest对象的内部状态发生变化时，就会调用这个回调函数。当进行了异步调用后，请求就会发出，脚本立即继续处理（在脚本继续工作之前，不必等待请求结束）。一旦发出了请求，对象的readyState属性会经过几个变化。尽管针对任何状态都可以做一些处理，不过读者最感兴趣的状态可能是服务器响应结束时的状态。通过设置回调函数，就可以有效地告诉XMLHttpRequest对象：“只要响应到来，就调用这个函数来处理响应”。

下面将以一个实例来介绍如何实现一个异步请求，如代码14.3所示。

代码14.3　异步请求程序：14-3.html

＜html＞

＜!--程序名称：14-3.html--＞

＜!--程序功能：异步发送请求程序--＞

＜head＞

＜title＞异步发送请求＜/title＞

＜/head＞

＜body＞

＜!—方法部分--＞

function getinfo(){

var email=document.getemailID("email").value;

var url="/cgi-local/lookupCustomer.php?email="+escape(email);

request.open("GET",url,true);

request.onreadystatechange=updatePage;

request.send(null);

}

＜/boyd＞

＜/html＞

异步请求的使用要比同步请求更困难，因为这些请求将直接返回数据，不需要创建回调函数。但是这并不是使用XMLHttpRequest的标准方法，因为在请求发生时浏览器会被锁定。在有些情况下，这种阻塞是很有效的，主要是决策必须在当前函数结束之前做出，但在大多数情况下，会希望这些请求在后台完成。而异步请求则允许浏览器在载入新数据时继续执行JavaScript代码，用户也可以继续与页面进行交互。加上适当的用户界面，异步通信机制能够使得Ajax应用程序十分有用，即使用户与该网站的连接速度很慢。

为了发起一个异步调用，需要完成两个任务：在open方法中将异步标志设置为true，然后添加一个readyStateChanged事件，该事件的属性值为updatePage。

注意　需要特别注意的是该属性在代码中设置的位置，它是在调用send()之前设置的。发送请求之前必须设置该属性，这样服务器在回答完成请求之后才能查看该属性。

14.3.3　回调函数的应用

回调函数实际上就是在调用某个函数时，将自己的一个函数的地址作为参数传递给那个函数。当然这个函数也为回调函数。

回调和API非常接近，两者的共性都是跨层调用的函数。区别是：API是低层提供给高层的调用，一般这个函数对高层都是已知的；而回调正好相反，它是高层提供给低层的调用，对于低层来说，它是未知的，必须由高层进行安装。这个安装函数其实就是一个低层提供的API，安装后低层不知道这个回调的名字，但它通过一个函数指针来保存这个回调函数，在需要调用时，只需引用这个函数指针和相关的参数指针。下面介绍一个简单的回调函数的应用实例，如代码14.4所示。

代码14.4　回调函数的应用程序14-4.php

＜?php

//********************

//程序名称：14-4.php

//功能：回调函数的应用程序

//*********************

/*关键是参数前加个＆*/

function foo(＆$bar)

{

$bar='4';

}

$str='1';

foo($str);

echo$str;//输出2

?＞

14.3.4　Ajax与XML的应用

Ajax读取XML的原理很简单，就是在客户端创建一个XMLHttpRequest对象，用来与服务器进行异步通信，这就是Ajax的核心。其实早就已经在用异步通信了，只是没把这项技术用在网页设计中而已。为该对象的onreadystatechange属性添加一个事件，当对象的readyState改变的时候就会引发指定的事件。下面就介绍如何使用Ajax读取XML文件的实例，首先要建立一个XML文件，如代码14.5所示。

代码14.5　XML文件程序14-5.xml

＜?xml version="1.0"encoding="utf-8"?＞

＜!--名称：14-5.xml--＞

＜!--功能：XML文件--＞

＜books＞

＜book＞

＜author＞李刚＜/author＞

＜title＞php jquery＜/title＞

＜/book＞

＜book＞

＜author＞李刚＜/author＞

＜title＞Java＜/title＞

＜/book＞

＜book＞

＜author＞李刚＜/author＞

＜title＞php＜/title＞

＜/book＞

＜/books＞

在此程序中，代码"＜?xml version=“1.0”encoding="utf-8"?＞"指明了XML的版本是1.0及程序所采用的编码是utf-8。接下来是定义作者及书名等。这些标记与HTML类似，都是成双成对出现的。程序的运行效果如图14.3所示。

图　14.3　XML文件运行效果图

注意　程序中的标记可以是读者定义的，不是固定的，标记也是成双成对出现的。

在上面可以看到XML程序的运行效果成树型结构，可以展开也可以隐藏。下面将介绍如何使用Ajax来读取XML中的数据，如代码14.6所示。

代码14.6　Ajax读取XML文件程序：14-6.html

＜html＞

＜!--名称：14-6.htm--＞

＜!--功能：Ajax读取XML文件程序--＞

＜head＞

＜!—脚本部分--＞

＜script＞

＜!—定义变量--＞

var req=null;

＜!—定义方法--＞

function processReqChange(){

if(req.readyState==4＆＆req.status==200＆＆req.responseXML){

var dtable=document.getElementById('dataBody');

var nl=req.responseXML.getElementsByTagName('book');

for(var i=0;i＜nl.length;i++){

var nli=nl.item(i);

var elAuthor=nli.getElementsByTagName('author');

var author=elAuthor.item(0).firstChild.nodeValue;

var elTitle=nli.getElementsByTagName('title');

var title=elTitle.item(0).firstChild.nodeValue;

var elTr=dtable.insertRow(-1);

var elAuthorTd=elTr.insertCell(-1);

elAuthorTd.innerHTML=author;

var elTitleTd=elTr.insertCell(-1);

elTitleTd.innerHTML=title;

}

}

}

function loadXMLDoc(url){

if(window.XMLHttpRequest){

try{req=new XMLHttpRequest();

}catch(e){req=false;}

}else if(window.ActiveXObject){

try{req=new ActiveXObject('Msxml2.XMLHTTP');

}catch(e){

try{req=new ActiveXObject('Microsoft.XMLHTTP');

}catch(e){req=false;}

}}

if(req){

req.onreadystatechange=processReqChange;

req.open('GET',url,true);

req.send('');

}

}

var url=window.location.toString();

url=url.replace(/14-6.html/,'14-5.xml');

loadXMLDoc(url);

＜/script＞

＜/head＞

＜body＞

＜table cellspacing="0"cellpadding="3"width="100%"＞

＜tbody id="dataBody"＞

＜tr＞

＜th width="20%"＞作者＜/th＞

＜th width="80%"＞书名＜/th＞

＜/tr＞

＜/tbody＞

＜/table＞

＜/body＞

＜/html＞

在此代码中，processReqChange()用来读取XML文件中的标记book、author和title，然后把读取的结果输出到表格中。在此程序中要考虑浏览器的兼容，方法"loadXMLDoc"定义了在3种浏览器中浏览。程序的运行效果如图14.4所示。

图　14.4　Ajax读取XML文件程序的运行效果图

注意　大多数程序员在设计网页程序时，没有考虑到浏览器的兼容问题，而用户根据自己的喜好，使用的浏览器是不同的，这样就会影响网页的浏览效果。

14.3.5　一个基于Ajax的用户名验证程序

本节将为读者介绍如何使用Ajax实现用户名的验证程序。此实例包括两部分：一部分为静态页面，主要负责前台页面的显示；另一部分为一个模拟查询结果的PHP程序。而在静态页面的JavaScript中包括了Ajax的基本框架内容。

❑XMLHttpRequest对象初始化部分。为了兼容更多的浏览器，在这里详细地说明了XMLHttpRequest对象初始化代码。变量xmlhttp就是一个全局的XMLHttpRequest对象。

❑sendRequest()函数用于发送请求。该函数首先对xmlhttp进行判断，如果XMLHttpRequest对象是无效的话，程序将终止运行。

❑processRequest()函数负责处理服务器的返回信息。请求状态readyState和页面状态status都已成功返回后，使用responseText属性修改内容。＜tr＞及＜td＞标记的内容将被修改，并返回的数据值进行填充。

❑showPos()函数负责运行用户操作。当用户点击页面链接后，该函数负责调用sendRequest()发送HTTP请求。

静态页面的代码如代码14.7所示。

代码14.7　用户输入信息的静态页面程序：14-7.html

＜!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞

＜html xmlns="http://www.w3.org/1999/xhtml"＞

＜!--名称：14-7.html--＞

＜!--功能：PHP+Ajax注册用户名验证的表单程序--＞

＜head＞

＜!—设置页面的编码--＞

＜meta http-equiv="Content-Type"content="text/html;charset=utf-8"/＞

＜META HTTP-EQUIV="expires"CONTENT="0"＞

＜META HTTP-EQUIV="Pragma"CONTENT="no-cache"＞

＜title＞PHP+Ajax注册用户名验证＜/title＞

＜!—样式部分--＞

＜style type="text/css"＞

＜!--

body{

text-align:center;

font-family:Verdana,Arial,Helvetica,sans-serif;

font-size:12px;

background:#dfddfd;

}

#login{

margin-top:6%;

margin-right:auto;

margin-left:auto;

line-height:20px;

color:#000000;

width:300px;

border:1px solid#336699;

background:#fdd;

}

#frmlogin{

text-align:left;

margin-left:8px;

}

h1{

margin:0px 0px 10px 0px;

padding:0px;

width:100%;

height:30px;

line-height:30px;

color:#FFF;

background:#336699;

font-size:18px;

text-align:left;

text-indent:10px;

font-weight:normal;

font-family:Arial,Helvetica,sans-serif;

}

input{

border:1px solid#336699;

height:14px;

line-height:14px;

width:120px;

}

.button{

padding-right:10px;

padding-left:10px;

height:22px;

line-height:22px;

background:#fbfbfb;

color:#000;

text-align:center;

border-right:2px solid#999;

border-left:2px solid#999;

border-top:1px solid#999;

border-bottom:1px solid#999;

margin-right:5px;

margin-left:5px;

}

label{

font-weight:bold;

color:#336699;

}

#tip{

color:#fidxd0;

}

--＞

＜/style＞

＜script type="text/javascript"＞

＜!--

//XMLHttpRequest

var xmlhttp=false;

try{

xmlhttp=new ActiveXObject("Msxml2.XMLHTTP");

}catch(e){

try{

xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

}catch(e2){

xmlhttp=false;

}

}

if(!xmlhttp＆＆typeof XMLHttpRequest!='undefined'){

xmlhttp=new XMLHttpRequest();

}

function Ajax(data){

xmlhttp.open("GET","14-7.php?username="+escape(document.getElementById("username")

.value),true);

xmlhttp.send(null);

xmlhttp.onreadystatechange=function(){

if(4==xmlhttp.readyState){

if(200==xmlhttp.status){

document.getElementById("tip").innerHTML=xmlhttp.responseText;

}else{

alert("发生错误！");

}

}

}

}

function chkUserName(obj){

if(obj.value.length＜1){

obj.style.backgroundColor="#efefef";

alert("请输入用户名！");

obj.focus();

}else{

//调用Ajax函数，向服务器端发送查询

Ajax(obj.value);

}

}

//--＞

＜/script＞

＜/head＞

＜body＞

＜div id="login"＞

＜h1＞PHP+Ajax注册用户名验证＜/h1＞

＜form id="frmlogin"name="frmlogin"＞

＜label＞用户名:

＜input name="username"type="text"id="username"size="22"maxlength="10"

onblur="chkUserName(this)"/＞

＜/label＞＜label id="tip"＞＜/label＞

＜p＞

＜label＞密码:

＜input name="pwd"type="password"id="pwd"size="24"maxlength="16"/＞

＜/label＞

＜/p＞

＜p align="center"＞

＜input name="Submit"type="button"class="button"id="

btn_login"style="width:60px;background:#efefef;height:25px;line-height:25px;font-

size:12px;"value="注册"/＞

＜input name="Submit2"type="reset"class="button"style="

width:60px;background:#EFEFEF;height:25px;line-height:25px;font-size:12px;"value="重置"

/＞

＜/p＞

＜/form＞

＜/div＞

＜/body＞

＜/html＞

在此程序中使用CSS样式及Ajax技术。程序中的CSS样式定义了表格的显示效果，如颜色等。通过脚本来判断用户名是否注册。程序的运行效果如图14.5所示。

图　14.5　PHP+Ajax注册用户名验证的表单程序运行效果图

注意　此程序对用户名的判断不是在此页面中进行的，而是通过调用服务器验证程序，把用户输入的用户名与数据库中的所有用户名进行比较，如果用户输入的用户名在数据库中已经存在，则程序会输出“此用户已经注册”。

前面介绍了PHP+Ajax注册用户名验证的表单程序，光有此程序是实现不了用户的惟一性的，还要有用户输入用户名的处理程序。处理程序的代码如代码14.8所示。

代码14.8　服务器验证程序：14-8.php

＜?php

//××××××××××××××××××××××××××××××××××××××××××××××

//名称：14-8.php

//功能：服务器验证程序

//××××××××××××××××××××××××××××××××××××××××××××××

/*数据库连接*/

$conn=@mysql_connect("localhost","root","");

mysql_query("SET NAMES UTF8");//设置编码

mysql_select_db("yz",$conn);//查询语句

header("Content-type:text/html;charset=UTF-8");//设置页面编码

//查询数据库

if(isset($_GET["username"])){

$strsql="SELECT*FROM member WHERE

username='".unescape($_GET["username"])."'";

$result=mysql_query($strsql);

$rows=@mysql_num_rows($result);

mysql_close($conn);

/*判断是否有此记录*/

if($rows){

echo"已被注册！";

}else{

echo"此用户名未被注册！";

}

}else{

echo"错误！";

}

/*PHP的unescape转换函数，用来转换JavaScript用escape函数加密过的字符

--此函数需要iconv函数库支持*/

function unescape($str){

$str=rawurldecode($str);

preg_match_all("/%u.{4}|＆#x.{4};|＆#\d+;|＆#\d+?|.+/U",$str,$r);

$ar=$r[0];

foreach($ar as$k=＞$v){

if(substr($v,0,2)=="%u")

$ar[$k]=iconv("UCS-2","UTF-8",pack("H4",substr($v,-4)));

elseif(substr($v,0,3)=="＆#x")

$ar[$k]=iconv("UCS-2","UTF-8",pack("H4",substr($v,3,-1)));

elseif(substr($v,0,2)=="＆#"){

$ar[$k]=iconv("UCS-2","UTF-8",pack("n",preg_replace("/[^\d]/","",$v)));

}

}

return join("",$ar);

}

?＞

在此程序中，首先连接数据库，把数据库中的用户名提取出来，然后与用户输入的用户名进行判断，如果相同，则会输出“已被注册”；如果不相同，提示“此用户名未被注册”。在上面介绍完了PHP+Ajax注册用户名验证的程序，但是现在还不能实现，因为还差一个数据库的支持。下面就来介绍数据库的创建代码如下所示：

服务器：localhost

--phpMyAdmin SQL Dump

--version 2.11.2.1

--http://www.phpmyadmin.net

--

--主机：localhost

--生成日期：2008年09月04日03:11

--服务器版本：5.0.45

--PHP版本：5.2.3

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--

--数据库：'yz'

--

CREATE DATABASE'yz'DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

USE'yz';

----------------------------------------------------------

--

--表的结构'member'

--

CREATE TABLE'member'(

'id'int(11)NOT NULL auto_increment,

'username'varchar(20)NOT NULL default'',

'pwd'varchar(50)NOT NULL default'',

PRIMARY KEY('id')

)ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=10;

--

--导出表中的数据'member'

--

INSERT INTO'member'('id','usernam','pwd')VALUES

(8,'admin','admin888'),

(9,'测试','测试');

上面是创建数据库zy及数据表"member"的代码，读者需要打开phpmyadmin导入就可以了。现在就以用户名"admin"为例来运行“PHP+Ajax注册用户名验证”的程序，运行效果如图14.6所示。

图　14.6　PHP+Ajax注册用户名验证的程序运行效果图

14.4　Spry框架

本节将为读者介绍Spry框架，包括Spry框架的介绍及如何使用。为了让读者更好地理解，笔者采用几个实例来给读者进行介绍。其中包括Spry框架的使用方法、联级下拉菜单的实现等。

14.4.1　Spry框架简介

Spry是一个为Web设计人员开发的Ajax框架，它实现了在一个HTML页面中创建丰富体验。

Spry的目的是成为实现Ajax的一种简单方式，对HTML、CSS和JavaScript体验只有入门级水平的设计人员应该能够发现Spry是一种整合内容的简单方法。

Spry与Ajax框架是不同的，因为它是面向设计人员而不是开发人员。与其他Ajax框架相比，它的服务器端的技术不是很可靠，它依赖于XML,XML可以很容易被Spry组件接受，几乎没有什么大问题。

Spry实现的动机已经引起一些Web标准拥护者的怒火，批评Spry利用了定制HTML属性。最近，Adobe在Adobe实验网站上发布了一个更新版本Spry 1.5，这是自从去年最初的测试版发行以来的第6次发布，增加了一些新特性用于同不同类型的数据交互。包括以下几种。

❑嵌套数据集。

❑JSON数据集。

❑HTML数据集。

❑会话处理。

❑表单提交。

❑分页数据视图。

❑重写已经存在的效果。

❑单选按钮验证框。

❑自动建议框Spry API函数。

Spry框架其实就是一个客户端的JavaScript类库，包含了一组JavaScript文件、CSS、图片文件。通过官方的框架结构图，我们能看出Spry框架的核心是4部分，即XML数据器（XML Data Sets）、动态区域（Dynamic Regions）、装饰器库（Widgets）和变化效果库（Transition Effects）。

XML数据器是一个提供了从XML文档中载入和管理数据的JavaScript对象。它是Spry框架中处理XML格式数据的一个JavaScript功能实现。通过它可以从XML中直接得到转换成表格数据格式的行和列的值，其实就是数组。它封装了获取XMLhttpRequest的方法，和发送并接收数据等一系列获取数据的方法。

要创建一个XML数据器，必须在HTML文件中加入两行引入JavaScript文件的代码。

Spry框架的核心js文件之一。"xpath.js"是Google基于XPath 1.0标准的JavaScript功能实现。"SpryData.js"则包含了定义XML数据器和动态区域的代码。

构造XML数据器就好像新建一个类一样，用"new"关键字即可，代码如下所示：

Var dsPhotos=newSpry.Data.XMLDataSet(

"/photos.php?galleryid=2000","/gallery/photos/photo");

Spry框架为XML数据器提供了一些有特色的功能，如数据排序、数据过滤、按指定时间间隔自动更新，以及引入观察者通知模式以支持事件的触发。

动态区域是读者一旦建立了XML数据器，就可以在动态区域中显示这个数据器的数据了。创建动态区域块很简单，只要在HTML标签的相应位置加上spry：region属性就可以了，Spry框架就会知道这一块是被标识成动态区域了。在动态区域，读者可以有条件地选择要输出的数据，也可用循环输出。动态区域另一个特点就是，它分为"master"和"detail"两个区域类型。

装饰器库是指一个装饰器由一组HTML、CSS和JavaScript封装成的高级UI。最常见的装饰器有可折叠的菜单、树型菜单和选项table面板等。这些对象都比较难于创建，需要一些更高级的编程经验。Spry的开发组创建装饰器这一概念就是希望开发者们能相互协作，共享各自的设计，把这些高级界面元素用在网站的页面上。

Spry框架下的装饰器是易于编辑的。这种模型非常适合于设计者和编辑人员，要改变外观，只要改变CSS就可以了，要增加一个可折叠菜单就变得非常简单了。

Spry框架的变化效果库都存于"SpryEffects.js"文件中，变化效果库是基于JavaScript的一些动态变化效果。如淡出、改变形状等。Spry框架在设计时，曾考虑直接用第3方的效果库，如"Script.aculo.us"，但后来开发小组觉得要保证框架代码和标签的一致性，还是选择了自已开发，但是也基本上是以"Script.aculo.us"为原型进行设计，因为"Script.aculo.us"本身就是一个非常优秀的变化效果库框架。

14.4.2　Spry框架的使用方法

Adobe的Ajax框架Spry的正式版还没放出，所以文档是少之又少，在这里将为读者总结几种Spry的知识点，相信会对读者有一定帮助，至少读者通过学习本节，可以对Spry有个初步的认识。

（1）使用Spry框架，必须引用的两个核心js文件，这两个文件为"xpath.js"和"SpryData.js"，引用的语法格式如下所示：

＜script type="text/javascript"src="../../includes/xpath.js"＞script＞

＜script type="text/javascript"src="../../includes/SpryData.js"＞script＞

其中，"type"是指引用文本的类型，而"src"是指引用文件的相对路径。

（2）创建一个数据器"dataset"。XML数据器是一个提供了从XML文档中载入和管理数据的JavaScript对象。它是Spry框架中处理XML格式数据的一个JavaScript功能实现。通过它，读者可以从XML中直接得到转换成表格数据格式的行和列的值，其实就是数组。它封装了获取XMLhttpRequest的方法，和发送并接收数据等一系列获取数据的方法。代码如下所示：

var dsPhotos=new Spry.Data.XMLDataSet("/photos.php","/gallery/photos/photo",{

method:"POST",postData:"galleryid=2000＆offset=20＆limit=10",headers:{

"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"

}});

var dsPhotos2=new Spry.Data.XMLDataSet(

"/photos.php?galleryid=2000","/gallery/photos/photo");

其中，"method:"为请求发送方式，其值为POST和/GET，默认为GET。而postData:为请求参数，可省略，可直接把"/photos.php"换成"/photos.php?galleryid=2000＆offset=20＆limit=10"。"Content-Type:"为头信息。

（3）不使用缓存。这里要重点说明一下，在应用时，会出现设置为“不使用缓存”时，页面仍然不是最新数据，是用一个servlet生成XML，然后对生成的数据进行删除和添加，但页面显示的数据不会自动更新。

出现这样的现象，是因为在IE浏览器中，使用"userCache：false"是不够的，还要在生成XML的JSP、PHP等中，设置头不使用"cache"，如在生成XML的JSP和servlet中要加上如下的代码：

response.addHeader("Cache-Control","no-cache");

注意　以上问题只存在IE浏览器中，在Firefox和Opera中不存在。Spry对Opera9版本支持很好，使用版本8的朋友要注意了。在PHP中的使用代码如下所示：

Var dsPhotos=new Spry.Data.XMLDataSet(

"/photos.php?galleryid=2000","/gallery/photos/photo",{useCache:false})

另外，也可以在构造完数据器后，再设置缓存。设置缓存的代码如下所示：

dsData.useCache=false;

dsData.loadData();

（4）获取数据形式。假如上面的程序发送请求，则返回的XML的代码如下所示：

gallery id="12345"＞

photographer id="4532"＞John Doephotographer＞

email＞john@doe.comemail＞

photos id="2000"＞

photo path="sun.jpg"width="16"height="16"/＞

photo path="tree.jpg"width="16"height="16"/＞

photo path="surf.jpg"width="16"height="16"/＞

hotos＞

gallery＞

那么运行此程序时，"gallery/photos/photo"将会返回的数据是下面的数组"[{"@path":"sun.jpg","@width":16,"@height":16},{"@path":"tree.jpg","@width":16,"@height":16},{"@path":"surf.jpg","@width":16,"@height":16}]"。程序的代码如下所示：

var rows=dsPhotos.getData();

//获取所有行.

var path=rows[0]["@path"];

//获取第一行中"@path"的值

dsPhotos.setCurrentRowNumber(2);

//将第3行做为当前处理行，下标以0开始

var id=dsPhotos.getData()[2]["ds_RowID"];

//获取第3行的ID。

dsPhotos.setCurrentRow(id);

//通过第3行的id，将第3行设为当前处理行.

其中第1行"var rows=dsPhotos.getData();"用于获取程序中所有行的函数；第3行代码"var path=rows[0]["@path"];"用于获取程序中第1行中"@path"的值；第4行代码"dsPhotos.setCurrentRow Number(2);"，则是做为当前处理行，下标以“0”开始。

14.5　小结

通过本章节的学习，读者要理解以下内容。

❑什么是Ajax。

❑Ajax的实现原理和工作流程。

❑Ajax应用。

❑Spry框架。

通过对本章的学习，读者还需要知道如何采用Ajax与PHP的结合使用，要知道如何实现Ajax的实现原理和工作流程、如何建立远程连接对象、如何异步发送请求、回调函数的应用以及基于Ajax的用户名验证程序等相关内容。读者还需要知道Spry框架的使用这些知识。

第15章　PHP与正则表达式

本章向读者介绍的是PHP与正则表达式。正则表达式就是一种可以用于模式匹配和替换的强有力的工具。本章需要了解什么是正则表达式，然后介绍正则表达式的语法，关键是了解PHP中相关正则表达式的函数。最后本章还会提供一些常用的正则表达式，掌握这些可以提高页面的复杂度，也能提高编程效率。

15.1　了解正则表达式

本节要介绍什么是正则表达式，以及在PHP中如何使用正则表达式。

正则表达式可以使用户通过使用一系列的特殊字符构建匹配的模式，然后使用匹配的模式与数据文件、程序输入法及Web页面里的输入表单$等目标对象进行比较，根据比较对象中有没有包含匹配的模式，运行相应的程序。例如，正则表达式的一个最为常用的应用就是验证用户在线输入的邮件地址的格式是否合法。如果通过正则表达式验证用户邮件地址的格式合法，用户所输入的表单信息就会被正常处理；反之，如果用户输入的邮件地址与正则表达式的模式不匹配，就会弹出提示信息，要求用户重新填写正确的邮件地址。所以可见，正则表达式在Web中应用的逻辑判断有比较重要的作用。

15.1.1　什么是正则表达式

在编写处理字符串的程序或网页时，经常会使用到查找符合某些复杂规则的字符串，这时就可以使用正则表达式来进行查找。正则表达式就是用于描述这些规则的工具。换句话说，正则表达式就是用于记录文本规则的代码。

正则表达式就是一种可以用于模式匹配和替换的强有力的工具。读者可以在几乎所有的基于UNIX系统的工具中看到正则表达式的影子。例，vi编辑器、Perl或PHP脚本语言等。还有就是JavaScript这样的客户端脚本语言也提供了对正则表达式的支持。由此可以证明，正则表达式超出了一些语言或某种系统的局限，成为广泛使用和接受的概念和功能。

比如说，很可能读者都使用过在Windows/DOS下用于文件查找的通配符（wildcard），也就是“*”和“?”。如果读者想查找某个目录下的所有的Word文档，就会会搜索"*.doc"。在这里，“*”会被解释成任意的字符串。与通配符类似，正则表达式也是用来进行文本匹配的工具，只不过与通配符相比，正则表达式能更精确地描述读者的需求。当然，代价就是更复杂。例如读者可以编写一个正则表达式，用来查找所有以“0”开头，后面跟着如“7-1”的π个数字，然后是一个连字号“-”，最后是7或8位数字的字符串。

15.1.2　一个简单的正则表达式

正则表达式的功能强大特性使它在编程中有了非常重要的地位，也得到了广大程序员的喜爱。下面笔者就介绍一个简单的正则表达式的实例，此实例是一个日期匹配。程序如代码15.1所示。

代码15.1　一个简单的正则表达式程序：15-1.php

＜html＞

＜!--程序名称：15-1.php--＞

＜!--程序功能：一个简单的正则表达式--＞

＜head＞

＜meta http-equiv="Content-Language"content="zh-cn"＞

＜meta http-equiv="Content-Type"content="text/html;charset=zh-utf-8"＞

＜title＞一个简单的正则表达式＜/title＞

＜/head＞

＜body＞

＜?php

/*分隔符可以是斜线，点，或横线*/

$date="05/05/2008";//设置时间

list($month,$day,$year)=split('[/.-]',$date);//格式时间

echo"Month:$month;Day:$day;Year:$year＜br/＞\n";//输出时间

?＞

＜/body＞

＜/html＞

此程序使用正则表达式对日期进行匹配，先给变量$date赋一个日期，然后使用正则表达式进行匹配操作，最后输出日期。程序的运行效果如图15.1所示。

图　15.1　一个简单的正则表达式的运行效果图

注意　正则表达式的分隔符可以是斜线、点或横线。

15.2　正则表达式的语法

现在读者对正则表达式的功能和作用有了初步的了解，接下来为读者介绍一下正则表达式的语法格式。正则表达式的基本格式如下所示：

/love/

其中界于“/”定界符号之间的部分就是要在目标对象中进行匹配比较的模式。用户只要把想要查找匹配对象的模式内容放入定界符“/”之间就可以了。

15.2.1　元字符

为了可以使用户更加灵活地定制匹配模式的内容，正则表达式提供了专门的“元字符”。在对如何使用正则表达式有了初步了解之后，下面来看一下几个重要的元字符的使用方式。

❑\s：用于匹配单个空格符，包括Tab键和换行符。

❑\S：用于匹配除单个空格符之外的所有字符。

❑\d：用于匹配从0～9的数字。

❑\w：用于匹配字母、数字或下画线字符。

❑\W：用于匹配所有与“\w”不匹配的字符。

❑.：用于匹配除换行符之外的所有字符。

❑\？：用于在字母i后面连续出现0个或一个字母i的字符串相匹配。

❑\*：用于在字母e后面连续出现0个或多个字母g的字符串相匹配。

❑\+：用于在字母f后面连续出现一个或多个字母o的字符串相匹配。

❑/\s+/：此正则表达式可以用于匹配目标对象中的一个或多个空格字符。

❑/\d000/：如果我们手中有一份复杂的财务报表，那么我们可以通过上述正则表达式轻而易举地查找到所有总额达千元的款项。

❑/fo+/：因为上述正则表达式中包含“+”元字符，表示可以与目标对象中的"fool"，"fo"或者"football"等在字母f后面连续出现一个或多个字母o的字符串相匹配。

❑/eg*/：因为上述正则表达式中包含“*”元字符，表示可以与目标对象中的"easy"，"ego"或者"egg"等在字母e后面连续出现0个或多个字母g的字符串相匹配。

❑/Wil?/：因为上述正则表达式中包含“？”元字符，表示可以与目标对象中的"Win"，或者"Wilson"，等在字母i后面连续出现0个或一个字母l的字符串相匹配。

除了元字符之外，用户还可以精确指定模式在匹配对象中出现的频率。例如如下代码：

/jim{2,6}/

上述正则表达式规定字符"m"可以在匹配对象中连续出现2～6次，因此，上述正则表达式可以同"jimmy"或"jimmmmmy"等字符串相匹配。

15.2.2　字符定位符

除了以上介绍的元字符之外，正则表达式中还有另外一种较为独特的专用字符，即定位符。定位符用于规定匹配模式在目标对象中的出现位置。

较为常用的定位符包括：“^”，“$”，"\b"以及"\B"。其中，“^”定位符规定匹配模式必须出现在目标字符串的开头；“$”定位符规定匹配模式必须出现在目标对象的结尾；"b"定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一；而"\B"定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内，即匹配对象既不能作为目标字符串的开头，也不能作为目标字符串的结尾。同样，读者也可以把“^”和“$”以及"\b"和"\B"看作是互为逆运算的两组定位符。

❑"/^hell/"：因为上述正则表达式中包含“^”定位符，所以可以与目标对象中以"hell"、"hello"或"hellhound"开头的字符串相匹配。

❑"/ar$/"：因为上述正则表达式中包含“$”定位符，所以可以与目标对象中以"car"、"bar"或"ar"结尾的字符串相匹配。

❑"/\bbom/"：因为上述正则表达式模式以"\b"定位符开头，所以可以与目标对象中以"bomb"或"bom"开头的字符串相匹配。

❑"/man\b/"：因为上述正则表达式模式以"\b"定位符结尾，所以可以与目标对象中以"human"、"woman"或"man"结尾的字符串相匹配。

为了能够方便用户更加灵活地设定匹配模式，正则表达式允许使用者在匹配模式中指定某一个范围而不局限于具体的字符。例如：

"/[A-Z]/"，正则表达式将会与从A～Z范围内任何一个大写字母相匹配；

"/[a-z]/"，正则表达式将会与从a～z范围内任何一个小写字母相匹配；

“/[0-9]/”，正则表达式将会与从0～9范围内任何一个数字相匹配。

"/（[a-z][A-Z][0-9]）+/"此实例中，正则表达式将与任何由字母和数字组成的字符串，如"aB0"等相匹配。这里需要提醒用户注意的一点就是，可以在正则表达式中使用“()”把字符串组合在一起。“()”符号包含的内容必须同时出现在目标对象中。因此，上述正则表达式将无法与诸如"abc"等的字符串匹配，因为"abc"中的最后一个字符为字母而非数字。如果我们希望在正则表达式中实现类似编程逻辑中的“或”运算，在多个不同的模式中任选一个进行匹配的话，可以使用管道符“|”。例如"/to|too|2/"此实例中，正则表达式将会与目标对象中的"to"、"too"或“2”相匹配。

正则表达式中还有一个较为常用的运算符，即否定符“[^]”。与我们前面所介绍的定位符“^”不同，否定符“[^]”规定目标对象中不能存在模式里所规定的字符串。例如"/[^A-C]/"此实例中，字符串将会与目标对象中除A、B和C之外的任何字符相匹配。一般来说，当“^”出现在“[]”内时就被视做否定运算符；而当“^”位于“[]”之外，或没有“[]”时，则应当被视做定位符。

最后，当用户需要在正则表达式的模式中加入元字符，并查找其匹配对象时，可以使用转义符“\”。例如"/Th\*/"此实例中，正则表达式将会与目标对象中的"Th*"而非"The"等相匹配。

15.2.3　字符类

字符类是实现数字、字母或数字、空白查找时比较简单的。虽然已经有了对应这些字符集合的元字符，但是如果读者想匹配没有预定义元字符的字符集合，例如元音字母a、e、i、o、u，应该怎么办？

很简单，读者只需要在方括号里列出想要查找的字符就行了，如"[aeiou]"就匹配任何一个英文元音字母。

读者也可以轻松地指定一个字符范围，例如“[0-9]”代表的含意与"\d"就是完全一致的，即一位数字。同理"[a-z0-9A-Z_]"也完全等同于"\w"，不过是只考虑英文的情况下。

正则表达式还提供有关定义要匹配的子字符串的正则表达式字符集的信息，如下所示。

❑[.]：匹配除“\n”以外的任何字符。如果已用"Singleline"选项做过修改，则句点字符可与任何字符匹配。

❑[aeiou]：与指定字符集中包含的任何单个字符匹配，即与"a"、"e"、"i"、"o"和"u"中的任意一个匹配。

❑[^aeiou]：与不在指定字符集中包含的任何单个字符匹配，即与除"a"、"e"、"i"、"o"和"u"中的任意一个匹配。

❑[0-9a-fA-F]：使用连字符“-”指定连续字符范围。此处为从0～9与从小写字母a到小写字母f以及大写字母A到大写字母F中的任何一个匹配。

❑\p{name}：与在"{name}"指定的名字符类中的任何字符都匹配。

❑\P{name}：与在"{name}"中指定的组织和范围不包括的文本匹配。

❑\w：与任何单词字符匹配。等效于Unicode字符类别[^\p{L1}\p{Lu}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]，如果用"ECMAScrip"选项指定了符合ECMAScript的行为，则"\S"等效于"[a-zA-Z_0-9]"。

❑\W：与任何非单词字符匹配。等效于Unicode字符类别[^\p{L1}\p{Lu}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]，如果用"ECMAScrip"选项指定了符合ECMAScript的行为，则"\S"等效于"[^a-zA-Z_0-9]"。

❑\s：与任何空白字符匹配。等效于Unicode字符类别[\f\n\r\t\v\x85\p{z}]，如果用"ECMAScrip"选项指定了符合"ECMAScript"的行为，则"\S"等效于"[\f\n\r\t\v]"。

❑\S：与任何非空白字符匹配。等效于Unicode字符类别[^\f\n\r\t\v\x85\p{z}]，如果用"ECMAScrip"选项指定了符合"ECMAScript"的行为，则"\S"等效于"[^\f\n\r\t\v]"。

❑\d：与任何十进制数字匹配。对于Unicode类别的ECMAScript行为，等效于\P{Nd}，对于非Unicode类别的ECMAScript行为，等效于“[0-9]”。

❑\D：与任何非数字匹配。对于Unicode类别的ECMAScript行为，等效于"\P{Nd}"，对于非Unicode类别的ECMAScript行为，等效于“[^0-9]”。

15.2.4　反义

如果读者需要查找不属于某个能简单定义的字符类的字符，例如想查找除了数字以外，其他任意字符都行的情况，这时需要用到反义。接下来介绍常用的反义代码，如下所示。

❑\W：匹配任意不是字母、数字、下划线或汉字的字符。

❑\S：匹配任意不是空白符的字符。

❑\D：匹配任意非数字的字符。

❑\B：匹配不是单词开头或结束的位置。

❑[^x]：匹配除了x以外的任意字符。

❑[^aeiou]：匹配除了a、e、i、o、u这几个字母以外的任意字符。

下面通过实例来介绍如何使用这类代码。需要匹配非数字的字符，该如何实现这项操作呢？可以通过使用正则表达式的反义代码来实现，如下所示：

\D+

此代码是匹配任何非数字的字符。

15.2.5　贪婪模式与懒惰模式

贪婪匹配就是当正则表达式中包含能接受重复的限定符时，在使整个表达式能得到匹配的前提下，匹配尽可能多的字符。

懒惰匹配也就是当正则表达式中包含能接受重复的限定符时，通常的行为是，在使整个表达式能得到匹配的前提下，匹配尽可能少的字符。

接下来介绍懒惰匹配代码及语法和说明。懒惰匹配代码如下所示。

❑*?：重复任意次，但尽可能少重复。

❑+?：重复1次或更多次，但尽可能少重复。

❑??：重复0次或1次，但尽可能少重复。

❑{n,m}?：重复n到m次，但尽可能少重复。

❑{n，}?：重复n次以上，但尽可能少重复。

上面给出的限定符的懒惰匹配代码，懒惰匹配和贪婪匹配是可以相互转化的。那如何实现之间的转化呢？很简单，就是只要把懒惰匹配后面的问号“?”去掉就变成了贪婪匹配模式。例如"a.*d"，这将会匹配最长的以"a"开始、以"d"结束的字符串。如果用此代码来搜索"aababadda"的话，此代码会匹配整个字符串"aababadda"，这就是贪婪匹配。而懒惰匹配模式的代码就是"a.*?d"，匹配最短的、以a开始、以b结束的字符串。如果把此代码应用于"aababadda"的话，它会匹配"aab"、"aba"和"dda"。为什么第1个匹配是"aab"，而不是"aba"？简单地说，因为正则表达式有另一条规则，比懒惰与贪婪规则的优先级更高，即最先开始的匹配拥有最高的优先权。

15.2.6　正则表达式中的特殊字符

笔者已经描述了构造正则表达式的大量元素，还有一些笔者没有提到的东西。下面是正则表达式中的特殊字符元素，如下所示。

❑\a：报警字符。比如打印其效果时电脑嘀一声。

❑\b：通常代表单词分界位置，但如果使用在字符类里代表退格。

❑\t：制表符，Tab键。

❑\r：回车。

❑\v：竖向制表符。

❑\f：换页符。

❑\n：换行符。

❑\e：Escape。

❑\0nn：ASCII代码中八进制代码为nn的字符。

❑\xnn：ASCII代码中十六进制代码为nn的字符。

❑\unnnn：Unicode代码中十六进制代码为nnnn的字符。

❑\cN：ASCII控制字符。例如\cC代表Ctrl+C。

❑\A：字符串开头。类似^，但不受处理多行选项的影响。

❑\Z：字符串结尾或行尾，不受处理多行选项的影响。

❑\z：字符串结尾，类似$，但不受处理多行选项的影响。

❑\G：当前搜索的开头。

❑\p{name}：Unicode中命名为"name"的字符类，例如\p{IsGreek}。

❑（?＞exp）：贪婪子表达式。

❑（?＜x＞-＜y＞exp）：平衡组。

❑（?im-nsx：exp）：在子表达式exp中改变处理选项。

❑（?im-nsx）：为表达式后面的部分改变处理选项。

❑（?（exp）yes|no）：把exp当作零宽正向先行断言，如果在这个位置能匹配，使用yes作为此组的表达式；否则使用no。

❑（?（exp）yes）：同上，只是使用空表达式作为no。

❑（?（name）yes|no）：如果命名为"name"的组捕获到了内容，使用yes作为表达式；否则使用no。

❑（?（name）yes）：同上，只是使用空表达式作为no。

15.3　PHP中相关正则表达式的使用

PHP被大量地应用于Web的后台CGI开发，通常在用户数据之后得出某种结果。但是如果用户输入的数据不正确，就会出现问题，例如某用户的密码。那应该怎么样来检验是否正确呢？在PHP中加入了正则表达式的支持，让读者可以十分方便地进行数据匹配。

15.3.1　用正则表达式检查输入的数字是否是合法的数字

使用正则表达式可以检查用户输入的数字、字母等是否是合法的。读者可以给定一个数字，要求用户输入的与读者设置的是一样的，此时就可以用正则表达式来检验。例如读者的网页设置了一个问题，让用户去回答，如果用户回答正确就可以访问读者的网页，如果答案错误将没有权限访问。这种情况就可以使用正则表达式来检验。下面通过一个实例来介绍如何在PHP中使用正则表达式对此进行检验，程序如代码15.2所示。

代码15.2　用正则表达式检查输入的数字是否是合法的数字程序：15-2.php

＜html＞

＜!--程序名称15-2.php

＜!--程序功能：用正则表达式检查输入的数字是否是合法的数字

＜head＞

＜title＞用正则表达式检查输入的数字是否是合法的数字＜/title＞

＜/head＞

＜body＞

＜?php

$in="2344";//设置变量

if(ereg("^(-{0,1}|\+{0,1})[0-5]+(\.{0,1}[0-5]+)$",$in))//使用正则进行判断

echo"Ok!";//输出结果

else

echo"Sorry,Please input again!";

?＞

＜br＞比较简单的吧！

＜/body＞

＜/html＞

在此程序中，笔者设置了一个变量$in并把“2344”赋值给变量。然后使用正则表达式进行检验，如语句ereg(“^(-{0，1}|\+{0，1})[0-5]+(\.{0，1}[0-5]+)$”,$in)。此语句是检验设置的变量值是不是在0～5的范围内。如果在，则输出"OK"；如果不在，则就提示用户重新设置变量值。程序的过行效果如图15.2所示。

图　15.2　用正则表达式检查输入的数字是否是合法的数字程序运行图

在此程序中，如果读者想看看在什么情况下会输出错误提示，可以这样来实现：把变量的值修改为大于5的数字，可以修改其中的一个数字，也可以全部修改；或者是把正则表达式的修改为5～9之间，输出的也会是错误提示。

15.3.2　在一个字符串中查找另一个字符串

在一个字符串中查找另一个字符串，读者可以设置在第1个字符串中查找第2个字符串。也可以查找第2个字串是不是第1个字符串的开始或结尾等。也可以使用这一思想在一篇文章中查找指定的字符串。实例程序如代码15.3所示。

代码15.3　在一个字符串中查找另一个字符串程序：15-3.php

＜html＞

＜!--程序名称：15-3.php--＞

＜!--程序功能：在一个字符串中查找另一个字符串--＞

＜head＞

＜title＞在一个字符串中查找另一个字符串＜/title＞

＜/head＞

＜body＞

＜!—链接--＞

＜a href="./"＞返回列表＜/a＞＜br＞

＜!—表单部分--＞

＜form action="＜?echo$PHP_SELF;?＞"method="post"＞

在＜input type="text"name="string"value="＜?echo$string;?＞"＞中查找＜input type="

text"name="query"value="＜?echo$query;?＞"＞＜br＞

＜input type="radio"name="where"value=""＜?if(!isset($where)or$where=="")echo

"checked";?＞＞第二个字符串可以在第一个字符串的任何位置＜br＞

＜input type="radio"name="where"value="^"＜?if(isset($where)and$where=="^")

echo"checked";?＞＞第一个字符串以第二个字符串开始＜br＞

＜input type="radio"name="where"value="$"＜?if(isset($where)and$where=="$")

echo"checked";?＞＞第一个字符串以第二个字符串结束＜br＞

＜input type="checkbox"name="case"value="case"＜?if(isset($case))echo

"checked";?＞＞区分大小写＜br＞

＜input type="submit"value="查询"＞

＜/form＞

＜?php

if(isset($string)and isset($query)and$string＜＞""and$query＜＞"")//判断字符

{

if(isset($case)){

$func="ereg";

}

else{

$func="eregi";

}

switch($where){

case"^":

$query="^".$query;

break;

case"$":

$query.="$";

break;

}

eval("\$found=$func(\"$query\",\"$string\");");

if($found){

echo"找到！";//输出结果

}

else{

echo"未找到！";

}

}

?＞

＜/body＞

＜/html＞

此程序通过HTML表单获取到用户输入的两个字符串，通过选择下边的查找方式进行查找。笔者在此程序中提供的查找方式是：第2个字符串可以在第1个字符串的任何位置、第1个字符串以第2个字符串开始、第1个字符串以第2个字符串结束，区分大小写。程序的运行效果如图15.3所示。

图　15.3　在一个字符串中查找另一个字符串程序运行效果图

15.3.3　正则表达式判断E-mail和URL

在PHP中也可以使用正则表达式来对用户的E-mail和URL进行判断，笔者设计一个HTML表单，用户通过这个表单输入需要查询的E-mail地址，然后单击“提交查询内容”按钮就可以查出E-mail和URL，如代码15.4所示。

代码15.4　正则表达式判断E-mail和URL程序：15-4.php

＜html＞

＜!--程序名称：15-4.php--＞

＜!--程序功能：正则表达式判断E-mail和URL--＞

＜head＞

＜title＞正则表达式判断E-mail和URL＜/title＞

＜/head＞

＜＜body onload="f.a.select();"＞

＜?php

echo'a:'.htmlspecialchars($a);

echo'＜br＞a1:';

$a1=eregi_replace('(^[_.][:alnum:]-]+@([[:alnum:]][[:alnum:]-]*.)

+[[:alpha:]]{2,3}$)','＜a href="mailto:\1"＞\1＜/a＞',$a);//判断E-maiL

echo htmlspecialchars($a1);//输出变量

echo"＜br＞a1:$a1";

echo'＜br＞a2:';

$a2=eregi_replace('([[:alnum:]]+://([[:alnum:]][[:alnum:]-]*\.)//判断URL

+[[:alpha:]]{2,3}([#\?^\][^#\?/\\][:space:]][^[:space:]]*)?)',

'＜a href="\1"target="_blank"＞\1＜/a＞',$a);//返回地址

echo htmlspecialchars($a2);//输出变量

echo"＜br＞a2:$a2";

?＞

＜!—表单部分--＞

＜form name="f"＞

＜input name="a"value="＜?php echo$a;?＞"＞

＜input type="submit"＞

＜/form＞

＜/body＞

＜/html＞

在此程序中，使用表单接收用户输入的信息，然后把获取的信息使用正则表达式进行判断，再把判断的结果信息输出到页面中。程序的运行效果如图15.4所示。在此程序中，当用户输入一个E-mail地址后单击“提交查询内容”按钮，会把判断的信息输出到页面中，如图15.5所示。

图　15.4　正则表达式判断E-mail和URL程序运行效果图

图　15.5　当用户输入E-mail地址后判断结果图

15.3.4　实例：获得某页面中的所有链接地址

获取页面中的所有链接地址，就是把页面中的所有链接地址从网页中返回，如代码15.5所示。

代码15.5　获得某页面中的所有链接地址程序：15-5.php

＜html＞

＜!--程序名称：15-5.php--＞

＜!--程序功能：获得某页面中的所有链接地址程序--＞

＜head＞

＜title＞获得某页面中的所有链接地址程序＜/title＞＜/head＞

＜body＞

＜a href="15-5.php"＞返回列表＜/a＞＜br＞

＜!—表单部分--＞

＜form action="＜?php echo$PHP_SELF;?＞"method="post"＞

URL:＜input type="text"name="url"value="＜?echo$url?＞"＞＜input type="submit"

value="获取所有链接"＞

＜/form＞

＜?php

if(isset($url)){

echo"$url有下列链接:＜br＞";//输出链接

$fcontents=file($url);//文件地址

while(list(,$line)=each($fcontents)){

while(eregi('(href[[:space:]]*=[[:space:]]*"?[[:alnum:]:@/._-

]+"?)(.*)',$line,$regs)){

$regs[1]

eregi_replace('(href[[:space:]]*=[[:space:]]*"?)([[:alnum:]:@/._-

]+)("?)',"\\2",$regs[1]);

echo"

$regs[1]＜br＞";

$line=$regs[2];

}

}

}

?＞

＜/body＞

＜/html＞

此程序是使用了一个提交表单，把需要查询的网页地址提交到处理程序，通过处理程序的正则表达式href[[:space:]]*=[[:space:]]*”?[[:alnum:]:@/._-]+”?）(.*)',$line,$regs，分析网页的所有链接地址。程序的运行效果如图15.6所示。

图　15.6　获得某页面中的所有链接地址程序运行图

此页面是一个网页的链接地址的获取程序，其中“返回列表”是指返回到程序15-5.php，可以进行下一个网页链接地址查询。下面笔者查询一下网页http://localhost/Chapter%2017/15-5.php的链接地址，程序的运行效果如图15.7所示。

图　15.7　获取网页链接地址图

在此页面中获取到了网页http://localhost/Chapter%2015/15-5.php链接地址是15-5.php。此程序中只有一个链接地址。

15.4　常用的正则表达式

正则表达式用于字符串处理、表单验证等场合，实用高效。现将一些常用的表达式收集于此，以备不时之需。正则表达式可以用于检测邮件地址，检查电话号码、用户名的合法性以及检测中文字符等。常用的正则表达式如下所示。

❑匹配中文字符的正则表达式：[\u4e00-\u9fa5]。

❑匹配双字节字符（包括汉字在内）：[^\x00-\xff]。可以用来计算字符串的长度。如一个双字节字符长度计2，ASCII字符计1。

❑匹配空白行的正则表达式：\n\s*\r。可以用来删除空白行。

❑匹配HTML标记的正则表达式：＜（\S*?）[^＞]*＞.*?＜/\1＞|＜.*?/＞。

❑匹配首尾空白字符的正则表达式：^\s*|\s*$。可以用来删除行首行尾的空白字符，包括空格、制表符及换页符等，是非常有用的表达式。

❑匹配E-mail地址的正则表达式：\w+（[-+.]\w+）*@\w+（[-.]\w+）*\.\w+（[-.]\w+）*。表单验证时很实用。

❑匹配网址URL的正则表达式：[a-zA-z]+：//[^\s]*。此正则表达式基本可以满足需求。

❑匹配账号是否合法，是否以字母开头，允许5～16字节，允许字母数字下画线的账号：^[a-zA-Z][a-zA-Z0-9_]{4，15}$。表单验证时很实用。

❑匹配国内电话号码：\d{3}-\d{8}|\d{4}-\d{7}。匹配形式如010-12345678或021-87456123。

❑匹配腾讯QQ号：[1-9][0-9]{4，}。腾讯QQ号从10000开始。

❑匹配中国邮政编码：[1-9]\d{5}（?!\d）。中国邮政编码为6位数字。

❑匹配身份证：\d{15}|\d{18}。中国的身份证为15位或18位。

❑匹配IP地址：\d+\.\d+\.\d+\.\d+。提取IP地址时有用。

以下是匹配特定数字。

❑^[1-9]\d*$：匹配正整数。

❑^-[1-9]\d*$：匹配负整数。

❑^-?[1-9]\d*$：匹配整数。

❑^[1-9]\d*|0$：匹配非负整数（正整数+0）。

❑^-[1-9]\d*|0$：匹配非正整数（负整数+0）。

❑^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$：匹配正浮点数。

❑^-（[1-9]\d*\.\d*|0\.\d*[1-9]\d*）$：匹配负浮点数。

❑^-?（[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0）$：匹配浮点数。

❑^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$：匹配非负浮点数（正浮点数+0）。

❑^（-（[1-9]\d*\.\d*|0\.\d*[1-9]\d*））|0?\.0+|0$：匹配非正浮点数（负浮点数+0）。

匹配特定字符串如下。

❑^[A-Za-z]+$：匹配由26个英文字母组成的字符串。

❑^[A-Z]+$：匹配由26个英文字母的大写组成的字符串。

❑^[a-z]+$：匹配由26个英文字母的小写组成的字符串。

❑^[A-Za-z0-9]+$：匹配由数字和26个英文字母组成的字符串。

❑^\w+$：匹配由数字、26个英文字母或者下画线组成的字符串。

上面的正则表达式是一些最基本也是最常用的表达式。

15.5　正则表达式实例

检测邮件地址的真实性就是对用户输入的邮箱地址进行验证，如果是正确的，邮箱地址格式就会显示“正确”；如果用户输入的邮箱是不符合邮箱地址的格式，就会输出“错误”提示，如代码15.6所示。

代码15.6　检测邮件地址的真实性程序：15-6.php

＜html＞

＜!--程序名称：15-6.php--＞

＜!--程序功能：检测邮件地址的真实性--＞

＜head＞

＜title＞检测邮件地址的真实性＜/title＞

＜/head＞

＜body＞

＜?php

$email=$_POST['email'];//变量转换

if(check_email_address($email)==1)//判断地址

{

echo"正确";//输出结果

}

else{

echo"错误";

}

function check_email_address($email){//定义方法

if(!ereg("[^@]{1,64}@[^@]{1,255}",$email))//检测用户输入的邮箱是否合法

{

return false;

}

$email_array=explode("@",$email);

$local_array=explode(".",$email_array[0]);

for($i=0;$i＜sizeof($local_array);$i++)

{

if(!ereg("^(([A-Za-z0-9!#$%＆'*+/=?^_'{|}～-][A-Za-z0-9!#$%＆'*+/=?^_'{|}～\.-]{0,63})|

(\"[^(\\|\")]{0,62}\"))$",$local_array[$i])){

return false;

}

}

if(!ereg("^\[?[0-9\.]+\]?$",$email_array[1])){

$domain_array=explode(".",$email_array[1]);

if(sizeof($domain_array)＜2){

return false;//Not enough parts to domain

}

for($i=0;$i＜sizeof($domain_array);$i++){

if(!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$",$domain_array[$i]))

{

return false;}

}

}

return true;

}

?＞

＜!--提交邮箱地址表单--＞

＜form action=""method="post"＞

＜input name="email"type="text"＞＜br＞

＜input name=""type="submit"value="验证"＞

＜/form＞

＜/body＞

＜html＞

程序中使用了表单把用户输入的邮箱地址提交到程序，程序通过正则表达式来判断用户输入的邮箱地址是否合法。如果用户输入的邮箱地址是合法的，程序通过check_email_address函数把结果显示到页面上。如果用户输入的邮箱地址是错误的，程序调用函数把运行结果输出到页面上，运行效果如图15.8所示。

图　15.8　检测邮件地址的真实性程序运行效果图

因为初次运行此程序，没有用户输入邮箱地址，因此会在上面显示“错误”。为了测试此程序，先输入一个正确的邮箱地址"lookhaizi88@163.com"，程序运行效果如图15.9所示。

图　15.9　用户输入正确的邮箱地址运行效果图

通过网页显示，笔者输入的邮箱地址是正确的。如果用户输入错误的邮箱地址，看看程序的运行效果如何，下面笔者输入一个错误的邮箱地址，如aa123163.com，程序的运行效果如图15.10所示。

图　15.10　用户输入错误的邮箱地址运行效果图

作用　使用正则表达式的作用就是对复杂数据进行筛选，使用户得到需要的数据。

15.6　小结

通过对本章的学习，可以掌握正则表达式的语法结构以及正则表达式在PHP中是如何应用的。而正则表达式在PHP中的应用包括：用正则表达式检查输入的数字是否是合法的数字；在一个字符串中查找另一个字符串；正则表达式判断E-mail和URL；获得某页面中的所有链接地址。通过本章的学习，读者可以使用正则表达式来轻松地完成一些比较复杂的判断。

第16章　PHP与XML

本章介绍PHP中XML的使用，XML弥补了PHP与HTML嵌套的不足之处，使网页更加生动。本章将介绍什么是XML，并介绍网页使用XML为什么越来越流行。了解这些基础应用后，会介绍XML文档的一些构成，并学习如何用PHP解析XML文档，这里也会了解一个很重要的概念：DOM。

16.1　XML快速入门

通过本节的学习，读者可以知道XML是什么、XML可以用来做什么、XML有哪些特点，以及XML与HTML、SGML相同之处是什么，不同之处有哪些。如何使用XML开发PHP程序。

16.1.1　什么是XML

XML是可扩展标记语言，即eXensible Markup Language。它是由万维网开发的，主要的目的是为了添补HTML语言的不足。最早，Web是用来发布文档的一个工具，可是今天的Web，已是用户不能离开的一种交互式的媒体。因为Web可以是电影院，也可以是电视机，还可以是商店。

使用XML进行交换信息的好处如下。

❑使用人的语言而不是计算机语言。XML便于阅读且也容易理解，即使是初学者亦如此，且与HTML编码相比并不难。

❑与Java完全兼容，且完全可以移植。可以在任何平台上处理XML的任何应用程序，都可以使用你的信息。

❑可扩展。创建读者自己的标记或使用其他人创建的标记。

❑XML可以用于交互式页面的开发，并且使用XML创建电子商务应用程序更加直观。使用XML存储数据一次，可以根据XSL/XALT处理器的样式表来处理，可以在不同的浏览器或设备中显示这些数据。

❑XML提供访问信息的标准方法，可以使各种类型的应用程序和设备更加容易使用，方便地存储、传送和显示数据。

❑XML的可移植性、可重复使用的格式表达使元数据更加容易。

虽然以前的PHP版本中也提供了XML的支持，但是随着PHP 5.0的推出，大大地强化了对XML的支持。PHP 5.0中的XML实现了W3C标准，符合了常用的标准。在PHP 5.0中新增的XML特性有SAX解析器、DOM、SimpleXML、XMLReader、XMLWriter和XSLT处理程序。这些扩展者是以libxml 2为基础。PHP 5.0符合W3C标准中的DOM和SimpleXML扩展。同时也支持SAX、DOM和SimpeXML。对于熟悉其他语言的DOM的读者来说，使用PHP实现类似的功能会更加简单。

16.1.2　XML与HTML之间的关系和区别

XML不是要替换HTML，实际上XML可以视作对HTML的补充。XML和HTML的目标不同：HTML的设计目标是显示数据并集中于数据外观，而XML的设计目标是描述数据并集中于数据的内容。XML与HTML相似，XML不进行任何操作。虽然XML标记可用于描述订单之类的项的结构，但它不包含可用于发送或处理该订单以及确保按该订单交货的任何代码。读者必须编写代码来对XML格式的数据执行这些操作。XML与HTML不同，XML标记由架构或文档的作者定义，并且是无限制的。HTML标记则是预定义的；HTML作者只能使用当前HTML标准所支持的标记。

注意　XML是区分大小写字母的，HTML不区分。

HTML实际上是一种置标语言，用来对文档的显示格式进行标记。在互联网中，HTML应用广泛，各种基于HTML的技术已经是非常成熟，还有许多强大的浏览器对其进行支持。那为什么还要推出XML呢？是因为在国际互联网的发展中，HTML不能满足用户的需求。HTML是把结构和显示混在一起的，无法对数据内容进行描述，而这一点却是数据检索、电子商务所不可缺少的一部分。HTML对数据表现的描述能力不是非常的到位，如HTML不可以描述矢量图形、科学符号等对象，只通过图像来表现这些对象。由于HTML语言给浏览器太大的解释的灵活性，使得Web页面的设计和显示发生比较多的冲突。在数据的交换方面，HTML不太实用。

XML的推出，能够很好地弥补上述的一些问题。XML标准下没有内建的标签，默认状态下，浏览器不能以任何特定的方式决定一个给定标签的使用。XML文档中的标签都必须以结构的方式在其他标签中或之后出现。由于没有内建标签，所以XML的文档开发可以由程序员来构建有意义的标签，这将极大地简化与其他应用程序交换数据的任务。

XML在采用简单、灵活的标准化格式表达和在应用间交换数据方面比HTML语言迈出了一大步。HTML提供了查看数据的通用方法，XML则提供的是直接在数据上工作的通用方法。XML的特点就是将用户界面和结构化数据相分离，允许不限来源的数据无缝集成和对同一数据的多种处理。从数据描述语言的角度看，XML是灵活的、可扩展的，有良好的结构和约束。

16.1.3　建立一个简单的XML文件

前面介绍了XML语言，读者也了解到了XML的优点和功能，那么XML是如何使用的呢？下面就建立一个简单的XML文件，如代码16.1所示。

代码16.1　第1个XML程序：16-1.xml

＜?xml version="1.0"encoding="GB2312"?＞

＜!--程序名称：16-1.xml--＞

＜!--程序功能：第一个XML程序--＞

＜介绍＞

＜名字＞XML学习＜/名字＞

＜成员＞

＜!--这里是注释--＞

＜姓名＞郑海生＜/姓名＞

＜年岁＞23＜/年岁＞

＜职务＞程序开发人员＜/职务＞

＜/成员＞

＜成员＞

＜姓名＞郑海生＜/姓名＞

＜年岁＞23＜/年岁＞

＜职务＞主持人＜/职务＞

＜/成员＞

＜/介绍＞

此程序就是一个XML的实例，要在浏览器中浏览这个程序，在IE浏览器中可以直接浏览。如果在本程序中加入了连接XSL文件的代码，浏览本程序就必须要有一个XSL样式文件，把模式文件与此程序文件存放在一个目录下面，才可以浏览。XSL也就是eXtensible Stylesheet Language，可扩展样式语言。此程序的运行效果如图16.1所示。

图　16.1　第1个XML实例的运行效果图

16.2　深入XML文档

前面介绍了XML是什么？本节主要为读者介绍XML是如何使用的，包括如下所示的内容。

❑XML声明。

❑元素的概念。

❑标记和属性。

❑Valid XML。

❑Well-formed XML。

❑文件类型定义。

16.2.1　XML声明

XML声明通常在XML文档的第1行出现。XML声明不是必选项，但是如果使用XML声明，必须在文档的第1行，前面不得包含任何其他内容或空白。文档映射中的XML声明包含下列内容，版本号和编码声明。

＜?xml version="1.0"encoding="UTF-8"?＞

这是必选项。尽管以后的XML版本可能会更改该数字，但是1.0是当前的版本，这是可选项。如果使用编码声明，必须紧接在XML声明的版本信息之后，并且必须包含表现有字符编码的值。

XML声明也可能包含一个独立的声明，例如＜?xml version="1.0"encoding="UTF-8"standalone="yes"?＞。与编码声明类似，独立声明也是可选项。如果使用独立声明，必须在XML声明的最后。编码声明标识用于表示文档中的字符的编码。尽管XML分析器可以自动确定文档使用的是UTF-8还是UTF-16 Unicode编码，但是在支持其他编码的文档中应使用此声明。

注意　该编码声明不考虑指定值的大小写。如utf-8等效于UTF-8。

独立声明指示文档的内容是否依赖来自外部源的信息，例如外部文档类型定义"DTD"。如果独立的声明有yes值，例如＜?xml version="1.0"standalone="yes"?＞，则这个文档如果引用外部DTD或外部实体，分析器将报告错误。省略独立声明与包含独立声明no的结果相同。XML分析器将接受外部源，如果有就不报告错误。

16.2.2　元素的概念及标记和属性

在XML中可以出现诸如处理指令、注释、根元素、子元素和属性等对象。

1.处理指令

处理指令用来给XML解析器提供信息，使其能够解释文档内容，以“＜?”为起始标识，“？＞”为结束标记。例如：

＜?xml version="1.0"encoding="ISO-8859-1"?＞

2.注释

在XML中注释语句使用的标识为“＜!--”和“--＞”，其可以出现在XML元素的任何地方，但是不可嵌套。例如：

＜!--e Name：myXml.xml--＞

注意　XML中的空白将被保留。在XML文档中，空白部分不会被解析器自动删除。

3.根元素和子元素

如果一个元素从文件头的序言部分之后一直应用到文件尾，包含了文件中所有的数据信息，则称之为根元素。XML元素是可以嵌套的，嵌套在其他元素中的元素被称为子元素。例如：

＜note＞

4.属性

在XML中，属性用于给元素提供更多、更详细的说明信息，其必须出现在起始标记中。属性以名称和值对的形式出现，属性名称不能重复，名称与取值之间用等号“=”分割，并用引号把取值标注起来，例如以下代码：

＜from home="shanxi"＞zhang＜/from＞

其表示来自家在"shanxi"的名为"zhang"的信。

在XML中，其文档结构由序言和文档元素组成。XML声明和注释外，还可以包含空格、文档类型声明一个或多个处理指令。文档类型声明定义了文档类型和结构，其必须在文档类型声明之后。而文档元素则是根元素和子元素及属性。

如何查看XML文档？可以在IE 5.0浏览器中直接打开XML文档，就像打开一个HTML Web页一样，显示一个打开的XML文档。IE 5.0浏览器用带有颜色的代码区分不同的文档组成部分，以便帮助区别，并且还可以通过收缩及扩展的形式来显示文档元素，清楚地指出该文档的逻辑结构并允许详细地查看各层。

16.2.3　DTD的使用

DTD文档的全称为Document Type Definition，是一套关于标记符的语法规则。它是XML1.0版规格的一部分，是XML文件的验证机制，属于XML文件组成的一部分。

DTD是一种保证XML文档格式正确的有效方法，可以通过比较XML文档和DTD文件来看文档是否符合规范，元素和标签使用是否正确。一个DTD文档包含有：元素的定义规则、元素间关系的定义规则、元素可使用的属性以及可使用的实体或符号规则。

XML文件提供的应用程序是一个数据交换的格式，DTD就是让XML文件能够成为数据交换的标准，因为不同的公司只需定义好标准的DTD文档。各公司都能够依照DTD建立XML文件，并且进行验证。这样就可以轻易地建立标准和交换数据，因此可以满足网络共享和数据交互。DTD文件是一个ASCII的文本文件，后缀名为".dtd"。

DTD文档类型可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD可被成行地声明于XML文档中，也可作为一个外部引用文件。内部的DOCTYPE声明，假如DTD被包含在XML源文件中，它应当通过下面的语法包装在一个DOCTYPE声明中，如代码16.2所示。

代码16.2　内部的DOCTYPE声明程序：16-2.dtd

＜!****************************************************

＜!名称：16-2.dtd＞

＜!功能：内部的DOCTYPE声明程序＞

＜!******************************************************＞

＜?xml version="1.0"?＞

＜!DOCTYPE note[

＜!ELEMENT note(to,from,heading,body)＞

＜!ELEMENT to(#PCDATA)＞

＜!ELEMENT from(#PCDATA)＞

＜!ELEMENT heading(#PCDATA)＞

＜!ELEMENT body(#PCDATA)＞

]＞

＜note＞

＜to＞Tove＜/to＞

＜from＞Jani＜/from＞

＜heading＞Reminder＜/heading＞

＜body＞Don't forget me this weekend＜/body＞

＜/note＞

在此程序中第2行，!DOCTYPE note定义此文档是"note"类型的文档；第3行"!ELEMENT note"定义"note"元素有4个元素："to、from、heading、body"。第4行"!ELEMENT to"定义"to"元素为"#PCDATA"类型。第5行"!ELEMENT from"定义"frome"元素为"#PCDATA"类型。第6行"!ELEMENT heading"定义"heading"元素为"#PCDATA"类型。第7行"!ELEMENT body"定义"body"元素为"#PCDATA"类型。

注意　如果是外部文档声明，可以使用语句如＜!DOCTYPE根元素SYSTEM"文件名"＞。

上面介绍了内部的DOCTYPE声明程序，下面将为读者介绍外部的DOCTYPE声明程序。也就是DTD位于XML源文件的外部，那么它应通过下面的语法被封装在一个DOCTYPE中被定义，格式如下所示：

＜!DOCTYPE根元素SYSTEM"文件名"＞

通过这样的定义，这个XML文档和上面的XML文档是相同的，但是其拥有一个外部的DTD文档，如代码16.3所示。

代码16.3　外部的DOCTYPE声明程序：16-3.dtd

＜!****************************************************

＜!名称：16-3.dtd＞

＜!功能：外部的DOCTYPE声明程序＞

＜!******************************************************＞

＜?xml version="1.0"?＞

＜!DOCTYPE note SYSTEM"note.dtd"＞

＜note＞

＜to＞Tove＜/to＞

＜from＞Jani＜/from＞

＜heading＞Reminder＜/heading＞

＜body＞Don't forget me this weekend!＜/body＞

＜/note＞这是包含DTD的"note.dtd"文件：

＜!ELEMENT note(to,from,heading,body)＞

＜!ELEMENT to(#PCDATA)＞

＜!ELEMENT from(#PCDATA)＞

＜!ELEMENT heading(#PCDATA)＞

＜!ELEMENT body(#PCDATA)＞

在XML程序中使用DTD的好处是通过DTD，读者的每一个XML文件均可携带一个有关其自身格式的描述。通过DTD，独立的团体可以一致地使用某个标准的DTD来交换数据。而读者的应用程序也可使用某个标准的DTD来验证从外部接收到的数据，读者还可以使用DTD来验证自身的数据。

16.3　用PHP函数处理XML文档

作为一个在不同平台之间通信的通用语言，XML正在被越来越多的爱好者的使用。一些程序员甚至叫XML“新的互联网革命”。XML有时用来作为数据库存放文档，但是数据存储永远不是它主要的用途。它是为了使通用的格式从一个系统传递信息到另一个系统中而开发的。

XML是一种标记语言。真实的数据在结构中包含的，用文档的元素来标记。通常，信息需要被转换成另外一种格式。本节的重点是使用PHP来读取并传输XML文档，然后使用XML作为与远程服务通信的协议。提供所有的使用XML的技术已经超过了本书的范围。

读者在阅读完本节后，需要学会如下的内容。

❑建立和释放XML解析器。

❑建立元素事件处理函数。

❑建立字符数据处理函数。

❑开始解析一个XML文档。

❑其他事件处理函数的建立。

❑如何实现从XML文件中读取新闻列表。

16.3.1　建立XML解析器

用PHP解析XML文档，非常适合于服务器端的应用。PHP解析XML文档的工作原理很简单。首先建立一个解析器，它是所有工作的核心。解析器将分析XML文档，并在各种事件发生时通知对应的处理函数进行处理。函数xml_parser_create()和xml_parser_create_ns()用于建立一个XML解析器，并返回可被其他XML函数使用的资源句柄。函数的格式如下所示：

resource xml_parser_create([string$encoding])

resource xml_parser_create_ns([string$encoding[,string$seperator]])

PHP 4中用于指定要被解析的XML输入的数字编码方式的参数是$encoding，并且此参数是可选的。从PHP 5.0开始，可以自动侦测输入的XML的编码，因此可选参数$encoding仅用于指定解析后输出数据的编码。解析器支持的编码有ISO-8859-1、UTF-8和US-ASCII。

xml-parser-create-ns()函数用于建立支持XML命名空间的解析器。通过这种解析器，传递给各个句柄函数的标签参数将由命名空间和标签名组成。命名空间和标签名的分隔符由参数$encoding给出的字符串决定。

16.3.2　建立元素事件处理函数

前面介绍了建立XML解析器，接下来介绍如何设置XML解析器。在使用XML解析器之前，需要先进行了解。例如，默认情况下XML文档中的空白字符是有意义的，解析器也会对其进行处理。在XML文档的空白中，如制表符等仅用于控制XML文档内容的缩进格式，使之容易阅读。如果也把这些空白符作为元素的内容，就会导致一些不可想象的错误，所以需要忽略这些空白符。元素处理函数可能会出现元素名称大小写的问题。为了调整XML解析器的运行过程序，可以通过xml_parser_set_option()函数来设置，此函数的代码格式如下所示：

bool xml_parser_set_option(resource$parser,int$option,mixed$value)

在此代码中，"$parser"是XML解析器的指针。"$option"为要设置的选项，选项值由$value参数给出。value可被设置的选项如表16.1所示。

如果读者想获取XML解析器中上面表中所示的这些选项的设置值，可以使用xml_parser_get_option()函数，此函数的代码格式如下所示：

mixed xml_parser_get_option(resource$parser,int$option)

由于是获取了XML解析器中的选项值，所以该函数只需要提供解析器指针"$parser"，以及选项"$option"就可以了。

16.3.3　开始解析一个XML文档

PHP用Expat这种XML工具包，通过C语言来解析XML。这个工具包的函数集同Perl XML解析所采用的函数集是一样的。此外，这种工具包还是事件驱动型的解析器。也就是说，Expat把每个XML标签或者新一行代码当作事件的起始，而事件就是函数的触发器。Expat的安装非常简单。用PHP解析XML的基本任务是这样的：首先，创建XML解析器的一个实例；接着，定义处理触发事件的函数，如开始或者结束标签等；随后，定义实际意义的数据处理程序；最后，打开XML文件，读取文件数据并解析数据；之后关闭文件并释放XML解析器。

Expat不对XML进行检验。这意味着只要XML文件格式正确、所有的元素嵌套得当、开始和关闭标签没有任何错误，此时XML就会被解析。Expat把XML标签全部转换为大写字母。如果你的脚本在标签名和其他内容上，大小写字母混用可就要小心了，这样会产生不可想象的错误。下面以一个实例来为读者介绍如何实现一个XML文档的解析，如代码16.4所示。

代码16.4　解析一个XML文档程序：16-4.php

＜?php

//*************************************************

//名称：16-4.php

//功能：解析一个XML文档程序

//*************************************************

$xml_file="16-5.xml";//设置XML文件

echo"＜table border=0 cellpadding=5＞";//输出表格

echo"＜tr＞＜th colspan=2＞XML Articles＜/th＞＜/tr＞";//输出表格中内容

function startElement($parser_instance,$element_name,$attrs)//定义方法

{

switch($element_name){

case"URL":echo"＜tr＞＜td＞＜a href=\"";

break;//跳出循环

case"SUMMARY":echo"＜td＞";

break

}

}

function characterData($parser_instance,$xml_data)//定义方法

{

echo$xml_data;//输出变量

}

function endElement($parser_instance,$element_name)

{

switch($element_name){

case"URL":echo"\"＞";

break;

case"TITLE":echo"＜/a＞＜/td＞";

break;

case"SUMMARY":echo"＜/td＞＜/tr＞";

break;

}

}

$parser=xml_parser_create();

xml_set_element_handler($parser,"startElement","endElement");

xml_set_character_data_handler($parser,"characterData");

if(!($filehandler=fopen($xml_file,"r")))

{

die("could not open XML input");

}

while($data=fread($filehandler,4096)){

if(!xml_parse($parser,$data,feof($filehandler))){

die(sprintf("XML error:%s at line%d",xml_error_string(xml_get_error_code($parser)),

xml_get_current_line_number($parser)));

}

}

fclose($filehandler);xml_parser_free($parser);

echo"＜/table＞";

?＞

在此程序中，首先创建了XML解析器的一个实例，代码如下所示：

$parser=xml_parser_create();

接着，定义解析器遭遇开始和结束标签时的操作。注意startElement和endElement是用户定义的函数。当然也可以按照自己的喜好定义名字，但定义这些名字可是有标准要求，格式如下所示：

xml_set_element_handler($parser,"startElement","endElement");

然后定义了数据操作。这里的characterData也是用户定义的函数，名字也是有标准需求的，格式如下所示：

xml_set_character_data_handler($parser,"characterData");

现在打开文件读取数据。读者可以在这里开始编写错误处理代码，笔者在此例子中省略了这些错误处理。不要忘了在脚本的开头定义$xml_file，其代码格式如下所示：

$filehandler=fopen($xml_file,"r");

开始读取文件内容，一次读"4K"字节并放在变量$data内，直到文件末尾。笔者用xml_parse解析读取的这些数据段。其代码如下所示：

while($data=fread($filehandler,4096)){

xml_parse($parser,$data,feof($filehandler));

}

最后进行清空、关闭文件和释放解析器等操作。这样做的目的是回收资源。其代码如下所示。以上就是脚本中所用到的所有XML函数。

fclose($filehandler);

xml_parser_free($parser);

注意　Expat可不管XML是否遵守XML文件头中引用的标准或者定义。PHP是在magic quotes设置启用的情况下编译而成的，那么复杂的XML文件就不会得到正确的解析。

在上面介绍了如何使用PHP函数解析XML文档，接下来需要创建一个XML文档，这样解析程序才能真正地实现XML文档的解析，代码如代码16.5所示。

代码16.5　XML文档程序：16-5.xml

＜?xml version="1.0"encoding="utf-8"?＞

＜series＞

＜article＞

＜url＞http://builder.com.com/article.jhtml?id=u00220020327adm01.htm＜/url＞

＜title＞Remedial XML for programmers:Basic syntax＜/title＞

＜summary＞In this first installment in a three-part series,I'll introduce you to XML

and its basic syntax.＜/summary＞＜/article＞

＜article＞＜url＞http://builder.com.com/article.jhtml?id=u00220020401adm01.htm＜/url＞

＜title＞Remedial XML:Enforcing document formats with DTDs＜/title＞

＜summary＞To enforce structure requirements for an XML document,you have to turn to

one of XML's attendant technologies,data type definition(DTD).＜/summary＞＜/article＞

＜article＞

＜url＞http://builder.com.com/article.jhtml?id=u00320020418adm01.htm＜/url＞

＜title＞Remedial XML:Using XML Schema＜/title＞

＜summary＞In this article,we'll briefly touch on the shortcomings of DTDs and

discuss the basics of a newer,more powerful standard:XML Schemas.＜/summary＞＜/article＞

＜article＞＜url＞http://builder.com.com/article.jhtml?id=u00220020522adm01.htm＜/url＞

＜title＞Remedial XML:Say hello to DOM＜/title＞

＜summary＞Now it's time to put on your programmer's hat and get acquainted with

Document Object Model(DOM),which provides easy access to XML documents via a

tree-like set of objects.＜/summary＞＜/article＞

＜article＞

＜url＞http://builder.com.com/article.jhtml?id=u00220020527adm01.htm＜/url＞

＜title＞Remedial XML:Learning to play SAX＜/title＞

＜summary＞In this fifth installment in our Remedial XML series,I'll introduce you to

the SAX API and provide some links to SAX implementations in several

languages.＜/summary＞

＜/article＞

＜/series＞

此程序就是一个简单的XML程序，在这里就不做太多的介绍了。运行解析XML文档的程序效果如图16.2所示。

图　16.2　解析XML文档程序的运行效果图

注意　此程序的运行效果类似一个手册，方便读者阅读。如果读者想做这样的一个手册，就可修改此程序。

16.4　使用DOM库处理XML文档

DOM是Document Object Model文档对象模型的缩写。根据W3C DOM规范，DOM是一种与浏览器、平台、语言无关的接口，使用户可以访问页面其他的标准组件。简单理解，DOM解决了Netscape的JavaScript和Microsoft的Jscript之间的冲突，给予Web设计师和开发者一个标准的方法，来访问站点中的数据、脚本和表现层对象。

DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中导航寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构，然后才能做任何工作。由于它是基于信息层次的，因而DOM被认为是基于树或对象的。对于特别大的文档，解析和加载整个文档可能很慢且很耗资源，因此使用其他手段来处理这样的数据会更好。这些基于事件的模型，如Simple API for XML（SAX），适用于处理数据流，即随着数据的流动而依次处理数据。基于事件的API消除了在内存中构造树的需要，但是却不允许开发人员实际更改原始文档中的数据。

SAX等模型会从头至尾地顺序解析整个XML文档，当遇到一个节点的开始或者结束时，会产生一个时间，程序员可以注册事件处理函数以对各个节点进行处理。另一方面，DOM还提供了一个API，允许开发人员添加、编辑、移动或删除树中任意位置的节点，从而创建一个引用程序。这个模型就是基于树型数据结构的，在使用之前必须加载整个文档或者至少是结构良好的文档片段。

解析器是一个软件应用程序，用于分析文档，以及做一些特定于该信息的事情。在诸如SAX这样基于事件的API中，解析器将向某种监听器发送事件。在诸如DOM这样基于树的API中，解析器将在内存中构造一棵数据树。作为API的DOM从DOM Level 1开始，DOM API包含了一些接口，用于表示可从XML文档中找到的所有不同类型的信息。它还包含使用这些对象所必需的方法和属性。

16.4.1　创建一个DOM对象并装载XML文档

本节将为读者介绍如何创建一个DOM对象，并装载XML文档。DOM是XML的一种解析器，通过DOM解析器所创建的对象，把XML文档装载到此解析器中，方便读者的使用。现以实例来介绍如何创建DOM对象并装载XML文档，程序如代码16.6所示。

代码16.6　创建一个DOM对象并装载XML文档程序：16-6.html

＜html＞

＜!--名称：16-6.html--＞

＜!--功能：加载XML文档--＞

＜body＞

＜script type="text/javascript"＞

＜!--IE浏览器--＞

try

{

xmlDoc=new ActiveXObject("Microsoft.XMLDOM");

}

catch(e)

{

＜!--其他浏览器，如Firefox,Mozilla,Opera,etc--＞

try

{

xmlDoc=document.implementation.createDocument("","",null);

}

catch(e){alert(e.message)}

}

try

{

xmlDoc.async=false;

xmlDoc.load("16-7.xml");

document.write("xmlDoc is loaded,ready for use");

}

catch(e){alert(e.message)}

＜/script＞

＜/body＞

＜/html＞

此程序中首先通过脚本程序来判断用户所使用的浏览器，浏览器分为IE、Firefox、Mozilla、Opera和etc。然后通过"xmlDoc.load()"来装载XML文档。这样创建一个DOM对象并装载XML文档的程序是完成了，接下来要介绍一下要装载的XML文档，程序如代码16.7所示。

代码16.7　需要装载的XML文档程序：16-7.xml

＜?xml version="1.0"encoding="utf-8"?＞

＜!--名称：16-7.xml--＞

＜!--功能：一个XML文档--＞

＜bookstore＞

＜book category="children"＞

＜title lang="en"＞中国＜/title＞

＜author＞作者＜/author＞

＜year＞2008＜/year＞

＜price＞29＜/price＞

＜/book＞

＜book category="cooking"＞

＜title lang="en"＞中国＜/title＞

＜author＞作者一＜/author＞

＜year＞2008＜/year＞

＜price＞30＜/price＞

＜/book＞

＜book category="web"＞

＜title lang="en"＞中国＜/title＞

＜author＞作者二＜/author＞

＜author＞作者三＜/author＞

＜author＞作者四＜/author＞

＜author＞作者五＜/author＞

＜author＞作者六＜/author＞

＜year＞2008＜/year＞

＜price＞67＜/price＞

＜/book＞

＜book category="web"cover="paperback"＞

＜title lang="en"＞中国＜/title＞

＜author＞作者八＜/author＞

＜year＞2008＜/year＞

＜price＞69＜/price＞

＜/book＞

＜/bookstore＞

该程序是一个图书的介绍程序，包括图书的语言、作者、出版时间、图书的价格。此XML文档通过该程序装载到DOM对象中。程序的运行效果如图16.3所示。

图　16.3　创建一个DOM对象并装载XML文档程序的运行效果图

注意　该程序将XML文档成功地装载到DOM对象后，才会显示上面的图的效果。

16.4.2　取得节点

XML文档中的每个成分都是一个节点。下面介绍如何使用DOM来获取XML文档中节点的内容，并对不同的浏览器进行了详细的介绍。关于节点的操作设计如下面所示。

❑childNodes属性：返回一个节点的所有节点元素，但是只是第1级，嵌套的将不会计算在内。

❑getElementsByTagName：返回一个节点列表数组，因而就会有一个length属性。

注意　不过childNodes在IE和Firefox浏览器中表现是不一样的，关键在于文本节点的差异，后面的例子中会给出分析。

下面介绍nodeType属性。它将会返回节点类型包括元素节点，例如"div"、"p"、"ul"这些标签；属性节点；文本节点，如一些描述性的内容。nodeValue属性将返回或者设置文本节点值。firstChild和lastChild属性，将分别返回首个和最后一个节点。下面进入具体的实践，childNodes是一个比较麻烦的属性，先举个例子来介绍，代码如下所示：

＜div id="father"＞

＜div id="son1"＞＜/div＞

＜div id="son2"＞

＜div id="grandson1"＞＜/div＞

＜div id="grandson2"＞＜/div＞

＜/div＞

＜div id="son3"＞＜/div＞

＜/div＞

假设读者取得了id属性值为father的节点，那么"childNodes"在IE浏览器下为father本身的文本节点，但是这里为空，因为IE浏览器将不计算这个节点。然后就是"son1"、"son2"、"son3"这3个节点，再次说明："father"的文本节点由于为空，IE浏览器不计算这个节点，但如果不为空，就和"son1"、"son2"、"son3"并列，是一个文本节点。另外"grandson1"和"grandson2"是嵌套的，"childNodes"只计算第1个元素，因而不计算这两个节点。综上所述，得出IE浏览器解释"childNodes"原则是：如果父节点存在文本节点，计算一个节点，否则这个节点不计算。父节点下只计算第1级元素节点，不包括嵌套的元素节点，忽略空白文本节点，其实第1条是空白节点的特例，只是位置有点不同。

而在Firefox下，无论什么情况都会计算文本节点，即使节点为空，包括父节点和子结点的文本节点。因而上面例子中在Firefox下得到的结果是："father"自身的文本节点"son1"、"son1"后的文本节点"son2"、"son2"后的文本节点"son3"、"son3"后的文本节点，共7个节点。代码在两个浏览器中测试会发现二者的差异很大。IE浏览器显示3个节点，而在Firefox下则显示7个节点。下面就以一个实例来介绍，程序如代码16.8所示。

代码16.8　XML文档程序：16-8.xml

＜?xml version="1.0"encoding="utf-8"?＞

＜!--名称：16-8.xml--＞

＜!--功能：一个XML文档--＞

＜bookstore＞

＜book category="COOKING"＞

＜title lang="en"＞国家＜/title＞

＜author＞书名＜/author＞

＜year＞2008＜/year＞

＜price＞30.00＜/price＞

＜/book＞

＜book category="CHILDREN"＞

＜title lang="en"＞PHP学习＜/title＞

＜author＞作者＜/author＞

＜year＞2008＜/year＞

＜price＞59.99＜/price＞

＜/book＞

＜book category="WEB"＞

＜title lang="en"＞JAVA学习＜/title＞

＜author＞作者一＜/author＞

＜author＞作者二＜/author＞

＜author＞作者三＜/author＞

＜author＞作者四＜/author＞

＜author＞作者五＜/author＞

＜year＞2007＜/year＞

＜price＞89.99＜/price＞

＜/book＞

＜book category="WEB"＞

＜title lang="en"＞AJAX＜/title＞

＜author＞作者＜/author＞

＜year＞2008＜/year＞

＜price＞69.95＜/price＞

＜/book＞

＜/bookstore＞

在上面的XML中，根节点是＜bookstore＞。文档中的所有其他节点都被包含在＜bookstore＞中。根节点＜bookstore＞有4个＜book＞节点。第1个＜book＞节点有4个节点，＜title＞、＜author＞、＜year＞以及＜price＞，其中每个节点都包含一个文本节点。下面以实例来介绍如何获取节点，程序如代码16.9所示。

代码16.9　获取节点的程序：16-8.html

＜html＞

＜!--名称：16-9.html--＞

＜!--功能：获取节点程序--＞

＜head＞

＜/head＞

＜body＞

＜!—脚本部分--＞

＜script type="text/javascript"＞

＜!—读取XML文件--＞

xmlDoc=loadXMLDoc("16-7.xml");

＜!—获取X的值--＞

x=xmlDoc.getElementsByTagName("title")[0];

＜!—获取Y的值--＞

y=x.childNodes[0];

document.write(y.nodeValue);

＜/script＞

＜/body＞

＜/html＞

在此程序中，通过使用loadXMLDoc()把XML文档载入xmlDoc中，并检索第1个"＜title＞"元素，通过getElementsByTagName()方法返回包含拥有指定标签名的所有元素的节点列表，其中的元素的顺序是其所在源文档中出现的顺序。检索"＜title＞"元素的文本节点的代码如下所示：

x=xmlDoc.getElementsByTagName("title")[0]

y=x.childNodes[0];

通过运行此代码，首先把XML文档载入，然后获取节点。程序的运行结果为“国家”。

注意　程序从第1个"＜title＞"开始检索。通过脚本进行检索。

16.4.3　取得节点属性

本节介绍如何获取节点属性。在上节中，介绍了如何获取节点，读者理解了上节后，实现此节获取节点属性其实是就非常简单了。只要在上面实例中，在获取节点的代码行中加入一个属性，就可以实现节点属性的获取。获取节点属性的代码如下所示：

txt=xmlDoc.getElementsByTagName("title")[0].getAttribute("lang");

document.write(txt);

下面就以实例来介绍如何获取节点属性的，程序如代码16.10所示。

代码16.10　获取节点属性程序：16-10.html

＜html＞

＜head＞

＜!--名称：16-10.html--＞

＜!--功能：获取节点属性程序--＞

＜!—脚本结束部分--＞

＜/script＞

＜/head＞

＜body＞

＜!—脚本部分--＞

＜script type="text/javascript"＞

xmlDoc=loadXMLDoc("/example/xdom/books.xml");

txt=xmlDoc.getElementsByTagName("title")[0].getAttribute("lang");

document.write(txt);

＜/script＞

＜/body＞

＜/html＞

在此程序中，通过使用loadXMLDoc()把XML文档载入xmlDoc中，并检索第1个"＜title＞"元素，通过getElementsByTagName()方法返回包含拥有指定标签名的所有元素的节点列表，其中的元素的顺序是其所在源文档中出现的顺序。通过getAttribute()来获取节点的属性。

16.5　小结

通过本章的学习，读者需要掌握以下内容。

❑XML是什么。

❑如何创建XML文档。

❑用PHP函数处理XML文档。

❑使用DOM库处理XML文档。

其中需要重点学习的内容就是使用PHP函数处理XML文档，这是在程序开发时常会使用到的技术。

第五篇　PHP综合实例

第17章　PHP留言板实例

本章将详细地介绍留言板实现的整个过程，其中重点介绍留言板数据表的建立、发表留言和显示留言内容等步骤的实现过程，这样可以使读者轻松地掌握留言板的工作原理和实现过程。

留言板是实现网站运营者和访问者之间的一个互动关系。网站的访问者可以通过留言板写下自己对网站的看法和意见，也可以提出一些问题等，这样网站的维护人员也可以在留言板上回复这些意见和看法，更好地维护好网站。由此可以看出留言板的重要性。因此，在大多数网站中，留言板是必不可少的一个模块。

下面就来介绍实现留言板模块的方法和步骤。在实现留言板模块的时候，首先要考虑如何建立留言板数据表，然后是怎样把网友发表的留言信息存入到数据表中，最后就是如何把网友留言信息全部显示在页面上。下面就按上面步骤一步一步地实现留言板程序。

17.1　数据库设计

为了实现留言板这个模块，需要独立建立一张数据表，用于存放访问者的留言信息。在这张数据表中，需要保存留言者所有的留言信息，还需要将用户名、留言的时间、留言的IP地址等信息同时放入数据表中；也可以用专门的一个字段来存储附加图片。数据表的数据结构就如图17.1所示。

图　17.1　留言板数据表的数据结构

在这张数据表中，字段"id"是标识每条记录的标识；字段"name"用于记录留言用户的用户名；字段"time"记录用户留言的时间；字段"content"是记录用户的留言内容；字段"ip"用于存储访问者的ip地址。

下面就开始在MySQL数据库中建立一个luiyan数据库，再按照图17.1中所示的数据结构来建立一张数据表，用于存储留言板中的数据。把这张数据表取名为"guestbook"。在MySQL数据库进行如下的操作。建立luiyan数据库的SQL语句如下：

CREATE DATABASE'liuyan';

在数据库tennis中建立一张表content的语句如下：

CREATE TABLE'guestbook'(

'id'bigint(20)unsigned NOT NULL auto_increment,

'hide'tinyint(1)NOT NULL default'0',

'name'varchar(16)NOT NULL default'',

'gender'tinyint(1)NOT NULL default'1',

'email'varchar(64)NOT NULL default'',

'homepage'varchar(64)NOT NULL default'',

'oicq'varchar(16)NOT NULL default'',

'face'tinyint(2)NOT NULL default'0',

'ip'varchar(12)NOT NULL default'',

'time'datetime NOT NULL default'0000-00-00 00:00:00',

'content'text NOT NULL,

'revort'text NOT NULL,

'retime'datetime NOT NULL default'0000-00-00 00:00:00',

PRIMARY KEY('id')

);

在建立好了留言板的数据表后，留言板的数据存储表就建好了，就可以进行下一步工作了。

注意　在进行数据库的创建时，要规划好数据库，这样才能保证数据库执行效率。

17.2　共用页面部分

共用页面部分就是程序中的共享页面部分，在程序中使用的次数较多，所以把这些代码写成共用的部分，来实现代码的重复使用。共用部分包括：共用头部页面、共用尾部页面、样式文件、操作数据库配置文件。下来就来介绍这些共用页面是如何实现的。

17.2.1　共用头部页面

为了使程序模块化，笔者把程序的主体页面分为了共用头部页面、共用尾部页面等，下面介绍留言板头部显示部分，也就是共用头部页面。留言板的头部显示部分代码如代码17.1所示。

代码17.1　留言板的头部显示页面程序：17-1.php

＜html＞

＜!--名称：17-1.php--!＞

＜!--功能：留言板的头部显示页面--!＞

＜head＞

＜!—设置页面的编码--＞

＜meta name="keywords"content="留言本"/＞

＜meta name="Description"content="PHP留言本"/＞

＜meta http-equiv=Content-Type content="text/html;charset=gb2312"/＞

＜title＞留言本＜/title＞

＜!—样式部分--＞

＜style type="text/css"＞

.booktext{TABLE-LAYOUT:fixed;WORD-BREAK:break-all;

WORD-WRAP:break-word;overflow:hidden;width:550px;}

＜/style＞

＜/head＞

＜body topmargin=0 leftmargin=0 marginwidth=0 marginheight=0＞

＜!—居中显示--＞

＜center＞

＜div align=center＞

＜!--Header--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730＞

＜tr＞

＜td class=MenuBar_B rowspan=8 width=1＞＜/td＞

＜td height=8 class=MenuBar_B＞＜/td＞

＜td class=MenuBar_B rowspan=8 width=1＞＜/td＞

＜/tr＞

＜tr＞

＜td height=2＞＜/td＞＜/tr＞

＜tr＞

＜td height=1 class=MenuBar_B＞＜/td＞＜/tr＞

＜tr＞

＜td height=74＞

＜table border=0 cellpadding=0 cellspacing=0 width=100%＞

＜tr＞

＜td＞＜/td＞

＜td align=right＞＆nbsp;

＜/td＞

＜/tr＞

＜/table＞＜/td＞

＜/tr＞

＜tr＞

＜td height=1 class=MenuBar_B＞＜/td＞

＜/tr＞

＜tr＞

＜td height=2＞＜/td＞

＜/tr＞

＜tr＞

＜td height=6 class=MenuBar_B＞＜/td＞

＜/tr＞

＜tr＞

＜td＞

＜table border=0 width=728 cellspacing=0 cellpadding=0 class=MenuBar＞

＜tr＞

＜td valign=middle id=MenuBar＞＜div＞＆nbsp;＆nbsp;

＜a href="17-6.php"＞返回首页＜/a＞┊

＜?php

/*根据管理员登录与否，输出不同的链接*/

if($_SESSION['isAdmin'])

{

echo'＜a href="17-10.php?logout=1"＞退出管理＜/a＞';//退出管理链接

}

else

{

echo'＜a href="17-9.php"＞登录＜/a＞';//登录链接

}

?＞

┊＜/div＞＜/td＞

＜td align=right id=MenuBar＞＆nbsp;＜/td＞

＜/tr＞

＜/table＞＜/td＞

＜/tr＞

＜/table＞

＜br/＞

＜!--头部信息--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730 height=45＞

＜tr＞

＜td valign=top＞＜/td＞

＜td align=right valign=top＞

＜img src="images/write.gif"height=32 width=32 border="0"＞

＜a href="17-7.php"＞＜strong＞留言＜/strong＞＜/a＞

＜img src="images/system.gif"height=32 width=32 border="0"＞

＜?php

//根据管理员登录与否，输出不同的链接

if($_SESSION['isAdmin'])

{

echo'＜a href="17-10.php?logout=1"＞＜strong＞退出管理＜/strong＞＜/a＞';

}

else

{

echo'＜a href="17-9.php"＞＜strong＞登录管理＜/strong＞＜/a＞';

}

?＞

＜/strong＞＜/a＞＆nbsp;＜/td＞

＜/tr＞

＜/table＞

＜!--头部文件结束，正文开始部分--＞

此程序是定义留言板的标题等一些头部信息，管理员的登录也显示在此页面中。此程序通过if判断来判断管理员是否登录。如果管理员已经登录，就会出现退出管理的提示，如果没有登录就要提示“登录”。程序的运行效果如图17.2所示。

图　17.2　留言板的头部页面运行效果图

注意　此程序中使用了样式，样式文件将在下面介绍。

17.2.2　共用尾部页面

上面介绍了留言板的共用头部，接下来介绍留言板的共用尾部页面的建立。共用尾部页面用来显示网站的版权所有等相关信息，实例代码如代码17.2所示。

代码17.2　共用尾部页面程序：17-2.php

＜!—名称：17-2.php--!＞

＜!—功能：共用尾部页面--!＞

＜!--正文结束部分--＞

＜hr size="1"width="730"align="center"＞

＜table cellpadding="0"cellspacing="0"height="35"width="728"＞

＜tr＞

＜td align="center"height="34"＞Copyright©2007＜a href=

"http://www.taodoor.com"target="_blank"＞＜font color="#000000"＞PHP

留言本＜/font＞＜/a＞＜br＞＜/td＞

＜/tr＞

＜/table＞

＜/div＞

＜/center＞

＜/body＞

＜/html＞

此代码比较简单，就是显示一个版权所有信息，这里就不多做介绍了。接下来介绍样式文件。

17.2.3　样式文件

在前面的章节中介绍过CSS样式，样式文件主要的作用是定义页面中的内容是如何显示的。例如字体、字体的颜色、字体的大小及背景颜色等。样式文件的代码如代码17.3所示。

代码17.3　页面显示的样式文件程序：17-3.css

＜!--名称：17-3.css--!＞

＜!--功能：页面显示的样式文件--!＞

BODY{

font-size:9pt;

font-family:"宋体";

cursor:default;

background-color:#EEF2F5;

scrollbar-face-color:#EDEDED;

scrollbar-highlight-color:#E6E6E6;

scrollbar-shadow-color:#FFFFFF;

scrollbar-3dlight-color:#FFFFFF;

scrollbar-arrow-color:#7788A0;

scrollbar-track-color:#F5F5F5;

scrollbar-darkshadow-color:#242930;

}

TD{font-size:9pt;color:#333333;}

.Revert{color:#37527D;}

A:link,A:visited{color:#333333;text-decoration:none;}

A:hover,A:active{color:#37527D;text-decoration:underline;}}

INPUT.text,TEXTAREA,SELECT,INPUT.button{

font-size:9pt;

border:1px solid#37527D;

background-color:#F3F3F3;

}

.locktext{

background-color:#F5F5F5;

border:1px solid#F5F5F5;

}

.MenuBar_B{

background-color:#5E6C83;

}

.MenuBar{

color:#000000;

height:25px;

background-repeat:repeat-x;

background-color:#D6DCE5;

}

#MenuBar,#MenuBar a:link,#MenuBar a:visited{color:#333333;text-decoration:none;}

#MenuBar a:hover,#MenuBar a:active{color:#37527D}

.TitleBar{

height:23px;

background-color:#5E6C83;

border-left:1px solid#26354F;

border-right:1px solid#26354F;

border-top:1px solid#26354F;

}

.TitleBar_L{width:5px;}

.TitleBar_R{}

.TitleBar_T{

font-family:"宋体","Times New Roman";

font-size:9.3pt;

font-weight:bold;

color:#F3F3F3;

background-repeat:no-repeat;

}

.Border_L,.Border_R{

width:1px;

background-color:#26354F

}

.Hemline{

height:1px;

background-color:#26354F;

}

.Hemline_L{}

.Hemline_R{}

.Hemline_T{}

.bgLine{background-color:#425E8A;

}

hr{color:#425E8A;}

.insist{color:#FF0000;

}

.TextBox_1{background-color:#F5F5F5;

}

.TextBox_2{background-color:#EDEDED;

}

此代码就是留言板的页面显示样式代码，在这里定义了页面中显示字体、背景、表单的颜色等信息。作用就是使留言板的页面显示效果更加美观。

注意　如果读者没有定义好样式文件，就会使页面显示的效果更加无序。

17.2.4　操作数据库配置文件

在此留言板中，笔者把程序的一些操作都模块化了，因为这样可以使得在以后的维护中比较简单。笔者把操作数据库也写成了一个模块，没有把数据库操作代码写入到页面中，这样在以后修改操作数据库代码时，只需要修改这个操作数据库配置文件就可以了，程序代码如代码17.4所示。

代码17.4　操作数据库配置文件程序：17-4.php

＜?php

/********************/

//名称：17-4.php

//功能：操作数据库配置文件

/********************/

//连接数据库的定义

define('DB_USER',"root");//用户名

define('DB_PASSWORD',"");//密码

define('DB_HOST',"localhost");//数据库主机地址

define('DB_NAME',"liuyan");//数据库

/*管理员用户账号*/

define('ADMIN_USER',"admin");

define('ADMIN_PASS',"admin");

/*分页设置，每页最多显示的记录数*/

define('EACH_PAGE',5);

/******************/

/*初始化程序*/

/******************/

ob_start();//开启SESSION，允许COOKIE

if(function_exists(session_cache_limiter))

{

session_cache_limiter("private,must-revalidate");

}

session_start();

$db=mysql_pconnect(DB_HOST,DB_USER,DB_PASSWORD);//打开数据库连接

if(!$db)

{

die('＜b＞数据库连接失败！＜/b＞');

exit;

}

mysql_select_db(DB_NAME);//选择数据库

?＞

在此程序中，分为了4部分：定义连接数据、定义管理员账号、定义每一页面显示有多少条信息及对数据库的打开关闭操作。此模块是在当页面中要对数据库进行操作，把此模块调入，这样操作数据库就实现了。

17.3　UBBCode转换为HTML

此程序就是当程序中不允许使用HTML语法的情况下，通过UBB特殊转换程序，以至可以支持少量常用的、无危害性的HTML效果显示。程序如代码17.5所示。

代码17.5　UBBCode转换为HTML程序：17-5.php

＜?php

/**********************************/

//文件名：17-5.php

//功能：UBBCode转换为HTML

/**********************************/

//UBBCode转换为HTML

//输入：字符串

//输出：字符串

function ubbcode($d)

{

$pattern=array(

"/\[b\](.+?)\[\/b\]/is",

"/\[i\](.+?)\[\/i\]/is",

"/\[u\](.+?)\[\/u\]/is",

"/\[font=([^\[]*)\](.+?)\[\/font\]/is",

"/\[color=([#0-9a-z]{1,10})\](.+?)\[\/color\]/is",

"/\[size=([0-9]{1,2})\](.+?)\[\/size\]/is",

"/\[email=([^\[]*)\](.+?)\[\/email\]/is",

"/\[email\]([^\[]*)\[\/email\]/is",

"/\[url=([^\[]*)\](.+?)\[\/url\]/is",

"/\[url\]www\.([^\[]*)\[\/url\]/is",

"/\[url\]([^\[]*)\[\/url\]/is",

"/\[fly\](.+?)\[\/fly\]/is",

"/\[move\](.+?)\[\/move\]/is",

"/\[align=(left|center|right)\](.+?)\[\/align\]/is",

"/\[shadow=([#0-9a-z]{1,10})\,([0-9]{1,3})\,([0-9]{1,2})\](.+?)\[\/shadow\]/is",

"/\[glow=([#0-9a-z]{1,10})\,([0-9]{1,2})\](.+?)\[\/glow\]/is",

"/\[code\](.+?)\[\/code\]/is",

"/\[list\](.+?)\[\/list\]/Uis",

"/\[list=([aA1iI])\](.+?)\[\/list\]/Uis",

"/\[\*\](.*?)/i",

);

$replacement=array(

'＜b＞\\1＜/b＞',

'＜i＞\\1＜/i＞',

'＜u＞\\1＜/u＞',

'＜font face="\\1"＞\\2＜/font＞',

'＜font color="\\1"＞\\2＜/font＞',

'＜font size="\\1"＞\\2＜/font＞',

'＜img src=images/Emaillink.gif title="电子邮件"

align=absmiddle border=0 height=14＞＜a href="mailto:\\1"＞\\2＜/a＞',

'＜img src=images/Emaillink.gif title="电子邮件"

align=absmiddle border=0 height=14＞＜a href="mailto:\\1"＞\\1＜/a＞',

'＜img src=images/Hyperlink.gif title="超级链接"

align=absmiddle border=0 height=14＞＜a href="\\1"target=_blank＞\\2＜/a＞',

'＜img src=images/Hyperlink.gif title="超级链接"

align=absmiddle border=0 height=14＞＜a href="http://www.\\1\"target=_blank＞\\1＜/a＞',

'＜img src=images/Hyperlink.gif title="超级链接"

align=absmiddle border=0 height=14＞＜a href="\\1"target=_blank＞\\1＜/a＞',

'＜marquee width=90%behavior=alternate scrollamount=3＞\\1＜/marquee＞',

'＜marquee scrollamount=3＞\\1＜/marquee＞',

'＜div align=\\1＞\\2＜/div＞',

'＜table width=*＞＜tr＞

＜td style="filter:shadow(color=\\1,direction=\\2,strength=\\3)"

＞\\4＜/td＞＜/tr＞＜/table＞',

'＜table width=*＞＜tr＞＜td style="filter:glow(color=\\1,strength=\\2)"

＞\\3＜/td＞＜/tr＞＜/table＞',

'＜blockquote＞＜img src=images/Script.gif title="代码"align=absmiddle border=0 height=14＞

＜b＞代码:＜/b＞

＜hr color=#990000＞＜font face="Courier New"＞\\1＜/font＞＜hr color=#990000＞＜/blockquote＞',

'＜ul＞\\1＜/ul＞',

'＜ol type=\\1＞\\2＜/ol＞',

'＜li＞\\1＜/li＞',

);

$d=stripslashes($d);

$d=preg_replace($pattern,$replacement,$d);

//图像和Flash

$d=preg_replace

(

"/\[img\]\s*(http:\/\/\S+?)\s*\[\/img\]/is",

"＜a href=\\1 target=_blank title=\"贴图：点击放大查看\"＞＜img src=\\1 border=0

onload=\"javascript:if(this.width＞520)this.width=520;\"＞＜/a＞",

$d

);

//Flash

$d=preg_replace

(

"/\[flash\]\s*(http:\/\/\S+?)\s*\[\/flash\]/is",

'＜object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"width="80%"

codebase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,

29,0＞＜param name="movie"value="\\1"＞＜param name="quality"value="high"＞＜embed

src="\\1"quality="high"pluginspage="http://www.macromedia.com/go/getflashplayer"

type="application/x-shockwave-flash"width="80%"＞＜/embed＞＜/object＞',

$d

);

return$d;

}

?＞

此程序是把输入及输出的数据转化成HTML，将其显示到页面中，其中包括电子邮件和超级链接、图像、Flash等。

注意　此程序是当程序中不允许使用HTML语法的情况下，通过UBB特殊转换程序，转换成HTML。

17.4　留言列表页面

留言列表页面是把留言板中的留言信息都显示在页面中，包括留言板的共用头部页面、共用尾部页面、操作数据库程序、转换程序等，也就是把所有的模块结合到一起。程序的模块代码如下所示。

（1）引用文件部分。此部分是把留言列表页面中使用到的其他页面程序引用到此页面中。引用其他页面的代码如下所示：

include"17-4.php";

include"17-5.php";

include"17-1.php";

include"17-2.php";

此代码是把留言板程序中的操作数据库配置文件、UBBCode转换为HTML，将留言板的头部显示页面、共用尾部页面引用到此程序中，实现留言列表与数据库的连接及代码的转换和留言板的共用头部页面和共用尾部页面。

注意　引用文件的位置应该合适，例如引用共用尾部页面，就应该把引用共用尾部的代码放在页面的最后，这样才能实现理想的页面。

（2）留言列表的查询功能。此功能是在留言列表页面中进行查询的功能，帮助用户快速地查找用户需要的内容。此功能的代码如下所示：

$each_page=EACH_PAGE;//每页最多显示留言数

$offset=intval($_GET['offset']);//记录偏移量

$keyword=$_GET['keyword'];//关键字，用于留言搜索

/*构造检索条件*/

if($keyword)

{

$where="content LIKE'%$keyword%'OR revort LIKE'%$keyword%'";

$title="搜索结果";

}

else

{

$where="1=1";

$title="最新留言";

}

/*总记录数*/

$sql="SELECT Count(*)FROM guestbook WHERE$where";

$result=mysql_query($sql);

$row=mysql_fetch_row($result);

$total=$row[0];

//规范$offset

if($offset＜0)

$offset=0;

elseif($offset＞$total)

$offset=$total;

$result=mysql_query($sql);

/*查询当前页记录*/

$sql="SELECT*FROM guestbook WHERE$where ORDER BY id DESC

LIMIT$offset,$each_page";

$result=mysql_query($sql);

/*/查询的记录数*/

$numrows=mysql_num_rows($result);

?＞

＜script＞

function vaildForm(obj)

{

if(obj.keyword.value==''||obj.keyword.value.length＜3)

{

alert('您没有填写搜索关键词，或者您的关键词太短！\n请重新填写至少3个字符。');

return false;

}

else

{

return true;

}

}

＜/script＞

此代码中包括了设置留言列表页面，用于显示留言的条数及对查询关键字的判断。设置留言列表的显示条数就是指定留言列表的显示留言内容的个数。而判断查询关键字就是对查询关键字的设置，如关键字的长度、不能为空等。

（3）其他代码。其他代码中包括留言板的布局部分，如代码17.6所示。

代码17.6　留言列表程序：17-6.php

＜?php

/************************/

/*文件名：17-6.php

/*说明：留言列表

/************************/

//引用部分

//留言列表的查询功能

?＞

＜!--标题--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730 class=TitleBar＞

＜tr＞

＜td class=TitleBar_L＞＜/td＞

＜td class=TitleBar_T＞≡＜?php echo$title?＞≡＜/td＞

＜td class=TitleBar_R＞＜/td＞

＜/tr＞

＜/table＞

＜?php

if($numrows＞0)

{

$tmp=0;

/*循环遍历数组，输出列表*/

while($data=mysql_fetch_array($result))

{

$tmp++;

/*表格背景样式*/

$bg_style=($tmp%2)+1;

$id=$data['id'];//留言ID

$hide=$data['hide'];//是只有管理员阅读

$name=$data['name'];//用户名

$gender=($data['gender'])?'男':'女';//性别

$email=$data['email'];//电子邮件地址

$homepage=$data['homepage'];//主页

$face=$data['face'];//头像

$oicq=$data['oicq'];//OICQ号码

$ip=$data['ip'];//IP地址

$time=$data['time'];//发布时间

$content=nl2br(ubbcode($data['content']));//发布内容

if($data['revort'])

{

$retime=$data['retime'];//回复时间

$revort=nl2br(ubbcode($data['revort']));//回复内容

}

?＞

＜!--留言内容，开始--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="TextBox_＜?php echo

$bg_style?＞"＞

＜tr＞

＜td width="5"rowspan="4"class="Border_L"＞＜/td＞

＜td height="1"class="BgLine"＞＜/td＞

＜td width="5"rowspan="4"class="Border_R"＞＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜tr＞

＜td valign="top"＞

＜table border="0"width="100%"cellspacing="0"cellpadding="0"＞

＜tr＞

＜td valign="top"width="144"＞＆nbsp;

＜div align="center"＞

＜strong＞＜?php echo$name?＞＜/strong＞＜br＞

＜br＞

＜img src="images/face/＜?php echo$face?＞.gif"border=0 width=100 height=100＞

＜br＞

＜br＞性别:＜?php echo$gender?＞＜br＞

＜br＞

＜/div＞

＜/td＞

＜td width="1"class="bgLine"＞＜/td＞

＜td valign="top"width="575"＞＆nbsp;

＜img alt="5345@et.com"border=0 src="images/email.gif"width=16 height=16＞

＜a href="mailto:＜?php echo$email?＞"＞信箱＜/a＞

＜img alt="＜?php echo$email?＞"src="images/home.gif"border=0 width=16 height=16＞

＜a href="＜?php echo$homepage?＞"target=_blank＞主页＜/a＞

＜img alt="IP地址:＜?php echo$ip?＞"border=0 src="images/ip.gif"width=16

height=15＞地址

＜img alt="＜?php echo$time?＞"border=0 src="images/time.gif"width=16 height=16＞发表时间：

＜?php echo$time?＞

＜?php if($_SESSION['isAdmin']){?＞

＜img src="images/revert.gif"border=0＞＜a href="17-11.php?id=＜?php echo$id?＞"＞回复＜/a＞

＜img src="images/delete.gif"border=0＞＜a href="delete.php?id=＜?php echo$id?＞"

OnClick="JavaScript:if(confirm('确实要删除这条留言吗？'))return true;else

return false;"＞删除＜/a＞

＜?php}?＞

＜hr align="left"width="70%"size="1"noshade＞

＜!--start Text--＞

＜table border="0"width="96%"cellspacing="4"cellpadding="4"＞

＜tr＞

＜td class="booktext"＞＜div class="booktext"＞

＜?php

if($_SESSION['isAdmin']||!$hide)

{

echo$content;

}else{

echo"＜b＞这是一条悄悄话，只有管理员能看＜/b＞";

}

?＞

＜/div＞＜/td＞

＜/tr＞

＜/table＞

＜!--end Text--＞＜/td＞

＜/tr＞

＜?php

//如果有回复信息

if($revort){

?＞

＜tr＞

＜td valign="top"align="center"＞

＜hr align="right"width="80%"size="1"noshade＞

版主回复＜br＞

＜?php echo$retime?＞＜/td＞

＜td width="1"class="bgLine"＞＜/td＞

＜td valign="top"＞

＜hr align="left"width="80%"size="1"noshade＞

＜!--回复内容--＞

＜table border="0"width="96%"cellspacing="4"cellpadding="4"class="booktext"＞

＜tr＞

＜td class="Revert"＞＜?php echo$revort?＞＜/td＞

＜/tr＞

＜/table＞

＜/td＞

＜/tr＞

＜?php}?＞

＜/table＞＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜/table＞

＜!--留言内容，结束--＞

＜?php

}//endforeach

}else{//endif

?＞

＜h3＞暂时没有留言＜/h3＞

＜?php

}

?＞

＜!--底边--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="Hemline"＞

＜tr＞

＜td class="Hemline_L"＞＜/td＞

＜td class="Hemline_T"＞＜img style="width:1;height:0"＞＜/td＞

＜td class="Hemline_R"＞＜/td＞

＜/tr＞

＜/table＞

＜!--搜索和分页框--＞

＜table width=730 border=0 cellspacing=0 cellpadding=0 height=34＞

＜tr＞

＜td nowrap width=100＞

＜table border=0 cellspacing=0 cellpadding=0＞

＜form action="17-6.php"method=GET

OnSubmit="return vaildForm(this)"＞

＜tr＞

＜td nowrap＞＆nbsp;搜索：

＜input class=text size=13 name="keyword"value="＜?php echo htmlspecialchars($keyword)?＞"＞

＆nbsp;＜/td＞

＜/tr＞

＜/form＞

＜!--搜索框结束--＞

＜/table＞

＜/td＞

＜td align=right nowrap＞

＜!--分页内容--＞

＜p＞共＜font color=red＞＜b＞＜?php echo$total?＞＜/b＞＜/font＞条记录＆nbsp;＜b＞

＜?php

//为分页准备

$last_offset=$offset-$each_page;

if($last_offset＜0)

{

?＞前一页＜?php

}else{

?＞＜a href="?offset=＜?php echo$last_offset?＞＆keyword=＜?php echo$keyword?＞"＞前一页＜/a＞＜?php

}

echo"＆nbsp;";

$next_offset=$offset+$each_page;

if($next_offset＞=$total)

{

?＞后一页＜?

}else{

?＞＜a href="?offset=＜?php echo$next_offset?＞＆keyword=＜?php echo$keyword?＞"＞后一页＜/a＞＜?php

}

?＞

＜/td＞

＜/tr＞

＜/table＞

＜?php

include"17-2.php";

?＞

此程序中把一些模块调用进来，包括留言板的共用头部页面、共用尾部页面、操作数据库程序、转换程序以及管理员登录等。调用模块的语句如include""；。在此程序中也定义了分页显示，每个页面中只显示5条记录，如果大于5条记录，程序将会自动显示在第2页面中。程序的运行效果如图17.3所示。

图　17.3　留言列表运行效果图

注意　在程序中调用了其他模块，要注意调用的位置。

上面的程序中调用了发布留言表单页面、管理员登录表单页面、管理员回复表单页面等程序，接下来介绍留言表单页面。

17.5　发表留言程序

留言板的目的就是接收用户的留言信息，为了实现这一目的，笔者在留言板中设计了用户发表留言模块，用来让文件浏览者留下宝贵的意见。发表留言模块分为发表留言程序和发表留言操作程序两部分。

17.5.1　留言表单页面

留言表单页面的作用就是接收用户的留言，然后把用户的留言提交到留言操作程序。以实现用户和管理员的一个信息的交流窗口。下面介绍留言表单页面是如何实现的，程序如代码17.7所示。

代码17.7　签写留言的表单页面程序：17-7.php

＜?php

/**********************************/

//名称：17-7.php

//功能：签写留言的表单页面

/**********************************/

include"17-4.php";

include"17-1.php";

?＞

＜!--标题--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730 class=TitleBar＞

＜tr＞

＜td class=TitleBar_L＞＜/td＞

＜td class=TitleBar_T＞≡签写留言≡＜/td＞

＜td class=TitleBar_R＞＜/td＞

＜/tr＞

＜/table＞

＜!--留言输入框开始--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="TextBox_1"＞

＜tr＞

＜td width="5"rowspan="4"class="Border_L"＞＜/td＞

＜td height="1"class="BgLine"＞＜/td＞

＜td width="5"rowspan="4"class="Border_R"＞＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜tr＞

＜td valign="top"＞

＜table border=0 cellpadding=0 cellspacing=0 width=100%＞

＜form method=POST name="form1"action="17-8.php"id="form1"onsubmit="return vaildForm();"＞

＜tr＞

＜td width=199 align=center＞

＜img id="imgFace"height=100 width=100 alt="选择一个头像"src="images/face/1.gif"/＞

＜p＞

＜/p＞

＜p＞性别：

＜select size=1 name="gender"＞

＜option value=1 selected＞帅哥＜/option＞

＜option value=0＞美眉＜/option＞

＜/select＞

＜/p＞

＜/td＞

＜td width=1 class=bgLine＞＜/td＞

＜td width=520 align=right＞

＜!--左侧表格开始--＞

＜table border=0 cellpadding=2 cellspacing=2 width=97%＞

＜tr＞

＜td＞姓名：＜/td＞

＜td＞＜input type=text class=text name="name"size=24 maxlength=15 value=""＞

＜font class=insist＞*＜/font＞

＜/td＞

＜td nowrap＞邮件：＜/td＞

＜td＞＜input type=text class=text name="email"size=24

maxlength=50 value=""＞＜/td＞

＜/tr＞

＜tr＞

＜td＞主页：＜/td＞

＜td＞＜input type=text class=text name="homepage"size=24 value=""＞＜/td＞

＜td＞OICQ：＜/td＞

＜td＞＜input type=text class=text name="oicq"size=24 maxlength=15

value=""＞＜/td＞

＜/tr＞

＜tr＞

＜td nowrap＞密语：＜/td＞

＜td colspan=3＞

＜input type=checkbox name="hide"value=ON＞

＜label for=checkbox＞悄悄话，只有管理员可见呀。＜/label＞

＜/td＞

＜/tr＞

＜tr＞

＜td valign=top＞留言：＜/td＞

＜td colspan=3＞

＜textarea name="content"id="content"rows=10 style="width:410;

height:200"＞＜/textarea＞

＜font class=insist＞*＜/font＞＜/td＞

＜/tr＞

＜tr＞

＜td＞＜/td＞

＜td colspan=3＞

＜input class=button type="submit"value="提交留言"name="submit"＞

＜input class=button type="reset"value="全部重写"＞＜/td＞

＜/tr＞

＜/table＞

＜!--左侧表格结束--＞

＜/td＞

＜/tr＞

＜/form＞

＜/table＞

＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜/table＞

＜!--留言输入框结束--＞

＜Script language="JavaScript"＞

//表单

var oForm=document.forms[0];

function vaildForm()

{

if(oForm.name.value==""||execRE("^[\n\t\r\0\x0B]+$",oForm.name.value))

{

alert('您的昵称没有填写！');

return false;

}

else if(!execRE("^[-a-zA-Z0-9_\u0391-\uFFE5]+$",oForm.name.value))

{

alert('您的昵称不能包含非法字符！');

return false;

}

else if(oForm.content.value==""||execRE("^[\n\t\r\0\x0B]+$",

oForm.content.value))

{

alert('您的留言内容不能留空白！');

return false;

}

else if(oForm.email.value＆＆

!execRE("[-a-z0-9_\.]+\@([0-9a-z][-a-z0-9_]+\.)+[a-z]{2,3}$",oForm.email.value))

{

alert('您的邮件地址填写不规范！');

return false;

}

else if(oForm.page.value＆＆!execRE("^http://",oForm.page.value))

{

alert('您的主页地址填写不规范！');

return false;

}

else if(oForm.oicq.value＆＆!execRE("^[0-9]{5,14}$",oForm.oicq.value))

{

alert('您的OICQ填写不规范！');

return false;

}

else

{

return true;

}

}

//--＞

＜/Script＞

＜!--底边--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="Hemline"＞

＜tr＞

＜td class="Hemline_L"＞＜/td＞

＜td class="Hemline_T"＞＜img style="width:1;height:0"＞＜/td＞

＜td class="Hemline_R"＞＜/td＞

＜/tr＞

＜/table＞

＜?php

include"17-2.php";

?＞

此程序中分为5个部分，其中包括操作数据库部分、共用头部页面部分、标题部分、表单部分以及共用尾部页面部分。操作数据库部分、共用头部页面部分、共用尾部页面部分是通过调用语句调用的。表单部分是通过脚本语句判断是否合法。程序的运行效果如图17.4所示。

图　17.4　留言表单页面运行的效果图

注意　程序在设置性别时，提交的值只有1和2，并不是把“男”或“女”提交到留言表单的处理页面。

17.5.2　发布留言操作程序

上面介绍了留言的表单页面，那么表单页面把数据提交到发布留言操作程序。发布留言操作程序就要把提交过来的数据写入到数据库，程序如代码17.8所示。

代码17.8　签写留言的处理程序：17-8.php

＜?php

/********************************/

/*名称：17-8.php

/*功能：签写留言的处理程序

/********************************/

require_once'17-4.php';

$errmsg='';//错误信息

if(getenv('HTTP_CLIENT_IP'))//获取用户IP地址

{

$ip=getenv('HTTP_CLIENT_IP');

}

elseif(getenv('HTTP_X_FORWARDED_FOR'))

{

$ip=getenv('HTTP_X_FORWARDED_FOR');

}

elseif(getenv('REMOTE_ADDR'))

{

$ip=getenv('REMOTE_ADDR');

}

else

{

$ip=$_SERVER['REMOTE_ADDR'];

}

/*悄悄话部分*/

$hide=($_POST['hide'])?1:0;

$name=$_POST['name'];//用户名

$gender=($_POST['gender'])?1:0;//性别

$email=$_POST['email'];//电子邮件地址

$homepage=$_POST['homepage'];//个人主页

$face=$_POST['face'];//代表头像

$oicq=$_POST['oicq'];//OICQ

$content=$_POST['content'];//留言内容

if(trim($name,"\n\t\r\0\x0B")=="")//判断输入的正确性

{

$errmsg="您的昵称没有填写！\n请重新填写。";

}

elseif(!eregi("^[-a-zA-Z0-9_\x7f-\xff]+$",$name))

{

$errmsg="您的昵称包含非法字符！\n昵称只能由字母、数字或汉字组成。";

}

elseif(strlen($name)＞16)

{

$errmsg="您的昵称填写不规范！\n昵称最多只能包含16字节。";

}

elseif($email＆＆!eregi('[-a-z0-9_\.]+\@([0-9a-z][-a-z0-9_]+\.)+[a-z]{2,3}$',$email))

{

$errmsg="您的邮箱地址填写不规范！\n请正确填写您的常用邮箱地址。";

}

elseif($oicq＆＆!ereg('^[0-9]{5,14}$',$oicq))

{

$errmsg="您的OICQ号码填写不规范！\n请正确填写您的OICQ号码。";

}

elseif($homepage＆＆!eregi('^http://',$homepage))

{

$errmsg="您的主页地址填写不规范！\n主页地址必须以"http://"开头。";

}

elseif(trim($content,"\n\t\r\0\x0B")=="")

{

$errmsg="您的留言内容不能留空白！\n请重新填写。";

}

elseif(strlen($content)＞5000)

{

$errmsg="您的留言内容太长了！\n您要把留言本撑爆呀？";

}

if($errmsg)

{

?＞

＜!--弹出错误信息框--＞

＜script＞

alert("＜?php echo str_replace("\n",'\n',$errmsg);?＞");

history.back();

＜/script＞

＜?php

}

else

{

$sql="INSERT INTO guestbook(hide,name,gender,email,homepage,

oicq,face,ip,time,content)

VALUES('$hide','$name','$gender','$email','$homepage',

'$oicq','$face','$ip',NOW(),'$content')";

mysql_query($sql);

$errmsg="留言发表成功！";

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("＜?php echo str_replace("\n",'\n',$errmsg);?＞");

location.href="17-6.php";

＜/script＞

＜?php

}

?＞

此程序先对提交的数据信息进行判断，如果用户提交的信息是合法的，程序将会执行$sql="INSERT INTO guestbook(hide,name,gender,email,homepage,oicq,face,ip,time,content)VALUES('$hide','$name','$gender','$email','$homepage','$oicq','$face','$ip',NOW(),'$content')"；数据库操作语句，完成用户的留言；如果用户提交的信息不是合法的信息，将不会写入到数据库中。

注意　数据库操作语句中的字段与字段值要一一对应。

17.6　管理员的登录

管理员登录的实现是为了方便留言板的维护，管理员登录后可以对留言板的所有留言进行操作，例如修改留言、删除留言等操作。也就是说管理员具有最高的权限。

17.6.1　管理员登录页面

管理员登录页面就是实现获取管理权限的一个过程，当管理员成功地登录后，系统会自动为管理员分配相应的管理权限。本程序是接收用户输入的用户名和密码，并将其提交到登录处理页面，程序如代码17.9所示。

代码17.9　管理员登录页面程序：17-9.php

＜?php

/*************************/

/*名称：17-9.php*/

/*功能：管理员登录页面*/

/*************************/

include"17-4.php";

include"17-1.php";

?＞

＜Script language="JavaScript"＞

＜!--//

var oForm=document.forms[0];

function vaildForm()

{

if(oForm.user_name.value=="")

{

alert('您的管理账号没有填写！');

return false;

}

else if(oForm.user_pass.value=="")

{

alert('您的管理密码没有填写！');

return false;

}

else

{

return true;

}

}

//--＞

＜/Script＞

＜!--标题--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730 class=TitleBar＞

＜tr＞

＜td class=TitleBar_L＞＜/td＞

＜td class=TitleBar_T＞≡管理员登录≡＜/td＞

＜td class=TitleBar_R＞＜/td＞

＜/tr＞

＜/table＞

＜!--登录框--＞

＜table border="0"cellpadding="0"cellspacing="0"width="100%"＞

＜form method=POST action="17-10.php"id="form1"onsubmit="return vaildForm();"＞

＜tr＞

＜td height="18"colspan="2"width="715"＞＜/td＞

＜/tr＞

＜tr＞

＜td width="40%"align="right"＞账号：＜/td＞

＜td width="60%"＞＜input type="text"class="text"name="user_name"size="20"style="width:

120"＞＜/td＞

＜/tr＞

＜tr＞

＜td height="5"colspan="2"width="715"＞＜/td＞

＜/tr＞

＜tr＞

＜td width="40%"align="right"＞密码：＜/td＞

＜td width="60%"＞

＜input type="password"class="text"name="user_pass"size="20"style="width:120"＞

＜/td＞

＜/tr＞

＜tr＞

＜td colspan="2"align="center"height="60"＞

＜input type="submit"value="进入"class="button"name="submit"＞

＜/td＞

＜/tr＞

＜/table＞

＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜/table＞

＜!--底边--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="Hemline"＞

＜tr＞

＜td class="Hemline_L"＞＜/td＞

＜td class="Hemline_T"＞＜img style="width:1;height:0"＞＜/td＞

＜td class="Hemline_R"＞＜/td＞

＜/tr＞

＜/table＞

＜?php

include"17-2.php";

?＞

此程序通过3个表单子框，接收用户输入的账号和密码，然后把表单的内容通过post方法，提交到登录的处理页面，这就是登录页面的作用。程序的运行效果如图17.5所示。

图　17.5　登录页面运行效果图

注意　此程序对账号和密码的表单先进行判断，判断是否为空，然后提交到处理页面进行合法性的判断。

17.6.2　管理员登录处理页面

管理员登录处理页面的作用是，把管理员登录表单页面中的数据提交到管理员的此页面，管理员处理页面将把程序中的管理员的账号和密码取出，与提交的管理员账号和密码进行比较，如果相同，就会进入管理页面；如果不相同，则不会进入管理页面，此时会提示账号或密码错误。管理员登录的处理页面的代码如代码17.10所示。

代码17.10　管理员登录处理程序：17-10.php

＜?php

/********************************/

/*名称：17-10.php

/*功能：管理员登录处理程序

/********************************/

include"17-4.php";

if(isset($_POST['user_name']))//用户登录

{

/*判断用户登录信息与定义是否相同*/

if($_POST['user_name']==ADMIN_USER＆＆$_POST['user_pass']==ADMIN_PASS)

{

$_SESSION['isAdmin']=1;

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("欢迎管理员登录。");

location.href="17-6.php";

＜/script＞

＜?php

exit;

}

else

{

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("用户名或者密码错误，请重试。");//用户名密码错误

location.href="17-9.php";

＜/script＞

＜?php

exit;//退出登录

}

}

if(isset($_GET['logout'])＆＆$_GET['logout'])

{

unset($_SESSION['isAdmin']);

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("成功退出登录。");

location.href="17-9.php";

＜/script＞

＜?php

exit;

}

?＞

此程序中，判断用户输入的账号和密码的语句是$_POST['user_name']==ADMIN_USER＆＆$_POST['user_pas']==ADMIN_PASS。如果相同，程序通过脚本弹出信息提示对话框“欢迎管理员登录”；如果是错误的，就会提示“用户名或者密码错误，请重试”。成功登录后的提示如图17.6所示。

图　17.6　成功登录的运行效果图

注意　在判断登录管理员账号和密码时，判断语句中账号和密码间的关系是“＆＆”，而不是“||”。

17.7　管理员的回复程序

为了使管理员和浏览者进行交流，笔者在留言板中增加了管理员的回复模块。管理员可以对浏览者的所有留言进行回复。

17.7.1　管理员回复表单页面

管理员回复表单页面是管理员与用户间交流时，发表回复的一个表单页面。然后管理员回复表单页面，把回复的内容提交到管理员的回复处理页面。例如用户在此留言板提出问题，管理员通过管理员的回复表单页面进行回答，程序如代码17.11所示。

代码17.11　管理员回复页面程序：17-11.php

＜?php

/****************************/

/*名称：17-11.php*/

/*功能：管理员回复页面*/

/****************************/

include"17-4.php";

include"17-5.php";

include"17-1.php";

if(!$_SESSION['isAdmin'])//如果不是管理员，则退出

{

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("你不是管理员，请退出该页。");

location.href="17-6.php";

＜/script＞

＜?php

exit;//退出

}

$id=intval($_GET['id']);

$sql="SELECT*FROM guestbook WHERE id=$id";

$result=mysql_query($sql);

$numrows=mysql_num_rows($result);

?＞

＜script＞

function vaildForm(obj)//方法定义

{

if(obj.keyword.value==''||obj.keyword.value.length＜3)

{

alert('您没有填写搜索关键词，或者您的关键词太短！\n请重新填写至少3个字符。');

return false;

}

else

{

return true;

}

}

＜/script＞

＜!—表格部分--＞

＜table border=0 cellpadding=0 cellspacing=0 width=730 class=TitleBar＞

＜tr＞

＜td class=TitleBar_L＞＜/td＞

＜td class=TitleBar_T＞≡回复留言≡＜/td＞

＜td class=TitleBar_R＞＜/td＞

＜/tr＞

＜/table＞

＜?php

if($numrows＞0)

{

//获取留言记录

$data=mysql_fetch_array($result);

$id=$data['id'];//留言ID

$hide=$data['hide'];//是只有管理员阅读

$name=$data['name'];//用户名

$gender=($data['gender'])?'男'：'女';//性别

$email=$data['email'];//电子邮件地址

$homepage=$data['homepage'];//主页

$face=$data['face'];//头像

$oicq=$data['oicq'];//OICQ号码

$ip=$data['ip'];//IP地址

$time=$data['time'];//发布时间

$content=nl2br(ubbcode($data['content']));//发布内容

if($data['revort'])

{

$retime=$data['retime'];

$revort=$data['revort'];

}

?＞

＜!--Frame start here--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="TextBox_1"＞

＜tr＞

＜td width="5"rowspan="4"class="Border_L"＞＜/td＞

＜td height="1"class="BgLine"＞＜/td＞

＜td width="5"rowspan="4"class="Border_R"＞＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜tr＞

＜td valign="top"＞

＜table border="0"width="100%"cellspacing="0"cellpadding="0"＞

＜tr＞

＜td valign="top"width="144"＞＆nbsp;

＜div align="center"＞＜strong＞＜?php echo$name?＞＜/strong＞＜br＞

＜br＞

＜img src="images/face/＜?php echo$face?＞.gif"border=0 width=100 height=100＞

＜br＞

＜br＞

性别：＜?php echo$gender?＞＜br＞

＜br＞

＜/div＞＜/td＞

＜td width="1"class="bgLine"＞＜/td＞

＜td valign="top"width="575"＞＆nbsp;

＜img alt="5345@et.com"border=0 src="images/email.gif"width=16 height=16＞

＜a href="mailto:＜?php echo$email?＞"＞信箱＜/a＞

＜img alt="＜?php echo$email?＞"src="images/home.gif"border=0 width=16 height=16＞

＜a href="＜?php echo$homepage?＞"target=_blank＞主页＜/a＞

＜img alt="IP地址:＜?php echo$ip?＞"border=0 src="images/ip.gif"width=16 height=15＞地址

＜img alt="＜?php echo$time?＞"border=0 src="images/time.gif"width=16 height=16＞

发表时间：

＜?php echo$time?＞

＜?php if($_SESSION['isAdmin']){?＞

＜img src="images/delete.gif"border=0＞＜a href="delete.php?id=＜?php echo$id?＞"

OnClick="JavaScript:if(confirm('确实要删除这条留言吗？'))return true;else return false;"

＞删除＜/a＞

＜?php}?＞

＜hr align="left"width="70%"size="1"noshade＞

＜!--start Text--＞

＜table border="0"width="96%"cellspacing="4"cellpadding="4"＞

＜tr＞

＜td class="booktext"＞＜div class="booktext"＞＜?php echo$content?＞＜/div＞＜/td＞

＜/tr＞

＜/table＞

＜!--end Text--＞＜/td＞

＜/tr＞

＜tr＞

＜td valign="top"align="center"＞

＜hr align="right"width="80%"size="1"noshade＞

版主回复

＜br＞

＜?php echo$retime?＞

＜/td＞

＜td width="1"class="bgLine"＞＜/td＞

＜form action="17-12.php"method="post"＞

＜td valign="top"＞

＜hr align="left"width="80%"size="1"noshade＞

＜textarea name="revort"rows=10

style="width:400;height:200"＞＜?php echo htmlspecialchars($revort)?＞＜/textarea＞

＜input type="submit"value="立即回复"/＞

＜input type="hidden"name="id"value="＜?php echo$id?＞"/＞

＜/td＞

＜/form＞

＜/tr＞

＜/table＞＜/td＞

＜/tr＞

＜tr＞

＜td height="8"＞＜/td＞

＜/tr＞

＜/table＞

＜!--Frame close here--＞

＜?php

}else{//endif

?＞

＜h3＞留言不存在，或者已经被删除！＜/h3＞

＜?php

}

?＞

＜!--底边--＞

＜table border="0"cellpadding="0"cellspacing="0"width="730"class="Hemline"＞

＜tr＞

＜td class="Hemline_L"＞＜/td＞

＜td class="Hemline_T"＞＜img style="width:1;height:0"＞＜/td＞

＜td class="Hemline_R"＞＜/td＞

＜/tr＞

＜/table＞

＜!--搜索和分页框--＞

＜table width=730 border=0 cellspacing=0 cellpadding=0 height=34＞

＜tr＞

＜td nowrap width=100＞＜table border=0 cellspacing=0 cellpadding=0＞

＜!--搜索框--＞

＜form action="17-6.php"method=GET OnSubmit="return vaildForm(this)"＞

＜tr＞

＜td nowrap＞＆nbsp;搜索：

＜input class=text size=13 name="keyword"value="＜?php echo htmlspecialchars($keyword)?＞"＞

＆nbsp;＜/td＞

＜/tr＞

＜/form＞

＜/table＞＜/td＞

＜td align=right nowrap＞＆nbsp;

＜/td＞

＜/tr＞

＜/table＞

＜?php

include"17-2.php";

?＞

此程序分为3个部分，分别为留言表单部分、显示留言内容部分、站内搜索部分。留言表单部分是管理员输入回复内容的提交页面。显示留言内容部分是把留言板中的留言内容显示到此页面。程序的运行效果如图17.7所示。

图　17.7　管理员回复处理页面运行效果图

注意　此页面的运行效果只能在管理员登录后才正常显示。如果没有登录会提示用户登录。

17.7.2　管理员回复操作程序

管理员回复操作程序是指把管理员的回复内容写入数据库，并把留言内容及回复内容返回到留言列表页面中。对数据库的操作语句是UPDATE guestbook SET revort='$_POST[revort]'，retime=NOW()WHERE id=$_POST[id]，通过这条语句把回复内容写入到数据库。程序如代码17.12所示。

代码17.12　管理员回复留言处理程序：17-12.php

＜?php

/**********************************/

/*名称：17-12.php*/

/*功能：管理员回复留言处理*/

/**********************************/

require_once'17-4.php';

if(!$_SESSION['isAdmin'])//如果不是管理员，则退出

{

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("你不是管理员，请退出该页。");

location.href="17-6.php";

＜/script＞

＜?php

exit;

}

$sql="UPDATE guestbook SET revort='$_POST[revort]',retime=NOW()

WHERE id=$_POST[id]";

$result=mysql_query($sql);

$num=mysql_affected_rows($db);//判断记录是否被更新

if($num＞0)

$errmsg="留言回复成功！";

else

$errmsg="留言回复失败！";

?＞

＜!--弹出信息对话框--＞

＜script＞

alert("＜?php echo$errmsg?＞");

location.href="17-6.php";

＜/script＞

＜?php

exit;

?＞

此程序先用一个条件判断语句判断管理员是否登录，如果没有登录，就会提示“不是管理员，退出此页面”；如果管理已经登录，就会提示回复成功。

注意　判断记录是否被更新，如果没有更新就会提示“留言回复成功”，否则提示“留言回复失败”。

17.8　设计首页

首页就是把所有程序集合的程序，把所有分散的程序结合到一起，进行协助的一个工作过程，下面介绍一下首页的代码，如代码17.13所示。

代码17.13　首页程序：17-13.php

＜?php

//*******************************/

//名称：17-13.php

//功能：首页

//******************************/

header("Location:17-6.php");

?＞

此程序中只有一条语句，就是header（"Location：17-6.php"），它将17-6.php程序的内容显示到首页上。这个比较简单，就不做过多的介绍。这样一个留言板就全部完成了，如果读者觉得不太美观，可以用图片等做一下完善。

17.9　小结

通过对本章节的学习，用户要知道如何实现一个PHP留言板。本章节中所需要掌握的内容如下。

❑数据库设计。

❑如何实现用户的留言模块及留言数据的处理。

❑如何实现管理员的登录模块程序。

❑如何实现管理员对留言进行回复的模块。

❑如何实现把UBBCode转换为HTML的处理程序。

❑如何显示用户的留言信息及管理员的回复信息。

第18章　新闻发布系统

现今的互联网功能非常强大，可以用它来看新闻、电影、发布信息等。在许多的大型网站上都有新闻发布这一功能，以方便用户的需要。现在就来介绍一下新闻发布系统，本系统具有增加新闻、修改新闻、删除新闻和浏览新闻的功能。但是这个新闻发布系统需要数据库的支持，其主要内容是对数据库的操作。

18.1　数据库准备

本新闻发布系统所使用的数据库是MySQL数据库，用于对新闻发布系统中的信息存储。从前面介绍的MySQL数据库可以知道，数据是存储在数据库中的数据表里。现在笔者就本新闻发布系统的数据库进行设计。首先要创建一个为本系统服务的数据库news，然后进入数据库后，创建一个用于存储新闻发布系统信息的数据表tnews。在这个表中包含3个字段，分别是ID、新闻的标题title、新闻的内容text。

18.1.1　设计数据库

在设计数据库时，使用了MySQL数据库的数据库管理工具phpMyAdmin进行设计。创建数据库news,MySQL数据库数据库管理工具phpMyAdmin的页面如图18.1所示。

图　18.1　创建数据库图

在此页面中创建的一个新的数据库中输入数据库的名字news，然后单击“创建”按钮，这样一个新闻发布系统的数据库就创建成功了，如图18.2所示。

图　18.2　创建数据表图

18.1.2　创建数据表

创建数据表tnews。在图18.2所示的页面中的数据库news里，创建一个新表的表单，输入数据表的名称为tnews，在设置数据表的字段一项number of fields中输入数据表的字段个数为3，然后单击“执行”按钮。这样数据库中的数据表就创建成功了，如图18.3所示。

图　18.3　字段的设计图

18.1.3　设计数据表字段

在图18.3所示的数据表字段的设计页面中，在“字段”文本框中分别输入id、title和text；在“类型”下拉列表框中分别选择int、varchar和text；在数据的长度一栏中，与字段title对应的选项中输入255，其他不用填写；在Null一栏中全部都选择not null；在额外一栏字段id对应的选项中选择AUTO_INCREMENT项；在主键一栏中，选中字段"id"对应的选项。然后单击“保存”按钮，这样数据库中的表就创建成功了。

注意　在设置字段的数据类型时，应选择适合字段的数据类型，如果设置不合理，会影响程序的整体效果。

18.2　添加新闻

在大型网站的新闻发布中，新闻要不断地更新，所以要通过添加新闻的模块来实现。下面就来介绍本新闻发布系统中的添加新闻模块。

18.2.1　添加新闻的代码实现

添加新闻的程序如代码18.1所示，可以添加新闻的标题，也可以添加新闻的内容。所谓添加就是从表单中获取信息，然后把获取的信息使用MySQL数据库中的insert命令写入数据库中的过程。

代码18.1　添加新闻模块的程序：18-1.php

＜html＞

＜!程序名称：18-1.php＞

＜!程序功能：添加新闻＞

＜head＞

＜title＞添加新闻＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜center＞

＜br＞＜br＞

＜?php

$MySQLuser="root";//用户名

$MySQLpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//数据表名

$limit="5";//设置页面显示条数

MySQL_connect('localhost',$MySQLuser,$MySQLpass);//连接语句

MySQL_select_db($dbname);//选择数据库

if($action=="add")

{

$query="insert into$tablename(id,title,text)

values(null,'$title','$text')";

echo$query;

MySQL_query($query);

echo"你的新闻已经增加";

}

else

{

$script=getenv("$SCRIPT_NAME");

?＞

＜form action="18-1.php"method="post"＞

＜input type="hidden"name="action"value="add"＞

新闻标题：＜br＞

＜input type="text"name="title"size=50＞＜br＞＜br＞

新闻内容：＜br＞

＜textarea rows=5 cols=50 name="text"＞

＜/textarea＞

＜br＞

＜input type="submit"value="添加"＞

＜?php

}

?＞

＜/center＞

＜/body＞

＜/html＞

18.2.2　添加新闻的界面效果

上面的程序使用了PHP的数据库操作函数，使程序连接到MySQL数据库news。然后把表单中的数据提交到PHP的表单处理程序，通过条件判断语句进行间断，如果变量action接收到add参数，程序就会使用MySQL数据库的插入命令insert，把获取到的数据写入数据库，程序的运行效果如图18.4所示。

图　18.4　添加新闻程序的运行效果图

在图18.4所示的页面中，输入新闻的标题和新闻的内容后，单击“添加”按钮，如果添加新闻成功，则会弹出图18.5所示的信息反馈。

图　18.5　添加新闻程序的信息反馈图

注意　在本程序中使用了PHP与HTML的嵌套，需要注意的是HTML语句的放置位置。如果放置得不适合，程序会出现意想不到的错误。

18.3　修改新闻

新闻的修改是当用户发现已经添加的新闻中有错误时，可以使用新闻的修改模块来实现对不理想的新闻进行修改。也就是修改数据库中已经记录过的数据。

18.3.1　修改新闻的代码实现

在这里可以使用MySQL数据库中的update命令修改数据表中的内容，程序如代码18.2所示。

代码18.2　修改新闻的程序：18-2.php

＜html＞

＜!程序名称：18-2.php＞

＜!程序功能：修改新闻＞

＜head＞

＜title＞修改新闻＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$MySQLuser="root";//用户名

$MySQLpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//数据表名

$limit="5";//设置页面显示条数

MySQL_connect('localhost',$MySQLuser,$MySQLpass);//连接语句

MySQL_select_db($dbname);//选择数据库

if($action=="edit")//判断值

{

MySQL_query("update$tablename set title='$title'where id='$id'");

MySQL_query("update$tablename set text='$text'where id='$id'");

print"你的新闻已经被修改";

}

else if($action=="view")

{

$get=MySQL_fetch_row(MySQL_query("select*from$tablename where

ID='$id'"));

?＞

＜form action="18-2.php"method="post"＞

＜input type="hidden"name="action"value="edit"＞

＜input type="hidden"name="id"value="＜?php echo"$get[0]";?＞"＞

新闻标题：＜br＞

＜input type="text"name="title"size=50 value="＜?php echo"$get[1]";?＞"＞

＜br＞＜br＞

新闻内容：＜br＞

＜textarea rows=5 cols=50 name="text"＞＜?php echo"$get[2]";?＞

＜/textarea＞

＜input type="submit"value="编辑"＞

＜?php

}

else

{

?＞

＜!—表单部分--＞

＜form action="18-2.php"method="post"＞

＜input type="hidden"name="action"value="view"＞

＜select name="id"size=5＞

＜?php

$get=MySQL_query("select*from$tablename");

while($stuff=MySQL_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";

}

?＞

＜/select＞

＜input type="submit"value="修改"＞

＜?php

}

?＞

＜/center＞

＜/body＞

＜/html＞

程序使用了PHP中数据库的连接函数连接数据库news，通过条件判断语句进行判断。如果条件成立，使用MySQL数据库中的update命令把PHP中获取函数获得的数据重新写入到数据库的数据表中。

注意　在本程序条件判断语句的"if($action=="edit")"条件语句中，“==”相当于数据学运算中的等于号，但不是“=”赋值符号。

18.3.2　修改新闻的界面效果

上面的程序中使用了PHP与HTML的嵌套，运行结果如图18.6所示。在此修改新闻页面中，选择用户要修改的新闻标题，然后单击“修改”按钮，进行新闻标题和内容的修改，如图18.7所示。

图　18.6　修改新闻程序图

图　18.7　修改新闻标题和内容的程序图

在此页面中可以对新闻的标题和新闻的内容进行修改，如果修改完成，单击“编辑”按钮，把已经修改好的新闻标题和新闻内容重新写入数据库的数据表中。

18.4　删除新闻

在一个新闻发布型网站中，如果用户发布的新闻是不良新闻，或网站中很早的旧新闻不再需要时，网站的编辑人员就可以使用删除新闻模块来实现删除功能。

18.4.1　删除新闻的代码实现

删除新闻的程序模块如下面的代码所示。使用时选择需要删除的新闻标题，用MySQL数据库中的删除命令delete把该新闻的标题和新闻的内容删除，同时把数据库中对应的记录也删除，实例代码如代码18.3所示。

代码18.3　删除新闻程序：18-3.php

＜html＞

＜!程序名称：18-3.php＞

＜!程序功能：删除新闻＞

＜head＞

＜title＞删除新闻＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜?php

$MySQLuser="root";//用户名

$MySQLpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//数据表名

$limit="5";//设置页面显示条数

MySQL_connect('localhost',$MySQLuser,$MySQLpass);//连接语句

MySQL_select_db($dbname);//选择数据库

if($action=="delete")//判断值

{

MySQL_query("DELETE FROM$tablename WHERE id='$id'");

print"你的新闻已经被删除。";//删除语句

}

else

{

$script=getenv("SCRIPT_NAME");

?＞

＜!—表单部分--＞

＜form action="18-3.php"method="post"＞

＜input type="hidden"name="action"value="delete"＞

＜select name="id"size=5＞

＜?php

$get=MySQL_query("select*from$tablename");

while($stuff=MySQL_fetch_array($get))

{

print"＜option value=\"$stuff[0]\"＞$stuff[1]\n";

}

?＞

＜/select＞

＜input type="submit"value="删除"＞

＜?php

}

?＞

＜table align=center border=0 width=776＞

＜tbody＞

＜tr＞

＜td align=middle＞

＜br＞

＜br＞

＜hr size="0"width="80%"＞

＜/td＞

＜/tr＞

＜tr align="center"＞

＜/tr＞

＜/tbody＞

＜/table＞

＜/body＞

＜/html＞

程序使用了PHP的数据库操作函数，使程序连接到MySQL数据库news。然后把需要删除的记录信息提交到PHP处理程序，通过条件判断语句进行间断，如果变量action接收到delete参数，程序就会使用MySQL数据库的插入命令delete，把用户需要删除的记录从数据库中删除。

注意　本程序是先进行数据库的查询操作，把网站中的新闻标题显示在页面中，然后用户才可以选择要删除的标题，进行删除操作。

18.4.2　删除新闻的界面效果

删除新闻程序的运行效果如图18.8所示。程序列出了网站中所有新闻的标题，用户可以选择要删除的新闻标题，然后单击“删除”按钮，程序通过PHP的处理模块把新闻从数据库中删除，运行效果如图18.9所示。

图　18.8　删除新闻程序的运行效果图

图　18.9　删除新闻程序的反馈信息图

18.5　浏览新闻

浏览新闻是把用户发布的新闻显示到页面中，供访问者查阅的一个程序模块。本节同前面一样，也是通过后台代码和运行界面两方面进行讲解。

18.5.1　浏览新闻的代码实现

浏览新闻的程序比较简单，就是程序连接到数据库后，使用MySQL数据库中的查询函数从数据表中调出所有新闻的标题和内容并将其显示到页面中，如代码18.4所示。

代码18.4　浏览新闻程序：18-4.php

＜html＞

＜!程序名称：18-4.php＞

＜!程序功能：浏览新闻＞

＜head＞

＜title＞浏览新闻＜/title＞

＜/head＞

＜body bgcolor="#ffffff"text="#000000"＞

＜tbody＞

＜center＞

＜?php

$MySQLuser="root";//用户名

$MySQLpass="123456";//密码

$dbname="news";//数据库名

$tablename="tnews";//数据表名

MySQL_connect('localhost',$MySQLuser,$MySQLpass);//连接语句

MySQL_select_db($dbname);//选择数据库

if($id=="")//判断是否为空

{

if(MySQL_num_rows(MySQL_query("select*from$tablename"))!=0)

{

$get=MySQL_query("select*from$tablename order by id desc");

while($stuff=MySQL_fetch_array($get))

{

print"＜a href=\"18-4.php?id=$stuff[0]\"target=\"_blank\"＞

＜b＞$stuff[1]＜/b＞＜br＞＜/a＞";

}

}

else

{

echo"现在没有新闻";

}

}

else

{

$getnews=MySQL_query("select*from$tablename where id=$id");//查询语句

$result=MySQL_fetch_array($getnews);

echo"＜h1＞$result[1]＜/h1＞";

echo"$result[2]＜br＞＜br＞";

}

?＞

＜/center＞

＜tbody＞

＜/body＞

＜/html＞

此程序使用了PHP的数据库操作函数，使程序连接到MySQL数据库news。然后使用条件语句if...else的嵌套，把数据库中所有的新闻调出并显示到页面中。

注意　使用条件语句if...else的嵌套，把数据库中所有的新闻调出并显示到页面中，如果条件语句if(MySQL_num_rows(MySQL_query("select*from$tablename"))!=0)成立，也就是条件不等于0时，程序将会继续向下执行。如果条件不成立，程序将停止循环。

18.5.2　浏览新闻的界面效果

程序的运行效果如图18.10所示。此程序把网站中的所有新闻显示在页面中，使访问者可以单击页面中的新闻标题就可以进行新闻的阅读，单击页面中的一个新闻标题后，程序将把此新闻对应的内容从数据表中调出，程序的运行效果如图18.11所示。

图　18.10　浏览新闻的程序运行效果图

图　18.11　阅读新闻的程序运行效果图

18.6　小结

本章主要介绍了如何实现一个新闻发布系统，在此新闻发布系统中用到了如下的知识。

❑使用MySQL数据库函数连接MySQL数据库。

❑数据库的操作，如增加记录、修改记录、删除记录等。

相信本章的介绍，将对读者学习如何使用MySQL数据库进行新闻发布及修改、删除等操作有很大的帮助。

第19章　PHP论坛

相信读者们见过的论坛应该不少，那么是否想过自己实现一个PHP论坛呢？本章将介绍如何实现一个论坛。论坛是一个用户与用户之间的交流的平台。PHP论坛的结构流程如图19.1所示。

图　19.1　PHP论坛的结构流程图

从图19.1中可以看出，用户需先注册，注册完成后才可登录，如果是管理员登录可以设置“锁定”和“置顶”，普通的用户只能发布和访问信息。

19.1　数据库准备

下面就为存放PHP论坛信息做一下准备，创建用于存放PHP论坛信息的数据库。数据库可分为以下3个数据表：forum_topic、forum_reply和forum_user，分别用来存放PHP论坛中的用户文章、用户回复的记录和用户信息。创建数据的代码如下所示：

CREATE DATABASE'longt';

这样数据库就创建好了，下面创建数据库中的数据表。此数据库中有3个数据表，创建数据表forum_topic的代码如下所示：

/****************************/

/*表名：forum_topic*/

/*作用：用户文章表*/

/****************************/

CREATE TABLE'forum_topic'

(

'id'INT(10)NOT NULL auto_increment,

'topic'VARCHAR(255)NOT NULL,

'detail'TEXT NOT NULL,

'name'VARCHAR(32)NOT NULL,

'email'VARCHAR(100)NOT NULL,

'datetime'DATETIME NOT NULL default'0000-00-00 00:00:00',

'view'INT(10)NOT NULL default'0',

'reply'INT(10)NOT NULL default'0',

'locked'TINYINT(1)NOT NULL default'0',

'sticky'TINYINT(1)NOT NULL default'0',

PRIMARY KEY('id')

)TYPE=MyISAM;

这样用于存放用户文章的数据表就创建完成了，其中包括有10个字段。创建数据表forum_reply的代码如下所示：

/******************************/

/*表名：forum_reply*/

/*作用：用户回复的记录表*/

/******************************/

CREATE TABLE'forum_reply'

(

'id'INT(10)NOT NULL auto_increment,

'topic_id'INT(10)NOT NULL default'0',

'reply_id'INT(10)NOT NULL default'0',

'reply_name'VARCHAR(32)NOT NULL,

'reply_email'VARCHAR(100)NOT NULL,

'reply_detail'text NOT NULL,

'reply_datetime'DATETIME NOT NULL default'0000-00-00 00:00:00',

PRIMARY KEY('id'),

KEY'a_id'('reply_id')

)TYPE=MyISAM;

这样用于存放用户回复记录的数据表forum_reply就创建完成了。接下来创建数据表forum_user，代码如下所示：

/***************************/

/*表名：forum_user*/

/*作用：用户信息表*/

/***************************/

CREATE TABLE'forum_user'

(

'id'INT(10)NOT NULL AUTO_INCREMENT,

'username'VARCHAR(32)NOT NULL,

'password'VARCHAR(32)NOT NULL,

'email'VARCHAR(100)NOT NULL,

'realname'VARCHAR(50)NOT NULL,

'regdate'DATETIME NOT NULL default'0000-00-00 00:00:00',

PRIMARY KEY('id')

)TYPE=MyISAM;

这样用于存放用户信息的数据表forum_user就创建完成了。用于存放PHP论坛信息的数据库也就创建好了。

注意　创建数据表时可以把上面的代码复制到PHPADMIN中，使用SQL脚本运行就可以创建。

19.2　共用显示部分

共用页面部分就是程序中的共享页面部分，在程序中使用得次数较多，因此把这些代码写成共用的部分，来实现代码的重复使用。共用部分包括共用头部页面、共用尾部页面、操作数据库配置文件。下面就介绍这些共用页面是如何实现的。

19.2.1　共用头部页面

为了使程序模块化，笔者把程序的主体页面分为了共用头部页面、共用尾部页面等。下面介绍PHP论坛的标题显示部分，也就是共用头部页面，如代码19.1所示。

代码19.1　PHP论坛标题部分程序：19-1.php

＜html＞

＜!--名称：19-1.PHP--!＞

＜!--功能：php论坛标题部分--!＞

＜head＞

＜meta http-equiv="content-type"content="text/html;charset=gb2312"＞

＜title＞论坛＜/title＞

＜style type="text/css"media="all"＞

body{margin:0px;padding:0px;font:12px verdana,arial,helvetica,sans-serif;}

td,legend{font-size:14px;line-height:16px;}

p{font-size:12px;}

/*HTML头样式*/

#Header{margin:10px 0px 10px 0px;padding:10px 8px 8px 20px;border-style:solid;

border-color:black;background-color:#eee;font-size:14px;height:14px;

}

/*HTML正文内容样式*/

#Content{margin:5px;width:100%;padding:10px;}

＜/style＞

＜/head＞

＜body＞

＜center＞

＜h1＞论坛＜/h1＞

＜/center＞

＜!--头开始--＞

＜div id="Header"＞

＜?php

if($_SESSION['username'])//判断用户是否登录，从而显示不同的导航界面

{

?＞

＜!--用户登录后的导航条--＞

＜strong＞＜?php echo$_SESSION['username'];?＞，欢迎登录＜/strong＞|＆nbsp;

＜a href="main_forum.php"＞首页＜/a＞|＆nbsp;

＜a href="edit_profile.php"＞个人资料＜/a＞|＆nbsp;

＜a href="logoff_user.php"＞退出论坛＜/a＞

＜?php}else{?＞

＜!--用户未登录的导航条--＞

＜a href="main_forum.php"＞首页＜/a＞|＆nbsp;

＜a href="create_user.php"＞注册＜/a＞|＆nbsp;

＜a href="logon_form.php"＞登录＜/a＞

＜?php

}//判断结束

?＞

＜br＞

＜/div＞

＜!--头结束--＞

＜!--正文内容开始--＞

＜div id="Content"＞

这样PHP论坛页面的共用头部页面就完成了，在这个页面中可以显示首页、用户登录、注册。当用户登录后会显示用户的信息栏目、退出论坛。用户没有登录的运行效果如图19.2所示。

图　19.2　PHP论坛共用头部页面运行效果图

注意　在此程序中加入了CSS样式文件，样式文件将在下面介绍。

19.2.2　共用尾部页面

在上面介绍了PHP论坛的共用头部，接下来介绍PHP论坛的共用尾部页面的建立。共用尾部页面是用来显示网站的版权所有，程序的代码如代码19.2所示。

代码19.2　共用尾部页面程序：19-2.php

＜!--名称：19-2.php--!＞

＜!---功能：共用尾部页面-!＞

＜/div＞

＜!--正文内容结束--＞

＜!--版权信息--＞

＜style type="text/css"＞

＜!--

.STYLE1{color:#FF0000}

--＞

＜/style＞

＜center＞

＜table border=0＞

＜tr＞

＜td＞＜span class="STYLE1"＞版权所有＜/span＞:PHP完全自学手册＜/td＞

＜/tr＞

＜/table＞

＜/center＞

＜/body＞

＜/html＞

此程序实现PHP论坛页面的尾部的一些信息，笔者只加入了版权所有，读者也可加入其他的内容，例如友情链接等。共用尾部页面的运行效果如图19.3所示。

图　19.3　共用尾部页面的运行效果

注意　在上面共用头部页面和共用尾部页面的两部分代码中，共用头部的最后一行代码"＜div id="Content"＞"和共用尾部页面代码中第3行"＜/div＞"形成了对应。一个开始一个结束。

19.2.3　数据库连接文件

数据库连接文件是PHP论坛程序中连接数据库的程序模块。笔者把程序的一些操作都模块化了，因为这样可以使以后的维护比较简单。笔者把操作数据库也写成了一个模块，没有把数据库操作代码写入到页面中，这样在以后修改操作数据库代码时，只需要修改这个操作数据库配置文件就可以了，程序代码如代码19.3所示。

代码19.3　数据库操作程序：19-3.php

＜?php

/*******************/

//名称：19-3.php

//功能：数据库操作程序

/*******************/

/*连接数据库的定义*/

define('DB_USER',"root");//用户名

define('DB_PASSWORD',"pass");//密码

define('DB_HOST',"localhost");//数据库主机地址

define('DB_NAME',"php_bbs");//数据库

define('ADMIN_USER',"admin");//管理员用户

define('EACH_PAGE',5);//分页设置，每页最多显示的记录数

$invalidchars=array(//无效的字符，用于ClearSpecialChars()函数

"'",//单引号

";",//分号

"=",//等号

"\\",//反斜线

"/"//斜线

);

$badwords=array//"脏字"数组，用于FilterBadWords()

(

"fuck","shit","wanker","cunt","gay",

"nigger","bastard","tosser","dipshit",

"homosexual","nigga","gaylord","retard",

"asshole","slut","prick","cock","pussy",

"bitch","wanking","bollocks"

);

/*******************/

/*公共函数设置*/

/*******************/

/*功能：检查电子邮件地址格式是否正确

输入：电子邮件地址

输出：true或false*/

function CheckEmail($email)

{

$check="/^[0-9a-zA-Z_-]+@[0-9a-zA-Z_-]+(\.[0-9a-zA-Z_-]+){0,3}$/";

if(preg_match($check,$email)){

return true;

}

else{

return false;

}

}

/*功能：显示错误信息和返回的链接地址，并终止程序执行

输入：错误信息，链接地址

输出：字符串*/

function ExitMessage($message,$url='')

{

echo'＜p class="message"＞';

echo$message;

echo'＜br＞';

if($url){

echo'＜a href="'.$url.'"＞返回＜/a＞';

}else{

echo'＜a href="#"onClick="window.history.go(-1);"＞返回＜/a＞';

}

echo'＜/p＞';

exit;

}

/*功能：清除字符串中的特殊字符

输入：字符串

输出：字符串*/

function ClearSpecialChars($str)

{

global$invalidchars;

$str=trim($str);

$str=str_replace($invalidchars,"",$str);

return$str;

}

/*功能："脏字"处理程序

输入：字符串

输出：字符串*/

function FilterBadWords($str)

{

global$badwords;

$replacements=array("[ensored]","***");//替代字数组

for($i=0;$i＜sizeof($badwords);$i++)

{

srand((double)microtime()*1000000);//随机函数发生器

$rand_key=(rand()%sizeof($replacements));//生成随机代码

$str=eregi_replace($badwords[$i],$replacements[$rand_key],$str);

}

return$str;

}

/*******************/

/*初始化程序*/

/*******************/

session_start();//开启SESSION

$db=mysql_pconnect(DB_HOST,DB_USER,DB_PASSWORD);//打开数据库连接

if(!$db)

{

die('＜b＞数据库连接失败！＜/b＞');

exit;

}

mysql_select_db(DB_NAME);//选择数据库

?＞

此程序中分为两个部分，分别为连接数据库部分和脏字处理部分。连接数据库部分是创建一个数据库与程序的通道，使操作数据库程序正确执行。脏字处理部分是把用户发布的内容中含有不文明的词处理掉。下一小节将介绍用户注册页面。

19.3　用户注册

用户的注册就是创建一个表单页面，用来接收用户输入的信息，然后通过用户注册处理页面，把用户的信息写到数据库中，并在数据库中创建唯一的一个用户。

19.3.1　生成用户注册页面

在PHP论坛中，可以通过此程序来增加用户，以实现用户与用户之间的交流。用户注册页面就是把用户的信息写入到数据库中，程序代码如代码19.4所示。

代码19.4　生成用户注册页面程序：19-4.php

＜?php

/**************************************/

//文件名：19-4.php

//功能：生成用户注册页面

/**************************************/

require('config.inc.php');

include('header.inc.php');

?＞

＜h2＞注册新用户＜/h2＞

＜fieldset＞

＜!—表单部分--＞

＜form method="post"action="add_user.php"＞

＜table＞

＜tr＞

＜td＞用户名：＜/td＞

＜td＞＜input name="username"type="text"＞＜/td＞

＜/tr＞

＜tr＞

＜td＞密码：＜/td＞

＜td＞＜input name="password"type="password"＞＜/td＞

＜/tr＞

＜tr＞

＜td＞E-mail：＜/td＞

＜td＞＜input name="email"type="text"＞＜/td＞

＜/tr＞

＜tr＞

＜td＞真实姓名：＜/td＞

＜td＞＜input name="realname"type="text"＞＜/td＞

＜/tr＞

＜/table＞

＜!—结束表单--＞

＜input type="submit"name="Submit"value="提交注册"class="button"/＞

＜input type="reset"name="Submit2"value="清空"class="button"/＞

＜/form＞

＜/fieldset＞

＜?php

//公用尾部页面

include('footer.inc.php');

?＞

此程序是当用户想在论坛中进行交流时，必须先登录才能进行交流。要登录就要有用户的ID，如果没有用户ID就需要注册一个。此程序就是接收用户输入的信息的一个表单。程序的运行效果如图19.4所示。

图　19.4　PHP论坛的注册页面运行效果图

注意　在此页面中并没有对用户信息进行判断，而是在下面要介绍的用户注册处理页面进行的判断。

19.3.2　用户注册处理页面

用户注册处理页面是把用户注册表单页面接收到的用户信息提交到此页面，通过此页面把合法的用户信息写入数据库中，如果不合法则注册不成功。用户注册处理程序的代码如代码19.5所示。

代码19.5　添加注册用户记录程序：19-5.php

＜?php

/**********************************/

/*名称：19-5.php

/*功能：添加注册用户记录

/**********************************/

require('config.inc.php');

/*取得提交的数据，并做清理*/

$username=ClearSpecialChars($_POST['username']);//用户名

$password=$_POST['password'];//密码

$email=ClearSpecialChars($_POST['email']);//电子邮件地址

$realname=ClearSpecialChars($_POST['realname']);//真实姓名

if(!$username){//检验数据的合法性

ExitMessage('请输入用户名！');

}

if(!$password){

ExitMessage('请输入密码！');

}

if(!$email){

ExitMessage('请输入电子邮件地址！');

}

elseif(!checkEmail($email)){

ExitMessage('电子邮件地址格式错误！');

}

$password=md5($_POST['password']);//对密码进行MD5加密

$sql="SELECT*FROM forum_user WHERE username='$username'";//判断用户是否已经存在

$result=mysql_query($sql);

$num_rows=mysql_num_rows($result);

if($num_rows＞0){

ExitMessage('该用户已经存在！');

}

$sql="INSERT INTO forum_user(username,password,email,realname,regdate)

VALUES('$username','$password','$email','$realname',NOW())";

//创建用户

$result=mysql_query($sql);

if($result)

{

?＞

＜h2＞创建用户＜/h2＞

＜p＞您的用户账号已经建立，请点击＜a href="logon_form.php"＞这里＜/a＞登录。＜/p＞

＜?php

}

else{

ExitMessage("数据库错误！");

}

?＞

此程序是通过数据库查询语句SELECT*FROM forum_user WHERE username='$username把数据库中的用户信息提取出来，与用户输入的信息进行对比，如果相等，则提示该用户已经注册；如果不相等，就可以创建用户了。通过语句INSERT INTO forum_user(username,password,email,realname,regdate)VALUES('$username','$password','$email','$realname',NOW())把用户信息写入到数据库中。

注意　此程序对用户信息的判断是通过if来实现的。

19.4　登录页面

管理员登录页面就是实现获取管理权限的一个过程，当管理员成功的登录后，系统会自动为管理员分配相应的管理权限。本程序是接收用户输入的用户名和密码，判断是否是合法的用户，如果合法，则提示登录，否则提示“用户名或者密码错误”，程序的代码如代码19.6所示。

代码19.6　用户登录程序：19-6.php

＜?php

/**************************************/

/*名称：19-6.php

/*功能：用户登录程序

/**************************************/

require('config.inc.php');

if($_POST['submit'])

{

$username=ClearSpecialChars($_POST['username']);//用户名

$password=md5($_POST['password']);//密码，需要进行MD5加密

$sql="SELECT*FROM forum_user//从数据库中检索用户名，密码是否匹配

WHERE username='$username'AND password='$password'";

$result=mysql_query($sql);

$num_rows=mysql_num_rows($result);

if($num_rows==1)

{

$row=mysql_fetch_assoc($result);//获得用户名

$_SESSION['username']=$row['username'];//将用户名存入SESSION中

header("Location:main_forum.php");//跳转到论坛主页面

}

else{

ExitMessage("用户名或者密码错误！","logon_form.php");

}

}

else{

//公用头部页面

include('header.inc.php');

?＞

＜h2＞用户登录＜/h2＞

＜fieldset＞

＜form method="post"action="logon_form.php"＞

＜table＞

＜tr＞

＜td＞用户名：＜/td＞

＜td＞＜input name="username"type="text"＞＜/td＞

＜/tr＞

＜tr＞

＜td＞密码：＜/td＞

＜td＞＜input name="password"type="password"＞＜/td＞

＜/tr＞

＜/table＞

＜input type="submit"name="submit"value="登录"class="button"＞

＜/form＞

＜/fieldset＞

＜?php

}

//公用尾部页面

include('footer.inc.php');

?＞

此程序是先把登录表单输出到页面中，用户输入数据后提交到程序中，再判断是否是合法的用户。如果是合法的用户，则可以正常登录；如果不是合法的用户，就会提示用户名和密码有误。程序的运行效果如图19.5所示。

图　19.5　登录程序的运行效果图

注意　此程序中使用了表单和程序的混合，要注意表单的位置。

19.5　发表文章程序部分

在一个论坛中，注册的用户可以发表自己的文章，那就需要一个文章发表程序。此文章发表程序中分为两部分：发表文章表单页面和发表文章处理页面。发表文章的表单页面就是用户用来编辑文章的页面，然后把编辑的文章提交到发表文章处理页面，通过发表文章处理页面把用户将要发表的文章写入到数据库中，供浏览者阅读。

19.5.1　发表文章的表单页面

发表文章的表单页面是程序为用户展现的一个表单窗口，用户可以在这里发表自己的信息。发表文章的前提是用户必须先登录，才能够有发表文章的权限。在此程序中如果用户是普通的用户，则只能发表文章，不能进行帖子置顶、锁定帖子的操作，只有管理员才可以，程序的代码如代码19.7所示。

代码19.7　发表文章页面程序：19-7.php

＜?php

/***********************************/

/*名称：19-7.php

/*功能：发表文章页面

/***********************************/

require('config.inc.php');

include('header.inc.php');

?＞

＜h2＞创建新帖＜/h2＞

＜?php

if(!$_SESSION['username'])

{

//如果用户未登录，显示错误信息

?＞

＜h3＞未注册的用户＜/h3＞

＜p＞对不起，请＜a href="create_user.php"＞注册＜/a＞新用户，

或者进行＜a href="logon_form.php"＞登录＜/a＞

＜/p＞

＜?php

}else{

//如果用户登录，显示输入表单

?＞

＜h3＞发言注意事项＜/h3＞

＜ul＞

＜li＞所有项目必须填写。＜/li＞

＜li＞在标题和正文中不能使用HTML代码。＜/li＞

＜/ul＞

＜form method="post"action="add_topic.php"id="postComment"＞

＜table＞

＜tr＞

＜td＞话题＜/td＞

＜td＞＜input name="topic"type="text"id="topic"size="50"＞＜td＞

＜/tr＞

＜tr＞

＜td＞正文＜/td＞

＜td＞＜textarea name="detail"cols="50"rows="10"id="detail"＞＜/textarea＞＜/td＞

＜/tr＞

＜/table＞

＜?php

/*如果是管理员，将显示"置顶"和"锁定"功能*/

if($_SESSION['username']==ADMIN_USER)

{

?＞

＜br＞将帖子置顶＜input type="checkbox"name="sticky"value="on"＞

＜br＞锁定该帖子＜input type="checkbox"name="locked"value="on"＞

＜?php

}

?＞

＜br＞＜br＞

＜input type="submit"name="Submit"value="立即发布"class="button"＞

＜input type="reset"name="Submit2"class="button"＞

＜/form＞

＜?php}?＞

＜?php

//公用尾部页面

include('footer.inc.php');

?＞

此页面就是一个生成HTML表单的程序，此程序的管理员和普通会员发表文章的页面有所不同，程序通过对用户权限的判断来显示不同的文章发表页面。下面就是管理员登录后程序的运行效果，如图19.6所示。

图　19.6　发表文章的表单页面运行效果图

注意　用户权限的判断是在发表文章处理程序中进行的。

19.5.2　发表文章处理页面

发表文章处理页面是通过发表文章表单页面接收到用户输入的数据信息，然后通过post方法把数据提交到发表文章处理页面，通过发表文章处理页面程序操作数据库语句把用户的数据信息写入到数据库中，程序代码如代码19.8所示。

代码19.8　发表文章处理页面程序：19-8.php

＜?php

/**************************************/

/*名称：19-8.php

/*功能：发表文章处理页面

/**************************************/

require('config.inc.php');

if(!$_SESSION['username'])

{

/*如果用户未登录，显示错误信息*/

include('header.inc.php');//头文件

?＞

＜h2＞创建新帖＜/h2＞

＜h3＞未注册的用户＜/h3＞

＜p＞对不起，请＜a href="create_user.php"＞注册＜/a＞新用户

或者进行＜a href="logon_form.php"＞登录＜/a＞。

＜/p＞

＜?php

include('footer.inc.php');//尾文件

}else{

$username=$_SESSION['username'];//获得用户信息

$sql="SELECT*from forum_user WHERE username='$username'";

$result=mysql_query($sql);

$info=mysql_fetch_array($result);

//取得传递来的值

$topic=filterBadWords($_POST['topic']);//标题的脏字过滤

$detail=filterBadWords($_POST['detail']);//正文的脏字过滤

$name=$_SESSION['username'];//发帖人

$email=$info['email'];//电子邮件地址

$sticky=$_POST['sticky'];//是否置顶

$locked=$_POST['locked'];//是否锁定

if(!$topic)//数据合法性检查

{

ExitMessage("请输入标题！");

}

if(!$detail)

{

ExitMessage("请输入正文！");

}

//判断是否为锁定状态

if($locked=="on"＆＆$name==ADMIN_USER){

$locked=1;

}

else{

$locked=0;

}

if($sticky=="on"＆＆$name==ADMIN_USER)//判断是否置顶状态

$sticky=1;

}

else{

$sticky=0;

}

//将数据插入数据库

$sql="INSERT INTO forum_topic(topic,detail,name,email,datetime,locked,sticky)

VALUES('$topic','$detail','$name','$email',NOW(),'$locked','$sticky')";

$result=mysql_query($sql);

if($result)

{

header("Location:main_forum.php");//成功后，跳转页面到论坛主页面

}

else

{

ExitMessage("数据库错误！");

}

}

?＞

此程序是把用户要发表的文章信息通过INSERT INTO forum_topic（topic,detail,name,email,datetime,locked,sticky）VALUES（'$topic'，'$detail'，'$name'，'$email'，NOW()，'$locked'，'$sticky语句写入到数据库中，完成文章的发表。

注意　程序中先对用户名进行判断，然后把数据写入数据库中。

19.6　文章的显示页面及文章的回复程序

在上面一节中介绍了文章的发表，接下来要把用户发表的文章显示在页面中，供浏览者阅读及回复。

文章的显示程序是把用户存入到数据库的内容，读取并显示到页面中，当用户点击进行阅读后，也可以回复或评价此文章。

19.6.1　文章的详细列表页面

文章的详细列表页面指的是程序从数据库中把数据读取出来，显示到此页面中，并且按一定的顺序排列。排列的顺序由程序员来确定，例如按发表的时间、按数据ID等。文章的详细列表页面的程序代码如代码19.9所示。

代码19.9　文章详细页面程序：19-9.php

＜?php

/**************************************/

/*名称：19-9.php

/*功能：文章详细页面

/**************************************/

require('config.inc.php');

$id=$_GET['id'];//根据ID取得帖子记录

$sql="SELECT*FROM forum_topic WHERE id='$id'";

$result=mysql_query($sql);

$rows=mysql_fetch_array($result);

if(!$rows)//记录不存在

{

ExitMessage("该帖记录不存在！","main_forum.php");

}

$sticky=$rows['sticky'];//置顶标记

?＞

＜?php include('header.inc.php');?＞

＜h2＞＜?echo$rows['topic'];?＞＜/h2＞

＜em class="info"＞

由＜a href="view_profile.php?id=＜?php echo$rows['name'];?＞"＞

＜?echo$rows['name'];?＞＜/a＞于＜?echo$rows['datetime'];?＞

创建

＜/em＞

＜p＞

＜?php

echo nl2br(htmlspecialchars($rows['detail']));//输出整理好的内容

?＞

＜/p＞

＜?php if($rows['locked']){$locked=1;}?＞

＜hr size=1/＞

＜dl＞＜?php

$sql

="SELECT*FROM forum_reply WHERE topic_id='$id'";//获取回复内容

$result=mysql_query($sql);

$num_rows=mysql_num_rows($result);

if($num_rows)

{

while($rows=mysql_fetch_array($result))//循环取出记录内容

{

?＞

＜dt＞

＜a href="view_profile.php?id=＜?php echo$rows['reply_name'];?＞"＞

＜?echo$rows['reply_name'];?＞

＜/a＞

-＜em＞＜?php echo$rows['reply_datetime'];?＞＜/em＞

＜/dt＞

＜dd＞

＜p＞＜?php

echo nl2br(htmlspecialchars($rows['reply_detail']));//输出整理好的内容

?＞＜/p＞

＜/dd＞

＜?

}//结束循环

}else{

echo"＜p＞＜strong＞没有跟帖记录。＜/strong＞＜/p＞";

}

$sql="UPDATE forum_topic set view=view+1 WHERE id='$id'";//浏览量加1

$result=mysql_query($sql);

?＞

＜/dl＞

＜!--内容回复表单，开始--＞

＜fieldset＞

＜legend＞帖子回复＜/legend＞

＜?php

if(!$_SESSION['username'])//判断用户是否已经注册

{

echo'＜p＞请先＜a href="create_user.php"＞注册＜/a＞,

或者＜a href="logon_form.php"＞登录＜/a＞或后进行操作。＜br＞＆nbsp;＜/p＞';

}else{

if($locked==1)//帖子已经被锁定

{

echo'＜p＞＜strong＞该帖是被锁定的，无法回帖＜/strong＞＜br＞＆nbsp;＜/p＞';

}else{

?＞

＜form name="form1"method="post"action="add_reply.php"id="reply"＞

＜input name="id"type="hidden"value="＜?echo$id;?＞"＞

＜table＞

＜tr＞

＜td valign="top"＞回帖＜br＞内容＜/td＞

＜td＞

＜textarea name="reply_detail"cols="45"rows="10"＞＜/textarea＞

＜/td＞

＜/tr＞

＜tr＞

＜td valign="top"＞＆nbsp;＜/td＞

＜td＞＜em＞请不要使用HTML标签＜/em＞＜/td＞

＜/tr＞

＜/table＞

＜br/＞

＜input type="submit"name="Submit"value="回复该帖"class="button"/＞

＜input type="reset"name="Reset"class="button"/＞

＜/form＞

＜?php}?＞

＜/fieldset＞＜br＞

＜!--内容回复表单，结束--＞

＜?php

/*如果是管理员用户，则输出"置顶"、"锁定"和"删除"按钮*/

if($_SESSION['username']==ADMIN_USER)

{

?＞

＜!--管理员操作表单，开始--＞

＜fieldset＞

＜legend＞管理员操作＜/legend＞

＜!--显示锁定操作按钮--＞

＜?php if($locked==0){?＞

＜form name="lock"method="post"action="lock_topic.php"＞

＜input type="hidden"name="id"value="＜?php echo$id;?＞"＞

＜input type="submit"name="Submit"value="锁定该帖"class="button"＞

将该帖锁定，其他用户无法回复

＜/form＞

＜?php}else{?＞

＜form name="unlock"method="post"action="unlock_topic.php"＞

＜input type="hidden"name="id"value="＜?php echo$id;?＞"＞

＜input type="submit"name="Submit"value="解除锁定"class="button"＞

解除锁定，其他人可以回复

＜/form＞

＜?php}?＞

＜!--显示置顶操作按钮--＞

＜?php if($sticky==0){?＞

＜form name="stick"method="post"action="stick_topic.php"＞

＜input type="hidden"name="id"value="＜?php echo$id;?＞"＞

＜input type="submit"name="Submit"value="置顶该帖"class="button"＞

将该帖置于顶端

＜/form＞

＜?php}else{?＞

＜form name="unstick"method="post"action="unstick_topic.php"＞

＜input type="hidden"name="id"value="＜?php echo$id;?＞"＞

＜input type="submit"name="Submit"value="取消置顶"class="button"＞

取消该帖置顶

＜/form＞

＜?php}?＞

＜!--显示删除操作按钮--＞

＜form name="delete"method="get"action="del_topic.php"＞

＜input type="hidden"name="id"value="＜?php echo$id;?＞"＞

＜input type="submit"name="Submit"value="删除帖子"class="button"＞

删除该帖与回复内容

＜/form＞

＜/fieldset＞

＜!--管理员操作表单，结束--＞

＜?php

}

}

?＞

＜?php

include('footer.inc.php');

?＞

此程序通过SQL语句SELECT*FROM forum_topic WHERE id='$id'把数据库中的数据读取出来，然后显示在页面中。此程序也对用户进行了判断，如果是管理员就有设置“置顶”、“锁定”及取消置顶和锁定的权限。

注意　在此程序中涉及删除等操作程序，将在下面介绍。

19.6.2　回复文章程序

回复文章程序的作用是供用户提出问题或发表文章，作为管理员或用户可以对其进行回答或评论的一个提交窗口。回复文章程序的代码如代码19.10所示。

代码19.10　回复文章保存页面程序：19-10.php

＜?php

/**************************************/

/*名称：19-10.php

/*功能：回复文章保存页面

/***************************************/

require('config.inc.php');

if(!$_SESSION['username'])//判断用户是否登录

{

ExitMessage("请＜b＞登录＜/b＞后执行该请求。","logon_form.php");

}

$id=$_POST['id'];//回帖的ID

//验证帖子已经存在，未被锁定

$sql="SELECT*from forum_topic WHERE id='$id'";

$result=mysql_query($sql);

$topic_info=mysql_fetch_array($result);

if(!$topic_info)

{

ExitMessage("帖子记录不存在！","main_forum.php");

}

if($topic_info['locked']==1)

{

ExitMessage("该帖已经被锁定，无法进行回复。");

}

$username=$_SESSION['username'];//取得用户信息

$sql="SELECT*from forum_user WHERE username='$username'";

$result=mysql_query($sql);

$user_info=mysql_fetch_array($result);

$reply_name=$_SESSION['username'];//取得提交过来的数据

$reply_email=$user_info['email'];

$reply_detail=filterBadWords($_POST['reply_detail']);

if(!$reply_detail)

{

ExitMessage("没有回帖记录！","main_forum.php");

}

$sql="SELECT Count(reply_id)AS MaxReplyId//取得reply_id的最大值

FROM forum_reply WHERE topic_id='$id'";

$result=mysql_query($sql);

$rows=mysql_fetch_row($result);

if($rows)//将reply_id最大值+1，如

果没有该值，则设置为1

{

$Max_id=$rows[0]+1;

}

else{

$Max_id=1;

}

$sql="INSERT INTO forum_reply(topic_id,reply_id,reply_name,//插入回复数据

reply_email,reply_detail,reply_datetime)

VALUES('$id','$Max_id','$reply_name',

'$reply_email','$reply_detail',NOW())";

$result=mysql_query($sql);

if($result)

{

$sql="UPDATE forum_topic SET reply='$Max_id'WHERE id='$id'";//更新reply字段

$result=mysql_query($sql);

header("Location:view_topic.php?id=$id");//页面跳转

}

else{

ExitMessage("记录不存在");

}

?＞

此程序是一个用户对发表的文章进行回复的程序。通过语句INSERT INTO forum_reply（topic_id,reply_id,reply_name,reply_email,reply_detail,reply_datetime）VALUES（'$id'，'$Max_id'，'$reply_name'，'$reply_email'，'$reply_detail'，NOW()）来实现把回复文章插入到数据库中。

注意　此程序的工作流程是先判断用户信息，然后获取权限，最后才可以回复文章。

19.7　文章的锁定操作

在上面介绍了浏览者对文章的回复或评价程序，为了方便管理员或用户操作，有些文章不需要，可设置锁定操作，当管理员或用户想要再次把锁定的文章，可以让浏览者实行回复操作时，也可对锁定的文章实行取消锁定操作。

19.7.1　设置锁定操作

在论坛中，如果用户发表的文章管理员不想让别人回复，则可以设置锁定此文章，也就是可以通过此程序来实现。设置了锁定文章，用户只能看到文章内容，但是不可以发表回复。设置锁定操作程序的代码如代码19.11所示。

代码19.11　设置锁定操作程序：19-11.php

＜?php

/**************************************/

/*名称：19-11.php

/*功能：设置"锁定"操作

/**************************************/

require('config.inc.php');

if($_SESSION['username']==ADMIN_USER)//判断是否为管理员

{

$id=$_POST['id'];//取得文章ID

$sql="UPDATE forum_topic SET locked='1'WHERE id='$id'";//锁定的SQL语句

$result=mysql_query($sql);

if($result)

{

header("Location:view_topic.php?id=$id");//跳转页面

}

else{

ExitMessage("数据库操作错误！");

}

}else{

ExitMessage("你没有管理权限！");

}

?＞

此程序中首先调用了数据库连接程序config.inc.php，进行数据库的连接，然后判断是否是管理员，如果是管理员，则可以设置锁定操作；如果是普通用户，则没有权限设置锁定操作。

注意　如果是管理员，设置锁定操作是通过语句UPDATE forum_topic SET locked='1'WHERE id='$id来实现的。

19.7.2　取消锁定操作

当管理员想让用户回复锁定的文章时，可以把锁定取消，这样用户就可以回复文章了。取消锁定操作与设置锁定操作类似，这里就不多介绍了。下面来看个取消锁定程序的实例，如代码19.12所示。

代码19.12　取消锁定操作程序：19-12.php

＜?php

/**************************************/

/*名称：19-12.php

/*功能：取消"锁定"操作

/**************************************/

require('config.inc.php');

if($_SESSION['username']==ADMIN_USER)//判断是否为管理员

{

$id=$_POST['id'];//取得文章ID

$sql="UPDATE forum_topic SET locked='0'WHERE id='$id'";//取消"锁定"的SQL语句

$result=mysql_query($sql);

if($result)

{

header("Location:view_topic.php?id=$id");//跳转页面

}

else{

ExitMessage("数据库操作错误！");

}

}else{

ExitMessage("你没有管理权限！");

}

?＞

此程序中首先调用了数据库连接程序config.inc.php，进行数据库的连接，然后判断是否是管理员，如果是管理员，则可以取消锁定操作；如果是普通用户，则没有权限取消锁定操作。

注意　如果是管理员，取消锁定操作是通过语句UPDATE forum_topic SET locked='0'WHERE id='$id来实现的。

19.8　文章的置顶操作

在论坛中，如果一些好的文章，需要把它放在文章显示页面的最前面，就可以使用置顶来实现此操作。当用户不需要置顶此文章时，也可以取消置顶。这样可以方便管理员或用户管理自己所发表的文章。

19.8.1　设置置顶操作

在论坛中，如果管理员想把用户发表的一些比较好的文章始终位于顶部，则可以设置置顶此文章，也就是可以通过此程序来实现。设置了置顶文章，用户发表的文章内容始终会处于文章列表的顶部。设置置顶操作的程序如代码19.13所示。

代码19.13　设置置顶操作程序：19-13.php

＜?php

/**************************************/

/*名称：19-13.php

/*功能：设置"置顶"操作

/**************************************/

require('config.inc.php');

if($_SESSION['username']==ADMIN_USER)//判断是否为管理员

{

$id=$_POST['id'];//取得文章ID

$sql="UPDATE forum_topic SET sticky='1'WHERE id='$id'";

//设置"置顶"的SQL语句

$result=mysql_query($sql);

if($result)

{

header("Location:view_topic.php?id=$id");//跳转页面

}

else{

ExitMessage("数据库操作错误！");

}

}else{

ExitMessage("你没有管理权限！");

}

?＞

此程序中首先调用了数据库连接程序config.inc.php，进行数据库的连接，然后判断是否是管理员，如果是管理员，则可以设置置顶操作；如果是普通用户，则没有权限设置置顶操作。

注意　如果是管理员，设置置顶操作是通过语句UPDATE forum_topic SET sticky='1'WHERE id='$id来实现的。

19.8.2　取消置顶操作

在论坛中，如果管理员不想把用户发表的已经设置置顶的文章放置于顶部，则可以取消置顶此文章。取消置顶文章后，用户发表的文章内容将不会处于文章列表的顶部。程序如代码19.14所示。

代码19.14　取消置顶操作程序：19-14.php

＜?php

/**************************************/

/*名称：19-14.php

/*功能：取消"置顶"操作

/**************************************/

require('config.inc.php');

if($_SESSION['username']==ADMIN_USER)//判断是否为管理员

{

$id=$_POST['id'];//取得文章ID

$sql="UPDATE forum_topic SET sticky='0'WHERE id='$id'";//取消"置顶"的SQL语句

$result=mysql_query($sql);

if($result)

{

header("Location:view_topic.php?id=$id");//跳转页面

}

else{

ExitMessage("数据库操作错误！");

}

}else{

ExitMessage("你没有管理权限！");

}

?＞

此程序中首先调用了数据库连接程序config.inc.php，进行数据库的连接，然后判断是否是管理员，如果是管理员，则可以取消置顶操作；如果是普通用户，则没有权限取消置顶操作。

注意　如果是管理员，取消置顶操作是通过语句UPDATE forum_topic SET sticky='0'WHERE id='$id来实现的。

19.9　文章的删除及修改

在论坛中，管理员或用户可以对自己的文章进行删除及修改操作，以方便论坛的管理。删除文章是把文章从论坛的数据库中删除。修改文章就是把文章中的错误或不理想的地方修改成需要的内容。

19.9.1　删除文章操作

如果管理员发现论坛中有不合法或不健康的文章以及发表得比较老的文章时，都可以通过此程序进行删除操作。删除文章的操作程序如代码19.15所示。

代码19.15　删除文章内容操作程序：19-15.php

＜?php

/**************************************/

/*名称：19-15.php

/*功能：删除文章内容操作

/**************************************/

require('config.inc.php');

if($_SESSION['username']==ADMIN_USER)//判断是否为管理员

{

$id=$_GET['id'];//设置获得的数据的发送形式

$sql="DELETE FROM forum_topic WHERE id=$id";//删除文章

$result=mysql_query($sql);

$sql2="DELETE FROM forum_reply WHERE topic_id=$id";//删除回复内容

$result2=mysql_query($sql2);

if($result AND$result2)

{

header("Location:main_forum.php");//页面跳转

}

else{

ExitMessage("数据库操作错误！");

}

}else{

ExitMessage("你没有管理权限！");

}

?＞

此程序首先要对用户的权限进行判断，如果是管理员，则可以进行删除操作；如不是管理员，则无法进行删除操作。删除文章时，同时要把此文章的回复内容一并删除。所以在判断语句结束后，将会执行两个SQL删除语句。

注意　在程序中删除文章的同时，还要对此文章的回复内容进行删除。所以会有两个删除语句。

19.9.2　修改用户资料表单页面

用户资料表单页面是对用户注册资料的一个更新表单页面，用户可以通过此页面来修改自己的资料。然后提交到用户资料详细处理页面，来完成用户个人资料的修改。程序的代码如代码19.16所示。

代码19.16　用户资料修改页面程序：19-16.php

＜?php

/******************************************/

/*名称：19-16.php

/*功能：用户资料修改页面

/******************************************/

require('config.inc.php');

$id=$_SESSION['username'];//用户名

if(!$_SESSION['username']){//如果用户没有登录

ExitMessage("请＜b＞登录＜/b＞后执行该请求。","logon_form.php");

}

?＞

＜?php include('header.inc.php');?＞

＜h2＞编辑个人资料＜/h2＞

＜?php

$sql="SELECT*FROM forum_user WHERE username='$id'";//查询用户资料

$result=mysql_query($sql);

$rows=mysql_fetch_array($result);

?＞

＜fieldset＞

＜legend＞个人资料＜/legend＞

＜form method="post"action="update_profile.php"＞

＜table＞

＜tr＞

＜td＞登录用户：＜/td＞

＜td＞＜b＞＜?echo$rows['username'];?＞＜/b＞＜/td＞

＜/tr＞

＜tr＞

＜td＞更新密码：＜/td＞＜td＞＜input name="password"type="password"＞

密码留空，将不被更新。＜/td＞

＜/tr＞

＜tr＞

＜td＞电子邮件：＜/td＞

＜td＞＜input name="email"type="text"

value="＜?php echo$rows['email'];?＞"＞＜/td＞

＜/tr＞

＜tr＞

＜td＞真实姓名：＜/td＞

＜td＞＜input name="realname"type="text"

value="＜?php echo$rows['realname'];?＞"＞＜/td＞

＜/tr＞

＜/table＞

＜br＞＜br＞

＜input type="submit"name="submit"value="更新个人资料"class="button"＞

＜/form＞

＜/fieldset＞

＜?php

php include('footer.inc.php');

?＞

此程序首先引入PHP论坛的共用头部页面，然后把登录用户的注册信息显示在HTML表单中，用户可以对此进行修改。当用户修改完成个人资料后，单击“提交”按钮就会通过用户资料处理页面来完成数据库操作。这里以管理员账号为例来介绍，在管理员单击个人资料时的显示效果如图19.7所示。

图　19.7　用户资料详细表单页面运行效果图

注意　程序在HTML表单中显示用户的信息的语句如＜input name="email"type="text"value="＜?php echo$rows['email']；?＞"＞所示。

19.9.3　修改用户资料处理页面

修改用户资料处理页面是将修改用户资料详细表单页面提交过来的数据，通过SQL语句"UPDATE forum_user SET password='$password'，email='$email'，realname='$realname'WHERE username='$username"'修改用户资料，如代码19.17所示。

代码19.17　用户资料修改页面程序：19-17.php

＜?php

/**************************************/

/*名称：19-17.php

/*功能：用户资料修改页面

/**************************************/

require('config.inc.php');

if(!$_SESSION['username']){

ExitMessage("请＜b＞登录＜/b＞后执行该请求","logon_form.php");

}

$username=$_SESSION['username'];//用户名

$email=ClearSpecialChars($_POST['email']);//电子邮件

$realname=ClearSpecialChars($_POST['realname']);//真实姓名

$password=$_POST['password'];

if(!$password)

{

$sql="UPDATE forum_user//如果密码为空，则密码项不予更新

SET email='$email',

realname='$realname'

WHERE username='$username'";

}else{

$password=md5($password);//如果输入了新的密码，则密码项也予以更新

$sql="UPDATE forum_user

SET password='$password',

email='$email',

realname='$realname'

WHERE username='$username'";

}

$result=mysql_query($sql);

if($result){

?＞

＜h2＞个人资料更新成功＜/h2＞

＜p＞

您的个人资料已经被成功更新

请＜a href="main_forum.php"＞返回＜/a＞论坛主页

＜/p＞

＜?php

}

else{

ExitMessage("记录不存在！");

}

?＞

此程序首先调用共用头部页面，然后判断用户是否登录，如果登录，则会显示出用户的详细的资料；如果用户没有修改密码而只修改了E-mail等信息，程序会执行UPDATE forum_user SET email='$email'，realname='$realname'WHERE username='$username'语句；如果用户密码也做修改，程序就会执行UPDATE forum_user SET password='$password'，email='$email'，realname='$realname'WHERE username='$username'语句。

注意　修改用户个人资料时有两种情况，修改密码与不修改密码的操作数据库语句不一样。

19.10　论坛主页面

论坛的主页面是把所有的模块组合到一起，相互配合工作，以实现PHP论坛的美观与程序的整体化。论坛主页面的代码如代码19.18所示。

代码19.18　论坛主页面程序：19-18.php

＜?php

/**************************************/

/*名称：19-18.php

/*功能：论坛主页面

/**************************************/

require('config.inc.php');

$page=$_GET['page'];//取得当前页数

$each_page=EACH_PAGE;//每页最多显示的记录

if(!$page||$page==1)//计算页面开始位置

{

$start=0;

}else{

$offset=$page-1;

$start=($offset*$each_page);

}

?＞

＜?php include('header.inc.php');?＞

＜h2＞论坛＜/h2＞

＜p＞

＜?php

$sql="SELECT*FROM forum_topic//检索记录，按照置顶标记和时间排序

ORDER BY sticky DESC,datetime DESC LIMIT$start,$each_page";

$result=mysql_query($sql);

?＞

＜table width="100%"border="0"align="center"

cellpadding="3"cellspacing="1"bgcolor="#111"＞

＜tr bgcolor="#E6E6E6"＞

＜td width="60%"align="center"＞＜strong＞帖子＜/strong＞＜/td＞

＜td width="8%"align="center"＞＜strong＞访问量＜/strong＞＜/td＞

＜td width="8%"align="center"＞＜strong＞回复数＜/strong＞＜/td＞

＜td width="24%"align="center"＞＜strong＞日期＜/strong＞＜/td＞

＜/tr＞

＜?php

while($rows=mysql_fetch_array($result))//循环输出记录列表

{

?＞

＜tr bgcolor="#FFFFFF"＞

＜td＞

＜?php

if($rows['sticky']=="1")//如果是"置顶"的记录

{

?＞＜img src="sticky.gif"alt="置顶"border="0"＞＜?php

}

if($rows['locked']=="1")//如果是"锁定"的记录

{

?＞＜img src="lock.gif"alt="锁定"border="0"＞＜?php

}

?＞

＜a href="view_topic.php?id=＜?php echo$rows['id'];?＞"＞＜?php echo$rows['topic'];?＞＜/a＞

＜/td＞

＜td align="center"＞

＜?php

echo$rows['view'];//浏览量

?＞

＜/td＞

＜td align="center"＞

＜?php

echo$rows['reply'];//回复量

?＞

＜/td＞

＜td align="center"＞

＜?php

echo$rows['datetime'];//日期

?＞

＜/td＞

＜/tr＞

＜?php

}//退出while循环

?＞

＜tr＞

＜td colspan="5"align="right"bgcolor="#E6E6E6"＞

＜input type="button"onClick="location.href='create_topic.php'"value="创建新帖子"＞

＜/td＞

＜/tr＞

＜/table＞

＜?php

if($page＞1)//计算前一页

{

$prevpage=$page-1;

}

$currentend=$start+EACH_PAGE;//当前记录

$sql="SELECT COUNT(*)FROM forum_topic";//取得所有记录数

$result=mysql_query($sql);

$row=mysql_fetch_row($result);

$total=$row[0];

if($total＞$currentend)//计算后一页

{

if(!$page){

$nextpage=2;

}else{

$nextpage=$page+1;

}

}

?＞

＜/p＞

＜p style="text-align:right;"＞

＜?php

if($prevpage||$nextpage)//判断分页并输出

{

if($prevpage)//前一页

{

echo"＜a href=\"?page={$prevpage}\"＞＜＜前一页＜/a＞";

}else{

echo"＆nbsp";

}

if($nextpage)//后一页

{

echo"＜a href=\"?page={$nextpage}\"＞后一页＞＞＜/a＞";

}else{

echo"＆nbsp";

}

}

?＞

＜/p＞

＜h3 align="right"＞标志＜/h3＞

＜p align="right"＞

＜img src="sticky.gif"alt="Sticky"border="0"align="absmiddle"＞置顶的帖子＜br＞

＜img src="lock.gif"alt="Locked"border="0"align="absmiddle"＞锁定的帖子＜br＞

＜?php

$sql="SELECT COUNT(*)FROM forum_user";//检索在线用户

$result=mysql_query($sql);

$row=mysql_fetch_row($result);

$total_user=$row[0];

?＞

共有＜b＞＜?php echo$total_user?＞＜/b＞位注册的用户。＜/p＞

＜?php

//公用尾部页面

include('footer.inc.php')

?＞

此程序中首先调用了共用头部页面，来显示论坛的头部信息。然后调用数据库操作程序，实现程序与数据库的连接。再把PHP论坛中发表的文章一条一条地显示在页面中，如果超出了一个页面中的显示条数，程序会自动分页显示。最后调用论坛的共用尾部信息页面，来显示论坛的版权等信息。程序的运行效果如图19.8所示。

图　19.8　论坛主页面运行效果图

19.11　小结

通过对此程序的学习，相信读者可以掌握以下的知识。

❑数据库的创建与修改语句的语法。

❑HTML表单的使用。

❑如何使用PHP来操作数据库。

❑如何实现一个PHP论坛。

附录

附录A　正则表达式参考

本书第15章对正则表达式做了简要介绍，除详细介绍了PHP中处理正则表达式的函数之外，对正则表达式本身也做了简明阐述，包括各种字符、字符匹配、匹配模式、匹配方法。同时对几类常见的正则表达式做了较为深入的分析，以便读者通过实例理解正则表达式的原理。这里再对正则表达式的重要知识点做一些总结性的介绍。

A.1　普通字符

字母、数字、汉字、下画线，以及没有特殊定义的标点符号，都是“普通字符”。表达式中的普通字符，在匹配一个字符串的时候，匹配与之相同的一个字符。例如，表达式c在匹配字符串"abcde"时，匹配结果是：成功；匹配到的内容是：c。

A.2　元字符

正则表达式中的元字符是指定义了特殊含义的字符，元字符如表A.1所示。

例如，正则表达式^abc在与"abc000xyz"匹配时成功，但不匹配"000abc000"，因为字符“^”要求与字符串开始的地方匹配。又如，正则表达式xyz$匹配"abc000xyz"，但不匹配"xyzabc"，因为字符“$”要求与字符串结束的地方匹配。

A.3　转义字符

建立正则表达式时，对一些不便书写的字符，在其前加“\”来表示，如表A.2所示。

另外一种转义是对于元字符的转义。例如，要匹配“$”，就要使用“\$”，要匹配“^”，就要使用“\^”，同理，“\.”匹配句点本身。举一个简单的例子，表达式\$d在匹配字符串"abc$de"时，匹配可以成功，其匹配到的内容是$d。

A.4　匹配多种字符的表达式

正则表达式中的一些表示方法，可以匹配“多种字符”中的任意一个字符。例如，表达式\d可以匹配任意一个数字。虽然可以匹配其中任意字符，但是只能匹配一个，不能匹配多个。这样的表达式有很多，如表A.3所示。

例如，正则表达式\d\d，可以匹配"ab10c"，匹配的内容是10，又如表达式a\d可以匹配"cba2008"，匹配的内容是a2。

A.5　使用符号创建匹配多种字符的表达式

使用方括号[]包含一系列字符，能够匹配其中任意一个字符。用[^]包含一系列字符，则能够匹配其中“^”之后所列字符之外的任意一个字符。同样的道理，虽然可以匹配其中任意字符，但是只能匹配一个，不是多个。

例如，正则表达式[a@5]可以匹配字符"a"，或者匹配字符“@”，或者匹配字符“5”，而正则表达式[^a@5]匹配除"a"、“@”和“5”之外的任意一个字符。再例如，[a-p]匹配小写字母"a"到小写字母"p"之间的任意一个字符。

A.6　用来限定匹配次数的表达式

这里的限定匹配次数，其实是为满足多次匹配而设置的。因为无论是只能匹配一种字符的表达式，还是可以匹配多种字符中任意一个的表达式，都只能匹配一次。如果使用表达式再加上限定匹配次数的特殊表达式，那么不用重复书写表达式，也可以完成重复匹配。这种用法的规则是，“次数限定”放在“被限定的表达式”的后面。例如，[cbd][cbd]可以写成[cbd]{2}。这种用法的具体说明如表A.4所示。

A.7　其他说明

如果要求表达式所匹配的内容是整个字符串，而不是从字符串中找一部分，可以在表达式的首尾分别使用“^”和“$”，例如，正则表达式^\d+$要求整个字符串只有数字。

表达式不要匹配空字符串，否则会一直等到匹配成功，而结果什么都没有匹配到。

使用“|”匹配时，其左右两边对某个字符最好只有一边可以匹配，这样不会因为“|”两边的表达式交换位置而有所不同。

附录B　PHP代码编写的一般规则

在软件开发过程中，编程的工作量是相当大的，同一项目参与的开发人员可能有各自编程的经验和习惯，不同的代码编写风格，使维护工作变得复杂和困难。众所周知，程序的可读性是非常重要的。良好的空格和缩进习惯将使代码易读、易改，会极大减少日后的维护工作量。

为了提高代码的可读性、系统的稳定性及降低维护成本，有必要在进行软件项目开发时，指定一套切实可行的代码编写规则。即便是一般情况下的程序编写，也应遵照某种代码编写规则，这不仅对个人来说可以养成良好的编程习惯，促进个人水平的提高，而且对整个团队来说都是大有裨益的。

需要特别说明的是，这里所介绍的PHP代码编写的一般规则，并不是某种标准。也就是说，PHP程序并不要求一定按这里介绍的规则进行代码编写。这里介绍的代码编写规则，只能算是对一些经验的总结，以供读者参考，希望对读者有所帮助。

B.1　标识符命名规范

首先介绍标识符的命名规范，包括变量、常量、函数、类以及文件等的命名规范。总体规则是：所有命名使用有意义或接近意义的英文单词（或英文单词的缩写、简写）。

❑全局变量和常量命名：全部使用大写字母，变量名的各个单词之间使用下画线分隔，如全局变量$CONFIG['POP_INFO']，常量ROOT_DIR。

❑普通变量的命名：包括函数、类及类方法中的变量，全部使用小写字母，变量名各个单词之间使用下画线分隔，如$user_name。

❑普通函数命名：全部使用小写字母，单词之间使用下画线分隔，如load_info()。

❑类方法命名：方法名的第1个单词小写，此后每个单词的首字母大写，单词不做分隔，如loadConfigInfo()。

❑类命名：单词首字母大写，单词之间不做分隔，如WorkGroup。

❑文件命名：全部使用小写字母，单词之间用下画线分隔，如card_list.php。

B.2　代码编写规范

这里介绍的PHP代码编写规范包括程序注释规则、语句规则、空格空行规则、括号位置规则等，下面分别加以介绍。

❑注释规则：对整个程序文件的注释，必须说明文件名称、程序表述、开发人员、开发日期以及版本信息等，并且采用“/**/”多行注释的方式。代码如下所示：

/**

*@file:config.php

*@brife:程序描述信息

*@author:mike

*@date:2007-5-23

*@version:1.0

*/

❑每个函数、方法等开头部分必须说明功能、参数、返回值等。

❑赋值语句书写规则：在有等号的赋值（区别于自加或自减等的赋值方式）语句中，等号两边需要各加一个空格，此规则也适用于函数返回的赋值或连接赋值，代码如下所示：

$style='';

❑空格规则：程序中滥用空格是绝对不允许的。空格的滥用会导致程序可读性变得很差，使代码看起来松散难看。为使程序语句紧凑，首先，for循环中的赋值可以不在等号两边加空格。其次，保持if、elseif、for、while等语句与其后的括号之间不存在空白字符，如空格等；括号内语句中的分号紧跟前一个语句，不要加空白字符，如空格等；但分号可以与下一个语句之间存在一个空白字符，或不加空格，保持括弧内的变量与运算符之间不存在空白，代码如下所示：

for($i=$begin;$i＜$begin+$this-＞pagenum;$i++);

这一行代码是不符合这里所介绍规则的PHP代码的，因为for与其之后的“（”之间有空格，变量$i与运算符“＜”之间存在空格，变量$i与自加符号之间也存在空格等，这都造成了代码松散，不易阅读。如下所示的代码也不符合规则：

if(empty($index))

{

//do something

}

在这段代码中，空格被滥用了，类似的情况还包括函数名与其参数列表之间加了空格等。

❑括号位置规则：使用括号如“{}”或“()”包含的语句块（如类定义、函数定义、for循环语句，if...else控制语句等），请将开始括号和结束括号分别放在新开始的一行，并且此行只有括号存在。一对开始括号和结束括号在列上要对齐，一对开始括号和结束括号之间的语句，必须以括号所在列为准向内增加缩进（以缩进4个字符为佳）。开始括号或结束括号紧接着语句是不允许的，如下所示的代码段不符合规则：

if($real==123){

$timer=$_POST['timer'];

if($type=='a'){

$tmp=jumps($timer);

}else{

$tmp=jumps("120");

}

}

这段代码中的括号完全没有对齐，给阅读程序带来了极大不便，而且也不美观。这样写似乎节省程序长度，减少文件行数，但实际上，节省文件长度不应该在这里过多考虑，因为程序的可读性在这里才是最重要的。修改为如下所示的代码即可符合规则：

if($real==123)

{

$timer=$_POST['timer'];

if($type=='a')

{

$tmp=jumps($timer);

}

else

{

$tmp=jumps("120");

}

}

❑空行规则：程序开发员需要在一个功能代码块结束后的适当位置，添加一行空行，以增加程序的可读性。如在函数定义结束之后、函数内部的一个循环语句块结束后等加入一个空行。

再次强调一下，这里介绍的代码编写规则并不是很标准，仅作为实际开发中的一个参考。

附录C　PHP下的编码

本附录介绍什么是码制、什么是编码以及如何解码等与编码相关的问题。在PHP处理编码时，经常会出现一些乱码，本章从基本原理和机制入手，教读者掌握这些问题，并避免Web程序中容易出现的码制问题。

C.1　我们面对的是纷繁复杂世界

作为一个中国人，使用以美国为首的国家发明的计算机时，应该比美国本土用户，有着更为深切的关于“本土语言化”的感受，放置到软件开发领域也是如此。因此首先来回顾和讨论计算机在非英语化方面支持的一些原则和方法，是非常有裨益的，本节即将就此来进行一些说明。

C.1.1　什么是码制

首先来介绍码制的概念。熟悉计算机的读者应该清楚，计算机本身是不能表达任何字符的，其内部表述数据的手段是一系列的二进制位（bit），每个二进制位具有两个截然不同的状态，即0或1。

提示显然，和十进制等其他进位制比较，在这种情况下，要表达一个信息需要更大的空间，但计算机没有采取其他进位制，而是从电工实现的角度看，表示多个状态的难度要远远大于仅表示两个状态。

因此，要表示某个字符，就必须人为地为这些二进制位所组成的串制定对应的识别规则。例如，用00000001代表单字“啊”—只要愿意，完全可以这么来做，因为规则仅涉及对二进制串的理解，是和计算机无关的。

而所谓的码制，就可以视为在人为规则下，所有使用二进制串表示的字符的集合，其可以使用数学方法表述为：S={x|x=(code,character)}。

其中，"code"代表码制中的一个单独的字符编码所对应的二进制串；"character"则代表这个二进制串所对应的字符，反映到计算机上，则应该是这个二进制串所对应字符的读取和显示方式，即当计算机发出指令，要求计算机显示该二进制串所对应的字符时，计算机应该可以准确地检索到该字符所存储在计算机中的模型，并根据该模型将字符“画”到屏幕上。

当然，这只是码制和计算机之间关系的一个“简要”描述，没有向读者展示字符和字体之间的相互关联。但笔者认为，对于开发人员而言，创造新的码制，并非是工作的重点，这属于系统开发人员（如开发Windows操作系统的人员）所需要考虑的问题。开发人员所应该关注的是，在当今计算机现实中，形成了哪些可用的码制，并且这些码制对于应用程序开发是否有影响，以及应该如何处理这些影响，而这正是在下一小节所要谈论的问题。

C.1.2　从ASCII码到Unicode

那么，在当今的计算机现实中，究竟形成了哪些约定俗成的码制呢？一个目前支持最为广泛，应用历史也最为悠久的码制是ASCII，其全称为American Standard Code for Information Interchange（美国标准信息交换码），后又被国际标准化组织（ISO）吸收为ISO 646标准。表C.1显示了整个ASCII码的基本情况，该表是所有编程人员所应该熟悉的，之所以罗列于此，完全是为了读者以后编程过程中可以方便地进行参考，就不再进行详细的介绍了。

显然，从字面上看，这是一个以实现美国文化文字表达要求为目标的标准，在这个文化体系中，英文字母（包括其大写和小写方式）是构成语言的基本要素，同时也加上了用于表达数字含义的阿拉伯字母0～9、小数点（“.”），以及一些必要的标点符号和计算机屏幕控制符号（如回车）等。

提示其中，Dec、Hx和Char分别代表十进制、十六进制和字符表达方式，括号内的内容表示该ASCII码在JavaScript（包括PHP）中撰写该字符的转义序列形式。在所有的ASCII码中，0～32及127都属于控制字符。从码表所列的十六进制表述方法可以看出，其相关字母序列，如大写的A～Z等的位置安排是非常科学的，这种安排对编程有着很好的辅助作用（例如读者可以根据表考虑一下如何实现大小写字母的转换）。

但是，当计算机应用（而非研究）的领域扩展到非英语国家和地区时，该码制的局限性便体现出来了，毕竟还有太多的国家和地区并不使用英语，因此亟需新的码制来支持这些文化背景下的计算机应用。

由于各个国家和地区在计算机应用发展历程和文化、政治背景等方面的不同，码制的制定经常处在一个“各自为政”的阶段。以汉字的编码为例，在主要使用汉字的国家和地区，如中华人民共和国、日本、韩国等，各自的计算机标准制定部门，几乎都独立地根据本国应用的需要，编制了相关的码制表，来表达汉字的计算机识别的需要，例如中华人民共和国的GB2312码，日本的JISX码和韩国的KSC码等。

提示巧合的是，这些编码方案大多吸收了ASCII码来作为其表述英文内容的解决方案，因此码制的前128个字符的排列顺序和表述意义和ASCII码是一致的，这也在一定程度上反映了ASCII码的强势地位。

应该承认，在相对封闭的环境中，这些不同的码制的实现都为所在国和地区的文字计算机化提供了较为完整的解决方案，这也是为什么这些码制大多至今仍然存在，甚至有所发展的原因（如中华人民共和国所强制推行的、在华发行软件必须遵守的编码规范GB18030-2000，就是对GB2312进行了改进，使之融合了更多汉字及少数民族文字，并在一定程度上和Unicode编码实现了融合）。但随着电子文档在国际间的交流日隆，因为码制的不同而带来的问题也日益显示了出来。

例"%src%/%4_1%/index.htm"可以帮助读者了解问题所带来的“危害”，在该例中显示了字符在GB2312码制下和在Big5码制下的编码，并同时给出了在这个编码下，如果使用相对的码制进行解读，返回的字符。从中，读者可以很好地体会因为码制而造成的“沟通不畅”问题。

因此，当计算机应用开始面向全世界时，为应用准备一个统一的码制，便显得尤为重要而急迫了，这不仅仅是出于对多国语言支持的需要，也是为了在涉及字符计算的程序中，可以更加“真实而准确”地反映处理的结果。

当然，相关的方案已经产生，并且也得到了广泛的商业化支持，这个方案就是Unicode编码方案（严格地说，Unicode编码方案曾经分别由两个组织独立制定，但幸运的是，其很快就发现，世界上不需要两套互相竞争的方案，因此进行了相关的方案融合工作）。

Unicode码制在其设计理念上，较以前的码制有所不同。如果包括ASCII码在内的其他码制（如GB2312码干脆就被称为“区位码”，其中，“区”可以看成为代表了平面上的x轴，“位”代表y轴，每个“区位码”就对应了平面上的一个点），都是一个建筑在二维平面上，且一一对应的码制，Unicode编码则可以视为是一种“三维立体”的结构。在这个方案中，不仅增加了"z"轴的概念，还分离了编码和实现的对应关系。因此，Unicode编码组织便呈现出了如下的基本特征。

（1）编码以“平面”（plane）为最大的组织单元进行组织。

在Unicode中，“平面”的信息使用最高字节（从左向右）来表示，其取值范围是0x00～0x10（在本书中，0x代表了下面的编码使用十六进制完成，下同）。也就是说，Unicode目前的规范中，仅支持创建12个不同的平面。其中，第1个平面又被称为基本多语言平面（Basic Multilingual Plane,BMP），用于对所有文化背景下“常用”的字符进行编码，这也是目前获得支持最多的平面。

提示在这里，“常用”并非最合适的词汇，因为就目前的情况看，BMP几乎包含了所有需要用到的字符，不管常用不常用。

表C.2给出了目前的标准中，所支持的主要平面及其意义。

（2）每个“平面”中，按照不同的区段来组织具体的编码。

以BMP平面为例，其按照所进行编码的文字对应的文化背景的不同，分为不同的区段，以此来实现对字符的编码组织。表C.3中列出了部分区段所对应的含义。

提示从中可以看到，从码值角度而言，Unicode编码吸收了ASCII码的成果。本表依据"%src%/4_2"中，Unicode 5.0.0版本所使用的编码字典文件"CodeCharts.pdf"编制而成，读者可以通过查阅该表获得更为详细的Unicode编码区信息。

（3）Unicode标准下的编码规范和传输存储方式之间具有一定的差异。

这在其他的码制规范中的表现并不“明显”，因此许多人认为，其是造成Unicode编码规范“晦涩难懂”的重要原因之一。

但事实绝非如此。实际上，许多编码规范都存在这样的差异性情况。即使在ASCII码中，编码规范和存储传输方式之间也不是一一对应的。ASCII的编码规范要求每个编码占用7个二进制位，而在实际的存储和传输中，则一般使用了8个二进制位（即1字节）来实现，这当然也是不同的，只不过长期以来，一直由于一种“模糊”的宣讲，才使得很多读者都忽视了这一点。

而在Unicode中，由于一个Unicode编码需要3个字节才能完成，这便使得在编码的存储和传输方面产生了许多新的变化，从而使整个规范看上去变得复杂了起来。

例如因为在绝大多数情况下，文件所使用的字符都没有离开BMP平面，所以在表示和存储这些字符时，显然可以采取一种“简化”的方案，即将字符所应该占据的平面编码字节去除，仅保留其在BMP平面内的编码来表示该字符，由于BMP平面的平面编码为0，所以这样做是不会造成表达信息的缺失的。而这显然造成了Unicode编码规范要求和编码的实际表达方面的差异，为此，Unicode的规范制定者专门为其创造了术语UCS-2，即用2字节的Unicode码来表述该种Unicode的编码存储方式。

提示而和其并列的是Unicode用于表达多平面字符的编码方案UCS-4，其使用了4个字节来表示一个字符。颇令人奇怪的是，在这方面它并没有使用3字节来进行表达。当然，如果考虑到硬件在进行数据传送时，一般总是按照字节、双字节、4字节等模式进行，便也不以为奇了。

再例如，由于Unicode码值并非是一个单字节的编码规范，因此，编码在传输、存储和读取时，依据不同的顺序，会造成截然不同的结果。而这也显然促成了Unicode“不得不”为适应各种顺序情况而制定相应的规范。

仍然以UCS-2的编码为例，从Unicode码表中可以查到，0x0065位代表了字符"e"，而0x6500位则代表了另外的字符“攀”。如果某双字节的值为0x0065，那么其究竟是代表"e"还是“攀”，显然是一个从计算机角度都可以接受的结果。

尤其是当数据在网络上传输时，由于数据是陆续地从端口处获得的，因此如果不增加相关的规范，解析引擎根本就无法正确理解所传递数据，应该按照高字节在先还是低字节在先进行处理。下一小节将对此进行更加深入地介绍。

提示作为一种编码规范，Unicode完全可以“强制”要求其编码的传输顺序和存储方法，但Unicode之所以为此，也正反映出Unicode试图创建一种可以适应于各种历史情况和复杂环境的编码规范。

C.1.3　了解UTF-8

在上一小节，笔者介绍了目前码制发展过程主要形成的一些成果，特别是介绍了有关Unicode编码的一般性知识。在小节的最后，笔者谈到了Unicode编码方案包含了多个层面的意思，其中，编码在传输和读取过程中如何进行组合，也是方案的重要组成部分。本小节即将就此进一步地进行有关的说明。

熟悉网络应用的读者大多知道，在Web浏览中，直接使用术语Unicode（或者用来表征其存储方式的UCS-2或UCS-4）来表示所浏览文件的编码的情况，是几乎不可见的。

在Web中，更多的情况是：在出现需要使用Unicode的场合，都使用了名称为UTF-8的编码来替代。打开IE浏览器，在任何一个页面，使用鼠标右键单击，更可以在其“编码”菜单的子菜单中，看到图C.1所示的编码列表，其中，清晰地标明了Unicode（UTF-8），其所代表的意思显然是：IE浏览器认为，UTF-8就是其所选用的Unicode编码方案。

图　C.1　IE浏览器使用UTF-8示意图

那么，了解在UTF-8和Unicode之间所存在的“特殊”的对应关系，对于相关的编程人员而言，自然是一个比较重要的内容。而结合本小节开始时笔者的说明，不难想到，UTF-8应该是Unicode在传输和读取方面的一种特殊的规范，事实也的确如此。下面就将对此给予一定的介绍。

提示这对于Ajax的编程尤其重要，因为在Ajax的规范中明确规定，所有通过XMLHttpRequest对象的responseText属性所获得的内容，都是以UTF-8作为其“编码”标准的。

（1）UTF-8编码下的字符可以在“数学运算”的帮助下还原为Unicode编码。

之所以使用“数学运算”，而非“算法”，表明了在此处，还原的行为不需要借助任何其他的资源（如一张大的UTF-8和Unicode编码对应表），而仅需要经过简单地加减乘除就可以完成。

也就是说，UTF-8的码表的编制是以Unicode码表为蓝本，经过简单的数学转换而得到的。在阅读完本小节之后，相信读者也会具有这样的能力，当然，作为一个范例，笔者也会在后面的例子中给予实现。

（2）UTF-8是和ASCII码紧密关联的编码方案。

结合上面的讲解，读者应该清楚，对于Unicode编码而言，其BMP平面下的0x0000-0x007F段中的编码和ASCII码是一一对应的，二者之间的区别仅在于各自理论占用的空间不同。因此，当ASCII码数据在网络上进行传播时，即使使用UCS-2的方案，理论上使用Unicode编码传送的数据量也会比使用ASCII码增大一倍。

因此，为了更好地传送数据，降低ASCII码数据的传送流量，UTF-8将自身的编码规则设计成为了一种特殊的变宽的格式，从而实现了在ASCII部分，UTF-8编码和ASCII码的重合，即都使用1字节即可完成编码（这样做的好处是显而易见的，对于完全使用ASCII编写的文件，可以不加任何编码转换地应用到UTF-8的场合）。

表C.4给出了UTF-8和Unicode编码之间转换的标准，从中读者不难看到UTF-8在变宽方面的一些特征，其是一个跨度为1～4个字节的Unicode编码方案（其中，Unicode码特征和UTF-8变宽标准都使用二进制进行表述，笔者觉得，这样可以更加清晰地体现问题的实质）。

提示在现在的Unicode编码中，平面编码最大值仅为0x10（即二进制00010000），因此对于目前的所有非BMP平面的编码而言，最高位的u值总为0，而之所以写作成表C.4所示的模式，则纯粹是为了使得UTF-8的变宽标准看起来更具规律性。

从表C.4中可以看出，虽然其实现了和ASCII码的重合，但是当表述的对象转为其他文字，如汉字时，其编码空间甚至比使用UCS-2还要更大。例"%src%/%4_3%/index.htm"给出了通过编程手段，获取UTF-8编码字符所对应Unicode码的实现方法。作为一个练习，读者可以自行完成其反过程，即将一个字符的Unicode码转化为对应的UTF-8码。笔者相信，在具备了上述知识后，这是一个非常容易实现的过程。

技巧　在PHP中实现该功能时，最为重要的两个技巧是，一方面要了解PHP是以字节作为其字符处理对象的；另一方面，字符的ord()函数所返回的值就是存储于该字节的内容的二进制数值表达形式。同时，要特别注意，在PHP中，位运算符“＆”的优先级较“＞＞”为弱，因此需要使用括号（“()”）来强制其进行优先运算。

（3）UTF-8“建议”使用相关BOM标志作为其传输文件头，便于解析器进行解读。

这是对于UTF-8及其相关编码方式的一个比较“特别”的内容。在Web编程中，由于该内容而导致出现程序问题的情况并不多见，这主要是因为程序在调用后台服务的时候，很少会涉及诸如服务器需要发送特殊头信息等问题。

但是在传统的PHP编程中，这确是一个比较常见的问题。下例"%src%/%4_4%/index.php"所希望实现的功能是：当用户访问index.php时，系统会通过header()函数发送重定向的命令，将用户的访问重定向至index2.php。

文件index.php使用Windows XP自带的记事本程序进行编写，并在编码处选择UTF-8格式进行保存。在浏览器中浏览该网页，则会发现，其并未按照事先的预想重新载入index2.php页面，而是出现了图C.2所示的结果。

图　C.2　调用index.php的处理结果图

该警示的意思是：PHP在通过header函数发送头信息时，不允许在此之前有任何的输出。但是查阅index.php源代码，结果却令人沮丧，在header前根本就不存在任何输出，如下所示：

＜?php

header("location:index2.php");

?＞

那么，究竟问题发生在哪儿呢？事实上，问题的根源就在于UTF-8文件的BOM标志上。

首先来解释一下关于BOM的概念，BOM是Byte Order Mark的简称，如果进行直译，可以翻译为：字节顺序标志。也就是说，BOM是用来指示字节排列顺序的。

在C.1.2的最后，笔者给出了在进行UCS-2编码传输过程中，因为对字节序排列的理解不相一致，而造成的理解错误的例子。正是出于解决该问题的考虑，Unicode规范提出了BOM的方案，该方案要求：在Unicode文件的开始字节，附加一个特殊的传递标志，用于表示后面的Unicode文本按照怎样的字节序来进行处理。

例如，对于UCS-2而言，如果其传输时是按照高字节在先的模式，则其首字节的内容为0xFEFF（该Unicode码表示一0长度的空格），该模式也被称为UTF-16BE；而如果传输是按照小字节在先的模式进行的，则首字节内容为0xFFFE，对应的模式被称为UTF-16LE。

显然，对于按照UTF-16（或者说按照UCS-2）进行编码传输的文本而言，BOM的指示作用是非常必要的，但是如果按照UTF-8的模式进行传输，结合上小节的讲解可以知道，其是通过一种特殊的编码规则来对Unicode码进行处理后传输的，因此BOM便成为了一种可有可无的“鸡肋”，根本不对解析产生任何的作用。

可能正是因为这个原因，各个文本的编辑器或解析器在对待UTF-8文本上的“态度”便截然不同起来。在上面所举的范例中，代码的编辑器就遵从了Unicode对于UTF-8中BOM的规定，在其所编辑的UTF-8文件的头部放置了用于标志该文件为使用UTF-8规范进行编码的标志0xEFBBBF（这甚至已经无法归属到现在的任何一个Unicode平面中了）。

但是对于PHP的解析器而言，其并未遵循该规范来处理UTF-8文件，因此对于在"＜?php……?＞"段之前的0xEFBBBF，PHP遵循了对于非PHP段的内容便输出的处理标准，将其输出至浏览器端。而在这之后，调用header函数时，便不符合该函数要求在其被调用之前不得有任何输出的规范了。这就是出现上述问题的原因所在。而修改该问题的方法也同时变得清晰起来，就是换用一种在编写UTF-8文件时，不用为其附加0xEFBBBF的BOM标志的编辑器来完成文件的编辑工作，如Eclipe。再次浏览本网页，相信读者可以看到和预想一致的结果了。

提示从总的方面看，我们更愿意将此视为PHP的一个至今没有解决的Bug。但这也反过来提醒我们，规范的制定应该是这个世界上最简单也最复杂的事情。说其简单，是因为规范的制定者具有对规范100%的控制权，其完全可以随心所欲之。而说其复杂，则是因为如果规范本身便或可有可无，或晦涩难懂，或违背常理，则其所造成的混乱有时候也是不可控制的，因此规范的制定者还是应该慎重行事为好。

在下一节，将开始讨论另外一种编码形式，即URL编码。这是一种基于HTTP传输要求而产生的编码形式，和Unicode一样，其在PHP+Ajax应用中也具有非常重要的意义，因此，十分值得读者去进行较深入的研究。

C.2　浏览器的编码和解码

在上一节对计算机常用的编码，特别是UTF-8编码进行了研究，本节则将针对另外的一种编码体系进行研究。和UTF-8主要用于网络数据编码一样，该编码体系也有其特定的或者说主要的应用场合，即编码主要用于在HTTP中进行网络数据传输，这种编码的名称为URL编码。

C.2.1　URL编码的目的

在使用PHP+Ajax进行POST数据传递时，通常需要发送application/x-www-form-urlencoded头信息来指示服务器对所发送的头信息进行解码，这种解码的结果是形成为可通过$_POST变量进行访问的数组。

显然在此处，application/x-www-form-urlencoded的作用是非常重要的。在使用该信息进行传输时，有经验的开发人员总是借助encodeURIComponent函数对所传输的内容进行“包装”。

首先谈论为什么需要进行这样的“包装”。这主要是基于以下的两点考虑。

（1）确保特殊字符可以通过Internet安全地传输。

如果用户输入的数据中存在足以混淆服务器进行判断的字符“＆”，则服务器对数据的解析可能会和用户所设想的相差甚远。因此需要制定特殊的规则来进行该数据的传输，例如使用URL标准所制定的“%26”，这样才可以有效地保护数据的传输不被玷污。

提示URL编码规范要求，对于类似“＆”这样的字符，都必须使用其所对应的编码进行传输，而不能使用明文传输，这类字符统一被称为"Unsafe"字符（即不安全的字符）。除了“＆”外，所有的ASCII码控制符，以及一些和HTML标记相冲突的符号，如“＜”、“＞”、“#”等，都需要使用对应的URL编码来进行传输。读者可以参考RFC 1738文档中查询全部说明，该文档是URL编码规范所遵循的主要文档之一。

（2）确保数据传输的完整性。

这方面最为典型的例子则是关于非ASCII码数据的传输。在Internet世界中，由于网络连接所使用的设备具有不可确定性，因此传输标准必须按照所有网络设备中的“最短板”为基准来进行设计。这个标准就是7位的ASCII码。这便带来了一个问题，就是当所传输的字节数据的首位并不为0时，该数据便无法准确地到达目的地，会产生缺失。因此制定一个原则来确保所传输的数据都在ASCII码范围内，显然是非常必要的。

C.2.2 URL编码方法

如上小节所述，详细的URL编码方法主要是由RFC 1738协议所规定的。对于PHP+Ajax的编程者而言，详细地了解URL的编码方法，特别是JavaScript在该方面的表现，对于有效地处理需要向服务器端传递的数据，意义重大。毕竟和传统的使用Form表单进行数据传递有所不同，在使用Ajax模式传递数据时，需要手动处理所传递的参数，而不是由浏览器来完成这一过程。

提示在前书中已经介绍过，在使用Form表单进行数据传递时，表单所遵循的缺省编码方式就是application/x-www-form-urlencoded，这是通过表单的mime属性来表达的。而提交（submit）动作所触发的缺省行为之一，就是将当前需要传递的数据进行名值对封装并URL编码。

当然，作为一种编码方式，URL编码的原则并不复杂，其建制的基本原则如下。

❑字符的URL编码以字节为单位，采用“%+字节所对应十六进制值”的形式组织。

❑处于Unsafe（非安全）模式的字符，必须使用URL编码形式表达。

例如，小节中所介绍的“＆”的URL编码是“%26”，如果查阅表C.1，便不难发现，符号“＆”所对应的十六进制码正是0x26。

光盘内容

光盘下载地址：http://pan.baidu.com/s/1jGl0s1g