我正在寻找一种获取大量用户输入的方法,将它们连接成一个sql查询,并从我的数据库返回结果。到目前为止,我尝试了一些不同的技术,包括将所有变量放入一个数组,然后使用implode(),但我无法使其工作。为简单起见,我决定只使用几个if语句来检查每个变量是否有值。如果确实那么它应该添加一些sql。我的错误信息如下:
您的SQL语法有错误;检查手册 对应于您的MySQL服务器版本,以便使用正确的语法 靠近'AND
type
= AND(city
LIKE'%%')或(addressLineOne
LIKE '%%')OR(第1行的`addres'
即使我在测试期间输入了输入,看起来$ type也没有被选中。除了$ type和$ bedroom之外,我没有给出任何其他输入值。 任何有关代码的帮助和改进将不胜感激。我是PHP和SQL的新手,很抱歉,如果它是愚蠢的,但我已经尝试解决这个问题多年了。
HTML
<form action="searchresults.php" method="get">
<fieldset>
<legend><h3>Search</h3></legend>
<p>Please enter criteria for your search.</p>
<label for="location">Location</label>
<input type="text" name="location" />
<select name="type">
<option value="Studio Flat" selected>Studio Flat</option>
<option value="Flat">Flat</option>
<option value="Detached">Detached</option>
<option value="Semi-detached">Semi-detached</option>
<option value="Terraced">Terraced</option>
<option value="Bungalow">Bungalow</option>
</select>
<label for="bedroom">Bedrooms</label>
<select name="bedroom">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<label for="min">Min Price</label>
<input type="number" name="min" />
<label for="max">Max Price</label>
<input type="number" name="max" />
<br />
<input type="submit" value="Search" />
</fieldset>
</form>
PHP
<?php
session_start();
include './auth.php'; // connection to db
$location = trim($_POST['location']);
$location = strip_tags($location);
$location = htmlspecialchars($location);
$bedroom = trim($_POST['bedroom']);
$bedroom = strip_tags($bedroom);
$bedroom = htmlspecialchars($bedroom);
$type = trim($_POST['type']);
$type = strip_tags($type);
$type = htmlspecialchars($type);
$max = trim($_POST['max']);
$max = strip_tags($max);
$max = htmlspecialchars($max);
$min = trim($_POST['min']);
$min = strip_tags($min);
$min = htmlspecialchars($min);
// build query
$query = "SELECT * FROM Listings WHERE `bedroom` = ".$bedroom." AND `type` = ".$type."";
if(isset($location)){
$query .= " AND (`city` LIKE '%".$location."%') OR (`addressLineOne` LIKE '%".$location."%') OR (`addressLineTwo` LIKE '%".$location."%') OR (`county` LIKE '%".$location."%')";
}
if(isset($max)){
$query .= " AND (`price` <= '%".$price."%')";
}
if(isset($min)){
$query .= " AND (`price` >= '%".$price."%')";
}
$query .= "ORDER BY price;";
// send query to database and return error if it fails
$input = mysqli_query($connect, $query) or die(mysqli_error($connect));
// output results
if(mysqli_num_rows($input)>0){ // if one or more results returned do this code
while($result = mysqli_fetch_array($input)){ // puts data in array then loops the following code
echo "<p><h3>".$result['addressLineOne']." ".$result['addressLineTwo']."
".$result['location']."</h3><h4>£".$result['price']."</h4>".$result['information']."</p><br /><hr />";
}
}else{ // no results then print the following
echo "Sorry, we couldn't find any results.
Please refine your search and try again.";
}
echo $query;
// close the connection
mysqli_close($connect)
?>
答案 0 :(得分:1)
我知道你目前正在使用mysqli,但PDO使构建动态查询变得更加容易,所以如果你在这个项目上不是很远的话,我强烈建议你切换到它。
在mysqli prepared statement中,您必须调用mysqli_stmt::bind_param()
,传递参数列表中的每个参数。相反,PDO不需要绑定,参数全部传递给数组中的PDOStatement::execute()
。这个答案将向您展示您的代码如何与PDO一起使用。
<?php
$connection = new \PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$query = "SELECT * FROM Listings WHERE bedroom = :bed AND type = :type AND (city LIKE :loc OR addressLineOne LIKE :loc OR addressLineTwo LIKE :loc OR county LIKE :loc)";
$parameters = [
":bed" => $_POST["bedroom"],
":type" => $_POST["type"],
":loc" => "%$_POST[location]%",
];
if(!empty($_POST["max"])) {
$query .= " AND price <= :max";
$parameters[":max"] = $_POST["max"];
}
if (!empty($_POST["min"])) {
$query .= " AND price >= :min";
$parameters[":min"] = $_POST["min"];
}
$query .= " ORDER BY price";
$stmt = $connection->prepare($query);
$stmt->execute($parameters);
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
if (empty($results)) { // no results then print the following
echo "Sorry, we couldn't find any results. Please refine your search and try again.";
}
foreach ($results as $result) {
//escape for HTML output
$result = array_map("htmlspecialchars", $result);
echo <<< HTML
<p>
<h3>$result[addressLineOne] $result[addressLineTwo] $result[location]</h3>
<h4>£$result[price]</h4>
$result[information]
</p>
<br />
<hr />
HTML;
}
我还使用heredoc字符串简化了HTML输出,但您应该将HTML和PHP分开。
如果这是一个更大的现有项目的一部分,你可能会坚持使用mysqli,在这种情况下,我建议你学习如何使用准备好的语句;使用字符串连接构建查询的日子已经过去了!
答案 1 :(得分:0)
使用PDO和绑定参数@ miken32建议是可能的,但我建议反对它,因为它有几个缺点:
PDO::ATTR_EMULATE_PREPARES
设置为true
)时,此仅有效,其本身有多个问题:
PDO::ATTR_EMULATE_PREPARES
的默认值,显然&#34;这取决于驱动程序&#34;。PDO::ATTR_EMULATE_PREPARES
后,您无法再在LIMIT
子句中使用绑定参数HY000
与服务器 - side和HY093
与客户端参数绑定。这使正确的错误处理变得复杂。所以,我说要继续手动构建您的查询,但要以干净和安全的方式。要做到这一点,您需要了解这些概念:
通常,您需要htmlspecialchars()
的唯一地方是将数据(例如从数据库)传递到浏览器。
所以,改变每一个
$location = trim($_POST['location']);
$location = strip_tags($location);
$location = htmlspecialchars($location);
到
$location = trim($_POST['location']);
此时无需strip_tags()
或htmlspecialchars()
。来自浏览器的表单数据在没有任何编码的情况下到达PHP端。当然,如果某人实际上将some<br>city
输入到位置字段中,他就找不到任何房间,但如果您正确使用其余的应用程序,则不会破坏任何房间。
同时更改每个
echo "<p>".$result['addressLineOne']." ... </p><br /><hr />";
到
echo "<p>".htmlspecialchars($result['addressLineOne'])." ... </p><br /><hr />";
否则,人们将数据输入进入数据库可以运行&#34;跨站点脚本攻击&#34; - 恶意或意外。
当作为查询的一部分将数据发送到数据库时,您必须以数据库知道它的可变数据而不是SQL命令的一部分的方式对其进行编码。
所以,而不是例如
$query .= " AND (`city` LIKE '%".$location."%') ";
你必须写
$query .= " AND (`city` LIKE '%".addslashes($location)."%') ";
这可以确保如果'
变量中有引号字符($location
),它将被转义,因此它不会在该点结束字符串。
如果您使用UTF-8以外的字符集,则应使用mysql_real_escape_string()
代替addslashes()
,但您可能使用的是UTF-8,所以它很好。< / p>
此外,在这种情况下,您可能希望删除或转义值中的%
和_
,因为它们在LIKE查询中具有特殊含义。
您的代码中还有两个问题:
$query = "SELECT * FROM Listings WHERE `bedroom` = ".$bedroom." AND `type` = ".$type."";
在这里,您不仅需要添加addslashes()
,还需要添加值周围的引号:
$query = "SELECT * FROM Listings WHERE `bedroom` = '".addslashes($bedroom)."' AND `type` = '".addslashes($type)."'";
在这里:
$query .= " AND (`price` <= '%".$price."%')";
显然百分号在这里毫无意义,你的意思是:
$query .= " AND (`price` <= '".addslashes($price)."')";
稍后你会建议使用一个为你做这些事情的图书馆或框架(因为它很容易忘记addslashes()
某个地方),但它不会伤害到首先手动完成,以了解它是如何工作的。