繁体   English   中英

php 中的 SQL 查询,输入来自 html 下拉列表

[英]SQL query in php with input from html dropdown

好的,我要做的是为项目制作一个查询评估工具。 我将用户输入作为 php 变量获取并在我的查询中使用它,因此就像用户正在提交查询一样。 我正在使用 mysqli

我目前正在使用我的查询执行此操作

$sql = "SELECT * FROM `idk` where  `alias` = '".$s."'"; 

我从下面的表格中获取值

$s = $_GET['val'];
<select name="selector" id = "selector">
        <option value="">Select a criteria:</option>
        <option value="0">id</option>
        <option value="1">name</option>
        <option value="2">email</option>
        <option value="3">alias</option>
        <option value="4">position</option>

我想知道是否可以为 where 子句条件(=,!=)添加用户输入,并像获取列的值一样获取它,而不是对其进行硬编码。

请记住,这是一个 uni 项目,没有人会使用它或删除我的数据库,但任何安全建议将不胜感激。

最短的答案:是的。 你可以控制一切。 要实现这一点,您只需在表单中添加另一个选择元素,让用户控制比较值的方式。 我将使用一个简化的示例。

如果您有用户值的输入:

<input type="number" name="age" value="" />

在它之前添加一个选择字段:

<select name="age_comparison">
    <option value="equal">equal to</option>
    <option value="not_equal">not equal to</option>
    <option value="less_than">less than</option>
    <option value="greater_than">greater than</option>
</select>
<input type="number" name="age" value="" />

注意:该位置与处理无关 - 根本不相关。 我只是认为如果用户像阅读现实生活中的一段文字一样阅读您的页面,那将是更好的用户体验。 这意味着当输入稍后出现时,它会读作“年龄大于 X”,这比“年龄 X,大于”更好,如果你先输入输入。

出于同样的原因(更好的用户体验),我倾向于用更像人类的东西来标记选项,因此“等于”而不仅仅是“等于”。 但是我从选项值中省略了它,因为它没有向代码添加任何有价值的信息(“equal”作为参数值说明了整个故事)。

然后,在提交表单后,您可以检测用户的选择并相应地构建查询字符串:

if (isset($_GET['age'])) {
    $age = $_GET['age'];
}
if (isset($_GET['age_comparison'])) {
    switch ($_GET['age_comparison']) {
        case 'equal':
            $ageComparison = '=';
            break;
        case 'not_equal':
            $ageComparison = '!=';
            break;
        case 'less_than':
            $ageComparison = '<';
            break;
        case 'greater_than':
            $ageComparison = '>';
            break;
    }
}
// if we have all the parameters, we can query the database
if (isset($age) && isset($ageComparison)) {
    // the following line is very unsafe - we'll be on that in a minute
    $queryString = 'SELECT * FROM students WHERE age '.$ageComparison.$age;
    ...

注意:我使用$_GET是因为您在问题中使用了它。 如果您要在表单中包含多个参数,我建议您宁可使用post方法并避免将一大堆参数添加到页面的 url 中。 您的表单值将位于相同的键下,仅在$_POST变量中。 另外,当您使用post ,它足以检测是否设置了提交的名称 - 如果是,则保证来自同一表单的其余输入也存在。 使用get您必须单独检查每个参数。

所以你有它。 带有变量比较运算符的查询。

我们还没有完成。 有一些不好的做法需要摆脱,也有一些好的做法需要在路上学习。

首先,永远不要通过直接插入参数来构建查询:

$sql = "SELECT * FROM `idk` where  `alias` = '".$s."'";

这让您对SQL 注入持开放态度 您应该改用准备好的语句 准备好的语句具有内置的保护机制,还可以满足您所有的引用需求(这意味着您不必手动在字符串参数周围放置 uote 标记)。 所以你这样做:

// the question mark means we'll be adding a parameter in that position
$queryString = 'SELECT * FROM students WHERE age '.$ageComparison.' ?';
// here I assume you have mysqli statement ready
// you can see an example about creating one in the link about prepared statements
$statement->prepare($queryString);
$statement->bindParam('i', $age);

您可能会说“但是等一下!您只是直接添加了比较运算符!这不是很危险吗?” - 不,因为它不是直接来自用户。 我们在 switch 语句中决定了它的值,这意味着我们接受了用户的输入(可能会受到损害)并将其转换为我们控制的值。 用户无法决定 switch 语句的结果,我们可以。 因此,直接将它连接到查询字符串是安全的,因为我们知道我们已经定义了一些安全值。

说到 switch 语句,那里也有一个改进。 如果我们在select添加另一个选项,但我们忘记在 switch 语句中添加它怎么办? 还是恶意用户破坏了发送的选项的价值? 我们最终会得到一个错误,因为这样就不会匹配 switch 中的任何情况(我们放置的 4 之外的值的情况未定义),因此永远不会创建变量$ageComparison ,我们永远不会执行查询,因为我们的 if 条件将失败。 那么我们该如何修复呢? 我们添加一个默认案例(默认在没有任何案例匹配时执行):

// remainder of statement cut for length
    ...
    case 'greater_than':
        $queryComparison = '>';
        break;
    default:
        throw new Exception('Unsupported value for age comparison: '.$ageComparison);
}

异常在未处理时停止执行(正确的术语被捕获),但是如果您想自己探索该主题,我会将其留给您(对于初学者来说似乎有点多,而且这里已经有很多文字)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM