Merge pull request #505 from MrPetovan/task/4116-move-twitteroauth-to-composer
Move TwitterOAuth to composer Part 1: Twitter
This commit is contained in:
commit
ffa36da2c9
|
@ -5,6 +5,7 @@
|
|||
To install all addons using git, cd into your top level Friendica directory and
|
||||
|
||||
git clone https://github.com/friendica/friendica-addons.git addon
|
||||
util/composer.phar install -d addon
|
||||
|
||||
This will clone the entire repository in a directory called addon. They can now be activated in the addons section of your admin panel.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
|
||||
Copyright (c) 2011-2018 Tobias Diekershoff, Michael Vogel, Hypolite Petovan
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,39 +1,23 @@
|
|||
Twitter Addon
|
||||
==============
|
||||
|
||||
Main authors Tobias Diekershoff and Michael Vogel.
|
||||
Main authors Tobias Diekershoff, Michael Vogel and Hypolite Petovan.
|
||||
|
||||
With this addon to friendica you can give your users the possibility to post their *public* messages to Twitter and
|
||||
to import their timeline. The messages will be strapped their rich context and shortened to 280 characters length if
|
||||
necessary.
|
||||
This bi-directional connector addon allows each user to crosspost their Friendica public posts to Twitter, import their
|
||||
Twitter timeline, interact with tweets from Friendica, and crosspost to Friendica their public tweets.
|
||||
|
||||
The addon can also mirror a users Tweets into the ~friendica wall.
|
||||
## Installation
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To use this addon you have to register an [application](https://apps.twitter.com/) for your friendica instance on Twitter. Please leave the field "Callback URL" empty.
|
||||
To use this addon you have to register an [application](https://apps.twitter.com/) for your Friendica instance on Twitter.
|
||||
Please leave the field "Callback URL" empty.
|
||||
|
||||
After the registration please enter the values for "Consumer Key" and "Consumer Secret" in the [administration](admin/addons/twitter).
|
||||
|
||||
Where to find
|
||||
-------------
|
||||
## License
|
||||
|
||||
In the friendica addon git repository /twitter/, this directory contains
|
||||
all required PHP files (including the [Twitter OAuth library][1] by Abraham
|
||||
Williams, MIT licensed and the [Slinky library][2] by Beau Lebens, BSD license),
|
||||
a CSS file for styling of the user configuration and an image to _Sign in with
|
||||
Twitter_.
|
||||
|
||||
[1]: https://github.com/abraham/twitteroauth
|
||||
[2]: http://dentedreality.com.au/projects/slinky/
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
The _StatusNet Connector_ is licensed under the [3-clause BSD license][3] see the
|
||||
LICENSE file in the addons directory.
|
||||
|
||||
[3]: http://opensource.org/licenses/BSD-3-Clause
|
||||
The _Twitter Connector_ is licensed under the [3-clause BSD license][2] see the LICENSE file in the addons directory.
|
||||
|
||||
The _Twitter Connector_ uses the [Twitter OAuth library][2] by Abraham Williams, MIT licensed
|
||||
|
||||
[1]: http://opensource.org/licenses/BSD-3-Clause
|
||||
[2]: https://github.com/abraham/twitteroauth
|
||||
|
|
1026
twitter/codebird.php
1026
twitter/codebird.php
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "friendica-addons/twitter",
|
||||
"description": "Twitter Connector addon for Friendica",
|
||||
"type": "friendica-addon",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Diekershoff",
|
||||
"homepage": "https://f.diekershoff.de/profile/tobias",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Michael Vogel",
|
||||
"homepage": "https://pirati.ca/profile/heluecht",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hypolite Petovan",
|
||||
"email": "mrpetovan@gmail.com",
|
||||
"homepage": "https://friendica.mrpetovan.com/profile/hypolite",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"abraham/twitteroauth": "^0.7.4"
|
||||
},
|
||||
"license": "3-clause BSD license",
|
||||
"minimum-stability": "stable"
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "341c2ca2f25177375c65577f7e5d7369",
|
||||
"packages": [
|
||||
{
|
||||
"name": "abraham/twitteroauth",
|
||||
"version": "0.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/abraham/twitteroauth.git",
|
||||
"reference": "c6f9e692552dd037b2324ed0dfa28a4e60875acf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/abraham/twitteroauth/zipball/c6f9e692552dd037b2324ed0dfa28a4e60875acf",
|
||||
"reference": "c6f9e692552dd037b2324ed0dfa28a4e60875acf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmd/phpmd": "~2.6",
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"squizlabs/php_codesniffer": "~3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Abraham\\TwitterOAuth\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Abraham Williams",
|
||||
"email": "abraham@abrah.am",
|
||||
"homepage": "https://abrah.am",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "The most popular PHP library for use with the Twitter OAuth REST API.",
|
||||
"homepage": "https://twitteroauth.com",
|
||||
"keywords": [
|
||||
"Twitter API",
|
||||
"Twitter oAuth",
|
||||
"api",
|
||||
"oauth",
|
||||
"rest",
|
||||
"social",
|
||||
"twitter"
|
||||
],
|
||||
"time": "2017-06-30T22:02:01+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
|
@ -2,11 +2,12 @@
|
|||
/**
|
||||
* Name: Twitter Connector
|
||||
* Description: Bidirectional (posting, relaying and reading) connector for Twitter.
|
||||
* Version: 1.0.4
|
||||
* Version: 1.1.0
|
||||
* Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
|
||||
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
|
||||
* Maintainer: Hypolite Petovan <https://friendica.mrpetovan.com/profile/hypolite>
|
||||
*
|
||||
* Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
|
||||
* Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel, Hypolite Petovan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -56,9 +57,10 @@
|
|||
* setting. After this, your user can configure their Twitter account settings
|
||||
* from "Settings -> Addon Settings".
|
||||
*
|
||||
* Requirements: PHP5, curl [Slinky library]
|
||||
* Requirements: PHP5, curl
|
||||
*/
|
||||
|
||||
use Abraham\TwitterOAuth\TwitterOAuth;
|
||||
use Friendica\App;
|
||||
use Friendica\Content\OEmbed;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
|
@ -77,7 +79,12 @@ use Friendica\Model\User;
|
|||
use Friendica\Object\Image;
|
||||
use Friendica\Util\Network;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/dba.php';
|
||||
require_once 'include/enotify.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
|
||||
define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
|
||||
|
||||
|
@ -151,16 +158,8 @@ function twitter_follow(App $a, &$contact)
|
|||
$otoken = PConfig::get($uid, 'twitter', 'oauthtoken');
|
||||
$osecret = PConfig::get($uid, 'twitter', 'oauthsecret');
|
||||
|
||||
require_once "addon/twitter/codebird.php";
|
||||
|
||||
$cb = \Codebird\Codebird::getInstance();
|
||||
$cb->setConsumerKey($ckey, $csecret);
|
||||
$cb->setToken($otoken, $osecret);
|
||||
|
||||
$parameters = [];
|
||||
$parameters["screen_name"] = $nickname;
|
||||
|
||||
$user = $cb->friendships_create($parameters);
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$connection->post('friendships/create', ['screen_name' => $nickname]);
|
||||
|
||||
twitter_fetchuser($a, $uid, $nickname);
|
||||
|
||||
|
@ -218,7 +217,6 @@ function twitter_settings_post(App $a, $post)
|
|||
if (isset($_POST['twitter-pin'])) {
|
||||
// if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
|
||||
logger('got a Twitter PIN');
|
||||
require_once 'library/twitteroauth.php';
|
||||
$ckey = Config::get('twitter', 'consumerkey');
|
||||
$csecret = Config::get('twitter', 'consumersecret');
|
||||
// the token and secret for which the PIN was generated were hidden in the settings
|
||||
|
@ -299,7 +297,6 @@ function twitter_settings(App $a, &$s)
|
|||
* which the user can request a PIN to connect the account to a
|
||||
* account at Twitter.
|
||||
*/
|
||||
require_once 'library/twitteroauth.php';
|
||||
$connection = new TwitterOAuth($ckey, $csecret);
|
||||
$request_token = $connection->getRequestToken();
|
||||
$token = $request_token['oauth_token'];
|
||||
|
@ -320,7 +317,6 @@ function twitter_settings(App $a, &$s)
|
|||
* we have an OAuth key / secret pair for the user
|
||||
* so let's give a chance to disable the postings to Twitter
|
||||
*/
|
||||
require_once 'library/twitteroauth.php';
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$details = $connection->get('account/verify_credentials');
|
||||
|
||||
|
@ -399,11 +395,7 @@ function twitter_action(App $a, $uid, $pid, $action)
|
|||
$otoken = PConfig::get($uid, 'twitter', 'oauthtoken');
|
||||
$osecret = PConfig::get($uid, 'twitter', 'oauthsecret');
|
||||
|
||||
require_once "addon/twitter/codebird.php";
|
||||
|
||||
$cb = \Codebird\Codebird::getInstance();
|
||||
$cb->setConsumerKey($ckey, $csecret);
|
||||
$cb->setToken($otoken, $osecret);
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
||||
$post = ['id' => $pid];
|
||||
|
||||
|
@ -411,13 +403,13 @@ function twitter_action(App $a, $uid, $pid, $action)
|
|||
|
||||
switch ($action) {
|
||||
case "delete":
|
||||
// To-Do: $result = $cb->statuses_destroy($post);
|
||||
// To-Do: $result = $connection->post('statuses/destroy', $post);
|
||||
break;
|
||||
case "like":
|
||||
$result = $cb->favorites_create($post);
|
||||
$result = $connection->post('favorites/create', $post);
|
||||
break;
|
||||
case "unlike":
|
||||
$result = $cb->favorites_destroy($post);
|
||||
$result = $connection->post('favorites/destroy', $post);
|
||||
break;
|
||||
}
|
||||
logger("twitter_action '" . $action . "' send, result: " . print_r($result, true), LOGGER_DEBUG);
|
||||
|
@ -435,7 +427,10 @@ function twitter_post_hook(App $a, &$b)
|
|||
logger("twitter_post_hook: parameter " . print_r($b, true), LOGGER_DATA);
|
||||
|
||||
// Looking if its a reply to a twitter post
|
||||
if ((substr($b["parent-uri"], 0, 9) != "twitter::") && (substr($b["extid"], 0, 9) != "twitter::") && (substr($b["thr-parent"], 0, 9) != "twitter::")) {
|
||||
if ((substr($b["parent-uri"], 0, 9) != "twitter::")
|
||||
&& (substr($b["extid"], 0, 9) != "twitter::")
|
||||
&& (substr($b["thr-parent"], 0, 9) != "twitter::"))
|
||||
{
|
||||
logger("twitter_post_hook: no twitter post " . $b["parent"]);
|
||||
return;
|
||||
}
|
||||
|
@ -484,10 +479,12 @@ function twitter_post_hook(App $a, &$b)
|
|||
|
||||
if ($b['verb'] == ACTIVITY_LIKE) {
|
||||
logger("twitter_post_hook: parameter 2 " . substr($b["thr-parent"], 9), LOGGER_DEBUG);
|
||||
if ($b['deleted'])
|
||||
if ($b['deleted']) {
|
||||
twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "unlike");
|
||||
else
|
||||
} else {
|
||||
twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "like");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -521,9 +518,7 @@ function twitter_post_hook(App $a, &$b)
|
|||
return;
|
||||
}
|
||||
|
||||
require_once 'library/twitteroauth.php';
|
||||
require_once 'include/bbcode.php';
|
||||
$tweet = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
||||
$max_char = 280;
|
||||
$msgarr = BBCode::toPlaintext($b, $max_char, true, 8);
|
||||
|
@ -545,29 +540,16 @@ function twitter_post_hook(App $a, &$b)
|
|||
|
||||
// and now tweet it :-)
|
||||
if (strlen($msg) && ($image != "")) {
|
||||
$img_str = Network::fetchUrl($image);
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$media = $connection->upload('media/upload', ['media' => $image]);
|
||||
|
||||
$tempfile = tempnam(get_temppath(), "cache");
|
||||
file_put_contents($tempfile, $img_str);
|
||||
|
||||
// Twitter had changed something so that the old library doesn't work anymore
|
||||
// so we are using a new library for twitter
|
||||
// To-Do:
|
||||
// Switching completely to this library with all functions
|
||||
require_once "addon/twitter/codebird.php";
|
||||
|
||||
$cb = \Codebird\Codebird::getInstance();
|
||||
$cb->setConsumerKey($ckey, $csecret);
|
||||
$cb->setToken($otoken, $osecret);
|
||||
|
||||
$post = ['status' => $msg, 'media[]' => $tempfile];
|
||||
$post = ['status' => $msg, 'media_ids' => $media->media_id_string];
|
||||
|
||||
if ($iscomment) {
|
||||
$post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
|
||||
}
|
||||
|
||||
$result = $cb->statuses_updateWithMedia($post);
|
||||
unlink($tempfile);
|
||||
$result = $connection->post('statuses/update', $post);
|
||||
|
||||
logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
|
||||
|
||||
|
@ -612,7 +594,7 @@ function twitter_post_hook(App $a, &$b)
|
|||
$post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
|
||||
}
|
||||
|
||||
$result = $tweet->post($url, $post);
|
||||
$result = $connection->post($url, $post);
|
||||
logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
|
||||
|
||||
if ($result->source) {
|
||||
|
@ -690,8 +672,9 @@ function twitter_cron(App $a, $b)
|
|||
}
|
||||
|
||||
$abandon_days = intval(Config::get('system', 'account_abandon_days'));
|
||||
if ($abandon_days < 1)
|
||||
if ($abandon_days < 1) {
|
||||
$abandon_days = 0;
|
||||
}
|
||||
|
||||
$abandon_limit = date("Y-m-d H:i:s", time() - $abandon_days * 86400);
|
||||
|
||||
|
@ -828,7 +811,14 @@ function twitter_do_mirrorpost(App $a, $uid, $post)
|
|||
// We don't support nested shares, so we mustn't show quotes as shares on retweets
|
||||
$item = twitter_createpost($a, $uid, $post->retweeted_status, ['id' => 0], false, false, true);
|
||||
|
||||
$datarray['body'] = "\n" . share_header($item['author-name'], $item['author-link'], $item['author-avatar'], "", $item['created'], $item['plink']);
|
||||
$datarray['body'] = "\n" . share_header(
|
||||
$item['author-name'],
|
||||
$item['author-link'],
|
||||
$item['author-avatar'],
|
||||
"",
|
||||
$item['created'],
|
||||
$item['plink']
|
||||
);
|
||||
|
||||
$datarray['body'] .= $item['body'] . '[/share]';
|
||||
} else {
|
||||
|
@ -871,7 +861,6 @@ function twitter_fetchtimeline(App $a, $uid)
|
|||
require_once 'include/items.php';
|
||||
require_once 'mod/share.php';
|
||||
|
||||
require_once 'library/twitteroauth.php';
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
||||
$parameters = ["exclude_replies" => true, "trim_user" => false, "contributor_details" => true, "include_rts" => true, "tweet_mode" => "extended"];
|
||||
|
@ -954,15 +943,8 @@ function twitter_queue_hook(App $a, &$b)
|
|||
|
||||
$z = unserialize($x['content']);
|
||||
|
||||
require_once "addon/twitter/codebird.php";
|
||||
|
||||
$cb = \Codebird\Codebird::getInstance();
|
||||
$cb->setConsumerKey($ckey, $csecret);
|
||||
$cb->setToken($otoken, $osecret);
|
||||
|
||||
if ($z['url'] == "statuses/update") {
|
||||
$result = $cb->statuses_update($z['post']);
|
||||
}
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$result = $connection->post($z['url'], $z['post']);
|
||||
|
||||
logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
|
||||
|
||||
|
@ -1010,7 +992,8 @@ function twitter_fetch_contact($uid, $contact, $create_user)
|
|||
"addr" => $contact->screen_name . "@twitter.com", "generation" => 2]);
|
||||
|
||||
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
|
||||
intval($uid), dbesc("twitter::" . $contact->id_str));
|
||||
intval($uid),
|
||||
dbesc("twitter::" . $contact->id_str));
|
||||
|
||||
if (!count($r) && !$create_user) {
|
||||
return 0;
|
||||
|
@ -1133,12 +1116,6 @@ function twitter_fetchuser(App $a, $uid, $screen_name = "", $user_id = "")
|
|||
$otoken = PConfig::get($uid, 'twitter', 'oauthtoken');
|
||||
$osecret = PConfig::get($uid, 'twitter', 'oauthsecret');
|
||||
|
||||
require_once "addon/twitter/codebird.php";
|
||||
|
||||
$cb = \Codebird\Codebird::getInstance();
|
||||
$cb->setConsumerKey($ckey, $csecret);
|
||||
$cb->setToken($otoken, $osecret);
|
||||
|
||||
$r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
|
||||
intval($uid));
|
||||
|
||||
|
@ -1159,7 +1136,8 @@ function twitter_fetchuser(App $a, $uid, $screen_name = "", $user_id = "")
|
|||
}
|
||||
|
||||
// Fetching user data
|
||||
$user = $cb->users_show($parameters);
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
$user = $connection->get('users/show', $parameters);
|
||||
|
||||
if (!is_object($user)) {
|
||||
return;
|
||||
|
@ -1542,7 +1520,14 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
|
|||
|
||||
$postarray['body'] = $statustext;
|
||||
|
||||
$postarray['body'] .= "\n" . share_header($quoted['author-name'], $quoted['author-link'], $quoted['author-avatar'], "", $quoted['created'], $quoted['plink']);
|
||||
$postarray['body'] .= "\n" . share_header(
|
||||
$quoted['author-name'],
|
||||
$quoted['author-link'],
|
||||
$quoted['author-avatar'],
|
||||
"",
|
||||
$quoted['created'],
|
||||
$quoted['plink']
|
||||
);
|
||||
|
||||
$postarray['body'] .= $quoted['body'] . '[/share]';
|
||||
}
|
||||
|
@ -1655,8 +1640,9 @@ function twitter_fetchparentposts(App $a, $uid, $post, $connection, $self, $own_
|
|||
foreach ($posts as $post) {
|
||||
$postarray = twitter_createpost($a, $uid, $post, $self, false, false, false);
|
||||
|
||||
if (trim($postarray['body']) == "")
|
||||
if (trim($postarray['body']) == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = Item::insert($postarray);
|
||||
$postarray["id"] = $item;
|
||||
|
@ -1687,7 +1673,6 @@ function twitter_fetchhometimeline(App $a, $uid)
|
|||
$application_name = $a->get_hostname();
|
||||
}
|
||||
|
||||
require_once 'library/twitteroauth.php';
|
||||
require_once 'include/items.php';
|
||||
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
@ -1849,8 +1834,9 @@ function twitter_fetchhometimeline(App $a, $uid)
|
|||
$item = $r[0]['id'];
|
||||
$parent_id = $r[0]['parent'];
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
$parent_id = $postarray['parent'];
|
||||
}
|
||||
|
||||
if (($item != 0) && !function_exists("check_item_notification")) {
|
||||
require_once 'include/enotify.php';
|
||||
|
@ -1889,8 +1875,6 @@ function twitter_fetch_own_contact(App $a, $uid)
|
|||
$contact_id = 0;
|
||||
|
||||
if ($own_id == "") {
|
||||
require_once 'library/twitteroauth.php';
|
||||
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
||||
// Fetching user data
|
||||
|
@ -1957,9 +1941,7 @@ function twitter_is_retweet(App $a, $uid, $body)
|
|||
$otoken = PConfig::get($uid, 'twitter', 'oauthtoken');
|
||||
$osecret = PConfig::get($uid, 'twitter', 'oauthsecret');
|
||||
|
||||
require_once 'library/twitteroauth.php';
|
||||
$connection = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
|
||||
|
||||
$result = $connection->post('statuses/retweet/' . $id);
|
||||
|
||||
logger('twitter_is_retweet: result ' . print_r($result, true), LOGGER_DEBUG);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<?php
|
||||
|
||||
use Friendica\Core\Config;
|
||||
|
||||
function twitter_sync_run($argv, $argc) {
|
||||
function twitter_sync_run($argv, $argc)
|
||||
{
|
||||
global $a;
|
||||
|
||||
require_once("addon/twitter/twitter.php");
|
||||
require_once 'addon/twitter/twitter.php';
|
||||
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
$load = sys_getloadavg();
|
||||
|
@ -27,4 +29,3 @@ function twitter_sync_run($argv, $argc) {
|
|||
twitter_fetchhometimeline($a, $uid);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.DS_Store
|
||||
composer.lock
|
||||
vendor
|
||||
env
|
|
@ -0,0 +1,13 @@
|
|||
language: php
|
||||
dist: trusty
|
||||
php:
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
- hhvm
|
||||
sudo: false
|
||||
before_script:
|
||||
- composer self-update
|
||||
- composer install --prefer-source --no-interaction
|
||||
script:
|
||||
- vendor/bin/phpunit
|
|
@ -0,0 +1,46 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at abraham@abrah.am. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2009 Abraham Williams - http://abrah.am - abraham@abrah.am
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,10 @@
|
|||
<span itemprop="name">TwitterOAuth</span> [![Build Status](https://img.shields.io/travis/abraham/twitteroauth.svg)](https://travis-ci.org/abraham/twitteroauth) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/abraham/twitteroauth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/abraham/twitteroauth/?branch=master) [![Issues Count](https://img.shields.io/github/issues/abraham/twitteroauth.svg)](https://github.com/abraham/twitteroauth/issues) [![Latest Version](https://img.shields.io/packagist/v/abraham/twitteroauth.svg)](https://packagist.org/packages/abraham/twitteroauth)
|
||||
------------
|
||||
|
||||
<p itemprop="description">The most popular PHP library for Twitter's OAuth REST API.</p>
|
||||
|
||||
See documentation at https://twitteroauth.com.
|
||||
|
||||
PHP versions [listed](https://secure.php.net/supported-versions.php) as "active support" or "security fixes only" are supported.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/abraham/twitteroauth-demo/master/images/twitter-logo-blue.png" itemprop="image" alt="Twitter bird" width="200px">
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Use to autoload needed classes without Composer.
|
||||
*
|
||||
* @param string $class The fully-qualified class name.
|
||||
* @return void
|
||||
*/
|
||||
spl_autoload_register(function ($class) {
|
||||
|
||||
// project-specific namespace prefix
|
||||
$prefix = 'Abraham\\TwitterOAuth\\';
|
||||
|
||||
// base directory for the namespace prefix
|
||||
$base_dir = __DIR__ . '/src/';
|
||||
|
||||
// does the class use the namespace prefix?
|
||||
$len = strlen($prefix);
|
||||
if (strncmp($prefix, $class, $len) !== 0) {
|
||||
// no, move to the next registered autoloader
|
||||
return;
|
||||
}
|
||||
|
||||
// get the relative class name
|
||||
$relative_class = substr($class, $len);
|
||||
|
||||
// replace the namespace prefix with the base directory, replace namespace
|
||||
// separators with directory separators in the relative class name, append
|
||||
// with .php
|
||||
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
||||
|
||||
// if the file exists, require it
|
||||
if (file_exists($file)) {
|
||||
require $file;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "abraham/twitteroauth",
|
||||
"type": "library",
|
||||
"description": "The most popular PHP library for use with the Twitter OAuth REST API.",
|
||||
"keywords": ["twitter", "api", "oauth", "rest", "social", "twitter api", "twitter oauth"],
|
||||
"license": "MIT",
|
||||
"homepage": "https://twitteroauth.com",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Abraham Williams",
|
||||
"email": "abraham@abrah.am",
|
||||
"homepage": "https://abrah.am",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/abraham/twitteroauth",
|
||||
"issues": "https://github.com/abraham/twitteroauth/issues"
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"squizlabs/php_codesniffer": "~3.0",
|
||||
"phpmd/phpmd": "~2.6"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Abraham\\TwitterOAuth\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0"?>
|
||||
<ruleset name="My first PHPMD rule set"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
<description>Keep TwitterOAuth source code clean.</description>
|
||||
|
||||
<!-- <rule ref="rulesets/cleancode.xml" /> -->
|
||||
<rule ref="rulesets/codesize.xml" />
|
||||
<rule ref="rulesets/controversial.xml" />
|
||||
<rule ref="rulesets/design.xml" />
|
||||
<rule ref="rulesets/naming.xml" />
|
||||
<rule ref="rulesets/unusedcode.xml" />
|
||||
</ruleset>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
colors="true"
|
||||
bootstrap="tests/bootstrap.php">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="TwitterOAuth Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
/**
|
||||
* Handle setting and storing config for TwitterOAuth.
|
||||
*
|
||||
* @author Abraham Williams <abraham@abrah.am>
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
/** @var int How long to wait for a response from the API */
|
||||
protected $timeout = 5;
|
||||
/** @var int how long to wait while connecting to the API */
|
||||
protected $connectionTimeout = 5;
|
||||
/**
|
||||
* Decode JSON Response as associative Array
|
||||
*
|
||||
* @see http://php.net/manual/en/function.json-decode.php
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $decodeJsonAsArray = false;
|
||||
/** @var string User-Agent header */
|
||||
protected $userAgent = 'TwitterOAuth (+https://twitteroauth.com)';
|
||||
/** @var array Store proxy connection details */
|
||||
protected $proxy = [];
|
||||
|
||||
/** @var bool Whether to encode the curl requests with gzip or not */
|
||||
protected $gzipEncoding = true;
|
||||
|
||||
/** @var integer Size for Chunked Uploads */
|
||||
protected $chunkSize = 250000; // 0.25 MegaByte
|
||||
|
||||
/**
|
||||
* Set the connection and response timeouts.
|
||||
*
|
||||
* @param int $connectionTimeout
|
||||
* @param int $timeout
|
||||
*/
|
||||
public function setTimeouts($connectionTimeout, $timeout)
|
||||
{
|
||||
$this->connectionTimeout = (int)$connectionTimeout;
|
||||
$this->timeout = (int)$timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setDecodeJsonAsArray($value)
|
||||
{
|
||||
$this->decodeJsonAsArray = (bool)$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userAgent
|
||||
*/
|
||||
public function setUserAgent($userAgent)
|
||||
{
|
||||
$this->userAgent = (string)$userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $proxy
|
||||
*/
|
||||
public function setProxy(array $proxy)
|
||||
{
|
||||
$this->proxy = $proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to encode the curl requests with gzip or not.
|
||||
*
|
||||
* @param boolean $gzipEncoding
|
||||
*/
|
||||
public function setGzipEncoding($gzipEncoding)
|
||||
{
|
||||
$this->gzipEncoding = (bool)$gzipEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of each part of file for chunked media upload.
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setChunkSize($value)
|
||||
{
|
||||
$this->chunkSize = (int)$value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
class Consumer
|
||||
{
|
||||
/** @var string */
|
||||
public $key;
|
||||
/** @var string */
|
||||
public $secret;
|
||||
/** @var string|null */
|
||||
public $callbackUrl;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $secret
|
||||
* @param null $callbackUrl
|
||||
*/
|
||||
public function __construct($key, $secret, $callbackUrl = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->secret = $secret;
|
||||
$this->callbackUrl = $callbackUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return "Consumer[key=$this->key,secret=$this->secret]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
/**
|
||||
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
|
||||
* where the Signature Base String is the text and the key is the concatenated values (each first
|
||||
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
|
||||
* character (ASCII code 38) even if empty.
|
||||
* - Chapter 9.2 ("HMAC-SHA1")
|
||||
*/
|
||||
class HmacSha1 extends SignatureMethod
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return "HMAC-SHA1";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildSignature(Request $request, Consumer $consumer, Token $token = null)
|
||||
{
|
||||
$signatureBase = $request->getSignatureBaseString();
|
||||
|
||||
$parts = [$consumer->secret, null !== $token ? $token->secret : ""];
|
||||
|
||||
$parts = Util::urlencodeRfc3986($parts);
|
||||
$key = implode('&', $parts);
|
||||
|
||||
return base64_encode(hash_hmac('sha1', $signatureBase, $key, true));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
class Request
|
||||
{
|
||||
protected $parameters;
|
||||
protected $httpMethod;
|
||||
protected $httpUrl;
|
||||
public static $version = '1.0';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $httpMethod
|
||||
* @param string $httpUrl
|
||||
* @param array|null $parameters
|
||||
*/
|
||||
public function __construct($httpMethod, $httpUrl, array $parameters = [])
|
||||
{
|
||||
$parameters = array_merge(Util::parseParameters(parse_url($httpUrl, PHP_URL_QUERY)), $parameters);
|
||||
$this->parameters = $parameters;
|
||||
$this->httpMethod = $httpMethod;
|
||||
$this->httpUrl = $httpUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* pretty much a helper function to set up the request
|
||||
*
|
||||
* @param Consumer $consumer
|
||||
* @param Token $token
|
||||
* @param string $httpMethod
|
||||
* @param string $httpUrl
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public static function fromConsumerAndToken(
|
||||
Consumer $consumer,
|
||||
Token $token = null,
|
||||
$httpMethod,
|
||||
$httpUrl,
|
||||
array $parameters = []
|
||||
) {
|
||||
$defaults = [
|
||||
"oauth_version" => Request::$version,
|
||||
"oauth_nonce" => Request::generateNonce(),
|
||||
"oauth_timestamp" => time(),
|
||||
"oauth_consumer_key" => $consumer->key
|
||||
];
|
||||
if (null !== $token) {
|
||||
$defaults['oauth_token'] = $token->key;
|
||||
}
|
||||
|
||||
$parameters = array_merge($defaults, $parameters);
|
||||
|
||||
return new Request($httpMethod, $httpUrl, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function setParameter($name, $value)
|
||||
{
|
||||
$this->parameters[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getParameter($name)
|
||||
{
|
||||
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*/
|
||||
public function removeParameter($name)
|
||||
{
|
||||
unset($this->parameters[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The request parameters, sorted and concatenated into a normalized string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSignableParameters()
|
||||
{
|
||||
// Grab all parameters
|
||||
$params = $this->parameters;
|
||||
|
||||
// Remove oauth_signature if present
|
||||
// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
|
||||
if (isset($params['oauth_signature'])) {
|
||||
unset($params['oauth_signature']);
|
||||
}
|
||||
|
||||
return Util::buildHttpQuery($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base string of this request
|
||||
*
|
||||
* The base string defined as the method, the url
|
||||
* and the parameters (normalized), each urlencoded
|
||||
* and the concated with &.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSignatureBaseString()
|
||||
{
|
||||
$parts = [
|
||||
$this->getNormalizedHttpMethod(),
|
||||
$this->getNormalizedHttpUrl(),
|
||||
$this->getSignableParameters()
|
||||
];
|
||||
|
||||
$parts = Util::urlencodeRfc3986($parts);
|
||||
|
||||
return implode('&', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP Method in uppercase
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNormalizedHttpMethod()
|
||||
{
|
||||
return strtoupper($this->httpMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* parses the url and rebuilds it to be
|
||||
* scheme://host/path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNormalizedHttpUrl()
|
||||
{
|
||||
$parts = parse_url($this->httpUrl);
|
||||
|
||||
$scheme = $parts['scheme'];
|
||||
$host = strtolower($parts['host']);
|
||||
$path = $parts['path'];
|
||||
|
||||
return "$scheme://$host$path";
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a url usable for a GET request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toUrl()
|
||||
{
|
||||
$postData = $this->toPostdata();
|
||||
$out = $this->getNormalizedHttpUrl();
|
||||
if ($postData) {
|
||||
$out .= '?' . $postData;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the data one would send in a POST request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toPostdata()
|
||||
{
|
||||
return Util::buildHttpQuery($this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the Authorization: header
|
||||
*
|
||||
* @return string
|
||||
* @throws TwitterOAuthException
|
||||
*/
|
||||
public function toHeader()
|
||||
{
|
||||
$first = true;
|
||||
$out = 'Authorization: OAuth';
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
if (substr($k, 0, 5) != "oauth") {
|
||||
continue;
|
||||
}
|
||||
if (is_array($v)) {
|
||||
throw new TwitterOAuthException('Arrays not supported in headers');
|
||||
}
|
||||
$out .= ($first) ? ' ' : ', ';
|
||||
$out .= Util::urlencodeRfc3986($k) . '="' . Util::urlencodeRfc3986($v) . '"';
|
||||
$first = false;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SignatureMethod $signatureMethod
|
||||
* @param Consumer $consumer
|
||||
* @param Token $token
|
||||
*/
|
||||
public function signRequest(SignatureMethod $signatureMethod, Consumer $consumer, Token $token = null)
|
||||
{
|
||||
$this->setParameter("oauth_signature_method", $signatureMethod->getName());
|
||||
$signature = $this->buildSignature($signatureMethod, $consumer, $token);
|
||||
$this->setParameter("oauth_signature", $signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SignatureMethod $signatureMethod
|
||||
* @param Consumer $consumer
|
||||
* @param Token $token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function buildSignature(SignatureMethod $signatureMethod, Consumer $consumer, Token $token = null)
|
||||
{
|
||||
return $signatureMethod->buildSignature($this, $consumer, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function generateNonce()
|
||||
{
|
||||
return md5(microtime() . mt_rand());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
/**
|
||||
* The result of the most recent API request.
|
||||
*
|
||||
* @author Abraham Williams <abraham@abrah.am>
|
||||
*/
|
||||
class Response
|
||||
{
|
||||
/** @var string|null API path from the most recent request */
|
||||
private $apiPath;
|
||||
/** @var int HTTP status code from the most recent request */
|
||||
private $httpCode = 0;
|
||||
/** @var array HTTP headers from the most recent request */
|
||||
private $headers = [];
|
||||
/** @var array|object Response body from the most recent request */
|
||||
private $body = [];
|
||||
/** @var array HTTP headers from the most recent request that start with X */
|
||||
private $xHeaders = [];
|
||||
|
||||
/**
|
||||
* @param string $apiPath
|
||||
*/
|
||||
public function setApiPath($apiPath)
|
||||
{
|
||||
$this->apiPath = $apiPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApiPath()
|
||||
{
|
||||
return $this->apiPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|object $body
|
||||
*/
|
||||
public function setBody($body)
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|object|string
|
||||
*/
|
||||
public function getBody()
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $httpCode
|
||||
*/
|
||||
public function setHttpCode($httpCode)
|
||||
{
|
||||
$this->httpCode = $httpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHttpCode()
|
||||
{
|
||||
return $this->httpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
*/
|
||||
public function setHeaders(array $headers)
|
||||
{
|
||||
foreach ($headers as $key => $value) {
|
||||
if (substr($key, 0, 1) == 'x') {
|
||||
$this->xHeaders[$key] = $value;
|
||||
}
|
||||
}
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getsHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $xHeaders
|
||||
*/
|
||||
public function setXHeaders(array $xHeaders = [])
|
||||
{
|
||||
$this->xHeaders = $xHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getXHeaders()
|
||||
{
|
||||
return $this->xHeaders;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
/**
|
||||
* A class for implementing a Signature Method
|
||||
* See section 9 ("Signing Requests") in the spec
|
||||
*/
|
||||
abstract class SignatureMethod
|
||||
{
|
||||
/**
|
||||
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getName();
|
||||
|
||||
/**
|
||||
* Build up the signature
|
||||
* NOTE: The output of this function MUST NOT be urlencoded.
|
||||
* the encoding is handled in OAuthRequest when the final
|
||||
* request is serialized
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Consumer $consumer
|
||||
* @param Token $token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function buildSignature(Request $request, Consumer $consumer, Token $token = null);
|
||||
|
||||
/**
|
||||
* Verifies that a given signature is correct
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Consumer $consumer
|
||||
* @param Token $token
|
||||
* @param string $signature
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkSignature(Request $request, Consumer $consumer, Token $token, $signature)
|
||||
{
|
||||
$built = $this->buildSignature($request, $consumer, $token);
|
||||
|
||||
// Check for zero length, although unlikely here
|
||||
if (strlen($built) == 0 || strlen($signature) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($built) != strlen($signature)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid a timing leak with a (hopefully) time insensitive compare
|
||||
$result = 0;
|
||||
for ($i = 0; $i < strlen($signature); $i++) {
|
||||
$result |= ord($built{$i}) ^ ord($signature{$i});
|
||||
}
|
||||
|
||||
return $result == 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
class Token
|
||||
{
|
||||
/** @var string */
|
||||
public $key;
|
||||
/** @var string */
|
||||
public $secret;
|
||||
|
||||
/**
|
||||
* @param string $key The OAuth Token
|
||||
* @param string $secret The OAuth Token Secret
|
||||
*/
|
||||
public function __construct($key, $secret)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the basic string serialization of a token that a server
|
||||
* would respond to request_token and access_token calls with
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf("oauth_token=%s&oauth_token_secret=%s",
|
||||
Util::urlencodeRfc3986($this->key),
|
||||
Util::urlencodeRfc3986($this->secret)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
<?php
|
||||
/**
|
||||
* The most popular PHP library for use with the Twitter OAuth REST API.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
use Abraham\TwitterOAuth\Util\JsonDecoder;
|
||||
|
||||
/**
|
||||
* TwitterOAuth class for interacting with the Twitter API.
|
||||
*
|
||||
* @author Abraham Williams <abraham@abrah.am>
|
||||
*/
|
||||
class TwitterOAuth extends Config
|
||||
{
|
||||
const API_VERSION = '1.1';
|
||||
const API_HOST = 'https://api.twitter.com';
|
||||
const UPLOAD_HOST = 'https://upload.twitter.com';
|
||||
|
||||
/** @var Response details about the result of the last request */
|
||||
private $response;
|
||||
/** @var string|null Application bearer token */
|
||||
private $bearer;
|
||||
/** @var Consumer Twitter application details */
|
||||
private $consumer;
|
||||
/** @var Token|null User access token details */
|
||||
private $token;
|
||||
/** @var HmacSha1 OAuth 1 signature type used by Twitter */
|
||||
private $signatureMethod;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $consumerKey The Application Consumer Key
|
||||
* @param string $consumerSecret The Application Consumer Secret
|
||||
* @param string|null $oauthToken The Client Token (optional)
|
||||
* @param string|null $oauthTokenSecret The Client Token Secret (optional)
|
||||
*/
|
||||
public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null)
|
||||
{
|
||||
$this->resetLastResponse();
|
||||
$this->signatureMethod = new HmacSha1();
|
||||
$this->consumer = new Consumer($consumerKey, $consumerSecret);
|
||||
if (!empty($oauthToken) && !empty($oauthTokenSecret)) {
|
||||
$this->token = new Token($oauthToken, $oauthTokenSecret);
|
||||
}
|
||||
if (empty($oauthToken) && !empty($oauthTokenSecret)) {
|
||||
$this->bearer = $oauthTokenSecret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $oauthToken
|
||||
* @param string $oauthTokenSecret
|
||||
*/
|
||||
public function setOauthToken($oauthToken, $oauthTokenSecret)
|
||||
{
|
||||
$this->token = new Token($oauthToken, $oauthTokenSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLastApiPath()
|
||||
{
|
||||
return $this->response->getApiPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLastHttpCode()
|
||||
{
|
||||
return $this->response->getHttpCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getLastXHeaders()
|
||||
{
|
||||
return $this->response->getXHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function getLastBody()
|
||||
{
|
||||
return $this->response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the last response cache.
|
||||
*/
|
||||
public function resetLastResponse()
|
||||
{
|
||||
$this->response = new Response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make URLs for user browser navigation.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url($path, array $parameters)
|
||||
{
|
||||
$this->resetLastResponse();
|
||||
$this->response->setApiPath($path);
|
||||
$query = http_build_query($parameters);
|
||||
return sprintf('%s/%s?%s', self::API_HOST, $path, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make /oauth/* requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array
|
||||
* @throws TwitterOAuthException
|
||||
*/
|
||||
public function oauth($path, array $parameters = [])
|
||||
{
|
||||
$response = [];
|
||||
$this->resetLastResponse();
|
||||
$this->response->setApiPath($path);
|
||||
$url = sprintf('%s/%s', self::API_HOST, $path);
|
||||
$result = $this->oAuthRequest($url, 'POST', $parameters);
|
||||
|
||||
if ($this->getLastHttpCode() != 200) {
|
||||
throw new TwitterOAuthException($result);
|
||||
}
|
||||
|
||||
parse_str($result, $response);
|
||||
$this->response->setBody($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make /oauth2/* requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function oauth2($path, array $parameters = [])
|
||||
{
|
||||
$method = 'POST';
|
||||
$this->resetLastResponse();
|
||||
$this->response->setApiPath($path);
|
||||
$url = sprintf('%s/%s', self::API_HOST, $path);
|
||||
$request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
|
||||
$authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer);
|
||||
$result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
|
||||
$response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
|
||||
$this->response->setBody($response);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make GET requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function get($path, array $parameters = [])
|
||||
{
|
||||
return $this->http('GET', self::API_HOST, $path, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make POST requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function post($path, array $parameters = [])
|
||||
{
|
||||
return $this->http('POST', self::API_HOST, $path, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make DELETE requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function delete($path, array $parameters = [])
|
||||
{
|
||||
return $this->http('DELETE', self::API_HOST, $path, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make PUT requests to the API.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function put($path, array $parameters = [])
|
||||
{
|
||||
return $this->http('PUT', self::API_HOST, $path, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload media to upload.twitter.com.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
* @param boolean $chunked
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public function upload($path, array $parameters = [], $chunked = false)
|
||||
{
|
||||
if ($chunked) {
|
||||
return $this->uploadMediaChunked($path, $parameters);
|
||||
} else {
|
||||
return $this->uploadMediaNotChunked($path, $parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to upload media (not chunked) to upload.twitter.com.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
private function uploadMediaNotChunked($path, array $parameters)
|
||||
{
|
||||
$file = file_get_contents($parameters['media']);
|
||||
$base = base64_encode($file);
|
||||
$parameters['media'] = $base;
|
||||
return $this->http('POST', self::UPLOAD_HOST, $path, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to upload media (chunked) to upload.twitter.com.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
private function uploadMediaChunked($path, array $parameters)
|
||||
{
|
||||
$init = $this->http('POST', self::UPLOAD_HOST, $path, $this->mediaInitParameters($parameters));
|
||||
// Append
|
||||
$segmentIndex = 0;
|
||||
$media = fopen($parameters['media'], 'rb');
|
||||
while (!feof($media))
|
||||
{
|
||||
$this->http('POST', self::UPLOAD_HOST, 'media/upload', [
|
||||
'command' => 'APPEND',
|
||||
'media_id' => $init->media_id_string,
|
||||
'segment_index' => $segmentIndex++,
|
||||
'media_data' => base64_encode(fread($media, $this->chunkSize))
|
||||
]);
|
||||
}
|
||||
fclose($media);
|
||||
// Finalize
|
||||
$finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
|
||||
'command' => 'FINALIZE',
|
||||
'media_id' => $init->media_id_string
|
||||
]);
|
||||
return $finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to get params for upload media chunked init.
|
||||
* Twitter docs: https://dev.twitter.com/rest/reference/post/media/upload-init.html
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function mediaInitParameters(array $parameters)
|
||||
{
|
||||
$return = [
|
||||
'command' => 'INIT',
|
||||
'media_type' => $parameters['media_type'],
|
||||
'total_bytes' => filesize($parameters['media'])
|
||||
];
|
||||
if (isset($parameters['additional_owners'])) {
|
||||
$return['additional_owners'] = $parameters['additional_owners'];
|
||||
}
|
||||
if (isset($parameters['media_category'])) {
|
||||
$return['media_category'] = $parameters['media_category'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $host
|
||||
* @param string $path
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
private function http($method, $host, $path, array $parameters)
|
||||
{
|
||||
$this->resetLastResponse();
|
||||
$url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path);
|
||||
$this->response->setApiPath($path);
|
||||
$result = $this->oAuthRequest($url, $method, $parameters);
|
||||
$response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
|
||||
$this->response->setBody($response);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and sign an OAuth / API request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return string
|
||||
* @throws TwitterOAuthException
|
||||
*/
|
||||
private function oAuthRequest($url, $method, array $parameters)
|
||||
{
|
||||
$request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
|
||||
if (array_key_exists('oauth_callback', $parameters)) {
|
||||
// Twitter doesn't like oauth_callback as a parameter.
|
||||
unset($parameters['oauth_callback']);
|
||||
}
|
||||
if ($this->bearer === null) {
|
||||
$request->signRequest($this->signatureMethod, $this->consumer, $this->token);
|
||||
$authorization = $request->toHeader();
|
||||
if (array_key_exists('oauth_verifier', $parameters)) {
|
||||
// Twitter doesn't always work with oauth in the body and in the header
|
||||
// and it's already included in the $authorization header
|
||||
unset($parameters['oauth_verifier']);
|
||||
}
|
||||
} else {
|
||||
$authorization = 'Authorization: Bearer ' . $this->bearer;
|
||||
}
|
||||
return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Curl options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function curlOptions()
|
||||
{
|
||||
$options = [
|
||||
// CURLOPT_VERBOSE => true,
|
||||
CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_SSL_VERIFYHOST => 2,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_TIMEOUT => $this->timeout,
|
||||
CURLOPT_USERAGENT => $this->userAgent,
|
||||
];
|
||||
|
||||
if ($this->useCAFile()) {
|
||||
$options[CURLOPT_CAINFO] = __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem';
|
||||
}
|
||||
|
||||
if($this->gzipEncoding) {
|
||||
$options[CURLOPT_ENCODING] = 'gzip';
|
||||
}
|
||||
|
||||
if (!empty($this->proxy)) {
|
||||
$options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
|
||||
$options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
|
||||
$options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
|
||||
$options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
|
||||
$options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param string $authorization
|
||||
* @param array $postfields
|
||||
*
|
||||
* @return string
|
||||
* @throws TwitterOAuthException
|
||||
*/
|
||||
private function request($url, $method, $authorization, array $postfields)
|
||||
{
|
||||
$options = $this->curlOptions($url, $authorization);
|
||||
$options[CURLOPT_URL] = $url;
|
||||
$options[CURLOPT_HTTPHEADER] = ['Accept: application/json', $authorization, 'Expect:'];
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
break;
|
||||
case 'POST':
|
||||
$options[CURLOPT_POST] = true;
|
||||
$options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
|
||||
break;
|
||||
case 'DELETE':
|
||||
$options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
|
||||
break;
|
||||
case 'PUT':
|
||||
$options[CURLOPT_CUSTOMREQUEST] = 'PUT';
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) {
|
||||
$options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
|
||||
}
|
||||
|
||||
|
||||
$curlHandle = curl_init();
|
||||
curl_setopt_array($curlHandle, $options);
|
||||
$response = curl_exec($curlHandle);
|
||||
|
||||
// Throw exceptions on cURL errors.
|
||||
if (curl_errno($curlHandle) > 0) {
|
||||
throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle));
|
||||
}
|
||||
|
||||
$this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
|
||||
$parts = explode("\r\n\r\n", $response);
|
||||
$responseBody = array_pop($parts);
|
||||
$responseHeader = array_pop($parts);
|
||||
$this->response->setHeaders($this->parseHeaders($responseHeader));
|
||||
|
||||
curl_close($curlHandle);
|
||||
|
||||
return $responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the header info to store.
|
||||
*
|
||||
* @param string $header
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseHeaders($header)
|
||||
{
|
||||
$headers = [];
|
||||
foreach (explode("\r\n", $header) as $line) {
|
||||
if (strpos($line, ':') !== false) {
|
||||
list ($key, $value) = explode(': ', $line);
|
||||
$key = str_replace('-', '_', strtolower($key));
|
||||
$headers[$key] = trim($value);
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode application authorization header with base64.
|
||||
*
|
||||
* @param Consumer $consumer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encodeAppAuthorization(Consumer $consumer)
|
||||
{
|
||||
$key = rawurlencode($consumer->key);
|
||||
$secret = rawurlencode($consumer->secret);
|
||||
return base64_encode($key . ':' . $secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the code running from a Phar module.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function pharRunning()
|
||||
{
|
||||
return class_exists('Phar') && \Phar::running(false) !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Use included CA file instead of OS provided list.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function useCAFile()
|
||||
{
|
||||
/* Use CACert file when not in a PHAR file. */
|
||||
return !$this->pharRunning();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
/**
|
||||
* @author Abraham Williams <abraham@abrah.am>
|
||||
*/
|
||||
class TwitterOAuthException extends \Exception
|
||||
{
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2007 Andy Smith
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param $input
|
||||
*
|
||||
* @return array|mixed|string
|
||||
*/
|
||||
public static function urlencodeRfc3986($input)
|
||||
{
|
||||
$output = '';
|
||||
if (is_array($input)) {
|
||||
$output = array_map([__NAMESPACE__ . '\Util', 'urlencodeRfc3986'], $input);
|
||||
} elseif (is_scalar($input)) {
|
||||
$output = rawurlencode($input);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function urldecodeRfc3986($string)
|
||||
{
|
||||
return urldecode($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes a input like a=b&a=c&d=e and returns the parsed
|
||||
* parameters like this
|
||||
* array('a' => array('b','c'), 'd' => 'e')
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function parseParameters($input)
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$pairs = explode('&', $input);
|
||||
|
||||
$parameters = [];
|
||||
foreach ($pairs as $pair) {
|
||||
$split = explode('=', $pair, 2);
|
||||
$parameter = Util::urldecodeRfc3986($split[0]);
|
||||
$value = isset($split[1]) ? Util::urldecodeRfc3986($split[1]) : '';
|
||||
|
||||
if (isset($parameters[$parameter])) {
|
||||
// We have already recieved parameter(s) with this name, so add to the list
|
||||
// of parameters with this name
|
||||
|
||||
if (is_scalar($parameters[$parameter])) {
|
||||
// This is the first duplicate, so transform scalar (string) into an array
|
||||
// so we can add the duplicates
|
||||
$parameters[$parameter] = [$parameters[$parameter]];
|
||||
}
|
||||
|
||||
$parameters[$parameter][] = $value;
|
||||
} else {
|
||||
$parameters[$parameter] = $value;
|
||||
}
|
||||
}
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function buildHttpQuery(array $params)
|
||||
{
|
||||
if (empty($params)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Urlencode both keys and values
|
||||
$keys = Util::urlencodeRfc3986(array_keys($params));
|
||||
$values = Util::urlencodeRfc3986(array_values($params));
|
||||
$params = array_combine($keys, $values);
|
||||
|
||||
// Parameters are sorted by name, using lexicographical byte value ordering.
|
||||
// Ref: Spec: 9.1.1 (1)
|
||||
uksort($params, 'strcmp');
|
||||
|
||||
$pairs = [];
|
||||
foreach ($params as $parameter => $value) {
|
||||
if (is_array($value)) {
|
||||
// If two or more parameters share the same name, they are sorted by their value
|
||||
// Ref: Spec: 9.1.1 (1)
|
||||
// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
|
||||
sort($value, SORT_STRING);
|
||||
foreach ($value as $duplicateValue) {
|
||||
$pairs[] = $parameter . '=' . $duplicateValue;
|
||||
}
|
||||
} else {
|
||||
$pairs[] = $parameter . '=' . $value;
|
||||
}
|
||||
}
|
||||
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
|
||||
// Each name-value pair is separated by an '&' character (ASCII code 38)
|
||||
return implode('&', $pairs);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Util;
|
||||
|
||||
/**
|
||||
* @author louis <louis@systemli.org>
|
||||
*/
|
||||
class JsonDecoder
|
||||
{
|
||||
/**
|
||||
* Decodes a JSON string to stdObject or associative array
|
||||
*
|
||||
* @param string $string
|
||||
* @param bool $asArray
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
public static function decode($string, $asArray)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
|
||||
return json_decode($string, $asArray, 512, JSON_BIGINT_AS_STRING);
|
||||
}
|
||||
|
||||
return json_decode($string, $asArray);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Tests;
|
||||
|
||||
use Abraham\TwitterOAuth\SignatureMethod;
|
||||
|
||||
abstract class AbstractSignatureMethodTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @return SignatureMethod
|
||||
*/
|
||||
abstract public function getClass();
|
||||
|
||||
abstract protected function signatureDataProvider();
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals($this->name, $this->getClass()->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider signatureDataProvider
|
||||
*/
|
||||
public function testBuildSignature($expected, $request, $consumer, $token)
|
||||
{
|
||||
$this->assertEquals($expected, $this->getClass()->buildSignature($request, $consumer, $token));
|
||||
}
|
||||
|
||||
protected function getRequest()
|
||||
{
|
||||
return $this->getMockBuilder('Abraham\TwitterOAuth\Request')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
protected function getConsumer($key = null, $secret = null, $callbackUrl = null)
|
||||
{
|
||||
return $this->getMockBuilder('Abraham\TwitterOAuth\Consumer')
|
||||
->setConstructorArgs([$key, $secret, $callbackUrl])
|
||||
->getMock();
|
||||
}
|
||||
|
||||
protected function getToken($key = null, $secret = null)
|
||||
{
|
||||
return $this->getMockBuilder('Abraham\TwitterOAuth\Token')
|
||||
->setConstructorArgs([$key, $secret])
|
||||
->getMock();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Tests;
|
||||
|
||||
use Abraham\TwitterOAuth\Consumer;
|
||||
|
||||
class ConsumerTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testToString()
|
||||
{
|
||||
$key = uniqid();
|
||||
$secret = uniqid();
|
||||
$consumer = new Consumer($key, $secret);
|
||||
|
||||
$this->assertEquals("Consumer[key=$key,secret=$secret]", $consumer->__toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Tests;
|
||||
|
||||
use Abraham\TwitterOAuth\HmacSha1;
|
||||
|
||||
class HmacSha1Test extends AbstractSignatureMethodTest
|
||||
{
|
||||
protected $name = 'HMAC-SHA1';
|
||||
|
||||
public function getClass()
|
||||
{
|
||||
return new HmacSha1();
|
||||
}
|
||||
|
||||
public function signatureDataProvider()
|
||||
{
|
||||
return [
|
||||
['5CoEcoq7XoKFjwYCieQvuzadeUA=', $this->getRequest(), $this->getConsumer(), $this->getToken()],
|
||||
[
|
||||
'EBw0gHngam3BTx8kfPfNNSyKem4=',
|
||||
$this->getRequest(),
|
||||
$this->getConsumer('key', 'secret'),
|
||||
$this->getToken()
|
||||
],
|
||||
[
|
||||
'kDsHFZzws2a5M6cAQjfpdNBo+v8=',
|
||||
$this->getRequest(),
|
||||
$this->getConsumer('key', 'secret'),
|
||||
$this->getToken('key', 'secret')
|
||||
],
|
||||
['EBw0gHngam3BTx8kfPfNNSyKem4=', $this->getRequest(), $this->getConsumer('key', 'secret'), null],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Tests;
|
||||
|
||||
use Abraham\TwitterOAuth\Token;
|
||||
|
||||
class TokenTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @dataProvider tokenProvider
|
||||
*/
|
||||
public function testToString($expected, $key, $secret)
|
||||
{
|
||||
$token = new Token($key, $secret);
|
||||
|
||||
$this->assertEquals($expected, $token->__toString());
|
||||
}
|
||||
|
||||
public function tokenProvider()
|
||||
{
|
||||
return [
|
||||
['oauth_token=key&oauth_token_secret=secret', 'key', 'secret'],
|
||||
['oauth_token=key%2Bkey&oauth_token_secret=secret', 'key+key', 'secret'],
|
||||
['oauth_token=key~key&oauth_token_secret=secret', 'key~key', 'secret'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
/**
|
||||
* WARNING: Running these tests will post and delete through the actual Twitter account.
|
||||
*/
|
||||
namespace Abraham\TwitterOAuth\Test;
|
||||
|
||||
use Abraham\TwitterOAuth\TwitterOAuth;
|
||||
|
||||
class TwitterOAuthTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/** @var TwitterOAuth */
|
||||
protected $twitter;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
|
||||
}
|
||||
|
||||
public function testBuildClient()
|
||||
{
|
||||
$this->assertObjectHasAttribute('consumer', $this->twitter);
|
||||
$this->assertObjectHasAttribute('token', $this->twitter);
|
||||
}
|
||||
|
||||
public function testSetOauthToken()
|
||||
{
|
||||
$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
|
||||
$twitter->setOauthToken(ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
|
||||
$this->assertObjectHasAttribute('consumer', $twitter);
|
||||
$this->assertObjectHasAttribute('token', $twitter);
|
||||
$twitter->get('friendships/show', ['target_screen_name' => 'twitterapi']);
|
||||
$this->assertEquals(200, $twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
public function testOauth2Token()
|
||||
{
|
||||
$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
|
||||
$result = $twitter->oauth2('oauth2/token', ['grant_type' => 'client_credentials']);
|
||||
$this->assertEquals(200, $twitter->getLastHttpCode());
|
||||
$this->assertObjectHasAttribute('token_type', $result);
|
||||
$this->assertObjectHasAttribute('access_token', $result);
|
||||
$this->assertEquals('bearer', $result->token_type);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testOauth2Token
|
||||
*/
|
||||
public function testBearerToken($accessToken)
|
||||
{
|
||||
$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, null, $accessToken->access_token);
|
||||
$result = $twitter->get('statuses/user_timeline', ['screen_name' => 'twitterapi']);
|
||||
if ($twitter->getLastHttpCode() !== 200) {
|
||||
$this->assertEquals('foo', substr($accessToken->access_token, 0, 75));
|
||||
$this->assertEquals('foo', print_r($result, true));
|
||||
}
|
||||
$this->assertEquals(200, $twitter->getLastHttpCode());
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
// This causes issues for parallel run tests.
|
||||
// /**
|
||||
// * @depends testBearerToken
|
||||
// */
|
||||
// public function testOauth2TokenInvalidate($accessToken)
|
||||
// {
|
||||
// $twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
|
||||
// // HACK: access_token is already urlencoded but gets urlencoded again breaking the invalidate request.
|
||||
// $result = $twitter->oauth2(
|
||||
// 'oauth2/invalidate_token',
|
||||
// array('access_token' => urldecode($accessToken->access_token))
|
||||
// );
|
||||
// $this->assertEquals(200, $twitter->getLastHttpCode());
|
||||
// $this->assertObjectHasAttribute('access_token', $result);
|
||||
// return $result;
|
||||
// }
|
||||
|
||||
public function testOauthRequestToken()
|
||||
{
|
||||
$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
|
||||
$result = $twitter->oauth('oauth/request_token', ['oauth_callback' => OAUTH_CALLBACK]);
|
||||
$this->assertEquals(200, $twitter->getLastHttpCode());
|
||||
$this->assertArrayHasKey('oauth_token', $result);
|
||||
$this->assertArrayHasKey('oauth_token_secret', $result);
|
||||
$this->assertArrayHasKey('oauth_callback_confirmed', $result);
|
||||
$this->assertEquals('true', $result['oauth_callback_confirmed']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Abraham\TwitterOAuth\TwitterOAuthException
|
||||
* @expectedExceptionMessage Could not authenticate you
|
||||
*/
|
||||
public function testOauthRequestTokenException()
|
||||
{
|
||||
$twitter = new TwitterOAuth('CONSUMER_KEY', 'CONSUMER_SECRET');
|
||||
$result = $twitter->oauth('oauth/request_token', ['oauth_callback' => OAUTH_CALLBACK]);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Abraham\TwitterOAuth\TwitterOAuthException
|
||||
* @expectedExceptionMessage Invalid oauth_verifier parameter
|
||||
* @depends testOauthRequestToken
|
||||
*/
|
||||
public function testOauthAccessTokenTokenException(array $requestToken)
|
||||
{
|
||||
// Can't test this without a browser logging into Twitter so check for the correct error instead.
|
||||
$twitter = new TwitterOAuth(
|
||||
CONSUMER_KEY,
|
||||
CONSUMER_SECRET,
|
||||
$requestToken['oauth_token'],
|
||||
$requestToken['oauth_token_secret']
|
||||
);
|
||||
$twitter->oauth("oauth/access_token", ["oauth_verifier" => "fake_oauth_verifier"]);
|
||||
}
|
||||
|
||||
public function testUrl()
|
||||
{
|
||||
$url = $this->twitter->url('oauth/authorize', ['foo' => 'bar', 'baz' => 'qux']);
|
||||
$this->assertEquals('https://api.twitter.com/oauth/authorize?foo=bar&baz=qux', $url);
|
||||
}
|
||||
|
||||
public function testGetAccountVerifyCredentials()
|
||||
{
|
||||
// Include entities boolean added to test parameter value cohearsion
|
||||
$this->twitter->get('account/verify_credentials', ["include_entities" => false]);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
// BUG: testing is too unreliable for now
|
||||
// public function testSetProxy()
|
||||
// {
|
||||
// $this->twitter->setProxy(array(
|
||||
// 'CURLOPT_PROXY' => PROXY,
|
||||
// 'CURLOPT_PROXYUSERPWD' => PROXYUSERPWD,
|
||||
// 'CURLOPT_PROXYPORT' => PROXYPORT,
|
||||
// ));
|
||||
// $this->twitter->setTimeouts(60, 60);
|
||||
// $result = $this->twitter->get('account/verify_credentials');
|
||||
// $this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
// $this->assertObjectHasAttribute('id', $result);
|
||||
// }
|
||||
|
||||
public function testGetStatusesMentionsTimeline()
|
||||
{
|
||||
$this->twitter->get('statuses/mentions_timeline');
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
public function testGetSearchTweets()
|
||||
{
|
||||
$result = $this->twitter->get('search/tweets', ['q' => 'twitter']);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
return $result->statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetSearchTweets
|
||||
*/
|
||||
public function testGetSearchTweetsWithMaxId($statuses)
|
||||
{
|
||||
$maxId = array_pop($statuses)->id_str;
|
||||
$this->twitter->get('search/tweets', ['q' => 'twitter', 'max_id' => $maxId]);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
public function testPostFavoritesCreate()
|
||||
{
|
||||
$result = $this->twitter->post('favorites/create', ['id' => '6242973112']);
|
||||
if ($this->twitter->getLastHttpCode() == 403) {
|
||||
// Status already favorited
|
||||
$this->assertEquals(139, $result->errors[0]->code);
|
||||
} else {
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testPostFavoritesCreate
|
||||
*/
|
||||
public function testPostFavoritesDestroy()
|
||||
{
|
||||
$this->twitter->post('favorites/destroy', ['id' => '6242973112']);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
public function testPostStatusesUpdateWithMedia()
|
||||
{
|
||||
$this->twitter->setTimeouts(60, 30);
|
||||
// Image source https://www.flickr.com/photos/titrans/8548825587/
|
||||
$file_path = __DIR__ . '/kitten.jpg';
|
||||
$result = $this->twitter->upload('media/upload', ['media' => $file_path]);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
$this->assertObjectHasAttribute('media_id_string', $result);
|
||||
$parameters = ['status' => 'Hello World ' . time(), 'media_ids' => $result->media_id_string];
|
||||
$result = $this->twitter->post('statuses/update', $parameters);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
if ($this->twitter->getLastHttpCode() == 200) {
|
||||
$result = $this->twitter->post('statuses/destroy/' . $result->id_str);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function testPostStatusesUpdateWithMediaChunked()
|
||||
{
|
||||
$this->twitter->setTimeouts(60, 30);
|
||||
// Video source http://www.sample-videos.com/
|
||||
$file_path = __DIR__ . '/video.mp4';
|
||||
$result = $this->twitter->upload('media/upload', ['media' => $file_path, 'media_type' => 'video/mp4'], true);
|
||||
$this->assertEquals(201, $this->twitter->getLastHttpCode());
|
||||
$this->assertObjectHasAttribute('media_id_string', $result);
|
||||
$parameters = ['status' => 'Hello World ' . time(), 'media_ids' => $result->media_id_string];
|
||||
$result = $this->twitter->post('statuses/update', $parameters);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
if ($this->twitter->getLastHttpCode() == 200) {
|
||||
$result = $this->twitter->post('statuses/destroy/' . $result->id_str);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function testPostStatusesUpdateUtf8()
|
||||
{
|
||||
$result = $this->twitter->post('statuses/update', ['status' => 'xこんにちは世界 ' . time()]);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testPostStatusesUpdateUtf8
|
||||
*/
|
||||
public function testPostStatusesDestroy($status)
|
||||
{
|
||||
$this->twitter->post('statuses/destroy/' . $status->id_str);
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
}
|
||||
|
||||
public function testLastResult()
|
||||
{
|
||||
$this->twitter->get('search/tweets', ['q' => 'twitter']);
|
||||
$this->assertEquals('search/tweets', $this->twitter->getLastApiPath());
|
||||
$this->assertEquals(200, $this->twitter->getLastHttpCode());
|
||||
$this->assertObjectHasAttribute('statuses', $this->twitter->getLastBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testLastResult
|
||||
*/
|
||||
public function testResetLastResponse()
|
||||
{
|
||||
$this->twitter->resetLastResponse();
|
||||
$this->assertEquals('', $this->twitter->getLastApiPath());
|
||||
$this->assertEquals(0, $this->twitter->getLastHttpCode());
|
||||
$this->assertEquals([], $this->twitter->getLastBody());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Abraham\TwitterOAuth\Tests;
|
||||
|
||||
use Abraham\TwitterOAuth\Util\JsonDecoder;
|
||||
|
||||
class JsonDecoderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider jsonProvider
|
||||
*/
|
||||
public function testDecode($input, $asArray, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, JsonDecoder::decode($input, $asArray));
|
||||
}
|
||||
|
||||
public function jsonProvider()
|
||||
{
|
||||
return [
|
||||
['[]', true, []],
|
||||
['[1,2,3]', true, [1, 2, 3]],
|
||||
['[{"id": 556179961825226750}]', true, [['id' => 556179961825226750]]],
|
||||
['[]', false, []],
|
||||
['[1,2,3]', false, [1, 2, 3]],
|
||||
[
|
||||
'[{"id": 556179961825226750}]',
|
||||
false,
|
||||
[
|
||||
$this->getClass(function ($object) {
|
||||
$object->id = 556179961825226750;
|
||||
return $object;
|
||||
})
|
||||
]
|
||||
],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callable
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function getClass(\Closure $callable)
|
||||
{
|
||||
$object = new \stdClass();
|
||||
|
||||
return $callable($object);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
define('CONSUMER_KEY', getenv('TEST_CONSUMER_KEY'));
|
||||
define('CONSUMER_SECRET', getenv('TEST_CONSUMER_SECRET'));
|
||||
define('ACCESS_TOKEN', getenv('TEST_ACCESS_TOKEN'));
|
||||
define('ACCESS_TOKEN_SECRET', getenv('TEST_ACCESS_TOKEN_SECRET'));
|
||||
define('OAUTH_CALLBACK', getenv('TEST_OAUTH_CALLBACK'));
|
||||
define('PROXY', getenv('TEST_CURLOPT_PROXY'));
|
||||
define('PROXYUSERPWD', getenv('TEST_CURLOPT_PROXYUSERPWD'));
|
||||
define('PROXYPORT', getenv('TEST_CURLOPT_PROXYPORT'));
|
Binary file not shown.
After Width: | Height: | Size: 211 KiB |
|
@ -0,0 +1,13 @@
|
|||
# WARNING: Running the tests will perform live actions as the Twitter account.
|
||||
# Set all values, move to `env`, run `source tests/env` and `phpunit` to start testing.
|
||||
|
||||
# To run the tests you must register Twitter application at https://app.twitter.com/.
|
||||
export TEST_CONSUMER_KEY=
|
||||
export TEST_CONSUMER_SECRET=
|
||||
export TEST_ACCESS_TOKEN=
|
||||
export TEST_ACCESS_TOKEN_SECRET=
|
||||
export TEST_OAUTH_CALLBACK=
|
||||
# You can find proxies for testing at http://proxylist.hidemyass.com/.
|
||||
export TEST_CURLOPT_PROXY=
|
||||
export TEST_CURLOPT_PROXYUSERPWD=
|
||||
export TEST_CURLOPT_PROXYPORT=
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitd051a3fd38373f38066f9a7f62be4c25::getLoader();
|
|
@ -0,0 +1,445 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
// PSR-4
|
||||
private $prefixLengthsPsr4 = array();
|
||||
private $prefixDirsPsr4 = array();
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
private $prefixesPsr0 = array();
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath.'\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Abraham\\TwitterOAuth\\' => array($vendorDir . '/abraham/twitteroauth/src'),
|
||||
);
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitd051a3fd38373f38066f9a7f62be4c25
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitd051a3fd38373f38066f9a7f62be4c25', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitd051a3fd38373f38066f9a7f62be4c25', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitd051a3fd38373f38066f9a7f62be4c25::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitd051a3fd38373f38066f9a7f62be4c25
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'A' =>
|
||||
array (
|
||||
'Abraham\\TwitterOAuth\\' => 21,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Abraham\\TwitterOAuth\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/abraham/twitteroauth/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitd051a3fd38373f38066f9a7f62be4c25::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitd051a3fd38373f38066f9a7f62be4c25::$prefixDirsPsr4;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
[
|
||||
{
|
||||
"name": "abraham/twitteroauth",
|
||||
"version": "0.7.4",
|
||||
"version_normalized": "0.7.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/abraham/twitteroauth.git",
|
||||
"reference": "c6f9e692552dd037b2324ed0dfa28a4e60875acf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/abraham/twitteroauth/zipball/c6f9e692552dd037b2324ed0dfa28a4e60875acf",
|
||||
"reference": "c6f9e692552dd037b2324ed0dfa28a4e60875acf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmd/phpmd": "~2.6",
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"squizlabs/php_codesniffer": "~3.0"
|
||||
},
|
||||
"time": "2017-06-30T22:02:01+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Abraham\\TwitterOAuth\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Abraham Williams",
|
||||
"email": "abraham@abrah.am",
|
||||
"homepage": "https://abrah.am",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "The most popular PHP library for use with the Twitter OAuth REST API.",
|
||||
"homepage": "https://twitteroauth.com",
|
||||
"keywords": [
|
||||
"Twitter API",
|
||||
"Twitter oAuth",
|
||||
"api",
|
||||
"oauth",
|
||||
"rest",
|
||||
"social",
|
||||
"twitter"
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user