I recently decided that adding image uploads to Revision.net was of vital importance.

I personally use the Revision.net tooling on a daily basis to schedule my social media posts. Recently I have found myself taking significantly more photos, and as such I wanted an easy way to post them to Facebook, and Twitter and a specific time in the future.

In principle this should have been a relatively simple feature to implement. I did however encounter a few small issues which I wanted to document here.

Specification

Given the nature of the product, I wanted to allow a user to upload images directly to the Revision.net server. As the tool schedules posts to be submitted in the future this seemed like the logical approach.

Uploading photos directly to the Facebook and Twitter APIs on submission limits what we can and cannot do as regards future functionality. Furthermore, a brief look at the respective API documentation states:

  • Twitter: "The returned media_id is only valid for expires_after_secs seconds."

  • Facebook: "After you upload an unpublished photo, Facebook stores it in a temporary upload state, which means it will remain on Facebook servers for about 24 hours."

That is to say that were we to upload the images upon submission (to Revision.net) they would possibly not be available when we want to actual submit the status/tweet (to the respective API) at some point in the future.

The first specification requirement was thus image upload. This post will not go into how one can do that. The more crucial aspect of my implementation was the user experience - implementing image upload within the current React based interface so it looks good and functions seamlessly.

Uploading an image

The second part of the specification was obviously the uploading/transmission of the photos from our server to the respective APIs at/before the scheduled posting time, and then attaching them to the respective posts.

Implementation

Twitter provides a guide to uploading media. Facebook provides documentation on photo uploads.

Reading these pieces of documentation you will discern that Twitter requires you to upload a files binary data directly to their API OR a base64 encoded representation of the image. The Facebook API is more flexible in that it allows uploading binary file data but it also allows you to specify an image URL from which Facebook will 'pull' the image.

The implementation is largely the same across platforms - you 'upload' the images, and then you post the Tweet/status attaching the unique identifiers of the uploaded images.

Twitter

For interacting with the Twitter API I have been utilising twitter-api-php by James Mallison. I had been using my own extended fork of an older version of his codebase. I encountered a few issues with submitting image identifiers with a Tweet (once uploaded) as a result of some CURL encoding issues.

The latest version of the codebase works flawlessly out of the box, and even includes example implementations within the test suite.

I chose to continue with my own fork and implement upload of binary image data. This requires the specification of the Content-Type:multipart/form-data header within the CURL request.

The Twitter API upload endpoint (https://upload.twitter.com/1.1/media/upload.json) returns a media_id and a media_id_string value. These are appended to a comma separated string and then submitted as the media_ids parameter to the https://api.twitter.com/1.1/statuses/update.json endpoint.

One of the benefits of simple, bare bones open source projects like this is that you can (and should) read all of the source code. The simplicity makes it manageable, and easily extensible.

Facebook

Facebook provide their own comprehensive SDKs. I am using their PHP SDK (version 5.1).

Uploading an image simply requires firing off a POST request to the me/photos endpoint.

In my workflow, (as alluded to above) I specify the published=false parameter. This prevents the photo from being shown on the users wall - it will show on their wall when you attach the image to a status submission.

This call returns an id which is then posted as a JSON encoded parameter to the me/feed endpoint.

$postData['attached_media[' . $i . ']'] = json_encode(array('media_fbid' => $facebookImageId));

Facebook Pages

One great thing about how Facebook have built their API is that pages and user accounts are identified by a type agnostic unique identifier.

Revision.net allows scheduling posts to user accounts and user administrated pages. To achieve this we simply use the endpoints unique-identifier/photos and unique-identifier/feed regardless of whether the unique-identifier references a page or an account.

Debugging

The few issues that I had when working with these APIs were relatively simple to debug.

Both twitter-api-php and the Facebook PHP SDK use CURL behind the scenes. If you can not get things working I recommend debugging utilising CURL from the command line.

Twitter also provide twurl which makes the authorisation aspect of testing through the command line significantly simpler.

The Facebook SDK is feature rich, and it handles the processing of API errors and converts them to easily debuggable Exceptions. These relate to permissions, and access token validity for example. Simply catch these exceptions and handle them appropriately.

The only minor time drain that I had when developing this functionality was an Exception message from Facebook stating Unsupported post request. This occurred when attaching photos to a call to the feed endpoint that had previously been published (having not set published=false when uploading the image).
This error message is pretty unhelpful, and there seem to be a number of unanswered questions about it on StackOverflow. I suggest that should the above not resolve your issue, you:

  • Make sure the image you are trying to attach was uploaded by the same user.

  • Make sure that it has not already been 'published' through another medium.

  • Make sure the user has the appropriate permissions.

  • Make sure that the image has actually been uploaded correctly and that you can read data about it by calling the /v2.8/{photo-id} endpoint.

Given the simplicity of the twitter-api-php codebase similar Exception based simplicity is not provided out of the box. That said, the Twitter API does return JSON encoded error data which you can process and handle accordingly.

I have taken to handling all obvious errors, and logging anything that is not being (currently) handled. I can then monitor any issues that are occurring and implement appropriate handling down the line.

Intricacies and further considerations

It is probably apparent that my requirements are very basic - the uploading and scheduling of simple images via the Facebook and Twitter APIs.

Both APIs do however offer more complex endpoints for uploading other forms of media as well as for more complex upload requirements (resuming uploads etc).

One consideration of note is that the same user (API credentials) is used to post the tweet/status as was used to upload the photo. Twitter does allow the setting of the additional_owners property upon upload such that you can (for example) upload an image with your own site administrative credentials whilst specifying the user as the owner. This was not however appropriate for my use case - uploading and submitting as the user allows for permission verification, and error handling as part of the 'flow'.

Hopefully..

Hopefully the above provides some pretty clear insight into how one can work with the Twitter and Facebook APIs for uploading images.

All things considered, they are very well built, and very easy to work with.

If you have any specific questions or concerns, please let me know and I will do my best to answer them.