PHP对接百度文档服务DOC

生成认证字符串需要用到的工具类

namespace App\Service;

class HttpUtil
{
    // 根据RFC 3986,除了:
    //   1.大小写英文字符
    //   2.阿拉伯数字
    //   3.点'.'、波浪线'~'、减号'-'以及下划线'_'
    // 以外都要编码
    public static $PERCENT_ENCODED_STRINGS;
    //填充编码数组
    public static function __init()
    {
        HttpUtil::$PERCENT_ENCODED_STRINGS = array();
        for ($i = 0; $i < 256; ++$i) {
            HttpUtil::$PERCENT_ENCODED_STRINGS[$i] = sprintf("%%%02X", $i);
        }
        //a-z不编码
        foreach (range('a', 'z') as $ch) {
            HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
        }
        //A-Z不编码
        foreach (range('A', 'Z') as $ch) {
            HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
        }
        //0-9不编码
        foreach (range('0', '9') as $ch) {
            HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
        }
        //以下4个字符不编码
        HttpUtil::$PERCENT_ENCODED_STRINGS[ord('-')] = '-';
        HttpUtil::$PERCENT_ENCODED_STRINGS[ord('.')] = '.';
        HttpUtil::$PERCENT_ENCODED_STRINGS[ord('_')] = '_';
        HttpUtil::$PERCENT_ENCODED_STRINGS[ord('~')] = '~';
    }
    //在uri编码中不能对'/'编码
    public static function urlEncodeExceptSlash($path)
    {
        return str_replace("%2F", "/", HttpUtil::urlEncode($path));
    }
    //使用编码数组编码
    public static function urlEncode($value)
    {
        $result = '';
        for ($i = 0; $i < strlen($value); ++$i) {
            $result .= HttpUtil::$PERCENT_ENCODED_STRINGS[ord($value[$i])];
        }
        return $result;
    }
    //生成标准化QueryString
    public static function getCanonicalQueryString(array $parameters)
    {
        //没有参数,直接返回空串
        if (count($parameters) == 0) {
            return '';
        }
        $parameterStrings = array();
        foreach ($parameters as $k => $v) {
            //跳过Authorization字段
            if (strcasecmp('Authorization', $k) == 0) {
                continue;
            }
            if (!isset($k)) {
                throw new \InvalidArgumentException(
                    "parameter key should not be null"
                );
            }
            if (isset($v)) {
                //对于有值的,编码后放在=号两边
                $parameterStrings[] = HttpUtil::urlEncode($k)
                    . '=' . HttpUtil::urlEncode((string) $v);
            } else {
                //对于没有值的,只将key编码后放在=号的左边,右边留空
                $parameterStrings[] = HttpUtil::urlEncode($k) . '=';
            }
        }
        //按照字典序排序
        sort($parameterStrings);
        //使用'&'符号连接它们
        return implode('&', $parameterStrings);
    }
    //生成标准化uri
    public static function getCanonicalURIPath($path)
    {
        //空路径设置为'/'
        if (empty($path)) {
            return '/';
        } else {
            //所有的uri必须以'/'开头
            if ($path[0] == '/') {
                return HttpUtil::urlEncodeExceptSlash($path);
            } else {
                return '/' . HttpUtil::urlEncodeExceptSlash($path);
            }
        }
    }
    //生成标准化http请求头串
    public static function getCanonicalHeaders($headers)
    {
        //如果没有headers,则返回空串
        if (count($headers) == 0) {
            return '';
        }
        $headerStrings = array();
        foreach ($headers as $k => $v) {
            //跳过key为null的
            if ($k === null) {
                continue;
            }
            //如果value为null,则赋值为空串
            if ($v === null) {
                $v = '';
            }
            //trim后再encode,之后使用':'号连接起来
            $headerStrings[] = HttpUtil::urlEncode(strtolower(trim($k))) . ':' . HttpUtil::urlEncode(trim($v));
        }
        //字典序排序
        sort($headerStrings);
        //用'\n'把它们连接起来
        return implode("\n", $headerStrings);
    }
}



对接百度文档服务接口, 这里写了注册文档和阅读文档两个例子

namespace App\Service;

use GuzzleHttp\Client;

class BaiduDoc
{
    protected $credentials = ['ak' => '', 'sk' => ''];
    protected $host = 'doc.bj.baidubce.com';
    protected $timestamp;
    protected $expirationInSeconds = 60;


    public function __construct()
    {
        HttpUtil::__init();
        date_default_timezone_get('UTC');
        $this->timestamp = new \DateTime();
    }

    /**
     * 注册文档
     * @return array|\Psr\Http\Message\StreamInterface
     */
    public function register()
    {
        // >> first: get authorization
        $method = 'POST';
        $uri = '/v2/document' ;
        $params = ['register' => ''];
        $authorization = $this->getAuthorization($method, $this->host, $uri, $params, $this->timestamp, $this->expirationInSeconds);

        // >> second: create header and body information for http request
        $url = "https://{$this->host}{$uri}?register";
        $timeStr = $this->timestamp->format("Y-m-d\TH:i:s\Z");
        $head = [
            "Content-Type" => "application/json",
            "Authorization" => $authorization,
            "x-bce-date" => $timeStr,
        ];
        $body = [
            'title' => '123',
            'format' => 'doc',
        ];
        $client = new Client();
        $response = $client->request($method, $url, [
            'body' => json_encode($body),
            'headers' => $head
        ]);
        $body = $response->getBody();
        return $body;

    }

     /**
     * 阅读文档
     * @return array|\Psr\Http\Message\StreamInterface
     */
    public function read()
    {
        // >> first: get authorization
        $method = 'GET';
        $documentId = 'doc-icukvvnfq6ixnat';
        $uri = '/v2/document/'. $documentId;
        $params = ['read' => ''];
        $this->expirationInSeconds = 3600;
        $authorization = $this->getAuthorization($method, $this->host, $uri, $params, $this->timestamp, $this->expirationInSeconds);

        // >> second: create header and body information for http request

        $url = "http://{$this->host}{$uri}?read";
        $timeStr = $this->timestamp->format("Y-m-d\TH:i:s\Z");
        $head = [
            "Content-Type" => "application/json",
            "Authorization" => $authorization,
            "x-bce-date" => $timeStr,
        ];
        $client = new Client();
        $response = $client->request($method, $url, [
            'headers' => $head
        ]);
        $body = $response->getBody();
        return $body;
    }


    // 获取认证字符串
    protected function getAuthorization($method, $host, $uri, $params, $timestamp, $expirationInSeconds)
    {
        $timeStr = $timestamp->format("Y-m-d\TH:i:s\Z");
        $authStringPrefix = "bce-auth-v1/{$this->credentials['ak']}/{$timeStr}/{$expirationInSeconds}";
        $signingKey = hash_hmac('SHA256', $authStringPrefix, $this->credentials['sk']);
        $canonicalHeader1 = "host;x-bce-date";
        $canonicalHeader2 = "host:{$host}\n" . "x-bce-date:" . urlencode($timeStr);
        $httpUtil = new HttpUtil();
        $canonicalString = $httpUtil->getCanonicalQueryString($params);
        $canonicalUri = $httpUtil->getCanonicalURIPath($uri);
        $method = strtoupper($method);
        $canonicalRequest = "{$method}\n{$canonicalUri}\n{$canonicalString}\n{$canonicalHeader2}";
        $signature = hash_hmac('SHA256', $canonicalRequest, $signingKey);
        $authorization = "bce-auth-v1/{$this->credentials['ak']}/{$timeStr}/{$expirationInSeconds}/{$canonicalHeader1}/{$signature}";
        return $authorization;
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容