PHP пропонує три різні API для підключення до MySQL. Це mysql
(видалено з PHP 7) mysqli
та PDO
розширення.
Раніше mysql_*
функції були дуже популярними, але їх використання вже не рекомендується. Команда з документації обговорює ситуацію з безпекою бази даних, і навчає користувачів відходити від загальновживаного розширення ext / mysql є частиною цього (перевірити php.internals: deprecating ext / mysql ).
І пізніше команда PHP розробник вирішив генерувати E_DEPRECATED
помилки , коли користувачі підключаються до MySQL, будь то через mysql_connect()
, mysql_pconnect()
або неявне функціональність підключення вбудованого в ext/mysql
.
ext/mysql
був офіційно застарілим PHP 5.5 і був видалений в PHP 7 .
Бачите Червону скриньку?
Коли ви переходите на будь-яку mysql_*
сторінку керівництва з функціями, ви бачите червоне поле, в якому пояснюється, що його більше не слід використовувати.
Чому?
Відійти від ext/mysql
не лише щодо безпеки, але й щодо доступу до всіх можливостей бази даних MySQL.
ext/mysql
був побудований для MySQL 3.23 і отримав лише дуже мало доповнень з тих пір, в основному зберігаючи сумісність із цією старою версією, що робить код трохи складнішим у підтримці. Відсутні функції, які не підтримуються ext/mysql
: ( з посібника PHP ).
Причина не використовувати mysql_*
функцію :
- Не в активному розвитку
- Видалено станом на PHP 7
- Не вистачає інтерфейсу ОО
- Не підтримує неблокуючі, асинхронні запити
- Не підтримує підготовлені заяви або параметризовані запити
- Не підтримує збережені процедури
- Не підтримує кілька заяв
- Не підтримує транзакції
- Не підтримує всі функції в MySQL 5.1
Над точкою, цитованою з відповіді Квентіна
Відсутність підтримки підготовлених висловлювань особливо важлива, оскільки вони забезпечують чіткіший, менш схильний до помилок спосіб втечі та цитування зовнішніх даних, ніж вручну, уникаючи їх за допомогою окремого виклику функції.
Дивіться порівняння розширень SQL .
Придушення попереджень про депресію
Поки код перетворюється в MySQLi
/ PDO
, E_DEPRECATED
помилки можна придушити, встановивши error_reporting
в php.ini для виключенняE_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Зауважте, що це також приховуватиме інші попередження про депресію , що, однак, може бути для інших речей, ніж MySQL. ( з посібника PHP )
Стаття PDO проти MySQLi: Що слід використовувати? автор Dejan Marjanovic допоможе вам вибрати.
І кращий спосіб - PDO
і я зараз пишу простий PDO
підручник.
Простий та короткий навчальний посібник із PDO
Питання: Першим моїм запитанням було: що таке "PDO"?
A. " PDO - PHP Data Objects - це рівень доступу до бази даних, що забезпечує єдиний метод доступу до декількох баз даних."
Підключення до MySQL
З mysql_*
функцією або ми можемо сказати це по-старому (застаріло в PHP 5.5 і вище)
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
З PDO
: Все, що вам потрібно зробити, це створити новий PDO
об’єкт. Конструктор приймає параметри для вказівки джерела бази даних PDO
«s конструктора в основному приймає чотири параметри , які DSN
(ім'я джерела даних) і , можливо username
, password
.
Тут я думаю, що ви знайомі з усім, крім DSN
; це нове в PDO
. A DSN
- це в основному рядок параметрів, які вказують, PDO
який драйвер використовувати, та деталі з'єднання. Для подальшої довідки перевірте PDO MySQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
Примітка: ви також можете використовувати charset=UTF-8
, але іноді це спричиняє помилку, тому краще використовувати utf8
.
Якщо є якась помилка підключення, вона кине PDOException
об'єкт, який може бути спійманий для Exception
подальшої обробки .
Добре читати : Підключення та управління з’єднаннями ¶
Ви також можете передати кілька варіантів драйверів як масив до четвертого параметра. Рекомендую передати параметр, який PDO
переходить у режим виключення. Оскільки деякі PDO
драйвери не підтримують готові висловлювання, тому PDO
виконується емуляція підготовки. Це також дозволяє вручну ввімкнути цю емуляцію. Щоб використовувати власні підготовлені на сервері висловлювання, слід чітко встановити його false
.
Інший - вимкнути емуляцію підготовки, яка включена у MySQL
драйвері за замовчуванням, але емуляція підготовки повинна бути вимкнена для PDO
безпечного використання .
Пізніше я поясню, чому підготовку емуляції слід вимкнути. Щоб знайти причину, будь ласка, перевірте це повідомлення .
Він корисний лише в тому випадку, якщо ви використовуєте стару версію, MySQL
яку я не рекомендую.
Нижче наведено приклад того, як це можна зробити:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Чи можемо ми встановити атрибути після побудови PDO?
Так , ми також можемо встановити деякі атрибути після побудови PDO setAttribute
методом:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Помилка обробки
Поводження з помилками набагато простіше, PDO
ніж mysql_*
.
Поширена практика при використанні mysql_*
:
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()
це не гарний спосіб вирішити помилку, оскільки ми не можемо впоратись із річчю die
. Він просто закінчиться сценарієм різко, а потім повторить помилку на екрані, яку зазвичай НЕ хочеться показувати кінцевим користувачам, і дозволить кривавим хакерам відкрити вашу схему. Крім того, зворотні значення mysql_*
функцій часто можна використовувати спільно з mysql_error () для обробки помилок.
PDO
пропонує краще рішення: винятки. Все , що ми робимо з PDO
повинні бути загорнуті в try
- catch
блок. Ми можемо застосувати PDO
один з трьох режимів помилок, встановивши атрибут режиму помилок. Нижче наведено три режими роботи з помилками.
PDO::ERRMODE_SILENT
. Це просто встановлення кодів помилок і діє приблизно так само, як і mysql_*
де ви повинні перевірити кожен результат, а потім переглянути, $db->errorInfo();
щоб отримати детальну інформацію про помилку.
PDO::ERRMODE_WARNING
Підняти E_WARNING
. (Попередження під час виконання (нефактичні помилки). Виконання сценарію не зупинено.)
PDO::ERRMODE_EXCEPTION
: Киньте винятки. Він представляє помилку, висунуту PDO. Не слід викидати PDOException
з власного коду. Див. Винятки для отримання додаткової інформації про винятки в PHP. Це дуже схоже or die(mysql_error());
, коли його не спіймали. Але на відміну від цього or die()
, PDOException
можна вирішити вишукану роботу з ними, якщо ви вирішите це зробити.
Добре читайте :
Подібно до:
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
І ви можете обернути його в try
- catch
, як показано нижче:
try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}
Вам не доведеться впоратися try
- catch
прямо зараз. Ви можете зловити його в будь-який відповідний час, але настійно рекомендую вам скористатися try
- catch
. Крім того, може бути більше сенсу піймати його поза функцією, яка викликає PDO
матеріал:
function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}
Крім того, ви можете впоратися з, or die()
або ми можемо сказати, як mysql_*
, але це буде дійсно різноманітно. Ви можете приховати небезпечні повідомлення про помилки у виробництві, повернувши display_errors off
та просто прочитавши свій журнал помилок.
Тепер, після прочитання всіх речей вище, ви, ймовірно , думаєте: що це таке , коли я просто хочу , щоб почати спираючись простим SELECT
, INSERT
, UPDATE
, або DELETE
заяву? Не хвилюйтесь, ось ми:
Вибір даних
Отже, що ви робите, mysql_*
це:
<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());
$num_rows = mysql_num_rows($result);
while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}
Тепер PDO
ви можете це зробити так:
<?php
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}
Або
<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Use $results
Примітка : Якщо ви використовуєте метод, як показано нижче ( query()
), цей метод повертає PDOStatement
об'єкт. Тож якщо ви хочете отримати результат, використовуйте його, як вище.
<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}
У PDO Data він отримується за ->fetch()
допомогою методу обробки вашого оператора. Перед тим, як зателефонувати за фактом, найкращим підходом було б розповісти PDO про те, як ви хотіли б отримати дані У наведеному нижче розділі я пояснюю це.
Режими отримання
Зверніть увагу на використання PDO::FETCH_ASSOC
в fetch()
і fetchAll()
код вище. Це говорить PDO
про повернення рядків у вигляді асоціативного масиву з іменами полів як ключів. Існує також багато інших режимів вибору, які я поясню один за одним.
Перш за все, я пояснюю, як вибрати режим отримання.
$stmt->fetch(PDO::FETCH_ASSOC)
У вищесказаному я користувався fetch()
. Ви також можете використовувати:
Тепер я переходжу до режиму:
PDO::FETCH_ASSOC
: повертає масив, індексований назвою стовпця, як повернутий у вашому наборі результатів
PDO::FETCH_BOTH
(за замовчуванням): повертає масив, індексований як іменем стовпця, так і номером стовпця, що індексується 0, як повернутий у вашому наборі результатів
Вибору ще більше! Про них читайте в PDOStatement
документації про отримання. .
Отримання кількості рядків :
Замість того, mysql_num_rows
щоб використовувати кількість повернутих рядків, ви можете отримати PDOStatement
та робити rowCount()
, як:
<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Отримання останнього вставленого ідентифікатора
<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
Вставте та оновіть або видаліть заяви
Що ми робимо у mysql_*
функції:
<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);
І в pdo це те ж саме можна зробити:
<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;
У вищезазначеному запиті PDO::exec
виконується оператор SQL і повертається кількість постраждалих рядків.
Вставлення та видалення буде висвітлено пізніше.
Вищеописаний метод корисний лише тоді, коли ви не використовуєте змінну в запиті. Але коли вам потрібно використовувати змінну в запиті, ніколи не намагайтеся, як описано вище, і там для підготовленого оператора чи параметризованого оператора є.
Підготовлені заяви
З. Що таке підготовлена заява і навіщо вони мені потрібні?
A. Підготовлений оператор - це попередньо складений оператор SQL, який можна виконати кілька разів, надсилаючи на сервер лише дані.
Типовий робочий процес використання підготовленого твердження такий ( цитується з Вікіпедії три 3 бали ):
Підготуйтеся : шаблон заяви створюється програмою та надсилається до системи управління базами даних (СУБД). Окремі значення залишаються невизначеними, називаються параметрами, заповнювачами чи змінними змінними (позначені ?
нижче):
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
СУБД аналізує, компілює та виконує оптимізацію запитів на шаблоні оператора та зберігає результат, не виконуючи його.
- Виконати : Пізніше додаток постачає (або прив'язує) значення для параметрів, а СУБД виконує оператор (можливо, повертає результат). Додаток може виконувати оператор стільки разів, скільки хоче, з різними значеннями. У цьому прикладі він може поставити "Хліб" для першого параметра та
1.00
для другого параметра.
Ви можете використовувати підготовлений оператор, включивши заповнювачі у свій SQL. В основному є три без заповнювачів (не намагайтеся це змінити вище, ніж один), один із неназваними заповнювачами та один із названими заповнювачами.
В .: Отже, що називають заповнювачами і як я їх використовую?
A. Названі заповнювачі. Використовуйте описові назви, що передують двокрапці, замість знаків запитання. Нас не хвилює позиція / порядок значення у власнику імені:
$stmt->bindParam(':bla', $bla);
bindParam(parameter,variable,data_type,length,driver_options)
Ви також можете зв'язати, використовуючи масив Execute:
<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Ще одна приємна особливість OOP
друзів - це те, що названі заповнювачі мають можливість вставляти об'єкти безпосередньо у вашу базу даних, припускаючи, що властивості відповідають названим полям. Наприклад:
class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}
}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);
Q. Отже, що таке безіменні заповнювачі та як я ними користуюся?
А. Маємо приклад:
<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();
і
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));
У вищесказаному ви можете побачити ті ?
замість імені, як у власнику місць імені. Тепер у першому прикладі ми присвоюємо змінні різним заповнювачам ( $stmt->bindValue(1, $name, PDO::PARAM_STR);
). Потім ми присвоюємо значення цим заповнювачам і виконуємо оператор. У другому прикладі перший елемент масиву переходить до першого, ?
а другий до другого ?
.
ПРИМІТКА . У неназваних заповнювачах ми повинні подбати про правильний порядок елементів у масиві, який ми передаємо PDOStatement::execute()
методу.
SELECT
, INSERT
, UPDATE
, DELETE
Підготовлено запити
SELECT
:
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
INSERT
:
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
DELETE
:
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
UPDATE
:
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
ПРИМІТКА:
Однак PDO
та / або MySQLi
не є повністю безпечними. Перевірте відповідь Чи готові заяви PDO, щоб запобігти ін'єкції SQL? автор ircmaxell . Також я цитую частину його відповіді:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));