Ubuntu One Oauth login from PHP

I have searched the whole internet trying to find a simple example that could point me in the right direction, but no luck, so here comes my questions:

I want to log into Ubuntu One and sync (or almost read) files from my web page, all done with PHP. The needs to reach files are all described in that page: https://one.ubuntu.com/developer/account_admin/issue_tokens/cloud/

I am able to complete the first request with:

$url = 'https://login.ubuntu.com/api/1.0/authentications?ws.op=authenticate&token_name=Ubuntu%20One%20@%20try1';
$data = curlPetition(array('URL'=>$url,'USERPWD'=>'user:pass'));
$ar = fopen('uOne','w');fwrite($ar,$data['responseBody']);fclose($ar);
$tokenA = json_decode($data['responseBody'],1);

Ok, curlPetition only makes basic curl petitions. Note that you need a valid user:pass ubuntu one account. I get the response correctly in json with "consumer_secret" , "token" , "consumer_key" , "name" , "token_secret". Even the entry appear listed in the ubuntu one's granted apps.

I hace installed the most new OAuth PCL php extensión and its working good. but when I try to:

    $api_url = 'https://one.ubuntu.com/api/file_storage/v1/';
    $conskey = $tokenA['consumer_key'];
    $conssec = $tokenA['consumer_secret'];
    $token = $tokenA['token'];
    $secret = $tokenA['token_secret'];
    $oauth = new OAuth($conskey,$conssec,OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
    $oauth->enableDebug();
    $oauth->enableSSLChecks();
    $oauth->setToken($token,$secret);
    $oauth->fetch($api_url.'~/Ubuntu%20One/');
    print_r($oauth->getLastResponse());

I get moved to the "OpenID transaction in progress" page where you pass when doing a manual web login. Im definitely doing something wrong. I tried to get the second step from https://one.ubuntu.com/developer/account_admin/issue_tokens/cloud/ with $oauth->fetch, $oauth->getAccessToken and $oauth->getRequestToken, same response on all with 403 error :S

I was trying to figure how the payload works but the main examples are writed with python, using "import ubuntuone.couch.auth as auth" that makes the token stuff almost automatic.

I'll love to get some hints. Thanks


I believe the problem was that step 2 of the "create a new token" workflow, defined on https://one.ubuntu.com/developer/account_admin/issue_tokens/cloud/, was failing with a 503 for you because the service was down at a couple of points this weekend. You'll need to trap this situation and deal with it (a 503 indicates that you should retry the request later, as per standard HTTP).

I've tested the below PHP (beware: I am not a PHP hacker, so it might not be the most idiomatic code) and it works fine for me. It goes through three steps:

  1. Create a new token in Ubuntu SSO (login.ubuntu.com) (API docs)
  2. Tell Ubuntu One about that new token (API docs)
  3. Use that new token to sign a request to the Ubuntu One files API (API docs)

You'll see the individual parts commented below. Remember that this requests and gets a brand new token; once you have the token (after step 2), save it somewhere; don't request a new one every time.

<?php
function curlPetition($arr){
    $curl = curl_init($arr['URL']);
    if($arr['USERPWD']){curl_setopt($curl, CURLOPT_USERPWD, $arr['USERPWD']);}  
    curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
    curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,2);
    curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
    $out = curl_exec($curl);
    curl_close($curl);
    $data['responseBody'] = $out;
    return $data;
}

/* Define username and password details */
$email_address = '[email protected]';
$password = 'MY PASSWORD';

/* Step 1: Get a new OAuth token from Ubuntu Single-Sign-On */
$url = 'https://login.ubuntu.com/api/1.0/authentications?ws.op=authenticate&token_name=Ubuntu%20One%20@%20try1';
$data = curlPetition(array('URL'=>$url,'USERPWD'=> $email_address.':'.$password));
$tokenA = json_decode($data['responseBody'],1);

