Nawiązywanie połączenia z bazą danych MySQL

30 listopada 2015
1 gwiadka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek

Należy używać PDO i instrukcji gotowych (ang. prepared statement).

W PHP jest wiele możliwości łączenia się z bazą danych MySQL. Najnowszą i najlepszą aktualnie metodą jest posługiwanie się obiektami PDO. PDO posiada spójny interfejs do pracy z różnymi typami baz danych, jest konstrukcją obiektową oraz obsługuje wiele nowych funkcji baz danych.

Instrukcje gotowe PDO pomagają uniknąć ataków typu SQL injection. Funkcja bindValue() uniemożliwia przeprowadzanie ataków polegających na natychmiastowym wykonaniu wstrzykniętego szkodliwego kodu. (Nie jest ona niestety całkowicie bezpieczna, o czym można przeczytać w portalu Stack Overflow). Kiedyś trzeba było wykonywać skomplikowane manewry za pomocą kombinacji „magicznych cytatów”. Dzięki PDO wszystkie te sztuczki stały się zbędne.

Przykład użycia PDO w PHP

	<?php
try{
    // utworzenie nowego połączenia
    // w pierwszym parametrze pewnie trzeba będzie wpisać localhost
    // Zwróć uwagę na deklarację zestawu znaków utf8mb4 — jest to sygnał, że zamierzamy używać danych w formacie UTF-8. Czasami nie jest to konieczne, ale może zaoszczędzić nam sporo kłopotów, gdy będziemy chcieli zapisywać w bazie danych łańcuchy Unicode.  Zobacz też Pułapki na dole strony.
    // opis przkazywanych przez nas opcji PDO:
    // \PDO::ATTR_ERRMODE — włącza wyjątki dla błędów. Jest to ustawienie opcjonalne, ale bardzo przydatne.
    // \PDO::ATTR_PERSISTENT — wyłącza trwałe połączenia, które czasami mogą powodować problemy ze współbieżnością. Zobacz Pułapki na dole strony.
    $link = new \PDO(   'mysql:host=nazwa-hosta;dbname=baza-danych;charset=utf8mb4',
                        'nazwa-użytkownika',
                        'hasło',
                        array(
                            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                            \PDO::ATTR_PERSISTENT => false
                        )
                    );
 
    $handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');
 
    // Błąd PHP: bez PDO::PARAM_INT, PDO może umieścić argument w cudzysłowie.  To z kolei może uszkodzić zapytania MySQL, w których liczby całkowite nie powinny być w cudzysłowach.
    // Zobacz: https://bugs.php.net/bug.php?id=44639
    // Jeśli nie masz pewności co do tego czy przekazywana wartość jest liczbą całkowitą, użyj funkcji is_int().
    $handle->bindValue(1, 100, PDO::PARAM_INT);
    $handle->bindValue(2, 'Bilbo Baggins');
    $handle->bindValue(3, 5, PDO::PARAM_INT);
 
    $handle->execute();
 
    // Jeśli trzeba pobrać bardzo dużo wierszy, metoda fetchAll() może nadmiernie obciążać system.
    // W takim przypadku można posłużyć się metodą fetch(), a nastęnie przeglądać wiersze za pomocą pętli.
    // Ewentualnie można też zwracać tablicę i inne konstrukcje zamiast obiektów. Szczegółowe informacje znajdziesz w dokumentacji PDO.
    $result = $handle->fetchAll(\PDO::FETCH_OBJ);
 
    foreach($result as $row){
        print($row->Username);
    }
}
catch(\PDOException $ex){
    print($ex->getMessage());
}
?>

Pułapki

  • Brak parametru PDO::PARAM_INT przy wiązaniu zmiennych całkowitoliczbowych może czasami spowodować umieszczenie ich przez PDO w cudzysłowie. W efekcie może dojść do uszkodzenia niektórych zapytań MySQL. Zobacz to zgłoszenie błędu PHP.
  • Jeśli w łańcuchu połączenia zestaw znaków nie zostanie ustawiony na utf8mb4, to dane w formacie Unicode mogą zostać nieprawidłowo zapisane w bazie danych, choć wszystko zależy od konfiguracji.
  • Nawet jeśli zostanie ustawiony zestaw znaków utf8mb4, należy jeszcze dopilnować, by takie same ustawienie miały tabele bazy danych. O tym dlaczego używamy utf8mb4, a nie po prostu utf8 napiszemy w jednym z dalszych artykułów.
  • Włączenie trwałych połączeń może przyczynić się do występowania dziwnych problemów ze współbieżnością. Nie jest to problem PHP, tylko aplikacji. Połączeń trwałych można bezpiecznie używać pod warunkiem, że ma się świadomość konsekwencji.
  • W jednym wywołaniu funkcji execute() można wykonać więcej niż jedno zapytanie SQL, należy tylko poszczególne instrukcje rozdzielić średnikami. W PHP <= 5.3.10 należy przy tym pamiętać o tym błędzie, którego nie naprawiono w wersji PHP dostępnej w Ubuntu 12.04.

Autor: Alex Cabal

Źródło: http://phpbestpractices.org/

Tłumaczenie: Łukasz Piwko

Treść tej strony dostępna jest na zasadach licencji CC BY-SA 3.0

Zobacz również:

2 komentarze

  1. Link do art. o PHP i UTF-8 nie działa

    Odpowiedz
    • Racja. To dopiero planowany artykuł i dlatego jeszcze nie działa.

      Odpowiedz

Dyskusja

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *