Location: PHPKode > scripts > xTwitter > xTwitter.php
<?php
/**
* The probably most complete twitter API written in PHP
*
* @version 1.0
* @author Robert Eisele <hide@address.com>
* @copyright Copyright (c) 2010, Robert Eisele
* @link http://www.xarg.org/2010/02/php-twitter-api/
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/

class xTwitter {

	/**
	 * Current version of xTwitter.
	 *
	 */
	const CLIENT_VERSION = '1.0.0';


	/**
	 * Our project name.
	 *
	 */
	const CLIENT_NAME = 'PHP xTwitter';


	/**
	 * The twitter API client description file.
	 *
	 */
	const CLIENT_META = 'http://www.xarg.org/projects/xTwitter.xml';


	/**
	 * A back reference to the description.
	 *
	 */
	const CLIENT_URL = 'http://www.xarg.org/2010/02/php-twitter-api/';


	/**
	 * Socket connect timeout in seconds.
	 *
	 */
	const CLIENT_TIMEOUT = 3;


	/**
	 * Maximum number of items twitter make accessable via the API.
	 *
	 */
	const PAGINATION_LIMIT = 3200;


	/**
	 * The famous 140 as maximum length of every new status.
	 *
	 */
	const MAX_LENGTH = 140;


	/**
	 * twitter allows the access using user id's or usernames or both (which is not implemented because it's buggy).
	 * Every parameter which indicates the username ($name) can be turned to the user-id by using this flag.
	 *
	 */
	const USER_IS_ID = false;


	/**
	 * The URL prefix for general API calls.
	 *
	 */
	const TWITTER_API_URL = 'http://twitter.com/';


	/**
	 * The URL prefix for search API calls.
	 *
	 */
	const TWITTER_SEARCH_URL = 'http://search.twitter.com/';


	/**
	 * The credentials cache for a running session, as we do not use HTTP Cookies.
	 *
	 * @var string
	 */
	private $credentials = null;


	/**
	 * Return type of every API call. By default an object made by json_decode() will returned.
	 *
	 * @var string
	 */
	private $type = 'object';

	/**
	 * The last HTTP status code, as twitter sometimes make use of this.
	 *
	 * @var int
	 */
	private $last_http_status = null;





	/**
	 * constructor to optionally pass credentials
	 *
	 * @param string $user username for authentication process
	 * @param string $pass password for authentication process
	 */
	public function __construct($user=null, $pass=null) {

		if($pass !== null && $user !== $pass) {
			$this->setAuth($user, $pass);
		}
	}


	/**
	 * Defines the credentials to access private places on twitter
	 *
	 * @param string $user username for authentication process
	 * @param string $pass password for authentication process
	 */
	public function setAuth($user, $pass) {
		$this->credentials = $user.':'.$pass;
	}


	/**
	 * Defines the output type of the result. Every method has several types like XML, JSON and so on.
	 * It's also possible to pass "object" (which is default) to get a json_decoded() object.
	 *
	 * @param string $type return type. What types are possible depends on the API method. Consult the manual.
	 */
	public function setType($type) {
		$this->type = $type;
	}


	/**
	 * Enter description here...
	 *
	 * @param unknown_type $url
	 * @param unknown_type $api_key
	 * @param unknown_type $callback
	 * @return unknown
	 */
	public function getShortUrl($url, $api_key=null, $callback=null) {

		if($api_key === null) {
			return $this->_request('http://api.tr.im/v1/trim_simple?url='.urlencode($url));
		} else if($callback === null) {
			return $this->_request('http://api.tr.im/api/trim_url.json?url='.urlencode($url));
		}
		return $this->_request('http://tr.im/api/trim_url.json?api_key='.$api_key.'&url='.urlencode($url).'&callback='.$callback);
	}

	### Search API Methods


	/**
	 * Returns tweets that match a specified query.
	 *
	 * @param string $query the search query
	 * @param int $per_page number of items per page
	 * @param int $page page number, starting with 1
	 * @param string $lang the ISO language code
	 * @return the API result or null if there was an error
	 */
	public function search($query, $per_page=20, $page=1, $lang='en') {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT / 2) {
			return null;
		}
		return $this->_search('search', 'json,atom', array('rpp' => (int)$per_page, 'page' => (int)$page, 'lang' => $lang, 'q' => $query));
	}


	/**
	 * Returns the top ten topics that are currently trending on Twitter.
	 *
	 * @return the API result
	 */
	public function getTrends() {
		return $this->_search('trends', 'json', array());
	}


	/**
	 * Returns the current top 10 trending topics on Twitter.
	 *
	 * @param string $exclude exclude something from the result
	 * @return the API result
	 */
	public function getCurrentTrends($exclude=null) {
		return $this->_search('trends/current', 'json', array('exclude' => $exclude));
	}


	/**
	 * Returns the top 20 trending topics for each hour in a given day.
	 *
	 * @param int/string $date get trends by unix_timestamp (int) or by string in format YYYY-MM-DD
	 * @param string $exclude exclude something from the result
	 * @return the API result
	 */
	public function getDailyTrends($date=0, $exclude=null) {

		if($date === 0) {
			$date = null;
		} else if(gettype($date) === 'integer') {
			$date = date('Y-m-d', $date);
		}
		return $this->_search('trends/daily', 'json', array('exclude' => $exclude, 'date' => $date));
	}


	/**
	 * Returns the top 30 trending topics for each day in a given week.
	 *
	 * @param int/string $date get trends by unix_timestamp (int) or by string in format YYYY-MM-DD
	 * @param string $exclude exclude something from the result
	 * @return the API result
	 */
	public function getWeeklyTrends($date=0, $exclude=null) {

		if($date === 0) {
			$date = null;
		} else if(gettype($date) === 'integer') {
			$date = date('Y-m-d', $date);
		}
		return $this->_search('trends/weekly', 'json', array('exclude' => $exclude, 'date' => $date));
	}


	# Timeline Methods


	/**
	 * Returns the 20 most recent statuses from non-protected users who have set a custom user icon.
	 *
	 * @return the API result
	 */
	public function getPublicTimeline() {
		return $this->_call('get', 'statuses/public_timeline', 'xml,json,rss,atom', array(), false);
	}


	/**
	 * Returns the 20 most recent statuses posted by the authenticating user and that user's friends.
	 *
	 * @param int $per_page numbers of results per page
	 * @param int $page the desired page
	 * @return the API result or null if there was an error
	 */
	public function getFriendTimeline($per_page=20, $page=1) {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT) {
			return null;
		}
		return $this->_call('get', 'statuses/friends_timeline', 'xml,json,rss,atom', array('page' => (int)$page, 'count' => (int)$per_page), true);
	}


	/**
	 * Returns the 20 most recent statuses posted from the authenticating user.
	 *
	 * @param string $name get the user of a certain user
	 * @param int $per_page numbers of results per page
	 * @param int $page the desired page
	 * @return the API result or null if there was an error
	 */
	public function getUserTimeline($name=null, $per_page=20, $page=1) {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT) {
			return null;
		}
		return $this->_call('get', 'statuses/user_timeline', 'xml,json,rss,atom', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name, 'page' => (int)$page, 'count' => (int)$per_page), !empty($user));
	}


	/**
	 * Returns the 20 most recent mentions (status containing @username) for the authenticating user.
	 *
	 * @param int $per_page numbers of results per page
	 * @param int $page the desired page
	 * @return the API result or null if there was an error
	 */
	public function getMentions($per_page=20, $page=1) {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT) {
			return null;
		}
		return $this->_call('get', 'statuses/mentions', 'xml,json,rss,atom', array('page' => (int)$page, 'count' => (int)$per_page), true);
	}


	/**
	 * Returns replies to the authenticated user.
	 *
	 * @param int $page the desired page
	 * @param int $since the date of since when we need replies
	 * @param int $since_id the id of since when we need replies
	 * @return the API result
	 */
	public function getReplies($page=null, $since=null, $since_id=null) {
		return $this->_call('get', 'statuses/replies', 'xml,json,rss,atom', array('page' => (int)$page, 'since' => (int)$since, 'since_id' => (int)$since_id), true);
	}


	/**
	 * Returns a single status, specified by the id parameter.
	 *
	 * @param id $id status id
	 * @return the API result
	 */
	public function showStatus($id) {
		return $this->_call('get', 'statuses/show', 'xml,json', array('id' => (int)$id), false);
	}


	/**
	 * Updates the authenticating user's status. Probably the most important method.
	 *
	 * @param string $status the status text
	 * @param int $replying_to new status is in reply to another id
	 * @param float $lat the latitude of the current location
	 * @param unknown_type $lon the longitude of the current location
	 * @return the API result or null if there was an error
	 */
	public function updateStatus($status, $replying_to=null, $lat=null, $lon=null) {

		$status = preg_replace_callback('|(http://[^\s]+)|', array(&$this, '_short_url_cb'), $status);

		if(strlen($status) > xTwitter::MAX_LENGTH) {
			return null;
		}
		return $this->updateSimple($status, $replying_to, $lat, $lon);
	}


	/**
	 * Update the authenticating user's status without any modification and check
	 *
	 * @param string $status the status text
	 * @param int $replying_to new status is in reply to another id
	 * @param float $lat the latitude of the current location
	 * @param unknown_type $lon the longitude of the current location
	 * @return the API result
	 */
	public function updateSimple($status, $replying_to=null, $lat=null, $lon=null) {
		return $this->_call('post', 'statuses/update', 'xml,json', array('status' => $status, 'in_reply_to_status_id' => $replying_to, 'lat' => $lat, 'long' => $lon), true);
	}


	/**
	 * Destroys the status specified by the required ID parameter.
	 *
	 * @param int $id the status id
	 * @return the API result
	 */
	public function deleteStatus($id) {
		return $this->_call('post', 'statuses/destroy', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 * Returns extended information of a given user, specified by screen name.
	 *
	 * @param string $name the name of the user
	 * @return the API result
	 */
	public function showUser($name) {
		return $this->_call('get', 'users/show', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), false);
	}


	/**
	 * Returns a user's friends, each with current status inline.
	 *
	 * @param string $name the name of the user
	 * @return the API result
	 */
	public function getFriendStatus($name) {
		return $this->_call('get', 'statuses/friends', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), false);
	}


	/**
	 * Returns the authenticating user's followers, each with current status inline.
	 *
	 * @param string $name the name of the user
	 * @return the API result
	 */
	public function getFollowerStatus($name) {
		return $this->_call('get', 'statuses/followers', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), false);
	}


	/**
	 * Returns a list of the 20 most recent direct messages sent to the authenticating user.
	 *
	 * @param int $per_page number of results per page
	 * @param int $page the desired page
	 * @return the API result or null if there was an error
	 */
	public function getDirectMessages($per_page=20, $page=1) {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT) {
			return null;
		}
		return $this->_call('get', 'direct_messages', 'xml,json', array('count' => (int)$per_page, 'page' => (int)$page), true);
	}


	/**
	 * Returns a list of the 20 most recent direct messages sent by the authenticating user.
	 *
	 * @param int $per_page number of results per page
	 * @param int $page the desired page
	 * @return the API result or null if there was an error
	 */
	public function getSentDirectMessages($per_page=20, $page=1) {

		if($page < 1 || $per_page * $page > xTwitter::PAGINATION_LIMIT) {
			return null;
		}
		return $this->_call('get', 'direct_messages/sent', 'xml,json', array('count' => (int)$per_page, 'page' => (int)$page), true);
	}


	/**
	 * Sends a new direct message to the specified user from the authenticating user.
	 *
	 * @param string $name the recipient name
	 * @param string $text the text to send
	 * @return the API result
	 */
	public function sendDirectMessage($name, $text) {
		return $this->_call('post', 'direct_messages/new', 'xml,json', array('text' => $text, self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Destroys the direct message specified in the required ID parameter.
	 *
	 * @param int $id id of the DM
	 * @return the API result
	 */
	public function deleteDirectMessage($id) {
		return $this->_call('post', 'direct_messages/destroy', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 * Allows the authenticating users to follow the user specified in the ID parameter.
	 *
	 * @param string $name the name of the user to be a friend
	 * @return the API result
	 */
	public function createFriendship($name) {
		return $this->_call('post', 'friendships/create', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Allows the authenticating users to unfollow the user specified in the ID parameter.
	 *
	 * @param string $name the name of the friend we want to delete
	 * @return the API result
	 */
	public function deleteFriendship($id, $name) {
		return $this->_call('post', 'friendships/destroy', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Tests for the existence of friendship between two users.
	 * Use getFriends() for more details and an USER_IS_ID implementation instead!
	 *
	 * @param string $user_a name of one user
	 * @param string $user_b name of the other user
	 * @return the API result
	 */
	public function isFriendship($user_a, $user_b) {
		return $this->_call('get', 'friendships/exists', 'xml,json', array('user_a' => $user_a, 'user_b' => $user_b), false);
	}


	/**
	 * Returns detailed information about the relationship between two users.
	 *
	 * @param string $user_a name of one user
	 * @param string $user_b name of the other user
	 * @return the API result
	 */
	public function getFriendshipDetails($user_a, $user_b) {
		return $this->_call('get', 'friendships/show', 'xml,json', array(
		self::USER_IS_ID ? 'source_id' : 'source_screen_name' => $user_a,
		self::USER_IS_ID ? 'target_id' : 'target_screen_name' => $user_b
		), false);
	}


	/**
	 * Returns an array of numeric IDs for every user the specified user is following.
	 *
	 * @param string $name name of the user we want to view the friends
	 * @return the API result
	 */
	public function getFriends($name) {
		return $this->_call('get', 'friends/ids', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), false);
	}


	/**
	 * Returns an array of numeric IDs for every user following the specified user.
	 *
 	 * @param string $name name of the user we want to view the followers
	 * @return the API result
	 */
	public function getFollowers($name) {
		return $this->_call('get', 'followers/ids', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), false);
	}


	/**
	 * Verifies the user credentials
	 *
	 * @return the API result
	 */
	public function verifyCredentials() {
		$ret = $this->_call('get', 'account/verify_credentials', 'xml,json', array(), true);

		if($this->last_http_status === 401) {
			return false;
		}
		return $ret;
	}


	/**
	 * Returns the remaining number of API requests available to the requesting user before the API limit is reached for the current hour.
	 *
	 * @param bool $ip_limit show the ip rate or the rate of the authenticated user (default)
	 * @return the API result
	 */
	public function getRateStatus($ip_limit=false) {
		return $this->_call('get', 'account/rate_limit_status', 'xml,json', array(), !$ip_limit);
	}


	/**
	 * Sets which device Twitter delivers updates to for the authenticating user.
	 *
	 * @param enum $device one of "im", "sms", "none"
	 * @return the API result or null if there was an error
	 */
	public function updateDeliveryDevice($device) {

		if(!in_array($device, array('im', 'sms', 'none'))) {
			return null;
		}
		return $this->_call('post', 'account/update_delivery_device', 'xml,json', array('device' => $device), true);
	}


	/**
	 * Sets one or more color values that control the color scheme of the authenticating user's profile page on twitter.com.
	 *
	 * @param mixed $background color of the background
	 * @param mixed $text color of the text
	 * @param mixed $link color of the link text
	 * @param mixed $sidebar color of the sidebar
	 * @param mixed $sidebar_border color of the sidebar border
	 * @return the API result or null if no colors are set or readable
	 */
	public function updateColors($background=null, $text=null, $link=null, $sidebar=null, $sidebar_border=null) {

		$sum = $this->_parse_color($background);
		$sum+= $this->_parse_color($text);
		$sum+= $this->_parse_color($link);
		$sum+= $this->_parse_color($sidebar);
		$sum+= $this->_parse_color($sidebar_border);

		if($sum === 0) {
			return null;
		}

		return $this->_call('post', 'account/update_profile_colors', 'xml,json', array(
		'profile_background_color' => $background,
		'profile_text_color' => $text,
		'profile_link_color' => $link,
		'profile_sidebar_fill_color' => $sidebar,
		'profile_sidebar_border_color' => $sidebar_border), true);
	}


	/**
	 * Updates the authenticating user's profile image.
	 *
	 * @param string $image file name
	 * @return the API result or null if there was an error
	 */
	public function updateAvatar($image) {

		if(false === ($stat = stat($image)) || $stat['size'] >= 716800) {
			return null;
		}
		return $this->_call('post', 'account/update_profile_image', 'xml,json', array('image' => '@'.$image), true);
	}


	/**
	 * Updates the authenticating user's profile background image.
	 *
	 * @param string $file file name
	 * @param bool $tile should the background tile?
	 * @return the API result or null if there was an error
	 */
	public function updateBackground($file, $tile=null) {

		if(false === ($stat = stat($file)) || $stat['size'] >= 819200) {
			return null;
		}
		return $this->_call('post', 'account/update_profile_background_image', 'xml,json', array('image' => '@'.$file, 'tile' => $tile), true);
	}


	/**
	 * Sets values that users are able to set under the "Account" tab of their settings page.
	 *
	 * @param string $name the full name
	 * @param string $url the url of the users blog/site
	 * @param string $loc the location as plain text (no geo coding is involved)
	 * @param string $descr a short description of the user
	 * @return the API result
	 */
	public function updateProfile($name=null, $url=null, $loc=null, $descr=null) {

		if($name !== null) {
			$name = substr($name, 0, 20);
		}

		if($url !== null && strlen($url) > 100) {
			$url = null;
		}

		if($loc !== null) {
			$loc = substr($loc, 0, 20);
		}

		if($descr !== null) {
			$descr = substr($descr, 0, 160);
		}

		return $this->_call('post', 'account/update_profile', 'xml,json', array(
		'name' => $name,
		'url' => $url,
		'location' => $loc,
		'description' => $descr), true);
	}


	/**
	 *Returns the 20 most recent favorite statuses for the authenticating user or user specified by the ID parameter in the requested format.
	 *
	 * @param string $id username or user id
	 * @param int $page the desired page
	 * @return the API result
	 */
	public function getFavorites($id=null, $page=1) {
		return $this->_call('get', 'favorites', 'xml,json,rss,atom', array('id' => $id, 'page' => (int)$page), true);
	}


	/**
	 * Favorites the status specified in the ID parameter as the authenticating user.
	 *
	 * @param int $id status id
	 * @return the API result
	 */
	public function createFavorite($id) {
		return $this->_call('post', 'favorites/create', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 * Un-favorites the status specified in the ID parameter as the authenticating user.
	 *
	 * @param int $id the status id
	 * @return the API result
	 */
	public function deleteFavorite($id) {
		return $this->_call('post', 'favorites/destroy', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 * Enables device notifications for updates from the specified user.
	 *
	 * @param string $name the username
	 * @return the API result
	 */
	public function followNotify($name) {
		return $this->_call('post', 'notifications/follow', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Disables notifications for updates from the specified user to the authenticating user.
	 *
	 * @param string $name the username
	 * @return the API result
	 */
	public function leaveNotify($name) {
		return $this->_call('post', 'notifications/leave', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Blocks the specified user as the authenticating user.
	 *
	 * @param string $name the username
	 * @return the API result
	 */
	public function createBlock($name) {
		return $this->_call('post', 'blocks/create', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Un-blocks the user specified in the ID parameter for the authenticating user.
	 *
	 * @param string $name the username
	 * @return the API result
	 */
	public function deleteBlock($name) {
		return $this->_call('post', 'blocks/destroy', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Returns if the authenticating user is blocking a target user.
	 *
	* @param string $name the username
	 * @return the API result
	 */
	public function isBlocked($name) {
		return $this->_call('get', 'blocks/exists', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Returns an array of user objects that the authenticating user is blocking.
	 *
	 * @param int $page the desired page of block listing
	 * @return the API result
	 */
	public function getBlocking($page=1) {
		return $this->_call('get', 'blocks/blocking', 'xml,json', array('page' => $page), true);
	}


	/**
	 * Returns an array of numeric user ids the authenticating user is blocking.
	 *
	 * @return the API result
	 */
	public function getBlockingIds() {
		return $this->_call('get', 'blocks/blocking/ids', 'xml,json', array(), true);
	}


	/**
	 * The specified user is blocked by the authenticated user and reported as a spammer.
	 *
	 * @param string $name the username
	 * @return the API result
	 */
	public function reportSpam($name) {
		return $this->_call('post', 'report_spame', 'xml,json', array(self::USER_IS_ID ? 'user_id' : 'screen_name' => $name), true);
	}


	/**
	 * Returns the authenticated user's saved search queries.
	 *
	 * @return the API result
	 */
	public function getSavedSearches() {
		return $this->_call('get', 'saved_searches', 'xml,json', array(), true);
	}


	/**
	 * Retrieve the data for a saved search owned by the authenticating user specified by the given id.
	 *
	 * @param int $id id of the saved search item
	 * @return the API result
	 */
	public function showSavedSearch($id) {
		return $this->_call('get', 'saved_searches/show', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 * Creates a saved search for the authenticated user.
	 *
	 * @param string $query
	 * @return the API result
	 */
	public function createSavedSearch($query) {
		return $this->_call('post', 'saved_searches/create', 'xml,json', array('query' => $query), true);
	}


	/**
	 * Destroys a saved search for the authenticated user.
	 *
	 * @param int $id id of the saved search item
	 * @return the API result
	 */
	public function deleteSavedSearch($id) {
		return $this->_call('post', 'saved_searches/destroy', 'xml,json', array('id' => (int)$id), true);
	}


	/**
	 *Returns the string "ok" in the requested format.
	 *
	 * @return the API result
	 */
	public function test() {
		return $this->_call('get', 'help/test', 'xml,json', array(), false);
	}

	protected function _call($method, $url, $types, $param, $auth=true) {

		$param = array_filter($param);

		if($this->type === 'object') {
			$type = 'json';
		} else {
			$type = $this->type;
		}

		if(false === strpos($types, $type)) {
			return null;
		}

		$url = self::TWITTER_API_URL.$url.'.'.$type;

		if($method === 'post') {
			if(empty($param)) {
				return null;
			}
			$ret = $this->_request($url, $param, $auth);
		} else {
			$ret = $this->_request($url.'?'.http_build_query($param), null, $auth);
		}

		if($this->type === 'object') {
			return json_decode($ret);

		}
		return $ret;
	}

	protected function _search($url, $types, $param) {

		$param = http_build_query(array_filter($param));

		if($this->type === 'object') {
			$type = 'json';
		} else {
			$type = $this->type;
		}

		if(false === strpos($types, $type)) {
			return null;
		}

		$ret = $this->_request(self::TWITTER_SEARCH_URL.$url.'.'.$type.'?'.$param);

		if($this->type === 'object') {
			return json_decode($ret);
		}
		return $ret;
	}

	private function _short_url_cb($arr) {

		if(strlen($arr[1]) > 18 /*strlen('http://tr.im/aaaaa')*/) {
			return $this->getShortUrl($arr[1]);
		}
		return $arr[1];
	}

	private function _parse_color(&$col) {

		switch(gettype($col)) {
			case 'NULL':
				return 0;

			case 'string':
				$col = trim($col, '#');

				switch(strlen($col)) {
					case 3:
						$a = str_split($col);
						$a[0].= $a[0];
						$a[1].= $a[1];
						$a[2].= $a[2];
						$col = array(hexdec($a[0]), hexdec($a[1]), hexdec($a[2]));
						break 2;

					case 6:
						$a = str_split($col, 2);
						$col = array(hexdec($a[0]), hexdec($a[1]), hexdec($a[2]));
						break 2;

					default:
						$col = null;
						return 0;
				}

			case 'integer':
				$col = array(($col >> 16) & 0xff, ($col >> 8) & 0xff, $col & 0xff);
				break;

			case 'object':
				$col = (array)$col;

			case 'array':
				switch(true) {
					case isset($col[0], $col[1], $col[2]):
						$col = array((int)$col[0], (int)$col[1], (int)$col[2]);
						break 2;

					case isset($col['r'], $col['g'], $col['b']):
						$col = array((int)$col['r'], (int)$col['g'], (int)$col['b']);
						break 2;

					default:
						$col = null;
						return 0;
				}
		}
		$col = sprintf('%02x%02x%02x', $col[0], $col[1], $col[2]);

		return 1;
	}

	private function _request($host, $data=null, $auth=false) {

		$ch = curl_init();
		curl_setopt($ch	, CURLOPT_URL, $host);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::CLIENT_TIMEOUT);
		curl_setopt($ch, CURLOPT_USERAGENT, self::CLIENT_NAME.'/'.self::CLIENT_VERSION.' +'.self::CLIENT_URL);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
		"Expect:", // fucking bug in lighttpd
		'X-Twitter-Client: '.self::CLIENT_NAME,
		'X-Twitter-Client-URL: '.self::CLIENT_META,
		'X-Twitter-Client-Version: '.self::CLIENT_VERSION
		));

		if($data !== null) { // POST
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
		}

		if($auth && $auth !== empty($this->credentials)) {
			curl_setopt($ch, CURLOPT_USERPWD, $this->credentials);
		}

		$data = curl_exec($ch);
		$info = curl_getinfo($ch);
		$this->last_http_status = $info['http_code'];

		curl_close($ch);
		return $data;
	}
}

?>
Return current item: xTwitter