From ace505401e450bba328c1e73e3c4382c552e2e92 Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 09:39:17 -0700 Subject: [PATCH 1/9] create basic Composer Package --- buffer.php | 207 -------------------------------- composer.json | 8 ++ src/Buffer/App/BufferApp.php | 227 +++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 207 deletions(-) delete mode 100644 buffer.php create mode 100644 composer.json create mode 100644 src/Buffer/App/BufferApp.php diff --git a/buffer.php b/buffer.php deleted file mode 100644 index 70b4148..0000000 --- a/buffer.php +++ /dev/null @@ -1,207 +0,0 @@ - 'get', - - '/profiles' => 'get', - '/profiles/:id/schedules/update' => 'post', // Array schedules [0][days][]=mon, [0][times][]=12:00 - '/profiles/:id/updates/reorder' => 'post', // Array order, int offset, bool utc - '/profiles/:id/updates/pending' => 'get', - '/profiles/:id/updates/sent' => 'get', - '/profiles/:id/schedules' => 'get', - '/profiles/:id' => 'get', - - '/updates/:id/update' => 'post', // String text, Bool now, Array media ['link'], ['description'], ['picture'], Bool utc - '/updates/create' => 'post', // String text, Array profile_ids, Aool shorten, Bool now, Array media ['link'], ['description'], ['picture'] - '/updates/:id/destroy' => 'post', - '/updates/:id' => 'get', - - '/links/shares' => 'get', - ); - - public $errors = array( - 'invalid-endpoint' => 'The endpoint you supplied does not appear to be valid.', - - '403' => 'Permission denied.', - '404' => 'Endpoint not found.', - '405' => 'Method not allowed.', - '1000' => 'An unknown error occurred.', - '1001' => 'Access token required.', - '1002' => 'Not within application scope.', - '1003' => 'Parameter not recognized.', - '1004' => 'Required parameter missing.', - '1005' => 'Unsupported response format.', - '1010' => 'Profile could not be found.', - '1011' => 'No authorization to access profile.', - '1012' => 'Profile did not save successfully.', - '1013' => 'Profile schedule limit reached.', - '1014' => 'Profile limit for user has been reached.', - '1020' => 'Update could not be found.', - '1021' => 'No authorization to access update.', - '1022' => 'Update did not save successfully.', - '1023' => 'Update limit for profile has been reached.', - '1024' => 'Update limit for team profile has been reached.', - '1028' => 'Update soft limit for profile reached.', - '1030' => 'Media filetype not supported.', - '1031' => 'Media filesize out of acceptable range.', - ); - - public $responses = array( - '403' => 'Permission denied.', - '404' => 'Endpoint not found.', - '405' => 'Method not allowed.', - '500' => 'An unknown error occurred.', - '403' => 'Access token required.', - '403' => 'Not within application scope.', - '400' => 'Parameter not recognized.', - '400' => 'Required parameter missing.', - '406' => 'Unsupported response format.', - '404' => 'Profile could not be found.', - '403' => 'No authorization to access profile.', - '400' => 'Profile did not save successfully.', - '403' => 'Profile schedule limit reached.', - '403' => 'Profile limit for user has been reached.', - '404' => 'Update could not be found.', - '403' => 'No authorization to access update.', - '400' => 'Update did not save successfully.', - '403' => 'Update limit for profile has been reached.', - '403' => 'Update limit for team profile has been reached.', - '403' => 'Update soft limit for profile reached.', - '400' => 'Media filetype not supported.', - '400' => 'Media filesize out of acceptable range.', - ); - - function __construct($client_id = '', $client_secret = '', $callback_url = '') { - if ($client_id) $this->set_client_id($client_id); - if ($client_secret) $this->set_client_secret($client_secret); - if ($callback_url) $this->set_callback_url($callback_url); - - if ($_GET['code']) { - $this->code = $_GET['code']; - $this->create_access_token_url(); - } - - $this->retrieve_access_token(); - } - - function go($endpoint = '', $data = '') { - if (in_array($endpoint, array_keys($this->endpoints))) { - $done_endpoint = $endpoint; - } else { - $ok = false; - - foreach (array_keys($this->endpoints) as $done_endpoint) { - if (preg_match('/' . preg_replace('/(\:\w+)/i', '(\w+)', str_replace('/', '\/', $done_endpoint)) . '/i', $endpoint, $match)) { - $ok = true; - break; - } - } - - if (!$ok) return $this->error('invalid-endpoint'); - } - - if (!$data || !is_array($data)) $data = array(); - $data['access_token'] = $this->access_token; - - $method = $this->endpoints[$done_endpoint]; //get() or post() - return $this->$method($this->buffer_url . $endpoint . '.json', $data); - } - - function store_access_token() { - $_SESSION['oauth']['buffer']['access_token'] = $this->access_token; - } - - function retrieve_access_token() { - $this->access_token = $_SESSION['oauth']['buffer']['access_token']; - - if ($this->access_token) { - $this->ok = true; - } - } - - function error($error) { - return (object) array('error' => $this->errors[$error]); - } - - function create_access_token_url() { - $data = array( - 'code' => $this->code, - 'grant_type' => 'authorization_code', - 'client_id' => $this->client_id, - 'client_secret' => $this->client_secret, - 'redirect_uri' => $this->callback_url, - ); - - $obj = $this->post($this->access_token_url, $data); - $this->access_token = $obj->access_token; - - $this->store_access_token(); - } - - function req($url = '', $data = '', $post = true) { - if (!$url) return false; - if (!$data || !is_array($data)) $data = array(); - - $options = array(CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false); - - if ($post) { - $options += array( - CURLOPT_POST => $post, - CURLOPT_POSTFIELDS => $data - ); - } else { - $url .= '?' . http_build_query($data); - } - - $ch = curl_init($url); - curl_setopt_array($ch, $options); - $rs = curl_exec($ch); - - $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if ($code >= 400) { - return $this->error($code); - } - - return json_decode($rs); - } - - function get($url = '', $data = '') { - return $this->req($url, $data, false); - } - - function post($url = '', $data = '') { - return $this->req($url, $data, true); - } - - function get_login_url() { - return $this->authorize_url . '?' - . 'client_id=' . $this->client_id - . '&redirect_uri=' . urlencode($this->callback_url) - . '&response_type=code'; - } - - function set_client_id($client_id) { - $this->client_id = $client_id; - } - - function set_client_secret($client_secret) { - $this->client_secret = $client_secret; - } - - function set_callback_url($callback_url) { - $this->callback_url = $callback_url; - } - } -?> \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..8e4addb --- /dev/null +++ b/composer.json @@ -0,0 +1,8 @@ +{ + "name": "buffer/app", + "autoload": { + "psr-0" : { + "Buffer\\App" : "src" + } + } +} \ No newline at end of file diff --git a/src/Buffer/App/BufferApp.php b/src/Buffer/App/BufferApp.php new file mode 100644 index 0000000..65048f5 --- /dev/null +++ b/src/Buffer/App/BufferApp.php @@ -0,0 +1,227 @@ + 'get', + + '/profiles' => 'get', + '/profiles/:id/schedules/update' => 'post', // Array schedules [0][days][]=mon, [0][times][]=12:00 + '/profiles/:id/updates/reorder' => 'post', // Array order, int offset, bool utc + '/profiles/:id/updates/pending' => 'get', + '/profiles/:id/updates/sent' => 'get', + '/profiles/:id/schedules' => 'get', + '/profiles/:id' => 'get', + + '/updates/:id/update' => 'post', // String text, Bool now, Array media ['link'], ['description'], ['picture'], Bool utc + '/updates/create' => 'post', // String text, Array profile_ids, Aool shorten, Bool now, Array media ['link'], ['description'], ['picture'] + '/updates/:id/destroy' => 'post', + '/updates/:id' => 'get', + + '/links/shares' => 'get', + ); + + public $errors = array( + 'invalid-endpoint' => 'The endpoint you supplied does not appear to be valid.', + '400' => 'Required parameter missing.', + '403' => 'Permission denied.', + '404' => 'Endpoint not found.', + '405' => 'Method not allowed.', + '1000' => 'An unknown error occurred.', + '1001' => 'Access token required.', + '1002' => 'Not within application scope.', + '1003' => 'Parameter not recognized.', + '1004' => 'Required parameter missing.', + '1005' => 'Unsupported response format.', + '1010' => 'Profile could not be found.', + '1011' => 'No authorization to access profile.', + '1012' => 'Profile did not save successfully.', + '1013' => 'Profile schedule limit reached.', + '1014' => 'Profile limit for user has been reached.', + '1020' => 'Update could not be found.', + '1021' => 'No authorization to access update.', + '1022' => 'Update did not save successfully.', + '1023' => 'Update limit for profile has been reached.', + '1024' => 'Update limit for team profile has been reached.', + '1028' => 'Update soft limit for profile reached.', + '1030' => 'Media filetype not supported.', + '1031' => 'Media filesize out of acceptable range.', + ); + + public $responses = array( + '403' => 'Permission denied.', + '404' => 'Endpoint not found.', + '405' => 'Method not allowed.', + '500' => 'An unknown error occurred.', + '403' => 'Access token required.', + '403' => 'Not within application scope.', + '400' => 'Parameter not recognized.', + '400' => 'Required parameter missing.', + '406' => 'Unsupported response format.', + '404' => 'Profile could not be found.', + '403' => 'No authorization to access profile.', + '400' => 'Profile did not save successfully.', + '403' => 'Profile schedule limit reached.', + '403' => 'Profile limit for user has been reached.', + '404' => 'Update could not be found.', + '403' => 'No authorization to access update.', + '400' => 'Update did not save successfully.', + '403' => 'Update limit for profile has been reached.', + '403' => 'Update limit for team profile has been reached.', + '403' => 'Update soft limit for profile reached.', + '400' => 'Media filetype not supported.', + '400' => 'Media filesize out of acceptable range.', + ); + + public function __construct($client_id = '', $client_secret = '', $callback_url = '') { + + if (isset($client_id)) { + $this->set_client_id($client_id); + } + + if (isset($client_secret)) { + $this->set_client_secret($client_secret); + } + + if (isset($callback_url)) { + $this->set_callback_url($callback_url); + } + + if (isset($_GET['code']) && !empty($_GET['code'])) { + $code = $_GET['code']; + } + + if (isset($code)) { + $this->code = $code; + $this->create_access_token_url(); + } + + $this->retrieve_access_token(); + } + + public function go($endpoint = '', $data = '') { + if (in_array($endpoint, array_keys($this->endpoints))) { + $done_endpoint = $endpoint; + } else { + $ok = false; + + foreach (array_keys($this->endpoints) as $done_endpoint) { + if (preg_match('/' . preg_replace('/(\:\w+)/i', '(\w+)', str_replace('/', '\/', $done_endpoint)) . '/i', $endpoint, $match)) { + $ok = true; + break; + } + } + + if (!$ok) return $this->error('invalid-endpoint'); + } + + if (!$data || !is_array($data)) $data = array(); + $data['access_token'] = $this->access_token; + + $method = $this->endpoints[$done_endpoint]; //get() or post() + return $this->$method($this->buffer_url . $endpoint . '.json', $data); + } + + public function store_access_token() { + $_SESSION['oauth']['buffer']['access_token'] = $this->access_token; + } + + public function retrieve_access_token() { + if (isset($_SESSION['oauth']['buffer']['access_token'])) { + $this->access_token = $_SESSION['oauth']['buffer']['access_token']; + } + + if ($this->access_token) { + $this->ok = true; + } + } + + public function error($error) { + return (object) array('error' => $this->errors[$error]); + } + + public function create_access_token_url() { + $data = array( + 'client_id' => $this->client_id, + 'client_secret' => $this->client_secret, + 'redirect_uri' => $this->callback_url, + 'code' => $this->code, + 'grant_type' => 'authorization_code', + ); + + $obj = $this->post($this->access_token_url, $data); + $this->access_token = $obj->access_token; + + $this->store_access_token(); + } + + public function req($url = '', $data = '', $post = true) { + if (!$url) return false; + if (!$data || !is_array($data)) $data = array(); + + $options = array(CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false); + + if ($post) { + $options += array( + CURLOPT_POST => $post, + CURLOPT_POSTFIELDS => $data + ); + } else { + $url .= '?' . http_build_query($data); + } + + $ch = curl_init($url); + + curl_setopt_array($ch, $options); + $rs = curl_exec($ch); + + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($code >= 400) { + return $this->error($code); + } + + return json_decode($rs); + } + + public function get($url = '', $data = '') { + return $this->req($url, $data, false); + } + + public function post($url = '', $data = '') { + return $this->req($url, $data, true); + } + + public function get_login_url() { + return $this->authorize_url . '?' + . 'client_id=' . $this->client_id + . '&redirect_uri=' . urlencode($this->callback_url) + . '&response_type=code'; + } + + public function set_client_id($client_id) { + $this->client_id = $client_id; + } + + public function set_client_secret($client_secret) { + $this->client_secret = $client_secret; + } + + public function set_callback_url($callback_url) { + $this->callback_url = $callback_url; + } + } \ No newline at end of file From d10c6dbfea041ce6f0feafcaca6b9cff0ed385ae Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:07:42 -0700 Subject: [PATCH 2/9] update README --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8fcc818..f10e935 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -bufferapp-php +bufferapp ============= Simple PHP library for the amazing buffer at http://bufferapp.com # Why? -There wasn't one listed on Buffer's website and a quick Google search didn't turn one up. For most use cases Buffer's plugins will work just fine, but for those of you looking to pump lots of info into buffer via PHP this may help! +There wasn't one listed on Buffer's website and a quick Google search didn't turn one up. +For most use cases Buffer's plugins will work just fine, but for those of you looking to pump lots of info into buffer via PHP this may help! # Using this library @@ -16,7 +17,7 @@ There wasn't one listed on Buffer's website and a quick Google search didn't tur - Initialize like this `$buffer = new BufferApp($client_id, $client_secret, $callback_url);` The `callback_url` needs to be the exact same as the app you registered 3. Start adding buffers! - Once you're in you really only need to check `$buffer->ok` to see if you can perform actions, and then `$buffer->go($endpoint, $data)` to get going! - + ##### Image Attachments The Buffer API seems to be missing documentation for the `media` parameter for creating an update. @@ -26,7 +27,7 @@ Their [example here](http://bufferapp.com/developers/api/updates#updatescreate) To get the desired result you will need to use `media[picture]` _and_ `media[thumbnail]`. - + # Example First thing's first: start a session and require `buffer.php`. We're going to be storing the `access_token` in the session for now. @@ -45,7 +46,7 @@ If `$_GET['code']` is set on this page it assumes it came from Buffer and will a $buffer = new BufferApp($client_id, $client_secret, $callback_url); -Once we've got an `access_token` set the `$buffer->ok` property will read true. It is false by default. +Once we've got an `access_token` set the `$buffer->ok` property will read true. It is false by default. Now that we've received access we are free to run queries against Buffer endpoints! Below we pull the list of profiles associated with the logged in buffer user and submit a test update to each one. if (!$buffer->ok) { @@ -53,7 +54,7 @@ Now that we've received access we are free to run queries against Buffer endpoin } else { //this pulls all of the logged in user's profiles $profiles = $buffer->go('/profiles'); - + if (is_array($profiles)) { foreach ($profiles as $profile) { //this creates a status on each one From c47b125d05a54b8928940f8691ac957521887a73 Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:09:53 -0700 Subject: [PATCH 3/9] update license --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8e4addb..73e547c 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,9 @@ { "name": "buffer/app", + "license": "Apache-2.0", "autoload": { "psr-0" : { "Buffer\\App" : "src" } - } + }, } \ No newline at end of file From 926430bf30d26ffb07caf160220cfcc634e436ea Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:11:16 -0700 Subject: [PATCH 4/9] fix json error --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 73e547c..9efca8b 100644 --- a/composer.json +++ b/composer.json @@ -5,5 +5,5 @@ "psr-0" : { "Buffer\\App" : "src" } - }, + } } \ No newline at end of file From 065eaa78a2b190ca7aa64cccab4e5edbaec2e839 Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:19:14 -0700 Subject: [PATCH 5/9] Update README.md --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f10e935..193063e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ For most use cases Buffer's plugins will work just fine, but for those of you lo # Using this library 1. Include the file - - Make sure you've got `buffer.php` included + - Make sure you've got: "require": "buffer/app": "dev-master" included in your composer.json file 2. Create a new Buffer app - You'll need to [register an app](http://bufferapp.com/developers/api) with buffer before you can begin - Initialize like this `$buffer = new BufferApp($client_id, $client_secret, $callback_url);` The `callback_url` needs to be the exact same as the app you registered @@ -30,10 +30,10 @@ To get the desired result you will need to use `media[picture]` _and_ `media[thu # Example -First thing's first: start a session and require `buffer.php`. We're going to be storing the `access_token` in the session for now. +First thing's first: start a session. +We're going to be storing the `access_token` in the session for now. session_start(); - require('buffer.php'); Set this thing up with your credentials and your callback URL. Remember: `callback_url` must match what you've got in Buffer exactly! @@ -44,6 +44,8 @@ Set this thing up with your credentials and your callback URL. Remember: `callba Set up the new buffer client. This is a super simple action that does a few things under the hood. If `$_GET['code']` is set on this page it assumes it came from Buffer and will attempt to trade that code for an `access_token`. If there is an `access_token` in the session it will be loaded in. + + use Buffer\App\BufferApp; $buffer = new BufferApp($client_id, $client_secret, $callback_url); Once we've got an `access_token` set the `$buffer->ok` property will read true. It is false by default. @@ -70,5 +72,7 @@ Right now this baby just stores the `access_token` in `$_SESSION['oauth']['buffe Realistically these methods should be replaced with some sort of abstraction -- pull requests are welcome! # License +Apache-2.0 +Do whatever you like with this. +Feel free (but not obligated) to [drop me a line](http://preilly.me) or the original author [drop kevin a line](http://kevin.fm) if it helps! -Do whatever you like with this. Feel free (but not obligated) to [drop me a line](http://kevin.fm) if it helps! From 6e714bc432de6f62fa1cb4ac6c9a6d991ee6f8a4 Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:19:56 -0700 Subject: [PATCH 6/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 193063e..bb7bf77 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Now that we've received access we are free to run queries against Buffer endpoin if (is_array($profiles)) { foreach ($profiles as $profile) { //this creates a status on each one - $buffer->go('/updates/create', array('text' => 'My first status update from bufferapp-php worked!', 'profile_ids[]' => $profile->id)); + $buffer->go('/updates/create', array('text' => 'My first status update from BufferApp worked!', 'profile_ids[]' => $profile->id)); } } } From 3706f53e689867aa25a77ebb0813b6a5a724e1bc Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:22:50 -0700 Subject: [PATCH 7/9] update example --- example.php | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/example.php b/example.php index 5b5950a..0af90a1 100644 --- a/example.php +++ b/example.php @@ -1,22 +1,27 @@ -ok) { - echo 'Connect to Buffer!'; - } else { - $profiles = $buffer->go('/profiles'); - - if (is_array($profiles)) { - foreach ($profiles as $profile) { - $buffer->go('/updates/create', array('text' => 'My first status update from bufferapp-php worked!', 'profile_ids[]' => $profile->id)); - } - } - } -?> \ No newline at end of file +ok) { + echo 'Connect to Buffer!'; + } else { + $profiles = $buffer->go('/profiles'); + + if (is_array($profiles)) { + foreach ($profiles as $profile) { + $buffer->go('/updates/create', array( + 'text' => 'My first status update from BufferApp worked!', + 'profile_ids[]' => $profile->id)); + } + } + } \ No newline at end of file From 4109e1e942c1449b1185cac292cd1e0aa89c5040 Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:26:21 -0700 Subject: [PATCH 8/9] add Apache 2 license --- LICENSE | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a220143 --- /dev/null +++ b/LICENSE @@ -0,0 +1,16 @@ +This software is licensed under the Apache 2 license, quoted below. + +Copyright 2014 Patrick Reilly +Copyright 2012 Kevin Khandjian + +Licensed under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. \ No newline at end of file From 199990471a0d12fea88aa3a44e62d96f6dc3d9dc Mon Sep 17 00:00:00 2001 From: Patrick Reilly Date: Fri, 23 May 2014 10:29:38 -0700 Subject: [PATCH 9/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb7bf77..c4869a0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -bufferapp +BufferApp ============= -Simple PHP library for the amazing buffer at http://bufferapp.com +Simple PHP composer package for the amazing buffer at http://bufferapp.com # Why?