WechatConfigForm.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\admin\models;
  8. use app\models\WechatConfig;
  9. use EasyWeChat\Factory;
  10. use EasyWeChat\Kernel\Exceptions\HttpException;
  11. use yii\base\Model;
  12. use GuzzleHttp\Exception\RequestException;
  13. class WechatConfigForm extends Model
  14. {
  15. public $store_id;
  16. public $type;
  17. public $app_id;
  18. public $app_name;
  19. public $app_secret;
  20. public $pay_key;
  21. public $cert_pem;
  22. public $key_pem;
  23. public $cert_pem_url;
  24. public $key_pem_url;
  25. public $mch_id;
  26. public $auto_reply;
  27. public $token;
  28. public $aes_key;
  29. public $app;
  30. public $model;
  31. public $name;
  32. public $gh_wechat_app_id;
  33. public function rules()
  34. {
  35. return [
  36. [['app_id', 'app_secret', 'mch_id', 'pay_key', 'cert_pem', 'key_pem', 'token', 'app_name', 'auto_reply', 'name', 'gh_wechat_app_id', 'cert_pem_url', 'key_pem_url'],
  37. 'trim'],
  38. [['type'], 'integer'],
  39. [['app_id'], 'required'],
  40. [['aes_key'], 'safe'],
  41. ['app_secret', 'default', 'value'=> '0'],
  42. ];
  43. }
  44. /**
  45. * 存储配置
  46. */
  47. public function saveConfig() {
  48. if (!$this->validate()) {
  49. return [
  50. 'code' => 1,
  51. 'msg' => '参数错误'
  52. ];
  53. }
  54. // if (\Yii::$app->isSaas()) {
  55. // $this->model->app_id = $this->app_id;
  56. // $this->model->mch_id = $this->mch_id;
  57. // $this->model->store_id = $this->store_id;
  58. // $this->model->name = $this->name;
  59. // $this->model->gh_wechat_app_id = $this->gh_wechat_app_id;
  60. // if ($this->model->save()) {
  61. // return [
  62. // 'code' => 0,
  63. // 'msg' => '保存成功',
  64. // ];
  65. // }
  66. // return [
  67. // 'code' => 1,
  68. // 'msg' => json_encode($this->model->errors),
  69. // ];
  70. // }
  71. if (!is_dir(\Yii::$app->runtimePath . '/pem')) {
  72. mkdir(\Yii::$app->runtimePath . '/pem');
  73. file_put_contents(\Yii::$app->runtimePath . '/pem/index.html', '');
  74. }
  75. if (!empty($this->cert_pem_url)) {
  76. $this->cert_pem = file_get_contents(str_replace('https://' . \Yii::$app->request->hostName, \Yii::$app->basePath, $this->cert_pem_url));
  77. } else {
  78. if (!empty($this->cert_pem)) {
  79. $this->cert_pem_url = $this->handlePemFile($this->cert_pem);
  80. }
  81. }
  82. if (!empty($this->key_pem_url)) {
  83. $this->key_pem = file_get_contents(str_replace('https://' . \Yii::$app->request->hostName, \Yii::$app->basePath, $this->key_pem_url));
  84. } else {
  85. if (!empty($this->key_pem)) {
  86. $this->key_pem_url = $this->handlePemFile($this->key_pem);
  87. }
  88. }
  89. $config = [
  90. 'app_id' => $this->app_id,
  91. 'secret' => $this->app_secret,
  92. 'key' => $this->pay_key,
  93. 'mch_id' => $this->mch_id,
  94. 'cert_path' => self::handlePemFile($this->cert_pem, 1),
  95. 'key_path' => self::handlePemFile($this->key_pem, 1)
  96. ];
  97. // 验证appid appsecret 是否合法
  98. if ($this->app_secret) {
  99. try {
  100. if ($this->type == WechatConfig::TYPE_CONFIG_MINI) {
  101. $this->app = Factory::miniProgram($config);
  102. }
  103. if ($this->type == WechatConfig::TYPE_CONFIG_MP) {
  104. $this->app = Factory::officialAccount($config);
  105. }
  106. if ($this->type == WechatConfig::TYPE_CONFIG_APP) {
  107. \Yii::error($config);
  108. $this->app = Factory::miniProgram($config);
  109. }
  110. $this->app->access_token->getToken();
  111. } catch (HttpException $e) {
  112. if ($e->formattedResponse['errcode'] == 40013) {
  113. return [
  114. 'code' => 1,
  115. 'msg' => 'AppId错误'
  116. ];
  117. }
  118. if ($e->formattedResponse['errcode'] == 40125) {
  119. return [
  120. 'code' => 1,
  121. 'msg' => 'AppSecret错误'
  122. ];
  123. }
  124. }
  125. }
  126. //$app = Factory::payment($config);
  127. if (!empty($this->cert_pem) || !empty($this->cert_pem)) {
  128. if ($this->type == 2 && empty($this->mch_id)) {
  129. return [
  130. 'code' => 1,
  131. 'msg' => '请填写商户号'
  132. ];
  133. }
  134. if ($this->type == 2 && empty($this->pay_key)) {
  135. return [
  136. 'code' => 1,
  137. 'msg' => '请填写微信支付Api支付密钥'
  138. ];
  139. }
  140. // 验证证书
  141. try {
  142. $app = Factory::payment($config);
  143. $app->security->getPublicKey();
  144. } catch (\Exception $e) {
  145. return [
  146. 'code' => 1,
  147. 'msg' => '证书验证失败'
  148. ];
  149. } catch (RequestException $e) {
  150. if ($e->getHandlerContext()['errno'] == 58) {
  151. return [
  152. 'code' => 1,
  153. 'msg' => '微信支付证书错误'
  154. ];
  155. }
  156. }
  157. }
  158. if (($this->mch_id && $this->pay_key)) {
  159. if (empty($this->cert_pem) || empty($this->key_pem)) {
  160. return [
  161. 'code' => 1,
  162. 'msg' => '请填写微信支付证书'
  163. ];
  164. }
  165. $order_no = date('YmdHis') . mt_rand(1000, 9999);
  166. $res = $app->order->queryByOutTradeNumber($order_no);
  167. if ($res['return_code'] == "FAIL") {
  168. return [
  169. 'code' => 1,
  170. 'msg' => '微信支付商户号或微信支付Api密钥错误--('.$res['return_msg'].')'
  171. ];
  172. }
  173. }
  174. $ext_arr = [];
  175. if ($this->model->isNewRecord) {
  176. $this->model->store_id = $this->store_id;
  177. $this->model->type = $this->type;
  178. if ($this->type == WechatConfig::TYPE_CONFIG_APP && !empty($this->app_name)) {
  179. $ext_arr = [
  180. 'app_name' => ''
  181. ];
  182. if (!empty($this->app_name)) {
  183. $ext_arr['app_name'] = $this->app_name;
  184. }
  185. $this->model->ext = json_encode($ext_arr);
  186. }
  187. if ($this->type == WechatConfig::TYPE_CONFIG_MP) {
  188. $ext_arr = [
  189. 'token' => '',
  190. 'auto_reply' => ''
  191. ];
  192. if (!empty($this->token)) {
  193. $ext_arr['token'] = $this->token;
  194. }
  195. if (!empty($this->auto_reply)) {
  196. $ext_arr['auto_reply'] = $this->auto_reply;
  197. }
  198. $this->model->ext = json_encode($ext_arr);
  199. }
  200. $this->model->created_at = $this->model->updated_at = time();
  201. } else {
  202. $ext_arr = json_decode($this->model->ext, true);
  203. if ($this->type == WechatConfig::TYPE_CONFIG_APP && !empty($this->app_name)) {
  204. if (!empty($this->app_name)) {
  205. $ext_arr['app_name'] = $this->app_name;
  206. }
  207. $this->model->ext = json_encode($ext_arr);
  208. }
  209. if ($this->type == WechatConfig::TYPE_CONFIG_MP) {
  210. if (!empty($this->token)) {
  211. $ext_arr['token'] = $this->token;
  212. }
  213. if (!empty($this->auto_reply)) {
  214. $ext_arr['auto_reply'] = $this->auto_reply;
  215. }
  216. $this->model->ext = json_encode($ext_arr);
  217. }
  218. $this->model->updated_at = time();
  219. }
  220. empty($this->token) || $ext_arr['token'] = $this->token;
  221. empty($this->aes_key) || $ext_arr['aes_key'] = $this->aes_key;
  222. $this->model->ext = json_encode($ext_arr);
  223. $this->model->app_id = $this->app_id;
  224. $this->model->app_secret = $this->app_secret;
  225. $this->model->mch_id = $this->mch_id;
  226. $this->model->pay_key = $this->pay_key;
  227. $this->model->name = $this->name;
  228. $this->model->gh_wechat_app_id = $this->gh_wechat_app_id;
  229. if ($this->cert_pem) {
  230. $this->model->cert_pem = $this->cert_pem;
  231. }
  232. if ($this->key_pem) {
  233. $this->model->key_pem = $this->key_pem;
  234. }
  235. if ($this->cert_pem_url) {
  236. $this->model->cert_pem_url = $this->cert_pem_url;
  237. }
  238. if ($this->cert_pem_url) {
  239. $this->model->cert_pem_url = $this->cert_pem_url;
  240. }
  241. if ($this->model->save()) {
  242. return [
  243. 'code' => 0,
  244. 'msg' => '保存成功',
  245. ];
  246. }
  247. return [
  248. 'code' => 1,
  249. 'msg' => implode(';', array_values($this->model->firstErrors))
  250. ];
  251. }
  252. /**
  253. * 获取配置
  254. */
  255. public function getConfig() {
  256. $returnArray = [
  257. 'mini' => [],
  258. 'mp' => [],
  259. 'app' => [],
  260. 'self_mini' =>0,
  261. 'is_saas' => 0,
  262. 'store_id' => $this->store_id,
  263. ];
  264. $wechatConfig = WechatConfig::find()->where(['store_id' => $this->store_id, 'is_delete' => 0]);
  265. if ($wechatConfig) {
  266. //是商盟和saas
  267. if(\Yii::$app->isSaas()){
  268. // $wechatConfig->select(['app_id','app_secret','name','mch_id','ext','type', 'gh_wechat_app_id']);
  269. $returnArray['is_saas'] = 1;
  270. }
  271. $self_mini = \app\models\Option::get('self_mini', $this->store_id, 'store', 0)['value'];
  272. if($self_mini){
  273. $returnArray['self_mini'] = 1;
  274. }
  275. foreach ($wechatConfig->asArray()->all() as $value) {
  276. if (empty($value['key_pem_url']) && !empty($value['key_pem'])) {
  277. $value['key_pem_url'] = self::handlePemFile($value['key_pem']);
  278. }
  279. if (empty($value['cert_pem_url']) && !empty($value['cert_pem'])) {
  280. $value['cert_pem_url'] = self::handlePemFile($value['cert_pem']);
  281. }
  282. $ext = json_decode($value['ext'], true);
  283. switch ($value['type']) {
  284. case WechatConfig::TYPE_CONFIG_MINI:
  285. $value['token'] = !empty($ext['token']) ? $ext['token'] : '';
  286. $value['aes_key'] = !empty($ext['aes_key']) ? $ext['aes_key'] : '';
  287. $returnArray['mini'] = $value;
  288. break;
  289. case WechatConfig::TYPE_CONFIG_MP:
  290. $ext = json_decode($value['ext'], true);
  291. $value['token'] = !empty($ext['token']) ? $ext['token'] : '';
  292. $value['auto_reply'] = !empty($ext['auto_reply']) ? $ext['auto_reply'] : '';
  293. // unset($value['ext']);
  294. $returnArray['mp'] = $value;
  295. break;
  296. case WechatConfig::TYPE_CONFIG_APP:
  297. $ext = json_decode($value['ext'], true);
  298. $value['app_name'] = !empty($ext['app_name']) ? $ext['app_name'] : '';
  299. unset($value['ext']);
  300. $returnArray['app'] = $value;
  301. break;
  302. default:
  303. break;
  304. }
  305. }
  306. }
  307. return [
  308. 'code' => 0,
  309. 'msg' => 'success',
  310. 'data' => $returnArray
  311. ];
  312. }
  313. //处理上传证书
  314. public static function handlePemFile($pem_content, $type = 0) {
  315. // 证书
  316. if (!is_dir(\Yii::$app->runtimePath . '/pem')) {
  317. mkdir(\Yii::$app->runtimePath . '/pem');
  318. file_put_contents(\Yii::$app->runtimePath . '/pem/index.html', '');
  319. }
  320. $pem_file = null;
  321. $pem_url = '';
  322. if ($pem_content) {
  323. $pem_file_name = md5($pem_content) . '.pem';
  324. $pem_file = \Yii::$app->runtimePath . '/pem/' . $pem_file_name;
  325. if (!file_exists($pem_file)) {
  326. file_put_contents($pem_file, $pem_content);
  327. }
  328. $pem_url = 'https://' . \Yii::$app->request->hostName . '/runtime/pem/' . $pem_file_name;
  329. }
  330. if ($type) {
  331. return $pem_file;
  332. }
  333. return $pem_url;
  334. }
  335. }