acp_service.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <?php
  2. namespace com\unionpay\acp\sdk;
  3. header ( 'Content-type:text/html;charset=utf-8' );
  4. include_once 'log.class.php';
  5. include_once 'SDKConfig.php';
  6. include_once 'common.php';
  7. include_once 'cert_util.php';
  8. class AcpService {
  9. /**
  10. *
  11. * 更新证书
  12. *
  13. * Enter description here ...
  14. */
  15. public static function updateEncryptCert(&$params)
  16. {
  17. $logger = LogUtil::getLogger();
  18. // 取得证书
  19. $strCert = $params['encryptPubKeyCert'];
  20. $certType = $params['certType'];
  21. openssl_x509_read($strCert);
  22. $certInfo = openssl_x509_parse($strCert);
  23. if($certType === "01"){
  24. $logger->LogInfo ('原证书certId:'.CertUtil::getEncryptCertId().',新证书certId:'.$certInfo['serialNumber']);
  25. // 更新敏感信息加密公钥
  26. if (CertUtil::getEncryptCertId() != $certInfo['serialNumber']) {
  27. $newFileName = getBackupFileName(SDKConfig::getSDKConfig()->encryptCertPath);
  28. // 将原证书备份重命名
  29. if(!copy(SDKConfig::getSDKConfig()->encryptCertPath, $newFileName)){
  30. $logger->LogError ('原证书备份失败');
  31. return -1;
  32. }
  33. // 更新证书
  34. if(!file_put_contents(SDKConfig::getSDKConfig()->encryptCertPath, $strCert)){
  35. $logger->LogError ('更新证书失败');
  36. return -1;
  37. }
  38. $logger->LogInfo ('证书更新成功');
  39. return 1;
  40. } else {
  41. $logger->LogInfo ('证书无需更新');
  42. return 0;
  43. }
  44. } else if($certType === "02"){
  45. return 0;
  46. } else {
  47. $logger->LogError ('unknown cerType: '. $certType);
  48. return -1;
  49. }
  50. }
  51. /**
  52. * 签名
  53. * @param req 请求要素
  54. * @param resp 应答要素
  55. * @return 是否成功
  56. */
  57. static function sign(&$params) {
  58. if($params['signMethod']=='01') {
  59. return AcpService::signByCertInfo($params, SDKConfig::getSDKConfig()->signCertPath, SDKConfig::getSDKConfig()->signCertPwd);
  60. } else {
  61. return AcpService::signBySecureKey($params, SDKConfig::getSDKConfig()->secureKey);
  62. }
  63. }
  64. static function signByCertInfo(&$params, $cert_path, $cert_pwd) {
  65. $logger = LogUtil::getLogger();
  66. $logger->LogInfo ( '=====签名报文开始======' );
  67. if(isset($params['signature'])){
  68. unset($params['signature']);
  69. }
  70. $result = false;
  71. if($params['signMethod']=='01') {
  72. //证书ID
  73. $params ['certId'] = CertUtil::getSignCertIdFromPfx($cert_path, $cert_pwd);
  74. $private_key = CertUtil::getSignKeyFromPfx( $cert_path, $cert_pwd );
  75. // 转换成key=val&串
  76. $params_str = createLinkString ( $params, true, false );
  77. $logger->LogInfo ( "签名key=val&...串 >" . $params_str );
  78. if($params['version']=='5.0.0'){
  79. $params_sha1x16 = sha1 ( $params_str, FALSE );
  80. $logger->LogInfo ( "摘要sha1x16 >" . $params_sha1x16 );
  81. // 签名
  82. $result = openssl_sign ( $params_sha1x16, $signature, $private_key, OPENSSL_ALGO_SHA1);
  83. if ($result) {
  84. $signature_base64 = base64_encode ( $signature );
  85. $logger->LogInfo ( "签名串为 >" . $signature_base64 );
  86. $params ['signature'] = $signature_base64;
  87. } else {
  88. $logger->LogInfo ( ">>>>>签名失败<<<<<<<" );
  89. }
  90. } else if($params['version']=='5.1.0'){
  91. //sha256签名摘要
  92. $params_sha256x16 = hash( 'sha256',$params_str);
  93. $logger->LogInfo ( "摘要sha256x16 >" . $params_sha256x16 );
  94. // 签名
  95. $result = openssl_sign ( $params_sha256x16, $signature, $private_key, 'sha256');
  96. if ($result) {
  97. $signature_base64 = base64_encode ( $signature );
  98. $logger->LogInfo ( "签名串为 >" . $signature_base64 );
  99. $params ['signature'] = $signature_base64;
  100. } else {
  101. $logger->LogInfo ( ">>>>>签名失败<<<<<<<" );
  102. }
  103. } else {
  104. $logger->LogError ( "wrong version: " + $params['version'] );
  105. $result = false;
  106. }
  107. } else {
  108. $logger->LogError ( "signMethod不正确");
  109. $result = false;
  110. }
  111. $logger->LogInfo ( '=====签名报文结束======' );
  112. return $result;
  113. }
  114. static function signBySecureKey(&$params, $secureKey) {
  115. $logger = LogUtil::getLogger();
  116. $logger->LogInfo ( '=====签名报文开始======' );
  117. if($params['signMethod']=='11') {
  118. // 转换成key=val&串
  119. $params_str = createLinkString ( $params, true, false );
  120. $logger->LogInfo ( "签名key=val&...串 >" . $params_str );
  121. $params_before_sha256 = hash('sha256', $secureKey);
  122. $params_before_sha256 = $params_str.'&'.$params_before_sha256;
  123. $logger->LogDebug( "before final sha256: " . $params_before_sha256);
  124. $params_after_sha256 = hash('sha256',$params_before_sha256);
  125. $logger->LogInfo ( "签名串为 >" . $params_after_sha256 );
  126. $params ['signature'] = $params_after_sha256;
  127. $result = true;
  128. } else if($params['signMethod']=='12') {
  129. //TODO SM3
  130. $logger->LogError ( "signMethod=12未实现");
  131. $result = false;
  132. } else {
  133. $logger->LogError ( "signMethod不正确");
  134. $result = false;
  135. }
  136. $logger->LogInfo ( '=====签名报文结束======' );
  137. return $result;
  138. }
  139. /**
  140. * 验签
  141. * @param $params 应答数组
  142. * @return 是否成功
  143. */
  144. static function validate($params) {
  145. $logger = LogUtil::getLogger();
  146. $isSuccess = false;
  147. if($params['signMethod']=='01')
  148. {
  149. $signature_str = $params ['signature'];
  150. unset ( $params ['signature'] );
  151. $params_str = createLinkString ( $params, true, false );
  152. $logger->LogInfo ( '报文去[signature] key=val&串>' . $params_str );
  153. $logger->LogInfo ( '签名原文>' . $signature_str );
  154. if($params['version']=='5.0.0'){
  155. // 公钥
  156. $public_key = CertUtil::getVerifyCertByCertId ( $params ['certId'] );
  157. $signature = base64_decode ( $signature_str );
  158. $params_sha1x16 = sha1 ( $params_str, FALSE );
  159. $logger->LogInfo ( 'sha1>' . $params_sha1x16 );
  160. $isSuccess = openssl_verify ( $params_sha1x16, $signature, $public_key, OPENSSL_ALGO_SHA1 );
  161. $logger->LogInfo ( $isSuccess ? '验签成功' : '验签失败' );
  162. } else if($params['version']=='5.1.0'){
  163. $strCert = $params['signPubKeyCert'];
  164. $strCert = CertUtil::verifyAndGetVerifyCert($strCert);
  165. if($strCert == null){
  166. $logger->LogError ("validate cert err: " . $params["signPubKeyCert"]);
  167. $isSuccess = false;
  168. } else {
  169. $params_sha256x16 = hash('sha256', $params_str);
  170. $logger->LogInfo ( 'sha256>' . $params_sha256x16 );
  171. $signature = base64_decode ( $signature_str );
  172. $isSuccess = openssl_verify ( $params_sha256x16, $signature,$strCert, "sha256" );
  173. $logger->LogInfo ( $isSuccess ? '验签成功' : '验签失败' );
  174. }
  175. } else {
  176. $logger->LogError ( "wrong version: " + $params['version'] );
  177. $isSuccess = false;
  178. }
  179. } else {
  180. $isSuccess = AcpService::validateBySecureKey($params, SDKConfig::getSDKConfig()->secureKey);
  181. }
  182. return $isSuccess;
  183. }
  184. static function validateBySecureKey($params, $secureKey) {
  185. $logger = LogUtil::getLogger();
  186. $isSuccess = false;
  187. $signature_str = $params ['signature'];
  188. unset ( $params ['signature'] );
  189. $params_str = createLinkString ( $params, true, false );
  190. $logger->LogInfo ( '报文去[signature] key=val&串>' . $params_str );
  191. $logger->LogInfo ( '签名原文>' . $signature_str );
  192. if($params['signMethod']=='11') {
  193. $params_before_sha256 = hash('sha256', $secureKey);
  194. $params_before_sha256 = $params_str.'&'.$params_before_sha256;
  195. $params_after_sha256 = hash('sha256',$params_before_sha256);
  196. $isSuccess = $params_after_sha256 == $signature_str;
  197. $logger->LogInfo ( $isSuccess ? '验签成功' : '验签失败' );
  198. } else if($params['signMethod']=='12') {
  199. //TODO SM3
  200. $logger->LogError ( "sm3没实现");
  201. $isSuccess = false;
  202. } else {
  203. $logger->LogError ( "signMethod不正确");
  204. $isSuccess = false;
  205. }
  206. return $isSuccess;
  207. }
  208. /**
  209. * @deprecated 5.1.0开发包已删除此方法,请直接参考5.1.0开发包中的VerifyAppData.php验签。
  210. * 对控件支付成功返回的结果信息中data域进行验签
  211. * @param $jsonData json格式数据,例如:{"sign" : "J6rPLClQ64szrdXCOtV1ccOMzUmpiOKllp9cseBuRqJ71pBKPPkZ1FallzW18gyP7CvKh1RxfNNJ66AyXNMFJi1OSOsteAAFjF5GZp0Xsfm3LeHaN3j/N7p86k3B1GrSPvSnSw1LqnYuIBmebBkC1OD0Qi7qaYUJosyA1E8Ld8oGRZT5RR2gLGBoiAVraDiz9sci5zwQcLtmfpT5KFk/eTy4+W9SsC0M/2sVj43R9ePENlEvF8UpmZBqakyg5FO8+JMBz3kZ4fwnutI5pWPdYIWdVrloBpOa+N4pzhVRKD4eWJ0CoiD+joMS7+C0aPIEymYFLBNYQCjM0KV7N726LA==", "data" : "pay_result=success&tn=201602141008032671528&cert_id=68759585097"}
  212. * @return 是否成功
  213. */
  214. static function validateAppResponse($jsonData) {
  215. $data = json_decode($jsonData);
  216. $sign = $data->sign;
  217. $data = $data->data;
  218. $dataMap = parseQString($data);
  219. $public_key = CertUtil::getVerifyCertByCertId( $dataMap ['cert_id'] );
  220. $signature = base64_decode ( $sign );
  221. $params_sha1x16 = sha1 ( $data, FALSE );
  222. $isSuccess = openssl_verify ( $params_sha1x16, $signature,$public_key, OPENSSL_ALGO_SHA1 );
  223. return $isSuccess;
  224. }
  225. /**
  226. * 后台交易 HttpClient通信
  227. *
  228. * @param unknown_type $params
  229. * @param unknown_type $url
  230. * @return mixed
  231. */
  232. static function post($params, $url) {
  233. $logger = LogUtil::getLogger();
  234. $opts = createLinkString ( $params, false, true );
  235. $logger->LogInfo ( "后台请求地址为>" . $url );
  236. $logger->LogInfo ( "后台请求报文为>" . $opts );
  237. $ch = curl_init ();
  238. curl_setopt ( $ch, CURLOPT_URL, $url );
  239. curl_setopt ( $ch, CURLOPT_POST, 1 );
  240. curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false ); // 不验证证书
  241. curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false ); // 不验证HOST
  242. curl_setopt ( $ch, CURLOPT_SSLVERSION, 1 ); // http://php.net/manual/en/function.curl-setopt.php页面搜CURL_SSLVERSION_TLSv1
  243. curl_setopt ( $ch, CURLOPT_HTTPHEADER, array (
  244. 'Content-type:application/x-www-form-urlencoded;charset=UTF-8'
  245. ) );
  246. curl_setopt ( $ch, CURLOPT_POSTFIELDS, $opts );
  247. curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
  248. $html = curl_exec ( $ch );
  249. $logger->LogInfo ( "后台返回结果为>" . $html );
  250. if(curl_errno($ch)){
  251. $errmsg = curl_error($ch);
  252. curl_close ( $ch );
  253. $logger->LogInfo ( "请求失败,报错信息>" . $errmsg );
  254. return null;
  255. }
  256. if( curl_getinfo($ch, CURLINFO_HTTP_CODE) != "200"){
  257. $errmsg = "http状态=" . curl_getinfo($ch, CURLINFO_HTTP_CODE);
  258. curl_close ( $ch );
  259. $logger->LogInfo ( "请求失败,报错信息>" . $errmsg );
  260. return null;
  261. }
  262. curl_close ( $ch );
  263. $result_arr = convertStringToArray ( $html );
  264. return $result_arr;
  265. }
  266. /**
  267. * 后台交易 HttpClient通信
  268. *
  269. * @param unknown_type $params
  270. * @param unknown_type $url
  271. * @return mixed
  272. */
  273. static function get($params, $url) {
  274. $logger = LogUtil::getLogger();
  275. $opts = createLinkString ( $params, false, true );
  276. $logger->LogDebug( "后台请求地址为>" . $url ); //get的日志太多而且没啥用,设debug级别
  277. $logger->LogDebug ( "后台请求报文为>" . $opts );
  278. $ch = curl_init ();
  279. curl_setopt ( $ch, CURLOPT_URL, $url );
  280. curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false ); // 不验证证书
  281. curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false ); // 不验证HOST
  282. curl_setopt ( $ch, CURLOPT_SSLVERSION, 1 ); // http://php.net/manual/en/function.curl-setopt.php页面搜CURL_SSLVERSION_TLSv1
  283. curl_setopt ( $ch, CURLOPT_HTTPHEADER, array (
  284. 'Content-type:application/x-www-form-urlencoded;charset=UTF-8'
  285. ) );
  286. curl_setopt ( $ch, CURLOPT_POSTFIELDS, $opts );
  287. curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
  288. $html = curl_exec ( $ch );
  289. $logger->LogInfo ( "后台返回结果为>" . $html );
  290. if(curl_errno($ch)){
  291. $errmsg = curl_error($ch);
  292. curl_close ( $ch );
  293. $logger->LogDebug ( "请求失败,报错信息>" . $errmsg );
  294. return null;
  295. }
  296. if( curl_getinfo($ch, CURLINFO_HTTP_CODE) != "200"){
  297. $errmsg = "http状态=" . curl_getinfo($ch, CURLINFO_HTTP_CODE);
  298. curl_close ( $ch );
  299. $logger->LogDebug ( "请求失败,报错信息>" . $errmsg );
  300. return null;
  301. }
  302. curl_close ( $ch );
  303. return $html;
  304. }
  305. static function createAutoFormHtml($params, $reqUrl) {
  306. // <body onload="javascript:document.pay_form.submit();">
  307. $encodeType = isset ( $params ['encoding'] ) ? $params ['encoding'] : 'UTF-8';
  308. $html = <<<eot
  309. <html>
  310. <head>
  311. <meta http-equiv="Content-Type" content="text/html; charset={$encodeType}" />
  312. </head>
  313. <body onload="javascript:document.pay_form.submit();">
  314. <form id="pay_form" name="pay_form" action="{$reqUrl}" method="post">
  315. eot;
  316. foreach ( $params as $key => $value ) {
  317. $html .= " <input type=\"hidden\" name=\"{$key}\" id=\"{$key}\" value=\"{$value}\" />\n";
  318. }
  319. $html .= <<<eot
  320. <!-- <input type="submit" type="hidden">-->
  321. </form>
  322. </body>
  323. </html>
  324. eot;
  325. $logger = LogUtil::getLogger();
  326. $logger->LogInfo ( "自动跳转html>" . $html );
  327. return $html;
  328. }
  329. static function getCustomerInfo($customerInfo) {
  330. if($customerInfo == null || count($customerInfo) == 0 )
  331. return "";
  332. return base64_encode ( "{" . createLinkString ( $customerInfo, false, false ) . "}" );
  333. }
  334. /**
  335. * map转换string,按新规范加密
  336. *
  337. * @param
  338. * $customerInfo
  339. */
  340. static function getCustomerInfoWithEncrypt($customerInfo) {
  341. if($customerInfo == null || count($customerInfo) == 0 )
  342. return "";
  343. $encryptedInfo = array();
  344. foreach ( $customerInfo as $key => $value ) {
  345. if ($key == 'phoneNo' || $key == 'cvn2' || $key == 'expired' ) {
  346. //if ($key == 'phoneNo' || $key == 'cvn2' || $key == 'expired' || $key == 'certifTp' || $key == 'certifId') {
  347. $encryptedInfo [$key] = $customerInfo [$key];
  348. unset ( $customerInfo [$key] );
  349. }
  350. }
  351. if( count ($encryptedInfo) > 0 ){
  352. $encryptedInfo = createLinkString ( $encryptedInfo, false, false );
  353. $encryptedInfo = AcpService::encryptData ( $encryptedInfo, SDKConfig::getSDKConfig()->encryptCertPath );
  354. $customerInfo ['encryptedInfo'] = $encryptedInfo;
  355. }
  356. return base64_encode ( "{" . createLinkString ( $customerInfo, false, false ) . "}" );
  357. }
  358. /**
  359. * 解析customerInfo。
  360. * 为方便处理,encryptedInfo下面的信息也均转换为customerInfo子域一样方式处理,
  361. * @param unknown $customerInfostr
  362. * @return array形式ParseCustomerInfo
  363. */
  364. static function parseCustomerInfo($customerInfostr) {
  365. $customerInfostr = base64_decode($customerInfostr);
  366. $customerInfostr = substr($customerInfostr, 1, strlen($customerInfostr) - 2);
  367. $customerInfo = parseQString($customerInfostr);
  368. if(array_key_exists("encryptedInfo", $customerInfo)) {
  369. $encryptedInfoStr = $customerInfo["encryptedInfo"];
  370. unset ( $customerInfo ["encryptedInfo"] );
  371. $encryptedInfoStr = AcpService::decryptData($encryptedInfoStr);
  372. $encryptedInfo = parseQString($encryptedInfoStr);
  373. foreach ($encryptedInfo as $key => $value){
  374. $customerInfo[$key] = $value;
  375. }
  376. }
  377. return $customerInfo;
  378. }
  379. static function getEncryptCertId() {
  380. $cert_path=SDKConfig::getSDKConfig()->encryptCertPath;
  381. return CertUtil::getEncryptCertId($cert_path);
  382. }
  383. /**
  384. * 加密数据
  385. * @param string $data数据
  386. * @param string $cert_path 证书配置路径
  387. * @return unknown
  388. */
  389. static function encryptData($data, $cert_path=null) {
  390. if( $cert_path == null ) {
  391. $cert_path = SDKConfig::getSDKConfig()->encryptCertPath;
  392. }
  393. $public_key = CertUtil::getEncryptKey( $cert_path );
  394. openssl_public_encrypt ( $data, $crypted, $public_key );
  395. return base64_encode ( $crypted );
  396. }
  397. /**
  398. * 解密数据
  399. * @param string $data数据
  400. * @param string $cert_path 证书配置路径
  401. * @return unknown
  402. */
  403. static function decryptData($data, $cert_path=null, $cert_pwd=null) {
  404. if( $cert_path == null ) {
  405. $cert_path = SDKConfig::getSDKConfig()->signCertPath;
  406. $cert_pwd = SDKConfig::getSDKConfig()->signCertPwd;
  407. }
  408. $data = base64_decode ( $data );
  409. $private_key = CertUtil::getSignKeyFromPfx ( $cert_path, $cert_pwd);
  410. openssl_private_decrypt ( $data, $crypted, $private_key );
  411. return $crypted;
  412. }
  413. /**
  414. * 处理报文中的文件
  415. *
  416. * @param unknown_type $params
  417. */
  418. static function deCodeFileContent($params, $fileDirectory) {
  419. $logger = LogUtil::getLogger();
  420. if (isset ( $params ['fileContent'] )) {
  421. $logger->LogInfo ( "---------处理后台报文返回的文件---------" );
  422. $fileContent = $params ['fileContent'];
  423. if (empty ( $fileContent )) {
  424. $logger->LogInfo ( '文件内容为空' );
  425. return false;
  426. } else {
  427. // 文件内容 解压缩
  428. $content = gzuncompress ( base64_decode ( $fileContent ) );
  429. $filePath = null;
  430. if (empty ( $params ['fileName'] )) {
  431. $logger->LogInfo ( "文件名为空" );
  432. $filePath = $fileDirectory . $params ['merId'] . '_' . $params ['batchNo'] . '_' . $params ['txnTime'] . '.txt';
  433. } else {
  434. $filePath = $fileDirectory . $params ['fileName'];
  435. }
  436. $handle = fopen ( $filePath, "w+" );
  437. if (! is_writable ( $filePath )) {
  438. $logger->LogInfo ( "文件:" . $filePath . "不可写,请检查!" );
  439. return false;
  440. } else {
  441. file_put_contents ( $filePath, $content );
  442. $logger->LogInfo ( "文件位置 >:" . $filePath );
  443. }
  444. fclose ( $handle );
  445. }
  446. return true;
  447. } else {
  448. return false;
  449. }
  450. }
  451. static function enCodeFileContent($path){
  452. $file_content_base64 = '';
  453. if(!file_exists($path)){
  454. echo '文件没找到';
  455. return false;
  456. }
  457. $file_content = file_get_contents ( $path );
  458. //UTF8 去掉文本中的 bom头
  459. $BOM = chr(239).chr(187).chr(191);
  460. $file_content = str_replace($BOM,'',$file_content);
  461. $file_content_deflate = gzcompress ( $file_content );
  462. $file_content_base64 = base64_encode ( $file_content_deflate );
  463. return $file_content_base64;
  464. }
  465. }