Twitter Datasource

By Alex Ciobanu (iscandr)
Datasource for Twitter API
Basic usage tutorial:
http://bakery.cakephp.org/articles/view/building-your-first-twitter-mash-up

To get the latest version please use: http://github.com/ics/twitter_datasource


Install instructions :

- Place twitter_source.php in your app/models/datasources folder
- Add the credidentials to database.php:
Download code
var $twitter = array(
        'datasource' => 'twitter',
        'username' => 'ics',
        'password' => 'uncrackable',
    );

Calling it in your controller:

Download code
<?php
class TweetsController extends AppController {
    function 
index(){
        
$this->Twitter ConnectionManager::getDataSource('twitter');
        
$response $this->Twitter->account_verify_credentials();
        
$search_results $this->Twitter->search('cakephp');
        
debug($response);
        
debug($search_results);    
    }
}
?>

twitter_source.php:
Download code
<?php
/**
 * Twitter Datasource 0.2
 *
 * Twitter datasource to communicate with the Twitter API.
 *
 * References(Credits):
 * http://bakery.cakephp.org/articles/view/paypal-datasource
 * http://bakery.cakephp.org/articles/view/twitter-component
 * http://debuggable.com/posts/new-google-analytics-api:480f4dd6-c59c-445f-8ce0-4202cbdd56cb
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 *
 * @author Alexandru Ciobanu <ics@4algorithms.com>
 * @copyright (c) 2009 Alexandru Ciobanu
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link http://bakery.cakephp.org/articles/view/twitter-datasource
 * @created May 4, 2009
 * @version 0.2 *
 */
App::import('Core', array('Xml''HttpSocket'));

