Studienarbeit Medien und Informationswesen Design, Entwurf und Implementierung einer KFZ-Sonderausstattungsabfrage als Webseite bearbeitet durch Mario Schmidt, MI8, Matrikelnummer: 163932 erstellt im Sommersemester 2005 an der Hochschule Offenburg betreut durch Prof. Dr. Volker Sänger Inhaltsverzeichnis Abbildungsverzeichnis 4 Listings 5 Tabellenverzeichnis 6 1. Allgemeines 1.1. Aufgabenbeschreibung . . . 1.2. Vorkenntnisse . . . . . . . 1.2.1. HTML, CSS & Co. 1.2.2. PHP . . . . . . . . 1.2.3. MySQL . . . . . . . 1.2.4. Apache . . . . . . . 1.2.5. Adobe Photoshop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 7 8 8 8 8 2. Planung 2.1. Datenbankplanung . . . . . . 2.2. Webseiten-Design . . . . . . 2.3. Entwicklungsumgebung . . . 2.3.1. Entwicklungswebserver 2.3.2. Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 9 12 13 13 14 . . . . . . . . . 16 16 17 18 22 22 23 24 27 29 3. Implementierung 3.1. MySQL Datenbankaufbau . . . . . . 3.1.1. Erstellung des Datenbestands 3.2. XHTML Seitenbeschreibung . . . . . 3.3. PHP Programmierung . . . . . . . . 3.3.1. Dateiordnung . . . . . . . . . 3.3.2. Datenbankklasse . . . . . . . 3.3.3. Datenverarbeitungsklasse . . 3.3.4. Mailklasse . . . . . . . . . . 3.3.5. Sonstige Programmierung . . Inhaltsverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 4. Ergebnis 4.1. Betatest . . . . . . 4.2. Das fertige Produkt 4.3. Schlußbetrachtung . 4.4. Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 35 36 36 37 A. Anhang 38 A.1. Inhalte der CD-ROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 A.2. Informationen zur benutzten Software . . . . . . . . . . . . . . . . . . . . . 38 Literaturverzeichnis Inhaltsverzeichnis 39 3 Abbildungsverzeichnis 2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7. erster Entwurf des ER-Schemas . . . . . . . zweiter Entwurf des ER-Schemas . . . . . . endgültiges ER-Schema . . . . . . . . . . . Datenbanktabellen . . . . . . . . . . . . . . unfertiges Designbeispiel 1 . . . . . . . . . . unfertiges Designbeispiel 2 . . . . . . . . . . Homesite HTML-Editor mit geöffneter Datei . . . . . . . 9 10 11 12 12 13 15 3.1. unterschiedliche Darstellung in vier gängigen Browsern . . . . . . . . . . . . 3.2. Darstellung ´mit und ohne CSS . . . . . . . . . . . . . . . . . . . . . . . . 21 22 Abbildungsverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Listings 2.1. Konfiguration von Virtual Hosts bei Apache . . 3.1. Anlegen einer neuen Datenbank . . . . . . . . 3.2. Anlegen der Tabelle Sonderausstattungen . . . 3.3. Anlegen der Tabelle Polsterung . . . . . . . . 3.4. Anlegen der Tabelle Lackierung . . . . . . . . 3.5. Dokumententyp einer XHTML-Datei . . . . . 3.6. Blockelemente einer XHTML-Datei . . . . . . 3.7. CascadingStyleSheet-Datei . . . . . . . . . . . 3.8. Erstellung eines Datenbankobjekts . . . . . . . 3.9. Verarbeitung der SQL-Ergebnisse . . . . . . . 3.10. falsche Eingaben prüfen . . . . . . . . . . . . 3.11. SQL-Code generieren . . . . . . . . . . . . . 3.12. HTML-Code für die Ausgabe generieren . . . . 3.13. Die Methoden der Klasse: sendmail . . . . . 3.14. allgemeine Logik zum Inkludieren von Dateien 3.15. Anlegen eines data_handler-Objekts . . . . . 3.16. Fehlerüberprüfung der Eingaben . . . . . . . . 3.17. Absenden der Datenbankanfrage . . . . . . . . 3.18. Ausgabe der Ergebnisse . . . . . . . . . . . . 3.19. Mail über das Kontaktformular verschicken . . Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 16 16 17 17 18 18 19 23 23 24 25 26 27 29 30 31 31 32 33 5 Tabellenverzeichnis 3.1. Darstellung und Benutzbarkeit in verschiedenen Browsern . . . . . . . . . . Tabellenverzeichnis 21 6 1. Allgemeines Als Einführung wird eine allgemeine Aufgabenbeschreibung und die dazugehörige Ausgangssituation beschrieben. Welche Kenntnisse bestehen schon, was soll mit der Arbeit vertieft beziehungsweise erlernt werden. 1.1. Aufgabenbeschreibung Ziel der Arbeit ist es, eine Sonderausstattungsabfrage für Mercedes-Benz Fahrzeuge der Baureihe W126 als Webseite zu erstellen. Diese soll datenbankbasierend sein. Viele Liebhaber dieser Baureihe möchten nach dem (Gebraucht-)Kauf gerne den damaligen Auslieferungszustand ihres Fahrzeuges wissen. Welche Sonderausstattungsmerkmale wurden zusätzlich zur Serienausstattung vom Erstbesitzer bestellt. Hier gibt es zwei Möglichkeiten. Man kann sich bei Mercedes die Datenkarte ausdrucken lassen oder man erwirbt eine so genannte EPC-CD1 bei Mercedes. Gibt man nach Installation der CD im Programm eine Fahrgestellnummer ein, bekommt man die Sonderausstattungscodes, mit denen der Wagen das Werk verlassen hat, zurück. Leider sind dies nur die reinen (dreistelligen) Zahlencodes, nicht mehr. Genau hier setzt diese Studienarbeit an. Die Liebhaber fragen meist in einschlägigen Foren im Internet nach, was diese Codes bedeuten. Wieder andere suchen per Hand die Aufschlüsselungen der Codes und antworten. Genau dieser Schritt soll automatisiert werden. Die Codes werden in ein Formular eingegeben und zurück kommt die Beschreibung. 1.2. Vorkenntnisse 1.2.1. HTML, CSS & Co. Sehr gute Grundkenntnisse in HTML 4.012 und CSS 23 , sowie fundierte Grundkenntnisse in JavaScript sind vorhanden. Die Webseite soll XHTML 1.04 konform mit dem Dokumenttyp Transitional erstellt werden. Dies stellt die erste Lernstufe dar. Parallel zur Entwicklung wird der offizielle W3C HTML-Validator[7] benutzt, um die Seiten auf Fehler zu überprüfen. Ebenso werden die CSS-Dateien mit dem offiziellen W3C CSS-Validator[6] überprüft. 1 „Electronic Parts Catalog-CD“ HyperText Markup Language 4.01 3 Cascading Style Sheets 2 4 eXtensible HyperText Markup Language 1.0 2 1. Allgemeines 7 1.2.2. PHP PHP5 -Grundkenntnisse sind vorhanden. Bisher beschränkte es sich allerdings darauf, vorhandene Skripte für die eigenen Bedürfnisse anzupassen. Die strukturierte Programmierung soll nun anhand dieser Arbeit erlernt werden. 1.2.3. MySQL Die Kenntnisse im Bereich relationale Datenbanken beschränken sich auf das Wissen aus der Vorlesung „Datenbanken“ und dem dazugehörigen „Labor: Datenbanken“. Mit dieser Arbeit soll der praktische Umgang mit der relationalen Datenbank MySQL erlernt werden. Sie bietet sich an, da PHP von Haus aus sehr viele Funktionen mit sich bringt, die speziell für die Arbeit mit MySQL geschaffen wurden. 1.2.4. Apache Im Umgang mit Webservern sind keine Kenntnisse vorhanden. Um angenehm entwickeln zu können soll ein Apache Webserver aufgesetzt und konfiguriert werden. Der Zielserver für die Veröffentlichung wird ebenfalls ein Apache Webserver sein. 1.2.5. Adobe Photoshop Sehr gute Adobe Photoshop Kenntnisse sind vorhanden. Mittels Photoshop wird das Layout und Design der Webseite erstellt, welches danach mit XHTML (vgl. Abschnitt 1.2.1) umgesetzt wird. 5 rekursives Akronym für „PHP: Hypertext Preprocessor“, ursprünglich „Personal Home Page Tools“ 1. Allgemeines 8 2. Planung In diesem Kapitel wird zuerst die Datenbankplanung dokumentiert. Danach wird gezeigt, wie das (Web-)Design entstand, um dann noch kurz auf die zur Implementierung genutzte Entwicklungsumgebung einzugehen. 2.1. Datenbankplanung Am Anfang eines jeden datenbankbasierenden Projekts steht die Planung der eigentlichen Datenbankstruktur. Von ihr hängt der weitere Verlauf der Implementierung, sowie die Komplexität direkt ab. Die Datenbankplanung ist somit einer der wichtigsten Schritte. Dazu wird als erstes ein ER-Schema1 erstellt, um die Verknüpfungen der einzelnen Entities untereinander überblicken zu können. Im ersten Entwurf werden eher zu viel, als zu wenig Informationen eingebracht. Man verringert so die Gefahr, wichtige Details auszulassen und diese zu übersehen. Das erste ER-Schema zu diesem Projekt sieht wie in Abbildung 2.1 aus. Abbildung 2.1.: erster Entwurf des ER-Schemas Von diesem ER-Schema ausgehend kann man nun im Ausschlußverfahren die unnötigen Bestandteile herauskürzen. Im ersten Entwurf ist im Prinzip fast jeder Bestandteil eines Autos 1 Entity-Relationship Schema 2. Planung 9 beinhaltet. Man hätte damit eine Datenbank zum Speichern von Autos, mit den dazugehörigen Sonderausstattungsmerkmalen, entwerfen können. Durch Diskussion und Blick auf den eigentlichen Sinn der Anwendung, wird das ER-Schema in Abbildung 2.2 entwickelt. Abbildung 2.2.: zweiter Entwurf des ER-Schemas Man erkennt, dass hier einiges verfeinert wurde. Bei der weiteren Diskussion des zweiten Entwurfs stellt sich heraus, dass zu viel Gewicht auf den Preis gelegt wird. Es wäre ein vielfach höherer Programmieraufwand geworden dieses Schema zu implementieren. Da das Hauptaugenmerk aber auf Sonderausstattungsmerkmalen liegt, muss hier also nochmals nachgebessert werden. Statt mit einzelnen Tabellen für den Preis zu rechnen, werden Felder für den Minimal- und den Maximalpreis eines Sonderausstattungsmerkmals eingeführt, sowie ein Zusatzinfofeld, in dem weiterführende Informationen zum Preis oder auch des ganzen Sonderausstattungsmerkmals gespeichert werden. So entsteht nochmals ein deutlich vereinfachtes ER-Schema welches in Abbildung 2.3 dargestellt wird. Aus diesem ER-Schema entstehen die Tabellen, die später in der Datenbank implementiert werden. Nachdem die Felder klar sind, müssen sinnvolle Spaltentypen gewählt werden. • code wird mit dem Spaltentyp SMALLINT UNSIGNED ZEROFILL definiert, da hier positive Zahlen größer als 255 gebraucht werden. Falls ein Code ohne führende Null eingegeben wird, so wird sie automatisch eingefügt, um wieder einen dreistelligen Code zu bekommen. 2. Planung 10 Abbildung 2.3.: endgültiges ER-Schema • beschreibung und zusatzinfo wird mit dem Spaltentyp TEXT definiert, da hier Texte variabler Länge gespeichert werden. • bild und farbe werden mit dem Spaltentyp VARCHAR() definiert, da hier nur kurze Zeichenfolgen gespeichert werden. Für bild sind maximal 200 Zeichen vorgesehen, da hier URLs2 zu den Bildern des jeweiligen Sonderausstattungsmerkmals gespeichert werden. Für farbe werden maximal 30 Zeichen vorgesehen, da hier kurze Farbnamen der Lackierungen und Polster gespeichert werden. • polsterart und lackart werden mit dem Spaltentyp SET(„“) definiert, da hier bestimmte Worte gespeichert werden. Für polsterart sind die Worte Stoff, MB-Tex, Amaretta, Leder und Velour vorgesehen. Für lackart sind die Worte Serien- und Sonderlackierungen und Metallic Lackierungen vorgesehen. • minPreis und maxPreis werden mit dem Spaltentyp MEDIUMINT UNSIGNED definiert, da hier Preise gespeichert werden. Es werden nur positive Werte benötigt. Eingegeben werden Pfennigbeträge3 , die vor der Ausgabe umgerechnet werden. Würde man FLOAT als Spaltentyp benutzen, bekäme man unter Umständen bei Rechenoperationen falsche Werte durch Rundungsfehler. 2 3 Uniform Resource Locator Zu Bauzeiten des W126 gab es noch die Deutsche Mark. Die Werte sollen hier absichtlich erhalten bleiben und werden somit nicht in Euro umgerecht. Besser wäre es später eine Euroumrechnungsfunktion zu schreiben, die auf die Originalpreise zugreift. 2. Planung 11 Diese Tabellen sind in Abbildung 2.4 schematisch dargestellt. Abbildung 2.4.: Datenbanktabellen 2.2. Webseiten-Design Das eigentliche Design wird im Programm Adobe Photoshop entworfen (vgl. Abschnitt 1.2.5). Das Design soll einfach, schlicht und vor allem benutzerfreundlich gehalten werden. Genauso soll es aber auch modern und frisch erscheinen. Es besteht anfangs die Frage, ob die Anwendung ein eigenes Browserfenster ausfüllen soll oder nicht. Da die Anwendung aber relativ klein ist, wird sie so aufgebaut, dass man sie einerseits normal im Browser aufrufen kann und andererseits auch in einem Popupfenster benutzen kann. Es werden mehrere Designs ausprobiert und sich am Ende für eines entschieden. Zwei anfängliche Designbeispiele zeigen die beiden Abbildungen 2.5 und 2.6. Abbildung 2.5.: unfertiges Designbeispiel 1 2. Planung 12 Abbildung 2.6.: unfertiges Designbeispiel 2 2.3. Entwicklungsumgebung Im Folgenden wird die Entwicklungsumgebung, in der diese Studienarbeit erstellt wird, näher betrachtet. Entwickelt wird auf einem Apple Rechner, der unter Mac OSX4 10.3.8 läuft. Da Mac OSX auf Unix basiert hat das den entscheidenden Vorteil, auf der selben Grundplattform entwickeln zu können, auf der das Programm später laufen soll. Desweiteren hat man so den Vorteil direkt „auf dem Server“ arbeiten zu können. Folglich muss man nicht nach jeder erfolgten Änderung in einem Skript, dieses einzeln auf den Server laden, um es zu testen. Einfaches Speichern und Neuladen reicht aus. 2.3.1. Entwicklungswebserver Mac OSX hat von Hause aus einen vorinstallierten Apache5 Webserver. Auf dem Entwicklungswebserver läuft Version 1.3.33, welche bis dato die aktuellste Version darstellt. Um die Entwicklung zu erleichtern, müssen als erstes PHP (Version 4.3.6) und MySQL (Version 4.1.11-standard) installiert werden. Auf der Homepage6 des Schweizers Marc Liyanage können sehr einfach zu installierende PHP Packages für Mac OSX gefunden werden. MySQL Packages können auf der offiziellen MySQL Homepage7 heruntergeladen werden. Aufgrund der sehr guten Anleitung auf Marc Liyanages Homepage[5] stellte auch diese Installation kein Problem dar. Nachdem PHP und MySQL installiert sind, soll sicher gestellt werden, dass es möglich ist, mehrere Webprojekte nebeneinander und störungsfrei auf dem Server zu entwickeln und zu testen. Es werden mehrere sogenannte virtuelle Hosts konfiguriert. Dazu musste die Konfigurationsdatei httpd.conf des Webservers angepasst werden. Ein Beispiel für das Hinzufügen 4 Betriebssystem der Firma Apple http://www.apache.org 6 http://www.entropy.ch 7 http://dev.mysql.com/downloads/mysql/4.1.html 5 2. Planung 13 eines virtuellen Host ist im Listing 2.1 zu sehen. Listing 2.1: Konfiguration von Virtual Hosts bei Apache 1 2 3 4 5 < VirtualHost 127.0.0.1 > ServerName dev1 . dd DocumentRoot / Library / WebServer / dev1 . dd ServerAdmin mario@skapunk . de </ VirtualHost > Zusätzlich müssen die angelegten virtuellen Hosts in der hosts-Datei des Rechners eingetragen werden und auf die IP 127.0.0.18 gesetzt werden. Ein Nameserver im Internet würde die Top-Level-Domain .dd nicht finden und einen Fehler ausgeben. Gibt man nun im Browser http://dev1.dd ein, wird man auf das entsprechende Verzeichnis geleitet und kann Dateien aufrufen, wie auf einem Webserver im Internet auch. Um später Änderungen direkt in der Datenbank vornehmen zu können, wird noch das Programm phpMyAdmin9 in der Version 2.6.2 installiert. Damit ist es möglich, Datenbanken über ein Webinterface direkt zu manipulieren. Es können auch, wie von der Konsole gewohnt, SQL-Befehle eingegeben werden. 2.3.2. Editor Als Editor für den HTML und PHP Code fällt die Entscheidung auf Homesite10 der Firma Marcomedia. Er besticht vor allen durch seine Schnelligkeit im Umgang mit allerlei Textdateien und bringt auch keine unnötige WYSIWYG11 Oberfläche mit sich. Da man den Code von Hand schreiben muss, kann die W3C Konformität (vgl. Abschnitt 1.2.1) deutlich leichter erreicht und kontrolliert werden. 8 Loopback Device oder localhost, gemeint ist der eigene Rechner http://www.phpmyadmin.net 10 http://www.macromedia.com/software/homesite/ 11 WhatYouSeeIsWhatYouGet 9 2. Planung 14 Abbildung 2.7.: Homesite HTML-Editor mit geöffneter Datei 2. Planung 15 3. Implementierung In diesem Kapitel wird die Vorgehensweise der Implementierung beschrieben. Hier werden Codebeispiele gezeigt, die die Umsetzung näher erläutern und damit das Projekt wesentlich dokumentieren. 3.1. MySQL Datenbankaufbau In Kapitel 2.1 wird die Planung der Datenbankstruktur erläutert. Die aus dem erarbeiteten ER-Schema entstandenen Tabellen werden nun in einer Datenbank angelegt. Dazu wird eine neue Datenbank erstellt. Sie heisst w126sa. Der Einfachkeit halber werden die Befehle mit phpMyAdmin durchgeführt. Listing 3.1: Anlegen einer neuen Datenbank 1 CREATE DATABASE ’ w126sa ’; Als nächstes werden die einzelnen Tabellen, wie sie im Abschnitt 2.1 beschrieben werden, angelegt. Den Tabellennamen wird ein Präfix „sa_“ vorrangestellt. Dies geschieht aus dem Grund, um später alle zur Anwendung gehörenden Tabellen leichter aufzufinden. Spätestens wenn die Möglichkeit besteht, dass in einer Datenbank mehrere Anwendungen Tabellen anlegen muss man sich darüber Gedanken machen, wie man diese später unterscheiden kann. Will man also zum Beispiel die Anwendung später entfernen, so müssen nur diejenigen Spalten gelöscht werden, die das Präfix enthalten. Daraus folgt, dass natürlich jede Anwendung auch ein eigenes und eindeutiges Präfix benutzt. Listing 3.2: Anlegen der Tabelle Sonderausstattungen 1 2 3 4 5 6 7 8 9 CREATE TABLE ’ s a _s o n d e r ausstattung ’( ’ code ’ SMALLINT (3) UNSIGNED ZEROFILL NOT NULL , ’ beschreibung ’ TEXT NOT NULL , ’ bild ’ VARCHAR (200) NOT NULL , ’ minPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ maxPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ zusatzinfo ’ TEXT NOT NULL , PRIMARY KEY ( ’ code ’) ); Die beiden Tabellen für Polsterung und Lackart werden analog dazu angelegt. Die SQLBefehle sind im Listing 3.3 und 3.4 zu sehen. Nach dem alle drei Tabellen angelegt sind, müssen als nächstes verwertbare Daten in die Spalten gefüllt werden. Anhand vorhandener Ori- 3. Implementierung 16 ginalpreislisten von Mercedes werden CSV-Dateien1 erstellt, die wiederum mit phpMyAdmin importiert werden. Listing 3.3: Anlegen der Tabelle Polsterung 1 2 3 4 5 6 7 8 9 10 CREATE TABLE ’ sa_polster ’( ’ code ’ SMALLINT (3) UNSIGNED ZEROFILL NOT NULL , ’ farbe ’ VARCHAR (30) NOT NULL , ’ polsterart ’ SET ( ’ Stoff ’ , ’MB - Tex ’ , ’ Amaretta ’ , ’ Leder ’ , ’ Velours ’) NOT NULL , ’ bild ’ VARCHAR (200) NOT NULL , ’ minPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ maxPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ zusatzinfo ’ TEXT NOT NULL , PRIMARY KEY ( ’ code ’) ); Listing 3.4: Anlegen der Tabelle Lackierung 1 2 3 4 5 6 7 8 9 10 CREATE TABLE ’ sa_lack ’( ’ code ’ SMALLINT (3) UNSIGNED ZEROFILL NOT NULL , ’ farbe ’ VARCHAR (30) NOT NULL , ’ lackart ’ SET ( ’ Serien - und Sonderlackierung ’ , ’ Metalliclackierung ’) NOT NULL , ’ bild ’ VARCHAR (200) NOT NULL , ’ minPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ maxPreis ’ MEDIUMINT UNSIGNED NOT NULL , ’ zusatzinfo ’ TEXT NOT NULL , PRIMARY KEY ( ’ code ’) ); 3.1.1. Erstellung des Datenbestands Ein großer Teil der Arbeit bestand auch darin, die angelegte Datenbank mit Daten zu füllen. Diese Daten sind überall verstreut im Internet zu finden. Eine relativ komplette Auflistung der damaligen Preislisten ist auf der Webseite von Ingo Licha2 zu finden. Die Listen wurden komplett in einer Tabelle zusammengefügt um danach Dubletten zu entfernen. Ebenso wurde somit der Minimal- und Maximalpreis der verschiedenen Ausstattungsmerkmale ermittelt. Die Bilder stammen zum großen Teil von Martin Makolskis Webseite3 . Hier sind ein paar schöne Auflistungen zum Thema Lacke und Polster zu finden. Die Originalprospektfotos 1 CSV steht für Character Separated Values. Es handelt sich um tabellarisch strukturierte Daten die durch ein spezielles Zeichen getrennt werden. Solche Dateien können in jedem beliebigen Texteditor erstellt werden. 2 Die Webseite von Ingo Licha ist zu finden unter http://www.meinbenz.de 3 Martin Makolskis Webseite findet man unter http://www.mercedes500.de 3. Implementierung 17 stammen wiederum von Ingo Lischas Seite. Die restlichen Bilder stammen entweder aus dem Internet oder aus dem eigenen Fotobestand, der bei verschiedenen Treffen entstand. 3.2. XHTML Seitenbeschreibung Jede korrekte XHTML-Datei muss über einen richtig definierten Dokumententyp definiert sein. Dies geschieht ganz am Anfang der jeweiligen XHTML-Datei. Listing 3.5: Dokumententyp einer XHTML-Datei 1 2 3 4 5 <! DOCTYPE html PUBLIC " -// W3C // DTD XHTML 1.0 Transitional // EN " " http :// www . w3 . org / TR / xhtml1 / DTD / xhtml1 - transitional . dtd " > < html xmlns = " http :// www . w3 . org /1999/ xhtml " > < head profile = " http :// gmpg . org / xfn /1 " > < title > W126 S o n d e r a u s st a t t u ng s a b fr a g e - Online SA - Codes abfragen </ title > < meta http - equiv = " Content - Type " content = " text / html ; charset = UTF -8 " / > Am Ende sieht man noch die Zeichencodierung, welche im diesem Fall als UTF-84 angegeben ist. Falls das Encoding nicht seitens des Servers erledigt wird, kann man so sicher gehen, dass Sonderzeichen auch in anderen Ländern richtig übertragen werden. Die Verwendung in einem Meta-Tag5 sichert die Abwärtskompatibilität in älteren Browsern, die mit XML6 Daten nicht richtig umgehen können. Danach wird die Grundstruktur des Designs in XHTML übertragen. Das Design besteht aus einem Headerbereich. Die Navigation befindet sich links darunter. Der Contentbereich füllt den Rest des Platzes auf. Wo früher bei solchen Designs mit Tabellen hantiert wurde, wird das gesamte Layout nun mittels CSS positioniert. In der XHTML-Datei werden nur noch die einzelnen Bereiche als sogenannte Blockelemente notiert. Soviel zu Theorie. In der Praxis sieht es so aus, dass leider die vielen verschiedenen Browser die CSS-Standards des W3C mehr oder weniger gut beherrschen. In der Umsetzung werden dann die Blockelemente wie in Listing 3.6 beschrieben. Man sieht, dass hier keinerlei Angabe zur Position oder Formatierung angegeben werden. Diese sind komplett in der CascadingStyleSheet-Datei enthalten, die in Listing 3.7 (mit Kürzungen) zu sehen ist. Listing 3.6: Blockelemente einer XHTML-Datei 1 2 3 4 5 < body > < div id = " header " > < div id = " headerimg " > < div id = " pagetitle " > <! -- Header - Bereich -- > 4 populäre Kodierung für Unicode-Zeichen Meta-Tags sind HTML-Elemente einer Webseite, welche Metadaten über diese Webseite enthalten. 6 XML ist die Abkürzung für Extensible Markup Language. 5 3. Implementierung 18 6 7 8 9 10 11 12 13 14 15 16 17 18 19 </ div > </ div > </ div > < div id = " wrapper " > < div id = " navigation " > <! -- Na vig ati ons ber eich -- > </ div > < div id = " contentwrapper " > < div id = " content " > <! -- Content - Bereich -- > </ div > </ div > </ div > </ body > Listing 3.7: CascadingStyleSheet-Datei 1 /* Allgemeine CSS */ 2 3 4 5 body { margin : 0; font - family : Arial , Helvetica , Verdana , sans - serif ; font - size : 12 px ; background - color : # fff ; text - align : left ; } 6 7 [...] 8 9 /* Layout */ 10 11 12 13 # header { padding : 0; margin : auto auto ; height : 75 px ; width : 100%; background : url ( " img / bg / header_bg . jpg " ) no - repeat top center ; position : fixed ; z - index : 3; } 14 15 [...] 16 17 18 19 # navigation { background : # FFFFFF ; width : 110 px ; min - height : 200 px ; top : 75 px ; margin : 0; padding : 5 px 0 px 5 px 5 px ; font - size : 10 px ; position : fixed ; } 20 21 22 23 # navigation ul { margin : 0 px ; padding : 0 px ; } 24 3. Implementierung 19 25 [...] 26 27 28 29 # contentwrapper { position : absolute ; top : 75 px ; right : auto ; width : 500 px ; } left : auto ; 30 31 32 33 # content { background : # fff ; padding : 5 px 5 px 5 px 5 px ; position : absolute ; right : 0 px ; width : 370 px ; } 34 35 [...] Als sehr guter Browser zur Entwicklung hat sich Mozilla Firefox7 herausgestellt. Er lässt sich mittels Plugins zusätzlich für die Webentwicklung anpassen. Da auf Grund der starken Stellung von Microsoft Windows, deren hauseigener Browser Internet Explorer oft benutzt wird, wird speziell auch dort auf eine korrekte Darstellung geachtet. Genau hier lag auch ein Hauptteil der Arbeit. Leider hat der Microsoft Internet Explorer eine sehr fehlerhafte Implementierung von CSS2, weshalb man immer wieder Code ändern und anpassen muss, damit ein Layout funktioniert. Man steckt erfahrungsgemäß in etwa die doppelte Zeit in die Entwicklung hinein um Workarounds für diese Bugs zu finden. Ein paar Beispiele, die bei der Entwicklung dieser Studienarbeit als Bugs im Internet Explorer aufgetreten sind. • Text der kleiner als 11 Pixel groß ist, kann nicht fett dargestellt werden. • Breiten- und Höhenangaben werden nicht mit Paddingangaben verrechnet, sondern addiert. Dadurch erschwert sich die Positionierung erheblich. • Gepunktete Linien (border-style: dotted;) werden falsch dargestellt, wie border-style: dashed;. • position: fixed; wird nicht unterstützt (Windows). • a:hover; wird vom Internet Explorer 5.2 (Macintosh) und 5.5 (Windows) nicht richtig interpretiert. Fährt man über einen Link erscheínt kein Handcursor. Benutzt man cursor: hand; funktioniert es wieder. Laut W3C gibt es aber in den CSS-Spezifikationen keine solche Option und die Dokumente validieren so nicht mehr. Um aber auf den meisten gängigen Browsern die Benutzbarkeit der Anwendung sicherzustellen, wird sie mit verschiedenen Browsern getestet und bewertet. Tabelle 3.1 gibt nähere Auskunft über die Darstellung in den verschiedenen Browsern. In Abbildung 3.1 sieht man die unterschiedliche Darstellung in vier gängigen Browsern. 7 Mozilla Firefox ist ein aus der Mozilla-Suite hervorgegangener Standalone-Browser. Download unter folgendem URL: http://www.mozilla-europe.org/de/products/firefox/ 3. Implementierung 20 Tabelle 3.1.: Darstellung und Benutzbarkeit in verschiedenen Browsern Gecko (Mozilla, Firefox, etc.) 1.0.4 Internet Explorer 6 Opera 8 Safari 1.2 Darstellung in % Benutzbarkeit in % 100 100 80 100 90 100 100 100 Abbildung 3.1.: unterschiedliche Darstellung in vier gängigen Browsern 3. Implementierung 21 Benutzer nicht CSS-fähiger Browser können dank der sauberen Trennung zwischen Layout und Inhalt dennoch die Seite nutzen. Benutzt jemand beispielsweise Lynx8 als Browser sieht er nur den reinen Text. Hier zeigt sich wie klar eine Seite strukturiert ist um sie auf solchen Browsern anzuzeigen. Tabellenlayouts oder Frames bereiten hier bei der Navigation im Textbrowser arge Probleme. In Abbildung 3.2 sieht man die unterschiedliche Darstellung mit und ohne CSS. Abbildung 3.2.: Darstellung ´mit und ohne CSS 3.3. PHP Programmierung In diesem Abschnitt werden die erstellten Klassen und sonstige Programmierlogik genauer erklärt. Es werden keine Quellcodes komplett gelistet, da diese auch auf der beiliegenden CD-ROM zu finden sind. Sollte es dem Verständnis dienen, werden natürlich kurze Auszüge aus den Quellcodes eingebunden. 3.3.1. Dateiordnung Komplette HTML-Seiten und CSS-Dateien werden alle im Root-Verzeichnis des Webservers gespeichert. Alle Dateien die inkludiert werden oder zur Anwendung gehören, wie z.B. Klassendateien, werden im Unterverzeichnis /inc gespeichert. Dort sind sie durch ein Präfix voneinander zu unterscheiden. „class.“ steht allen Klassendateien vor. Sie beinhalten fast aussschließlich PHP-Code. „inc.“ steht für normale Dateien, die durch andere Dateien inkludiert werden. Sie beinhalten meist Teilstücke einer HTML-Seite und PHP-Code. „tpl.“ steht vor allen Dateien, die als Template benutzt werden. Sie enthalten nur HTML-Code, der teilweise mit Platzhaltern versehen ist, damit später per Suchen und Ersetzen Inhalte eingefügt werden können. Die Bilder befinden sich im Unterordner img. Dort sind sie wiederum aufgeteilt in die Unterordner bg (für Hintergrundbilder der Seite im allgemeinen), lacke (für alle Bilder der verschiedenen Lacke), polster (für alle Bilder der verschiedenen Polster) und sa (für alle Bilder der verschiedenen Sonderausstattungen). 8 Lynx ist ein textbasierter Browser, der keine Grafiken anzeigt. Er wird meist auf Terminals benutzt und ist auf vielen Unixsystemen direkt verfügbar. 3. Implementierung 22 3.3.2. Datenbankklasse Die Datenbankklasse ist für alle Verbindungen und Abfragen mit der Datenbank zuständig. Als Variablen des entstehenden Objekts werden eine Objektreferenz, der Benutzername, das Passwort, die Serveradresse und der Datenbankname gesetzt. Die Konstruktormethode9 mysql füllt diese Variablen bei der Erstellung mit den entsprechenden Werten. So ist sichergestellt, dass die Zugangsdaten mit Instanzierung eines neuen Objekts vorhanden sind. Sie haben den selben Namen wie die Klasse. Listing 3.8: Erstellung eines Datenbankobjekts 1 /* Datenbankdaten */ 2 3 4 5 6 $user $pass $server $db = = = = " username " ; // Benutzername " password " ; // Passwort " localhost " ; // Datenbankserver " w126sa " ; // Datenbankname 7 8 include ( " class . mysql . php " ) ; // Datenbankklasse includen 9 10 $dbconnection = new mysql ( $user , $pass , $server , $db ) ; // Konstruktor wird direkt mit den Werten aufgerufen 11 12 $dbconnection - > dbconnect () ; // Verbindung wird hergestellt Die Methode dbconnect stellt die Verbindung zur Datenbank her und wählt dann eine Datenbank aus. Sie erwartet keine weiteren Argumente und bezieht ihre Informationen aus den Variablen des Objekts. Tritt ein Fehler auf, wird eine Fehlermeldung, die die MySQL Fehlerbeschreibung beinhaltet, ausgegeben. Ansonsten wird die Referenz der Datenbankverbindung in die Variable des Objekts gespeicherrt und true zurückgegeben. Die Methode dbquery stellt Anfragen an die Datenbank. Als Argumente erwartet sie SQL Code in einem String und die Referenz der Datenbankverbindung. Tritt ein Fehler bei der Anfrage auf, so wird dieser mitsamt der MySQL-Fehlerbeschreibung ausgegeben. Ist die Anfrage erfolgreich, wird ein mehrdimensionales Array gebildet. Es ist auf erster Ebene über einen Index ansprechbar. In zweiter Ebene werden die Ergebnisse der Anfrage als assoziatives Array gespeichert. Dieses Array wird am Ende zurückgegeben. Listing 3.9: Verarbeitung der SQL-Ergebnisse 1 2 3 4 5 9 $count = 0; // Zaehlervariable fuer Datenarray $data = array () ; // Datenarray while ( $row = mysql_fetch_assoc ( $results ) ) { // Zeilen auslesen $data [ $count ] = $row ; // jede Zeile in den ( assoz .) Array schreiben $count ++; Die Konstruktormethode wird mit der Erstellung eines neuen Objektes einer Klasse aufgerufen. Sie wird also mindestens einmal innerhalb der Lebensdauer eines Objekts ausgeführt. 3. Implementierung 23 6 7 8 } mysql_free_result ( $results ) ; // Ergebnisse freigeben return $data ; // assoz . Array zurueckgeben 3.3.3. Datenverarbeitungsklasse Die Klasse data_handler ist für alle Manipulationen an den Daten zuständig, die über die SQL-Anfrage zurückgegeben werden. In ihr werden als Variablen, die vom Benutzer gesendeten Eingaben für Sonderausstattungscodes, Lackcode und Polstercode, sowie die Information ob eine ausführliche Ausgabe gewünscht ist, gespeichert. Dies geschieht, wie auch schon bei der Klasse mysql, mit Instanzierung eines neuen Objekts und des automatischen Aufrufs der Konstruktormethode data_handler. Die Methode codeCheck erwartet einen String als Argument, welcher die vom Benutzer eingegebenen Codes beinhaltet. Diese werden auf Richtigkeit überprüft. Eingegeben werden dürfen nur dreistellige Zahlenkombinationen. Die Eingaben werden um überflüssige Leerzeichen erleichtert und am Separator getrennt. Anschließend wird über einen regulären Ausdruck die Richtigkeit der einzelnen Codes geprüft. Falls zudem mehr als ein Sonderausstattungscode eingegeben wird, werden diese aufsteigend sortiert, bevor das Array mit den einzelnen Codes zurückgegeben wird. Listing 3.10: falsche Eingaben prüfen 1 2 $data = trim ( $this - > $string ) ; // ueberfluessige Leerzeichen am Anfang und Ende entfernen $sa_array = explode ( " " , $data ) ; // Eingabestring an Leerzeichen trennen 3 4 5 6 7 8 9 for ( $i =0; $i < count ( $sa_array ) ; $i ++) { if (! preg_match ( " /^\ d {3} $ / " , $sa_array [ $i ]) && ( $sa_array [0] != " " ) ) { // Test auf 3 - stellige Zahlen oder ob Array leer ist return FALSE ; // falls fehlerhafte Zahl gefunden -> Abbruch break ; } } 10 11 12 13 14 if ( count ( $sa_array ) > 1) { // Falls mehr als ein SA - Code im Array sort ( $sa_array ) ; // Array sortieren } return $sa_array ; Die Methode generateSql generiert den benötigten SQL-Code für die Methode dbquery und erwartet drei Argumente. Das Array aus der Methode codeCheck, die Spalten die ausgewählt werden und die Angabe, aus welcher Tabelle diese Spalten gelesen werden. Der 3. Implementierung 24 vorhandene Teil des SQL-Codes wird Schritt für Schritt komplettiert. Zuerst werden die übergebenen Spalten angehängt. Danach wird geprüft ob eine ausführliche Abfrage gewünscht ist und bei Bedarf weitere Spalten angehängt. Diese Spalten sind bei jeder ausführlichen Info gleich und müssen daher nicht übergeben werden. Als nächstes wird die auszuwählende Tabelle angefügt. Jetzt werden die Elemente aus dem Array eingefügt. Es kann vorkommen, dass das übergebene Array leer ist, weshalb dies auch nochmals geprüft wird. In der anschließenden for-Schleife werden die Elemente der Reihe nach angehängt. Danach wird der SQL-Code als String zurückgegeben. Listing 3.11: SQL-Code generieren 1 2 3 4 5 6 $sql = " SELECT code " . $select ; // SQL beginnen und $select anhaengen $full = " , bild , minPreis , maxPreis , zusatzinfo " ; // string fuer vollinfo bei allen Tabellen // SQL Full oder Light - Unterscheidung ( $this - > vollinfo == " on " ) ? $sql .= $full : $sql .= " " ; // bei Vollinfo string anhaengen sonst nichts ("") $sql .= " FROM " . $from . " WHERE " ; // SQL from mit Tabellenname $from und where Bedingung beginnen $anzahl = count ( $array ) ; // Anzahl der Codes im Array zaehlen 7 8 9 10 11 if (! isset ( $array [0][0]) ) { // echo (" Array ist leer ! < br / >") ; // debug return false ; } 12 13 14 15 16 17 18 19 20 /* Array durchlaufen , mit normaler for - Schleife da Unterscheidung noetig , ob eines oder mehrere vorhanden */ for ( $i = 1; $i <= $anzahl ; $i ++) { if ( $i > 1) { // falls mehr als ein Element ( SA Code ) vorhanden $sql .= " OR " ; // $sql um " _OR " erweitern } $sql .= " code = " . $array [ $i -1]; // Bedingung an $sql anfuegen } return $sql ; In der Methode generateTable wird der Ausgabecode generiert. Es handelt sich hierbei um eine Tabelle, die aus verschiedenen Templatedateien10 erstellt wird. Die Methode erwartet zwei Parameter. Zuerst einen Array mit den Ergebnissen aus der Datenbankabfrage und danach einen Teil des Names des gewünschten Templates. Der komplette Dateiname wird als erstes in der Methode generiert. Auch hier erfolgt wieder eine Unterscheidung zwischen 10 Templatedateien sind Dateien die immer wieder verwendet werden können und nach außen hin gleich aussehen, sich jedoch im Inhalt unterscheiden. Deshalb stehen dort oft Platzhalter für die Inhalte, die dann vor der Ausgabe ausgetauscht werden. 3. Implementierung 25 kurzer und ausführlicher Ausgabe der Ergebnisse, da hierfür das entsprechende Template geladen werden muss. Nachdem das Template in eine Variable eingelesen wird, werden die Inhalte für die kurze Ausgabe durch Suchen und Ersetzen der Platzhalter eingefügt. Es folgt eine Abfrage nach ausführlicher Ausgabe. Falls diese zutrifft, werden auch die restlichen Werte ersetzt. Am Ende wird die fehlende Ummantelung der Tabelle hinzugefügt und die komplette Tabelle zurückgegeben. Listing 3.12: HTML-Code für die Ausgabe generieren 1 2 3 4 $html = " " ; // Variable fuer den HTML Code // Dateifile zum includen zusammenstricken ( Unterscheidung : Vollinfo / Kurzinfo ) $filename = " inc / tpl . $tpl " ; ( $this - > vollinfo == " on " ) ? $filename .= " _full . php " : $filename .= " . php " ; 5 6 $rowtemplate = file_get_contents ( $filename ) ; // Template in Variable einlesen 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 foreach ( $array as $sa ) { if ( $tpl == " sa_codes " ) { // SA - spezifische Inhalte einfuegen $row = str_replace ( " % code % " , $sa [ ’ code ’] , $rowtemplate ) ; $row = str_replace ( " % beschreibung % " , htmlentities ( $sa [ ’ beschreibung ’ ]) , $row ) ; } if ( $tpl == " lack " ) { // Lack - spezifische Inhalte einfuegen $row = str_replace ( " % code % " , $sa [ ’ code ’] , $rowtemplate ) ; $row = str_replace ( " % farbe % " , htmlentities ( $sa [ ’ farbe ’ ]) , $row ) ; $row = str_replace ( " % lackart % " , htmlentities ( $sa [ ’ lackart ’ ]) , $row ) ; } if ( $tpl == " polster " ) { // Polster - spezifische Inhalte einfuegen $row = str_replace ( " % code % " , $sa [ ’ code ’] , $rowtemplate ) ; $row = str_replace ( " % farbe % " , htmlentities ( $sa [ ’ farbe ’ ]) , $row ) ; $row = str_replace ( " % polsterart % " , htmlentities ( $sa [ ’ polsterart ’ ]) , $row ) ; } if ( $this - > vollinfo == " on " ) { // falls Vollinfo gewuenscht ist weitere Inhalte einfuegen $imgsize = getimagesize ( " . $sa [ bild ] " ) ; // Bildgroesse auslesen $row = str_replace ( " % bildgroesse % " , $imgsize [3] , $row ) ; // Bildgroesse einfuegen $row = str_replace ( " % bild % " , $sa [ ’ bild ’] , $row ) ; // 3. Implementierung 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Bildpfad einfuegen $row = str_replace ( " % minpreis % " , number_format (( $sa [ ’ minPreis ’ ]/100) , 2 , ’ , ’ , ’. ’) , $row ) ; // Minimalpreis einfuegen $row = str_replace ( " % maxpreis % " , number_format (( $sa [ ’ maxPreis ’ ]/100) , 2 , ’ , ’ , ’. ’) , $row ) ; // Maximalpreis einfuegen if ( $sa [ ’ zusatzinfo ’] == " " ) { // Falls ZusatzinfoString leer ist $row = str_replace ( " % zusatzinfo % " , " -" , $row ) ; // " -" einfuegen } else { $row = str_replace ( " % zusatzinfo % " , htmlentities ( $sa [ ’ zusatzinfo ’ ]) , $row ) ; // Zusatzinfo einfuegen } } $html .= $row ; } // fertige Tabelle generieren $table = ’ < table width ="100%" border ="0" > ’; $table .= $html . " </ table > " ; return $table ; 3.3.4. Mailklasse Die Klasse sendmail ist für das Kontaktformular geschrieben und hat mit der eigentlichen Aufgabenstellung nichts zu tun. Der Vollständigkeit halber sei sie aber hier auch aufgeführt und erläutert. Mit der Erstellung eines neuen sendmail-Objekts werden die vom Benutzer eingegebenen Daten in den Variablen des Objekts gespeichert und die Mail grundlegend vorbereitet. Dabei wird aus dem Konstruktor die Methode toggleRecipient aufgerufen. Der Empfänger der Mail wird aus einem Zahlenwert ermittelt. Der Zahlenwert kann wie im vorliegenden Fall aus einer Auswahlliste abgesendet werden oder ganz normal, als z.B. ein Wert aus einem versteckten Eingabefeld. Hier wird wert auf Flexibilität gelegt. In der Funktion wird die Betreffzeile der Mail über den Zahlenwert im Originalobjekt gesetzt. Danach wird die richtige Empfängeradresse anhand des Zahlenwerts zurückgesendet. Zurück in der Methode sendmail werden zusätzliche Kopfzeilen der eMail generiert. Die Methode checkAdress überprüft die eigegebene eMail-Adresse auf Gültigkeit. Mittels eines regulären Ausdrucks wird geprüft, ob eine eMail-Adresse zumindest syntaktisch korrekt eingegeben wurde. Ist die Adresse korrekt, so kann die eMail anschliessend mit der Methode sendNow verschickt werden. Listing 3.13: Die Methoden der Klasse: sendmail 1 2 function sendmail ( $from , $name , $subject , $message ) { $this - > from = $from ; // Absenderemailadresse speichern 3. Implementierung 27 $this - > message = $message ; // Nachricht speichern $this - > to = $this - > toggleRecipient ( $subject ) ; // Empfaenger und Betreff einfuegen // Extra H e ad e ri nf o rm ationen generieren $this - > xtra = " From : $this - > from ( $this - > name ) \ r \ n " ; $this - > xtra .= " Content - Type : text / plain \ r \ n " ; $this - > xtra .= " Content - Transfer - Encoding : 8 bit \ r \ n " ; $this - > xtra .= "X - Mailer : PHP " . phpversion () ; 3 4 5 6 7 8 9 10 } 11 12 13 14 15 16 17 18 19 20 21 function toggleRecipient ( $subjectnumber ) { // Em pfa eng era dre sse n und Betreffzeilen definieren $mailadressen = array ( ’ mario@skapunk . de ’ , ’ mario@skapunk . de ’ , ’ mario@skapunk . de ’ , ’ mario@skapunk . de ’) ; $betreffzeilen = array ( ’ Allgemein Anfrage ’ , ’ Hilfe zur Webseite benötigt ’ , ’ V erbe sse rung svo rsch lag ’ , ’ Fehlende Codes gefunden ’) ; $this - > subject = $betreffzeilen [ $subjectnumber ]; // Betreffzeile speichern return $mailadressen [ $subjectnumber ]; // Empfaengeradresse zurueckgeben } 22 23 24 25 26 27 28 29 30 function checkAdress ( $mailadress ) { // Em pfa eng era dre sse n und Betreffzeilen definieren $checkemail = eregi ( " ^ " . // Beginn der Zeichenkette " [a - z0 -9]+([ _ \. -][ a - z0 -9]+) * " . // user : ein oder mehr Zeichen + Zahlen , Unterstrich Punkt oder Minus zusaetzlich so oft wie sie vorkommen erlaubt ( auch kein mal ) " @ " . // @ Zeichen " ([ a - z0 -9]+([\. -][ a - z0 -9]+) *) + " . // Domain : faengt mit Buchstaben oder Zahl an . Dann kann selbiges plus zusaetzlich Punkt und Minus kommen . " \.([ a - z ]{2}| aero | arpa | biz | com | coop | edu | gov | info | int | mil | museum | name | nato | net | org | pro ) " . // sld , tld " $ " , $_POST [ ’ email ’ ]) ; // $ == Ende der Zeichenkette 31 32 33 34 35 36 if (! $checkemail ) { return FALSE ; // eMailadresse nicht korrekt exit ; } return TRUE ; // eMailadresse korrekt 3. Implementierung 28 37 } 38 39 40 41 42 43 44 45 46 function sendNow () { // fertige Mail verschicken if (! mail ( $this - > to , $this - > subject , $this - > message , $this - > xtra ) ) { return FALSE ; exit ; } return TRUE ; } 3.3.5. Sonstige Programmierung In diesem Abschnitt wird näher auf die Programmlogik ausserhalb der Klassen eingegangen. Es wird kurz erklärt, wie die Klassen benutzt werden, um die Anwendung lauffähig zu machen. Allgemeine Logik zur Inkludierung von Dateien Es werden verschiedene Dateien nur in bestimmten Fällen gebraucht. Die Datenbankklassen beispielsweise werden nur auf den Seiten eingebunden, auf denen auch wirklich ein Datenbankzugriff erforderlich ist. Am Beispiel der Datei index.php (also die Datei, die als erstes beim Aufrufen der Webseite angezeigt wird) lässt sich das deutlich zeigen. Im Contentbereich findet sich eine switch-Anweisung, die den entsprechenden Fall abfragt. Es wird geprüft ob die Variable action existiert und ob sie einen bestimmten Wert enthält. Trifft das zu, so heisst das gleichzeitig, dass eine Anfrage über das Formular abgesendet wurde und es werden die benötigten Klassen inkludiert. Danach wird noch die Datei inc.abfrage.php eingebunden, welche die Suchergebnisse im Contentbereich platziert. Wurde noch kein Formular abgeschickt, z.B. wenn die Seite das erste Mal aufgerufen wird, so tritt der default-Fall ein. Hier wird die Datei inc.form.php inkludiert welche im Contentbereich das Formular einblendet. Listing 3.14: allgemeine Logik zum Inkludieren von Dateien 1 2 3 4 5 6 7 8 9 10 11 < div id = " content " > <? php switch ( TRUE ) { case ( isset ( $_POST [ ’ action ’ ]) && $_POST [ ’ action ’] == ’ anfrage ’) ; // Abfrage gestartet include ( " inc / inc . dbdata . php " ) ; include ( " inc / class . data_handler . php " ) ; include ( " inc / inc . abfrage . php " ) ; break ; default ; // Abfrageformular anzeigen include ( " inc / inc . form . php " ) ; } 3. Implementierung 29 12 13 ?> </ div > Ausgabe der Suchergebnisse Wie im oberen Abschnitt erwähnt, ist die Datei inc.abfrage.php für die Ausgabe der Suchergebnisse zuständig. Diese Datei wird nach Absenden des Formulars aufgerufen und hat somit die Eigaben des Benutzers in den Umgebungsvariablen zur Verfügung. Diese werden nun der Reihe nach behandelt. Da die Fehlerbehandlung der Übersicht wegen auch in dieser Datei abläuft (und zwar bevor die Abfragen an die Datenbank gesendet werden), wird zu Beginn eine Fehlervariable definiert und auf den Wert 0 (entspricht FALSE) gesetzt. Ebenso werden zwei Variablen mit Textinhalten gefüllt, die ausgegeben werden, wenn gar kein Ergebnis oder nur ein Teilergebnis gefunden wird. Bevor jetzt ein neues data_handler-Objekt angelegt wird, muss noch das Feld zur ausführlichen Ausgabe überprüft werden. Wird es im Formular nicht angewählt, so steht auch keine Information darüber in den Umgebungsvariablen. Wird es angewählt, so steht der Feldname (vollinfo) als auch der Status (on) zur Verfügung. Listing 3.15: Anlegen eines data_handler-Objekts 1 2 3 4 error = 0; // Fehlervariable auf FALSE setzen // Templatedateien in String einlesen $keinErgebnis = file_get_contents ( " inc / tpl . kein_ergebnis . php " ) ; $teilergebnis = file_g et_contents ( " inc / tpl . teilergebnis . php " ) ; 5 6 7 8 9 10 11 // leeres Feld ’ vollinfo ’ abfangen if ( isset ( $_POST [ ’ vollinfo ’ ]) && $_POST [ ’ vollinfo ’ ]== " on " ) { // pruefen auf Existenz der Variable und Inhalt $vollinfo = $_POST [ ’ vollinfo ’ ]; } else { $vollinfo = " off " ; } 12 13 $anfrage = new data_handler ( $_POST [ ’ sacodes ’] , $_POST [ ’ lackcode ’] , $_POST [ ’ polstercode ’] , $vollinfo ) ; // neues Objekt fuer SA - Codes Jetzt werden die Eingaben durch die Methode codeCheck, welche im Abschnitt 3.3.3 erklärt wird, auf Fehler überprüft. Das Ergebnis dieser Überprüfung wird in eine Variable des Objekts geschrieben, welche gleich danach auf Richtigkeit überprüft wird. Tritt ein Fehler auf, wird direkt eine Nachricht ausgegeben und die Fehlervariable auf 1 (also TRUE) gesetzt. Sind Sa-Code-, Lack- und Polstereingaben überprüft, wird die Fehlervariable abgefragt. Ist diese im Verlauf der Verarbeitung auf 1 gesetzt worden, so wird das Skript abgebrochen. Anmerkung: Leere Eingaben sind ausdrücklich erlaubt, da es sein kann, dass ein Benutzer z.B. nur einen Lackcode abfragen möchte, wobei die restlichen Felder leer bleiben. Aus diesem 3. Implementierung 30 Grund wird am Anfang ein Hinweis für eine Teilausgabe vorbereitet, der durchaus gewollt sein kann. Listing 3.16: Fehlerüberprüfung der Eingaben 1 // Empfangene Daten auf fehlerhafte Eingaben ueberpruefen 2 3 4 $anfrage - > sa_codes = $anfrage - > codeCheck ( ’ sa_codes ’) ; // SA - Codes checken // echo (" Inhalt sacodes : $sacodes < br / >") ; 5 6 7 8 9 if (! $anfrage - > sa_codes ) { // im Fehlerfall Meldung ausgeben und $error auf 1 setzen damit das Skript abgebrochen wird echo ( " < h2 class =\ " error \ " > Achtung </ h2 > <p > < strong > SA - Codes fehlerhaft . </ strong > Bitte & uuml ; berpr & uuml ; fen Sie Ihre Eingaben ! </p > " ) ; $error = 1; } 10 11 [...] 12 13 14 15 16 if ( $error ) { echo ( " < br / > < br / > < h2 > Hinweis </ h2 > <p > Bitte gehen Sie zur & uuml ; ck und korrigieren Sie Ihre Eingaben ! </p > " ) ; return false ; } Als nächstes wird der benötigte SQL-Code generiert und die Anfrage an die Datenbank gesendet. Falls keine Eingaben gemacht wurden, so wird auch keine Anfrage gesendet. Das Absenden einer leeren Anfrage wäre unnötig. Listing 3.17: Absenden der Datenbankanfrage 1 2 3 4 5 6 / $sql = $anfrage - > generateSql ( $anfrage - > sa_codes , ’ , beschreibung ’ , ’ s a _s onderausstattung ’) ; if (! $sql == " " ) { // falls kein SQL Code generiert wurde weil keine Eingabe erfolgte keinen Query absenden $sa_codes = $dbconnection - > dbquery ( $sql , $dbconnection - > conn ) ; } // weitere folgen ... [...] Es fehlt nun noch die endgültige Ausgabe der Suchergebnisse. Erneut wird über eine switch-Anweisung zwischen den einzelnen Fällen unterschieden. Erstens könnte kein Ergebnis gefunden werden, so sind die Variablen leer und es wird eine dementsprechende Fehlermeldung ausgegeben. Zweitens könnte nur ein Teilergebnis dargestellt werden. Hier wird geprüft, in welchen Fällen ein Ergebnis vorliegt und diese werden dann über die Methode generateTable der Klasse data_handler ausgegeben. Zudem wird der Hinweis auf das 3. Implementierung 31 Teilergebnis ausgegeben. Und der dritte Fall, falls für alle Eingaben ein Ergebnis gefunden wird, werden diese der Reihe nach ausgegeben. Listing 3.18: Ausgabe der Ergebnisse 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 switch ( TRUE ) { case ( empty ( $sa_codes ) && empty ( $lack ) && empty ( $polster ) ) ; // alle Variablen sind leer print $keinErgebnis ; break ; case ( empty ( $sa_codes ) || empty ( $lack ) || empty ( $polster ) ) ; // einige Variablen waren leer // die Gefundenen werden ausgegeben if (! empty ( $lack ) ) { echo ( " < br / > < h2 > Lackierung </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $lack , ’ lack ’) ; } if (! empty ( $polster ) ) { echo ( " < br / > < h2 > Polsterung </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $polster , ’ polster ’) ; } if (! empty ( $sa_codes ) ) { echo ( " < br / > < h2 > Sonderausstattungen </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $sa_codes , ’ sa_codes ’) ; } print $teilergebnis ; break ; default ; // zu allen Variablen ein Ergebnis gefunden echo ( " < br / > < h2 > Lackierung </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $lack , ’ lack ’) ; echo ( " < br / > < h2 > Polsterung </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $polster , ’ polster ’) ; echo ( " < br / > < h2 > Sonderausstattungen </ h2 > < br / > " ) ; print $anfrage - > generateTable ( $sa_codes , ’ sa_codes ’) ; } Absenden des Kontaktformulars Wie schon bei der Datei index.php wird hier über eine switch-Anweisung überprüft, ob das Formular abgesendet wurde oder nicht. Ist dies nicht der Fall, wird das Formular inkludiert und angezeigt. Ist das Formular abgesendet worden, wird zuerst geprüft, ob alle Felder des Formulars ausgefüllt sind oder nicht, bevor dann, falls dies zutrifft, die Klasse class.sendmail.php inkludiert wird. Danach wird ein neues Objekt angelegt und mit den Werten aus den Umgebungsvariablen gefüllt. Es muss noch geprüft werden, ob die eingegebene eMail-Adresse syntaktisch korrekt ist, was über die Methode checkAdress geschieht. Wird eine falsche Adresse erkannt, bricht das Skript mit einer Fehlermeldung ab. Ist die Adresse korrekt, wird versucht die eMail zu verschicken, was bei Erfolg eine Bestätigung hervorruft. 3. Implementierung 32 Sollte es Probleme beim Mailversand geben, wird eine Fehlermeldung ausgegeben. Listing 3.19: Mail über das Kontaktformular verschicken 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 switch ( TRUE ) { case ( isset ( $_POST [ ’ action ’ ]) && $_POST [ ’ action ’] == ’ kontakt ’) ; // Abfrage gestartet // Fehlerbehandlung if ( $_POST [ ’ email ’] == " " || $_POST [ ’ name ’] == " " || $_POST [ ’ nachricht ’] == " " ) { echo ( " < h2 class =\ " error \ " > Achtung </ h2 > <p > < strong > Bitte alle Felder ausf & uuml ; llen . </ strong > Es wurden nicht in allen Feldern Angaben gemacht . Bitte & uuml ; berpr & uuml ; fen Sie Ihre Eingaben ! </p > " ) ; break ; } include ( " inc / class . sendmail . php " ) ; // sendmail Klasse inkluden // Mailobjekt wird angelegt $mail = new sendmail ( $_POST [ ’ email ’] , $_POST [ ’ name ’] , $_POST [ ’ betreff ’] , $_POST [ ’ nachricht ’ ]) ; if (! $mail - > checkAdress ( $mail - > from ) ) { // eMailadresse ueberpruefen ?> < h2 class = " error " > Achtung </ h2 > <p > < strong > Falsche eMailadresse . </ strong > Es wurde eine eMailadresse mit falschem Format angegeben . Bitte & uuml ; berpr & uuml ; fen Sie Ihre Eingaben ! </p > <? php break ; } if ( $mail - > sendNow () ) { // Mail verschicken geglueckt ?> <h2 > Nachricht abgeschickt </ h2 > <p > Ihre Nachricht wurde soeben versendet . Ich versuche sie m & ouml ; glichst bald zu beantworten . </p > <p > Sollte wider erwarten keine Antwort erfolgen , so kann es sein , dass die eMail beim Versand in den Weiten des Internets verloren gegangen ist . Bitte schicken Sie einfach eine erneute Anfrage . </p > <? php } else { ?> < h2 class = " error " > Nachricht nicht abgeschickt </ h2 > <p > < strong > Es ist ein Fehler aufgetreten . </ strong > Die eMail konnte leider nicht verschickt werden . Bitte versuchen Sie es sp & auml ; ter erneut . </p > <? php 3. Implementierung 33 return false ; } break ; default ; // Abfrageformular anzeigen include ( " inc / inc . kontakt . php " ) ; 29 30 31 32 33 34 } 3. Implementierung 34 4. Ergebnis Im letzten Kapitel wird kurz auf das fertige Produkt eingegangen, um dann in der Schlußbetrachtung die gesetzten und erfüllten Ziele zu betrachten. 4.1. Betatest Kurz nach Vollendung der Programmierarbeit habe ich die Seite öffentlich im W126-Forum vorgestellt1 , mit der Bitte an die User, die Seite zu testen und mir eventuelle Verbesserungsvorschläge mitzuteilen. Das Feedback war mehr als positiv. Fehler in der Programmierung sind hierbei keine in Erscheinung getreten. Der Datenbestand war noch nicht ganz vollständig oder leicht fehlerhaft. Bei so einer Menge an Daten war das durchaus zu erwarten und es konnten somit noch einige Fehler ausgemerzt werden und neue Sonderausstattungscodes hinzugefügt werden. Beispiele für Änderungen nach dem Betatest: • Der Farbcode 618 (Mimosengelb) wurde um die Zusatzinformation „Ab 07/81 war diese Lackierung nicht mehr bestellbar.“ ergänzt. • Der SA-Code 260 (Typenkennzeichen auf Heckdeckel, Wegfall) wurde mit Beschreibung und Bild ergänzt. • Der SA-Code 630 (ECE-Warndreieck) wurde hinzugefügt. • Der SA-Code 823 (Zusatzteile Abgasreinigung für Schweiz-Ausführung bei KAT-Ausrüstung.) wurde hinzugefügt. • Der Lackcode 923 (Lapisblau) wurde um die Zusatzinformation „Lieferbar von 10/79 bis 05/84.“ ergänzt. • Der SA-Code 823 (Zusatzteile Abgasreinigung für Schweiz-Ausführung bei KAT-Ausrüstung.) wurde hinzugefügt. • Der SA-Code 823 (Zusatzteile Abgasreinigung für Schweiz-Ausführung bei KAT-Ausrüstung.) wurde hinzugefügt. • Der SA-Code 823 (Zusatzteile Abgasreinigung für Schweiz-Ausführung bei KAT-Ausrüstung.) wurde hinzugefügt. 1 Das genaue Thema findet sich unter folgendem Link: http://f11.parsimony.net/forum16936/messages/125726.htm 4. Ergebnis 35 4.2. Das fertige Produkt Das fertige Produkt dieser Studienarbeit kann man in Abbildung 3.1 betrachten. In jedem der getesteten Browser funktioniert die geschriebene Applikation ohne Einschränkungen. Leichte Unterschiede im Design sind auf die verschiedenen Rendering-Engines2 der Browser zurückzuführen. Da auf XHTML-konformen Code geachtet wurde, müssten die Browserhersteller auf eine korrekte Implementierung wertlegen. Die Anwendung kann unter der Adresse http://w126.xmariox.com/sa/ ausprobiert werden. 4.3. Schlußbetrachtung Es wurden konkret folgende Ziele zu Beginn der Arbeit festgelegt: • Die Seiten sollen valides XHTML 1.0 mit dem Dokumententyp Transitional sein. • Ebenso sollen die CSS-Dateien mit dem Validator des W3C validieren. • PHP Code soll weitestgehend objektorientiert geschrieben sein. • Die Daten werden in einer MySQL Datenbank gespeichert. Hinzu kamen während der Arbeit, teils aus Interesse, teils der Vollständigkeit halber, folgende Ziele: • Ein Apache-Webserver soll als Entwicklungsserver dienen und durch Virtual Hosts erreichbar sein. • Um die Webseite komplett zu machen, soll eine Kontaktmöglichkeit für Benutzer geschaffen werden. Hierbei fiel zusätzlicher Programmieraufwand für eine Mailfunktion an. Wie man aus der vorangegangenen Lektüre dieser Dokumentation entnehmen kann, sind alle oben erwähnten Ziele erfüllt worden. Dabei waren besonders das Anlegen der richtigen MySQL-Tabellen ein wichtiger Schritt und Lerneffekt. Ebenso die für mich völlig neue, objektorientierte Art zu programmieren war anfangs gar nicht so einfach zu meistern. Die Theorie in die Praxis umzusetzen, hört sich manchmal leichter an, als es wirklich ist. Gerade hier habe ich einen enormen Schritt nach vorne gemacht und mein Wissen erweitert. Mir fiel dabei besonders auf, dass sehr viel Aufwand im Abfangen von Fehlern, z.B. durch falsche Eingaben eines Benutzers, steckt. Die eigentliche Logik entsteht für konforme Eingaben recht schnell, doch alle Fehler abzufangen und dazu eine entsprechende Meldung auszugeben, macht einiges an Mühe. Mit der vorliegenden Endversion der Anwendung bin ich sehr zufrieden. Sie erfüllt alle meine Kriterien und Erwartungen, die anfangs aufgestellt wurden. Der Betatest (siehe 4.1) hat zudem gezeigt, dass die Anwendung recht einfach zu pflegen ist. 2 Jeder Browser besitzt eine Rendering-Engine, um die HTML- bzw. CSS-Textdateien formatiert am Bildschirm auszugeben. 4. Ergebnis 36 4.4. Ausblick Die Anwendung wird auch in Zukunft produktiv eingesetzt, was gleichzeitig bedeutet, dass sie auch weiterentwickelt werden soll. Das betrifft einerseits die Inhalte der Datenbank, die unter Mithilfe von verschiedenen Forenmitgliedern durch neue oder verbesserte Sonderausstattungscodes und Fotos erweitert werden soll und andererseits die Programmlogik. Hier bietet es sich speziell an, eine Adminoberfläche zu programmieren, über die man die Datenbank bequem verwalten kann. So entfällt der Schritt über PHPmyAdmin. 4. Ergebnis 37 A. Anhang A.1. Inhalte der CD-ROM Die beiliegende CD-ROM ist in die folgenden Bereiche untergliedert: • /datenbank_dump/: SQL-Dump der Datenbank. • /design_daten/: Photoshop- und Illustratordateien mit Designentwürfen. • /dokumentation/: Dokumentation und Zeitplan im PDF-Format • /webroot/: Kopie des Wurzelverzeichnisses von http://w126.xmariox.com/sa/. Hier sind alle PHP-Skripte und HTML-Dateien enthalten. Eine Datei namens read_me.txt im Stammverzeichnis enthält zusätzliche Informationen. A.2. Informationen zur benutzten Software • HTML- und Texteditor: Macromedia Homesite • Bildbearbeitungsprogramm: Adobe Photoshop • Vektorbearbeitungsprogramm: Adobe Illustrator • ER-Schemata: DIA • Datenbank: PHPmyAdmin • Dokumentation: LATEX (MiKTeX und TeXnicCenter) A. Anhang 38 Literaturverzeichnis [1] diverse Autoren. PHP FAQ der IRC-Channels #php und #php.de. http://www.php-q. net/. [2] diverse Autoren. PHP FAQ der Newsgroups de.comp.lang.php.*. http://www.php-faq. de/. [3] diverse Autoren. Wikipedia - Die freie Enzyklopädie. http://de.wikipedia.org/. [4] Paul Dubois. MySQL - Entwicklung, Implementierung und Referenz. Markt & Technik, 2000. [5] Marc Liyanage. Mysql Database Server. http://www.entropy.ch/software/macosx/ mysql/. [6] The W3C Validator Team. css-validator/. W3C CSS Validator. http://jigsaw.w3.org/ [7] The W3C Validator Team. W3C HTML Validator. http://validator.w3.org/. Literaturverzeichnis 39