diff --git a/composer.json b/composer.json index 94d6f6a..67247d2 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "dg/twitter-php": "3.6.*", "p3k/timezone": "*", "p3k/http": "0.1.*", - "cebe/markdown": "1.1.*" + "cebe/markdown": "1.1.*", + "facebook/graph-sdk": "^5.5" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 79cf6c0..bb40af9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,8 @@ "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": "082e2019c20a5d611f58716d3f75a131", + "hash": "280d14580c259d2219f07c649ef3c613", + "content-hash": "c4305989e1c70ad69a6073d15652f52e", "packages": [ { "name": "cebe/markdown", @@ -64,7 +65,7 @@ "markdown", "markdown-extra" ], - "time": "2016-09-14T20:40:20+00:00" + "time": "2016-09-14 20:40:20" }, { "name": "dg/twitter-php", @@ -106,7 +107,7 @@ "oauth", "twitter" ], - "time": "2016-08-15T16:46:22+00:00" + "time": "2016-08-15 16:46:22" }, { "name": "ezyang/htmlpurifier", @@ -153,7 +154,65 @@ "keywords": [ "html" ], - "time": "2017-03-13T06:30:53+00:00" + "time": "2017-03-13 06:30:53" + }, + { + "name": "facebook/graph-sdk", + "version": "5.5.0", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-graph-sdk.git", + "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/93d7dc87e55a541d2e27d38f3aed40abbffdf6e1", + "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1", + "shasum": "" + }, + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "~5.0", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client", + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": [ + "src/Facebook/polyfills.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Facebook Platform" + ], + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "description": "Facebook SDK for PHP", + "homepage": "https://github.com/facebook/php-graph-sdk", + "keywords": [ + "facebook", + "sdk" + ], + "time": "2017-04-20 14:15:02" }, { "name": "indieweb/link-rel-parser", @@ -199,7 +258,7 @@ "indieweb", "microformats2" ], - "time": "2017-01-11T17:14:49+00:00" + "time": "2017-01-11 17:14:49" }, { "name": "mf2/mf2", @@ -254,7 +313,7 @@ "parser", "semantic" ], - "time": "2017-05-27T15:27:47+00:00" + "time": "2017-05-27 15:27:47" }, { "name": "p3k/http", @@ -292,7 +351,7 @@ ], "description": "A simple wrapper API around the PHP curl functions", "homepage": "https://github.com/aaronpk/p3k-http", - "time": "2017-04-29T17:43:29+00:00" + "time": "2017-04-29 17:43:29" }, { "name": "p3k/timezone", @@ -327,7 +386,7 @@ "p3k", "timezone" ], - "time": "2017-01-12T17:30:08+00:00" + "time": "2017-01-12 17:30:08" } ], "packages-dev": [ @@ -383,7 +442,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "ircmaxell/password-compat", @@ -425,7 +484,7 @@ "hashing", "password" ], - "time": "2014-11-20T16:49:30+00:00" + "time": "2014-11-20 16:49:30" }, { "name": "league/container", @@ -483,7 +542,7 @@ "injection", "league" ], - "time": "2015-04-05T17:14:48+00:00" + "time": "2015-04-05 17:14:48" }, { "name": "league/plates", @@ -538,7 +597,7 @@ "templating", "views" ], - "time": "2016-12-28T00:14:17+00:00" + "time": "2016-12-28 00:14:17" }, { "name": "league/route", @@ -596,7 +655,7 @@ "league", "route" ], - "time": "2015-09-11T07:40:31+00:00" + "time": "2015-09-11 07:40:31" }, { "name": "nikic/fast-route", @@ -639,7 +698,7 @@ "router", "routing" ], - "time": "2016-03-25T23:46:52+00:00" + "time": "2016-03-25 23:46:52" }, { "name": "phpdocumentor/reflection-common", @@ -693,7 +752,7 @@ "reflection", "static analysis" ], - "time": "2015-12-27T11:43:31+00:00" + "time": "2015-12-27 11:43:31" }, { "name": "phpdocumentor/reflection-docblock", @@ -738,7 +797,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30T07:12:33+00:00" + "time": "2016-09-30 07:12:33" }, { "name": "phpdocumentor/type-resolver", @@ -785,7 +844,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-11-25T06:54:22+00:00" + "time": "2016-11-25 06:54:22" }, { "name": "phpspec/prophecy", @@ -848,7 +907,7 @@ "spy", "stub" ], - "time": "2017-03-02T20:05:34+00:00" + "time": "2017-03-02 20:05:34" }, { "name": "phpunit/php-code-coverage", @@ -910,7 +969,7 @@ "testing", "xunit" ], - "time": "2015-10-06T15:47:00+00:00" + "time": "2015-10-06 15:47:00" }, { "name": "phpunit/php-file-iterator", @@ -957,7 +1016,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -998,7 +1057,7 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", @@ -1047,7 +1106,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2017-02-26 11:10:40" }, { "name": "phpunit/php-token-stream", @@ -1096,7 +1155,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-02-27T10:12:30+00:00" + "time": "2017-02-27 10:12:30" }, { "name": "phpunit/phpunit", @@ -1168,7 +1227,7 @@ "testing", "xunit" ], - "time": "2017-02-06T05:18:07+00:00" + "time": "2017-02-06 05:18:07" }, { "name": "phpunit/phpunit-mock-objects", @@ -1224,7 +1283,7 @@ "mock", "xunit" ], - "time": "2015-10-02T06:51:40+00:00" + "time": "2015-10-02 06:51:40" }, { "name": "sebastian/comparator", @@ -1288,7 +1347,7 @@ "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2017-01-29 09:50:25" }, { "name": "sebastian/diff", @@ -1340,7 +1399,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2017-05-22 07:24:03" }, { "name": "sebastian/environment", @@ -1390,7 +1449,7 @@ "environment", "hhvm" ], - "time": "2016-08-18T05:49:44+00:00" + "time": "2016-08-18 05:49:44" }, { "name": "sebastian/exporter", @@ -1457,7 +1516,7 @@ "export", "exporter" ], - "time": "2016-06-17T09:04:28+00:00" + "time": "2016-06-17 09:04:28" }, { "name": "sebastian/global-state", @@ -1508,7 +1567,7 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2015-10-12 03:26:01" }, { "name": "sebastian/recursion-context", @@ -1561,7 +1620,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-10-03T07:41:43+00:00" + "time": "2016-10-03 07:41:43" }, { "name": "sebastian/version", @@ -1596,7 +1655,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" + "time": "2015-06-21 13:59:46" }, { "name": "symfony/http-foundation", @@ -1651,7 +1710,7 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2017-05-01T14:31:55+00:00" + "time": "2017-05-01 14:31:55" }, { "name": "symfony/polyfill-mbstring", @@ -1710,7 +1769,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php54", @@ -1768,7 +1827,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php55", @@ -1824,7 +1883,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/yaml", @@ -1879,7 +1938,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-05-01T14:55:58+00:00" + "time": "2017-05-01 14:55:58" }, { "name": "webmozart/assert", @@ -1929,7 +1988,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2016-11-23 20:04:58" } ], "aliases": [], diff --git a/controllers/Parse.php b/controllers/Parse.php index ed6a753..46392f8 100644 --- a/controllers/Parse.php +++ b/controllers/Parse.php @@ -83,6 +83,7 @@ class Parse { $fields = [ 'twitter_api_key','twitter_api_secret','twitter_access_token','twitter_access_token_secret', + 'facebook_app_id', 'facebook_app_secret', 'github_access_token', 'token' ]; diff --git a/lib/XRay/Fetcher.php b/lib/XRay/Fetcher.php index 8139cf8..ec8e175 100644 --- a/lib/XRay/Fetcher.php +++ b/lib/XRay/Fetcher.php @@ -43,6 +43,11 @@ class Fetcher { return $this->_fetch_tweet($url, $opts); } + // Check if this is a Facebook URL and use the API + if(Formats\Facebook::matches_host($url)) { + return $this->_fetch_facebook($url, $opts); + } + // Transform the HTML GitHub URL into an GitHub API request and fetch the API response if(Formats\GitHub::matches_host($url)) { return $this->_fetch_github($url, $opts); @@ -155,6 +160,26 @@ class Fetcher { ]; } + private function _fetch_facebook($url, $opts) { + $fields = ['facebook_app_id','facebook_app_secret']; + $creds = []; + foreach($fields as $f) { + if(isset($opts[$f])) + $creds[$f] = $opts[$f]; + } + + if(count($creds) < 2) { + return [ + 'error_code' => 400, + 'error' => 'missing_parameters', + 'error_description' => 'Both Facebook credentials must be included in the request' + ]; + } + + // TODO: Question, should I do this like Twitter or like Github? + return Formats\Facebook::fetch($url, $creds); + } + private function _fetch_github($url, $opts) { $fields = ['github_access_token']; $creds = []; diff --git a/lib/XRay/Formats/Facebook.php b/lib/XRay/Formats/Facebook.php new file mode 100644 index 0000000..af1ca68 --- /dev/null +++ b/lib/XRay/Formats/Facebook.php @@ -0,0 +1,105 @@ + 'event', + 'url' => $url, + 'name' => $fbObject['name'], + 'start' => $fbObject['start_time'], + 'end' => $fbObject['end_time'], + 'summary' => $fbObject['description'], + 'location' => [ + $fbObject['place']['name'] + ] + ); + + return [ + 'data' => $event, + 'original' => $fbObject + ]; + } + } + + public static function fetch($url, $creds) { + + $parts = self::extract_url_parts($url); + + if(!$parts or $parts['api_uri'] == false) { + return [ + 'error' => 'unsupported_url', + 'error_description' => 'This Facebook URL is not supported', + 'error_code' => 400, + ]; + } + + $fb = new \Facebook\Facebook([ + 'app_id' => $creds['facebook_app_id'], + 'app_secret' => $creds['facebook_app_secret'], + 'default_graph_version' => 'v2.9', + ]); + + $fbApp = new \Facebook\FacebookApp($creds['facebook_app_id'], $creds['facebook_app_secret']); + $token = $fbApp->getAccessToken(); + + $request = new \Facebook\FacebookRequest($fbApp, $token, 'GET', $parts['api_uri']); + + try { + $response = $fb->getClient()->sendRequest($request); + } catch(\Facebook\Exceptions\FacebookResponseException $e) { + return [ + 'error' => 'facebook_graph_error', + 'error_description' => 'Graph returned an error: ' . $e->getMessage(), + 'error_code' => 400, + ]; + } catch(\Facebook\Exceptions\FacebookSDKException $e) { + return [ + 'error' => 'facebook_sdk_error', + 'error_description' => 'Facebook SDK returned an error: ' . $e->getMessage(), + 'error_code' => 400, + ]; + } + + return [ + 'code' => 200, + 'body' => $response->getDecodedBody(), + 'url' => $url + ]; + } + + private static function extract_url_parts($url) { + $response = false; + + if(preg_match('~https://(.*?).?facebook.com/([^/]+)/posts/(\d+)/?$~', $url, $match)) { + // TODO: how do we get these? + // $response['type'] = 'entry'; + // $response['api_uri'] = false; + + } elseif(preg_match('~https://(.*?).?facebook.com/events/(\d+)/?$~', $url, $match)) { + $response['type'] = 'event'; + $response['api_uri'] = '/'.$match[2]; + } + + return $response; + } +} diff --git a/lib/XRay/Parser.php b/lib/XRay/Parser.php index 639aba7..bf9f13a 100644 --- a/lib/XRay/Parser.php +++ b/lib/XRay/Parser.php @@ -30,6 +30,10 @@ class Parser { return Formats\Twitter::parse($body, $url); } + if(Formats\Facebook::matches($url)) { + return Formats\Facebook::parse($body, $url); + } + if(Formats\XKCD::matches($url)) { return Formats\XKCD::parse($body, $url); }