php 卷曲跟随位置错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2511410/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
curl follow location error
提问by embedded
I got this error message:
我收到此错误消息:
CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set in.
CURLOPT_FOLLOWLOCATION 在 safe_mode 或 open_basedir 设置时无法激活。
safe_mode is turned off on my web hosting.
我的虚拟主机上的 safe_mode 已关闭。
open_basedir is "".
open_basedir 是“”。
How do I resolve this?
我该如何解决?
回答by dolmen
The workaround is to implement redirection in PHP code.
解决方法是在 PHP 代码中实现重定向。
Here is my own implementation. It has two known limitations:
这是我自己的实现。它有两个已知的限制:
- It will force
CURLOPT_RETURNTRANSFER - It is incompatible with
CURLOPT_HEADERFUNCTION
- 它会强迫
CURLOPT_RETURNTRANSFER - 它不兼容
CURLOPT_HEADERFUNCTION
The code:
编码:
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, "\r\n")+2;
$headers = substr($data, $header_start, strpos($data, "\r\n\r\n", $header_start)+2-$header_start);
if (!preg_match("!\r\n(?:Location|URI): *(.*?) *\r\n!", $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, "\r\n\r\n")+4);
return $data;
}
}
回答by VolkerK
The only place where this warning message is printed is in ext/curl/interface.c
打印此警告消息的唯一位置是在 ext/curl/interface.c
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;
}
}
As you can see from the if-condition either open_basedir or safe_mode must be enabled.
从 if 条件中可以看出,必须启用 open_basedir 或 safe_mode。
回答by Patrick
I encountered a similar situation a while back and found the solution below. If you know generally where you'll be redirected to this might work for you.
不久前我遇到了类似的情况,并在下面找到了解决方案。如果您通常知道您将被重定向到的位置,这可能对您有用。
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("\n\r", $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;
}
}
回答by zsalab
Never tested in real environment but has more transparency with curl_exec (no problem with header and returntransfer options).
从未在真实环境中测试过,但使用 curl_exec 具有更高的透明度(标题和返回传输选项没有问题)。
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:(.*?)\n/', $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);
}
回答by Mrten
Just a note:
只是一个注意事项:
All answers with code here manually parse the headers from a curl request to find a Location:header.
此处的所有代码答案都手动解析 curl 请求中的Location:标头以查找标头。
However, since PHP 5.3.7, there is an option CURLINFO_REDIRECT_URLyou can use with curl_getinfo(). No need to do requests twice, no need to enable headers if you don't want them, no need for regexps.
但是,从 PHP 5.3.7 开始,有一个选项CURLINFO_REDIRECT_URL可以与curl_getinfo(). 不需要两次请求,不需要的话就不需要启用标头,不需要正则表达式。
回答by Alain Tiemblo
If you already have a $curlinstance already configured and just want to simulate curl_execwith FOLLOWLOCATION enabled, you can use this one:
如果您已经$curl配置了一个实例并且只想在curl_exec启用 FOLLOWLOCATION的情况下进行模拟,您可以使用这个:
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("\r\n\r\n", $data);
while (strpos(reset($arr), 'HTTP/1.1 100 Continue') !== false)
{
array_shift($arr);
}
$header = $arr[0];
$body = implode("\r\n", array_slice($arr, 1));
if ($status['http_code'] == 301 || $status['http_code'] == 302)
{
$matches = array ();
preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches);
$url = trim(str_replace($matches[1], "", $matches[0]));
return curl_follow_exec($curl, $url);
}
return $body;
}
Note: don't provide an URL when calling this function if you already specified the option, it is just used for recursive purposes.
注意:如果您已经指定了该选项,则在调用此函数时不要提供 URL,它仅用于递归目的。
I inspired this code from the accepted answer, and added some stuffs to manage multiple headers.
我从接受的答案中启发了这段代码,并添加了一些东西来管理多个标题。
This function is like an ugly hack for ie6: if you can, change your hosting :-).
这个功能就像 ie6 的丑陋黑客:如果可以,请更改您的主机 :-)。

