学习 PHP,第 1 部分: 注册帐户、上传需要批准的文件、并查看和下载已批准的文件

来源:互联网 发布:达内java培优班笔试题 编辑:程序博客网 时间:2024/05/17 22:06

开始之前

在本系列的第一部分中,我们将了解基本的 PHP 语法、表单和函数,以及如何连接到您的 PHP 应用程序,并通过它使用 MySQL 或者其他任何数据库。

关于本教程

本教程将引导您使用 PHP 创建一个简单的工作流应用程序。用户可以注册帐户,上传需要批准的文件,并查看和下载已获批准的文件。指派为管理员的用户可以查看和批准上传的文件,让所有用户都能使用这些文件。本系列的第 2 部分 和 第 3 部分 将探讨 HTTP密码保护、XML、JASON 和其他相关问题。

本教程的主要内容如下:

  • 创建基本的页面
  • 变量、循环和 if-then 语句
  • 函数
  • 连接到数据库
  • 使用 include 文件
  • 工具

谁应该阅读本教程?

如果您是一名希望学习使用 PHP 构建基于 Web 的应用程序的程序员,那么可以从这里开始,本系列教程由三部分组成,这是第 1 部分。PHP 虽然是一门易学的基于脚本的语言,但仍然能够帮您建立功能强大的复杂应用程序。本教程将详细介绍如何使用 HTML 表单创建基本的 PHP 页面。本文还将介绍如何访问数据库。

先决条件

本教程假设您没有 PHP 经验。实际上,尽管熟悉 HTML 的概念会很有帮助,但本教程不要求掌握其他编程语言知识。请随时 下载 本教程中所使用的源代码。

系统要求

您需要一台 Web 服务器、PHP 和一个已安装并且可用的数据库。如果您已经拥有一个主机帐户,那么只需在服务器上安装 PHP V5,并且能够访问某个 MySQL 数据库,您就可以使用该帐户。否则,请下载并安装以下程序包:

XAMPP
无论您是在 Windows® 、Linux® 还是 Mac 上,都需要获得本教程的所有必需软件,最简单的方法是安装 XAMPP,它包括一个 Web 服务器、PHP 和 MySQL 数据库引擎。如果您选择采用这种方法,只需安装 XAMPP,然后运行控制面板,启动 Apache 和 MySQL 进程。您也可以选择分别安装各个部件,但要记住,您必须配置它们,使它们能够协同工作,这一步已经由 XAMPP 解决了。
Web 服务器
如果您选择不使用 XAMPP,那么对 Web 服务器有几个选项可供选择。如果您使用的是 PHP 5.4(在撰写本文时,XAMPP 只使用 PHP 5.3.8),那么您可以使用内置 Web 服务器 进行测试。但是,对于生产环境,我会假设您正在使用的是 Apache Web 服务器,版本 2.x。
PHP 5.x
如果您没有使用 XAMPP,那么需要单独下载 PHP5.x。其标准发行版包括您在本教程中需要的一切。可以随时下载二进制文件;您将不再需要本教程的源代码(或永远不需要它,除非您想破解 PHP 本身)。本教程的编写和测试都是在 PHP 5.3.8 上完成的。
MySQL
该项目的一部分涉及将数据保存到数据库中,所以您还需要一个数据库。同样,如果您已经安装了 XAMPP,那么可以跳过这一步,但如果您愿意的话,还可以单独安装一个数据库。在本教程中,我将以 MySQL 为主,因为这是与 PHP 结合使用的最常见的数据库,如果您选择使用该数据库,那么可以下载并安装 Community Server。

基本 PHP 语法

我们来看一看使用 PHP 创建页面的一些基础知识。下一节将介绍如何使用 HTML 表单向 PHP 提交信息,但首先您需要了解如何完成一些基本任务。

基本的 PHP 页面

首先,打开您的文本编辑器,并创建一个最基本的 PHP 页面(参见 清单 1)。

清单 1. 基本的 PHP 页面
<html>   <title>Workflow Registration</title>   <body>      <p>You entered:</p>      <p><?php echo "Some Data"; ?></p>   </body></html>

从整体来说,您有一个简单的 HTML 页面,页面上包含一段以粗体显示的 PHP 代码。当服务器遇到 <?php 符号时,就知道要计算后面的命令,而不是直接将它们发送给浏览器。它保存后面的指令(稍后讨论),直到这一段代码结束,以遇到?> 符号为标志。

在本例中,只需使用一条命令,即 echo,它告诉服务器输出给定的文本。这意味着,如果您保存该页面,然后通过浏览器调用它(您等一会儿就要这样做),浏览器将收到如清单 2 所显示的页面。

清单 2. 浏览器收到的 PHP 页面
<html>   <title>Workflow Registration</title>   <body>      <p>You entered:</p>      <p>Some Data</p>   </body></html>

为了查看这一项操作,可以将该文件保存为 registration_action.php,并转移到服务器的文档根目录下。对于 XAMPP,根目录是 <XAMPP_HOME>/htdocs。(对于 Apache,根目录可能是 /var/www/html。)

要调用该页面,请打开您的浏览器并将它指向 http://localhost/registration_action.php。您会看到类似 图 1 的结果。

图 1. echo 命令的输出
echo 命令的输出

恭喜您,您已经完成了您的第一个 PHP 页面。您使用该语言执行的其他所有操作都将以此为基础。

变量

变量是数据的占位符。变量可以赋值,这之后,只要 PHP 遇到该变量,就会使用赋予它的值来代替它。比如,将您的页面更改为如 清单 3 所示。

清单 3. 在您的 PHP 页面中使用变量
<html>   <title>Workflow Registration</title>   <body>      <p>You entered:</p>         <?php         $username = "nick";         $password = "mypassword";         echo "<p>Username = " . $username . "</p>";         echo "<p>Password = " . $password . "</p>";      ?>   </body></html>

首先要注意的是,每一行都必须以分号结束。其次,要注意使用句点 (.) 连接 文本,或者说将它们合并在一起。您可以采用这种方法将任意数量的字符串或文本块合并在一起。

