PHP

Get Tweets and cache in XML whilst staying under the API Limit

Edit: Added security features for judging when malicious tweets with dead links enter the XML. These links are designed to break XML web services to harm a site. We now test the xml and if it validates then write it to file.

The view:

    	<div class="twitter_box" style='width:150px; word-wrap: break-word;'>
    		<?php $tweet_amount=3; include $GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT']."/ext_webservices/twitter/test_twitter.php"; ?>
    		<?php 
    		if(is_array($tweets)){
	
				echo '<ul id="tweets">';
				foreach($tweets as $tweet){
					if($iterations < 4){				
						/** Echo Changed string **/
						if($iterations == 1){
							echo '<li class="first">'.$tweet['text'].'</li>';
						}elseif($iterations == 3){
							echo '<li class="last">'.$tweet['text'].'</li>';
						}else{
							echo '<li>'.$tweet['text'].'</li>';
						}	
						$iterations++;
					}
				}
				echo '</ul>';
			}else echo '<p>'.$tweets.'</p>';
		?>
    	</div>

The controller:

<?php
include_once "twitter.inc.php";

$iterations = 1;

$twitter = new Twitter();
$tweets = $twitter->getTweets('username', 'pass');
if(is_array($tweets)){
	for($i=0;$i<count($tweets);$i++){
		
		/** Put into a variable to make our coding lives a little easier **/
		$tweet_text = $tweets[$i]['text'];
		
		/** Replace tiny and shortened URIs
		 * 
		 * @ This replaces all the URIs in a tweet to correctly redirect 
		 */
		$pattern = "/http:\/\/([a-zA-z0-9]+).([a-zA-z]+)\/([a-zA-z0-9]+)/";
		$replacement = "<a href='http://$1.$2/$3'>http://$1.$2/$3</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		
		/** Replace URIs in general
		 * 
		 * @ This will replace all URIs in general
		 */
		$pattern = "/([http|https]+):\/\/([a-zA-z0-9.]+)([com|co.uk|biz]+)\/([a-zA-z0-9#=?._\-\/ ]+)/";
		$replacement = "<a href='$1://$2$3/$4'>$1://$2$3/$4</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);		
		
		/** Replace #URIs
		 * 
		 * @ This replaces all the hashed URIs to redirect to search pages
		 */
		$pattern = "/#([a-zA-Z0-9]+)/";
		$replacement = '<a href="http://twitter.com/search?q=%23$1">#$1</a>';
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		
		/** Replace Usernames
		 * 
		 * @ This replace all the @username URIs to redirect to profiles on Twitter
		 */
		$pattern = "/@([a-zA-Z0-9_]+)/";
		$replacement = "<a href='http://twitter.com/$1'>@$1</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		$tweets[$i]['text'] = $tweet_text;
	}
}else{
		/** Put into a variable to make our coding lives a little easier **/
		$tweet_text = $tweets;
		
		/** Replace tiny and shortened URIs
		 * 
		 * @ This replaces all the URIs in a tweet to correctly redirect 
		 */
		$pattern = "/http:\/\/([a-zA-z0-9]+).([a-zA-z]+)\/([a-zA-z0-9]+)/";
		$replacement = "<a href='http://$1.$2/$3'>http://$1.$2/$3</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		
		/** Replace URIs in general
		 * 
		 * @ This will replace all URIs in general
		 */
		$pattern = "/([http|https]+):\/\/([a-zA-z0-9.]+)([com|co.uk|biz]+)\/([a-zA-z0-9#=?._\-\/ ]+)/";
		$replacement = "<a href='$1://$2$3/$4'>$1://$2$3/$4</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);		
		
		/** Replace #URIs
		 * 
		 * @ This replaces all the hashed URIs to redirect to search pages
		 */
		$pattern = "/#([a-zA-Z0-9]+)/";
		$replacement = '<a href="http://twitter.com/search?q=%23$1">#$1</a>';
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		
		/** Replace Usernames
		 * 
		 * @ This replace all the @username URIs to redirect to profiles on Twitter
		 */
		$pattern = "/@([a-zA-Z0-9_]+)/";
		$replacement = "<a href='http://twitter.com/$1'>@$1</a>";
		$tweet_text = preg_replace($pattern, $replacement, $tweet_text);
		$tweets = $tweet_text;	
}

