phpbar.de logo

Mailinglisten-Archive

[php] Zeitproblem mit fread

[php] Zeitproblem mit fread

Michael Hansen webmaster at web-prinz.de
Die Sep 11 19:04:23 CEST 2007


Hallo Liste,

ich bin eher ein stiller Teilnehmer dieser Liste. Nun bin ich jedoch auf ein
Problem gestoßen, bei dem ich alleine nicht mehr weiterkomme ich nun auf
eure Hilfe bauen muss.

Grob geht es darum einen POST-Request an einen Server zu schicken und die
Response des Servers wieder auszugeben. Dabei schicke ich im POST eine Datei
mit. Dies sei aber nur am Rande erwähnt, weil das eigentliche Problem ist -
wie der Titel es schon andeutet - das Auslesen der Response. 
Quelltext beschreibt es vielleicht exakter. Daher zunächst einmal meine
Funktion (Erklärung folgt nach dem Quelltext):


function sendPostData($host, $port, $path, $filepath, $ssl = true ) {
	$scheme = ($ssl) ? "ssl://" : "";
	
	$ip = gethostbyname($host);
	$url = $ip . ':' . $port . $path;

	if ( ( $io = fsockopen( $scheme.$url, $port, $errno, $errstr, 10 )
!== false )
	{
		$boundary = "---------------------------0123456789012";
		
		if (file_exists($filepath)) {
			$contentfile = file_get_contents($filepath);
		} else {
			$contentfile = null;
		}

		// set header info ...
		$header  = "POST $path HTTP/1.1\r\n";
		$header .= "Host: $host\r\n";
		$header .= "User-Agent: werAuchImmer\r\n";
		$header .= "Accept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=
0.8,image/png,*/*;q=0.5\r\n";
		$header .= "Accept-Encoding: gzip,deflate\r\n";
		$header .= "Keep-Alive: 300\r\n";
		$header .= "Connection: keep-alive\r\n";
		$header .= "Content-type: multipart/form-data,
boundary=".$boundary."\r\n";

		// ... and attach the file
		$data  = "--".$boundary."\r\n";
		$data .= "Content-Disposition: form-data;
name=\"dateiupload\"; filename=\"".$filepath."\"\r\n";
		$data .= "Content-Type: application/upload\r\n\r\n";
		$data .= $contentfile."\r\n";
		$data .= "--".$boundary."--\r\n";
		
		$header .= "Content-Length: " . strlen($data) . "\r\n\r\n";
		$header .= $data;

		// then just
		fputs($io, $header);

		// get header
		$response = '';
		
		do
		{
			$response .= fgets ( $io, 4096 );

		} while ( strpos ( $response, "\r\n\r\n" ) === false );

		// and get header infos
            $info = decode_header ( $response );
		
		$response = '';

		$starttime = time() + 80;

		$test = array();
		$start = microtime(true);
		$i = 1;

		while ( !feof($io) )
		{
			$test[$i]['timea'] = (microtime(true) - $start) *
1000;
			$response .= fread( $io, 1024 );
			$test[$i++]['timeb'] = (microtime(true) - $start) *
1000;

			if ($starttime <= time()) { 
				return false;
			}
		}

            // print_r($test);

		fclose ( $io );
		
		$response = decode_body ( $info, $response );

		return $response;

	} else {
		return "Fehler: $errno - $errstr<br />\n";
	}
	
	return false;
}


Zu den Parametern:

$host: z.B. www.example.com
$port: z.B. 8443
$path: z.B. /pfad/zu/einer/datei.php?mit=parametern
$filepath: Pfad zu einer Datei, z.B. einem PDF-Dokument, welches
mitgeschickt werden soll
$ssl:  Über SSL oder eben nicht...


Innerhalb der Funktion werden 2 Hilfsfunktionen verwendet. "decode_header"
holt sich dabei nur die zurückgelieferten Header-Informationen und packt
diese zur Weiterverarbeitung in ein Array. "decode_body" nutzt diese
Header-Informationen um den Body entsprechend darzustellen. So far... 

Die Funktion ist effektiv, aber nicht effizient. Ich will damit sagen dass
ich bei einer Anfrage 60 Sekunden auf warten muss, bis mir das Ergebnis
angezeigt wird. Nach kurzer Analyse habe ich dann auch den zeitkritischen
Teil ausfindig machen könnt. Wie ihr an der Funktion sehen könnt, sind sogar
noch die letzten Variablen für die Zeitmessungen drin (absichtlich).
Die gesamte Funktion wird schnell durchlaufen, bis hin zu den fread. Hier
gehen gute 59 Sekunden der gesamten 60 Sekunden drauf. Nach weiterer Analyse
(so wie ihr es jetzt auch seht) habe ich dann festgestellt, dass diese 59
Sekunden durch den letzten Schleifendurchlauf zustande kommen. Ich habe
keine Ahnung warum, aber im letzten Durchlauf scheint fread zu hängen.

Ein Blick in die zurück gelieferten Header brachte keine weiteren
Erkenntnisse. Bei mir wurden nur die Standard-Header gesetzt wie Status 200
usw. Ich gehe also davon aus, dass mir die Daten nicht als chunked oder so
zurückgeliefert werden. Austauschen von fread mit fgets brachte auch kein
anderes Verhalten. Getestet habe ich es mit unterschiedlichen PHP-Versionen
(5.0.3 und eine ganz aktuelle - kann gerade leider nicht genau sagen
welche).

Hat irgendwer auf dieser Liste schon ähnliche Erfahrungen gesammelt und
kennt vielleicht meinen Fehler? Ich bin für jede konstruktive Hilfe dankbar!


// Michael Hansen


php::bar PHP Wiki   -   Listenarchive