PHP开发中值得注意的几个问题

注意的问题一:字符串是否自动转义的问题
a.用户从页面中输入的内容或从URL地址中传入的参数的字符串转义问题
http://www.abc.com/advice.php?email=caihuafeng@gmail.com&osval=winxp&brval=ie70&question=i%20come%20from%20baidu,test%20%22%20and%20%27&indexUrl=http://www.265.com/&im=caihf666@hotmail.com

如果php.ini中magic_quotes_gpc的设置为Off,sql是由变量动态生成的,这些变量可能含有特殊字符,但是你在进行sql查询前没有将其中的特殊字符(如"、'及\等)进行转义,则执行mysql时会报类似如下的错误。
magic_quotes_gpc = On
; 是否对输入的GET/POST/Cookie数据使用自动字符串转义( '  "  \  NULL )。
; 这里的设置将自动影响 $_GEST $_POST $_COOKIE 数组的值。
; 若将本指令与magic_quotes_sybase指令同时打开,则仅将单引号(')转义为(''),
; 其它特殊字符将不被转义,即( "  \  NULL )将保持原样!!
; 建议关闭此特性,并使用自定义的过滤函数。

作用范围是:WEB客户服务端;
作用时间:请求开始是,例如当脚本运行时.

参数question的值为i come from baidu,test " and '
MySQL Query Error: Insert INTO client_feedback (`os`,`browse`,`index`,`email`,`question`,`im`,`time`,`ip`) VALUES ('winxp','ie70','http://www.265.com/','caihuafeng@gmail.com','i come from baidu,test " and '','caihf666@hotmail.com','1258536394','127.0.0.1') Error Info:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'caihf666@hotmail.com','1258536394','127.0.0.1')' at line 1

此时应该对有可能出现特殊字符的变量进行处理,如定义如下的一个函数,则处理完了以后,不管变量中是否有特殊字符,不管magic_quotes_runtime的值是什么,则执行sql语句时不会报这种类型的错误了。
function strAddslashes($value)
{
    if ($value == '') return false;
   
    if (is_array($value)) {
        $value = array_map('strAddslashes', $value) :
    } else {
        if (!get_magic_quotes_gpc()) $value = addslashes($value);
    }

    return $value;
}

b.从数据库或文件中读取数据的字符串转义问题
magic_quotes_runtime = Off
; 是否对运行时从外部资源产生的数据使用自动字符串转义( '  "  \  NULL )。
; 若打开本指令,则大多数函数从外部资源(数据库,文本文件等)返回数据都将被转义。
; 例如:用SQL查询得到的数据,用exec()函数得到的数据,等等
; 若将本指令与magic_quotes_sybase指令同时打开,则仅将单引号(')转义为(''),
; 其它特殊字符将不被转义,即( "  \  NULL )将保持原样!!
; 建议关闭此特性,并视具体情况使用自定义的过滤函数。

作用范围:从文件中读取的数据或执行exec()的结果或是从SQL查询中得到的;
作用时间:每次当脚本访问运行状态中产生的数据.

假如magic_quotes_runtime的设置为on,某些变量需要从某个文件中读取,从其中读取的字符串含有特别字符串(如"、'及\等),此时如果不处理,则页面上这些特殊字符分别会显示\"、\'及\\,不是我们想要看到的结果,因此此时可以用下面定义的函数strStripslashes处理一下就可以了。
function strStripslashes($value)
{
    if ($value == '') return false;
   
    if (is_array($value)) {
        $value = array_map('strStripslashes', $value) :
    } else {
        if (!get_magic_quotes_runtime()) $value = stripslashes($value);
    }

    return $value;
}

测试一
文件file1.txt内容如下:
Test the special character " and ' and \

如果采用读取文件内容的方式读取文件(如用file_get_contents函数读取文件),则内容中的特殊字符会自动转义
文件file.php内容如下:
<?php
//refer http://doc.bsdlover.cn/html/php/2009/0522/2344.html
define("NEWLINE", "<br />\n");
echo "This is file file.php" . NEWLINE;
echo 'get_magic_quotes_runtime:' . get_magic_quotes_runtime() . NEWLINE;
//include_once(dirname(__FILE__) . '/./file1.txt');
$str = file_get_contents('file1.txt');
echo "str:$str" . NEWLINE;
echo "abcd\"ef" . NEWLINE;
?>

执行file.php输出内容如下:
This is file file.php
get_magic_quotes_runtime:1
str:Test the special character \" and \' and \\
abcd"ef

测试二
文件file1.txt内容如下:
Test the special character " and ' and \

如果采用直接包含文件的方式加载文件,则内容中的特殊字符不会自动转义,所以一定要注意
文件file.php内容如下:
<?php
//refer http://doc.bsdlover.cn/html/php/2009/0522/2344.html
define("NEWLINE", "<br />\n");
echo "This is file file.php" . NEWLINE;
echo 'get_magic_quotes_runtime:' . get_magic_quotes_runtime() . NEWLINE;
include_once(dirname(__FILE__) . '/./file1.txt');
echo NEWLINE;
//$str = file_get_contents('file1.txt');
//echo "str:$str" . NEWLINE;
echo "abcd\"ef" . NEWLINE;
?>

执行file.php输出内容如下:
This is file file.php
get_magic_quotes_runtime:1
Test the special character " and ' and \
abcd"ef

测试三
文件file1.php的内容如下:
<?php
$str = "Test the special character \" and ' and \\";
?>

与上面的测试二加载文本文件file1.txt文件一样,用包含文件的方式加载php文件file1.php,内容中的特殊字符也不会自动转义。
顺便说一下,页面中的字符串abcd"ef输出时"也不会自动转义
文件file.php内容如下:
<?php
//refer http://doc.bsdlover.cn/html/php/2009/0522/2344.html
define("NEWLINE", "<br />\n");
echo "This is file file.php" . NEWLINE;
echo 'get_magic_quotes_runtime:' . get_magic_quotes_runtime() . NEWLINE;
include_once(dirname(__FILE__) . '/./file1.php');
//$str = file_get_contents('file1.txt');
echo "str:$str" . NEWLINE;
echo "abcd\"ef" . NEWLINE;
?>

执行file.php输出内容如下:
This is file file.php
get_magic_quotes_runtime:1
str:Test the special character " and ' and \
abcd"ef

注意问题二:php.ini中几个重要的配置
php的错误级别
error_reporting  =  E_ALL & ~E_NOTICE

display_errors最好设置为On,否则程序报错的时候都不知道错在哪里
; To output errors to STDERR with CGI/CLI:              
;display_errors = "stderr"
;
; Default
;
display_errors = On

是否将上一次的错误或警告信息保存在变量$php_errormsg中,如果网站上线后有一些敏感信息不想让用户知道,则可以将track_errors设为on,将display_errors设为Off,然后将此变量写到日志文件,以方便调试bug。
; Store the last error/warning message in $php_errormsg (boolean).
track_errors = Off

error_log =
; 将错误日志记录到哪个文件中。该文件必须对Web服务器用户可写。
; syslog 表示记录到系统日志中(NT下的事件日志, Unix下的syslog(3))
; 如果此处未设置任何值,则错误将被记录到Web服务器的错误日志中。

log_errors = Off
; 是否在日志文件里记录错误,具体在哪里记录取决于error_log指令。
; 强烈建议你在最终发布的web站点时使用日志记录错误而不是直接输出,
; 这样可以让你既知道那里出了问题,又不会暴露敏感信息。

register_globals最好设置为Off,这样更加安全一点
; You should do your best to write your scripts so that they do not require
; register_globals to be on;  Using form variables as globals can easily lead
; to possible security problems, if the code is not very well thought of.
register_globals = Off

如果你需要php作为脚本运行,同时又需要往php的命令行里面传递参数,则需要将register_argc_argc设置为On
; This directive tells PHP whether to declare the argv&argc variables (that
; would contain the GET information).  If you don't use these variables, you
; should turn it off for increased performance.
register_argc_argv = Off

如果你想通过PHP上传超大的文件,以下几项配置可能都需要修改
;Maximum size of POST data that PHP will accept.
post_max_size = 100M
     
; Maximum allowed size for uploaded files.
upload_max_filesize = 100M
     
max_execution_time = 1800     ; Maximum execution time of each script, in seconds
max_input_time = 1800    ; Maximum amount of time each script may spend parsing request data
memory_limit = 128M      ; Maximum amount of memory a script may consume (128MB)

除非提高程序的移植性,建议用<?php ?>,这样不管short_open_tag是On还是Off,则均不会出现无法解析php程序的问题。
short_open_tag = On
; 是否允许使用"<? ?>"短标识。否则必须使用"<?php ?>"长标识。
; 除非你的php程序仅在受控环境下运行,且只供自己使用,否则请不要使用短标记。
; 如果要和XML结合使用PHP,可以选择关闭此选项以方便直接嵌入"<?xml ... ?>",
; 不然你必须用PHP来输出:<? echo '<?xml version="1.0"'; ?>
; 本指令也会影响到缩写形式"<?=",它和"<? echo"等价,要使用它也必须打开短标记。

关于php.ini的配置选项可以看http://cn2.php.net/manual/en/ini.list.php

You can use the ini_set() function to set a directive's  value in your scripts provided the "CHANGEABLE" attribute in the above chart is PHP_INI_USER or PHP_INI_ALL.
php.ini中是PHP_INI_USER及PHP_INI_ALL级别的选项可以通过ini_set函数在php脚本中手动的设置

PHP_INI_* 常量的定义

常量 值 含义
PHP_INI_USER 1 配置选项可在用户的 PHP 脚本或 Windows 注册表中设置
PHP_INI_PERDIR 2 配置选项可在 php.ini, .htaccess 或 httpd.conf 中设置
PHP_INI_SYSTEM 4 配置选项可在 php.ini or httpd.conf 中设置
PHP_INI_ALL 7 配置选项可在各处设置

注意问题三:关于空值的判断
如果判断一个变量是否为空且认为0不为空,则最好的判断方法是用if ($value == '') return false;
如果用if (empty($value)) 来判断的话,则当$value的值为0的时候,此条件返回true,而又假如0又不是我们想要过滤的值,则此时程序会出现bug,我以前出现过两三次这样的错误,也在这里顺便总结一下。

$a !== $b 非全等 TRUE,如果 $a 不等于 $b,或者它们的类型不同。(PHP 4 引进)
$val = "0";
var_dump($val !== 0);
var_dump((int)$val !== 0);
var_dump($val != 0);

分别输出如下:
bool(true) bool(false) bool(false)

$val = 0;
var_dump($val !== 0);
var_dump((int)$val !== 0);
var_dump($val != 0);

分别输出如下:
bool(false) bool(false) bool(false)

empty在PHP手册中的说明
如果 var 是非空或非零的值,则 empty() 返回 FALSE。换句话说,""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE。

isset在PHP手册中的说明
如果 var 存在则返回 TRUE,否则返回 FALSE。

如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。同时要注意的是一个 NULL 字节("\0")并不等同于 PHP 的 NULL 常数。

<?php
$var = '';

// 结果为 TRUE,所以后边的文本将被打印出来。
if (isset($var)) {
    print "This var is set set so I will print.";
}

// 在后边的例子中,我们将使用 var_dump 输出 isset() 的返回值。

$a = "test";
$b = "anothertest";

var_dump( isset($a) );      // TRUE
var_dump( isset ($a, $b) ); // TRUE

unset ($a);

var_dump( isset ($a) );     // FALSE
var_dump( isset ($a, $b) ); // FALSE

$foo = NULL;
var_dump( isset ($foo) );   // FALSE
?>  

这对于数组中的元素也同样有效:
<?php
$a = array ('test' => 1, 'hello' => NULL);

var_dump( isset ($a['test']) );            // TRUE
var_dump( isset ($a['foo']) );             // FALSE
var_dump( isset ($a['hello']) );           // FALSE

// 键 'hello' 的值等于 NULL,所以被认为是未置值的。
// 如果想检测 NULL 键值,可以试试下边的方法。
var_dump( array_key_exists('hello', $a) ); // TRUE
?> 
 



[本日志由 admin 于 2012-04-13 01:46 PM 更新]
上一篇: PHP开发中值得注意的几个问题(二)
下一篇: 关于PHP中的文件包含方法
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: php
相关日志:
评论: 0 | 引用: 0 | 查看次数: 1552
发表评论
昵 称:
密 码: 游客发言不需要密码.
邮 箱: 邮件地址支持Gravatar头像,邮箱地址不会公开.
网 址: 输入网址便于回访.
内 容:
验证码:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭

 广告位

↑返回顶部↑