Missionare müssen Indianisch lernen –
mit Lateinisch bekehrt man keine Indianer.
– Kurt Tucholsky
13 Server für Webanwendungen
Bereits in Kapitel 6, »Windows«, 7, »Linux« und 8, »Mac OS X«, haben Sie einige Netzwerk-Serverdienste kennengelernt. Dort ging es um Datei- und Druckserver, die vornehmlich im lokalen Netzwerk von Firmen und Organisationen eingesetzt werden. In diesem und dem nächsten Kapitel werden dagegen Internetserver behandelt, die für den systemunabhängigen Fernzugriff durch viele, oft anonyme Benutzer konzipiert wurden, aber auch oft im lokalen Intranet eingesetzt werden.
Im vorliegenden Kapitel erfahren Sie, wie Sie eine Infrastruktur für datenbankgetriebene PHP-Webanwendungen einrichten – ein LAMP- oder WAMP-System aus Linux beziehungsweise Windows, Apache, MySQL und PHP.[51] Die Entwicklung der zugehörigen Anwendungen wird in Kapitel 18, »Webserveranwendungen«, beschrieben.
13.1 HTTP im Überblick

Wie bereits erwähnt, kommunizieren Webserver und Browser über das TCP/IP-Anwendungsprotokoll HTTP (Hypertext Transfer Protocol). Wie die meisten Internetprotokolle der Anwendungsebene ist es klartextbasiert und besteht aus einigen Clientbefehlen sowie Serverantworten in einem bestimmten Format. Es handelt sich also um ein Request-Response-Verfahren (Anfrage und Antwort).
13.1.1 Ablauf der HTTP-Kommunikation

Die HTTP-Kommunikation läuft von der Dokumentanforderung durch den Browser bis zur Darstellung oder Speicherung des empfangenen Dokuments wie folgt ab:
- Der Browser zerlegt die URL in Schema, Hostname, gegebenenfalls Portnummer und Ressourcenteil (Pfad). Er ermittelt per DNS die IP-Adresse zum Hostnamen und stellt eine TCP-Verbindung zu ihr her. Falls keine Portnummer angegeben wurde, wird je nach Schema 80 (http:) oder 443 (https:, das heißt HTTP über eine gesicherte Verbindung) gewählt. Bei der URL http://buecher.lingoworld.de/fachinfo/index.html ist das Schema beispielsweise http:, woraus sich Port 80 ergibt; der Hostname ist buecher.lingoworld.de und der Pfad /fachinfo/index.html.
- Über die TCP-Verbindung sendet der Browser eine HTTP-Anfrage. Die erste Zeile besteht
aus HTTP-Methode, Pfad und Protokollversion. Wenn Sie eine URL in den Browser eintippen,
ist die Methode immer GET; das bedeutet, dass eine Ressource geliefert werden soll. Eine andere wichtige Methode
ist POST; sie wird zum Versenden umfangreicherer Formulardaten oder gar für Datei-Uploads
aus dem Browser verwendet. Tabelle 13.1 zeigt eine Übersicht über die verfügbaren Methoden.
Tabelle 13.1 Alle HTTP-Methoden im Überblick
HTTP-Methode seit HTTP-Version Bedeutung GET 0.9 Dokument anfordern HEAD 1.0 nur Header anfordern POST 1.0 Formulardaten oder Dateien senden PUT 1.0 Datei auf dem Server speichern DELETE 1.0 Datei vom Server löschen LINK 1.0 Verknüpfung erzeugen UNLINK 1.0 Verknüpfung löschen TRACE 1.1 Proxys anzeigen CONNECT 1.1 Proxy-Zugriff auf gesicherte Server OPTIONS 1.1 Liste verfügbarer Optionen anfordern - Der Server empfängt die Clientanfrage und reagiert darauf. Bei einer GET-Anfrage liefert er in den meisten Fällen einfach die angeforderte Datei aus. Falls es sich dagegen um ein serverseitiges Skript oder Programm im Rahmen einer Webanwendung handelt, wird dieses zunächst vom zuständigen Servermodul oder externen Interpreter ausgeführt, anschließend wird seine Ausgabe (meist ein HTML-Dokument, manchmal auch ein anderer Dateityp wie etwa ein dynamisch generiertes Bild) als Antwort an den Browser geschickt.
Im vorliegenden Beispielfall lautet die Startzeile der Anfrage:
GET /fachinfo/index.html HTTP/1.1
Auf diese Anforderung folgen mehrere Header-Zeilen im Format »Headername: Wert«. Bei HTTP/1.1-Anfragen muss stets der Header Host gesendet werden, da unter derselben IP-Adresse mehrere virtuelle Hosts betrieben werden können; andere Anfrage-Header sind freiwillig.
Auch die Serverantwort besitzt einen Header-Bereich. Die erste Zeile besteht aus der Protokollversion sowie einer Statusinformation aus Codenummer und standardisiertem Text. Falls das angeforderte Dokument geliefert werden kann, lautet diese Zeile:
HTTP/1.1 200 OK
Ein weiterer häufiger Statuscode ist 404 Not Found; er besagt, dass die angeforderte Ressource nicht gefunden wurde. Nach der Statuszeile folgen diverse Antwort-Header. Der wichtigste ist Content-Type; er gibt den MIME-Type des mitgelieferten Dokuments an. Eine Leerzeile trennt die Header vom Body, der die eigentliche Ressource enthält.[52]
Zum Schluss nimmt der Browser den Body der Serverantwort entgegen und zeigt ihn je nach Datentyp selbst an (zum Beispiel HTML-Dokumente und bestimmte Bild- oder Multimediadateien) oder bietet ihn zum Speichern auf Datenträger an. Außerdem speichert er viele gelieferte Dokumente in seinem Cache, damit zuvor angeforderte Dateien nicht nochmals heruntergeladen werden müssen.
Hier ein Beispiel für eine komplette GET-Anfrage:
GET /fachinfo/index.html HTTP/1.1
Accept: */*
Accept-Language: de, en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1;
i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2)
Host: buecher.lingoworld.de
Connection: Keep-Alive
Die Header dieser Anfrage haben folgende Bedeutung:
- Accept: */*
Jeder beliebige MIME-Type (Typ/Untertyp) wird akzeptiert. Das heißt lediglich, dass der Browser keinen bestimmten Datentyp bevorzugt, aber nicht, dass er auch jeden verarbeiten könnte. - Accept-Language: de, en-US
Wenn der Server mehrere Sprachvarianten einer Ressource zur Wahl stellt, bevorzugt dieser Browser Deutsch und US-Englisch in der angegebenen Reihenfolge. - Accept-Encoding: gzip, deflate
Der Browser ist in der Lage, GNU-zip- oder ZIP-komprimierte Ressourcen anzunehmen und selbst zu entpacken; wenn ein Server dies unterstützt, spart es Netzwerkbandbreite. - User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1;
i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2)
Dies ist die Angabe der Browserversion, die der Server zum Umgang mit Inkompatibilitäten auswerten kann sowie zu statistischen Zwecken in seine Log-Dateien schreibt. Hierbei handelt es sich um den Microsoft Internet Explorer 7.0 unter Windows XP.[53] - Host: buecher.lingoworld.de
Wie bereits erwähnt, ist dies ein Pflicht-Header, der bestimmt, welcher virtuelle Host angesprochen wurde. - Connection: Keep-Alive
Der Browser fordert an, dass der Server die TCP-Verbindung nach dem Versand der aktuellen Antwort offenhalten soll. Dies beschleunigt den Seitenaufbau, weil beispielsweise für jedes eingebettete Bild eine weitere Anfrage erforderlich ist, die über eine bereits geöffnete Verbindung schneller bearbeitet werden kann.
Bei einer erfolgreichen Anfrage könnte die Serverantwort beispielsweise so aussehen:
HTTP/1.1 200 OKDate: Sat, 16 Apr 2011 12:18:57 GMT
Server: Apache/2.2.9 (Unix)
Last-Modified: Wed 22 Sep 2010 10:21:37 GMT
ETag: "1b380f2-1ba9-454723b1"
Accept-Ranges: bytes
Content-Length: 7081
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML
4.0//Transitional//EN">
<html>
<head>
[...]
Hier die Bedeutung der Antwort-Header:
- Date: Sat, 16 Apr 2011 12:18:57 GMT
Datum und Uhrzeit des Servers - Server: Apache/2.2.9 (Unix)
Versionsinformationen des Servers; die Ausführlichkeit kann mit Hilfe der weiter unten vorgestellten Direktive ServerTokens geändert werden. - Last-Modified: Wen, 16 Sep 2010 10:21:37 GMT
Datum und Uhrzeit der letzten Änderung; wird vom Browser verwendet, um – zum Beispiel per HEAD-Anfrage – zu entscheiden, ob eine eventuell noch im Cache befindliche Version aktuell ist. - ETag: "1b380f2–1ba9–454723b1"
Ein Hash-Wert aus Metadaten wie Änderungsdatum und Dateigröße, der Aufschluss über die Identität einer Ressource gibt und so ebenfalls für Cache-Entscheidungen verwendet werden kann - Accept-Ranges: bytes
Der Server kann auf Wunsch Teile eines Dokuments ausliefern, wenn der Browser in einem Range-Header die gewünschten Byte-Grenzen mitteilt – dies ist etwa praktisch, um abgebrochene Downloads später fortzusetzen. - Content-Length: 7081
Länge des gelieferten Bodys in Byte - Connection: keep-alive
Der Server bestätigt die Bitte des Browsers, die Verbindung offenzuhalten. - Content-Type: text/html
Der bereits erwähnte MIME-Type des Bodys, der wichtigste Antwort-Header. Im vorliegenden Beispiel handelt es sich um den Haupttyp Text und den Untertyp HTML.
13.1.2 HTTP-Statuscodes

