EDIT: использовать или не использовать mysqli_
выходит за рамки этого вопроса. Рассмотрим использование PDO.
Какие шаги необходимо предпринять, чтобы преобразовать скрипт из использования устаревших функций mysqli_
в mysqli_
?
Есть ли что-то, что нужно сделать по-другому при использовании mysqli_
вместо mysql
?
Вот базовый сценарий с использованием функций mysql_
:
<?php //define host, username and password $con = mysql_connect($host,$username,$password); if (!$con) { die('Could not connect: ' . mysql_error()); } $db_name ="db1"; mysql_select_db($dbname, $con); $value1 = mysql_real_escape_string($input_string); $query = 'SELECT * FROM table1 WHERE table1.col1=' . $value1 . ''; $result = mysql_query($query, $con); while($row = mysql_fetch_assoc*$result) { $col1 = $row['col1']; $col2 = $row['col2']; echo $col1 . ' ' . $col2 . '<br />'; } mysql_close($con); ?>
mysql_
в mysqli_
может оказаться не оптимальным. Рассмотрим PDO, если вы готовы преобразовать весь свой код в ООП . Может возникнуть соблазн попытаться заменить все экземпляры mysql_
на mysqli_
и помолиться. Вы будете близки, но не совсем на высоте.
К счастью, mysqli_connect
работает достаточно близко к mysql_query
что вы можете просто заменить имена своих функций.
mysql_:
$con = mysql_connect($host, $username, $password);
mysqli_:
$con = mysqli_connect($host, $username, $password);
Теперь, используя большинство других функций в библиотеке mysqli_
, вам необходимо передать mysqli_select_db
соединение с базой данных в качестве первого параметра. Для большинства функций mysqli_
требуется объект соединения.
Для этой функции вы можете просто переключить порядок аргументов, переданных функции. Если вы ранее не передавали объект соединения, вы должны добавить его в качестве первого параметра.
mysql_:
mysql_select_db($dbname, $con);
mysqli_:
mysqli_select_db($con, $dbname);
В качестве бонуса вы также можете передать имя базы данных в качестве четвертого параметра в mysqli_connect
– минуя необходимость вызова mysqli_select_db
.
$con = mysqli_connect($host, $username, $password, $dbname);
Использование mysqli_real_escape_string
очень похоже на mysql_real_escape_string
. Вам просто нужно передать объект соединения в качестве первого параметра.
mysql_:
$value1 = mysql_real_escape_string($input_string);
mysqli_:
$value1 = mysqli_real_escape_string($con, $input_string);
Одной из причин, по mysql_
функции mysql_
были устаревшими для начала, была их неспособность обрабатывать подготовленные операторы. Если вы просто конвертируете свой код в mysqli_
не делая этого важного шага, вы подвержены некоторым из самых слабых мест в mysql_
.
Стоит прочитать эти статьи на подготовленных заявлениях и их преимуществах:
Википедия – Подготовленные заявления
PHP.net – подготовленные отчеты MySQLi
Примечание. При использовании подготовленных операторов лучше явно указывать каждый столбец, который вы пытаетесь запросить, вместо того, чтобы использовать *
нотацию для запроса ко всем столбцам. Таким образом, вы можете обеспечить mysqli_stmt_bind_result
всех столбцов в своем вызове mysqli_stmt_bind_result
.
mysql_:
$query = 'SELECT * FROM table1 WHERE table1.col1=' . $value1 . ''; $result = mysql_query($query, $con); while($row = mysql_fetch_assoc*$result) { $col1 = $row['col1']; $col2 = $row['col2']; echo $col1 . ' ' . $col2 . '<br />'; }
mysqli_:
$query = 'SELECT col1,col2 FROM table1 WHERE table1.col1=?'; if ($stmt = mysqli_prepare($link, $query)) { /* pass parameters to query */ mysqli_stmt_bind_param($stmt, "s", $value1); /* run the query on the database */ mysqli_stmt_execute($stmt); /* assign variable for each column to store results in */ mysqli_stmt_bind_result($stmt, $col1, $col2); /* fetch values */ while (mysqli_stmt_fetch($stmt)) { /* on each fetch, the values for each column in the results are automatically stored in the variables we assigned using "mysqli_stmt_bind_result" */ echo $col1 . ' ' . $col2 . '<br />'; } /* close statement */ mysqli_stmt_close($stmt); }
Показ ошибок работает несколько иначе с mysqli_
. mysqli_error
требует, чтобы объект подключения был первым параметром. Но что, если соединение не получилось? mysqli_
вводит небольшой набор функций, которые не требуют объекта соединения: функции mysqli_connect_*
.
mysql_:
if (!$con) { die('Could not connect: ' . mysql_error()); } if (!$result) { die('SQL Error: ' . mysql_error()); }
mysqli_:
/* check connection error*/ if (mysqli_connect_errno()) { die( 'Could not connect: ' . mysqli_connect_error() ); } /* check query error */ if ($stmt = mysqli_prepare($link, $query)) { // ... execute query if (mysqli_stmt_error($stmt)) { echo 'SQL Error: ' . mysqli_stmt_error($stmt); } }
ПРИМЕР.
Это ваш класс dbc
<?php class dbc { public $dbserver = 'server'; public $dbusername = 'user'; public $dbpassword = 'pass'; public $dbname = 'db'; function openDb() { try { $db = new PDO('mysql:host=' . $this->dbserver . ';dbname=' . $this->dbname . ';charset=utf8', '' . $this->dbusername . '', '' . $this->dbpassword . ''); } catch (PDOException $e) { die("error, please try again"); } return $db; } function getAllData($qty) { //prepared query to prevent SQL injections $query = "select * from TABLE where qty = ?"; $stmt = $this->openDb()->prepare($query); $stmt->bindValue(1, $qty, PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); return $rows; } ?>
ваша страница PHP:
<?php require "dbc.php"; $getList = $db->getAllData(25); foreach ($getList as $key=> $row) { echo $row['columnName'] .' key: '. $key; }
Для этого нет никакой причины.
Во-первых, нет причин делать это просто механически, изменяя только имена функций, оставляя алгоритм одинаковым:
Без реализации параметризованных запросов такой ход имеет мало смысла.
Если ваше единственное беспокойство – ошибки «Устаревшие», вы можете просто отключить их
error_reporting(E_ALL & ~E_DEPRECATED);
и продолжать счастливо использовать старый mysql_ *
Обратите внимание, что вам понадобится только через 2-3 года, когда PHP 5.5 достигнет общих хостов.
Поэтому нет необходимости торопиться.
Во-вторых, то, что вам действительно нужно, – это устранить все вызовы с открытым кодом API из кода
инкапсулируя их в какую-то библиотеку абстракции. Это должно быть вашей главной заботой, а не конкретным API, используемым в этой библиотеке, который может быть изменен подмигиванием.
Наконец, единственной реальной причиной переключения с mysql_*
на mysqli_*
являются параметризованные запросы.
С подготовленными заявлениями PDO – единственный выбор, который у вас есть.
Позвольте мне показать вам, что я имею в виду.
Представьте, что у нас есть массив флажков из HTML-формы для динамического добавления запроса.
С PDO мы можем иметь некоторый относительно нормальный и довольно краткий (но все же бесполезно сложный и загрязненный) код:
$in = str_repeat('?,', count($_GET['cat']) - 1) . '?'; $sql = "SELECT * FROM table WHERE category IN ($in)"; $stm = $db->prepare($sql); $stm->execute($_GET['cat']); $data = $stm->fetchAll();
-$in = str_repeat('?,', count($_GET['cat']) - 1) . '?'; $sql = "SELECT * FROM table WHERE category IN ($in)"; $stm = $db->prepare($sql); $stm->execute($_GET['cat']); $data = $stm->fetchAll();
Просто попробуй и посмотри.
Однако даже PDO требует некоторого неясного и бесполезного кода для создания определенных частей запроса. Таким образом, лучший способ – использовать более интеллектуальную библиотеку, такую как safemysql , которая будет выполнять всю работу внутри, от привязки к извлечению, делая весь ваш код в одну строку :
$data = $db->getALL("SELECT * FROM table WHERE category IN (?a)", $_GET['cat']);