AipBase.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. <?php
  2. /*
  3. * Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  6. * use this file except in compliance with the License. You may obtain a copy of
  7. * the License at
  8. *
  9. * Http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations under
  15. * the License.
  16. */
  17. namespace common\helpers\ocr\baidu\lib;
  18. /**
  19. * Aip Base 基类
  20. */
  21. class AipBase {
  22. /**
  23. * 获取access token url
  24. * @var string
  25. */
  26. protected $accessTokenUrl = 'https://aip.baidubce.com/oauth/2.0/token';
  27. /**
  28. * 反馈接口
  29. * @var string
  30. */
  31. protected $reportUrl = 'https://aip.baidubce.com/rpc/2.0/feedback/v1/report';
  32. /**
  33. * appId
  34. * @var string
  35. */
  36. protected $appId = '';
  37. /**
  38. * apiKey
  39. * @var string
  40. */
  41. protected $apiKey = '';
  42. /**
  43. * secretKey
  44. * @var string
  45. */
  46. protected $secretKey = '';
  47. /**
  48. * 权限
  49. * @var array
  50. */
  51. protected $scope = 'brain_all_scope';
  52. protected $isCloudUser;
  53. protected $client;
  54. protected $version;
  55. protected $proxies;
  56. protected $authFileDirPath;
  57. /**
  58. * @param string $appId
  59. * @param string $apiKey
  60. * @param string $secretKey
  61. */
  62. public function __construct($appId, $apiKey, $secretKey){
  63. AipHttpUtil::__init();
  64. AipSampleSigner::__init();
  65. $this->appId = trim($appId);
  66. $this->apiKey = trim($apiKey);
  67. $this->secretKey = trim($secretKey);
  68. $this->isCloudUser = null;
  69. $this->client = new AipHttpClient();
  70. $this->version = '2_2_3';
  71. $this->proxies = array();
  72. $this->authFileDirPath = \Yii::getAlias('@common/runtime/baiduOcr/');
  73. }
  74. /**
  75. * 查看版本
  76. * @return string
  77. *
  78. */
  79. public function getVersion(){
  80. return $this->version;
  81. }
  82. /**
  83. * 连接超时
  84. * @param int $ms 毫秒
  85. */
  86. public function setConnectionTimeoutInMillis($ms){
  87. $this->client->setConnectionTimeoutInMillis($ms);
  88. }
  89. /**
  90. * 响应超时
  91. * @param int $ms 毫秒
  92. */
  93. public function setSocketTimeoutInMillis($ms){
  94. $this->client->setSocketTimeoutInMillis($ms);
  95. }
  96. /**
  97. * 代理
  98. * @param $proxies
  99. */
  100. public function setProxies($proxies){
  101. $this->client->setConf($proxies);
  102. }
  103. /**
  104. * 处理请求参数
  105. * @param string $url
  106. * @param array $params
  107. * @param array $data
  108. * @param array $headers
  109. */
  110. protected function proccessRequest($url, &$params, &$data, $headers){
  111. $params['aipSdk'] = 'php';
  112. $params['aipSdkVersion'] = $this->version;
  113. }
  114. /**
  115. * Api 请求
  116. * @param $url
  117. * @param $data
  118. * @param array $headers
  119. * @return array|mix|mixed
  120. * @throws \Exception
  121. */
  122. protected function request($url, $data, $headers=array()){
  123. try{
  124. $result = $this->validate($url, $data);
  125. if($result !== true){
  126. return $result;
  127. }
  128. $params = array();
  129. $authObj = $this->auth();
  130. if($this->isCloudUser === false){
  131. $params['access_token'] = $authObj['access_token'];
  132. }
  133. // 特殊处理
  134. $this->proccessRequest($url, $params, $data, $headers);
  135. $headers = $this->getAuthHeaders('POST', $url, $params, $headers);
  136. $response = $this->client->post($url, $data, $params, $headers);
  137. $obj = $this->proccessResult($response['content']);
  138. if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
  139. $authObj = $this->auth(true);
  140. $params['access_token'] = $authObj['access_token'];
  141. $response = $this->client->post($url, $data, $params, $headers);
  142. $obj = $this->proccessResult($response['content']);
  143. }
  144. if(empty($obj) || !isset($obj['error_code'])){
  145. $this->writeAuthObj($authObj);
  146. }
  147. }catch(\Exception $e){
  148. return array(
  149. 'error_code' => 'SDK108',
  150. 'error_msg' => 'connection or read data timeout',
  151. );
  152. }
  153. return $obj;
  154. }
  155. /**
  156. * Api 多个并发请求
  157. * @param $url
  158. * @param $data
  159. * @return array
  160. * @throws \Exception
  161. */
  162. protected function multi_request($url, $data){
  163. try{
  164. $params = array();
  165. $authObj = $this->auth();
  166. $headers = $this->getAuthHeaders('POST', $url);
  167. if($this->isCloudUser === false){
  168. $params['access_token'] = $authObj['access_token'];
  169. }
  170. $responses = $this->client->multi_post($url, $data, $params, $headers);
  171. $is_success = false;
  172. foreach($responses as $response){
  173. $obj = $this->proccessResult($response['content']);
  174. if(empty($obj) || !isset($obj['error_code'])){
  175. $is_success = true;
  176. }
  177. if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
  178. $authObj = $this->auth(true);
  179. $params['access_token'] = $authObj['access_token'];
  180. $responses = $this->client->post($url, $data, $params, $headers);
  181. break;
  182. }
  183. }
  184. if($is_success){
  185. $this->writeAuthObj($authObj);
  186. }
  187. $objs = array();
  188. foreach($responses as $response){
  189. $objs[] = $this->proccessResult($response['content']);
  190. }
  191. }catch(\Exception $e){
  192. return array(
  193. 'error_code' => 'SDK108',
  194. 'error_msg' => 'connection or read data timeout',
  195. );
  196. }
  197. return $objs;
  198. }
  199. /**
  200. * 格式检查
  201. * @param $url
  202. * @param $data
  203. * @return bool
  204. */
  205. protected function validate($url, &$data){
  206. return true;
  207. }
  208. /**
  209. * 格式化结果
  210. * @param $content string
  211. * @return mixed
  212. */
  213. protected function proccessResult($content){
  214. return json_decode($content, true);
  215. }
  216. /**
  217. * 返回 access token 路径
  218. * @return string
  219. */
  220. private function getAuthFilePath(){
  221. return $this->authFileDirPath . DIRECTORY_SEPARATOR . md5($this->apiKey);
  222. }
  223. /**
  224. * 写入本地文件
  225. * @param array $obj
  226. * @return void
  227. */
  228. private function writeAuthObj($obj){
  229. if($obj === null || (isset($obj['is_read']) && $obj['is_read'] === true)){
  230. return;
  231. }
  232. $obj['time'] = time();
  233. $obj['is_cloud_user'] = $this->isCloudUser;
  234. @file_put_contents($this->getAuthFilePath(), json_encode($obj));
  235. }
  236. /**
  237. * 读取本地缓存
  238. * @return array
  239. */
  240. private function readAuthObj(){
  241. $content = @file_get_contents($this->getAuthFilePath());
  242. if($content !== false){
  243. $obj = json_decode($content, true);
  244. $this->isCloudUser = $obj['is_cloud_user'];
  245. $obj['is_read'] = true;
  246. if($this->isCloudUser || $obj['time'] + $obj['expires_in'] - 30 > time()){
  247. return $obj;
  248. }
  249. }
  250. return null;
  251. }
  252. /**
  253. * 认证
  254. * @param bool $refresh 是否刷新
  255. * @return array
  256. */
  257. private function auth($refresh=false){
  258. //非过期刷新
  259. if(!$refresh){
  260. $obj = $this->readAuthObj();
  261. if(!empty($obj)){
  262. return $obj;
  263. }
  264. }
  265. $response = $this->client->get($this->accessTokenUrl, array(
  266. 'grant_type' => 'client_credentials',
  267. 'client_id' => $this->apiKey,
  268. 'client_secret' => $this->secretKey,
  269. ));
  270. $obj = json_decode($response['content'], true);
  271. $this->isCloudUser = !$this->isPermission($obj);
  272. return $obj;
  273. }
  274. /**
  275. * 判断认证是否有权限
  276. * @param array $authObj
  277. * @return boolean
  278. */
  279. protected function isPermission($authObj)
  280. {
  281. if(empty($authObj) || !isset($authObj['scope'])){
  282. return false;
  283. }
  284. $scopes = explode(' ', $authObj['scope']);
  285. return in_array($this->scope, $scopes);
  286. }
  287. /**
  288. * @param string $method HTTP method
  289. * @param string $url
  290. * @param array $params 参数
  291. * @param array $headers
  292. * @return array
  293. */
  294. private function getAuthHeaders($method, $url, $params=array(), $headers=array()){
  295. //不是云的老用户则不用在header中签名 认证
  296. if($this->isCloudUser === false){
  297. return $headers;
  298. }
  299. $obj = parse_url($url);
  300. if(!empty($obj['query'])){
  301. foreach(explode('&', $obj['query']) as $kv){
  302. if(!empty($kv)){
  303. list($k, $v) = explode('=', $kv, 2);
  304. $params[$k] = $v;
  305. }
  306. }
  307. }
  308. //UTC 时间戳
  309. $timestamp = gmdate('Y-m-d\TH:i:s\Z');
  310. $headers['Host'] = isset($obj['port']) ? sprintf('%s:%s', $obj['host'], $obj['port']) : $obj['host'];
  311. $headers['x-bce-date'] = $timestamp;
  312. //签名
  313. $headers['authorization'] = AipSampleSigner::sign(array(
  314. 'ak' => $this->apiKey,
  315. 'sk' => $this->secretKey,
  316. ), $method, $obj['path'], $headers, $params, array(
  317. 'timestamp' => $timestamp,
  318. 'headersToSign' => array_keys($headers),
  319. ));
  320. return $headers;
  321. }
  322. /**
  323. * 反馈
  324. * @param $feedback
  325. * @return array|mix|mixed
  326. * @throws \Exception
  327. */
  328. public function report($feedback){
  329. $data = array();
  330. $data['feedback'] = $feedback;
  331. return $this->request($this->reportUrl, $data);
  332. }
  333. /**
  334. * 通用接口
  335. * @param $url
  336. * @param $data
  337. * @param array $headers
  338. * @return array|mix|mixed
  339. * @throws \Exception
  340. */
  341. public function post($url, $data, $headers=array()){
  342. return $this->request($url, $data, $headers);
  343. }
  344. }