1091 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			1091 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| 
								 | 
							
								<?php
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Bwsaas
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Gitee ( https://gitee.com/buwangyun/bwsaas )
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Author: buwangyun <hnlg666@163.com>
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								// | Date: 2020-9-28 10:55:00
							 | 
						|||
| 
								 | 
							
								// +----------------------------------------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace bw;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								use app\admin\model\Miniqrcode;
							 | 
						|||
| 
								 | 
							
								use app\admin\model\Xftts;
							 | 
						|||
| 
								 | 
							
								use app\common\library\Upload;
							 | 
						|||
| 
								 | 
							
								use think\Cache;
							 | 
						|||
| 
								 | 
							
								use think\File;
							 | 
						|||
| 
								 | 
							
								use app\common\model\Attachment;
							 | 
						|||
| 
								 | 
							
								use addons\xftts\library\Tts;
							 | 
						|||
| 
								 | 
							
								use addons\xftts\library\WebSocket\Client;
							 | 
						|||
| 
								 | 
							
								use addons\xftts\library\WebSocket\Exception;
							 | 
						|||
| 
								 | 
							
								use traits\CacheTrait;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/** 商城工具类
							 | 
						|||
| 
								 | 
							
								 * Class Common
							 | 
						|||
| 
								 | 
							
								 * @package app\bwmall\model
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								class Common
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    use CacheTrait;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 获取图片完整连接
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getImagesFullUrl($value = '')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (stripos($value, 'http') === 0 || $value === '' || stripos($value, 'data:image') === 0) {
							 | 
						|||
| 
								 | 
							
								            return $value;
							 | 
						|||
| 
								 | 
							
								        } else {
							 | 
						|||
| 
								 | 
							
								            $upload = \think\Config::get('upload');
							 | 
						|||
| 
								 | 
							
								            if (!empty($upload['cdnurl'])) {
							 | 
						|||
| 
								 | 
							
								                return  $upload['cdnurl'] . $value;
							 | 
						|||
| 
								 | 
							
								            } else {
							 | 
						|||
| 
								 | 
							
								                return self::getHttpLocation() . $value;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 获取当前地址
							 | 
						|||
| 
								 | 
							
								     * @return string
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getHttpLocation() {
							 | 
						|||
| 
								 | 
							
								        $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
							 | 
						|||
| 
								 | 
							
								        return $http_type . $_SERVER['HTTP_HOST'];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 时间戳 - 精确到毫秒
							 | 
						|||
| 
								 | 
							
								     * @return float
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getMillisecond() {
							 | 
						|||
| 
								 | 
							
								        list($t1, $t2) = explode(' ', microtime());
							 | 
						|||
| 
								 | 
							
								        return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 判断文件是否存在,支持本地及远程文件
							 | 
						|||
| 
								 | 
							
								     * @param  String  $file 文件路径
							 | 
						|||
| 
								 | 
							
								     * @return Boolean
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function check_file_exists($file){
							 | 
						|||
| 
								 | 
							
								// 屏蔽域名不存在等访问问题的警告
							 | 
						|||
| 
								 | 
							
								        error_reporting(E_ALL ^ (E_WARNING|E_NOTICE));
							 | 
						|||
| 
								 | 
							
								        // 远程文件
							 | 
						|||
| 
								 | 
							
								        if(strtolower(substr($file, 0, 4))=='http'){
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            $header = get_headers($file, true);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return isset($header[0]) && (strpos($header[0], '200') || strpos($header[0], '304'));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // 本地文件
							 | 
						|||
| 
								 | 
							
								        }else{
							 | 
						|||
| 
								 | 
							
								            return file_exists($file);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**将目录下的文件保存到框架文件系统
							 | 
						|||
| 
								 | 
							
								     * @param $file_path 原文件全路径(物理=>[绝对|相对])
							 | 
						|||
| 
								 | 
							
								     * @param $file_name 源文件名
							 | 
						|||
| 
								 | 
							
								     * @return \app\common\model\attachment|\think\Model
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function setFastAdminFile($file_path,$file_name){
							 | 
						|||
| 
								 | 
							
								        //保存到第三方文件
							 | 
						|||
| 
								 | 
							
								        //name 原文件名 type 文件类型  tmp_name 原目录 error =0 size 文件大小
							 | 
						|||
| 
								 | 
							
								        $fi = new \finfo(FILEINFO_MIME_TYPE);
							 | 
						|||
| 
								 | 
							
								        $mime_type = $fi->file($file_path);
							 | 
						|||
| 
								 | 
							
								        $temp = [
							 | 
						|||
| 
								 | 
							
								            'name'=> $file_name,
							 | 
						|||
| 
								 | 
							
								            'size'=> filesize($file_path),
							 | 
						|||
| 
								 | 
							
								            'tmp_name'=>$file_path,
							 | 
						|||
| 
								 | 
							
								            'error'=>0,
							 | 
						|||
| 
								 | 
							
								            'type'=>$mime_type
							 | 
						|||
| 
								 | 
							
								        ];
							 | 
						|||
| 
								 | 
							
								        $file = (new File($file_path))->isTest(true)->setUploadInfo($temp);
							 | 
						|||
| 
								 | 
							
								        $upload = new Upload($file);
							 | 
						|||
| 
								 | 
							
								        return $upload->upload();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public $temp_url = 'uploads/qrcode';//临时,目录
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public $path = '';
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**将目录下的文件保存到框架文件系统
							 | 
						|||
| 
								 | 
							
								     * @param $file_path 原文件全路径(物理=>[绝对|相对])
							 | 
						|||
| 
								 | 
							
								     * @param $file_name 源文件名
							 | 
						|||
| 
								 | 
							
								     * @return \app\common\model\attachment|\think\Model
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public  function setFastAdminFileByUrl($url,$fileName){
							 | 
						|||
| 
								 | 
							
								        ob_start();
							 | 
						|||
| 
								 | 
							
								        readfile($url);
							 | 
						|||
| 
								 | 
							
								        $res = ob_get_contents();//文件二进制流
							 | 
						|||
| 
								 | 
							
								        ob_end_clean();
							 | 
						|||
| 
								 | 
							
								        $outfile = $this->temp_url . '/';  //本地缓存地址
							 | 
						|||
| 
								 | 
							
								        if (!file_exists('./' . $outfile . $this->path)) mkdir('./' . $outfile . $this->path, 0777, true);
							 | 
						|||
| 
								 | 
							
								        $filepath = './' . $outfile . $this->path . '/' . $fileName;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        file_put_contents($filepath, $res);
							 | 
						|||
| 
								 | 
							
								        //保存到fastadmin框架
							 | 
						|||
| 
								 | 
							
								        $attachment = Common::setFastAdminFile($filepath, $fileName);
							 | 
						|||
| 
								 | 
							
								        // TODO: 生成后删除源文件
							 | 
						|||
| 
								 | 
							
								        @unlink($filepath);
							 | 
						|||
| 
								 | 
							
								        return $attachment;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 字符串命名风格转换
							 | 
						|||
| 
								 | 
							
								     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
							 | 
						|||
| 
								 | 
							
								     * @access public
							 | 
						|||
| 
								 | 
							
								     * @param string $name 字符串
							 | 
						|||
| 
								 | 
							
								     * @param integer $type 转换类型
							 | 
						|||
| 
								 | 
							
								     * @param bool $ucfirst 首字母是否大写(驼峰规则)
							 | 
						|||
| 
								 | 
							
								     * @return string
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function parseName($name, $type = 0, $ucfirst = true)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if ($type) {
							 | 
						|||
| 
								 | 
							
								            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
							 | 
						|||
| 
								 | 
							
								                return strtoupper($match[1]);
							 | 
						|||
| 
								 | 
							
								            }, $name);
							 | 
						|||
| 
								 | 
							
								            return $ucfirst ? ucfirst($name) : lcfirst($name);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public static function toreplace($str, $find)//$str是你需要操作的字符串,$find是你指定的字符串
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (strpos($str, $find) === false) return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        $a = explode($find, $str);
							 | 
						|||
| 
								 | 
							
								        return $a[0] . $find;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 无限级归类
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     * @param array $list 归类的数组
							 | 
						|||
| 
								 | 
							
								     * @param string $id 父级ID
							 | 
						|||
| 
								 | 
							
								     * @param string $pid 父级PID
							 | 
						|||
| 
								 | 
							
								     * @param string $child key
							 | 
						|||
| 
								 | 
							
								     * @param string $root 顶级
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function tree(array $list, string $pk = 'id', string $pid = 'pid', string $child = 'child', int $root = 0): array
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $tree = [];  //最终得到的树形数据
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (is_array($list)) {
							 | 
						|||
| 
								 | 
							
								            $refer = [];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            //基于数组的指针(引用) 并 同步改变数组
							 | 
						|||
| 
								 | 
							
								            foreach ($list as $key => $val) {
							 | 
						|||
| 
								 | 
							
								                $list[$key][$child] = [];
							 | 
						|||
| 
								 | 
							
								                $refer[$val[$pk]] = &$list[$key];  //以主键为下标,值为列表数据的引用
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            foreach ($list as $key => $val) {
							 | 
						|||
| 
								 | 
							
								                //是否存在parent
							 | 
						|||
| 
								 | 
							
								                $parentId = isset($val[$pid]) ? $val[$pid] : $root;  //取出父级id
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                //如果是根节点,直接放入根层级(实际放入的是一个组装好的树分支)
							 | 
						|||
| 
								 | 
							
								                if ($root == $parentId) {
							 | 
						|||
| 
								 | 
							
								                    $tree[$val[$pk]] = &$list[$key];
							 | 
						|||
| 
								 | 
							
								                } else {  //如果是其他节点,通过引用传入树分支
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                    if (isset($refer[$parentId])) {
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                        $refer[$parentId][$child][] = &$list[$key];  //1  3  4
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            // die;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        //var_dump(array_values($tree));
							 | 
						|||
| 
								 | 
							
								        return array_values($tree);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**得到关系树中的全部用户id(递归)
							 | 
						|||
| 
								 | 
							
								     * @param array $list tree数据来源
							 | 
						|||
| 
								 | 
							
								     * @param string $name 需要获取的数据名
							 | 
						|||
| 
								 | 
							
								     * @param string $child 树子节点名
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getTreeItem(array $list, string $name = 'pid', string $child = 'child')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $item = [];
							 | 
						|||
| 
								 | 
							
								        //遍历关系
							 | 
						|||
| 
								 | 
							
								        foreach ($list as &$value) {
							 | 
						|||
| 
								 | 
							
								            $item[] = $value[$name];
							 | 
						|||
| 
								 | 
							
								            if ($value[$child]) $item = array_merge($item, self::getTreeItem($value[$child], $name, $child));//合并两个数组
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $item;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 排列组合
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     * @param array $input 排列的数组
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static public function arrayArrange(array $input): array
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $temp = [];
							 | 
						|||
| 
								 | 
							
								        $result = array_shift($input);  //挤出数组第一个元素
							 | 
						|||
| 
								 | 
							
								        while ($item = array_shift($input))  //循环每次挤出数组的一个元素,直到数组元素全部挤出
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            $temp = $result;
							 | 
						|||
| 
								 | 
							
								            $result = [];
							 | 
						|||
| 
								 | 
							
								            foreach ($temp as $v) {
							 | 
						|||
| 
								 | 
							
								                foreach ($item as $val) {
							 | 
						|||
| 
								 | 
							
								                    $result[] = array_merge_recursive($v, $val);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $result;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 富文本base64解码
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function r_text_decode($text)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $text = base64_decode($text);
							 | 
						|||
| 
								 | 
							
								        return htmlspecialchars_decode(urldecode($text));
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**得到小程序太阳码
							 | 
						|||
| 
								 | 
							
								     * @param $path
							 | 
						|||
| 
								 | 
							
								     * @param string $scene
							 | 
						|||
| 
								 | 
							
								     * @param bool $cache
							 | 
						|||
| 
								 | 
							
								     * @return attachment|array|false|\PDOStatement|string|\think\Model
							 | 
						|||
| 
								 | 
							
								     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
							 | 
						|||
| 
								 | 
							
								     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\DataNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\ModelNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\exception\DbException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getMiniappCode($path,$scene='',$cache = true){
							 | 
						|||
| 
								 | 
							
								        // 写入到文件
							 | 
						|||
| 
								 | 
							
								        $file_name = md5( $path.$scene.'MiniCode') . '.png';
							 | 
						|||
| 
								 | 
							
								        if($cache){
							 | 
						|||
| 
								 | 
							
								            $file_info = Attachment::where('filename',$file_name)->find();
							 | 
						|||
| 
								 | 
							
								            if($file_info){
							 | 
						|||
| 
								 | 
							
								                $file_info['full_url'] = cdnurl($file_info['url'],true);
							 | 
						|||
| 
								 | 
							
								                return $file_info;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        if (empty($path)) {
							 | 
						|||
| 
								 | 
							
								            $path = 'pages/index/index';
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $wechat = new \addons\shopro\library\Wechat('wxMiniProgram');
							 | 
						|||
| 
								 | 
							
								        $content = $wechat->getApp()->app_code->getUnlimit($scene, [
							 | 
						|||
| 
								 | 
							
								            'page' => $path,
							 | 
						|||
| 
								 | 
							
								            'is_hyaline' => true,
							 | 
						|||
| 
								 | 
							
								        ]);
							 | 
						|||
| 
								 | 
							
								        if ($content instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
							 | 
						|||
| 
								 | 
							
								            $filePath = ROOT_PATH . 'public/uploads/qrcode/' . $file_name;
							 | 
						|||
| 
								 | 
							
								            $content->saveAs(ROOT_PATH . 'public/uploads/qrcode', $file_name);
							 | 
						|||
| 
								 | 
							
								            //保存到fastadmin框架
							 | 
						|||
| 
								 | 
							
								            $attachment = Common::setFastAdminFile($filePath, $file_name);
							 | 
						|||
| 
								 | 
							
								            $attachment['full_url'] = cdnurl($attachment['url'],true);
							 | 
						|||
| 
								 | 
							
								            // TODO: 生成后删除源文件
							 | 
						|||
| 
								 | 
							
								            @unlink($filePath);
							 | 
						|||
| 
								 | 
							
								            return $attachment;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        } else {
							 | 
						|||
| 
								 | 
							
								            // 小程序码获取失败
							 | 
						|||
| 
								 | 
							
								            $msg = isset($content['errcode']) ? $content['errcode'] : '-';
							 | 
						|||
| 
								 | 
							
								            $msg .= isset($content['errmsg']) ? $content['errmsg'] : '';
							 | 
						|||
| 
								 | 
							
								            \think\Log::write('wxacode-error' . $msg);
							 | 
						|||
| 
								 | 
							
								            throw new \Exception($msg);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**得到小程序二维码(调用次数上限为10万)
							 | 
						|||
| 
								 | 
							
								     * @param $path
							 | 
						|||
| 
								 | 
							
								     * @param bool $cache
							 | 
						|||
| 
								 | 
							
								     * @return attachment|array|false|\PDOStatement|string|\think\Model
							 | 
						|||
| 
								 | 
							
								     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
							 | 
						|||
| 
								 | 
							
								     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\DataNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\ModelNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\exception\DbException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getMiniappQrCode($path,$getContent=false,$cache = true){
							 | 
						|||
| 
								 | 
							
								        // 写入到文件
							 | 
						|||
| 
								 | 
							
								        $file_name = md5( $path.'MiniQrCode') . '.png';
							 | 
						|||
| 
								 | 
							
								        if($cache){
							 | 
						|||
| 
								 | 
							
								            $file_info = Attachment::where('filename',$file_name)->find();
							 | 
						|||
| 
								 | 
							
								            if($file_info){
							 | 
						|||
| 
								 | 
							
								                $file_info['full_url'] = cdnurl($file_info['url'],true);
							 | 
						|||
| 
								 | 
							
								                $file_info['common_content'] = null;
							 | 
						|||
| 
								 | 
							
								                if($getContent){
							 | 
						|||
| 
								 | 
							
								                    //得到返解析的内容
							 | 
						|||
| 
								 | 
							
								                    $qrcode = new \Zxing\QrReader( $file_info['full_url']);   //绝对路径
							 | 
						|||
| 
								 | 
							
								                    $file_info['common_content'] = $qrcode->text(); //返回二维码的内容
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                return $file_info;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        if (empty($path)) {
							 | 
						|||
| 
								 | 
							
								            $path = 'pages/index/index';
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $wechat = new \addons\shopro\library\Wechat('wxMiniProgram');
							 | 
						|||
| 
								 | 
							
								        $content = $wechat->getApp()->app_code->getQrCode($path);
							 | 
						|||
| 
								 | 
							
								        if ($content instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
							 | 
						|||
| 
								 | 
							
								            $filePath = ROOT_PATH . 'public/uploads/qrcode/' . $file_name;
							 | 
						|||
| 
								 | 
							
								            $content->saveAs(ROOT_PATH . 'public/uploads/qrcode', $file_name);
							 | 
						|||
| 
								 | 
							
								            //保存到fastadmin框架
							 | 
						|||
| 
								 | 
							
								            $attachment = Common::setFastAdminFile($filePath, $file_name);
							 | 
						|||
| 
								 | 
							
								            $attachment['full_url'] = cdnurl($attachment['url'],true);
							 | 
						|||
| 
								 | 
							
								            $attachment['common_content'] = null;
							 | 
						|||
| 
								 | 
							
								            if($getContent) {
							 | 
						|||
| 
								 | 
							
								                //得到返解析的内容
							 | 
						|||
| 
								 | 
							
								                $qrcode = new \Zxing\QrReader($attachment['full_url']);   //绝对路径
							 | 
						|||
| 
								 | 
							
								                $attachment['common_content'] = $qrcode->text(); //返回二维码的内容
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            // TODO: 生成后删除源文件
							 | 
						|||
| 
								 | 
							
								            @unlink($filePath);
							 | 
						|||
| 
								 | 
							
								            return $attachment;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        } else {
							 | 
						|||
| 
								 | 
							
								            // 小程序码获取失败
							 | 
						|||
| 
								 | 
							
								            $msg = isset($content['errcode']) ? $content['errcode'] : '-';
							 | 
						|||
| 
								 | 
							
								            $msg .= isset($content['errmsg']) ? $content['errmsg'] : '';
							 | 
						|||
| 
								 | 
							
								            \think\Log::write('wxacode-error' . $msg);
							 | 
						|||
| 
								 | 
							
								            throw new \Exception($msg);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**生成二维码
							 | 
						|||
| 
								 | 
							
								     * @param $params
							 | 
						|||
| 
								 | 
							
								     * @throws \Endroid\QrCode\Exception\InvalidPathException
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getQrcode($params,$stream = false,$cache = true){
							 | 
						|||
| 
								 | 
							
								        $qrCode = \addons\qrcode\library\Service::qrcode($params);
							 | 
						|||
| 
								 | 
							
								        if($stream)return $qrCode;
							 | 
						|||
| 
								 | 
							
								        // 写入到文件
							 | 
						|||
| 
								 | 
							
								        $file_name = md5(implode('', $params).'Qrcode') . '.png';
							 | 
						|||
| 
								 | 
							
								        if($cache){
							 | 
						|||
| 
								 | 
							
								            $file_info = Attachment::where('filename',$file_name)->find();
							 | 
						|||
| 
								 | 
							
								            if($file_info){
							 | 
						|||
| 
								 | 
							
								                $file_info['full_url'] = cdnurl($file_info['url'],true);
							 | 
						|||
| 
								 | 
							
								                return $file_info;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $filePath = ROOT_PATH . 'public/uploads/qrcode/' . $file_name;
							 | 
						|||
| 
								 | 
							
								        $qrCode->writeFile($filePath);
							 | 
						|||
| 
								 | 
							
								        //保存到fastadmin框架
							 | 
						|||
| 
								 | 
							
								        $attachment = Common::setFastAdminFile($filePath, $file_name);
							 | 
						|||
| 
								 | 
							
								        // TODO: 生成后删除源文件
							 | 
						|||
| 
								 | 
							
								        @unlink($filePath);
							 | 
						|||
| 
								 | 
							
								        $attachment['full_url'] = cdnurl($attachment['url'],true);
							 | 
						|||
| 
								 | 
							
								        return $attachment;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**生成一维码
							 | 
						|||
| 
								 | 
							
								     * @param $params
							 | 
						|||
| 
								 | 
							
								     * @throws \Endroid\QrCode\Exception\InvalidPathException
							 | 
						|||
| 
								 | 
							
								     * @throws \app\common\exception\UploadException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getBarcode($params,$stream = false,$cache = true){
							 | 
						|||
| 
								 | 
							
								        $qrCode = \addons\barcode\library\Service::barcode($params);
							 | 
						|||
| 
								 | 
							
								        if($stream)return $qrCode;
							 | 
						|||
| 
								 | 
							
								        // 写入到文件
							 | 
						|||
| 
								 | 
							
								        $file_name = md5(implode('', $params).'Barcode') . '.png';
							 | 
						|||
| 
								 | 
							
								        if($cache){
							 | 
						|||
| 
								 | 
							
								            $file_info = Attachment::where('filename',$file_name)->find();
							 | 
						|||
| 
								 | 
							
								            if($file_info){
							 | 
						|||
| 
								 | 
							
								                $file_info['full_url'] = cdnurl($file_info['url'],true);
							 | 
						|||
| 
								 | 
							
								                return $file_info;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $outfile =  'uploads/barcode/';
							 | 
						|||
| 
								 | 
							
								        if (!file_exists('./' . $outfile )) mkdir('./' . $outfile, 0777, true);
							 | 
						|||
| 
								 | 
							
								        $filePath = './' . $outfile  . '/' . $file_name;
							 | 
						|||
| 
								 | 
							
								        file_put_contents($filePath, $qrCode);
							 | 
						|||
| 
								 | 
							
								        //保存到fastadmin框架
							 | 
						|||
| 
								 | 
							
								        $attachment = Common::setFastAdminFile($filePath, $file_name);
							 | 
						|||
| 
								 | 
							
								        // TODO: 生成后删除源文件
							 | 
						|||
| 
								 | 
							
								        @unlink($filePath);
							 | 
						|||
| 
								 | 
							
								        $attachment['full_url'] = cdnurl($attachment['url'],true);
							 | 
						|||
| 
								 | 
							
								        return $attachment;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**执行字符串模板替换
							 | 
						|||
| 
								 | 
							
								     * @param $template
							 | 
						|||
| 
								 | 
							
								     * @param array $params
							 | 
						|||
| 
								 | 
							
								     * @param string $expression
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function parsePrintTemplateString($template,$params=[],$expression = '{{KEYWORD}}'){
							 | 
						|||
| 
								 | 
							
								        foreach ($params as $name => $value)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            //得到需要替换的字符串
							 | 
						|||
| 
								 | 
							
								            $replace_name = str_replace("KEYWORD",$name,$expression);
							 | 
						|||
| 
								 | 
							
								            //执行模板字符串替换
							 | 
						|||
| 
								 | 
							
								            $template = str_replace($replace_name,$value,$template);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $template;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 返回多层栏目
							 | 
						|||
| 
								 | 
							
								     * @param $data 操作的数组
							 | 
						|||
| 
								 | 
							
								     * @param int $pid 一级PID的值
							 | 
						|||
| 
								 | 
							
								     * @param string $html 栏目名称前缀
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPri 唯一键名,如果是表则是表的主键
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父ID键名
							 | 
						|||
| 
								 | 
							
								     * @param int $level 不需要传参数(执行时调用)
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static public function channelLevel($data, $pid = 0, $html = " ", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (empty($data)) {
							 | 
						|||
| 
								 | 
							
								            return array();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $arr = array();
							 | 
						|||
| 
								 | 
							
								        foreach ($data as $v) {
							 | 
						|||
| 
								 | 
							
								            if ($v[$fieldPid] == $pid) {
							 | 
						|||
| 
								 | 
							
								                $arr[$v[$fieldPri]] = $v;
							 | 
						|||
| 
								 | 
							
								                $arr[$v[$fieldPri]]['_level'] = $level;
							 | 
						|||
| 
								 | 
							
								                $arr[$v[$fieldPri]]['_html'] = str_repeat($html, $level - 1);
							 | 
						|||
| 
								 | 
							
								                $arr[$v[$fieldPri]]["_data"] = self::channelLevel($data, $v[$fieldPri], $html, $fieldPri, $fieldPid, $level + 1);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $arr;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 获得所有子栏目
							 | 
						|||
| 
								 | 
							
								     * @param $data 栏目数据
							 | 
						|||
| 
								 | 
							
								     * @param int $pid 操作的栏目
							 | 
						|||
| 
								 | 
							
								     * @param string $html 栏目名前字符
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPri 表主键
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父id
							 | 
						|||
| 
								 | 
							
								     * @param int $level 等级
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static public function channelList($data, $pid = 0, $html = " ", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $data = self::_channelList($data, $pid, $html, $fieldPri, $fieldPid, $level);
							 | 
						|||
| 
								 | 
							
								        if (empty($data))
							 | 
						|||
| 
								 | 
							
								            return $data;
							 | 
						|||
| 
								 | 
							
								        foreach ($data as $n => $m) {
							 | 
						|||
| 
								 | 
							
								            if ($m['_level'] == 1)
							 | 
						|||
| 
								 | 
							
								                continue;
							 | 
						|||
| 
								 | 
							
								            $data[$n]['_first'] = false;
							 | 
						|||
| 
								 | 
							
								            $data[$n]['_end'] = false;
							 | 
						|||
| 
								 | 
							
								            if (!isset($data[$n - 1]) || $data[$n - 1]['_level'] != $m['_level']) {
							 | 
						|||
| 
								 | 
							
								                $data[$n]['_first'] = true;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            if (isset($data[$n + 1]) && $data[$n]['_level'] > $data[$n + 1]['_level']) {
							 | 
						|||
| 
								 | 
							
								                $data[$n]['_end'] = true;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        //更新key为栏目主键
							 | 
						|||
| 
								 | 
							
								        $category = array();
							 | 
						|||
| 
								 | 
							
								        foreach ($data as $d) {
							 | 
						|||
| 
								 | 
							
								            $category[$d[$fieldPri]] = $d;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $category;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //只供channelList方法使用
							 | 
						|||
| 
								 | 
							
								    static private function _channelList($data, $pid = 0, $html = " ", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (empty($data))
							 | 
						|||
| 
								 | 
							
								            return array();
							 | 
						|||
| 
								 | 
							
								        $arr = array();
							 | 
						|||
| 
								 | 
							
								        foreach ($data as $v) {
							 | 
						|||
| 
								 | 
							
								            $id = $v[$fieldPri];
							 | 
						|||
| 
								 | 
							
								            if ($v[$fieldPid] == $pid) {
							 | 
						|||
| 
								 | 
							
								                $v['_level'] = $level;
							 | 
						|||
| 
								 | 
							
								                $v['_html'] = str_repeat($html, $level - 1);
							 | 
						|||
| 
								 | 
							
								                array_push($arr, $v);
							 | 
						|||
| 
								 | 
							
								                $tmp = self::_channelList($data, $id, $html, $fieldPri, $fieldPid, $level + 1);
							 | 
						|||
| 
								 | 
							
								                $arr = array_merge($arr, $tmp);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $arr;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 获得展示状态的树 数据 例如  ├─ xxx
							 | 
						|||
| 
								 | 
							
								     * @param $data 数据
							 | 
						|||
| 
								 | 
							
								     * @param $title 字段名
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPri 主键id
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父id
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static public function exhibition_tree($data, $title, $fieldPri = 'cid', $fieldPid = 'pid')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (!is_array($data) || empty($data))
							 | 
						|||
| 
								 | 
							
								            return array();
							 | 
						|||
| 
								 | 
							
								        $arr = self::channelList($data, 0, '', $fieldPri, $fieldPid);
							 | 
						|||
| 
								 | 
							
								        foreach ($arr as $k => $v) {
							 | 
						|||
| 
								 | 
							
								            $str = "";
							 | 
						|||
| 
								 | 
							
								            if ($v['_level'] > 2) {
							 | 
						|||
| 
								 | 
							
								                for ($i = 1; $i < $v['_level'] - 1; $i++) {
							 | 
						|||
| 
								 | 
							
								                    $str .= " │";
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            if ($v['_level'] != 1) {
							 | 
						|||
| 
								 | 
							
								                $t = $title ? $v[$title] : "";
							 | 
						|||
| 
								 | 
							
								                if (isset($arr[$k + 1]) && $arr[$k + 1]['_level'] >= $arr[$k]['_level']) {
							 | 
						|||
| 
								 | 
							
								                    $arr[$k]['_name'] = $str . " ├─ " . $v['_html'] . $t;
							 | 
						|||
| 
								 | 
							
								                } else {
							 | 
						|||
| 
								 | 
							
								                    $arr[$k]['_name'] = $str . " └─ " . $v['_html'] . $t;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            } else {
							 | 
						|||
| 
								 | 
							
								                $arr[$k]['_name'] = $v[$title];
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        //设置主键为$fieldPri
							 | 
						|||
| 
								 | 
							
								        $data = array();
							 | 
						|||
| 
								 | 
							
								        foreach ($arr as $d) {
							 | 
						|||
| 
								 | 
							
								            $data[$d[$fieldPri]] = $d;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $data;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 获得所有父级栏目
							 | 
						|||
| 
								 | 
							
								     * @param $data 栏目数据
							 | 
						|||
| 
								 | 
							
								     * @param $sid 子栏目
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPri 唯一键名,如果是表则是表的主键
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父ID键名
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static public function parentChannel($data, $sid, $fieldPri = 'cid', $fieldPid = 'pid')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (empty($data)) {
							 | 
						|||
| 
								 | 
							
								            return $data;
							 | 
						|||
| 
								 | 
							
								        } else {
							 | 
						|||
| 
								 | 
							
								            $arr = array();
							 | 
						|||
| 
								 | 
							
								            foreach ($data as $v) {
							 | 
						|||
| 
								 | 
							
								                if ($v[$fieldPri] == $sid) {
							 | 
						|||
| 
								 | 
							
								                    $arr[] = $v;
							 | 
						|||
| 
								 | 
							
								                    $_n = self::parentChannel($data, $v[$fieldPid], $fieldPri, $fieldPid);
							 | 
						|||
| 
								 | 
							
								                    if (!empty($_n)) {
							 | 
						|||
| 
								 | 
							
								                        $arr = array_merge($arr, $_n);
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return $arr;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 判断$s_cid是否是$d_cid的子栏目
							 | 
						|||
| 
								 | 
							
								     * @param $data 栏目数据
							 | 
						|||
| 
								 | 
							
								     * @param $sid 子栏目id
							 | 
						|||
| 
								 | 
							
								     * @param $pid 父栏目id
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPri 主键
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父id字段
							 | 
						|||
| 
								 | 
							
								     * @return bool
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static function isChild($data, $sid, $pid, $fieldPri = 'cid', $fieldPid = 'pid')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $_data = self::channelList($data, $pid, '', $fieldPri, $fieldPid);
							 | 
						|||
| 
								 | 
							
								        foreach ($_data as $c) {
							 | 
						|||
| 
								 | 
							
								            //目标栏目为源栏目的子栏目
							 | 
						|||
| 
								 | 
							
								            if ($c[$fieldPri] == $sid)
							 | 
						|||
| 
								 | 
							
								                return true;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return false;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 检测是不否有子栏目
							 | 
						|||
| 
								 | 
							
								     * @param $data 栏目数据
							 | 
						|||
| 
								 | 
							
								     * @param $cid 要判断的栏目cid
							 | 
						|||
| 
								 | 
							
								     * @param string $fieldPid 父id表字段名
							 | 
						|||
| 
								 | 
							
								     * @return bool
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static function hasChild($data, $cid, $fieldPid = 'pid')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        foreach ($data as $d) {
							 | 
						|||
| 
								 | 
							
								            if ($d[$fieldPid] == $cid) return true;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return false;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 递归实现迪卡尔乘积
							 | 
						|||
| 
								 | 
							
								     * @param $arr 操作的数组
							 | 
						|||
| 
								 | 
							
								     * @param array $tmp
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    static function descarte($arr, $tmp = array())
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        static $n_arr = array();
							 | 
						|||
| 
								 | 
							
								        foreach (array_shift($arr) as $v) {
							 | 
						|||
| 
								 | 
							
								            $tmp[] = $v;
							 | 
						|||
| 
								 | 
							
								            if ($arr) {
							 | 
						|||
| 
								 | 
							
								                self::descarte($arr, $tmp);
							 | 
						|||
| 
								 | 
							
								            } else {
							 | 
						|||
| 
								 | 
							
								                $n_arr[] = $tmp;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            array_pop($tmp);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $n_arr;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**得到可复用的小程序二维码
							 | 
						|||
| 
								 | 
							
								     * @param $link_id
							 | 
						|||
| 
								 | 
							
								     * @param bool $cache
							 | 
						|||
| 
								 | 
							
								     * @return Miniqrcode|array|false|\PDOStatement|string|\think\Model
							 | 
						|||
| 
								 | 
							
								     * @throws \Exception
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getLinkMiniQrCode($link_id,$mini_path=null,$type = 'mock',$cache = true){
							 | 
						|||
| 
								 | 
							
								        try{
							 | 
						|||
| 
								 | 
							
								         $miniqrcode =  Miniqrcode::where("link_id",$link_id)->where("type",$type)->where("value","not null")->find();
							 | 
						|||
| 
								 | 
							
								         if($miniqrcode && $miniqrcode['value']){
							 | 
						|||
| 
								 | 
							
								             $miniqrcode['status'] = '2';
							 | 
						|||
| 
								 | 
							
								             $miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								             return $miniqrcode;
							 | 
						|||
| 
								 | 
							
								         }
							 | 
						|||
| 
								 | 
							
								        //判断是否有空余小程序二维码
							 | 
						|||
| 
								 | 
							
								         $miniqrcode  =  Miniqrcode::where("status","1")->where("value","not null")->where("value","<>","")->find();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //如果有,则更新二维码为使用中,保存新的连接信息并返回
							 | 
						|||
| 
								 | 
							
								        if($miniqrcode  && $miniqrcode['value']){
							 | 
						|||
| 
								 | 
							
								            $miniqrcode['status'] = '2';
							 | 
						|||
| 
								 | 
							
								            $miniqrcode['link_id'] = $link_id;
							 | 
						|||
| 
								 | 
							
								            $miniqrcode['type'] = $type;
							 | 
						|||
| 
								 | 
							
								            $miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								            return Miniqrcode::where('id',$miniqrcode['id'])->find();
							 | 
						|||
| 
								 | 
							
								        }else{
							 | 
						|||
| 
								 | 
							
								        //如果没有,则
							 | 
						|||
| 
								 | 
							
								            $count = Miniqrcode::count();
							 | 
						|||
| 
								 | 
							
								            $miniqrcode_limit = config("site.miniqrcode_limit");//练车小程序码url
							 | 
						|||
| 
								 | 
							
								            $mock_minicode_url = $mini_path ?: config("site.mock_minicode_url");//练车码生成上限数量
							 | 
						|||
| 
								 | 
							
								            //1,判断是否超出使用数量,如果超出则抛异常
							 | 
						|||
| 
								 | 
							
								            if($count >= $miniqrcode_limit)throw new \Exception("已超出能生成的小程序二维码上限!");
							 | 
						|||
| 
								 | 
							
								           //如果未超出
							 | 
						|||
| 
								 | 
							
								               //1插入小程序二维码表
							 | 
						|||
| 
								 | 
							
								            $miniqrcode     = new Miniqrcode;
							 | 
						|||
| 
								 | 
							
								            $miniqrcode->link_id     = $link_id;
							 | 
						|||
| 
								 | 
							
								            $miniqrcode['type'] = $type;
							 | 
						|||
| 
								 | 
							
								            $miniqrcode['status'] = '2';
							 | 
						|||
| 
								 | 
							
								            $miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								             // 获取自增ID
							 | 
						|||
| 
								 | 
							
								            $miniqrcode_id = $miniqrcode->id;
							 | 
						|||
| 
								 | 
							
								            //拼接二维码内容
							 | 
						|||
| 
								 | 
							
								            $path = "{$mock_minicode_url}?link_id={$miniqrcode_id}";
							 | 
						|||
| 
								 | 
							
								               //2生成小程序二维码,并逆解析内容:找到能解析出内容的二维码
							 | 
						|||
| 
								 | 
							
								            while(true)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                $attachment = Common::getMiniappQrCode($path,true,$cache);
							 | 
						|||
| 
								 | 
							
								                $image = $attachment['url'];
							 | 
						|||
| 
								 | 
							
								                $value = $attachment['common_content'];
							 | 
						|||
| 
								 | 
							
								                //解析不出二维码,存入码表,循环下一张
							 | 
						|||
| 
								 | 
							
								                if(!$value){
							 | 
						|||
| 
								 | 
							
								                    //原码更新成失败码
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode  =  Miniqrcode::where("id",$miniqrcode_id)->find();
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['link_id']     = 0;
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['status'] = '1';
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['type'] = 'other';
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['path'] = $path;
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['image'] = $image;
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode['value'] = $value;
							 | 
						|||
| 
								 | 
							
								                    $error_miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                    //1插入新的小程序二维码
							 | 
						|||
| 
								 | 
							
								                    $new_miniqrcode     = new Miniqrcode;
							 | 
						|||
| 
								 | 
							
								                    $new_miniqrcode->link_id     = $link_id;
							 | 
						|||
| 
								 | 
							
								                    $new_miniqrcode['type'] = $type;
							 | 
						|||
| 
								 | 
							
								                    $new_miniqrcode['status'] = '2';
							 | 
						|||
| 
								 | 
							
								                    $new_miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                    //赋值新自增ID
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode_id = $new_miniqrcode->id;
							 | 
						|||
| 
								 | 
							
								                    //拼接新二维码内容
							 | 
						|||
| 
								 | 
							
								                    $path = "{$mock_minicode_url}?link_id={$miniqrcode_id}";
							 | 
						|||
| 
								 | 
							
								                    //开始新一轮循环,直到获取到能解析的二维码为止
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                }else{
							 | 
						|||
| 
								 | 
							
								                //解析得出二维码直接返回
							 | 
						|||
| 
								 | 
							
								                    //3返回表信息
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode  =  Miniqrcode::where("id",$miniqrcode_id)->find();
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode['path'] = $path;
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode['image'] = $image;
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode['value'] = $value;
							 | 
						|||
| 
								 | 
							
								                    $miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								                    break;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return $miniqrcode;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        }catch (\Throwable $e){
							 | 
						|||
| 
								 | 
							
								            throw new \Exception($e->getMessage());
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /** 释放被占用的小程序二维码
							 | 
						|||
| 
								 | 
							
								     * @param $link_id
							 | 
						|||
| 
								 | 
							
								     * @param string $type
							 | 
						|||
| 
								 | 
							
								     * @return bool
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\DataNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\db\exception\ModelNotFoundException
							 | 
						|||
| 
								 | 
							
								     * @throws \think\exception\DbException
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function freeLinkMiniQrCode($link_id,$type = 'mock'){
							 | 
						|||
| 
								 | 
							
								        $miniqrcode =  Miniqrcode::where("link_id",$link_id)->where("type",$type)->find();
							 | 
						|||
| 
								 | 
							
								        if(!$miniqrcode)return true;
							 | 
						|||
| 
								 | 
							
								        $miniqrcode['status']  = '1';
							 | 
						|||
| 
								 | 
							
								        $miniqrcode['link_id']  = 0;
							 | 
						|||
| 
								 | 
							
								        $miniqrcode['type']  = 'other';
							 | 
						|||
| 
								 | 
							
								        $miniqrcode->save();
							 | 
						|||
| 
								 | 
							
								        return true;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**射线与边是否有交点
							 | 
						|||
| 
								 | 
							
								     * @param $poi
							 | 
						|||
| 
								 | 
							
								     * @param $sPoi
							 | 
						|||
| 
								 | 
							
								     * @param $ePoi
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function isRayIntersectsSegment($poi, $sPoi, $ePoi){
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 排除 与射线平行、重合、是一个点的情况
							 | 
						|||
| 
								 | 
							
								    if($sPoi[0] == $ePoi[0])return false;
							 | 
						|||
| 
								 | 
							
								    //# 排除 线段在射线上边
							 | 
						|||
| 
								 | 
							
								    if($sPoi[0] > $poi[0] && $ePoi[0] > $poi[0])return false;
							 | 
						|||
| 
								 | 
							
								    // # 排除 线段在射线下边
							 | 
						|||
| 
								 | 
							
								    if($sPoi[0] < $poi[0] && $ePoi[0] < $poi[0])return false;
							 | 
						|||
| 
								 | 
							
								    // # 排除 交点为下端点
							 | 
						|||
| 
								 | 
							
								    if($sPoi[0] == $poi[0] && $ePoi[0] > $poi[0])return false;
							 | 
						|||
| 
								 | 
							
								    // # 排除 交点为上端点
							 | 
						|||
| 
								 | 
							
								    if($ePoi[0] == $poi[0] && $sPoi[0] > $poi[0])return false;
							 | 
						|||
| 
								 | 
							
								    //  # 排除 线段在射线左边
							 | 
						|||
| 
								 | 
							
								    if($sPoi[1] < $poi[1] && $ePoi[1] < $poi[1])return false;
							 | 
						|||
| 
								 | 
							
								    // # 求交,相似多边形性质
							 | 
						|||
| 
								 | 
							
								        //规避除零异常
							 | 
						|||
| 
								 | 
							
								        $meddle_v = ($sPoi[0] - $ePoi[0]) * ($sPoi[1] - $ePoi[1]);
							 | 
						|||
| 
								 | 
							
								        if($meddle_v == 1)return false;
							 | 
						|||
| 
								 | 
							
								       $xseg = $ePoi[1] + ($poi[0] - $ePoi[0]) / ($sPoi[0] - $ePoi[0]) * ($sPoi[1] - $ePoi[1]);
							 | 
						|||
| 
								 | 
							
								    //  # 交点在射线起点的左侧
							 | 
						|||
| 
								 | 
							
								    if($xseg < $poi[1])return false;
							 | 
						|||
| 
								 | 
							
								    // #  排除上述情况之后真正有效的点
							 | 
						|||
| 
								 | 
							
								    return true;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**地理围栏算法实现-单围栏(射线法:多变遍历)
							 | 
						|||
| 
								 | 
							
								     * @param $poi
							 | 
						|||
| 
								 | 
							
								     * @param $poly
							 | 
						|||
| 
								 | 
							
								     * @return bool
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function poiInPoly($poi, $poly,$count_check=true){
							 | 
						|||
| 
								 | 
							
								       // # 交点个数
							 | 
						|||
| 
								 | 
							
								        $count = 0 ;
							 | 
						|||
| 
								 | 
							
								       // # 逐个二维数组进行判断
							 | 
						|||
| 
								 | 
							
								        $last_index = count($poly)-1; //最后一个数组下标
							 | 
						|||
| 
								 | 
							
								        foreach ($poly as $index=>$epoly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            //最后一个节点
							 | 
						|||
| 
								 | 
							
								           if($last_index == $index){
							 | 
						|||
| 
								 | 
							
								               $e_poi = $poly[$index];
							 | 
						|||
| 
								 | 
							
								               $s_poi = $poly[0];
							 | 
						|||
| 
								 | 
							
								           }else{
							 | 
						|||
| 
								 | 
							
								               //正常节点
							 | 
						|||
| 
								 | 
							
								               $e_poi = $poly[$index];
							 | 
						|||
| 
								 | 
							
								               $s_poi = $poly[$index + 1];
							 | 
						|||
| 
								 | 
							
								           }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            //刚好压在点上
							 | 
						|||
| 
								 | 
							
								            if($poi[0] == $e_poi[0] && $poi[1] == $e_poi[1])return true;
							 | 
						|||
| 
								 | 
							
								            if($poi[0] == $s_poi[0] && $poi[1] == $s_poi[1])return true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            if(self::isRayIntersectsSegment($poi, $e_poi, $s_poi))$count += 1;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        if($count_check)return $count % 2 != 0;
							 | 
						|||
| 
								 | 
							
								        return $count;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**地理围栏算法实现-多围栏(射线法:多变遍历)
							 | 
						|||
| 
								 | 
							
								     * @param $poi
							 | 
						|||
| 
								 | 
							
								     * @param $polys
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function poiInPolyArray($poi, $polys){
							 | 
						|||
| 
								 | 
							
								        // # 交点个数
							 | 
						|||
| 
								 | 
							
								        //记录下包含围栏数
							 | 
						|||
| 
								 | 
							
								        $contain = [];
							 | 
						|||
| 
								 | 
							
								        foreach ($polys as $poly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if(is_string($poly))$poly = json_decode($poly, true);
							 | 
						|||
| 
								 | 
							
								            if(self::poiInPoly($poi, $poly))$contain[] = $poly;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return $contain;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 得到时间标识(当天6点前算当天)
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getTimeflag($change=false,$tomorrow_s=""){
							 | 
						|||
| 
								 | 
							
								        //得到当前时间
							 | 
						|||
| 
								 | 
							
								        $time = time();
							 | 
						|||
| 
								 | 
							
								        if($tomorrow_s){
							 | 
						|||
| 
								 | 
							
								            $tomorrow_string = $tomorrow_s;
							 | 
						|||
| 
								 | 
							
								        }else{
							 | 
						|||
| 
								 | 
							
								            $tomorrow_string = config("site.queue_tomorrow_string") ?: "6:0:0";
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //得到当前六点的时间
							 | 
						|||
| 
								 | 
							
								        $format_six_time = date("Y-m-d {$tomorrow_string}",$time);
							 | 
						|||
| 
								 | 
							
								        //得到当前六点的时间戳
							 | 
						|||
| 
								 | 
							
								        $time_six = strtotime($format_six_time);
							 | 
						|||
| 
								 | 
							
								        //如果小于六点取前一天的六点
							 | 
						|||
| 
								 | 
							
								        if($time < $time_six){
							 | 
						|||
| 
								 | 
							
								            $time_six = strtotime("{$format_six_time} -1 day");
							 | 
						|||
| 
								 | 
							
								        } //如果大于六点取今天的六点的时间戳
							 | 
						|||
| 
								 | 
							
								        //如果是取范围则返回当天时间范围
							 | 
						|||
| 
								 | 
							
								        if($change){
							 | 
						|||
| 
								 | 
							
								            $format_time_end = date("Y-m-d H:i:s",$time_six);
							 | 
						|||
| 
								 | 
							
								            $time_end = strtotime("{$format_time_end} +1 day") - 1; //59分秒时
							 | 
						|||
| 
								 | 
							
								            return ['time_start'=>$time_six,'time_end'=>$time_end];
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        //不是取范围则直接返回
							 | 
						|||
| 
								 | 
							
								        return $time_six;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 下划线转驼峰
							 | 
						|||
| 
								 | 
							
								     * 思路:
							 | 
						|||
| 
								 | 
							
								     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
							 | 
						|||
| 
								 | 
							
								     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function  camelize($uncamelized_words,$separator='_')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        $uncamelized_words = $separator. str_replace($separator, " ", strtolower($uncamelized_words));
							 | 
						|||
| 
								 | 
							
								        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator );
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 驼峰命名转下划线命名
							 | 
						|||
| 
								 | 
							
								     * 思路:
							 | 
						|||
| 
								 | 
							
								     * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function uncamelize($camelCaps,$separator='_')
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**讯飞语音合成
							 | 
						|||
| 
								 | 
							
								     * @param $params
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function xftts($params)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (!isset($params['text']) || empty($params['text'])) {
							 | 
						|||
| 
								 | 
							
								            throw new\Exception('请输入合成文字');
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $config = get_addon_config('xftts');
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        $tts = new Tts();
							 | 
						|||
| 
								 | 
							
								        $url = $tts->createAuthUrl($config['APIKey'], $config['APISecret'], time());
							 | 
						|||
| 
								 | 
							
								        $client = new Client($url);
							 | 
						|||
| 
								 | 
							
								        $message = $tts->createMsg(
							 | 
						|||
| 
								 | 
							
								            $config['APPID'],
							 | 
						|||
| 
								 | 
							
								            $params['text'].",,,,,,,,,,,,,,,,,,,,,,,,,,",
							 | 
						|||
| 
								 | 
							
								            isset($params['ent']) ? $params['ent'] : $config['ent'],
							 | 
						|||
| 
								 | 
							
								            isset($params['aue']) ? $params['aue'] : $config['aue'],
							 | 
						|||
| 
								 | 
							
								            isset($params['auf']) ? $params['auf'] : $config['auf'],
							 | 
						|||
| 
								 | 
							
								            isset($params['vcn']) ? $params['vcn'] : $config['vcn'],
							 | 
						|||
| 
								 | 
							
								            isset($params['speed']) ? $params['speed'] : $config['speed'],
							 | 
						|||
| 
								 | 
							
								            isset($params['volume']) ? $params['volume'] : $config['volume'],
							 | 
						|||
| 
								 | 
							
								            isset($params['pitch']) ? $params['pitch'] : $config['pitch'],
							 | 
						|||
| 
								 | 
							
								            isset($params['bgs']) ? $params['bgs'] : $config['bgs'],
							 | 
						|||
| 
								 | 
							
								            isset($params['tte']) ? $params['tte'] : $config['tte'],
							 | 
						|||
| 
								 | 
							
								            isset($params['reg']) ? $params['reg'] : $config['reg'],
							 | 
						|||
| 
								 | 
							
								            isset($params['ram']) ? $params['ram'] : $config['ram'],
							 | 
						|||
| 
								 | 
							
								            isset($params['rdn']) ? $params['rdn'] : $config['rdn']
							 | 
						|||
| 
								 | 
							
								        );
							 | 
						|||
| 
								 | 
							
								        $params = array_merge($config,$params);
							 | 
						|||
| 
								 | 
							
								        try {
							 | 
						|||
| 
								 | 
							
								            $client->send(json_encode($message, true));
							 | 
						|||
| 
								 | 
							
								            $date = date('YmdHis', time());
							 | 
						|||
| 
								 | 
							
								            $file_name = $date . ($params['aue'] === 'raw' ? '.pcm' : '.mp3');
							 | 
						|||
| 
								 | 
							
								            $folder = '/uploads/tts/';
							 | 
						|||
| 
								 | 
							
								            //判断文件夹是否存在
							 | 
						|||
| 
								 | 
							
								            if (!is_dir(ROOT_PATH . 'public' . $folder)) {
							 | 
						|||
| 
								 | 
							
								                @mkdir(ROOT_PATH . 'public' . $folder);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            $audio_file = fopen(ROOT_PATH . 'public' . $folder . $file_name, 'ab');
							 | 
						|||
| 
								 | 
							
								            $response = $client->receive();
							 | 
						|||
| 
								 | 
							
								            $response = json_decode($response, true);
							 | 
						|||
| 
								 | 
							
								            do {
							 | 
						|||
| 
								 | 
							
								                if ($response['code']) {
							 | 
						|||
| 
								 | 
							
								                    throw new \Exception($response['msg']);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                //返回的音频需要进行base64解码
							 | 
						|||
| 
								 | 
							
								                $audio = base64_decode($response['data']['audio']);
							 | 
						|||
| 
								 | 
							
								                fwrite($audio_file, $audio);
							 | 
						|||
| 
								 | 
							
								                // 第一次消息就收到结束标志的情况
							 | 
						|||
| 
								 | 
							
								                if ($response['data']['status'] == 2) {
							 | 
						|||
| 
								 | 
							
								                    fclose($audio_file);
							 | 
						|||
| 
								 | 
							
								                    $client->close();
							 | 
						|||
| 
								 | 
							
								                    $url = $folder . $file_name;
							 | 
						|||
| 
								 | 
							
								                    $filesize = filesize(ROOT_PATH . 'public' . $url);
							 | 
						|||
| 
								 | 
							
								                    //保存语音数据
							 | 
						|||
| 
								 | 
							
								                    $params['speech_url'] = $url;
							 | 
						|||
| 
								 | 
							
								                    $params['filesize'] = $filesize;
							 | 
						|||
| 
								 | 
							
								                    $params['admin_id'] = 1;
							 | 
						|||
| 
								 | 
							
								                    $result = (new Xftts())->allowField(true)->save($params);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                    return [
							 | 
						|||
| 
								 | 
							
								                        'code' => 0,
							 | 
						|||
| 
								 | 
							
								                        'msg'  => '合成成功',
							 | 
						|||
| 
								 | 
							
								                        'data' => [
							 | 
						|||
| 
								 | 
							
								                            'url'      => $url,
							 | 
						|||
| 
								 | 
							
								                            'full_url'      => cdnurl($url,true),
							 | 
						|||
| 
								 | 
							
								                            'filesize' => $filesize,
							 | 
						|||
| 
								 | 
							
								                            'object'      => Xftts::where('speech_url',$url)->find(),
							 | 
						|||
| 
								 | 
							
								                        ]
							 | 
						|||
| 
								 | 
							
								                    ];
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                //继续接收消息
							 | 
						|||
| 
								 | 
							
								                $response = $client->receive();
							 | 
						|||
| 
								 | 
							
								                $response = json_decode($response, true);
							 | 
						|||
| 
								 | 
							
								            } while ($response['data']['status'] != 2);
							 | 
						|||
| 
								 | 
							
								            fclose($audio_file);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            $url = $folder . $file_name;
							 | 
						|||
| 
								 | 
							
								            $filesize = filesize(ROOT_PATH . 'public' . $url);
							 | 
						|||
| 
								 | 
							
								            //保存语音数据
							 | 
						|||
| 
								 | 
							
								            $params['speech_url'] = $url;
							 | 
						|||
| 
								 | 
							
								            $params['filesize'] = $filesize;
							 | 
						|||
| 
								 | 
							
								            $params['admin_id'] = 1;
							 | 
						|||
| 
								 | 
							
								            $result = (new Xftts())->allowField(true)->save($params);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return [
							 | 
						|||
| 
								 | 
							
								                'code' => 0,
							 | 
						|||
| 
								 | 
							
								                'msg'  => '合成成功',
							 | 
						|||
| 
								 | 
							
								                'data' => [
							 | 
						|||
| 
								 | 
							
								                    'url'      => $url,
							 | 
						|||
| 
								 | 
							
								                    'full_url'      => cdnurl($url,true),
							 | 
						|||
| 
								 | 
							
								                    'filesize' => $filesize,
							 | 
						|||
| 
								 | 
							
								                    'object'      => Xftts::where('speech_url',$url)->find(),
							 | 
						|||
| 
								 | 
							
								                ]
							 | 
						|||
| 
								 | 
							
								            ];
							 | 
						|||
| 
								 | 
							
								        } catch (Exception $e) {
							 | 
						|||
| 
								 | 
							
								            throw new \Exception($e->getMessage(),1);
							 | 
						|||
| 
								 | 
							
								//            return [
							 | 
						|||
| 
								 | 
							
								//                'code' => 1,
							 | 
						|||
| 
								 | 
							
								//                'msg'  => $e->getMessage(),
							 | 
						|||
| 
								 | 
							
								//            ];
							 | 
						|||
| 
								 | 
							
								        } finally {
							 | 
						|||
| 
								 | 
							
								            $client->close();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**得到音频信息  composer require james-heinrich/getid3
							 | 
						|||
| 
								 | 
							
								     * @param $localRelativePath
							 | 
						|||
| 
								 | 
							
								     * @return array
							 | 
						|||
| 
								 | 
							
								     * @throws \getid3_exception
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getAudioInfo($fullPath){
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        $remotefilename = $fullPath;
							 | 
						|||
| 
								 | 
							
								        if ($fp_remote = fopen($remotefilename, 'rb')) {
							 | 
						|||
| 
								 | 
							
								            $localtempfilename = tempnam('/tmp', 'getID3');
							 | 
						|||
| 
								 | 
							
								            if ($fp_local = fopen($localtempfilename, 'wb')) {
							 | 
						|||
| 
								 | 
							
								                while ($buffer = fread($fp_remote, 8192)) {
							 | 
						|||
| 
								 | 
							
								                    fwrite($fp_local, $buffer);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                fclose($fp_local);
							 | 
						|||
| 
								 | 
							
								                // 初始化getID3引擎
							 | 
						|||
| 
								 | 
							
								                $getID3 = new \getID3;
							 | 
						|||
| 
								 | 
							
								                $ThisFileInfo = $getID3->analyze($localtempfilename);
							 | 
						|||
| 
								 | 
							
								                // 删除临时文件
							 | 
						|||
| 
								 | 
							
								                unlink($localtempfilename);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            fclose($fp_remote);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								     return $ThisFileInfo;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /**
							 | 
						|||
| 
								 | 
							
								     * 得到语音播报内容(讯飞语音)
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    public static function getAudioContent($template_content,$params=[],$expression = '{{KEYWORD}}'){
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //解析获取文本内容
							 | 
						|||
| 
								 | 
							
								        $content = self::parsePrintTemplateString($template_content,$params,$expression);
							 | 
						|||
| 
								 | 
							
								        //判断是否存在当前文件
							 | 
						|||
| 
								 | 
							
								        $xftts = Xftts::where("text",$content)->find();
							 | 
						|||
| 
								 | 
							
								        //如果存在,则继续往下走
							 | 
						|||
| 
								 | 
							
								        if(!$xftts){
							 | 
						|||
| 
								 | 
							
								            //如果不存在,则生成文件继续往下走
							 | 
						|||
| 
								 | 
							
								            $audio_info = self::xftts(['text'=> $content]);
							 | 
						|||
| 
								 | 
							
								            $xftts = $audio_info['data']['object'];
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $tts_key = "xftts_{$content}";
							 | 
						|||
| 
								 | 
							
								        //判断是否存在当前播放秒数
							 | 
						|||
| 
								 | 
							
								        $content_seconds = Cache::get($tts_key);
							 | 
						|||
| 
								 | 
							
								        if(!$content_seconds){
							 | 
						|||
| 
								 | 
							
								            //不存在当前秒数则解析当前秒数并存入缓存
							 | 
						|||
| 
								 | 
							
								            $audio_info = self::getAudioInfo(cdnurl($xftts['speech_url'],true));
							 | 
						|||
| 
								 | 
							
								//            var_dump($audio_info['playtime_seconds']);die;
							 | 
						|||
| 
								 | 
							
								            Cache::set($tts_key,$audio_info['playtime_seconds'],3600);
							 | 
						|||
| 
								 | 
							
								            $content_seconds = $audio_info['playtime_seconds'];
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        $xftts['content_seconds'] = $content_seconds;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return $xftts;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								}
							 |