/* Set up that new token for use in OAuth requests */
$conskey = $tokenA['consumer_key'];
$conssec = $tokenA['consumer_secret'];
$token = $tokenA['token'];
$secret = $tokenA['token_secret'];
$oauth = new OAuth($conskey,$conssec,OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
$oauth->enableDebug();
$oauth->enableSSLChecks();
$oauth->setToken($token,$secret);

/* Step 2: tell Ubuntu One about the new token (signed with the token itself) */
$tell_u1_about_token_url = 'https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/' . $email_address;
$oauth->fetch($tell_u1_about_token_url);
print_r($oauth->getLastResponse());

/* Step 3: use the token to make a request to the Files API */
$api_url = 'https://one.ubuntu.com/api/file_storage/v1/';
$oauth->fetch($api_url.'~/Ubuntu%20One/');
print_r($oauth->getLastResponse());
?>

Code from one first-step-class to talk with ubuntuOne

<?php
class ubuntuOne{
    var $curl = array('cookieSrc'=>'cookie.txt','enableCookies'=>false);
    var $auth = array('consumer_key'=>false,'consumer_secret'=>false,'token'=>false,'token_secret'=>false);
    var $oauth = false;
    function ubuntuOne(){

    }
    function u1_getRoot(){
        if($this->oauth === false){return false;}
        $url = 'https://one.ubuntu.com/api/file_storage/v1';
        $this->oauth->fetch($url);
        print_r($this->oauth->getLastResponse());
    }
    function u1_listFolder($path){
        if($this->oauth === false){return false;}
        //FIXME: parse $path
        $url = 'https://one.ubuntu.com/api/file_storage/v1';
        //FIXME: $path debe terminar en '/'
        $url .= str_replace(' ','%20',$path);

        $this->oauth->fetch($url);
        $lr = $this->oauth->getLastResponse();
        if($lr === '{"error": "not found"}'){return false;}
        print_r($this->oauth->getLastResponse());
    }
    function u1_createFolder($name,$path = ''){
        //FIXME: folder exists?
        $url = 'https://one.ubuntu.com/api/file_storage/v1';
        //FIXME: $path debe terminar en '/'
        $url .= str_replace(' ','%20',$path);
        //FIXME: $name no puede contener '/'
        $url .= str_replace(' ','%20',$name);

        $this->oauth->fetch($url,'{"kind":"directory"}',OAUTH_HTTP_METHOD_PUT);
        print_r($this->oauth->getLastResponse());
    }
    function u1_file_exists($path){
        //FIXME: cache?
        $url = 'https://one.ubuntu.com/api/file_storage/v1';
        $url .= str_replace(' ','%20',$path);

        try{$this->oauth->fetch($url);}
        catch(OAuthException $E){if($E->lastResponse === '{"error": "not found"}'){return false;}}
        $i = $this->oauth->getLastResponseInfo();
        if($i['http_code'] === 200){}
        print_r($this->oauth->getLastResponseInfo());
    }
    function requestAuthentification($user,$pass,$name){
        $url = 'https://login.ubuntu.com/api/1.0/authentications?ws.op=authenticate&token_name=Ubuntu%20One%20@%20'.rawurlencode($name);
        $data = curlPetition(array('URL'=>$url,'USERPWD'=>$user.':'.$pass));
        //FIXME: check the response header -> 200
        $this->auth = json_decode($data['responseBody'],1);
    }
    function registerToken($user){
        $url = 'https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/'.$user;
        $this->oauth->fetch($url);
        $r = $this->oauth->getLastResponse();
        if(substr($r,02) !== 'ok'){
            //FIXME: poner error
        }
        print_r($this->oauth->getLastResponse());
    }
    function saveAuth($fileName){$ar = fopen($fileName,'w');fwrite($ar,json_encode($this->auth));fclose($ar);return true;}
    function loadAuth($fileName){
        if(!file_exists($fileName)){return false;}
        $this->auth = json_decode(file_get_contents($fileName),1);
        if($this->auth === NULL){return false;}
        $this->oauth = new OAuth($this->auth['consumer_key'],$this->auth['consumer_secret'],OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
        $this->oauth->enableDebug();
        $this->oauth->enableSSLChecks();
        $this->oauth->setToken($this->auth['token'],$this->auth['token_secret']);
        return true;
    }
    function curlPetition($arr,$data = array()){
        $curl = curl_init($arr['URL']);
        if(!isset($data['URLTRACK'])){$data['URLTRACK'] = array();}
        $data['URLTRACK'][] = $arr['URL'];

        if(isset($this->curl['userAgent'])){curl_setopt($curl,CURLOPT_USERAGENT,$this->curl['userAgent']);}
        if(count($data['URLTRACK']) > 1){curl_setopt($curl,CURLOPT_REFERER,$data['URLTRACK'][count($data['URLTRACK'])-2]);}
        if(isset($arr['USERPWD'])){curl_setopt($curl,CURLOPT_USERPWD,$arr['USERPWD']);}
        if(isset($arr['userAgent'])){curl_setopt($curl,CURLOPT_USERAGENT,$arr['userAgent']);}
        if(isset($arr['POST'])){curl_setopt($curl,CURLOPT_POST,true);curl_setopt($curl,CURLOPT_POSTFIELDS,$arr['POST']);}
        if(isset($arr['referer'])){curl_setopt($curl,CURLOPT_REFERER,$arr['referer']);}
        if(isset($arr['timeout'])){curl_setopt($curl,CURLOPT_TIMEOUT,$arr['timeout']);}
        curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,2);
        curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($curl,CURLOPT_HEADER,true);

        if($this->curl['enableCookies'] !== false ){$cookieSrc = $this->curl['cookieSrc'];curl_setopt($curl,CURLOPT_COOKIEFILE,$cookieSrc);curl_setopt($curl,CURLOPT_COOKIEJAR,$cookieSrc);}
        if(isset($arr['header'])){curl_setopt($curl,CURLOPT_HTTPHEADER,$arr['header']);}
        curl_setopt($curl,CURLOPT_TIMEOUT,25);

        $viewcode = curl_exec($curl);
        $curlInfo = curl_getinfo($curl);
        curl_close($curl);
        if(empty($viewcode)){return false;}
        $data['responseHeader'] = substr($viewcode,0,$curlInfo['header_size']);
        $data['responseBody'] = substr($viewcode,$curlInfo['header_size']);
        //$data['viewcode'] = $viewcode;

        if(isset($arr['FOLLOWLOCATION']) && preg_match('/HTTP\/1\.1 30[12]{1}/',$data['responseHeader'])){
            preg_match('/Location: (.*)/',$data['responseHeader'],$p);
            $nurl = trim($p[1]);
            if($nurl[0]=='/'){list($arr['URL'],) = explode('/',str_replace('http://','',$arr['URL']));$nurl = 'http://'.$arr['URL'].$nurl;}
            $arr['URL'] = $nurl;
            unset($arr['POST']);
            return curlPetition($arr,$data);
        }

        return $data;
    }
}
?>

Some example calls (srry for the disorder and commented code, maybe documentation one day):

echo time()."\n";
$ub = new ubuntuOne;
/* The first time you made the commented calls, then you save the authorization 
 * to a file. Once you have it on a file, you load it every time from there */
//$ub->requestAuthentification('[email protected]','*****','st');
//$ub->registerToken('[email protected]');
//print_r($ub->auth);
//$ub->saveAuth($GLOBALS['userPath'].'db/uOne.protected');
$ub->loadAuth($GLOBALS['userPath'].'db/uOne.protected');
//$ub->registerToken('[email protected]');
$ub->u1_getRoot();
//$ub->u1_file_exists('/~/Ubuntu One/non_exists/');
echo "\n";
$ub->u1_listFolder('/~/Ubuntu One/');
echo "\n";
$ub->u1_createFolder('new folder','/~/Ubuntu One/');

Good Luck, I hope it helps


Updated version, some features added, some bug catched

    class ubuntuOne{
        var $curl = array('cookieSrc'=>'cookie.txt','enableCookies'=>false);
        var $auth = array('consumer_key'=>false,'consumer_secret'=>false,'token'=>false,'token_secret'=>false);
        var $oneInfo = false;
        var $oauth = false;
        var $E = array('errorCode'=>0,'errorDescription'=>'');
        var $fs = array();
        function ubuntuOne(){
            $this->fs['/'] = $this->helper_nodeSkeleton(array('name'=>'/','kind'=>'directory','resource_path'=>'/'));
        }
        function helper_nodeSkeleton($a = array()){return array_merge(array('name'=>false,'kind'=>false,'when_created'=>false,'generation'=>false,'has_children'=>false,'content_path'=>false,'generation_created'=>false,'parent_path'=>false,'resource_path'=>false,'when_changed'=>false,'key'=>false,'path'=>false,'volume_path'=>false,'size'=>0,'children'=>array()),$a);}
        function helper_storePath($path,$node = false){
            $path = explode('/',$path);
            $curPath = &$this->fs['/'];
            $resPath = '';
            foreach($path as $p){if($p === ''){continue;}$resPath .= '/'.$p;if(!isset($curPath['children'][$p])){$curPath['children'][$p] = $this->helper_nodeSkeleton(array('name'=>$p,'kind'=>'directory','resource_path'=>$resPath));}$curPath = &$curPath['children'][$p];}
            if($node !== false){$curPath = array_merge($curPath,$node);if($curPath['kind'] == 'file'){unset($curPath['children']);}}
        }
        function helper_storeNode($node){
            if(!isset($node['name'])){$r = preg_match('/\/([^\/]+)$/',$node['resource_path'],$name);if($r === 0){$this->E = array('errorCode'=>1,'errorDescription'=>'NAME_NOT_PARSED');return null;}$node['name'] = $name[1];}
            $this->helper_storePath($node['resource_path'],$node);
            $this->E = array('errorCode'=>0,'errorDescription'=>'');
        }
        function u1_getRoot(){
            if($this->oauth === false){return false;}
            $url = 'https://one.ubuntu.com/api/file_storage/v1';
            try{$this->oauth->fetch($url);}
            catch(OAuthException $E){print_r($E);return false;}
            $lr = json_decode($this->oauth->getLastResponse(),1);
            $this->helper_storePath($lr['root_node_path']);
            foreach($lr['user_node_paths'] as $np){$this->helper_storePath($np);}
            $this->oneInfo = $lr;
            return $lr;
        }
        function u1_getVolumeTree(){
            if($this->oneInfo === false){$r = $this->u1_getRoot();if($r === null){return $r;}}
            $base = $this->fs['/']['children']['~']['children'];
            foreach($base as $k=>$node){$this->u1_helper_getVolumeTree($node);}
            return $this->fs;
        }
        function u1_helper_getVolumeTree($node,$i = 0){
            if($node['kind'] == 'file'){return;}
            $r = $this->u1_folder_list($node['resource_path']);
            foreach($r['children'] as $child){$this->u1_helper_getVolumeTree($child,$i);}
        }
        function u1_folder_list($path){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            if(substr($path,-1) != '/'){$path .= '/';}
            $url = 'https://one.ubuntu.com/api/file_storage/v1'.$this->helper_encodeURL($path).'?include_children=true';

            try{$this->oauth->fetch($url);}
            catch(OAuthException $E){echo $path;print_r($E);return null;}
            $lr = $this->oauth->getLastResponse();
            if($lr === '{"error": "not found"}'){return null;}
            $lr = json_decode($lr,1);

            /* Store the base node */
            $node = $lr;unset($node['children']);
            $this->helper_storeNode($node);
            foreach($lr['children'] as $child){$this->helper_storeNode($child);}
            return $lr;
        }
        function u1_folder_create($name,$path = '/~/Ubuntu One/'){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            if(substr($path,-1) != '/'){$path .= '/';}
            $name = preg_replace(array('/[\.]$/','/[\/]*/'),'',$name);

            //FIXME: folder exists?
            $url = 'https://one.ubuntu.com/api/file_storage/v1'.$this->helper_encodeURL($path).$this->helper_encodeURL($name);

            $this->oauth->fetch($url,'{"kind":"directory"}',OAUTH_HTTP_METHOD_PUT);
            $node = json_decode($this->oauth->getLastResponse(),1);
            $this->helper_storeNode($node);
            return $node;
        }
        function u1_file_create($path,$blob){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            //if(substr($path,-1) != '/'){$path .= '/';}
            $url = 'https://files.one.ubuntu.com/content'.$this->helper_encodeURL($path);
            //FIXME: u1_file_exists

            $this->oauth->fetch($url,$blob,OAUTH_HTTP_METHOD_PUT,array('Content-Type'=>'application/json'));
            //$i = $this->oauth->getLastResponseInfo();
            //print_r($i);
            $node = json_decode($this->oauth->getLastResponse(),1);
            $this->helper_storeNode($node);
            return $node;
        }
        function u1_file_exists($path,$nocache = false){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            //FIXME: cache?
            $url = 'https://one.ubuntu.com/api/file_storage/v1'.$this->helper_encodeURL($path);

            try{$this->oauth->fetch($url);}
            catch(OAuthException $E){if($E->lastResponse === '{"error": "not found"}'){return false;}}
            $i = $this->oauth->getLastResponseInfo();
            if($i['http_code'] === 200){}
            //FIXME: respuesta adecuada
            print_r($this->oauth->getLastResponseInfo());
        }
        function u1_file_get($contentPath,$destinyPath = false){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            if(substr($contentPath,0,9) != '/content/'){$this->E = array('errorCode'=>1,'errorDescription'=>'NO_CONTENT_PATH');return null;}
            $url = 'https://files.one.ubuntu.com'.$this->helper_encodeURL($contentPath);

            /* I hope nobody ask me about the following concat, never gonna give you up!! */
            $time = time();
            $data = array('oauth_consumer_key'=>$this->auth['consumer_key'],'oauth_nonce'=>$time*rand(0,200),'oauth_signature_method'=>'HMAC-SHA1','oauth_timestamp'=>$time,'oauth_token'=>$this->auth['token'],'oauth_version'=>'1.0');
            $b = '';foreach($data as $k=>$v){$b .= '&'.$k.'='.$v;}
            $b = 'GET&'.rawurlencode($url).'&'.rawurlencode(substr($b,1));

            $key = $this->auth['consumer_secret'].'&'.$this->auth['token_secret'];
            $signature = $this->helper_oauth_hmacsha1($key,$b);

            $data['oauth_signature'] = $signature;
            $a = $url.'?';foreach($data as $k=>$v){$a .= $k.'='.rawurlencode($v).'&';}

            $h = fopen($a,'r');
            if(!$h){
                //FIXME: poner error
                return null;
            }

            //FIXME: is_writable
            //FIXME: file_exists
            $fileName = basename($contentPath);
            $ar = fopen($destinyPath.$fileName,'w');

            //FIXME: comprobar los primeros bits del buffer para asegurarse de que no está fallando
            $buffer = '';while(!feof($h)){$buffer = fgets($h,8192);fwrite($ar,$buffer);}fclose($h);

            fclose($ar);
            $filehash = sha1_file($destinyPath.$fileName);
            //echo "\n".$filehash."\n";

            return array('fileName'=>$fileName,'filePath'=>$destinyPath,'fileHash'=>$filehash);
        }
        function u1_file_unlink($path){
            if($this->oauth === false){$this->E = array('errorCode'=>99,'errorDescription'=>'NO_OAUTH_DATA');return null;}
            $url = 'https://one.ubuntu.com/api/file_storage/v1'.$this->helper_encodeURL($path);
            //FIXME: u1_file_exists

            try{$this->oauth->fetch($url,$blob,OAUTH_HTTP_METHOD_DELETE,array('Content-Type'=>'application/json'));}
            catch(OAuthException $E){print_r($E);$this->E = array('errorCode'=>1,'errorDescription'=>'FILE_NOT_EXISTS');return null;}
            $i = $this->oauth->getLastResponseInfo();
    //FIXME: eliminar el fichero de la caché
            //print_r($i);
        }
        function requestAuthentification($user,$pass,$name){
            $url = 'https://login.ubuntu.com/api/1.0/authentications?ws.op=authenticate&token_name=Ubuntu%20One%20@%20'.rawurlencode($name);
            $data = $this->curlPetition(array('URL'=>$url,'USERPWD'=>$user.':'.$pass));
            //FIXME: check the response header -> 200
            $this->auth = json_decode($data['responseBody'],1);
            if($this->auth === NULL){return false;}
            $this->oauth = new OAuth($this->auth['consumer_key'],$this->auth['consumer_secret'],OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
            $this->oauth->enableDebug();
            $this->oauth->enableSSLChecks();
            $this->oauth->setToken($this->auth['token'],$this->auth['token_secret']);
            return true;
        }
        function registerToken($user){
    //FIXME: check $this->oauth == false
            $url = 'https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/'.$user;
            $this->oauth->fetch($url);
            $r = $this->oauth->getLastResponse();
            if(substr($r,02) !== 'ok'){
                //FIXME: poner error
            }
            //print_r($this->oauth->getLastResponse());
        }
        function saveAuth($fileName){$ar = fopen($fileName,'w');fwrite($ar,json_encode($this->auth));fclose($ar);return true;}
        function loadAuth($fileName){
            if(!file_exists($fileName)){return false;}
            $this->auth = json_decode(file_get_contents($fileName),1);
            if($this->auth === NULL){return false;}
            return $this->helper_makeOauth();
        }
        function setAuth($auth){$this->auth = $auth;return $this->helper_makeOauth();}
        function helper_makeOauth(){
            $this->oauth = new OAuth($this->auth['consumer_key'],$this->auth['consumer_secret'],OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
            $this->oauth->enableDebug();
            $this->oauth->enableSSLChecks();
            $this->oauth->setToken($this->auth['token'],$this->auth['token_secret']);
            return true;
        }
        function helper_encodeURL($url){return str_replace('%2F','/',rawurlencode($url));}
        function helper_oauth_hmacsha1($key,$data){
            $blocksize=64;$hashfunc='sha1';
            if(strlen($key)>$blocksize){$key=pack('H*',$hashfunc($key));}
            $key=str_pad($key,$blocksize,chr(0x00));
            $ipad=str_repeat(chr(0x36),$blocksize);
            $opad=str_repeat(chr(0x5c),$blocksize);
            $hmac=pack('H*',$hashfunc(($key^$opad).pack('H*',$hashfunc(($key^$ipad).$data))));
            return base64_encode($hmac);
        }
        function curlPetition($arr,$data = array()){
            //FIXME: data puede ser una propiedad de la clase
            $curl = curl_init($arr['URL']);
            if(!isset($data['URLTRACK'])){$data['URLTRACK'] = array();}
            $data['URLTRACK'][] = $arr['URL'];

            if(isset($this->curl['userAgent'])){curl_setopt($curl,CURLOPT_USERAGENT,$this->curl['userAgent']);}
            if(count($data['URLTRACK']) > 1){curl_setopt($curl,CURLOPT_REFERER,$data['URLTRACK'][count($data['URLTRACK'])-2]);}
            if(isset($arr['USERPWD'])){curl_setopt($curl,CURLOPT_USERPWD,$arr['USERPWD']);}
            if(isset($arr['userAgent'])){curl_setopt($curl,CURLOPT_USERAGENT,$arr['userAgent']);}
            if(isset($arr['POST'])){curl_setopt($curl,CURLOPT_POST,true);curl_setopt($curl,CURLOPT_POSTFIELDS,$arr['POST']);}
            if(isset($arr['referer'])){curl_setopt($curl,CURLOPT_REFERER,$arr['referer']);}
            if(isset($arr['timeout'])){curl_setopt($curl,CURLOPT_TIMEOUT,$arr['timeout']);}
            curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
            curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,2);
            curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
            curl_setopt($curl,CURLOPT_HEADER,true);

            if($this->curl['enableCookies'] !== false ){$cookieSrc = $this->curl['cookieSrc'];curl_setopt($curl,CURLOPT_COOKIEFILE,$cookieSrc);curl_setopt($curl,CURLOPT_COOKIEJAR,$cookieSrc);}
            if(isset($arr['header'])){curl_setopt($curl,CURLOPT_HTTPHEADER,$arr['header']);}
            curl_setopt($curl,CURLOPT_TIMEOUT,25);

            $viewcode = curl_exec($curl);
            $curlInfo = curl_getinfo($curl);
            curl_close($curl);
            if(empty($viewcode)){return false;}
            $data['responseHeader'] = substr($viewcode,0,$curlInfo['header_size']);
            $data['responseBody'] = substr($viewcode,$curlInfo['header_size']);
            //$data['viewcode'] = $viewcode;

            if(isset($arr['FOLLOWLOCATION']) && preg_match('/HTTP\/1\.1 30[12]{1}/',$data['responseHeader'])){
                preg_match('/Location: (.*)/',$data['responseHeader'],$p);
                $nurl = trim($p[1]);
                if($nurl[0]=='/'){list($arr['URL'],) = explode('/',str_replace('http://','',$arr['URL']));$nurl = 'http://'.$arr['URL'].$nurl;}
                $arr['URL'] = $nurl;
                unset($arr['POST']);
                return $this->curlPetition($arr,$data);
            }

            return $data;
        }
    }