The following function gives a validation error instead of the token:
failed to validate oAuth signature and token
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.
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 '';
}
}
}
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));
}
}
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.