# Was sonst noch wichtig ist

Im Alltag siegt das Dringende über das Wichtige.
Jean Remy von Matt, dt. Werbefachmann

Dieses Kapitel beschäftigt sich mit dem Sammeln der Informationen von Server und Browser. Aber auch die Netzwerkprogrammierung, reguläre Ausdrücke und das dynamische Erstellen von PDF-Dokumenten werden behandelt.

# Server-Informationen

Da leider alle Webserver unterschiedliche Informationen zur Verfügung stellen, ist es schwer zu sagen, welche Variablen Sie genau auslesen können. Das folgende Script soll dies jedoch erleichtern.

<?php

  echo "<h1>Umgebungsvariablen</h1><table border=\"1\">";
  echo "<tr><th>Schl�ssel</th><th>Wert</th></tr>";
  foreach($_ENV as $key=>$value)
  {
    echo "<tr><td>$key</td><td>$value</td></tr>";
  }
  echo "</table>";
  
  echo "<h1>Servervariablen</h1><table border=\"1\">";
  echo "<tr><th>Schl�ssel</th><th>Wert</th></tr>";
  foreach($_SERVER as $key=>$value)
  {
    echo "<tr><td>$key</td><td>$value</td></tr>";
  }
  echo "</table>";
  
?>

Listing 9.1: Ausgabe der Server-Informationen

Die beiden assoziativen Arrays $_ENV und $_SERVER stellen die unterschiedlichsten Informationen bereit. Dabei finden Sie in $_ENV die Umgebungsvariablen und in $_SERVER die vom Server zur Verfügung gestellten Daten.

Außerdem können Sie mit der Funktion phpinfo unterschiedlichste Daten im Browser ausgeben.

void phpinfo(void)

Ein Beispiel:

<?php

  phpinfo();
  
?>

Listing 9.2: Ausgabe der unterschiedlichsten Informationen mit phpinfo

# Netzwerkfunktionen

In Bezug auf Netzwerke sind in PHP einige Funktionen sehr hilfreich, auch wenn sie eher selten verwendet werden.

# IP-Adressen und DNS

Die Funktion gethostbyaddr ermittelt den Hostnamen eines Rechners im Internet anhand seiner IP-Adresse. Die IP-Adresse wird als Parameter erwartet. Bei einem Fehler wird die übergebene IP-Adresse zurückgegeben, ansonsten der entsprechende Hostname.

string gethostbyaddr(string ipaddress)

Sie können die IP-Adresse jedoch auch anhand eines Hostnamens ermitteln. Der Hostname wird als Parameter übergeben, und die IP-Adresse wird zurückgegeben.

string gethostbyname(string hostname)

Alternativ können Sie jedoch auch eine Liste von passenden IP-Adressen zu einem Hostname als Array erhalten. Die IP-Adresse muss als Parameter übergeben werden. Das Array wird zurückgegeben.

array gethostbynamel(string hostname)

# Verbindungen zu anderen Servern

Mit der Funktion fsockopen können Sie eine Verbindung zu einem anderen Server aufbauen.

int fsockopen([string udp://hostname, int port [, int errno   
  [, string errstr [, double timeout]]]])

Die Funktion gibt bei Erfolg ein Handle zurück, das einem Dateihandle entspricht. Dadurch ist es möglich, Dateifunktionen wie z. B. fgets, fputs, feof oder fclose zu verwenden. Wenn die Verbindungsanforderung scheitert, gibt die Funktion FALSE zurück und speichert in den Parametern errno und errstr die Fehlernummer sowie eine entsprechende Meldung.

<?php

  $connection = fsockopen("www.google.de",80);
  if($connection)
  {
    fputs($connection,"GET / HTTP/1.0\r\n\r\n");
    while(!feof($connection))
    {
      echo fgets($connection,128);
    }
    fclose($connection);
  }
  else
  {
    echo "Verbindung zu www.google.de fehlgeschlagen.";
  }

?>

Listing 9.3: Verbindungsaufbau zum Server www.google.de über den Port 80

