get_remote_file() mit fsockopen() Dateien mit PHP über HTTP holen | 12. Januar 2007 um 16:31 Uhr
Wenn man mit PHP arbeitet und die Aufgabe hat eine Datei von einem fremden Server zu holen dann gibt es verschiedene Möglichkeiten. Jede hat so ihre Tücken:
curl- wohl am komfortabelsen, haben aber nur wenige Hoster installiertPEAR::HTTP_Request(und Verwandte) - sehr komfortabel, haben aber die wenigsten installiertfopen()- da dies ein Sicherheitsrisiko mit sich bringt schalten da sehr viele Hoster die Unterstützung für remote files ausfsockopen()ist bei allen verfügbar, dafür etwas tückisch zu implementieren
Das sinnvollste ist es also das ganze mit fsockopen() zu implementieren wenn man nicht auf irgendwelche Abhängigkeiten angewiesen sein möchte.
Mit Hilfe der Jungs aus dem SELFHTML-Chat konnte ich das ganze elegant und mit erstaunlich wenig Code hinbekommen:
function get_remote_file($url, $method = "GET", $data = "", $redirect = 10) {
$url = parse_url($url);
$fp = fsockopen ($url['host'], (!empty($url['port']) ? (int)$url['port'] : 80), $errno, $errstr, 30);
if ($fp) {
$path = (!empty($url['path']) ? $url['path'] : "/").(!empty($url['query']) ? "?".$url['query'] : "");
$header = "\r\nHost: ".$url['host'];
if("post" == strtolower($method)) $header .= "\r\nContent-Length: ".mb_strlen($data);
fputs ($fp, $method." ".$path." HTTP/1.0".$header."\r\n\r\n".("post" == strtolower($method) ? $data : ""));
if(!feof($fp)) {
$scheme = fgets($fp);
list(, $code ) = explode(" ", $scheme);
$headers = array("Scheme" => $scheme);
}
while ( !feof($fp) ) {
$h = fgets($fp);
if($h == "\r\n" OR $h == "\n") break;
list($key, $value) = explode(":", $h, 2);
$key = strtolower($key);
$value = trim($value);
if(isset($headers[$key])) $headers[$key] .= ','.trim($value);
else $headers[$key] = trim($value);
if($code >= 300 AND $code < 400 AND strtolower($key) == "location" AND $redirect > 0)
return get_remote_file($headers[$key], $method, $data, --$redirect);
}
$body = "";
while ( !feof($fp) ) $body .= fgets($fp);
fclose($fp);
}
else return (array("error" => array("errno" => $errno, "errstr" => $errstr)));
return array("headers" => $headers, "body" => $body);
}
[update 2007-05-05] Ich bin drauf gekommen, dass es ja durchaus Header gibt, die öfters als einmal vorkommen. Bisher wurden diese einfach immer wieder überschrieben, ab jetzt werden die Daten, getrennt durch ein Komma, angehängt.
Man ruft die Funktion einfach mit der kompletten URL auf und bekommt dann ein Array aus den HTTP-Headern und den Body der Datei als String zurück.
Gedacht war es vor allem für die, die Pavatare mit Hilfe von PHP in ihre Software implementieren wollen, aber vielleicht hilft es auch anderen.
Die Funktion ist natürlich Public Domain, also für alle frei nutz-, veränder- und kopierbar. Frei im Sinne von Freibier.




abonnieren.
Robert Wetzlmayr schrieb am 12.01.2007
Da man ja nie weiss, ob nicht gerade ein Bagger das Internet weggegraben hat, sind Timeouts keine überflüssige Sicherheitsmassnahme ;-) Es gibt ja nichts Schlimmeres als ein PHP-Script, das einfach wegen Laufzeitüberschreitung terminiert wird.
Sowas in der Art wäre eine erste Notbremse, wenn der gegenerische Host gerade schläft:
... stream_set_timeout($fp, 30); $info = stream_get_meta_data($fp); while (!feof($fp) && !$info['timed_out']) { ...Natürlich sollte man diesen Zustand auch dem Caller irgendwie zeigen.
Martin schrieb am 13.01.2007
Ich würde ja file_get_contents() nehmen. Und als Hoster vielleicht allow_url_include abschalten (was aber in der php.ini-recommended ohnehin der Fall sein dürfte).
Martin schrieb am 13.01.2007
Ach ja, ich glaube, bei Tripod ist fsockopen() deaktiviert.
Rolf aus Karlsruhe schrieb am 15.01.2007
Ohhje,
guckt mal wie einfach das mit PERL geht:
use LWP::Simple;
my $document = get('http://example.com/index.html');
# fertisch!
--roro
Martin schrieb am 15.01.2007
Oder in PHP:
$document = file_get_contents('http://example.com/');
Fertig! Unglaublich!
Siechfred schrieb am 19.01.2007
Rolf, Sinn des Codes ist die Rückgabe eines Arrays (oder in Perlsprache Hashs), der einem u.a. den Zugriff auf den HTTP-Header nach dem Schema $array['Headerzeile'] und auf den Body der Antwort via $array['body'] erlaubt. Dein Code schreibt alles in einen String, ist also in keinster Weise mit Jeenas PHP-Funktion vergleichbar. Wollte man etwas ähnliches in Perl umsetzen, müsste man das objektorientierte Interface LWP::UserAgent verwenden. Und schon wird's ähnlich komplex.
miro aus Wien schrieb am 04.04.2007
coole funktion, hat mir weitergeholfen. danke!
Fritz aus Jena / Thür. schrieb am 13.05.2008
Danke, hat mir nen Haufen Ärger erspart, das selbst zusammenzubasteln.
Obwohl derartiges ein Sicherheitsrisiko darstellt bin ich ausnahmsweise drauf angewiesen, es zu benutzen.
Pawel aus Halle schrieb am 24.05.2008
http://snippets.dzone.com/tag/fsockopen