The model:

<?php
class Twitter{
	private $tweet_count =10;
	private $twitter_api_url = 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=';
	private $cache_folder = "";
	private $cache_expiration = 3600;

	public function getTweets($twitter_username = false, $twitter_password = false){

		if(!$twitter_username) return 'Error, you have not provided a Twitter username';

		$this->cache_folder = $_SERVER['DOCUMENT_ROOT']."/ext_webservices/twitter/cache";
		$cache_file = $this->cache_folder.'/'.$twitter_username.'.xml';

		if(!is_file($cache_file) || (date("U") - date("U", filemtime($cache_file))) > $this->cache_expiration){
			if(is_string($value = $this->storeCache($cache_file, $twitter_username, $twitter_password))) return $value;
		}

		return $this->readCache($cache_file);
	}

	private function readCache($cache_file = false, $tweets_array = false){

		libxml_use_internal_errors(true);

		$cacheXML = simplexml_load_file($cache_file);
		if(is_object($cacheXML)){
			foreach($cacheXML->status as $status){
				$tweets_array[] = array(
					'created' => (string)$status->created_at,
					'text' => (string)$status->text);
			}
			return(is_array($tweets_array))? array_slice($tweets_array, 0, $this->tweet_count) : 'There are no tweets available';
		}else{
			return 'There was an unknown error please try again later';
		}
	}

	private function storeCache($cache_file = false, $twitter_username = false, $twitter_password = false){

		libxml_use_internal_errors(true);

		if(is_dir($this->cache_folder)){
			if(is_writable($this->cache_folder)){
				if($twitter_password){
					ini_set("default_socket_timeout", 1);
					$context = stream_context_create(array(
														'http' => array(
																'header'=>"Authorization: Basic".base64_encode("$twitter_username:$twitter_password"),
																'timeout'=>5)
															));

					if(@file_get_contents($this->twitter_api_url . $twitter_username, false, $context)){

						$tweets = file_get_contents($this->twitter_api_url . $twitter_username, false, $context);

						$a = @simplexml_load_string($tweets);
						if($a===FALSE) {
						}else{
							$cacheHandle = fopen($cache_file, 'w');
							fwrite($cacheHandle, $tweets);
							fclose($cacheHandle);
						}
					}else{
						if(!file_exists($cache_file)){

							$a = @simplexml_load_string($tweets);
							if($a===FALSE) {
							}else{
								/** write an empty xml file **/
								$tweets = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<statuses type=\"array\"/>";
								$cacheHandle = fopen($cache_file, 'w');
								fwrite($cacheHandle, $tweets);
								fclose($cacheHandle);
							}
						}else{
							touch($cache_file);
						}
						//return "Twitter seems to be having problems at the moment. Please standby";
					}
				}else{
					$tweets = file_get_contents($this->twitter_api_url, $twitter_username);

					switch($http_response_header[0]){
						case 'HTTP/1.1 200 OK':

							$a = @simplexml_load_string($tweets);
							if($a===FALSE) {
							}else{
								$cacheHandle = fopen($cache_file, 'w');
								fwrite($cacheHandle, $tweets);
								fclose($cacheHandle);
							}
							break;
						case 'HTTP/1.1 401 Unauthorized':
							return "Error, the Twitter password you have supplied is either invalid or missing";
							break;
						case 'HTTP/1.1 404 Not Found':
							return "Error, the Twitter username you supplied has not been found";
							break;
						default:
							return "Error, an error occured while communicating with Twitter, please try again later";
							break;
					}

					return true;
				}
			}else return 'Error, the folder you have specified is not writable';
		}else return 'Error, the folder you have specified does not exist';
	}
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s