PayController.php 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  1. <?php
  2. namespace app\controllers;
  3. use app\common\components\SiteUrl;
  4. use app\components\WeiXin\WeiXin;
  5. use app\common\components\MessageOne;
  6. use app\modules\doc\models\DocDowncode;
  7. use app\modules\ucenter\models\User;
  8. use app\modules\ucenter\models\UserVipType;
  9. use app\modules\ucenter\models\UserVipOrder;
  10. use app\modules\doc\models\DocReal;
  11. use app\common\helpers\Identify;
  12. use app\common\components\Wallet;
  13. use app\modules\shopping\models\ShoppingOrder;
  14. use app\modules\shopping\models\ShoppingPaycode;
  15. use WeChatPay\Builder;
  16. use WeChatPay\Crypto\Rsa;
  17. use WeChatPay\Util\PemUtil;
  18. use WeChatPay\Crypto\AesGcm;
  19. use WeChatPay\Formatter;
  20. use Yii;
  21. use yii\web\Controller;
  22. Yii::setAlias('@payerdrivers','@app/components/payer/drivers');
  23. class PayController extends Controller
  24. {
  25. public $enableCsrfValidation = false;
  26. public $userInfo;
  27. public $payconfig;
  28. public $coinconfig;
  29. public $wechatPay;
  30. public $logdir;
  31. public function init()
  32. {
  33. $this->logdir = Yii::getAlias('@runtime').DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'pay'.DIRECTORY_SEPARATOR;
  34. dir_create($this->logdir);
  35. $this->userInfo = Identify::getUserInfo();
  36. $this->payconfig = Yii::$app->params['pay'];
  37. $this->coinconfig = Yii::$app->params['coin'];
  38. if($this->payconfig['weixin_pay'])
  39. {
  40. // 商户号
  41. $merchantId = $this->payconfig['weixin_mchid'];
  42. // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
  43. $merchantPrivateKeyFilePath = 'file://'.$this->payconfig['weixin_apiclient_key'];
  44. $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
  45. // 「商户API证书」的「证书序列号」
  46. $merchantCertificateSerial = $this->payconfig['weixin_serialnumber'];
  47. // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
  48. $platformCertificateFilePath = 'file://'.$this->payconfig['weixin_cert'];
  49. $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
  50. // 从「微信支付平台证书」中获取「证书序列号」
  51. $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
  52. // 构造一个 APIv3 客户端实例
  53. $this->wechatPay = Builder::factory([
  54. 'mchid' => $merchantId,
  55. 'serial' => $merchantCertificateSerial,
  56. 'privateKey' => $merchantPrivateKeyInstance,
  57. 'certs' => [
  58. $platformCertificateSerial => $platformPublicKeyInstance,
  59. ],
  60. ]);
  61. }
  62. }
  63. public function actionDo()
  64. {
  65. }
  66. //处理来自手机端的支付请求
  67. public function actionDowap()
  68. {
  69. $initData = $_POST;
  70. extract($initData);
  71. //解决微信跳转后参数传递问题
  72. $state = Yii::$app->request->get('state');
  73. if(!empty($state)&&$state=='MR8888')
  74. {
  75. $initData = $_GET;
  76. extract($initData);
  77. }
  78. //购买文档时候,调整回跳地址
  79. if($act=='buydoc')
  80. {
  81. $doc = DocReal::findOne($id);
  82. if($doc->doc_type==2)
  83. {
  84. $return_url = SiteUrl::colDetail($id,$order_sn);
  85. }
  86. else
  87. {
  88. $return_url = SiteUrl::docDetail($id,$order_sn);
  89. }
  90. }
  91. //支付宝
  92. if($pay_method=='apw_pay')
  93. {
  94. require_once(Yii::getAlias('@payerdrivers').'/alipaywap/wappay/service/AlipayTradeService.php');
  95. require_once(Yii::getAlias('@payerdrivers').'/alipaywap/wappay/buildermodel/AlipayTradeWapPayContentBuilder.php');
  96. $order = $this->_initOrder($initData);
  97. $config = array (
  98. //应用ID,您的APPID。
  99. 'app_id' => $this->payconfig['apw_appid'],
  100. //商户私钥,您的原始格式RSA私钥
  101. 'merchant_private_key' => $this->payconfig['apw_merchant_private_key'],
  102. //异步通知地址
  103. 'notify_url' => $this->payconfig['apw_notify_url'],
  104. //同步跳转
  105. 'return_url' => $return_url,
  106. //编码格式
  107. 'charset' => "UTF-8",
  108. //签名方式
  109. 'sign_type'=>"RSA2",
  110. //支付宝网关
  111. 'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
  112. //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
  113. 'alipay_public_key' => $this->payconfig['apw_alipay_public_key'],
  114. //日志路径
  115. 'log_path' => $this->logdir.get_date(TIMESTAMP, "Y-m").'.txt',
  116. );
  117. //商户订单号,商户网站订单系统中唯一订单号,必填
  118. $out_trade_no = trim($order_sn);
  119. //订单名称,必填
  120. $subject = $order->remark;
  121. //付款金额,必填
  122. $total_amount = trim($total_price);
  123. //商品描述,可空
  124. $body = '';
  125. //超时时间
  126. $timeout_express="1m";
  127. $payRequestBuilder = new \AlipayTradeWapPayContentBuilder();
  128. $payRequestBuilder->setBody($body);
  129. $payRequestBuilder->setSubject($subject);
  130. $payRequestBuilder->setOutTradeNo($out_trade_no);
  131. $payRequestBuilder->setTotalAmount($total_amount);
  132. $payRequestBuilder->setTimeExpress($timeout_express);
  133. $payResponse = new \AlipayTradeService($config);
  134. $result=$payResponse->wapPay($payRequestBuilder,$config['return_url'],$config['notify_url']);
  135. return ;
  136. }
  137. //微信公众号支付
  138. if($pay_method=='weixin_pay'){
  139. $args = array(
  140. 'appId'=>$this->payconfig['weixin_appid'],
  141. 'appSecret'=>$this->payconfig['weixin_appsecret'],
  142. 'token'=>$this->payconfig['weixin_token'],
  143. );
  144. $weixin = new WeiXin($args);
  145. $weixin->init();
  146. //JS API接口支付(仅在微信里面)
  147. if(isset($_GET['code'])&&$_GET['code']!='')
  148. {
  149. $order = $this->_initOrder($initData);
  150. $result = $weixin->getOauthAccessToken($_GET['code']);
  151. try {
  152. $pay_money = max($total_price, 0.01);
  153. $resp = $this->wechatPay->chain('v3/pay/transactions/jsapi')
  154. ->post(['json' => [
  155. 'appid' => $this->payconfig['weixin_appid'],
  156. 'mchid' => $this->payconfig['weixin_mchid'],
  157. 'out_trade_no' => $order_sn,
  158. 'description' => $order->remark,
  159. 'notify_url' => $this->payconfig['weixin_notify_url'],
  160. 'amount' => [
  161. 'total' => $pay_money*100,
  162. 'currency' => 'CNY'
  163. ],
  164. 'payer' => [
  165. 'openid'=>$result['openid']
  166. ],
  167. ]]);
  168. if($resp->getStatusCode()==200)
  169. {
  170. $respBody = json_decode($resp->getBody(),true);
  171. $prepay_id = $respBody['prepay_id'];
  172. if($prepay_id)
  173. {
  174. $timestamp = TIMESTAMP;
  175. $noncestr = TIMESTAMP;
  176. $signstr = $this->getWechartSign($this->payconfig['weixin_appid'], strval($timestamp), strval($noncestr), 'prepay_id='.$prepay_id);
  177. $jsApiParameters = json_encode([
  178. 'appId' => $this->payconfig['weixin_appid'],
  179. 'timeStamp' => strval($timestamp) ,
  180. 'package' => 'prepay_id=' . $respBody['prepay_id'],
  181. 'paySign' => $signstr,
  182. 'nonceStr' => strval($noncestr)
  183. ]);
  184. ob_clean();
  185. require_once(Yii::getAlias('@app/views').DIRECTORY_SEPARATOR.'pay'.DIRECTORY_SEPARATOR.$pay_method.'.php');
  186. exit;
  187. }
  188. else
  189. {
  190. exit('支付失败');
  191. }
  192. }
  193. else
  194. {
  195. exit('支付失败');
  196. }
  197. }
  198. catch (\Exception $e) {
  199. exit($e->getMessage());
  200. }
  201. }
  202. else
  203. {
  204. $redirectUrl = get_url();
  205. $queryParams = http_build_query($initData);
  206. if(strpos($redirectUrl,'?')===false)
  207. {
  208. $redirectUrl = $redirectUrl.'?'.urldecode($queryParams);
  209. }
  210. else
  211. {
  212. $redirectUrl = $redirectUrl.'&'.urldecode($queryParams);
  213. }
  214. $codeUrl = $weixin->getWebAuthUrl(urlencode($redirectUrl),'snsapi_base','MR8888');
  215. echo "<script>";
  216. echo "window.location.href='".$codeUrl."';";
  217. echo "</script>";
  218. }
  219. }
  220. //微信H5支付
  221. if($pay_method=='wxh5_pay'){
  222. $order = $this->_initOrder($initData);
  223. // 官方提供网址
  224. $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";
  225. //拆解为:[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
  226. $urlarr = parse_url($url);
  227. $time = time(); //时间戳
  228. $noncestr = $time;
  229. $appid = $this->payconfig['wxh5_appid'];//appID
  230. $mchid = $this->payconfig['wxh5_mchid'];//商户ID
  231. //秘钥序列号 可在这个网址中查询 https://myssl.com/cert_decode.html
  232. $xlid = $this->payconfig['wxh5_serialnumber'];
  233. $data = [];
  234. $data['appid'] = $appid;
  235. $data['mchid'] = $mchid;
  236. $data['description'] = $order->remark;//商品描述
  237. $data['out_trade_no'] = $order_sn;//订单编号,订单号在微信支付里是唯一的
  238. $data['notify_url'] = $this->payconfig['wxh5_notify_url'];//需根据自己的情况修改回调接口,也可以为空
  239. $data['amount']['total'] = max($total_price, 0.01)*100;//金额 单位 分
  240. $data['scene_info']['payer_client_ip'] = $_SERVER['REMOTE_ADDR'];//场景
  241. $data['scene_info']['h5_info']['type'] = "Wap";//场景
  242. $data = json_encode($data); //变为json格式
  243. // echo "<pre>";
  244. // print_r($data);
  245. // echo "<pre>";die;
  246. //签名,包含了$data数据、微信指定地址、随机数和时间
  247. $key = $this->getSign($data,$urlarr['path'],$noncestr,$time);
  248. //头部信息
  249. $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"',$mchid,$xlid,$noncestr,$time,$key);
  250. // echo $token;die;
  251. $header = array(
  252. 'Content-Type:'.'application/json; charset=UTF-8',
  253. 'Accept:application/json',
  254. 'User-Agent:*/*',
  255. 'Authorization: WECHATPAY2-SHA256-RSA2048 '.$token
  256. );
  257. //向微信接口地址提交json格式的$data和header的头部信息,得到返回值
  258. $ret = $this->curl_post_https($url,$data,$header);
  259. //如果是个code_url网址,则说明成功了。在浏览器里打开该地址测试是否能付钱。
  260. // echo $ret;
  261. $resInfo = json_decode($ret, true);
  262. // var_dump($resInfo['h5_url']);die;
  263. // header("Location: ".$resInfo['h5_url']);
  264. echo "<script>location.href='".$resInfo['h5_url']."'</script>";
  265. exit;
  266. }
  267. //虎皮椒
  268. if($pay_method=='hpwx_pay'||$pay_method=='hpali_pay')
  269. {
  270. require_once(Yii::getAlias('@payerdrivers').'/xunhupay/api.php');
  271. $order = $this->_initOrder($initData);
  272. if($pay_method=='hpwx_pay')
  273. {
  274. $appid = Yii::$app->params['pay']['hpwx_appid'];
  275. $appsecret = Yii::$app->params['pay']['hpwx_appsecret'];
  276. $my_plugin_id = Yii::$app->params['pay']['hpwx_pluginid'];
  277. $subject = $order->remark;
  278. $notify_url = Yii::$app->params['pay']['hpwx_notify_url'];
  279. //$return_url = Yii::$app->params['pay']['hpwx_return_url'];
  280. }
  281. else if($pay_method=='hpali_pay')
  282. {
  283. $appid = Yii::$app->params['pay']['hpali_appid'];
  284. $appsecret = Yii::$app->params['pay']['hpali_appsecret'];
  285. $my_plugin_id = Yii::$app->params['pay']['hpali_pluginid'];
  286. $subject = $order->remark;
  287. $notify_url = Yii::$app->params['pay']['hpali_notify_url'];
  288. //$return_url = Yii::$app->params['pay']['hpali_return_url'];
  289. }
  290. $data=array(
  291. 'version' => '1.1',//固定值,api 版本,目前暂时是1.1
  292. 'lang' => 'zh-cn', //必须的,zh-cn或en-us 或其他,根据语言显示页面
  293. 'plugins' => $my_plugin_id,//必须的,根据自己需要自定义插件ID,唯一的,匹配[a-zA-Z\d\-_]+
  294. 'appid' => $appid, //必须的,APPID
  295. 'trade_order_id'=> $order_sn, //必须的,网站订单ID,唯一的,匹配[a-zA-Z\d\-_]+
  296. 'payment' => $pay_method=='hpwx_pay'?'wechat':'alipay',//必须的,支付接口标识:wechat(微信接口)|alipay(支付宝接口)
  297. 'total_fee' => max(0,$total_price),//人民币,单位精确到分(测试账户只支持0.1元内付款)
  298. 'title' => $subject, //必须的,订单标题,长度32或以内
  299. 'time' => TIMESTAMP,//必须的,当前时间戳,根据此字段判断订单请求是否已超时,防止第三方攻击服务器
  300. 'notify_url'=> $notify_url, //必须的,支付成功异步回调接口
  301. 'return_url'=> $return_url,//必须的,支付成功后的跳转地址
  302. 'callback_url'=> APP_URL,//必须的,支付发起地址(未支付或支付失败,系统会会跳到这个地址让用户修改支付信息)
  303. 'modal'=>null, //可空,支付模式 ,可选值( full:返回完整的支付网页; qrcode:返回二维码; 空值:返回支付跳转链接)
  304. 'nonce_str' => str_shuffle(TIMESTAMP)//必须的,随机字符串,作用:1.避免服务器缓存,2.防止安全密钥被猜测出来
  305. );
  306. $hashkey = $appsecret;
  307. $data['hash'] = \XH_Payment_Api::generate_xh_hash($data,$hashkey);
  308. $url = 'https://api.xunhupay.com/payment/do.html';
  309. try {
  310. $response = \XH_Payment_Api::http_post($url, json_encode($data));
  311. $result = $response?json_decode($response,true):null;
  312. if(!$result){
  313. echo_json([
  314. 'error' => 1,
  315. 'msg' => 'Internal server error',
  316. 'code'=>500
  317. ]);
  318. }
  319. $hash = \XH_Payment_Api::generate_xh_hash($result,$hashkey);
  320. if(!isset( $result['hash'])|| $hash!=$result['hash']){
  321. echo_json([
  322. 'error' => 1,
  323. 'msg' => 'Invalid sign!',
  324. 'code'=>500
  325. ]);
  326. }
  327. if($result['errcode']!=0){
  328. echo_json([
  329. 'error' => 1,
  330. 'msg' => $result['errmsg'],
  331. 'code'=>$result['errcode']
  332. ]);
  333. }
  334. $pay_url = $result['url'];
  335. header("Location: $pay_url");
  336. exit;
  337. } catch (\Exception $e) {
  338. $result = [
  339. 'error' => 1,
  340. 'msg' => $e->getMessage(),
  341. 'data' => [],
  342. 'code'=>200
  343. ];
  344. echo_json($result);
  345. }
  346. }
  347. }
  348. //生成二维码付款图片
  349. public function actionCodeimg()
  350. {
  351. $initData = $_POST;
  352. extract($initData);
  353. //微信支付
  354. if($paymethod=='weixin_pay')
  355. {
  356. if($this->_checkOrder($order_sn,$paymethod))
  357. {
  358. $order_sn = getUniOrderNo();
  359. $result = [
  360. 'error' => 2,
  361. 'msg' => '需要生成新订单',
  362. 'data' => ['order_sn'=>$order_sn],
  363. 'code'=>200
  364. ];
  365. echo_json($result);
  366. }
  367. $order = $this->_initOrder($initData);
  368. try {
  369. $pay_money = max($total_price, 0.01);
  370. $resp = $this->wechatPay->chain('v3/pay/transactions/native')
  371. ->post(['json' => [
  372. 'mchid' => $this->payconfig['weixin_mchid'],
  373. 'out_trade_no' => $order_sn,
  374. 'appid' => $this->payconfig['weixin_appid'],
  375. 'description' => $order->remark,
  376. 'notify_url' => $this->payconfig['weixin_notify_url'],
  377. 'amount' => [
  378. 'total' => $pay_money*100,
  379. 'currency' => 'CNY'
  380. ],
  381. ]]);
  382. if($resp->getStatusCode()==200)
  383. {
  384. $respBody = json_decode($resp->getBody(),true);
  385. $code_url = APP_URL.'ajax/qrcode/?url='.$respBody['code_url'];
  386. $result = [
  387. 'error' => 0,
  388. 'msg' => '操作成功',
  389. 'data' => ['code_url'=>$code_url,'order_sn'=>$order_sn],
  390. 'code'=>200
  391. ];
  392. echo_json($result);
  393. }
  394. } catch (\Exception $e) {
  395. $result = [
  396. 'error' => 1,
  397. 'msg' => $e->getMessage(),
  398. 'data' => [],
  399. 'code'=>200
  400. ];
  401. echo_json($result);
  402. // 进行错误处理
  403. /*echo $e->getMessage(), PHP_EOL;
  404. if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
  405. $r = $e->getResponse();
  406. echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
  407. echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
  408. }
  409. echo $e->getTraceAsString(), PHP_EOL;*/
  410. }
  411. }
  412. //支付宝PC
  413. if($paymethod=='apd_pay')
  414. {
  415. require_once(Yii::getAlias('@payerdrivers').'/alipaypage/pagepay/service/AlipayTradeService.php');
  416. require_once(Yii::getAlias('@payerdrivers').'/alipaypage/pagepay/buildermodel/AlipayTradePagePayContentBuilder.php');
  417. if($this->_checkOrder($order_sn,$paymethod))
  418. {
  419. $order_sn = getUniOrderNo();
  420. $result = [
  421. 'error' => 2,
  422. 'msg' => '需要生成新订单',
  423. 'data' => ['order_sn'=>$order_sn],
  424. 'code'=>200
  425. ];
  426. echo_json($result);
  427. }
  428. $order = $this->_initOrder($initData);
  429. $config = array (
  430. //应用ID,您的APPID。
  431. 'app_id' => $this->payconfig['apd_appid'],
  432. //商户私钥
  433. 'merchant_private_key' => $this->payconfig['apd_merchant_private_key'],
  434. //异步通知地址
  435. 'notify_url' => $this->payconfig['apd_notify_url'],
  436. //同步跳转
  437. 'return_url' => $this->payconfig['apd_return_url'],
  438. //编码格式
  439. 'charset' => "UTF-8",
  440. //签名方式
  441. 'sign_type'=>"RSA2",
  442. //支付宝网关
  443. 'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
  444. //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
  445. 'alipay_public_key' => $this->payconfig['apd_alipay_public_key'],
  446. //日志路径
  447. 'log_path' => $this->logdir.get_date(TIMESTAMP, "Y-m").'.txt',
  448. );
  449. //商户订单号,商户网站订单系统中唯一订单号,必填
  450. $out_trade_no = trim($order_sn);
  451. //订单名称,必填
  452. $subject = $order->remark;
  453. //付款金额,必填
  454. $total_amount = trim($total_price);
  455. //商品描述,可空
  456. $body = '';
  457. //构造参数
  458. $payRequestBuilder = new \AlipayTradePagePayContentBuilder();
  459. $payRequestBuilder->setBody($body);
  460. $payRequestBuilder->setSubject($subject);
  461. $payRequestBuilder->setTotalAmount($total_amount);
  462. $payRequestBuilder->setOutTradeNo($out_trade_no);
  463. $payRequestBuilder->setQrPayMode(4);
  464. $payRequestBuilder->setQrPayWidth(110);
  465. $aop = new \AlipayTradeService($config);
  466. $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
  467. //输出表单
  468. $result = [
  469. 'error' => 0,
  470. 'msg' => '操作成功',
  471. 'data' => ['code_url'=>APP_URL.'pay/alicode/?response='.urlencode($response),'order_sn'=>$order_sn],
  472. 'code'=>200
  473. ];
  474. echo_json($result);
  475. }
  476. //虎皮椒
  477. if($paymethod=='hpwx_pay'||$paymethod=='hpali_pay')
  478. {
  479. require_once(Yii::getAlias('@payerdrivers').'/xunhupay/api.php');
  480. if($this->_checkOrder($order_sn,$paymethod))
  481. {
  482. $order_sn = getUniOrderNo();
  483. $result = [
  484. 'error' => 2,
  485. 'msg' => '需要生成新订单',
  486. 'data' => ['order_sn'=>$order_sn],
  487. 'code'=>200
  488. ];
  489. echo_json($result);
  490. }
  491. $order = $this->_initOrder($initData);
  492. if($paymethod=='hpwx_pay')
  493. {
  494. $appid = Yii::$app->params['pay']['hpwx_appid'];
  495. $appsecret = Yii::$app->params['pay']['hpwx_appsecret'];
  496. $my_plugin_id = Yii::$app->params['pay']['hpwx_pluginid'];
  497. $subject = $order->remark;
  498. $notify_url = Yii::$app->params['pay']['hpwx_notify_url'];
  499. $return_url = Yii::$app->params['pay']['hpwx_return_url'];
  500. }
  501. else if($paymethod=='hpali_pay')
  502. {
  503. $appid = Yii::$app->params['pay']['hpali_appid'];
  504. $appsecret = Yii::$app->params['pay']['hpali_appsecret'];
  505. $my_plugin_id = Yii::$app->params['pay']['hpali_pluginid'];
  506. $subject = $order->remark;
  507. $notify_url = Yii::$app->params['pay']['hpali_notify_url'];
  508. $return_url = Yii::$app->params['pay']['hpali_return_url'];
  509. }
  510. $data=array(
  511. 'version' => '1.1',//固定值,api 版本,目前暂时是1.1
  512. 'lang' => 'zh-cn', //必须的,zh-cn或en-us 或其他,根据语言显示页面
  513. 'plugins' => $my_plugin_id,//必须的,根据自己需要自定义插件ID,唯一的,匹配[a-zA-Z\d\-_]+
  514. 'appid' => $appid, //必须的,APPID
  515. 'trade_order_id'=> $order_sn, //必须的,网站订单ID,唯一的,匹配[a-zA-Z\d\-_]+
  516. 'payment' => $paymethod=='hpwx_pay'?'wechat':'alipay',//必须的,支付接口标识:wechat(微信接口)|alipay(支付宝接口)
  517. 'total_fee' => max(0,trim($total_price)),//人民币,单位精确到分(测试账户只支持0.1元内付款)
  518. 'title' => $subject, //必须的,订单标题,长度32或以内
  519. 'time' => TIMESTAMP,//必须的,当前时间戳,根据此字段判断订单请求是否已超时,防止第三方攻击服务器
  520. 'notify_url'=> $notify_url, //必须的,支付成功异步回调接口
  521. 'return_url'=> $return_url,//必须的,支付成功后的跳转地址
  522. 'callback_url'=> APP_URL,//必须的,支付发起地址(未支付或支付失败,系统会会跳到这个地址让用户修改支付信息)
  523. 'modal'=>null, //可空,支付模式 ,可选值( full:返回完整的支付网页; qrcode:返回二维码; 空值:返回支付跳转链接)
  524. 'nonce_str' => str_shuffle(TIMESTAMP)//必须的,随机字符串,作用:1.避免服务器缓存,2.防止安全密钥被猜测出来
  525. );
  526. $hashkey = $appsecret;
  527. $data['hash'] = \XH_Payment_Api::generate_xh_hash($data,$hashkey);
  528. $url = 'https://api.xunhupay.com/payment/do.html';
  529. try {
  530. $response = \XH_Payment_Api::http_post($url, json_encode($data));
  531. $result = $response?json_decode($response,true):null;
  532. if(!$result){
  533. echo_json([
  534. 'error' => 1,
  535. 'msg' => 'Internal server error',
  536. 'code'=>500
  537. ]);
  538. }
  539. $hash = \XH_Payment_Api::generate_xh_hash($result,$hashkey);
  540. if(!isset( $result['hash'])|| $hash!=$result['hash']){
  541. echo_json([
  542. 'error' => 1,
  543. 'msg' => 'Invalid sign!',
  544. 'code'=>500
  545. ]);
  546. }
  547. if($result['errcode']!=0){
  548. echo_json([
  549. 'error' => 1,
  550. 'msg' => $result['errmsg'],
  551. 'code'=>$result['errcode']
  552. ]);
  553. }
  554. if($paymethod=='hpwx_pay'){
  555. echo_json( [
  556. 'error' => 0,
  557. 'msg' => '操作成功',
  558. 'data' => ['code_url'=>$result['url_qrcode'],'order_sn'=>$order_sn],
  559. 'code'=>200
  560. ]);
  561. }else{
  562. echo_json([
  563. 'error' => 0,
  564. 'msg' => '操作成功',
  565. 'data' => ['code_url'=>APP_URL.'pay/paycode/?response='.urlencode($result['url_qrcode']),'order_sn'=>$order_sn],
  566. 'code'=>200
  567. ]);
  568. }
  569. } catch (\Exception $e) {
  570. $result = [
  571. 'error' => 1,
  572. 'msg' => $e->getMessage(),
  573. 'data' => [],
  574. 'code'=>200
  575. ];
  576. echo_json($result);
  577. }
  578. }
  579. }
  580. //生成支付宝二维码
  581. public function actionAlicode()
  582. {
  583. echo $_GET['response'];
  584. }
  585. //对支付二维码做缩略图
  586. public function actionPaycode()
  587. {
  588. $fileHash = md5($_GET['response']);
  589. $dstrootdir = THUMB_PATH.'paycode'.DIRECTORY_SEPARATOR;
  590. dir_create($dstrootdir);
  591. $resize = new \app\common\components\ResizeImage($_GET['response'], 110, 110,$fileHash, 0,0,$dstrootdir);
  592. $dstimg = $resize->dstimg;
  593. ob_clean();
  594. header('Content-type: image/jpeg');
  595. echo file_get_contents($dstimg);
  596. exit;
  597. }
  598. //微信支付回调
  599. public function actionWeixincallback(){
  600. $headers = $this->_getAllHeader();
  601. //$this->payLog(var_export($headers,true));
  602. $inWechatpaySignature = $headers['wechatpay-signature'];
  603. $inWechatpayTimestamp = $headers['wechatpay-timestamp'];
  604. $inWechatpaySerial = $headers['wechatpay-serial'];
  605. $inWechatpayNonce = $headers['wechatpay-nonce'];
  606. $inBody = file_get_contents('php://input');
  607. $apiv3Key = $this->payconfig['weixin_v3secret'];// 在商户平台上设置的APIv3密钥
  608. $platformPublicKeyInstance = Rsa::from('file://'.$this->payconfig['weixin_cert'], Rsa::KEY_TYPE_PUBLIC);
  609. // 检查通知时间偏移量,允许5分钟之内的偏移
  610. $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
  611. $verifiedStatus = Rsa::verify(
  612. // 构造验签名串
  613. Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
  614. $inWechatpaySignature,
  615. $platformPublicKeyInstance
  616. );
  617. if ($timeOffsetStatus && $verifiedStatus) {
  618. // 转换通知的JSON文本消息为PHP Array数组
  619. $inBodyArray = (array)json_decode($inBody, true);
  620. // 使用PHP7的数据解构语法,从Array中解构并赋值变量
  621. ['resource' => [
  622. 'ciphertext' => $ciphertext,
  623. 'nonce' => $nonce,
  624. 'associated_data' => $aad
  625. ]] = $inBodyArray;
  626. // 加密文本消息解密
  627. $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
  628. // 把解密后的文本转换为PHP Array数组
  629. $inBodyResourceArray = (array)json_decode($inBodyResource, true);
  630. //$this->payLog(var_export($inBodyResourceArray,true));
  631. if ($inBodyResourceArray['trade_state'] == 'SUCCESS') {
  632. // 这里写业务逻辑
  633. if($this->_processOrder($inBodyResourceArray['out_trade_no'],($inBodyResourceArray['amount']['payer_total']/100),1,
  634. $inBodyResourceArray['payer']['openid']))
  635. {
  636. $result = ['code'=>'SUCCESS','message'=>'成功',];
  637. echo_json($result);
  638. }
  639. }
  640. }
  641. }
  642. //支付宝PC扫码支付回调
  643. public function actionAlipaydirectnotify()
  644. {
  645. require_once(Yii::getAlias('@payerdrivers').'/alipaypage/pagepay/service/AlipayTradeService.php');
  646. $config = array (
  647. //应用ID,您的APPID。
  648. 'app_id' => $this->payconfig['apd_appid'],
  649. //商户私钥
  650. 'merchant_private_key' => $this->payconfig['apd_merchant_private_key'],
  651. //异步通知地址
  652. 'notify_url' => $this->payconfig['apd_notify_url'],
  653. //同步跳转
  654. 'return_url' => $this->payconfig['apd_return_url'],
  655. //编码格式
  656. 'charset' => "UTF-8",
  657. //签名方式
  658. 'sign_type'=>"RSA2",
  659. //支付宝网关
  660. 'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
  661. //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
  662. 'alipay_public_key' => $this->payconfig['apd_alipay_public_key'],
  663. //日志路径
  664. 'log_path' => $this->logdir.get_date(TIMESTAMP, "Y-m").'.txt',
  665. );
  666. $arr=$_POST;
  667. $alipaySevice = new \AlipayTradeService($config);
  668. $alipaySevice->writeLog(var_export($_POST,true));
  669. $result = $alipaySevice->check($arr);
  670. /* 实际验证过程建议商户添加以下校验。
  671. 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
  672. 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
  673. 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
  674. 4、验证app_id是否为该商户本身。
  675. */
  676. if($result) {//验证成功
  677. //请在这里加上商户的业务逻辑程序代
  678. //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
  679. //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
  680. //商户订单号
  681. $out_trade_no = $_POST['out_trade_no'];
  682. //支付宝交易号
  683. $trade_no = $_POST['trade_no'];
  684. //交易状态
  685. $trade_status = $_POST['trade_status'];
  686. $total_amount = $_POST['total_amount'];
  687. if($_POST['trade_status'] == 'TRADE_FINISHED') {
  688. $this->_processOrder($out_trade_no,$total_amount,3);
  689. }
  690. else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
  691. $this->_processOrder($out_trade_no,$total_amount,3);
  692. }
  693. //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
  694. echo "success"; //请不要修改或删除
  695. }else {
  696. //验证失败
  697. echo "fail";
  698. }
  699. }
  700. //支付成功之后的虎皮椒回调处理(微信)
  701. public function actionHpwxnotify()
  702. {
  703. try
  704. {
  705. require_once(Yii::getAlias('@payerdrivers').'/xunhupay/api.php');
  706. $appid = Yii::$app->params['pay']['hpwx_appid'];
  707. $appsecret = Yii::$app->params['pay']['hpwx_appsecret'];
  708. $my_plugin_id = Yii::$app->params['pay']['hpwx_pluginid'];
  709. $data = $_POST;
  710. foreach ($data as $k=>$v){
  711. $data[$k] = stripslashes($v);
  712. }
  713. if(!isset($data['hash'])||!isset($data['trade_order_id'])){
  714. echo 'failed';exit;
  715. }
  716. //自定义插件ID,请与支付请求时一致
  717. if(isset($data['plugins'])&&$data['plugins']!=$my_plugin_id){
  718. echo 'failed';exit;
  719. }
  720. //APP SECRET
  721. $appkey =$appsecret;
  722. $hash =\XH_Payment_Api::generate_xh_hash($data,$appkey);
  723. if($data['hash']!=$hash){
  724. //签名验证失败
  725. echo 'failed';exit;
  726. }
  727. //商户订单ID
  728. $trade_order_id =$data['trade_order_id'];
  729. $total_fee = $data['total_fee'];
  730. if($data['status']=='OD'){
  731. $this->_processOrder($trade_order_id,$total_fee,88);
  732. echo 'success';
  733. exit;
  734. }else{
  735. echo 'failed';exit;
  736. }
  737. }
  738. catch(\Exception $e)
  739. {
  740. $this->payLog($e->getMessage());exit;
  741. }
  742. }
  743. //支付成功之后的虎皮椒回调处理(支付宝)
  744. public function actionHpalinotify()
  745. {
  746. try
  747. {
  748. require_once(Yii::getAlias('@payerdrivers').'/xunhupay/api.php');
  749. $appid = Yii::$app->params['pay']['hpali_appid'];
  750. $appsecret = Yii::$app->params['pay']['hpali_appsecret'];
  751. $my_plugin_id = Yii::$app->params['pay']['hpali_pluginid'];
  752. $data = $_POST;
  753. foreach ($data as $k=>$v){
  754. $data[$k] = stripslashes($v);
  755. }
  756. if(!isset($data['hash'])||!isset($data['trade_order_id'])){
  757. echo 'failed';exit;
  758. }
  759. //自定义插件ID,请与支付请求时一致
  760. if(isset($data['plugins'])&&$data['plugins']!=$my_plugin_id){
  761. echo 'failed';exit;
  762. }
  763. //APP SECRET
  764. $appkey =$appsecret;
  765. $hash =\XH_Payment_Api::generate_xh_hash($data,$appkey);
  766. if($data['hash']!=$hash){
  767. //签名验证失败
  768. echo 'failed';exit;
  769. }
  770. //商户订单ID
  771. $trade_order_id =$data['trade_order_id'];
  772. $total_fee = $data['total_fee'];
  773. if($data['status']=='OD'){
  774. $this->_processOrder($trade_order_id,$total_fee,99);
  775. echo 'success';
  776. exit;
  777. }else{
  778. echo 'failed';exit;
  779. }
  780. }
  781. catch(\Exception $e)
  782. {
  783. $this->payLog($e->getMessage());exit;
  784. }
  785. }
  786. //手机端支付宝回调
  787. public function actionAlipaywapnotify()
  788. {
  789. require_once(Yii::getAlias('@payerdrivers').'/alipaywap/wappay/service/AlipayTradeService.php');
  790. $config = array (
  791. //应用ID,您的APPID。
  792. 'app_id' => $this->payconfig['apw_appid'],
  793. //商户私钥,您的原始格式RSA私钥
  794. 'merchant_private_key' => $this->payconfig['apw_merchant_private_key'],
  795. //异步通知地址
  796. 'notify_url' => $this->payconfig['apw_notify_url'],
  797. //同步跳转
  798. 'return_url' => $this->payconfig['apw_return_url'],
  799. //编码格式
  800. 'charset' => "UTF-8",
  801. //签名方式
  802. 'sign_type'=>"RSA2",
  803. //支付宝网关
  804. 'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
  805. //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
  806. 'alipay_public_key' => $this->payconfig['apw_alipay_public_key'],
  807. //日志路径
  808. 'log_path' => $this->logdir.get_date(TIMESTAMP, "Y-m").'.txt',
  809. );
  810. $arr=$_POST;
  811. $alipaySevice = new \AlipayTradeService($config);
  812. $alipaySevice->writeLog(var_export($_POST,true));
  813. $this->payLog(var_export($_POST,true));
  814. $result = $alipaySevice->check($arr);
  815. /* 实际验证过程建议商户添加以下校验。
  816. 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
  817. 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
  818. 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
  819. 4、验证app_id是否为该商户本身。
  820. */
  821. if($result) {//验证成功
  822. //请在这里加上商户的业务逻辑程序代
  823. //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
  824. //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
  825. //商户订单号
  826. $out_trade_no = $_POST['out_trade_no'];
  827. //支付宝交易号
  828. $trade_no = $_POST['trade_no'];
  829. //交易状态
  830. $trade_status = $_POST['trade_status'];
  831. $total_amount = $_POST['total_amount'];
  832. if($_POST['trade_status'] == 'TRADE_FINISHED') {
  833. $this->_processOrder($out_trade_no,$total_amount,3);
  834. }
  835. else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
  836. $this->_processOrder($out_trade_no,$total_amount,3);
  837. }
  838. //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
  839. echo "success"; //请不要修改或删除
  840. }else {
  841. //验证失败
  842. echo "fail";
  843. }
  844. }
  845. //检测订单是否存在
  846. private function _checkOrder($order_sn,$pay_method)
  847. {
  848. $exist = ShoppingPaycode::find()->where("order_sn='".$order_sn."' and pay_method='".$pay_method."'")->exists();
  849. if($exist)
  850. {
  851. return true;
  852. }
  853. else
  854. {
  855. $paycode = new ShoppingPaycode();
  856. $paycode->order_sn = $order_sn;
  857. $paycode->pay_method = $pay_method;
  858. $paycode->create_time = TIMESTAMP;
  859. $paycode->save();
  860. return false;
  861. }
  862. }
  863. //初始化订单
  864. private function _initOrder($initData)
  865. {
  866. extract($initData);
  867. $order = ShoppingOrder::find()->where("order_sn='".$order_sn."'")->one();
  868. if($order)
  869. {
  870. return $order;
  871. }
  872. else
  873. {
  874. //充值金币
  875. if($act=='coinrecharge'){
  876. $pay_credit = $act.'_'.$coin_num;
  877. $order_type = 2;
  878. $remark = '充值'.Yii::$app->params['coin']['coin_name'];
  879. }
  880. //开通VIP
  881. if($act=='buyvip'){
  882. $userVipType = UserVipType::findOne($vip_type);
  883. $pay_credit = $act.'_'.$vip_type;
  884. $order_type = 3;
  885. $remark = '开通VIP-'.$userVipType->title;
  886. }
  887. //购买文档
  888. if($act=='buydoc'){
  889. $pay_credit = $act.'_'.$id;
  890. $order_type = 1;
  891. $remark = '购买文档';
  892. }
  893. //百度搜索词
  894. $baidukw = \app\common\helpers\Cookie::getCookie(Yii::$app->params['baidukwName']);
  895. $order = new ShoppingOrder();
  896. $order->user_id = intval($this->userInfo['user_id']);
  897. $order->order_sn = $order_sn;
  898. $order->pay_credit = $pay_credit;
  899. $order->total_price = $total_price;
  900. $order->discount_price = $discount_price;
  901. $order->remark = $remark;
  902. $order->order_type = $order_type;
  903. $order->status = 0;
  904. $order->ad_words = $baidukw?urldecode($baidukw):'';
  905. $order->request_from = REQUEST_FROM;
  906. $order->create_time = TIMESTAMP;
  907. $order->save();
  908. return $order;
  909. }
  910. }
  911. // 获取header头的方法
  912. private function _getAllHeader()
  913. {
  914. // 忽略获取的header数据。这个函数后面会用到。主要是起过滤作用
  915. $ignore = array('host','accept','content-length','content-type','connection','accept-encoding');
  916. $headers = array(); //这里大家有兴趣的话,可以打印一下。会出来很多的header头信息。咱们想要的部分,都是‘http_'开头的。所以下面会进行过滤输出。
  917. foreach($_SERVER as $key=>$value){
  918. if(substr($key, 0, 5)==='HTTP_'){ //这里取到的都是'http_'开头的数据。
  919. //前去开头的前5位
  920. $key = substr($key, 5); //把$key中的'_'下划线都替换为空字符串
  921. $key = str_replace('_', ' ', $key); //再把$key中的空字符串替换成‘-’
  922. $key = str_replace(' ', '-', $key); //把$key中的所有字符转换为小写
  923. $key = strtolower($key); //这里主要是过滤上面写的$ignore数组中的数据
  924. if(!in_array($key, $ignore)){
  925. $headers[$key] = $value;
  926. }
  927. }
  928. }//输出获取到的header
  929. return $headers;
  930. }
  931. // 记录日志
  932. public function payLog($word) {
  933. $logFile = $this->logdir.get_date(TIMESTAMP, "Y-m").'.txt';
  934. $fp = fopen($logFile, "a");
  935. flock($fp, LOCK_EX) ;
  936. fwrite($fp, get_date(TIMESTAMP, "Y-m-d H:i:s").' | '.$word."\r\n");
  937. flock($fp, LOCK_UN);
  938. fclose($fp);
  939. }
  940. //支付成功后处理业务逻辑
  941. public function _processOrder($order_sn,$total_price,$pay_method,$openid='')
  942. {
  943. $order = ShoppingOrder::find()->where("order_sn='".$order_sn."'")->one();
  944. if($order&&$order->status==0)
  945. {
  946. $order->status = $order->is_virtual==1?9:1;
  947. $order->pay_time = strval(TIMESTAMP);
  948. $order->pay_method = $pay_method;
  949. if($order->save())
  950. {
  951. //充值金币
  952. if(strpos($order->pay_credit,'coinrecharge')!==false)
  953. {
  954. $coin_num = str_replace('coinrecharge_','',$order->pay_credit);
  955. Wallet::coinChange($order->user_id,$coin_num,$order->remark,1);
  956. }
  957. //开通VIP
  958. if(strpos($order->pay_credit,'buyvip')!==false)
  959. {
  960. $vip_type = str_replace('buyvip_','',$order->pay_credit);
  961. $userVipType = UserVipType::findOne($vip_type);
  962. $userVipOrder = UserVipOrder::findOne($order->order_id);
  963. //付款金额校验
  964. if($userVipType&&$order->total_price==$userVipType->price)
  965. {
  966. //判断是否是续费
  967. $vipInfo = UserVipOrder::find()->where("user_id='".$order->user_id."' and vip_type=$vip_type and status=1 and (expire_time>=".TIMESTAMP." or expire_time=0) and order_id!='".$order->order_id."'")->orderBy(['order_id'=>SORT_DESC])->limit(1)->one();
  968. if($vipInfo)
  969. {
  970. $startTime = $vipInfo->expire_time;
  971. }
  972. else
  973. {
  974. $startTime = TIMESTAMP;
  975. }
  976. if(empty($userVipOrder))
  977. {
  978. $userVipOrder = new UserVipOrder();
  979. }
  980. $userVipOrder->order_id = $order->order_id;
  981. $userVipOrder->user_id = $order->user_id;
  982. $userVipOrder->vip_type = $vip_type;
  983. $userVipOrder->money = $total_price;
  984. $userVipOrder->days = $userVipType->days;
  985. $userVipOrder->settings = $userVipType->settings;
  986. $userVipOrder->expire_time = $userVipType->forever==1?0:$startTime+$userVipType->days*24*3600;
  987. $userVipOrder->create_time = TIMESTAMP;
  988. $userVipOrder->status = 1;
  989. if($userVipOrder->save())
  990. {
  991. $vipSettings = string2array($userVipType->settings);
  992. //如果有赠送金币
  993. if(intval($vipSettings['coin_num'])>0)
  994. {
  995. Wallet::coinChange($order->user_id,$vipSettings['coin_num'],'开通会员赠送金币',1);
  996. }
  997. //处理分销
  998. Wallet::vipCommission($order->user_id,$userVipOrder);
  999. }
  1000. }
  1001. }
  1002. //购买文档
  1003. if(strpos($order->pay_credit,'buydoc')!==false)
  1004. {
  1005. $id = str_replace('buydoc_','',$order->pay_credit);
  1006. $this->addDownCode($id,$order);
  1007. }
  1008. //百度竞价跟踪
  1009. $bd_vid = \app\common\helpers\Cookie::getCookie('bd_vid');
  1010. if(!empty($bd_vid))
  1011. {
  1012. $higherconfigResult = \app\modules\admin\models\Config::find()->where("name='higherconfig'")->one();
  1013. $higherconfig = string2array($higherconfigResult->value);
  1014. $token = $higherconfig['cpc_token'];
  1015. if(!empty($token))
  1016. {
  1017. $cv = array(
  1018. 'logidUrl' => APP_URL.'?bd_vid='.$bd_vid, // 您的落地页url
  1019. 'newType' => 10 // 转化类型请按实际情况填写
  1020. );
  1021. $conversionTypes = array($cv);
  1022. $baiducpc = new \app\common\components\BaiduCpc();
  1023. $baiducpc->sendConvertData($token, $conversionTypes);
  1024. }
  1025. }
  1026. }
  1027. return true;
  1028. }
  1029. else
  1030. {
  1031. return false;
  1032. }
  1033. }
  1034. //获取订单状态
  1035. public function actionOrderstatus()
  1036. {
  1037. $order_sn = Yii::$app->request->get('order_sn');
  1038. if($order_sn)
  1039. {
  1040. $order = ShoppingOrder::find()->where("order_sn='".$order_sn."'")->one();
  1041. if(!empty($order))
  1042. {
  1043. if($order->status==1||$order->status==9)
  1044. {
  1045. $data = [];
  1046. //购买文档
  1047. if(strpos($order->pay_credit,'buydoc')!==false)
  1048. {
  1049. $downCode = DocDowncode::find()->where("openid='".$order_sn."'")->one();
  1050. $data['downurl'] = SiteUrl::docDownByCode($downCode->downcode,1);
  1051. $data['downcode'] = $downCode->downcode;
  1052. }
  1053. $result = [
  1054. 'error' => 0,
  1055. 'msg' => '支付成功',
  1056. 'data' => $data,
  1057. 'code'=>200
  1058. ];
  1059. echo_json($result);
  1060. }
  1061. }
  1062. else
  1063. {
  1064. $result = [
  1065. 'error' => 1,
  1066. 'msg' => '订单不存在',
  1067. 'code'=>200
  1068. ];
  1069. echo_json($result);
  1070. }
  1071. }
  1072. else
  1073. {
  1074. $result = [
  1075. 'error' => 1,
  1076. 'msg' => '缺少参数',
  1077. 'code'=>200
  1078. ];
  1079. echo_json($result);
  1080. }
  1081. }
  1082. //购买文档
  1083. public function addDownCode($doc_id,$order)
  1084. {
  1085. try
  1086. {
  1087. $doc = DocReal::findOne($doc_id);
  1088. $downCode = new \app\modules\doc\models\DocDowncode();
  1089. $downCode->doc_id = $doc_id;
  1090. $downCode->user_id = intval($order->user_id);
  1091. $downCode->openid = $order->order_sn;
  1092. $downCode->downcode = strval(getDowncode($doc->id));
  1093. $downCode->doc_user_id = $doc->user_id;
  1094. $downCode->type = 2;
  1095. $downCode->create_time = TIMESTAMP;
  1096. $downCode->save();
  1097. //判断用户VIP权限情况
  1098. if($order->user_id) $vipSettings = User::findOne($order->user_id)->vipSettings();
  1099. //如果是机构推广文档,标记推广文档订单
  1100. if($doc->is_ad)
  1101. {
  1102. $store = \app\modules\shopping\models\ShoppingStore::find()->where("user_id=".$doc->user_id)->one();
  1103. if($store)
  1104. {
  1105. $order->store_id = $store->store_id;
  1106. $order->save();
  1107. }
  1108. }
  1109. //将价格转成金币数量
  1110. $coin_num = $order->total_price*Yii::$app->params['coin']['coin_recharge_rate'];
  1111. //生成支付记录
  1112. $paylog = new \app\modules\doc\models\DocPaylog();
  1113. $paylog->user_id = intval($order->user_id);
  1114. $paylog->doc_user_id = intval($doc->user_id);
  1115. $paylog->doc_id = $doc->id;
  1116. $paylog->cat_id = $doc->cat_id;
  1117. $paylog->cat_ids = $doc->cat_ids;
  1118. $paylog->doc_type = $doc->doc_type;
  1119. $paylog->is_vip = ($doc->is_vip||$vipSettings['buy_doc_discount']<100)?1:0;
  1120. $paylog->coin_price = $doc->coin_price;
  1121. $paylog->coin_num = $coin_num;
  1122. $paylog->agent_id = intval($order->user->referer_id);
  1123. $paylog->agent_ids = strval($order->user->referer_ids);
  1124. $paylog->create_time = TIMESTAMP;
  1125. if($paylog->save())
  1126. {
  1127. $doc->updateCounters(['sales'=>1]);
  1128. $left_coin = $coin_num;
  1129. $point_num = intval($order->total_price*Yii::$app->params['point']['rmb_price_rate']);
  1130. //购买方
  1131. $logTitleBuy = '购买'.DocReal::typeOptions($doc->doc_type);
  1132. if($order->user_id)
  1133. {
  1134. Wallet::pointChange($order->user_id,$point_num,$logTitleBuy,1,'point',DocReal::shortTableName(),$doc->id);
  1135. //处理分销
  1136. $left_coin = Wallet::docCommission($order->user_id,$doc,$paylog,$left_coin);
  1137. }
  1138. //出售方
  1139. $logTitleSell = '出售'.DocReal::typeOptions($doc->doc_type);
  1140. if($left_coin>0&&$doc->user_id)
  1141. {
  1142. //金币变化
  1143. Wallet::coinChange($doc->user_id,$left_coin,$logTitleSell,1,'coin_income',DocReal::shortTableName(),$doc->id);
  1144. //消息通知
  1145. MessageOne::soldDoc($logTitleSell,$doc,$left_coin);
  1146. }
  1147. return true;
  1148. }
  1149. else
  1150. {
  1151. $this->payLog($paylog->returnFirstError());
  1152. }
  1153. }
  1154. catch(\Exception $e)
  1155. {
  1156. $this->payLog($e->getMessage());exit;
  1157. }
  1158. }
  1159. //初始化视图
  1160. public function initForm($pay_method)
  1161. {
  1162. $view = $pay_method;
  1163. $this->setView($view);
  1164. $this->setData(array("return_url"=>$this->return_url));
  1165. $this->getFormHtml();
  1166. }
  1167. //微信支付签名
  1168. public function getSign($data = [], $url, $randstr, $time)
  1169. {
  1170. $str = "POST" . "\n" . $url . "\n" . $time . "\n" . $randstr . "\n" . $data . "\n";
  1171. $key = file_get_contents($this->payconfig['weixin_apiclient_key']);//在商户平台下载的秘钥
  1172. $str = $this->getSha256WithRSA($str, $key);
  1173. return $str;
  1174. }
  1175. //调起支付的签名
  1176. public function getWechartSign($appid, $timeStamp, $noncestr, $prepay_id)
  1177. {
  1178. $str = $appid . "\n" . $timeStamp . "\n" . $noncestr . "\n" . $prepay_id . "\n";
  1179. $key = file_get_contents($this->payconfig['weixin_apiclient_key']);
  1180. $str = $this->getSha256WithRSA($str, $key);
  1181. return $str;
  1182. }
  1183. public function getSha256WithRSA($content, $privateKey)
  1184. {
  1185. $binary_signature = "";
  1186. $algo = "SHA256";
  1187. openssl_sign($content, $binary_signature, $privateKey, $algo);
  1188. $sign = base64_encode($binary_signature);
  1189. return $sign;
  1190. }
  1191. function curl_post_https($url,$data,$header){ // 模拟提交数据函数
  1192. $curl = curl_init(); // 启动一个CURL会话
  1193. curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
  1194. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
  1195. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在,如果出错则修改为0,默认为1
  1196. curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
  1197. curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
  1198. curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
  1199. curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
  1200. curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
  1201. curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
  1202. curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
  1203. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
  1204. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  1205. $tmpInfo = curl_exec($curl); // 执行操作
  1206. if (curl_errno($curl)) {
  1207. echo 'Errno'.curl_error($curl);//捕抓异常
  1208. }
  1209. curl_close($curl); // 关闭CURL会话
  1210. return $tmpInfo; // 返回数据,json格式
  1211. }
  1212. }