curl follow location error
我收到此错误消息:
CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set in.
在我的网络托管上,safe_mode已关闭。
open_basedir是"。
我该如何解决?
解决方法是在PHP代码中实现重定向。
这是我自己的实现。它有两个已知的局限性:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function curl_exec_follow(/*resource*/ &$ch, /*int*/ $redirects = 20, /*bool*/ $curlopt_header = false) { if ((!ini_get('open_basedir') && !ini_get('safe_mode')) || $redirects < 1) { curl_setopt($ch, CURLOPT_HEADER, $curlopt_header); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $redirects > 0); curl_setopt($ch, CURLOPT_MAXREDIRS, $redirects); return curl_exec($ch); } else { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FORBID_REUSE, false); do { $data = curl_exec($ch); if (curl_errno($ch)) break; $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($code != 301 && $code != 302) break; $header_start = strpos($data," ")+2; $headers = substr($data, $header_start, strpos($data," ", $header_start)+2-$header_start); if (!preg_match("! (?:Location|URI): *(.*?) * !", $headers, $matches)) break; curl_setopt($ch, CURLOPT_URL, $matches[1]); } while (--$redirects); if (!$redirects) trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING); if (!$curlopt_header) $data = substr($data, strpos($data," ")+4); return $data; } } |
打印此警告消息的唯一位置是ext / curl / interface.c。
1 2 3 4 5 6 7 | if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) { if (Z_LVAL_PP(zvalue) != 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING,"CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set"); RETVAL_FALSE; return 1; } } |
从if条件可以看出,必须启用open_basedir或safe_mode。
不久前,我遇到了类似的情况,并在下面找到了解决方案。如果您大致知道将您重定向到的位置,则可能对您有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | function curl($url, $postVars) { $go = curl_init($url); curl_setopt ($go, CURLOPT_URL, $url); curl_setopt($go, CURLOPT_VERBOSE, 1); //follow on location problems if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { curl_setopt ($go, CURLOPT_FOLLOWLOCATION, $l); $syn = curl_exec($go); if(curl_error($go)) return false; } else $syn = curl_redir_exec($go, $postVars); curl_close($go); return $syn; } function curl_redir_exec($ch, $postVars) { static $curl_loops = 0; static $curl_max_loops = 20; if ($curl_loops++>= $curl_max_loops) { $curl_loops = 0; return FALSE; } curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postVars); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); $data = curl_exec($ch); if(curl_error($ch)) return false; list($header, $data) = explode(" ", $data, 2); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $redirect_page ="[0-9]*.html"; $base_redirect ="http://example.com/"; if ($http_code == 301 || $http_code == 302) { $matches = array(); $pregs = eregi($redirect_page, $data, $matches); $new_url = $base_redirect . $matches[0]; if (!$new_url) { //couldn't process the url to redirect to $curl_loops = 0; return $data; } curl_setopt($ch, CURLOPT_URL, $new_url); return curl_redir_exec($ch, $postVars); } else { $curl_loops=0; return $data; } } |
请注意:
此处包含代码的所有答案均手动解析curl请求中的标头,以找到
但是,从PHP 5.3.7开始,有一个选项
从未在实际环境中进行过测试,但是curl_exec具有更高的透明度(标头和returntransfer选项没有问题)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | function curl_exec_follow(/*resource*/ $ch, /*int*/ $maxredirect = 5) { if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); } else { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); $newurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $rch = curl_copy_handle($ch); curl_setopt($rch, CURLOPT_HEADER, true); curl_setopt($rch, CURLOPT_NOBODY, true); curl_setopt($rch, CURLOPT_RETURNTRANSFER, true); do { curl_setopt($rch, CURLOPT_URL, $newurl); $header = curl_exec($rch); if (curl_errno($rch)) { $code = 0; } else { $code = curl_getinfo($rch, CURLINFO_HTTP_CODE); if ($code == 301 || $code == 302) { preg_match('/Location:(.*?) /', $header, $matches); $newurl = trim(array_pop($matches)); } else { $code = 0; } } } while ($code && $maxredirect--); curl_close($rch); curl_setopt($ch, CURLOPT_URL, $newurl); } return curl_exec($ch); } |
如果已经配置了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | function curl_follow_exec($curl, $url = null) { curl_setopt($curl, CURLOPT_HEADER, true); if (!is_null($url)) { $opts = array ( CURLOPT_URL => $url, CURLOPT_POST => false, CURLOPT_PUT => false, ); curl_setopt_array($curl, $opts); } $data = curl_exec($curl); $status = curl_getinfo($curl); $arr = explode(" ", $data); while (strpos(reset($arr), 'HTTP/1.1 100 Continue') !== false) { array_shift($arr); } $header = $arr[0]; $body = implode(" ", array_slice($arr, 1)); if ($status['http_code'] == 301 || $status['http_code'] == 302) { $matches = array (); preg_match("/(Location:|URI:)[^( )]*/", $header, $matches); $url = trim(str_replace($matches[1],"", $matches[0])); return curl_follow_exec($curl, $url); } return $body; } |
注意:如果您已经指定了选项,则在调用此函数时不要提供URL,它仅用于递归目的。
我从可接受的答案中启发了这段代码,并添加了一些东西来管理多个标题。
此功能就像是针对ie6的丑陋骇客:如果可以,请更改您的托管:-)。