关于变量,还有一点需要注意:在 PHP 中,变量名是区分大小写的,因此 $UserName$username 是不同的变量。

采用一致的命名约定,比如决定对所有变量都使用小写形式,这可以在很大程度上防止出现无法匹配的错误。

保存文件(并在必要时上传它),并刷新浏览器。您应该会看到类似 图 2 的结果。

图 2. 刷新后的浏览器
浏览器刷新

在继续下一步的讨论之前,首先看一类特殊的变量。

常量

您可以将变量的值更改任意次数,但在设置变量时,有时您可能会希望它的值不会改变。这些项不再被称为变量,而是将它们称为常量。例如,您可能希望定义一个常量,用它来表示每个页面的标题,如清单 4 所示。

清单 4. 定义一个常量
<?php   define("PAGE_TITLE", "Workflow Registration");?><html>   <title><?php echo PAGE_TITLE ?></title>   <body>      <p>You entered:</p>      ...

(现在看起来这样做似乎意义不大,但是您在后面将会看到,这个定义可以在多个页面中使用。)

请注意,您需要定义常量的名称和值。如果您试图在定义常量之后再更改它的值,那么您会收到一个错误消息。

还要注意的是,在引用常量时,比如在 title 元素中,不使用美元符号,仅使用常量的名称。常量的命名并没有限制,但按照惯例是全部采用大写字母。

稍后,当您了解对象的时候,就会看到用来指定常数的一个稍微紧凑一些的方法。

更简单的输出

到目前为止,您已经使用了 echo 命令输出信息,但是如果输出的数据只有一个,那么该命令可能显得比较麻烦。

所幸的是,PHP 提供了一种更简单的方法。通过使用输出运算符构造 <?= ?>,您可以指定要输出的信息,如 清单 5 所示。

清单 5. 使用输出运算符
<?php   define("PAGE_TITLE", "Workflow Registration");?><html>   <title><?= PAGE_TITLE ?></title>   <body>      <p>You entered:</p>      ...

注意,在使用输出运算符时,信息后面没有分号。

稍后,我们将了解其他基本的 PHP 构造,比如 if-then 语句,因为在构建应用程序时会用到它们。

PHP 和表单

在这一节中,我们将了解数组,以及使用表单数据的方法。我们还将了解如何控制 PHP 脚本的流程,比如循环和 if-then 语句。

在 PHP 中创建和使用表单

开发人员将 PHP 创建为一种 Web 编程语言。事实上,虽然可以从命令行中运行 PHP,但很少有人在 Web 应用程序领域以外的地方使用这种语言。结果,PHP 程序员最常见的任务就是使用 Web 表单。

您可以使用 HTML 创建 Web 表单,当用户提交表单时,浏览器会向服务器发送一个信息数组

用 HTML 创建表单

首先为您的应用程序创建注册页面。最终,用户将在这里输入他们的信息,在将这些信息保存到数据库之前,您需要验证它们或者检查它们的完整性。但现在,我们只需要创建一个基本的表单。创建一个名为 registration.php 的新文件,在该文件中添加下面清单 6 中的内容。

清单 6. 创建注册页面
<html>   <head><title>Workflow System</title></head>   <body>      <h1>Register for an Account:</h1>      <form action="registration_action.php" method="GET">         Username: <input type="text" name="name" /><br />         Email: <input type="text" name="email" /><br />         Password: <input type="password" name="pword" /><br />         <input type="submit" value="GO" />      </form>   </body></html>

这是一个简单的表单(包含在 form 元素中),其中有两个文本输入:一个口令输入和一个提交按钮。将该文件保存到文档根目录(与 registration_action.php 一起)中。要打开该文件,请将您的浏览器指向http://localhost/registration.php 并输入每个字段。您应该看到类似图 3 的结果。

图 3. 帐户注册表单
帐户注册表单

注意,口令输入框中没有显示您实际输入的内容;使用这种类型的表单元素是为了掩盖敏感信息,防止有人可能从您背后看到屏幕上的信息。但单击 GO 按钮后会出现什么样的情况呢?

提交表单

在您创建表单时,您创建了一个真正的 form 元素,比如 <form action="registration_action.php" method="GET">

该元素包含两部分的信息。首先,action 告诉浏览器将信息发送到哪里。在本例中,会将信息发送到您之前创建的页面 registration_action.php。其次,method 会告诉浏览器如何发送数据。

让我们看看这些操作是如何实现的。填充一些数据(如果您还没有输入数据)并单击 GO 按钮。您应该看到类似于 图 4 的结果。

图 4. 输出数据
输出数据

在本例中,请注意,信息似乎是不准确的(并不是您真正提交的信息),但这是因为您尚未调整用于查看提交数据的页面。但请检查一下 URL:http://localhost/registration_action.php?name=nickChase&email=nickchase%40noTooMi.com&pword=asupersecretpassword

请注意,对于有名称的每个表单元素,URL 中都包含用地址符号分隔的一个名值对。URL 采用这种格式是因为您使用了 GET 方法,它告诉浏览器以这种方式发送数据。我们还将学习如何使用 POST,这涉及到使用不同的方式发送数据,不过,让我们首先来看看如何从 PHP 页面中检索此数据。

访问表单数据

现在已经提交了表单,您还需要将数据放到真正的响应页面 registration_action.php 中。对该文件进行如 清单 7 所示的更改。

清单 7. 将数据放入响应页面
...   <body>      <p>You entered:</p>      <?php         $username = $_GET['name'];         $password = $_GET['pword'];s         echo "<p>Username = " . $username . "</p>";         echo "<p>Password = " . $password . "</p>";      ?>   </body></html>

您要做的就是从 $_GET 数组中获取指定值。后面很快将会进一步讨论数组,但目前要注意的是,如果您刷新浏览器,页面上就会显示您的真正回答,如图 5 所示。

图 5. 浏览器中的正确信息
浏览器中的正确信息

您可以按照名称获得所有提交的信息,因为这是一个数组,所以还可选择其他方式。

数组

PHP 允许您创建数组或者值列表,以便能够很方便地同时引用一组值。比如,您可以创建一个由多个值组成的数组,并将这些值输出到页面(参见 清单 8)。