class 
TwitterSource extends DataSource
{
    var 
$username "";
    var 
$password "";
    var 
$description "Twitter API";
    var 
$Http null;

    function 
__construct($config) {
        
parent::__construct($config);
        
$this->Http =& new HttpSocket();
        
$this->username $this->config['username'];
        
$this->password $this->config['password'];
    }


    
/**
     * Returns a single status, specified by the id parameter below.
     * The status's author will be returned inline.
     *
     * @param string id Required. The numerical ID or username of the status you're trying to retrieve.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_show($id) {
        
$url "http://twitter.com/statuses/show/{$id}.xml";
        return 
$this->__process($this->Http->get($url));
    }

    function 
user_show($id=false$params = array()) {
        
$url "http://twitter.com/users/show";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Returns the 20 most recent statuses from non-protected users
     * who have set a custom user icon.  Does not require authentication.
     *
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_public_timeline($params=array()) {
        
$url 'http://twitter.com/statuses/public_timeline.xml';
        return 
$this->__process($this->Http->get($url$params));
    }

    
/**
     * Returns the 20 most recent statuses posted in the last 24 hours from the authenticating
     * user and that user's friends.  It's also possible to request another user's
     * friends_timeline via the id parameter below.
     *
     * @param string id Optional. Specifies the ID or screen name of the user for whom to return the friends_timeline
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_friends_timeline($id=false$params = array()) {
        
$url 'http://twitter.com/statuses/friends_timeline';
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params));
    }

    
/**
     * Returns the 20 most recent statuses posted in the last 24 hours from the authenticating user.
     * It's also possible to request another user's timeline via the id parameter below.
     *
     * @param string id Optional. Specifies the ID or screen name of the user for whom to return the friends_timeline.
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_user_timeline($id=false$params = array()) {
        
$url 'http://twitter.com/statuses/user_timeline';
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }

        return 
$this->__process($this->Http->get($url$params));
    }

    
/**
     * Updates the authenticating user's status.  Requires the status parameter specified below.
     *
     * @param string status Required.  The text of your status update.
     *              Be sure to URL encode as necessary.  Must not be more than 160 characters
     *              and should not be more than 140 characters to ensure optimal display.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_update($status) {
        
$url "http://twitter.com/statuses/update.xml";
        return 
$this->__process($this->Http->post($url, array('status' => $status), $this->__getAuthHeader()));
    }

    
/**
     * Returns the 20 most recent replies
     * (status updates prefixed with @username posted by users who
     * are friends with the user being replied to)
     * to the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_replies($params = array()) {
        
$url "http://twitter.com/statuses/replies.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Destroys the status specified by the required ID parameter.
     *
     * @param string id Required.  The ID of the status to destroy.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_destroy($id) {
        
$url "http://twitter.com/statuses/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Returns up to 100 of the authenticating user's friends who have most recently updated, each with current status inline.
     * It's also possible to request another user's recent friends list via the id parameter below.
     *
     * @param string id Optional.  The ID or screen name of the user for whom to request a list of friends.
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_friends($id=false$params = array()) {
        
$url "http://twitter.com/statuses/friends";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Returns the authenticating user's followers, each with current status inline.
     *
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_followers($params = array()) {
        
$url "http://twitter.com/statuses/followers.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Returns a list of the users currently featured on the site with their current statuses inline.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_featured() {
        
$url "http://twitter.com/statuses/featured.xml";
        return 
$this->__process($this->Http->get($url));
    }

    
/**
     * Returns a list of the 20 most recent direct messages sent to the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages($params = array()) {
        
$url "http://twitter.com/direct_messages.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Returns a list of the 20 most recent direct messages sent by the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_sent($params = array()) {
        
$url "http://twitter.com/direct_messages/sent.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Sends a new direct message to the specified user from the authenticating user.
     *
     * @param string user Required.  The ID or screen name of the recipient user.
     * @param string text Required.  The text of your direct message.
     *              Be sure to URL encode as necessary, and keep it under 140 characters.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_new($user$text) {
        
$url "http://twitter.com/direct_messages/new.xml";
        
$params = array('user' => $user'text' => $text);
        return 
$this->__process($this->Http->post($url$params$this->__getAuthHeader()));
    }

    
/**
     * Destroys the direct message specified in the required ID parameter.
     *
     * @param string id Required.  The ID of the direct message to destroy.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_destroy($id) {
        
$url "http://twitter.com/direct_messages/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Befriends the user specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to befriend.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function friendship_create($id) {
        
$url "http://twitter.com/friendships/create/{$id}.xml";
        return 
$this->__process($this->Http->post($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Discontinues friendship with the user specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user with whom to discontinue friendship.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function friendship_destroy($id) {
        
$url "http://twitter.com/friendships/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Returns an HTTP 200 OK response code and a format-specific response if authentication was successful.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_verify_credentials() {
        
$url "http://twitter.com/account/verify_credentials.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Ends the session of the authenticating user, returning a null cookie.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_end_session() {
        
$url "http://twitter.com/account/end_session";
        
$this->Http->get($urlnull$this->__getAuthHeader());
    }

    
/**
     * Returns 80 statuses per page for the authenticating user, ordered by descending date of posting.
     *
     * @param integer page Optional. Retrieves the 80 next most recent statuses.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_archive($page=1) {
        
$url 'http://twitter.com/statuses/user_timeline.xml';
        return 
$this->__process($this->Http->get($url, array('page' => $page), $this->__getAuthHeader()));
    }

    
/**
     * Updates the location attribute of the authenticating user,
     * as displayed on the side of their profile and returned in various API methods.
     *
     * @param string location The location of the user.  Please note this is not normalized, geocoded, or translated to latitude/longitude at this time.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_update_location($location) {
        
$url 'http://twitter.com/account/update_location.xml';
        return 
$this->__process($this->Http->get($url, array('location' => $location), $this->__getAuthHeader()));
    }

    
/**
     * Sets which device Twitter delivers updates to for the authenticating user.
     * Sending none as the device parameter will disable IM or SMS updates.
     *
     * @param string device  Must be one of: sms, im, none.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_update_delivery_device($device) {
        
$url 'http://twitter.com/account/update_delivery_device.xml';
        return 
$this->__process($this->Http->get($url, array('device' => $device), $this->__getAuthHeader()));
    }

    
/**
     * 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 Optional.  The ID or screen name of the user for whom to request a list of favorite statuses.
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites($id false$params = array()) {
        
$url "http://twitter.com/favorites";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }

    
/**
     * Favorites the status specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID of the status to favorite.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites_create($id) {
        
$url "http://twitter.com/favorites/create/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Un-favorites the status specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID of the status to un-favorite.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites_destroy($id) {
        
$url "http://twitter.com/favorites/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
    
/**
     * Search for keyword using the twitter search API
     *
     * @param string $keyword
     * @param string $language
     * @see http://search.twitter.com/api
     */
    
function search($keyword$language 'all'$rpp '10'){
        
$url "http://search.twitter.com/search.atom?q=$keyword&lang=$language&rpp=$rpp";
        return 
$this->__process($this->Http->get($url));
    }

    
/**
     * Enables notifications for updates from the specified user to the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to follow.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function notifications_follow($id) {
        
$url "http://twitter.com/notifications/follow/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Disables notifications for updates from the specified user to the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to leave.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function notifications_leave($id) {
        
$url "http://twitter.com/notifications/leave/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Blocks the user specified in the ID parameter as the authenticating user.
     * Returns the blocked user in the requested format when successful.
     *
     * @param string id The ID or screen_name of the user to block
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function block_create($id) {
        
$url "http://twitter.com/blocks/create/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Un-blocks the user specified in the ID parameter as the authenticating user.
     * Returns the un-blocked user in the requested format when successful.
     *
     * @param string id The ID or screen_name of the user to block
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function block_destroy($id) {
        
$url "http://twitter.com/blocks/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }

    
/**
     * Returns the string "ok" in the requested format with a 200 OK HTTP status code.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function help_test() {
        
$url 'http://twitter.com/help/test.xml';
        return 
$this->__process($this->Http->get($url));
    }

    
/**
     * Returns the same text displayed on http://twitter.com/home when
     * a maintenance window is scheduled, in the requested format.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function help_downtime_schedule() {
        
$url 'http://twitter.com/help/downtime_schedule.xml';
        return 
$this->__process($this->Http->get($url));
    }
    
/**
     * Credentials array for method with mandatory auth
     * @return array credentials
     */
    
function __getAuthHeader() {
        return array(
'auth' => array('method' => 'Basic',
                                     
'user' => $this->username,
                                     
'pass' => $this->password
        
)
        );
    }

    
/**
     *
     * @param string data to process
     * @return array Twitter API response
     */
    
function __process($response) {
        
$xml = new XML($response);
        
$array $xml->toArray();

        
$xml->__killParent();
        
$xml->__destruct();
        
$xml null;
        unset(
$xml);

        return 
$array;
    }
}
?>

 

