Wolfgang Pfnür

Merge pull request #12 from vslinko/php53

Added PHP5.3 support
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2;
class Client
{
/**
* @var string
*/
private $_clientKey;
/**
* @var string
*/
private $_clientSecret;
/**
* @var string
*/
private $_callbackUrl;
/**
*
* @param string $clientKey
* @param string $clientSecret
* @param string $callbackUrl
*/
public function __construct($clientKey, $clientSecret, $callbackUrl) {
$this->_clientKey = $clientKey;
$this->_clientSecret = $clientSecret;
$this->_callbackUrl = $callbackUrl;
}
/**
* @return string
*/
public function getClientKey() {
return $this->_clientKey;
}
/**
* @return string
*/
public function getClientSecret() {
return $this->_clientSecret;
}
/**
* @return string
*/
public function getCallbackUrl() {
return $this->_callbackUrl;
}
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2;
interface DataStore
{
/**
* @param \OAuth2\Token $token
*/
function storeAccessToken(Token $token);
/**
* @return \OAuth2\Token
*/
function retrieveAccessToken();
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2\DataStore;
use OAuth2\DataStore;
use OAuth2\Token;
class Session implements DataStore
{
public function __construct() {
session_start();
}
/**
*
* @return \OAuth2\Token
*/
public function retrieveAccessToken() {
return isset($_SESSION['oauth2_token']) ? $_SESSION['oauth2_token'] : new Token();
}
/**
* @param \OAuth2\Token $token
*/
public function storeAccessToken(Token $token) {
$_SESSION['oauth2_token'] = $token;
}
public function __destruct() {
session_write_close();
}
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2;
class Exception extends \Exception {}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2;
class HttpClient
{
/**
* @var string
*/
private $_url;
/**
* @var string
*/
private $_method;
/**
* @var string
*/
private $_parameters;
/**
* @var array
*/
private $_requestHeader;
/**
* @var string
*/
private $_response;
/**
* @var array
*/
private $_headers;
/**
* @var array
*/
private $_info;
/**
* @var boolean
*/
private $_debug = false;
/**
* @param string $url
* @param string $method
* @param string $parameters
* @param array $header any additional header which should be set
*/
public function __construct($url, $method, $parameters = null, array $header = array()) {
$this->_url = $url;
$this->_method = $method;
$this->_parameters = $parameters;
$this->_requestHeader = $header;
}
/**
* parses a string with two delimiters to an array
*
* example:
*
* param1=value1&param2=value2
*
* will result with delimiters & and = to
*
* array(
* 'param1' => 'value1',
* 'param2' => 'value2',
* )
*
* @param string $string
* @param string $firstDelimiter
* @param string $secondDelimiter
* @return array
*/
public static function parseStringToArray($string, $firstDelimiter, $secondDelimiter) {
$resultArray = array();
$parts = explode($firstDelimiter, $string);
foreach ($parts as $part) {
$partsPart = explode($secondDelimiter, $part);
$resultArray[$partsPart[0]] = isset($partsPart[1]) ? trim($partsPart[1]) : '';
}
return $resultArray;
}
/**
* executes the curl request
*/
public function execute() {
$ch = curl_init();
if ($this->_method === 'POST') {
curl_setopt($ch, CURLOPT_URL, $this->_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_parameters);
} else {
curl_setopt($ch, CURLOPT_URL, $this->_url . ($this->_parameters ? '?' . $this->_parameters : ''));
}
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if (! empty($this->_requestHeader)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->_requestHeader);
}
$fullResponse = curl_exec($ch);
$this->_info = curl_getinfo($ch);
$this->_response = substr($fullResponse, $this->_info['header_size'], strlen($fullResponse));
if ($this->_response === false) {
$this->_response = '';
}
$headers = rtrim(substr($fullResponse, 0, $this->_info['header_size']));
$this->_headers = static::parseStringToArray($headers, PHP_EOL, ':');
if ($this->_debug) {
echo "<pre>";
print_r($this->_url);
echo PHP_EOL;
print_r($this->_headers);
echo PHP_EOL;
print_r($this->_response);
echo "</pre>";
}
curl_close($ch);
}
/**
* @return string
*/
public function getResponse() {
return $this->_response;
}
/**
* @return array
*/
public function getHeaders() {
return $this->_headers;
}
/**
* @param boolean $debug
*/
public function setDebug($debug) {
$this->_debug = $debug;
}
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2;
class Service
{
/**
* @var \OAuth2\Client
*/
private $_client;
/**
* @var \OAuth2\Service\Configuration
*/
private $_configuration;
/**
* @var \OAuth2\DataStore
*/
private $_dataStore;
/**
* @var string
*/
private $_scope;
/**
* @param \OAuth2\Client $client
* @param \OAuth2\Service\Configuration $configuration
* @param \OAuth2\DataStore $dataStore
* @param string $scope optional
*/
public function __construct(Client $client,
Service\Configuration $configuration,
DataStore $dataStore,
$scope = null) {
$this->_client = $client;
$this->_configuration = $configuration;
$this->_dataStore = $dataStore;
$this->_scope = $scope;
}
/**
* redirect to authorize endpoint of service
*/
public function authorize() {
$parameters = array(
'type' => 'web_server',
'client_id' => $this->_client->getClientKey(),
'redirect_uri' => $this->_client->getCallbackUrl(),
'response_type' => 'code',
);
if ($this->_scope) {
$parameters['scope'] = $this->_scope;
}
$url = $this->_configuration->getAuthorizeEndpoint();
$url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($parameters);
header('Location: ' . $url);
die();
}
/**
* get access token of from service, has to be called after successful authorization
*
* @param string $code optional, if no code given method tries to get it out of $_GET
*/
public function getAccessToken($code = null) {
if (! $code) {
if (! isset($_GET['code'])) {
throw new Exception('could not retrieve code out of callback request and no code given');
}
$code = $_GET['code'];
}
$parameters = array(
'grant_type' => 'authorization_code',
'type' => 'web_server',
'client_id' => $this->_client->getClientKey(),
'client_secret' => $this->_client->getClientSecret(),
'redirect_uri' => $this->_client->getCallbackUrl(),
'code' => $code,
);
if ($this->_scope) {
$parameters['scope'] = $this->_scope;
}
$http = new HttpClient($this->_configuration->getAccessTokenEndpoint(), 'POST', http_build_query($parameters));
//$http->setDebug(true);
$http->execute();
$this->_parseAccessTokenResponse($http);
}
/**
* refresh access token
*
* @param \OAuth2\Token $token
* @return \OAuth2\Token new token object
*/
public function refreshAccessToken(Token $token) {
if (! $token->getRefreshToken()) {
throw new Exception('could not refresh access token, no refresh token available');
}
$parameters = array(
'grant_type' => 'refresh_token',
'type' => 'web_server',
'client_id' => $this->_client->getClientKey(),
'client_secret' => $this->_client->getClientSecret(),
'refresh_token' => $token->getRefreshToken(),
);
$http = new HttpClient($this->_configuration->getAccessTokenEndpoint(), 'POST', http_build_query($parameters));
$http->execute();
return $this->_parseAccessTokenResponse($http, $token->getRefreshToken());
}
/**
* parse the response of an access token request and store it in dataStore
*
* @param \OAuth2\HttpClient $http
* @param string $oldRefreshToken
* @return \OAuth2\Token
*/
private function _parseAccessTokenResponse(HttpClient $http, $oldRefreshToken = null) {
$headers = $http->getHeaders();
$type = 'text';
if (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'application/json') !== false) {
$type = 'json';
}
switch ($type) {
case 'json':
$response = json_decode($http->getResponse(), true);
break;
case 'text':
default:
$response = HttpClient::parseStringToArray($http->getResponse(), '&', '=');
break;
}
if (isset($response['error'])) {
throw new Exception('got error while requesting access token: ' . $response['error']);
}
if (! isset($response['access_token'])) {
throw new Exception('no access_token found');
}
$token = new Token($response['access_token'],
isset($response['refresh_token']) ? $response['refresh_token'] : $oldRefreshToken,
isset($response['expires_in']) ? $response['expires_in'] : null);
unset($response['access_token']);
unset($response['refresh_token']);
unset($response['expires_in']);
// add additional parameters which may be returned depending on service and scope
foreach ($response as $key => $value) {
$token->{'set' . $key}($value);
}
$this->_dataStore->storeAccessToken($token);
return $token;
}
/**
* call an api endpoint. automatically adds needed authorization headers with access token or parameters
*
* @param string $endpoint
* @param string $method default 'GET'
* @param array $uriParameters optional
* @param mixed $postBody optional, can be string or array
* @param array $additionalHeaders
* @return string
*/
public function callApiEndpoint($endpoint, $method = 'GET', array $uriParameters = array(), $postBody = null, array $additionalHeaders = array()) {
$token = $this->_dataStore->retrieveAccessToken();
//check if token is invalid
if ($token->getLifeTime() && $token->getLifeTime() < time()) {
$token = $this->refreshAccessToken($token);
}
$parameters = null;
$authorizationMethod = $this->_configuration->getAuthorizationMethod();
switch ($authorizationMethod) {
case Service\Configuration::AUTHORIZATION_METHOD_HEADER:
$additionalHeaders = array_merge(array('Authorization: OAuth ' . $token->getAccessToken()), $additionalHeaders);
break;
case Service\Configuration::AUTHORIZATION_METHOD_ALTERNATIVE:
if ($method !== 'GET') {
if (is_array($postBody)) {
$postBody['oauth_token'] = $token->getAccessToken();
} else {
$postBody .= '&oauth_token=' . urlencode($token->getAccessToken());
}
} else {
$uriParameters['oauth_token'] = $token->getAccessToken();
}
break;
default:
throw new Exception("Invalid authorization method specified");
break;
}
if ($method !== 'GET') {
if (is_array($postBody)) {
$parameters = http_build_query($postBody);
} else {
$parameters = $postBody;
}
}
if (! empty($uriParameters)) {
$endpoint .= (strpos($endpoint, '?') !== false ? '&' : '?') . http_build_query($uriParameters);
}
$http = new HttpClient($endpoint, $method, $parameters, $additionalHeaders);
$http->execute();
return $http->getResponse();
}
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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.
*
* @author Bastian Hofmann <bhfomann@vz.net>
* @author Vyacheslav Slinko <vyacheslav.slinko@gmail.com>
* @copyright 2010 VZnet Netzwerke Ltd.
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace OAuth2\Service;
class Configuration
{
const AUTHORIZATION_METHOD_HEADER = 1;
const AUTHORIZATION_METHOD_ALTERNATIVE = 2;
/**
* @var string
*/
private $_authorizeEndpoint;
/**
* @var string
*/
private $_accessTokenEndpoint;
/**
* @var string
*/
private $_authorizationMethod = self::AUTHORIZATION_METHOD_HEADER;
/**
* @param string $authorizeEndpoint
* @param string $accessTokenEndpoint
*/
public function __construct($authorizeEndpoint, $accessTokenEndpoint) {
$this->_authorizeEndpoint = $authorizeEndpoint;
$this->_accessTokenEndpoint = $accessTokenEndpoint;
}
/**
* @return string
*/
public function getAuthorizeEndpoint() {
return $this->_authorizeEndpoint;
}
/**
* @return string
*/
public function getAccessTokenEndpoint() {
return $this->_accessTokenEndpoint;
}
/**
* @return string
*/
public function setAuthorizationMethod($authorizationMethod) {
$this->_authorizationMethod = $authorizationMethod;
}
/**
* @return string
*/
public function getAuthorizationMethod() {
return $this->_authorizationMethod;
}
}
... ...
<?php
/**
* Copyright (c) 2010 VZnet Netzwerke Ltd.
*
* 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