ChapterShareWechatConfigService.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: tandunzhao
  5. * Date: 2017/12/4
  6. * Time: 上午11:49
  7. */
  8. namespace App\Modules\Book\Services;
  9. use Redis;
  10. use EasyWeChat\Foundation\Application;
  11. class ChapterShareWechatConfigService
  12. {
  13. private $appId;
  14. private $appSecret;
  15. public function __construct($appId,$appSecret)
  16. {
  17. $this->appId = $appId ? $appId : env('JS_AppID');
  18. $this->appSecret = $appSecret ? $appSecret : env('JS_AppSecret');
  19. //\Log::info('appId:'.($this->appId).'appSecret:'.($this->appSecret));
  20. }
  21. public function getSignPackage($url='',$is_force = true , $only_cache= false)
  22. {
  23. $jsapiTicket = $this->getJsApiTicket($is_force , $only_cache );
  24. $protocol = (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
  25. $url = $url?$url:"$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  26. $timestamp = time();
  27. $nonceStr = $this->createNonceStr();
  28. // 这里参数的顺序要按照 key 值 ASCII 码升序排序
  29. $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
  30. \Log::info($string);
  31. $signature = sha1($string);
  32. $signPackage = array(
  33. "appId" => $this->appId,
  34. "nonceStr" => $nonceStr,
  35. "timestamp" => $timestamp,
  36. "url" => $url,
  37. "signature" => $signature,
  38. "rawString" => $string
  39. );
  40. return $signPackage;
  41. }
  42. private function createNonceStr($length = 16)
  43. {
  44. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  45. $str = "";
  46. for ($i = 0; $i < $length; $i ++)
  47. {
  48. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  49. }
  50. return $str;
  51. }
  52. private function getJsApiTicket($is_force = false , $only_cache= true )
  53. {
  54. // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
  55. $data = unserialize(Redis::get(($this->appId)."jsapi_ticket"));
  56. if (empty($data) || $data['expire_time'] < time())
  57. {
  58. $accessToken = $this->getToken($is_force, $only_cache);
  59. \Log::info(($this->appId).':'.$accessToken);
  60. // 如果是企业号用以下 URL 获取 ticket
  61. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$accessToken}";
  62. $res = json_decode($this->httpGet($url));
  63. $ticket = $res->ticket;
  64. if ($ticket)
  65. {
  66. $data['expire_time'] = time() + 7000;
  67. $data['jsapi_ticket'] = $ticket;
  68. Redis::setex(($this->appId)."jsapi_ticket", 7000, serialize($data));
  69. }
  70. } else
  71. {
  72. $ticket = $data['jsapi_ticket'];
  73. }
  74. \Log::info(($this->appId).':'.'jsapi_tiket:'.$ticket);
  75. return $ticket;
  76. }
  77. private function httpGet($url)
  78. {
  79. $curl = curl_init();
  80. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  81. curl_setopt($curl, CURLOPT_TIMEOUT, 3);
  82. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  83. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  84. curl_setopt($curl, CURLOPT_URL, $url);
  85. $res = curl_exec($curl);
  86. curl_close($curl);
  87. return $res;
  88. }
  89. /**
  90. * 获取access token
  91. *
  92. * @param string $is_force
  93. * @return unknown|unknown|mixed|object|boolean
  94. */
  95. public function getToken($is_force = true , $only_cache= true )
  96. {
  97. if ($is_force == false)
  98. {
  99. $data = unserialize(Redis::get(($this->appId)."access_token"));
  100. if ($data)
  101. {
  102. if (is_array($data) && $data['expire_time'] > time())
  103. {
  104. $access_token = $data['access_token'];
  105. return $access_token;
  106. } else if (is_string($data))
  107. {
  108. $access_token = $data;
  109. return $access_token;
  110. }
  111. }
  112. if( $only_cache ){
  113. // 非强制获取access_token,cache没有就直接返回false,防止获取access_token的接口在高并发下被滥用
  114. return false;
  115. }
  116. }
  117. $appId = $this->appId;
  118. $appSecret = $this->appSecret;
  119. $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appId . '&secret=' . $appSecret;
  120. $rs1 = self::https_request($url);
  121. \Log::info(($this->appId).'get_token-'.$rs1);
  122. if ($rs1)
  123. {
  124. $rs = json_decode($rs1, true);
  125. if (is_array($rs) && $rs['access_token'])
  126. {
  127. $access_token = $rs['access_token'];
  128. $expires_in = intval($rs['expires_in'], 10);
  129. if ($expires_in <= 0)
  130. {
  131. $expires_in = 5;
  132. } else if ($expires_in >= 7200)
  133. {
  134. $expires_in = 7000;
  135. }
  136. $data = array();
  137. $data['expire_time'] = time() + $expires_in;
  138. $data['access_token'] = $access_token;
  139. Redis::setex(($this->appId).'access_token', $expires_in, serialize($data));
  140. return $access_token;
  141. } else
  142. {
  143. $content = "get access token error:" . $rs1;
  144. \Log::info(($this->appId).$content);
  145. }
  146. } else
  147. {
  148. $content = "get access token error:" . $rs1;
  149. \Log::info(($this->appId).$content);
  150. }
  151. return false;
  152. }
  153. /**
  154. * 抓https数据
  155. *
  156. * @param unknown $url
  157. * @param string $data
  158. * @param string $timeout
  159. */
  160. static function https_request($url, $data = null, $timeout = 5000)
  161. {
  162. $curl = curl_init();
  163. curl_setopt($curl, CURLOPT_URL, $url);
  164. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  165. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
  166. if (! empty($data)) {
  167. curl_setopt($curl, CURLOPT_POST, 1);
  168. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  169. }
  170. if ($timeout) {
  171. curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
  172. }
  173. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  174. $output = curl_exec($curl);
  175. if ($output === false) {
  176. \Log::error('Curl error: ' . curl_error($curl).". url:".$url);
  177. }
  178. curl_close($curl);
  179. return $output;
  180. }
  181. public static function getConfig($url){
  182. $options = [
  183. 'debug' => false,
  184. 'app_id' => env('JS_AppId'),
  185. 'secret' => env('JS_AppSecret'),
  186. //'token' => 'easywechat',
  187. // 'aes_key' => null, // 可选
  188. 'log' => [
  189. 'level' => 'debug',
  190. 'file' => storage_path('easywechat.log'), // XXX: 绝对路径!!!!
  191. ],
  192. ];
  193. $app = new Application($options);
  194. $js = $app->js;
  195. $js->setUrl($url);
  196. $config =$js ->Config([
  197. 'onMenuShareTimeline',
  198. 'onMenuShareAppMessage',
  199. 'onMenuShareQQ',
  200. 'onMenuShareWeibo',
  201. 'showOptionMenu',
  202. 'hideOptionMenu',
  203. 'hideMenuItems',
  204. 'hideAllNonBaseMenuItem'
  205. ],$debug = false, $beta = false, $json = false);
  206. return $config;
  207. }
  208. }