Need help pointing Javascript XML to PHP file for Twitter 1.1 API

Hi guys,

I noticed that my clients’ Twitter feeds aren’t working the other day and, after a bit of research, it turns out that Twitter require access tokens now to use their API.

I’ve seen this tutorial (http://www.fullondesign.co.uk/coding/2516-how-use-twitter-oauth-1-1-javascriptjquery.htm) and have sorted the PHP file with my access tokens etc.

However, I need help pointing to the PHP file. I can’t find the relevant code anywhere in my Javascript XML file. I assume it needs to be brought in another way.

Here is my Javascript XLM file - can anyone see how I can point it to twitter-proxy.php?



(function($) {

  $.fn.tweet = function(o){
    var s = $.extend({
      username: ["My_Client"],                // [string]   required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
      list: null,                               // [string]   optional name of list belonging to username
      avatar_size: null,                        // [integer]  height and width of avatar if displayed (48px max)
      count: 5,                                 // [integer]  how many tweets to display?
      intro_text: null,                         // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                         // [string]   do you want text AFTER your tweets?
      join_text:  null,                         // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "",        // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "",                   // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "",               // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "",     // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "",   // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                       // [string]   optional loading text, displayed while tweets load
      query: null,                              // [string]   optional search query
      refresh_interval: null ,                  // [integer]  optional number of seconds after which to reload tweets
      twitter_url: "twitter.com",               // [string]   custom twitter url, if any (apigee, etc.)
      twitter_api_url: "api.twitter.com",       // [string]   custom twitter api url, if any (apigee, etc.)
      twitter_search_url: "search.twitter.com", // [string]   custom twitter search url, if any (apigee, etc.)
      template: function(info) {                // [function] template used to construct each tweet <li>
        return info["avatar"] + info["time"] + info["join"] + info["text"];
      }
    }, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        // See http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        var regexp = /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'".,<>?«»“”‘’]))/gi;
        this.each(function() {
          returning.push(this.replace(regexp,
                                      function(match) {
                                        var url = (/^[a-z]+:/i).test(match) ? match : "http://"+match;
                                        return "<a href=\\""+url+"\\">"+match+"</a>";
                                      }));
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\\@]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"<a href=\\"http://"+s.twitter_url+"/$1\\">@$1</a>"));        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        var regexp = /(?:^| )[\\#]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp, ' <a href="http://'+s.twitter_search_url+'/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'" target="_blank">#$1</a>'));
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\\b(awesome)\\b/gi, '<span class="awesome">$1</span>'));
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\\b(epic)\\b/gi, '<span class="epic">$1</span>'));
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"));
        });
        return $(returning);
      }
    });

    function parse_date(date_str) {
      // The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
      // cannot handle in IE. We therefore perform the following transformation:
      // "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
      return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \\d\\d?)(.*)( \\d{4})$/i, '$1,$2$4$3'));
    }

    function relative_time(time_value) {
      var parsed_date = parse_date(time_value);
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - parsed_date) / 1000, 10);
      var r = '';
      if (delta < 60) {
        r = delta + ' seconds ago';
      } else if(delta < 120) {
        r = 'a minute ago';
      } else if(delta < (45*60)) {
        r = (parseInt(delta / 60, 10)).toString() + ' minutes ago';
      } else if(delta < (2*60*60)) {
        r = 'an hour ago';
      } else if(delta < (24*60*60)) {
        r = '' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
        r = 'a day ago';
      } else {
        r = (parseInt(delta / 86400, 10)).toString() + ' days ago';
      }
      return 'about ' + r;
    }

    function build_url() {
      var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
      if (s.list) {
        return proto+"//"+s.twitter_api_url+"/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?";
      } else if (s.query === null && s.username.length == 1) {
        return proto+'//'+s.twitter_api_url+'/1/statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+s.count+'&include_rts=1&callback=?';
      } else {
        var query = (s.query || 'from:'+s.username.join(' OR from:'));
        return proto+'//'+s.twitter_search_url+'/search.json?&q='+encodeURIComponent(query)+'&rpp='+s.count+'&callback=?';
      }
    }

    return this.each(function(i, widget){
      var list = $('<ul class="tweet_list">').appendTo(widget);
      var intro = '<p class="tweet_intro">'+s.intro_text+'</p>';
      var outro = '<p class="tweet_outro">'+s.outro_text+'</p>';
      var loading = $('<p class="loading">'+s.loading_text+'</p>');

      if(typeof(s.username) == "string"){
        s.username = [s.username];
      }

      if (s.loading_text) $(widget).append(loading);
      $(widget).bind("load", function(){
        $.getJSON(build_url(), function(data){
          if (s.loading_text) loading.remove();
          if (s.intro_text) list.before(intro);
          list.empty();

          var tweets = $.map(data.results || data, function(item){
            var join_text = s.join_text;

            // auto join text based on verb tense and content
            if (s.join_text == "auto") {
              if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
                join_text = s.auto_join_text_reply;
              } else if (item.text.match(/(^\\w+:\\/\\/[A-Za-z0-9-_]+\\.[A-Za-z0-9-_:%&\\?\\/.=]+) .*/i)) {
                join_text = s.auto_join_text_url;
              } else if (item.text.match(/^((\\w+ed)|just) .*/im)) {
                join_text = s.auto_join_text_ed;
              } else if (item.text.match(/^(\\w*ing) .*/i)) {
                join_text = s.auto_join_text_ing;
              } else {
                join_text = s.auto_join_text_default;
              }
            }

            // Basic building blocks for constructing tweet <li> using a template
            var screen_name = item.from_user || item.user.screen_name;
            var source = item.source;
            var user_url = "http://"+s.twitter_url+"/"+screen_name;
            var avatar_size = s.avatar_size;
            var avatar_url = item.profile_image_url || item.user.profile_image_url;
            var tweet_url = "http://"+s.twitter_url+"/"+screen_name+"/statuses/"+item.id_str;
            var tweet_time = item.created_at;
            var tweet_relative_time = relative_time(tweet_time);
            var tweet_raw_text = item.text;
            var tweet_text = $([tweet_raw_text]).linkUrl().linkUser().linkHash()[0];

            // Default spans, and pre-formatted blocks for common layouts
            var user = '<a target="_blank" class="tweet_user" href='+user_url+'">'+screen_name+'</a>';
            var join = ((s.join_text) ? ('<span class="tweet_join"> '+join_text+' </span>') : ' ');
            var avatar = (avatar_size ?
                          ('<a  target="_blank" class="tweet_avatar" href="'+user_url+'"><img src="'+avatar_url+
                           '" height="'+avatar_size+'" width="'+avatar_size+
                           '" alt="'+screen_name+'\\'s avatar" title="'+screen_name+'\\'s avatar" border="0"/></a>') : '');
            var time = '<span class="tweet_time"><a href="'+tweet_url+'" title="view tweet on twitter" target="_blank">'+tweet_relative_time+'</a></span><br />';
            var text = '<span class="tweet_text">'+$([tweet_text]).makeHeart().capAwesome().capEpic()[0]+ '</span>';

            return "<li>" +
                        s.template({
                          item: item, // For advanced users who want to dig out other info
                          screen_name: screen_name,
                          user_url: user_url,
                          avatar_size: avatar_size,
                          avatar_url: avatar_url,
                          source: source,
                          tweet_url: tweet_url,
                          tweet_time: tweet_time,
                          tweet_relative_time: tweet_relative_time,
                          tweet_raw_text: tweet_raw_text,
                          tweet_text: tweet_text,
                          user: user,
                          join: join,
                          avatar: avatar,
                          time: time,
                          text: text
                       }) +
                    "</li>";
          });

          list.append(tweets.join('')).
              children('li:first').addClass('tweet_first').end().
              children('li:odd').addClass('tweet_even').end().
              children('li:even').addClass('tweet_odd');

          if (s.outro_text) list.after(outro);
          $(widget).trigger("loaded").trigger((tweets.length === 0 ? "empty" : "full"));
          if (s.refresh_interval) {
            window.setTimeout(function() { $(widget).trigger("load"); }, 1000 * s.refresh_interval);
          }
        });
      }).trigger("load");
    });
  };
})(jQuery);



