Я новичок в использовании подготовленных операторов в 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 (как указано выше), который подготовлен?
БОНУС: Подготовленные заявления также предполагают увеличение скорости. Будет ли она увеличивать общую скорость, если я использую только подготовленное заявление три или четыре раза на странице?
Вот пример использования 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();
в$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); }
в$stmt->store_result(); $resultrow = array(); stmt_bind_assoc($stmt, $resultrow); while($stmt->fetch()) { print_r($resultrow); }
Вы можете написать это вместо этого:
$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); ?>
Я согласен с несколькими другими ответами:
ext/mysql
PHP нет поддержки параметризованных операторов SQL. mysql_real_escape_string()
также может быть эффективным, если вы используете его правильно, но он более подробный для кода. Следует также отметить, что вам все равно нужно быть осторожным в отношении SQL-инъекций, даже если вы используете параметры запроса, потому что параметры заменяют только литеральные значения в SQL-запросах. Если вы создаете SQL-запросы динамически и используете переменные PHP для имени таблицы, имени столбца или любой другой части синтаксиса SQL, ни параметры запроса, ни mysql_real_escape_string()
помогают в этом случае. Например:
$query = "SELECT * FROM $the_table ORDER BY $some_column";
Что касается производительности:
Есть даже некоторые случаи, когда подготовленный запрос вредит производительности. Например, в следующем случае оптимизатор не может предположить, что он может использовать индекс для поиска, поскольку он должен предположить, что значение параметра может начинаться с шаблона:
SELECT * FROM mytable WHERE textfield LIKE ?
Безопасность с MySQL в PHP (или любой другой язык в этом отношении) в значительной степени обсуждается. Вот несколько мест для вас, чтобы забрать несколько отличных советов:
На мой взгляд, два наиболее важных пункта:
mysql_real_escape_string()
всех ваших переменных запроса с mysql_real_escape_string()
функции mysql_real_escape_string()
PHP (или чего-то подобного). Подготовленные утверждения не поддерживаются простым старым интерфейсом Mysql / PHP. Вам понадобится PDO или mysqli . Но если вы просто хотите заменить заполнители, отметьте этот комментарий на странице руководства пользователя mysql_query php.
Если вы собираетесь использовать mysqli, что кажется лучшим решением для меня, я настоятельно рекомендую загрузить копию класса codeense_mysqli .
Это аккуратный маленький класс, который обертывает и скрывает большую часть трещины, которая накапливается при использовании raw mysqli, так что при использовании подготовленных операторов требуется только одна или две строки поверх старого интерфейса mysql / php