#25440 [Opn->Bgs]: fgets/fread on open socket looks like eof
| From: | sniper@php.net | Date: | Mon, 08 Sep 2003 22:46:50 +0000 |
| Subject: | #25440 [Opn->Bgs]: fgets/fread on open socket looks like eof | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-47284@lists.php.net to get a copy of this message | ||
ID: 25440
Updated by: sniper@php.net
Reported By: bret at levycodev dot com
-Status: Open
+Status: Bogus
Bug Type: Sockets related
Operating System: win32
PHP Version: 4.3.3
New Comment:
Sorry, but your problem does not imply a bug in PHP itself. For a
list of more appropriate places to ask for help using PHP, please
visit http://www.php.net/support.php as this bug system
is not the
appropriate forum for asking support questions.
Thank you for your interest in PHP.
or come up with SHORT example.
Previous Comments:
------------------------------------------------------------------------
[2003-09-08 18:10:35] bret at levycodev dot com
Description:
------------
I have an "HTTP requestor" class that I wrote many years ago using
fsocketopen, fgets and fread. It works and has always worked up until
I load PHP 4.3.3. If I backrev to 4.3.0rc2 (the last rev I was
running) the code works again.
Symptoms are this: I connect fine, I get the request sent fine, I see
the server respond with the correct and full message, but the php
client sometimes, but not always, does not see the whole response.
Sometimes the fread doesn't return everything requested.
IMHO, this is not the same problem as the other reported socket_xxx
related bugs, but I fully admit that I have not looked at the source!
Included is the class that sends/receives the http message (and yes,
there is probably something in PHP now that does this all for me, but
this always worked before, and still works in PHP <= 4.3.0rc2). There
were a few recent changes (I think), like the timeout call and the
removal of the call by reference on the fsocketopen call, to make php
4.3 happy.
Thanks,
Bret
Reproduce code:
---------------
<?php
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// http.php
// ========
//
// this class supplies a generic http request/response
interface for making requests to server (daemons)
//
// COPYRIGHT (C) 2000, Bret Levy. All Rights Are Reserved.
//
// ver 1.0.0 2000-01-20 BLevy
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class HTTP {
// private class properties
var $m_ReqMethod;
var $m_ReqURL;
var $m_ReqProtocol;
var $m_ReqHeaders;
var $m_ReqEntity;
var $m_RspProtocol;
var $m_RspStatus;
var $m_RspMessage;
var $m_RspHeaders;
var $m_RspEntity;
var $m_MaxRetries;
var $m_LastErr;
var $m_Timeout;
// public class methods
function Process ($sHost="127.0.0.1", $nPort=80) {
$tries = 0;
do {
// init ok to true
$ok = 1;
// open a connection to the server
$sck = fsockopen ($sHost, $nPort, $errnum, $errmsg, 2.0);
if ($sck === FALSE) {
$this->m_LastErr = $errmsg;
$ok = 0;
}
// see if we need to set a timeout
if ($this->m_Timeout > 0) {
$s = (int) ($this->m_Timeout / 1000);
$m = ($this->m_Timeout % 1000) * 1000;
stream_set_timeout ($sck, $s, $m);
}
// do the i/o if we got in
if ($ok) {
// add the request method line
$msg = $this->m_ReqMethod . " " . $this->m_ReqURL . " " .
$this->m_ReqProtocol . "\r\n";
// add the request headers (supress content-len
header(s))
reset ($this->m_ReqHeaders);
$nCount = sizeof ($this->m_ReqHeaders);
for ($i=0; $i<$nCount; $i++) {
list($key,$val) = each ($this->m_ReqHeaders);
if (strcasecmp($key,"content-length") != 0) {
$msg .= "$key:$val\r\n";
}
}
// ensure a content-length header went out (if we have an
entity to send)
if ($this->m_ReqEntity != "") {
$msg .= "Content-Length:" . strlen($this->m_ReqEntity) .
"\r\n";
}
// end the headers section
$msg .= "\r\n";
// write the entity body
if ($this->m_ReqEntity != "") {
$msg .= $this->m_ReqEntity;
}
// write the request
$size = fwrite ($sck, $msg);
// read the response header line
$methbuf = fgets ($sck, 8192);
$methinfo = explode (" ", $methbuf, 3);
$this->m_RspProtocol = $methinfo[0];
$this->m_RspStatus = (int) $methinfo[1];
$this->m_RspMessage = $methinfo[2];
// read the response headers
$this->m_RspHeaders = array();
do {
$buf = fgets ($sck, 8192);
$hdrinfo = explode (":", $buf);
$hdrid = trim ($hdrinfo[0]);
if ($hdrid != "") {
$hdrval = strstr ($buf, ":");
$hdrval = trim (substr($hdrval,1));
$this->m_RspHeaders[strtolower($hdrid)] = $hdrval;
}
} while (!feof($sck) && ($hdrid != ""));
// now read the content blob (could be chunked???)
if (strtolower($this->m_RspHeaders["transfer-encoding"]) ==
"chunked") {
// init the result string buffer
$data = "";
// read chunks until we have no more (chunk size of 0)
do {
$chunkid = fgets ($sck, 8192);
$chunklen = hexdec (trim($chunkid));
if ($chunklen > 0) {
$data .= fread ($sck, $chunklen);
}
} while ($chunklen > 0);
// save the (unchunked) data
$this->m_RspEntity = $data;
}
// the response is NOT chunked
else {
$contlen = (int) $this->m_RspHeaders["content-length"];
if ($contlen > 0) {
$this->m_RspEntity = fread ($sck, $contlen);
}
else {
$this->m_RspEntity = "";
}
}
// done with the socket
fclose ($sck);
}
// inc the retry counter
$tries++;
} while (($tries < $this->m_MaxRetries) && ($ok == 0));
// return the status code
return $this->m_RspStatus;
}
function SetRequestMethod ($method) {
$this->m_ReqMethod = strtoupper($method);
}
function GetRequestMethod () {
return $this->m_ReqMethod;
}
function SetRequestURL ($url) {
$this->m_ReqURL = $url;
}
function GetRequestURL () {
return $this->m_ReqURL;
}
function SetRequestProtocol ($proto) {
$this->m_ReqProtocol = strtoupper($proto);
}
function GetRequestProtocol () {
return $this->m_ReqProtocol;
}
function SetRequestHeader ($hdr, $val) {
$this->m_ReqHeaders[strtolower($hdr)] = $val;
}
function GetRequestHeader ($hdr) {
return $this->m_ReqHeaders[strtolower($hdr)];
}
function SetRequestEntity ($entity) {
$this->m_ReqEntity = $entity;
}
function GetRequestEntity () {
return $this->m_ReqEntity;
}
function GetResponseProtocol () {
return $this->m_RspProtocol;
}
function GetResponseStatus () {
return $this->m_RspStatus;
}
function GetResponseMessage () {
return $this->m_RspMessage;
}
function GetResponseHeaderCount () {
return sizeof ($this->m_RspHeaders);
}
function GetResponseHeaderInfo ($index, &$key, &$val) {
$count = sizeof ($this->m_RspHeaders);
if (($index < 0) || ($index >= $count)) {
$key = "";
$val = "";
return;
}
$i = 0;
reset ($this->m_RspHeaders);
do {
list($key,$val) = each ($this->m_RspHeaders);
$i++;
} while ($i <= $index);
}
function SetResponseHeader ($hdr, $val) {
$this->m_RspHeaders[strtolower($hdr)] = $val;
}
function GetResponseHeader ($hdr) {
return $this->m_RspHeaders[strtolower($hdr)];
}
function SetResponseEntity ($entity) {
$this->m_RspEntity = $entity;
}
function GetResponseEntity () {
return $this->m_RspEntity;
}
function SetRetries ($count) {
$this->m_MaxRetries = $count;
}
function GetRetries () {
return ($this->m_MaxRetries);
}
function SetTimeout ($value) {
$this->m_Timeout = $value;
}
function GetTimeout () {
return ($this->m_Timeout);
}
function GetLastError () {
return ($this->m_LastErr);
}
function Clear () {
$this->m_ReqMethod = "GET";
$this->m_ReqURL = "/";
$this->m_ReqProtocol = "HTTP/1.0";
$this->m_ReqHeaders = array();
$this->m_ReqEntity = "";
$this->m_RspProtocol = "";
$this->m_RspStatus = 0;
$this->m_RspMessage = "";
$this->m_RspHeaders = array();
$this->m_RspEntity = "";
$this->m_Timeout = 0;
}
function HTTP () {
$this->Clear();
$this->m_MaxRetries = 5;
}
}
?>
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=25440&edit=1