Comments 961

CakePHP Team Comments Author Comments
 

Comment

1 Setup Question

Hi,

I'm fairly new to CakePHP and so started out by following your directions exactly.

1. I didn't have an app/models/datasources directory. I had to create the directory datasources under app/models.
2. The credential was put in the database.php file in app/config.
3. Putting the controller code in the file tweets_controller.php under app/controllers and visiting http://www.domain.com/tweets I got an error. I then defined $users, $helpers, $layouts and $components variables to the controller and now get the following error:

Fatal error: Class 'AppHelper' not found in /var/www/html/project/trunk/cake/libs/view/helpers/xml.php on line 37

Cake Version: 1.2.0.6311 beta

Thanks for feedback,

Shaun
Posted Mar 9, 2009 by Shaun Johnson
 

Comment

2 Setup Question

1. I didn't have an app/models/datasources directory. I had to create the directory datasources under app/models.
AFAIK cakephp skel provides this directory.
3. Putting the controller code in the file tweets_controller.php under app/controllers and visiting http://www.domain.com/tweets I got an error.
I then defined $users, $helpers, $layouts and $components variables to the controller and now get the following error:
Fatal error: Class 'AppHelper' not found in /var/www/html/project/trunk/cake/libs/view/helpers/xml.php on line 37
You're missing some classes not only directories.
I'm inclined to say that something went wrong with your cakephp install.
I suggest getting the latest cakephp.
Posted Mar 10, 2009 by Alex Ciobanu
 

Question

3 Missing Database Table Error?

I've followed the instructions closely but I'm now receiving the following error:

Error: Database table tweets for model Tweet was not found.

Do I need to point my Tweet model at the tweet datasource?

Thanks in advance.
Posted May 13, 2009 by Mark Anderson
 

Comment

4 RE: Missing Database Table Error?

You don't need a model for the datasouce, however you do need a model for your controller if you want to save the search results.
Posted May 15, 2009 by Alex Ciobanu
 

Comment

5 RE: Missing Database Table Error?

Hi Mark,

Try adding:

var $useTable = false;

