I'm working on a script that utilizes the Twitter API to post a tweet. It's for a very minimal service so I chose to utilize with a single function rather than using an entire library.
This is what the function looks like:
function postTweet($content, $method = 'POST') {
$consumer_key = '';
$consumer_secret = '';
$access_token = '';
$access_secret = '';
$nonce = md5(mt_rand(1, 10000000));
$tstamp = time();
$uri = 'https://api.twitter.com/1.1/statuses/update.json';
$data = array('status' => $content);
$ch = curl_init();
$parameters = [
"oauth_consumer_key" => $consumer_key,
"oauth_nonce" => $nonce,
"oauth_signature_method" => "HMAC-SHA1",
"oauth_timestamp" => $tstamp,
"oauth_token" => $access_token,
"oauth_version" => "1.0"
];
$base = $method.'&'.rawurlencode($uri).'&';
$parameters = array_merge($parameters, $data);
array_map('rawurlencode', $parameters);
array_map('rawurlencode', array_keys($parameters));
$pstring = '';
foreach ($parameters as $key => $value) {
$pstring .= sprintf("%s=%s&", $key, $value);
}
$pstring = substr($pstring, 0, strlen($pstring) - 1);
$base .= rawurlencode($pstring);
$signingKey = rawurlencode($consumer_secret).'&'.rawurlencode($access_secret);
$signature = base64_encode(hash_hmac('sha1', $base, $signingKey, true));
$options = [
CURLOPT_URL => $uri,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
sprintf('Authorization: OAuth oauth_consumer_key="%s", oauth_nonce="%s", oauth_signature="%s", oauth_signature_method="HMAC-SHA1", oauth_timestamp="%d", oauth_token="%s", oauth_version="1.0"', $consumer_key, $nonce, rawurlencode($signature), $tstamp, $access_token)
]
];
curl_setopt_array($ch, $options);
if($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
}
if ($data !== null && $method == 'POST') {
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
}
return json_decode(curl_exec($ch), true);
}
And it works, but only for a single word. Testing!
passes and is being posted on Twitter, while Testing testing!
does not and Twitter returns error 32 "Could not authenticate you.".
I think this is some kind of encoding issue, otherwise it wouldn't post the word. I've tried adding urlencode
and rawurlencode
to $content
, which did not result in success.
What could be the problem?
The problem comes from these lines:
array_map('rawurlencode', $parameters);
array_map('rawurlencode', array_keys($parameters));
They have no effect because you don't do anything with the return values. I suggest removing them and doing this instead:
$pstring = '';
foreach ($parameters as $key => $value) {
$pstring .= sprintf("%s=%s&", rawurlencode($key), rawurlencode($value));
}