Tworzenie Aplikacji Internetowych dr Wojciech M. Gańcza 3 Zasięg zmiennych W PHP skrypt tworzący stronę zachowuje się jak program Gdy generowanie strony się kończy – program się kończy Wszystkie zmienne przestają istnieć Wszystkie zasoby otwarte lub utworzone przez skrypt – są zamykane lub usuwane A czasem warto coś zapamiętać… Sesja Jeśli informacje powinny przetrwać do następnej strony – możemy użyć sesji Do obsługi sesji służą polecenia session_start session_register I inne (->manual php) Oraz globalna tablica asocjacyjna $_SESSION Dane sesji obsługiwane są jako cookie. Ograniczenia sesji Sesja dotyczy pojedynczego użytkownika – nie można dzielić danych pomiędzy różnych użytkowników Sesja wygasa – po krótkim okresie nieaktywności – tracimy informacje zawarte w sesji Sesja wymaga akceptowania cookie Inne sposoby pamiętania Zamiast w sesji możemy pamiętać dane W ukrytych elementach formularza (nie można dzielić z innymi) W plikach (podobnie – problem wielodostępu) W bazie danych – tu jest najlepiej: dane mają strukturę i wszyscy mają dostęp – serwer bazy danych rozwiązuje konflikty wielodostępu Baza danych W bazie dane podzielone są na tabele Każda tabela zawiera rekordy o takiej samej strukturze Dane w bazie są chronione – by uzyskać dostęp musimy się autoryzować Baza zapewnia mechanizmy wyszukiwania danych Wiele baz zapewnia tranzakcyjność Dostęp do danych Mimo, że PHP zapewnia spory repertuar funkcji do obsługi bazy – wszystkie operacje możemy wykonywać komunikując się w języku SQL (sequence query language) Język ten składa się tylko z kilku poleceń Musimy jednak wcześniej nawiązać połączenie z bazą danych Połączenie - przykład Wszystkie polecenia jakie będziemy omawiali – dotyczą serwera MySQL Połączenie – mysql_connect Nazwa serwera Identyfikator użytkownika Hasło autoryzujące użytkownika Wartości połączenia mogą być określone w konfiguracji PHP Funkcja zwraca identyfikator połączenia – który można zapamiętać Pytanie SQL Do przesłania zapytania służy polecenie mysql_query Tekst zapytania (string) Opcjonalnie – identyfikator połączenia Jeśli nie określimy połączenia – będzie użyte ostatnio nawiązane Wynikiem może być identyfikator recordsetu zawierającego wynik działania zapytania Zapytanie może też nic nie zwracać Inne funkcje W manualu PHP można znaleźć sporo innych funkcji – jednak nie będziemy ich używać. Zamiast tego – skorzystamy z poleceń języka SQL Przykład – zamiast wyboru bazy użyjemy „use nazwa_bazy” Warto poinformować bazę w jakim kodowaniu będą przychodzić polecenia „set names utf8;” Klasa połączenia class DatabaseAccess { var $connection; function DatabaseAccess() { //… } function query($query) { //… } } Konstruktor Czy do konstruktora powinniśmy przekazywać parametry połączenia? Tak – bo to on decyduje z jakim serwerem i jaką bazą należy się połączyć Nie – bo różne serwery baz danych wymagają różnego określenia parametrów połączenia – a chcemy mieć możliwość podmienienia połączenia Klasa określająca konfigurację class DatabaseConfiguration { var $database_server; var $database_user; var $database_password; var $database_name; function DatabaseConfiguration() { $this->database_server = "localhost"; $this->database_user = "root"; $this->database_password = ""; $this->database_name = "UUK"; } }; Definicje obiektu konfiguracji po prostu dołączamy do plików włączanych w skrypt. Konstruktor function DatabaseAccess() { $config = new DatabaseConfiguration(); $this->connection = mysql_connect( $config->database_server, $config->database_user, $config->database_password); mysql_query("set names utf8;"); mysql_query("use " . $config->database_name . ";", $this->connection); } Przy połączeniu wybieramy bazę i ustawiamy sposób komunikacji! Po konstrukcji dostęp do bazy ma być przygotowany Metoda query() Wystarczyłoby napisać function query($query) { return mysql_query( $query, $this->connection)); } Jednak sposób czytania zasobu zwracanego przez mysql_query – jest typowy dla serwera MySQL! Recordset Dodajmy klasę recordset implementującą źródło danych Zapytanie może zwrócić pusty zbiór danych – musimy się na to przygotować (zwraca false zamiast identyfikatora zasobu) Metoda mysq_fetch_row zwraca tablicę lub false gdy nie ma więcej danych – a to za pózno (eof powinien zgłosić true przed pobraniem Recordset… class Recordset { var $recordset; var $record ; function Recordset($records) { …} function get() {…} }; function eof() {…} Recordset… function Recordset($records) { $this->recordset = $records; if (gettype($records) != "resource") { $this->record = false; } else { $this->get(); } } Recordset… function get() { $previousRecord = $this->record; $this->record = ($this->recordset ? mysql_fetch_row($this->recordset) : false); return $previousRecord; } function eof() { return ($this->record ? false : true); } Teraz możemy: … zakończyć pisanie dostępu do bazy danych: function query($query) { return new Recordset( mysql_query($query, $this->connection)); } Klasy DatabaseAccess i Recordset – powinny być umieszczone w jednym pliku. Konstrukcja bazy W czasie pracy nad programem często testujemy Testy często polegają na zmianie danych Testy powinny być powtarzalne Dane powinno się łatwo przywracać Z kopii zapasowej, lub Przy użyciu skryptów tworzących Wole to drugie rowzwiązanie Konstrukcja bazy Bazę tworzymy poleceniem SQL ‘create database nazwabazy;’ Po utworzeniu – powinniśmy przejść do tej bazy Całą bazę danych możemy usunąć poleceniem ‘drop database nazwabazy’ Jeśli coś jest tworzone poleceniem create – to jest usuwane przez drop Konstrukcja bazy … Tabele konstruujemy poleceniem ‘create table nazwatabeli ( pola i inne elementy tabeli);’ Tabelę usuwamy poleceniem ‘drop table nazwatabeli’. Usunięcie tabeli bezpowrotnie usuwa wszystkie zawarte w niej dane Różne serwery stosują różną składnię do określenia pól i innych elementów tabeli Klasy tworzące bazę DBDatabaseCreator – tworzy pustą bazę DBTableCreator – tworzy tabelę pozwalając dodawać pole po polu DBFieldTypes – zawiera określenia typów pól zrozumiałych przez bazę Wszystkie operacje tworzenia bazy muszą być wykonane jedynie przy użyciu tych klas DBFieldTypes class DBFieldTypes { var $primaryKey; var $refrence; var $title; var $name; var $description; var $money; function DBFieldTypes() { $this->primaryKey = "INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY"; $this->reference = "INTEGER"; $this->title = "VARCHAR(160)"; $this->name = "VARCHAR(64)"; $this->description = "VARCHAR(255)"; $this->money = "REAL"; } } DBDatabaseCreator class DBDatabaseCreator { var $database; function DBDatabaseCreator(&$database) { $this->database = &$database; } function createDatabase($name) { $this->database->query("create database $name default character set utf8;"); $this->database->query("set names utf8;"); $this->database->query("use $name;"); } } DBTableCreator class DBTableCreator { var $database; var $fieldTypes; var $definitionOfTable; function DBTableCreator(&$database) { $this->database = &$database; $this->fieldTypes= new DBFieldTypes(); $this->definitionOfTable = ""; } DBTableCreator … function startTable($name) { $this->definitionOfTable = "create table $name (" . $name . "ID " . $this->fieldTypes->primaryKey; } function addField($name, $type) { $this->definitionOfTable .= ", " . $name . " " . $this->fieldTypes->$type; } DBTableCreator … function createTable() { $this->database->query( $this->definitionOfTable . ") DEFAULT CHARSET utf8;"); } function createIndex($tableName, $fieldName) { $this->database->query("create index ${tableName}${fieldName} on ${tableName}($fieldName);"); } W następnym odcinku Poprawiamy konstruktor bazy Tworzymy bazę Wypełniamy bazę Tworzymy pierwszy widok danych z bazy Poznajemy ciekawe konstrukcje języka SQL Dowiemy się dlaczego nasza baza jest określana jako relacyjna