to your Tweet model (/app/models/tweet.php). It should then look something like this:

Model Class:

<?php 
     
class Tweet extends AppModel
     
{
          var 
$name 'Tweet';
          var 
$useTable false;
     }
?>

Hope that helps!
Posted May 18, 2009 by George Huger
 

Comment

6 Works perfect, use this fix.

Modify the controller as follows and it would work like a charm!! Make sure you have 'debug'=2 in the core.php in app/config, otherwise you won't see the dump.

Controller Class:

<?php 
class TweetsController extends AppController {
    var 
$uses = array();
    var 
$name 'Tweets';

    function 
index(){
        
$this->Twitter ConnectionManager::getDataSource('twitter');
        
$response $this->Twitter->account_verify_credentials();
        
$search_results $this->Twitter->search('cakephp');
        
debug($response);
        
debug($search_results);    
    }

?>


Kudos to Alex for sharing this twitter class.

Ketan

Audi Wallpaper
Posted May 26, 2009 by Ketan
 

Comment

7 RE: Works perfect, use this fix.

Modify the controller as follows and it would work like a charm!! Make sure you have 'debug'=2 in the core.php in app/config, otherwise you won't see the dump.

Controller Class:

<?php 
class TweetsController extends AppController {
    var 
$uses = array();
    var 
$name 'Tweets';

