1673 lines
59 KiB
TeX
1673 lines
59 KiB
TeX
|
% header
|
|||
|
% Dies ist version-0.9.8 der IHK Doku [FINAL]
|
|||
|
% let's go...
|
|||
|
%\documentclass[10pt,a4paper,ngerman]{article}
|
|||
|
\documentclass[11pt,a4paper]{article}
|
|||
|
\usepackage[latin1]{inputenc} % Ascii-Format dieses Dokuments
|
|||
|
%\usepackage{babel} % neue deutsche Rechtschreibung
|
|||
|
% Teutsch
|
|||
|
\usepackage{german}
|
|||
|
% lange Tabellen
|
|||
|
\usepackage{longtable}
|
|||
|
% pagestyle..
|
|||
|
\usepackage{fancyhdr}
|
|||
|
\pagestyle{fancy}
|
|||
|
%\fancyhf{} % bisherige Kopf- und Fusszeilen loeschen
|
|||
|
\fancyhead[R]{Nico Schottelius} % rechter Kopfzeileneintrag
|
|||
|
%\fancyhead[L]{Projekdokumentation} % linker Kopfzeileneintrag
|
|||
|
%\fancyhead[L]{\thepage} % linker Kopfzeileneintrag
|
|||
|
%\fancyfoot[C]{\thepage} % Fusszeileneintrag (Seitenzahl zentriert)
|
|||
|
\renewcommand{\headrulewidth}{0.4pt} % Strichstaerke unter der Kopfzeile
|
|||
|
% let's start
|
|||
|
\begin{document}
|
|||
|
\title{Projektdokumentation: Webzugriff auf eine Datenbank via PHP}
|
|||
|
\date{01.03.2004 - 30.04.2004}
|
|||
|
\author{
|
|||
|
Nico Schottelius\\
|
|||
|
Rodenstra\ss{}e 12\\
|
|||
|
30826 Garbsen\\
|
|||
|
nico-ihk@schottelius.org\\
|
|||
|
\\
|
|||
|
Ausbildungsbetrieb:\\
|
|||
|
Wirtschaftsgenossenschaft deutscher Tier\"arzte eG\\
|
|||
|
Siemensstra\ss{}e 14\\
|
|||
|
30827 Garbsen\\
|
|||
|
http://www.wdt.de\\
|
|||
|
}
|
|||
|
% Title
|
|||
|
\maketitle
|
|||
|
\newpage
|
|||
|
% Inhaltsverzeichnis
|
|||
|
\tableofcontents
|
|||
|
\newpage
|
|||
|
\section{Pers\"onliche Erkl\"arung}
|
|||
|
Ich versichere durch meine Unterschrift, dass ich die betriebliche Projektarbeit
|
|||
|
und die dazugeh\"orige Dokumentation selbst\"andig in der vorgegebenen Zeit
|
|||
|
erarbeitet habe. Ich habe keine anderen als die von mir angegebenen Quellen und
|
|||
|
Hilfsmittel verwendet.\\
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\begin{tabbing}
|
|||
|
xxxxxxxxxxxxxxxxx\=xxxxxxxxx\kill
|
|||
|
$\overline{\mbox{\large{Ort, Datum}}}$
|
|||
|
\>$\overline{\mbox{\large{Unterschrift des Pr\"uflings}}}$\\
|
|||
|
\end{tabbing}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
Zur Kenntnis genommen:
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
$\overline{\mbox{\large{Ausbilder/-in}}}$
|
|||
|
\newpage
|
|||
|
\section{Einleitung}
|
|||
|
\subsection{Projektumfeld}
|
|||
|
Das Projekt fand in der Wirtschaftsgenossenschaft deutscher Tier\"arzte eG
|
|||
|
("`\textit{WDT}"') am Standort in Garbsen statt. Die WDT liefert Arzneimittel und
|
|||
|
medizinisches Zubeh\"or f\"ur tier\"arztliche Praxen in ganz Deutschland. Zur Zeit
|
|||
|
arbeiten circa 170 Mitarbeiter an drei Firmenstandorten, davon sind 14
|
|||
|
Aussendienstmitarbeiter ("`\textit{ADM}"') in der Kundenbetreuung t\"atig. Ein
|
|||
|
Gro\ss{}teil der Arbeitsabl\"aufe wird durch das
|
|||
|
\textit{ERP-System}\footnote{ERP-System: Enterprise Resource Planing System}
|
|||
|
unterst\"utzt.
|
|||
|
So erfolgt die gesamte Auftragsbearbeitung, die Kommissionierung, der Versand,
|
|||
|
der Einkauf sowie die Buchhaltung mit Hilfe dieses Systems.
|
|||
|
Die Aussendiensmitarbeiter erhalten monatlich einen f\"ur sie relevanten,
|
|||
|
individuellen Auszug aus der Datenbank.
|
|||
|
\subsection{Ist-Zustand}
|
|||
|
Zur Zeit werden Informationen zur Planung der Kundenberatung an die
|
|||
|
Aussendienstmitarbeiter als \textit{Excel-Tabelle}\footnote{Excel ist ein Produkt
|
|||
|
von Microsoft. Excel-Tabellen stellen ein properit\"ares Format zur Speicherung
|
|||
|
von Tabellen dar}
|
|||
|
via E-Mail versandt. Aufgrund der Verbindungsart
|
|||
|
(\textit{HSCSD/GSM}\footnote{GSM ist die Technik die zum Verbinden der
|
|||
|
Mobiltelefone verwendet wird, HSCSD ist die Daten\"ubertragung \"uber GSM}, ISDN
|
|||
|
oder Modem) und der Gr\"o\ss{}e (circa 16 \textit{MiB}\footnote{KiB, MiB, GiB
|
|||
|
sind Alternativbezeichnungen zu KB, MB und GB. Bei der
|
|||
|
Verwendung von den letztern ist nicht klar, ob der Faktor 1000 oder 1024 gemeint
|
|||
|
ist, 1024Byte entsprechen \textbf{immer} 1KiB. So sind z.B. manche 80GB Platten
|
|||
|
nur 80000000000 Byte gross, was 74,51GiB entspricht.})
|
|||
|
der Datei kommt es zu Problemen bei der \"Ubertragung. Diese Probleme
|
|||
|
\"au\ss{}ern sich wie folgt:
|
|||
|
\begin{itemize}
|
|||
|
\item der Transfer der Datei dauert sehr lange (\"uber 30 Minuten)
|
|||
|
\item durch eine Zwangstrennung im Funknetz nach 30 Minuten kann die Datei nicht
|
|||
|
vollst\"andig \"ubertragen werden
|
|||
|
\end{itemize}
|
|||
|
Da E-Mail ein
|
|||
|
\textit{Push-System}\footnote{Als "`Push-Systeme"' werden Systeme bezeichnet,
|
|||
|
die die Informationen ohne Aufforderung des Benutzers zu selbigen senden
|
|||
|
(neben E-Mail auch z.B. Plakate). Bei "`Pull-Sytemen"' hingegen muss der
|
|||
|
Benutzer interaktiv die Informationen anfordern (z.B. Webseite).} ist,
|
|||
|
ergibt sich zus\"atzlich das Problem, dass grunds\"atzlich in dreifacher
|
|||
|
Hinsicht unn\"otige Daten \"ubertragen werden k\"onnen:
|
|||
|
\begin{enumerate}
|
|||
|
\item der ADM ben\"otigt die Informationen z.Z. nicht:
|
|||
|
komplett unn\"otiger Versand.\\
|
|||
|
Eine Filterung nach Anforderung ist mit dem momentanen System schwer zu realisieren
|
|||
|
und k\"onnte bestenfalls manuell mit R\"ucksprache geschehen.
|
|||
|
\item selbst wenn sich die Daten nicht ge\"andert haben, wird ein Update versandt\\
|
|||
|
Dies hat zwei Gr\"unde:
|
|||
|
\begin{enumerate}
|
|||
|
\item die regelm\"assig empfangene E-Mail ist ein
|
|||
|
Indiz f\"ur den ADM, dass das System ordnungsgem\"ass{} funktioniert
|
|||
|
\item zum Zweiten wird keine Versionsverwaltung betrieben, sondern die
|
|||
|
Excel-Tabellen jedes Mal komplett neu generiert
|
|||
|
\end{enumerate}
|
|||
|
\item Der ADM ben\"otigt nur einen Teil der Daten, bekommt
|
|||
|
jedoch immer eine vorgefertigte Version mit gro\ss{}em Umfang (Daten\"uberfluss)
|
|||
|
\item Bei jeder Aktualisierung werden auch die unver\"anderten Stammdaten
|
|||
|
transferiert
|
|||
|
\end{enumerate}
|
|||
|
\subsection{Soll-Zustand}
|
|||
|
Auf den Transfer via E-Mail soll grunds\"atzlich verzichtet und der
|
|||
|
Zugriff in ein Pull-System umgewandelt werden.
|
|||
|
Der Zugriff soll \"uber das
|
|||
|
Internet auf ein Webinterface geschehen. Die Implementation muss auf dem
|
|||
|
\textit{LAMP-System}\footnote{LAMP ist die Abk\"urzung f\"ur ein \textbf{L}inux,
|
|||
|
\textbf{A}pache, \textbf{M}ySQL, \textbf{P}HP Kombination, wobei Linux das
|
|||
|
Betriebssystem, Apache der Webserver, MySQL die Datenbank und PHP die
|
|||
|
Programmiersprache ist.}
|
|||
|
des Providers lauff\"ahig sein. Dazu soll ein m\"oglichst identisches Testsystem
|
|||
|
intern verf\"ugbar sein. Die Daten m\"ussen aus dem ERP-System in einem
|
|||
|
f\"ur MySQL importf\"ahigen Format bereitgestellt werden. Die entsprechenden
|
|||
|
Aufgaben sollen gem\"a\ss{} der Qualifizierung der Mitarbeiter delegiert werden:
|
|||
|
\begin{itemize}
|
|||
|
\item das LAMP-System soll durch die Systemintegration bereitgestellt werden
|
|||
|
\item der Export der Daten aus dem ERP-System soll durch die hauseigenen
|
|||
|
Programmierer bereitgestellt werden
|
|||
|
\item die Erstellung des Webzugriffs und der Dokumentation (inklusive Handbuch
|
|||
|
f\"ur Benutzer und Entwickler, Schnittstellendefinitionen und Pflichtenheft) soll
|
|||
|
vom Pr\"ufling erledigt werden
|
|||
|
\end{itemize}
|
|||
|
Ziel ist es, ein verwendbares System zu entwickeln und die Machbarkeit zu beweisen.
|
|||
|
\section{Planung}
|
|||
|
\subsection{Ablauf des Projektes}
|
|||
|
Zu Beginn des Projektes wurden die Projektgrundsteine "`gelegt"':
|
|||
|
\begin{enumerate}
|
|||
|
\item es wurde ein Zeitplan f\"ur die einzelnen Phasen festgelegt, inklusive der
|
|||
|
Festlegung von Besprechungsterminen
|
|||
|
\item es wurden f\"ur die einzelnen Teams Schnittstellen definiert, damit diese
|
|||
|
unabh\"angig voneinander arbeiten konnten und um eine klare Trennung zwischen den
|
|||
|
einzelnen Modulen zu schaffen
|
|||
|
\end{enumerate}
|
|||
|
\subsection{Schnittstellendefinition}
|
|||
|
Durch den sauberen Einsatz von Schnittstellen kann zum Beispiel ein Mitarbeiter
|
|||
|
die Daten aus dem ERP-System auslesen und sie in einem definierten Format
|
|||
|
speichern, w\"ahrend ein anderer schon die Umwandlung in die neue Datenbank
|
|||
|
mit Hilfe von Testdaten programmiert. \\
|
|||
|
Es sollen folgende Schnittstellendefinitionen erzeugt werden:
|
|||
|
\begin{enumerate}
|
|||
|
\item Benutzer/Weboberfl\"ache: Layoutdefiniton
|
|||
|
\item Weboberfl\"ache/Datenbank: Zugriffsdefiniton
|
|||
|
\item Datenbank/Quelldaten: Importformatdefiniton
|
|||
|
\end{enumerate}
|
|||
|
\subsection{Kompatibilit\"at}
|
|||
|
Die Skripte m\"ussen ein identisches Verhalten auf dem Testsystem und auf dem
|
|||
|
Echtsystem vorweisen. Um dies zu gew\"ahrleisten sind Modifizierungen, die im
|
|||
|
Rahmen der Installation von Programmen als normal zu betrachten sind
|
|||
|
(z.B. Pfad-, Limitierungs- oder Namensmodifikationen), n\"otig.
|
|||
|
Das Erscheinungsbild dem Benutzer gegen\"uber soll soweit wie m\"oglich
|
|||
|
identisch bleiben.
|
|||
|
Eine Absprache mit dem \textit{ISP}\footnote{Internet Service Provider
|
|||
|
bieten Internetanbindungen und Service an}
|
|||
|
soll vor Beginn der Entwicklung stattfinden, damit eventuelle
|
|||
|
Inkompatibilit\"aten vermieden werden k\"onnen.\\
|
|||
|
Ein System, das nur In-House funktioniert, w\"are f\"ur die bestehende Situation keine
|
|||
|
ad\"aquate L\"osung. Da die Kompatibilit\"at ein wichtiger Punkt im Rahmen des
|
|||
|
Projektes ist, wurde diese in einer eigenen Schnittstelle definiert
|
|||
|
("`Test /Echtsystem"').
|
|||
|
\subsection{Layout (Benutzerschnittstelle)}
|
|||
|
Das Layout muss vor Beginn der Entwicklung der Weboberfl\"ache definiert sein
|
|||
|
und den spezifischen Anforderungen entsprechen. An dieses Layout sollen
|
|||
|
s\"amtliche Skripte angepasst sein.
|
|||
|
\section{Durchf\"uhrung}
|
|||
|
\subsection{Erzeugen des PHP Such-Skripts}
|
|||
|
Das PHP Skript wurde nach der Vorlage des Excel Dokumentes erzeugt. Zuerst
|
|||
|
wurde das Skript monolithisch erzeugt, d.h. es enthielt keinerlei Module und
|
|||
|
s\"amtliche Einstellungen waren in dem Skript selbst zu finden. Da sich
|
|||
|
schnell herausstellte, dass eine solche Struktur schlecht zu erweitern ist,
|
|||
|
wurde das Skript in mehrere Teile aufgeteilt, welche wiederum modularisiert sind.
|
|||
|
Die Module wurden in ein Unterverzeichnis "`modules"' verschoben.
|
|||
|
Konfigurationen k\"onnen nun zentral in den dazu passenden Dateien im
|
|||
|
"`includes"' Verzeichnis vorgenommen werden.
|
|||
|
Es soll die M\"oglichkeit geben, dass die Skripte sp\"ater extern gepflegt oder
|
|||
|
erweitert werden. Da dies auch durch Dienstleistungen ausl\"andischer Firmen
|
|||
|
geschehen k\"onnte, sind die Kommentare in Englisch. Da ein Gro\ss{}teil der
|
|||
|
technischen Literatur in
|
|||
|
Englisch geschrieben ist, werden deutsche Informatiker mit den englischen
|
|||
|
Kommentaren keine Probleme haben.
|
|||
|
Mit einigen Problemen behaftet war der Wechsel von Apache 1.3 zu Apache 2.0.
|
|||
|
Der Letztere setzt keine globalen Variablen, wenn selbige durch eine Form
|
|||
|
an ein PHP Skript gesendet werden. Dadurch musste nach dem Wechsel der Inhalt der
|
|||
|
Formvariablen aus einem speziellen Parameterarray namens "`\_REQUEST"' ausgelesen
|
|||
|
werden.
|
|||
|
\subsection{Erzeugen des Importfilters}
|
|||
|
Der Importfilter ist dem Layout des Hauptskriptes, und damit der allgemeinen
|
|||
|
Definition, nachempfunden. Er wurde ebenfalls in PHP geschrieben und importiert
|
|||
|
die hochgeladenen ASCII Tabellen in die MySQL Datenbank. Das Format der
|
|||
|
ASCII-Tabellen wurde in der entsprechenden Schnittstellendefinition hinterlegt. \\
|
|||
|
Das Standardverhalten bei identischen Primary Key Feldern ist, den alten Wert mit
|
|||
|
dem neuen zu \"uberschreiben. Die Alternative, Werte zu addieren ist nur in
|
|||
|
wenigen F\"allen sinnvoll und w\"urde in der praktischen Anwendung zu komplizierten
|
|||
|
Abh\"angigkeiten und einigen zus\"atzlichen Definitionen und Tests f\"uhren. So
|
|||
|
m\"usste man z.B. Felder wie die Postleitzahl oder die Telefonnummer gesondert
|
|||
|
behandeln. Ebenfalls problematisch w\"are das Ergebnis, wenn jemand aus Versehen
|
|||
|
zweimal den Upload Knopf bet\"atigt und somit zum Beispiel den Umsatz f\"ur
|
|||
|
einen bestimmten Zeitraum verdoppelt. \\
|
|||
|
Problematisch ist auch das Standardverhalten von PHP, welches nur eine maximale
|
|||
|
Dateigr\"o\ss{}e von 2MiB vorsieht und einem Skript nur 8MiB Arbeitsspeicher
|
|||
|
erlaubt. Wenn die Dateien dieses Limit \"uberschreiten, erzeugt PHP keine
|
|||
|
Fehlermeldung, sondern ignoriert die hochzuladende Datei
|
|||
|
(verifiziert bei PHP 4.3.4 und 4.3.5RC3).
|
|||
|
\subsection{Erzeugen des Initialdatenbankgenerators}
|
|||
|
Zur Vereinfachung der Arbeit wurde zus\"atzlich ein Skript eingerichtet, welches
|
|||
|
eine initiale Datenbank mit den entsprechenden Tabellen anlegt. Die entsprechenden
|
|||
|
Tabellen wurden in den Quelltext integriert, da eine Auslagerung der
|
|||
|
Tabellenspezifikation einen zus\"atzlichen Parser erfordert h\"atte.
|
|||
|
\subsection{Transfer in das Echtsystem}
|
|||
|
Der Transfer in das Echtsystem verlief problemlos.
|
|||
|
Der Einsatz im Echtsystem wurde mit dem ISP der WDT abgesprochen und
|
|||
|
getestet.
|
|||
|
Zuerst wurden die Sicherheitseinstellungen transferiert.
|
|||
|
Danach wurden die PHP-Skripte hochgeladen, welche dann gleich zur Initialisierung der
|
|||
|
Datenbank und dem Transfer der Echtdaten benutzt wurden. Da die Verbindung
|
|||
|
\"uber das \textit{HTTPS}\footnote{Sicheres, verschl\"usselt \"ubertragen von
|
|||
|
Dateien; Alternative zu HTTP} Protokoll erfolgt, sind die Daten w\"ahrend des
|
|||
|
Transfers verschl\"usselt und f\"alschungssicher.
|
|||
|
Die maximale Dateigr\"o\ss{}e f\"ur einen Upload durch PHP ist beim ISP
|
|||
|
auf 8MB beschr\"ankt.
|
|||
|
Deswegen mussten die Umsatz Tabellen, die pro Jahr eine Gr\"o\ss{}e von 22MiB
|
|||
|
haben, aufgeteilt werden.
|
|||
|
\section{Dokumentationsphase}
|
|||
|
\subsection{Erstellen der Programmdokumentation}
|
|||
|
Die Programmdokumentation ist f\"ur die Verwendung durch Entwickler und
|
|||
|
Administratoren konzipiert und enth\"alt technische Fachbegriffe.
|
|||
|
Sie wurde in Stichw\"ortern w\"ahrend der Durchf\"uhrungsphase niedergeschrieben
|
|||
|
und danach zusammengefasst in ein Latex-Dokument. \textit{Latex}\footnote{
|
|||
|
Siehe auch die deutsche TeX Webseite http://www.dante.de} ist ein Textsatzsystem,
|
|||
|
welches insbesondere f\"ur wissenschaftliche und technische Dokumentation verwendet
|
|||
|
wird. Die Programmdokumentation ist entsprechend der Bed\"urfnisse von
|
|||
|
Administratoren und Entwicklern gegliedert und aufgebaut. Dies bedeutet z.B.,
|
|||
|
dass der Administrator schnell die entsprechenden Sektionen zur Installation
|
|||
|
und der Entwickler ebenso einfach den Aufbau der Programme finden kann.
|
|||
|
Als Ausgabeformat wurde PDF gew\"ahlt, da dieses Format auf jeder Plattform
|
|||
|
lesbar ist.
|
|||
|
\subsection{Erstellen des Benutzerhandbuches}
|
|||
|
Das Benutzerhandbuch wurde nach der Durchf\"uhrung erstellt. Dadurch
|
|||
|
wurde garantiert, dass die Screenshots der Oberfl\"ache sich nicht mehr
|
|||
|
ver\"andern k\"onnen. Vom Aufraggeber wurde eine Dokumentation gefordert, die den
|
|||
|
Ablauf m\"oglichst pr\"azise und zugleich simpel beschreibt. Dies wurde durch den
|
|||
|
Einsatz von Screenshots bewerkstelligt. Als Ausgabeformat wurde eine
|
|||
|
Pr\"asentation (entweder im \textit{PowerPoint oder OpenOffice}\footnote{
|
|||
|
PowerPoint ist ein Programm aus der Programmgruppe "`Microsoft Office"' von
|
|||
|
Microsoft, OpenOffice ist ein OpenSource Konkurrenzprodukt zu Microsoft Office}
|
|||
|
Format) gew\"ahlt, da in einer Pr\"asentation wie in einem Buch am Bildschirm
|
|||
|
gebl\"attert werden kann.
|
|||
|
\subsection{Erstellen der IHK-Projektdokumentation}
|
|||
|
Bei der Erstellung dieser Dokumentation wurde \"ahnlich verfahren wie
|
|||
|
bei der Erstellung der Programmdokumentation. Jedoch wurde diese Dokumentation
|
|||
|
zuerst in OpenOffice geschrieben und nachher in Latex konvertiert, da Latex
|
|||
|
wesentlich effektiver f\"ur die Erstellung von gro\ss{}en Dokumenten ist.
|
|||
|
\section{Testphase}
|
|||
|
\subsection{Testabschnitte w\"ahrend der Erstellung}
|
|||
|
W\"ahrend der Entwicklungsphase wurde die Funktionalit\"at der Skripte mit Hilfe
|
|||
|
einer Datenbank mit Pseudodaten getestet. Da die Anzahl der S\"atze in der
|
|||
|
Datenbank sehr gering war, waren die Ergebnisse schnell verf\"ugbar und es
|
|||
|
musste in Betracht gezogen werden, dass die Arbeit mit Echtdaten wesentlich
|
|||
|
langsamer laufen k\"onnte. Dies best\"atigte sich jedoch nicht, die Auslieferung
|
|||
|
der Daten durch die MySQL Datenbank verlief weiterhin gewohnt schnell. Die Ausgabe
|
|||
|
erfolgte teilweise mit Debug Informationen. Diese beinhalteten z.B.
|
|||
|
Variableninhalte oder R\"uckgabewerte von Funktionen.
|
|||
|
\subsection{Eigentest aller Programme}
|
|||
|
Nach der Entwicklungsphase wurden die Programme auf Funktionalit\"at und saubere
|
|||
|
Ausgaben \"uberpr\"uft. So durften keine Debug-Nachrichten mehr erscheinen und es
|
|||
|
sollten keine Fehler beim "`normalen Benutzen"' auftreten. Es wurde kritisch darauf
|
|||
|
geachtet, dass keine Situation auftritt, die ein normaler Benutzer nicht verstehen
|
|||
|
kann (z.B. Bildschirm ohne Inhalt). Des weiteren wurden generelle Sicherheitsl\"ucken
|
|||
|
\"uberpr\"uft, wie
|
|||
|
\textit{Buffer Overflows, SQL-Injektion und Cross-Site-Scripting}\footnote{Buffer
|
|||
|
Overflows, SQL-Injektion und Cross-Site-Scripting sind
|
|||
|
bekannte Fehler die bei der Programmierung auftreten. Die letzteren beiden
|
|||
|
besonders bei der Programmierung von Skripten mit Webzugriff}.
|
|||
|
\subsection{Fremdtest aller Programme}
|
|||
|
Zum Abschlu\ss{} wurden die Programme von Mitarbeitern aus der EDV Abteilung
|
|||
|
getestet und zus\"atzlich auf Sicherheitsl\"ucken gepr\"uft. Durch diese Hilfe
|
|||
|
konnten Fehler entdeckt werden, die ein Entwickler selbst nicht bemerkt. So
|
|||
|
wurde z.B. bemerkt, dass auf einer Seite ein Teil des Firmenlogos anders angezeigt
|
|||
|
wurde ("`stehende Karawane"', sollte "`bewegte Karawane"' sein).
|
|||
|
\section{Fazit}
|
|||
|
\subsection{R\"uckblick}
|
|||
|
Die Programmierung des Skriptes und die Einrichtung des Apache 2.0 mit PHP 4.3.4
|
|||
|
aus dem Quelltext verliefen ohne Probleme. Dies wurde durch den Einsatz des
|
|||
|
LAMP-Systems gef\"ordert, denn die einzelnen Komponenten,
|
|||
|
Linux, Apache, MySQL und PHP, sind sehr gut aufeinander abgestimmt.
|
|||
|
Einen Gro\ss{}teil der Zeit musste in die Entwicklung der Schnittstellen und
|
|||
|
das Testen investiert werden. \\
|
|||
|
Das Teamwork erleichterte die Entwicklungsarbeit, da durch vorhergehende Schulungen
|
|||
|
und Tipps w\"ahrend der Entwicklung Probleme im Design fr\"uhzeitig vermieden
|
|||
|
werden konnten.
|
|||
|
So empfahlen Kollegen das Datenbankdesign in die dritte Form
|
|||
|
der Normalisierung zu \"ubertragen um eine Umsetzung in eine relationale Datenbank
|
|||
|
zu erleichtern und zeigten an Beispielen, wie dies zu geschehen hat.
|
|||
|
Die strikte Trennung der einzelnen Aufgaben erleichterte die Arbeit. Dadurch konnte
|
|||
|
problemlos an einem anderen Teil weitergearbeitet werden, w\"ahrend noch die
|
|||
|
Echtdaten f\"ur die Datenbank fehlten.
|
|||
|
\newpage
|
|||
|
\subsection{Zeitplan mit Abweichungen}
|
|||
|
\setlongtables
|
|||
|
\begin{longtable}{||l|c|c||}
|
|||
|
\caption{Zeitplan}
|
|||
|
\endfirsthead
|
|||
|
\hline \hline
|
|||
|
\textbf{Aufgabe} & \textbf{ben\"otigte Zeit} & \textbf{geplante Zeit} \\
|
|||
|
& (in h) & (in h) \\
|
|||
|
\hline \hline
|
|||
|
\textbf{1 Vorarbeiten [Differenz: -1h]} & \textbf{10} & \textbf{11} \\
|
|||
|
\hline \hline
|
|||
|
1.1 Vorbesprechung mit unserem Au\ss{}endienst & 1 & 3 \\
|
|||
|
\hline
|
|||
|
1.2 Eruieren und dokumentieren des genauen Problems & 4 & 3 \\
|
|||
|
und Definition des IST-Status & & \\
|
|||
|
\hline
|
|||
|
1.3 R\"ucksprache mit dem Au\ss{}endienst und Abgleich & 1 & 1 \\
|
|||
|
des dokumentierten IST-Status mit dem Au\ss{}endienst & & \\
|
|||
|
\hline
|
|||
|
1.4 Definieren des SOLL-Status & 3 & 3 \\
|
|||
|
\hline
|
|||
|
1.5 R\"ucksprache mit dem Au\ss{}endienst und Abgleich & 1 & 1 \\
|
|||
|
des dokumentierten SOLL-Status mit dem Au\ss{}endienst & & \\
|
|||
|
\hline \hline
|
|||
|
\textbf{2 Planungsphase [-2h (gesamt: -3h)]} & \textbf{10} & \textbf{12}\\
|
|||
|
\hline \hline
|
|||
|
2.1 Grob-Modell entwickeln, das die Anforderungen des & 2 & 2 \\
|
|||
|
Soll-Status widerspiegelt & & \\
|
|||
|
\hline
|
|||
|
2.2 Schnittstellen definieren & & \\
|
|||
|
\hline
|
|||
|
2.2.1 Benutzer/Webinterface ("`Layoutdefinition"') & 1 & 2 \\
|
|||
|
\hline
|
|||
|
2.2.2 Webinterface/Datenbank & 2 & 2 \\
|
|||
|
\hline
|
|||
|
2.2.3 Datenbank/Quelldaten & 1 & 2 \\
|
|||
|
\hline
|
|||
|
2.2.4 Echtsystem/Testsystem & 2 & 2 \\
|
|||
|
\hline
|
|||
|
2.3 Pflichtenheft erstellen & 2 & 2 \\
|
|||
|
\hline \hline
|
|||
|
\textbf{3 Realisierungs- und Testphase [+2h (gesamt: -1h)]} & \textbf{28} & \textbf{25} \\
|
|||
|
\hline \hline
|
|||
|
\multicolumn{3}{||l||}{3.1 Erstellen des Webinterfaces} \\
|
|||
|
\hline \hline
|
|||
|
3.1.1 Erstellen der Zugriffseinstellungen & 1 & 1 \\
|
|||
|
\hline
|
|||
|
3.1.2 Erstellen des Hauptprogrammes inklusive & 3 & 2 \\
|
|||
|
Datenbankverbindung & & \\
|
|||
|
\hline
|
|||
|
3.1.3 Erstellen der Loginprozedur & 2 & 2 \\
|
|||
|
\hline
|
|||
|
3.1.4 Erstellen der Suchprozedur & 3 & 4 \\
|
|||
|
\hline
|
|||
|
3.1.5 Erstellen der Anzeigeprozedur & 5 & 2 \\
|
|||
|
\hline
|
|||
|
3.2 Testen des Webinterface in der Testumgebung & 5 & 5 \\
|
|||
|
\hline
|
|||
|
3.3 Erstellen des Konverters & 3 & 4 \\
|
|||
|
(CSV Datenbank in MySQL-Format) & & \\
|
|||
|
\hline
|
|||
|
3.4 Testen des Konverters in der Testumgebung & 2 & 2 \\
|
|||
|
\hline
|
|||
|
3.5 Fremdtest des Webinterface in der Testumgebung & 1 & 1 \\
|
|||
|
\hline
|
|||
|
3.6 Fremdtest des Konverters in der Testumgebung & 1 & 1 \\
|
|||
|
\hline
|
|||
|
3.7 Transfer des Testsystems in das Echtsystem des Providers & 2 & 2 \\
|
|||
|
\hline \hline
|
|||
|
\textbf{4 Dokumentationsphase [-5h (gesamt: -6h)]} & \textbf{12} & \textbf{17} \\
|
|||
|
\hline \hline
|
|||
|
4.1 Erstellen der Programmdokumentation & 7 & 7 \\
|
|||
|
\hline
|
|||
|
4.2 Erstellen des Benutzerhandbuches & 5 & 10 \\
|
|||
|
\hline \hline
|
|||
|
\textbf{5 Abschlussphase [(gesamt: -6h)]} & \textbf{1} & \textbf{1} \\
|
|||
|
\hline \hline
|
|||
|
5.1 Vorstellung des Systems in der Au\ss{}endienstleitung & 1 & 1 \\
|
|||
|
\hline \hline
|
|||
|
\textbf{6. Pufferzeit f\"ur nicht vorhersehbare Ereignisse} & \textbf{9} & \textbf{3} \\
|
|||
|
\hline \hline \hline
|
|||
|
\textbf{Gesamtzeit} & \textbf{70} & \textbf{70} \\
|
|||
|
\hline \hline
|
|||
|
\end{longtable}
|
|||
|
Einige Differenzen erl\"autere ich detaillierter, da sie wichtige Aspekte
|
|||
|
der Projektentwicklung widerspiegeln.\\
|
|||
|
Vorarbeiten:
|
|||
|
\begin{itemize}
|
|||
|
\item Die Besprechung mit dem Au\ss{}endienst verk\"urzte sich,
|
|||
|
da diesem die Problematik des alten Systems schon bekannt war
|
|||
|
\end{itemize}
|
|||
|
Realisierungs- und Testphase:
|
|||
|
\begin{itemize}
|
|||
|
\item Die Anbindung an die Datenbank verlief nicht so problemlos wie erwartet, da
|
|||
|
w\"ahrend der Entwicklung der Datenbankserver zwei kurze Ausf\"alle hatte. Dies
|
|||
|
f\"uhrte zu unvermuteten Ergebnissen im Hauptprogramm.
|
|||
|
\item Die Gestaltung der Anzeigeprozedur erwies sich als wesentlich komplexer als
|
|||
|
anfangs angenommen, da das Aussehen so wenig wie m\"oglich vom alten System
|
|||
|
abweichen sollte.
|
|||
|
\end{itemize}
|
|||
|
Dokumentationsphase:
|
|||
|
\begin{itemize}
|
|||
|
\item Die Benutzerhandb\"ucher wurden als einfache Pr\"asentation realisiert und
|
|||
|
bedurften kein spezielles Layout oder des Drucks.
|
|||
|
\end{itemize}
|
|||
|
Pufferzeit f\"ur nicht vorhersehbare Ereignisse:
|
|||
|
\begin{itemize}
|
|||
|
\item Im Zeitplan wurde der Punkt "`Erstellung der Projektdokumentation"' vergessen
|
|||
|
und musste deswegen hier einsortiert werden.
|
|||
|
\end{itemize}
|
|||
|
\subsection{Ausblick}
|
|||
|
\subsubsection{Erweiterung der bestehenden Programme}
|
|||
|
Zus\"atzlich zu den bestehenden Anzeigen k\"onnten noch Auswertungen programmiert
|
|||
|
werden, die sowohl schriftlich als auch graphisch pr\"asentiert werden.
|
|||
|
Des weiteren k\"onnte die Tabellenspezifikation aus init-database.php ausgelagert
|
|||
|
und selbiges Skript um einen Parser erweitert werden.
|
|||
|
\subsubsection{Hinzuf\"ugen weiterer Programme}
|
|||
|
Die Verwaltung der Benutzer k\"onnte durch ein Skript vereinfacht werden, welches
|
|||
|
das Hinzuf\"ugen, L\"oschen oder Modifizieren der MySQL Datenbank und der htpasswd
|
|||
|
Datei \"ubernimmt. Die Aktualisierung k\"onnte automatisiert werden, wenn von
|
|||
|
ProAlpha aus regelm\"assig (z.B. tagesweise) die aktuellen Ums\"atze an ein
|
|||
|
Programm \"ubermittelt werden, welches die Daten via HTTPS an das Upload Skript
|
|||
|
\"ubertr\"agt.
|
|||
|
\subsection{Kostenrechnung}
|
|||
|
\subsubsection{altes System}
|
|||
|
Die Kosten vorher setzten sich wie folgt zusammen:
|
|||
|
14 Au\ss{}endienstler holen 15 MiB gro\ss{}e Dateien zweimal im Monat ab.
|
|||
|
Die Internetverbindung erlaubt eine Transferrate von ca. 4 KiB pro Sekunde.\\
|
|||
|
\textbf{Rechnung:}
|
|||
|
$$\mbox{Transferrate} = \frac{4\mbox{KiB}}{\mbox{s}}$$\\
|
|||
|
$$15 \mbox{MiB} * 14 \mbox{ADM} = 210 \mbox{MiB} = 210 * \mbox{1024 KiB} =
|
|||
|
215040 \mbox{KiB}$$\\
|
|||
|
$$\frac{215040 \mbox{ KiB}}{\frac{4\mbox{ KiB}}{\mbox{s}}} = 53760\mbox{ Sekunden}
|
|||
|
= 896\mbox{ Minuten}$$\\
|
|||
|
$$1 \mbox{ Minute } \hat{=} 0,39 \mbox{Euro}$$\\
|
|||
|
$$896\mbox{ Minuten } * \frac{0,39 \mbox{ Euro}}{\mbox{Minute}} = 349,44
|
|||
|
\mbox{ Euro pro Update}$$\\
|
|||
|
2 $*$ Monatlich wird das Update gesendet.\\
|
|||
|
$$349,44\mbox{ Euro } * 2 = 698,88\mbox{ Euro pro Monat}$$
|
|||
|
Dies ergibt eine Online-Nutzdauer von 53.760 Sekunden, was 896 Minuten entspricht.
|
|||
|
Bei einem Minutenpreis von 39 Cent pro Minute enstehen \textbf{698,88 Euro}
|
|||
|
monatliche Kosten.
|
|||
|
\subsubsection{neues System}
|
|||
|
Die momentane Kosten setzen sich zusammen aus den Kosten f\"ur das Hosting
|
|||
|
des Webinterfaces und den Onlinekosten.
|
|||
|
Der Provider bietet einen Webauftritt, der \"uber eine
|
|||
|
HTTPS Verbindung abgesichert ist und eine Unterst\"utzung f\"ur PHP und MySQL
|
|||
|
enth\"alt, f\"ur 50 Euro pro Monat an. \\
|
|||
|
\textbf{Rechnung:}\\
|
|||
|
$$\mbox{MySQL Datenbank + PHP + Webspace } =
|
|||
|
\mbox{"`Webauftritt"' }= 50\mbox{ Euro pro Monat}$$
|
|||
|
$$\mbox{Nutzh\"aufigkeit} = \frac{\mbox{2mal}}{\mbox{Tag}}\mbox{ (benutzt der
|
|||
|
ADM das Webinterface)}$$\\
|
|||
|
Dies macht er an 20 Tagen (Arbeitstage) im Monat.
|
|||
|
$$\frac{\mbox{zweimal}}{\mbox{Tag}} * \frac{\mbox{Arbeitstage}}{\mbox{Monat}} = 40
|
|||
|
\mbox{mal Nachsehen pro Monat (pro ADM)}$$\\
|
|||
|
$$14 \mbox{ ADM} * 40\mbox{mal} \mbox{ Nachsehen} = 560\mbox{mal}
|
|||
|
\frac{\mbox{Nachsehen}}{\mbox{Monat}}$$\\
|
|||
|
Einmal Nachsehen entspricht statistisch nach einer Umfrage einer Minute
|
|||
|
(da nicht jeder das Angebot nutzen w\"urde und manche l\"anger brauchen).\\
|
|||
|
$$560 \mbox{Minuten} * \frac{0,39\mbox{ Euro}}{\mbox{Minute}} = 218.40
|
|||
|
\mbox{Euro}$$\\
|
|||
|
$$218,40 + 50,00 = 268,40 \frac{\mbox{Euro}}{\mbox{Monat}}$$
|
|||
|
Damit ergeben sich kumuliert Kosten von \textbf{268,40 Euro} pro Monat.\\
|
|||
|
In dieser Rechnung sind jedoch nicht die Entwicklungskosten f\"ur das neue
|
|||
|
System enthalten. Diese setzen sich zusammen aus dem Stundenlohn und der Anzahl
|
|||
|
der ben\"otigten Stunden.\\
|
|||
|
\textbf{Rechnung:}
|
|||
|
$$70\mbox{ Stunden} * 5\mbox{ Euro} = 350\mbox{ Euro}$$
|
|||
|
Dieser Betrag ist nur einmal f\"allig und amortisiert sich im Normalfall \"uber
|
|||
|
die Jahre. In unserem speziellen Fall sind die Entwicklungskosten sogar schon nach
|
|||
|
einem Monat kompensiert.\\
|
|||
|
\subsubsection{Kostenvergleich}
|
|||
|
Das neue System erbringt eine Kostenvorteil von \textbf{430,48 Euro}
|
|||
|
beziehungsweise verbraucht nur \textbf{38\%} der alten Kosten pro Monat.
|
|||
|
\section{Anhang}
|
|||
|
\subsection{Literatur}
|
|||
|
\subsubsection{PHP}
|
|||
|
\begin{itemize}
|
|||
|
\item "`PHP kurz \& gut"', O'Reilly, ISBN 3-89721-225-0
|
|||
|
\item "`Programmieren lernen in PHP4"', Hanser, ISBN 3-446-21754-1
|
|||
|
\item http://www.php.net
|
|||
|
\end{itemize}
|
|||
|
\subsubsection{Apache}
|
|||
|
\begin{itemize}
|
|||
|
\item http://httpd.apache.org/
|
|||
|
\end{itemize}
|
|||
|
\subsubsection{HTTP}
|
|||
|
\begin{itemize}
|
|||
|
\item HTTP Pocket Reference, O'Reilly, ISBN 1-56592-862-8
|
|||
|
\end{itemize}
|
|||
|
\subsubsection{MySQL}
|
|||
|
\begin{itemize}
|
|||
|
\item Managing and Using MySQL, 2nd Edition, O'Reilly, ISBN 0-596-00211-4
|
|||
|
\end{itemize}
|
|||
|
\subsection{Schnittstellen}
|
|||
|
\subsubsection{Benutzer/Weboberfl\"ache: Layoutdefiniton}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
Nico Schottelius, v0.6
|
|||
|
Schnittstelle: Webinterface/Layout
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
1. Generelle Layoutdefiniton
|
|||
|
2. Benutzerinteraktion
|
|||
|
3. Authentifizierung
|
|||
|
4. Sicherheit
|
|||
|
5. Einstiegsbildschirm
|
|||
|
6. Suchergebnisse
|
|||
|
7. Suchdetails
|
|||
|
|
|||
|
|
|||
|
1. Generelle Layoutdefiniton
|
|||
|
|
|||
|
Die Weboberfl<66>che sollte von der Farbwahl der Firmenhomepage [WL1] <20>hneln.
|
|||
|
Zudem sollte ein firmentypisches Objekt (Logo, Motto, etc.) pr<70>sent sein.
|
|||
|
|
|||
|
2. Benutzerinteraktion
|
|||
|
|
|||
|
Der Benutzer soll die Oberfl<66>che intuitiv bedienen k<>nnen.
|
|||
|
Fachw<68>rter und technische Details sind zu verbergen, Fehlermeldungen wenn
|
|||
|
m<>glich durch einfache Hinweise zu ersetzen.
|
|||
|
|
|||
|
3. Authentifizierung
|
|||
|
|
|||
|
Der Webserver (hier: Apache) sendet nach dem GET Aufruf des Clients
|
|||
|
einen 401 (Unauthorized) Code und den WWW-Authenticate Header an den Browser. [WL2]
|
|||
|
Dieser Header kann zus<75>tzlich noch einen Text enthalten, wie z.B.
|
|||
|
"Nur f<>r Au<41>endienstler erlaubt".
|
|||
|
|
|||
|
Die Authentifizierung wird dann in einem vom Browser selbstdefinierten
|
|||
|
Authentifizierungsfenster durchgef<65>hrt, das den zus<75>tzlichen Text
|
|||
|
des Serverheaders beinhalten kann, jedoch nicht muss.
|
|||
|
|
|||
|
Das bedeutet das man Serverseitig nur definieren kann, das sich der Client
|
|||
|
authentifizieren muss, jedoch nicht wie dieses Fenster aussieht (im Gegensatz
|
|||
|
zu Javascript basierten Authentifizierungen, die jedoch keine echte Sicherheit bieten).
|
|||
|
|
|||
|
Die Authentifizierung wird Serverseitig durch die htaccess Methodik [WL3]
|
|||
|
definiert. Diese ben<65>tigt die htaccess Einstellungen selbst [WL4] und
|
|||
|
zur Benutzerverwaltung die htpasswd [WL5].
|
|||
|
|
|||
|
Des weiteren m<>ssen die in der htpasswd vorhandenen Benutzer noch in der
|
|||
|
MySOL Benutzerverwaltung angelegt werden. Diese erhalten dort ein
|
|||
|
leeres Passwort vergeben, da die htaccess Authentifizierung ausreichend ist.
|
|||
|
|
|||
|
4. Sicherheit
|
|||
|
|
|||
|
Folgende Sicherheitsanforderungen sind vorhanden:
|
|||
|
|
|||
|
- Datenintegrit<69>t: die Daten m<>ssen gew<65>hrleistet unver<65>nderbar sein
|
|||
|
- Vertraulichkeit: niemand darf unauthorisiertes Daten lesen k<>nnen
|
|||
|
- Verf<72>gbarkeit: die Datenverbindung muss st<73>ndig verf<72>gbar sein
|
|||
|
|
|||
|
Die ersten beiden Anforderungen werden durch das TLS Protokoll [WL5] erf<72>llt.
|
|||
|
|
|||
|
Die Verf<72>gbarkeit des Webinterface im Internet ist abh<62>ngig von der Verf<72>gbarkeit des Web- und MySQL Servers.
|
|||
|
|
|||
|
|
|||
|
5. Einstiegsbildschirm
|
|||
|
|
|||
|
Die Einstiegsseite zeigt den Namen des aktuell angemeldeten Benutzers an.
|
|||
|
Des weiteren befindet sich ein Auswahlfeld, das die Suchoptionen enth<74>lt,
|
|||
|
und des Suchbegrifffeld auf dieser Seite.
|
|||
|
|
|||
|
Dem Benutzer muss eine angemessen Suchfunktion zur Verf<72>gung stehen, die
|
|||
|
das Suchen nach den erforderlichen Parametern erlaubt.
|
|||
|
|
|||
|
Als Suchoptionen m<>ssen die folgenden vorhanden sein:
|
|||
|
|
|||
|
- Kundennummer
|
|||
|
- Kundenname
|
|||
|
- Praxennummer
|
|||
|
- Telefon
|
|||
|
- PLZ
|
|||
|
- Ort
|
|||
|
|
|||
|
|
|||
|
6. Suchergebnisse
|
|||
|
|
|||
|
Auf der Seite der Ergebnisse sollen der Suchbegriff und das Suchkriterium
|
|||
|
als <20>berschrift dargestellt werden.
|
|||
|
|
|||
|
Die Suchergebnisse werden tabellarisch dargestellt, die Ergebnisse sind
|
|||
|
geordnet nach Kundennummern, aufsteigend.
|
|||
|
|
|||
|
Des weiteren muss die M<>glichkeit bestehen die Ergebnisse nach
|
|||
|
den anderen angezeigten Feldern zu sortieren.
|
|||
|
|
|||
|
|
|||
|
7. Suchdetails
|
|||
|
|
|||
|
Diese Seite soll sich an dem Beispiel Excel Dokument [WL6] orientieren.
|
|||
|
Sie muss Details <20>ber den Kunden enhalten, u.a. die Anschrift
|
|||
|
und soweit vorhanden die Telefonnummer.
|
|||
|
|
|||
|
|
|||
|
[WL1]: http://www.wdt.de
|
|||
|
[WL2]: RFC 2616
|
|||
|
[WL3]: http://httpd.apache.org/docs-2.0/howto/auth.html
|
|||
|
[WL4]: Beispiel: siehe Anhang dot-htaccess
|
|||
|
[WL5]: RFC 2246, RFC 3546, Beispiel: htpasswd
|
|||
|
[WL6]: Internes Dokument: Beispiel_Excel.xls
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Weboberfl\"ache/Datenbank: Zugriffsdefiniton}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
Nico Schottelius, v0.2
|
|||
|
Schnittstelle: Webinterface/Datenbank
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
Tabellen und Felder in der Datenbank
|
|||
|
------------------------------------
|
|||
|
|
|||
|
Die Typen der Felder und Tabellen sind in [WED1] dokumentiert.
|
|||
|
Die Namen der Felder und Tabellen sind in [WED2] definiert.
|
|||
|
Der Datenbankname und Datenbankserver sind frei w<>hlbar, muessen
|
|||
|
jedoch in der Konfigurationsdatei [WED3] angegeben werden.
|
|||
|
|
|||
|
|
|||
|
Quellen:
|
|||
|
[WED1]: Siehe Anhang: 2.2.3 Schnittstelle Datenbank/Quelldaten
|
|||
|
[WED2]: Siehe Anhang: Quellcode zu modules/init-db-create.php,
|
|||
|
Funktion create_db, array "$creat_query"
|
|||
|
[WED3]: Siehe Anhang: Quellcode zu includes/db-settings.php
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Datenbank/Quelldaten: Importformatdefiniton}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
Nico Schottelius, v0.6
|
|||
|
Schnittstelle: Quelldaten/Datenbank
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
1. Quelldaten
|
|||
|
2. Zielform
|
|||
|
3. Ziellayout / Typdefinition
|
|||
|
4. Verhalten beim Import
|
|||
|
|
|||
|
1. Quelldaten
|
|||
|
|
|||
|
Die Quelldaten liegen in der Progressdatenbank [QDD1]. Sie m<>ssen mithilfe von
|
|||
|
Progress oder Alternativ ProAlpha [QDD2] ausgelesen werden.
|
|||
|
|
|||
|
2. Zielform
|
|||
|
|
|||
|
Es sollen CSV Tabellen entsprechend der Typdefinition erstellt werden, wobei pro Tabelle eine Datei erstellt wird.
|
|||
|
Der Trenner soll jedoch kein Komma sein, sondern ein Semikolon.
|
|||
|
|
|||
|
Tabellenspalten sind getrennt durch Semikolen, Tabellenzeilen getrennt durch
|
|||
|
Zeilenumbruch, kein Header (wie z.B. ADM Name; ADM Nr) ist vorhanden,
|
|||
|
Reihenfolge wie unten in der Typdefinition.
|
|||
|
|
|||
|
3. Ziellayout / Typdefinition
|
|||
|
|
|||
|
Feldnamen(*) genutzte Feldergroessen
|
|||
|
* = Bemerkung vorhanden
|
|||
|
|
|||
|
0. ADM-Tabelle
|
|||
|
ADM-Nr.* [int]
|
|||
|
ADM-Name. [text 255 stellig]
|
|||
|
|
|||
|
ADM-Nr. ist >=0 und <=999.
|
|||
|
Nummern >=1000 und <=9999 werden fuer adminstrative Zwecke genutzt.
|
|||
|
|
|||
|
1. Kundentabelle
|
|||
|
KundenNr.* [int]
|
|||
|
Prax.Nr.* [int]
|
|||
|
ADM-Nr. [int] [wie oben]
|
|||
|
Name [text 255 stellig]
|
|||
|
Strasse [text 255 stellig]
|
|||
|
Strassennummer [text 255 stellig]
|
|||
|
PLZ [text 255 stellig]
|
|||
|
Ort [text 255 stellig]
|
|||
|
Telefon [text 255 stellig]
|
|||
|
|
|||
|
KundenNr sind 6 stellig
|
|||
|
PraxNr sind 6 stellig
|
|||
|
|
|||
|
2. Umsatztabelle
|
|||
|
KundenNr. [int] [wie oben]
|
|||
|
ArtNr. [int] [wie unten]
|
|||
|
|
|||
|
Umsatz [float]
|
|||
|
Menge [int]
|
|||
|
|
|||
|
Tag [int]
|
|||
|
Monat [int]
|
|||
|
Jahr* [int]
|
|||
|
|
|||
|
Jahr ist vierstellig
|
|||
|
|
|||
|
3. Artikeltabelle
|
|||
|
ArtNr. [int]
|
|||
|
ArtName [text 255 stellig]
|
|||
|
GruppenName [text 255 stellig]
|
|||
|
|
|||
|
|
|||
|
4. Verhalten beim Import
|
|||
|
|
|||
|
Wenn ein Datensatz mit identischen Primary Key vorhanden ist,
|
|||
|
so werden die alten Daten in der Zieldatenbank mit den neuen Werten
|
|||
|
<EFBFBD>berschrieben.
|
|||
|
|
|||
|
|
|||
|
Quellen:
|
|||
|
[QDD1]: http://www.progress.de/, http://www.progress.com/
|
|||
|
[QDD2]: http://www.proalpha.de/
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Test-/Echtsystem}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
Nico Schottelius, v0.2
|
|||
|
Schnittstelle: Test-/Echtsystem
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
1 generelle Anpassungen
|
|||
|
2 Probleme mit anderen PHP oder Apache Versionen oder Konfigurationen
|
|||
|
|
|||
|
|
|||
|
1 generelle Anpassungen
|
|||
|
|
|||
|
Der Datenbankname und Datenbankserver m<>ssen in der Konfiguration
|
|||
|
"includes/db-settings.php" angepasst werden.
|
|||
|
|
|||
|
|
|||
|
2 Probleme mit anderen PHP oder Apache Versionen oder Konfigurationen
|
|||
|
|
|||
|
Der Apache 2.0 bietet bei PHP keine globalen Variablen.
|
|||
|
Der Aufruf von "/script.php?option=test" setzt nur im Apache 1.3.x die Variable
|
|||
|
"option". Im Apache 1.3.x und im Apache 2.0 kann man jedoch <20>ber den Array
|
|||
|
_REQUEST und dem index des Variablennamens (z.B. $_REQUEST['option']) den Inhalt
|
|||
|
auslesen.
|
|||
|
|
|||
|
F<EFBFBD>r das Verzeichnis in dem die Skripte liegen muss in der Apache Config
|
|||
|
"AllowOverride Auth" angeschaltet sein, damit die .htaccess Datei beachtet wird.
|
|||
|
|
|||
|
In der Standard Installation von PHP d<>rfen Dateien beim Upload nicht
|
|||
|
gr<EFBFBD><EFBFBD>er sein als 2MiB.
|
|||
|
Somit muss unter Umst<73>nden die Tabellengr<67><72>e auf 2MiB limitiert werden.
|
|||
|
Dies ist jedoch unproblematisch, da die Aktualisierung der Datenbank
|
|||
|
inkrementell geschehen kann. Somit ist die M<>glichkeit gegeben z.B.
|
|||
|
monatlich, w<>chentlich, oder sogar t<>glich eine Aktualisierung vorzunehmen.
|
|||
|
Je kleiner die Abst<73>nde sind, desto kleiner sind logischerweise auch die Dateien.
|
|||
|
Sollte eine Tabelle gr<67><72>er werden als 2MiB, so kann man sie auch teilen und
|
|||
|
in mehreren Schritten hochladen.
|
|||
|
|
|||
|
Das Limit muss mit dem Provider abgekl<6B>rt werden.
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsection{Quelltext}
|
|||
|
\subsubsection{includes/search.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
|
|||
|
/* definiere die suchbegriffe nach feldern in der DB */
|
|||
|
|
|||
|
/* suche in welcher tabelle, modular ergaenzbar */
|
|||
|
$suchbegriff_tabelle = array(
|
|||
|
"Kundennummer" => "kunden",
|
|||
|
"Kundenname" => "kunden",
|
|||
|
"Praxennummer" => "kunden",
|
|||
|
"Telefon" => "kunden",
|
|||
|
"PLZ" => "kunden",
|
|||
|
"Ort" => "kunden"
|
|||
|
);
|
|||
|
|
|||
|
/* felder in den tabellen */
|
|||
|
$suchbegriff_felder = array(
|
|||
|
"Kundennummer" => "nr",
|
|||
|
"Praxennummer" => "praxisnr",
|
|||
|
"Kundenname" => "name",
|
|||
|
"Telefon" => "telefon",
|
|||
|
"PLZ" => "plz",
|
|||
|
"Ort" => "ort",
|
|||
|
);
|
|||
|
|
|||
|
/* felder in den tabellen */
|
|||
|
$suchbegriff_map_field_eqto_kdnr = array(
|
|||
|
"Kundennummer" => "nr",
|
|||
|
"Praxennummer" => "praxisnr",
|
|||
|
"Kundenname" => "name",
|
|||
|
"Telefon" => "telefon",
|
|||
|
"PLZ" => "plz",
|
|||
|
"Ort" => "ort",
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
Ausgabe: wie in excel
|
|||
|
|
|||
|
PraxenNummer
|
|||
|
Kundennummer
|
|||
|
Kundenname
|
|||
|
PLZ
|
|||
|
Telefon
|
|||
|
Ort
|
|||
|
WDT-Laufendes Jahr
|
|||
|
Differenz Vorjahr
|
|||
|
PRX-Laufendes Jahr
|
|||
|
Differenz Vorjahr
|
|||
|
GRO-Laufendes Jahr
|
|||
|
Differenz Vorjahr
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{includes/db-settings.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
$dbserver = "localhost";
|
|||
|
// $dbserver = "fs1";
|
|||
|
$database = "projekt06";
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{init-database.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* create the initial database
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
$HEADER='
|
|||
|
<HTML>
|
|||
|
<HEAD>
|
|||
|
<TITLE>Initialisieren der Datenbank</title>
|
|||
|
<META NAME="Author" CONTENT="Nico Schottelius <nico-wdt@schottelius.org>">
|
|||
|
</head>
|
|||
|
<body bgcolor="#ffffff" LINK="#133E70" VLINK="#B52243" TEXT="#000000">
|
|||
|
<P><IMG SRC="images/logo-wdt.png" ALT="WDT" HEIGHT="30" WIDTH="150"></P>
|
|||
|
';
|
|||
|
|
|||
|
$FOOTER='
|
|||
|
<P ALIGN=RIGHT><IMG SRC="images/tiere-animiert.gif"></P>
|
|||
|
</BODY>
|
|||
|
</HTML>
|
|||
|
';
|
|||
|
|
|||
|
/* output header */
|
|||
|
echo $HEADER;
|
|||
|
|
|||
|
/* select what todo */
|
|||
|
switch($_REQUEST["option"]) {
|
|||
|
case 1: /* create it */
|
|||
|
include "modules/init-db-create.php";
|
|||
|
create_db($_REQUEST['dbserver'],
|
|||
|
$_REQUEST['database'],
|
|||
|
$_REQUEST['dbuser'],
|
|||
|
$_REQUEST['dbpass']);
|
|||
|
break;
|
|||
|
|
|||
|
default: /* login */
|
|||
|
include "modules/init-db-login.php";
|
|||
|
login($dbserver,$database,$_SERVER["PHP_SELF"]);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
echo $FOOTER;
|
|||
|
|
|||
|
?>
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/init-db-login.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* create the initial database - login
|
|||
|
* v0.4
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
/* default function */
|
|||
|
function login($dbserver,$database,$self)
|
|||
|
{
|
|||
|
|
|||
|
include "includes/db-settings.php";
|
|||
|
|
|||
|
echo "<h3>Erzeugen der initialen Datenbank</h3>\n";
|
|||
|
|
|||
|
/* the upload form */
|
|||
|
echo "<FORM ACTION=\"$self\" METHOD=POST>\n";
|
|||
|
|
|||
|
$dbserver_name="Datenbankserver";
|
|||
|
$dbuser_name="Benutzer";
|
|||
|
$dbpass_name="Passwort";
|
|||
|
$database_name="Name der Datenbank";
|
|||
|
|
|||
|
/* fields */
|
|||
|
echo "<TABLE>\n";
|
|||
|
echo "<TR><TD>$dbserver_name:</TD>"
|
|||
|
. '<TD><INPUT TYPE="text" name="dbserver" value="' . "$dbserver" . '" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$dbuser_name:</TD>"
|
|||
|
. '<TD><INPUT TYPE="text" name="dbuser" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$dbpass_name:</TD>"
|
|||
|
. '<TD><INPUT TYPE="password" name="dbpass" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$database_name:</TD>"
|
|||
|
. '<TD><INPUT TYPE="text" name="database" value="' . "$database" . '" size="30">' . "</TD></TR>\n";
|
|||
|
echo "</TABLE>\n";
|
|||
|
|
|||
|
/* hidden */
|
|||
|
echo '<input type="hidden" name="option" value="1">' . "\n";
|
|||
|
echo '<INPUT TYPE="submit" value="Erstellen">' . "\n";
|
|||
|
echo '</form>' . "\n";
|
|||
|
|
|||
|
}
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/init-db-create.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* create the initial database - do the create
|
|||
|
* v0.3
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
function create_db($server, $database, $user, $pass)
|
|||
|
{
|
|||
|
|
|||
|
echo "<h3>Initialisere die Datenbank '$database' auf $server als $user</h3>";
|
|||
|
|
|||
|
/* open connection */
|
|||
|
$conn = mysql_connect($server,$user,$pass) or
|
|||
|
die("<H3>Verbindung zur Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* choose database */
|
|||
|
|
|||
|
/* initial query */
|
|||
|
$query= "CREATE DATABASE IF NOT EXISTS $database;";
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
echo "<P><B>Datenbank ist angelegt.</B></P>";
|
|||
|
|
|||
|
/* select the new db */
|
|||
|
$db_check = mysql_select_db($database,$conn) or
|
|||
|
die("<H3>Selektion der Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* create tables */
|
|||
|
$create_query = array(
|
|||
|
"CREATE TABLE IF NOT EXISTS adm (
|
|||
|
nr INT PRIMARY KEY,
|
|||
|
name TINYTEXT NOT NULL
|
|||
|
);",
|
|||
|
"CREATE TABLE IF NOT EXISTS kunden (
|
|||
|
nr INT PRIMARY KEY,
|
|||
|
praxisnr INT NOT NULL,
|
|||
|
admnr INT NOT NULL,
|
|||
|
name TINYTEXT NOT NULL,
|
|||
|
strasse TINYTEXT NOT NULL,
|
|||
|
strnr TINYTEXT NOT NULL,
|
|||
|
plz TINYTEXT NOT NULL,
|
|||
|
ort TINYTEXT NOT NULL,
|
|||
|
telefon TINYTEXT NOT NULL
|
|||
|
);",
|
|||
|
"CREATE TABLE IF NOT EXISTS umsatz (
|
|||
|
kundennr INT NOT NULL,
|
|||
|
artikelnr INT NOT NULL,
|
|||
|
umsatz FLOAT,
|
|||
|
menge INT,
|
|||
|
tag INT,
|
|||
|
monat INT,
|
|||
|
jahr INT
|
|||
|
);",
|
|||
|
"CREATE TABLE IF NOT EXISTS artikel (
|
|||
|
nr INT PRIMARY KEY,
|
|||
|
name TINYTEXT NOT NULL,
|
|||
|
gruppe TINYTEXT NOT NULL
|
|||
|
);"
|
|||
|
);
|
|||
|
|
|||
|
foreach($create_query as $query) {
|
|||
|
echo "<P><B>SQL-Kommando:</B> $query ...\n";
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
echo "done</p>";
|
|||
|
}
|
|||
|
|
|||
|
echo "<P><B>Datenbank und die Tabellen sind angelegt.</B></P>";
|
|||
|
}
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{search.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/* Nico Schottelius (c) 2004 *
|
|||
|
* Suchen in der Datenbank *
|
|||
|
* v0.4 */
|
|||
|
|
|||
|
$HEADER='
|
|||
|
<HTML>
|
|||
|
<HEAD>
|
|||
|
<TITLE>WDT Datenbankzugriff</title>
|
|||
|
<META NAME="Author" CONTENT="Nico Schottelius <nico-wdt@schottelius.org>">
|
|||
|
</head>
|
|||
|
<body bgcolor="#ffffff" LINK="#133E70" VLINK="#B52243" TEXT="#000000">
|
|||
|
<P><IMG SRC="images/logo-wdt.png" ALT="WDT" HEIGHT="30" WIDTH="150"></P>
|
|||
|
';
|
|||
|
|
|||
|
$FOOTER='
|
|||
|
<P ALIGN=RIGHt><IMG SRC="images/tiere-animiert.gif"></P>
|
|||
|
</BODY>
|
|||
|
</HTML>
|
|||
|
';
|
|||
|
|
|||
|
|
|||
|
/* database settings */
|
|||
|
$dbuser = $_SERVER["REMOTE_USER"];
|
|||
|
$dbpass = "";
|
|||
|
include "includes/db-settings.php";
|
|||
|
|
|||
|
/* output header */
|
|||
|
echo $HEADER;
|
|||
|
|
|||
|
/* select option */
|
|||
|
switch($_REQUEST['option']) {
|
|||
|
case 1: /* display list of results */
|
|||
|
include "modules/search_results.php";
|
|||
|
search_results($dbserver,$database,$dbuser,$dbpass,$_REQUEST['finde'],$_REQUEST['suchoption'],$_REQUEST['sortby']);
|
|||
|
break;
|
|||
|
|
|||
|
case 2: /* display details */
|
|||
|
include "modules/search_details.php";
|
|||
|
search_details($dbserver,$database,$dbuser,$dbpass,$_REQUEST['kdnr']);
|
|||
|
break;
|
|||
|
|
|||
|
default: /* login */
|
|||
|
include "modules/search_login.php";
|
|||
|
search_login($dbserver,$database,$dbuser,$dbpass,$PHP_SELF);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
echo $FOOTER;
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/search\_results.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/* (c) 2004 Nico Schottelius
|
|||
|
* display search results
|
|||
|
* code: missing sanity checks */
|
|||
|
|
|||
|
function search_results($server, $database, $user, $pass, $begriff, $kriterium, $sortby)
|
|||
|
{
|
|||
|
|
|||
|
include "includes/search.php";
|
|||
|
|
|||
|
/* open connection */
|
|||
|
$conn = mysql_connect($server,$user,$pass) or
|
|||
|
die("<H3>Verbindung zur Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* choose database */
|
|||
|
$db_check = mysql_select_db($database,$conn) or
|
|||
|
die("<H3>Selektion der Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* display name of ADM */
|
|||
|
echo "<h3>Suchergebnisse: (gesucht in \"$kriterium\", nach \"$begriff\")</h3>\n";
|
|||
|
|
|||
|
/* do the query */
|
|||
|
$table = $suchbegriff_tabelle[$kriterium];
|
|||
|
$field = $suchbegriff_felder[$kriterium];
|
|||
|
|
|||
|
/* really sort by */
|
|||
|
$rsortby = $suchbegriff_felder[$sortby];
|
|||
|
|
|||
|
/*****************************************************/
|
|||
|
/* table begin */
|
|||
|
/*****************************************************/
|
|||
|
echo "<TABLE BORDER=1>\n";
|
|||
|
|
|||
|
/* table headers */
|
|||
|
$query="DESCRIBE $table;";
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query1 fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* display header */
|
|||
|
echo "<TR>\n";
|
|||
|
|
|||
|
/* create links to sort */
|
|||
|
while ($row = mysql_fetch_array($resultcode) ) {
|
|||
|
echo "<TH><A HREF=\"$self?option=1&suchoption=$kriterium&finde=$begriff&sortby=$row[0]\">$row[0]</A></TH>\n";
|
|||
|
}
|
|||
|
echo "</TR>\n";
|
|||
|
|
|||
|
/* construct the query */
|
|||
|
$query_begin="SELECT * FROM `$table` ";
|
|||
|
$query_end=" admnr = '$user' ORDER BY ";
|
|||
|
|
|||
|
$query = $query_begin;
|
|||
|
|
|||
|
/* sort */
|
|||
|
if($sortby != "") $query_end .= " '$sortby'; ";
|
|||
|
else $query_end .= " 'nr'; ";
|
|||
|
|
|||
|
/* search string */
|
|||
|
if($begriff == "") $query .= " WHERE ";
|
|||
|
else $query .= " WHERE $field LIKE " . "'$begriff" . "%'" .
|
|||
|
" AND ";
|
|||
|
|
|||
|
/* complete the search */
|
|||
|
$query .= $query_end;
|
|||
|
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* count if we got results */
|
|||
|
$count=0;
|
|||
|
|
|||
|
/* get number of fields */
|
|||
|
$size=mysql_num_fields ($resultcode);
|
|||
|
|
|||
|
/* print all entries */
|
|||
|
while ($row = mysql_fetch_array($resultcode) ) {
|
|||
|
$count++;
|
|||
|
|
|||
|
echo "<TR>\n";
|
|||
|
|
|||
|
for($i=0;$i<$size;$i++) {
|
|||
|
if($i == 0) {
|
|||
|
$TD="<TD><A HREF=\"$PHP_SELF?option=2&kdnr=$row[$i]\">$row[$i]</A></TD>\n";
|
|||
|
} else {
|
|||
|
$TD="<TD>$row[$i]</TD>\n";
|
|||
|
}
|
|||
|
echo "$TD";
|
|||
|
}
|
|||
|
echo "</TR>\n";
|
|||
|
}
|
|||
|
echo "</TABLE>\n";
|
|||
|
|
|||
|
/* sanity check */
|
|||
|
if(!$count) {
|
|||
|
echo "<p><B>Keine Ergebnisse gefunden.</B></p>\n";
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/seach\_details.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* (c) 2004 Nico Schottelius
|
|||
|
* display customer details
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
function search_details($server, $database, $user, $pass, $nr)
|
|||
|
{
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* includes */
|
|||
|
/****************************************************************/
|
|||
|
include "includes/search.php";
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* get times */
|
|||
|
/****************************************************************/
|
|||
|
$date_info = getdate();
|
|||
|
$this_year = $date_info['year'];
|
|||
|
$last_year = $this_year -1;
|
|||
|
$oldest_year = $last_year -1;
|
|||
|
$this_month = $date_info['mon'];
|
|||
|
$this_day = $date_info['mday'];
|
|||
|
$all_years = array("$oldest_year",
|
|||
|
"$last_year",
|
|||
|
"$this_year");
|
|||
|
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* sanity checks for variables FIXME! */
|
|||
|
/****************************************************************/
|
|||
|
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* start database connection */
|
|||
|
/****************************************************************/
|
|||
|
|
|||
|
/* open connection */
|
|||
|
$conn = mysql_connect($server,$user,$pass) or
|
|||
|
die("<H3>Verbindung zur Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* choose database */
|
|||
|
$db_check = mysql_select_db($database,$conn) or
|
|||
|
die("<H3>Selektion der Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
echo "<h3>Details für Kunde $nr</h3>\n";
|
|||
|
|
|||
|
/******************************************************/
|
|||
|
/* table begin / headers */
|
|||
|
/******************************************************/
|
|||
|
$TABLE_BEGIN="<TABLE BORDER=0>\n";
|
|||
|
$TABLE_END="</TABLE>\n";
|
|||
|
|
|||
|
echo $TABLE_BEGIN;
|
|||
|
|
|||
|
$query= "SELECT praxisnr , name , strasse , strnr ," .
|
|||
|
"plz , ort , telefon FROM kunden WHERE nr = $nr " .
|
|||
|
"AND admnr = $user;";
|
|||
|
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
$row = mysql_fetch_array($resultcode);
|
|||
|
$size = mysql_num_fields ($resultcode);
|
|||
|
|
|||
|
echo "<TR><TH ALIGN=LEFT>".$row['name']."</TH></TR>";
|
|||
|
echo "<TR><TH ALIGN=LEFT>".$row['strasse']. " " . $row['strnr'] . "</TR>";
|
|||
|
echo "<TR><TH ALIGN=LEFT>".$row['plz']. " " . $row['ort'] . "</TR>";
|
|||
|
echo "<TR><TH ALIGN=LEFT>".$row['telefon']."</TH></TR>";
|
|||
|
echo "<TR><TH ALIGN=LEFT>".$nr ."</TH></TR>";
|
|||
|
|
|||
|
echo $TABLE_END;
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* last 3 months FIXME */
|
|||
|
/****************************************************************/
|
|||
|
echo $TABLE_BEGIN;
|
|||
|
|
|||
|
$last_month = $this_month-1;
|
|||
|
$before_last_month = $last_month-1;
|
|||
|
|
|||
|
/* get data like in .xls */
|
|||
|
$query= "SELECT umsatz FROM umsatz WHERE " .
|
|||
|
"kundennr = $nr " . /* Kunde */
|
|||
|
"AND jahr = $this_year " . /* Jahr */
|
|||
|
"AND monat = ($this_month OR $last_month OR $before_last_month);" ; /* Monat */
|
|||
|
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
$row = mysql_fetch_array($resultcode);
|
|||
|
$size = mysql_num_fields ($resultcode);
|
|||
|
|
|||
|
echo "<TR><TD>A: $row[0]</td></tr>";
|
|||
|
echo "<TR><TD>B: $query</td></tr>";
|
|||
|
echo "<TR><TD>C: $row[1] :: $row[2]</td></tr>";
|
|||
|
|
|||
|
echo $TABLE_END;
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* kummultative results */
|
|||
|
/****************************************************************/
|
|||
|
echo $TABLE_BEGIN;
|
|||
|
|
|||
|
/* get data like in .xls */
|
|||
|
$query= "SELECT praxisnr , name , strasse , strnr ," .
|
|||
|
"plz , ort , telefon FROM kunden WHERE nr = $nr " .
|
|||
|
"AND admnr = $user;";
|
|||
|
|
|||
|
echo $TABLE_END;
|
|||
|
|
|||
|
/****************************************************************/
|
|||
|
/* display all articles (details) */
|
|||
|
/****************************************************************/
|
|||
|
|
|||
|
echo $TABLE_BEGIN;
|
|||
|
|
|||
|
/* get all articles from this customer */
|
|||
|
/*
|
|||
|
$query= "SELECT artikelnr FROM umsatz WHERE kundennr = $nr " .
|
|||
|
"GROUP BY artikelnr;";
|
|||
|
*/
|
|||
|
$query= "SELECT umsatz.artikelnr FROM umsatz,kunden WHERE " .
|
|||
|
"umsatz.kundennr = $nr AND umsatz.kundennr = kunden.nr " .
|
|||
|
"AND kunden.admnr = $user " .
|
|||
|
"GROUP BY artikelnr;";
|
|||
|
|
|||
|
$rs_all_artikel = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* display table header */
|
|||
|
echo "<TR><TD> </td></tr>\n";
|
|||
|
echo "<TR>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Artikelnummer</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Umsatz $oldest_year</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Menge $oldest_year</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Umsatz $last_year</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Menge $last_year</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Umsatz $this_year</TH>\n";
|
|||
|
echo "\t<TH ALIGN=LEFT>Menge $this_year</TH>\n";
|
|||
|
echo "</TR>\n";
|
|||
|
|
|||
|
/* count columns */
|
|||
|
$count=0;
|
|||
|
|
|||
|
/* go through all articles */
|
|||
|
while ($row = mysql_fetch_array($rs_all_artikel) ) {
|
|||
|
$count++;
|
|||
|
$artikelnr="$row[0]";
|
|||
|
echo "<TR>\n";
|
|||
|
echo "<TD>$artikelnr</TD>\n";
|
|||
|
|
|||
|
/* go through all years */
|
|||
|
foreach($all_years as $work_year) {
|
|||
|
$query =
|
|||
|
"SELECT SUM(umsatz.umsatz) , SUM(umsatz.menge) " .
|
|||
|
"FROM umsatz WHERE umsatz.kundennr = $nr AND " .
|
|||
|
"umsatz.artikelnr = $artikelnr AND umsatz.jahr = $work_year;";
|
|||
|
|
|||
|
$rs_cur_artikel = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
$cur_umsatz_menge = mysql_fetch_array($rs_cur_artikel);
|
|||
|
$cur_umsatz=$cur_umsatz_menge[0];
|
|||
|
$cur_menge=$cur_umsatz_menge[1];
|
|||
|
|
|||
|
/* select 0 if nothing was found */
|
|||
|
if($cur_umsatz == "") {
|
|||
|
echo "\t<TD>0</TD>\n";
|
|||
|
} else {
|
|||
|
echo "\t<TD>" . $cur_umsatz . "</TD>\n";
|
|||
|
}
|
|||
|
|
|||
|
/* same here */
|
|||
|
if($cur_menge == "") {
|
|||
|
echo "\t<TD>0</TD>\n";
|
|||
|
} else {
|
|||
|
echo "\t<TD>" . $cur_menge . "</TD>\n";
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
echo "</TR>\n";
|
|||
|
}
|
|||
|
|
|||
|
echo $TABLE_END;
|
|||
|
|
|||
|
/* sanity check if there were no articles bought*/
|
|||
|
if(!$count) {
|
|||
|
echo "<p><B>Keine Ergebnisse gefunden.</B></p>\n";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{upload.php}
|
|||
|
\label{upload.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* Update der Datenbank
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
$HEADER='
|
|||
|
<HTML>
|
|||
|
<HEAD>
|
|||
|
<TITLE>Update der Datenbank</title>
|
|||
|
<META NAME="Author" CONTENT="Nico Schottelius <nico-wdt@schottelius.org>">
|
|||
|
</head>
|
|||
|
<body bgcolor="#ffffff" LINK="#133E70" VLINK="#B52243" TEXT="#000000">
|
|||
|
<P><IMG SRC="images/logo-wdt.png" ALT="WDT" HEIGHT="30" WIDTH="150"></P>
|
|||
|
';
|
|||
|
|
|||
|
$FOOTER='
|
|||
|
<P ALIGN=RIGHt><IMG SRC="images/tiere-animiert.gif"></P>
|
|||
|
</BODY>
|
|||
|
</HTML>
|
|||
|
';
|
|||
|
|
|||
|
|
|||
|
/* DB settings */
|
|||
|
include "includes/db-settings.php";
|
|||
|
|
|||
|
/* database settings */
|
|||
|
$dbuser = $_SERVER["REMOTE_USER"];
|
|||
|
$dbpass = "";
|
|||
|
|
|||
|
/* output header */
|
|||
|
echo $HEADER;
|
|||
|
|
|||
|
/* select option */
|
|||
|
switch($_REQUEST["option"]) {
|
|||
|
case 1: /* do the update */
|
|||
|
$filenames=array( 'adm' => $_FILES['tabelle_adm'],
|
|||
|
'kunden' => $_FILES['tabelle_kunden'],
|
|||
|
'umsatz' => $_FILES['tabelle_umsatz'],
|
|||
|
'artikel' => $_FILES['tabelle_artikel']
|
|||
|
);
|
|||
|
include "modules/upload-it.php";
|
|||
|
update_it($dbserver,$database,$dbuser,$dbpass,$filenames);
|
|||
|
break;
|
|||
|
|
|||
|
default: /* login */
|
|||
|
include "modules/upload-login.php";
|
|||
|
login($dbserver,$database,$dbuser,$dbpass,$PHP_SELF);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
echo $FOOTER;
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/upload-login.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* create the initial database - do the create
|
|||
|
* v0.5
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
/* default function */
|
|||
|
function login($dbserver, $database, $dbuser, $pass, $self)
|
|||
|
{
|
|||
|
|
|||
|
$adm_tab = "ADM Tabelle";
|
|||
|
$kunden_tab = "Kunden Tabelle";
|
|||
|
$umsatz_tab = "Umsatz Tabelle";
|
|||
|
$artikel_tab = "Artikel Tabelle";
|
|||
|
|
|||
|
/* 120 MB */
|
|||
|
$max_tab_size = 120 * 1024 * 1024;
|
|||
|
|
|||
|
echo "<H3>Update der Datenbank...</h3>\n";
|
|||
|
|
|||
|
/* the upload form */
|
|||
|
echo "<FORM enctype=\"multipart/form-data\" ACTION=\"$self\" METHOD=POST>\n";
|
|||
|
|
|||
|
/* fields */
|
|||
|
echo "<TABLE>\n";
|
|||
|
echo "<TR><TD>$adm_tab:</TD>"
|
|||
|
. '<TD><INPUT TYPE="file" name="tabelle_adm" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$kunden_tab:</TD>"
|
|||
|
. '<TD><INPUT TYPE="file" name="tabelle_kunden" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$umsatz_tab:</TD>"
|
|||
|
. '<TD><INPUT TYPE="file" name="tabelle_umsatz" size="30">' . "</TD></TR>\n";
|
|||
|
echo "<TR><TD>$artikel_tab:</TD>"
|
|||
|
. '<TD><INPUT TYPE="file" name="tabelle_artikel" size="30">' . "</TD></TR>\n";
|
|||
|
echo "</TABLE>\n";
|
|||
|
|
|||
|
/* hidden */
|
|||
|
echo '<input type="hidden" name="MAX_FILE_SIZE" value="' . "$max_tab_size\">\n";
|
|||
|
echo '<input type="hidden" name="option" value="1">' . "\n";
|
|||
|
echo '<INPUT TYPE="submit" value="Update!">' . "\n";
|
|||
|
echo '<INPUT TYPE="reset" value="Zurücksetzen">' . "\n";
|
|||
|
echo '</form>' . "\n";
|
|||
|
|
|||
|
}
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsubsection{modules/upload-it.php}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
<?php
|
|||
|
/*******************************************************************
|
|||
|
* Nico Schottelius (c) 2004
|
|||
|
* Update der Datenbank
|
|||
|
* v0.3
|
|||
|
*******************************************************************/
|
|||
|
|
|||
|
function update_it($dbserver, $database, $dbuser, $pass, $filenames)
|
|||
|
{
|
|||
|
|
|||
|
/* open connection */
|
|||
|
$conn = mysql_connect($dbserver,$dbuser,$pass) or
|
|||
|
die("<H3>Verbindung zur Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
/* choose database */
|
|||
|
$db_check = mysql_select_db($database,$conn) or
|
|||
|
die("<H3>Selektion der Datenbank fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
|
|||
|
$i=0;
|
|||
|
foreach($filenames as $tablename => $tableinfo) {
|
|||
|
|
|||
|
/* debug */
|
|||
|
// echo "<P>table: $tablename\n";
|
|||
|
// echo "<BR>tableinfo: $tableinfo</P>\n";
|
|||
|
|
|||
|
|
|||
|
$wert = $tableinfo["tmp_name"];
|
|||
|
$filename = $tableinfo["name"];
|
|||
|
|
|||
|
/* check if this table should get updated */
|
|||
|
if($wert != "none" and $wert != "") {
|
|||
|
|
|||
|
echo "<P><B>Update die Tabelle '$tablename' " .
|
|||
|
"aus Datei $filename ...</B>\n";
|
|||
|
|
|||
|
/* reset query */
|
|||
|
$query = "";
|
|||
|
|
|||
|
/* basic query array */
|
|||
|
$sql = array ('LOAD DATA LOCAL INFILE', " '$wert'", ' REPLACE INTO TABLE ',
|
|||
|
" `$tablename` ", 'FIELDS TERMINATED BY \';\' ENCLOSED BY \'"\' ESCAPED BY \'\\\\\' LINES TERMINATED BY \'\\n\';');
|
|||
|
|
|||
|
/* construct query */
|
|||
|
foreach($sql as $partofquery) {
|
|||
|
$query .= $partofquery;
|
|||
|
}
|
|||
|
|
|||
|
/* query() */
|
|||
|
echo "<P>$query </P>";
|
|||
|
$resultcode = mysql_query($query,$conn) or
|
|||
|
die("<H3>Query fehlgeschlagen: ". mysql_error() ."</h3>");
|
|||
|
echo "<B>done</B><br>\n";
|
|||
|
$i++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* result display */
|
|||
|
echo "<p>$i Tabelle(n) verarbeitet.</p>\n";
|
|||
|
}
|
|||
|
|
|||
|
?>
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsection{Testtabellen}
|
|||
|
Diese Tabellen wurden zum Testen benutzt, w\"ahrend noch keine Echtdaten
|
|||
|
verf\"ugbar waren. Sie werden von upload.php verarbeitet (siehe Seite
|
|||
|
\pageref{upload.php}).
|
|||
|
\subsubsection{Aussendienstmitarbeiter ("`adm.test"')}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
120; Heinz Martin
|
|||
|
140; Mutter Albert
|
|||
|
150; Kruenling
|
|||
|
1000; Der Admin
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Artikel ("`artikel.test"')}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
12345; Elefantenpritze; wdt
|
|||
|
12346; Elefantenbesteck; wdt
|
|||
|
12347; Kaenguruhnapf; prx
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Kunden ("`kunden.test"')}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
019066; 201749; 120;prakt. Tier<65>rztin aus Test;Testwegrein;23;22527;Hamburg;01234/4555
|
|||
|
010646; 201749; 120;prakt. Tieraerztin2 aus Test3;Testwegrein;23;22527;Hamburg;01234/4555
|
|||
|
019067; 019066; 140; Tierliebhaber Burgberg; veilenweg; 42; 30456; Hannover; 00123/123
|
|||
|
019068; 019069; 150; Tierer Bargberg;blumenstarre;235;33334; Testhause; 0042455/5533
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Umsatz ("`umsatz.test"')}
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
019066;12345;120,00;12; 01; 07; 2004
|
|||
|
019066;12346;120,00;12; 02; 06; 2004
|
|||
|
019066;12347;120,00;12; 03; 05; 2004
|
|||
|
019066;12347;150,00;12; 19; 04; 2003
|
|||
|
019066;12347;140,00;12; 19; 03; 2003
|
|||
|
019066;12346;110,00;12; 19; 02; 2002
|
|||
|
019066;12345;100,00;12; 10; 01; 2002
|
|||
|
019066;12346;150,00;12; 12; 01; 2004
|
|||
|
019067;12347;160,00;12; 12; 01; 2004
|
|||
|
019068;12346;160,00;12; 22; 01; 2004
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
|
|||
|
\subsection{Konfigurationsdateien}
|
|||
|
\subsubsection{Apache: .htaccess (oder "`dot-htaccess"')}
|
|||
|
.htaccess ist die Standardmethode f\"ur Authentfizierung beim Apache Webserver.
|
|||
|
In der gleichnamigen Datei wird definiert,
|
|||
|
um was f\"ur eine Art Authentifizierung es sich handelt ("`AuthType"'),
|
|||
|
welcher Text optional angezeigt wird beim Darstellen der Passwortbox
|
|||
|
("`AuthName"'),
|
|||
|
woraus die Authentifizierungsinformationen gelesen werden ("`AuthUserFile"') und
|
|||
|
welche Bedingung erf\"ullt sein muss ("`Require"').
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
AuthType Basic
|
|||
|
AuthName "Willkommen zum WDT Aussendienstler Programm"
|
|||
|
AuthUserFile /home/user/nico/www/projekt/source/testpasswd
|
|||
|
Require valid-user
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{Apache: htpasswd}
|
|||
|
In der htpasswd werden die Passw\"orter f\"ur die Authentifizierung \"uber das
|
|||
|
Webinterface definiert.
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
120:8ZnzPTAQ5IJkM
|
|||
|
9999:$apr1$/9xFh...$/Qy28iJzLaPWfhFWwsy1C/
|
|||
|
1000:$apr1$shOFt...$xoRiz8F4lClo2hv/MGi7n.
|
|||
|
|
|||
|
\end{verbatim}
|
|||
|
\subsubsection{PHP: Auszug php.ini}
|
|||
|
Im Gegensatz zur normalen Konfiguration ist hier die maximale Dateigr\"o\ss{}e 120MB
|
|||
|
erh\"oht. Es ist der \textit{Manpage} nicht zu entnehmen, ob MB hier MiB
|
|||
|
entspricht oder der Faktor 1000 als Basis genommen wurde.
|
|||
|
\begin{verbatim}
|
|||
|
|
|||
|
;;;;;;;;;;;;;;;;;;;
|
|||
|
; Resource Limits ;
|
|||
|
;;;;;;;;;;;;;;;;;;;
|
|||
|
|
|||
|
max_execution_time = 30 ; Maximum execution time of each script, in seconds
|
|||
|
max_input_time = 60 ; Maximum amount of time each script may spend parsing request data
|
|||
|
memory_limit = 128M ; Maximum amount of memory a script may consume (8MB)
|
|||
|
;;memory_limit = 8M ; Maximum amount of memory a script may consume (8MB)
|
|||
|
|
|||
|
; Maximum size of POST data that PHP will accept.
|
|||
|
;;post_max_size = 8M
|
|||
|
post_max_size = 120M
|
|||
|
|
|||
|
;;;;;;;;;;;;;;;;
|
|||
|
; File Uploads ;
|
|||
|
;;;;;;;;;;;;;;;;
|
|||
|
|
|||
|
; Whether to allow HTTP file uploads.
|
|||
|
file_uploads = On
|
|||
|
|
|||
|
; Temporary directory for HTTP uploaded files (will use system default if not
|
|||
|
; specified).
|
|||
|
;upload_tmp_dir =
|
|||
|
|
|||
|
; Maximum allowed size for uploaded files.
|
|||
|
;;upload_max_filesize = 2M
|
|||
|
upload_max_filesize = 120M
|
|||
|
\end{verbatim}
|
|||
|
\end{document}
|