在 PHP 中创建和使用表单
开发人员创建 PHP 是为了开发一种 Web 编程语言。事实上,虽然可以从命令行中运行 PHP,但很少有人在 Web 应用程序领域之外使用这种语言。结果,PHP 程序员最常见的任务就是使用 Web 表单。
使用 HTML 创建 Web 表单,当用户提交表单时,浏览器向服务器发送一个信息数组。
这一节将讨论数组和使用表单数据的方式,以及控制 PHP 脚本流的方法,如循环和 if-then 语句。
用 HTML 创建表单
首先来创建应用程序的注册页面。最终,用户将在这里输入他们的信息,而您则需要在将这些信息保存到数据库之前验证 它们或者检查它们的完整性。但现在,我们只需要创建一个基本的表单。创建一个命名为 registration.php 的新文件,在该文件中添加以下内容:
<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)中,那么输入各字段后的结果将如图 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=roadnick&email=ibmquestions%40nicholaschase.com&pword=supersecretpassword
注意,每个表单元素都有一个名称,URL 中包含用地址符号(&)分隔的名值对。URL 采用这种格式是因为使用了 GET 方法。在 使用 POST 一节中,还将介绍这些内容,不过,让我们首先来看看如何从 PHP 页面中检索数据。
访问表单数据
现在已经提交了表单,还要将数据放到真正的响应页面 registration_action.php 中,对该文件做如下更改:
...<body> <p>You entered:</p>
<?php $username = $_GET['name']; $password = $_GET['pword'];
echo "<p>Username = " . $username . "</p>"; echo "<p>Password = " . $password . "</p>"; ?>
</body></html>
要做的就是从 $_GET 数组中取得命名的值。后面还将进一步讨论数组,目前要注意的是,刷新浏览器后,真正的应答页面将如图 5 所示。
图 5. 浏览器中的正确信息

可以按照名称取得所有提交的信息,因为这是一个数组,所以还可通过其他的方式。
数组
PHP 允许创建数组或者值列表,从而方便地同时移动一组数据。比如,可以创建一个数组并将其值输出到页面中,如下所示:
$formnames = array("name", "email", "pword");echo "0=".$formnames[0]."<br />";echo "1=".$formnames[1]."<br />";echo "2=".$formnames[2]."<br />";
array() 函数返回一个值,这个例子中返回的值恰好是一个数组。(函数在后面讨论,现在只要知道调用函数,并为函数的返回值赋给一个变量即可。)
上述脚本的输出如下:
0=name<br />1=email<br />2=pword<br />
注意,第一个值的索引号是 0 而不是 1。 此外,通过在数组变量名后的方括号中使用索引可以指定需要的任意值。这项操作与访问表单数据的方式类似,这并不是偶然的。$_GET 变量是一种特殊类型的数组,称为关联(associative)数组,也就是说,每个值不使用数字索引,而使用 key。
提交表单的时候,实际上创建了以下这样一个数组:
$_GET = array("name" => "roadnick", "email" => "ibmquestions@nicholaschase.com", "pword" => "supersecretpassword");
这就是能够提取每个值(如 $_GET["name"])的原因。不过不需要分别提取。
访问数组信息
在处理数据时,使用关联数组非常方便,但经常会遇到不知道数组结构是什么样的情形。比如,您可能创建了一个通用数据库例程,从查询中接受一个关联数组。
幸运的是,PHP 提供的两个函数简化了此操作:
<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></html>
array_keys() 和 array_values() 函数都返回普通的数字索引数组,因此可以使用数字索引从这两个数组中获取信息,如图 6 所示。
图 6. 使用数字索引提取数据

还应该有更方便的办法。比方说,如果不知道有多少个值,该怎么办?PHP 提供了处理关联数组的多种方式,而使用哪一种最方便则由已经掌握的信息决定。我们来看看完成同样任务的其他方法。
使用 for-next 循环
PHP 中最常见的一项任务是遍历一组值。使用 for-next 可以很轻松地完成这项操作。for-next 循环按照定义遍历一组值。比如下面的循环:
for ($i = 0; $i < 10; $i++) { echo $i . " ";}
生成的结果为:
0 1 2 3 4 5 6 7 8 9
PHP 首先把 0 赋给 $i,这是在循环一开始定义的,只要 $i 小于 10,循环就会继续下去,每执行一次循环,PHP 就会把 $i 的值加一。
也就是说,如果知道 $_GET 数组中有多少个值(可以做到),那么很容易使用下面的形式遍历其中的每个值:
<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></html>
sizeof() 告诉您 $_GET 数组中包含多少个值。可以使用这个数据确定什么时候结束循环,如图 7 所示。
图 7. 使用 sizeof 函数结束循环

