예제 #1
0
/**
 * 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;
}