Dzisiejszy wpis będzie obejmował tematykę znaną już z serii na temat ADOdb. Dowiecie się w jaki sposób realizować podpinanie parametrów w PDO oraz na czym polegają różnice między obydwiema bibliotekami. Dla tych, którzy nie wiedzą co to jest, przedstawię także zasadę działania oraz powody dla których używa się tej funkcjonalności. Warto jedynie wspomnieć, że PDO obsługuje znacznie więcej możliwości związanych z podpinaniem parametrów.
Dlaczego stosować?
Podpinanie parametrów ma bardzo wiele zalet nad zwyczajnym filtrowaniem danych i podklejaniem ich do zapytań. Jedną z najważniejszych jest czytelność. Dzięki odpowiednim identyfikatorom wiemy, która zmienna pod jakie miejsce w zapytaniu trafia. Nie musimy się bawić w łączenie długich ciągów znaków, rzutowanie typów i setki filtrów, PDO zrobi to za nas samo. Osobiście znam pewną osobę która po prostu gubi się w tych wszystkich apostrofach gdy nadchodzi potrzeba dołączenia kilku zmiennych do zapytania, nawet bez filtrowania zmiennych!
Pomimo tego najważniejszą zaletą takiego działania jest zabezpieczenie przed ataki typu SQL Injection. Dane które wstawiamy do zapytań zawsze są filtrowane pod względem znaków niebezpiecznych dla bazy danych której używamy, ponadto PDO bierze pod uwagę typ danych który wysyłamy (jeżeli podamy jaki to typ).
Jak tego używać?
Jak dobrze dobrze zapewne pamiętacie (a jeżeli nie, to polecam ich ponowną lekturę) z poprzednich wpisów, wysyłanie zapytania pobierającego dane w PDO składa się z dwóch etapów:
- Przekazaniu zapytania do PDO::query()
- Pobranie danych przy pomocy zwróconego nam obiektu klasy PDOStatement
W przypadku podpinania parametrów także użyjemy klasy PDOStatement, jednak tym razem cała operacja będzie nieco bardziej skomplikowana. Pozwala to na zwiększenie możliwości, jednak znacznie zmniejsza wygodę użytkowania. Nic nie stoi na przeszkodzie, aby napisać sobie niewielką nakładkę dla ułatwienia niektórych operacji. Zapoznajmy się w takim razie z kolejnymi krokami, jakie należy wykonać:
- Przygotowanie zapytania przy pomocy PDO::prepare()
- Podpięcie parametrów przy pomocy obiektu klasy PDOStatement
- Wykonanie zapytania przy pomocy PDOStatement::execute()
- Pobranie danych z obiektu klasy PDOStatement()
PDO pozwala na podpinanie parametrów na dwa sposoby. Przed wykonaniem zapytania, przy pomocy metody PDOStatement::bindValue(), lub podczas wykonywania zapytania metodą PDOStatement::execute(). Ponadto biblioteka obsługuje dwa sposoby identyfikacji parametrów. Przy pomocy liczb oraz nazw.
PDO::bindValue()
W przypadku podpinania danych poprzez PDO::bindValue() uzyskujemy możliwość dokładnego określenia rodzaju danych, które wysyłamy do zapytania. Dokonujemy tego podczas przypisywania kolejnych zmiennych do identyfikatorów/liczb. Kilka przykładów:
$stmt = $db->prepare('SELECT * FROM users WHERE id = ? AND password = ?');
$stmt -> bindValue(0, $_SESSION['user_id'], PDO::PARAM_INT); //Podpinamy zmienną $_SESSION['user_id'] do pierwszego znaku zapytania jako liczbę
$stmt -> bindValue(1, $_SESSION['password'], PDO::PARAM_STR, 32); //Podpinamy zmienną $_SESSION['password'] zamiast drugiego znaku zapytania jako 32 literowy ciąg znaków
$stmt->execute();
Przypadek z numerycznym umieszczaniem parametrów (ang. placeholders). Każdy parametr posiada swój numer według kolejności występowania znaków zapytania. Liczenie zaczynamy od jedynki (w przypadku używania metody PDOStatement::bindValue()).
$stmt = $db->prepare('SELECT * FROM users WHERE id = :user_id AND password = :user_pass');
$stmt -> bindValue(':user_id', $_SESSION['user_id'], PDO::PARAM_INT); //Podpinamy zmienną $_SESSION['user_id'] do parametru o nazwie :user_id jako liczbę
$stmt -> bindValue(':user_pass', $_SESSION['password'], PDO::PARAM_STR, 32); //Podpinamy zmienną $_SESSION['password'] zamiast identyfikatora :user_pass jako 32 literowy ciąg znaków
$stmt->execute();
Przypadek z nazwami jako identyfikatory parametrów (ang. named parameters). Każdy parametr posiada swoją własną nazwę według której podpinane są wartości.
Warto wspomnieć jeszcze jednej funkcji do popinania parametrów - PDOStatement::bindParam(). Jedyna różnica w stosunku do PDOStatement::bindValue() jest taka, że zmienne przekazane jako parametry podpinane są przez referencję, co umożliwia wykonanie kilki podobnych zapytań zaraz po sobie, podobnie jak robiliśmy to w przypadku ADOdb. Wystarczy, że zmienimy wartość umieszczoną w zmiennej podpiętej do zapytania i ponownie wykonamy metodę execute().
$user = 'Klaus';
$players = $pdo -> prepare('SELECT * FROM players WHERE user = ?');
$players -> bindParam(1, $user);
$players -> execute();
$player = $players -> fetch();
echo $player['email'].'<br>';
$players -> closeCursor();
$user = 'PQA';
$players -> execute();
$player = $players -> fetch();
echo $player['email'].'<br>';
$players -> closeCursor();
$user = 'sss';
$players -> execute();
$player = $players -> fetch();
echo $player['email'].'<br>';
$players -> closeCursor();
Przekazywanie parametrów przy PDOStatement::execute()
Innym sposobem na umieszczenie wartości w zapytaniu jest podanie ich tablicy do metody PDOStatement::execute(). Jej indeksowanie zależy od wybranego przez nas sposobu identyfikowania parametrów. W przypadku parametrów z nazwami, używamy ich podobnie jak przy PDOStatement::bindValue(). Jeżeli natomiast numerujemy parametry, to ich indeks numeryczny w tablicy będzie odpowiadał kolejnym znakom zapytania.
$stmt = $db->prepare('SELECT * FROM users WHERE id = :user_id AND password = :user_pass');
$stmt->execute(array(
':user_id' => $_SESSION['user_id'],
':user_pass' => $_SESSION['password']
));
Przypadek z nazwami jako identyfikatorami. Każdej nazwie podstawiana jest odpowiednia warość z tablicy przekazanej do PDOStatement::execute() o kluczu zależnym od identyfikatora parametru.
$stmt = $db->prepare('SELECT * FROM users WHERE id = ? AND password = ?');
$stmt->execute(array($_SESSION['user_id'], $_SESSION['password']));
Przypadek ze znakami zapytania. Tym razem nie musimy podawać indeksów dla tablicy, ponieważ jest ona i tak domyślnie numerowana od zera. Osobiście używam właśnie tego sposobu ze względu na zwięzłość zapisu.
Dalej dane pobieramy już tak jak zwykle, przy pomocy metod PDOStatement::fetch(), PDOStatement::fetchAll() lub PDOStatement::fetchColumn(). Warto jedynie pamiętać, że PDOStatement zwraca jedynie wartość typu bool, która zawiera informację o powodzeniu wykonania zapytania. Wszelkie dane pobrane z bazy znajdują się nadal w obiekcie klasy PDOStatement na którym wykonaliśmy metodę execute().
$stmt = $db->prepare('SELECT * FROM users WHERE id = ? AND password = ?');
$stmt->execute(array($_SESSION['user_id'], $_SESSION['password']));
foreach($stmt as $user)
{
echo $user['login'].'<br>';
}
Zakończenie
To już wszystko co chciałem przedstawić w dzisiejszym wpisie. Następnym razem dowiemy się, w jaki sposób przy pomocy podpinania kolumn do zmiennych pobierać dane z bazy. Jeszcze tylko pytanie do czytelników: czy wpisy z serii na temat PDO są dla was przydatne? Jeżeli czegoś im brakuje, bardzo proszę o jakiś komentarz, chciałbym aby były one możliwie najlepszym źródłem wiedzy dla początkujących.