Oto, o czym do tej pory czytałem PDO::ATTR_EMULATE_PREPARES
:
- Przygotować emulacja PDO jest lepsza dla wydajności od MySQL ojczystym przygotować omija cache zapytań .
- Natywne przygotowanie MySQL jest lepsze pod względem bezpieczeństwa (zapobiega iniekcji SQL) .
- Natywne przygotowanie MySQL jest lepsze do raportowania błędów .
Nie wiem już, na ile prawdziwe są te stwierdzenia. Moim największym zmartwieniem przy wyborze interfejsu MySQL jest zapobieganie wstrzykiwaniu SQL. Drugi problem to wydajność.
Moja aplikacja używa obecnie proceduralnego MySQLi (bez przygotowanych instrukcji) i całkiem sporo wykorzystuje pamięć podręczną zapytań. Rzadko będzie ponownie wykorzystywać przygotowane oświadczenia w jednym wniosku. Rozpocząłem przechodzenie na PDO ze względu na wymienione parametry i bezpieczeństwo przygotowanych zestawień.
Używam MySQL 5.1.61
iPHP 5.3.2
Powinienem pozostawić PDO::ATTR_EMULATE_PREPARES
włączony czy nie? Czy istnieje sposób, aby zarówno wydajność pamięci podręcznej zapytań, jak i bezpieczeństwo przygotowywanych instrukcji?
Odpowiedzi:
Aby odpowiedzieć na Twoje obawy:
MySQL> = 5.1.17 (lub> = 5.1.21 dla instrukcji
PREPARE
iEXECUTE
) może używać przygotowanych instrukcji w pamięci podręcznej zapytań . Twoja wersja MySQL + PHP może więc używać przygotowanych instrukcji z pamięcią podręczną zapytań. Zwróć jednak uwagę na zastrzeżenia dotyczące buforowania wyników zapytań w dokumentacji MySQL. Istnieje wiele rodzajów zapytań, których nie można buforować lub które są bezużyteczne, mimo że są buforowane. Z mojego doświadczenia wynika, że pamięć podręczna zapytań i tak nie jest często bardzo korzystna. Zapytania i schematy wymagają specjalnej konstrukcji, aby maksymalnie wykorzystać pamięć podręczną. Często buforowanie na poziomie aplikacji i tak jest konieczne na dłuższą metę.Natywne przygotowania nie mają żadnego znaczenia dla bezpieczeństwa. Pseudo przygotowane instrukcje będą nadal unikały wartości parametrów zapytania, zostanie to po prostu wykonane w bibliotece PDO z ciągami znaków zamiast na serwerze MySQL przy użyciu protokołu binarnego. Innymi słowy, ten sam kod PDO będzie równie podatny (lub niewrażliwy) na ataki polegające na wstrzykiwaniu, niezależnie od
EMULATE_PREPARES
ustawień. Jedyna różnica polega na tym, gdzie następuje zamiana parametru - w przypadkuEMULATE_PREPARES
, w bibliotece PDO; bezEMULATE_PREPARES
, występuje na serwerze MySQL.Bez
EMULATE_PREPARES
ciebie mogą pojawić się błędy składniowe w czasie przygotowania, a nie w czasie wykonywania; zEMULATE_PREPARES
was dostanie tylko błędy składniowe w czasie wykonywania, ponieważ PDO nie posiada zapytanie dać MySQL aż do czasu wykonania. Zauważ, że ma to wpływ na kod, który napiszesz ! Zwłaszcza jeśli używaszPDO::ERRMODE_EXCEPTION
!Dodatkowa uwaga:
prepare()
(przy użyciu przygotowanych instrukcji przygotowanych natywnie)prepare();execute()
może być trochę wolniejszy niż wysyłanie zwykłego zapytania tekstowego przy użyciu emulowanych gotowych instrukcji. W wielu systemach baz danych plan zapytań dla aprepare()
jest również buforowany i może być współdzielony z wieloma połączeniami, ale nie sądzę, aby MySQL to robił. Jeśli więc nie użyjesz ponownie przygotowanego obiektu instrukcji do wielu zapytań, ogólne wykonanie może być wolniejsze.Na koniec uważam, że przy starszych wersjach MySQL + PHP należy emulować przygotowane instrukcje, ale w przypadku najnowszych wersji należy wyłączyć emulację.
Po napisaniu kilku aplikacji korzystających z PDO stworzyłem funkcję połączenia PDO, która ma, moim zdaniem, najlepsze ustawienia. Prawdopodobnie powinieneś użyć czegoś takiego lub dostosować preferowane ustawienia:
źródło
mysql_real_escape_string
ze znakami wielobajtowymi) nadal pozostawiałaby otwartą na ataki wstrzykiwania?mysql_real_escape_string
pod maską i wynikających z tego luk w zabezpieczeniach, które mogą się pojawić (w bardzo szczególnych przypadkach skrajnych).Uważaj na wyłączanie
PDO::ATTR_EMULATE_PREPARES
(włączanie natywnych przygotowań), gdy PHPpdo_mysql
nie jest kompilowanemysqlnd
.Ponieważ stary
libmysql
nie jest w pełni kompatybilny z niektórymi funkcjami, może prowadzić do dziwnych błędów, na przykład:PDO::PARAM_INT
(0x12345678AB zostanie przycięte do 0x345678AB na komputerze 64-bitowym)LOCK TABLES
(zgłaszaSQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet
wyjątek)mysqlnd
lub emulowanym przygotowuje, automatycznie robi to za Ciebie i nie traci synchronizacji z serwerem mysql)Te błędy znalazłem w moim prostym projekcie po migracji na inny serwer, który był używany
libmysql
dlapdo_mysql
modułu. Może jest znacznie więcej błędów, nie wiem. Testowałem również na świeżej, 64-bitowej wersji debian jessie, wszystkie wymienione błędy pojawiają się, gdy jaapt-get install php5-mysql
, i znikają, gdy jaapt-get install php5-mysqlnd
.Kiedy
PDO::ATTR_EMULATE_PREPARES
jest ustawione na true (domyślnie) - te błędy i tak się nie zdarzają, ponieważ PDO w ogóle nie używa przygotowanych instrukcji w tym trybie. Tak więc, jeśli używasz wpdo_mysql
oparciu olibmysql
(podciąg "mysqlnd" nie pojawia się w polu "Wersja API klienta" wpdo_mysql
sekcji phpinfo) - nie powinieneś goPDO::ATTR_EMULATE_PREPARES
wyłączać.źródło
Wyłączyłbym emulację przygotowań, gdy używasz 5.1, co oznacza, że PDO będzie korzystać z natywnej funkcji przygotowanych instrukcji.
http://php.net/manual/en/ref.pdo-mysql.php
Porzuciłem MySQLi na rzecz PDO ze względu na przygotowane nazwane instrukcje i lepsze API.
Aby jednak zachować równowagę, PDO działa pomijalnie wolniej niż MySQLi, ale warto o tym pamiętać. Wiedziałem o tym, kiedy dokonałem wyboru i zdecydowałem, że lepsze API i użycie standardu branżowego jest ważniejsze niż użycie pomijalnie szybszej biblioteki, która wiąże Cię z określonym silnikiem. FWIW Myślę, że zespół PHP również przychylnie patrzy na PDO zamiast MySQLi w przyszłości.
źródło
Polecam włączenie prawdziwych
PREPARE
wywołań bazy danych, ponieważ emulacja nie przechwytuje wszystkiego ... na przykład się przygotujeINSERT;
!Wyjście
Chętnie wezmę wydajność dla kodu, który faktycznie działa.
FWIW
Wersja PHP: PHP 5.4.9-4ubuntu2.4 (cli)
Wersja MySQL: 5.5.34-0ubuntu0
źródło
prepare
wykonać zadanie, do którego powinno. (Dodatkowo zawsze zakładałem, że parser parametrów po stronie klienta będzie musiał mieć własne błędy.)Jestem zaskoczony, że nikt nie wymienił jednego z największych powodów, dla których warto wyłączyć emulację. Przy włączonej emulacji PDO zwraca wszystkie liczby całkowite i zmiennoprzecinkowe jako łańcuchy . Po wyłączeniu emulacji liczby całkowite i zmiennoprzecinkowe w MySQL stają się liczbami całkowitymi i zmiennoprzecinkowymi w PHP.
Aby uzyskać więcej informacji, zapoznaj się z zaakceptowaną odpowiedzią na to pytanie: PHP + PDO + MySQL: jak zwrócić kolumny całkowite i liczbowe z MySQL jako liczby całkowite i liczby w PHP? .
źródło
https://tech.michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/
źródło
Tak dla porządku
PDO :: ATTR_EMULATE_PREPARES = true
Może to spowodować nieprzyjemny efekt uboczny. Może zwrócić wartości int jako ciąg.
PHP 7.4, pdo z mysqlnd.
Uruchamianie zapytania z PDO :: ATTR_EMULATE_PREPARES = true
Kolumna: id
Typ: liczba całkowita
Wartość: 1
Uruchamianie zapytania z PDO :: ATTR_EMULATE_PREPARES = false
Kolumna: identyfikator
Typ: ciąg
Wartość: „1”
W każdym przypadku wartości dziesiętne są zawsze zwracane jako ciąg znaków, niezależnie od konfiguracji :-(
źródło