Posted: 10th March 2015

Author: Ric

Tagged: Tutorials

Reading from a Twitter feed with PHP

It used to be pretty easy to output a Twitter feed onto your website, but since Twitter decided to close down their public feeds (both RSS and XML), and introduce OAuth into their API, doing this became a bit of a headache. This happened quite some time ago now but there still seems to be a large number of websites out there with broken Twitter outputs so here's a quick tutorial to get you up and running again.

For the record, I tend to recommend doing this server-side rather than using any of the available Javascript options, because this results in static HTML that Google etc can parse, making Twitter outputs a good way to keep your pages constantly updating which is great for SEO. Additionally, Javascript relies on client-side support which makes it a poor choice for anything other than fancying-up your website, assuming you care about accessibility.

  1. First of all head over to dev.twitter.com and sign in with the same credentials that you use to access the Twitter account that you intend to output from.

  2. Select Tools -> Manage Your Apps from the dev.twitter.com home page, then Create New App.

  3. Type in a sensible name, like "Feed for my website", a description like "API access for my website" and the url of your website. This information won't actually be output anywhere or effect how the feed works but we need to provide it before we can get our authentication keys. If we were creating something that posted to Twitter or required more interaction with your account, these fields would be more relevant. Agree to the terms and submit.

  4. You'll be taken to the details page of the 'app' you've just created. Under Application Settings hit the Manage Keys and Access Tokens link.

  5. Note down the Consumer Key and Consumer Secret. We'll need to reference these within the website code later. Then hit the Create Access Token and again note down the generated Access Token and Access Token Secret. You now have everything needed to access your Twitter account through the API.

  6. If you've been asked by your developer to generate these keys, pass all 4 over to them and you're done. Otherwise if you are a developer, copy the following code to your website and populate the variables at the top.
<?php
    $screen_name = 'Your Twitter Name';
    $count = 1; // How many tweets to output
    $retweets = 0; // 0 to exclude, 1 to include

    // Populate these with the keys/tokens you just obtained
    $oauthAccessToken = '';
    $oauthAccessTokenSecret = '';
    $oauthConsumerKey = '';
    $oauthConsumerSecret = '';

    // First we populate an array with the parameters needed by the API
    $oauth = array(
        'count' => $count,
        'include_rts' => $retweets,
        'oauth_consumer_key' => $oauthConsumerKey,
        'oauth_nonce' => time(),
        'oauth_signature_method' => 'HMAC-SHA1',
        'oauth_timestamp' => time(),
        'oauth_token' => $oauthAccessToken,
        'oauth_version' => '1.0'
    );

    $arr = array();
    foreach($oauth as $key => $val)
        $arr[] = $key.'='.rawurlencode($val);

    // Then we create an encypted hash of these values to prove to the API that they weren't tampered with during transfer
    $oauth['oauth_signature'] = base64_encode(hash_hmac('sha1', 'GET&'.rawurlencode('https://api.twitter.com/1.1/statuses/user_timeline.json').'&'.rawurlencode(implode('&', $arr)), rawurlencode($oauthConsumerSecret).'&'.rawurlencode($oauthAccessTokenSecret), true));

    $arr = array();
    foreach($oauth as $key => $val)
        $arr[] = $key.'="'.rawurlencode($val).'"';

    // Next we use Curl to access the API, passing our parameters and the security hash within the call
    $tweets = curl_init();
    curl_setopt_array($tweets, array(
        CURLOPT_HTTPHEADER => array('Authorization: OAuth '.implode(', ', $arr), 'Expect:'),
        CURLOPT_HEADER => false,
        CURLOPT_URL => 'https://api.twitter.com/1.1/statuses/user_timeline.json?count='.$count.'&include_rts='.$retweets,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => false,
    ));

    $json = curl_exec($tweets);
    curl_close($tweets);

    // $json now contains the response from the Twitter API, which should include however many tweets we asked for.

    // Loop through them for output
    foreach(json_decode($json) as $status) {
        // Convert links back into actual links, otherwise they're just output as text
        $enhancedStatus = htmlentities($status->text, ENT_QUOTES, 'UTF-8');
        $enhancedStatus = preg_replace('/http:\/\/t.co\/([a-zA-Z0-9]+)/i', '<a href="http://t.co/$1">http://$1</a>', $enhancedStatus);
        $enhancedStatus = preg_replace('/https:\/\/t.co\/([a-zA-Z0-9]+)/i', '<a href="https://t.co/$1">http://$1</a>', $enhancedStatus);

        // Finally, output a simple paragraph containing the tweet and a link back to the Twitter account itself. You can format/style this as you like.
?>
<p>&quot;<?php echo $enhancedStatus; ?>&quot;<br /><a href="https://twitter.com/intent/user?screen_name=<?php echo $screen_name; ?>">@<?php echo $screen_name; ?></a></p>
<?php
    }
?>

If you want the link back to open in a classic Twitter pop-up, add this Javascript to your page too:

<script type="text/javascript" src="//platform.twitter.com/widgets.js"></script>

Blog posts written by former QWeb employees are not necessarily an accurate indication of the current opinions of QWeb Ltd and the information provided in tutorials might be biased or subjective, or might become out of date.

Discuss this post

Jane
22/12/2015 12:50

Thank you, I looked everywhere for such a simple solution.

Intoxication
05/07/2016 12:00

Thank you for such a simple solution.
Please is it possible to have the twitter profile image displayed as well?