Thank you very much and I hope to hear from you!

SM

Hi,

You need to make a couple of small changes, here:

twitter_api_url: "/twitter-proxy.php?url=",  // Change the path if your php file is in a different location

and here:

function build_url() {
  var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
  if (s.list) {
    return s.twitter_api_url+encodeURIComponent(s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?");  // This line changed
  } else if (s.query === null && s.username.length == 1) {
    return s.twitter_api_url+encodeURIComponent('statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+s.count+'&include_rts=1&callback=?');  // And this one
  } else {
    var query = (s.query || 'from:'+s.username.join(' OR from:'));
    return proto+'//'+s.twitter_search_url+'/search.json?&q='+encodeURIComponent(query)+'&rpp='+s.count+'&callback=?';
  }
}

Note that I’ve not changed the search url, as it doesn’t seem to be supported in the PHP script you’re using. You also need to make sure that you add all the twitter urls (inc query strings) that you intend to use are included on the whitelist in the PHP script.

Hey Fretburner!

Thank you for the suggestion! Unfortunately it didn’t seem to work though - I still just get ‘Loading Tweets…’ when I test the page.

When I view twitter-proxy.php it says ‘No URL set’.

Is there something I am missing?

My code now looks like:



(function($) {

  $.fn.tweet = function(o){
    var s = $.extend({
      username: ["My_Client"],                // [string]   required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
      list: null,                               // [string]   optional name of list belonging to username
      avatar_size: null,                        // [integer]  height and width of avatar if displayed (48px max)
      count: 5,                                 // [integer]  how many tweets to display?
      intro_text: null,                         // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                         // [string]   do you want text AFTER your tweets?
      join_text:  null,                         // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "",        // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "",                   // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "",               // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "",     // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "",   // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                       // [string]   optional loading text, displayed while tweets load
      query: null,                              // [string]   optional search query
      refresh_interval: null ,                  // [integer]  optional number of seconds after which to reload tweets
      twitter_url: "twitter.com",               // [string]   custom twitter url, if any (apigee, etc.)
      twitter_api_url: "assets/scripts/tweets/twitter-proxy.php?url=",  // Change the path if your php file is in a different location
      twitter_search_url: "search.twitter.com", // [string]   custom twitter search url, if any (apigee, etc.)
      template: function(info) {                // [function] template used to construct each tweet <li>
        return info["avatar"] + info["time"] + info["join"] + info["text"];
      }
    }, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        // See http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        var regexp = /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'".,<>?«»“”‘’]))/gi;
        this.each(function() {
          returning.push(this.replace(regexp,
                                      function(match) {
                                        var url = (/^[a-z]+:/i).test(match) ? match : "http://"+match;
                                        return "<a href=\\""+url+"\\">"+match+"</a>";
                                      }));
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\\@]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"<a href=\\"http://"+s.twitter_url+"/$1\\">@$1</a>"));        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        var regexp = /(?:^| )[\\#]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp, ' <a href="http://'+s.twitter_search_url+'/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'" target="_blank">#$1</a>'));
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\\b(awesome)\\b/gi, '<span class="awesome">$1</span>'));
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\\b(epic)\\b/gi, '<span class="epic">$1</span>'));
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"));
        });
        return $(returning);
      }
    });

    function parse_date(date_str) {
      // The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
      // cannot handle in IE. We therefore perform the following transformation:
      // "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
      return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \\d\\d?)(.*)( \\d{4})$/i, '$1,$2$4$3'));
    }

    function relative_time(time_value) {
      var parsed_date = parse_date(time_value);
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - parsed_date) / 1000, 10);
      var r = '';
      if (delta < 60) {
        r = delta + ' seconds ago';
      } else if(delta < 120) {
        r = 'a minute ago';
      } else if(delta < (45*60)) {
        r = (parseInt(delta / 60, 10)).toString() + ' minutes ago';
      } else if(delta < (2*60*60)) {
        r = 'an hour ago';
      } else if(delta < (24*60*60)) {
        r = '' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
        r = 'a day ago';
      } else {
        r = (parseInt(delta / 86400, 10)).toString() + ' days ago';
      }
      return 'about ' + r;
    }


