新闻也好,文章也好,博客也罢,读取指定记录的最常用方法是通过URL传递ID到PHP页面,然后根据ID从数据库里取出对应的记录,即是说:

<?php
#代码段一
$id = $_GET['id'];
...
$result = mysql_query("SELECT * FROM table_name WHERE id=$id");
?>

这段代码存在的问题很明显:SQL注入。
为了防止SQL注入,一个很有效的方法是,将URL传递过来的ID转为整数。因为一般都利用MySQL的自动编号来作为主键,这个自动编号一般是INT类型,而且是加了UNSIGNED属性的INT。下面的代码健壮了许多:
<?php
#代码段二
$id = $_GET['id'];#行1
$id = intval($id);#行2
...
$result = mysql_query("SELECT * FROM table_name WHERE id=$id");#行3
?>

这样就够了吗?我觉得不够!理由是:32位系统中,PHP里的INT最大值(通过PHP_INT_MAX常量定义)是2147483647,而MySQL的UNSIGNED INT最大值是4294967295。
有什么问题吗?有!如果传递给intval(包括使用(int)mixed强制转型的)参数大于PHP的INT最大值(PHP_INT_MAX),那返回的结果将是PHP_INT_MAX。举例来说:
假如,要读数据库里一条ID为3183856184的记录,使用“代码段二”来处理:
行1:$id的值为3183856184(string, length=10)
行2:$id的值为2147483647(int)
由于3183856184超出了PHP的INT最大值2147483647,所以intval函数返回PHP的INT最大值。于是,行3变成了:$result = mysql_query("SELECT * FROM table_name WHERE id=2147483647");
所以,应该引入更完善的处理机制:
1、首先判断是否由1--10位的数字组成
2、如果是,判断其长度
3、如果小于10位,该值有效
4、如果等于10位,利用strcmp函数将该值和4294967295(转成字符串)进行比较
5、如果strcmp返回值小于1,该值有效
6、其它情况,值无效,将其置为0
下面是参考代码:
<?php
/**
* 获取URL变量id
*
* @return string 合法ID
* @author LoRui(i@lorui.com,www.lorui.com)
*/
function GetID()
{
$sid = $_GET['id'];
$id = '0';
#if(preg_match('/^\d{1,10}$/', $sid)) {#允许首位含0
if(preg_match('/^[1-9][0-9]{0,9}$/', $sid)) {#不允许首位含0
if(strlen($sid) < 10) { #如果输入的ID在10位以下
$id = $sid; #直接赋值
} elseif (strlen($sid) == 10) { #如果输入在ID是10位
if(strcmp($sid, '4294967295') <= 0) #和最大数进行比较,小于或等于就赋值
$id = $sid;
}
}
return $id;
}

#调用

$id = GetID();
...
$result = mysql_query("SELECT * FROM table_name WHERE id=$id");
?>

上一篇 下一篇