Ric
05/07/2016 12:44

Profile images are available via another API endpoint, https://api.twitter.com/1.1/users/show.json

If you therefore replace the two url instances in the above code with the new endpoint, strip out the count and include_rts values from the $oauth array, and add in the required screen_name value to the end of that array and as a parameter to the CURLOPT_URL value, the new response should include a profile_image_url part.

More information here: https://dev.twitter.com/rest/reference/get/users/show

And a working example here: http://pastebin.com/1XVq8GTW

Intoxication
05/07/2016 14:53

Worked perfectly.

Thank you so much. You are a legend.

Ric
05/07/2016 15:01

No worries. If you need anything further do get in touch.

vijay
26/09/2016 07:22

how to execute this program

Ric
26/09/2016 10:01

This should work on any Curl enabled PHP server, Vijay.

valerio
11/05/2017 14:17

dev.twitter.com doesn’t have a login. i think the right place is https://apps.twitter.com

valerio
11/05/2017 14:25

is there a way to use this php code in a simple html page? what would you suggest?

Ric
11/05/2017 14:52

dev.twitter.com actually still works, but you’ve to sign in to the regular Twitter front before heading there. You should then see links to create/manage the apps associated to that account. You’re right though, apps.twitter.com is the same place.

If you’re running an nginx + Apache set-up, chances are your .html pages are being served by nginx without any PHP parsing, and for performance it’s a good idea to keep it that way. In which case you won’t be able to include PHP code directly on those pages I’m afraid. You could however add a Javscript to call a PHP script on page load, which could in turn respond with the HTML to output. jQuery.get() would be my approach for that.

https://api.jquery.com/jQuery.get/

Sirisha Garapati
14/06/2017 09:20

Thank you for the article.

Jason
03/08/2017 09:08

Hi,
Great article, thank you. Is there a way to get the expanded url to display under the tweet please?
Thanks in advance

Ric
03/08/2017 10:43

You’ll find an array of urls within the entities object for that, one for each of the shorturls used in the post.

For example if you posts includes the shorturl t.co/abc then in the returned json data you should see something like this:

$status->entities->urls[0]->url => ‘t.co/abc’
$status->entities->urls[0]->expanded_url => ‘www.google.com’

If your post includes 2 urls then you’d see this:

$status->entities->urls[0]->url => ‘t.co/abc’
$status->entities->urls[0]->expanded_url => ‘www.google.com’
$status->entities->urls[1]->url => ‘t.co/abcdef’
$status->entities->urls[1]->expanded_url => ‘www.amazon.com’

And so on.

Jason
03/08/2017 11:18

Fantastic, thank you so much for your help.

Regards
Jason

Erik
07/08/2017 21:55

Very useful script. It just works. Thank you!
Two questions though:
1) how to filter for #hashtags? (yes, it is possible to filter *after* you have received the tweets, but I’m assuming Twitter has an API for that)
2) how to obtain tweet metadata like creation time and coordinates using your script as a starting point?

Thanks in advance!

Regards,
Erik

Ric
07/08/2017 23:08

Twitter has a search endpoint which I believe works exclusively on hashtags, though I could be wrong about that.

https://dev.twitter.com/rest/reference/get/search/tweets

Regarding metadata, if you just replace lines 51 – 59 of the above script with a print_r($status); you’ll see the available metadata from the user_timeline endpoint that this script uses.

Bahram
02/12/2017 19:06

Very useful, thank you so much.

jatinder
04/12/2017 14:24

It worked fine, but i need to get tweet posted date. how i get posted date in yours this code…

Ric
04/12/2017 14:55

In the example above, $status->created_at should contain a value for that which you can pass through strtotime() to convert to a Unix timestamp.

Inayat Cassambai
17/07/2018 16:51

Hi,

The script works a charm, but i have one query.

How do i pull in the media data for each tweet? So if i have an image i can output that as well.

Thank you.

Ric
17/07/2018 17:19

If images are available within a tweet, you should see a $status->entities->media array that contains those. It expect it’s the media_url value that you’d want from that, to then just render as an img src.

https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object#media

Inayat Cassambai
18/07/2018 09:12

Thanks for the reply Ric.

Just been looking through the docs, and the API we’re querying doesn’t seem to have any parameters for media entities unfortunately.

https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline

Tis a shame as i feel like that should be necessary to have. Unless i’m missing something.

Although what’s interesting is, one of my colleagues has successfully pulled in images from their tweets by passing the tweet_mode=extended parameter.

https://api.twitter.com/1.1/statuses/user_timeline.json?tweet_mode=extended&screen_name=$username&count=$count&include_rts=$retweet

Even though that’s not mentioned in the parameters list in the docs, that seems to have worked for him. I’ve tried adding that to your snippet but it didn’t work, probably because i’m not adding something to your authentication array too.

Ric
18/07/2018 09:32

That’s strange. We’ve definitely integrated Twitter inclusive of posted media somewhere and the code would have been somewhat similar to the above, but for the life of me I can’t think where we did that now.

Twitter do keep changing their API so it’s entirely possible that the parameter you’ve found is how you were supposed to do this originally and they’ve since separated the endpoints out but left that param in for compatibility with old scripts. I’d be tempted to just go with that approach for the time being, but yes you would need to add to the oAuth array too, in the same order that you’ve added it to the actual call, just like the count and include_rts params are included.

Leave a comment

Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text and you won't be added to any mailing list and your details won't be shared with any third party.