    function 
index(){
        
$this->Twitter ConnectionManager::getDataSource('twitter');
        
$response $this->Twitter->account_verify_credentials();
        
$search_results $this->Twitter->search('cakephp');
        
debug($response);
        
debug($search_results);    
    }

?>


Kudos to Alex for sharing this twitter class.

Ketan


Ketan,

ConnectionManager did not exist when i set $uses = array();
Posted Jun 2, 2009 by Simon Jackson
 

Comment

8 Awesome class but have a question

I have more than one twitter account and so I need a way to set the class up not using the data source method. I am getting credential from a DB and so they are not static.

What is the best way to pass in the username/password without the static DB method?

I look forward to your response.

Kind regards,

Luke Byrne
Posted Jun 5, 2009 by Luke Byrne
 

Comment

9 Re: Awesome class but have a question

I would go with something like:

$users = $this->User->find('all');
foreach($users as $user){
    $instance = ConnectionManager::getDataSource('twitter');
    $instance->username = 'username';
    $instance->password = 'password';
}
Make sure you have unique names for your instances.
Hope this helps.
Posted Jun 5, 2009 by Alex Ciobanu
 

Comment

10 Hi Alex, thanks for the quick reply

I think I follow you, I have added what I think you are saying here

http://bin.cakephp.org/view/2073952635
Is that on the right track, can you set the username and password on the class in that way??
Posted Jun 5, 2009 by Luke Byrne
 

Comment

11 yeap

Yes you can Luke, try it out.
Posted Jun 7, 2009 by Alex Ciobanu
 

Comment

12 'ConnectionManager' not found

Hi there,

Short tip the novice CakePHP developers.
When I first added the Twitter code to my Pages Controller I became familiar with the following error message:


Fatal error: Class 'ConnectionManager' not found in /app/controllers/pages_controller.php on line 55


To solve this just import the ConnectionManager within your Controller


App::Import('ConnectionManager');


just before


class YourControllerNameController extends AppController {

I'm novive to CakePHP so I did not know. I hope that other novice CakePHP developers will benefit from this hint.


Happy baking, Stinie
Posted Jun 28, 2009 by Christine Fürst
 

Comment

13 Kevin Smith answer

Kevin,

I had the same issue further up in the post as you can see.

The way to do it is this, set the values in the data source file to null.

Then do this to login using the credentials from the DB.

$this->Twitter = ConnectionManager::getDataSource('twitter');
$this->Twitter->username = 'username_from_db';
$this->Twitter->password = 'password_from_db';
$this->Twitter->account_verify_credentials();
Posted Jun 30, 2009 by Luke Byrne
 

Bug

14 account_archive depreciated

To fix the deprecation notice in account_archive use @285:

$url = 'http://twitter.com/account/archive.xml';
Should be:
$url = 'http://twitter.com/statuses/user_timeline.xml';
Posted Jul 22, 2009 by Nick Baker
 

Question

15 Thanks and OAuth support request

Thanks so much Alex!

Any plans for an OAuth version?

Cheers!
Posted Aug 1, 2009 by elven
 

Comment

16 No OAuth for now

I am unfamiliar with OAuth, so the short answer is no.
However I'll look into it.
Posted Aug 1, 2009 by Alex Ciobanu
 

Question

17 Inconsistent strange response

Hi:

First of all, this is great; thanks for sharing.

Was wondering if anyone else is experiencing this issue; about 10% of the time, the $response returned is:

View Template:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
<!-- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"> -->
<HTML>
<HEAD>
<META HTTP-EQUIV="Refresh" CONTENT="0.1">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
<TITLE></TITLE>
</HEAD>
<BODY><P></BODY>
</HTML>


Was hoping to understand if this is an error on Twitter's side, or mine. I've noticed that if I detect this error, and retry whatever method I called to trigger the initial request after a half second, it usually resolves the issue, but I want to be certain about what's going on. Thanks.
Posted Sep 4, 2009 by Tyler
 

Comment

18 RE: Inconsistent strange response

Hi Tyler,

I'm not experiencing this issue. Please give me more details about your code and I'll look it over ( http://bin.cakephp.org/ ). Posting your issue on the mailing list /IRC might also help.
Posted Sep 4, 2009 by Alex Ciobanu
 

Comment

19 RE: Inconsistent strange response

Hi Tyler,

I'm not experiencing this issue. Please give me more details about your code and I'll look it over ( http://bin.cakephp.org/ ). Posting your issue on the mailing list /IRC might also help.

Hi Alex:

Thanks for offering to help. I've been working at this for a while now. My index action is below, I've stripped it down to make it simpler to debug:

Controller Class:

<?php 
function index(){
            
        if(!empty(
$this->data)):
            
$this->Twitter->username $this->data['Tweet']['username'];
            
$this->Twitter->password $this->data['Tweet']['password'];
            
$response $this->Twitter->account_verify_credentials();

            if(isset(
$response['User'])):
                
$this->redirect(array('action' => 'select'));
                
            elseif(isset(
$response['Hash']['error'])):
                
$this->data['Tweet']['password'] = '';
                
$this->Session->setFlash($response['Hash']['error']);

            else:
                
$this->data['Tweet']['password'] = '';
                
$this->Session->setFlash('Response returned was an HTTP header, not the expected XML format: ' $response);

            endif;
                
                
        endif;
    }
?>

As I mentioned, about 10% of the time the response from my request returns a header with a refresh directive of .1 seconds. Also worth mentioning that the error appears more often after long periods of inactivity (which I assume is somehow related to the sessions expiring). The __process method immediately parses the response into an array, so the refresh header doesn't get rendered properly by the app. I'm still not 100% confident the refresh response is being sent from Twitter; there's no mention of that response in their documentation:
http://apiwiki.twitter.com/HTTP-Response-Codes-and-Errors
Also, at one point I had Controller::disableCache(); called from the subsequent method where the user is redirected after successful login, but that has since been removed.

I have added:
$this->log($this->Http->response['status']['code']);
to the first line of __process to see if I can determine the exact response that is sending this refresh header so I can account for it within my logic. I'll send along my findings...

==============================================================================

Just to follow up; the request was returning a 200 success response; upon digging, I found out it appears to be a problem with Twitter: http://code.google.com/p/twitter-api/issues/detail?id=968
What's even more frustrating is that I just rewrote the datasource to that I can make the request again after .1 seconds if it returns that HTML; but now the Twitter problem seems to be worse, and even after 10 attempts, it's still not returning XML.
Posted Sep 4, 2009 by Tyler
 

Question

20 Authenticated API request fails when calling status_user_timeline

Hi,

I am having issues with the authentication that is necessary to grab a protected user's timeline using the method status_user_timeline(). This is the issue:

I added the auth credentials to database.php. In my 'tweets_controller.php' class I have an action 'usertimelines' where I instantiate the twitter datasource for my controller:


$this->Twitter = ConnectionManager::getDataSource('twitter');
$response = $this->Twitter->account_verify_credentials(); 


$response returns the expected array with user info. The 'usertimeline' action requests a protected user's timeline:

 
$user_timeline_results = $this->Twitter->status_user_timeline($protected_user, array('count'=>'200', 'since_id'=>$since_id)); 

The account which has been authenticated in my application follows the $protected_user and he has accepted me as a follower, but when I request hist timeline with using the twitter_source.php methods and the above code, I get the error below.


[request] => /statuses/user_timeline/jpp9.xml?count=200&since_id=1
[error] => Not authorized

I verified that I indeed have access to this protected user's tweets by requesting http://twitter.com/statuses/user_timeline/jpp9.xml?count=200&since_id=1 directly on my browser. Indeed I was able to grab his tweets.

These are my thoughts:

This protected user is not following me Might that be the issue?

Or am I missing something to ensure valid authentication? (...recall that $response returned the user info)

Or is the current twitter_source.php code faulty with authenticated requests?

Thanks for any help!
Posted Oct 28, 2009 by Alan Garcia
 

Bug

21 some calls to twitter api using the datasource fail

I started using this wonderful datasource this week. First tweet was posted in an instant, very nice. But deleting through the api failed, because twitter api requires that you do a HTTP POST instead a GET. Some calls in this datasource already use Http->post like this one:


function status_update($status) {
        $url = "http://twitter.com/statuses/update.xml";
        return $this->__process($this->Http->post($url, array('status' => $status), $this->__getAuthHeader()));
    }

but not the status_destroy function, so I changed that to use post also:


function status_destroy($id) {
        $url = "http://twitter.com/statuses/destroy/{$id}.xml";
        return $this->__process($this->Http->post($url, null, $this->__getAuthHeader()));
    } 

It was an easy fix after I saw the response from twitter.

Cheers,
Steve
Posted Nov 13, 2009 by steven van loef
 

Comment

22 Brand New Twitter Datasource now with 100% more OAuth!

Thanks so much Alex!

Any plans for an OAuth version?

Cheers!

I just finished up working on a first revision of an oauth enable twitter datasource (http://code.google.com/p/cakephp-twitter-oauth-datasource/)
Posted Dec 12, 2009 by Michael Riddle
 

Comment

23 Minor change for 1.2.6 / 1.3

Commit:
http://github.com/cakephp/cakephp1x/commit/60465287445f546ea85ee12827772c06055984f7

<?php
/**
 * Twitter Datasource 0.2
 *
 * Twitter datasource to communicate with the Twitter API.
 *
 * Based on:
 * http://bakery.cakephp.org/articles/view/paypal-datasource
 * http://bakery.cakephp.org/articles/view/twitter-component
 * http://debuggable.com/posts/new-google-analytics-api:480f4dd6-c59c-445f-8ce0-4202cbdd56cb
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 *
 * @author Alexandru Ciobanu <iscandr@gmail.com>
 * @copyright (c) 2009 Alexandru Ciobanu
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link http://bakery.cakephp.org/articles/view/twitter-datasource
 * @created May 4, 2009
 * @version 0.2
 *
 */
App::import('Core', array('Xml''HttpSocket'));
 
class 
TwitterSource extends DataSource
{
    var 
$username "";
    var 
$password "";
    var 
$description "Twitter API";
    var 
$Http null;
 
    function 
__construct($config) {
        
parent::__construct($config);
        
$this->Http =& new HttpSocket();
        
$this->username $this->config['username'];
        
$this->password $this->config['password'];
    }
 
 
    
/**
     * Returns a single status, specified by the id parameter below.
     * The status's author will be returned inline.
     *
     * @param string id Required. The numerical ID or username of the status you're trying to retrieve.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_show($id) {
        
$url "http://twitter.com/statuses/show/{$id}.xml";
        return 
$this->__process($this->Http->get($url));
    }
 
    function 
user_show($id=false$params = array()) {
        
$url "http://twitter.com/users/show";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Returns the 20 most recent statuses from non-protected users
     * who have set a custom user icon.  Does not require authentication.
     *
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_public_timeline($params=array()) {
        
$url 'http://twitter.com/statuses/public_timeline.xml';
        return 
$this->__process($this->Http->get($url$params));
    }
 
    
/**
     * Returns the 20 most recent statuses posted in the last 24 hours from the authenticating
     * user and that user's friends.  It's also possible to request another user's
     * friends_timeline via the id parameter below.
     *
     * @param string id Optional. Specifies the ID or screen name of the user for whom to return the friends_timeline
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_friends_timeline($id=false$params = array()) {
        
$url 'http://twitter.com/statuses/friends_timeline';
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params));
    }
 
    
/**
     * Returns the 20 most recent statuses posted in the last 24 hours from the authenticating user.
     * It's also possible to request another user's timeline via the id parameter below.
     *
     * @param string id Optional. Specifies the ID or screen name of the user for whom to return the friends_timeline.
     * @param array params Optional. parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_user_timeline($id=false$params = array()) {
        
$url 'http://twitter.com/statuses/user_timeline';
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
 
        return 
$this->__process($this->Http->get($url$params));
    }
 
    
/**
     * Updates the authenticating user's status.  Requires the status parameter specified below.
     *
     * @param string status Required.  The text of your status update.
     *              Be sure to URL encode as necessary.  Must not be more than 160 characters
     *              and should not be more than 140 characters to ensure optimal display.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_update($status) {
        
$url "http://twitter.com/statuses/update.xml";
        return 
$this->__process($this->Http->post($url, array('status' => $status), $this->__getAuthHeader()));
    }
 
    
/**
     * Returns the 20 most recent replies
     * (status updates prefixed with @username posted by users who
     * are friends with the user being replied to)
     * to the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_replies($params = array()) {
        
$url "http://twitter.com/statuses/replies.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Destroys the status specified by the required ID parameter.
     *
     * @param string id Required.  The ID of the status to destroy.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function status_destroy($id) {
        
$url "http://twitter.com/statuses/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Returns up to 100 of the authenticating user's friends who have most recently updated, each with current status inline.
     * It's also possible to request another user's recent friends list via the id parameter below.
     *
     * @param string id Optional.  The ID or screen name of the user for whom to request a list of friends.
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_friends($id=false$params = array()) {
        
$url "http://twitter.com/statuses/friends";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Returns the authenticating user's followers, each with current status inline.
     *
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_followers($params = array()) {
        
$url "http://twitter.com/statuses/followers.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Returns a list of the users currently featured on the site with their current statuses inline.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function user_featured() {
        
$url "http://twitter.com/statuses/featured.xml";
        return 
$this->__process($this->Http->get($url));
    }
 
    
/**
     * Returns a list of the 20 most recent direct messages sent to the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages($params = array()) {
        
$url "http://twitter.com/direct_messages.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Returns a list of the 20 most recent direct messages sent by the authenticating user.
     *
     * @param array params Optional. Parameters passed to the query.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_sent($params = array()) {
        
$url "http://twitter.com/direct_messages/sent.xml";
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Sends a new direct message to the specified user from the authenticating user.
     *
     * @param string user Required.  The ID or screen name of the recipient user.
     * @param string text Required.  The text of your direct message.
     *              Be sure to URL encode as necessary, and keep it under 140 characters.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_new($user$text) {
        
$url "http://twitter.com/direct_messages/new.xml";
        
$params = array('user' => $user'text' => $text);
        return 
$this->__process($this->Http->post($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Destroys the direct message specified in the required ID parameter.
     *
     * @param string id Required.  The ID of the direct message to destroy.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function direct_messages_destroy($id) {
        
$url "http://twitter.com/direct_messages/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Befriends the user specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to befriend.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function friendship_create($id) {
        
$url "http://twitter.com/friendships/create/{$id}.xml";
        return 
$this->__process($this->Http->post($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Discontinues friendship with the user specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user with whom to discontinue friendship.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function friendship_destroy($id) {
        
$url "http://twitter.com/friendships/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Returns an HTTP 200 OK response code and a format-specific response if authentication was successful.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_verify_credentials() {
        
$url "http://twitter.com/account/verify_credentials.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Ends the session of the authenticating user, returning a null cookie.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_end_session() {
        
$url "http://twitter.com/account/end_session";
        
$this->Http->get($urlnull$this->__getAuthHeader());
    }
 
    
/**
     * Returns 80 statuses per page for the authenticating user, ordered by descending date of posting.
     *
     * @param integer page Optional. Retrieves the 80 next most recent statuses.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_archive($page=1) {
        
$url 'http://twitter.com/statuses/user_timeline.xml';
        return 
$this->__process($this->Http->get($url, array('page' => $page), $this->__getAuthHeader()));
    }
 
    
/**
     * Updates the location attribute of the authenticating user,
     * as displayed on the side of their profile and returned in various API methods.
     *
     * @param string location The location of the user.  Please note this is not normalized, geocoded, or translated to latitude/longitude at this time.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_update_location($location) {
        
$url 'http://twitter.com/account/update_location.xml';
        return 
$this->__process($this->Http->get($url, array('location' => $location), $this->__getAuthHeader()));
    }
 
    
/**
     * Sets which device Twitter delivers updates to for the authenticating user.
     * Sending none as the device parameter will disable IM or SMS updates.
     *
     * @param string device  Must be one of: sms, im, none.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function account_update_delivery_device($device) {
        
$url 'http://twitter.com/account/update_delivery_device.xml';
        return 
$this->__process($this->Http->get($url, array('device' => $device), $this->__getAuthHeader()));
    }
 
    
/**
     * 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 Optional.  The ID or screen name of the user for whom to request a list of favorite statuses.
     * @param array params Optional. Parameters passed to the query
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites($id false$params = array()) {
        
$url "http://twitter.com/favorites";
        if(
$id != false) {
            
$url .= "/{$id}.xml";
        } else {
            
$url .= ".xml";
        }
        return 
$this->__process($this->Http->get($url$params$this->__getAuthHeader()));
    }
 
    
/**
     * Favorites the status specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID of the status to favorite.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites_create($id) {
        
$url "http://twitter.com/favorites/create/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Un-favorites the status specified in the ID parameter as the authenticating user.
     *
     * @param string id Required.  The ID of the status to un-favorite.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function favorites_destroy($id) {
        
$url "http://twitter.com/favorites/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
    
/**
     * Search for keyword using the twitter search API
     *
     * @param string $keyword
     * @param string $language
     * @see http://search.twitter.com/api
     */
    
function search($keyword$language 'all'$rpp '10'){
        
$url "http://search.twitter.com/search.atom?q=$keyword&lang=$language&rpp=$rpp";
        return 
$this->__process($this->Http->get($url));
    }
 
    
/**
     * Enables notifications for updates from the specified user to the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to follow.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function notifications_follow($id) {
        
$url "http://twitter.com/notifications/follow/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Disables notifications for updates from the specified user to the authenticating user.
     *
     * @param string id Required.  The ID or screen name of the user to leave.
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function notifications_leave($id) {
        
$url "http://twitter.com/notifications/leave/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Blocks the user specified in the ID parameter as the authenticating user.
     * Returns the blocked user in the requested format when successful.
     *
     * @param string id The ID or screen_name of the user to block
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function block_create($id) {
        
$url "http://twitter.com/blocks/create/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Un-blocks the user specified in the ID parameter as the authenticating user.
     * Returns the un-blocked user in the requested format when successful.
     *
     * @param string id The ID or screen_name of the user to block
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function block_destroy($id) {
        
$url "http://twitter.com/blocks/destroy/{$id}.xml";
        return 
$this->__process($this->Http->get($urlnull$this->__getAuthHeader()));
    }
 
    
/**
     * Returns the string "ok" in the requested format with a 200 OK HTTP status code.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function help_test() {
        
$url 'http://twitter.com/help/test.xml';
        return 
$this->__process($this->Http->get($url));
    }
 
    
/**
     * Returns the same text displayed on http://twitter.com/home when
     * a maintenance window is scheduled, in the requested format.
     *
     * @see http://groups.google.com/group/twitter-development-talk/web/api-documentation
     */
    
function help_downtime_schedule() {
        
$url 'http://twitter.com/help/downtime_schedule.xml';
        return 
$this->__process($this->Http->get($url));
    }
    
/**
     * Credentials array for method with mandatory auth
     * @return array credentials
     */
    
function __getAuthHeader() {
        return array(
'auth' => array('method' => 'Basic',
                                     
'user' => $this->username,
                                     
'pass' => $this->password
        
)
        );
    }
 
    
/**
     *
     * @param string data to process
     * @return array Twitter API response
     */
    
function __process($response) {
        
$xml = new XML($response);
        
$array $xml->toArray();

        
$xml->__destruct();
        
$xml null;
        unset(
$xml);
 
        return 
$array;
    }
}
?>
Posted Feb 2, 2010 by Julian