function build_url() {
  var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
  if (s.list) {
    return s.twitter_api_url+encodeURIComponent(s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?");  // This line changed
  } else if (s.query === null && s.username.length == 1) {
    return s.twitter_api_url+encodeURIComponent('statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+s.count+'&include_rts=1&callback=?');  // And this one
  } else {
    var query = (s.query || 'from:'+s.username.join(' OR from:'));
    return proto+'//'+s.twitter_search_url+'/search.json?&q='+encodeURIComponent(query)+'&rpp='+s.count+'&callback=?';
  }
}



    return this.each(function(i, widget){
      var list = $('<ul class="tweet_list">').appendTo(widget);
      var intro = '<p class="tweet_intro">'+s.intro_text+'</p>';
      var outro = '<p class="tweet_outro">'+s.outro_text+'</p>';
      var loading = $('<p class="loading">'+s.loading_text+'</p>');

      if(typeof(s.username) == "string"){
        s.username = [s.username];
      }

      if (s.loading_text) $(widget).append(loading);
      $(widget).bind("load", function(){
        $.getJSON(build_url(), function(data){
          if (s.loading_text) loading.remove();
          if (s.intro_text) list.before(intro);
          list.empty();

          var tweets = $.map(data.results || data, function(item){
            var join_text = s.join_text;

            // auto join text based on verb tense and content
            if (s.join_text == "auto") {
              if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
                join_text = s.auto_join_text_reply;
              } else if (item.text.match(/(^\\w+:\\/\\/[A-Za-z0-9-_]+\\.[A-Za-z0-9-_:%&\\?\\/.=]+) .*/i)) {
                join_text = s.auto_join_text_url;
              } else if (item.text.match(/^((\\w+ed)|just) .*/im)) {
                join_text = s.auto_join_text_ed;
              } else if (item.text.match(/^(\\w*ing) .*/i)) {
                join_text = s.auto_join_text_ing;
              } else {
                join_text = s.auto_join_text_default;
              }
            }

            // Basic building blocks for constructing tweet <li> using a template
            var screen_name = item.from_user || item.user.screen_name;
            var source = item.source;
            var user_url = "http://"+s.twitter_url+"/"+screen_name;
            var avatar_size = s.avatar_size;
            var avatar_url = item.profile_image_url || item.user.profile_image_url;
            var tweet_url = "http://"+s.twitter_url+"/"+screen_name+"/statuses/"+item.id_str;
            var tweet_time = item.created_at;
            var tweet_relative_time = relative_time(tweet_time);
            var tweet_raw_text = item.text;
            var tweet_text = $([tweet_raw_text]).linkUrl().linkUser().linkHash()[0];

            // Default spans, and pre-formatted blocks for common layouts
            var user = '<a target="_blank" class="tweet_user" href='+user_url+'">'+screen_name+'</a>';
            var join = ((s.join_text) ? ('<span class="tweet_join"> '+join_text+' </span>') : ' ');
            var avatar = (avatar_size ?
                          ('<a  target="_blank" class="tweet_avatar" href="'+user_url+'"><img src="'+avatar_url+
                           '" height="'+avatar_size+'" width="'+avatar_size+
                           '" alt="'+screen_name+'\\'s avatar" title="'+screen_name+'\\'s avatar" border="0"/></a>') : '');
            var time = '<span class="tweet_time"><a href="'+tweet_url+'" title="view tweet on twitter" target="_blank">'+tweet_relative_time+'</a></span><br />';
            var text = '<span class="tweet_text">'+$([tweet_text]).makeHeart().capAwesome().capEpic()[0]+ '</span>';

            return "<li>" +
                        s.template({
                          item: item, // For advanced users who want to dig out other info
                          screen_name: screen_name,
                          user_url: user_url,
                          avatar_size: avatar_size,
                          avatar_url: avatar_url,
                          source: source,
                          tweet_url: tweet_url,
                          tweet_time: tweet_time,
                          tweet_relative_time: tweet_relative_time,
                          tweet_raw_text: tweet_raw_text,
                          tweet_text: tweet_text,
                          user: user,
                          join: join,
                          avatar: avatar,
                          time: time,
                          text: text
                       }) +
                    "</li>";
          });

          list.append(tweets.join('')).
              children('li:first').addClass('tweet_first').end().
              children('li:odd').addClass('tweet_even').end().
              children('li:even').addClass('tweet_odd');

          if (s.outro_text) list.after(outro);
          $(widget).trigger("loaded").trigger((tweets.length === 0 ? "empty" : "full"));
          if (s.refresh_interval) {
            window.setTimeout(function() { $(widget).trigger("load"); }, 1000 * s.refresh_interval);
          }
        });
      }).trigger("load");
    });
  };
})(jQuery);



