├── .DS_Store ├── README.md ├── tweets.php ├── tweets.txt └── twitteroauth ├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── _notes └── dwsync.xml ├── callback.php ├── clearsessions.php ├── config-sample.php ├── connect.php ├── html.inc ├── images ├── _notes │ └── dwsync.xml ├── darker.png └── lighter.png ├── index.php ├── redirect.php ├── test.php └── twitteroauth ├── .DS_Store ├── OAuth.php ├── _notes └── dwsync.xml └── twitteroauth.php /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | latest-tweets-php-o-auth 2 | ======================== 3 | 4 | Twitters API v1.0 has now been retired. Here's a way you can pull your tweets from Twitter using PHP and OAuth. 5 | 6 | Overview 7 | ======================== 8 | 9 | - Tweets are cached to avoid exceeding Twitter’s limit of 150 requests for a user’s RSS and json feed per hour. 10 | - A fallback is provided in case the twitter feed fails to load. this can be edited to suit your needs. 11 | - A configuration parameter allows you to specify how many tweets are displayed 12 | - Dates can optionally be displayed in “Twitter style”, e.g. "12 minutes ago" 13 | - You can edit the HTML that wraps your tweets, tweet status and meta information 14 | 15 | Parameters 16 | ======================== 17 | 18 | - Twitter handle. 19 | - Cache file location. 20 | - Tweets to display. 21 | - Ignore replies. 22 | - Include retweets. 23 | - Twitter style dates. ("16 hours ago") 24 | - Custom html. 25 | 26 | Usage 27 | ======================== 28 | 29 | Firstly you will need to register your app / website with Twitters developer site. (https://dev.twitter.com) you will then get your consumer key, consumer secret, access token and your access token secret. You then need to add them to the script. 30 | 31 | You should edit the Twitter ID in the function call above before using the function (it appears at the very bottom of the code snippet). 32 | 33 | You probably also want to edit the location where the twitter feed is cached – by default it is written to the root level of your domain. To change the location, modify the $cache_file variable, or pass the new location as a function parameter. 34 | 35 | Feel free to edit any of the other parameters to suit your needs. 36 | 37 | Notes 38 | ======================== 39 | 40 | Twitter feeds may contain UTF-8 characters. I have found that running PHP’s utf_decode method on tweets didn’t have the expected result, so my recommendation is to instead set the charset of your HTML page to UTF-8. Really we should all be doing this anyway. (http://www.w3.org/International/O-charset) 41 | 42 | Credits 43 | ======================== 44 | 45 | I was orginally using Pixel Acres script (http://f6design.com/journal/2010/10/07/display-recent-twitter-tweets-using-php/). But since Twitter has retired API v1.0, the script no longer worked because it didn't include authentication. I have now modified the script to include authentication using API v1.1. 46 | 47 | The hashtag/username parsing in my example is from Get Twitter Tweets (http://snipplr.com/view/16221/get-twitter-tweets/) by gripnrip (http://snipplr.com/users/gripnrip/). 48 | 49 | My RSS parsing is based on replies in the forum discussion "embedding twitter tweets" on the Boagworld website. (http://boagworld.com/forum/comments.php?DiscussionID=4639) 50 | 51 | The file caching is based on the AddedBytes article "Caching output in PHP". (http://www.addedbytes.com/articles/for-beginners/output-caching-for-beginners/) 52 | 53 | Authentication with Twitter uses twitteroauth. (https://github.com/abraham/twitteroauth) 54 | 55 | License 56 | ======================== 57 | 58 | The MIT License (MIT) 59 | 60 | Copyright (c) 2013 Andrew Biggart 61 | 62 | Permission is hereby granted, free of charge, to any person obtaining a copy 63 | of this software and associated documentation files (the "Software"), to deal 64 | in the Software without restriction, including without limitation the rights 65 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 66 | copies of the Software, and to permit persons to whom the Software is 67 | furnished to do so, subject to the following conditions: 68 | 69 | The above copyright notice and this permission notice shall be included in 70 | all copies or substantial portions of the Software. 71 | 72 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 73 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 74 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 75 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 76 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 77 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 78 | THE SOFTWARE. 79 | -------------------------------------------------------------------------------- /tweets.php: -------------------------------------------------------------------------------- 1 | ', 68 | $twitter_wrap_close = '', 69 | $tweet_wrap_open = '
  • ', 70 | $meta_wrap_open = '
    ', 71 | $meta_wrap_close = '', 72 | $tweet_wrap_close = '

  • ', 73 | $date_format = 'g:i A M jS', // Date formatting. (http://php.net/manual/en/function.date.php) 74 | $twitter_style_dates = true){ // Twitter style days. [about an hour ago] (Default : true) 75 | 76 | // Twitter keys (You'll need to visit https://dev.twitter.com and register to get these. 77 | $consumerkey = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; 78 | $consumersecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; 79 | $accesstoken = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; 80 | $accesstokensecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; 81 | 82 | // Seconds to cache feed (Default : 3 minutes). 83 | $cachetime = 60*3; 84 | 85 | // Time that the cache was last updtaed. 86 | $cache_file_created = ((file_exists($cache_file))) ? filemtime($cache_file) : 0; 87 | 88 | // A flag so we know if the feed was successfully parsed. 89 | $tweet_found = false; 90 | 91 | // Show cached version of tweets, if it's less than $cachetime. 92 | if (time() - $cachetime < $cache_file_created) { 93 | $tweet_found = true; 94 | // Display tweets from the cache. 95 | readfile($cache_file); 96 | } else { 97 | 98 | // Cache file not found, or old. Authenticae app. 99 | $connection = getConnectionWithAccessToken($consumerkey, $consumersecret, $accesstoken, $accesstokensecret); 100 | 101 | if($connection){ 102 | // Get the latest tweets from Twitter 103 | $get_tweets = $connection->get("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=".$twitter_user_id."&count=".$tweets_to_display."&include_rts=".$include_rts."&exclude_replies=".$ignore_replies); 104 | 105 | // Error check: Make sure there is at least one item. 106 | if (count($get_tweets)) { 107 | 108 | // Define tweet_count as zero 109 | $tweet_count = 0; 110 | 111 | // Start output buffering. 112 | ob_start(); 113 | 114 | // Open the twitter wrapping element. 115 | $twitter_html = $twitter_wrap_open; 116 | 117 | // Iterate over tweets. 118 | foreach($get_tweets as $tweet) { 119 | 120 | $tweet_found = true; 121 | $tweet_count++; 122 | $tweet_desc = $tweet->text; 123 | // Add hyperlink html tags to any urls, twitter ids or hashtags in the tweet. 124 | $tweet_desc = preg_replace("/((http)+(s)?:\/\/[^<>\s]+)/i", "\\0", $tweet_desc ); 125 | $tweet_desc = preg_replace("/[@]+([A-Za-z0-9-_]+)/", "\\0", $tweet_desc ); 126 | $tweet_desc = preg_replace("/[#]+([A-Za-z0-9-_]+)/", "\\0", $tweet_desc ); 127 | 128 | 129 | // replace t.co links with expanded link, if present 130 | $entities = $tweet->entities; 131 | if(!empty($entities->urls[0]->expanded_url)) { 132 | $tweet_desc = str_replace($entities->urls[0]->url, $entities->urls[0]->expanded_url, $tweet_desc); 133 | } 134 | $media_url = $entities->media[0]->media_url; 135 | if($media_url) { 136 | $img = ""; 137 | $twitter_html .= $img; 138 | } 139 | 140 | 141 | // Convert Tweet display time to a UNIX timestamp. Twitter timestamps are in UTC/GMT time. 142 | $tweet_time = strtotime($tweet->created_at); 143 | 144 | // Get Tweet ID 145 | $tweet_id = $tweet->id_str; 146 | if ($twitter_style_dates){ 147 | // Current UNIX timestamp. 148 | $current_time = time(); 149 | $time_diff = abs($current_time - $tweet_time); 150 | switch ($time_diff) 151 | { 152 | case ($time_diff < 60): 153 | $display_time = $time_diff.' seconds ago'; 154 | break; 155 | case ($time_diff >= 60 && $time_diff < 3600): 156 | $min = floor($time_diff/60); 157 | $display_time = $min.' minutes ago'; 158 | break; 159 | case ($time_diff >= 3600 && $time_diff < 86400): 160 | $hour = floor($time_diff/3600); 161 | $display_time = 'about '.$hour.' hour'; 162 | if ($hour > 1){ $display_time .= 's'; } 163 | $display_time .= ' ago'; 164 | break; 165 | default: 166 | $display_time = date($date_format,$tweet_time); 167 | break; 168 | } 169 | } else { 170 | $display_time = date($date_format,$tweet_time); 171 | } 172 | 173 | // Render the tweet. 174 | $twitter_html .= $tweet_wrap_open.html_entity_decode($tweet_desc).$meta_wrap_open.''.$display_time.''.$meta_wrap_close.$tweet_wrap_close; 175 | 176 | // If we have processed enough tweets, stop. 177 | if ($tweet_count >= $tweets_to_display){ 178 | break; 179 | } 180 | 181 | } 182 | 183 | // Close the twitter wrapping element. 184 | $twitter_html .= $twitter_wrap_close; 185 | echo $twitter_html; 186 | 187 | // Generate a new cache file. 188 | $file = fopen($cache_file, 'w'); 189 | 190 | // Save the contents of output buffer to the file, and flush the buffer. 191 | fwrite($file, ob_get_contents()); 192 | fclose($file); 193 | ob_end_flush(); 194 | 195 | } 196 | 197 | } 198 | 199 | } 200 | 201 | } 202 | 203 | // Display latest tweets. (Modify username to your Twitter handle) 204 | display_latest_tweets('andrew_biggart'); 205 | ?> 206 | -------------------------------------------------------------------------------- /tweets.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/tweets.txt -------------------------------------------------------------------------------- /twitteroauth/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/twitteroauth/.DS_Store -------------------------------------------------------------------------------- /twitteroauth/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | -------------------------------------------------------------------------------- /twitteroauth/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Abraham Williams - http://abrah.am - abraham@poseurte.ch 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /twitteroauth/README.md: -------------------------------------------------------------------------------- 1 | TwitterOAuth 2 | ------------ 3 | 4 | PHP library for working with Twitter's OAuth API. 5 | 6 | Flow Overview 7 | ============= 8 | 9 | 1. Build TwitterOAuth object using client credentials. 10 | 2. Request temporary credentials from Twitter. 11 | 3. Build authorize URL for Twitter. 12 | 4. Redirect user to authorize URL. 13 | 5. User authorizes access and returns from Twitter. 14 | 6. Rebuild TwitterOAuth object with client credentials and temporary credentials. 15 | 7. Get token credentials from Twitter. 16 | 8. Rebuild TwitterOAuth object with client credentials and token credentials. 17 | 9. Query Twitter API. 18 | 19 | Terminology 20 | =========== 21 | 22 | The terminology has changed since 0.1.x to better match the draft-hammer-oauth IETF 23 | RFC. You can read that at http://tools.ietf.org/html/draft-hammer-oauth. Some of the 24 | terms will differ from those Twitter uses as well. 25 | 26 | client credentials - Consumer key/secret you get when registering an app with Twitter. 27 | temporary credentials - Previously known as the request token. 28 | token credentials - Previously known as the access token. 29 | 30 | Parameters 31 | ========== 32 | 33 | There are a number of parameters you can modify after creating a TwitterOAuth object. 34 | 35 | Switch an existing TwitterOAuth install to use version 1.1 of the API. 36 | 37 | $connection->$host = "https://api.twitter.com/1.1/"; 38 | 39 | Custom useragent. 40 | 41 | $connection->useragent = 'Custom useragent string'; 42 | 43 | Verify Twitters SSL certificate. 44 | 45 | $connection->ssl_verifypeer = TRUE; 46 | 47 | There are several more you can find in TwitterOAuth.php. 48 | 49 | Extended flow using example code 50 | ================================ 51 | 52 | To use TwitterOAuth with the Twitter API you need *TwitterOAuth.php*, *OAuth.php* and 53 | client credentials. You can get client credentials by registering your application at 54 | [dev.twitter.com/apps](https://dev.twitter.com/apps). 55 | 56 | Users start out on connect.php which displays the "Sign in with Twitter" image hyperlinked 57 | to redirect.php. This button should be displayed on your homepage in your login section. The 58 | client credentials are saved in config.php as `CONSUMER_KEY` and `CONSUMER_SECRET`. You can 59 | save a static callback URL in the app settings page, in the config file or use a dynamic 60 | callback URL later in step 2. In example use https://example.com/callback.php. 61 | 62 | 1) When a user lands on redirect.php we build a new TwitterOAuth object using the client credentials. 63 | If you have your own configuration method feel free to use it instead of config.php. 64 | 65 | $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET); // Use config.php client credentials 66 | $connection = new TwitterOAuth('abc890', '123xyz'); 67 | 68 | 2) Using the built $connection object you will ask Twitter for temporary credentials. The `oauth_callback` value is required. 69 | 70 | $temporary_credentials = $connection->getRequestToken(OAUTH_CALLBACK); // Use config.php callback URL. 71 | 72 | 3) Now that we have temporary credentials the user has to go to Twitter and authorize the app 73 | to access and updates their data. You can also pass a second parameter of FALSE to not use [Sign 74 | in with Twitter](https://dev.twitter.com/docs/auth/sign-twitter). 75 | 76 | $redirect_url = $connection->getAuthorizeURL($temporary_credentials); // Use Sign in with Twitter 77 | $redirect_url = $connection->getAuthorizeURL($temporary_credentials, FALSE); 78 | 79 | 4) You will now have a Twitter URL that you must send the user to. 80 | 81 | https://api.twitter.com/oauth/authenticate?oauth_token=xyz123 82 | 83 | 5) The user is now on twitter.com and may have to login. Once authenticated with Twitter they will 84 | will either have to click on allow/deny, or will be automatically redirected back to the callback. 85 | 86 | 6) Now that the user has returned to callback.php and allowed access we need to build a new 87 | TwitterOAuth object using the temporary credentials. 88 | 89 | $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], 90 | $_SESSION['oauth_token_secret']); 91 | 92 | 7) Now we ask Twitter for long lasting token credentials. These are specific to the application 93 | and user and will act like password to make future requests. Normally the token credentials would 94 | get saved in your database but for this example we are just using sessions. 95 | 96 | $token_credentials = $connection->getAccessToken($_REQUEST['oauth_verifier']); 97 | 98 | 8) With the token credentials we build a new TwitterOAuth object. 99 | 100 | $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $token_credentials['oauth_token'], 101 | $token_credentials['oauth_token_secret']); 102 | 103 | 9) And finally we can make requests authenticated as the user. You can GET, POST, and DELETE API 104 | methods. Directly copy the path from the API documentation and add an array of any parameter 105 | you wish to include for the API method such as curser or in_reply_to_status_id. 106 | 107 | $account = $connection->get('account/verify_credentials'); 108 | $status = $connection->post('statuses/update', array('status' => 'Text of status here', 'in_reply_to_status_id' => 123456)); 109 | $status = $connection->delete('statuses/destroy/12345'); 110 | 111 | Contributors 112 | ============ 113 | 114 | * [Abraham Williams](https://twitter.com/abraham) - Main developer, current maintainer. 115 | -------------------------------------------------------------------------------- /twitteroauth/_notes/dwsync.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /twitteroauth/callback.php: -------------------------------------------------------------------------------- 1 | getAccessToken($_REQUEST['oauth_verifier']); 24 | 25 | /* Save the access tokens. Normally these would be saved in a database for future use. */ 26 | $_SESSION['access_token'] = $access_token; 27 | 28 | /* Remove no longer needed request tokens */ 29 | unset($_SESSION['oauth_token']); 30 | unset($_SESSION['oauth_token_secret']); 31 | 32 | /* If HTTP response is 200 continue otherwise send to connect page to retry */ 33 | if (200 == $connection->http_code) { 34 | /* The user has been verified and the access tokens can be saved for future use */ 35 | $_SESSION['status'] = 'verified'; 36 | header('Location: ./index.php'); 37 | } else { 38 | /* Save HTTP status for error dialog on connnect page.*/ 39 | header('Location: ./clearsessions.php'); 40 | } 41 | -------------------------------------------------------------------------------- /twitteroauth/clearsessions.php: -------------------------------------------------------------------------------- 1 | dev.twitter.com/apps'; 14 | exit; 15 | } 16 | 17 | /* Build an image link to start the redirect process. */ 18 | $content = 'Sign in with Twitter'; 19 | 20 | /* Include HTML to display on the page. */ 21 | include('html.inc'); 22 | -------------------------------------------------------------------------------- /twitteroauth/html.inc: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Twitter OAuth in PHP 6 | 7 | 11 | 12 | 13 |
    14 |

    Welcome to a Twitter OAuth PHP example.

    15 | 16 |

    This site is a basic showcase of Twitters OAuth authentication method. If you are having issues try clearing your session.

    17 | 18 |

    19 | Links: 20 | Source Code & 21 | Documentation | 22 | Contact @abraham 23 |

    24 |
    25 | 26 | 27 | 28 |
    29 | 30 | '.$status_text.''; ?> 31 | 32 |

    33 |

    34 |         
    35 |       
    36 |

    37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /twitteroauth/images/_notes/dwsync.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /twitteroauth/images/darker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/twitteroauth/images/darker.png -------------------------------------------------------------------------------- /twitteroauth/images/lighter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/twitteroauth/images/lighter.png -------------------------------------------------------------------------------- /twitteroauth/index.php: -------------------------------------------------------------------------------- 1 | get('account/verify_credentials'); 24 | 25 | /* Some example calls */ 26 | //$connection->get('users/show', array('screen_name' => 'abraham')); 27 | //$connection->post('statuses/update', array('status' => date(DATE_RFC822))); 28 | //$connection->post('statuses/destroy', array('id' => 5437877770)); 29 | //$connection->post('friendships/create', array('id' => 9436992)); 30 | //$connection->post('friendships/destroy', array('id' => 9436992)); 31 | 32 | /* Include HTML to display on the page */ 33 | include('html.inc'); 34 | -------------------------------------------------------------------------------- /twitteroauth/redirect.php: -------------------------------------------------------------------------------- 1 | getRequestToken(OAUTH_CALLBACK); 13 | 14 | /* Save temporary credentials to session. */ 15 | $_SESSION['oauth_token'] = $token = $request_token['oauth_token']; 16 | $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; 17 | 18 | /* If last connection failed don't display authorization link. */ 19 | switch ($connection->http_code) { 20 | case 200: 21 | /* Build authorize URL and redirect user to Twitter. */ 22 | $url = $connection->getAuthorizeURL($token); 23 | header('Location: ' . $url); 24 | break; 25 | default: 26 | /* Show notification if something went wrong. */ 27 | echo 'Could not connect to Twitter. Refresh the page or try again later.'; 28 | } 29 | -------------------------------------------------------------------------------- /twitteroauth/test.php: -------------------------------------------------------------------------------- 1 | get('account/rate_limit_status'); 24 | echo "Current API hits remaining: {$content->remaining_hits}."; 25 | 26 | /* Get logged in user to help with tests. */ 27 | $user = $connection->get('account/verify_credentials'); 28 | 29 | $active = FALSE; 30 | if (empty($active) || empty($_GET['confirmed']) || $_GET['confirmed'] !== 'TRUE') { 31 | echo '

    Warning! This page will make many requests to Twitter.

    '; 32 | echo '

    Performing these test might max out your rate limit.

    '; 33 | echo '

    Statuses/DMs will be created and deleted. Accounts will be un/followed.

    '; 34 | echo '

    Profile information/design will be changed.

    '; 35 | echo '

    USE A DEV ACCOUNT!

    '; 36 | echo '

    Before use you must set $active = TRUE in test.php

    '; 37 | echo 'Continue or go back.'; 38 | exit; 39 | } 40 | 41 | function twitteroauth_row($method, $response, $http_code, $parameters = '') { 42 | echo ''; 43 | echo "{$method}"; 44 | switch ($http_code) { 45 | case '200': 46 | case '304': 47 | $color = 'green'; 48 | break; 49 | case '400': 50 | case '401': 51 | case '403': 52 | case '404': 53 | case '406': 54 | $color = 'red'; 55 | break; 56 | case '500': 57 | case '502': 58 | case '503': 59 | $color = 'orange'; 60 | break; 61 | default: 62 | $color = 'grey'; 63 | } 64 | echo "{$http_code}"; 65 | if (!is_string($response)) { 66 | $response = print_r($response, TRUE); 67 | } 68 | if (!is_string($parameters)) { 69 | $parameters = print_r($parameters, TRUE); 70 | } 71 | echo '', strlen($response), ''; 72 | echo '', $parameters, ''; 73 | echo ''; 74 | echo '', substr($response, 0, 400), '...'; 75 | echo ''; 76 | 77 | } 78 | 79 | function twitteroauth_header($header) { 80 | echo '', $header, ''; 81 | } 82 | 83 | /* Start table. */ 84 | echo '

    '; 85 | echo ''; 86 | echo ''; 87 | echo ''; 88 | echo ''; 89 | echo ''; 90 | echo ''; 91 | echo ''; 92 | echo ''; 93 | echo ''; 94 | 95 | /** 96 | * Help Methods. 97 | */ 98 | twitteroauth_header('Help Methods'); 99 | 100 | /* help/test */ 101 | twitteroauth_row('help/test', $connection->get('help/test'), $connection->http_code); 102 | 103 | 104 | /** 105 | * Timeline Methods. 106 | */ 107 | twitteroauth_header('Timeline Methods'); 108 | 109 | /* statuses/public_timeline */ 110 | twitteroauth_row('statuses/public_timeline', $connection->get('statuses/public_timeline'), $connection->http_code); 111 | 112 | /* statuses/public_timeline */ 113 | twitteroauth_row('statuses/home_timeline', $connection->get('statuses/home_timeline'), $connection->http_code); 114 | 115 | /* statuses/friends_timeline */ 116 | twitteroauth_row('statuses/friends_timeline', $connection->get('statuses/friends_timeline'), $connection->http_code); 117 | 118 | /* statuses/user_timeline */ 119 | twitteroauth_row('statuses/user_timeline', $connection->get('statuses/user_timeline'), $connection->http_code); 120 | 121 | /* statuses/mentions */ 122 | twitteroauth_row('statuses/mentions', $connection->get('statuses/mentions'), $connection->http_code); 123 | 124 | /* statuses/retweeted_by_me */ 125 | twitteroauth_row('statuses/retweeted_by_me', $connection->get('statuses/retweeted_by_me'), $connection->http_code); 126 | 127 | /* statuses/retweeted_to_me */ 128 | twitteroauth_row('statuses/retweeted_to_me', $connection->get('statuses/retweeted_to_me'), $connection->http_code); 129 | 130 | /* statuses/retweets_of_me */ 131 | twitteroauth_row('statuses/retweets_of_me', $connection->get('statuses/retweets_of_me'), $connection->http_code); 132 | 133 | 134 | /** 135 | * Status Methods. 136 | */ 137 | twitteroauth_header('Status Methods'); 138 | 139 | /* statuses/update */ 140 | date_default_timezone_set('GMT'); 141 | $parameters = array('status' => date(DATE_RFC822)); 142 | $status = $connection->post('statuses/update', $parameters); 143 | twitteroauth_row('statuses/update', $status, $connection->http_code, $parameters); 144 | 145 | /* statuses/show */ 146 | $method = "statuses/show/{$status->id}"; 147 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 148 | 149 | /* statuses/destroy */ 150 | $method = "statuses/destroy/{$status->id}"; 151 | twitteroauth_row($method, $connection->delete($method), $connection->http_code); 152 | 153 | /* statuses/retweet */ 154 | $method = 'statuses/retweet/6242973112'; 155 | twitteroauth_row($method, $connection->post($method), $connection->http_code); 156 | 157 | /* statuses/retweets */ 158 | $method = 'statuses/retweets/6242973112'; 159 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 160 | 161 | 162 | /** 163 | * User Methods. 164 | */ 165 | twitteroauth_header('User Methods'); 166 | 167 | /* users/show */ 168 | $method = 'users/show/27831060'; 169 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 170 | 171 | /* users/search */ 172 | $parameters = array('q' => 'oauth'); 173 | twitteroauth_row('users/search', $connection->get('users/search', $parameters), $connection->http_code, $parameters); 174 | 175 | /* statuses/friends */ 176 | $method = 'statuses/friends/27831060'; 177 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 178 | 179 | /* statuses/followers */ 180 | $method = 'statuses/followers/27831060'; 181 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 182 | 183 | 184 | /** 185 | * List Methods. 186 | */ 187 | twitteroauth_header('List Methods'); 188 | 189 | /* POST lists */ 190 | $method = "{$user->screen_name}/lists"; 191 | $parameters = array('name' => 'Twitter OAuth'); 192 | $list = $connection->post($method, $parameters); 193 | twitteroauth_row($method, $list, $connection->http_code, $parameters); 194 | 195 | /* POST lists id */ 196 | $method = "{$user->screen_name}/lists/{$list->id}"; 197 | $parameters = array('name' => 'Twitter OAuth List 2'); 198 | $list = $connection->post($method, $parameters); 199 | twitteroauth_row($method, $list, $connection->http_code, $parameters); 200 | 201 | /* GET lists */ 202 | $method = "{$user->screen_name}/lists"; 203 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 204 | 205 | /* GET lists id */ 206 | $method = "{$user->screen_name}/lists/{$list->id}"; 207 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 208 | 209 | /* DELETE list */ 210 | $method = "{$user->screen_name}/lists/{$list->id}"; 211 | twitteroauth_row($method, $connection->delete($method), $connection->http_code); 212 | 213 | /* GET list statuses */ 214 | $method = "oauthlib/lists/4097351/statuses"; 215 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 216 | 217 | /* GET list members */ 218 | $method = "{$user->screen_name}/lists/memberships"; 219 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 220 | 221 | 222 | /* GET list subscriptions */ 223 | $method = "{$user->screen_name}/lists/subscriptions"; 224 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 225 | 226 | 227 | /** 228 | * List Members Methods. 229 | */ 230 | twitteroauth_header('List Members Methods'); 231 | 232 | /* Create temp list for list member methods. */ 233 | $method = "{$user->screen_name}/lists"; 234 | $parameters = array('name' => 'Twitter OAuth Temp'); 235 | $list = $connection->post($method, $parameters); 236 | 237 | 238 | /* POST list members */ 239 | $parameters = array('id' => 27831060); 240 | $method = "{$user->screen_name}/{$list->id}/members"; 241 | twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); 242 | 243 | /* GET list members */ 244 | $method = "{$user->screen_name}/{$list->id}/members"; 245 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 246 | 247 | /* GET list members id */ 248 | $method = "{$user->screen_name}/{$list->id}/members/27831060"; 249 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 250 | 251 | /* DELETE list members */ 252 | $parameters = array('id' => 27831060); 253 | $method = "{$user->screen_name}/{$list->id}/members"; 254 | twitteroauth_row($method, $connection->delete($method, $parameters), $connection->http_code, $parameters); 255 | 256 | /* Delete the temp list */ 257 | $method = "{$user->screen_name}/lists/{$list->id}"; 258 | $connection->delete($method); 259 | 260 | 261 | /** 262 | * List Subscribers Methods. 263 | */ 264 | twitteroauth_header('List Subscribers Methods'); 265 | 266 | 267 | /* POST list subscribers */ 268 | $method = 'oauthlib/test-list/subscribers'; 269 | twitteroauth_row($method, $connection->post($method), $connection->http_code); 270 | 271 | /* GET list subscribers */ 272 | $method = 'oauthlib/test-list/subscribers'; 273 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 274 | 275 | /* GET list subscribers id */ 276 | $method = "oauthlib/test-list/subscribers/{$user->id}"; 277 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 278 | 279 | /* DELETE list subscribers */ 280 | $method = 'oauthlib/test-list/subscribers'; 281 | twitteroauth_row($method, $connection->delete($method), $connection->http_code); 282 | 283 | 284 | /** 285 | * Direct Message Methdos. 286 | */ 287 | twitteroauth_header('Direct Message Methods'); 288 | 289 | /* direct_messages/new */ 290 | $parameters = array('user_id' => $user->id, 'text' => 'Testing out @oauthlib code'); 291 | $method = 'direct_messages/new'; 292 | $dm = $connection->post($method, $parameters); 293 | twitteroauth_row($method, $dm, $connection->http_code, $parameters); 294 | 295 | /* direct_messages */ 296 | $method = 'direct_messages'; 297 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 298 | 299 | /* direct_messages/sent */ 300 | $method = 'direct_messages/sent'; 301 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 302 | 303 | /* direct_messages/sent */ 304 | $method = "direct_messages/destroy/{$dm->id}"; 305 | twitteroauth_row($method, $connection->delete($method), $connection->http_code); 306 | 307 | 308 | /** 309 | * Friendships Methods. 310 | */ 311 | twitteroauth_header('Friendships Methods'); 312 | 313 | /* friendships/create */ 314 | $method = 'friendships/create/93915746'; 315 | twitteroauth_row($method, $connection->post($method), $connection->http_code); 316 | 317 | /* friendships/show */ 318 | $parameters = array('target_id' => 27831060); 319 | $method = 'friendships/show'; 320 | twitteroauth_row($method, $connection->get($method, $parameters), $connection->http_code, $parameters); 321 | 322 | /* friendships/destroy */ 323 | $method = 'friendships/destroy/93915746'; 324 | twitteroauth_row($method, $connection->post($method), $connection->http_code); 325 | 326 | 327 | /** 328 | * Social Graph Methods. 329 | */ 330 | twitteroauth_header('Social Graph Methods'); 331 | 332 | /* friends/ids */ 333 | $method = 'friends/ids'; 334 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 335 | 336 | /* friends/ids */ 337 | $method = 'friends/ids'; 338 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 339 | 340 | 341 | /** 342 | * Account Methods. 343 | */ 344 | twitteroauth_header('Account Methods'); 345 | 346 | /* account/verify_credentials */ 347 | $method = 'account/verify_credentials'; 348 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 349 | 350 | /* account/rate_limit_status */ 351 | $method = 'account/rate_limit_status'; 352 | twitteroauth_row($method, $connection->get($method), $connection->http_code); 353 | 354 | /* account/update_profile_colors */ 355 | $parameters = array('profile_background_color' => 'fff'); 356 | $method = 'account/update_profile_colors'; 357 | twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); 358 | 359 | /* account/update_profile */ 360 | $parameters = array('location' => 'Teh internets'); 361 | $method = 'account/update_profile'; 362 | twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); 363 | 364 | 365 | 366 | 367 | /** 368 | * OAuth Methods. 369 | */ 370 | twitteroauth_header('OAuth Methods'); 371 | 372 | /* oauth/request_token */ 373 | $oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET); 374 | twitteroauth_row('oauth/reqeust_token', $oauth->getRequestToken(), $oauth->http_code); 375 | -------------------------------------------------------------------------------- /twitteroauth/twitteroauth/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewbiggart/latest-tweets-php-o-auth/03a0a2ddcc72ff174fced2c6b8240416f4118e42/twitteroauth/twitteroauth/.DS_Store -------------------------------------------------------------------------------- /twitteroauth/twitteroauth/OAuth.php: -------------------------------------------------------------------------------- 1 | key = $key; 16 | $this->secret = $secret; 17 | $this->callback_url = $callback_url; 18 | } 19 | 20 | function __toString() { 21 | return "OAuthConsumer[key=$this->key,secret=$this->secret]"; 22 | } 23 | } 24 | 25 | class OAuthToken { 26 | // access tokens and request tokens 27 | public $key; 28 | public $secret; 29 | 30 | /** 31 | * key = the token 32 | * secret = the token secret 33 | */ 34 | function __construct($key, $secret) { 35 | $this->key = $key; 36 | $this->secret = $secret; 37 | } 38 | 39 | /** 40 | * generates the basic string serialization of a token that a server 41 | * would respond to request_token and access_token calls with 42 | */ 43 | function to_string() { 44 | return "oauth_token=" . 45 | OAuthUtil::urlencode_rfc3986($this->key) . 46 | "&oauth_token_secret=" . 47 | OAuthUtil::urlencode_rfc3986($this->secret); 48 | } 49 | 50 | function __toString() { 51 | return $this->to_string(); 52 | } 53 | } 54 | 55 | /** 56 | * A class for implementing a Signature Method 57 | * See section 9 ("Signing Requests") in the spec 58 | */ 59 | abstract class OAuthSignatureMethod { 60 | /** 61 | * Needs to return the name of the Signature Method (ie HMAC-SHA1) 62 | * @return string 63 | */ 64 | abstract public function get_name(); 65 | 66 | /** 67 | * Build up the signature 68 | * NOTE: The output of this function MUST NOT be urlencoded. 69 | * the encoding is handled in OAuthRequest when the final 70 | * request is serialized 71 | * @param OAuthRequest $request 72 | * @param OAuthConsumer $consumer 73 | * @param OAuthToken $token 74 | * @return string 75 | */ 76 | abstract public function build_signature($request, $consumer, $token); 77 | 78 | /** 79 | * Verifies that a given signature is correct 80 | * @param OAuthRequest $request 81 | * @param OAuthConsumer $consumer 82 | * @param OAuthToken $token 83 | * @param string $signature 84 | * @return bool 85 | */ 86 | public function check_signature($request, $consumer, $token, $signature) { 87 | $built = $this->build_signature($request, $consumer, $token); 88 | return $built == $signature; 89 | } 90 | } 91 | 92 | /** 93 | * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] 94 | * where the Signature Base String is the text and the key is the concatenated values (each first 95 | * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' 96 | * character (ASCII code 38) even if empty. 97 | * - Chapter 9.2 ("HMAC-SHA1") 98 | */ 99 | class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { 100 | function get_name() { 101 | return "HMAC-SHA1"; 102 | } 103 | 104 | public function build_signature($request, $consumer, $token) { 105 | $base_string = $request->get_signature_base_string(); 106 | $request->base_string = $base_string; 107 | 108 | $key_parts = array( 109 | $consumer->secret, 110 | ($token) ? $token->secret : "" 111 | ); 112 | 113 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 114 | $key = implode('&', $key_parts); 115 | 116 | return base64_encode(hash_hmac('sha1', $base_string, $key, true)); 117 | } 118 | } 119 | 120 | /** 121 | * The PLAINTEXT method does not provide any security protection and SHOULD only be used 122 | * over a secure channel such as HTTPS. It does not use the Signature Base String. 123 | * - Chapter 9.4 ("PLAINTEXT") 124 | */ 125 | class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { 126 | public function get_name() { 127 | return "PLAINTEXT"; 128 | } 129 | 130 | /** 131 | * oauth_signature is set to the concatenated encoded values of the Consumer Secret and 132 | * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is 133 | * empty. The result MUST be encoded again. 134 | * - Chapter 9.4.1 ("Generating Signatures") 135 | * 136 | * Please note that the second encoding MUST NOT happen in the SignatureMethod, as 137 | * OAuthRequest handles this! 138 | */ 139 | public function build_signature($request, $consumer, $token) { 140 | $key_parts = array( 141 | $consumer->secret, 142 | ($token) ? $token->secret : "" 143 | ); 144 | 145 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 146 | $key = implode('&', $key_parts); 147 | $request->base_string = $key; 148 | 149 | return $key; 150 | } 151 | } 152 | 153 | /** 154 | * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in 155 | * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for 156 | * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a 157 | * verified way to the Service Provider, in a manner which is beyond the scope of this 158 | * specification. 159 | * - Chapter 9.3 ("RSA-SHA1") 160 | */ 161 | abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { 162 | public function get_name() { 163 | return "RSA-SHA1"; 164 | } 165 | 166 | // Up to the SP to implement this lookup of keys. Possible ideas are: 167 | // (1) do a lookup in a table of trusted certs keyed off of consumer 168 | // (2) fetch via http using a url provided by the requester 169 | // (3) some sort of specific discovery code based on request 170 | // 171 | // Either way should return a string representation of the certificate 172 | protected abstract function fetch_public_cert(&$request); 173 | 174 | // Up to the SP to implement this lookup of keys. Possible ideas are: 175 | // (1) do a lookup in a table of trusted certs keyed off of consumer 176 | // 177 | // Either way should return a string representation of the certificate 178 | protected abstract function fetch_private_cert(&$request); 179 | 180 | public function build_signature($request, $consumer, $token) { 181 | $base_string = $request->get_signature_base_string(); 182 | $request->base_string = $base_string; 183 | 184 | // Fetch the private key cert based on the request 185 | $cert = $this->fetch_private_cert($request); 186 | 187 | // Pull the private key ID from the certificate 188 | $privatekeyid = openssl_get_privatekey($cert); 189 | 190 | // Sign using the key 191 | $ok = openssl_sign($base_string, $signature, $privatekeyid); 192 | 193 | // Release the key resource 194 | openssl_free_key($privatekeyid); 195 | 196 | return base64_encode($signature); 197 | } 198 | 199 | public function check_signature($request, $consumer, $token, $signature) { 200 | $decoded_sig = base64_decode($signature); 201 | 202 | $base_string = $request->get_signature_base_string(); 203 | 204 | // Fetch the public key cert based on the request 205 | $cert = $this->fetch_public_cert($request); 206 | 207 | // Pull the public key ID from the certificate 208 | $publickeyid = openssl_get_publickey($cert); 209 | 210 | // Check the computed signature against the one passed in the query 211 | $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); 212 | 213 | // Release the key resource 214 | openssl_free_key($publickeyid); 215 | 216 | return $ok == 1; 217 | } 218 | } 219 | 220 | class OAuthRequest { 221 | private $parameters; 222 | private $http_method; 223 | private $http_url; 224 | // for debug purposes 225 | public $base_string; 226 | public static $version = '1.0'; 227 | public static $POST_INPUT = 'php://input'; 228 | 229 | function __construct($http_method, $http_url, $parameters=NULL) { 230 | @$parameters or $parameters = array(); 231 | $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); 232 | $this->parameters = $parameters; 233 | $this->http_method = $http_method; 234 | $this->http_url = $http_url; 235 | } 236 | 237 | 238 | /** 239 | * attempt to build up a request from what was passed to the server 240 | */ 241 | public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { 242 | $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") 243 | ? 'http' 244 | : 'https'; 245 | @$http_url or $http_url = $scheme . 246 | '://' . $_SERVER['HTTP_HOST'] . 247 | ':' . 248 | $_SERVER['SERVER_PORT'] . 249 | $_SERVER['REQUEST_URI']; 250 | @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; 251 | 252 | // We weren't handed any parameters, so let's find the ones relevant to 253 | // this request. 254 | // If you run XML-RPC or similar you should use this to provide your own 255 | // parsed parameter-list 256 | if (!$parameters) { 257 | // Find request headers 258 | $request_headers = OAuthUtil::get_headers(); 259 | 260 | // Parse the query-string to find GET parameters 261 | $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); 262 | 263 | // It's a POST request of the proper content-type, so parse POST 264 | // parameters and add those overriding any duplicates from GET 265 | if ($http_method == "POST" 266 | && @strstr($request_headers["Content-Type"], 267 | "application/x-www-form-urlencoded") 268 | ) { 269 | $post_data = OAuthUtil::parse_parameters( 270 | file_get_contents(self::$POST_INPUT) 271 | ); 272 | $parameters = array_merge($parameters, $post_data); 273 | } 274 | 275 | // We have a Authorization-header with OAuth data. Parse the header 276 | // and add those overriding any duplicates from GET or POST 277 | if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { 278 | $header_parameters = OAuthUtil::split_header( 279 | $request_headers['Authorization'] 280 | ); 281 | $parameters = array_merge($parameters, $header_parameters); 282 | } 283 | 284 | } 285 | 286 | return new OAuthRequest($http_method, $http_url, $parameters); 287 | } 288 | 289 | /** 290 | * pretty much a helper function to set up the request 291 | */ 292 | public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { 293 | @$parameters or $parameters = array(); 294 | $defaults = array("oauth_version" => OAuthRequest::$version, 295 | "oauth_nonce" => OAuthRequest::generate_nonce(), 296 | "oauth_timestamp" => OAuthRequest::generate_timestamp(), 297 | "oauth_consumer_key" => $consumer->key); 298 | if ($token) 299 | $defaults['oauth_token'] = $token->key; 300 | 301 | $parameters = array_merge($defaults, $parameters); 302 | 303 | return new OAuthRequest($http_method, $http_url, $parameters); 304 | } 305 | 306 | public function set_parameter($name, $value, $allow_duplicates = true) { 307 | if ($allow_duplicates && isset($this->parameters[$name])) { 308 | // We have already added parameter(s) with this name, so add to the list 309 | if (is_scalar($this->parameters[$name])) { 310 | // This is the first duplicate, so transform scalar (string) 311 | // into an array so we can add the duplicates 312 | $this->parameters[$name] = array($this->parameters[$name]); 313 | } 314 | 315 | $this->parameters[$name][] = $value; 316 | } else { 317 | $this->parameters[$name] = $value; 318 | } 319 | } 320 | 321 | public function get_parameter($name) { 322 | return isset($this->parameters[$name]) ? $this->parameters[$name] : null; 323 | } 324 | 325 | public function get_parameters() { 326 | return $this->parameters; 327 | } 328 | 329 | public function unset_parameter($name) { 330 | unset($this->parameters[$name]); 331 | } 332 | 333 | /** 334 | * The request parameters, sorted and concatenated into a normalized string. 335 | * @return string 336 | */ 337 | public function get_signable_parameters() { 338 | // Grab all parameters 339 | $params = $this->parameters; 340 | 341 | // Remove oauth_signature if present 342 | // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 343 | if (isset($params['oauth_signature'])) { 344 | unset($params['oauth_signature']); 345 | } 346 | 347 | return OAuthUtil::build_http_query($params); 348 | } 349 | 350 | /** 351 | * Returns the base string of this request 352 | * 353 | * The base string defined as the method, the url 354 | * and the parameters (normalized), each urlencoded 355 | * and the concated with &. 356 | */ 357 | public function get_signature_base_string() { 358 | $parts = array( 359 | $this->get_normalized_http_method(), 360 | $this->get_normalized_http_url(), 361 | $this->get_signable_parameters() 362 | ); 363 | 364 | $parts = OAuthUtil::urlencode_rfc3986($parts); 365 | 366 | return implode('&', $parts); 367 | } 368 | 369 | /** 370 | * just uppercases the http method 371 | */ 372 | public function get_normalized_http_method() { 373 | return strtoupper($this->http_method); 374 | } 375 | 376 | /** 377 | * parses the url and rebuilds it to be 378 | * scheme://host/path 379 | */ 380 | public function get_normalized_http_url() { 381 | $parts = parse_url($this->http_url); 382 | 383 | $port = @$parts['port']; 384 | $scheme = $parts['scheme']; 385 | $host = $parts['host']; 386 | $path = @$parts['path']; 387 | 388 | $port or $port = ($scheme == 'https') ? '443' : '80'; 389 | 390 | if (($scheme == 'https' && $port != '443') 391 | || ($scheme == 'http' && $port != '80')) { 392 | $host = "$host:$port"; 393 | } 394 | return "$scheme://$host$path"; 395 | } 396 | 397 | /** 398 | * builds a url usable for a GET request 399 | */ 400 | public function to_url() { 401 | $post_data = $this->to_postdata(); 402 | $out = $this->get_normalized_http_url(); 403 | if ($post_data) { 404 | $out .= '?'.$post_data; 405 | } 406 | return $out; 407 | } 408 | 409 | /** 410 | * builds the data one would send in a POST request 411 | */ 412 | public function to_postdata() { 413 | return OAuthUtil::build_http_query($this->parameters); 414 | } 415 | 416 | /** 417 | * builds the Authorization: header 418 | */ 419 | public function to_header($realm=null) { 420 | $first = true; 421 | if($realm) { 422 | $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; 423 | $first = false; 424 | } else 425 | $out = 'Authorization: OAuth'; 426 | 427 | $total = array(); 428 | foreach ($this->parameters as $k => $v) { 429 | if (substr($k, 0, 5) != "oauth") continue; 430 | if (is_array($v)) { 431 | throw new OAuthException('Arrays not supported in headers'); 432 | } 433 | $out .= ($first) ? ' ' : ','; 434 | $out .= OAuthUtil::urlencode_rfc3986($k) . 435 | '="' . 436 | OAuthUtil::urlencode_rfc3986($v) . 437 | '"'; 438 | $first = false; 439 | } 440 | return $out; 441 | } 442 | 443 | public function __toString() { 444 | return $this->to_url(); 445 | } 446 | 447 | 448 | public function sign_request($signature_method, $consumer, $token) { 449 | $this->set_parameter( 450 | "oauth_signature_method", 451 | $signature_method->get_name(), 452 | false 453 | ); 454 | $signature = $this->build_signature($signature_method, $consumer, $token); 455 | $this->set_parameter("oauth_signature", $signature, false); 456 | } 457 | 458 | public function build_signature($signature_method, $consumer, $token) { 459 | $signature = $signature_method->build_signature($this, $consumer, $token); 460 | return $signature; 461 | } 462 | 463 | /** 464 | * util function: current timestamp 465 | */ 466 | private static function generate_timestamp() { 467 | return time(); 468 | } 469 | 470 | /** 471 | * util function: current nonce 472 | */ 473 | private static function generate_nonce() { 474 | $mt = microtime(); 475 | $rand = mt_rand(); 476 | 477 | return md5($mt . $rand); // md5s look nicer than numbers 478 | } 479 | } 480 | 481 | class OAuthServer { 482 | protected $timestamp_threshold = 300; // in seconds, five minutes 483 | protected $version = '1.0'; // hi blaine 484 | protected $signature_methods = array(); 485 | 486 | protected $data_store; 487 | 488 | function __construct($data_store) { 489 | $this->data_store = $data_store; 490 | } 491 | 492 | public function add_signature_method($signature_method) { 493 | $this->signature_methods[$signature_method->get_name()] = 494 | $signature_method; 495 | } 496 | 497 | // high level functions 498 | 499 | /** 500 | * process a request_token request 501 | * returns the request token on success 502 | */ 503 | public function fetch_request_token(&$request) { 504 | $this->get_version($request); 505 | 506 | $consumer = $this->get_consumer($request); 507 | 508 | // no token required for the initial token request 509 | $token = NULL; 510 | 511 | $this->check_signature($request, $consumer, $token); 512 | 513 | // Rev A change 514 | $callback = $request->get_parameter('oauth_callback'); 515 | $new_token = $this->data_store->new_request_token($consumer, $callback); 516 | 517 | return $new_token; 518 | } 519 | 520 | /** 521 | * process an access_token request 522 | * returns the access token on success 523 | */ 524 | public function fetch_access_token(&$request) { 525 | $this->get_version($request); 526 | 527 | $consumer = $this->get_consumer($request); 528 | 529 | // requires authorized request token 530 | $token = $this->get_token($request, $consumer, "request"); 531 | 532 | $this->check_signature($request, $consumer, $token); 533 | 534 | // Rev A change 535 | $verifier = $request->get_parameter('oauth_verifier'); 536 | $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); 537 | 538 | return $new_token; 539 | } 540 | 541 | /** 542 | * verify an api call, checks all the parameters 543 | */ 544 | public function verify_request(&$request) { 545 | $this->get_version($request); 546 | $consumer = $this->get_consumer($request); 547 | $token = $this->get_token($request, $consumer, "access"); 548 | $this->check_signature($request, $consumer, $token); 549 | return array($consumer, $token); 550 | } 551 | 552 | // Internals from here 553 | /** 554 | * version 1 555 | */ 556 | private function get_version(&$request) { 557 | $version = $request->get_parameter("oauth_version"); 558 | if (!$version) { 559 | // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. 560 | // Chapter 7.0 ("Accessing Protected Ressources") 561 | $version = '1.0'; 562 | } 563 | if ($version !== $this->version) { 564 | throw new OAuthException("OAuth version '$version' not supported"); 565 | } 566 | return $version; 567 | } 568 | 569 | /** 570 | * figure out the signature with some defaults 571 | */ 572 | private function get_signature_method(&$request) { 573 | $signature_method = 574 | @$request->get_parameter("oauth_signature_method"); 575 | 576 | if (!$signature_method) { 577 | // According to chapter 7 ("Accessing Protected Ressources") the signature-method 578 | // parameter is required, and we can't just fallback to PLAINTEXT 579 | throw new OAuthException('No signature method parameter. This parameter is required'); 580 | } 581 | 582 | if (!in_array($signature_method, 583 | array_keys($this->signature_methods))) { 584 | throw new OAuthException( 585 | "Signature method '$signature_method' not supported " . 586 | "try one of the following: " . 587 | implode(", ", array_keys($this->signature_methods)) 588 | ); 589 | } 590 | return $this->signature_methods[$signature_method]; 591 | } 592 | 593 | /** 594 | * try to find the consumer for the provided request's consumer key 595 | */ 596 | private function get_consumer(&$request) { 597 | $consumer_key = @$request->get_parameter("oauth_consumer_key"); 598 | if (!$consumer_key) { 599 | throw new OAuthException("Invalid consumer key"); 600 | } 601 | 602 | $consumer = $this->data_store->lookup_consumer($consumer_key); 603 | if (!$consumer) { 604 | throw new OAuthException("Invalid consumer"); 605 | } 606 | 607 | return $consumer; 608 | } 609 | 610 | /** 611 | * try to find the token for the provided request's token key 612 | */ 613 | private function get_token(&$request, $consumer, $token_type="access") { 614 | $token_field = @$request->get_parameter('oauth_token'); 615 | $token = $this->data_store->lookup_token( 616 | $consumer, $token_type, $token_field 617 | ); 618 | if (!$token) { 619 | throw new OAuthException("Invalid $token_type token: $token_field"); 620 | } 621 | return $token; 622 | } 623 | 624 | /** 625 | * all-in-one function to check the signature on a request 626 | * should guess the signature method appropriately 627 | */ 628 | private function check_signature(&$request, $consumer, $token) { 629 | // this should probably be in a different method 630 | $timestamp = @$request->get_parameter('oauth_timestamp'); 631 | $nonce = @$request->get_parameter('oauth_nonce'); 632 | 633 | $this->check_timestamp($timestamp); 634 | $this->check_nonce($consumer, $token, $nonce, $timestamp); 635 | 636 | $signature_method = $this->get_signature_method($request); 637 | 638 | $signature = $request->get_parameter('oauth_signature'); 639 | $valid_sig = $signature_method->check_signature( 640 | $request, 641 | $consumer, 642 | $token, 643 | $signature 644 | ); 645 | 646 | if (!$valid_sig) { 647 | throw new OAuthException("Invalid signature"); 648 | } 649 | } 650 | 651 | /** 652 | * check that the timestamp is new enough 653 | */ 654 | private function check_timestamp($timestamp) { 655 | if( ! $timestamp ) 656 | throw new OAuthException( 657 | 'Missing timestamp parameter. The parameter is required' 658 | ); 659 | 660 | // verify that timestamp is recentish 661 | $now = time(); 662 | if (abs($now - $timestamp) > $this->timestamp_threshold) { 663 | throw new OAuthException( 664 | "Expired timestamp, yours $timestamp, ours $now" 665 | ); 666 | } 667 | } 668 | 669 | /** 670 | * check that the nonce is not repeated 671 | */ 672 | private function check_nonce($consumer, $token, $nonce, $timestamp) { 673 | if( ! $nonce ) 674 | throw new OAuthException( 675 | 'Missing nonce parameter. The parameter is required' 676 | ); 677 | 678 | // verify that the nonce is uniqueish 679 | $found = $this->data_store->lookup_nonce( 680 | $consumer, 681 | $token, 682 | $nonce, 683 | $timestamp 684 | ); 685 | if ($found) { 686 | throw new OAuthException("Nonce already used: $nonce"); 687 | } 688 | } 689 | 690 | } 691 | 692 | class OAuthDataStore { 693 | function lookup_consumer($consumer_key) { 694 | // implement me 695 | } 696 | 697 | function lookup_token($consumer, $token_type, $token) { 698 | // implement me 699 | } 700 | 701 | function lookup_nonce($consumer, $token, $nonce, $timestamp) { 702 | // implement me 703 | } 704 | 705 | function new_request_token($consumer, $callback = null) { 706 | // return a new token attached to this consumer 707 | } 708 | 709 | function new_access_token($token, $consumer, $verifier = null) { 710 | // return a new access token attached to this consumer 711 | // for the user associated with this token if the request token 712 | // is authorized 713 | // should also invalidate the request token 714 | } 715 | 716 | } 717 | 718 | class OAuthUtil { 719 | public static function urlencode_rfc3986($input) { 720 | if (is_array($input)) { 721 | return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); 722 | } else if (is_scalar($input)) { 723 | return str_replace( 724 | '+', 725 | ' ', 726 | str_replace('%7E', '~', rawurlencode($input)) 727 | ); 728 | } else { 729 | return ''; 730 | } 731 | } 732 | 733 | 734 | // This decode function isn't taking into consideration the above 735 | // modifications to the encoding process. However, this method doesn't 736 | // seem to be used anywhere so leaving it as is. 737 | public static function urldecode_rfc3986($string) { 738 | return urldecode($string); 739 | } 740 | 741 | // Utility function for turning the Authorization: header into 742 | // parameters, has to do some unescaping 743 | // Can filter out any non-oauth parameters if needed (default behaviour) 744 | public static function split_header($header, $only_allow_oauth_parameters = true) { 745 | $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; 746 | $offset = 0; 747 | $params = array(); 748 | while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { 749 | $match = $matches[0]; 750 | $header_name = $matches[2][0]; 751 | $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; 752 | if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { 753 | $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); 754 | } 755 | $offset = $match[1] + strlen($match[0]); 756 | } 757 | 758 | if (isset($params['realm'])) { 759 | unset($params['realm']); 760 | } 761 | 762 | return $params; 763 | } 764 | 765 | // helper to try to sort out headers for people who aren't running apache 766 | public static function get_headers() { 767 | if (function_exists('apache_request_headers')) { 768 | // we need this to get the actual Authorization: header 769 | // because apache tends to tell us it doesn't exist 770 | $headers = apache_request_headers(); 771 | 772 | // sanitize the output of apache_request_headers because 773 | // we always want the keys to be Cased-Like-This and arh() 774 | // returns the headers in the same case as they are in the 775 | // request 776 | $out = array(); 777 | foreach( $headers AS $key => $value ) { 778 | $key = str_replace( 779 | " ", 780 | "-", 781 | ucwords(strtolower(str_replace("-", " ", $key))) 782 | ); 783 | $out[$key] = $value; 784 | } 785 | } else { 786 | // otherwise we don't have apache and are just going to have to hope 787 | // that $_SERVER actually contains what we need 788 | $out = array(); 789 | if( isset($_SERVER['CONTENT_TYPE']) ) 790 | $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; 791 | if( isset($_ENV['CONTENT_TYPE']) ) 792 | $out['Content-Type'] = $_ENV['CONTENT_TYPE']; 793 | 794 | foreach ($_SERVER as $key => $value) { 795 | if (substr($key, 0, 5) == "HTTP_") { 796 | // this is chaos, basically it is just there to capitalize the first 797 | // letter of every word that is not an initial HTTP and strip HTTP 798 | // code from przemek 799 | $key = str_replace( 800 | " ", 801 | "-", 802 | ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) 803 | ); 804 | $out[$key] = $value; 805 | } 806 | } 807 | } 808 | return $out; 809 | } 810 | 811 | // This function takes a input like a=b&a=c&d=e and returns the parsed 812 | // parameters like this 813 | // array('a' => array('b','c'), 'd' => 'e') 814 | public static function parse_parameters( $input ) { 815 | if (!isset($input) || !$input) return array(); 816 | 817 | $pairs = explode('&', $input); 818 | 819 | $parsed_parameters = array(); 820 | foreach ($pairs as $pair) { 821 | $split = explode('=', $pair, 2); 822 | $parameter = OAuthUtil::urldecode_rfc3986($split[0]); 823 | $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; 824 | 825 | if (isset($parsed_parameters[$parameter])) { 826 | // We have already recieved parameter(s) with this name, so add to the list 827 | // of parameters with this name 828 | 829 | if (is_scalar($parsed_parameters[$parameter])) { 830 | // This is the first duplicate, so transform scalar (string) into an array 831 | // so we can add the duplicates 832 | $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); 833 | } 834 | 835 | $parsed_parameters[$parameter][] = $value; 836 | } else { 837 | $parsed_parameters[$parameter] = $value; 838 | } 839 | } 840 | return $parsed_parameters; 841 | } 842 | 843 | public static function build_http_query($params) { 844 | if (!$params) return ''; 845 | 846 | // Urlencode both keys and values 847 | $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); 848 | $values = OAuthUtil::urlencode_rfc3986(array_values($params)); 849 | $params = array_combine($keys, $values); 850 | 851 | // Parameters are sorted by name, using lexicographical byte value ordering. 852 | // Ref: Spec: 9.1.1 (1) 853 | uksort($params, 'strcmp'); 854 | 855 | $pairs = array(); 856 | foreach ($params as $parameter => $value) { 857 | if (is_array($value)) { 858 | // If two or more parameters share the same name, they are sorted by their value 859 | // Ref: Spec: 9.1.1 (1) 860 | natsort($value); 861 | foreach ($value as $duplicate_value) { 862 | $pairs[] = $parameter . '=' . $duplicate_value; 863 | } 864 | } else { 865 | $pairs[] = $parameter . '=' . $value; 866 | } 867 | } 868 | // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 869 | // Each name-value pair is separated by an '&' character (ASCII code 38) 870 | return implode('&', $pairs); 871 | } 872 | } 873 | -------------------------------------------------------------------------------- /twitteroauth/twitteroauth/_notes/dwsync.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /twitteroauth/twitteroauth/twitteroauth.php: -------------------------------------------------------------------------------- 1 | http_status; } 54 | function lastAPICall() { return $this->last_api_call; } 55 | 56 | /** 57 | * construct TwitterOAuth object 58 | */ 59 | function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { 60 | $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); 61 | $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); 62 | if (!empty($oauth_token) && !empty($oauth_token_secret)) { 63 | $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); 64 | } else { 65 | $this->token = NULL; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * Get a request_token from Twitter 72 | * 73 | * @returns a key/value array containing oauth_token and oauth_token_secret 74 | */ 75 | function getRequestToken($oauth_callback) { 76 | $parameters = array(); 77 | $parameters['oauth_callback'] = $oauth_callback; 78 | $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters); 79 | $token = OAuthUtil::parse_parameters($request); 80 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 81 | return $token; 82 | } 83 | 84 | /** 85 | * Get the authorize URL 86 | * 87 | * @returns a string 88 | */ 89 | function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) { 90 | if (is_array($token)) { 91 | $token = $token['oauth_token']; 92 | } 93 | if (empty($sign_in_with_twitter)) { 94 | return $this->authorizeURL() . "?oauth_token={$token}"; 95 | } else { 96 | return $this->authenticateURL() . "?oauth_token={$token}"; 97 | } 98 | } 99 | 100 | /** 101 | * Exchange request token and secret for an access token and 102 | * secret, to sign API calls. 103 | * 104 | * @returns array("oauth_token" => "the-access-token", 105 | * "oauth_token_secret" => "the-access-secret", 106 | * "user_id" => "9436992", 107 | * "screen_name" => "abraham") 108 | */ 109 | function getAccessToken($oauth_verifier) { 110 | $parameters = array(); 111 | $parameters['oauth_verifier'] = $oauth_verifier; 112 | $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters); 113 | $token = OAuthUtil::parse_parameters($request); 114 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 115 | return $token; 116 | } 117 | 118 | /** 119 | * One time exchange of username and password for access token and secret. 120 | * 121 | * @returns array("oauth_token" => "the-access-token", 122 | * "oauth_token_secret" => "the-access-secret", 123 | * "user_id" => "9436992", 124 | * "screen_name" => "abraham", 125 | * "x_auth_expires" => "0") 126 | */ 127 | function getXAuthToken($username, $password) { 128 | $parameters = array(); 129 | $parameters['x_auth_username'] = $username; 130 | $parameters['x_auth_password'] = $password; 131 | $parameters['x_auth_mode'] = 'client_auth'; 132 | $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters); 133 | $token = OAuthUtil::parse_parameters($request); 134 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 135 | return $token; 136 | } 137 | 138 | /** 139 | * GET wrapper for oAuthRequest. 140 | */ 141 | function get($url, $parameters = array()) { 142 | $response = $this->oAuthRequest($url, 'GET', $parameters); 143 | if ($this->format === 'json' && $this->decode_json) { 144 | return json_decode($response); 145 | } 146 | return $response; 147 | } 148 | 149 | /** 150 | * POST wrapper for oAuthRequest. 151 | */ 152 | function post($url, $parameters = array()) { 153 | $response = $this->oAuthRequest($url, 'POST', $parameters); 154 | if ($this->format === 'json' && $this->decode_json) { 155 | return json_decode($response); 156 | } 157 | return $response; 158 | } 159 | 160 | /** 161 | * DELETE wrapper for oAuthReqeust. 162 | */ 163 | function delete($url, $parameters = array()) { 164 | $response = $this->oAuthRequest($url, 'DELETE', $parameters); 165 | if ($this->format === 'json' && $this->decode_json) { 166 | return json_decode($response); 167 | } 168 | return $response; 169 | } 170 | 171 | /** 172 | * Format and sign an OAuth / API request 173 | */ 174 | function oAuthRequest($url, $method, $parameters) { 175 | if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) { 176 | $url = "{$this->host}{$url}.{$this->format}"; 177 | } 178 | $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); 179 | $request->sign_request($this->sha1_method, $this->consumer, $this->token); 180 | switch ($method) { 181 | case 'GET': 182 | return $this->http($request->to_url(), 'GET'); 183 | default: 184 | return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata()); 185 | } 186 | } 187 | 188 | /** 189 | * Make an HTTP request 190 | * 191 | * @return API results 192 | */ 193 | function http($url, $method, $postfields = NULL) { 194 | $this->http_info = array(); 195 | $ci = curl_init(); 196 | /* Curl settings */ 197 | curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); 198 | curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); 199 | curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); 200 | curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); 201 | curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:')); 202 | curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); 203 | curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); 204 | curl_setopt($ci, CURLOPT_HEADER, FALSE); 205 | 206 | switch ($method) { 207 | case 'POST': 208 | curl_setopt($ci, CURLOPT_POST, TRUE); 209 | if (!empty($postfields)) { 210 | curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); 211 | } 212 | break; 213 | case 'DELETE': 214 | curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); 215 | if (!empty($postfields)) { 216 | $url = "{$url}?{$postfields}"; 217 | } 218 | } 219 | 220 | curl_setopt($ci, CURLOPT_URL, $url); 221 | $response = curl_exec($ci); 222 | $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); 223 | $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); 224 | $this->url = $url; 225 | curl_close ($ci); 226 | return $response; 227 | } 228 | 229 | /** 230 | * Get the header info to store. 231 | */ 232 | function getHeader($ch, $header) { 233 | $i = strpos($header, ':'); 234 | if (!empty($i)) { 235 | $key = str_replace('-', '_', strtolower(substr($header, 0, $i))); 236 | $value = trim(substr($header, $i + 2)); 237 | $this->http_header[$key] = $value; 238 | } 239 | return strlen($header); 240 | } 241 | } 242 | --------------------------------------------------------------------------------
    API MethodHTTP CodeResponse LengthParameters
    Response Snippet