substr($response, 0, $headerSize), 'content' => substr($response, $headerSize), 'status' => curl_getinfo($ch, CURLINFO_HTTP_CODE) ); } } else { // explicitly turn FOLLOWLOCATION off, just in case servers do weird things. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // use a local copy of the cURL handle. $local = curl_copy_handle($ch); $redirected = false; $target = curl_getinfo($local, CURLINFO_EFFECTIVE_URL); $last = parse_url($target); // need to maintain a reference to the last redirect in case following redirects are relative paths. if (empty($last['hostname'])) { // relative path on the server, very trivial attempt to build a correct path so it may not work in all cases $last = parse_url("http" . (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 's://' : '://') . $_SERVER['HTTP_HOST'] . $target); } $redirectCodes = array(301,302,307); // no support for 305 proxy redirects...yet :) $headers = array(); // maintain the headers throughout the redirection. do { curl_setopt($local, CURLOPT_URL, $target); if (!($response = curl_exec($local))) { break; } $code = curl_getinfo($local, CURLINFO_HTTP_CODE); $headerSize = curl_getinfo($local, CURLINFO_HEADER_SIZE); $header = substr($response, 0, $headerSize); $headers[] = rtrim($header); $redirected = in_array($code, $redirectCodes); if ($redirected) { if (preg_match('/^(?:Location|URI):\\s*([^\\r\\n]+)/m', $header, $matches) !== 1) { trigger_error("Requested resource is redirecting incorrectly.", E_USER_WARNING); $redirected = false; // set the loop-breaking condition. $response = false; // invalidate the response } $target = parse_url(trim($matches[1])); if (empty($target['scheme'])) { // relative redirect, use the last url $target = $last['scheme'] . '://' . $last['host'] . $target['path']; $last = parse_url($target); } elseif ($target['scheme'] === 'file') { // Redirecting into the file:// protocol, can be unsafe trigger_error("Requested resource is attempting to redirect to files on the local system.", E_USER_WARNING); $redirected = false; // set the loop-breaking condition. $response = false; // invalidate the response } else { $target = trim($matches[1]); $last = parse_url($target); } if ($code === 302) { // Many browsers implemented the 302-redirect in this way. i.e subsequent redirects // used the GET method, even when the original method used POST. // See http://en.wikipedia.org/wiki/HTTP_302 for more information. curl_setopt($local, CURLOPT_HTTPGET, true); } } } while($redirected && --$max >= 0); if ($response !== false) { $response = array( 'headers' => implode("\r\n\r\n", $headers), // standard is an CRLF seperator between headers as far as I know. 'content' => substr($response, curl_getinfo($local, CURLINFO_HEADER_SIZE)), 'status' => curl_getinfo($local, CURLINFO_HTTP_CODE) ); } curl_close($local); } return $response; } ?>