Hi everyone!
I wrote my own PHP code to publish statuses from my website through the REST API. Everything is working like a charm except when I want to publish with the media_ids parameter, which seems being ignored when using the status endpoint.
I tried everything I could, adding my own owner ID with the additional_owners parameter but with no luck. I don’t understand where my code failed.
You’ll find below my snippet code to call the API
<?php
function Twitter_api_call($array)
{
$time = time();
$action = $array['action'];
if ($action == 'view' || $action == 'get' || $action == 'read') {
$action = 'show';
} elseif ($action == 'post') {
$action = 'update';
} elseif ($action == 'delete') {
$action = 'destroy';
} elseif ($action == 'create_metadata') {
$action = 'metadata';
}
$consumer_key = $array['consumer_key'];
$consumer_secret = $array['consumer_secret'];
$access_token = $array['access_token'];
$access_token_secret = $array['access_token_secret'];
if (is_null($action) || empty($action)) {
exit('Action is not set');
} if (is_null($consumer_key) || empty($consumer_key)) {
exit('Consumer key is not set');
} if (is_null($consumer_secret) || empty($consumer_secret)) {
exit('Consumer secret is not set');
} if (is_null($access_token) || empty($access_token)) {
exit('Access token is not set');
} if (is_null($access_token_secret) || empty($access_token_secret)) {
exit('Access token secret is not set');
}
/* API calls */
$api_url['timeline'] = 'https://api.twitter.com/1.1/statuses/user_timeline.json';
$api_url['update'] = 'https://api.twitter.com/1.1/statuses/update.json';
$api_url['destroy'] = 'https://api.twitter.com/1.1/statuses/destroy/' . $array['id'] . '.json';
$api_url['upload'] = 'https://upload.twitter.com/1.1/media/upload.json';
$api_url['metadata'] = 'https://upload.twitter.com/1.1/media/metadata/create.json';
$api_url['show'] = 'https://api.twitter.com/1.1/statuses/show/' . $array['id'] . '.json';
/* curl URL */
$curl_url = $api_url[$action];
/* Method */
$method = 'GET';
if ('metadata' == $action || 'update' == $action || 'upload' == $action || 'destroy' == $action) {
$method = 'POST';
}
/* OAuth fields */
$oauth_fields['oauth_consumer_key'] = $consumer_key;
$oauth_fields['oauth_nonce'] = $time;
$oauth_fields['oauth_signature_method'] = 'HMAC-SHA1';
$oauth_fields['oauth_timestamp'] = $time;
$oauth_fields['oauth_token'] = $access_token;
$oauth_fields['oauth_version'] = '1.0';
/* Signature */
$oauth_hash = '';
foreach ($oauth_fields as $key => $val) {
$oauth_hash .= $key . '=' . $val . '&';
}
$oauth_hash = trim($oauth_hash, ' &');
$base = $method
. '&' . rawurlencode($api_url[$action])
. '&' . rawurlencode($oauth_hash);
$key = rawurlencode($consumer_secret)
. '&' . rawurlencode($access_token_secret);
$hash_hmac = hash_hmac('sha1', $base, $key, true);
$signature = base64_encode($hash_hmac);
$signature = rawurlencode($signature);
/* cURL header */
$oauth_fields['oauth_signature'] = $signature;
ksort($oauth_fields);
$oauth_header = '';
foreach ($oauth_fields as $key => $val) {
$oauth_header .= $key . '="' . $val . '", ';
}
$oauth_header = trim($oauth_header, ' ,');
$curl_header[] = 'Authorization: OAuth ' . $oauth_header;
$curl_opt[CURLOPT_URL] = $curl_url;
$curl_opt[CURLOPT_SSL_VERIFYPEER] = false;
$curl_opt[CURLOPT_RETURNTRANSFER] = true;
$curl_opt[CURLOPT_HEADER] = false;
if ('update' == $action || 'upload' == $action) {
$curl_opt[CURLOPT_POST] = true;
if ('upload' == $action) {
$opt['media'] = file_get_contents($array['media']);
if (!is_null($array['additional_owners'])) {
$opt['additional_owners'] = $array['additional_owners'];
}
} else {
$opt['status'] = $array['status'];
if (!empty($array['media_ids'])) {
$opt['media_ids'] = $array['media_ids'];
}
}
$curl_opt[CURLOPT_POSTFIELDS] = $opt;
} elseif ('metadata' == $action) {
$curl_opt[CURLOPT_POST] = true;
$curl_header[] = 'Content-Type: application/json';
$json = json_encode([
'media_id' => $array['media_id'],
'alt_text' => [
'text' => $array['alt_text']
]
]);
$curl_opt[CURLOPT_POSTFIELDS] = $json;
}
$curl_opt[CURLOPT_HTTPHEADER] = $curl_header;
$ch = curl_init();
curl_setopt_array($ch, $curl_opt);
$json = curl_exec($ch);
return $json;
}
What are my steps:
- Uploading the media file:
Twitter_api_call([
'consumer_key' => $consumer_key,
'consumer_secret' => $consumer_secret,
'access_token' => $access_token,
'access_token_secret' => $access_token_secret,
'action' => 'upload',
'media' => 'path_to_file'
]);
The server response looks all good:
{
"media_id": 993508580614602753,
"media_id_string": "993508580614602753",
"size":415253,
"expires_after_secs":86400,
"image": {
"image_type": "image\/jpeg",
"w":1707,
"h":1280
}
}
- Retrieving the media_id_string return, then posting status:
Twitter_api_call([
'consumer_key' => $consumer_key,
'consumer_secret' => $consumer_secret,
'access_token' => $access_token,
'access_token_secret' => $access_token_secret,
'action' => 'update',
'media_ids' => $media_id_string,
'status' => 'My new tweet with an attached media!'
]);
And the response from the status:
{
"created_at": "Mon May 07 15: 32: 28 +0000 2018",
"id": 993513906030239745,
"id_str": "993513906030239745",
"text": "My new tweet with an attached media!",
"truncated": true,
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": [
{
"url": "http:\/\/t.co\/MwRajL5w3X",
"expanded_url": "http:\/\/twitter.com\/i\/web\/status\/993513906030239745",
"display_url": "twitter.com\/i\/web\/status\/9\u2026",
"indices": [117,140]
}
]
},
"source": "<a href=\"http:\/\/www.coasterrider.fr\" rel=\"nofollow\">Coasterrider<\/a>",
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": ...,
"id_str": "...",
"name": "Coasterrider",
"screen_name": "CoasterriderFR",
"location": "",
"description": "Roller coasters, parcs, attractions et divertissement au rapport depuis 2004",
"url": "http:\/\/t.co\/cTsSmPTzmd",
"entities": {
"url": {
"urls": [
{
"url": "http:\/\/t.co\/cTsSmPTzmd",
"expanded_url": "http:\/\/www.coasterrider.fr",
"display_url": "coasterrider.fr",
"indices": [0,23]
}
]
},
"description": {
"urls": []
}
},
"protected": false,
"followers_count": 5,
"friends_count": 0,
"listed_count": 0,
"created_at": "Wed Sep 07 05: 39: 09 +0000 2011",
"favourites_count": 0,
"utc_offset": 7200,
"time_zone": "Brussels",
"geo_enabled": true,
"verified": false,
"statuses_count": 1,
"lang": "fr",
"contributors_enabled": false,
"is_translator": false,
"is_translation_enabled": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png",
"profile_background_image_url_https": "http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png",
"profile_background_tile": false,
"profile_image_url": "http:\/\/pbs.twimg.com\/profile_images\/992174072086835200\/pz4Y1Yut_normal.jpg",
"profile_image_url_https": "http:\/\/pbs.twimg.com\/profile_images\/992174072086835200\/pz4Y1Yut_normal.jpg",
"profile_banner_url": "http:\/\/pbs.twimg.com\/profile_banners\/369337898\/1525387292",
"profile_link_color": "1DA1F2",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"has_extended_profile": false,
"default_profile": true,
"default_profile_image": false,
"following": false,
"follow_request_sent": false,
"notifications": false,
"translator_type": "none"
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"retweet_count": 0,
"favorite_count": 0,
"favorited": false,
"retweeted": false,
"lang": "fr"
}
As you can see, I don’t get any errors from the calls, but the status is still posted, just without the media attached to it.
I tried to follow the suggestions from this topic, this one, this one or this one but haven’t found solutions to my problem…
That’s why I’m coming to you, any helps and clues are welcomed! Many thanks 