Authorizing with oAuth, posting to Twitter

curl, php, twitter, twitter-oauth

Solution

I had three problems:

(1) I did not include it in this question, but my signature wasn't created correctly.

What I was doing was `base64_encode(hash_hmac('sha1', $base, $key));` but I should have set the hash_hmac fourth parameter to `true` to return a raw binary instead of the hexidecimal (the hexidecimal is shown as the example in the Twitter docs, which was what was confusing me). The correct function is therefore: `base64_encode(hash_hmac('sha1', $base, $key, true));`.

(2) The cURL was not set up correctly. I required CURLOPT_HTTPHEADER to set the Authorization, and CURL_VERBOSE set to true:

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: ' . $DST));
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'status='.rawurlencode($status));
curl_setopt($ch, CURLOPT_URL, $url);

(3) As seen in the above code, I had to post the status as a string, and not an array. I found the solution to this problem on this question: Why can't I authenticate with OAuth?.

All of this is now working perfectly. Also, make sure that your access token in your Twitter application says that the access level is "Read and write". If not, change the permissions in Settings, then go back to Details and recreate your access token.

Full Script

<?php

class Tweet {

public $url = 'https://api.twitter.com/1/statuses/update.json';

function the_nonce(){
    $nonce = base64_encode(uniqid());
    $nonce = preg_replace('~[\W]~','',$nonce);
    return $nonce;
}

function get_DST($status){

    $url = $this->url;

    $consumer_key = $your_consumer_key_here;
    $nonce = $this->the_nonce();
    $sig_method = 'HMAC-SHA1';
    $timestamp = time();
    $version = "1.0";
    $token = $your_token_here;
    $access_secret = $your_access_secret_here;
    $consumer_secret = $your_consumer_secret_here;

    $param_string = 'oauth_consumer_key='.$consumer_key.
            '&oauth_nonce='.$nonce.
            '&oauth_signature_method='.$sig_method.
            '&oauth_timestamp='.$timestamp.
            '&oauth_token='.$token.
            '&oauth_version='.$version.
            '&status='.rawurlencode($status);
    $sig_base_string = 'POST&'.rawurlencode($url).'&'.rawurlencode($param_string);
    $sig_key = rawurlencode($consumer_secret).'&'.rawurlencode($access_secret);

    $tweet_sig = base64_encode(hash_hmac('sha1', $sig_base_string, $sig_key, true));

    $DST = 'OAuth oauth_consumer_key="'.rawurlencode($consumer_key).'",'.
        'oauth_nonce="'.rawurlencode($nonce).'",'.
        'oauth_signature="'.rawurlencode($tweet_sig).'",'.
        'oauth_signature_method="HMAC-SHA1",'.
        'oauth_timestamp="'.rawurlencode($timestamp).'",'.
        'oauth_token="'.rawurlencode($token).'",'.
        'oauth_version="1.0"';
    return $DST;
}

function set($status){

    $url = $this->url;

    $ch = curl_init();

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: ' . $this->get_DST($status)));
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'status='.rawurlencode($status));
curl_setopt($ch, CURLOPT_URL, $url);

    $result = json_decode(curl_exec($ch));
if(!curl_errno($ch)){
    $info = curl_getinfo($ch);
    if($info['http_code']!='200'){
//error posting
echo 'Error: '.$result->{'error'};
    }else{
//success
echo 'Success! <a href="https://twitter.com/AOKHalifax/status/'.$result->{'id_str'}.'" target="_blank">View Tweet</a>';
    }
}else{
    //error connecting
    echo 'error posting';
    }
    curl_close($ch);
    }
}

/* 
Usage example:
$status = new Tweet();
$status->set('checking'); 
*/

?>

Problem

I've created a Twitter Application to auto-post to my Twitter account. So, I don't need to authorize new users. I've already set access level to read/write, and received an access token. I've used the OAuth Tool in the application to generate a cURL command: curl --request 'POST' 'https://api.twitter.com/1/statuses/update.json' --data 'status=Maybe+he%27ll+finally+find+his+keys.+%23peterfalk' --header 'Authorization: OAuth oauth_consumer_key="...", oauth_nonce="97fad626790e8e5988d4a06cfd47fa74", oauth_signature="...", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1364161424", oauth_token="...", oauth_version="1.0"' --verbose Above the command, it says: Important: This will only be valid for a few minutes. Also remember the cURL command will actually execute the request. I assume that this will work in a linux terminal. I'd like to know how to translate this into a PHP cURL command. Here's what I've tried. Note that value of $DST is the value of "DST" in https://dev.twitter.com/docs/auth/authorizing-request; it is also equal to the value of the string after `--header 'Authorization:` in the cURL command in the OAuth tool. ``` $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => $url, CURLOPT_POST => 1, CURLOPT_POSTFIELDS => array( data => 'status='.urlencode($status), header => 'Authorization: '.$DST ) )); $resp = curl_exec($ch); curl_close($ch); ``` But the value of `$resp` is: ``` { request: "/1/statuses/update.json", error: "Could not authenticate you." } ``` Is there something I'm doing wrong? Note that the OAuth Tool said that the cURL command would actually work. So I think it's just a matter of figuring out how to arrange the cURL in PHP. I'm not very familiar with it. Also note that I want to avoid using the OAuth libraries if I can. I feel like there should be a much more light-weight solution to this than to install a whole library.

Original source

Related problems