本节汇集了你在写 PHP 脚本时可能碰到的大多数普通错误。
PHP 是一个将数百个外部库连接在一起的粘合剂,尽管有时候会有一些混乱。这里有一些简单的经验法则:
数组函数 参数的顺序为 "needle, haystack", 字符串函数 则相反,顺序为 "haystack, needle"。
PHP 提供很多“ 预定义变量”,例如超全局变量 $_POST。可以遍历 $_POST变量,因为它是一个和所有通过 POST 方法传递数据相联系的数组。例如,可以用 foreach简单地遍历它,检查 empty()值,以及将它们输出。
<?php
$empty = $post = array();
foreach ($_POST as $varname => $varvalue) {
if (empty($varvalue)) {
$empty[$varname] = $varvalue;
} else {
$post[$varname] = $varvalue;
}
}
print "<pre>";
if (empty($empty)) {
print "None of the POSTed values are empty, posted:\n";
var_dump($post);
} else {
print "We have " . count($empty) . " empty values\n";
print "Posted:\n"; var_dump($post);
print "Empty:\n"; var_dump($empty);
exit;
}
?>
假设是针对数据库,请使用数据库自带的转义机制。比如,针对 MySQL 使用 mysql_real_escape_string() 函数,针对 PostgreSQL 则使用 pg_escape_string() 函数。还有两个标准函数 addslashes() 和 stripslashes() 可以在旧的 PHP 版本中实现类似的操作。
Note: 设置选项说明: magic_quotes_gpc
设置选项magic_quotes_gpc默认值为 on。相当于对所有 GET, POST, and COOKIE 数据使用了 addslashes()。可以用 stripslashes() 来去掉它们。
最可能的情况是,由于 PHP 的 magic_quotes_gpc 被开启,反斜线神奇的存在了。这是 PHP 的一个旧特性引起的,应该被禁用,不要依赖它。另外, stripslashes() 函数能够从 string中去掉所有的反斜线。
Note: 设置选项说明: magic_quotes_gpc
设置选项magic_quotes_gpc默认值为 on。相当于对所有 GET, POST, and COOKIE 数据使用了 addslashes()。可以用 stripslashes() 来去掉它们。
本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。
首先要理解这个设置选项的作用。假如我们使用以下 URL: http://example.com/foo.php?animal=cat,那么在 foo.php中我们可能会使用以下代码:
<?php
// 建议使用这种访问变量的方式
echo $_GET['animal'];
// 如果想直接访问 $animal 变量,就要把 register_globals 选项设置为 on
// 强烈建议不要这么做!!
echo $animal;
// 这个选项的值会影响到所有变量,包括 $_SERVER
echo $_SERVER['PHP_SELF'];
// 同样,要使 $PHP_SELF 变量自动生效,register_globals 选项必须设置为 on
// 强烈建议不要这么做!!
echo $PHP_SELF;
?>
上面的代码解释了 register_globals 的作用,就是自动生成变量。多年来,这种编程方式被很多人所不喜,所以从 PHP 6 开始,这个选项就被禁用了。目前市面上绝大部分虚拟主机服务商也都默认把 register_globals 禁用,但是请注意,你在阅读一些过时的资料时,可能仍有一些文章、教程、书籍要求把该选项开启。不用管它!
请参阅以下资源进一步了解:
Note:
以上示例中,我们使用了一个 URL,其中包含了一个 QUERY_STRING。PHP 会把 QUERY_STRING 中的信息通过 GET HTTP 请求传递,所以我们可以通过超级全局变量(superglobal) $_GET 来访问其中的变量。
<?php
function myfunc($argument)
{
echo $argument + 10;
}
$variable = 10;
echo "myfunc($variable) = " . myfunc($variable);
?>
要在一个表达式中(例如在上面的例子中和其它字符串连接)使用函数的结果,需要 return 这个值,而不是 echo 它。
<pre>
<?php echo "This should be the first line."; ?>
<?php echo "This should show up after the new line above."; ?>
</pre>
在 PHP 中,一段代码的结束标记要么是“?>”要么是“?>\n”(\n 表示换行)。因此在上面的例子中,输出的句子将显示在同一行中,因为 PHP 忽略了代码结束标记后面的换行。这意味着如果要输出一个换行符,需要在每段 PHP 代码的结束标记后面多加一个换行。
PHP 为什么这么做呢?因为在格式化正常的 HTML 时,这样通常会更容易。假如输出了换行而你不需要这个换行时,就不得不用一个非常长的行来达到这样的效果,或者让产生的 HTML 页面的源文件的格式很难读。
函数 header(), setcookie() 和 session 函数需要在输出流中添加头信息。但是头信息只能在其它任何输出内容之前发送。在使用这些函数前不能有任何(如 HTML)的输出。函数 headers_sent() 能够检查脚本是否已经发送了头信息。请参阅 输出控制函数。
如果以 Apache 的模块方式运行 PHP,那么函数 getallheaders() 可以做这件事。因此下面的代码可以显示所有的请求报头:
<?php
$headers = getallheaders();
foreach ($headers as $name => $content) {
echo "headers[$name] = $content<br />\n";
}
?>
请参阅函数 apache_lookup_uri()、 apache_response_headers() 和 fsockopen()。
IIS 的安全模型这里有毛病。这是所有 IIS 下运行的 CGI 程序所共有的问题。一个解决办法是建立一个纯 HTML 文件(不经过 PHP 解析)作为要进入认证目录的登录页面,然后用 META 标记来重定向到 PHP 页面,或者用一个连接到 PHP 页面。然后 PHP 就可以正确识别认证信息了。如果是用 ISAPI 模块,那没有这个问题。其它 NT 下的 web 服务器不受此影响。更多信息见 » http://support.microsoft.com/kb/q160422/ 及 HTTP 认证 一章。
必须要做些修改。打开 Internet 信息服务,找到你的 PHP 文件并打开属性页,选择 文件安全性标签,点击 匿名访问和身份验证控制的“编辑”按钮。
解决此问题有两个方法,一是不要选中 匿名访问并且选中 集成 Windows 身份验证,二是选中 匿名访问并编辑匿名访问使用的帐户,改成一个有权限的。
要能够在 PHP 代码中直接嵌入 <?xml,需要将 PHP 设置项 short_open_tags设置为 0以关闭短标记格式。无法通过函数 ini_set()来更改这项设置。不管 short_open_tags是开或者关,都可以用类似于 <?php echo '<?xml'; ?>的方法达到目的。该项设置的默认值为开。
请阅读手册中的 预定义变量 一章,该部分的文档已经包含了一部分可以用于你的脚本的预定义变量的列表。可用变量的完整列表(及更多信息)可以通过调用 phpinfo() 函数来查阅。请务必阅读手册中 来自 PHP 之外的变量 一节,这部分文档阐述了外部变量的概念,例如来自 HTML 表单、Cookie 和 URL 的变量。
Note: register_globals 重要说明:
自 PHP 4.2.0 起,PHP 指令 register_globals 的默认值为 off。PHP 社区鼓励开发者不要依赖于此指令, 用其他手段替代,例如superglobals。
首先非常重要的一点是 PHP 设置项 register_globals 同样会对服务器端和环境变量产生影响。当 register_globals = off (从 PHP 4.2.0 开始其默认值为 off),变量 $DOCUMENT_ROOT 将不会存在,而只有 $_SERVER['DOCUMENT_ROOT']。如果 register_globals = on 则变量 $DOCUMENT_ROOT 和 $GLOBALS['DOCUMENT_ROOT'] 将同时存在。
如果确认 register_globals = on 但不知道为什么 $DOCUMENT_ROOT 在函数内部不可用,这是因为它和其它的变量一样需要在函数中执行 global $DOCUMENT_ROOT。请参阅手册中的 变量范围 一节。建议在 register_globals = off 的情况下进行编码。
可用的选择有 K(对应 Kilobytes),M(对应 Megabytes)和 G(对应 Gigabytes;自 PHP 5.1.0 起可用),区分大小写。其余的都认为是字节。 1M等于一个 Megabyte,即 1048576 字节。 1K 等于一个 Kilobyte,即 1024 字节。不能在 php.ini 之外使用这些符号,最好用整数的 integer 字节值。参见 ini_get() 文档中的转换示例。要注意,数字类型为 integer 会自动取整,这意味着 0.5M 与 0 是等价的。
Note: kilobyte 和 kibibyte 的区别
PHP 将一个千字节(kilobyte)描述为等于 1024 字节(bytes),而 IEC 标准则认为这是一个 kibibyte。结论:k 和 K = 1024 bytes.
在 PHP 5.3.4 之前,如果启用了 IPv6,PHP 内部的网络解析代码有一个 bug,会导致处理 localhost 相关的地址时失败。可以通过使用 "127.0.0.1" 或在 hosts 文件中禁止 IPv6 来解决这个问题。