Adding File Caching To Your Twitter API Script
On 02.24.2010 by Paul Robinson |
In our last tutorial we created a script to connect to the Twitter API, collect our tweets & display them in some simple paragraphs. In this part we are going to add a very important part, file caching. This will stop our script from running out of API requests.
File caching is extremely important in a script like this. It stops you from running over your allocated API limit by saving the received API data in a file on your server. We tell the script to use the data in the file until a preset amount of time has passed. Once the allotted time has passed the script will re-connect to Twitter, grab the API data & store it in the file again. The process then repeats.
Let’s look at an example. If we set our cache time to 1800 seconds (30 minutes), the script will continue to use the cached API data until the file is 1800 seconds old. To do this we check the file’s modified date and time against the current date and time.
Adding File Caching
Let’s take a look at where we got to with our code last time:
//initialize a new curl resource
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://twitter.com/statuses/user_timeline/twitterusername.json?count=10');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
if($content === FALSE) {
//Content couldn't be retrieved... Do something. Possibly end the function prematurely hence no else.
}
$content = json_decode($content);
foreach($content as $tweet) {
echo '<p>'.$tweet->text.'</p>';
}
Now that we’ve recapped where we were up to in our code, let’s try and add some file caching. If this is your first foray into file writing using PHP, don’t worry; it’s actually fairly simple. The first thing we need to do is write the part of the script that checks the age of the cache file and determines if we need to renew it or not. Let’s get down to it.
//This part goes before all the other scripting we have done
$cache = FALSE; //Assume the cache is empty
$cPath = '/path/to/cache/file.cache';
if(file_exists($cPath)) {
$modtime = filemtime($cPath);
$timeago = time() - 1800; //30 minutes ago in Unix timestamp format (no. seconds since 1st Jan 1970)
if($modtime < $timeago) {
$cache = FALSE; //Set to false just in case as the cache needs to be renewed
} else {
$cache = TRUE; //The cache is not too old so the cache can be used.
}
}
This part of the code goes before everything else (as noted in the comment). Let’s go through what the code does. First we set a cache variable to false as we should always assume that this is first run and has no cache to load. Next we set the path to the cache, use a path from root if possible (Unix and Windows).
Now we check to see if the cache exists yet, if it does we get the last time it was modified, and we get the current time minus 30 minutes. Now we ask if the time the file was modified is older than the current time minus 30 minutes. For example; if the file was modified at 8:30 and the script is ran at 8:45, the modified time would be greater than the $timeago variable as $timeago would be 8:15 (8:45 -30 mins = 8:15) meaning the cache would not be updated. Of course in this case we are just setting a variable to true or false to tell the script to update (or not) the cache later.
Hopefully that wasn’t too confusing. I know I said it wasn’t confusing, but I meant the file creation code, not the file modification time comparison code.
Now we need to modify the code we wrote before slightly. To save time I’ll write out the entire code together.
$cache = FALSE; //Assume the cache is empty
$cPath = '/path/to/cache/file.cache';
if(file_exists($cPath)) {
$modtime = filemtime($cPath);
$timeago = time() - 1800; //30 minutes ago in Unix timestamp format (no. seconds since 1st Jan 1970)
if($modtime < $timeago) {
$cache = FALSE; //Set to false just in case as the cache needs to be renewed
} else {
$cache = TRUE; //The cache is not too old so the cache can be used.
}
}
if($cache === FALSE) {
//initialize a new curl resource
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://twitter.com/statuses/user_timeline/twitterusername.json?count=10');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
if($content === FALSE) {
//Content couldn't be retrieved... Do something. Possibly end the function prematurely hence no else.
}
//Let's save our data into the cache
$fp = fopen($cPath, 'w');
if(flock($fp, LOCK_EX)) {
fwrite($fp, serialize($content));
flock($fp, LOCK_UN);
}
fclose($fp);
} else {
//cache is TRUE let's load the data from the cache.
$content = file_get_contents($cPath);
}
$content = json_decode($content);
foreach($content as $tweet) {
echo '<p>'.$tweet->text.'</p>';
}
That is the entire script. Let’s go through the new parts. First we have wrapped our cURL code in a conditional statement. It just checks to see if $cache was false, as we only want to connect to Twitter if our cache is either non-existent or out of date.
After the Twitter connection we have our cache generation code. It’s fairly simple. We first use fopen, the first parameter is the path to the file to alter (or create) & the second is the mod, ‘w’ means write, truncate to zero if not empty & create if non-existent. flock() tries to give exclusive file access so that we can edit the file without interruptions. fwrite() writes the data to the file. We then unlock file access & close our file. For those wondering $fp is a file pointer resource used by the other file access scripts to know what file you are altering etc.
Finally should the cache already exist & not be out of date the other part of our conditional statement is activated & we just get the contents of our cache file & load them into $content. It is then handed to the same functions as if it had just came from Twitter.
I hope that has helped make some sense out of the complicated business that is file caching. The hard part is not so much creating the file, but checking if the file is too old or not. As always if you have any questions, suggestions etc let me know via the comments.
For those interested, there is one more tutorial to come in this series. It will be on how to merge retweets onto the standard tweets. It will probably be for more advanced users as it can get quite complicated, but feel free to follow along whatever your experience. Let me know if you have any other requests for the next tutorial.
Discussion: 6 Comments
Thanks for sharing this, i was looking for a good way to cache tweets and this works perfect!
No problem. Glad the tutorial helped you.
Thank you! I was using juitter but felt it was just too heavy for what I wanted to accomplish and just coded a very lightweight recent tweets widget with caching thanks to your code
Thanks. It’s good to know it helped.
Nice job explaining this, but I believe the script has an error.
Line 29 should read … $fp = fopen($cPath, ‘w’);
Indeed it should, sorry about that & thanks for letting me know about the mistake.
Tis fixed now though.