Thank you for all your help :slight_smile:

Is the page online somewhere that you could link to? Or if not, could you post the code for the whole page?

Yeah sure, sorry - the link is here.

Thank you, much appreciated!

The server is returning ‘URL is not authorised’, so it seems that your PHP script couldn’t find the URL in the whitelist. According to the article you linked to, you need to set the whitelist like this:


$whitelist = array(
	'statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1&callback=?'=>true
);

Thank you for the reply.

I’m afraid I still can’t get it to work - I’m sure it’s me missing something! This is what my PHP looks like:



<?php

/**
 *  Usage:
 *  Send the url you want to access url encoded in the url paramater, for example (This is with JS): 
 *  /twitter-proxy.php?url='+encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=2')
*/

// The tokens, keys and secrets from the app you created at https://dev.twitter.com/apps
$config = array(
	'oauth_access_token' => '',
	'oauth_access_token_secret' => '',
	'consumer_key' => '',
	'consumer_secret' => '',
	'use_whitelist' => true, // If you want to only allow some requests to use this script.
	'base_url' => 'http://api.twitter.com/1.1/'
);

// Only allow certain requests to twitter. Stop randoms using your server as a proxy.

// WHITELIST
$whitelist = array(
    'statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1&callback=?'=>true
); 

/*
* Ok, no more config should really be needed. Yay!
*/