Das Script aus Listing 9.3 baut eine Verbindung zum Server www.google.de auf; und zwar über den Port 80. Dies ist der Standard-Port für HTTP-Verbindungen. Aus diesem Grund müssen und dürfen Sie das Protokoll nicht in der URI mit angeben, da das zu verwendende Protokoll aus dem angesprochenen Port resultiert. Wurde die Verbindung erfolgreich hergestellt, wird in der Variablen $connection ein Dateihandle gespeichert, über das im if-Anweisungsblock die Kommunikation mit dem Server erfolgt. Zuerst wird dem Server per HTTP-Kommando mitgeteilt, welche Methode und welche Protokollversion bei der Kommunikation verwendet werden soll. In der nachfolgenden while-Schleife werden so lange Zeichen eingelesen, bis der Server nichts mehr sendet.

Alternativ können Sie anstelle des while-Konstrukts auch die Funktion fpassthru verwenden. Diese Funktion liest alle Zeichen ein, die über eine Verbindung empfangen werden können.

if($connection)  
{  
  fputs($connection,"GET / HTTP/1.0\\r\n\\r\n");  
  fpassthru($connection);  
  fclose($connection);  
}

Neben HTTP-Verbindungen können Sie auch andere POP3- oder FTP-Verbindungen herstellen.

Die entsprechenden Ports können Sie der Tabelle 9.1 entnehmen.

Port Dienst bzw. Protokoll
13 Daytime
21 FTP
23 Telnet
25 Mailto / SMTP
37 Time
42 DNS
43 WhoIs
69 Trivial File Transfer Protocol (TFTP)
70 Gopher
79 Finger
80 HTTP
110 Mailfrom / POP3
119 News/NNTP

Tabelle 9.1: Ports für verschiedene Verbindungen

# HTTP-Verbindungen

Auf die gleiche Art und Weise wie in Listing 9.3 kommuniziert auch ein Browser mit einem Webserver. Er sendet unterschiedliche HTTP-Kommandos und wartet die Reaktion des Servers ab. Ein solches HTTP-Kommando ist folgendermaßen aufgebaut:

  • Kommando (Methode ID Protokoll-Version)
  • Header
  • Content-Length-Feld
  • Daten (ggf. zwei Leerzeilen)

Das Kommando in Listing 9.3 besteht aus der Methode GET der ID / und der Protokoll-Version HTTP/1.0.

Anstelle der Methode GET können Sie auch eine der anderen, in Tabelle 9.2 enthaltenen Methoden verwenden.

Für ID können Sie auch eine Domain oder einen Dateinamen angeben, und als Protokollversion ist auch die Angabe HTTP/1.1 möglich. Wenn Sie keine Daten an den Server übergeben möchten, müssen Sie das Kommando mit zwei Leerzeilen abschließen. In Abschnitt 47.4, PDF-Dokumente erzeugen, finden Sie das Beispiel eines HTTP-Kommandos, das sowohl den Header als auch das Content-Length-Feld als auch Daten an den Browser sendet.

Methode Erklärung
DELETE Ressource löschen
GET Ressource anfordern
HEAD Header anfordern
LINK Verknüpfung anlegen
OPTIONS Optionen ermitteln
POST Daten senden
PUT Ressource ablegen
TRACE Rückverfolgung des Kommandos
UNLINK Verknüpfung löschen

Tabelle 9.2: Kommando-Methoden

# POP3-Verbindung

Verbindungen, bei denen das POP3-Protokoll verwendet wird, sind Verbindungen, um E‑Mails von einem Server abzurufen. Das Listing 9.4 enthält hierfür ein Beispiel. Der Port für eine solche Verbindung lautet 110.

<?php

  $connection = fsockopen('pop.server.tld',110);
  if($connection)
  {
    echo fgets($connection,1024);
    fputs($connection,'USER username\r\n');
    echo fgets($connection,1024);
    fputs($connection,'PASS passwort\r\n');
    echo fgets($connection,1024);
    fputs($connection,'STAT\r\n');
    echo fgets($connection,1024);
    fputs($connection,'QUIT\r\n');
    echo fgets($connection,1024);
    fclose($connection);
  }

?>

Listing 9.4: Verbindung zu einem POP3-Server mit PHP

Anstelle von USER, PASS oder STAT können Sie auch eines der in Tabelle 9.3 aufgeführten Kommandos verwenden.

