Skip to content

Instantly share code, notes, and snippets.

@idhowardgj94
Last active May 5, 2020 12:11
Show Gist options
  • Save idhowardgj94/6444027c73d35047666de6bf282d18fc to your computer and use it in GitHub Desktop.
Save idhowardgj94/6444027c73d35047666de6bf282d18fc to your computer and use it in GitHub Desktop.
oauth example in php
<?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
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment