본문 바로가기

Story/php

PHP, cURL, CURLOPT FOLLOWLOCATION and Open Basedir or Safe Mode

반응형

PHP, cURL, CURLOPT FOLLOWLOCATION and Open Basedir or Safe Mode

 

php cURL 을 이용해서 rss feed 를 가져오는경우

 

    $ch = curl_init($url);
    curl_setopt( $ch, CURLOPT_POST, false );
    curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
    curl_setopt( $ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7" );
    curl_setopt( $ch, CURLOPT_HEADER, false );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    $data = curl_exec($ch);
    curl_close($ch);

 

    echo '<pre>';

    print_r($data);

    echo '</pre>';

 

와 같이 사용한다.

위의 예는 facebook page 를 가져올때 사용한 방법인대

$url = "http://www.facebook.com/feeds/page.php?id=241164952623108&format=rss20";

와 같이 사용해서 페이스북을 사용했다.

 

그런대 일부 서버에서 이게 동작하지 않고

Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set in /home/rss.php on line 11

와 같은 에러가 발생한다.

이 문제를 해결하기 위해서 구글링을 하던중 해결책을 발견했다.

 

function curl($url){
$go = curl_init($url);
curl_setopt ($go, CURLOPT_URL, $url);
//follow on location problems

if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')){
curl_setopt ($go, CURLOPT_FOLLOWLOCATION, $l);
$syn = curl_exec($go);
}else{
$syn = curl_redir_exec($go);
}
curl_close($go);
return $syn;
}

//follow on location problems workaround
function curl_redir_exec($ch)
{
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, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
list($header, $data) = explode("\n\n", $data, 2);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code == 301 || $http_code == 302)
{
$matches = array();
preg_match('/Location:(.*?)\n/', $header, $matches);
$url = @parse_url(trim(array_pop($matches)));
if (!$url)
{
//couldn't process the url to redirect to
$curl_loops = 0;
return $data;
}
$last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
if (!$url['scheme'])
$url['scheme'] = $last_url['scheme'];
if (!$url['host'])
$url['host'] = $last_url['host'];
if (!$url['path'])
$url['path'] = $last_url['path'];
$new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:'');
curl_setopt($ch, CURLOPT_URL, $new_url);
return curl_redir_exec($ch);
} else {
$curl_loops=0;
return $data;
}
}

이 방법으로 처리하니 해결은 되었으나 rss 값이 헤더 부분과 본문을 나누는 \n\n 부분에서 앞부분 일부가 잘리는 현상이 발견되었다.

그래서 이 함수를 수정해서 최종 사용한 함수는 다음과 같다.

function curl_redir_exec($ch){
    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, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $oridata = $data = curl_exec($ch);
    list($header, $data) = explode("\n\n", $data, 2);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($http_code == 301 || $http_code == 302){
        $matches = array();
        preg_match('/Location:(.*?)\n/', $header, $matches);
        $url = @parse_url(trim(array_pop($matches)));
        if (!$url){
            //couldn't process the url to redirect to
            $curl_loops = 0;
            return $data;
        }
        $last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
        if (!$url['scheme']) $url['scheme'] = $last_url['scheme'];
        if (!$url['host']) $url['host'] = $last_url['host'];
        if (!$url['path']) $url['path'] = $last_url['path'];
        $new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:'');
        curl_setopt($ch, CURLOPT_URL, $new_url);
        return curl_redir_exec($ch);
    } else {
        list($header, $data) = explode("\n\r", $oridata, 2);

        $curl_loops=0;
        return trim($data);
    }
}

 

 

 

출처 : http://edmondscommerce.github.io/curl/php-curl-curlopt_followlocation-and-open_basedir-or-safe-mode.html

반응형