Kommando Erklärung
DELE E‑Mail löschen
LIST E‑Mails auflisten
NOOP Verbindungsstatus abfragen
PASS Passwort
QUIT Verbindung beenden
RETR E‑Mail öffnen bzw. empfangen
RSET Löschmarkierung entfernen
STAT E‑Mails mit entsprechender Größe auflisten
USER Benutzername

Tabelle 9.3: Kommandos für POP3-Verbindungen

Die in Listing 9.4 angegebenen Platzhalter username und password müssen durch die entsprechenden Daten ersetzt werden. Außerdem sollten Sie jedes Kommando mit \\r\n (carriage return und line feed) abschließen.

# Perl-kompatible reguläre Ausdrücke in PHP

Reguläre Ausdrücke, wie sie in Perl typisch sind, lassen sich mit ein wenig Mehraufwand auch in PHP einsetzen. So können Sie einen String auf einen regulären Ausdruck überprüfen, Treffer durch eine andere Zeichenkette ersetzen oder Strings anhand eines regulären Ausdrucks in ein Array zerlegen.

Während Sie in Perl einfach den Bindungsoperator =\~ verwenden konnten, müssen Sie in PHP hierfür eine Funktion bemühen: preg_match. Sie erwartet als ersten Parameter den regulären Ausdruck und als zweiten die Zeichenkette, die durch den regulären Ausdruck überprüft werden soll.

int preg_match(string regexp, string str)

Ein Beispiel:

if(preg_match("/aus/","Haus"))  
{  
  echo "Treffer!";  
}  
else  
{  
  echo "Kein Treffer!";  
}

Dieses Beispiel wird Treffer! im Browser ausgeben, da aus in Haus vorkommt. Beachten Sie, dass ein regulärer Ausdruck, anders als in Perl, in doppelten Anführungsstrichen notiert werden muss. Mit einer foreach-Schleife lässt sich ein regulärer Ausdruck auch auf ein Array anwenden.

$strings = Array("Maus","Haus","Haut","Laus");  
foreach($strings as $value)  
{  
  if(preg_match("/aus/",$value))  
  {  
    echo "Treffer in $value<br>\n";  
  }  
  else  
  {  
    echo "Kein Treffer in $value<br>\n";  
  }  
}

Ausgabe:

Treffer in Maus
Treffer in Haus
Kein Treffer in Haut
Treffer in Laus

Leider kann PHP das Flag g nicht interpretieren, das in einer Zeichenkette nach allen Vorkommen des regulären Ausdrucks sucht. Daher müssen Sie in solchen Fällen eine andere Funktion verwenden: preg_match_all.

int preg_match_all(string regexp, string str, array matches)

Wenn Sie als dritten Parameter nun ein Array angeben, werden alle Treffer in diesem Array gespeichert. Beachten Sie dabei, dass das angegebene Array danach mehrdimensional ist und die Treffer im Unter-Array $matches[0] gespeichert werden.

Mit der Funktion preg_replace können Sie Zeichenketten mit Hilfe regulärer Ausdrücke ersetzen.

mixed preg_replace(mixed regexp, mixed replacewith, mixed replacein)

Anstelle des Parameters regexp können Sie einen regulären Ausdruck als String oder mehrere als Array übergeben. Der Parameter replacewith nimmt entweder einen String oder ein Array von Strings entgegen, mit denen ersetzt werden soll. Die Zeichenkette bzw. die Zeichenketten, in denen ersetzt werden soll, werden als Parameter replacein übergeben. Wurde eine Ersetzung vorgenommen, wird/werden die überarbeitete(n) Zeichenkette(n) zurückgegeben, andernfalls die unbearbeitete(n) Zeichenkette(n).

echo preg_replace("/[\\d]{2}\\.[\\d]{2}\\.[\\d]{4}/",  
                  strftime("%d.%m.%Y"),  
                  "Heute ist der 04.10.2002");

Dieses Beispiel ersetzt jedes Datum, das gefunden wird, durch das aktuelle Datum.

Die Funktion preg_split ermöglicht das Zerlegen eines String in mehrere Teilstrings anhand eines regulären Ausdrucks. Als Parameter erwartet die Funktion den regulären Ausdruck als String und die Zeichenkette, die zerlegt werden soll. Der Rückgabewert der Funktion ist ein Array.