清单 8. 创建一个由多个值组成的数组
$formnames = array("name", "email", "pword");echo "0=".$formnames[0]."<br />";echo "1=".$formnames[1]."<br />";echo "2=".$formnames[2]."<br />";

array() 函数返回一个值,该值是一个数组,由传递给函数的值所组成。(在后面将会讨论函数,现在只需要知道如何调用函数,并将函数返回的值赋给某个变量即可。)

请注意,第一个值的索引是 0,不是 1。还要注意的是,通过在数组变量名称后的括号内添加索引,可以指定您想要的值。该脚本产生的输出如 清单 9 所示。

清单 9. 数组输出
0=name<br />1=email<br />2=pword<br />

这项操作与访问表单数据的方式类似,但这并不是偶然的。$_GET 变量是一种特殊类型的数组,称为 associative(关联)数组,也就是说,每个值都不使用数字索引,而是使用key(键)

当您提交表单的时候,实际上创建了一个数组,如 清单 10 所示。

清单 10. 通过提交表单创建一个数组
$_GET = array("name" => "roadnick", "email" => "ibmquestions@nicholaschase.com", pword" => "supersecretpassword");

该数组支持您提取单个的值,比如 $_GET["name"]。不过,您不必逐个值提取它们。

按编号获得数组信息

在处理数据时,使用关联数组非常方便,但经常会遇到您不知道数组是什么结构的情况。例如,您可能创建了一个通用数据库例程,从某个查询接收关联数组。

幸运的是,PHP 提供了两个函数,可以让您稍微轻松一点(参见 清单 11)。

清单 11. array_keys()array_values() 函数
...<body>   <p>You entered:</p>      <?php      $form_names = array_keys($_GET);      $form_values = array_values($_GET);      echo "<p>" . $form_names[0] . " = " . $form_values[0] . "</p>";      echo "<p>" . $form_names[1] . " = " . $form_values[1] . "</p>";      echo "<p>" . $form_names[2] . " = " . $form_values[2] . "</p>";    ?></body>...

array_keys()array_values() 函数都返回信息的常规数字索引数组,因此您可以使用数字索引从这两个数组中获取数据,如图 6 所示。

图 6. 使用数字索引提取数据的数组
使用数字索引提取数据

但是,应该还有更方便的办法。比方说,如果您实际上并不知道有多少个值,该怎么办?PHP 提供了处理关联数组的多种方式,哪一种最方便则由已经掌握的信息来决定。我们接下来看看完成同样任务的两种其他方法。

使用 for-next 循环

PHP 中最常见的一项任务是遍历一组值。您可以使用一个 for-next 循环轻松地完成这项操作。for-next 循环将会根据定义来遍历一组值。让我们来看一下清单 12 的示例中的循环。

清单 12. for-next 循环
for ($i = 0; $i < 10; $i++) {   echo $i . " ";}

PHP 首先将 0 赋给 $i,因为这是在循环的开始所定义的,只要 $i 小于 10,循环就会继续下去,每执行一次循环,PHP 就会将$i 的值加 1。以下是输出:

0 1 2 3 4 5 6 7 8 9

这意味着,如果您可以知道 $_GET 数组中有多少个值(这是您可以做到的),您就可以轻松遍历表单所提供的所有值,如 清单 13 所示。

清单 13. 遍历表单提供的所有值
...<body>   <p>You entered:</p>   <?php      $form_names = array_keys($_GET);      $form_values = array_values($_GET);         for ($i = 0; $i < sizeof($_GET); $i++) {         echo "<p>".$form_names[$i]." = " . $form_values[$i] . "</p>";      }        ?></body>...

sizeof() 函数告诉您 $_GET 数组中包含多少个值。您可以使用该数据确定何时结束循环,如 图 7 所示。

图 7. 使用 sizeof 函数来结束循环
使用 sizeof 函数来结束循环

$_GET 是一个关联数组,而您实际上还有另一种选择:foreach 循环。

使用 foreach 循环

关联数组在 PHP 中很常见,而该语言还提供了一种很简单的方法来获得其中的数据,不需要经过提取键和值的过程。但是,您还可以使用 foreach 循环,它可以直接操纵数组。例如,试想一下清单 14 中的代码。

清单 14. 使用 foreach 循环
...   $form_values = array_values($_GET);   foreach ($_GET as $value) {      echo "<p>" . $value . "</p>";   }?>...

PHP 第一次执行该循环时,会从 $_GET 数组中取得第一个值,并将该值赋给 $value,然后输出该变量。然后,它返回到循环的顶部,将下一个值赋给$value,依次对 $_GET 中的每个值(也包括名称)执行相同的操作。最终结果是生成 清单 15 中所示的输出。

清单 15. foreach 循环的输出
<p>roadnick</p><p>ibmquestions@nicholaschase.com</p><p>supersecretpassword</p>

但是,更方便的是,它还能提取值 键,如 清单 16 所示。

清单 16. 提取值和键
...   $form_values = array_values($_GET);   foreach ($_GET as $key=>$value) {      echo "<p>" . $key . " = " . $value . "</p>";   }?>...

这会将您再次带回最初的结果(参见 图 8)。

图 8. 最初的结果
最初的结果

多表单值

对于表单值,您需要处理一个偶尔会出现的情况:多个表单值都使用一个名称。比如,由于用户看不到自己输入的密码,您可能希望他们输入两次,以确认他们没有输入错误,您可以将清单 17 中的代码添加到 registration.php:

清单 17. 多个表单值使用一个名称
...Username: <input type="text" name="name" /><br />Email: <input type="text" name="email" /><br />Password: <input type="password" name="pword[]" /><br />Password (again): <input type="password" name="pword[]" /><br /><input type="submit" value="GO" />...

请注意,pword 字段的名称稍微做了一下修改。因为您要检索多个值,所以需要将密码本身看成一个数组。是的,也就是说,一个数组值本身是另一个数组。那么,如果您现在提交表单,那么它会创建一个 URL:http://localhost/registration_action.php?name=nickChase&email=nickchase%40noTooMi.com&pword%5B%5D=asupersecretpassword&pword%5B%5D=asupersecretpassword

(值 %5B%5D 是 URL 编码版本的 []。)

提交表单相当于创建数组(参见 清单 18)。

清单 18. 提交表单相当于创建数组
$passwords = array("asupersecretpassword", "asupersecretpassword");$_GET = array("name"=>"nickChase",                "email"=>"nickChase@noTooMi.com",                "pword"=>$passwords);

这意味着如果您想查看密码值,就需要将它们作为数字数组来访问,如 清单 19 所示。

清单 19. 将密码值作为数字数组来访问
...foreach ($_GET as $key=>$value) {   echo "<p>".$key." = " . $value . "</p>";}$passwords = $_GET["pword"];echo "First password = ".$passwords[0];echo "<br />";echo "Second password = ".$passwords[1];...

如果您提交表单(或者刷新页面),就会看到其中的差别,如 图 9 所示。

图 9. 提交表单
提交表单

请注意,密码字段现在作为 Array 输出,但是您可以直接访问它的值。

使用 GET 和 使用 POST 的比较

到目前为止,我们一直使用 GET 方法来提交数据,如您所见,这种方法将数据直接放在 URL 中。这样做有时候很合适,但有时候不合适。比如,您可以通过这种技术使用链接来模仿表单的提交,但是如果有大量的数据(比方说数据来自用户可以输入注释的textarea),那么这项技术就不是达到目标的最佳方法。原因之一是,Web 服务器通常限制它们能够在 GET 请求中接收的字符个数。

另一个原因是,好的技术和标准要求告诉我们,永远不要使用 GET 执行有 “副作用” 的操作或者真正什么事情的操作。比如说,现在您只是查看数据,这不会产生影响操作的副作用。但是,您最终要将数据添加到数据库中,根据定义,这就会产生副作用。

很多 Web 程序员不知道这种特殊的限制,因此可能造成问题。使用 GET(尤其是将它作为 URL 使用)有可能导致系统多次执行某项操作,因为用户将其添加到了收藏夹,或者因为搜索引擎索引了该 URL,并不知道实际上它是在更新数据库或者执行其他某项操作。

因此,在这些情况下,您必须改为使用 POST

使用 POST

使用 POST 方法代替 GET 方法实际上非常简单。首先,您需要更改 registration.php 页面,如清单 20 所示。

清单 20. 在注册页面上使用 POST 方法代替 GET
...<h1>Register for an Account:</h1><form action="registration_action.php" method="POST">   Username: <input type="text" name="name" /><br />...

现在,当您提交该表单时,URL 会变得非常干净:

http://localhost/registration_action.php

要检索数据,您有两个选择。第一,使用 registration_action.php 中的 $_POST 数组,而不是 $_GET 数组,如 清单 21 所示。

清单 21. 使用 $_POST 数组检索数据
...<body>   <p>You entered:</p>   <?php      foreach ($_POST as $key=>$value) {         echo "<p>".$key." = " . $value . "</p>";      }      $passwords = $_POST["pword"];      echo "First password = ".$passwords[0];      echo "<br />";      echo "Second password = ".$passwords[1];   ?></body>...

使用 $_POST 数组的方式与使用 $_GET 数组的方式完全相同。

这种方法的好处是,您可以准确地控制您的脚本要寻找什么。坏处是,如果您想要把某个东西放在 URL 中进行调试,则必须更改您的脚本。解决这个问题的一个常用方法是使用第三个数组$_REQUEST,它包括传递给这两个地方的数据(参见 清单 22)。

清单 22. 使用 $_REQUEST 数组进行调试
...   <?php      foreach ($_REQUEST as $key=>$value) {         echo "<p>".$key." = " . $value . "</p>";      }      $passwords = $_REQUEST["pword"];      echo "First password = ".$passwords[0];...

错误检查:if-then 语句

转入下一节之前,如果无法确保用户两次输入的密码可以匹配,那么要求用户这样做就没有任何意义。因此,您需要使用 if-then 语句,如 清单 23 所示。

清单 23. 使用 if-then 语句
...$passwords = $_POST["pword"];echo "First password = ".$passwords[0];echo "<br />";echo "Second password = ".$passwords[1];if ($passwords[0] == $passwords[1]) {   echo "<p>Passwords match. Thank you.</p>";} else {   echo "<p>Passwords don't match. Please try again.</p>";}...

在 if-then 语句中,如果括号中的表达式(该例中为 $passwords[0] == $passwords[1])成立,那么 PHP 将执行第一对括号中的语句,否则不执行任何语句。在本例中,还提供了该语句不成立时需要执行的替代操作。

需要注意的是,这里没有使用单个等号的 $passwords[0] = $passwords[1],而是使用了双等号的 $passwords[0] == $passwords[1]。双等号是比较运算符。它实际上用于检查两者是否相等。单等号是赋值运算符。如果使用单等号,在执行该语句时,PHP 会将$passwords[1] 的值赋给 $passwords[0],这显然违背了您的意愿。

在本例中,如果密码不匹配,那么会在页面上向用户发出警告,如 图 10 所示。

图 10. 密码不匹配时发出的警告
密码不匹配

还有两个方便的运算符,分别是运算符 (&&) 和运算符 (||)。清单 24 中显示了它们的实际使用。

清单 24. 运算符
if (($today == "Monday") && ($status == "Not a holiday")) {   echo "GO TO WORK!!!";}

在本例中,只有当今天是星期一并且不是节假日时,表达式才成立。但对于运算符,只要有一个条件成立,就会返回 true。

函数

是时候更深入地了解 PHP 了,看看在 PHP 中如何实现一些函数,从而帮助您节省时间。

创建一个函数

在您构建比较大的应用程序时,常常遇到需要反复使用的操作、计算或者其他代码段。

在这些情况下,取出这些代码并使用它创建一个函数会非常有用。例如,您可以取出密码验证,并将它放在单独的函数中,如 清单 25 所示。

清单 25. 创建一个函数
...<body>   <p>You entered:</p>   <?php      function checkPasswords($firstPass, $secondPass){         if ($firstPass == $secondPass) {            echo "<p>Passwords match. Thank you.</p>";         } else {            echo "<p>Passwords don't match. Please try again.</p>";         }      }      foreach ($_POST as $key=>$value) {         echo "<p>".$key." = " . $value . "</p>";      }      $passwords = $_POST["pword"];      echo "First password = ".$passwords[0];      echo "<br />";      echo "Second password = ".$passwords[1];   ?></body>...

在服务器处理这个页面时,如果遇到关键字 function,那么它会知道在收到专门的请求后才执行这段代码。因此,在该页面上仍将首先执行foreach 循环,如 图 11 所示。

图 11. 执行 foreach 循环
执行 foreach 循环

那么如何实际使用函数呢?

调用函数

调用函数的方式是,使用函数名称,后面跟一对括号。如果您打算像本例这样使用参数的话,可以将参数放在括号中,如 清单 26 所示。

清单 26. 调用函数
...<body>   <p>You entered:</p>      <?php      function checkPasswords($firstPass, $secondPass){         if ($firstPass == $secondPass) {            echo "<p>Passwords match. Thank you.</p>";         } else {            echo "<p>Passwords don't match. Please try again.</p>";         }      }      foreach ($_POST as $key=>$value) {         echo "<p>".$key." = " . $value . "</p>";      }      $passwords = $_POST["pword"];      echo "First password = ".$passwords[0];      echo "<br />";      echo "Second password = ".$passwords[1];      checkPasswords($passwords[0], $passwords[1]);   ?></body>...

在 PHP 执行这个页面时,它会首先执行 foreach 循环,输出密码,然后执行 checkPasswords() 函数,并将两次密码输入作为参数传递。(参见图 12)。(您也可以传递数组,然后在函数内部取出每个值。)

图 12. 在 foreach 循环之后执行 checkPasswords() 函数
执行 checkPasswords()

如果您曾经使用过其他编程语言,那么您可能认为它更像是子例程,因为目标是执行一段代码而不是返回值。您可以通过这两种方法使用函数,如后面所述。

返回值

除了使用函数执行代码段之外,还可以使用函数执行某项操作并返回一个值,这往往很有帮助。比如,您可以创建一个验证函数来执行一系列操作,然后返回一个值表明是否有问题(参见清单 27)。

清单 27. 返回值
...<body>   <p>You entered:</p>   <?php         function validate($allSubmitted){         $message = "";         $passwords = $allSubmitted["pword"];         $firstPass = $passwords[0];         $secondPass = $passwords[1];         $username = $allSubmitted["name"];         if ($firstPass != $secondPass) {            $message = $message."Passwords don't match<br />";         }         if (strlen($username) < 5 || strlen($username) > 50){            $message = $message."Username must be \            between 5 and 50 characters<br />";         }         if ($message == ""){            $message = "OK";         }         return $message;      }      function checkPasswords($firstPass, $secondPass){...

该函数接收 $_POST 数组作为参数,然后取出需要检查的信息。首先从一个空 $message 字符串开始,如果密码不匹配,或者用户名的长度(由strlen()string length 函数返回)出错,则向 $message 字符串中添加文本。如果密码匹配并且用户名长度也正确,那么最终会得到一个空的字符串,然后您对其赋值 “OK”,以便可以在页面的正文中检查它,如下一节所述。

验证数据

您已经创建了一个函数,它会根据用户的输入是否适当来返回一个值,因此您现在可以测试这个值(参见 清单 28)。

清单 28. 验证数据
...   echo "<br />";   echo "Second password = ".$passwords[1];      if (validate($_POST) == "OK") {      echo "<p>Thank you for registering!</p>";   } else {      echo "<p>There was a problem with your registration:</p>";      echo validate($_POST);      echo "<p>Please try again.</p>";   } ?>...

在 if-then 语句中检查 validate() 函数的返回值。如果等于 “OK”,则提供一条简单的感谢消息,否则显示消息本身,如图 13 所示。

图 13. 显示的警告信息
显示的警告信息

首先要注意的是,对于测试特定的结果,这种技术方便得多。设想一下,如果将所有这些条件都放在 if-then 语句中,那该有多乱!此外,还要注意的是,该函数在此处调用了两次,这样做效率很低。在生产应用程序中,应该将返回值赋给一个变量,然后检查该变量,不必重复执行此操作。

既然您已经有办法知道所有数据都是正确的,那么现在可以将它们输入到数据库中了。

连接和使用数据库

许多 PHP 应用程序需要使用数据库,我在这一节中会讨论这一点。

选择数据库:使用 PHP 数据对象 (PDO)

因为它是免费提供的,所以许多 PHP 托管计划和发行版中已包括相关的配置,MySQL 通常是绝大多数 PHP 应用程序的首选数据库。生成的代码是 MySQL 特定的,除此之外一切都很好。

不幸的是,这意味着如果进一步走下去,您需要更改数据库,例如,将它更改为 SQLite、IBM® DB2® 或 Oracle,而所有与数据库相关的代码都要重新编写。幸运的是,随着 PHP 数据对象 (PDO) 的出现,它包含到了 PHP 版本 5.3 核心安装中,编写不依赖于特定数据库的、与数据库相关的 PHP 代码成为了可能。

它的工作原理是,使用 PDO 编写您的数据库访问代码,然后提供数据库特定的 PDO 驱动程序。如果要更改您的数据库,只需要提供相应的驱动程序,并更改数据库的 “连接字符串”。

在本例中,将使用 PDO 连接到 MySQL 数据库。如果您使用 XAMPP,您不需要做任何额外配置;MySQL 驱动程序在默认情况下已启用。如果您不使用 XAMPP,您需要确保 php.ini 文件中的以下行已去掉注释:extension=php_pdo.dllextension=php_pdo_mysql.dll

这些 DLL 应该已经存在于 php.ini 文件中的 extension_dir 所指定的位置。

现在,您需要照顾数据库本身。

设置

继续后面的内容之前,您需要创建一个数据库、添加一个表并创建访问它的新用户。

为了转到 MySQL 控制台,如果您已经安装了 XAMPP,那么请键入 清单 29 中的命令。

清单 29. 转到 MySQL 控制台
cd <XAMPP_HOME>mysql/bin/mysql -h localhost -u root

(如果您已经单独安装了 MySQL,并为 root 用户创建了密码,则需要添加 -p 参数并按照要求输入密码)。

进入控制台后,请键入 清单 30 中的代码。

清单 30. 创建数据库
create database workflow;use workflow;create table users (id int auto_increment primary key, username varchar(50),                    email varchar(255), password varchar(50));show tables;

最终输出看起来应类似于 清单 31。

清单 31. 最终输出
>+--------------------+| Tables_in_workflow |+--------------------+| users              |+--------------------+1 row in set (0.00 sec)

最后添加新用户 wfuser,密码为 wfpass(参见 清单 32)。

清单 32. 添加新用户
GRANT ALL PRIVILEGES ON *.* TO 'wfuser'@'localhost'IDENTIFIED BY 'wfpass' WITH GRANT OPTION;

现在,您就可以继续下一步,实际使用数据库。

连接到数据库

如果没有以某种形式与数据库进行交互,那么创建任何较大规模的 Web 应用程序基本上都是不可能的。在您的示例应用程序中,将使用 MySQL 数据库保存用户名和密码信息。在本节中,我们将在注册页面中添加必要的功能,让它能够检查提交的用户名是否惟一,如果是惟一的,则将数据添加到表中。您还要查看已经在数据库中的显示信息。最终,您将创建应用程序的登录页面。

首先要连接到您在 设置 一节中创建的工作流数据库(参见 清单 33)。

清单 33. 连接到工作流数据库
...if (validate($_POST) == "OK") {   $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');   echo "<p>Thank you for registering!</p>";} else {   echo "<p>There was a problem with your registration:</p>";...

这里,您建立了一个新对象 $dbh。您将在本系列后面的文章中学习有关对象的更多内容,但现在,您可以将对象视为您要使用的多个函数的集合。

对象使用数据库的 “连接字符串” (mysql:host=localhost;dbname=workflow) 以及用户名和密码来连接 MySQL 数据库。(不同的数据库有不同类型的连接字符串。)

假设一切顺利,此连接将保持打开,直到您销毁对象(您很快会看到),或直到页面的处理已完成。

您现在已经为插入用户数据做好了准备。

插入记录

现在是时候将数据添加到您之前创建的用户表了。要添加数据,则需要创建一个 SQL 语句来将数据插入这个表,然后执行该语句。

该语句的形式如 清单 34 所示。

清单 34. 将数据插入表的 SQL 语句
insert into users (username, email, password) values                  ('roadnick', 'ibmquestions@nicholaschase.com', 'supersecretpassword')

现在,如果您在创建表时有特别注意,您可能想知道 id 列上发生了什么事。您将第一列指定为 AUTO_INCREMENT,所以,如果您离开它,就像这里采用的做法一样,MySQL 会自动使用下一个可用的整数来填充它。

但实际上,插入数据需要的不仅仅是构建 insert 语句。以前的常见实践类似于 清单 35。

清单 35. 插入数据的旧方法
$sql = "insert into users (username, email, password) values \                  ('".$_POST["name"]."', '".$_POST["email"]."', '".$passwords[0]."')

但是,这种构造很容易受到称为 “SQL注入” 的黑客技术的攻击,可能会导致数据被窃取或删除。幸运的是,使用 PDO 而不是直接访问数据库的优点之一是,能够轻松地使用 “预处理语句” 来消除这种风险。下面是该语句的工作原理:

您需要创建或准备语句(参见 清单 36)。

清单 36. 创建语句
...if (validate($_POST) == "OK") {   $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');   $stmt = $dbh->prepare("insert into users (username, email, password) \                                        values (:name, :email, :pword)");   echo "<p>Thank you for registering!</p>";} else {   echo "<p>There was a problem with your registration:</p>";...

请注意 -> 构造。这就是您引用对象的函数或属性的方式。在本例中,您告诉数据库要准备一个带有三个参数的插入语句。

接下来,您需要到将变量 “绑定” 到参数(参见 清单 37)。

清单 37. 将变量绑定到参数
...   $stmt = $dbh->prepare("insert into users (username, email, password) \                                        values (?, ?, ?)");   $stmt->bindParam(1, $name);   $stmt->bindParam(2,  $email);   $stmt->bindParam(3, $pword);   echo "<p>Thank you for registering!</p>";} else {...

这一步会告诉数据库从变量中提取值,并将它用作特定的参数。然后,您可以设置值,并执行语句,如 清单 38 所示。

清单 38. 设置值,并执行语句
...   $stmt = $dbh->prepare("insert into users (username, email, password) \                                        values (?, ?, ?)");   $stmt->bindParam(1, $name);   $stmt->bindParam(2,  $email);   $stmt->bindParam(3, $pword);   $name = $_POST["name"];   $email = $_POST["email"];   $pword = $passwords[0];   $stmt->execute();   echo "<p>Thank you for registering!</p>";} else {...

最终的结果是,数据库用正确的值执行查询,并且不会产生 SQL 注入攻击的风险。(避开特定字符等正确步骤是在后端处理的)。

这样做的另一个好处是,您可以重用预处理语句。只需将新的值赋给 $name$email$pword 变量,并重新执行语句。

现在已经在数据库中添加了信息,下一步则是了解如何将它们取出来。

选择记录

现在就可以向数据库中添加数据了,但是如何知道用户名是否惟一呢?目前还不知道,但是可以通过在执行插入之前检查用户表来对此进行补救(参见 清单 39)。

清单 39. 确保用户名是惟一的
...if (validate($_POST) == "OK") {    $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');    $checkUserStmt = $dbh->prepare("select * from users where username = ?");    $checkUserStmt->bindParam(1, $name);    $name = $_POST["name"];    $checkUserStmt->execute();    if ($checkUserStmt->rowCount() == 0) {            $stmt = $dbh->prepare("insert into users (username, email, password)\                                          values (?, ?, ?)");...        echo "<p>Thank you for registering!</p>";    } else {        echo "There is already a user with that name: <br />";    } } else {...

在本例中,需要创建一个预处理语句,就像您第一次做的那样,但 execute() 函数看起来可能有点不太直观。毕竟,您还没有真正地任何事情,对吧?错了。您在做的是用满足查询(数据库中有用户所输入的用户名的行)的数据填充语句。

如果想知道数据库是否找到任何记录,那么可以检查 rowCount() 函数,它返回查询所找到的行数。如果能够找到的话,则意味着用户名并不是惟一的。

事实上,语句中包含满足查询条件的行的所有信息。接下来,您将检索一组结果。

检索结果

当然,在现实中,如果有人输入了已经存在的用户名,绝对不需要显示所有已存在的用户名,不过,在这里这样做是为了说明如何完成这类工作。

前面已演示了如何使用一个预处理语句。如果您没有使用任何不可信数据(比如用户名或由用户提交的其他信息),那么您可以选择直接执行查询(参见 清单 40)。

清单 40. 直接执行查询
...    } else {        echo "<p>There is already a user with that name: </p>";        $users = $dbh->query("SELECT * FROM users");        $row = $users->fetch();        echo $row["username"] . " -- " . $row["email"] . "<br />";    }...

第一步是通过执行查询填充 $users 语句,该查询将会选择 users 表中的所有行。

接下来,您将使用 fetch() 函数来提取一行。该函数返回一个关联数组,其中包含某一行的数据。键和列名称相同,因此,您可以从 $row 数组中请求相应的值,非常轻松地输出该行的数据。

但本例只是一行。如何访问所有数据呢?

查看所有的结果:while 循环

为了查看所有数据,您可能希望,只要有可以获取的行,页面就会一直获取这些行。要做到这一点,可以建立一个 while 循环(参见 清单 41)。

清单 41. 建立 while 循环
                    ...                          $users = $dbh->query("SELECT * FROM users");        while ($row = $users->fetch()) {            echo $row["username"] . " -- " . $row["email"] . "<br />";        }                           ...

PHP 首先尝试 fetch 一行。如果成功,结果是 true 并会继续显示该行的信息。如果失败(换言之,如果没有更多行要fetch),那么表达式会返回 false,并且 while 循环结束。

查询的结果是目前存在的所有帐户的列表,如 图 14 所示。

图 14. 显示来自一个表的多个行
显示来自一个表的多个行

关闭数据库连接

在继续下一步之前,您需要确保您打开的数据库连接被再次关闭。您可以通过销毁连接到数据库的 PDO 对象来完成该任务(参见 清单 42)。

清单 42. 销毁 PDO 对象
...            echo $row["username"] . " -- " . $row["email"] . "<br />";        }    }     $dbh = null;} else {    echo "<p>There was a problem with your registration:</p>";...

现在,是时候把事情理一理了。

清理:包括文件

到目前为止,您已编写的每个脚本都是自含的,所有代码都放在一个 PHP 文件中。这一节将讨论如何将代码组织到多个文件中。将那些在多个页面中使用的代码段取出来,放在单独的文件中,然后将该文件包括到原来的页面中。

为何要使用 include 文件?

PHP 提供了两种使用 include 文件的方法。其中一种方法用于包括支持文件,比如界面元素;另一种方法用于包括关键文件,比如页面中调用的函数。

包括定义

首先创建最终将要包括的文件。无论何时创建网站,您要做的第一件事就是创建包含主要界面元素的页眉文件和页脚文件。这样,您就可以创建任意多数量的页面,在编码工作完成之前都无需担心页面的外观。因此,只需要在 include 文件中创建一次界面,整个站点都会立即更新。

首先要创建一个 top.txt 文件,并添加 清单 43 中的代码。

清单 43. 创建一个 top.txt 文件
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">  <head>    <title>Workflow Manager</title>    <link rel="stylesheet" type="text/css" href="style.css" />  </head>  <body>    <div id="wrapper"><div id="bg"><div id="header"></div>      <div id="page"><div id="container"><div id="banner"></div>        <div id="nav1">          <ul style='float: left'>            <li><a href="#" shape="rect">Home</a></li>            <li><a href="#" shape="rect">Upload</a></li>            <li><a href="#" shape="rect">Files</a></li>          </ul>        </div>        <div id="content">          <div id="center">

在另一个名称为 bottom.txt 的文件中,添加以下 清单 44 所示的代码。

清单 44. bottom.txt
          </div>        </div>      </div>    </div></div></div>  </body></html>

将这两个文件和 registration.php 保存在同一目录中。将 Downloads 的 PHPPart1SampleFiles.zip 中的 images 目录和 style.css 文件也复制到了那个目录中,因为 top.txt 中的 HTML 代码会引用它们。

包括文件

现在就将这些文件添加到注册页面中。编辑 registration.php,如 清单 45 所示。

清单 45. 将 top.txt 和 bottom.txt 添加到注册页面
<?php   include("top.txt");?><h1>Register for an Account:</h1><form action="registration_action.php" method="POST">      Username: <input type="text" name="name" /><br />   Email: <input type="text" name="email" /><br />   Password: <input type="password" name="pword[]" /><br />   Password (again): <input type="password" name="pword[]" /><br />   <input type="submit" value="GO" /></form><?php   include("bottom.txt");?>

请注意,您已经删除了通常包围页面内容的 HTML,并使用一个命令来替代它,以便包括您刚刚创建的文件。现在是时候查看该操作的结果。

结果

如果您现在将浏览器指回注册页面,您会看到完全不同的外观,如 图 15 所示。

图 15. 注册页面的新外观
新的注册页面

如果您在该页上 “查看源代码”,那么可以看到所有三个文件都已合并到了输出中(参见 清单 46)。

清单 46. 文件都被合并到输出中
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">  <head>    <title>Workflow Manager</title>    <link rel="stylesheet" type="text/css" href="style.css" />  </head>  <body>    <div id="wrapper"><div id="bg"><div id="header"></div>      <div id="page"><div id="container"><div id="banner"></div>        <div id="nav1">          <ul style='float: left'>            <li><a href="#" shape="rect">Home</a></li>            <li><a href="#" shape="rect">Upload</a></li>            <li><a href="#" shape="rect">Files</a></li>          </ul>        </div>        <div id="content">          <div id="center"><h1>Register for an Account:</h1><form action="registration_action.php" method="POST">   Username: <input type="text" name="name" /><br />   Email: <input type="text" name="email" /><br />   Password: <input type="password" name="pword[]" /><br />   Password (again): <input type="password" name="pword[]" /><br />   <input type="submit" value="GO" /></form>          </div>        </div>      </div>    </div></div></div>  </body></html>

如果您继续下去,对 registration_action.php 进行同样的更改,然后提交表单,就会看到所做的更改立刻起作用了。

现在,这个页面虽然算不上出色,但是也不错了。之后,可以让设计师对其进行美化,您只需对所包含的文件执行一次更改,而不是更改站点中的每个页面。

要求文件

如果 PHP 找不到界面文件,那么这将存在一个问题,但不一定是灾难性的问题,尤其在您只关注应用程序的功能的时候。因此,如果 PHP 找不到由 include() 函数指定的文件,那么它会显示一条警告消息,并继续处理页面。

但是,在某些情况下,找不到 include 文件一个灾难。例如,您可以将 validate() 脚本放在单独的文件中,然后在 registration_action.php 中包含该文件。如果 PHP 找不到它,问题就大了,因为您要在页面中调用这些函数。为了避免这种情况,您可以使用require() 函数代替 include()(参见 清单 47)。

清单 47. 使用 require() 函数
<?php   include("top.txt");    require("scripts.txt");?><p>You entered:</p><?php   foreach ($_POST as $key=>$value) {      echo "<p>".$key." = " . $value . "</p>";   }   $passwords = $_POST["pword"];   echo "First password = ".$passwords[0];   echo "<br />";   echo "Second password = ".$passwords[1];   if (validate($_POST) == "OK") {      echo "<p>Thank you for registering!</p>";...

如果 PHP 找不到所要求的文件,就会发送致命错误消息,并中止处理。

避免重复

没有什么能够阻止您在一个本身被另一个文件包含的文件中包含另一个文件。事实上,要处理这么多 include 文件,它可能会造成混乱,您有可能不小心多次包含同一文件。这种重复可能会造成界面元素的反复出现,或者由于函数或变量的重复定义而导致错误。为了避免这种情况,PHP 提供了特殊版本的include()require() 函数。例如,您可以确保 registration_action.php 文件仅加载这些文件一次(参见清单 48)。

清单 48. 确保 registration_action.php 文件仅加载这些文件一次
<?php   include_once("top.txt");   require_once("scripts.txt");?><p>You entered:</p><?php...

如果 PHP 遇到 include_once()require_once() 函数,那么它会检查在页面中是否已包括该文件,从而避免再次包括它。

结束语

本教程中,我们开始了使用 PHP 构建基于 Web 的应用程序的历程。本文介绍了 PHP 脚本的基本语法,并使用它建立了一个从 HTML 表单接收输入的页面。在表单的处理中,我们介绍了 PHP 的基本结构,比如变量、if-then 语句和循环。还分析了数字数组和关联数组,以及如何访问数组中的数据。然后,我们介绍了如何通过创建和执行 SQL 语句,向 MySQL 数据库插入数据,从数据库中提取数据,以及如何使用表示每行数据的数组。最后,我们查看了如何使用 include 文件。

本系列教程的目的是:通过构建一个工作流应用程序来帮助您掌握 PHP 的使用。在第 1 部分中,通过支持用户注册新的帐户,然后将帐户保存到数据库中,开始您的学习历程。本系列的后续部分将讨论 HTTP 密码保护,以及帮助您成为一名 PHP 开发人员的其他重要问题。

下载

描述名字大小第 1 部分的源代码PHPPart1SampleFiles.zip62KB

参考资料

学习

  • 您可以参阅本文在 developerWorks 全球网站上的 英文原文。
  • PHP 文档 提供了多种语言版本。
  • 还提供了 MySQL 文档。
  • 了解有关使用 "PHP 数据对象" 创建独立于数据库的代码的更多信息。
  • 阅读 "将 PHP 应用程序连接到 IBM DB2 通用数据库"(Dan Scott,developerWorks,2001 年 7 月)。
  • 查看 "将 PHP 应用程序连接到 Apache Derby"(Moira Casey,developerWorks,2004 年 9 月)。
  • 不要错过 "用 PHP 开发 IBM Cloudscape 和 DB2 通用数据库应用程序:(Dan Scott,developerWorks,2005 年 2 月)。
  • 有关 PHP 与 MySQL 的信息,阅读 "Creating dynamic Web sites with PHP and MySQL"(Md. Ashraful Anam,developerWorks,2001 年 5 月)。
  • "Using HTML forms with PHP" 讨论了本文未涉及到的其他一些问题。(Nicholas Chase,developerWorks,2002 年 8 月)。
  • 访问 IBM developerWorks 的PHP 项目资源,了解有关 PHP 的更多信息。
  • 随时关注 developerWorks 技术活动和网络广播。
  • 查看在全球各地即将举行的会议、贸易展览、网络广播和 IBM 开源开发人员感兴趣的其他 活动。
  • 访问 developerWorks 开源专区,获得丰富的 how-to 信息、工具和项目更新,帮助您利用开源技术进行开发,并在 IBM 产品中使用这些技术。
  • 要收听面向软件开发人员的有趣访谈和讨论,一定要留意 developerWorks 播客。
  • 关注 Twitter 上的 developerWorks。

获得产品和技术

  • 下载 XAMPP。
  • 下载 PHP。
  • 下载 MySQL。
  • 获得 IBM 试用软件(可以通过下载或从 DVD 中获得),并在您的下一个开源开发项目中使用专门针对开发人员的软件进行创新。

讨论

  • 与其他 developerWorks 用户交流,同时探索由开发人员推动的博客、论坛、组和维基。帮助在 developerWorks 社区中构建真实世界的开源 组。


0 0
原创粉丝点击