1 Bazy Danych Wykład 7 Wojciech St. Mościbrodzki [email protected]
2 Implementacja MySQL w PHPImplementacja obsługi mySQL odbywa się w postaci natywnego API dla PHP: mysql, mysqli lub PDO Alternatywą jest stosowanie Open Connectivity (np. ODBC): mySQL mySQLi PDO ODBC ODBC
3 PHP i MySQL Konstrukcja dynamicznego HTML z szablonu w PHP i danych:
4 Operacje na bazie przeprowadzane są przez handlery połączeń (my)SQL w PHP Operacje na bazie przeprowadzane są przez handlery połączeń PHP zapewnia specjalny typ resource: połączenie z serwerem HTTP connection MySQL query MySQL connection
5 mysql_connect resource mysql_connect ( [ string $serwer[, string $nazwa_użytkownika [, string $hasło [, bool $nowe_połączenie [, int $flagi_klienta ]]]]] ) Serwer, do jakiego łączymy user password testowanie, jeśli już otwarte? dodatki
6 MySQL wysyła błędy do PHP – mogą być one przechwycone:Obsługa błędów MySQL wysyła błędy do PHP – mogą być one przechwycone: int mysql_errno ([ resource $link ] ) string mysql_error ([ resource $link ] ) Typowa obsługa:
7 Wybranie połączenia z bazą (może być także – baza domyślna)Wybór bazy danych Wybranie połączenia z bazą (może być także – baza domyślna) bool mysql_select_db ( string $nazwa_bazy [, resource $identyfikator_połączenia ] )
8 Sprzątamy po zakończeniu pracyDobrze napisany skrypt usuwa po sobie połączenie (choć nie jest to konieczne dla połączeń nie-stałych); bool mysql_close ([ resource $link ] ) Dobry skrypt: otwórz-wybierz-query1-query2-…-queryN-zamknij
9 Zapytania: typu result i typu execZapytanie typu result zwraca JAKIŚ wynik (tabelę). Zapytania tego typu to: SELECT, DESCRIBE, EXPLAIN i SHOW Zapytanie typu exec wykonuje się na bazie danych i zwraca jedynie status (true, albo false). Typowe zapytania to CREATE, DELETE, DROP i INSERT. Oba typy zapytań obsługuje funkcja mysql_query. Dla zapytań result zwracany jest resource typu handler wyniku. Dla zapytań exec zwracany jest resource typu bool. resource mysql_query ( string $query [, resource $link [, int $typ_wyniku ]] ) Treść zapytania Handler połączenia (otwartego!) Flagi (np. buforowanie)
10 Zapytania takie mają prostą obsługę błędów:Zapytania typu exec Zapytania takie mają prostą obsługę błędów: zwrócona wartość to TRUE lub FALSE Dodatkowo, można sprawdzić, ile krotek uległo zmianie (DELETE!): int mysql_affected_rows ([ resource $link ] ) int mysql_insert_id ([ resource $ link ] )
11 zwrócona wartość to handler tablicyZapytania typu result Zapytania tego typu zwracają tabelę (jako handler wyniku) z danymi. Jest ona przetwarzana wolniej niż kursor SQL. mixed mysql_result ( resource $wynik, int $wiersz [, mixed $pole ] ) Wynik zwrócony przez mysql_query() Który wiersz wyniku (numerowanie od 0) Która kolumna wyniku (numerowanie od 0) zwrócona wartość to handler tablicy
12 Kursor - Szybka forma przetwarzaniaFunkcja mysql_fetch_row działa szybciej niż mysql_result array mysql_fetch_row (resource $wynik) bool mysql_data_seek (resource $wynik, int $nr) mysql_query() mysql_data_seek() mysql_fetch_row() int mysql_num_rows (resource $wynik) mysql_data_fields() int mysql_num_fields (resource $wynik) mysql_num_rows()
13 Obsługa kursora po stronie PHPfunction DBArrayQuery($query) { $link = mysql_connect('localhost', ‘alex', ‘lipton'); $result $tablica = array(); $num_fields = mysql_num_fields($result); // kursor - X $num_rows = mysql_num_rows($result); // kursor - Y $nr_row = 0; while ($nr_row < $num_rows) { $nr_field = 0; $curr_row = mysql_fetch_row($result); while ($nr_field < $num_fields) { $tablica[$nr_row][$nr_field]=$curr_row[$nr_field]; $nr_field++; }; $nr_row++; }; return $tablica; };
14 Obsługa praw dostępu Autoryzacja za pomocą wielu użytkowników: database: mysql database: mysql Autoryzacja za pomocą auth-usera: database: moja
15 Typowe problemy: Na stronach zbudowanych w oparciu o PHP często napotykamy na błędy przy wywołaniu takiej funkcji: function DBInsert($value) { $link = mysql_connect('localhost', ‘alex', ‘lipton'); $query = ”insert into pracownik (nazwisko) values ”; $query .= ”(‘”.$value.”’)”; @mysql_query($query); mysql_close($link); }; DBInsert(‘Kowalski’); Dlaczego?
16 Aby tego uniknąć można zastosować funkcję ochronną:Typowe problemy: Problemem jest fakt, że użytkownik lub autor skryptu może dopisać do zapytania łańcuchy zaburzające składnię SQL: function DBInsert($value) { $link = mysql_connect('localhost', ‘alex', ‘lipton'); $query = ”insert into pracownik (nazwisko) values ”; $query .= ”(‘”.$value.”’)”; @mysql_query($query); }; DBInsert(” d`Artagnan ”); insert into pracownik (nazwisko) values (’d’Artagnan’); Aby tego uniknąć można zastosować funkcję ochronną: string mysql_escape_string ( string $łańcuch )
17 Tablica SQL w tabelce HTML dzięki tablicy PHPEtapy rozwiązywania problemu: Obsłużyć połączenie z bazą danych Wysłać zapytanie Odebrać rezultat i wpisać do tablicy dwuwymiarowej w PHP Opakować zawartość tablicy PHP w znaczniki HTML Funkcja tworząca połączenie: function DBlink($db_base, $db_user, $db_pass) { $link = mysql_connect($db_host, $db_user, $db_pass) or die ('Cant access: ' . mysql_error()); mysql_select_db($db_base, $link); or die ('Cant switch to DB: ' . mysql_error()); return $link; };
18 Tablica SQL w tabelce HTML dzięki tablicy PHPFunkcja wysyłająca zapytanie i odbierająca wynik: function DBArrayQuery($query) { $link = DBlink(); $result $tablica = array(); $nr_row = 0; while ($nr_row < mysql_num_rows($result)) { $nr_field = 0; $curr_row = mysql_fetch_row($result); while ($nr_field < mysql_num_fields($result); ){ $tablica[$nr_row][$nr_field]=$curr_row[$nr_field]; $nr_field++; }; $nr_row++; }; return $tablica; };
19 Tablica SQL w tabelce HTML dzięki tablicy PHPFunkcja obsługująca wynik w postaci HTML: function HTMLize($tablica) { echo ” 20 Uwagi o bezpieczeństwieNajważniejsze przykazania: NIGDY nie pisz skryptów łączących się do bazy jako root (mysql) NIGDY nie uruchamiaj serwera bazy danych z konta superusera Nie dopuszczaj do wykonania komendy LOAD DATA INFILE z sieci Nie dopuszczaj do wykonania komendy SELECT INTO OUTFILE z sieci Nie pozwalaj na generowanie dowolnych SQLi przez użytkownika Uważaj na SQL injection attack SQL Injection attack (UNION type): $query = "SELECT * FROM user where max_connections = " . $_REQUEST['user']; $result = mysql_result($query); 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1+from+func 21 Atak typu UNION + LOAD FILEW SQL łańcuch tekstowy można reprezentować jako jego wartości numeryczne. Na przykład: 'c:/boot.ini' jest równoznaczne z: 0x633a2f626f6f742e696e69 Skoro tak to można wykonać zapytanie select 0x633a2f626f6f742e696e69 A więc można wpisać taki URL: I zobaczyć W PRZEGLĄDARCE: [boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)pa 1 1 N N N N N N N N N N N N N N N N N N N N N 22 Ataki typu DATA INFILE/DATA OUTFILETa metoda ataku wymaga dopuszczenia zapytań SQL podawanych przez klienta. Żeby obejrzeć plik z serwera wystarczy: create table foo( line blob ); load data infile 'c:/boot.ini' into table foo; select * from foo; Ta metoda ataku pozwala (na niespatchowanym mysql) na podmianę plików konfiguracyjnych: create table xxx( line text ); insert into xxx values (”A to mój nowy plik konfiguracyjny”); select line from xxx into c:\mysql\mysql.cnf 23 Zarządzanie i administracja MySQL 24 mysqldump Do przygotowywania zrzutów danych z serwera służy mysqldumpProgramiku mysqldump używa się najczęściej z parametrami: -uuser – użytkownik (musi mieć odpowiednie prawa do bazy danych) -ppassword – hasło (warto otoczyć hasło cudzysłowami) --all-databases – jeśli chcemy archiwizować wszystkie bazy Przykład: mysqldump –uroot –p”taki;kera” bazatestowa Zrzuty wykonuje się często do pliku tekstowego: mysqldump –uroot –p”taki;kera” bazatestowa > zrzut.bazatestowa.sql Wynik działania jest gotowym skryptem sql do wykorzystania 25 mysqldump -- MySQL dump 10.11 -- -- Host: localhost Database: poligon -- Server version /*!40101 SET */; /*!40101 SET */; /*!40101 SET */; /*!40101 SET NAMES utf8 */; /*!40103 SET */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET UNIQUE_CHECKS=0 */; /*!40014 SET FOREIGN_KEY_CHECKS=0 */; /*!40101 SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET SQL_NOTES=0 */; 26 -- -- Table structure for table `user` DROP TABLE IF EXISTS `user`; = SET character_set_client = utf8; CREATE TABLE `user` ( `id` int(11) NOT NULL auto_increment, `imie` char(30) default NULL, `nazwisko` char(50) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client 27 -- -- Dumping data for table `user` LOCK TABLES `user` WRITE; /*!40000 ALTER TABLE `user` DISABLE KEYS */; INSERT INTO `user` VALUES (1,'Jan','Kowalski'); /*!40000 ALTER TABLE `user` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET */; /*!40101 SET */; /*!40014 SET */; /*!40014 SET */; /*!40101 SET */; /*!40101 SET */; /*!40101 SET */; /*!40111 SET */;”; foreach ($tablica as $wiersz) { echo ”
”; foreach ($wiersz as $komorka) { echo ” ”. $komorka . ” ”; }; echo ””; }; }; Program główny: HTMLize(DBArrayQuery(”select name, ind from student”));