Curl 旋度跟随定位误差

Curl 旋度跟随定位误差,curl,php,Curl,Php,我收到了以下错误消息: 处于安全模式或中设置了打开的basedir时,无法激活CURLOPT_FOLLOWLOCATION 在我的web主机上已关闭安全模式 open_basedir为“” 如何解决此问题?打印此警告消息的唯一位置是ext/curl/interface.c if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) { if (Z_LVAL_PP(zvalue) != 0) { php_e

我收到了以下错误消息:

处于安全模式或中设置了打开的basedir时,无法激活CURLOPT_FOLLOWLOCATION

在我的web主机上已关闭安全模式

open_basedir为“”


如何解决此问题?

打印此警告消息的唯一位置是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;
  }
}

正如您从if条件中看到的,必须启用open\u basedir或safe\u模式。

我不久前遇到了类似的情况,并找到了下面的解决方案。如果你知道你将被重定向到哪里,这可能对你有用

    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;
    }
}

从未在实际环境中进行过测试,但使用curl_exec具有更高的透明度(header和returntransfer选项没有问题)


解决方法是在PHP代码中实现重定向

这是我自己的实现。它有两个已知的限制:

  • 它将强制
    CURLOPT\u RETURNTRANSFER
  • 它与卷发头功能不兼容
  • 守则:

    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;
        }
    }
    
    函数curl\u exec\u follow(/*resource*/&$ch,/*int*/$redirects=20,/*bool*/$curlopt\u header=false){
    如果(!ini_get('open_basedir')&&!ini_get('safe_mode'))| |$redirects<1){
    curl_setopt($ch,CURLOPT_头,$CURLOPT_头);
    curl_setopt($ch,CURLOPT_FOLLOWLOCATION,$redirects>0);
    curl_setopt($ch,CURLOPT_MAXREDIRS,$redirects);
    返回curl_exec($ch);
    }否则{
    curl_setopt($ch,CURLOPT_FOLLOWLOCATION,false);
    curl_setopt($ch,CURLOPT_头,true);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch,CURLOPT_禁止再使用,false);
    做{
    $data=curl\u exec($ch);
    if(旋度误差($ch))
    打破
    $code=curl\u getinfo($ch,CURLINFO\u HTTP\u code);
    如果($code!=301&&$code!=302)
    打破
    $header\u start=strpos($data,“\r\n”)+2;
    $headers=substr($data,$header\u start,strpos($data,“\r\n\r\n”,$header\u start)+2-$header\u start);
    if(!preg_match(!\r\n(?:Location|URI):*(*?*\r\n!,$headers,$matches))
    打破
    curl_setopt($ch,CURLOPT_URL,$matches[1]);
    }而(-$redirects);
    如果(!$重定向)
    trigger_error('重定向太多。在执行重定向时,libcurl达到最大值',E_USER_警告);
    if(!$curlopt_标题)
    $data=substr($data,STRPO($data,“\r\n\r\n”)+4);
    返回$data;
    }
    }
    
    如果您已经配置了
    $curl
    实例,并且只想在启用FOLLOWLOCATION的情况下模拟
    curl\u exec
    ,则可以使用此实例:

    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;
    }
    
    注意:调用此函数时不要提供URL。如果您已经指定了该选项,则它仅用于递归目的

    我从公认的答案中启发了这段代码,并添加了一些东西来管理多个标题

    这个功能就像ie6的一个丑陋的黑客:如果可以,请更改您的主机:-)。

    请注意:

    这里所有带代码的答案都手动解析curl请求的标题,以查找
    位置:
    标题


    但是,从PHP5.3.7开始,有一个选项
    CURLINFO\u REDIRECT\u URL
    可以与
    curl\u getinfo()
    一起使用。不需要执行两次请求,不需要启用头文件(如果不需要),也不需要regexp

    有没有办法克服这个问题?与自定义跟随位置函数或类似函数一样,您可以使用
    curl\u getinfo($ch,CURLINFO\u HTTP\u code)
    如果返回301或302,则获取位置:header。这是zsalab的实现此实现有两个问题:1。如果发生错误,它将丢失;2.最终URL的请求会执行两次(一次只针对标题,一次完整)
    ini\u get('safe\u mode'='Off')
    Typo(括号中应该包含'safe\u mode',并且不会在任何地方都起作用),我需要添加
    &&$code=303
    (参见其他)到do循环中的if条件,以复制我的
    CURLOPT_FOLLOWLOCATION=true
    行为。相关博客文章-这也不完美,但如果有人想查看代码,可能会有所帮助。您可以轻松提取引用的站点链接:这里回答:
    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;
    }