Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

はてなの認証を行い下記のレスポンスが返ってくること

解決したいこと

PHP8.3にて、はてなAPIの認証(/oauth/initiate)を行い下記のレスポンスが返ってくること.
はてなAPIの認証で躓いています.
いろいろ試してみましたが、oauth_signatureの作成がうまく行っていないのか
curlの書き方が駄目なのかが分かっていない状態です.

ご回答どうぞよろしくお願い致します.

参考にしているサイト
https://developer.hatena.ne.jp/ja/documents/auth/apis/oauth/consumer
https://www.softel.co.jp/blogs/tech/archives/3283

HTTP/1.1 200 OK
Content-Type: application/x-www-form-urlencoded

oauth_token=QB%2FfqbXTpFB1GQ%3D%3D&
oauth_token_secret=M1xSNaj0mw0J%2Bksk0k7WpZiGNP4%3D&
oauth_callback_confirmed=true

発生している問題・エラー

array(1) { ["oauth_problem"]=> string(17) "signature_invalid" }

該当するソースコード

<?php
ini_set('display_errors', 1);
require '../config/config.php';

class hatena
{
    public $oauthCallback = OAUTH_CALLBACK;
    public $oauthConsumerKey = OAUTH_CONSUMER_KEY;
    public $oauthConsumeSecret = OAUTH_CONSUMER_SECRET;
    public $oauthNonce = '';
    public $oauthSignature = null;
    public $oauthSignatureMethod = "HMAC-SHA1";
    public $oauthTimestamp = '';
    public $oauthVersion = "1.0";
    public $contentType = 'application/x-www-form-urlencoded';
    public $oauthParameters = [];

    public function oauthInitiate()
    {

        $url = 'https://www.hatena.com/oauth/initiate';
        $this->oauthNonce = uniqid();
        $this->oauthTimestamp = time();

        $this->oauthParameters = [
            'oauth_consumer_key' => rawurlencode($this->oauthConsumerKey),
            'oauth_nonce' => rawurlencode($this->oauthNonce),
            'oauth_signature_method' => rawurlencode($this->oauthSignatureMethod),
            'oauth_timestamp' => rawurlencode($this->oauthTimestamp),
        ];


        $params = [
            'scope' => 'read_public,write_public,read_private,write_private'
        ];

        $this->getSignature($url, 'POST', $params);
        $this->oauthParameters['oauth_signature'] = rawurlencode($this->oauthSignature);

        $ch = curl_init($url);

        $headers = [ //'.$this->oauthParameters['realm'].'
            'Authorization: OAuth realm="",oauth_callback="' .  rawurlencode($this->oauthCallback) . '",oauth_consumer_key="' . $this->oauthParameters['oauth_consumer_key'] . '",oauth_nonce="' . $this->oauthParameters['oauth_nonce'] . '",oauth_signature="' . $this->oauthParameters['oauth_signature'] . '",oauth_signature_method="' . $this->oauthParameters['oauth_signature_method'] . '",oauth_timestamp="' . $this->oauthParameters['oauth_timestamp'] . '",oauth_version="1.0"',
            'Content-Type: ' . $this->contentType,
            'Content-Length: ' . (string)strlen($this->contentType)
        ];


        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $response = curl_exec($ch);
        if (curl_error($ch)) {
            echo 'Curl error: ' . curl_error($ch);
        }
        parse_str($response, $response_params);
        var_dump($response_params);
        curl_close($ch);

        return $this;
    }

    public function getSignature($url, $method = 'POST', $params = [], $oauthTokenSecret = '')
    {

        foreach($params as $key=>$value){
            $params[$key] = rawurlencode($value);
        }
        $hasBase = http_build_query($this->oauthsort(array_merge($this->oauthParameters, $params)), '', '&', PHP_QUERY_RFC3986);

        $signingKey = implode('&', [rawurlencode($this->oauthConsumeSecret), rawurlencode($oauthTokenSecret)]);
        $baseString = implode('&', [
            rawurlencode($method),
            rawurlencode($url),
            $hasBase,
        ]);

        $signature = hash_hmac('sha1', $baseString, $signingKey, true);
        $signature = base64_encode($signature);
        $this->oauthSignature = $signature;

        return $this;
    }
    //OAuth式 パラメータのソート関数
    public function oauthsort($a)
    {
        $b = array_map(null, array_keys($a), $a);
        usort($b, ['hatena', 'oauthcmp']);
        $c = array();
        foreach ($b as $v) {
            $c[$v[0]] = $v[1];
        }

        return $c;
    }
    public function oauthcmp($a, $b)
    {
        return strcmp($a[0], $b[0])
            ? strcmp(rawurlencode($a[0]), rawurlencode($b[0]))
            : strcmp(rawurlencode($a[1]), rawurlencode($b[1]));
    }
}

