Twitter oAuth: getting an error 215 - php

I have the following code in one of my classes:
public function build_httpheader ($options = NULL)
{
if (!$this->oauth_token && !$this->oauth_token_secret && !$this->http_method) {
throw new Exception('The oauth_token, oauth_token_secret and the http method must be set');
}
$url = $this->base_uri;
$url_curl = $this->base_uri;
if ($options) {
$this->options = $options;
$url .= '?';
$url_curl .= '?';
$count = count($options);
foreach($options as $key => $value) {
$count = $count--;
if ($count) {
$url .= '&'.$key.'='.$value;
$url_curl .= '&'.$key.'='.rawurlencode($value);
} else {
$url .= $key.'='.$value;
$url_curl .= $key.'='.rawurlencode($value);
}
}
}
$this->url = $url_curl;
/**
* #internal Create a 32 chars unique string to
* use as the nonce value
*/
list($usec, $sec) = explode(" ", microtime());
$usec = str_replace('0.', '', $usec);
$nonce_str = utf8_encode($sec.$usec.'ABCD'.$sec);
$oauth_nonce = md5($nonce_str);
/**
* #internal Create the initial oAuth array
*/
$oauth = array (
'oauth_consumer_key' => $this->consumer_key,
'oauth_nonce' => $this->$oauth_nonce,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $this->oauth_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
/**
* #internal generate basic info
*/
$t_oauth = array();
ksort($oauth);
foreach($oauth as $key=>$value){
$t_oauth[] = "$key=" . rawurlencode($value);
}
$base_info = $this->http_method."&" . rawurlencode($url) . '&' . rawurlencode(implode('&', $t_oauth));
$composite_key = rawurlencode($this->consumer_secret) . '&' . rawurlencode($this->oauth_token_secret);
$oauth['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth_string = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value) {
$values[] = "$key=\"" . rawurlencode($value) . "\"";
}
$oauth_string .= implode(', ', $values);
$this->http_headers = array ($oauth_string, 'Expect:');
}
public function tw_curl_api_call ()
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->http_headers);
if ($this->http_method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
}
if ( ($this->http_method != 'POST') && ($this->http_method != 'GET') ) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->http_method);
}
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
$result = json_decode(curl_exec($ch), TRUE);
$info = curl_getinfo($ch);
curl_close($ch);
return array ('result' => $result, 'info' => $info);
}
Another script uses this class as follows:
$options = array ('resources' => 'help,users,search,statuses');
$tw_wrapper->build_httpheader ($options);
$results = $tw_wrapper->tw_curl_api_call ();
I am however getting an error 215 (bad authentication data). Any ideas (I am aware that there are existing PHP oAuth classes and twitter wrappers, but it does not seem as if any of them has completely migrated to the 1.1 API).

Have you had a look at Codebird? It has support for 1.1 and works well for what I've needed. YMWV of course.
A simple example:
Codebird::setConsumerKey('KEY', 'SECRET');
$cb = Codebird::getInstance();
$cb->setToken('AUTH_KEY', 'AUTH_SECRET');
$result = $cb->statuses_userTimeline(array(
'include_rts' => true,
'screen_name' => 'hansnilsson',
));

Related

Signature doesn't work when using spaces in url parameter

