previous_look = $_COOKIE['twitter-lastlook']; } else { // First time here. $this->previous_look = 0; } header('Set-Cookie:twitter-lastlook=' . gmmktime() . ';expires=Friday, 16-Jan-2037 00:00:00 GMT;domain=' . $_SERVER['SERVER_NAME'] . ";path=/\n\n"); // Do we need to change the default number of posts to show? if (isset($_GET['show'])) { if ($_GET['show'] == 'all') { $this->show = 'all'; } elseif ($_GET['show'] == 'recent') { $this->show = 'recent'; } } } /** * Show the latest posts from the user's friends. * @access public * @return boolean */ function display() { // Fetch the XML feed. $xml_data = $this->_fetchFileContents('http://twitter.com/statuses/friends_timeline.xml'); // Turn the XML into an array of TwitterPost objects. $parser = new TwitterParser(); $posts = $parser->parse($xml_data); return $this->_displayPosts($posts); } /** * Create a new status update. * @access public * @param string $text The status text to send. * @return string */ function post($text) { return $this->_fetchFileContents( 'http://twitter.com/statuses/update.xml', array ( 'status' => $text ) ); } /** * Display a list of posts. * @access private * @param array $posts An array of TwitterPost objects. * @return boolean */ function _displayPosts($posts) { // The URL of this page, so we can have a Refresh link. $url = $_SERVER['PHP_SELF']; if ($_SERVER['QUERY_STRING']) { $url .= '?' . $_SERVER['QUERY_STRING']; } print "

Refresh   "; // Navigation for recent/24hours. if ($this->show == 'recent') { print '[ Recent | 24 hours ]'; } elseif ($this->show == 'all') { print '[ Recent | 24 hours ]'; } print "

\n"; if (strtotime($posts[0]->created_at) < $this->previous_look) { print "

No new twitters.

\n"; } $html = ''; foreach ($posts as $n => $post) { if ($this->show == 'recent' && strtotime($post->created_at) < $this->previous_look) { // This post is older than when we last looked. // So we're not going to show any more. break; } if ($this->order_by == 'newest') { $html .= $post->display(false); } else { $html = $post->display(false) . $html; } } print $html; return true; } /** * Replacement for file_get_contents for when URL file-access is disabled. * @access private * @param string $url The URL of the file to fetch. * @param array $post_args A hash of POST arguments. * @return string The contents of the file or empty on failure. */ function _fetchFileContents($url, $post_args=array()) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt ($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_USERPWD, $this->email.':'.$this->password); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // Return the result instead of printing it curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); if (count($post_args) > 0) { $postfields = array(); foreach ($post_args as $key => $val) { $postfields[] = "$key=" . urlencode(utf8_encode($val)); } curl_setopt ( $ch, CURLOPT_POST, 1); curl_setopt ( $ch, CURLOPT_POSTFIELDS, implode('&', $postfields)); } $string = curl_exec ($ch); if (curl_errno($ch)) { print "

ERROR: " . curl_error($ch) . "

\n"; } curl_close ($ch); if (!is_string($string) || !strlen($string)) { // Something went wrong with the curl_exec and it returned false. return ''; } else { return $string; } } } /** * Class describing a single post to Twitter. * * This is not complete - it only describes the data we need to display. * * @author Phil Gyford (phil@gyford.com) */ class TwitterPost { /** * The time the post was created at, in a format like 'Fri Dec 01 23:25:35 +0000 2006' * @var string */ var $created_at = ''; /** * The content of the post. * @var string */ var $text = ''; /** * The name of the post's author. * @var string */ var $name = ''; /** * The screen name of the post's author. * @var string */ var $screen_name = ''; /** * Display the post. * @access public * @param boolean $print Print the results or return them? * @return mixed True or the string if we're returning it. */ function display($print=true) { $string = "

screen_name . "\">".$this->name.": " . $this->_truncateLinks($this->text) . ' ' . $this->_relativeTime($this->created_at) ."

\n"; if ($print) { print $string; return true; } else { return $string; } } /** * Returns a relative date, eg "4 hrs ago". * * Assumes the passed-in can be parsed by strtotime. * Precision could be one of: * 1 5 hours, 3 minutes, 2 seconds ago (not yet implemented). * 2 5 hours, 3 minutes * 3 5 hours * * This is all a little overkill, but copied from other places I've used it. * Also superfluous, now I've noticed that the Twitter API includes something * similar, but this version is more accurate and less verbose. * * @access private * @param string date In a format parseable by strtotime(). * @param integer precision * @return string */ function _relativeTime ($date, $precision=2) { $time = strtotime($date); $now = gmmktime(); $diff = $now - $time; $months = floor($diff/2419200); $diff -= $months * 2419200; $weeks = floor($diff/604800); $diff -= $weeks*604800; $days = floor($diff/86400); $diff -= $days * 86400; $hours = floor($diff/3600); $diff -= $hours * 3600; $minutes = floor($diff/60); $diff -= $minutes * 60; $seconds = $diff; if ($days > 0) { // Over a day old, just show the actual date. // Probably won't happen as the feeds only have 24 hours of posts. return date('j M Y', $time); } else { $relative_date = ''; if ($weeks > 0) { // Weeks and days $relative_date .= ($relative_date?', ':'').$weeks.' week'.($weeks>1?'s':''); if ($precision <= 2) { $relative_date .= $days>0?($relative_date?', ':'').$days.' day'.($days>1?'s':''):''; if ($precision == 1) { $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hr'.($hours>1?'s':''):''; } } } elseif ($days > 0) { // days and hours $relative_date .= ($relative_date?', ':'').$days.' day'.($days>1?'s':''); if ($precision <= 2) { $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hr'.($hours>1?'s':''):''; if ($precision == 1) { $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':''):''; } } } elseif ($hours > 0) { // hours and minutes $relative_date .= ($relative_date?', ':'').$hours.' hr'.($hours>1?'s':''); if ($precision <= 2) { $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':''):''; if ($precision == 1) { $relative_date .= $seconds>0?($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':''):''; } } } elseif ($minutes > 0) { // minutes only $relative_date .= ($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':''); if ($precision == 1) { $relative_date .= $seconds>0?($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':''):''; } } else { // seconds only $relative_date .= ($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':''); } } // Return relative date and add proper verbiage return $relative_date.' ago'; } /** * Truncates any long links and makes them clickable. * @access private * @param string $text * @param boolean $make_link_live Whether to make the links clickable. * @return string The same text with short, possibly clickable links. */ function _truncateLinks($text, $make_link_live=true) { $link_length = 25; if ($make_link_live) { $replace = '(strlen(\'$0\')>$link_length) ? "".substr("$0",0,$link_length)."..." : "$0"'; } else { $replace = '(strlen(\'$0\')>$link_length) ? substr("$0",0,$link_length)."..." : "$0"'; } $text = preg_replace( "/((http(s?):\/\/))([a-zA-Z\d\_\.\+\,\;\?\%\~\-\/\#\='\*\$\!\(\)\&]+)([a-zA-Z\d\_\?\%\~\-\/\#\='\*\$\!\(\)\&])/e", $replace, $text); return $text; } } /** * A class for parsing a Twitter XML feed and creating an array of TwitterPost objects. * * @author Phil Gyford (phil@gyford.com) */ class TwitterParser { /** * Holds a TwitterPost object when we're cycling through the XML. * @var object */ var $current_post; /** * Keeps track of which element in the XML we're currently within. * @var string */ var $current_tag; /** * Where we store an array of TwitterPosts gathered from the feed. * @var array */ var $posts = array(); /** * Pass in some XML data, as a string, and it returns an array of TwitterPost objects. * @access public * @param string $xml_data A Twitter XML feed's contents. * @return An array of TwitterPost objects. */ function parse ($xml_data) { $this->xml_parser = xml_parser_create(); xml_set_object($this->xml_parser, $this); xml_set_element_handler($this->xml_parser, '_tagOpen', '_tagClose'); xml_set_character_data_handler($this->xml_parser, '_characterData'); xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false); // Start going through the data, calling the methods specified above for each bit. xml_parse($this->xml_parser, $xml_data); xml_parser_free($this->xml_parser); return $this->posts; } /** * When we reach a new XML tag, what do we do? * @access private * @param object $parser An xml_parser object. * @param string $tag A tag name. * @param array $attributes */ function _tagOpen($parser, $tag, $attributes) { if ($tag == 'status') { // Starting a new post. $this->current_post = new TwitterPost; } elseif (!empty($this->current_post)) { // Inside a 'status' element, so record the tag's name. $this->current_tag = $tag; } } /** * When we reach a closing XML tag, what do we do? * @access private * @param object $parser An xml_parser object. * @param string $tag A tag name */ function _tagClose($parser, $tag) { if ($tag == 'status') { // Finished a post, add this one to our store. $this->posts[] = $this->current_post; // Re-set our post object ready for a new one. unset($this->current_post); } } /** * What do we do with the contents of a tag? * @access private * @param object $parser An xml_parser object. * @param string $cdata The contents of the tag. */ function _characterdata($parser, $cdata) { if (!empty($this->current_post)) { // Inside a 'status' element. if (isset($this->current_post->{$this->current_tag})) { // This is a property of the TwitterPost class, so save the data. $this->current_post->{$this->current_tag} .= trim($cdata); } } } } // Below here is the HTML of the page... ?> Your Recent Twitters 0) { $result = $twitter->post(trim($_POST['status'])); if ($result) { print "

Update posted.

\n"; } else { print "

Looks like the update didn't post.

\n"; $status = $_POST['status']; } } ?>


Characters left: 140

display(); ?>