因为 $_GET 是关联数组,实际上还有另一种选择:foreach 循环。
使用 foreach 循环
关联数组在 PHP 中很常见,该语言提供了一种很简单的方法来获得其中的数据,不需要经过提取键和值的过程。使用 foreach 循环可以直接操纵这类数组。比如下面的代码:
...<?php foreach ($_GET as $value) { echo "<p>" . $value . "</p>"; }?>
PHP 第一次执行该循环时,会从 $_GET 数组中取得第一个值,然后将该值赋给 $value 并输出它。然后,返回到循环的顶部,把下一个值赋给 $value,依次处理 $_GET 中的每个值(也包括名称)。最终的结果如下:
<p>roadnick</p><p>ibmquestions@nicholaschase.com</p><p>supersecretpassword</p>
更方便的是,它还能提取值和键:
...<?php
foreach ($_GET as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; }?<...
于是又得到了最初的结果:
图 8. 最初的结果

多表单值
对于表单值,还需要处理偶尔出现的情况:一个名称具有多个表单值。比如,由于用户看不到输入的口令,您可能希望他们输入两次进行确认,以避免发生错误:
...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字段名稍做了修改。因为将检索多个值,所以需要将 password 本身看成一个数组。也就是说,一个数组值本身也是另一个数组。提交该表单时,得到的 URL 将是:
http://localhost/registration_action.php?name=roadnick&email=ibmquestions%40nicholaschase.com&pword[]=supersecretpassword&pword[]=supersecretpassword
提交表单相当于创建下面的数组:
$passwords = array("supersecretpassword", "supersecretpassword");$_POST = array("name"=>"roadnick", "email"=>"ibmquestions@nicholaschase.com", "pword"=>$passwords);
这意味着如果查看口令值,则必须将该值作为数字数组来访问,例如:
... 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. 提交表单

注意,password 字段是作为 Array 输出的,但是您可以直接访问它的值。
GET 和 POST

到目前为止,提交数据使用的一直是 GET 方法,这种方法将数据放在 URL 中。这样做有时候很合适,但有时候不合适。比如,可以通过这种技术使用链接来模仿表单的提交,但是如果有大量的数据,比方说数据来自 textarea(用户可以输入注释),那么这种技术就不是达到目标的最佳方法。因为,Web 服务器通常限制能够在 GET 请求中接收的字符个数。
另外,好的技术和标准需求告诉我们,永远不要使用 GET 执行有“副作用”的操作或者真正做 什么事情的操作。比如说,现在我们只是查看数据,这不会带来什么副作用。但是,如果要将数据添加到数据库中,按照定义,这就是有副作用的操作。
很多 Web 程序员不知道这种特殊的限制,因此可能造成问题。使用 GET,特别是将它作为 URL 使用,可能导致系统多次执行一项操作,因为用户将其添加到了收藏夹中,或者搜索引擎正在建立该 URL 的索引, 并不知道实际上是在更新数据库或者执行其他某项操作。
因此,在这种情况下必须使用 POST。
使用 POST
使用 POST 方法代替 GET 方法实际上非常简单。首先需要修改 registration.php 页面:
...<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 数组:
...<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></html>
使用 $_POST 数组的方式与使用 $_GET 数组的方式相同。
错误检查:if-then 语句
转入下一节之前,如果无法确保两者匹配,那么要求用户两次输入口令就没有任何意义。因此需要使用 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. 口令不匹配发出的警告
还有两个方便的运算符,与运算符(&&)和或运算符(||)。比如,可以说:
if (($today == "Monday") && ($status == "Not a holiday")) { echo "GO TO WORK!!!";}
在上面的例子中,只有当今天是星期一并且不是节假日时,表达式才成立。但对于或运算符,只要有一个条件成立,就会返回 true。