AopClient.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. <?php
  2. namespace app\phpPay;
  3. require_once 'AopEncrypt.php';
  4. class AopClient
  5. {
  6. //返回数据格式
  7. public $format = "json";
  8. //api版本
  9. public $apiVersion = "1.0";
  10. // 表单提交字符集编码
  11. public $postCharset = "UTF-8";
  12. public $debugInfo = false;
  13. private $fileCharset = "UTF-8";
  14. private $RESPONSE_SUFFIX = "_response";
  15. private $ERROR_RESPONSE = "error_response";
  16. private $SIGN_NODE_NAME = "sign";
  17. //加密XML节点名称
  18. private $ENCRYPT_XML_NODE_NAME = "response_encrypted";
  19. private $needEncrypt = false;
  20. //签名类型
  21. public $signType = "RSA";
  22. //加密密钥和类型
  23. public $encryptKey;
  24. public $encryptType = "AES";
  25. public function generateSign($params, $privateKey, $signType = "RSA")
  26. {
  27. return $this->sign($this->getSignContent($params), $privateKey, $signType);
  28. }
  29. public function rsaSign($params, $privateKey, $signType = "RSA")
  30. {
  31. return $this->sign($this->getSignContent($params), $privateKey, $signType);
  32. }
  33. function unicodeDecode($name)
  34. {
  35. $json = '{"str":"' . $name . '"}';
  36. $arr = json_decode($json, true);
  37. if (empty($arr)) return '';
  38. return $arr['str'];
  39. }
  40. public function getSignContent($params)
  41. {
  42. ksort($params);
  43. $stringToBeSigned = "";
  44. foreach ($params as $k => $v) {
  45. $isarray = is_array($v);
  46. if ($isarray) {
  47. $stringToBeSigned .= "$k" . "=" . json_encode($v, 320) . "&";
  48. } else {
  49. $stringToBeSigned .= "$k" . "=" . "$v" . "&";
  50. }
  51. }
  52. unset ($k, $v);
  53. $stringToBeSigned = substr($stringToBeSigned, 0, strlen($stringToBeSigned) - 1);
  54. return $stringToBeSigned;
  55. }
  56. protected function sign($data, $rsaPrivateKey, $signType = "RSA")
  57. {
  58. $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
  59. wordwrap($rsaPrivateKey, 64, "\n", true) .
  60. "\n-----END RSA PRIVATE KEY-----";
  61. ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
  62. if ("RSA2" == $signType) {
  63. openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
  64. } else {
  65. openssl_sign($data, $sign, $res);
  66. }
  67. $sign = base64_encode($sign);
  68. return $sign;
  69. }
  70. //废弃
  71. protected function signold($data, $signType = "RSA")
  72. {
  73. if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  74. $priKey = $this->rsaPrivateKey;
  75. $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
  76. wordwrap($priKey, 64, "\n", true) .
  77. "\n-----END RSA PRIVATE KEY-----";
  78. } else {
  79. $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
  80. $res = openssl_get_privatekey($priKey);
  81. }
  82. ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
  83. if ("RSA2" == $signType) {
  84. openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
  85. } else {
  86. openssl_sign($data, $sign, $res);
  87. }
  88. if (!$this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  89. openssl_free_key($res);
  90. }
  91. $sign = base64_encode($sign);
  92. return $sign;
  93. }
  94. public function curl($url, $postBodyString = null)
  95. {
  96. $ch = curl_init();
  97. curl_setopt($ch, CURLOPT_URL, $url);
  98. curl_setopt($ch, CURLOPT_FAILONERROR, false);
  99. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  100. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  101. $encodeArray = Array();
  102. $postMultipart = false;
  103. //echo $postBodyString;
  104. unset ($k, $v);
  105. curl_setopt($ch, CURLOPT_POST, true);
  106. curl_setopt($ch, CURLOPT_POSTFIELDS, $postBodyString);
  107. $this->writeLog("postBodyString" . $postBodyString);
  108. $headers = array('content-type:application/json;charset=' . $this->postCharset);
  109. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  110. $reponse = curl_exec($ch);
  111. //echo "reponse".$reponse;
  112. if (curl_errno($ch)) {
  113. throw new Exception(curl_error($ch), 0);
  114. } else {
  115. $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  116. if (200 !== $httpStatusCode) {
  117. throw new Exception($reponse, $httpStatusCode);
  118. }
  119. }
  120. curl_close($ch);
  121. return $reponse;
  122. }
  123. protected function getMillisecond()
  124. {
  125. list($s1, $s2) = explode(' ', microtime());
  126. return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
  127. }
  128. //请确保项目文件有可写权限,不然打印不了日志。
  129. function writeLog($text)
  130. {
  131. // $text=iconv("GBK", "UTF-8//IGNORE", $text);
  132. //$text = characet ( $text );
  133. file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . "../log.txt", date("Y-m-d H:i:s") . " " . $text . "\r\n", FILE_APPEND);
  134. }
  135. /**
  136. * 转换字符集编码
  137. * @param $data
  138. * @param $targetCharset
  139. * @return string
  140. */
  141. function characet($data, $targetCharset)
  142. {
  143. if (!empty($data)) {
  144. $fileType = $this->fileCharset;
  145. if (strcasecmp($fileType, $targetCharset) != 0) {
  146. $data = mb_convert_encoding($data, $targetCharset, $fileType);
  147. // $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
  148. }
  149. }
  150. return $data;
  151. }
  152. /**
  153. * 校验$value是否非空
  154. * if not set ,return true;
  155. * if is null , return true;
  156. **/
  157. protected function checkEmpty($value)
  158. {
  159. if (!isset($value))
  160. return true;
  161. if ($value === null)
  162. return true;
  163. if (trim($value) === "")
  164. return true;
  165. return false;
  166. }
  167. /** rsaCheckV1 & rsaCheckV2
  168. * 验证签名
  169. * 在使用本方法前,必须初始化AopClient且传入公钥参数。
  170. * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
  171. **/
  172. public function rsaCheckV1($params, $rsaPublicKeyFilePath, $signType = 'RSA')
  173. {
  174. $sign = $params['sign'];
  175. $params['sign_type'] = null;
  176. $params['sign'] = null;
  177. return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
  178. }
  179. public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType = 'RSA')
  180. {
  181. $sign = $params['sign'];
  182. $params['sign'] = null;
  183. return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
  184. }
  185. function verify($paramStr, $sign,$rsaPublicKey)
  186. {
  187. // $pubKey = $this->$rsaPublicKey;
  188. //将字符串格式公私钥转为pem格式公私钥
  189. $pubKeyPem = $this->format_secret_key($rsaPublicKey, 'pub');
  190. //转换为openssl密钥,必须是没有经过pkcs8转换的公钥
  191. $res = openssl_get_publickey($pubKeyPem);
  192. //url解码签名
  193. //$signUrl = urldecode($sign);
  194. //base64解码签名
  195. $signBase64 = base64_decode($sign);
  196. //调用openssl内置方法验签,返回bool值
  197. $result = (bool)openssl_verify($paramStr, $signBase64, $res);
  198. //释放资源
  199. openssl_free_key($res);
  200. //返回资源是否成功
  201. return $result;
  202. }
  203. function format_secret_key($secret_key, $type)
  204. {
  205. // 64个英文字符后接换行符"\n",最后再接换行符"\n"
  206. $key = (wordwrap($secret_key, 64, "\n", true)) . "\n";
  207. // 添加pem格式头和尾
  208. if ($type == 'pub') {
  209. $pem_key = "-----BEGIN PUBLIC KEY-----\n" . $key . "-----END PUBLIC KEY-----\n";
  210. } else if ($type == 'pri') {
  211. $pem_key = "-----BEGIN RSA PRIVATE KEY-----\n" . $key . "-----END RSA PRIVATE KEY-----\n";
  212. } else {
  213. echo('公私钥类型非法');
  214. exit();
  215. }
  216. return $pem_key;
  217. }
  218. public function checkSignAndDecrypt($params, $rsaPublicKeyPem, $rsaPrivateKeyPem, $isCheckSign, $isDecrypt)
  219. {
  220. $charset = $params['charset'];
  221. $bizContent = $params['biz_content'];
  222. if ($isCheckSign) {
  223. if (!$this->rsaCheckV2($params, $rsaPublicKeyPem)) {
  224. echo "<br/>checkSign failure<br/>";
  225. exit;
  226. }
  227. }
  228. if ($isDecrypt) {
  229. return $this->rsaDecrypt($bizContent, $rsaPrivateKeyPem, $charset);
  230. }
  231. return $bizContent;
  232. }
  233. public function encryptAndSign($bizContent, $rsaPublicKeyPem, $rsaPrivateKeyPem, $charset, $isEncrypt, $isSign)
  234. {
  235. // 加密,并签名
  236. if ($isEncrypt && $isSign) {
  237. $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
  238. $sign = $this->sign($bizContent);
  239. $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type><sign>$sign</sign><sign_type>RSA</sign_type></alipay>";
  240. return $response;
  241. }
  242. // 加密,不签名
  243. if ($isEncrypt && (!$isSign)) {
  244. $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
  245. $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type></alipay>";
  246. return $response;
  247. }
  248. // 不加密,但签名
  249. if ((!$isEncrypt) && $isSign) {
  250. $sign = $this->sign($bizContent);
  251. $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$bizContent</response><sign>$sign</sign><sign_type>RSA</sign_type></alipay>";
  252. return $response;
  253. }
  254. // 不加密,不签名
  255. $response = "<?xml version=\"1.0\" encoding=\"$charset\"?>$bizContent";
  256. return $response;
  257. }
  258. public function rsaEncrypt($data, $rsaPublicKeyPem, $charset)
  259. {
  260. //读取公钥文件
  261. $pubKey = file_get_contents($rsaPublicKeyPem);
  262. //转换为openssl格式密钥
  263. $res = openssl_get_publickey($pubKey);
  264. $blocks = $this->splitCN($data, 0, 30, $charset);
  265. $chrtext  = null;
  266. $encodes  = array();
  267. foreach ($blocks as $n => $block) {
  268. if (!openssl_public_encrypt($block, $chrtext , $res)) {
  269. echo "<br/>" . openssl_error_string() . "<br/>";
  270. }
  271. $encodes[] = $chrtext ;
  272. }
  273. $chrtext = implode(",", $encodes);
  274. return $chrtext;
  275. }
  276. public function rsaDecrypt($data, $rsaPrivateKeyPem, $charset)
  277. {
  278. //读取私钥文件
  279. $priKey = file_get_contents($rsaPrivateKeyPem);
  280. //转换为openssl格式密钥
  281. $res = openssl_get_privatekey($priKey);
  282. $decodes = explode(',', $data);
  283. $strnull = "";
  284. $dcyCont = "";
  285. foreach ($decodes as $n => $decode) {
  286. if (!openssl_private_decrypt($decode, $dcyCont, $res)) {
  287. echo "<br/>" . openssl_error_string() . "<br/>";
  288. }
  289. $strnull .= $dcyCont;
  290. }
  291. return $strnull;
  292. }
  293. function splitCN($cont, $n = 0, $subnum, $charset)
  294. {
  295. //$len = strlen($cont) / 3;
  296. $arrr = array();
  297. for ($i = $n; $i < strlen($cont); $i += $subnum) {
  298. $res = $this->subCNchar($cont, $i, $subnum, $charset);
  299. if (!empty ($res)) {
  300. $arrr[] = $res;
  301. }
  302. }
  303. return $arrr;
  304. }
  305. function subCNchar($str, $start = 0, $length, $charset = "gbk")
  306. {
  307. if (strlen($str) <= $length) {
  308. return $str;
  309. }
  310. $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
  311. $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
  312. $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
  313. $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
  314. preg_match_all($re[$charset], $str, $match);
  315. $slice = join("", array_slice($match[0], $start, $length));
  316. return $slice;
  317. }
  318. function parserResponseSubCode($request, $responseContent, $respObject, $format)
  319. {
  320. if ("json" == $format) {
  321. $apiName = $request->getApiMethodName();
  322. $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
  323. $errorNodeName = $this->ERROR_RESPONSE;
  324. $rootIndex = strpos($responseContent, $rootNodeName);
  325. $errorIndex = strpos($responseContent, $errorNodeName);
  326. if ($rootIndex > 0) {
  327. // 内部节点对象
  328. $rInnerObject = $respObject->$rootNodeName;
  329. } elseif ($errorIndex > 0) {
  330. $rInnerObject = $respObject->$errorNodeName;
  331. } else {
  332. return null;
  333. }
  334. // 存在属性则返回对应值
  335. if (isset($rInnerObject->sub_code)) {
  336. return $rInnerObject->sub_code;
  337. } else {
  338. return null;
  339. }
  340. } elseif ("xml" == $format) {
  341. // xml格式sub_code在同一层级
  342. return $respObject->sub_code;
  343. }
  344. }
  345. function parserJSONSignData($request, $responseContent, $responseJSON)
  346. {
  347. $signData = new SignData();
  348. $signData->sign = $this->parserJSONSign($responseJSON);
  349. $signData->signSourceData = $this->parserJSONSignSource($request, $responseContent);
  350. return $signData;
  351. }
  352. function parserJSONSignSource($request, $responseContent)
  353. {
  354. $apiName = $request->getApiMethodName();
  355. $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
  356. $rootIndex = strpos($responseContent, $rootNodeName);
  357. $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
  358. if ($rootIndex > 0) {
  359. return $this->parserJSONSource($responseContent, $rootNodeName, $rootIndex);
  360. } else if ($errorIndex > 0) {
  361. return $this->parserJSONSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
  362. } else {
  363. return null;
  364. }
  365. }
  366. function parserJSONSource($responseContent, $nodeName, $nodeIndex)
  367. {
  368. $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
  369. $signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
  370. // 签名前-逗号
  371. $signDataEndIndex = $signIndex - 1;
  372. $indexLen = $signDataEndIndex - $signDataStartIndex;
  373. if ($indexLen < 0) {
  374. return null;
  375. }
  376. return substr($responseContent, $signDataStartIndex, $indexLen);
  377. }
  378. function parserJSONSign($responseJSon)
  379. {
  380. return $responseJSon->sign;
  381. }
  382. function parserXMLSignData($request, $responseContent)
  383. {
  384. $signData = new SignData();
  385. $signData->sign = $this->parserXMLSign($responseContent);
  386. $signData->signSourceData = $this->parserXMLSignSource($request, $responseContent);
  387. return $signData;
  388. }
  389. function parserXMLSignSource($request, $responseContent)
  390. {
  391. $apiName = $request->getApiMethodName();
  392. $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
  393. $rootIndex = strpos($responseContent, $rootNodeName);
  394. $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
  395. // $this->echoDebug("<br/>rootNodeName:" . $rootNodeName);
  396. // $this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>");
  397. if ($rootIndex > 0) {
  398. return $this->parserXMLSource($responseContent, $rootNodeName, $rootIndex);
  399. } else if ($errorIndex > 0) {
  400. return $this->parserXMLSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
  401. } else {
  402. return null;
  403. }
  404. }
  405. function parserXMLSource($responseContent, $nodeName, $nodeIndex)
  406. {
  407. $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
  408. $signIndex = strpos($responseContent, "<" . $this->SIGN_NODE_NAME . ">");
  409. // 签名前-逗号
  410. $signDataEndIndex = $signIndex - 1;
  411. $indexLen = $signDataEndIndex - $signDataStartIndex + 1;
  412. if ($indexLen < 0) {
  413. return null;
  414. }
  415. return substr($responseContent, $signDataStartIndex, $indexLen);
  416. }
  417. function parserXMLSign($responseContent)
  418. {
  419. $signNodeName = "<" . $this->SIGN_NODE_NAME . ">";
  420. $signEndNodeName = "</" . $this->SIGN_NODE_NAME . ">";
  421. $indexOfSignNode = strpos($responseContent, $signNodeName);
  422. $indexOfSignEndNode = strpos($responseContent, $signEndNodeName);
  423. if ($indexOfSignNode < 0 || $indexOfSignEndNode < 0) {
  424. return null;
  425. }
  426. $nodeIndex = ($indexOfSignNode + strlen($signNodeName));
  427. $indexLen = $indexOfSignEndNode - $nodeIndex;
  428. if ($indexLen < 0) {
  429. return null;
  430. }
  431. // 签名
  432. return substr($responseContent, $nodeIndex, $indexLen);
  433. }
  434. /**
  435. * 验签
  436. * @param $request
  437. * @param $signData
  438. * @param $resp
  439. * @param $respObject
  440. * @throws Exception
  441. */
  442. public function checkResponseSign($request, $signData, $resp, $respObject)
  443. {
  444. if (!$this->checkEmpty($this->alipayPublicKey) || !$this->checkEmpty($this->alipayrsaPublicKey)) {
  445. if ($signData == null || $this->checkEmpty($signData->sign) || $this->checkEmpty($signData->signSourceData)) {
  446. throw new Exception(" check sign Fail! The reason : signData is Empty");
  447. }
  448. // 获取结果sub_code
  449. $responseSubCode = $this->parserResponseSubCode($request, $resp, $respObject, $this->format);
  450. if (!$this->checkEmpty($responseSubCode) || ($this->checkEmpty($responseSubCode) && !$this->checkEmpty($signData->sign))) {
  451. $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
  452. if (!$checkResult) {
  453. if (strpos($signData->signSourceData, "\\/") > 0) {
  454. $signData->signSourceData = str_replace("\\/", "/", $signData->signSourceData);
  455. $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
  456. if (!$checkResult) {
  457. throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
  458. }
  459. } else {
  460. throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
  461. }
  462. }
  463. }
  464. }
  465. }
  466. private function setupCharsets($request)
  467. {
  468. if ($this->checkEmpty($this->postCharset)) {
  469. $this->postCharset = 'UTF-8';
  470. }
  471. $str = preg_match('/[\x80-\xff]/', $this->appId) ? $this->appId : print_r($request, true);
  472. $this->fileCharset = mb_detect_encoding($str, "UTF-8, GBK") == 'UTF-8' ? 'UTF-8' : 'GBK';
  473. }
  474. // 获取加密内容
  475. private function encryptJSONSignSource($request, $responseContent)
  476. {
  477. $parsetItem = $this->parserEncryptJSONSignSource($request, $responseContent);
  478. $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
  479. $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
  480. $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
  481. return $bodyIndexContent . $bizContent . $bodyEndContent;
  482. }
  483. private function parserEncryptJSONSignSource($request, $responseContent)
  484. {
  485. $apiName = $request->getApiMethodName();
  486. $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
  487. $rootIndex = strpos($responseContent, $rootNodeName);
  488. $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
  489. if ($rootIndex > 0) {
  490. return $this->parserEncryptJSONItem($responseContent, $rootNodeName, $rootIndex);
  491. } else if ($errorIndex > 0) {
  492. return $this->parserEncryptJSONItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
  493. } else {
  494. return null;
  495. }
  496. }
  497. private function parserEncryptJSONItem($responseContent, $nodeName, $nodeIndex)
  498. {
  499. $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
  500. $signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
  501. // 签名前-逗号
  502. $signDataEndIndex = $signIndex - 1;
  503. if ($signDataEndIndex < 0) {
  504. $signDataEndIndex = strlen($responseContent) - 1;
  505. }
  506. $indexLen = $signDataEndIndex - $signDataStartIndex;
  507. $encContent = substr($responseContent, $signDataStartIndex + 1, $indexLen - 2);
  508. $encryptParseItem = new EncryptParseItem();
  509. $encryptParseItem->encryptContent = $encContent;
  510. $encryptParseItem->startIndex = $signDataStartIndex;
  511. $encryptParseItem->endIndex = $signDataEndIndex;
  512. return $encryptParseItem;
  513. }
  514. // 获取加密内容
  515. private function encryptXMLSignSource($request, $responseContent)
  516. {
  517. $parsetItem = $this->parserEncryptXMLSignSource($request, $responseContent);
  518. $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
  519. $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
  520. $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
  521. return $bodyIndexContent . $bizContent . $bodyEndContent;
  522. }
  523. private function parserEncryptXMLSignSource($request, $responseContent)
  524. {
  525. $apiName = $request->getApiMethodName();
  526. $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
  527. $rootIndex = strpos($responseContent, $rootNodeName);
  528. $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
  529. // $this->echoDebug("<br/>rootNodeName:" . $rootNodeName);
  530. // $this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>");
  531. if ($rootIndex > 0) {
  532. return $this->parserEncryptXMLItem($responseContent, $rootNodeName, $rootIndex);
  533. } else if ($errorIndex > 0) {
  534. return $this->parserEncryptXMLItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
  535. } else {
  536. return null;
  537. }
  538. }
  539. private function parserEncryptXMLItem($responseContent, $nodeName, $nodeIndex)
  540. {
  541. $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
  542. $xmlStartNode = "<" . $this->ENCRYPT_XML_NODE_NAME . ">";
  543. $xmlEndNode = "</" . $this->ENCRYPT_XML_NODE_NAME . ">";
  544. $indexOfXmlNode = strpos($responseContent, $xmlEndNode);
  545. if ($indexOfXmlNode < 0) {
  546. $item = new EncryptParseItem();
  547. $item->encryptContent = null;
  548. $item->startIndex = 0;
  549. $item->endIndex = 0;
  550. return $item;
  551. }
  552. $startIndex = $signDataStartIndex + strlen($xmlStartNode);
  553. $bizContentLen = $indexOfXmlNode - $startIndex;
  554. $bizContent = substr($responseContent, $startIndex, $bizContentLen);
  555. $encryptParseItem = new EncryptParseItem();
  556. $encryptParseItem->encryptContent = $bizContent;
  557. $encryptParseItem->startIndex = $signDataStartIndex;
  558. $encryptParseItem->endIndex = $indexOfXmlNode + strlen($xmlEndNode);
  559. return $encryptParseItem;
  560. }
  561. function echoDebug($content)
  562. {
  563. if ($this->debugInfo) {
  564. echo "<br/>" . $content;
  565. }
  566. }
  567. }