2013-08-17 20:20:20 +04:00
< ? php
/**
* Dropbox OAuth
2015-04-01 16:25:11 +03:00
*
* @ package Dropbox
2013-08-17 20:20:20 +04:00
* @ copyright Copyright ( C ) 2011 Daniel Huesken
* @ author Daniel Huesken ( http :// www . danielhuesken . de / )
* @ license MIT
*/
/**
* This class is used to sign all requests to dropbox .
*
* This specific class uses WordPress WP_Http to authenticate .
*/
class Dropbox_OAuth_Curl extends Dropbox_OAuth {
/**
*
* @ var string ConsumerKey
*/
protected $consumerKey = null ;
/**
*
* @ var string ConsumerSecret
*/
protected $consumerSecret = null ;
/**
*
* @ var string ProzessCallBack
*/
public $ProgressFunction = false ;
2015-04-01 16:25:11 +03:00
2013-08-17 20:20:20 +04:00
/**
* Constructor
2015-04-01 16:25:11 +03:00
*
* @ param string $consumerKey
* @ param string $consumerSecret
2013-08-17 20:20:20 +04:00
*/
public function __construct ( $consumerKey , $consumerSecret ) {
2015-04-01 16:25:11 +03:00
if ( ! function_exists ( 'curl_exec' ))
2013-08-17 20:20:20 +04:00
throw new Dropbox_Exception ( 'The PHP curl functions not available!' );
$this -> consumerKey = $consumerKey ;
$this -> consumerSecret = $consumerSecret ;
2015-04-01 16:25:11 +03:00
$this -> putSupported = true ;
2013-08-17 20:20:20 +04:00
}
/**
2015-04-01 16:25:11 +03:00
* Fetches a secured oauth url and returns the response body .
*
* @ param string $uri
* @ param mixed $arguments
* @ param string $method
* @ param array $httpHeaders
* @ return string
2013-08-17 20:20:20 +04:00
*/
2015-04-01 16:25:11 +03:00
public function fetch ( $uri , $arguments = array (), $method = 'GET' , $httpHeaders = array ()) {
2013-08-17 20:20:20 +04:00
$uri = str_replace ( 'http://' , 'https://' , $uri ); // all https, upload makes problems if not
if ( is_string ( $arguments ) and strtoupper ( $method ) == 'POST' ) {
2015-04-01 16:25:11 +03:00
preg_match ( " / \ ?file=(.*) $ /i " , $uri , $matches );
2013-08-17 20:20:20 +04:00
if ( isset ( $matches [ 1 ])) {
2015-04-01 16:25:11 +03:00
$uri = str_replace ( $matches [ 0 ], " " , $uri );
$filename = rawurldecode ( str_replace ( '%7E' , '~' , $matches [ 1 ]));
2013-08-17 20:20:20 +04:00
$httpHeaders = array_merge ( $httpHeaders , $this -> getOAuthHeader ( $uri , array ( " file " => $filename ), $method ));
2015-04-01 16:25:11 +03:00
}
2013-08-17 20:20:20 +04:00
} else {
$httpHeaders = array_merge ( $httpHeaders , $this -> getOAuthHeader ( $uri , $arguments , $method ));
}
2015-04-01 16:25:11 +03:00
$ch = curl_init ();
2013-08-17 20:20:20 +04:00
if ( strtoupper ( $method ) == 'POST' ) {
curl_setopt ( $ch , CURLOPT_URL , $uri );
curl_setopt ( $ch , CURLOPT_POST , true );
2015-04-01 16:25:11 +03:00
if ( is_array ( $arguments )) {
$arguments = http_build_query ( $arguments );
}
2013-08-17 20:20:20 +04:00
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $arguments );
2015-04-01 16:25:11 +03:00
$httpHeaders [ 'Content-Length' ] = strlen ( $arguments );
} else if ( strtoupper ( $method ) == 'PUT' && $this -> inFile ) {
curl_setopt ( $ch , CURLOPT_URL , $uri . '?' . http_build_query ( $arguments ));
curl_setopt ( $ch , CURLOPT_PUT , true );
curl_setopt ( $ch , CURLOPT_BINARYTRANSFER , true );
curl_setopt ( $ch , CURLOPT_INFILE , $this -> inFile );
curl_setopt ( $ch , CURLOPT_INFILESIZE , $this -> inFileSize );
fseek ( $this -> inFile , 0 );
$this -> inFileSize = $this -> inFile = null ;
2013-08-17 20:20:20 +04:00
} else {
curl_setopt ( $ch , CURLOPT_URL , $uri . '?' . http_build_query ( $arguments ));
curl_setopt ( $ch , CURLOPT_POST , false );
}
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
2015-04-01 16:25:11 +03:00
curl_setopt ( $ch , CURLOPT_TIMEOUT , 600 );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , true );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , 2 );
2013-08-17 20:20:20 +04:00
curl_setopt ( $ch , CURLOPT_FRESH_CONNECT , true );
2015-04-01 16:25:11 +03:00
curl_setopt ( $ch , CURLOPT_CAINFO , dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . 'ca-bundle.pem' );
2013-08-17 20:20:20 +04:00
//Build header
$headers = array ();
foreach ( $httpHeaders as $name => $value ) {
$headers [] = " { $name } : $value " ;
}
curl_setopt ( $ch , CURLOPT_HTTPHEADER , $headers );
if ( ! ini_get ( 'safe_mode' ) && ! ini_get ( 'open_basedir' ))
curl_setopt ( $ch , CURLOPT_FOLLOWLOCATION , true );
if ( function_exists ( $this -> ProgressFunction ) and defined ( 'CURLOPT_PROGRESSFUNCTION' )) {
curl_setopt ( $ch , CURLOPT_NOPROGRESS , false );
curl_setopt ( $ch , CURLOPT_PROGRESSFUNCTION , $this -> ProgressFunction );
curl_setopt ( $ch , CURLOPT_BUFFERSIZE , 512 );
}
$response = curl_exec ( $ch );
$errorno = curl_errno ( $ch );
$error = curl_error ( $ch );
$status = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
curl_close ( $ch );
2015-04-01 16:25:11 +03:00
$this -> lastResponse = array (
'httpStatus' => $status ,
'body' => $response
);
2013-08-17 20:20:20 +04:00
if ( ! empty ( $errorno ))
throw new Dropbox_Exception_NotFound ( 'Curl error: (' . $errorno . ') ' . $error . " \n " );
2015-04-01 16:25:11 +03:00
2013-08-17 20:20:20 +04:00
if ( $status >= 300 ) {
2015-04-01 16:25:11 +03:00
$body = array ();
$body = json_decode ( $response , true );
if ( ! is_array ( $body )) {
$body = array ();
}
$jsonErr = isset ( $body [ 'error' ]) ? $body [ 'error' ] : '' ;
2013-08-17 20:20:20 +04:00
switch ( $status ) {
// Not modified
case 304 :
return array (
'httpStatus' => 304 ,
'body' => null ,
);
break ;
2015-04-01 16:25:11 +03:00
case 400 :
throw new Dropbox_Exception_Forbidden ( 'Forbidden. Bad input parameter. Error message should indicate which one and why.' );
case 401 :
throw new Dropbox_Exception_Forbidden ( 'Forbidden. Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user.' );
2013-08-17 20:20:20 +04:00
case 403 :
2015-04-01 16:25:11 +03:00
throw new Dropbox_Exception_Forbidden ( 'Forbidden. This could mean a bad OAuth request, or a file or folder already existing at the target location.' );
2013-08-17 20:20:20 +04:00
case 404 :
2015-04-01 16:25:11 +03:00
throw new Dropbox_Exception_NotFound ( 'Resource at uri: ' . $uri . ' could not be found' );
case 405 :
throw new Dropbox_Exception_Forbidden ( 'Forbidden. Request method not expected (generally should be GET or POST).' );
case 500 :
throw new Dropbox_Exception_Forbidden ( 'Server error. ' . $jsonErr );
case 503 :
throw new Dropbox_Exception_Forbidden ( 'Forbidden. Your app is making too many requests and is being rate limited. 503s can trigger on a per-app or per-user basis.' );
2013-08-17 20:20:20 +04:00
case 507 :
2015-04-01 16:25:11 +03:00
throw new Dropbox_Exception_OverQuota ( 'This dropbox is full' );
default :
throw new Dropbox_Exception_RequestToken ( 'Error: (' . $status . ') ' . $jsonErr );
2013-08-17 20:20:20 +04:00
}
if ( ! empty ( $body [ " error " ]))
2015-04-01 16:25:11 +03:00
throw new Dropbox_Exception_RequestToken ( 'Error: (' . $status . ') ' . $jsonErr );
2013-08-17 20:20:20 +04:00
}
return array (
'body' => $response ,
2015-04-01 16:25:11 +03:00
'httpStatus' => $status
);
2013-08-17 20:20:20 +04:00
}
/**
* Returns named array with oauth parameters for further use
* @ return array Array with oauth_ parameters
*/
private function getOAuthBaseParams () {
$params [ 'oauth_version' ] = '1.0' ;
$params [ 'oauth_signature_method' ] = 'HMAC-SHA1' ;
$params [ 'oauth_consumer_key' ] = $this -> consumerKey ;
$tokens = $this -> getToken ();
if ( isset ( $tokens [ 'token' ]) && $tokens [ 'token' ]) {
$params [ 'oauth_token' ] = $tokens [ 'token' ];
}
$params [ 'oauth_timestamp' ] = time ();
$params [ 'oauth_nonce' ] = md5 ( microtime () . mt_rand ());
return $params ;
}
/**
* Creates valid Authorization header for OAuth , based on URI and Params
*
* @ param string $uri
* @ param array $params
* @ param string $method GET or POST , standard is GET
* @ param array $oAuthParams optional , pass your own oauth_params here
* @ return array Array for request ' s headers section like
* array ( 'Authorization' => 'OAuth ...' );
*/
private function getOAuthHeader ( $uri , $params , $method = 'GET' , $oAuthParams = null ) {
$oAuthParams = $oAuthParams ? $oAuthParams : $this -> getOAuthBaseParams ();
// create baseString to encode for the sent parameters
$baseString = $method . '&' ;
$baseString .= $this -> oauth_urlencode ( $uri ) . " & " ;
// OAuth header does not include GET-Parameters
$signatureParams = array_merge ( $params , $oAuthParams );
// sorting the parameters
ksort ( $signatureParams );
$encodedParams = array ();
foreach ( $signatureParams as $key => $value ) {
2015-04-01 16:25:11 +03:00
if ( ! is_null ( $value )) $encodedParams [] = rawurlencode ( $key ) . '=' . rawurlencode ( $value );
2013-08-17 20:20:20 +04:00
}
$baseString .= $this -> oauth_urlencode ( implode ( '&' , $encodedParams ));
// encode the signature
$tokens = $this -> getToken ();
$hash = $this -> hash_hmac_sha1 ( $this -> consumerSecret . '&' . $tokens [ 'token_secret' ], $baseString );
$signature = base64_encode ( $hash );
// add signature to oAuthParams
$oAuthParams [ 'oauth_signature' ] = $signature ;
$oAuthEncoded = array ();
foreach ( $oAuthParams as $key => $value ) {
$oAuthEncoded [] = $key . '="' . $this -> oauth_urlencode ( $value ) . '"' ;
}
return array ( 'Authorization' => 'OAuth ' . implode ( ', ' , $oAuthEncoded ));
}
/**
* Requests the OAuth request token .
*
2015-04-01 16:25:11 +03:00
* @ return void
2013-08-17 20:20:20 +04:00
*/
public function getRequestToken () {
$result = $this -> fetch ( self :: URI_REQUEST_TOKEN , array (), 'POST' );
if ( $result [ 'httpStatus' ] == " 200 " ) {
$tokens = array ();
parse_str ( $result [ 'body' ], $tokens );
$this -> setToken ( $tokens [ 'oauth_token' ], $tokens [ 'oauth_token_secret' ]);
return $this -> getToken ();
} else {
throw new Dropbox_Exception_RequestToken ( 'We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.' );
}
}
/**
* Requests the OAuth access tokens .
*
* This method requires the 'unauthorized' request tokens
* and , if successful will set the authorized request tokens .
2015-04-01 16:25:11 +03:00
*
* @ return void
2013-08-17 20:20:20 +04:00
*/
public function getAccessToken () {
$result = $this -> fetch ( self :: URI_ACCESS_TOKEN , array (), 'POST' );
if ( $result [ 'httpStatus' ] == " 200 " ) {
$tokens = array ();
parse_str ( $result [ 'body' ], $tokens );
$this -> setToken ( $tokens [ 'oauth_token' ], $tokens [ 'oauth_token_secret' ]);
return $this -> getToken ();
} else {
throw new Dropbox_Exception_RequestToken ( 'We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.' );
}
}
/**
* Helper function to properly urlencode parameters .
* See http :// php . net / manual / en / function . oauth - urlencode . php
*
* @ param string $string
* @ return string
*/
private function oauth_urlencode ( $string ) {
return str_replace ( '%E7' , '~' , rawurlencode ( $string ));
}
/**
* Hash function for hmac_sha1 ; uses native function if available .
*
* @ param string $key
* @ param string $data
* @ return string
*/
private function hash_hmac_sha1 ( $key , $data ) {
if ( function_exists ( 'hash_hmac' ) && in_array ( 'sha1' , hash_algos ())) {
return hash_hmac ( 'sha1' , $data , $key , true );
} else {
$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 );
$hash = pack ( 'H*' , $hashfunc (( $key ^ $opad ) . pack ( 'H*' , $hashfunc (( $key ^ $ipad ) . $data ))));
return $hash ;
}
}
2015-04-01 16:25:11 +03:00
}