/** * HTTP Client * * Returns the raw data from the given URL, uses proxy when configured * and follows redirects * * @author Andreas Goetz <*****@*****.**> * @param string $url URL to fetch * @param bool $cache use caching? defaults to false * @param string $post POST data, if nonempty POST is used instead of GET * @param integer $timeout Timeout in seconds defaults to 15 * @return mixed HTTP response */ function httpClient($url, $cache = false, $para = null, $reload = false) { global $config; // use this as workaround for php bug http://bugs.php.net/bug.php?id=22526 session_start/popen hang # session_write_close(); // <-- We don't use popen! But sometimes we need the session afterwards! (Chinamann) $method = 'GET'; $headers = ''; // additional HTTP headers, used for post data $post = $para['post']; if (is_array($post)) { $post = http_build_query($post); } if (!empty($post)) { // POST request $method = 'POST'; $headers .= "Content-Type: application/x-www-form-urlencoded\r\n"; $headers .= "Content-Length: " . strlen($post) . "\r\n"; } // get data from cache? if ($cache & !$reload) { $resp = getHTTPcache($url . $post); if ($resp !== false) { $resp['cached'] = true; return $resp; } } $response['error'] = ''; $response['header'] = ''; $response['data'] = ''; $response['url'] = $url; $response['success'] = false; $uri = parse_url($url); $server = $uri['host']; $path = $uri['path']; if (empty($path)) { $path = '/'; } if (!empty($uri['query'])) { $path .= '?' . $uri['query']; } $port = @$uri['port']; // proxy setup if (!empty($config['proxy_host']) && !$para['no_proxy']) { $request_url = $url; $server = $config['proxy_host']; $port = @$config['proxy_port']; if (!$port) { $port = 8080; } } else { $request_url = $path; // cpuidle@gmx.de: use $path instead of $url if HTTP/1.0 $server = $server; if (!$port) { $port = 80; } } // open socket $socket = fsockopen($server, $port); if (!$socket) { $response['error'] = "Could not connect to {$server}"; return $response; } stream_set_timeout($socket, $para['timeout'] ? $para['timeout'] : 10); // build request $request = "{$method} {$request_url} HTTP/1.0\r\n"; $request .= "Host: " . $uri['host'] . "\r\n"; $request .= "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)\r\n"; if (extension_loaded('zlib')) { $request .= "Accept-encoding: gzip\r\n"; } # $request .= "Accept-Charset: iso-8859-1, utf-8, *\r\n"; // add cookies- these are expcted to be in array form if ($para['cookies']) { $request .= cookies2header($para['cookies']); } $request .= "Connection: Close\r\n"; // additional request headers $request .= $headers; if ($para['header']) { $request .= $para['header']; } $request .= "\r\n"; $request .= $post; // send request fputs($socket, $request); if (@$config['debug']) { echo "request:<br>" . nl2br($request) . "<p>"; } // log request if (@$config['httpclientlog']) { $log = fopen('httpClient.log', 'a'); fwrite($log, $request . "\n"); fclose($log); } // read headers from socket while (!(feof($socket) || preg_match('/\\r\\n\\r\\n$/', $response['header']))) { $read = fgets($socket); $response['header'] .= $read; // $header_size += strlen($read); } // chunked encoding? if (preg_match('/transfer\\-(en)?coding:\\s+chunked\\r\\n/i', $response['header'])) { do { unset($chunk_size); do { $byte = fread($socket, 1); $chunk_size .= $byte; } while (preg_match('/[a-zA-Z0-9]/', $byte)); // read chunksize including \r $byte = fread($socket, 1); // read trailing \n $chunk_size = hexdec($chunk_size); $this_chunk = fread($socket, $chunk_size); $response['data'] .= $this_chunk; if ($chunk_size) { $byte = fread($socket, 2); } // read trailing \r\n } while ($chunk_size); } else { // read entire socket while (!feof($socket)) { $response['data'] .= fread($socket, 4096); } } // close socket $status = socket_get_status($socket); fclose($socket); if (@$config['debug']) { echo "header:<br>" . nl2br($response['header']) . "<p>"; } // if ($config['debug']) echo "data:<br>".htmlspecialchars($response['data'])."<p>"; // check for timeout if (@$status['timed_out']) { $response['error'] = "Connection timed out"; return $response; } // log response if (@$config['httpclientlog']) { $log = fopen('httpClient.log', 'a'); fwrite($log, $response['header'] . "\n"); fclose($log); } // check server status code to follow redirect if (preg_match("/^HTTP\\/1.\\d 30[12].*?\n/s", $response['header'])) { preg_match("/Location:\\s+(.*?)\n/is", $response['header'], $matches); if (empty($matches[1])) { $response['error'] = 'Redirect but no Location header found'; return $response; } else { // in case no redirect is needed stop here and respond success if ($para['no_redirect']) { // save time if result is not needed $response['error'] = ''; $response['success'] = true; return $response; } // get redirection target $location = trim($matches[1]); if (preg_match("/^\\//", $location)) { // local redirect $location = 'http://' . $uri['host'] . ':' . $uri['port'] . $location; } elseif (!preg_match('/^http/', $location)) { // local redirect without path $path = substr($uri['path'], 0, strrpos($uri['path'], '/') + 1); $location = 'http://' . $uri['host'] . ':' . $uri['port'] . $path . $location; } // don't use old headers again $headers = ''; // add new cookies from response $para['cookies'] = get_cookies_from_response($response, $para['cookies']); // perform redirected request; we must GET, not POST if ($para['post']) { unset($para['post']); } $response = httpClient($location, $cache, $para); // remember we were redirected $response['redirect'] = $location; // store response a 2nd time under the the original post attributes if ($response['success'] == true && $cache) { putHTTPcache($url . $post, $response); } return $response; } } // verify status code if (!preg_match("/^.*? 200 .*?\n/s", $response['header'])) { $response['error'] = 'Server returned wrong status.'; return $response; } $response['success'] = true; // decode data if necessary- do not modify original headers if (preg_match("/Content-Encoding:\\s+gzip\r?\n/i", $response['header'])) { $response['data'] = gzinflate(substr($response['data'], 10)); } // commit successful request to cache if ($cache) { putHTTPcache($url . $post, $response); } return $response; }
function httpClient($url, $cache = 0, $post = '', $timeout = 15, $cookies = null, $headers2 = '', $omitProxy = false, $omitRedirect = false) { global $config; // since we shouldn't don't need session functionality here, // use this as workaround for php bug #22526 session_start/popen hang session_write_close(); $method = 'GET'; $headers = ''; // additional HTTP headers, used for post data if (!empty($post)) { // POST request $method = 'POST'; $headers .= "Content-Type: application/x-www-form-urlencoded\r\n"; $headers .= "Content-Length: " . strlen($post) . "\r\n"; } $response['error'] = ''; $response['header'] = ''; $response['data'] = ''; $response['url'] = $url; $response['success'] = false; $uri = parse_url($url); $server = $uri['host']; $path = $uri['path']; if (empty($path)) { $path = '/'; } #get root on empty path if (!empty($uri['query'])) { $path .= '?' . $uri['query']; } $port = @$uri['port']; // proxy setup if (!empty($config['proxy_host']) && !$omitProxy) { $request_url = $url; $server = $config['proxy_host']; $port = $config['proxy_port']; if (empty($port)) { $port = 8080; } } else { $request_url = $path; // cpuidle@gmx.de: use $path instead of $url if HTTP/1.0 $server = $server; if (empty($port)) { $port = 80; } } // print "<pre>$request_url</pre>"; // open socket $socket = fsockopen($server, $port, $errno, $errstr, isset($config['connection_timeout']) ? $config['connection_timeout'] : 5); if (!$socket) { $response['error'] = "Could not connect to {$server}"; return $response; } socket_set_timeout($socket, $timeout); // build request $request = "{$method} {$request_url} HTTP/1.0\r\n"; $request .= "Host: " . $uri['host'] . "\r\n"; $request .= "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)\r\n"; // if (extension_loaded('zlib')) $request .= "Accept-encoding: gzip\r\n"; if ($cookies) { $request .= cookies2header($cookies); } $request .= "Connection: Close\r\n"; $request .= $headers; $request .= $headers2; $request .= "\r\n"; $request .= $post; // send request fputs($socket, $request); // read headers from socket do { $response['header'] .= fread($socket, 1); } while (!preg_match('/\\r\\n\\r\\n$/', $response['header']) && !feof($socket)); // read entire socket while (!feof($socket)) { $response['data'] .= fread($socket, 4096); } // chunked encoding? if (preg_match('/transfer\\-(en)?coding:\\s+chunked\\r\\n/i', $response['header'])) { $data2 = ""; $pos = 0; do { unset($chunk_size); do { $cb = 1; $byte = substr($response['data'], $pos, $cb); $pos += $cb; $chunk_size .= $byte; } while (preg_match('/[a-zA-Z0-9]/', $byte)); // read chunksize including \r while ($response['data'][$pos] != "\n") { $pos++; // readtrailing \n } $pos++; // readtrailing \n $chunk_size = hexdec($chunk_size); $this_chunk = substr($response['data'], $pos, $chunk_size); $pos += $chunk_size; $data2 .= $this_chunk; if ($chunk_size) { $pos += 2; } // read trailing \r\n } while ($chunk_size); $response['data'] = $data2; } // close socket $status = socket_get_status($socket); fclose($socket); // check for timeout if ($status['timed_out']) { $response['error'] = "Connection timed out"; return $response; } /* // verify status code if (!preg_match("/^.*? 200 .*?\n/s", $response['header'])) { $response['error'] = 'Server returned wrong status.'; return $response; }*/ $response['success'] = true; // decode data if necessary- do not modify original headers if (preg_match("/Content-Encoding:\\s+gzip\r?\n/i", $response['header'])) { $response['data'] = gzdecode($response['data']); } // decode UTF8 if (preg_match("/Content-Type:.*?charset=UTF-8/i", $response['header'])) { $response['data'] = utf8_decode($response['data']); } return $response; }