// We'll get the URL from $_GET[]. Make sure the url is url encoded, for example encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=10&include_rts=false&exclude_replies=true')
if(!isset($_GET['url'])){
	die('No URL set');
}

$url = $_GET['url'];


if($config['use_whitelist'] && !isset($whitelist[$url])){
	die('URL is not authorised');
}

// Figure out the URL parmaters
$url_parts = parse_url($url);
parse_str($url_parts['query'], $url_arguments);

$full_url = $config['base_url'].$url; // Url with the query on it.
$base_url = $config['base_url'].$url_parts['path']; // Url without the query.

/**
* Code below from http://stackoverflow.com/questions/12916539/simplest-php-example-retrieving-user-timeline-with-twitter-api-version-1-1 by Rivers 
* with a few modfications by Mike Rogers to support variables in the URL nicely
*/

function buildBaseString($baseURI, $method, $params) {
	$r = array();
	ksort($params);
	foreach($params as $key=>$value){
	$r[] = "$key=" . rawurlencode($value);
	}
	return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}

function buildAuthorizationHeader($oauth) {
	$r = 'Authorization: OAuth ';
	$values = array();
	foreach($oauth as $key=>$value)
	$values[] = "$key=\\"" . rawurlencode($value) . "\\"";
	$r .= implode(', ', $values);
	return $r;
}

// Set up the oauth Authorization array
$oauth = array(
	'oauth_consumer_key' => $config['consumer_key'],
	'oauth_nonce' => time(),
	'oauth_signature_method' => 'HMAC-SHA1',
	'oauth_token' => $config['oauth_access_token'],
	'oauth_timestamp' => time(),
	'oauth_version' => '1.0'
);
	
$base_info = buildBaseString($base_url, 'GET', array_merge($oauth, $url_arguments));
$composite_key = rawurlencode($config['consumer_secret']) . '&' . rawurlencode($config['oauth_access_token_secret']);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;

// Make Requests
$header = array(
	buildAuthorizationHeader($oauth), 
	'Expect:'
);
$options = array(
	CURLOPT_HTTPHEADER => $header,
	//CURLOPT_POSTFIELDS => $postfields,
	CURLOPT_HEADER => false,
	CURLOPT_URL => $full_url,
	CURLOPT_RETURNTRANSFER => true,
	CURLOPT_SSL_VERIFYPEER => false
);

$feed = curl_init();
curl_setopt_array($feed, $options);
$result = curl_exec($feed);
$info = curl_getinfo($feed);
curl_close($feed);

