| PHP kann nicht nur Dateien vom eigenen Server oder aus dem lokalen Netzwerk lesen (Zugriffs-Berechtigung vorausgesetzt). | Hier wird gezeigt, wie man mit PHP den HTML-Quelltext beliebiger erreichbarer Webseiten lesen kann. |
File-I/O mit PHP
|
Zum übergeordneten Kapitel |
| Live-Demo | Lesen und einfache 'Auswertung' einer Webseite. |
| Webseiten lesen | Einfache Technik ähnlich normalen Text-Dateien |
| GET-Anforderung | Die Anforderung einer Webseite durch einen Browser |
| Socket | Verbindung mit einstellbaren Details |
| Verwandtes Thema: | Aufspaltung und Analyse einer Web-Adresse |
Webseiten lesen mit PHP |
|
|
Jede erreichbare Webseite kann mit einem PHP Script-Programm gelesen werden.
Der Vorgang unterscheidet sich kaum vom Lesen einer
→ Text-Seite vom
eigenen Server. Die Funktionen file(), fopen(), fgets()... werden genauso verwendet, wie im Beispiel für das → Lesen von Text-Dateien gezeigt. An Stelle einer 'Auswertung' wird der empfangene Quelltext ausgegeben. Meist werden nur bestimmte Teile extrahiert und weiter verwendet. HTML-Codierung:Ein HTML-Quelltext kann nicht direkt auf der 'selbst erzeugten' Webseite des PHP-Programms ausgegeben werden, da er HTML-Anweisungen enthält: Diese dürfen vom Browser nicht interpretiert, d.h. als 'echte' HTML-Befehle behandelt werden. Sie werden daher vor der Ausgabe mit PHP-Funktion htmlentities() in → HTML-Sonderzeichen-Code umgewandelt.Beispiel: Der rohe Text <body> wird für die Ausgabe zu <body> codiert. |
$url = 'http://test.com/index.html';
$fh = @fopen($url,'r'); if($fh) {
while(!feof($fh)){
}
$line = fgets($fh,1000);
}$h = htmlentities($line); print "$h <br />"; fclose($fh); // else {... }
• Die → PHP Konfigurations-Variable allow_url_fopen bestimmt, ob es erlaubt ist, mit der Funktion fopen eine Webseite (URL) zu öffnen. Die Standard-Konfiguration am eigenen Webserver lautet meistens allow_url_fopen = On
Testen sie vor Verwendung, wie diese Variable am Server ihres Providers
eingestellt ist:
$test = ini_get('allow_url_fopen');
|
'Fehlende' Webseite:Es kann vorkommen, dass eine wichtige Webseite zeitweise nicht verfügbar ist, oder dass dorthin momentan keine Verbindung besteht. In diesem Fall bleibt Funktion fopen() erfolglos. |
Im Beispiel oben wird angedeutet ( else {...} ), wie man darauf reagieren kann: z.B. durch Umleitung an eine andere Webseite, Anzeige einer eigenen Fehlerseite, usw. |
Dynamische Webseiten:Wenn sie versuchen, mit PHP eine dynamische Webseite zu lesen, dann erhalten sie die gleichen Daten wie ein Browser - den durch das Script-Programm erzeugten HTML-Quelltext. |
Der Quelltext von Script-Programmen *.php ist als Web-Datei nicht zugänglich. Man kann diese Dateien wie jede andere → Text-Datei lesen, wenn man darauf Zugriff hat - Das trifft nur am eigenen Webserver zu. ● Ein Programm zur Anzeige von Quelltext öffnet eine gefährliche Sicherkeits-Lücke. Seine Funktion muss daher kontrolliert und so weit wie möglich eingeschränkt werden. |
FTP:Analog ist es möglich, an Stelle von http-Adressen auch ftp-Adressen zu verwenden. Beachten sie, dass FTP-Sites alle Arten von Dateien enthalten können, also auch Binärdaten. |
Urheberrecht:Es ist unanständig und verboten, Inhalte fremder Webseiten ungefragt in eigene Webseiten einzubauen.Die meisten privaten und öffentlichen Web-InhaberInnen erlauben das jedoch, wenn man darum ersucht und danach die Quelle angibt ! |
GET - Anforderung einer Webseite |
|
Manueller Ablauf► Wenn sie einen Hyperlink auf einer Webseite klicken, dann sendet ihr Browser einen Auftrag (→ HTTP-Request) 'in das Internet'. Das ist ein lesbarer Text (text/plain) der mit GET beginnt, und danach die Web-Adresse (URL) der gewünschten Webseite enthält. Im Daten-Paket des Auftrags ist darüber hinaus auch die IP-Adresse des Absenders (Client) enthalten.► Wenn die Verbindung zum angegebenen Webserver funktioniert, dann erhält dieser den HTTP GET-Auftrag. ► Der Server versucht, die gewünschte Datei zu finden und sendet sie an ihren PC. Dieser übergibt sie an den Browser. ► Ihr Browser empfängt den HTML-Quelltext und erzeugt daraus eine Webseite, die sie sehen, wenn alles funktioniert hat. ► Wenn der Webserver die Anforderung nicht erfüllen kann, sendet er den HTML-Quelltext einer Fehler-Seite. |
Programmierter Ablauf► Genau der gleiche Vorgang kann auch von einem (PHP)-Programm ausgeführt werden.► Wenn PHP die ↑ Funktion fopen() ausführt, dann wird ebenfalls eine GET-Anfrage abgesendet, deren Details allerdings den Vor-Einstellungen von PHP entsprechen. Erst ab PHP Version 5 haben sie einige Möglichkeiten, diese Anfrage zu beeinflussen. ► Der empfangene Quelltext wird in diesem Fall nicht an einen Browser übergeben sondern an das PHP-Programm. Dieses hat die Möglichkeit, ihn (z.B. mit Funktion fgets() ) zu lesen und beliebig damit zu verfahren. ► Wenn möglich, verwenden sie die einfache Methode mit PHP-Funktion fopen(), um eine Webseite zu lesen. Das funktioniert fast immer. Nur in ganz wenigen Fällen können sie eine Webseite mit PHP Standard-Funktionen nicht erreichen. Nur dann lohnt die Mühe, die GET-Anfrage mit ↓ Socket-Methoden zu programmieren. |
Konsole & telnet:Bevor sie 'low-level' programmieren, sollten sie den Vorgang manuell testen.• Sie können jede GET-Anfrage von einer Konsole (Linux-Shell oder Windows command.exe) ausführen.
C:\> telnet 192.168.0.1 80
Ändern sie IP-Adresse (hier 192.168.0.1) oder
Name (z.B. www.provider.com) nach Bedarf.
Mit Leerzeichen getrennt wird der
→ Port angeführt, für Webserver immer
dezimal 80 GET / • Nach Eingabe der ersten Zeile wird der Bildschirm meist gelöscht. Geben sie dann die GET-Anfrage 'blind' ein und senden sie mit der <return>-Taste. Wenn keine Antwort kommt, versuchen sie es nochmals mit 2 oder 3 <return>-Tasten nach dem GET-Befehl. • Wenn das nicht funktioniert, versuchen sie eine Variante, z.B. mit Angabe des Protokolls oder der genauen URL einer Webseite:
GET / HTTP/1.1
GET /index.html HTTP/1.1 GET /sub/seite.htm HTTP/1.1 • Für die GET-Anfrage haben sie nur wenige Sekunden Zeit, da der Webserver sonst die Verbindung trennt. • Bei Erfolg erhalten sie den HTML-Quelltext der angeforderten Webseite oder zumindest der Fehlerseite ('... nicht gefunden'). ♣ Tipp: Für HTTP-Debug und Experimente ist das Konsolen-Programm und PHP-Modul CURL besonders praktisch. |
Proxy-Server (Router)Der Test mit telnet sollte funktionieren, wenn ihr PC direkt mit dem Internet verbunden ist.Wenn ihr PC in einem lokalen Netzwerk (LAN) arbeitet, dann sorgt ein eigener PC - → Proxy-Server oder → Router - für die gemeinsame Verbindung mit dem Internet. In diesem Fall benötigen sie → IP-Adresse und → Port des Proxy, z.B. 192.168.0.1 8080 • Die telnet-Verbindung erfolgt nun nicht mit dem gewünschten Webserver sondern mit dem Proxy. Die Ziel-Adresse (URI) wird dafür in der GET-Anfrage angegeben:
C:\> telnet 192.168.0.1 8080
GET www.provider.com/ • Senden sie die Anfrage mit 2-3 <return>-Tasten ab. • Für ein (PHP)-Programm gelten die gleichen Bedingungen, und zwar aus Sicht jenes PC, auf dem PHP läuft, das ist normalerweise ihr eigener Webserver. Wenn sich PC und Webserver im gleichen LAN befinden, dann können sie funktionierende GET-Anfragen direkt aus telnet in ihr PHP-Programm übertragen. • Achtung bei Upload auf den Webserver eines Providers: Testen sie, ob entfernte Webseiten genauso gelesen werden wie auf ihrem eigenen Test-Server. Mit den Daten des → globalen Arrays $_SERVER['HTTP_HOST'] können sie eine bedingte Verzweigung einrichten - ihr PHP-Programm stellt fest, auf welchem Server es läuft und stellt danach die gewünschte Verbindung mit oder ohne Proxy her. |
Packet-Monitor:Ein ausgezeichnetes Werkzeug für die Programmierung von Netzwerk-(Internet)-Verbindungen ist ein Packet Monitor (z.B. kostenfrei bei WireShark oder AnalogX). Damit können sie den Datenverkehr auf ihrem Netzwerk protokollieren.Insbesondere ist es möglich, sämtliche von ihrem PC ausgehenden GET-Anfragen genau zu erfassen: Sie sehen direkt allfällige Unterschiede in den GET -Texten ihres Browsers, ihrer Konsole (telnet, siehe oben) und ihrer PHP-Programme. |
Auch Webserver können natürlich den Text einlangender GET-Anfragen analysieren. Manche Server versuchen auf diese Art, zwischen manschlich bedienten Browsern und automatisch ausgeführten Programmen zu unterscheiden. Umgekehrt können sie die GET-Anfragen ihrer PHP-Programme so abfassen, dass sie von jenen eines Browsers nicht unterscheidbar sind. Eine weitere Maßnahme solcher programm-feindlicher Webserver ist es, gesuchte Webseiten öfters neu zu benennen. Allerdings muss sich dann irgendwo ein Link befinden, der auf die so geschützte Webseite weist - und genau diesen Link kann man natürlich auch mit einem (PHP)-Programm lesen. |
Browser-Anfrage mit PHP anzeigen:Wenn sie eine Browser-Anfrage genau simulieren wollen, dann müssen sie wissen, was ihr(e) Browser an zusätzlicher Information (Header-Variable) mit jedem GET-Auftrage senden.Am eigenen Webserver können sie das mit dem gezeigten Beispiel ausprobieren. |
HTTP-Request-Header mit der Funktion apache_request_headers()
aus dem
→ Modul apache2handler
if(extension_loaded('apache2handler')) {
$headers = apache_request_headers();
}
foreach ($headers as $n => $v) { print "$n: $v<br />\n";
}
|
| Wenn das → Modul apache2handler nicht verfügbar ist, dann kann man zumindest die meisten Header-Variablen aus den Elementen des → Globalen Array $_SERVER rekonstruieren: |
$z="<br />\n";
print 'Host: '; print $_SERVER['HTTP_HOST'].$z; print 'User-Agent:'; print $_SERVER['HTTP_USER_AGENT'].$z; print 'Accept: '; print $_SERVER['HTTP_ACCEPT'].$z; print 'Accept-Language: '; print $_SERVER['HTTP_ACCEPT_LANGUAGE'].$z; print 'Accept-Charset: '; print $_SERVER['HTTP_ACCEPT_CHARSET'].$z; print 'Keep-Alive: '; print $_SERVER['HTTP_KEEP_ALIVE'].$z; print 'Connection: '; print $_SERVER['HTTP_CONNECTION'].$z; |
|
Live-PHP: Etwa so lautete der HTTP GET-Auftrags-Text dieser Webseite durch ihren Browser:
GET http://www.topsoft.at/pstrainer/entwicklung/php/inout/web_read.php HTTP/1.1
Host: www.topsoft.at User-Agent: CCBot/1.0 (+http://www.commoncrawl.org/bot.html) Accept: text/html,application/xhtml+xml,text/xml;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: Connection: close |
|
Socket-Verbindung mit PHP |
|
|
Bevor sie ein Programm ähnlich diesem Beispiel ausprobieren, sollten sie
die gewünschte Webseite sowohl mit ihrem Browser als auch mit
telnet (von ihrer Konsole)
erfolgreich geladen haben. ● PHP-Funktion fsockopen() stellt die Verbindung mit dem Webserver her. • Sein Name (alternativ seine → IP-Adresse) wird in der Variablen $pu angegeben. • Port: Webserver 'horchen' normalerweise auf dem → Port 80 • Fehler: Allfällige Fehler-Nummern und -Meldungen werden an die beiden Variablen $errnr und $errmsg übergeben. • Der Timeout ist mit 30 Sekunden eingestellt - Wenn bis dahin keine Antwort erfolgt, wird die Fehlermeldung ausgegeben. ● Wenn die Verbindung funktioniert, wird in der Variablen $out eine GET-Anfrage zusammengestellt. Schließen sie jedes Daten-Paar name:wert mit \r\n ab. Zuletzt wird die komplette Anfrage mit PHP-Funktion fwrite() abgesendet. ● Wenn alles funktioniert, erhält ihr Programm die gewünschte Antwort = meist den HTML-Quelltext einer Webseite. Im Beispiel wird der Roh-Text zeilenweise abgerufen und in der Ausgabe-Webseite angezeigt. Durch Kommentar abgeschaltet die Funktion htmlentities(), mit deren Hilfe man den empfangenen Text komplett als Quelltext anzeigen kann. • Zuletzt wird die Socket-Verbindung mit Funktion fclose geschlossen. • Wenn sie nicht die Homepage des Servers sondern eine bestimmte Webseite anfordern, dann verwenden sie die abgeschaltete Variable $url wie gezeigt. |
$pu = 'www.server.com';
// $url = '/sub/test.html';
$fp = fsockopen($pu,80,$errnr,$errmsg,30);
print "fsockopen($pu) = $fp<br />\n"; if ($fp) {
$out = "GET / HTTP/1.1\r\n";
}//$out = "GET $url HTTP/1.1\r\n"; $out .= "Accept: image/gif, image/jpeg\r\n"; $out .= "Accept-Language: de\r\n"; $out .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp,$out); while (!feof($fp)) {
$line = fgets($fp, 128);
}//$line=htmlentities($line)."<br />\n";
print $line;
fclose($fp); else {print "Fehler: $errmsg ($errnr)<br />\n";} |
Socket-Verbindung über Proxy:Auch in diesem Fall sollten sie die realen Verhältnisse getestet haben, bevor sie zu programmieren beginnen.Abweichend vom oben angeführten Beispiel wird mit PHP-Funktion fsockopen() der eigene → Router / Proxy-Server adressiert. Dafür wird die gewünschte Ziel-URI (Variable $pu ) in den GET-Befehl eingefügt. Der Rest bleibt gleich: Zusammenstellung der Client-Argumente im der GET-Auftrag, Absenden des GET-Auftrags, Empfang und Decodierung der Antwort. |
$proxy = '192.168.0.1';
$proxyport = '8080'; $pu = 'www.server.com'; $fp = fsockopen($proxy,$proxyport,$errnr, $errmsg,30); print "fsockopen(proxy) = $fp<br />\n"; if ($fp) {
$out = "GET $pu HTTP/1.1\r\n";
}//...Analyse und Verarbeitung
|
| Wenn man sich die Mühe macht, ein Programm zum Lesen einer Webseite zu erstellen, dann wird aus dieser meistens (automatisch) eine wichtige Information entnommen. | Um bestimmte Daten im Antwort-Strom exakt zu finden und zu isolieren, verwendet man am besten → Reguläre Ausdrücke. |
|
Letzte Änderung dieser Seite: 2011-10-13 14:33:11
|