array preg_split(string regexp, string string_to_split)

Ein Beispiel:

$splitted = preg_split("/[\\s]/","Dies ist eine normale Zeichenkette");  
foreach($splitted as $value)  
{  
  echo "$value<br>\n";  
}

In diesem Beispiel wird eine Zeichenkette anhand aller gefundenen nicht druckbaren Zeichen zerlegt (z. B. \n, \\r oder \\t) und im Array $splitted gespeichert. Anschließend wird das Array in einer foreach-Schleife ausgegeben.

# PDF-Dokumente erzeugen

Seit geraumer Zeit ist in PHP eine Erweiterung verfügbar, mit der Sie zur Laufzeit eines Scripts ein PDF-Dokument erzeugen können. Sie können dabei beliebige Texte und Bilder in das Dokument einfügen und verschiedene Formatierungen vornehmen.

<?php

  $pdf = pdf_new();
  pdf_open_file($pdf);
  pdf_set_info($pdf,'Creator','pdf.php');
  pdf_set_info($pdf,'Author','pdf.php');
  pdf_set_info($pdf,'Title','Hallo Welt');
  pdf_begin_page($pdf,595,842);
  
  $font = pdf_findfont($pdf,'Times New Roman','host',0);
  pdf_setfont($pdf,$font,20.0);
  pdf_show_xy($pdf,'Hallo Welt!',50,842-20-50);
  
  pdf_end_page($pdf);
  pdf_set_parameter($pdf,"openaction","fitpage");
  pdf_close($pdf);
  
  $buffer = pdf_get_buffer($pdf);
  $size = strlen($buffer);
  header('Content-Type: application/pdf');
  header("Content-Length: $size");
  header('Content-Disposition: inline; filename=pdf.pdf');
  echo $buffer;
  pdf_delete($pdf);
  
?>

Listing 9.5: Erzeugen eines PDF-Dokuments zur Laufzeit

Es gibt verschiedene Erweiterungen, mit denen PHP ein PDF-Dokument zur Laufzeit erzeugen kann. PHP liefert bereits eine dieser Erweiterungen mit: die PDFLIB. Für private Zwecke ist diese Bibliothek kostenfrei und dadurch für die meisten Personen verwendbar. Wollen Sie die Bibliothek kommerziell verwenden, müssen Sie zuerst eine Lizenz erwerben. Aufgrund ihrer weiten Verbreitung werde ich mich in diesem Kapitel auf diese Bibliothek beziehen.

Zuallererst muss mit der Funktion pdf_new eine neue Datenstruktur erzeugt werden. Die Funktion liefert anschließend ein Handle auf diese Struktur zurück. Die Funktion pdf_open_file öffnet ein neues Dokument. Als erster Parameter wird das Datenstruktur-Handle erwartet und optional ein Dateiname, unter dem das Dokument gespeichert wird.

$pdf = pdf_new();  
pdf_open_file($pdf);

Spezielle Informationen, die im Dokument gespeichert werden sollen, wie z. B. der Name des Autors, der Ersteller oder der Titel des Dokuments werden »Metadaten« genannt. Metadaten werden mit der Funktion pdf_set_info angegeben. Auch diese Funktion erwartet wieder als ersten Parameter das Handle4; der zweite Parameter identifiziert den Feldnamen und der dritte den einzufügenden Wert.

pdf_set_info($pdf,'Creator','pdf.php');  
pdf_set_info($pdf,'Author','pdf.php');  
pdf_set_info($pdf,'Title','Hallo Welt');

Nach diesen Vorbereitungen wird mit der Funktion pdf_begin_page eine neue Seite in das Dokument eingefügt. Zuerst wird wieder das Handle übergeben, gefolgt von den Abmessungen der Seite in der Reihenfolge Breite und dann Höhe. Eine Seite wird in Punkt angegeben. Ein Punkt entspricht 1/72 Zoll.

pdf_begin_page($pdf,595,842);

Die Maße 595 × 842 entsprechen einer DIN-A4-Seite.

# Dokument mit Inhalt füllen

