* @license BSD */ namespace Domframework; require_once ("domframework/tcpclient.php"); /** 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. */ class Httpclient { ////////////////////////// //// PROPERTIES //// ////////////////////////// // {{{ /** The debug depth. 0: Nothing is displayed, 1: Only URL are displayed, * 2: headers only, 3: all the content */ private $debug = null; /** The URL to use */ private $url = ""; /** The cookies */ private $cookies = array (); /** Store the session cookies when analyzing the answer of the server */ private $cookiesSession = true; /** The headersReceived */ private $headersReceived = array (); /** The headersSent to the server */ private $headersSent = array (); /** The Method used to communicate : GET, POST, HEAD, PUT, DELETE */ private $method = "GET"; /** The TCP port used for connection */ private $port = null; /** The TCPClient object */ private $tcpclient = null; /** The SSL Options parameters (if set) */ private $ssloptions = array (); /** Authentication value */ private $authentication = ""; /** The maximum maxsize allowed */ private $maxsize; /** The returned HTTP code from the server */ private $httpCode = null; /** The body size staying to read */ private $bodySize = null; /** The content method to get the content : chunked or Content-Length */ private $contentMethod = false; /** Follow X redirects before abort */ private $redirectMaxCount = 10; /** The actual number of redirect */ private $redirectCount = 0; /** The form data to send * Will be of type array ("field" => "value") * If value is like "@/tmp/file", use the /tmp/file as content */ private $formData = array (); /** The raw data to send */ private $rawData = ""; /** The timeout in second before expiring the connection */ private $timeout = 30; /** Store the user agent. If it is empty, it will not be sent to the server */ private $useragent = "HTTPClient"; /** The last valid page known. Used as referer */ private $referer = ""; /** The accept type of data wanted by the client */ private $accept = "text/html,application/xhtml+xml,application/xml;q=0.9,". "*/*;q=0.8"; /** The accept language wanted by the client */ private $acceptLanguage = "en-us,en;q=0.5"; /** The accept encoding wanted by the client */ private $acceptEncoding = "gzip, deflate"; // }}} /** The constructor */ public function __construct () // {{{ { $maxsize = str_replace (array ('G', 'M', 'K'), array ('000000000', '000000', '000'), ini_get ('memory_limit')); $maxsize = intval ($maxsize / 2); // If no maxsize limit, set to 8G if ($maxsize === 0) $maxsize = 8000000000; $this->maxsize = $maxsize; $this->headersReset (); } // }}} ///////////////////////////////// //// GETTERS / SETTERS //// ///////////////////////////////// /** Set / Get the url * @param string|null $url Set / Get the url */ public function url ($url = null) // {{{ { if ($url === null) return $this->url; if (! is_string ($url)) throw new \Exception ("Invalid url to set : not a string", 406); $this->url = $url; return $this; } // }}} /** Set / Get the cookies stored * @param array|null $cookies Set / Get the cookies */ public function cookies ($cookies = null) // {{{ { if ($cookies === null) return $this->cookies; if (! is_array ($cookies)) throw new \Exception ("Invalid cookies to set : not an array", 406); $this->cookies = $cookies; return $this; } // }}} /** Set / Get the method * @param string|null $method Set / Get the method */ public function method ($method = null) // {{{ { if ($method === null) 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; return $this; } // }}} /** Get the headersReceived after the page was get */ public function headersReceived () // {{{ { return $this->headersReceived; } // }}} /** Get the headers sent to the server after the page was get */ public function headersSent () // {{{ { return $this->headersSent; } // }}} /** 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 () // {{{ { return $this->port; } // }}} /** Set / Get the maximum maxsize allowed * @param integer|null $maxsize The maxsize in bytes */ public function maxsize ($maxsize = null) // {{{ { if ($maxsize === null) return $this->maxsize; $this->maxsize = intval ($maxsize); return $this; } // }}} /** Get the HTTP Return code from connection */ public function httpCode () // {{{ { return $this->httpCode; } // }}} /** Set / Get the debug mode * 0: Nothing is displayed, 1: Only URL are displayed, * 2: headers only send and received, 3: all the content, but without sent * files, 4: all the content * @param boolean|null $debug The debug value to set or get */ public function debug ($debug = null) // {{{ { if ($debug === null) return $this->debug; $this->debug = intval ($debug); return $this; } // }}} /** Set / Get the form Data * Will be of type array ("field" => "value") * 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 = null) // {{{ { if ($formData === null) return $this->formData; 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; } // }}} /** Get / Set the Store of session cookies when analyzing the answer of the * server * @param boolean|null $cookiesSession Allow to store the session cookies */ public function cookiesSession ($cookiesSession = null) // {{{ { if ($cookiesSession === null) return $this->cookiesSession; $this->cookiesSession = !! $cookiesSession; return $this; } // }}} /** Get / Set the maximum number of redirect to follow before aborting * @param integer|null $redirectMaxCount The maximum number of redirect * before exception */ public function redirectMaxCount ($redirectMaxCount = null) // {{{ { if ($redirectMaxCount === null) return $this->redirectMaxCount; $this->redirectMaxCount = intval ($redirectMaxCount); return $this; } // }}} /** Get / Set the actual number of redirect * @param integer|null $redirectCount The actual number of redirect */ public function redirectCount ($redirectCount = null) // {{{ { if ($redirectCount === null) return $this->redirectCount; $this->redirectCount = intval ($redirectCount); return $this; } // }}} /** Get / Set the timeout in second before expiring the connection * 30s by default * @param integer|null $timeout The timeout value */ public function timeout ($timeout = null) // {{{ { if ($timeout === null) return $this->timeout; $this->timeout = intval ($timeout); return $this; } // }}} /** Get / Set the useragent sent to the server. If it is empty, it will not be * sent * @param string|null $useragent The user agent to use */ public function useragent ($useragent = null) // {{{ { if ($useragent === null) return $this->useragent; $this->useragent = $useragent; return $this; } // }}} /** Get/Set the referer page * @param string|null $referer The new referer that will be used on next * request */ public function referer ($referer = null) // {{{ { if ($referer === null) return $this->referer; $this->referer = $referer; return $this; } // }}} /** Get/Set the accept type of page wanted by the client * @param string|null $accept The accept types with weight */ public function accept ($accept = null) // {{{ { if ($accept === null) return $this->accept; $this->accept = $accept; return $this; } // }}} /** Get/Set the accept Language wanted by the client * @param string|null $acceptLanguage The languages with weight */ public function acceptLanguage ($acceptLanguage = null) // {{{ { if ($acceptLanguage === null) return $this->acceptLanguage; $this->acceptLanguage = $acceptLanguage; return $this; } // }}} /** Get/Set the accept Encoding wanted by the client * @param string|null $acceptEncoding The encoding requested */ public function acceptEncoding ($acceptEncoding = null) // {{{ { if ($acceptEncoding === null) return $this->acceptEncoding; $this->acceptEncoding = $acceptEncoding; return $this; } // }}} /** Set the authentication in Basic type * @param string $login The login to use * @param string $password The password to use */ public function authBasic ($login, $password) // {{{ { $this->authentication = "Basic ". base64_encode ("$login:$password"); return $this; } // }}} /** Get/Set authentication * To remove authentication, pass "" to $auth arg * @param string|null $auth The authentication string to send * @return value or $this */ public function authentication ($auth = null) // {{{ { if ($auth === null) return $this->authentication; $this->authentication = $auth; return $this; } // }}} /** Get/Set the ssl options * @param array|null $ssloptions The SSL Options to use * @return $this */ public function ssloptions ($ssloptions = null) // {{{ { if ($ssloptions === null) return $this->ssloptions; $this->ssloptions = $ssloptions; return $this; } // }}} /** Get meta data, like the timeout state, the crypto protocol and ciphers... */ public function getMeta () // {{{ { return $this->tcpclient->getMeta (); } // }}} /** Return the TCP infos of the connection */ public function getInfo () { return $this->tcpclient->getInfo (); } ////////////////////////////////// //// THE ACTIVE METHODS //// ////////////////////////////////// /** Get the page * Will fill the headersReceived, cookies and port properties. * This will fill all the RAM if the page is too big. For big files, use * $httpclient->url ($url) * ->connect () ; * while ($content = $httpclient->read ()) {} * $httpclient->disconnect (); * If no maxsize limit is set, limit the download to 8G * @param string $url The URL to get * @param array|null $ssloptions The SSL options (stream_context_set_option) * @return the page body */ public function getPage ($url, $ssloptions = null) // {{{ { $this->method ("GET"); $this->url ($url); $this->connect ($ssloptions); return $this->getContent (); } // }}} /** Init the connection to URL * Will fill the headersReceived, cookies and port properties. * @param array|null $ssloptions The SSL options (stream_context_set_option) * @return $this */ public function connect ($ssloptions = null) // {{{ { $this->log (2, "## URL Start $this->method $this->url"); if ($ssloptions !== null) $this->ssloptions = $ssloptions; $this->headersReceived = array (); $this->bodySize = null; $this->httpCode = null; if ($this->url === "") throw new \Exception ("No URL set to connect", 406); // Manage the URL (and the parameters in GET method) // {{{ $parseURL = parse_url ($this->url); if (! key_exists ("scheme", $parseURL)) throw new \Exception ("Scheme must be set to http or https", 406); if ($parseURL["scheme"] !== "http" && $parseURL["scheme"] !== "https") throw new \Exception ("Scheme must be http or https only", 406); if (key_exists ("port", $parseURL)) $this->port = $parseURL["port"]; elseif (key_exists ("scheme", $parseURL)) { if ($parseURL["scheme"] === "http") $this->port = 80; elseif ($parseURL["scheme"] === "https") $this->port = 443; } if (! key_exists ("path", $parseURL)) $path = "/"; else $path = $parseURL["path"]; if (key_exists ("query", $parseURL)) $path .= "?".$parseURL["query"]; if ($this->method === "GET" && ! empty ($this->formData)) { // In GET method, the form data are added to the path if (! key_exists ("query", $parseURL)) $path .= "?"; else $path .= "&"; $i = 0; foreach ($this->formData as $key => $val) { if ($i > 0) $path .= "&"; $path .= rawurlencode ($key)."="; if (isset ($val{0}) && $val{0} === "@") { $file = substr ($val, 1); if (! file_exists ($file)) throw new \Exception ("Data file '$file' doesn't exists", 406); $val = file_get_contents ($file); } $path .= rawurlencode ($val); $i ++; } } if (key_exists ("fragment", $parseURL)) $path .= "#".$parseURL["fragment"]; if (! key_exists ("host", $parseURL)) throw new \Exception ("No host provided to URL", 406); // }}} // Prepare the headers to be sent // {{{ 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; if ($this->acceptLanguage !== "") $this->headersSent["Accept-Language"] = $this->acceptLanguage; if ($this->accept != "") $this->headersSent["Accept"] = $this->accept; if ($this->useragent !== "") $this->headersSent["User-Agent"] = $this->useragent; if ($this->referer !== "") $this->headersSent["Referer"] = $this->referer; if ($this->authentication !== "") $this->headersSent["Authorization"] = $this->authentication; $this->headersSent["Connection"] = "keep-alive"; $cookies = $this->cookieToSend ($this->url); if (! empty ($cookies)) { $this->headersSent["Cookie"] = implode ("; ", $cookies); } if ($this->method !== "GET" && ! empty ($this->formData)) { if (! key_exists ("Content-Type", $this->headersSent)) $this->headersSent["Content-Type"] = "application/x-www-form-urlencoded"; $len = 0; foreach ($this->formData as $key => $val) { if ($len > 0) $len++; // Add the & $len += strlen (rawurlencode ($key)) + 1; if (isset ($val{0}) && $val{0} === "@") { $file = substr ($val, 1); if (! file_exists ($file)) throw new \Exception ("Data file '$file' doesn't exists", 406); // TODO : Do a loop of 1MB for big files instead of loading the mem $len += strlen (rawurlencode (file_get_contents ($file))); } else $len += strlen (rawurlencode ($val)); } $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); // }}} // Send the request to the server // {{{ if ($this->tcpclient === null) { $this->tcpclient = new tcpclient ($parseURL["host"], $this->port); $this->tcpclient->timeout ($this->timeout); $this->tcpclient->connect (); if ($parseURL["scheme"] === "https") $this->tcpclient->cryptoEnable (true, null, $this->ssloptions); } $this->tcpclient->readMode ("text"); $this->tcpclient->send ($this->headersSent[0]."\r\n"); foreach ($this->headersSent as $header => $value) { if ($header === 0) continue; $this->tcpclient->send ("$header: $value\r\n"); } $this->tcpclient->send ("\r\n"); // }}} // Send the POST data form if exists // {{{ if ($this->method !== "GET" && ! empty ($this->formData)) { $i = 0; $this->log (3, "Body Send : \n"); foreach ($this->formData as $key => $val) { if ($i > 0) { $this->tcpclient->send ("&"); $this->log (3, "&"); } $this->tcpclient->send (rawurlencode ($key)."="); $this->log (3, rawurlencode ($key)."="); if (isset ($val{0}) && $val{0} === "@") { $file = substr ($val, 1); if (! file_exists ($file)) throw new \Exception ("Data file '$file' doesn't exists", 406); // TODO : Do a loop of 1MB for big files instead of loading the mem $val = file_get_contents ($file); $this->tcpclient->send (rawurlencode ($val)); $this->log (4, rawurlencode ($val)); } else { $this->tcpclient->send (rawurlencode ($val)); $this->log (3, rawurlencode ($val)); } $i ++; } $this->log (3, "\n"); } elseif ($this->method !== "GET" && $this->rawData !== "") { $this->tcpclient->send ($this->rawData); $this->log (3, $this->rawData."\n"); } // }}} // Get the result header from the server // {{{ $headers = array (); while (($header = $this->tcpclient->read (4095)) !== "") { @list ($key, $val) = explode (":", $header, 2); if ($val === null) $headers[] = $header; else { if (key_exists ($key, $headers)) { if (! (is_array ($headers[$key]))) $headers[$key] = array ($headers[$key]); $headers[$key][] = trim ($val); } else $headers[$key] = trim ($val); } } if (! key_exists (0, $headers)) throw new \Exception ("No HTTP code available from server", 500); $this->headersReceived = $headers; $returnCode = $headers[0]; preg_match_all ("#^HTTP/(?P\d.\d) (?P\d+) ". "(?P.+)$#i", $returnCode, $matches); if (isset ($matches["HTTPCode"][0])) $this->httpCode = intval ($matches["HTTPCode"][0]); // Add the received cookies to property if (isset ($headers["Set-Cookie"])) { if (! is_array ($headers["Set-Cookie"])) $cookies = array ($headers["Set-Cookie"]); else $cookies = $headers["Set-Cookie"]; foreach ($cookies as $cookie) { // The invalid cookies are silently dropped $this->cookieAdd ($parseURL["host"], $cookie); } } $this->log (2, "Headers Received :"); $this->log (2, $this->headersReceived); $this->contentMethod = false; if (key_exists ("Transfer-Encoding", $headers) && $headers["Transfer-Encoding"] === "chunked") { $this->contentMethod = "chunked"; $this->bodySize = 0; } elseif (key_exists ("Content-Length", $headers)) { $this->contentMethod = "Content-Length"; $this->bodySize = $headers["Content-Length"]; } elseif (key_exists ("Connection", $headers) && $headers["Connection"] === "close") { // Connection closed by server. Nothing to get } elseif ($this->httpCode !== 204 && $this->httpCode !== 301 && $this->httpCode !== 302) { throw new \Exception ("No transfert content provided", 500); } if ($this->contentMethod === "chunked") $this->log (1, "URL $this->method $this->url $this->httpCode Chunked"); 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); } if (key_exists ("Content-Encoding", $this->headersReceived)) { if ($this->headersReceived["Content-Encoding"] === "gzip" && function_exists ("gzdecode")) $content = gzdecode ($content); } $this->disconnect (); $this->headersReset (); $this->formData = ""; $this->rawData = ""; 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; } // }}} /** Read max MAXSIZE bytes * Return "" if all the file is received * 3 methods are supported : Chunked mode, Content-Length defined and all * until the connection will be closed by the server * @param integer $maxsize The maxsize to get in this read */ public function read ($maxsize = 4096) // {{{ { if ($this->tcpclient === null) throw new \Exception ("HTTPClient : can not read non connected URL", 406); $this->tcpclient->timeout ($this->timeout); $content = ""; if ($this->contentMethod === "chunked" && $this->bodySize === 0) { // Get the body chunk size $this->tcpclient->readMode ("text"); $size = trim ($this->tcpclient->read ()); $this->bodySize = hexdec ($size); } if ($this->bodySize === 0) return ""; if ($this->bodySize === null) $toBeRead = $maxsize; else $toBeRead = $this->bodySize; if ($toBeRead > $maxsize) $toBeRead = $maxsize; $this->tcpclient->readMode ("binary"); 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); if ($this->contentMethod === "chunked" && $this->bodySize === 0) { // Get the Carriage return before the next chunk size $this->tcpclient->readMode ("text"); $cr = trim ($this->tcpclient->read ()); } $this->log (3, $content); return $content; } // }}} /** Disconnect the connection */ public function disconnect () // {{{ { $this->tcpclient = null; } // }}} /** Display the log message * @param integer $priority The minimal priority to display the message * @param mixed $message The message to display */ public function log ($priority, $message) { if ($this->debug < $priority) return; if (is_array ($message)) print_r ($message); elseif (is_bool ($message)) { if ($message) echo "TRUE\n"; else echo "FALSE\n"; } else { echo "$message"; if ($priority < 3) echo "\n"; } } /** Return the base URL of the site * @return the URL */ public function baseURL () // {{{ { if ($this->url === "") throw new \Exception ("Can not get baseURL of empty url", 500); $parseURL = parse_url ($this->url); $scheme = isset ($parseURL['scheme']) ? $parseURL['scheme'] . '://' : ''; $host = isset ($parseURL['host']) ? $parseURL['host'] : ''; $port = isset ($parseURL['port']) ? ':' . $parseURL['port'] : ''; $user = isset ($parseURL['user']) ? $parseURL['user'] : ''; $pass = isset ($parseURL['pass']) ? ':' . $parseURL['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; return "$scheme$user$pass$host$port"; } // }}} ////////////////////////////////// //// COOKIES MANAGEMENT //// ////////////////////////////////// /** The cookies are stored in Netscape cookies.txt file : The layout of Netscape's cookies.txt file is such that each line contains one name-value pair. An example cookies.txt file may have an entry that looks like this: .netscape.com TRUE / FALSE 946684799 NETSCAPE_ID 100103 Each line represents a single piece of stored information. A tab is inserted between each of the fields. From left-to-right, here is what each field represents: domain : The domain that created AND that can read the variable. flag : A TRUE/FALSE value indicating if all machines within a given domain can access the variable. This value is set automatically by the browser, depending on the value you set for domain. path : The path within the domain that the variable is valid for. secure : A TRUE/FALSE value indicating if a secure connection with the domain is needed to access the variable. expiration : The UNIX time that the variable will expire on. UNIX time is defined as the number of seconds since Jan 1, 1970 00:00:00 GMT. name : The name of the variable. value : The value of the variable. */ /** Add a cookie in the store * If the cookie already exists, the old one is replaced by the new value * @param string $domain The domain to use * @param string $cookie The cookie content to store */ public function cookieAdd ($domain, $cookie) // {{{ { // echo "COOKIE = $cookie\n"; $content = explode (";", $cookie); $flag = "FALSE"; $path = "/"; $secure = "FALSE"; $expiration = 0; $name = ""; $value = ""; foreach ($content as $part) { @list ($key, $val) = explode ("=", $part, 2); $key = trim ($key); if (strtolower ($key) === "path") $path = $val; elseif (strtolower ($key) === "domain") { // Check if $domain is compatible with $key before storing the cookie if (substr ($domain, -1 * strlen ($val)) === $val) { $domain = $val; $flag = "TRUE"; } else { return "Invalid domain provided"; } } elseif (strtolower ($key) === "expires") { try { $date = new \DateTime ($val); $expiration = $date->getTimestamp(); } catch (\Exception $e) { return "Invalid expires date provided"; } } elseif ($val !== null && $name === "") { // Only the first value will be stored as cookie (name, val) pair // echo "KEY=$key => $val\n"; $name = $key; $value = $val; } elseif ($val !== null) { // echo "Not managed key=>val $key=>$val\n"; } else { // No value provided : no test } } $cookieLine = "$domain\t$flag\t$path\t$secure\t$expiration\t$name\t$value"; if (strlen ($cookieLine) > 4096) return "Cookie value too long"; if ($expiration === 0 && $this->cookiesSession === false) { // echo "Do not store Session cookies\n"; return; } $found = false; foreach ($this->cookies as $key => $storedCookie) { $storedCookie = explode ("\t", $storedCookie); if (! key_exists (0, $storedCookie) || ! key_exists (5, $storedCookie)) continue; if ($storedCookie[0] !== $domain || $storedCookie[5] !== $name) continue; if ($expiration > 0 && $expiration < time ()) { //echo "Remove the already set cookie for $domain $name : expired\n"; unset ($this->cookies[$key]); $found = true; } else { //echo "Update the already set cookie for $domain $name\n"; $this->cookies[$key] = $cookieLine; $found = true; } } if ($found === false) { //echo "Append the new cookie for $domain $name\n"; $this->cookies[] = $cookieLine; } } // }}} /** Check if some stored cookies must be send to the server, because they are * in the same domain. * @param string $url The URL requested * @return array the cookies to add to the headers send to the server */ public function cookieToSend ($url) // {{{ { $parseURL = parse_url ($this->url); if ($parseURL === false) return array (); if (! key_exists ("host", $parseURL)) return array (); if (! key_exists ("path", $parseURL)) $parseURL["path"] = "/"; if ($parseURL["path"]{0} !== "/") $parseURL["path"] = "/".$parseURL["path"]; $res = array (); foreach ($this->cookies as $storedCookie) { $storedCookie = explode ("\t", $storedCookie); if (! key_exists (0, $storedCookie) || ! key_exists (2, $storedCookie) || ! key_exists (5, $storedCookie) || ! key_exists (6, $storedCookie)) continue; if ($storedCookie[0] !== substr ($parseURL["host"], -1 * strlen ($storedCookie[0])) || $storedCookie[2] !== substr ($parseURL["path"], 0, strlen ($storedCookie[2]))) continue; $res[] = $storedCookie[5]."=".$storedCookie[6]; } return $res; } // }}} }