I want to use an endpoint that uses an url parameter with spaces in it.
I have a function that generates an signature.
function generateSignature($request, $timestamp, $nonce)
{
Global $consumerKey, $accessToken, $consumerSecret, $tokenSecret, $realm, $signatureMethod, $version, $limit;
$baseparams = "";
$baseurl = strtok($request['url'], "?");
$base = strtoupper($request['method']) . "&" . urlencode($baseurl) . "&";
if(strpos($request['url'], '?') !== false){
$url_components = parse_url($request['url']);
parse_str($url_components['query'], $params);
$paramnr = 0;
foreach($params as $param => $value){
$paramnr++;
if($paramnr > 1){
$baseparams .= "&".$param."=" . urlencode($value);
}
else{
$baseparams .= $param."=" . urlencode($value);
}
}
$trailingand = "&";
}
else{
$trailingand = "";
}
echo $baseparams .= $trailingand
. "oauth_consumer_key=" . urlencode($consumerKey)
. "&oauth_nonce=" . urlencode($nonce)
. "&oauth_signature_method=" . urlencode($signatureMethod)
. "&oauth_timestamp=" . urlencode($timestamp)
. "&oauth_token=" . urlencode($accessToken)
. "&oauth_version=" . urlencode($version);
$base = $base.urlencode($baseparams);
$key = urlencode($consumerSecret) . '&' . urlencode($tokenSecret);
$signature = hash_hmac('sha256', $base, $key, true);
$signature = urlencode(base64_encode($signature));
return $signature;
}
My execute function:
function execute($options = array()){
Global $consumerKey, $accessToken, $consumerSecret, $tokenSecret, $realm, $signatureMethod, $version;
$curl = curl_init();
echo $options['url'];
curl_setopt_array($curl, array(
CURLOPT_URL => $options['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1
));
$timestamp = round(microtime(true));
$nonce = getNonce(11);
$signature = generateSignature($options, $timestamp, $nonce);
$authHeader = 'Authorization: OAuth realm="'.$realm.'",oauth_consumer_key="'.$consumerKey.'",oauth_token="'.$accessToken.'",oauth_signature_method="'.$signatureMethod.'",oauth_timestamp="'.$timestamp.'",oauth_nonce="'.$nonce.'",oauth_version="'.$version.'",oauth_signature="'.$signature.'"';
curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, strtoupper($options['method']) );
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
$authHeader
));
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
$response = curl_exec($curl);
$array = json_decode($response, true);
echo "<br/>".$responsecode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if(curl_errno($curl)){
return 'Curl error: ' . curl_error($curl);
}
else{
return $array;
}
curl_close($curl);
}
This works fine when I have an url like this:
https://website.com/api/customer?limit=10 - WORKS
But the API also supports this:
https://website.com/api/customer?q=partner+EQUALS+10 - DOESNT WORK
When I put this URL into my function, it doesn't work and I get an 400 error instead.
My guess is that the signature is incorrect due to the spaces inside the url parameter.
How can I make this work with an url parameter that has spaces in it?
I already tried to use urlencode but that didnt work as well.
If it helps you out: I'm using the NETSUITE REST API for this.
Can someone help me plz...
When you make a req use encoded url insted of spaces.
https://website.com/api/customer?q=partner+EQUALS+10
this type will works for you

Uploaded file rename to untitled Google drive

I have done google api integration code as well as file is upload to a drive. I have issue regarding a uploaded file name is "Untitled". Please review code and guide me what is missing.
<?php
$GAPIS = 'https://www.googleapis.com/';
$GAPIS_AUTH = $GAPIS . 'auth/';
$GOAUTH = 'https://accounts.google.com/o/oauth2/';
$CLIENT_ID = '709846732498-t19mhuuvq0nqtng5ogg8XXXXXX0im8.apps.googleusercontent.com';
$CLIENT_SECRET = 'XXXXXXXXKa';
$REDIRECT_URI = 'http' . ($_SERVER['SERVER_PORT'] == 80 ? '' : 's') . '://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME'];
$SCOPES = array($GAPIS_AUTH . 'drive', $GAPIS_AUTH . 'drive.file', $GAPIS_AUTH . 'userinfo.email', $GAPIS_AUTH . 'userinfo.profile');
$STORE_PATH = 'credentials.json';
function uploadFile($credentials, $filename, $targetPath)
{
global $GAPIS;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $GAPIS . 'upload/drive/v2/files?uploadType=media');
//$content = { title "mypdf.pdf", description = "mypdf.pdf", mimeType = "application/pdf" };
$contentArry = array('title' =>'veridoc' );
$contentArry = json_encode($contentArry);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
//curl_setopt($ch, CURLOPT_POSTFIELDS,$contentArry);
curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filename));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER,
array('Content-Type : application/pdf','Content-Length:' . filesize($filename),'Authorization: Bearer ' . getAccessToken($credentials))
);
$postResult = curl_exec($ch);
curl_close($ch);
return json_decode($postResult, true);
}
function getStoredCredentials($path)
{
$credentials = json_decode(file_get_contents($path), true);
if (isset($credentials['refresh_token']))
return $credentials;
$expire_date = new DateTime();
$expire_date->setTimestamp($credentials['created']);
$expire_date->add(new DateInterval('PT' . $credentials['expires_in'] . 'S'));
$current_time = new DateTime();
if ($current_time->getTimestamp() >= $expire_date->getTimestamp())
{
$credentials = null;
unlink($path);
}
return $credentials;
}
function storeCredentials($path, $credentials)
{
$credentials['created'] = (new DateTime())->getTimestamp();
file_put_contents($path, json_encode($credentials));
return $credentials;
}
function requestAuthCode()
{
global $GOAUTH, $CLIENT_ID, $REDIRECT_URI, $SCOPES;
$url = sprintf($GOAUTH . 'auth?scope=%s&redirect_uri=%s&response_type=code&client_id=%s&approval_prompt=force&access_type=offline',
urlencode(implode(' ', $SCOPES)), urlencode($REDIRECT_URI), urlencode($CLIENT_ID)
);
header('Location:' . $url);
}
function requestAccessToken($access_code)
{
global $GOAUTH, $CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI;
$url = $GOAUTH . 'token';
$post_fields = 'code=' . $access_code . '&client_id=' . urlencode($CLIENT_ID) . '&client_secret=' . urlencode($CLIENT_SECRET)
. '&redirect_uri=' . urlencode($REDIRECT_URI) . '&grant_type=authorization_code';
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
}
function getAccessToken($credentials)
{
$expire_date = new DateTime();
$expire_date->setTimestamp($credentials['created']);
$expire_date->add(new DateInterval('PT' . $credentials['expires_in'] . 'S'));
$current_time = new DateTime();
if ($current_time->getTimestamp() >= $expire_date->getTimestamp())
return $credentials['refresh_token'];
else
return $credentials['access_token'];
}
function authenticate()
{
global $STORE_PATH;
if (file_exists($STORE_PATH))
$credentials = getStoredCredentials($STORE_PATH);
else
$credentials = null;
if (!(isset($_GET['code']) || isset($credentials)))
requestAuthCode();
if (!isset($credentials))
$credentials = requestAccessToken($_GET['code']);
if (isset($credentials) && isset($credentials['access_token']) && !file_exists($STORE_PATH))
$credentials = storeCredentials($STORE_PATH, $credentials);
return $credentials;
}
$credentials = authenticate();
$result = uploadFile($credentials, 'veridoc.pdf', '');
if (!isset($result['id']))
throw new Exception(print_r($result));
else
echo 'File copied successfuly (file Id: ' . $result['id'] . ')';
echo '<pre>'; print_r($result);
`
going by the documentation at https://developers.google.com/drive/api/v3/reference/files/update , to rename a file, do a PATCH request to https://www.googleapis.com/drive/v3/files/<fileId> with the new name, in your case, i guess that would be
$postResult = curl_exec ( $ch );
$parsed = json_decode ( $postResult, true );
if (! $parsed || $parsed ['code'] !== 200) {
throw new \RuntimeException ( 'google api error: ' . $postResult );
}
$id = $parsed ['id']; // ?? wait, is it id or fileId?
curl_setopt_array ( $ch, array (
CURLOPT_URL => 'https://www.googleapis.com/drive/v3/files/' . urlencode ( $id ),
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => json_encode ( array (
'name' => basename ( $filename )
) ),
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => array (
'Content-Type : application/json',
'Authorization: Bearer ' . getAccessToken ( $credentials )
)
) );
curl_exec($ch);
ps, don't set the Content-Length header manually when using CURLOPT_POSTFIELDS, because curl will do it for you, and if you're using multipart/form-data, the length you set yourself is very likely to be wrong even (doesn't concern your code as you're not using multipart/form-data, but it's a good habit to learn nonetheless, get rid of it.)

Unable to print Json array in php table format

Here is my code to print Json array in table format
<?php include 'header.php' ; ?>
<?php
$base_url = "http://tic.sugarcrmdemo.com/rest/v10";
$username = "sereneintegration";
$password = "Sugar123!";
function call(
$url,
$oauthtoken='',
$type='GET',
$arguments=array(),
$encodeData=true,
$returnHeaders=false
)
{
$type = strtoupper($type);
if ($type == 'GET')
{
$url.= "?" . http_build_query($arguments);
}
$curl_request = curl_init($url);
if ($type == 'POST')
{
curl_setopt($curl_request, CURLOPT_POST, 1);
}
elseif ($type == 'PUT')
{
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "PUT");
}
elseif ($type == 'DELETE')
{
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "DELETE");
}
curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl_request, CURLOPT_HEADER, $returnHeaders);
curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
if (!empty($oauthtoken))
{
$token = array("oauth-token: {$oauthtoken}");
curl_setopt($curl_request, CURLOPT_HTTPHEADER, $token);
}
if (!empty($arguments) && $type !== 'GET')
{
if ($encodeData)
{
$arguments = json_encode($arguments);
}
curl_setopt($curl_request, CURLOPT_POSTFIELDS, $arguments);
}
$result = curl_exec($curl_request);
if ($returnHeaders)
{
list($headers, $content) = explode("\r\n\r\n", $result ,2);
foreach (explode("\r\n",$headers) as $header)
{
header($header);
}
return trim($content);
}
curl_close($curl_request);
$response = json_decode($result);
return $response;
}
$url = $base_url . "/oauth2/token";
$oauth2_token_arguments = array(
"grant_type" => "password",
"client_id" => "sugar",
"client_secret" => "",
"username" => $username,
"password" => $password,
"platform" => "base"
);
$oauth2_token_response = call($url, '', 'POST', $oauth2_token_arguments);
$url = $base_url . "/SREV1_Property/48f10d2c-eca2-9163-77fb-56c7677240e2/link/srev1_property_srev1_unit";
$unit_response = call($url, $oauth2_token_response->access_token, 'GET');
$json = $unit_response;
$jd = json_decode(json_encode($json), 1);
$floors = array();
foreach ($jd->records AS $key => $obj) {
$f = $obj->unit_floor;
$id = $obj->id;
$name = $obj->name;
$suite = $obj->suite;
$sf = $obj->sf;
$floors[$f][$suite]['name'] = $name;
$floors[$f][$suite]['id'] = $id;
$floors[$f][$suite]['sf'] = $sf;
}
//sort floors in desc order
krsort($floors);
foreach($floors as $id => $floor){
ksort($floors[$id]);
}
print '<table class="data-table" >';
foreach($floors as $floor => $suites){
$sqf = 0;
print '<tr>';
print '<td>FLOOR: '.$floor.'</td>';
foreach($suites AS $suite => $value){
$sqf += $value['sf'];
print'<td>Suite:'.$suite.'<br>SF:'.$value['sf'].'</td>';
}
print '<td>'.$sqf.'</td>';
print '</tr>';
}
print '</table>';
?>
But when I try to run this code i am getting an errors like "Trying to get property of non-object " and " Invalid argument supplied for foreach()". Please help me,.
Here is the expected output

Failed to validate oauth signature and token - Issue generating OAuth Token

I have been looking into creating a signature on the OAuth site & over SF but however I create my signature I always get the same error, any ideas what I am doing wrong here?
Error: Failed to validate oauth signature and token
I have a working app for the old rest API so I know that my issue is not with my app or server etc
<?php
function Post_Data($url,$data,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
// Get OAuth Token
$consumer_key = "hidden";
$consumer_secret = "hidden";
$request_url = "http://api.twitter.com/oauth/request_token";
$callback = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$nonce = md5(time());
$timestamp = time();
$data = array(
"oauth_callback" => $callback,
"oauth_consumer_key" => $consumer_key,
"oauth_nonce" => $nonce,
"oauth_signature_method" => "HMAC-SHA1",
"oauth_timestamp" => $timestamp,
"oauth_version" => "1.0"
);
$post_string = '';
foreach($data as $key => $value){
$post_string .= $key.'='.($value).'&';
}
$post_string = rtrim($post_string, '&');
$base_string = 'GET&'.urlencode($request_url).'&'.urlencode($post_string);
$data["oauth_signature"] = base64_encode(hash_hmac('sha1', $base_string, $consumer_secret, true));
$header = array("Expect:");
$content = Post_Data($request_url,$data,$header);
print_r($content);
?>
Maybe you should remove the "oauth_callback" and try again.
This is my code
class Twitter
{
private $CALLBACK_URL = 'http://your_site';
private $REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token';
private $ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token';
private $AUTHORIZE_URL = 'https://api.twitter.com/oauth/authorize';
private $consumer_key = 'your_key';
private $consumer_secret = 'your_secret';
private $access_token = 'your_token'; // oauth_token
private $access_token_secret = 'your_token_secret';
private $token_secret = '';
private $method = 'POST'; // [HEAD, GET, POST]
private $params = array();
public function get_request_token() {
//$this->params['oauth_callback'] = $this->CALLBACK_URL; // Something worng with this "Failed to validate oauth signature and token", God dammit...
$this->params['oauth_consumer_key'] = $this->consumer_key;
$this->params['oauth_nonce'] = md5(uniqid('prefix'));
$this->params['oauth_signature_method'] = 'HMAC-SHA1'; // [HMAC-SHA1, RSA-SHA1, PLAINTEXT]
$this->params['oauth_timestamp'] = time();
$this->params['oauth_version'] = '1.0'; // [1.0, 1.1] *Optional
$this->params['oauth_signature'] = $this->HMAC_SHA1();
$headers = array();
ksort($this->params);
foreach($this->params as $k => $v){
$headers[] = $this->RFC3986($k).'="'.$this->RFC3986($v).'"';
}
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $this->REQUEST_TOKEN_URL);
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Authorization: OAuth '.implode(', ', $headers)));
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($c); // if(CURLOPT_RETURNTRANSFER == true){ return "Result" or FALSE }else{ return TRUE or FALSE }
curl_close($c);
return $result;
}
private function HMAC_SHA1() {
$text = $this->get_signature_base_string();
$key = $this->RFC3986($this->consumer_secret).'&'.$this->RFC3986($this->token_secret);
if(function_exists('hash_hmac')){
$signature = base64_encode(hash_hmac('sha1', $text, $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);
$hmac = pack('H*', $hashfunc(($key ^ $opad).pack('H*', $hashfunc(($key ^ $ipad).$base_string))));
$signature = base64_encode($hmac);
}
return $signature;
}
private function get_signature_base_string() {
$base = array(
strtoupper($this->method),
$this->RFC3986($this->REQUEST_TOKEN_URL),
$this->RFC3986($this->get_normalized_params())
);
return implode('&', $base);
}
private function RFC3986($str) {
return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($str))));
}
private function get_normalized_params() {
$normalized = array();
ksort($this->params);
foreach($this->params as $k => $v){
if($k != 'oauth_signature'){
$normalized[] = $k.'='.$v;
}
}
return implode('&', $normalized);
}
}
$T = new Twitter();
echo $T->get_request_token();
Could it be your server clock? http://blainegarrett.com/2009/07/14/failed-to-validate-oauth-signature-and-token-on-twitter-oauth-check-your-cloc/

another twitter oAuth cURL access token request that fails

The following function gives a validation error instead of the token:
failed to validate oAuth signature and token
function request_token()
{
// Set url
$url = $this->site.$this->request_token_path; // http://api.twitter.com/oauth/request_token
// Params to pass to twitter and create signature
$params['oauth_consumer_key'] = $this->consumerKey;
$params['oauth_token'] = '';
$params['oauth_nonce'] = SHA1(time());
$params['oauth_timestamp'] = time();
$params['oauth_signature_method'] = $this->signatureMethod; // HMAC-SHA1;
$params['oauth_version'] = $this->version; // 1.0
ksort($params);
//print "<pre>"; print_r($params); print "</pre>";
// Create Signature
$concatenatedParams = '';
foreach($params as $k => $v){
$concatenatedParams .= "{$k}={$v}&";
}
$concatenatedParams = substr($concatenatedParams,0,-1);
$signatureBaseString = "POST&".urlencode($url)."&".urlencode($concatenatedParams);
$params['oauth_signature'] = base64_encode(hash_hmac('SHA1', $signatureBaseString, $this->secret."&", TRUE));
// Do cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLINFO_HEADER_OUT, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
$exec = curl_exec ($ch);
$info = curl_getinfo($ch);
curl_close ($ch);
print $exec;
//print "<pre>"; print_r($info); print "</pre>";
}
Below is what Ive put together so far and it works :-)
class Twitauth
{
var $key = '';
var $secret = '';
var $request_token = "https://twitter.com/oauth/request_token";
function Twitauth($config)
{
$this->key = $config['key']; // consumer key from twitter
$this->secret = $config['secret']; // secret from twitter
}
function getRequestToken()
{
// Default params
$params = array(
"oauth_version" => "1.0",
"oauth_nonce" => time(),
"oauth_timestamp" => time(),
"oauth_consumer_key" => $this->key,
"oauth_signature_method" => "HMAC-SHA1"
);
// BUILD SIGNATURE
// encode params keys, values, join and then sort.
$keys = $this->_urlencode_rfc3986(array_keys($params));
$values = $this->_urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
uksort($params, 'strcmp');
// convert params to string
foreach ($params as $k => $v) {$pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v);}
$concatenatedParams = implode('&', $pairs);
// form base string (first key)
$baseString= "GET&".$this->_urlencode_rfc3986($this->request_token)."&".$this->_urlencode_rfc3986($concatenatedParams);
// form secret (second key)
$secret = $this->_urlencode_rfc3986($this->secret)."&";
// make signature and append to params
$params['oauth_signature'] = $this->_urlencode_rfc3986(base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE)));
// BUILD URL
// Resort
uksort($params, 'strcmp');
// convert params to string
foreach ($params as $k => $v) {$urlPairs[] = $k."=".$v;}
$concatenatedUrlParams = implode('&', $urlPairs);
// form url
$url = $this->request_token."?".$concatenatedUrlParams;
// Send to cURL
print $this->_http($url);
}
function _http($url, $post_data = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
if(isset($post_data))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->last_api_call = $url;
curl_close($ch);
return $response;
}
function _urlencode_rfc3986($input)
{
if (is_array($input)) {
return array_map(array('Twitauth', '_urlencode_rfc3986'), $input);
}
else if (is_scalar($input)) {
return str_replace('+',' ',str_replace('%7E', '~', rawurlencode($input)));
}
else{
return '';
}
}
}
not sure if your still looking into this, or if it will work for you, but i had a similar setup and had the same issue. I eventually found i was urlencoding one to many times.
Try commenting out this section:
$keys = $this->_urlencode_rfc3986(array_keys($params));
$values = $this->_urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
Worked for me, so maybe it will help.
I'll admit this isn't really an answer, but if you can, use the PECL OAuth package. Rasmus Lerdorf wrote a tutorial on how to use it and it got me around this same issue.
I faced same issue, what I was missing is passing header in to the curl request. As shown in this question, I was also sending the $header = array('Expect:'), which was the problem in my case. I started sending signature in header with other data as below and it solved the case for me.
$header = calculateHeader($parameters, 'https://api.twitter.com/oauth/request_token');
function calculateHeader(array $parameters, $url)
{
// redefine
$url = (string) $url;
// divide into parts
$parts = parse_url($url);
// init var
$chunks = array();
// process queries
foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', urlencode_rfc3986($key) . '="' . urlencode_rfc3986($value) . '"');
// build return
$return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
$return .= implode(',', $chunks);
// prepend name and OAuth part
return $return;
}
function urlencode_rfc3986($value)
{
if(is_array($value)) return array_map('urlencode_rfc3986', $value);
else
{
$search = array('+', ' ', '%7E', '%');
$replace = array('%20', '%20', '~', '%25');
return str_replace($search, $replace, urlencode($value));
}
}

Categories