httpclient : add rawData support
httpclient : add getContent () method httpclient : solve a bug when the Content-Length = 0 (waiting socket not needed) git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4809 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
195
httpclient.php
195
httpclient.php
@@ -4,8 +4,6 @@
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
*/
|
||||
|
||||
namespace vendor\domframework;
|
||||
|
||||
/** This programe allow to get a HTTP page from a site, and examine the content.
|
||||
* It will store the Cookies, allow to do the redirects, follow links and
|
||||
* get form / input and send the values.
|
||||
@@ -53,6 +51,10 @@ class Httpclient
|
||||
*/
|
||||
private $tcpclient = null;
|
||||
|
||||
/** The SSL Options parameters (if set)
|
||||
*/
|
||||
private $ssloptions = array ();
|
||||
|
||||
/** The maximum maxsize allowed
|
||||
*/
|
||||
private $maxsize;
|
||||
@@ -83,6 +85,10 @@ class Httpclient
|
||||
*/
|
||||
private $formData = array ();
|
||||
|
||||
/** The raw data to send
|
||||
*/
|
||||
private $rawData = "";
|
||||
|
||||
/** The timeout in second before expiring the connection
|
||||
*/
|
||||
private $timeout = 30;
|
||||
@@ -123,6 +129,7 @@ class Httpclient
|
||||
if ($maxsize === 0)
|
||||
$maxsize = 8000000000;
|
||||
$this->maxsize = $maxsize;
|
||||
$this->headersReset ();
|
||||
}
|
||||
// }}}
|
||||
|
||||
@@ -169,6 +176,7 @@ class Httpclient
|
||||
return $this->method;
|
||||
if (! is_string ($method))
|
||||
throw new \Exception ("Invalid method to set : not an string", 406);
|
||||
$method = strtoupper ($method);
|
||||
if (! in_array ($method, array ("GET", "POST", "PUT", "DELETE", "HEAD")))
|
||||
throw new \Exception ("Invalid method to set : not in list", 406);
|
||||
$this->method = $method;
|
||||
@@ -194,6 +202,28 @@ class Httpclient
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Set the headers to initial value
|
||||
*/
|
||||
public function headersReset ()
|
||||
// {{{
|
||||
{
|
||||
$this->headersSent = array ();
|
||||
return $this;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Add a new header to be sent to the server
|
||||
* @param string $header The header to add/update
|
||||
* @param string $value The value to save
|
||||
*/
|
||||
public function headerAdd ($header, $value)
|
||||
// {{{
|
||||
{
|
||||
$this->headersSent[$header] = $value;
|
||||
return $this;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the port used for connection
|
||||
*/
|
||||
public function port ()
|
||||
@@ -245,7 +275,7 @@ class Httpclient
|
||||
* If value is like "@/tmp/file", use the /tmp/file as content
|
||||
* @param array|null $formData The data to send to the server
|
||||
*/
|
||||
public function formData ($formData)
|
||||
public function formData ($formData = null)
|
||||
// {{{
|
||||
{
|
||||
if ($formData === null)
|
||||
@@ -253,6 +283,25 @@ class Httpclient
|
||||
if (! is_array ($formData))
|
||||
throw new \Exception ("Invalid form data provided : not an array", 406);
|
||||
$this->formData = $formData;
|
||||
$this->rawData = "";
|
||||
return $this;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Set / Get the content Data
|
||||
* The data is in raw format and will not be modified.
|
||||
* Overwrite the eventually previous form data and rawData
|
||||
* @param string|null $rawData The data to use
|
||||
*/
|
||||
public function rawData ($rawData = null)
|
||||
// {{{
|
||||
{
|
||||
if ($rawData === null)
|
||||
return $this->rawData;
|
||||
if (! is_string ($rawData))
|
||||
throw new \Exception ("Invalid raw data provided : not a string", 406);
|
||||
$this->rawData = $rawData;
|
||||
$this->formData = array ();
|
||||
return $this;
|
||||
}
|
||||
// }}}
|
||||
@@ -400,39 +449,7 @@ class Httpclient
|
||||
$this->method ("GET");
|
||||
$this->url ($url);
|
||||
$this->connect ($ssloptions);
|
||||
$content = "";
|
||||
while ($tmp = $this->read (1000000))
|
||||
{
|
||||
$content .= $tmp;
|
||||
if (strlen ($content) > $this->maxsize)
|
||||
throw new \Exception ("File to get exceeded maxsize", 500);
|
||||
}
|
||||
$this->disconnect ();
|
||||
if ($this->httpCode === 301 || $this->httpCode === 302 ||
|
||||
key_exists ("Location", $this->headersReceived))
|
||||
{
|
||||
if (! key_exists ("Location", $this->headersReceived))
|
||||
throw new \Exception ("Redirect without location provided", 406);
|
||||
$this->redirectCount++;
|
||||
if ($this->redirectCount > $this->redirectMaxCount)
|
||||
throw new \Exception ("Redirect exceed maximum limit", 406);
|
||||
// echo "REDIRECT TO ".$this->headersReceived["Location"]."\n";
|
||||
$location = $this->headersReceived["Location"];
|
||||
$parseURLInit = parse_url ($url);
|
||||
$parseURLLocation = parse_url ($location);
|
||||
if (! key_exists ("port", $parseURLLocation) &&
|
||||
key_exists ("port", $parseURLInit))
|
||||
$location = ":".$parseURLInit["port"].$location;
|
||||
if (! key_exists ("host", $parseURLLocation))
|
||||
$location = $parseURLInit["host"].$location;
|
||||
if (! key_exists ("scheme", $parseURLLocation))
|
||||
$location = $parseURLInit["scheme"]."://".$location;
|
||||
$this->log (1, "REDIRECT $this->httpCode to $location");
|
||||
$content = $this->getPage ($location, $ssloptions);
|
||||
}
|
||||
$this->referer = $url;
|
||||
$this->redirectCount = 0;
|
||||
return $content;
|
||||
return $this->getContent ();
|
||||
}
|
||||
// }}}
|
||||
|
||||
@@ -445,6 +462,7 @@ class Httpclient
|
||||
// {{{
|
||||
{
|
||||
$this->log (2, "## URL Start $this->method $this->url");
|
||||
$this->ssloptions = $ssloptions;
|
||||
$this->headersReceived = array ();
|
||||
$this->bodySize = null;
|
||||
$this->httpCode = null;
|
||||
@@ -507,20 +525,21 @@ class Httpclient
|
||||
|
||||
// Prepare the headers to be sent
|
||||
// {{{
|
||||
$this->headersSent = array ();
|
||||
$this->headersSent[] = "$this->method $path HTTP/1.1";
|
||||
$this->headersSent[] = "Host: ".$parseURL["host"];
|
||||
unset ($this->headersSent[0]);
|
||||
array_unshift ($this->headersSent,
|
||||
"$this->method $path HTTP/1.1");
|
||||
$this->headersSent["Host"] = $parseURL["host"];
|
||||
if ($this->acceptEncoding !== "")
|
||||
$this->headersSent[] = "Accept-Encoding: $this->acceptEncoding";
|
||||
$this->headersSent["Accept-Encoding"] = $this->acceptEncoding;
|
||||
if ($this->acceptLanguage !== "")
|
||||
$this->headersSent[] = "Accept-Language: $this->acceptLanguage";
|
||||
$this->headersSent["Accept-Language"] = $this->acceptLanguage;
|
||||
if ($this->accept != "")
|
||||
$this->headersSent[] = "Accept: $this->accept";
|
||||
$this->headersSent["Accept"] = $this->accept;
|
||||
if ($this->useragent !== "")
|
||||
$this->headersSent[] = "User-Agent: $this->useragent";
|
||||
$this->headersSent["User-Agent"] = $this->useragent;
|
||||
if ($this->referer !== "")
|
||||
$this->headersSent[] = "Referer: $this->referer";
|
||||
$this->headersSent[] = "Connection: keep-alive";
|
||||
$this->headersSent["Referer"] = $this->referer;
|
||||
$this->headersSent["Connection"] = "keep-alive";
|
||||
$cookies = $this->cookieToSend ($this->url);
|
||||
if (! empty ($cookies))
|
||||
{
|
||||
@@ -528,7 +547,7 @@ class Httpclient
|
||||
}
|
||||
if ($this->method !== "GET" && ! empty ($this->formData))
|
||||
{
|
||||
$this->headersSent[] = "Content-Type: application/x-www-form-urlencoded";
|
||||
$this->headersSent["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
$len = 0;
|
||||
foreach ($this->formData as $key => $val)
|
||||
{
|
||||
@@ -546,8 +565,16 @@ class Httpclient
|
||||
else
|
||||
$len += strlen (rawurlencode ($val));
|
||||
}
|
||||
$this->headersSent[] = "Content-Length: $len";
|
||||
$this->headersSent["Content-Length"] = $len;
|
||||
}
|
||||
if ($this->method !== "GET" && $this->rawData !== "")
|
||||
{
|
||||
if (! key_exists ("Content-Type", $this->headersSent))
|
||||
$this->headersSent["Content-Type"] =
|
||||
"application/x-www-form-urlencoded";
|
||||
$this->headersSent["Content-Length"] = strlen ($this->rawData);
|
||||
}
|
||||
|
||||
$this->log (2, "Headers Send :");
|
||||
$this->log (2, $this->headersSent);
|
||||
// }}}
|
||||
@@ -561,12 +588,15 @@ class Httpclient
|
||||
$this->tcpclient->timeout ($this->timeout);
|
||||
$this->tcpclient->connect ();
|
||||
if ($parseURL["scheme"] === "https")
|
||||
$this->tcpclient->cryptoEnable (true, null, $ssloptions);
|
||||
$this->tcpclient->cryptoEnable (true, null, $this->ssloptions);
|
||||
}
|
||||
$this->tcpclient->readMode ("text");
|
||||
foreach ($this->headersSent as $header)
|
||||
$this->tcpclient->send ($this->headersSent[0]."\r\n");
|
||||
foreach ($this->headersSent as $header => $value)
|
||||
{
|
||||
$this->tcpclient->send ("$header\r\n");
|
||||
if ($header === 0)
|
||||
continue;
|
||||
$this->tcpclient->send ("$header: $value\r\n");
|
||||
}
|
||||
$this->tcpclient->send ("\r\n");
|
||||
// }}}
|
||||
@@ -595,6 +625,10 @@ class Httpclient
|
||||
$i ++;
|
||||
}
|
||||
}
|
||||
elseif ($this->method !== "GET" && $this->rawData !== "")
|
||||
{
|
||||
$this->tcpclient->send ($this->rawData);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Get the result header from the server
|
||||
@@ -649,8 +683,7 @@ class Httpclient
|
||||
$this->contentMethod = "chunked";
|
||||
$this->bodySize = 0;
|
||||
}
|
||||
elseif (key_exists ("Content-Length", $headers) &&
|
||||
$headers["Content-Length"] > 0)
|
||||
elseif (key_exists ("Content-Length", $headers))
|
||||
{
|
||||
$this->contentMethod = "Content-Length";
|
||||
$this->bodySize = $headers["Content-Length"];
|
||||
@@ -667,12 +700,59 @@ class Httpclient
|
||||
}
|
||||
if ($this->contentMethod === "chunked")
|
||||
$this->log (1, "URL $this->method $this->url $this->httpCode Chunked");
|
||||
elseif (is_int ($this->bodySize))
|
||||
elseif (is_numeric ($this->bodySize))
|
||||
$this->log (1, "URL $this->method $this->url $this->httpCode ".
|
||||
$this->bodySize);
|
||||
else
|
||||
$this->log (1, "URL $this->method $this->url $this->httpCode 0");
|
||||
// }}}
|
||||
return $this;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the content from the server and put it in memory
|
||||
*/
|
||||
public function getContent ()
|
||||
// {{{
|
||||
{
|
||||
$url = $this->url;
|
||||
$content = "";
|
||||
while ($tmp = $this->read (1000000))
|
||||
{
|
||||
$content .= $tmp;
|
||||
if (strlen ($content) > $this->maxsize)
|
||||
throw new \Exception ("File to get exceeded maxsize", 500);
|
||||
}
|
||||
$this->disconnect ();
|
||||
if ($this->httpCode === 301 || $this->httpCode === 302 ||
|
||||
key_exists ("Location", $this->headersReceived))
|
||||
{
|
||||
if (! key_exists ("Location", $this->headersReceived))
|
||||
throw new \Exception ("Redirect without location provided", 406);
|
||||
$this->redirectCount++;
|
||||
if ($this->redirectCount > $this->redirectMaxCount)
|
||||
throw new \Exception ("Redirect exceed maximum limit", 406);
|
||||
// echo "REDIRECT TO ".$this->headersReceived["Location"]."\n";
|
||||
$location = $this->headersReceived["Location"];
|
||||
$parseURLInit = parse_url ($url);
|
||||
$parseURLLocation = parse_url ($location);
|
||||
if ($parseURLLocation["path"]{0} !== "/" &&
|
||||
key_exists ("path", $parseURLInit))
|
||||
$location = dirname ($parseURLInit["path"]).$location;
|
||||
if (! key_exists ("port", $parseURLLocation) &&
|
||||
key_exists ("port", $parseURLInit))
|
||||
$location = ":".$parseURLInit["port"].$location;
|
||||
if (! key_exists ("host", $parseURLLocation))
|
||||
$location = $parseURLInit["host"].$location;
|
||||
if (! key_exists ("scheme", $parseURLLocation))
|
||||
$location = $parseURLInit["scheme"]."://".$location;
|
||||
$this->log (1, "REDIRECT $this->httpCode to $location");
|
||||
$this->log (2, " content=$content\n");
|
||||
$content = $this->getPage ($location, $this->ssloptions);
|
||||
}
|
||||
$this->referer = $url;
|
||||
$this->redirectCount = 0;
|
||||
return $content;
|
||||
}
|
||||
// }}}
|
||||
|
||||
@@ -688,12 +768,6 @@ class Httpclient
|
||||
if ($this->tcpclient === null)
|
||||
throw new \Exception ("HTTPClient : can not read non connected URL", 406);
|
||||
$this->tcpclient->timeout ($this->timeout);
|
||||
/* if ($this->contentMethod === false)
|
||||
{
|
||||
// If the server will never send anything, code 204 by example, do not try
|
||||
// to get data
|
||||
return "";
|
||||
}*/
|
||||
$content = "";
|
||||
if ($this->contentMethod === "chunked" && $this->bodySize === 0)
|
||||
{
|
||||
@@ -711,7 +785,8 @@ class Httpclient
|
||||
if ($toBeRead > $maxsize)
|
||||
$toBeRead = $maxsize;
|
||||
$this->tcpclient->readMode ("binary");
|
||||
$content = $this->tcpclient->read ($toBeRead);
|
||||
if ($toBeRead > 0)
|
||||
$content = $this->tcpclient->read ($toBeRead);
|
||||
// In close mode, the bodySize is not set and should not be updated
|
||||
if ($this->bodySize !== null)
|
||||
$this->bodySize = $this->bodySize - strlen ($content);
|
||||
|
||||
Reference in New Issue
Block a user