Używając wspólnego interfejsu programowania



Podobne dokumenty
Podstawy programowania III WYKŁAD 2

Dostęp do baz danych z serwisu www - PHP. Wydział Fizyki i Informatyki Stosowanej Joanna Paszkowska, 4 rok FK

Języki programowania wysokiego poziomu. PHP cz.4. Bazy danych

PHP może zostać rozszerzony o mechanizmy dostępu do różnych baz danych:

PHP: bazy danych, SQL, AJAX i JSON

Sprawdzenie czy połączenie przebiegło poprawnie if (mysqli_connect_errno()) { echo Błąd; Połączenie z bazą danych nie powiodło się.

Wydział Elektrotechniki, Informatyki i Telekomunikacji Instytut Informatyki i Elektroniki

Wdrożenie modułu płatności eservice. dla systemu oscommerce 2.3.x

Instalacja MySQL.

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Wdrożenie modułu płatności eservice. dla systemu Zen Cart

dziennik Instrukcja obsługi

Laboratorium nr 4. Temat: SQL część II. Polecenia DML

Projektowanie systemów baz danych

Ćwiczenia laboratoryjne nr 11 Bazy danych i SQL.

6. Bezpieczeństwo przy współpracy z bazami danych

Wprowadzenie do Doctrine ORM

Wdrożenie modułu płatności eservice. dla systemu Magento

Wykład 5: PHP: praca z bazą danych MySQL

Język SQL, zajęcia nr 1

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java

Wdrożenie modułu płatności eservice. dla systemu Gekosale 1.4

Informatyka I. Programowanie aplikacji bazodanowych w języku Java. Standard JDBC.

Bazy danych II. Andrzej Grzybowski. Instytut Fizyki, Uniwersytet Śląski

Bazy danych. Wykład IV SQL - wprowadzenie. Copyrights by Arkadiusz Rzucidło 1

Programowanie w SQL procedury i funkcje. UWAGA: Proszę nie zapominać o prefiksowaniu nazw obiektów ciągiem [OLIMP\{nr indeksu}] Funkcje użytkownika

DECLARE VARIABLE zmienna1 typ danych; BEGIN

Zagadnienia. Konstrukcja bibliotek mysql i mysqli w PHP. Dynamiczne generowanie stron. Połączenie, zapytanie i sesja

SQL (ang. Structured Query Language)

5. Współpraca z bazą danych MySQL

Wprowadzenie. Rozdział 23 PDO. Podstawowe kroki aplikacji. Źródło danych

Blaski i cienie wyzwalaczy w relacyjnych bazach danych. Mgr inż. Andrzej Ptasznik

Aplikacje WWW - laboratorium

Języki skryptowe - PHP. PHP i bazy danych. Paweł Kasprowski. pawel@kasprowski.pl. vl07

strukturalny język zapytań używany do tworzenia i modyfikowania baz danych oraz do umieszczania i pobierania danych z baz danych

Ref. 7 - Język SQL - polecenia DDL i DML

Database Connectivity

Programowanie MSQL. show databases; - pokazanie jakie bazy danych są dostępne na koncie

Struktura drzewa w MySQL. Michał Tyszczenko

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

SQL 4 Structured Query Lenguage

CREATE USER

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Internetowe bazy danych

Internetowe bazy danych

Systemy baz danych Prowadzący: Adam Czyszczoń. Systemy baz danych. 1. Import bazy z MS Access do MS SQL Server 2012:

Autor: Joanna Karwowska

Przykłady najlepiej wykonywać od razu na bazie i eksperymentować z nimi.

Aplikacje WWW - laboratorium

E.14 Bazy Danych cz. 18 SQL Funkcje, procedury składowane i wyzwalacze

DECLARE <nazwa_zmiennej> typ [(<rozmiar> )] [ NOT NULL ] [ { := DEFAULT } <wartość> ];

Paweł Rajba

Systemy GIS Tworzenie zapytań w bazach danych

Systemy internetowe. Wykład 4 mysql. West Pomeranian University of Technology, Szczecin; Faculty of Computer Science

Oracle PL/SQL. Paweł Rajba.

Wykład I. Wprowadzenie do baz danych

Wprowadzenie do projektowania i wykorzystania baz danych Relacje

Bazy danych. Polecenia SQL

Odnawialne Źródła Energii I rok. Tutorial PostgreSQL

Smarty PHP. Leksykon kieszonkowy

Programowanie w Ruby

Dlaczego PHP? - zalety

Składowane procedury i funkcje

Bazy danych. Bazy danych. Podstawy języka SQL. Dr inż. Paweł Kasprowski.

ZAAWANSOWANE BAZY DANYCH I HURTOWNIE DANYCH MySQL, PHP

koledzy, Jan, Nowak, ul. Niecała 8/23, , Wrocław, , ,

Relacyjne bazy danych. Podstawy SQL

PRZESTRZENNE BAZY DANYCH WYKŁAD 2

Bazy Danych i Usługi Sieciowe

Wprowadzenie do JDBC z wykorzystaniem bazy H2

Leszek Stasiak Zastosowanie technologii LINQ w

Założenia do ćwiczeń: SQL Server UWM Express Edition: \SQLEXPRESS. Zapoznaj się ze sposobami użycia narzędzia T SQL z wiersza poleceń.

Uruchamianie bazy PostgreSQL

Podstawy języka SQL. SQL Structured Query Languagestrukturalny

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Programowanie w Sieci Internet Python - c. d. Kraków, 28 listopada 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

BAZY DANYCH. Obsługa bazy z poziomu języka PHP. opracowanie: Michał Lech

Sprzeg podstawowy do baz danych w PHP Mateusz Sowa, 2007

Bazy danych dla producenta mebli tapicerowanych. Bartosz Janiak Marcin Sikora Wrocław r.

Wykład 5. SQL praca z tabelami 2

NARZĘDZIA WIZUALIZACJI

Data modyfikacji:

QUERY język zapytań do tworzenia raportów w AS/400

15. Funkcje i procedury składowane PL/SQL

Integralność danych Wersje języka SQL Klauzula SELECT i JOIN

Dokumentacja SQL API 1

Administracja i programowanie pod Microsoft SQL Server 2000

Projektowanie baz danych za pomocą narzędzi CASE

Bazy danych i usługi sieciowe

Wprowadzenie do BD Operacje na bazie i tabelach Co poza zapytaniami? Algebra relacji. Bazy Danych i Systemy informacyjne Wykład 2.

Literatura: SQL Ćwiczenia praktyczne Autor: Marcin Lis Wydawnictwo: Helion. Autor: Joanna Karwowska

Ustalanie dostępu do plików - Windows XP Home/Professional

Język DML. Instrukcje DML w różnych implementacjach SQL są bardzo podobne. Podstawowymi instrukcjami DML są: SELECT INSERT UPDATE DELETE

Programowanie w Ruby

Trigger jest obiektem związanym z tablicą, który aktywuje się gdy do tablicy następuje odpowiednie zapytanie.

Oracle PL/SQL. Paweł Rajba.

1 Kursory 1. 2 Wyjątki Wyjątki predefiniowane Wyjątki niezdefiniowane wcześniej Definiowanie własnych wyjątków...

SSI Katalog. Program do katalogowania zawartości dysków. Dariusz Kalinowski

1.1. System otwartych baz danych ODBC. System otwartych baz danych ODBC. Interfejs ODBC. Interfejs ODBC. System otwartych baz danych ODBC

Transkrypt:

PROGRAMOWANIE Pear::DB Moduł PEAR::DB Próbowanie gruszek Programowanie w językach wysokiego poziomu, jakich jak PHP, daje gwarancję, że kod może być wykorzystany przez wiele osób. Dlaczego nie zastosować tej zasady do programowania baz danych? Czy można jakoś pomóc użytkownikom platform, które nie obsługują MySQL? STEVEN GOODWIN Używając wspólnego interfejsu programowania API można sprawić, aby program mógł pracować z różnymi bazami danych bez potrzeby modyfikacji kodu źródłowego. W tym miesiącu Steven Goodwin próbuje tego dokonać przy pomocy modułu PEAR::DB (ang. pear gruszka). Cudowny moduł PEAR::DB jest modułem PHP umożliwiającym kontrolę nad bazą danych, bez potrzeby określenia, której bazy konkretnie używamy. Znaczy to, że ten sam kod może być użyty do dostępu zarówno do MySQL, jak i Oracle. Jak to działa? Kluczem do powodzenia jest stworzenie warstwy abstrakcji uniwersalnego systemu lub interfejsu programowego, tak żeby szczegóły implementacji pozostały niewidoczne. Większość z nas posługuje się po- Co to jest Pear? PEAR to skrót od PHP Extension and Application Repository (wydaje się, że niektórzy zamieniają tu Application na Add-on), jest to biblioteka dla kodu PHP, podobnie jak CPAN dla PERL. Oprócz modułów dla baz danych (DB) istnieje też kod obsługujący HTML, a także autoryzacje i szyfrowanie. niać nie tylko nazwy funkcji, ale także strukturę i format argumentów. Musimy również dostosować kody błędów. Odpowiedzią na problem jest oddzielenie specyficznej funkcji database_connect od określonej bazy i użycie wspólnych wywołań API. Należy to zrobić dla każdej funkcji przyporządkowanej do określonej bazy danych. Oczywiście wymaga to mnóstwo pracy. Całe szczęście, że ktoś to zrobił za nas! W PHP mamy kilka interfejsów programowych (API) dla baz danych. W tym artykule skupimy się na PEAR::DB, jednym z wielu dobrych modułów PEAR dostępnych pod adresem [1]. Znajduje się on w fazie aktywnego rozwoju prowadzonego przez kilku najważniejszych programistów projektu PHP. Obecna wersja uznawana za stabilną to 1.6.0. Dla tych, którzy chcą porównać PERA::DB z konkurencją polecamy ADOdb [2], Metabajęciem abstrakcji, często nie zdając sobie z tego sprawy. Nawet programiści C zatwardziali przestępcy w świecie programowania, przez abstrakcję ułatwiają sobie życie. Każda funkcja, wyrażenie czy instrukcja, dzięki językowi C oddziela programistę od szczegółów sprzętowych procesora. Jest to jednak abstrakcja niskiego poziomu. Programowanie baz danych w języku SQL jest abstrakcją wysokiego poziomu. Baza typu MySQL, Postgre- SQL lub Oracle może pracować w dowolny sposób, według dowolnego algorytmu i używając dowolnych plików. Dzięki wykorzystaniu języka SQL nie musimy się martwić o szczegóły działania bazy, zamiast tego możemy poświęcić czas na ważniejsze zadania, jak tworzenie wydajnych zapytań typu inner join i select. Niestety, ten rodzaj abstrakcji nie przenosi się na sposób, w jaki programujemy bazę danych, ponieważ każda z nich ma jednak swóje własne API. W PHP możemy zainicjować dialog z bazą MySQL o nazwie fredbloggs przez użycie: $db = mysql_connect('localu host', myuser, mypass ); mysql_select_db('fredbloggs'); PostgreSQL wymaga abyśmy napisali: $db = pg_connect('host=localu host dbname=fredbloggs user=u myuser password=mypass'); Mimo że większość z tych parametrów jest opcjonalna, przenoszenie kodu pomiędzy bazami danych jest ciągle bolesne, każde polecenie connect, select i obsługa błędów muszą zostać przepisane na nowo, aby działały z inną bazą danych. Musimy zmie- 72 Maj 2004 www.linux-magazine.pl

Pear::DB PROGRAMOWANIE se [3] oraz PHPlib [4]. Wykorzystanie MySQL było zbawieniem, a jednocześnie przekleństwem dla programistów PHP. Pozytywną stroną jest to, że MySQL jest zintegrowany z obecną instalacją PHP, co oznacza, że każdy bez większych problemów może wykonać dobrą stronę internetową opartą na bazie danych. Niestety z tego powodu wielu programistów nie dostrzega, że istnieją również inne bazy danych posiadające równie dobre wsparcie, jak to widać w Tabeli 2 (bazy danych obsługiwane przez PHP). Dodatkowe informacje na temat obecnej sytuacji można znaleźć w pliku docs/status. Mając na uwadze powyższe rozważania, artykuł będzie podążał najprostszą drogą od MySQL do PEAR::DB. Przyjrzymy się też prostemu przykładowi bazy danych kanałów telewizyjnych na stronie wygenerowanej za pomocą PHP. Misja specjalna Korzystanie z PEAR::DB polega właściwie na aktualizacji oprogramowania, dlatego wcześniej musimy dysponować już istniejącą aplikacją. Aby spełnić tę role powrócimy do tematu artykułu sprzed miesiąca i naszego maila do bramki wideo [5]. Zamiast zapisywać kanały TV jawnie w pliku wsadowym, umiejscowimy odnoszące się wpisy (stacje, kanały i nazwy) w niedużej bazie danych. Na początek wprowadzimy zrzut kodu SQL do bazy danych w standardowy sposób, zezwalając na dostęp odpowiedniemu użytkownikowi (na przykład www-data). Do bazy dostajemy się używając MySQL, tak jak na Listingu 2. W tym raczej prostym fragmencie kodu (dla przejrzystości usunięto kontrolę błędów) mamy nie mniej niż 5 oddzielnych odwołań do MySQL. Zamiast odwoływania się do tabeli tv.channels, niektórzy pewnie woleliby, żeby określić aktualną bazę, używając mysql_select_db('tv'); Działa to w ten sam sposób, jak polecenie use z linii komend MySQL, z tym że dodaje jeszcze jedno wywołanie MySQL. Po zmianie serwera bazy danych każde odwołanie do mysql musi zostać przepisane. Przy większej ilości funkcji i obsłudze większej ilości baz danych ilość powtórzeń w kodzie wzrasta. Zazwyczaj jedynym powodem zmian jest przenoszenie hosta bazy danych, użytkownika i hasła do oddzielnego pliku, np. dbase.inc. $dbhost = 'localhost'; $dbuser = 'www-data'; $dbpass = ''; $dbname = 'tv'; Ale to jeszcze nie wystarczy. Potrzebujemy warstwy abstrakcji, takiej jak PEAR::DB. Większość instalacji zawiera domyślnie bibliotekę PEAR::DB, zwykle w /usr/share/pear. Aby potwierdzić, czy instalacja zawiera pełny system wpisujemy, <?php require_once 'DB.php';?> Jeżeli nie, możemy użyć do instalacji PEAR Packet Manager (używając polecenia pear install DB) lub ręcznie, używając archiwum tar. Dalsze szczegóły co do procesu instalacji PEAR można znaleźć w podręczniku on- -line, znajdującym się pod adresem [6]. Alternatywnie można skopiować pliki do katalogu domowego (say ~/pear/) i zmienić ścieżkę dostępu PHP include. Będzie to konieczne, jeżeli nie mamy uprawnień root-a na komputerze, np. <?php ini_set('include_path', U '~/pear/lib'.path_separator.iniu _get('include_path'));?> Teraz mamy dostęp do nowych funkcji obsługi baz danych, zgodnych z konwencją nazw PEAR. Jak zacząć pracę z PEAR? Oczywistym miejscem są funkcje podstawowe, jak connect i close. W porównaniu do poprzednich wersji MySQL i PostgreSQL, PEAR::DB wymaga jedynie nieznacznej zmiany. Ponieważ inne bazy danych mogą wymagać mniej lub więcej parametrów, prosta funkcja zamiany, która zmieni nazwy parametrów nie będzie działać. Zamiast tego musimy określić nazwę źródła danych data source name, czyli DSN. Zbierzemy tym samym wszystkie możliwe argumenty do pojedynczego sformatowanego łańcucha znaków. Listing 1: Przykładowa baza danych TV CREATE DATABASE IF NOT EXISTS tv; USE tv; drop table IF EXISTS channels; CREATE TABLE channels ( station smallint(2) NOT NULL default '0', channel smallint(2) default NULL, name varchar(10) default NULL, PRIMARY KEY (station) ) TYPE=MyISAM; INSERT INTO channel VALUES (1,55,'TVP 1'); INSERT INTO channel VALUES (2,62,'TVP 2'); INSERT INTO channel VALUES (3,59,'TVN'); INSERT INTO channel VALUES (4,65,'Polsat'); INSERT INTO channel VALUES (5,37,'TVP4'); Listing 2: Dostęp przez MySQL function GetStationsList() $db = mysql_connect("localhost", "www-data", ""); $query = "SELECT * FROM tv.channels"; $result = mysql_query($query); while ($row = mysql_fetch_array($result, MYSQL_NUM)) print "$row[0] - $row[2] ($row[1])<br>"; mysql_free_result($result); mysql_close($db); www.linux-magazine.pl Maj 2004 73

PROGRAMOWANIE Pear::DB Format tego łańcucha wygląda następująco: phptype(dbsyntax)://username:u password@protocol+hostspec/u databasename DSN wygląda jak adres internetowy, określa, gdzie się połączyć i w jaki sposób określona baza danych ma być użyta oraz jakich opcji użyć podczas łączenia. Pierwsza część opisuje, jakiej bazy użyto i zawiera opis rodzaju bazy (określanego jako phptype, np.: mysql) oraz wszystkie specyficzne dla określonej bazy wymagania, podane w dbsyntax. Lista phptype jest pokazana w Tabeli 2. Często podawany przykład łańcucha dbsyntax jest nazwą odpowiedniego sterownika podczas używania bazy ODBC (access, db2, mssql). Nie jest to trudne do ustalenia, ale dotyczy bardziej użytkowników Windows, nie musimy więc dalej się tym zajmować. Druga część DSN zawiera wszystko, co jest niezależne od bazy danych, jak nazwa hosta, port, nazwa użytkownika i hasło. Tak jak w zwykłej funkcji mysql_connect, nie wszystkie parametry są obowiązkowe, w razie potrzeby mogą zostać opuszczone. Na przykład: mysql://www-data@localhost/tv Naturalnie nasz finalny kod zapisze te parametry we wspólnym pliku dbase.inc, tak jak to poprzednio pokazaliśmy. DSN nie musi być wyspecyfikowany jako łańcuch znaków. Może być także podany jako tablica, jak to zostało wyszczególnione w ramce -- DSN jako tablica. To rozwiązanie jest nieco szybsze, bo do inicjalizacji nie ma potrzeby pobierania żadnego łańcucha. DSN pozwala też określić opcje inicjujące przy użyciu zbliżonej do adresu internetowego metody?option1=value1&option2=value2. Dostępnych jest kilka opcji, które opisują zarówno praktyczne cechy dotyczące połączenia (użycie SSL), jak i te pomocne w programowaniu (kontrola wiadomości o błędach). DSN jako tablica $dsn = array( 'phptype' => mysql, 'hostspec' => localhost, 'database' => tv, 'username' => www-data, 'password' => ); $db = DB::connect($dsn); Ponieważ opcje te mogą się różnić między określonymi kwerendami, nie będziemy ich włączać do DSN. Zamiast tego utworzymy tablicę, która je wyszczególnia i przekażemy je osobno do funkcji DB::connect. $dsn = $dbbackend://$dbuseru bhost/$dbname ; $options = array( debug => 2); $db =& DB::connect($dsn, U $options); Opcje te mogą być w każdej chwili zmienione przez użycie funkcji: $db->setoption('debug', 0); Połączenie powinno działać (obsługą błędów zajmiemy się później), będziemy odtąd mieć do dyspozycji obiekt bazodanowy o nazwie $db, który używany jest we wszystkich innych wywołaniach tej bazy np. do zamykania bazy po użytkowaniu. $db->disconnect(); Następnie musimy przystąpić do przystosowania istniejących funkcji do użycia nowego obiektu i stowarzyszonych funkcji. Nie jest to trudne, ponieważ mają one bardzo zbliżone nazwy do ich oryginalnych wersji w MySQL. Zatem, na przykład mysql_query stanie się query, a mysql_fetch_array będzie fetchrow. Nasza podstawowa funkcja jest pokazana na Listingu 3. Czarne pudełko Ponieważ wszystkie zapytania do bazy przechodzą przez sterownik PEAR::DB, kod wewnątrz sterownika ma możliwość zmiany, a także narobienia bałaganu z zapytaniem. To konkretna cena za przenośność i uniwersalność. Poziom dopuszczalnej ingerencji można ustawiać w opcjach dotyczących przenośności, dostępnych w metodzie setoption, którą już widzieliśmy. Te kompromisy pomiędzy przenośnością i wydajnością w wielkim stopniu zależą od konkretnej aplikacji. Opcje te mogą być też użyte do obsługi starszego kodu przez PE- AR::DB. Według konwencji większość nazw tablic jest opisana małymi literami. Na przykład, jeżeli aplikacja próbuje pobrać dane używając mieszanych, małych i dużych liter, nazwy zostaną automatycznie przekonwertowane na małe litery: $db->setoption('portability', U DB_PORTABILITY_LOWERCASE); Usuwa to element niespodzianki, który pojawia się, gdy nieznany kod zawiesza aplikację. Inne opcje dostępne tutaj są podane w Tabeli 1. Domyślnie wszystkie te opcje są włączone dla zwiększenia wydajności, jednak od nas zależy, które z nich będą włączone. Istnieją też definicje dla DB_PORTABILITY_ALL i DB_PORTABILITY_NONE, które przełączają flagi. Przemieszczanie się w tłumie Nie wszystkie funkcje idą w kierunku uczynienia łatwiejszym dostępu do bazy danych. Na przykład fetchrow ułatwia pobieranie danych w formacie przyjaznym raczej dla programisty. PEAR::DB obecnie wspiera trzy takie formaty. Domyślnie będzie to tablica sortowana od zera, jak pokazano w przykładzie powyżej. Opcjonalny para- Listing 3: Konwencja nazw w PEAR function PearVersion() global $dbname, $dbhost, $dbuser, $dbbackend; $dsn = $dbbackend://$dbuser@$dbhost/$dbname ; $db =& DB::connect($dsn); $query = 'SELECT * FROM channels'; $result = $db->query($query); while ($row = $result->fetchrow()) print $row[0] $row[2] ($row[1])<br> ; $result->free(); $db->disconnect(); 74 Maj 2004 www.linux-magazine.pl

Pear::DB PROGRAMOWANIE Opcja Tabela 1:Opcje zawiązane z przenośnością DB_PORTABILITY_LOWERCASE DB_PORTABILITY_RTRIM DB_PORTABILITY_DELETE_COUNT DB_PORTABILITY_NUMROWS DB_PORTABILITY_ERRORS DB_PORTABILITY_NULL_TO_EMPTY Opis metr w DB_FETCHMODE_ORDERED został w tym przykładzie pominięty. Jest to użyteczne do obsługi prostych baz danych lub wyświetlania tabel bez potrzeby znajomości nazw pól lub odniesień. W większości jednak sytuacji numeryczne indeksy nie są wystarczająco opisowe, możemy więc zażądać, aby rezultaty otrzymywać w skojarzonej tablicy. Kosztem uogólnień otrzymamy dużo łatwiejszy do analizy kod. while ($row = $result->fetchrowu (DB_FETCHMODE_ASSOC)) print $row['station'].' U '.$row['name'].' ('.$rowu ['channel'].')<br>'; W końcu fetchrow dostarcza sposobów na użycie zorientowanych obiektowo możliwości PHP do zwracania obiektu dla każdego wiersza tabeli wyników. Każda kolumna jest oznaczona jako własność obiektu. Tak jak poprzednio, sprawia to, że kod jest łatwiejszy do analizy, jednak możliwości zastosowania dla bardziej uniwersalnych aplikacji są ograniczone. while ($row = $result->fetchrowu (DB_FETCHMODE_OBJECT)) print $row->station.' U '.$row->name. ' ('.$row->u channel.')<br>'; Wykryć błąd Żaden program nie jest właściwie napisany, jeśli nie posiada obsługi błędów i dokumentacji. Rzeczy te nie fascynują programistów, ale są konieczne. Możliwości obsługi błędów w PEAR::DB zostały ujednolicone (choćby przez odpowiednie kody błędów) i wynikają z podstawowych możliwości obsługi błędów w PEAR_Error. W przypadku niepowodzenia jakiejś funkcji z PE- AR::DB, większość z nich zwróci konkretną Konwertuje nazwy pól i tabel na małe litery (przy get i fetch) Obcina wyjście od prawej Zawsze raportuje liczbę skasowanych rzędów Wspomaga numrows w Oracle Odwzorowuje wiadomości o błędach między różnymi bazami danych Konwertuje zera do pustych łańcuchów (przy get i fetch), ponieważ Oracle nie rozpoznaje między nimi różnicy klasę błędu od najwyższej connect do najniższej getrow. Klasa ta nie tylko przechowuje błąd z funkcji PEAR, ale też dodatkowe informacje przydatne w usuwaniu problemów. $db =& DB::connect($dsn); // DB::isError is the same as U PEAR::isError if (DB::isError($db)) print $db->getmessage(); print $db->getdebuginfo(); Błędy mogą być także wychwytywane przy użyciu standardowej procedury obsługi błędów w PEAR. Jest to definiowana przez użytkownika funkcja, która będzie wywołana zawsze, gdy moduł PEAR (jak db) wygeneruje błąd. Ta funkcja może być użyta do stworzenia kodu generującego dla użytkownika standardową stronę HTML, informującą administratora o problemie. Programy obsługi błędów są tradycyjnie połączone z możliwościami PHP, co do przekazywania wyników do buforowanego wyjścia, co umożliwia czyszczenie wynikowego kodu HTML. Jednak tradycyjne błędy (takie jak dzielenie przez zero) nie będą tu wyłapywane. // Przygotuj uchwyt PEAR::setErrorHandling(PEAR_ERRU OR_CALLBACK, 'error_function'); // włącz buforowanie wyników ob_start(); // uruchom kod PearVersion(); Name dbase FrontBase InterBase Informix Mini SQL Microsoft SQL Server MySQL MySQL >=4.1 Oracle 7/8/9 ODBC PostgreSQL SQLite Sybase Listing 4: tableinfo Tabela 2: Obsługiwane bazy danych Keyword dbase fbsql ibase ifx msql mssql mysql mysql4 oci8 odbc pgsql sqlite sybase // zrzuć zawartość bufora ob_end_flush(); // przygotuj uchwyt function error_function($err) ob_end_clean(); print 'Wystapil blad ('.$err->u getmessage().')!'); exit; Właściwości PEAR::DB PEAR::DB jest rzeczywiście tak łatwy, jak na to wygląda. Złożoność pochodzi od samego SQL. PEAR::DB chroni jedynie przed niektórymi problemami. SQL istnieje od wielu lat, jednak w ramach wojen pomiędzy poszczególnymi dostawcami zostały dodane różne rozszerzenia SQL, co sprawia, że poszczególne implementacje są ze sobą niekompatybilne. Mimo że komitet ANSI kierował standaryzacją części języka (podstawowe wersje select, insert i update są w pełni przenośne), istnieje nadal wiele problemów. Pisanie w standardowym SQL-u jest wyzwaniem samym w sobie i istnieje kilka reguł, które należy w tym celu poznać. Większość specjalizujących się w bazach danych programistów zna je doskonale, początkujący mogą sięgnąć do tutoriali, takich jak [7]. Często chcemy wiedzieć, jak baza zare- $tableinfo = $result->tableinfo()); for($col=0; $col < $result->numcols(); $col++) print $tableinfo[$col]['name']." is a ".$tableinfo[$col]['type']; www.linux-magazine.pl Maj 2004 75

PROGRAMOWANIE Pear::DB Tabela 3: Tabela 4: Zakres testowania Ograniczenia SQL przy pomocy provides Database SQL Syntax string Functionality DB2 select * from table fetch prepare Czy baza sprawdza wstępnie kolejkę SQL Informix first 10 rows only select first 10 * from table pconnect Persistentne połączenia Microsoft SQL Server select top 10 * from table transactions Czy baza wspiera transakcje MySQL select * from table limit 10 limitograniczone kolejki selectoracle 8i select * from (select * from table) where rownum <= 10 PostgreSQL select * from table limit 10 aguje na określone zapytanie, zanim je wykonamy. Wymaga to dodatkowej pracy, którą albo wykonamy sami albo poprzez PE- AR::DB. Niestety, jeżeli już dostaliśmy się do bazy, nie ma często sposobu, aby dowiedzieć się, czy potrafi ona obsługiwać określone polecenia SQL. Metoda provides pokazuje możliwości aktualnej bazy danych. Pozwala na przełączanie pomiędzy dwoma ręcznie dostrojonymi kwerendami, tak aby zwiększyć wydajność. Przecież nowa wersja bazy danych może oferować nową cechę, dlatego metoda provides użyta w PEAR::DB umożliwia budowanie bardziej optymalnych kwerend dla naszej bazy bez znajomości szczegółów o nowej bazie danych. if ($db->providesu ('transactions')) print 'Super! Ta funkcja jest U obsługiwana'; Zakres możliwości, które można przetestować, pokazano w Tabeli 3. W każdym z przypadków możliwe jest, że baza nie wspiera sama w sobie danej funkcji. Słowem kluczowym jest tutaj natively, ponieważ istnieje rozróżnienie pomiędzy wewnętrznym procesorem bazy a sterownikiem PEAR::DB. Na przykład, jeżeli baza danych nie posiada wsparcia dla poleceń prepare/execute, sterownik obsłuży pojawienie się tego polecenia poprzez emulację. Kuszące może być tu użycie provides do utworzenia zupełnie odmiennych, ręcznie optymalizowanych kolejek dla każdej bazy danych. W większości przypadków nie jest to konieczne. Powód (niektórzy powiedzą wymówka) dla tego rodzaju zwyczajów wynika z rozszerzeń, które są widoczne wewnątrz SQL. Typowy przykład tego problemu pochodzi z ograniczeń kolejek select, co prowadziło do zatrzymania generowania rezultatów po, powiedzmy, pierwszych dziesięciu rzędach. Obecnie wszystkie bazy danych potrafią wykonać to działanie, lecz za pomocą różnych kolejek (Tabela 4). Pisanie kodu dla każdego z przykładów to mnóstwo dodatkowej pracy. Ponieważ nie możemy się troszczyć o każdą bazę danych (razem z nowymi i tymi jeszcze nie napisanymi), nasz kod stanie się bardzo szybko nieprzenośny i narażony na obumieranie. Problem ten łatwo rozwiązać, jakkolwiek musimy tu zastosować te same zasady abstrakcyjności. PEAR::DB dostarcza metody nazywającej się limitquery, która ukrywa przed nami dokładną składnię i stosuje to, co jest kompatybilne z aktualną bazą danych. Jest to bardziej optymalne niż pisanie oddzielnych kolejek dla każdej bazy. $query = SELECT name FROM U channels ; // no reference to U limits here! $result = limitqueryu ($query, 2, 1); Polecenie to pobiera 1 wiersz z rezultatów wykonanej kwerendy, zaczynając od indeksu 2, ponieważ trzeci wpis liczy się od 0. Jeżeli zapytanie typu select może zostać zmodyfikowane, tak aby utworzyć odpowiedni łańcuch w pytaniu do bazy danych, $db->provides('limit') zwróci alter i kwerenda, zanim będzie przekazana dalej, zostanie przekształcona przez sterownik PE- AR::DB. W przeciwnym razie provides zwróciłoby emulate, ponieważ sterownik może wykonywać kwerendę na zasadzie wiersz za wierszem, albo mogłaby zostać zwrócona wartość false. Powinno się zawsze kolejkować zasoby bazy używając rezultatu z provides, a nie polegać na własnej pamięci czy doświadczeniu. Tabela 5 pokazuje aktualny zestaw sterowników. Z uwagi na błędy, czasem konieczna jest wiedza o tym, jakiej dokładnie używamy bazy. Jeżeli nie można usunąć błędów, musimy wiedzieć, gdzie się one znajdują, aby przynajmniej móc ich unikać. print $db->phptype; Polecenie powyżej pokaże nam te same identyfikatory, jak te w Tabeli 2. Szczegóły dotyczące błędów w bazach danych nie są celem niniejszego artykułu. Tylko dla was PEAR::DB nie tylko umożliwia budowanie warstwy abstrakcji dla kodu obsługi baz danych. Jako bonus otrzymujemy kilka narzędzi do obsługi samych danych, jak numrows i numcols. Listing 5: assertextension if (DB::assertExtension('oci8')) print 'Uzywamy Oracle jesli musimy...'; if (DB::assertExtension('mysql )) print Uzywam MySQL bo lepiej go znam... ; print Polecenie select zwrocilo U '.$result->numrows(). ' rows'; print 'Polecenie select zwrocilo U '.$result->numcols(). ' cols'; Efekty działania tych funkcji są samowyjaśniające i można to wydedukować z samego zapytania select. Oszczędzają ręcznego liczenia kolumn, gdy kwerenda jest generowana automatycznie. Mamy też metodę tableinfo, która dostarcza informacji, takich jak nazwa i typ dla każdej kolumny w rezultatach zapytania. Jest to użyteczne nie tylko przy wynajdywaniu błędów, ale także do tworzenia uniwersalnych aplikacji bazodanowych. Mamy możliwość zaznaczania kolorem różnych kolumn w zależności od ich rodzaju lub podświetlania pola klucza (Listing 4). Poza name i type można (używając składni użytej w przykładzie powyżej) wykonywać pytania o len (długość), flags (wskazuje na primary key) i table nazwę tabeli, dla każdej kolumny. Mimo że większość interfejsów programowych API wspiera zapytanie typu select, możemy też zostać obdarowani rezultatami kwerend typu insert. Jednym z przydatnych narzędzi jest metoda affectedrows, zwracająca liczbę wierszy, na które ma wpływ kwerenda typu 76 Maj 2004 www.linux-magazine.pl

Pear::DB PROGRAMOWANIE Tabela 5: Co umożliwia provides Database prepare pconnect transactions limit FrontBase false true true emulate InterBase true true true false Informix false true true emulate Mini SQL false true false emulate Microsoft SQL false true true emulate MySQL false true true alter Oracle 8i false true true alter ODBC true true false emulate PostgreSQL false true true alter Sybase false true false emulate insert, delete czy update. Mamy też możliwość generowania unikalnych ID, używając do tego funkcji sekwencyjnej nextid, która jest pomocna przy generowaniu unikalnych kluczy nie jest to obsługiwane przez MySQL. Na przykład: // Get a new ID. $id = $db->nextid('sequence'); U // (the sequence will be U created if it doesn't exist) Inną użyteczną właściwością jest statycznie deklarowana metoda assertextension nie wymaga obiektu bazy danych i będzie wskazywała, które z funkcji zostały zawarte w obecnej instalacji. Można określić, które bazy danych są zainstalowane w systemie i które z nich najbardziej pasują nam do użycia wewnątrz aplikacji (Listing 5). Pomimo swojej nazwy, nie jest to asercja w tradycyjnym programistycznym sensie, ponieważ żaden błąd nie jest tu wyraźnie zwracany. Metoda stwierdza jedynie, czy jakieś rozszerzenie istnieje lub nie. Wspomnijmy też o łączeniu pary prepare i execute. Jest to właściwość pozwalająca przygotować prepare kwerende do wielokrotnego użycia poprzez to, że elementy te są prekompilowane i rozkładane na tokeny. Kwerenda będzie się składać z miejsc zarezerwowanych dla innych informacji, dlatego może być wykonywana execute wiele razy z różnymi danymi wstawianymi w miejsca zarezerwowane (Listing 6). MetodaexecuteMultiple sprawdza zapytania SQL, INSERT INTO channels (station, U name, channel) VALUES (6, U 'Video', 0); INSERT INTO channels (station, U name, channel) VALUES (7, U 'PS2', 39); Listing 6: Przygotowanie zapytania $generic = $db->prepare('insert INTO channels (station, name, channel) VALUES (?,?,?)'); $data = array ( array(6, 'Video', 0), array(7, 'PS2', 39) ); $res = $db->executemultiple($generic, $data); Metoda executemultiple zatrzyma się na pierwszym błędzie, aby temu zapobiec będziemy musieli wykonywać każde kolejne zapytanie z pomocą metody execute. Na przykład, foreach ($data as $row) $db->execute($generic, $row); Ponadto tablica danych musi być indeksowana od zera. W większości przypadków powinniśmy zauważyć zwiększenie szybkości, gdy jednocześnie wprowadzanych będzie do bazy kilka wpisów. Korzyść jednak zależy od tego, czy baza danych posiada bezpośrednie wsparcie dla tej funkcji, niestety nie wszystkie posiadają. Idziemy na wojnę Posiadając w swoim arsenale PEAR::DB otrzymujemy możliwość atakowania większości baz danych, bez martwienia się o brakujące funkcje. Dzięki szerokiemu zakresowi metod możemy napisać w PHP dobrą, niezależną od platformy aplikację bazodanową, bez przejmowania się pomniejszymi problemami. INFO [1] PEAR: http://www.pear.php.net [2] ADOdb: http://php.weblogs.com/adodb [3] Metabase: http://freshmeat.net/projects/metabase/ [4] PHPlib: http://phplib.sourceforge.net/ [5] Linux Magazine, nr 41, kwiecień 2004, str. 72 [6] PEAR manual: http://www.pear.php.net/ manual/en/installation.cli.php [7] Writing Portable SQL Code: http://php.weblogs.com/portable_sql Prenumerata Linux Magazine Nie przegap takiej okazji Zamawiając prenumeratę oszczędzasz! Płacisz jak za 9 numerów, a otrzymujesz 12! Z każdym numerem DVD lub płyta CD-ROM. Najszybszy sposób zamówienia prenumeraty: http://www.linux-magazine.pl Infolinia: 0801-800-105