(new hatena)->oauthInitiate();

0

1Answer

自己解決しました.参考までに.

<?php
ini_set('display_errors', 1);
require '../config/config.php';

class hatena
{
    public $oauthCallback = OAUTH_CALLBACK;
    public $oauthConsumerKey = OAUTH_CONSUMER_KEY;
    public $oauthConsumeSecret = OAUTH_CONSUMER_SECRET;
    public $oauthToken = '';
    public $oauthTokenSecret = '';
    public $oauthSignature = '';
    public $oauthParameters = [];

    public function oauthInitiate($method = "POST", $url = 'https://www.hatena.com/oauth/initiate', $contentType = 'application/x-www-form-urlencoded')
    {
        $this->oauthParameters = [
            'oauth_callback' => $this->oauthCallback,
            'oauth_consumer_key' => $this->oauthConsumerKey,
            'oauth_nonce' => uniqid(),
            'oauth_signature_method' => 'HMAC-SHA1',
            'oauth_timestamp' => time(),
            'oauth_version' => '1.0',
        ];

        $params = [
            'scope' => 'read_public,write_public'
        ];

        $this->getSignature($url, $method, $params);

        $authorization = $this->getPostParam($this->oauthParameters, true, ',');

        $headers = [ 
            'Authorization: OAuth ' . $authorization,
            'Host' => 'www.hatena.com',
            'User-Agent: '=>$_SERVER['HTTP_USER_AGENT'],
            'Content-Type: ' . $contentType,
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params, '', '&', PHP_QUERY_RFC3986));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

        $response = curl_exec($ch);
        if (curl_error($ch)) {
            echo 'Curl error: ' . curl_error($ch);
        }
        //oauth_token=?????oauth_token_secret=?????&oauth_callback_confirmed=true
        parse_str($response, $responseParams);

        header('Location:https://www.hatena.ne.jp/oauth/authorize?oauth_token='.rawurlencode($responseParams['oauth_token']));
        return $this;
    }

    public function getSignature($url, $method = 'POST', $params = [], $oauthTokenSecret = '')
    {       
        $base_string = implode('&', array(
            rawurlencode($method),
            rawurlencode($url),
            rawurlencode(http_build_query($this->oauthsort(array_merge($this->oauthParameters, $params)), '', '&', PHP_QUERY_RFC3986))
        ));
        $key = implode('&', array(rawurlencode($this->oauthConsumeSecret), rawurlencode($oauthTokenSecret)));
        $this->oauthParameters['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_string, $key, true));
        ksort($this->oauthParameters);
        return $this;
    }
    //OAuth式 パラメータのソート関数
    public function oauthsort($a)
    {
        $b = array_map(null, array_keys($a), $a);
        usort($b, ['hatena', 'oauthcmp']);
        $c = array();
        foreach ($b as $v) {
            $c[$v[0]] = $v[1];
        }
        return $c;
    }
    public function oauthcmp($a, $b)
    {
        return strcmp($a[0], $b[0])
            ? strcmp(rawurlencode($a[0]), rawurlencode($b[0]))
            : strcmp(rawurlencode($a[1]), rawurlencode($b[1]));
    }

    public function getPostParam($value, $rawurlencodeSwitch = false, $separator = '&')
    {
        $str = [];
        foreach ($value as $key => $val) {
            $val = $rawurlencodeSwitch ? rawurlencode($val) : $val;
            $str[] = $key . '=' . $val . '';
        }
        return implode($separator, $str);
    }
}


(new hatena)->oauthInitiate();

0Like

Your answer might help someone💌