PHP oferuje trzy różne interfejsy API do łączenia się z MySQL. Są to mysql(usunięte z PHP 7) mysqlii PDOrozszerzenia.
Te mysql_*funkcje kiedyś bardzo popularne, ale ich stosowanie nie jest zalecane więcej. Zespół dokumentacji omawia sytuację w zakresie bezpieczeństwa bazy danych i częścią tego jest szkolenie użytkowników, jak odejść od powszechnie używanego rozszerzenia ext / mysql (sprawdź php.internals: wycofywanie ext / mysql ).
A później zespół PHP developer podjął decyzję, aby generować E_DEPRECATEDbłędy podczas łączenia się użytkowników MySQL, czy przez mysql_connect(), mysql_pconnect()lub niejawny funkcjonalność połączenia wbudowany ext/mysql.
ext/mysqlzostał oficjalnie uznany za przestarzały od wersji PHP 5.5 i został usunięty od wersji PHP 7 .
Widzisz czerwone pudełko?
Gdy przejdziesz do dowolnej mysql_*strony podręcznika funkcji, zobaczysz czerwone pole wyjaśniające, że nie należy jej już używać.
Dlaczego
Odejście od ext/mysqldotyczy nie tylko bezpieczeństwa, ale także dostępu do wszystkich funkcji bazy danych MySQL.
ext/mysqlzostał zbudowany dla MySQL 3.23 i od tego czasu otrzymał bardzo niewiele dodatków, przy jednoczesnym zachowaniu zgodności z tą starą wersją, co utrudnia utrzymanie kodu. Brakujące funkcje, które nie są obsługiwane przez ext/mysql: ( z podręcznika PHP ).
Powód nieużywania mysql_*funkcji :
- Nie w trakcie aktywnego rozwoju
- Usunięto z PHP 7
- Brakuje interfejsu OO
- Nie obsługuje nieblokujących zapytań asynchronicznych
- Nie obsługuje przygotowanych instrukcji ani sparametryzowanych zapytań
- Nie obsługuje procedur przechowywanych
- Nie obsługuje wielu instrukcji
- Nie obsługuje transakcji
- Nie obsługuje wszystkich funkcji MySQL 5.1
Powyższy punkt cytowany z odpowiedzi Quentina
Brak wsparcia dla przygotowanych instrukcji jest szczególnie ważny, ponieważ zapewniają one bardziej przejrzystą, mniej podatną na błędy metodę ucieczki i cytowania danych zewnętrznych niż ręczne ucieczkowanie ich osobnym wywołaniem funkcji.
Zobacz porównanie rozszerzeń SQL .
Pomijanie ostrzeżeń o wycofaniu
Natomiast kod jest konwertowana do MySQLi/ PDO, E_DEPRECATEDbłędy mogą być tłumione przez ustawienie error_reportingw php.ini wykluczaniaE_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Zauważ, że to ukryje także inne ostrzeżenia o wycofaniu , które jednak mogą dotyczyć rzeczy innych niż MySQL. ( z instrukcji PHP )
Artykuł PDO vs. MySQLi: Którego należy użyć? autor: Dejan Marjanovic pomoże ci wybrać.
I jest lepszy sposób PDO, a teraz piszę prosty PDOsamouczek.
Prosty i krótki samouczek PDO
P: Pierwsze pytanie w mojej głowie brzmiało: co to jest „PDO”?
A. „ PDO - PHP Data Objects - to warstwa dostępu do bazy danych zapewniająca jednolitą metodę dostępu do wielu baz danych.”

