AipBase.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. require_once 'AipHttpClient.php';
  18. require_once 'AipBCEUtil.php';
  19. require_once 'AipImageUtil.php';
  20. /**
  21. * Aip Base 基类
  22. */
  23. class AipBase {
  24. /**
  25. * 获取access token url
  26. * @var string
  27. */
  28. protected $accessTokenUrl = 'https://aip.baidubce.com/oauth/2.0/token';
  29. /**
  30. * appId
  31. * @var string
  32. */
  33. protected $appId = '';
  34. /**
  35. * apiKey
  36. * @var string
  37. */
  38. protected $apiKey = '';
  39. /**
  40. * secretKey
  41. * @var string
  42. */
  43. protected $secretKey = '';
  44. /**
  45. * 权限
  46. * @var array
  47. */
  48. protected $scope = 'brain_all_scope';
  49. /**
  50. * @param string $appId
  51. * @param string $apiKey
  52. * @param string $secretKey
  53. */
  54. public function __construct($appId, $apiKey, $secretKey){
  55. $this->appId = trim($appId);
  56. $this->apiKey = trim($apiKey);
  57. $this->secretKey = trim($secretKey);
  58. $this->isCloudUser = null;
  59. $this->client = new AipHttpClient();
  60. $this->version = '1_6_0';
  61. }
  62. /**
  63. * 连接超时
  64. * @param int $ms 毫秒
  65. */
  66. public function setConnectionTimeoutInMillis($ms){
  67. $this->client->setConnectionTimeoutInMillis($ms);
  68. }
  69. /**
  70. * 响应超时
  71. * @param int $ms 毫秒
  72. */
  73. public function setSocketTimeoutInMillis($ms){
  74. $this->client->setSocketTimeoutInMillis($ms);
  75. }
  76. /**
  77. * 处理请求参数
  78. * @param string $url
  79. * @param array $params
  80. * @param array $data
  81. * @param array $headers
  82. */
  83. protected function proccessRequest($url, &$params, &$data, $headers){
  84. $params['aipSdk'] = 'php';
  85. $params['aipSdkVersion'] = $this->version;
  86. }
  87. /**
  88. * Api 请求
  89. * @param string $url
  90. * @param mixed $data
  91. * @return mixed
  92. */
  93. protected function request($url, $data, $headers=array()){
  94. try{
  95. $result = $this->validate($url, $data);
  96. if($result !== true){
  97. return $result;
  98. }
  99. $params = array();
  100. $authObj = $this->auth();
  101. if($this->isCloudUser === false){
  102. $params['access_token'] = $authObj['access_token'];
  103. }
  104. // 特殊处理
  105. $this->proccessRequest($url, $params, $data, $headers);
  106. $headers = $this->getAuthHeaders('POST', $url, $params, $headers);
  107. $response = $this->client->post($url, $data, $params, $headers);
  108. $obj = $this->proccessResult($response['content']);
  109. if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
  110. $authObj = $this->auth(true);
  111. $params['access_token'] = $authObj['access_token'];
  112. $response = $this->client->post($url, $data, $params, $headers);
  113. $obj = $this->proccessResult($response['content']);
  114. }
  115. if(empty($obj) || !isset($obj['error_code'])){
  116. $this->writeAuthObj($authObj);
  117. }
  118. }catch(Exception $e){
  119. return array(
  120. 'error_code' => 'SDK108',
  121. 'error_msg' => 'connection or read data timeout',
  122. );
  123. }
  124. return $obj;
  125. }
  126. /**
  127. * Api 多个并发请求
  128. * @param string $url
  129. * @param mixed $data
  130. * @return mixed
  131. */
  132. protected function multi_request($url, $data){
  133. try{
  134. $params = array();
  135. $authObj = $this->auth();
  136. $headers = $this->getAuthHeaders('POST', $url);
  137. if($this->isCloudUser === false){
  138. $params['access_token'] = $authObj['access_token'];
  139. }
  140. $responses = $this->client->multi_post($url, $data, $params, $headers);
  141. $is_success = false;
  142. foreach($responses as $response){
  143. $obj = $this->proccessResult($response['content']);
  144. if(empty($obj) || !isset($obj['error_code'])){
  145. $is_success = true;
  146. }
  147. if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
  148. $authObj = $this->auth(true);
  149. $params['access_token'] = $authObj['access_token'];
  150. $responses = $this->client->post($url, $data, $params, $headers);
  151. break;
  152. }
  153. }
  154. if($is_success){
  155. $this->writeAuthObj($authObj);
  156. }
  157. $objs = array();
  158. foreach($responses as $response){
  159. $objs[] = $this->proccessResult($response['content']);
  160. }
  161. }catch(Exception $e){
  162. return array(
  163. 'error_code' => 'SDK108',
  164. 'error_msg' => 'connection or read data timeout',
  165. );
  166. }
  167. return $objs;
  168. }
  169. /**
  170. * 格式检查
  171. * @param string $url
  172. * @param array $data
  173. * @return mix
  174. */
  175. protected function validate($url, &$data){
  176. return true;
  177. }
  178. /**
  179. * 格式化结果
  180. * @param $content string
  181. * @return mixed
  182. */
  183. protected function proccessResult($content){
  184. return json_decode($content, true);
  185. }
  186. /**
  187. * 返回 access token 路径
  188. * @return string
  189. */
  190. private function getAuthFilePath(){
  191. return dirname(__FILE__) . DIRECTORY_SEPARATOR . md5($this->apiKey);
  192. }
  193. /**
  194. * 写入本地文件
  195. * @param array $obj
  196. * @return void
  197. */
  198. private function writeAuthObj($obj){
  199. if($obj === null || (isset($obj['is_read']) && $obj['is_read'] === true)){
  200. return;
  201. }
  202. $obj['time'] = time();
  203. $obj['is_cloud_user'] = $this->isCloudUser;
  204. @file_put_contents($this->getAuthFilePath(), json_encode($obj));
  205. }
  206. /**
  207. * 读取本地缓存
  208. * @return array
  209. */
  210. private function readAuthObj(){
  211. $content = @file_get_contents($this->getAuthFilePath());
  212. if($content !== false){
  213. $obj = json_decode($content, true);
  214. $this->isCloudUser = $obj['is_cloud_user'];
  215. $obj['is_read'] = true;
  216. if($this->isCloudUser || $obj['time'] + $obj['expires_in'] - 30 > time()){
  217. return $obj;
  218. }
  219. }
  220. return null;
  221. }
  222. /**
  223. * 认证
  224. * @param bool $refresh 是否刷新
  225. * @return array
  226. */
  227. private function auth($refresh=false){
  228. //非过期刷新
  229. if(!$refresh){
  230. $obj = $this->readAuthObj();
  231. if(!empty($obj)){
  232. return $obj;
  233. }
  234. }
  235. $response = $this->client->get($this->accessTokenUrl, array(
  236. 'grant_type' => 'client_credentials',
  237. 'client_id' => $this->apiKey,
  238. 'client_secret' => $this->secretKey,
  239. ));
  240. $obj = json_decode($response['content'], true);
  241. $this->isCloudUser = !$this->isPermission($obj);
  242. return $obj;
  243. }
  244. /**
  245. * 判断认证是否有权限
  246. * @param array $authObj
  247. * @return boolean
  248. */
  249. protected function isPermission($authObj)
  250. {
  251. if(empty($authObj) || !isset($authObj['scope'])){
  252. return false;
  253. }
  254. $scopes = explode(' ', $authObj['scope']);
  255. return in_array($this->scope, $scopes);
  256. }
  257. /**
  258. * @param string $method HTTP method
  259. * @param string $url
  260. * @param array $param 参数
  261. * @return array
  262. */
  263. private function getAuthHeaders($method, $url, $params=array(), $headers=array()){
  264. //不是云的老用户则不用在header中签名 认证
  265. if($this->isCloudUser === false){
  266. return $headers;
  267. }
  268. $obj = parse_url($url);
  269. if(!empty($obj['query'])){
  270. foreach(explode('&', $obj['query']) as $kv){
  271. if(!empty($kv)){
  272. list($k, $v) = explode('=', $kv, 2);
  273. $params[$k] = $v;
  274. }
  275. }
  276. }
  277. //UTC 时间戳
  278. $timestamp = gmdate('Y-m-d\TH:i:s\Z');
  279. $headers['Host'] = isset($obj['port']) ? sprintf('%s:%s', $obj['host'], $obj['port']) : $obj['host'];
  280. $headers['x-bce-date'] = $timestamp;
  281. //签名
  282. $headers['authorization'] = AipSampleSigner::sign(array(
  283. 'ak' => $this->apiKey,
  284. 'sk' => $this->secretKey,
  285. ), $method, $obj['path'], $headers, $params, array(
  286. 'timestamp' => $timestamp,
  287. 'headersToSign' => array_keys($headers),
  288. ));
  289. return $headers;
  290. }
  291. }