<?php
namespace App\Services;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Uri;
abstract class OauthRequestBase
{
protected $client;
protected $url;
protected $oauth_signature_method;
protected $oauth_nonce;
protected $oauth_timestamp;
protected $oauth_consumer_key;
protected $consumer_secret;
protected $oauth_version;
public function setParams($params)
{
$this->params = $params;
}
public function getParams()
{
return $this->params;
}
public function setOauthSignatureMethod($oauthSignatureMethod)
{
$this->oauthSignatureMethod = $oauthSignatureMethod;
}
public function getOauthSignatureMethod()
{
return $this->oauthSignatureMethod;
}
public function generateOauthNonce($length = 10)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
$this->oauth_nonce = $randomString;
return $randomString;
}
public function setOauthNonce($oauth_nonce)
{
$this->oauth_nonce = $oauth_nonce;
}
public function getOauthNonce()
{
return $this->oauth_nonce;
}
public function setOauthTimestamp($oauth_timestamp)
{
$this->oauth_timestamp = $oauth_timestamp;
}
public function getOauthTimestamp()
{
return $this->oauth_timestamp;
}
public function generateTimestamp()
{
$this->oauth_timestamp = time();
return $this->oauth_timestamp;
}
public function normalizeOauthParams($params)
{
// consumer_secret 不會再content_base中
$paramsName = array_filter(array_keys(get_class_vars(get_class($this))), function ($value) {
return $value !== 'consumer_secret' && $value !== 'url' && $value !== 'client';
});
$result = array_merge(array_keys($params), $paramsName);
sort($result);
$ret = [];
foreach ($result as $key) {
// XXX Find a better way
$ret[$key] = isset($this->$key) ? $this->$key : (isset($params[$key]) ? $params[$key] : null);
}
return $ret;
}
public function generateSignature($params)
{
$url = Psr7\uri_for($this->url);
$baseString = rawurlencode('POST').'&';
$schemeHostPath = Uri::fromParts(array(
'scheme' => $url->getScheme(),
'host' => $url->getHost(),
'path' => $url->getPath(),
));
$baseString .= rawurlencode($schemeHostPath).'&';
$data = array();
parse_str($url->getQuery(), $query);
$data = array_merge($query, $params);
// normalize data key/values
// credential必須要用 urlencode 的標準。
array_walk_recursive($data, function (&$key, &$value) {
$key = rawurlencode(rawurldecode($key));
$value = rawurlencode(rawurldecode($value));
});
$baseString .= $this->queryStringFromData($data);
return base64_encode($this->hash($baseString));
}
private function hash($string)
{
return hash_hmac('sha1', $string, $this->secret(), true);
}
public function secret()
{
return $this->consumer_secret.'&';
}
private function queryStringFromData($data, $queryParams = false, $prevKey = '')
{
if ($initial = (false === $queryParams)) {
$queryParams = array();
}
foreach ($data as $key => $value) {
if ($prevKey) {
$key = $prevKey.'['.$key.']'; // Handle multi-dimensional array
}
if (is_array($value)) {
$queryParams = $this->queryStringFromData($value, $queryParams, $key);
} else {
$queryParams[] = rawurlencode($key.'='.$value); // join with equals sign
}
}
if ($initial) {
return implode('%26', $queryParams); // join with ampersand
}
return $queryParams;
}
abstract public function request($arams);
}
使用方式:
<?php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Uri;
class OauthRequest extends OauthRequestBase
{
protected $client;
protected $url = "{url}";
/** @overide */
protected $oauth_signature_method='HMAC-SHA1';
/** @overide */
protected $oauth_nonce;
/** @overide */
protected $oauth_timestamp;
/** @overide */
protected $oauth_consumer_key='{key}';
/** @overide */
protected $oauth_version='1.0';
protected $consumer_secret='{secret}';
public function __construct()
{
$this->client = new Client(['base_uri' => $this->url]);
}
public function request($params)
{
$this->generateOauthNonce();
$this->generateTimestamp();
$params = $this->normalizeOauthParams($params);
$sig = $this->generateSignature($params);
$params['oauth_signature'] = $sig;
// XXX POST method should etract;
$response = $this->client->request('POST', '', ['form_params' => $params]);
return $response;
}
}
$oauthRequest = OauthRequest();
$oauthRequest->request([
// ...... params
]);