Łączenie z MySQL
Z mysql_*funkcją lub możemy to powiedzieć po staremu (przestarzałe w PHP 5.5 i nowszych)
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
Z PDO: Wszystko, co musisz zrobić, to utworzyć nowy PDOobiekt. Konstruktor przyjmuje parametry określające źródło bazy PDO„S konstruktor przeważnie czterech parametrów, które są DSN(nazwa źródła danych) i ewentualnie username, password.
Tutaj myślę, że znasz wszystko oprócz DSN; to jest nowy w PDO. A DSNto w zasadzie ciąg opcji określających, PDOktórego sterownika należy użyć, i szczegóły połączenia. Aby uzyskać dodatkowe informacje, sprawdź PDO MySQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
Uwaga: możesz także użyć charset=UTF-8, ale czasami powoduje to błąd, więc lepiej jest użyć utf8.
Jeśli wystąpi jakikolwiek błąd połączenia, wyrzuci PDOExceptionobiekt, który można złapać w celu Exceptiondalszej obsługi .
Dobra lektura : Połączenia i zarządzanie połączeniami ¶
Możesz również przekazać kilka opcji sterownika jako tablicę do czwartego parametru. Polecam przekazanie parametru, który przechodzi PDOw tryb wyjątku. Ponieważ niektóre PDOsterowniki nie obsługują natywnie przygotowanych instrukcji, PDOwykonuje emulację przygotowywania. Pozwala także ręcznie włączyć tę emulację. Aby użyć natywnych instrukcji przygotowanych po stronie serwera, należy je jawnie ustawić false.
Drugim jest wyłączenie przygotowania emulacji, która jest MySQLdomyślnie włączona w sterowniku, ale przygotowanie emulacji powinno być wyłączone, aby można było PDObezpiecznie korzystać .
Wyjaśnię później, dlaczego należy przygotować emulację. Aby znaleźć powód, sprawdź ten post .
Można go używać tylko wtedy, gdy używasz starej wersji, MySQLktórej nie zaleciłem.
Poniżej znajduje się przykład tego, jak możesz to zrobić:
$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));
Czy możemy ustawić atrybuty po budowie PDO?
Tak , możemy również ustawić niektóre atrybuty po konstrukcji PDO za pomocą setAttributemetody:
$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);
Obsługa błędów
Obsługa błędów jest znacznie łatwiejsza PDOniż mysql_*.
Powszechną praktyką podczas używania mysql_*jest:
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()nie jest dobrym sposobem na poradzenie sobie z błędem, ponieważ nie możemy sobie poradzić die. To po prostu nagle zakończy skrypt, a następnie powtórzy błąd na ekranie, którego zwykle NIE chcesz pokazywać użytkownikom końcowym, i pozwoli cholernym hakerom odkryć twój schemat. Alternatywnie, zwracane wartości mysql_*funkcji mogą być często używane w połączeniu z mysql_error () do obsługi błędów.
PDOoferuje lepsze rozwiązanie: wyjątki. Wszystko robimy z PDOpowinny być zapakowane w try- catchbloku. Możemy wymusić PDOprzejście do jednego z trzech trybów błędów, ustawiając atrybut trybu błędu. Poniżej przedstawiono trzy tryby obsługi błędów.
PDO::ERRMODE_SILENT. Po prostu ustawia kody błędów i działa prawie tak samo, jak mysql_*tam, gdzie trzeba sprawdzić każdy wynik, a następnie spojrzeć, $db->errorInfo();aby uzyskać szczegółowe informacje o błędzie.
PDO::ERRMODE_WARNINGPodbicie E_WARNING. (Ostrzeżenia w czasie wykonywania (błędy niekrytyczne). Wykonanie skryptu nie jest zatrzymane.)
PDO::ERRMODE_EXCEPTION: Zgłaszaj wyjątki. Reprezentuje błąd zgłoszony przez ChNP. Nie powinieneś wyrzucać PDOExceptionwłasnego kodu. Zobacz Wyjątki, aby uzyskać więcej informacji o wyjątkach w PHP. Zachowuje się bardzo podobnie or die(mysql_error());, gdy nie zostanie złapany. Ale w przeciwieństwie do tego or die(), PDOExceptionmożna je złapać i traktować z wdziękiem, jeśli zdecydujesz się to zrobić.
Dobra lektura :
Lubić:
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
I możesz to owinąć try- catchjak poniżej:
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());
}
Nie musisz sobie z tym poradzić try- w catchtej chwili. Możesz go złapać w dowolnym momencie, ale zdecydowanie zalecamy użycie try- catch. Bardziej sensowne może być złapanie go poza funkcją wywołującą te PDOrzeczy:
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.
}
Możesz sobie poradzić or die()lub możemy to powiedzieć mysql_*, ale będzie to bardzo zróżnicowane. Możesz ukryć niebezpieczne komunikaty o błędach podczas produkcji, obracając display_errors offi po prostu czytając dziennik błędów.
Teraz, po przeczytaniu wszystkich rzeczy powyżej, prawdopodobnie myśląc: co do cholery jest, że kiedy tylko chcesz rozpocząć pochylony proste SELECT, INSERT, UPDATElub DELETEoświadczenia? Nie martw się, zaczynamy:
Wybieranie danych

Więc to, co robisz, mysql_*to:
<?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'];
}
Teraz PDOmożesz to zrobić w następujący sposób:
<?php
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}
Lub
<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Use $results
Uwaga : Jeśli używasz metody jak poniżej ( query()), ta metoda zwraca PDOStatementobiekt. Więc jeśli chcesz pobrać wynik, użyj go jak powyżej.
<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}
W PDO Data jest uzyskiwany za ->fetch()pomocą metody obsługi wyciągu. Przed wywołaniem funkcji pobierania najlepszym rozwiązaniem byłoby określenie PDO, w jaki sposób dane mają być pobierane. W poniższej sekcji wyjaśniam to.
Tryby pobierania
Zwróć uwagę na użycie PDO::FETCH_ASSOCw fetch()i fetchAll()kodu powyżej. Mówi PDOto o zwróceniu wierszy jako tablicy asocjacyjnej z nazwami pól jako kluczami. Istnieje również wiele innych trybów pobierania, które wyjaśnię jeden po drugim.
Przede wszystkim wyjaśniam, jak wybrać tryb pobierania:
$stmt->fetch(PDO::FETCH_ASSOC)
W powyższym używam fetch(). Możesz także użyć:
Teraz przechodzę do trybu pobierania:
PDO::FETCH_ASSOC: zwraca tablicę indeksowaną według nazwy kolumny, tak jak zwrócono w zestawie wyników
PDO::FETCH_BOTH (domyślnie): zwraca tablicę zindeksowaną zarówno przez nazwę kolumny, jak i numer kolumny o indeksie 0, jak zwrócono w zestawie wyników
Jest jeszcze więcej możliwości! Przeczytaj o nich wszystkich w PDOStatementdokumentacji Fetch. .
Uzyskiwanie liczby wierszy :
Zamiast używać mysql_num_rowsdo uzyskania liczby zwróconych wierszy, możesz uzyskać PDOStatementi zrobić rowCount(), na przykład:
<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Uzyskiwanie ostatniego wstawionego identyfikatora
<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
Wstawianie i aktualizowanie lub usuwanie instrukcji

