2012-07-18 81 views
1

我需要通过URL来传递特殊符号为我的MySQL查询。例如,我需要有一个URL,它是这样的:使用urldecode()导致MySQL错误

www.example.com/index.php?q=AND name LIKE '%hi%' 

当我试着将它首先,我得到了一个406错误。我查了一下,显然我必须使用urlencode()urldecode()。我把那些和406错误走了,但后来我得到了一个MySQL错误:

mysql_fetch_array(): supplied argument is not a valid MySQL result resource 

通常当我得到这些就意味着查询不正确写入。所以我回应MySQL查询,并且一切都很好。我甚至删除了urldecode(),并将其硬编码到我想传递给页面的变量中,并且MySQL错误消失了。但是,使用urldecode()而不使用这两个查询完全相同,所以我有点困惑。

我去到php.net文档页面urldecode(),并有一个警告,说的一样使用_GETurldecode()在一起,可能会导致意想不到的事情,这已经_GET充当解码器(或者至少这是怎么我理解的措辞),所以我删除urldecode()但在_GET仍留下,而导致不能被解码的文本,所以我想我没有正确解释文档。

urldecode()不与MySQL查询兼容?我相当肯定这是编码/解码的问题,因为我已经用绕过编码/解码的硬编码信息测试了我的代码,并且它工作正常。也许urldecode()是以某种方式将字符转换为特殊的字符,看起来相同但内部不同,所以MySQL无法读取它们?

+86

你是...使用SQL注入作为功能? – 2012-07-18 16:47:48

+9

您可能想要检查http://xkcd.com/327 – 2012-07-18 19:13:52

回答

75

不要这样做。这是不对的。任何人当然可以使用;结束查询并开始一个新的查询,删除所有内容或读出用户和密码。

一个简单的和更好的方法来做到这一点是使用www.example.com/index.php?q=hi为您的网址,然后在服务器上(假设PHP)

$queryString = mysql_real_escape_string($_GET['q']); 

$query = "AND name LIKE '%$queryString%'"; 

// Then replace $query for whatever you were using $_GET['q'] for before. 
// Feel free to rename my variables what you like! 

通过这种方式,用户不能胡来,和该URL看起来更干净。 mysql_real_escape_string函数使字符串安全地在查询中通过转义事物来使用。阅读http://php.net/manual/en/function.mysql-real-escape-string.php了解更多。

如果你仍然不相信这是非常有用的,可以考虑,如果有人发布一个链接,放下你的表,然后谷歌每周一次抓取会发生什么。 Google发生任何变化时,您的数据都会被删除。

一旦你是否喜欢这个技术,阅读了关于mod_rewrite(如果使用Apache)清洁URL的更甚mysqli以及它是如何的MySQL的功能的改进版本,最后PHP Data Objects (PDO)这有助于清理PHP更多。

+47

+1用于教学而不是抨击。 :) – 2012-07-18 18:12:48

+5

而不是使用'mysql_real_escape_string'(这是MySQL专用的和客户端只有 - 希望正确的实现服务器的字符串转义),它将更清洁和更一般准备语句并传递字符串以%s为参数)。另外,我会指出,根据你正在寻找的语义,你可能也应该从'q'的值中剔除'LIKE'使用的各种特殊字符(比如%)(顺便说一句,这很容易混淆在这里被命名为'queryString',因为该术语在本文中通常指示“q = hi”)。 – 2012-07-18 19:05:36

+1

嗯,我认为我会选择超级简单的方式,以避免吓唬人 - 但是,我同意。我认为与变量相同 - 最初我没有使用$ queryString变量,并将mysql_r ...与另一位连接起来,但决定将其分开。 – 2012-07-18 19:23:26

8

丰富有正确的总体思路,但甚至比报价是使用数据库参数。它基本上在您的SQL查询中放置了一个“可变标记”,然后分别传递该变量。查询最终看起来是这样的:

SELECT ID, VALUE1, VALUE2 
FROM MY_TABLE 
WHERE VALUE3 = :param 

然后在你的代码,你添加一个值来代替在:param,然后发送到数据库旁边的SQL。 (在某些数据库库中,您将使用?而不是:parametername。)它比引用有更好的效果,原因有三:

首先,您可以保持查询字符串不变,而不必每次都重新构建它,这可以提高服务器的性能。其次,如果使用多个不同的参数向数据库多次发送相同的常量查询,数据库引擎可以缓存查询计划,这可以提高数据库的性能。第三,当你习惯以参数化风格编写你的查询时,它变得很自然,特别是如果你使用一个将参数列表作为参数的查询函数,所以很难出错。相比之下,很容易忘记引用某些内容,然后意外地在程序中打开了安全漏洞。

参数化的工作方式取决于您使用的数据库和数据库访问库,但每个SQL数据库都支持它们。你应该看看它是如何完成你正在使用的系统。它确实是使用SQL的最佳方式,特别是当您从不受信任的源(例如Internet)输入输入时。

0

在调用mysql_query()之后和调用mysql_fetch_array()之前的某个时刻,您应该检查查询是否返回false,如果是,则打印mysql_error()。例如: -

$result = mysql_query($query); 
if (!$result) { 
    die(htmlenitites(mysql_error())." when running <pre>".htmlenitites($query)."</pre>"); 
} 

但是:

  1. 你不应该使用PHP的MySQL的功能,你应该使用PDO,你应该使用准备/参数化查询。
  2. 除非您真的信任客户端可能键入的任何内容,例如,您不会让SQL从客户端传递 - 例如,这是为后端管理界面,即使如此,它可能是坏习惯,除非你真的需要它(如你正在写phpMySQLAdmin)