// Send suitable headers to the end user.
if(isset($info['content_type']) && isset($info['size_download'])){
	header('Content-Type: '.$info['content_type']);
	header('Content-Length: '.$info['size_download']);

}

echo($result);
?>


First things first, you should edit your last post right away if you still can and remove your twitter oauth and consumer keys and secrets - other people can abuse your twitter account with those. In fact, you should probably log into the twitter dev site and see if you can renew your access tokens.

The server is now returning the response: ({"errors":[{"message":"Could not authenticate you","code":32}]});
(You can check on what the server is returning by visiting: http://www.maxfewtrell.com/assets/scripts/tweets/twitter-proxy.php?url=statuses%2Fuser_timeline.json%3Fscreen_name%3DMax_Fewtrell%26count%3D5%26include_rts%3D1%26callback%3D%3F)

Thanks, and sorry - I’ve edited the post and changed my access codes.

I see the error you’re pointing out. Does that mean anything to you?

Thank you!

The error could mean something as simple as a typo in one of your API keys/tokens.

Edit: I’ve seen several conversations over at the twitter dev site that indicate it could be a variety of issues that cause that particular error, so if double-checking the keys/tokens doesn’t do it, I know another PHP library you could use which is simpler to get up and running (and which I know works, as I’ve been using it myself).

Hey!
Thanks for yet another informative and helpful reply!
I thought it could be the same thing so I re-checked and re-entered the API keys but to no avail.
Could we try your PHP library?
Thank you again! :slight_smile:

So, first off you’ll need to download the TwitterOAuth library.

Then, replace the contents of your twitter-proxy.php with this:


<?php
require_once('twitteroauth/twitteroauth.php');

// Your API credentials here:
$consumer_key = '';
$consumer_secret = '';
$access_token = '';
$access_token_secret = '';

$connection = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);
$connection->decode_json = FALSE;

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1&callback=?');

header('Content-type: application/json');
echo $tweets;

I’m assuming all you want to do is pull down a list of your latest tweets, so I’ve hardcoded the string with the API options here. This means that if you want to change any of the options (e.g number of tweets returned) you’ll have to do it here rather than in your JS code, but it leaves the script less open to abuse by malicious users.

8Mega, thank you very much for that!

twitter-proxy.php seems to be outputting something sensible now! However the tweets still aren’t coming out on the Twitter feed; I’m still getting ‘Loading tweets…’.

Is it anything to do with this bit of code in the header do you think?



<script>
jQuery.noConflict();
  function randomString(length) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('');
    var str = '';
    for (var i = 0; i < length; i++) {
      str += chars[Math.floor(Math.random() * chars.length)];
    }
    return str;
  }
  var rnd = randomString(8);

  jQuery(document).ready(function($) {
    $(".tweet").tweet({
      loading_text: "Loading tweets..."
    });
  })
</script>


I guess the problem is in /assets/scripts/tweets/jquery.tweet.js
You need to update the path to the php script, from:

twitter_api_url: "twitter-proxy.php?url=",

to:

twitter_api_url: "/assets/scripts/tweets/twitter-proxy.php?url=",

I updated the line as suggested but it didn’t work :frowning:
Any other ideas by any chance?
Thank you!

Hmm, OK well the request is being returned from the server, but the success callback in your JS isn’t being fired. Can you try editing this line in your twitter-proxy.php file please, from:

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1&callback=?');

to:

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1');

YES! Mega, thank you!

The only thing now is that the API only seems to be calling the latest 2 statuses - from what I can see from the code, it should be calling the latest 5. Do you have any ideas on that?

Almost there! :wink:

Thank you!

I think we need to make one last tweak to that line of PHP code. Try:

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=true');

I think that version 1.1 of the API might need include_rts explicitly set to true, rather than 1.

It still seems to be just getting the latest two tweets. I can’t find ‘include_rts’ in any of the files…

Sorry for being an idiot and thank you for being patient with me! :slight_smile:

Back in the twitter-proxy.php file, change this line:

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=1');

to this:

$tweets = $connection->get('statuses/user_timeline.json?screen_name=Max_Fewtrell&count=5&include_rts=true');