To, co robimy w mysql_*funkcji, to:
<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);
I w pdo, to samo można zrobić poprzez:
<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;
W powyższym zapytaniu PDO::execuruchom instrukcję SQL i zwróci liczbę dotkniętych wierszy.
Wstaw i usuń zostaną omówione później.
Powyższa metoda jest przydatna tylko wtedy, gdy nie używasz zmiennej w zapytaniu. Ale kiedy potrzebujesz użyć zmiennej w zapytaniu, nigdy nie próbuj tak jak wyżej, a tam jest gotowa instrukcja lub instrukcja sparametryzowana .
Przygotowane oświadczenia
P: Co to jest przygotowane oświadczenie i dlaczego ich potrzebuję?
Odp .: Przygotowana instrukcja to wstępnie skompilowana instrukcja SQL, którą można wykonać wiele razy, wysyłając tylko dane do serwera.
Typowy przepływ pracy przy użyciu przygotowanej instrukcji jest następujący ( cytowany z Wikipedii trzy 3 punkty ):
Przygotuj : Szablon instrukcji jest tworzony przez aplikację i wysyłany do systemu zarządzania bazą danych (DBMS). Niektóre wartości pozostają nieokreślone, nazywane parametrami, symbolami zastępczymi lub zmiennymi powiązania (oznaczone ?poniżej):
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
DBMS analizuje, kompiluje i wykonuje optymalizację zapytań na szablonie instrukcji i zapisuje wynik bez jego wykonania.
- Wykonaj : w późniejszym czasie aplikacja dostarcza (lub wiąże) wartości parametrów, a DBMS wykonuje instrukcję (ewentualnie zwraca wynik). Aplikacja może wykonać instrukcję tyle razy, ile chce z różnymi wartościami. W tym przykładzie może podać „Chleb” dla pierwszego parametru i
1.00dla drugiego parametru.
Możesz użyć przygotowanej instrukcji, umieszczając symbole zastępcze w kodzie SQL. Zasadniczo są trzy bez symboli zastępczych (nie próbuj tego ze zmienną powyżej jednego), jeden z nienazwanymi symbolami zastępczymi i jeden z nazwanymi symbolami zastępczymi.
P: Więc jakie są teraz nazwane symbole zastępcze i jak ich używać?
A. Nazwane symbole zastępcze. Używaj opisowych nazw poprzedzonych dwukropkiem zamiast znaków zapytania. Nie dbamy o pozycję / porządek wartości w nazwie zastępczej:
$stmt->bindParam(':bla', $bla);
bindParam(parameter,variable,data_type,length,driver_options)
Możesz również powiązać za pomocą tablicy wykonawczej:
<?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);
Inną ciekawą funkcją dla OOPznajomych jest to, że nazwane symbole zastępcze mają możliwość wstawiania obiektów bezpośrednio do bazy danych, zakładając, że właściwości pasują do nazwanych pól. Na przykład:
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);
P: Więc jakie są teraz nienazwane symbole zastępcze i jak ich używać?
A. Weźmy przykład:
<?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();
i
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));
Powyżej możesz zobaczyć te ?zamiast nazwy, jak w miejscu na nazwę. Teraz w pierwszym przykładzie przypisujemy zmienne do różnych symboli zastępczych ( $stmt->bindValue(1, $name, PDO::PARAM_STR);). Następnie przypisujemy wartości do tych symboli zastępczych i wykonujemy instrukcję. W drugim przykładzie pierwszy element tablicy przechodzi do pierwszego, ?a drugi do drugiego ?.
UWAGA : W nienazwanych symbolach zastępczych musimy zadbać o prawidłową kolejność elementów w tablicy, którą przekazujemy do PDOStatement::execute()metody.
SELECT, INSERT, UPDATE, DELETEPrzygotowany zapytania
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();
UWAGA:
Jednak PDOi / lub MySQLinie są całkowicie bezpieczne. Sprawdź odpowiedź Czy instrukcje przygotowane przez PDO są wystarczające, aby zapobiec wstrzyknięciu SQL? przez ircmaxell . Cytuję też część jego odpowiedzi:
$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 /*"));