Подтвердить что ты не робот

Как создать безопасный mysql подготовленный оператор в php?

Я новичок в использовании подготовленных операторов в mysql с php. Мне нужна помощь в создании подготовленного оператора для извлечения столбцов.

Мне нужно получить информацию из разных столбцов. В настоящее время для тестового файла я использую оператор полностью небезопасный SQL:

$qry = "SELECT * FROM mytable where userid='{$_GET['userid']}' AND category='{$_GET['category']}'ORDER BY id DESC"
$result = mysql_query($qry) or die(mysql_error()); 

Может ли кто-нибудь помочь мне создать безопасный оператор mysql с использованием ввода параметров url (как указано выше)?

БОНУС: Подготовленные утверждения предполагают также увеличить скорость. Будет ли она увеличивать общую скорость, если я использую только подготовленный оператор три или четыре раза на странице?

4b9b3361

Ответ 1

Вот пример использования mysqli (object-syntax - довольно легко перевести на синтаксис функции, если вы желаете):

$db = new mysqli("host","user","pw","database");
$stmt = $db->prepare("SELECT * FROM mytable where userid=? AND category=? ORDER BY id DESC");
$stmt->bind_param('ii', intval($_GET['userid']), intval($_GET['category']));
$stmt->execute();

$stmt->store_result();
$stmt->bind_result($column1, $column2, $column3);

while($stmt->fetch())
{
    echo "col1=$column1, col2=$column2, col3=$column3 \n";
}

$stmt->close();

Кроме того, если вам нужен простой способ захвата ассоциативных массивов (для использования с SELECT *) вместо того, чтобы точно указать, к каким переменным привязать, вот удобная функция:

function stmt_bind_assoc (&$stmt, &$out) {
    $data = mysqli_stmt_result_metadata($stmt);
    $fields = array();
    $out = array();

    $fields[0] = $stmt;
    $count = 1;

    while($field = mysqli_fetch_field($data)) {
        $fields[$count] = &$out[$field->name];
        $count++;
    }
    call_user_func_array(mysqli_stmt_bind_result, $fields);
}

Чтобы использовать его, просто вызовите его вместо вызова bind_result:

$stmt->store_result();

$resultrow = array();
stmt_bind_assoc($stmt, $resultrow);

while($stmt->fetch())
{
    print_r($resultrow);
}

Ответ 2

Вместо этого вы можете написать:

$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";

Но для использования подготовленных операторов лучше использовать общую библиотеку, например PDO

<?php
/* Execute a prepared statement by passing an array of values */
$sth = $dbh->prepare('SELECT * FROM mytable where userid=? and category=? 
                      order by id DESC');
$sth->execute(array($_GET['userid'],$_GET['category']));
//Consider a while and $sth->fetch() to fetch rows one by one
$allRows = $sth->fetchAll(); 
?>

Или, используя mysqli

<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$category = $_GET['category'];
$userid = $_GET['userid'];

/* create a prepared statement */
if ($stmt = mysqli_prepare($link, 'SELECT col1, col2 FROM mytable where 
                      userid=? and category=? order by id DESC')) {
    /* bind parameters for markers */
    /* Assumes userid is integer and category is string */
    mysqli_stmt_bind_param($stmt, "is", $userid, $category);  
    /* execute query */
    mysqli_stmt_execute($stmt);
    /* bind result variables */
    mysqli_stmt_bind_result($stmt, $col1, $col2);
    /* fetch value */
    mysqli_stmt_fetch($stmt);
    /* Alternative, use a while:
    while (mysqli_stmt_fetch($stmt)) {
        // use $col1 and $col2 
    }
    */
    /* use $col1 and $col2 */
    echo "COL1: $col1 COL2: $col2\n";
    /* close statement */
    mysqli_stmt_close($stmt);
}

/* close connection */
mysqli_close($link);
?>

Ответ 3

Я согласен с несколькими другими ответами:

  • PHP ext/mysql не поддерживает индексированные инструкции SQL.
  • Параметры запроса считаются более надежными в защите от проблем с SQL-инъекциями.
  • mysql_real_escape_string() также может быть эффективным, если вы используете его правильно, но он более подробный для кода.
  • В некоторых версиях международные наборы символов имеют случаи, когда символы не удаляются должным образом, оставляя тонкие уязвимости. Использование параметров запроса позволяет избежать этих случаев.

Вы также должны заметить, что вам все равно нужно быть осторожным в отношении SQL-инъекции, даже если вы используете параметры запроса, потому что параметры заменяют только литеральные значения в SQL-запросах. Если вы динамически создаете SQL-запросы и используете переменные PHP для имени таблицы, имени столбца или любой другой части синтаксиса SQL, ни параметры запроса, ни mysql_real_escape_string() не помогают в этом случае. Например:

$query = "SELECT * FROM $the_table ORDER BY $some_column"; 

Что касается производительности:

  • Эффективность производительности возникает, когда вы выполняете подготовленный запрос несколько раз с разными значениями параметров. Вы избегаете накладных расходов на разбор и подготовку запроса. Но как часто вам нужно выполнять один и тот же SQL-запрос много раз в одном и том же запросе PHP?
  • Даже когда вы можете воспользоваться преимуществами этой производительности, это, как правило, небольшое улучшение по сравнению со многими другими вещами, которые вы могли бы сделать для решения этой проблемы, например, с помощью кэширования кода операций или кэширования данных.
  • Есть даже некоторые случаи, когда подготовленный запрос вредит производительности. Например, в следующем случае оптимизатор не может предположить, что он может использовать индекс для поиска, потому что он должен предположить, что значение параметра может начинаться с шаблона:

    SELECT * FROM mytable WHERE textfield LIKE ?
    

Ответ 4

Безопасность с MySQL в PHP (или любой другой язык в этом отношении) является в значительной степени обсуждаемой проблемой. Вот несколько мест для вас, чтобы забрать несколько отличных советов:

Два наиболее важных пункта, на мой взгляд, следующие:

  • SQL Injection: Обязательно избегайте всех ваших переменных запроса с помощью функции PHP mysql_real_escape_string() (или что-то подобное).
  • Проверка ввода: Никогда не доверяйте пользователю. См. this для руководства по правильной дезинфекции и проверке ваших входов.

Ответ 5

Подготовленные утверждения не поддерживаются простым старым интерфейсом Mysql/PHP. Вам понадобится PDO или mysqli. Но если вы просто хотите заменить заполнители, проверить этот комментарий на странице руководства php mysql_query.

Ответ 6

Если вы собираетесь использовать mysqli, который кажется лучшим решением для меня, я настоятельно рекомендую загрузить копию codesense_mysqli class.

Это аккуратный маленький класс, который обертывает и скрывает большую часть трещины, которая накапливается при использовании raw mysqli, так что использование подготовленных операторов занимает только одну или две строки поверх старого интерфейса mysql/php