Für die Ausgabe eines Textes im Dokument müssen Sie zuerst eine Schriftart auswählen. Dabei hilft Ihnen die Funktion pdf_findfont. Dieser Funktion können Sie den Namen einer Schriftart übergeben und festlegen, wo sie suchen soll. Anschließend gibt sie den Font zurück. Diesen übergeben Sie der Funktion pdf_setfont, zusammen mit der Schriftgröße in Punkt.

$font = pdf_findfont($pdf,'Times New Roman','host',0);  
pdf_setfont($pdf,$font,20.0);

Nun können Sie mit der Funktion pdf_show_xy eine Zeichenkette in das Dokument einfügen. Dabei erwartet die Funktion die Zeichenkette und anschließend die x- und die y-Position. Beachten Sie dabei, dass der Ausgangspunkt (0,0) in der linken unteren Ecke liegt. In Listing 9.5 wird der Text Hallo Welt! an der x-Position 50 und der y‑Position 772 (842 – 20 – 50 = 772) ausgegeben.

pdf_show_xy($pdf,'Hallo Welt!',50,8422050);

Jede angefangene Seite muss mit der Funktion pdf_end_page beendet werden. Anschließend können Sie noch Parameter festlegen, die keinen informativen Gehalt besitzen. Sie werden vom öffnenden Programm interpretiert und führen z. B. dazu, dass eine Seite des PDF-Dokuments an die Fenstergröße angepasst wird (openaction und fitpage). Die hierfür zu verwendende Funktion lautet pdf_set_parameter. Zum Schluss können Sie das PDF-Dokument mit pdf_close schließen.

pdf_end_page($pdf);  
pdf_set_parameter($pdf,"openaction","fitpage");  
pdf_close($pdf);

Die PDF-Datenstruktur muss nun in einer Variable gespeichert werden. Dies erfolgt mit der Funktion pdf_get_buffer. Die Funktion liefert die Datenstruktur als String zurück. Die Länge dieses Strings wird ebenfalls benötigt. Aus diesem Grund wird in der Variablen $size die mit strlen ermittelte Zeichenzahl gespeichert.

$buffer = pdf_get_buffer($pdf);  
$size = strlen($buffer);

Anstatt nun einfach eine Ausgabe im Browser zu erzeugen, wird dem Browser zuerst der MIME-Typ der nun folgenden Daten mitgeteilt. Zusätzlich wird dabei auch die Größe des folgenden Datenstroms übergeben.

header('Content-Type: application/pdf');  
header("Content-Length: $size");  
header('Content-Disposition: inline; filename=pdf.pdf');

Abschließend wird die PDF-Datenstruktur ausgegeben und der auf dem Server belegte Speicher wieder freigeräumt.

echo $buffer;  
pdf_delete($pdf);

Weitere Informationen zum Erzeugen von PDF-Dokumenten finden Sie unter der Adresse http://www.pdflib.com/.

# Zusammenfassung

  • In den assoziativen Arrays $_ENV und $_SERVER stehen die verschiedenen Umgebungs- und Servervariablen zur Verfügung.
  • Mit der Funktion fsockopen können Verbindungen zu Servern aufgebaut werden. Zum Kommunizieren mit dem Server können die Funktionen fgets und fputs verwendet werden.
  • Mit speziellen Funktionen, wie z. B. gethostbyaddr, kann der Hostname eines Computers im Internet anhand seiner IP-Adresse ermittelt werden. Dies ist auch umgekehrt möglich.
  • Perl-kompatible reguläre Ausdrücke können mit den Funktionen preg_match, preg_repacle und preg_split auch in PHP verwendet werden.
  • Die Bibliothek PDFLIB wird mit PHP ausgeliefert und ermöglicht das Erzeugen von PDF-Dokumenten zur Laufzeit.

# Fragen und Übungen

  1. Mit welcher Anweisung können Sie die Servervariable DOCUMENT_ROOT ausgeben?
  2. Schreiben Sie ein PHP-Script, das die IP-Adresse eines Host ausgibt, dessen Name durch ein HTML-Formular übergeben wurde
  3. Schreiben Sie ein PHP-Script, das alle Ende-Tags in einer HTML-Datei ermittelt und die Zahl im Browser ausgibt.
  4. Schreiben Sie ein PHP-Script, das ein PDF-Dokument ausgibt. In das PDF-Dokument soll der Inhalt eines HTML-Dokuments eingefügt werden.