Es wurde bereits erwähnt, dass jede HTTP-Antwort eine Statusmeldung enthält, bestehend aus Codenummer und Beschreibungstext. Die Codes werden anhand ihrer ersten Ziffer in folgende Gruppen unterteilt:
- 1xx – Information
- 2xx – Erfolgsmeldungen
- 3xx – Umleitungsmeldungen
- 4xx – Clientfehler
- 5xx – Serverfehler
Zur ersten Gruppe, den informativen Meldungen, gehören nur zwei Statuscodes: 100 Continue besagt, dass der Server eine vorbereitende Anfrage erhalten hat und auf eine Fortsetzung wartet. 101 Switching Protocols gibt an, dass der Server auf die im Header Upgrade angegebene HTTP-Version wechseln möchte. Beides kommt relativ selten vor.
Statuscodes, die mit 2 beginnen, zeigen eine erfolgreiche Verarbeitung der Anfrage an. Die häufigste dieser Antworten ist 200 OK; sie wird bei fast allen erfolgreichen GET-, HEAD-, POST- und DELETE-Anfragen zurückgeliefert.
3xx-Statuscodes sind für Weiterleitungen zuständig. Diese werden unter anderem verwendet, wenn ein serverseitiges Skript zwar Formulardaten verarbeitet, aber keine eigene Ausgabe erzeugt. In diesem Fall kann es einen Location-Header mit einer Weiterleitungs-URL senden, zusammen mit einem der Statuscodes 301 Moved Permanently, 302 Found, 303 See Other oder 307 Temporary Redirect. Der Status 304 Not Modified dient dagegen als Antwort auf HEAD-Anfragen, die es dem Browser erlaubt, ein Dokument aus seinem Cache anzuzeigen.
4xx-Statuscodes zeigen verschiedene Fehlerzustände an, die aufgrund einer fehlerhaften oder unvollständigen Clientanfrage zustande gekommen sind. Der häufigste Header dieser Gruppe ist sicherlich 404 Not Found; er kommt sowohl bei Tippfehlern im Ressourcenteil einer eingegebenen URL als auch bei fehlerhaften oder veralteten Links vor. 401 Unauthorized wird gesendet, wenn der Server eine Benutzeranmeldung erwartet; dies wird im Abschnitt »Konfigurationsbeispiele« ab Seite 755 erläutert. Bei 403 Forbidden ist der Zugriff dagegen grundsätzlich verboten; auch eine Authentifizierung würde nichts daran ändern.
5xx-Statuscodes schließlich bezeichnen Fehler, die aufgrund eines serverseitigen Problems entstanden sind. Der häufigste dieser Fehler, 500 Internal Server Error, kommt unter anderem oft vor, wenn Sie bei der Programmierung eigener Webanwendungen Fehler machen. Einzelheiten über den Fehler stehen in diesem Fall in der Error-Log-Datei Ihres Webservers (siehe unten).
In Tabelle 13.2 sehen Sie noch einmal alle Statuscodes im Überblick.
| Statuscode | übliche Meldung | Beschreibung |
| 100 | Continue | Anfrage erhalten; der Server erwartet Fortsetzung. |
| 101 | Switching Protocol | Der Server möchte auf die angegebene Protokollversion wechseln. |
| 200 | OK | Die Anfrage war erfolgreich; die angeforderte Ressource wird geliefert. |
| 201 | Created | PUT-Anfrage zur Speicherung einer Datei auf dem Server war erfolgreich. |
| 202 | Accepted | Die Anfrage wurde erfolgreich verarbeitet. |
| 203 | Non-Authoritative | Die gelieferten Informationen stammen von einem Proxy; ihre Gültigkeit wurde nicht verifiziert. |
| 204 | No Content | Anfrage OK; die Antwort enthält keinen Body. |
| 205 | Reset Content | Der Client soll ein Formular zurücksetzen. |
| 206 | Partial Content | Anfrage enthält nur einen Teil der Ressource; der Header Content-Range gibt den Bereich an. |
| 300 | Multiple Choices | Es sind mehrere Ressourcen der gewünschten Ressource verfügbar; der Body enthält eine Liste mit entsprechenden Links. |
| 301 | Moved Permanently | Ressource wurde dauerhaft an die angegebene Stelle verschoben. |
| 302 | Found | vorübergehend verschoben |
| 303 | See Other | Die Ressource ist unter der angegebenen URL zu finden. |
| 304 | Not Modified | Die Ressource wurde nicht geändert. |
| 305 | Use Proxy | Der Client wird aufgefordert, die Anfrage an den angegebenen Proxy zu senden. |
| 307 | Temporary Redirect | vorübergehend verschoben |
| 400 | Bad Request | Syntaxfehler in der Anfrage |
| 401 | Unauthorized | Authentifizierung wird angefordert. |
| 402 | Payment Required | Micropayment (automatisierte Sammellastschrift für Kleinbeträge wie bei PayPal oder Clickandbuy) wird benötigt (als Statuscode noch nicht implementiert) |
| 403 | Forbidden | Zugriff verweigert |
| 404 | Not Found | Die Ressource existiert nicht. |
| 405 | Method Not Allowed | Unerlaubte HTTP-Methode (ein Allow-Header gibt die zulässigen Methoden an) |
| 406 | Not Acceptable | Der Datentyp der Ressource ist nicht akzeptabel. |
| 407 | Proxy Authentication Requested | Ein Proxy-Server fordert Authentifizierung an. |
| 408 | Request Timeout | zulässige Wartezeit überschritten |
| 409 | Conflict | Ein Konflikt verhindert die Ausführung der Anfrage, etwa beim Versuch, mittels PUT eine ältere als die vorhandene Version zu speichern. |
| 410 | Gone | Die Ressource ist nicht mehr vorhanden. |
| 411 | Length Required | Für den Anfrage-Body wird ein Content-Length-Header benötigt. |
| 412 | Precondition Failed | Eine vom Client geforderte Vorbedingung konnte nicht erfüllt werden. |
| 413 | Request Entity Too Long | zu großer Anfrage-Body |
| 414 | Request-URI Too Long | Die Anfrage-URL selbst ist zu lang (kann bei GET-Anfragen mit angehängten Formulardaten vorkommen). |
| 415 | Unsupported Media Type | Der Server akzeptiert den Datentyp des Anfrage-Bodys nicht. |
| 416 | Request Range Not Satisfiable | Im Range-Header wurde ein Bereich angefordert, der nicht existiert. |
| 417 | Expectation Failed | Eine Erwartung aus dem Expect-Header konnte nicht erfüllt werden. |
| 500 | Internal Server Error | Fehler in einem serverseitigen Programm |
| 501 | Not Implemented | Die Methode oder Funktionalität wird vom Server nicht unterstützt. |
| 502 | Bad Gateway | fehlerhafte Server- oder Proxy-Antwort |
| 503 | Service Unavailable | Ein Dienst steht zurzeit nicht zur Verfügung. |
| 504 | Gateway Timeout | Timeout einer Proxy-Anfrage |
| 505 | HTTP Version Not Supported | Der Server unterstützt die angegebene HTTP-Version nicht. |
13.1.3 HTTP-Header
Wie bereits erwähnt enthalten HTTP-Anfrage und -Antwort verschiedene Header im Format
Header-Name: Wert[, Wert ...]
Die Namen der Header bestehen aus Buchstaben und Bindestrichen; Groß- und Kleinschreibung spielen keine Rolle. Falls ein Header mehrere Werte besitzt, werden diese durch Komma getrennt.
Neben den in RFCs definierten offiziellen HTTP-Header können Server und Clients auch beliebige zusätzliche Header senden. Gemäß der Konvention sollten solche Erweiterungs-Header stets mit X- beginnen, also beispielsweise X-My-Header heißen.
Tabelle 13.3 zeigt alle offiziellen HTTP-Standard-Header. Die einzelnen Spalten der Tabelle haben folgende Bedeutung:
- Header
der Name des jeweiligen Headers - seit Version
Gibt die HTTP-Version an, in der der jeweilige Header eingeführt wurde: HTTP/1.0 gemäß RFC 1945 oder HTTP/1.1 (RFC 2616). Die nachträglich so benannte Vorabversion HTTP/0.9 besaß noch keine Header, sondern nur die Anfrage- beziehungsweise Statuszeile. - Anfr. (Anfrage)
angekreuzt, wenn der Header in einer HTTP-Anfrage stehen kann - Antw. (Antwort)
angekreuzt für Header, die in einer HTTP-Antwort vorkommen können - Ent. (Entity)
angekreuzt für Header, die den Body der Anfrage beziehungsweise Antwort beschreiben - Bedeutung
kurze Beschreibung der Aufgaben des Headers
| Header | seit Version | Anfr. | Antw. | Ent. | Bedeutung |
| Accept | 1.0 | X | MIME-Types, die der Client akzeptiert | ||
| Accept-Charset | 1.0 | X | Zeichensätze, die der Client akzeptiert | ||
| Accept-Encoding | 1.0 | X | Komprimierungsformate, die der Client akzeptiert | ||
| Accept-Language | 1.0 | X | Sprachen, die der Client akzeptiert | ||
| Accept-Ranges | 1.1 | X | Server kann Anfragen nach Dokumentteilen beantworten. | ||
| Age | 1.1 | X | Zeitspanne seit der letzten Änderung | ||
| Allow | 1.0 | X | X | erlaubte HTTP-Methoden (mit Status 405) | |
| Authorization | 1.0 | X | Anmeldedaten für geschützte Bereiche (Antwort auf WWW-Authenticate) | ||
| Cache-Control | 1.1 | X | X | Einstellungen für Caching der Ressource | |
| Connection | 1.0 | X | X | Verbindung geöffnet halten (keep-alive) oder schließen (close) | |
| Content-Encoding | 1.0 | X | X | X | Komprimierungsformat des Body-Inhalts |
| Content-Language | 1.0 | X | X | X | Sprache des Body-Inhalts |
| Content-Length | 1.0 | X | X | X | Länge des Body-Inhalts in Byte |
| Content-Location | 1.1 | X | X | alternative URL der angeforderten Ressource |
|
| Content-MD5 | 1.1 | X | X | X | MD5-Hash des Body-Inhalts zur Konsistenzprüfung |
| Content-Range | 1.1 | X | X | X | Start- und Endbyte des gelieferten Bereiches bei Teillieferungen |
| Content-Type | 1.0 | X | X | X | MIME-Type der gelieferten Ressource |
| Cookie | 1.0 | X | Lieferung eines Cookies, das der Browser zuvor von der angeforderten URL empfangen hatte | ||
| Date | 1.0 | X | X | Serverdatum und -uhrzeit bei Auslieferung | |
| ETag | 1.1 | X | eine aus diversen Meta-Informationen berechnete ID, z. B. zur Aktualitätsprüfung | ||
| Expect | 1.1 | X | Ankündigung des Clients, dass vor einer Anfrage mit Body 100 Continue erwartet wird | ||
| Expires | 1.0 | X | X | »Verfallsdatum« der gelieferten Ressource (für Caching) | |
| From | 1.0 | X | E-Mail-Adresse des Anfragenden (spielt in der Praxis keine Rolle) | ||
| Host | 1.1 | X | Hostname, an den die Anfrage gerichtet ist (Pflicht-Header wegen namensbasierter virtueller Hosts) | ||
| If-Match | 1.1 | X | Fordert eine Ressource unter der Bedingung an, dass das ETag (siehe oben) einem bestimmten Wert entspricht. | ||
| If-Modified-Since | 1.0 | X | Fordert die Ressource nur an, falls sie seit dem angegebenen Datum geändert wurde. | ||
| If-None-Match | 1.1 | X | Fordert die Ressource an, falls das ETag nicht dem angegebenen Wert entspricht. | ||
| If-Range | 1.1 | X | Fordert einen bestimmten Bereich unter einer Bedingung (ETag oder Änderungsdatum) an. | ||
| If-Unmodified-Since | 1.1 | X | Fordert die Ressource an, falls sie seit dem angegebenen Datum nicht geändert wurde. | ||
| Last-Modified | 1.0 | X | X | Gibt Datum und Uhrzeit der letzten Änderung an. |
|
| Location | 1.0 | X | geänderte URL, unter der die Ressource erreichbar ist (Weiterleitung) | ||
| Max-Forwards | 1.1 | X | maximal erlaubte Anzahl von Proxy-Weiterleitungen (vor allem für TRACE-Anfragen) | ||
| Negotiate | 1.1 | X | Fordert eine Liste von Alternativdokumenten (300 Multiple Choices) an, die verschiedenen Sprach-, Zeichensatz- und Dateitypwünschen genügen. | ||
| Pragma | 1.0 | X | X | Veraltete Einstellung für Caching-Verbot (Wert: no-cache); wurde durch Cache-Control ersetzt. | |
| Proxy-Authenticate | 1.1 | X | Proxy-Authentifizierungsanforderung | ||
| Proxy-Authorization | 1.0 | X | Proxy-Anmeldedaten (Antwort auf Proxy-Authenticate) | ||
| Range | 1.1 | X | Anforderung eines Teilbereichs einer Ressource (Start- und Endbyte) |
||
| Referer4 | 1.0 | X | URL des Dokuments, das auf das aktuelle verwies (in der Regel ein Hyperlink) | ||
| Retry-After | 1.0 | X | Information bei Ausfällen, wann der Server oder die gewünschte Ressource wieder verfügbar sein wird | ||
| Server | 1.0 | X | Selbstidentifikation der Serversoftware – z. B. Apache/2.2.2 (Unix) | ||
| Set-Cookie | 1.0 | X | Cookie, das der Browser im Namen des Servers speichern soll | ||
| TE | 1.1 | X | Ein Client kann mittels TE: trailers melden, dass er mehrteilige Antworten mit jeweils eigenen Headern akzeptiert. | ||
| Trailer | 1.1 | X | X | Liste der Header, die in einem späteren Block folgen | |
| Transfer-Encoding | 1.1 | X | X | Der einzige übliche Wert, chunked, bedeutet, dass die Antwort mehrteilig ist. | |
| Upgrade | 1.1 | X | X | Angabe der unterstützten HTTP-Version (1.1); der Server kann dies per 101 Switching Protocols akzeptieren. | |
| User-Agent | 1.0 | X | Selbstidentifikation der Client-Software | ||
| Vary | 1.1 | X | Gibt an, welche Aspekte (MIME-Type, Zeichensatz usw.) an Clientvorlieben angepasst wurden (Content-Negotiation). | ||
| Via | 1.1 | X | X | Liste der Proxys, über die die Anfrage oder Antwort weitergeleitet wurde | |
| Warning | 1.1 | X | X | Warnungen über den Body-Inhalt, die das Caching betreffen (veraltet usw.) | |
| WWW-Authenticate | 1.0 | X | Authentifizierungsanforderung für geschützte Verzeichnisse |
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.




Jetzt bestellen







