├── .gitignore ├── README-v1.md ├── README-v2.md ├── README.md ├── changelog.txt ├── license.txt ├── v1 ├── Chunks │ ├── chunk.JSONDerulo.AppDotNetFeedItem.html │ ├── chunk.JSONDerulo.DeliciousFeedItem.html │ ├── chunk.JSONDerulo.FlickrFeedItem.html │ ├── chunk.JSONDerulo.GoogleCalendarFeedItem.html │ ├── chunk.JSONDerulo.GooglePlusFeedItem.html │ ├── chunk.JSONDerulo.LastFmFeedItem.html │ ├── chunk.JSONDerulo.PicasaFeedItem.html │ ├── chunk.JSONDerulo.TumblrFeedItem.html │ ├── chunk.JSONDerulo.TwitterFeedItemNew.html │ ├── chunk.JSONDerulo.VimeoFeedItem.html │ ├── chunk.JSONDerulo.YouTubeFeedItem.html │ └── chunk.JSONDerulo.ZooToolFeedItem.html ├── Components │ └── twitteroauth │ │ ├── OAuth.php │ │ └── twitteroauth.php ├── Snippets │ ├── snippet.JSONDerulo.AppDotNetFeed.php │ ├── snippet.JSONDerulo.DeliciousFeed.php │ ├── snippet.JSONDerulo.FlickrFeed.php │ ├── snippet.JSONDerulo.GoogleCalendarFeed.php │ ├── snippet.JSONDerulo.GooglePlusFeed.php │ ├── snippet.JSONDerulo.LastFmFeed.php │ ├── snippet.JSONDerulo.LastFmListensFeed.php │ ├── snippet.JSONDerulo.PicasaFeed.php │ ├── snippet.JSONDerulo.TumblrFeed.php │ ├── snippet.JSONDerulo.TwitterFeedNew.php │ ├── snippet.JSONDerulo.TwitterFeedNewMultipleFeeds.php │ ├── snippet.JSONDerulo.VimeoFeed.php │ ├── snippet.JSONDerulo.YouTubeFeed.php │ ├── snippet.JSONDerulo.YouTubeFeedAPIV3PublicPlaylist.php │ ├── snippet.JSONDerulo.YouTubeFeedUploads.php │ └── snippet.JSONDerulo.ZooToolFeed.php └── Transport packages │ ├── jsonderulo-0.5-alpha.transport.zip │ ├── jsonderulo-0.6-alpha.transport.zip │ ├── jsonderulo-0.7-alpha.transport.zip │ ├── jsonderulo-0.9-alpha.transport.zip │ ├── jsonderulo-0.9.1-alpha.transport.zip │ ├── jsonderulo-1.0-beta.transport.zip │ ├── jsonderulo-1.1-pl.transport.zip │ ├── jsonderulo-1.2-pl.transport.zip │ ├── jsonderulo-1.3-pl.transport.zip │ ├── jsonderulo-1.3.1-pl.transport.zip │ ├── jsonderulo-1.3.2-pl.transport.zip │ ├── jsonderulo-1.3.3-pl.transport.zip │ ├── jsonderulo-1.3.4-pl.transport.zip │ ├── jsonderulo-1.4.0-pl.transport.zip │ ├── jsonderulo-1.5.0-pl.transport.zip │ ├── jsonderulo-1.6.0-pl.transport.zip │ ├── jsonderulo-1.7.0-pl.transport.zip │ ├── jsonderulo-1.7.1-pl.transport.zip │ ├── jsonderulo-1.7.3-pl.transport.zip │ └── jsonderulo-1.7.4-pl.transport.zip └── v2 ├── Chunks ├── jd.appNet.html ├── jd.delicious.html ├── jd.eventbrite.html ├── jd.flickr.html ├── jd.googleCalendar.html ├── jd.googlePlus.html ├── jd.instagram.html ├── jd.lastFm.html ├── jd.tumblr.html ├── jd.twitter.html ├── jd.vimeo.html └── jd.youTube.html ├── Components └── twitteroauth │ ├── OAuth.php │ └── twitteroauth.php ├── Transport Packages ├── jsonderulo-2.0-pl.transport.zip ├── jsonderulo-2.0.1-pl.transport.zip ├── jsonderulo-2.0.2-pl.transport.zip ├── jsonderulo-2.1.0-pl.transport.zip ├── jsonderulo-2.2.0-pl.transport.zip ├── jsonderulo-2.3.0-pl.transport.zip ├── jsonderulo-2.3.1-pl.transport.zip ├── jsonderulo-2.3.2-pl.transport.zip ├── jsonderulo-2.3.4-pl.transport.zip ├── jsonderulo-2.3.6-pl.transport.zip ├── jsonderulo-2.3.7-pl.transport.zip ├── jsonderulo-2.3.8-pl.transport.zip ├── jsonderulo-2.4.0-pl.transport.zip ├── jsonderulo-2.4.1-pl.transport.zip ├── jsonderulo-2.4.2-pl.transport.zip ├── jsonderulo-2.5-pl.transport.zip ├── jsonderulo-2.5.1-pl.transport.zip ├── jsonderulo-2.5.2-pl.transport.zip ├── jsonderulo-2.5.3-pl.transport.zip ├── jsonderulo-2.5.4-pl.transport.zip ├── jsonderulo-2.5.5-pl.transport.zip ├── jsonderulo-2.5.6-pl.transport.zip ├── jsonderulo-2.5.7-pl.transport.zip ├── jsonderulo-2.5.7-pl2.transport.zip ├── jsonderulo-2.6.0-pl.transport.zip └── jsonderulo-2.6.1-pl.transport.zip └── snippet.JSONDerulo.php /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | *.sublime-workspace 5 | -------------------------------------------------------------------------------- /README-v1.md: -------------------------------------------------------------------------------- 1 | # JSONDerulo - A JSON feed fetcher for MODX Revolution CMS 2 | 3 | ## Available snippets 4 | 5 | ### App.net 6 | 7 | You need your user id to get this working, not your username. You can find it on your profile page. [Hat tip to "man"](https://alpha.app.net/man/post/20858). 8 | 9 | ``` 10 | 13 | ``` 14 | 15 | ### Delicious 16 | 17 | ``` 18 | 21 | ``` 22 | 23 | ### Flickr 24 | 25 | Requires API key, get one here: [Flickr API Key](http://www.flickr.com/services/apps/create/apply) 26 | 27 | ``` 28 | 31 | ``` 32 | 33 | ### Google+ 34 | 35 | Requires API key, get one here: [Google API key](https://code.google.com/apis/console/) 36 | 37 | ``` 38 | 41 | ``` 42 | 43 | ### Google calendar 44 | 45 | You'll need to find the calendar's public feed URL. Don't panic, [read the instructions further down the page](#google-calendar-and-public-feed-urls)... 46 | 47 | ``` 48 | 51 | ``` 52 | 53 | ### LastFM 54 | 55 | Requires api key, get one here: [LastFM API Key](http://www.last.fm/api/account) 56 | 57 | ``` 58 | 61 | ``` 62 | 63 | ``` 64 | 67 | ``` 68 | 69 | ### Picasa 70 | 71 | ``` 72 | 75 | ``` 76 | 77 | ### Tumblr 78 | 79 | The &postType option is optional (if not set, feed will return all post types), but can be set to ```audio```, ```video```, ```photo```, ```link```, ```text``` 80 | 81 | You can only set ONE postType. 82 | 83 | ``` 84 | 87 | ``` 88 | 89 | ### Twitter (New API version) 90 | 91 | You need to set up a Twitter "App" to make this work - [from here](https://dev.twitter.com/apps). From March 2013, this is the ONLY way. 92 | 93 | The cacheName option is for users who may want to use the snippet more than once on a site for different users' tweets. Setting this appends the text to the cache filename so multiple feeds can be cached. I've added a string replacement to swap spaces for hyphens in there too. 94 | 95 | The screenName option is *optional*. It will allow you to fetch another user's timeline. If this is not provided, it will default to the user whose consumer key, etc, that you are using. 96 | 97 | ``` 98 | 101 | ``` 102 | 103 | ### Twitter (New API version for multiple timelines) 104 | 105 | As above, you'll need to have an app set up to use the new Twitter API. This version **does not** have the cacheName option, and the screenName is **required**. This is not needed for all timeline types available, but it is used by the snippet for generating a cache filename for the feed. Pass multiple screenNames separated by commas to get more than one timeline. E.g: &screenName=`twitter,twitterapi` 106 | 107 | For &timelineType, there are a few options: 108 | 109 | * user_timeline - the default option. Your tweets. 110 | * home_timeline - your tweets and tweets from those you follow 111 | * mentions - Ronseal. 112 | * retweets_of_me - Ronseal. 113 | * any other timeline type listed in the [Twitter API docs](https://dev.twitter.com/docs/api/1.1). The four above are likely the most useful! 114 | 115 | 116 | ``` 117 | 120 | ``` 121 | 122 | ### Vimeo 123 | 124 | ``` 125 | 128 | ``` 129 | 130 | ### YouTube 131 | 132 | ``` 133 | 136 | ``` 137 | 138 | ``` 139 | 142 | ``` 143 | 144 | ``` 145 | 148 | ``` 149 | 150 | Grab an API key for v3 from [Google API Console](https://code.google.com/apis/console/). Ensure you switch API v3 access on! 151 | 152 | ### ZooTool 153 | 154 | Requires API key, get one here: [ZooTool API Key](http://zootool.com/api/keys) 155 | 156 | ``` 157 | 160 | ``` 161 | -------------------------------------------------------------------------------- /README-v2.md: -------------------------------------------------------------------------------- 1 | # JSONDerulo - A JSON feed fetcher for MODX Revolution CMS 2 | 3 | ## Available snippets 4 | 5 | ### App.net 6 | 7 | You need your user id to get this working, not your username. You can find it on your profile page. [Hat tip to "man"](https://alpha.app.net/man/post/20858). 8 | 9 | ``` 10 | 21 | ``` 22 | 23 | 24 | ### Eventbrite 25 | 26 | Requires Single user oAuth token - see 'Personal Tokens' on the [Authentication page](http://developer.eventbrite.com/docs/auth/) 27 | status options are: all, draft, live, cancelled, started and ended. 28 | orderBy options are: start_asc, start_desc, created_asc and created_desc. 29 | 30 | 31 | ``` 32 | 45 | ``` 46 | 47 | 48 | ### Flickr 49 | 50 | Requires API key, get one here: [Flickr API Key](http://www.flickr.com/services/apps/create/apply) 51 | 52 | ``` 53 | 66 | ``` 67 | 68 | ### Google+ 69 | 70 | Requires API key, get one here: [Google API key](https://console.developers.google.com) 71 | 72 | ``` 73 | 85 | ``` 86 | 87 | ### Google calendar 88 | 89 | Requires API key - [Google API key](https://console.developers.google.com) 90 | 91 | ```feedLocation``` should be your Google Calendar ID. 92 | 93 | ```timeMin``` don't include this unless you want to show some past events (default from now) - format is ```Y-m-d\TH:i:sP``` 94 | 95 | ``` 96 | 109 | ``` 110 | 111 | ### LastFM 112 | 113 | Requires api key, get one here: [LastFM API Key](http://www.last.fm/api/account) 114 | 115 | ``` 116 | 128 | ``` 129 | 130 | ``` 131 | 143 | ``` 144 | 145 | ### Tumblr 146 | 147 | The &postType option is optional (if not set, feed will return all post types), but can be set to ```audio```, ```video```, ```photo```, ```link```, ```text``` 148 | 149 | You can only set ONE postType. 150 | 151 | ``` 152 | 167 | ``` 168 | 169 | ### Twitter 170 | 171 | You need to set up a Twitter "App" to make this work - [from here](https://dev.twitter.com/apps). From March 2013, this is the ONLY way. 172 | 173 | The cacheName option is for users who may want to use the snippet more than once on a site for different users' tweets. Setting this appends the text to the cache filename so multiple feeds can be cached. I've added a string replacement to swap spaces for hyphens in there too. 174 | 175 | The screenName option is *optional*. It will allow you to fetch another user's timeline. If this is not provided, it will default to the user whose consumer key, etc, that you are using. 176 | 177 | UPDATE: You can fetch and combine more than one screenName if you comma separate them. Not massively likely to be useful if you fetch more than a couple of feeds and only want a limit of 2 or 3, as you may never seen anything from some accounts if they do not tweet as regularly as any of the others you're pulling in. 178 | 179 | ``` 180 | 197 | ``` 198 | 199 | ### Twitter Favourites 200 | 201 | The screenName option is *optional*. It will allow you to fetch another user's favourites (if public). If this is not provided, it will default to the user whose consumer key, etc, that you are using. 202 | 203 | ``` 204 | 219 | ``` 220 | 221 | ### Vimeo 222 | 223 | ``` 224 | 235 | ``` 236 | 237 | ### YouTube 238 | 239 | ``` 240 | 251 | ``` 252 | 253 | ``` 254 | 265 | ``` 266 | 267 | ``` 268 | 280 | ``` 281 | 282 | Grab an API key for v3 from [Google API Console](https://console.developers.google.com). Ensure you switch API v3 access on! 283 | 284 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSONDerulo - A JSON feed fetcher for MODX Revolution CMS 2 | 3 | Snippets and chunks to pull in various social JSON feeds. [Available on the MODX Extras repo](http://modx.com/extras/package/jsonderulo). 4 | 5 | Results are cached for 12 hours by default, but you can specify your own time limit in seconds using &cacheTime. Make sure you call the snippet uncached from your templates! 6 | Most snippets allow you to specify multiple usernames, however any feeds which require an API key will not yet work with multiple accounts. 7 | The following feeds are already set up: 8 | 9 | * App.net - most recent posts 10 | * Flickr - most recent photographs in your photostream 11 | * Google+ - most recent public posts 12 | * Google calendar - upcoming public events 13 | * LastFM - recent "loved" tracks or recent "listens" 14 | * Tumblr - most recent posts (several post type options) 15 | * Twitter - most recent tweets, or a user's favourites 16 | * Vimeo - most recent "likes" 17 | * YouTube - Most recent additions to "favourites" playlist or specific user's uploads 18 | * YouTube - (For API v.3 - fetch a public playlist) 19 | 20 | ## Thanks! 21 | 22 | Plenty of thouroughly helpful help from [Mister John Noel](https://github.com/johnnoel) and his code on which these snippets are based. 23 | 24 | Also, hat tip to [basvaneijk](https://github.com/basvaneijk) for the preg_replace stuff to auto link @, # and URLs within the [[+message]] 25 | 26 | ## Requirements/Prerequisites 27 | 28 | * Tested on MODx 2.2.x 29 | * PHPThumbOf / pThumb 30 | * API Keys/app secrets, etc for certain feeds 31 | * That's it! 32 | 33 | #Specific details 34 | 35 | [JSONDerulo v1](https://github.com/pdincubus/JSONDerulo/blob/master/README-v1.md) | [JSONDerulo v2](https://github.com/pdincubus/JSONDerulo/blob/master/README-v2.md) 36 | 37 | #General details (applicable to v1 and v2) 38 | 39 | ## Chunks 40 | 41 | I've provided basic chunks to get you started. Any feed which returns thumbnails/imagery I've used PHPThumbOf, if you use these chunks make sure you have it installed too! 42 | 43 | You can also use the MODx's output filters to provide fallback should the feed you request be empty. E.g. - such as a new twitter account with no tweets yet: 44 | 45 | ``` 46 | [[!TwitterFeed:default=`
  • No tweets
  • `? &tpl=`TwitterFeedItem` &limit=`10` &users=`USERNAME`]] 47 | ``` 48 | 49 | The basic Twitter chunk also shows you how to use the isRetweet option to switch out your details for the author of the tweet you retweeted. The example isn't the best, but it'll give you the right idea, and will also allow you to integrate a retweet icon if you wish. 50 | 51 | ### Chunk placeholders 52 | 53 | Currently only the basics have placeholders provided. The YouTube feed, for example, has more options that you may ever need. If I find I ever use them, I will add them in. 54 | 55 | 56 | #### App.net: 57 | 58 | The App.net feed is very pleasant and gives you the option of either "text" or "html" versions of a post. I've included placeholders for both. The basic chunk I've provided only uses [[+text]]. 59 | 60 | ``` 61 | [[+id]] 62 | [[+text]] 63 | [[+html]] 64 | [[+created]] 65 | [[+picture]] 66 | [[+title]] 67 | [[+username]] 68 | [[+profile]] 69 | [[+postUrl]] 70 | ``` 71 | 72 | #### Eventbrite 73 | 74 | ``` 75 | [[+title]] 76 | [[+textDescription]] 77 | [[+htmlDescription]] 78 | [[+organiserName]] 79 | [[+organiserId]] 80 | [[+venueName]] 81 | [[+venueAddress1]] 82 | [[+venueAddress2]] 83 | [[+venueCity]] 84 | [[+venueRegion]] 85 | [[+venueCountryName]] 86 | [[+venueCountry]] 87 | [[+venueLatitude]] 88 | [[+venueLongitude]] 89 | [[+url]] 90 | [[+eventStart]] 91 | [[+eventEnd]] 92 | [[+eventCapacity]] 93 | [[+eventFormat]] 94 | [[+eventId]] 95 | ``` 96 | 97 | There are also some placeholders generated for ticket types (if you add these to your event). They're looped through with the index tagged on to the name. So if your event has only one type of ticket, you'd get these placeholders made available to you: 98 | 99 | ``` 100 | [[+ticketType1]] 101 | [[+ticketCost1]] 102 | [[+ticketFee1]] 103 | [[+ticketFree1]] 104 | [[+ticketTypeQuantity1]] 105 | [[+ticketTypeSold1]] 106 | ``` 107 | 108 | The basic chunk provided has placeholders set for up to three ticket classes - if you have more, just add more! 109 | 110 | 111 | #### Flickr: 112 | 113 | ``` 114 | [[+id]] 115 | [[+created]] 116 | [[+picture]] 117 | [[+picturelarge]] 118 | [[+title]] 119 | [[+username]] 120 | ``` 121 | 122 | ### Google+: 123 | 124 | ``` 125 | [[+text]] 126 | [[+html]] 127 | [[+postId]] 128 | [[+attachmentUrl]] 129 | [[+repliesCount]] 130 | [[+plusCount]] 131 | [[+resharesCount]] 132 | [[+postUrl]] 133 | [[+postDate]] 134 | [[+profileUrl]] 135 | [[+avatar]] 136 | [[+displayName]] 137 | [[+fullImage]] 138 | 139 | ``` 140 | 141 | ### Google Calendar: 142 | 143 | ``` 144 | [[+timezone]] 145 | [[+published]] 146 | [[+title]] 147 | [[+content]] 148 | [[+link]] 149 | [[+calendarName]] 150 | [[+eventStart]] 151 | [[+eventEnd]] 152 | [[+location]] 153 | [[+allDayEvent]] 154 | ``` 155 | 156 | 157 | #### LastFM: 158 | 159 | ``` 160 | [[+track]] 161 | [[+artist]] 162 | [[+link]] 163 | [[+picture]] 164 | [[+date]] 165 | [[+username]] 166 | ``` 167 | 168 | 169 | ### Tumblr: 170 | 171 | Default placeholders: 172 | 173 | ``` 174 | [[+blogUrl]] 175 | [[+blogName]] 176 | [[+blogDescription]] 177 | [[+post]] 178 | [[+postType]] 179 | [[+postUrl]] 180 | [[+created]] 181 | [[+createdDate]] 182 | [[+id]] 183 | [[+shortUrl]] 184 | ``` 185 | 186 | For video posts: 187 | 188 | ``` 189 | [[+caption]] 190 | [[+videoPermalink]] 191 | [[+thumbnail]] 192 | [[+player250]] 193 | [[+player400]] 194 | [[+player500]] 195 | ``` 196 | 197 | For link posts: 198 | 199 | ``` 200 | [[+title]] 201 | [[+linkUrl]] 202 | [[+linkDescription]] 203 | ``` 204 | 205 | For text posts: 206 | 207 | ``` 208 | [[+title]] 209 | [[+content]] 210 | ``` 211 | 212 | For audio posts: 213 | 214 | ``` 215 | [[+audioSourceUrl]] 216 | [[+audioSourceTitle]] 217 | [[+artist]] 218 | [[+album]] 219 | [[+trackName]] 220 | [[+player]] 221 | [[+audioUrl]] 222 | ``` 223 | 224 | For image posts: 225 | 226 | ``` 227 | [[+caption]] 228 | [[+imagePermalink]] 229 | [[+image]] 230 | ``` 231 | 232 | #### Twitter: 233 | 234 | ``` 235 | [[+id]] 236 | [[+message]] 237 | [[+created]] 238 | [[+picture]] 239 | [[+title]] 240 | [[+username]] 241 | [[+retweetCount]] 242 | [[+favouriteCount]] 243 | [[+inReplyToStatusId]] 244 | [[+inReplyToScreenName]] 245 | [[+isRetweet]] 246 | [[+originalAuthorPicture]] 247 | [[+originalAuthor]] 248 | [[+originalUsername]] 249 | [[+originalId]] 250 | [[+mediaThumb]] 251 | [[+mediaSmall]] 252 | [[+mediaMedium]] 253 | [[+mediaLarge]] 254 | ``` 255 | 256 | #### Vimeo: 257 | 258 | ``` 259 | [[+id]] 260 | [[+url]] 261 | [[+created]] 262 | [[+picture]] 263 | [[+title]] 264 | [[+username]] 265 | ``` 266 | 267 | #### YouTube: 268 | 269 | ``` 270 | [[+published]] 271 | [[+picture]] 272 | [[+title]] 273 | [[+ytlink]] 274 | [[+embedlink]] 275 | [[+videoId]] 276 | [[+author]] 277 | ``` 278 | 279 | 280 | ### CSS 281 | 282 | I've used the clearfix from the [HTML5 Boilerplate normalize.css](http://www.html5boilerplate.com) on ```
  • ``` items to clear floats inside them: 283 | 284 | ```css 285 | .cf:before, .cf:after { content: ""; display: table; } 286 | .cf:after { clear: both; } 287 | .cf { *zoom: 1; } 288 | ``` 289 | 290 | 291 | ### PHPThumbOf settings 292 | 293 | Ensure you have the following in the "phpthumb_nohotlink_valid_domains" section: 294 | 295 | * Flickr: ```*.flickr.com, *.staticflickr.com``` 296 | * ZooTool: ```s3.amazonaws.com``` 297 | * YouTube Thumbnails: ```.ytimg.com``` 298 | * LastFM Album art: ```userserve-ak.last.fm``` 299 | * Vimeo Thumbnails: ```*.vimeocdn.com``` 300 | * Twitter profile avatars: ```*.twimg.com``` 301 | * Picasa/Google+ Thumbnails: ```*.googleusercontent.com``` 302 | * App.net avatars: ```*.cloudfront.net``` 303 | 304 | 305 | ## Twitter feed and the new API 306 | 307 | Much publicised changes to the Twitter API means that you have to authenticate to get public feed data now. I will keep the original, easy way to get a Twitter feed until the date they switch this off, but you're probably best going through the pain of getting onto the new API stuff now. 308 | 309 | This uses the excellent (and thoroughly easy to use) [TwitterOAuth](https://github.com/abraham/twitteroauth/) by [Abraham Williams](https://github.com/abraham) (check out his incredible beard!). If you're adding the JSONDerulo snippets and chunks manually, you're going to need to upload a copy of the TwitterOAuth stuff to {core_path}/components/jsonderulo/ 310 | 311 | The transport package will do this automatically for you. (Hopefully). 312 | 313 | To set up a Twitter "App", go to the [Twitter dev site](https://dev.twitter.com/apps/) and choose "Create a new application". Fill in the form and you'll end up with a new "app" which will let you know the consumer secret, consumer key, access token, and access token secret. 314 | 315 | Hat tip also to [Stewart Orr](http://www.qodo.co.uk/blog/twitterx-a-new-modx-extra-for-pulling-in-twitter-feeds-using-api-1.1/), whose TwitterX addon reminded me to get my backside in gear and fix this package up! 316 | 317 | ## Twitter display "requirements" 318 | 319 | I've included a new chunk for displaying tweets. This includes several changes which *should* make the output acceptable based on the [Developer display requirements documentation](https://dev.twitter.com/terms/display-requirements). You will need to include the Twitter widgets.js somewhere on the page you're displaying tweets on. You only need this included ONCE on the page, not for each tweet. 320 | 321 | ``` 322 | 323 | ``` 324 | 325 | ## PLEASE NOTE - Twitter feeds and count limit 326 | 327 | The [Twitter API documentation](https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline) states under retweets that: "When set to false, the timeline will strip any native retweets (though they will still count toward both the maximal length of the timeline and the slice selected by the count parameter)". This means that if you set retweets OFF and the limit to return 5 tweets, and 4 of your most recent tweets are retweets the feed will only return ONE item. This is NOT a bug! 328 | 329 | 330 | ## Google calendar and public feed URLs 331 | 332 | Click the arrow beside the name of the calendar, then go to settings. 333 | 334 | ![Calendar Settings](http://pdincubus.github.com/JSONDerulo/img/cal-settings.png) 335 | 336 | Scroll down to find your Calendar ID and use it as the feedLocation parameter - it should look like this: ```str1ng0fr4nd0mch4r5@group.calendar.google.com``` 337 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | Oooo whatcha say? 2 | 3 | For all info: https://github.com/pdincubus/JSONDerulo/ 4 | 5 | Most recent additions 6 | --------------------- 7 | 8 | 2.6.2 9 | * Swap 'continue' for 'return' in several places for PHP7 10 | * Remove app.net feed 11 | 12 | 2.6.1 13 | * Added conditional statement around sksort function (thanks to k9dug) 14 | 15 | 2.6.0 16 | * Added randomise option (&random=`1`) 17 | 18 | 2.5.7: 19 | * Remove Instagram feed 20 | * Remove Delicious feed 21 | * Add timezone param to Google Calendar 22 | * Stop strtotime on Google Calendar dates/times 23 | 24 | 2.5.6: 25 | * Added tweet first media items (thanks to jonhorner) 26 | * Added tweet first media items to Twitter favourites feed 27 | 28 | 2.5.5: 29 | * Fixed 'continue' that should be a 'return' (thanks to raffy99) 30 | 31 | 2.5.4: 32 | * Fix Eventbrite expanding of items (thanks to apathyuk for the hat tip) 33 | 34 | 2.5.3: 35 | * Fix preg_replace for links in twitter message strings (Thanks for pointing out, kehezen) 36 | * Several minor tweaks to chunks 37 | 38 | 2.5.2: 39 | * Fix for accented chars in Twitter hashtags (https://github.com/pdincubus/JSONDerulo/issues/26 - thanks to hitodev) 40 | 41 | 2.5.1: 42 | * Google Calendar tweaks (thanks to andrewmfraser) 43 | 44 | 2.5.0: 45 | * NEW! Added support for Google Calendar API v3 (Hat tip to andrewmfraser) 46 | 47 | 2.4.2: 48 | * Small tweak to tumblr feed (thanks to romangetman) 49 | * New placeholders for twitter feed: "in reply to" options and included missing favourite count 50 | 51 | 2.4.1: 52 | * Added fullImage placeholder for G+ public posts with image attachments (thanks to thijsvandamme) 53 | 54 | 2.4.0: 55 | * NEW! Added instagram user public recent media feed 56 | 57 | 2.3.8: 58 | * Fixed Flickr URL to be HTTPS 59 | 60 | 2.3.7: 61 | * Add sortDir option to Twitter feed. (Hat tip to creatabledesign on GitHub) 62 | * Added unix timestamp for tweet created on so that sorting actually sorts properly! 63 | 64 | 2.3.6: 65 | * FFS. 66 | 67 | 2.3.5: 68 | * Fix missing chunks 69 | * Remove ZooTool feed 70 | * Remove Picasa web album feed 71 | 72 | 2.3.4: 73 | * Move sksort function into Twitter feed part to avoid errors 74 | 75 | 2.3.3: 76 | * Added eventId placeholder for Eventbrite 77 | 78 | 2.3.2: 79 | * Lots of updates to the Eventbrite feed fetcher 80 | 81 | 2.3.1: 82 | * Fix wrong named chunk. 83 | 84 | 2.3.0: 85 | * NEW Eventbrite user events feed. More info in README and README-v2 86 | 87 | 2.2.0: 88 | * Added ability to fetch more than one feed and combine automatically on Twitter feed fetcher, just comma separate the screenName option, ie - &screenName=`pdincubus,modx` 89 | 90 | 2.1.0: 91 | * Added Twitter user favourites feed option. 92 | * fixed limit/count on Twitter feed 93 | 94 | 2.0.2: 95 | * Fix twitter feed "search" links and $user/$screenName thing. 96 | 97 | 2.0.1: 98 | * Tweak to ensure &feed is pulled into snippet correctly. 99 | 100 | 2.0: 101 | * Combined all snippets into one for ease of maintenance 102 | * Fixed a couple of minor stupid things 103 | * Chunks renamed in the transport package to be prepended with package name 104 | 105 | 1.7.4: 106 | * Added YouTube v.3 API public playlist fetcher. 107 | * twitteroauth should now avoid throwing an error about class OAuthException. 108 | 109 | 1.7.3: 110 | * Switch the Twitter new API to ACTUALLY use 1.1. WTF. I mean really. 111 | 112 | 1.7.2: 113 | * Includes merged changes from "silentworks" to allow offset and videoParams on YouTube feeds. 114 | * Includes cacheName option on most snippets to allow multiple snippet calls on same page to same user account 115 | 116 | 1.7.1: 117 | * REMOVED old style Twitter feed as API 1.0 is now officially retired. 118 | * Fix to make sure twitter doesn't caused annoying crash problem if they decide to just randomly blackout API access. 119 | * New Twitter chunk with ID check switch to allow for the graceful fallback for no JSON. 120 | * Updated MODX extra repo package link to new one. 121 | 122 | 1.7.0: 123 | * NEW Google calendar public events feed 124 | 125 | 1.6.0: 126 | * NEW Tumblr post feed 127 | 128 | 1.5.0: 129 | * NEW Google+ public posts feed 130 | * NEW TwitterFeedNewMultipleFeeds lets you choose what time of timeline to return 131 | 132 | 1.4.0: 133 | * New Twitter multiple timeline combining feed fetcher. See the documentation for more info. 134 | 135 | 1.3.4: 136 | * By request: Added configurable cacheTime option on ALL feed fetchers. 137 | 138 | 1.3.3: 139 | * option to view a different user's tweets using &screenName in the Twitter feed fetcher 140 | 141 | 1.3.2: 142 | * auto linking of [[+message]] in the Twitter feed for @, # and URLs 143 | * updated Twitter chunk to reflect this change 144 | 145 | 1.3.1: 146 | * minor tweaks to new Twitter feed 147 | 148 | 1.3: 149 | * NEW App.net feed 150 | 151 | 1.2: 152 | * New Twitter feed for use with updated API 1.1 153 | 154 | 1.1: 155 | * YouTube user upload snippet added 156 | 157 | 1.0: 158 | * Twitter changes for retweets. 159 | 160 | 0.9.1: 161 | * Slight fix for Twitter feed. 162 | 163 | 0.8: 164 | * Usually helps when you make sure that ALL the snippets and chunks have actually been packaged! 165 | 166 | 0.7: 167 | * Added Picasa album feed fetching snippet 168 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | This work is licenced under the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) 2 | http://creativecommons.org/licenses/by-sa/3.0/ -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.AppDotNetFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title]]
    4 | [[+title]] 5 | [[+username]] 6 |
    7 |
    8 | 9 | [[+text]] 10 | 11 |
    12 | 13 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.DeliciousFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title]] 4 |
    5 | 6 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.FlickrFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]]
    4 | [[+title:esc]] 5 |

    6 | 7 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.GoogleCalendarFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | timezone: [[+timezone]]
    3 | published: [[+published:date=`%e %B %Y`]]
    4 | title: [[+title]]
    5 | content: [[+content]]
    6 | link: [[+link]]
    7 | calendar name: [[+calendarName]]
    8 | start: [[+eventStart:date=`%r, %e %B %Y`]]
    9 | end: [[+eventEnd:date=`%r, %e %B %Y`]]
    10 | location: [[+location]] 11 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.GooglePlusFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+displayName]]
    4 | [[+displayName]] 5 |
    6 |
    7 | [[+text]] 8 | [[+attachmentUrl:notempty=`
    Attachment`]] 9 |
    10 | Replies: [[+repliesCount]], 11 | Plus Ones: [[+plusCount]], 12 | Reshares: [[+resharesCount]] 13 |
    14 | 15 | 16 | 17 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.LastFmFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+artist]] - [[+track]]
    4 | [[+artist]] - [[+track]] 5 |

    6 | 7 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.PicasaFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]]
    4 | [[+title:esc]] 5 |

    6 | 7 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.TumblrFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | [[+blogName]]
    3 | [[+blogDescription]] 4 | 5 |
    6 | [[+post]]
    7 | [[+postType]] 8 |
    9 | 10 | Post direct link 11 | 12 | 13 | [[+createdDate]]
    14 | [[+id]]
    15 | [[+shortUrl]]
    16 | 17 | [[+postType:is=`video`:then=` 18 | [[+caption]]
    19 | [[+videoPermalink]]
    20 | [[+thumbnail]]
    21 | [[+player250]]
    22 | [[+player400]]
    23 | [[+player500]]
    24 | `]] 25 | 26 | [[+postType:eq=`link`:then=` 27 | [[+title]]
    28 | [[+linkUrl]]
    29 | [[+linkDescription]]
    30 | `]] 31 | 32 | [[+postType:eq=`text`:then=` 33 | [[+title]]
    34 | [[+content]]
    35 | `]] 36 | 37 | [[+postType:eq=`audio`:then=` 38 | [[+audioSourceUrl]]
    39 | [[+audioSourceTitle]]
    40 | [[+artist]]
    41 | [[+album]]
    42 | [[+trackName]]
    43 | [[+player]]
    44 | [[+audioUrl]]
    45 | `]] 46 | 47 | [[+postType:eq=`photo`:then=` 48 | [[+caption]]
    49 | [[+imagePermalink]]
    50 | [[+image]]
    51 | `]] 52 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.TwitterFeedItemNew.html: -------------------------------------------------------------------------------- 1 |
  • 2 | [[+id:notempty=` 3 | 4 | [[+isRetweet:is=`1`:then=` 5 | 6 | [[+originalAuthor]] 7 | [[+originalAuthor]] 8 | @[[+originalUsername]] 9 | 10 | `:else=` 11 | 12 | [[+title]] 13 | [[+title]] 14 | @[[+username]] 15 | 16 | `]] 17 | 18 |
    19 | [[+message]] 20 |
    21 | 22 | 23 | 24 | 25 | 26 | 31 | `:default=` 32 | [[+message]] 33 | `]] 34 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.VimeoFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]]
    4 | [[+title:esc]] 5 |

    6 | 7 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.YouTubeFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]] 4 |
    5 | [[+title:esc]] by [[+author]]
    6 | 7 |
  • -------------------------------------------------------------------------------- /v1/Chunks/chunk.JSONDerulo.ZooToolFeedItem.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]]
    4 | [[+title]] 5 |
    6 | (Found here)
    7 | 8 |
  • -------------------------------------------------------------------------------- /v1/Components/twitteroauth/OAuth.php: -------------------------------------------------------------------------------- 1 | key = $key; 18 | $this->secret = $secret; 19 | $this->callback_url = $callback_url; 20 | } 21 | 22 | function __toString() { 23 | return "OAuthConsumer[key=$this->key,secret=$this->secret]"; 24 | } 25 | } 26 | 27 | class OAuthToken { 28 | // access tokens and request tokens 29 | public $key; 30 | public $secret; 31 | 32 | /** 33 | * key = the token 34 | * secret = the token secret 35 | */ 36 | function __construct($key, $secret) { 37 | $this->key = $key; 38 | $this->secret = $secret; 39 | } 40 | 41 | /** 42 | * generates the basic string serialization of a token that a server 43 | * would respond to request_token and access_token calls with 44 | */ 45 | function to_string() { 46 | return "oauth_token=" . 47 | OAuthUtil::urlencode_rfc3986($this->key) . 48 | "&oauth_token_secret=" . 49 | OAuthUtil::urlencode_rfc3986($this->secret); 50 | } 51 | 52 | function __toString() { 53 | return $this->to_string(); 54 | } 55 | } 56 | 57 | /** 58 | * A class for implementing a Signature Method 59 | * See section 9 ("Signing Requests") in the spec 60 | */ 61 | abstract class OAuthSignatureMethod { 62 | /** 63 | * Needs to return the name of the Signature Method (ie HMAC-SHA1) 64 | * @return string 65 | */ 66 | abstract public function get_name(); 67 | 68 | /** 69 | * Build up the signature 70 | * NOTE: The output of this function MUST NOT be urlencoded. 71 | * the encoding is handled in OAuthRequest when the final 72 | * request is serialized 73 | * @param OAuthRequest $request 74 | * @param OAuthConsumer $consumer 75 | * @param OAuthToken $token 76 | * @return string 77 | */ 78 | abstract public function build_signature($request, $consumer, $token); 79 | 80 | /** 81 | * Verifies that a given signature is correct 82 | * @param OAuthRequest $request 83 | * @param OAuthConsumer $consumer 84 | * @param OAuthToken $token 85 | * @param string $signature 86 | * @return bool 87 | */ 88 | public function check_signature($request, $consumer, $token, $signature) { 89 | $built = $this->build_signature($request, $consumer, $token); 90 | return $built == $signature; 91 | } 92 | } 93 | 94 | /** 95 | * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] 96 | * where the Signature Base String is the text and the key is the concatenated values (each first 97 | * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' 98 | * character (ASCII code 38) even if empty. 99 | * - Chapter 9.2 ("HMAC-SHA1") 100 | */ 101 | class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { 102 | function get_name() { 103 | return "HMAC-SHA1"; 104 | } 105 | 106 | public function build_signature($request, $consumer, $token) { 107 | $base_string = $request->get_signature_base_string(); 108 | $request->base_string = $base_string; 109 | 110 | $key_parts = array( 111 | $consumer->secret, 112 | ($token) ? $token->secret : "" 113 | ); 114 | 115 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 116 | $key = implode('&', $key_parts); 117 | 118 | return base64_encode(hash_hmac('sha1', $base_string, $key, true)); 119 | } 120 | } 121 | 122 | /** 123 | * The PLAINTEXT method does not provide any security protection and SHOULD only be used 124 | * over a secure channel such as HTTPS. It does not use the Signature Base String. 125 | * - Chapter 9.4 ("PLAINTEXT") 126 | */ 127 | class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { 128 | public function get_name() { 129 | return "PLAINTEXT"; 130 | } 131 | 132 | /** 133 | * oauth_signature is set to the concatenated encoded values of the Consumer Secret and 134 | * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is 135 | * empty. The result MUST be encoded again. 136 | * - Chapter 9.4.1 ("Generating Signatures") 137 | * 138 | * Please note that the second encoding MUST NOT happen in the SignatureMethod, as 139 | * OAuthRequest handles this! 140 | */ 141 | public function build_signature($request, $consumer, $token) { 142 | $key_parts = array( 143 | $consumer->secret, 144 | ($token) ? $token->secret : "" 145 | ); 146 | 147 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 148 | $key = implode('&', $key_parts); 149 | $request->base_string = $key; 150 | 151 | return $key; 152 | } 153 | } 154 | 155 | /** 156 | * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in 157 | * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for 158 | * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a 159 | * verified way to the Service Provider, in a manner which is beyond the scope of this 160 | * specification. 161 | * - Chapter 9.3 ("RSA-SHA1") 162 | */ 163 | abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { 164 | public function get_name() { 165 | return "RSA-SHA1"; 166 | } 167 | 168 | // Up to the SP to implement this lookup of keys. Possible ideas are: 169 | // (1) do a lookup in a table of trusted certs keyed off of consumer 170 | // (2) fetch via http using a url provided by the requester 171 | // (3) some sort of specific discovery code based on request 172 | // 173 | // Either way should return a string representation of the certificate 174 | protected abstract function fetch_public_cert(&$request); 175 | 176 | // Up to the SP to implement this lookup of keys. Possible ideas are: 177 | // (1) do a lookup in a table of trusted certs keyed off of consumer 178 | // 179 | // Either way should return a string representation of the certificate 180 | protected abstract function fetch_private_cert(&$request); 181 | 182 | public function build_signature($request, $consumer, $token) { 183 | $base_string = $request->get_signature_base_string(); 184 | $request->base_string = $base_string; 185 | 186 | // Fetch the private key cert based on the request 187 | $cert = $this->fetch_private_cert($request); 188 | 189 | // Pull the private key ID from the certificate 190 | $privatekeyid = openssl_get_privatekey($cert); 191 | 192 | // Sign using the key 193 | $ok = openssl_sign($base_string, $signature, $privatekeyid); 194 | 195 | // Release the key resource 196 | openssl_free_key($privatekeyid); 197 | 198 | return base64_encode($signature); 199 | } 200 | 201 | public function check_signature($request, $consumer, $token, $signature) { 202 | $decoded_sig = base64_decode($signature); 203 | 204 | $base_string = $request->get_signature_base_string(); 205 | 206 | // Fetch the public key cert based on the request 207 | $cert = $this->fetch_public_cert($request); 208 | 209 | // Pull the public key ID from the certificate 210 | $publickeyid = openssl_get_publickey($cert); 211 | 212 | // Check the computed signature against the one passed in the query 213 | $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); 214 | 215 | // Release the key resource 216 | openssl_free_key($publickeyid); 217 | 218 | return $ok == 1; 219 | } 220 | } 221 | 222 | class OAuthRequest { 223 | private $parameters; 224 | private $http_method; 225 | private $http_url; 226 | // for debug purposes 227 | public $base_string; 228 | public static $version = '1.0'; 229 | public static $POST_INPUT = 'php://input'; 230 | 231 | function __construct($http_method, $http_url, $parameters=NULL) { 232 | @$parameters or $parameters = array(); 233 | $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); 234 | $this->parameters = $parameters; 235 | $this->http_method = $http_method; 236 | $this->http_url = $http_url; 237 | } 238 | 239 | 240 | /** 241 | * attempt to build up a request from what was passed to the server 242 | */ 243 | public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { 244 | $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") 245 | ? 'http' 246 | : 'https'; 247 | @$http_url or $http_url = $scheme . 248 | '://' . $_SERVER['HTTP_HOST'] . 249 | ':' . 250 | $_SERVER['SERVER_PORT'] . 251 | $_SERVER['REQUEST_URI']; 252 | @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; 253 | 254 | // We weren't handed any parameters, so let's find the ones relevant to 255 | // this request. 256 | // If you run XML-RPC or similar you should use this to provide your own 257 | // parsed parameter-list 258 | if (!$parameters) { 259 | // Find request headers 260 | $request_headers = OAuthUtil::get_headers(); 261 | 262 | // Parse the query-string to find GET parameters 263 | $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); 264 | 265 | // It's a POST request of the proper content-type, so parse POST 266 | // parameters and add those overriding any duplicates from GET 267 | if ($http_method == "POST" 268 | && @strstr($request_headers["Content-Type"], 269 | "application/x-www-form-urlencoded") 270 | ) { 271 | $post_data = OAuthUtil::parse_parameters( 272 | file_get_contents(self::$POST_INPUT) 273 | ); 274 | $parameters = array_merge($parameters, $post_data); 275 | } 276 | 277 | // We have a Authorization-header with OAuth data. Parse the header 278 | // and add those overriding any duplicates from GET or POST 279 | if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { 280 | $header_parameters = OAuthUtil::split_header( 281 | $request_headers['Authorization'] 282 | ); 283 | $parameters = array_merge($parameters, $header_parameters); 284 | } 285 | 286 | } 287 | 288 | return new OAuthRequest($http_method, $http_url, $parameters); 289 | } 290 | 291 | /** 292 | * pretty much a helper function to set up the request 293 | */ 294 | public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { 295 | @$parameters or $parameters = array(); 296 | $defaults = array("oauth_version" => OAuthRequest::$version, 297 | "oauth_nonce" => OAuthRequest::generate_nonce(), 298 | "oauth_timestamp" => OAuthRequest::generate_timestamp(), 299 | "oauth_consumer_key" => $consumer->key); 300 | if ($token) 301 | $defaults['oauth_token'] = $token->key; 302 | 303 | $parameters = array_merge($defaults, $parameters); 304 | 305 | return new OAuthRequest($http_method, $http_url, $parameters); 306 | } 307 | 308 | public function set_parameter($name, $value, $allow_duplicates = true) { 309 | if ($allow_duplicates && isset($this->parameters[$name])) { 310 | // We have already added parameter(s) with this name, so add to the list 311 | if (is_scalar($this->parameters[$name])) { 312 | // This is the first duplicate, so transform scalar (string) 313 | // into an array so we can add the duplicates 314 | $this->parameters[$name] = array($this->parameters[$name]); 315 | } 316 | 317 | $this->parameters[$name][] = $value; 318 | } else { 319 | $this->parameters[$name] = $value; 320 | } 321 | } 322 | 323 | public function get_parameter($name) { 324 | return isset($this->parameters[$name]) ? $this->parameters[$name] : null; 325 | } 326 | 327 | public function get_parameters() { 328 | return $this->parameters; 329 | } 330 | 331 | public function unset_parameter($name) { 332 | unset($this->parameters[$name]); 333 | } 334 | 335 | /** 336 | * The request parameters, sorted and concatenated into a normalized string. 337 | * @return string 338 | */ 339 | public function get_signable_parameters() { 340 | // Grab all parameters 341 | $params = $this->parameters; 342 | 343 | // Remove oauth_signature if present 344 | // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 345 | if (isset($params['oauth_signature'])) { 346 | unset($params['oauth_signature']); 347 | } 348 | 349 | return OAuthUtil::build_http_query($params); 350 | } 351 | 352 | /** 353 | * Returns the base string of this request 354 | * 355 | * The base string defined as the method, the url 356 | * and the parameters (normalized), each urlencoded 357 | * and the concated with &. 358 | */ 359 | public function get_signature_base_string() { 360 | $parts = array( 361 | $this->get_normalized_http_method(), 362 | $this->get_normalized_http_url(), 363 | $this->get_signable_parameters() 364 | ); 365 | 366 | $parts = OAuthUtil::urlencode_rfc3986($parts); 367 | 368 | return implode('&', $parts); 369 | } 370 | 371 | /** 372 | * just uppercases the http method 373 | */ 374 | public function get_normalized_http_method() { 375 | return strtoupper($this->http_method); 376 | } 377 | 378 | /** 379 | * parses the url and rebuilds it to be 380 | * scheme://host/path 381 | */ 382 | public function get_normalized_http_url() { 383 | $parts = parse_url($this->http_url); 384 | 385 | $port = @$parts['port']; 386 | $scheme = $parts['scheme']; 387 | $host = $parts['host']; 388 | $path = @$parts['path']; 389 | 390 | $port or $port = ($scheme == 'https') ? '443' : '80'; 391 | 392 | if (($scheme == 'https' && $port != '443') 393 | || ($scheme == 'http' && $port != '80')) { 394 | $host = "$host:$port"; 395 | } 396 | return "$scheme://$host$path"; 397 | } 398 | 399 | /** 400 | * builds a url usable for a GET request 401 | */ 402 | public function to_url() { 403 | $post_data = $this->to_postdata(); 404 | $out = $this->get_normalized_http_url(); 405 | if ($post_data) { 406 | $out .= '?'.$post_data; 407 | } 408 | return $out; 409 | } 410 | 411 | /** 412 | * builds the data one would send in a POST request 413 | */ 414 | public function to_postdata() { 415 | return OAuthUtil::build_http_query($this->parameters); 416 | } 417 | 418 | /** 419 | * builds the Authorization: header 420 | */ 421 | public function to_header($realm=null) { 422 | $first = true; 423 | if($realm) { 424 | $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; 425 | $first = false; 426 | } else 427 | $out = 'Authorization: OAuth'; 428 | 429 | $total = array(); 430 | foreach ($this->parameters as $k => $v) { 431 | if (substr($k, 0, 5) != "oauth") continue; 432 | if (is_array($v)) { 433 | throw new OAuthException('Arrays not supported in headers'); 434 | } 435 | $out .= ($first) ? ' ' : ','; 436 | $out .= OAuthUtil::urlencode_rfc3986($k) . 437 | '="' . 438 | OAuthUtil::urlencode_rfc3986($v) . 439 | '"'; 440 | $first = false; 441 | } 442 | return $out; 443 | } 444 | 445 | public function __toString() { 446 | return $this->to_url(); 447 | } 448 | 449 | 450 | public function sign_request($signature_method, $consumer, $token) { 451 | $this->set_parameter( 452 | "oauth_signature_method", 453 | $signature_method->get_name(), 454 | false 455 | ); 456 | $signature = $this->build_signature($signature_method, $consumer, $token); 457 | $this->set_parameter("oauth_signature", $signature, false); 458 | } 459 | 460 | public function build_signature($signature_method, $consumer, $token) { 461 | $signature = $signature_method->build_signature($this, $consumer, $token); 462 | return $signature; 463 | } 464 | 465 | /** 466 | * util function: current timestamp 467 | */ 468 | private static function generate_timestamp() { 469 | return time(); 470 | } 471 | 472 | /** 473 | * util function: current nonce 474 | */ 475 | private static function generate_nonce() { 476 | $mt = microtime(); 477 | $rand = mt_rand(); 478 | 479 | return md5($mt . $rand); // md5s look nicer than numbers 480 | } 481 | } 482 | 483 | class OAuthServer { 484 | protected $timestamp_threshold = 300; // in seconds, five minutes 485 | protected $version = '1.0'; // hi blaine 486 | protected $signature_methods = array(); 487 | 488 | protected $data_store; 489 | 490 | function __construct($data_store) { 491 | $this->data_store = $data_store; 492 | } 493 | 494 | public function add_signature_method($signature_method) { 495 | $this->signature_methods[$signature_method->get_name()] = 496 | $signature_method; 497 | } 498 | 499 | // high level functions 500 | 501 | /** 502 | * process a request_token request 503 | * returns the request token on success 504 | */ 505 | public function fetch_request_token(&$request) { 506 | $this->get_version($request); 507 | 508 | $consumer = $this->get_consumer($request); 509 | 510 | // no token required for the initial token request 511 | $token = NULL; 512 | 513 | $this->check_signature($request, $consumer, $token); 514 | 515 | // Rev A change 516 | $callback = $request->get_parameter('oauth_callback'); 517 | $new_token = $this->data_store->new_request_token($consumer, $callback); 518 | 519 | return $new_token; 520 | } 521 | 522 | /** 523 | * process an access_token request 524 | * returns the access token on success 525 | */ 526 | public function fetch_access_token(&$request) { 527 | $this->get_version($request); 528 | 529 | $consumer = $this->get_consumer($request); 530 | 531 | // requires authorized request token 532 | $token = $this->get_token($request, $consumer, "request"); 533 | 534 | $this->check_signature($request, $consumer, $token); 535 | 536 | // Rev A change 537 | $verifier = $request->get_parameter('oauth_verifier'); 538 | $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); 539 | 540 | return $new_token; 541 | } 542 | 543 | /** 544 | * verify an api call, checks all the parameters 545 | */ 546 | public function verify_request(&$request) { 547 | $this->get_version($request); 548 | $consumer = $this->get_consumer($request); 549 | $token = $this->get_token($request, $consumer, "access"); 550 | $this->check_signature($request, $consumer, $token); 551 | return array($consumer, $token); 552 | } 553 | 554 | // Internals from here 555 | /** 556 | * version 1 557 | */ 558 | private function get_version(&$request) { 559 | $version = $request->get_parameter("oauth_version"); 560 | if (!$version) { 561 | // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. 562 | // Chapter 7.0 ("Accessing Protected Ressources") 563 | $version = '1.0'; 564 | } 565 | if ($version !== $this->version) { 566 | throw new OAuthException("OAuth version '$version' not supported"); 567 | } 568 | return $version; 569 | } 570 | 571 | /** 572 | * figure out the signature with some defaults 573 | */ 574 | private function get_signature_method(&$request) { 575 | $signature_method = 576 | @$request->get_parameter("oauth_signature_method"); 577 | 578 | if (!$signature_method) { 579 | // According to chapter 7 ("Accessing Protected Ressources") the signature-method 580 | // parameter is required, and we can't just fallback to PLAINTEXT 581 | throw new OAuthException('No signature method parameter. This parameter is required'); 582 | } 583 | 584 | if (!in_array($signature_method, 585 | array_keys($this->signature_methods))) { 586 | throw new OAuthException( 587 | "Signature method '$signature_method' not supported " . 588 | "try one of the following: " . 589 | implode(", ", array_keys($this->signature_methods)) 590 | ); 591 | } 592 | return $this->signature_methods[$signature_method]; 593 | } 594 | 595 | /** 596 | * try to find the consumer for the provided request's consumer key 597 | */ 598 | private function get_consumer(&$request) { 599 | $consumer_key = @$request->get_parameter("oauth_consumer_key"); 600 | if (!$consumer_key) { 601 | throw new OAuthException("Invalid consumer key"); 602 | } 603 | 604 | $consumer = $this->data_store->lookup_consumer($consumer_key); 605 | if (!$consumer) { 606 | throw new OAuthException("Invalid consumer"); 607 | } 608 | 609 | return $consumer; 610 | } 611 | 612 | /** 613 | * try to find the token for the provided request's token key 614 | */ 615 | private function get_token(&$request, $consumer, $token_type="access") { 616 | $token_field = @$request->get_parameter('oauth_token'); 617 | $token = $this->data_store->lookup_token( 618 | $consumer, $token_type, $token_field 619 | ); 620 | if (!$token) { 621 | throw new OAuthException("Invalid $token_type token: $token_field"); 622 | } 623 | return $token; 624 | } 625 | 626 | /** 627 | * all-in-one function to check the signature on a request 628 | * should guess the signature method appropriately 629 | */ 630 | private function check_signature(&$request, $consumer, $token) { 631 | // this should probably be in a different method 632 | $timestamp = @$request->get_parameter('oauth_timestamp'); 633 | $nonce = @$request->get_parameter('oauth_nonce'); 634 | 635 | $this->check_timestamp($timestamp); 636 | $this->check_nonce($consumer, $token, $nonce, $timestamp); 637 | 638 | $signature_method = $this->get_signature_method($request); 639 | 640 | $signature = $request->get_parameter('oauth_signature'); 641 | $valid_sig = $signature_method->check_signature( 642 | $request, 643 | $consumer, 644 | $token, 645 | $signature 646 | ); 647 | 648 | if (!$valid_sig) { 649 | throw new OAuthException("Invalid signature"); 650 | } 651 | } 652 | 653 | /** 654 | * check that the timestamp is new enough 655 | */ 656 | private function check_timestamp($timestamp) { 657 | if( ! $timestamp ) 658 | throw new OAuthException( 659 | 'Missing timestamp parameter. The parameter is required' 660 | ); 661 | 662 | // verify that timestamp is recentish 663 | $now = time(); 664 | if (abs($now - $timestamp) > $this->timestamp_threshold) { 665 | throw new OAuthException( 666 | "Expired timestamp, yours $timestamp, ours $now" 667 | ); 668 | } 669 | } 670 | 671 | /** 672 | * check that the nonce is not repeated 673 | */ 674 | private function check_nonce($consumer, $token, $nonce, $timestamp) { 675 | if( ! $nonce ) 676 | throw new OAuthException( 677 | 'Missing nonce parameter. The parameter is required' 678 | ); 679 | 680 | // verify that the nonce is uniqueish 681 | $found = $this->data_store->lookup_nonce( 682 | $consumer, 683 | $token, 684 | $nonce, 685 | $timestamp 686 | ); 687 | if ($found) { 688 | throw new OAuthException("Nonce already used: $nonce"); 689 | } 690 | } 691 | 692 | } 693 | 694 | class OAuthDataStore { 695 | function lookup_consumer($consumer_key) { 696 | // implement me 697 | } 698 | 699 | function lookup_token($consumer, $token_type, $token) { 700 | // implement me 701 | } 702 | 703 | function lookup_nonce($consumer, $token, $nonce, $timestamp) { 704 | // implement me 705 | } 706 | 707 | function new_request_token($consumer, $callback = null) { 708 | // return a new token attached to this consumer 709 | } 710 | 711 | function new_access_token($token, $consumer, $verifier = null) { 712 | // return a new access token attached to this consumer 713 | // for the user associated with this token if the request token 714 | // is authorized 715 | // should also invalidate the request token 716 | } 717 | 718 | } 719 | 720 | class OAuthUtil { 721 | public static function urlencode_rfc3986($input) { 722 | if (is_array($input)) { 723 | return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); 724 | } else if (is_scalar($input)) { 725 | return str_replace( 726 | '+', 727 | ' ', 728 | str_replace('%7E', '~', rawurlencode($input)) 729 | ); 730 | } else { 731 | return ''; 732 | } 733 | } 734 | 735 | 736 | // This decode function isn't taking into consideration the above 737 | // modifications to the encoding process. However, this method doesn't 738 | // seem to be used anywhere so leaving it as is. 739 | public static function urldecode_rfc3986($string) { 740 | return urldecode($string); 741 | } 742 | 743 | // Utility function for turning the Authorization: header into 744 | // parameters, has to do some unescaping 745 | // Can filter out any non-oauth parameters if needed (default behaviour) 746 | public static function split_header($header, $only_allow_oauth_parameters = true) { 747 | $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; 748 | $offset = 0; 749 | $params = array(); 750 | while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { 751 | $match = $matches[0]; 752 | $header_name = $matches[2][0]; 753 | $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; 754 | if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { 755 | $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); 756 | } 757 | $offset = $match[1] + strlen($match[0]); 758 | } 759 | 760 | if (isset($params['realm'])) { 761 | unset($params['realm']); 762 | } 763 | 764 | return $params; 765 | } 766 | 767 | // helper to try to sort out headers for people who aren't running apache 768 | public static function get_headers() { 769 | if (function_exists('apache_request_headers')) { 770 | // we need this to get the actual Authorization: header 771 | // because apache tends to tell us it doesn't exist 772 | $headers = apache_request_headers(); 773 | 774 | // sanitize the output of apache_request_headers because 775 | // we always want the keys to be Cased-Like-This and arh() 776 | // returns the headers in the same case as they are in the 777 | // request 778 | $out = array(); 779 | foreach( $headers AS $key => $value ) { 780 | $key = str_replace( 781 | " ", 782 | "-", 783 | ucwords(strtolower(str_replace("-", " ", $key))) 784 | ); 785 | $out[$key] = $value; 786 | } 787 | } else { 788 | // otherwise we don't have apache and are just going to have to hope 789 | // that $_SERVER actually contains what we need 790 | $out = array(); 791 | if( isset($_SERVER['CONTENT_TYPE']) ) 792 | $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; 793 | if( isset($_ENV['CONTENT_TYPE']) ) 794 | $out['Content-Type'] = $_ENV['CONTENT_TYPE']; 795 | 796 | foreach ($_SERVER as $key => $value) { 797 | if (substr($key, 0, 5) == "HTTP_") { 798 | // this is chaos, basically it is just there to capitalize the first 799 | // letter of every word that is not an initial HTTP and strip HTTP 800 | // code from przemek 801 | $key = str_replace( 802 | " ", 803 | "-", 804 | ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) 805 | ); 806 | $out[$key] = $value; 807 | } 808 | } 809 | } 810 | return $out; 811 | } 812 | 813 | // This function takes a input like a=b&a=c&d=e and returns the parsed 814 | // parameters like this 815 | // array('a' => array('b','c'), 'd' => 'e') 816 | public static function parse_parameters( $input ) { 817 | if (!isset($input) || !$input) return array(); 818 | 819 | $pairs = explode('&', $input); 820 | 821 | $parsed_parameters = array(); 822 | foreach ($pairs as $pair) { 823 | $split = explode('=', $pair, 2); 824 | $parameter = OAuthUtil::urldecode_rfc3986($split[0]); 825 | $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; 826 | 827 | if (isset($parsed_parameters[$parameter])) { 828 | // We have already recieved parameter(s) with this name, so add to the list 829 | // of parameters with this name 830 | 831 | if (is_scalar($parsed_parameters[$parameter])) { 832 | // This is the first duplicate, so transform scalar (string) into an array 833 | // so we can add the duplicates 834 | $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); 835 | } 836 | 837 | $parsed_parameters[$parameter][] = $value; 838 | } else { 839 | $parsed_parameters[$parameter] = $value; 840 | } 841 | } 842 | return $parsed_parameters; 843 | } 844 | 845 | public static function build_http_query($params) { 846 | if (!$params) return ''; 847 | 848 | // Urlencode both keys and values 849 | $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); 850 | $values = OAuthUtil::urlencode_rfc3986(array_values($params)); 851 | $params = array_combine($keys, $values); 852 | 853 | // Parameters are sorted by name, using lexicographical byte value ordering. 854 | // Ref: Spec: 9.1.1 (1) 855 | uksort($params, 'strcmp'); 856 | 857 | $pairs = array(); 858 | foreach ($params as $parameter => $value) { 859 | if (is_array($value)) { 860 | // If two or more parameters share the same name, they are sorted by their value 861 | // Ref: Spec: 9.1.1 (1) 862 | natsort($value); 863 | foreach ($value as $duplicate_value) { 864 | $pairs[] = $parameter . '=' . $duplicate_value; 865 | } 866 | } else { 867 | $pairs[] = $parameter . '=' . $value; 868 | } 869 | } 870 | // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 871 | // Each name-value pair is separated by an '&' character (ASCII code 38) 872 | return implode('&', $pairs); 873 | } 874 | } 875 | -------------------------------------------------------------------------------- /v1/Components/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 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.AppDotNetFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'text')); 17 | $feeds = explode(',', $modx->getOption('userId', $scriptProperties, '')); 18 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 19 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 20 | 21 | $rawFeedData = array(); 22 | $cacheName = str_replace(" ", "-", $cacheName); 23 | 24 | foreach ($feeds as $user) { 25 | $cacheId = 'appdotnetfeed-'.$cacheName.'-'.$user; 26 | 27 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 28 | if ($ch === null) { 29 | $ch = curl_init(); 30 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 31 | curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0); 32 | } 33 | 34 | curl_setopt_array($ch, array( 35 | CURLOPT_URL => str_replace(array('{userId}', '{limit}'), array($user, $limit), $feedUrl), 36 | )); 37 | 38 | $json = curl_exec($ch); 39 | if (empty($json)) { 40 | continue; 41 | } 42 | 43 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 44 | } 45 | 46 | $feed = json_decode($json); 47 | 48 | if ($feed === null) { 49 | continue; 50 | } 51 | 52 | $feeditems = $feed->data; 53 | 54 | $i = 0; 55 | 56 | foreach ($feeditems as $message) { 57 | foreach ($excludeEmpty as $k) { 58 | if ($message->$k == '') { 59 | continue 2; 60 | } 61 | } 62 | 63 | $rawFeedData[$i] = array( 64 | 'id' => $message->id, 65 | 'text' => $message->text, 66 | 'html' => $message->html, 67 | 'created' => strtotime($message->created_at), 68 | 'picture' => $message->user->avatar_image->url, 69 | 'title' => $message->user->name, 70 | 'username' => $message->user->username, 71 | 'profile' => $message->user->canonical_url, 72 | 'postUrl' => $message->canonical_url, 73 | ); 74 | 75 | $i++; 76 | } 77 | } 78 | 79 | if ($ch !== null) { 80 | curl_close($ch); 81 | } 82 | 83 | $output = ''; 84 | foreach ($rawFeedData as $message) { 85 | $output .= $modx->getChunk($tpl, $message); 86 | } 87 | 88 | return $output; 89 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.DeliciousFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'd')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 18 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 19 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 20 | 21 | $rawFeedData = array(); 22 | $cacheName = str_replace(" ", "-", $cacheName); 23 | 24 | foreach ($feeds as $username) { 25 | $cacheId = 'deliciousfeed-'.$cacheName.'-'.$username; 26 | 27 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 28 | if ($ch === null) { 29 | $ch = curl_init(); 30 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 31 | } 32 | 33 | curl_setopt_array($ch, array( 34 | CURLOPT_URL => str_replace(array('{username}', '{limit}'), array($username, $limit), $feedUrl), 35 | )); 36 | 37 | $json = curl_exec($ch); 38 | if (empty($json)) { 39 | continue; 40 | } 41 | 42 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 43 | } 44 | 45 | $feed = json_decode($json); 46 | 47 | if ($feed === null) { 48 | continue; 49 | } 50 | 51 | 52 | foreach ($feed as $item) { 53 | foreach ($excludeEmpty as $k) { 54 | if ($item->$k == '') { 55 | continue 2; 56 | } 57 | } 58 | 59 | $rawFeedData[] = array( 60 | 'title' => $item->d, 61 | 'link' => $item->u, 62 | 'date' => strtotime($item->dt), 63 | 'description' => $item->n, 64 | 'username' => $username, 65 | ); 66 | 67 | } 68 | 69 | } 70 | 71 | if ($ch !== null) { 72 | curl_close($ch); 73 | } 74 | 75 | $output = ''; 76 | foreach ($rawFeedData as $item) { 77 | $output .= $modx->getChunk($tpl, $item); 78 | } 79 | 80 | return $output; 81 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.FlickrFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'url_m')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '3')); 18 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 19 | $userName = $modx->getOption('userName', $scriptProperties, ''); 20 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 21 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 22 | 23 | $rawFeedData = array(); 24 | $cacheName = str_replace(" ", "-", $cacheName); 25 | 26 | foreach ($feeds as $userId) { 27 | $cacheId = 'flickrfeed-'.$cacheName.'-'.$userId; 28 | 29 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 30 | if ($ch === null) { 31 | $ch = curl_init(); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 33 | } 34 | 35 | curl_setopt_array($ch, array( 36 | CURLOPT_URL => str_replace(array('{apikey}', '{userid}', '{limit}'), array($apiKey, $userId, $limit), $feedUrl), 37 | )); 38 | 39 | 40 | $json = curl_exec($ch); 41 | if (empty($json)) { 42 | continue; 43 | } 44 | 45 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 46 | } 47 | 48 | $feed = json_decode($json); 49 | 50 | if ($feed === null) { 51 | continue; 52 | } 53 | 54 | foreach ($feed->photos->photo as $photo) { 55 | foreach ($excludeEmpty as $k) { 56 | if ($photo->$k == '') { 57 | continue 2; 58 | } 59 | } 60 | 61 | $rawFeedData[] = array( 62 | 'id' => $photo->id, 63 | 'created' => $photo->dateupload, 64 | 'picture' => $photo->url_m, 65 | 'picturelarge' => $photo->url_l, 66 | 'title' => $photo->title, 67 | 'username' => $userName, 68 | ); 69 | } 70 | } 71 | 72 | if ($ch !== null) { 73 | curl_close($ch); 74 | } 75 | 76 | $output = ''; 77 | foreach ($rawFeedData as $photo) { 78 | $output .= $modx->getChunk($tpl, $photo); 79 | } 80 | 81 | return $output; 82 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.GoogleCalendarFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 16 | $limit = $modx->getOption('limit', $scriptProperties, 2); 17 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'link')); 18 | $feeds = explode(',', $modx->getOption('feedLocation', $scriptProperties, '')); 19 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 20 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 21 | 22 | $rawFeedData = array(); 23 | $cacheName = str_replace(" ", "-", $cacheName); 24 | 25 | foreach ($feeds as $username) { 26 | $cacheId = 'googlecalendarfeed-'.$cacheName.'-'.$username; 27 | 28 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 29 | if ($ch === null) { 30 | $ch = curl_init(); 31 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 32 | } 33 | 34 | curl_setopt_array($ch, array( 35 | CURLOPT_URL => str_replace(array('{feedlocation}', '{limit}'), array($username, $limit), $feedUrl), 36 | )); 37 | 38 | 39 | $json = curl_exec($ch); 40 | if (empty($json)) { 41 | continue; 42 | } 43 | 44 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 45 | } 46 | 47 | $feed = json_decode($json); 48 | 49 | 50 | if ($feed === null) { 51 | continue; 52 | } 53 | 54 | $feeditems = $feed->feed; 55 | 56 | $timezone = $feeditems->{'gCal$timezone'}->value; 57 | 58 | foreach ($feeditems->entry as $event) { 59 | 60 | foreach ($excludeEmpty as $k) { 61 | if ($event->$k == '') { 62 | continue 2; 63 | } 64 | } 65 | 66 | $videoId = substr($event->id->{'$t'},42); 67 | 68 | $rawFeedData[] = array( 69 | 'published' => strtotime($event->published->{'$t'}), 70 | 'timezone' => $timezone, 71 | 'title' => $event->title->{'$t'}, 72 | 'content' => $event->content->{'$t'}, 73 | 'link' => $event->link[0]->href, 74 | 'calendarName' => $event->title->{'$t'}, 75 | 'eventEnd' => strtotime($event->{'gd$when'}[0]->endTime), 76 | 'eventStart' => strtotime($event->{'gd$when'}[0]->startTime), 77 | 'location' => $event->{'gd$where'}[0]->valueString, 78 | ); 79 | } 80 | } 81 | 82 | if ($ch !== null) { 83 | curl_close($ch); 84 | } 85 | 86 | $output = ''; 87 | 88 | foreach ($rawFeedData as $image) { 89 | $output .= $modx->getChunk($tpl, $image); 90 | } 91 | 92 | return $output; 93 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.GooglePlusFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 16 | $limit = $modx->getOption('limit', $scriptProperties, 2); 17 | $userId = $modx->getOption('userId', $scriptProperties, ''); 18 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 19 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, '')); 20 | $feeds = explode(',', $modx->getOption('cacheName', $scriptProperties, 'default')); 21 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 22 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 23 | 24 | $rawFeedData = array(); 25 | $cacheName = str_replace(" ", "-", $cacheName); 26 | $output = ''; 27 | 28 | foreach ($feeds as $feed) { 29 | $cacheId = 'googleplusfeed-'.$cacheName.'-'.$userId; 30 | 31 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 32 | if ($ch === null) { 33 | $ch = curl_init(); 34 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 35 | } 36 | 37 | curl_setopt_array($ch, array( 38 | CURLOPT_URL => str_replace(array('{apikey}', '{userid}', '{limit}'), array($apiKey, $userId, $limit), $feedUrl), 39 | )); 40 | 41 | $json = curl_exec($ch); 42 | if (empty($json)) { 43 | continue; 44 | } 45 | 46 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 47 | } 48 | 49 | $feed = json_decode($json); 50 | 51 | if ($feed === null) { 52 | continue; 53 | } 54 | 55 | $i = 0; 56 | 57 | foreach ($feed->items as $message) { 58 | 59 | $rawFeedData[$i] = array( 60 | 'avatar' => $message->actor->image->url, 61 | 'displayName' => $message->actor->displayName, 62 | 'profileUrl' => $message->actor->url, 63 | 'postId' => $message->id, 64 | 'postDate' => strtotime($message->published), 65 | 'text' => $message->title, 66 | 'html' => $message->object->content, 67 | 'url' => $message->url, 68 | 'attachmentUrl' => $message->object->attachments->url, 69 | 'repliesCount' => $message->object->replies->totalItems, 70 | 'plusCount' => $message->object->plusoners->totalItems, 71 | 'resharesCount' => $message->object->resharers->totalItems, 72 | ); 73 | 74 | $i++; 75 | 76 | } 77 | } 78 | 79 | if ($ch !== null) { 80 | curl_close($ch); 81 | } 82 | 83 | foreach ($rawFeedData as $message) { 84 | $output .= $modx->getChunk($tpl, $message); 85 | } 86 | 87 | return $output; 88 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.LastFmFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'name')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 18 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 19 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 20 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 21 | 22 | $rawFeedData = array(); 23 | $cacheName = str_replace(" ", "-", $cacheName); 24 | 25 | foreach ($feeds as $username) { 26 | $cacheId = 'lastfmfeed-'.$cacheName.'-'.$username; 27 | 28 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 29 | if ($ch === null) { 30 | $ch = curl_init(); 31 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 32 | } 33 | 34 | curl_setopt_array($ch, array( 35 | CURLOPT_URL => str_replace(array('{apikey}', '{username}', '{limit}'), array($apiKey, $username, $limit), $feedUrl), 36 | )); 37 | 38 | $json = curl_exec($ch); 39 | if (empty($json)) { 40 | continue; 41 | } 42 | 43 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 44 | } 45 | 46 | $feed = json_decode($json); 47 | 48 | if ($feed === null) { 49 | continue; 50 | } 51 | 52 | $feedtracks = $feed->lovedtracks; 53 | 54 | foreach ($feedtracks->track as $item) { 55 | foreach ($excludeEmpty as $k) { 56 | if ($item->$k == '') { 57 | continue 2; 58 | } 59 | } 60 | 61 | $rawFeedData[] = array( 62 | 'track' => $item->name, 63 | 'artist' => $item->artist->name, 64 | 'link' => $item->url, 65 | 'picture' => $item->image[3]->{'#text'}, 66 | 'date' => $item->date->uts, 67 | 'username' => $username, 68 | ); 69 | 70 | } 71 | 72 | } 73 | 74 | if ($ch !== null) { 75 | curl_close($ch); 76 | } 77 | 78 | $output = ''; 79 | foreach ($rawFeedData as $item) { 80 | $output .= $modx->getChunk($tpl, $item); 81 | } 82 | 83 | return $output; 84 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.LastFmListensFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'name')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 18 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 19 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 20 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 21 | 22 | $rawFeedData = array(); 23 | $cacheName = str_replace(" ", "-", $cacheName); 24 | 25 | foreach ($feeds as $username) { 26 | $cacheId = 'lastfmlistensfeed-'.$cacheName.'-'.$username; 27 | 28 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 29 | if ($ch === null) { 30 | $ch = curl_init(); 31 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 32 | } 33 | 34 | curl_setopt_array($ch, array( 35 | CURLOPT_URL => str_replace(array('{apikey}', '{username}', '{limit}'), array($apiKey, $username, $limit), $feedUrl), 36 | )); 37 | 38 | $json = curl_exec($ch); 39 | if (empty($json)) { 40 | continue; 41 | } 42 | 43 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 44 | } 45 | 46 | $feed = json_decode($json); 47 | 48 | if ($feed === null) { 49 | continue; 50 | } 51 | 52 | $feedtracks = $feed->recenttracks; 53 | 54 | foreach ($feedtracks->track as $item) { 55 | foreach ($excludeEmpty as $k) { 56 | if ($item->$k == '') { 57 | continue 2; 58 | } 59 | } 60 | 61 | $rawFeedData[] = array( 62 | 'track' => $item->name, 63 | 'artist' => $item->artist->name, 64 | 'link' => $item->url, 65 | 'picture' => $item->image[3]->{'#text'}, 66 | 'date' => $item->date->uts, 67 | 'username' => $username, 68 | ); 69 | 70 | } 71 | 72 | } 73 | 74 | if ($ch !== null) { 75 | curl_close($ch); 76 | } 77 | 78 | $output = ''; 79 | foreach ($rawFeedData as $item) { 80 | $output .= $modx->getChunk($tpl, $item); 81 | } 82 | 83 | return $output; 84 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.PicasaFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'content')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '3')); 18 | $albumId = $modx->getOption('albumId', $scriptProperties, ''); 19 | $albumName = $modx->getOption('albumName', $scriptProperties, ''); 20 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 21 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 22 | 23 | $rawFeedData = array(); 24 | $cacheName = str_replace(" ", "-", $cacheName); 25 | 26 | foreach ($feeds as $userId) { 27 | $cacheId = 'picasafeed-'.$cacheName.'-'.$userId; 28 | 29 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 30 | if ($ch === null) { 31 | $ch = curl_init(); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 33 | } 34 | 35 | curl_setopt_array($ch, array( 36 | CURLOPT_URL => str_replace(array('{userid}', '{albumid}'), array($userId, $albumId), $feedUrl), 37 | )); 38 | 39 | 40 | $json = curl_exec($ch); 41 | if (empty($json)) { 42 | continue; 43 | } 44 | 45 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 46 | } 47 | 48 | $feed = json_decode($json); 49 | 50 | if ($feed === null) { 51 | continue; 52 | } 53 | 54 | $counter = NULL; 55 | 56 | $feeditems = $feed->feed; 57 | 58 | foreach ($feeditems->entry as $photo) { 59 | $counter++; 60 | 61 | if($counter>$limit){ 62 | break; 63 | } 64 | 65 | foreach ($excludeEmpty as $k) { 66 | if ($photo->$k == '') { 67 | continue 2; 68 | } 69 | } 70 | 71 | $rawFeedData[] = array( 72 | 'link' => $photo->link[1]->href, 73 | 'albumid' => $albumId, 74 | 'created' => strtotime($photo->published->{'$t'}), 75 | 'picture' => $photo->content->src, 76 | 'title' => $photo->{'media$group'}->{'media$title'}->{'$t'}, 77 | 'userid' => $userId, 78 | 'albumname' => $albumName, 79 | ); 80 | } 81 | } 82 | 83 | if ($ch !== null) { 84 | curl_close($ch); 85 | } 86 | 87 | $output = ''; 88 | foreach ($rawFeedData as $photo) { 89 | $output .= $modx->getChunk($tpl, $photo); 90 | } 91 | 92 | return $output; 93 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.TumblrFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $feeds = explode(',', $modx->getOption('blogUrl', $scriptProperties, '')); 17 | $postType = $modx->getOption('postType', $scriptProperties, ''); 18 | $tag = $modx->getOption('tag', $scriptProperties, ''); 19 | $notesInfo = $modx->getOption('notesInfo', $scriptProperties, 'false'); 20 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 21 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 22 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 23 | 24 | $rawFeedData = array(); 25 | $cacheName = str_replace(" ", "-", $cacheName); 26 | 27 | foreach ($feeds as $tumblr) { 28 | $cacheId = 'tumblrfeed-'.$cacheName.'-'.$tumblr; 29 | 30 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 31 | if ($ch === null) { 32 | $ch = curl_init(); 33 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 34 | curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0); 35 | } 36 | 37 | curl_setopt_array($ch, array( 38 | CURLOPT_URL => str_replace(array('{apikey}', '{posttype}', '{limit}', '{tag}', '{notesinfo}', '{blogurl}'), array($apiKey, '/'.$postType, $limit, $tag, $notesInfo, $blogUrl), $feedUrl), 39 | )); 40 | 41 | $json = curl_exec($ch); 42 | if (empty($json)) { 43 | continue; 44 | } 45 | 46 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 47 | } 48 | 49 | $feed = json_decode($json); 50 | 51 | if ($feed === null) { 52 | continue; 53 | } 54 | 55 | $feeditems = $feed->response->posts; 56 | 57 | $blogName = $feed->response->blog->title; 58 | $blogUrl = $feed->response->blog->url; 59 | $blogDescription = $feed->response->blog->description; 60 | 61 | $i = 0; 62 | 63 | foreach ($feeditems as $post) { 64 | 65 | $rawFeedData[$i] = array( 66 | 'id' => $post->id, 67 | 'post' => $post->text, 68 | 'created' => strtotime($post->timestamp), 69 | 'createdDate' => $post->date, 70 | 'blogName' => $blogName, 71 | 'blogUrl' => $blogUrl, 72 | 'blogDescription' => $blogDescription, 73 | 'postUrl' => $post->post_url, 74 | 'postType' => $post->type, 75 | 'shortUrl' => $post->short_url, 76 | ); 77 | 78 | if($post->type=='video'){ 79 | $rawFeedData[$i]['caption'] = $post->caption; 80 | $rawFeedData[$i]['videoPermalink'] = $post->permalink_url; 81 | $rawFeedData[$i]['thumbnail'] = $post->thumbnail_url; 82 | $rawFeedData[$i]['player250'] = $post->player[0]->embed_code; 83 | $rawFeedData[$i]['player400'] = $post->player[1]->embed_code; 84 | $rawFeedData[$i]['player500'] = $post->player[2]->embed_code; 85 | } 86 | 87 | if($post->type=='link'){ 88 | $rawFeedData[$i]['title'] = $post->title; 89 | $rawFeedData[$i]['linkUrl'] = $post->url; 90 | $rawFeedData[$i]['linkDescription'] = $post->description; 91 | } 92 | 93 | if($post->type=='text'){ 94 | $rawFeedData[$i]['title'] = $post->title; 95 | $rawFeedData[$i]['content'] = $post->body; 96 | } 97 | 98 | if($post->type=='audio'){ 99 | $rawFeedData[$i]['audioSourceUrl'] = $post->caption; 100 | $rawFeedData[$i]['audioSourceTitle'] = $post->source_title; 101 | $rawFeedData[$i]['artist'] = $post->artist; 102 | $rawFeedData[$i]['album'] = $post->album; 103 | $rawFeedData[$i]['trackName'] = $post->track_name; 104 | $rawFeedData[$i]['player'] = $post->player; 105 | $rawFeedData[$i]['audioUrl'] = $post->audio_url; 106 | } 107 | 108 | if($post->type=='photo'){ 109 | $rawFeedData[$i]['caption'] = $post->caption; 110 | $rawFeedData[$i]['imagePermalink'] = $post->image_permalink; 111 | $rawFeedData[$i]['image'] = $post->photos->original_size->url; 112 | } 113 | 114 | $i++; 115 | 116 | } 117 | } 118 | 119 | if ($ch !== null) { 120 | curl_close($ch); 121 | } 122 | 123 | $output = ''; 124 | foreach ($rawFeedData as $message) { 125 | $output .= $modx->getChunk($tpl, $message); 126 | } 127 | 128 | return $output; 129 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.TwitterFeedNew.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 12 | $limit = $modx->getOption('limit', $scriptProperties, 2); 13 | $screenName = $modx->getOption('screenName', $scriptProperties, ''); 14 | $includeRTs = $modx->getOption('includeRTs', $scriptProperties, 1); 15 | $timelineType = $modx->getOption('timelineType', $scriptProperties, 'user_timeline'); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'text')); 17 | $cacheName = $modx->getOption('cacheName', $scriptProperties, 'twitter'); 18 | $consumerKey = $modx->getOption('consumerKey', $scriptProperties, ''); 19 | $consumerSecret = $modx->getOption('consumerSecret', $scriptProperties, ''); 20 | $accessToken = $modx->getOption('accessToken', $scriptProperties, ''); 21 | $accessTokenSecret = $modx->getOption('accessTokenSecret', $scriptProperties, ''); 22 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 23 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 24 | 25 | $rawFeedData = array(); 26 | $cacheName = str_replace(" ", "-", $cacheName); 27 | $output = ''; 28 | 29 | if ($screenName != '') { 30 | $cacheId = 'twitterfeednew-'.$screenName.'-'.$cacheName; 31 | }else{ 32 | $cacheId = 'twitterfeednew-'.$cacheName; 33 | } 34 | 35 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 36 | require_once $modx->getOption('core_path').'components/jsonderulo/twitteroauth/twitteroauth.php'; 37 | $fetch = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret); 38 | $fetch->host = "https://api.twitter.com/1.1/"; 39 | $fetch->format = 'json'; 40 | $fetch->decode_json = FALSE; 41 | $fetch->ssl_verifypeer = FALSE; 42 | $json = $fetch->get('statuses/'.$timelineType, array('include_rts' => $includeRTs, 'count' => $limit, 'screen_name' => $user)); 43 | 44 | if(!empty($json)) { 45 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 46 | } 47 | } 48 | 49 | $feed = json_decode($json); 50 | 51 | if ($feed === null) { 52 | $message['message'] = 'No tweets returned.'; 53 | $output = $modx->getChunk($tpl, $message); 54 | } else { 55 | $i = 0; 56 | 57 | foreach ($feed as $message) { 58 | foreach ($excludeEmpty as $k) { 59 | if ($message->$k == '') { 60 | continue 2; 61 | } 62 | } 63 | 64 | $input = $message->text; 65 | // Convert URLs into hyperlinks 66 | $input= preg_replace("/(http:\/\/)(.*?)\/([\w\.\/\&\=\?\-\,\:\;\#\_\~\%\+]*)/", "\\0", $input); 67 | // Convert usernames (@) into links 68 | $input= preg_replace("(@([a-zA-Z0-9\_]+))", "\\0", $input); 69 | // Convert hash tags (#) to links 70 | $input= preg_replace('/(^|\s)#(\w+)/', '\1#\2', $input); 71 | 72 | $rawFeedData[$i] = array( 73 | 'id' => $message->id_str, 74 | 'message' => $input, 75 | 'created' => strtotime($message->created_at), 76 | 'picture' => $message->user->profile_image_url, 77 | 'title' => $message->user->name, 78 | 'username' => $message->user->screen_name, 79 | 'retweetCount' => $message->retweet_count, 80 | 'isRetweet' => '0', 81 | 'mediaThumb' =>$message->entities->media[0]->media_url.':thumb', 82 | 'mediaSmall' =>$message->entities->media[0]->media_url.':small', 83 | 'mediaMedium' =>$message->entities->media[0]->media_url.':medium', 84 | 'mediaLarge' =>$message->entities->media[0]->media_url.':large', 85 | ); 86 | 87 | if(isset($message->retweeted_status)){ 88 | $rawFeedData[$i]['originalAuthorPicture'] = $message->retweeted_status->user->profile_image_url; 89 | $rawFeedData[$i]['originalAuthor'] = $message->retweeted_status->user->name; 90 | $rawFeedData[$i]['originalUsername'] = $message->retweeted_status->user->screen_name; 91 | $rawFeedData[$i]['isRetweet'] = '1'; 92 | $rawFeedData[$i]['originalId'] = $message->retweeted_status->id; 93 | } 94 | 95 | $i++; 96 | } 97 | 98 | foreach ($rawFeedData as $message) { 99 | $output .= $modx->getChunk($tpl, $message); 100 | } 101 | } 102 | 103 | return $output; 104 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.TwitterFeedNewMultipleFeeds.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 11 | $limit = $modx->getOption('limit', $scriptProperties, 2); 12 | $screenName = explode(',', $modx->getOption('screenName', $scriptProperties, '')); 13 | $includeRTs = $modx->getOption('includeRTs', $scriptProperties, 1); 14 | $timelineType = $modx->getOption('timelineType', $scriptProperties, 'user_timeline'); 15 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'text')); 16 | $consumerKey = $modx->getOption('consumerKey', $scriptProperties, ''); 17 | $consumerSecret =$modx->getOption('consumerSecret', $scriptProperties, ''); 18 | $accessToken = $modx->getOption('accessToken', $scriptProperties, ''); 19 | $accessTokenSecret = $modx->getOption('accessTokenSecret', $scriptProperties, ''); 20 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 21 | 22 | $rawFeedData = array(); 23 | $output = ''; 24 | 25 | foreach ($screenName as $user) { 26 | 27 | $cacheId = 'twitterfeednewmultiplefeeds-'.$user; 28 | 29 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 30 | require_once $modx->getOption('core_path').'components/jsonderulo/twitteroauth/twitteroauth.php'; 31 | $fetch = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret); 32 | $fetch->host = "https://api.twitter.com/1.1/"; 33 | $fetch->format = 'json'; 34 | $fetch->decode_json = FALSE; 35 | $fetch->ssl_verifypeer = FALSE; 36 | $json = $fetch->get('statuses/'.$timelineType, array('include_rts' => $includeRTs, 'count' => $limit, 'screen_name' => $user)); 37 | 38 | if(!empty($json)) { 39 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 40 | } 41 | } 42 | 43 | $feed = json_decode($json); 44 | 45 | if ($feed === null) { 46 | $message['message'] = 'No tweets returned.'; 47 | $output = $modx->getChunk($tpl, $message); 48 | } else { 49 | $i = 0; 50 | 51 | foreach ($feed as $message) { 52 | foreach ($excludeEmpty as $k) { 53 | if ($message->$k == '') { 54 | continue 2; 55 | } 56 | } 57 | 58 | $input = $message->text; 59 | // Convert URLs into hyperlinks 60 | $input= preg_replace("/(http:\/\/)(.*?)\/([\w\.\/\&\=\?\-\,\:\;\#\_\~\%\+]*)/", "\\0", $input); 61 | // Convert usernames (@) into links 62 | $input= preg_replace("(@([a-zA-Z0-9\_]+))", "\\0", $input); 63 | // Convert hash tags (#) to links 64 | $input= preg_replace('/(^|\s)#(\w+)/', '\1#\2', $input); 65 | 66 | $rawFeedData[$i] = array( 67 | 'id' => $message->id_str, 68 | 'message' => $input, 69 | 'created' => strtotime($message->created_at), 70 | 'picture' => $message->user->profile_image_url, 71 | 'title' => $message->user->name, 72 | 'username' => $message->user->screen_name, 73 | 'retweetCount' => $message->retweet_count, 74 | 'isRetweet' => '0', 75 | 'mediaThumb' =>$message->entities->media[0]->media_url.':thumb', 76 | 'mediaSmall' =>$message->entities->media[0]->media_url.':small', 77 | 'mediaMedium' =>$message->entities->media[0]->media_url.':medium', 78 | 'mediaLarge' =>$message->entities->media[0]->media_url.':large', 79 | ); 80 | 81 | if(isset($message->retweeted_status)){ 82 | $rawFeedData[$i]['originalAuthorPicture'] = $message->retweeted_status->user->profile_image_url; 83 | $rawFeedData[$i]['originalAuthor'] = $message->retweeted_status->user->name; 84 | $rawFeedData[$i]['originalUsername'] = $message->retweeted_status->user->screen_name; 85 | $rawFeedData[$i]['isRetweet'] = '1'; 86 | $rawFeedData[$i]['originalId'] = $message->retweeted_status->id; 87 | } 88 | 89 | $i++; 90 | } 91 | 92 | foreach ($rawFeedData as $item) { 93 | $output .= $modx->getChunk($tpl, $item); 94 | } 95 | } 96 | } 97 | 98 | return $output; 99 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.VimeoFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, '2'); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'title')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 18 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 19 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 20 | 21 | $rawFeedData = array(); 22 | $cacheName = str_replace(" ", "-", $cacheName); 23 | 24 | foreach ($feeds as $username) { 25 | $cacheId = 'vimeofeed-'.$cacheName.'-'.$username; 26 | 27 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 28 | if ($ch === null) { 29 | $ch = curl_init(); 30 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 31 | } 32 | 33 | curl_setopt_array($ch, array( 34 | CURLOPT_URL => str_replace(array('{username}'), array($username), $feedUrl), 35 | )); 36 | 37 | 38 | $json = curl_exec($ch); 39 | if (empty($json)) { 40 | continue; 41 | } 42 | 43 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 44 | } 45 | 46 | $feed = json_decode($json); 47 | 48 | if ($feed === null) { 49 | continue; 50 | } 51 | 52 | $counter = NULL; 53 | 54 | foreach ($feed as $video) { 55 | $counter++; 56 | 57 | if($counter>$limit){ 58 | break; 59 | } 60 | 61 | foreach ($excludeEmpty as $k) { 62 | if ($video->$k == '') { 63 | continue 2; 64 | } 65 | } 66 | 67 | $rawFeedData[] = array( 68 | 'id' => $video->id, 69 | 'url' => $video->url, 70 | 'created' => strtotime($video->upload_date), 71 | 'picture' => $video->thumbnail_large, 72 | 'title' => $video->title, 73 | 'username' => $userName, 74 | ); 75 | } 76 | } 77 | 78 | if ($ch !== null) { 79 | curl_close($ch); 80 | } 81 | 82 | $output = ''; 83 | foreach ($rawFeedData as $video) { 84 | $output .= $modx->getChunk($tpl, $video); 85 | } 86 | 87 | return $output; 88 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.YouTubeFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $startIndex = $modx->getOption('startIndex', $scriptProperties, 1); 17 | $videoParams = $modx->getOption('videoParams', $scriptProperties, '?fs=1'); 18 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'link')); 19 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 20 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 21 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 22 | 23 | $rawFeedData = array(); 24 | $cacheName = str_replace(" ", "-", $cacheName); 25 | 26 | foreach ($feeds as $username) { 27 | $cacheId = 'youtubefeed-'.$cacheName.'-'.$username; 28 | 29 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 30 | if ($ch === null) { 31 | $ch = curl_init(); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 33 | } 34 | 35 | curl_setopt_array($ch, array( 36 | CURLOPT_URL => str_replace(array('{username}', '{limit}', '{offset}'), array($username, $limit, $startIndex), $feedUrl), 37 | )); 38 | 39 | 40 | $json = curl_exec($ch); 41 | if (empty($json)) { 42 | continue; 43 | } 44 | 45 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 46 | } 47 | 48 | $feed = json_decode($json); 49 | 50 | if ($feed === null) { 51 | continue; 52 | } 53 | 54 | $feeditems = $feed->feed; 55 | 56 | foreach ($feeditems->entry as $video) { 57 | 58 | foreach ($excludeEmpty as $k) { 59 | if ($video->$k == '') { 60 | continue 2; 61 | } 62 | } 63 | 64 | $videoId = substr($video->id->{'$t'},42); 65 | 66 | $rawFeedData[] = array( 67 | 'published' => strtotime($video->published->{'$t'}), 68 | 'picture' => $video->{'media$group'}->{'media$thumbnail'}[0]->url, 69 | 'title' => $video->title->{'$t'}, 70 | 'ytlink' => $video->link[0]->href, 71 | 'embedlink' => 'https://www.youtube.com/v/' .$videoId. $videoParams, 72 | 'author' => $video->author[0]->name->{'$t'}, 73 | ); 74 | } 75 | } 76 | 77 | if ($ch !== null) { 78 | curl_close($ch); 79 | } 80 | 81 | $output = ''; 82 | 83 | foreach ($rawFeedData as $image) { 84 | $output .= $modx->getChunk($tpl, $image); 85 | } 86 | 87 | return $output; 88 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.YouTubeFeedAPIV3PublicPlaylist.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 16 | $limit = $modx->getOption('limit', $scriptProperties, 2); 17 | $playlist = $modx->getOption('playlistId', $scriptProperties, ''); 18 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 19 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 20 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 21 | 22 | $rawFeedData = array(); 23 | $cacheName = str_replace(" ", "-", $cacheName); 24 | 25 | $cacheId = 'youtubefeedv3publicplaylist-'.$cacheName.'-'.$playlist; 26 | 27 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 28 | if ($ch === null) { 29 | $ch = curl_init(); 30 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 31 | } 32 | 33 | curl_setopt_array($ch, array( 34 | CURLOPT_URL => str_replace(array('{playlistid}', '{limit}', '{apikey}'), array($playlist, $limit, $apiKey), $feedUrl), 35 | )); 36 | 37 | 38 | $json = curl_exec($ch); 39 | if (empty($json)) { 40 | continue; 41 | } 42 | 43 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 44 | } 45 | 46 | $feed = json_decode($json); 47 | 48 | if ($feed === null) { 49 | $image['title'] = 'No videos returned.'; 50 | $output = $modx->getChunk($tpl, $image); 51 | } else { 52 | 53 | foreach ($feed->items as $video) { 54 | $rawFeedData[] = array( 55 | 'published' => strtotime($video->snippet->publishedAt), 56 | 'picture' => $video->snippet->thumbnails->high->url, 57 | 'title' => $video->snippet->title, 58 | 'description' => $video->snippet->description, 59 | 'ytlink' => 'http://www.youtube.com/watch?v=' . $video->snippet->resourceId->videoId, 60 | 'embedlink' => 'https://www.youtube.com/v/' . $video->snippet->resourceId->videoId, 61 | 'author' => $video->author[0]->name->{'$t'}, 62 | ); 63 | } 64 | 65 | 66 | if ($ch !== null) { 67 | curl_close($ch); 68 | } 69 | 70 | $output = ''; 71 | 72 | foreach ($rawFeedData as $image) { 73 | $output .= $modx->getChunk($tpl, $image); 74 | } 75 | 76 | } 77 | 78 | return $output; 79 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.YouTubeFeedUploads.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $startIndex = $modx->getOption('startIndex', $scriptProperties, 1); 17 | $videoParams = $modx->getOption('videoParams', $scriptProperties, '?fs=1'); 18 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'link')); 19 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 20 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 21 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 22 | 23 | $rawFeedData = array(); 24 | $cacheName = str_replace(" ", "-", $cacheName); 25 | 26 | foreach ($feeds as $username) { 27 | $cacheId = 'youtubeuploadsfeed-'.$cacheName.'-'.$username; 28 | 29 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 30 | if ($ch === null) { 31 | $ch = curl_init(); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 33 | } 34 | 35 | curl_setopt_array($ch, array( 36 | CURLOPT_URL => str_replace(array('{username}', '{limit}', '{offset}'), array($username, $limit, $startIndex), $feedUrl), 37 | )); 38 | 39 | 40 | $json = curl_exec($ch); 41 | if (empty($json)) { 42 | continue; 43 | } 44 | 45 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 46 | } 47 | 48 | $feed = json_decode($json); 49 | 50 | if ($feed === null) { 51 | continue; 52 | } 53 | 54 | $feeditems = $feed->feed; 55 | 56 | foreach ($feeditems->entry as $video) { 57 | 58 | foreach ($excludeEmpty as $k) { 59 | if ($video->$k == '') { 60 | continue 2; 61 | } 62 | } 63 | 64 | $videoId = substr($video->id->{'$t'},42); 65 | 66 | $rawFeedData[] = array( 67 | 'published' => strtotime($video->published->{'$t'}), 68 | 'picture' => $video->{'media$group'}->{'media$thumbnail'}[0]->url, 69 | 'title' => $video->title->{'$t'}, 70 | 'ytlink' => $video->link[0]->href, 71 | 'embedlink' => 'https://www.youtube.com/v/' .$videoId. $videoParams, 72 | 'author' => $video->author[0]->name->{'$t'}, 73 | ); 74 | } 75 | } 76 | 77 | if ($ch !== null) { 78 | curl_close($ch); 79 | } 80 | 81 | $output = ''; 82 | 83 | foreach ($rawFeedData as $image) { 84 | $output .= $modx->getChunk($tpl, $image); 85 | } 86 | 87 | return $output; 88 | -------------------------------------------------------------------------------- /v1/Snippets/snippet.JSONDerulo.ZooToolFeed.php: -------------------------------------------------------------------------------- 1 | getOption('tpl', $scriptProperties, ''); 15 | $limit = $modx->getOption('limit', $scriptProperties, 2); 16 | $excludeEmpty = explode(',', $modx->getOption('excludeEmpty', $scriptProperties, 'image')); 17 | $feeds = explode(',', $modx->getOption('users', $scriptProperties, '')); 18 | $apiKey = $modx->getOption('apiKey', $scriptProperties, ''); 19 | $cacheName = $modx->getOption('cacheName', $scriptProperties, ''); 20 | $cacheTime = $modx->getOption('cacheTime', $scriptProperties, 43200); 21 | 22 | $rawFeedData = array(); 23 | $cacheName = str_replace(" ", "-", $cacheName); 24 | 25 | foreach ($feeds as $username) { 26 | $cacheId = 'zootoolfeed-'.$cacheName.'-'.$username; 27 | 28 | if (($json = $modx->cacheManager->get($cacheId)) === null) { 29 | if ($ch === null) { 30 | $ch = curl_init(); 31 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 32 | } 33 | 34 | curl_setopt_array($ch, array( 35 | CURLOPT_URL => str_replace(array('{apikey}', '{username}', '{limit}'), array($apiKey, $username, $limit), $feedUrl), 36 | )); 37 | 38 | 39 | $json = curl_exec($ch); 40 | if (empty($json)) { 41 | continue; 42 | } 43 | 44 | $modx->cacheManager->set($cacheId, $json, $cacheTime); 45 | } 46 | 47 | $feed = json_decode($json); 48 | 49 | if ($feed === null) { 50 | continue; 51 | } 52 | 53 | foreach ($feed as $image) { 54 | foreach ($excludeEmpty as $k) { 55 | if ($image->$k == '') { 56 | continue 2; 57 | } 58 | } 59 | 60 | $rawFeedData[] = array( 61 | 'date' => $image->added, 62 | 'picture' => $image->image, 63 | 'title' => $image->title, 64 | 'username' => $username, 65 | 'referrer' => $image->referer, 66 | 'permalink' => $image->permalink, 67 | ); 68 | 69 | } 70 | } 71 | 72 | if ($ch !== null) { 73 | curl_close($ch); 74 | } 75 | 76 | $output = ''; 77 | foreach ($rawFeedData as $image) { 78 | $output .= $modx->getChunk($tpl, $image); 79 | } 80 | 81 | return $output; 82 | -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-0.5-alpha.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-0.5-alpha.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-0.6-alpha.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-0.6-alpha.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-0.7-alpha.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-0.7-alpha.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-0.9-alpha.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-0.9-alpha.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-0.9.1-alpha.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-0.9.1-alpha.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.0-beta.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.0-beta.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.1-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.1-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.2-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.2-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.3-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.3-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.3.1-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.3.1-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.3.2-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.3.2-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.3.3-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.3.3-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.3.4-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.3.4-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.4.0-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.4.0-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.5.0-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.5.0-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.6.0-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.6.0-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.7.0-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.7.0-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.7.1-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.7.1-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.7.3-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.7.3-pl.transport.zip -------------------------------------------------------------------------------- /v1/Transport packages/jsonderulo-1.7.4-pl.transport.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdincubus/JSONDerulo/b302ca1f11afb410f9166abb63f6b71c2ca33988/v1/Transport packages/jsonderulo-1.7.4-pl.transport.zip -------------------------------------------------------------------------------- /v2/Chunks/jd.appNet.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title]] 4 | [[+title]] 5 | [[+username]] 6 | 7 |
    8 | [[+text]] 9 |
    10 | 11 |
  • 12 | -------------------------------------------------------------------------------- /v2/Chunks/jd.delicious.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title]] 4 | 5 | 6 | 7 |
  • 8 | -------------------------------------------------------------------------------- /v2/Chunks/jd.eventbrite.html: -------------------------------------------------------------------------------- 1 |
  • 2 |

    3 | [[+textDescription]] 4 |

    5 | 6 |

    7 | Where?
    8 | [[+venueName]]
    9 | [[+venueName]]
    10 | [[+venueAddress1]]
    11 | [[+venueAddress2]]
    12 | [[+venueCity]]
    13 | [[+venueRegion]]
    14 | [[+venueCountryName]]
    15 | [[+venueCountry]] 16 |

    17 | 18 | [[+ticketType1:notempty=`

    19 | Ticket type: [[+ticketType1]]
    20 | Cost: [[+ticketCost1]]
    21 | Booking fee: [[+ticketFee1]]
    22 | Is ticket a freebie? [[+ticketFree1]]
    23 | Quantity total: [[+ticketTypeQuantity1]]
    24 | Tickets sold: [[+ticketTypeSold1]] 25 |

    `]] 26 | 27 | [[+ticketType2:notempty=`

    28 | Ticket type: [[+ticketType2]]
    29 | Cost: [[+ticketCost2]]
    30 | Booking fee: [[+ticketFee2]]
    31 | Is ticket a freebie? [[+ticketFree2]]
    32 | Quantity total: [[+ticketTypeQuantity2]]
    33 | Tickets sold: [[+ticketTypeSold2]] 34 |

    `]] 35 | 36 | [[+ticketType3:notempty=`

    37 | Ticket type: [[+ticketType3]]
    38 | Cost: [[+ticketCost3]]
    39 | Booking fee: [[+ticketFee3]]
    40 | Is ticket a freebie? [[+ticketFree3]]
    41 | Quantity total: [[+ticketTypeQuantity3]]
    42 | Tickets sold: [[+ticketTypeSold3]] 43 |

    `]] 44 | 45 |

    46 | Event start: [[+eventStart:strtotime:date=`%d-%m-%Y %I:%M %p`]]
    47 | Event end: [[+eventEnd:strtotime:date=`%d-%m-%Y %I:%M %p`]] 48 |

    49 | 50 |

    Event capacity: [[+eventCapacity]]

    51 |

    Event format: [[+eventFormat]]

    52 |

    Event ID: [[+eventId]]

    53 | 54 | Google Static Map - venue location 55 | 56 | Book tickets 57 |
  • 58 | -------------------------------------------------------------------------------- /v2/Chunks/jd.flickr.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+title:esc]] 4 | [[+title:esc]] 5 | 6 | 7 |
  • 8 | -------------------------------------------------------------------------------- /v2/Chunks/jd.googleCalendar.html: -------------------------------------------------------------------------------- 1 |
  • 2 | [[+title:neq=`No events.`:then=``:else=`No events.`]] 23 |
  • 24 | -------------------------------------------------------------------------------- /v2/Chunks/jd.googlePlus.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+displayName]] 4 | [[+displayName]] 5 | 6 |
    7 | [[+text]] 8 | [[+attachmentUrl:notempty=`
    Attachment`]] 9 |
    10 | Replies: [[+repliesCount]], 11 | Plus Ones: [[+plusCount]], 12 | Reshares: [[+resharesCount]] 13 |
    14 | 15 | 16 | 17 |
  • 18 | -------------------------------------------------------------------------------- /v2/Chunks/jd.instagram.html: -------------------------------------------------------------------------------- 1 |
  • 2 | Attribution: [[+attribution]]
    3 | Tags: [[+tags]]
    4 | Location latitude: [[+locationLat]]
    5 | Location longitude: [[+locationLong]]
    6 | Location name: [[+locationName]]
    7 | Filter: [[+filter]]
    8 | Link: [[+link]]
    9 | Likes: [[+likes]]
    10 | Date: [[+date]]
    11 | Image: [[+image]]
    12 | Caption: [[+caption]]
    13 | Username: [[+username]]
    14 | User full name: [[+userFullName]]
    15 | Avatar: [[+avatar]]
    16 | User bio: [[+userBio]]
    17 | User website: [[+userWebsite]] 18 |
  • 19 | -------------------------------------------------------------------------------- /v2/Chunks/jd.lastFm.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | [[+artist]] - [[+track]]
    4 | [[+artist]] - [[+track]] 5 |
    6 | 7 | 8 |
  • 9 | -------------------------------------------------------------------------------- /v2/Chunks/jd.tumblr.html: -------------------------------------------------------------------------------- 1 |
  • 2 | [[+blogName]] 3 | [[+blogDescription]] 4 | 5 |
    6 | [[+post]]
    7 | [[+postType]] 8 |
    9 | 10 | Post direct link 11 | 12 | 13 | [[+createdDate]]
    14 | [[+id]]
    15 | [[+shortUrl]]
    16 | 17 | [[+postType:is=`video`:then=` 18 | [[+caption]]
    19 | [[+videoPermalink]]
    20 | [[+thumbnail]]
    21 | [[+player250]]
    22 | [[+player400]]
    23 | [[+player500]]
    24 | `]] 25 | 26 | [[+postType:eq=`link`:then=` 27 | [[+title]]
    28 | [[+linkUrl]]
    29 | [[+linkDescription]]
    30 | `]] 31 | 32 | [[+postType:eq=`text`:then=` 33 | [[+title]]
    34 | [[+content]]
    35 | `]] 36 | 37 | [[+postType:eq=`audio`:then=` 38 | [[+audioSourceUrl]]
    39 | [[+audioSourceTitle]]
    40 | [[+artist]]
    41 | [[+album]]
    42 | [[+trackName]]
    43 | [[+player]]
    44 | [[+audioUrl]]
    45 | `]] 46 | 47 | [[+postType:eq=`photo`:then=` 48 | [[+caption]]
    49 | [[+imagePermalink]]
    50 | [[+image]]
    51 | `]] 52 |
  • 53 | -------------------------------------------------------------------------------- /v2/Chunks/jd.twitter.html: -------------------------------------------------------------------------------- 1 |
  • 2 | [[+id:notempty=` 3 | 4 | [[+isRetweet:is=`1`:then=` 5 | 6 | [[+originalAuthor]] 7 | [[+originalAuthor]] 8 | @[[+originalUsername]] 9 | 10 | `:else=` 11 | 12 | [[+title]] 13 | [[+title]] 14 | @[[+username]] 15 | 16 | `]] 17 | 18 |
    19 | [[+inReplyToStatusId:notempty=`

    In reply to [[+inReplyToScreenName]]

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