作者 周海龙

合并分支 'develop' 到 'master'

合并生成



查看合并请求 !10

要显示太多修改。

为保证性能只显示 40 of 40+ 个文件。

1 -APP_NAME=Laravel  
2 -APP_ENV=test  
3 -APP_KEY=base64:+ouoKlz2sFDOisnROMRpxT/u9xkZJVrXlzP4cfTqPow=  
4 -APP_DEBUG=false  
5 -APP_URL=http://localhost  
6 -  
7 -LOG_CHANNEL=stack  
8 -LOG_DEPRECATIONS_CHANNEL=null  
9 -LOG_LEVEL=debug  
10 -  
11 -DB_CONNECTION=mysql  
12 -DB_HOST=127.0.0.1  
13 -DB_PORT=3306  
14 -DB_DATABASE=globalso  
15 -DB_USERNAME=debian-sys-maint  
16 -DB_PASSWORD=WtujxV73XIclQet0  
17 -  
18 -BROADCAST_DRIVER=log  
19 -CACHE_DRIVER=file  
20 -FILESYSTEM_DRIVER=local  
21 -QUEUE_CONNECTION=sync  
22 -SESSION_DRIVER=file  
23 -SESSION_LIFETIME=120  
24 -  
25 -MEMCACHED_HOST=127.0.0.1  
26 -  
27 -REDIS_HOST=127.0.0.1  
28 -REDIS_PASSWORD=null  
29 -REDIS_PORT=6379  
30 -  
31 -MAIL_MAILER=smtp  
32 -MAIL_HOST=mailhog  
33 -MAIL_PORT=1025  
34 -MAIL_USERNAME=null  
35 -MAIL_PASSWORD=null  
36 -MAIL_ENCRYPTION=null  
37 -MAIL_FROM_ADDRESS=null  
38 -MAIL_FROM_NAME="${APP_NAME}"  
39 -  
40 -AWS_ACCESS_KEY_ID=  
41 -AWS_SECRET_ACCESS_KEY=  
42 -AWS_DEFAULT_REGION=us-east-1  
43 -AWS_BUCKET=  
44 -AWS_USE_PATH_STYLE_ENDPOINT=false  
45 -  
46 -PUSHER_APP_ID=  
47 -PUSHER_APP_KEY=  
48 -PUSHER_APP_SECRET=  
49 -PUSHER_APP_CLUSTER=mt1  
50 -  
51 -MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"  
52 -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"  
1 /node_modules 1 /node_modules
2 /public/hot 2 /public/hot
3 /public/storage 3 /public/storage
  4 +/public/.user.ini
4 /storage 5 /storage
5 /vendor 6 /vendor
  7 +/uploads
  8 +composer.lock
6 .env 9 .env
7 .env.backup 10 .env.backup
8 .phpunit.result.cache 11 .phpunit.result.cache
@@ -14,4 +17,9 @@ yarn-error.log @@ -14,4 +17,9 @@ yarn-error.log
14 /.idea 17 /.idea
15 /.vscode 18 /.vscode
16 composer.lock 19 composer.lock
17 -app/Console/Commands/Test/Demo.php  
  20 +app/Console/Commands/Test/Demo.php
  21 +/public/upload
  22 +/public/runtime
  23 +public/nginx.htaccess
  24 +public/.htaccess
  25 +.gitignore
  1 +<html>
  2 +<head><title>404 Not Found</title></head>
  3 +<body>
  4 +<center><h1>404 Not Found</h1></center>
  5 +<hr><center>nginx</center>
  6 +</body>
  7 +</html>
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\AyrShare;
  4 +
  5 +use App\Helper\AyrShare as AyrShareHelper;
  6 +use App\Models\AyrShare\AyrShare as AyrShareModel;
  7 +use Illuminate\Console\Command;
  8 +
  9 +class ShareConfig extends Command
  10 +{
  11 + public $error = 0;
  12 + /**
  13 + * The name and signature of the console command.
  14 + *
  15 + * @var string
  16 + */
  17 + protected $signature = 'share_config';
  18 +
  19 + /**
  20 + * The console command description.
  21 + *
  22 + * @var string
  23 + */
  24 + protected $description = '更新用户Ayr_share配置';
  25 + /**
  26 + * @name :(定时执行更新用户配置)handle
  27 + * @author :lyh
  28 + * @method :post
  29 + * @time :2023/5/12 14:48
  30 + */
  31 + public function handle()
  32 + {
  33 + $ayrShareModel = new AyrShareModel();
  34 + //更新用户配置
  35 + $lists = $ayrShareModel->lists($this->map,$this->page,$this->row,'id',['id','profile_key','bind_plat_from']);
  36 + foreach ($lists['list'] as $k => $v){
  37 + if(empty($v['profile_key'])){
  38 + continue;
  39 + }
  40 + //获取当前用户配置
  41 + $ayrShareHelper = new AyrShareHelper();
  42 + $share_info = $ayrShareHelper->get_profiles_users($v['profile_key']);
  43 + if(!isset($share_info['activeSocialAccounts'])){
  44 + $ayrShareModel->edit(['bind_plat_from'=>''],['id'=>$v['id']]);
  45 + continue;
  46 + }
  47 + $str = json_encode($share_info['activeSocialAccounts']);
  48 + if($str != $v['bind_plat_from']){
  49 + $rs = $ayrShareModel->edit(['bind_plat_from'=>$str],['id'=>$v['id']]);
  50 + if($rs === false){
  51 + $this->error++;
  52 + }
  53 + }
  54 + }
  55 + echo $this->error;
  56 + }
  57 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\AyrShare;
  4 +use App\Helper\AyrShare as AyrShareHelper;
  5 +use App\Models\AyrShare\AyrRelease as AyrReleaseModel;
  6 +use Carbon\Carbon;
  7 +use App\Models\AyrShare\AyrShare as AyrShareModel;
  8 +use Illuminate\Console\Command;
  9 +
  10 +class ShareUser extends Command
  11 +{
  12 + public $error = 0;
  13 + /**
  14 + * The name and signature of the console command.
  15 + *
  16 + * @var string
  17 + */
  18 + protected $signature = 'share_user';
  19 +
  20 + /**
  21 + * The console command description.
  22 + *
  23 + * @var string
  24 + */
  25 + protected $description = '用户一周内无记录清除Ayr_share';
  26 + /**
  27 + * @name :(定时执行)handle
  28 + * @author :lyh
  29 + * @method :post
  30 + * @time :2023/5/12 14:48
  31 + */
  32 + public function handle()
  33 + {
  34 + echo $this->user_operator_record();
  35 + }
  36 +
  37 + /**
  38 + * @name : 检测用户是否无操作记录
  39 + * @author :lyh
  40 + * @method :post
  41 + * @time :2023/5/12 14:55
  42 + */
  43 + protected function user_operator_record(){
  44 + //获取所有ayr_share用户
  45 + $ayr_share_model = new AyrShareModel();
  46 + $ayr_release = new AyrReleaseModel();
  47 + $ayr_share_list = $ayr_share_model->list(['profile_key'=>['!=','']]);
  48 + foreach ($ayr_share_list as $v){
  49 + $time = Carbon::now()->modify('-7 days')->toDateString();
  50 + //创建时间小于7天前的当前时间
  51 + if($v['created_at'] > $time){
  52 + continue;
  53 + }
  54 + //查询当前用户是否有未推送的博文
  55 + $release_info = $this->release_info($ayr_release,$v);
  56 + //有推文时,直接跳出循环
  57 + if($release_info !== false){
  58 + continue;
  59 + }
  60 + //查询7天是否发送博文
  61 + $release_info = $this->release_seven_info($ayr_release);
  62 + //有发送博文,则跳出循环
  63 + if($release_info !== false){
  64 + continue;
  65 + }
  66 + //删除用户第三方配置
  67 + if(!empty($v['profile_key'])){
  68 + $this->del_profiles($v);
  69 + }
  70 + //更新数据库
  71 + $this->save_ayr_share($ayr_share_model,$v);
  72 + }
  73 + return $this->error;
  74 + }
  75 +
  76 + /**
  77 + * @name :(删除第三方配置)del_profiles
  78 + * @author :lyh
  79 + * @method :post
  80 + * @time :2023/6/14 16:10
  81 + */
  82 + public function del_profiles($v){
  83 + $ayr_share_helper = new AyrShareHelper();
  84 + $data_profiles = [
  85 + 'title'=>$v['title'],
  86 + 'profileKey'=>$v['profile_key']
  87 + ];
  88 + $res = $ayr_share_helper->deleted_profiles($data_profiles);
  89 + if($res['status'] == 'fail'){
  90 + echo '第三方删除失败';
  91 + return true;
  92 + }
  93 + return true;
  94 + }
  95 +
  96 + /**
  97 + * @name :(更新数据库)save_ayr_share
  98 + * @author :lyh
  99 + * @method :post
  100 + * @time :2023/6/14 16:14
  101 + */
  102 + public function save_ayr_share(&$ayr_share_model,$v){
  103 +
  104 + //更新数据库
  105 + $data = [
  106 + 'title'=>'',
  107 + 'bind_platforms'=>'',
  108 + 'profile_key'=>'',
  109 + 'ref_id'=>'',
  110 + ];
  111 + $res = $ayr_share_model->edit($data,['id'=>$v['id']]);
  112 + if($res == false){
  113 + echo '更新数据库失败';
  114 + return true;
  115 + }
  116 + return true;
  117 + }
  118 +
  119 + /**
  120 + * @name :(查询是否有定时发送报文)info
  121 + * @author :lyh
  122 + * @method :post
  123 + * @time :2023/6/14 16:17
  124 + */
  125 + public function release_info(&$ayr_release,$v){
  126 + //查询当前用户是否有未推送的博文
  127 + $release_info = $ayr_release->read(['schedule_date'=>['>',date('Y-m-d H:i:s',time())],'share_id'=>$v['id']]);
  128 + return $release_info;
  129 + }
  130 +
  131 + /**
  132 + * @param $ayr_release
  133 + * @name :(7天内无发送记录)release_seven_info
  134 + * @author :lyh
  135 + * @method :post
  136 + * @time :2023/6/14 16:28
  137 + */
  138 + public function release_seven_info(&$ayr_release){
  139 + //查看用户是否在一周内有发送博客
  140 + $start_at = Carbon::now()->modify('-7 days')->toDateString();
  141 + $end_at = Carbon::now()->toDateString();
  142 + $release_info = $ayr_release->read(['created_at'=>['between',[$start_at,$end_at]]]);
  143 + return $release_info;
  144 + }
  145 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\DayCount;
  4 +
  5 +use App\Helper\Common;
  6 +use App\Helper\FormGlobalsoApi;
  7 +use App\Models\Project\DeployBuild;
  8 +use App\Models\Project\DeployOptimize;
  9 +use App\Models\Project\Project;
  10 +use Carbon\Carbon;
  11 +use Illuminate\Console\Command;
  12 +use Illuminate\Support\Facades\DB;
  13 +
  14 +class Count extends Command
  15 +{
  16 + const STATUS_ERROR = 400;
  17 + public $error = 0;
  18 + /**
  19 + * The name and signature of the console command.
  20 + *
  21 + * @var string
  22 + */
  23 + protected $signature = 'count';
  24 +
  25 + /**
  26 + * The console command description.
  27 + *
  28 + * @var string
  29 + */
  30 + protected $description = '统计昨日数据';
  31 + /**
  32 + * @name :(定时执行生成昨日数据统计)handle
  33 + * @author :lyh
  34 + * @method :post
  35 + * @time :2023/5/12 14:48
  36 + */
  37 + public function handle()
  38 + {
  39 + $list = DB::table('gl_project')->where('gl_project.extend_type','!=',5)
  40 + ->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
  41 + ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
  42 + ->select($this->selectParam())->get()->toArray();
  43 + $data = [];
  44 + $yesterday = Carbon::yesterday()->toDateString();
  45 + foreach ($list as $v){
  46 + $v = (array)$v;
  47 + if($v['domain'] != ''){
  48 + $v['test_domain'] = $v['domain'];
  49 + }
  50 + $arr = [];
  51 + //统计时间
  52 + $arr['date'] = $yesterday;
  53 + //pv统计
  54 + $arr['pv_num'] = $this->pv_num($yesterday,$v['test_domain']);
  55 + //ip统计
  56 + $arr['ip_num'] = $this->ip_num($yesterday,$v['test_domain']);
  57 + //服务达标天数
  58 + $arr['compliance_day'] = $this->compliance_day($v['test_domain']);
  59 + //剩余服务时常
  60 + $arr['service_day'] = ((int)$v['service_duration'] - (int)$arr['compliance_day']) > 0 ? ((int)$v['service_duration'] - (int)$arr['compliance_day']) : 0;
  61 + //项目id
  62 + $arr['project_id'] = $v['project_id'];
  63 + $arr['created_at'] = date('Y-m-d H:i:s');
  64 + $arr['updated_at'] = date('Y-m-d H:i:s');
  65 + //询盘统计
  66 + $arr = $this->inquiry($arr,$v['test_domain']);
  67 + $data[] = $arr;
  68 + }
  69 + //判断数据是否存在
  70 + DB::table('gl_count')->insert($data);
  71 + echo $this->error;
  72 + }
  73 +
  74 + /**
  75 + * @name :(统计pv)pv_num
  76 + * @author :lyh
  77 + * @method :post
  78 + * @time :2023/6/14 15:40
  79 + */
  80 + public function pv_num($yesterday,$domain){
  81 + $pv = DB::table('gl_customer_visit_item')->whereDate('updated_date', $yesterday)->where('domain',$domain)->count();
  82 + return $pv;
  83 + }
  84 +
  85 + /**
  86 + * @name :(统计ip)ip_num
  87 + * @author :lyh
  88 + * @method :post
  89 + * @time :2023/6/14 15:40
  90 + */
  91 + public function ip_num($yesterday,$domain){
  92 + $ip = DB::table('gl_customer_visit')->whereDate('updated_date', $yesterday)->where('domain',$domain)->count();
  93 + return $ip;
  94 + }
  95 +
  96 + /**
  97 + * @param $arr
  98 + * @param $domain
  99 + * @name :(询盘统计)inquiry
  100 + * @author :lyh
  101 + * @method :post
  102 + * @time :2023/6/14 15:44
  103 + */
  104 + public function inquiry($arr,$domain){
  105 + $inquiry_list = (new FormGlobalsoApi())->getInquiryList($domain,'',1,100000000);
  106 + if($inquiry_list['status'] == self::STATUS_ERROR){
  107 + $arr['inquiry_num'] = 0;
  108 + }else{
  109 + $arr['inquiry_num'] = $inquiry_list['data']['total'];
  110 + //询盘国家统计
  111 + $countryData = $inquiry_list['data']['data'];
  112 + $countryArr = [];
  113 + foreach ($countryData as $v1){
  114 + if(isset($countryArr[$v1['country']])){
  115 + $countryArr[$v1['country']]++;
  116 + }else{
  117 + $countryArr[$v1['country']] = 0;
  118 + }
  119 + }
  120 + arsort($countryArr);
  121 + $top20 = array_slice($countryArr, 0, 20, true);
  122 + $arr['country'] = json_encode($top20);
  123 + }
  124 + return $arr;
  125 + }
  126 +
  127 + /**
  128 + * @param $yesterday
  129 + * @name :(服务达标天数)compliance_day
  130 + * @author :lyh
  131 + * @method :post
  132 + * @time :2023/6/14 15:48
  133 + */
  134 + public function compliance_day($project_id){
  135 + //服务达标天数
  136 + $rank_info = DB::table('gl_rank_data')->where(['project_id'=>$project_id,'lang'=>''])->select(['compliance_day'])->first();
  137 + if(empty($rank_info)){
  138 + $compliance_day = 0;
  139 + }else{
  140 + $compliance_day = $rank_info->compliance_day;
  141 + }
  142 + return $compliance_day;
  143 + }
  144 +
  145 + /**
  146 + * @name :(查询参数设置)selectParam
  147 + * @author :lyh
  148 + * @method :post
  149 + * @time :2023/6/14 15:00
  150 + */
  151 + public function selectParam(){
  152 + $select = [
  153 + 'gl_project.id AS user_id',
  154 + 'gl_project.extend_type AS extend_type',
  155 + 'gl_project_deploy_build.test_domain AS test_domain',
  156 + 'gl_project_deploy_optimize.domain AS domain',
  157 + 'gl_project_deploy_build.project_id AS project_id',
  158 + 'gl_project.cooperate_date AS cooperate_date',
  159 + 'gl_project_deploy_build.service_duration AS service_duration',
  160 + ];
  161 + return $select;
  162 + }
  163 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\DayCount;
  4 +
  5 +use App\Models\Inquiry\InquiryCount as InquiryCountModel;
  6 +use App\Models\Inquiry\InquiryInfo;
  7 +use Carbon\Carbon;
  8 +use Illuminate\Console\Command;
  9 +
  10 +/**
  11 + * @remark :
  12 + * @class :InquiryCount.php
  13 + * @author :lyh
  14 + * @time :2023/7/14 16:20
  15 + */
  16 +class InquiryCount extends Command
  17 +{
  18 + /**
  19 + * The name and signature of the console command.
  20 + *
  21 + * @var string
  22 + */
  23 + protected $signature = 'inquiry_count';
  24 +
  25 + /**
  26 + * The console command description.
  27 + *
  28 + * @var string
  29 + */
  30 + protected $description = '每天统计询盘数量';
  31 +
  32 + /**
  33 + * @var :根据状态统计
  34 + */
  35 + public $status = [
  36 + 1=>'站群询盘',
  37 + 2=>'ai站群询盘',
  38 + 3=>'amp自建平台',
  39 + 4=>'fb询盘',
  40 + 5=>'fb广告',
  41 + 6=>'广告采集建站',
  42 + 7=>'黄金平台询盘',
  43 + 8=>'内部统计',
  44 + 9=>'GlobalImporter',
  45 + 10=>'whatsapp',
  46 + 11=>'Skype',
  47 + 12=>'建站客户',
  48 + 13=>'ChinaCn',
  49 + 14=>'EC21',
  50 + 15=>'邮件群发'
  51 + ];
  52 +
  53 + /**
  54 + * @remark :统计
  55 + * @name :handle
  56 + * @author :lyh
  57 + * @method :post
  58 + * @time :2023/7/14 16:21
  59 + */
  60 + public function handle(){
  61 + $data = [];
  62 + //获取昨天的时间
  63 + $yesterday = Carbon::yesterday()->toDateString();
  64 + $inquiryInfoModel = new InquiryInfo();
  65 + foreach ($this->status as $k=>$v){
  66 + $total = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']]])->count();
  67 + $untreated = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']],'status'=>1])->count();
  68 + $invalid = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']],'status'=>0])->count();
  69 + $data[] = [
  70 + 'type'=>$k,
  71 + 'day'=>$yesterday,
  72 + 'total'=>$total ?? 0,
  73 + 'untreated'=>$untreated ?? 0,
  74 + 'invalid'=>$invalid ?? 0
  75 + ];
  76 + }
  77 + $inquiryCount = new InquiryCountModel();
  78 + $inquiryCount->insert($data);
  79 + return true;
  80 + }
  81 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\DayCount;
  4 +
  5 +use App\Models\Inquiry\InquiryInfo;
  6 +use Illuminate\Console\Command;
  7 +
  8 +/**
  9 + * @remark :
  10 + * @class :InquiryDelay.php
  11 + * @author :lyh
  12 + * @time :2023/7/14 10:16
  13 + */
  14 +class InquiryDelay extends Command
  15 +{
  16 + /**
  17 + * The name and signature of the console command.
  18 + *
  19 + * @var string
  20 + */
  21 + protected $signature = 'inquiry_delay';
  22 +
  23 + /**
  24 + * The console command description.
  25 + *
  26 + * @var string
  27 + */
  28 + protected $description = '延时询盘转发';
  29 +
  30 + /**
  31 + * @remark :延时询盘转发
  32 + * @name :handle
  33 + * @author :lyh
  34 + * @method :post
  35 + * @time :2023/7/14 10:17
  36 + */
  37 + public function handle()
  38 + {
  39 + $inquiryInfoModel = new InquiryInfo();
  40 + $param = $inquiryInfoModel->formatQuery(['status'=>$inquiryInfoModel::STATUS_FOUR])->orderBy('send_time','asc')->first();
  41 + if($param !== false){
  42 + $time = date('Y-m-d H:i:s');
  43 + if($time >= $param['send_time']){
  44 + $data = [];
  45 + //TODO::处理转发的url
  46 + $arr_url = explode(',',$param['forward_url']);
  47 + foreach ($arr_url as $v){
  48 + $data['url'] = $v;
  49 + $this->inquiryForward($data);
  50 + }
  51 + $inquiryInfoModel->edit(['status'=>$inquiryInfoModel::STATUS_THREE],['id'=>$param['id']]);
  52 + }
  53 + }
  54 + return true;
  55 + }
  56 +
  57 + /**
  58 + * @remark :询盘转发
  59 + * @name :inquiryForward
  60 + * @author :lyh
  61 + * @method :post
  62 + * @time :2023/7/13 14:39
  63 + */
  64 + public function inquiryForward($post_data){
  65 + $url = 'https://form.globalso.com/api/external-interface/add/fa043f9cbec6b38f';
  66 + $post_data_new = [];
  67 + $post_data_new['refer'] = $post_data['url'];
  68 + $post_data_new['name'] = $post_data['name'];
  69 + $post_data_new['email'] = $post_data['email'];
  70 + $post_data_new['phone'] = $post_data['phone'];
  71 + $post_data_new['ip'] = $post_data['ip'];
  72 + $post_data_new['message'] = $post_data['message'];
  73 + $post_data_new['submit_time'] = date('Y-m-d H:i:s',time()+20);
  74 + $token = md5($post_data_new['refer'].$post_data_new['name'].$post_data_new['ip'].date("Y-m-d",time()));
  75 + $post_data_new['token'] = $token;
  76 + $header = array(
  77 + 'CLIENT-IP: '.$post_data['ip'],
  78 + 'X-FORWARDED-FOR: '.$post_data['ip']
  79 + );
  80 + return http_post($url,$post_data_new,$header);
  81 + }
  82 +
  83 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands;
  4 +
  5 +
  6 +use App\Models\Devops\DevopsTaskLog;
  7 +use App\Models\Project\Project;
  8 +use Illuminate\Console\Command;
  9 +use App\Models\Devops\DevopsTask as DevopsTaskModel;
  10 +
  11 +/**
  12 + * Class DevopsTask
  13 + * @package App\Console\Commands
  14 + * @author zbj
  15 + * @date 2023/4/25
  16 + */
  17 +class DevopsTask extends Command
  18 +{
  19 + /**
  20 + * The name and signature of the console command.
  21 + *
  22 + * @var string
  23 + */
  24 + protected $signature = 'devops_task';
  25 +
  26 + /**
  27 + * The console command description.
  28 + *
  29 + * @var string
  30 + */
  31 + protected $description = '运维任务执行';
  32 +
  33 + /**
  34 + * Create a new command instance.
  35 + *
  36 + * @return void
  37 + */
  38 + public function __construct()
  39 + {
  40 + parent::__construct();
  41 + }
  42 +
  43 + /**
  44 + * @return bool
  45 + */
  46 + public function handle()
  47 + {
  48 + while (true){
  49 + $tasks = DevopsTaskModel::where('status', DevopsTaskModel::STATUS_PENDING)->get();
  50 + foreach ($tasks as $task){
  51 + echo "Start task " . $task->id . PHP_EOL;
  52 + if($task->type == DevopsTaskModel::TYPE_MYSQL){
  53 + $this->updateTable($task);
  54 + }
  55 + echo "End task " . $task->id . PHP_EOL;
  56 + }
  57 + sleep(10);
  58 + }
  59 + }
  60 +
  61 + public function updateTable($task){
  62 + $projects = Project::all();
  63 + foreach ($projects as $project){
  64 + echo "project " . $project->id;
  65 + $log = DevopsTaskLog::addLog($task->id, $project->id);
  66 + if($log->status == DevopsTaskModel::STATUS_ACTIVE){
  67 + continue;
  68 + }
  69 + if(!$project->mysqlConfig){
  70 + $log->status = DevopsTaskLog::STATUS_ERROR;
  71 + $log->remark = '未配置数据库';
  72 + $log->save();
  73 + continue;
  74 + }
  75 + //DB类是单例模式,生命周期内修改配置不会生效
  76 + $conn = new \mysqli(
  77 + $project->mysqlConfig->host,
  78 + $project->mysqlConfig->user,
  79 + $project->mysqlConfig->password,
  80 + $project->databaseName(),
  81 + $project->mysqlConfig->port,
  82 + );
  83 + $res = $conn->query($task->sql);
  84 +
  85 + $log->status = $res ? DevopsTaskLog::STATUS_ACTIVE : DevopsTaskLog::STATUS_ERROR;
  86 + $log->remark = $res ? '成功' : 'sql执行失败';
  87 + $log->save();
  88 + echo '-->' . $log->remark . PHP_EOL;
  89 + }
  90 + $task->status = DevopsTaskModel::STATUS_ACTIVE;
  91 + $task->save();
  92 + }
  93 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :ImportManager.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2023/8/7 17:47
  8 + */
  9 +
  10 +namespace App\Console\Commands;
  11 +
  12 +use App\Models\Manage\EntryPosition;
  13 +use App\Models\Manage\JobLevel;
  14 +use App\Models\Manage\ManageHr;
  15 +use App\Models\Service\Service;
  16 +use Illuminate\Console\Command;
  17 +use Illuminate\Support\Facades\DB;
  18 +
  19 +class ImportManager extends Command
  20 +{
  21 + /**
  22 + * The name and signature of the console command.
  23 + *
  24 + * @var string
  25 + */
  26 + protected $signature = 'import_manager';
  27 +
  28 + /**
  29 + * The console command description.
  30 + *
  31 + * @var string
  32 + */
  33 + protected $description = '导入数据';
  34 + /**
  35 + * @remark :导入5.0管理员数据
  36 + * @name :handle
  37 + * @author :lyh
  38 + * @method :post
  39 + * @time :2023/8/7 17:49
  40 + */
  41 + public function handle(){
  42 + $model = new Service();
  43 + $info = $model->read(['type'=>5]);
  44 + $values = json_decode($info['values']);
  45 + $values = array_reverse($values);
  46 + foreach ($values as $k => $v){
  47 + $v = (array)$v;
  48 + $data = [
  49 + 'name'=>$v['name'],
  50 + 'mobile'=>$v['mobile'],
  51 + 'password'=>'$2y$10$ZNHxlIddWiQzQbIIzFgYJOsPlQ4n0cwWl8Sea53qvQvDXtu3WeYMC',
  52 + 'created_at'=>date('Y-m-d H:i:s'),
  53 + 'updated_at'=>date('Y-m-d H:i:s'),
  54 + ];
  55 + $manager_id = DB::table('gl_manage')->insertGetId($data);
  56 + if($v['sex'] == '女'){
  57 + $v['sex'] = 2;
  58 + }else{
  59 + $v['sex'] = 1;
  60 + }
  61 + $education = [
  62 + '专科' => 1,
  63 + '大专' => 1,
  64 + '中专' => 0,
  65 + '本科' => 2,
  66 + '自考本科'=>0,
  67 + '全日制本科'=>2,
  68 + '本科在读'=>2,
  69 + '大学本科'=>2,
  70 + '硕士研究生' => 3,
  71 + '硕士'=>3,
  72 + '其他' => 0,
  73 + ];
  74 + $belong_group = [
  75 + '-' => 0,
  76 + 'KA组' => 1,
  77 + 'A组' => 2,
  78 + 'B组' => 3,
  79 + 'C组'=>4,
  80 + 'D组'=>5,
  81 + 'E组'=>6,
  82 + 'F组'=>7,
  83 + 'G组' => 8,
  84 + 'H组'=>9,
  85 + 'GA组' => 10,
  86 + 'GB组' => 11,
  87 + 'GC组' => 12,
  88 + '前端组' => 13,
  89 + '后端组' => 14,
  90 + '黑格组' => 15,
  91 + '售后组' => 16,
  92 + '其他' => 0,
  93 + ];
  94 + //获取入职岗位
  95 + $entryPositionModel = new EntryPosition();
  96 + $entry_position = $entryPositionModel->read(['name'=>$v['entry_position']]);
  97 + if($entry_position !== false){
  98 + $entry_position = $entry_position['id'];
  99 + }else{
  100 + $entry_position = '';
  101 + }
  102 + //获取级别
  103 + $jobLevelModel = new JobLevel();
  104 + $p_level = $jobLevelModel->read(['name'=>$v['p_level']]);
  105 + if($entry_position !== false){
  106 + $p_level = $p_level['id'];
  107 + }else{
  108 + $p_level = '';
  109 + }
  110 + $manager_data = [
  111 + 'manage_id'=>$manager_id ?? '',
  112 + 'name'=>$v['name'],
  113 + 'id_card'=>$v['id_card'],
  114 + 'mobile'=>$v['mobile'],
  115 + 'birthday'=>$v['birthday'],
  116 + 'address'=>$v['address'],
  117 + 'sex'=>$v['sex'],
  118 + 'nationality'=>$v['nationality'],
  119 + 'belong_group'=>$belong_group[$v['belong_group']],
  120 + 'education'=>isset($education[$v['education']]) ? $education[$v['education']] : 0,
  121 + 'major'=>$v['major'],
  122 + 'graduate_school'=>$v['graduate_school'],
  123 + 'english_level'=>$v['english_level'],
  124 + 'entry_position'=>$entry_position,
  125 + 'p_level'=>$p_level,
  126 + 'residential_address'=>$v['residential_address'],
  127 + 'emergency_contact'=>$v['emergency_contact'],
  128 + 'career_history'=>json_encode((array)$v['career_history']),
  129 + 'learning_history'=>json_encode((array)$v['learning_history']),
  130 + 'bank_card'=>$v['bank_card'],
  131 + 'photo_gallery'=>json_encode((array)$v['photo_gallery']),
  132 + 'id_card_gallery'=>json_encode((array)$v['id_card_gallery']),
  133 + 'certificate_gallery'=>json_encode((array)$v['certificate_gallery']),
  134 + 'dangyuan'=>$v['dangyuan'],
  135 + 'dangzhibu'=>$v['dangzhibu'],
  136 + 'dang_address'=>$v['dang_address'],
  137 + 'join_date'=>$v['join_date'],
  138 + 'status'=>($v['status'] == '在职') ? 1 : 2,
  139 + 'computer_account'=>$v['computer_account'],
  140 + 'qq_account'=>$v['qq_account']
  141 + ];
  142 + $hrModel = new ManageHr();
  143 + $hrModel->add($manager_data);
  144 + }
  145 + return 1;
  146 + }
  147 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :ForwardInquiryCount.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2023/8/18 9:41
  8 + */
  9 +
  10 +namespace App\Console\Commands\MonthlyCount;
  11 +
  12 +use App\Models\Inquiry\ForwardCount;
  13 +use Carbon\Carbon;
  14 +use Illuminate\Console\Command;
  15 +use Illuminate\Support\Facades\DB;
  16 +
  17 +/**
  18 + * @remark :转发询盘人员统计
  19 + * @name :ForwardInquiryCount
  20 + * @author :lyh
  21 + * @method :post
  22 + * @time :2023/8/18 9:42
  23 + */
  24 +class ForwardInquiryCount extends Command
  25 +{
  26 + /**
  27 + * The name and signature of the console command.
  28 + *
  29 + * @var string
  30 + */
  31 + protected $signature = 'forward_count';
  32 +
  33 + /**
  34 + * The console command description.
  35 + *
  36 + * @var string
  37 + */
  38 + protected $description = '月转发报告统计';
  39 +
  40 + /**
  41 + * @remark :统计报告
  42 + * @name :handle
  43 + * @author :lyh
  44 + * @method :post
  45 + * @time :2023/8/18 9:52
  46 + */
  47 + public function handle(){
  48 + // 获取上个月的开始时间
  49 + $startTime = Carbon::now()->subMonth()->startOfMonth()->toDateString();
  50 + // 获取上个月的结束时间
  51 + $endTime = Carbon::now()->subMonth()->endOfMonth()->toDateString();
  52 + $list = DB::table('gl_inquiry_info')->groupBy('user_name')
  53 + ->select("user_name",DB::raw('COUNT(*) as count'))
  54 + ->where('send_time','>=',$startTime.' 00:00:00')
  55 + ->where('send_time','<=',$endTime.' 23:59:59')
  56 + ->get();
  57 + if(!empty($list)){
  58 + $list = $list->toArray();
  59 + $forwardModel = new ForwardCount();
  60 + foreach ($list as $v){
  61 + $data = [
  62 + 'date'=>Carbon::now()->subMonth()->format('Y-m'),
  63 + 'name'=>$v['user_name'],
  64 + 'count'=>$v['count']
  65 + ];
  66 + $forwardModel->add($data);
  67 + }
  68 + }
  69 + return 1;
  70 + }
  71 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\MonthlyCount;
  4 +
  5 +use App\Helper\FormGlobalsoApi;
  6 +use Carbon\Carbon;
  7 +use Illuminate\Console\Command;
  8 +use Illuminate\Support\Facades\DB;
  9 +
  10 +class InquiryMonthlyCount extends Command
  11 +{
  12 + const STATUS_ERROR = 400;
  13 + public $error = 0;
  14 + /**
  15 + * The name and signature of the console command.
  16 + *
  17 + * @var string
  18 + */
  19 + protected $signature = 'month_count';
  20 +
  21 + /**
  22 + * The console command description.
  23 + *
  24 + * @var string
  25 + */
  26 + protected $description = '询盘月报告统计';
  27 +
  28 + /**
  29 + * @remark :询盘月报告
  30 + * @name :handle
  31 + * @author :lyh
  32 + * @method :post
  33 + * @time :2023/6/30 9:32
  34 + */
  35 + public function handle(){
  36 + $list = DB::table('gl_project')->where('gl_project.extend_type','!=',5)
  37 + ->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
  38 + ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
  39 + ->select($this->selectParam())->get()->toArray();
  40 + // 获取上个月的开始时间
  41 + $startTime = Carbon::now()->subMonth()->startOfMonth()->toDateString();
  42 + // 获取上个月的结束时间
  43 + $endTime = Carbon::now()->subMonth()->endOfMonth()->toDateString();
  44 + foreach ($list as $value){
  45 + $value = (array)$value;
  46 + if($value['domain'] != ''){
  47 + $value['test_domain'] = $value['domain'];
  48 + }
  49 + $arr = [];
  50 + //按月统计询盘记录
  51 + $arr = $this->inquiryCount($arr,$startTime,$endTime,$value['test_domain']);
  52 + $arr = $this->flowCount($arr,$startTime,$endTime,$value['project_id']);
  53 + $arr = $this->sourceCount($arr,$value['test_domain'],$startTime,$endTime);
  54 + $arr['created_at'] = date('Y-m-d H:i:s');
  55 + $arr['updated_at'] = date('Y-m-d H:i:s');
  56 + $arr['project_id'] = $value['project_id'];
  57 + // 获取当前日期时间
  58 + $arr['month'] = Carbon::now()->subMonth()->format('Y-m');
  59 + DB::table('gl_month_count')->insert($arr);
  60 + }
  61 + return true;
  62 + }
  63 +
  64 + /**
  65 + * @param $domain
  66 + * @param $project_id
  67 + * @remark :询盘按月统计
  68 + * @name :inquiryCount
  69 + * @author :lyh
  70 + * @method :post
  71 + * @time :2023/6/30 14:29
  72 + */
  73 + public function inquiryCount(&$arr,&$startTime,&$endTime,$domain){
  74 + $inquiry_list = (new FormGlobalsoApi())->getInquiryList($domain,'',1,100000000);
  75 + //总数
  76 + $arr['total'] = $inquiry_list['data']['total'] ?? 0;
  77 + //数据详情
  78 + $data = $inquiry_list['data']['data'] ?? 0;
  79 + $arr['month_total'] = 0;
  80 + $countryArr = [];
  81 + $arr['country'] = "";
  82 + if(!empty($data)){
  83 + foreach ($data as $v){
  84 + if(($startTime.' 00:00:00' <= $v['submit_time']) && $v['submit_time'] <= $endTime.' 23:59:59'){
  85 + $arr['month_total']++;
  86 + }
  87 + if(isset($countryArr[$v['country']])){
  88 + $countryArr[$v['country']]++;
  89 + }else{
  90 + $countryArr[$v['country']] = 0;
  91 + }
  92 + }
  93 + arsort($countryArr);
  94 + $top20 = array_slice($countryArr, 0, 15, true);
  95 + $arr['country'] = json_encode($top20);
  96 + }
  97 + return $arr;
  98 + }
  99 +
  100 + /**
  101 + * @remark :流量统计
  102 + * @name :flowCount
  103 + * @author :lyh
  104 + * @method :post
  105 + * @time :2023/6/30 14:31
  106 + */
  107 + public function flowCount(&$arr,&$startTime,&$endTime,$project_id){
  108 + $pv_ip = DB::table('gl_count')
  109 + ->where(['project_id'=>$project_id])
  110 + ->where('date','>=',$startTime.' 00:00:00')
  111 + ->where('date','<=',$endTime.' 23:59:59')
  112 + ->select(DB::raw('SUM(pv_num) as pv_num'), DB::raw('SUM(ip_num) as ip_num'))
  113 + ->first();
  114 + $arr['pv'] = $pv_ip->pv_num;
  115 + $arr['ip'] = $pv_ip->ip_num;
  116 + if($arr['ip'] != 0){
  117 + $arr['rate'] = round(($arr['month_total'] / $arr['ip']) * 10,2);
  118 + }
  119 + return $arr;
  120 + }
  121 +
  122 + /**
  123 + * @remark :来源访问前8
  124 + * @name :sourceCount
  125 + * @author :lyh
  126 + * @method :post
  127 + * @time :2023/6/30 16:14
  128 + */
  129 + public function sourceCount(&$arr,$domain,$startTime,$endTime){
  130 + //访问来源前10
  131 + $source = DB::table('gl_customer_visit')
  132 + ->select('referrer_url', DB::raw('COUNT(*) as count'))
  133 + ->groupBy('referrer_url')->where(['domain'=>$domain])
  134 + ->whereBetween('updated_date', [$startTime,$endTime])
  135 + ->orderByDesc('count')->limit(10)->get()->toArray();
  136 + $arr['source'] = json_encode($source);
  137 + //访问国家前15
  138 + $source_country = DB::table('gl_customer_visit')
  139 + ->select('country',DB::raw('COUNT(*) as ip'),DB::raw('SUM(depth) as pv'))
  140 + ->groupBy('country')->where(['domain'=>$domain])
  141 + ->whereBetween('updated_date', [$startTime,$endTime])
  142 + ->orderBy('ip','desc')->limit(15)->get()->toArray();
  143 + $arr['source_country'] = json_encode($source_country);
  144 + //受访界面前15
  145 + $referrer_url = DB::table('gl_customer_visit')
  146 + ->select('url',DB::raw('COUNT(*) as num'))
  147 + ->orderBy('num','desc')->where(['domain'=>$domain])
  148 + ->whereBetween('updated_date', [$startTime,$endTime])
  149 + ->groupBy('url')
  150 + ->limit(15)->get()->toArray();
  151 + $arr['referrer_url'] = json_encode($referrer_url);
  152 + //访问端口
  153 + $referrer_port = DB::table('gl_customer_visit')
  154 + ->select('device_port',DB::raw('COUNT(*) as num'))
  155 + ->orderBy('num','desc')->where(['domain'=>$domain])
  156 + ->whereBetween('updated_date', [$startTime,$endTime])
  157 + ->groupBy('device_port')
  158 + ->limit(15)->get()->toArray();
  159 + $arr['referrer_port'] = json_encode($referrer_port);
  160 + return $arr;
  161 + }
  162 +
  163 + /**
  164 + * @name :(查询参数设置)selectParam
  165 + * @author :lyh
  166 + * @method :post
  167 + * @time :2023/6/14 15:00
  168 + */
  169 + public function selectParam(){
  170 + $select = [
  171 + 'gl_project.id AS user_id',
  172 + 'gl_project.extend_type AS extend_type',
  173 + 'gl_project_deploy_build.test_domain AS test_domain',
  174 + 'gl_project_deploy_optimize.domain AS domain',
  175 + 'gl_project_deploy_build.project_id AS project_id',
  176 + 'gl_project.cooperate_date AS cooperate_date',
  177 + 'gl_project_deploy_build.service_duration AS service_duration',
  178 + ];
  179 + return $select;
  180 + }
  181 +}
1 -<?php  
2 -/**  
3 - * Created by PhpStorm.  
4 - * User: zhl  
5 - * Date: 2023/4/12  
6 - * Time: 15:33  
7 - */  
8 -namespace App\Console\Commands;  
9 -  
10 -use App\Models\Project;  
11 -use App\Services\ProjectServer;  
12 -use Illuminate\Console\Command;  
13 -use Illuminate\Support\Facades\DB;  
14 -use Illuminate\Support\Facades\Schema;  
15 -  
16 -/**  
17 - * Class ProjectInitDatabase  
18 - * @package App\Console\Commands  
19 - */  
20 -class ProjectInit extends Command  
21 -{  
22 - /**  
23 - * The name and signature of the console command.  
24 - *  
25 - * @var string  
26 - */  
27 - protected $signature = 'project:init';  
28 -  
29 - /**  
30 - * The console command description.  
31 - *  
32 - * @var string  
33 - */  
34 - protected $description = '项目数据库初始化';  
35 -  
36 - protected $connect = null;  
37 -  
38 - /**  
39 - * Create a new command instance.  
40 - *  
41 - * @return void  
42 - */  
43 - public function __construct()  
44 - {  
45 - parent::__construct();  
46 - }  
47 -  
48 - /**  
49 - * @return bool  
50 - */  
51 - public function handle()  
52 - {  
53 - #TODO 通过项目ID获取项目部署数据库配置, 创建数据库, 同步数据表  
54 - $project_id = 102;  
55 - $project = Project::getProjectById($project_id);  
56 - if (empty($project) || empty($project->mysqlConfig()))  
57 - return true;  
58 - $this->initDatabase($project);  
59 -  
60 - return true;  
61 - }  
62 -  
63 - /**  
64 - * @param Project $project  
65 - * @return bool  
66 - */  
67 - public function initDatabase($project)  
68 - {  
69 - $create_flag = $this->createDatabase($project);  
70 -  
71 - if (!$create_flag) {  
72 - // 创建数据库失败 添加通知以及再次处理  
73 - }  
74 - // 设置 database.connections.custom_mysql 数据  
75 - ProjectServer::useProject($project->id);  
76 -  
77 - // TODO 创建对应库 初始化数据表  
78 - $this->initTable();  
79 - return true;  
80 - }  
81 -  
82 - /**  
83 - * @return bool  
84 - */  
85 - public function initTable()  
86 - {  
87 - $database_name = DB::connection('custom_tmp_mysql')->getDatabaseName();  
88 -  
89 - $table = Schema::connection('custom_tmp_mysql')->getAllTables();  
90 - $table = array_column($table, 'Tables_in_' . $database_name);  
91 - foreach ($table as $v) {  
92 - $has_table = Schema::connection('custom_mysql')->hasTable($v);  
93 - if ($has_table)  
94 - continue;  
95 -  
96 - $connection = DB::connection('custom_tmp_mysql');  
97 - $sql = $connection->getDoctrineSchemaManager()  
98 - ->getDatabasePlatform()  
99 - ->getCreateTableSQL($connection->getDoctrineSchemaManager()->listTableDetails($v));  
100 -  
101 - DB::connection('custom_mysql')->select($sql[0]);  
102 - }  
103 - return true;  
104 - }  
105 -  
106 - /**  
107 - * 创建数据库  
108 - * 链接mysql 查询数据库是否存在 创建数据库  
109 - * @param Project $project  
110 - * @return bool|\mysqli_result|null  
111 - */  
112 - public function createDatabase($project)  
113 - {  
114 - # 该方法需要:composer require parity-bit/laravel-db-commands  
115 -// $result = Artisan::call('db:create', [  
116 -// '--database' => $database_name,  
117 -// ]);  
118 -//  
119 -// return $result;  
120 -  
121 - if ($this->connect)  
122 - return $this->connect;  
123 -  
124 - //连接到 MySQL 服务器  
125 - $servername = $project->mysqlConfig()->host;  
126 - $username = $project->mysqlConfig()->user;  
127 - $password = $project->mysqlConfig()->password;  
128 - $conn = new \mysqli($servername, $username, $password);  
129 - //检查连接是否成功  
130 - if ($conn->connect_error) {  
131 - die("连接失败: " . $conn->connect_error);  
132 - }  
133 - $this->connect = $conn;  
134 -// $result = $conn->query('SHOW DATABASES LIKE \'' . $database_name . '\';');  
135 -// if ($result)  
136 -// return true;  
137 - $result = $conn->query('CREATE DATABASE ' . $project->databaseName() . ';');  
138 - return $result;  
139 - }  
140 -}  
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use Illuminate\Console\Command;
  6 +
  7 +/**
  8 + * Class BaseCommands
  9 + * @package App\Console\Commands\RankData
  10 + * @author zbj
  11 + * @date 2023/5/11
  12 + */
  13 +abstract class BaseCommands extends Command
  14 +{
  15 + /**
  16 + * @author zbj
  17 + * @date 2023/5/11
  18 + */
  19 + public function handle()
  20 + {
  21 + $try = 3;
  22 + do{
  23 + $try--;
  24 + if($try == 0){
  25 + break;
  26 + }
  27 +
  28 + $error = 0;
  29 + try {
  30 + if(!$this->do()){
  31 + $error = 1;
  32 + }
  33 + }catch (\Exception $e){
  34 + errorLog($this->signature . ' error', [], $e);
  35 + $error = 1;
  36 + }
  37 +
  38 + if($error){
  39 + echo 'error';
  40 + }
  41 + $error && sleep(60);
  42 + }while($error);
  43 + }
  44 +
  45 + abstract function do();
  46 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\Arr;
  6 +use App\Helper\SemrushApi;
  7 +use App\Models\RankData\ExternalLinks as ExternalLinksModel;
  8 +use App\Models\Project\DeployOptimize;
  9 +
  10 +/**
  11 + * Class ExternalLinks
  12 + * @package App\Console\Commands
  13 + * @author zbj
  14 + * @date 2023/5/9
  15 + */
  16 +class ExternalLinks extends BaseCommands
  17 +{
  18 + /**
  19 + * The name and signature of the console command.
  20 + *
  21 + * @var string
  22 + */
  23 + protected $signature = 'rank_data_external_links';
  24 +
  25 + /**
  26 + * The console command description.
  27 + *
  28 + * @var string
  29 + */
  30 + protected $description = '排名数据-外链数据';
  31 +
  32 + /**
  33 + * @author zbj
  34 + * @date 2023/5/6
  35 + */
  36 + public function do()
  37 + {
  38 + $error = 0;
  39 + $semrushApi = new SemrushApi();
  40 + //有排名api编号的项目
  41 + $list = DeployOptimize::where('api_no', '>', 0)->pluck('domain', 'project_id')->toArray();
  42 +
  43 + foreach ($list as $project_id => $domain) {
  44 + if(!$domain){
  45 + continue;
  46 + }
  47 + $model = ExternalLinksModel::where('project_id', $project_id)->first();
  48 + if ($model && $model->updated_date == getThisWeekStarDate()) {
  49 + continue;
  50 + }
  51 + if (!$model) {
  52 + $model = new ExternalLinksModel();
  53 + }
  54 +
  55 + //外链数据
  56 + $res = $semrushApi->backlinks_overview($domain);
  57 + if (!$res) {
  58 + $error++;
  59 + continue;
  60 + }
  61 +
  62 + $data = $this->_data($project_id, $res['total']);
  63 +
  64 + $model->project_id = $project_id;
  65 + $model->total = $data['total'];
  66 + $model->data = $data['data'];
  67 + $model->updated_date = date('Y-m-d');
  68 + $model->save();
  69 + }
  70 + return !$error;
  71 + }
  72 +
  73 +
  74 + /**
  75 + * 构造chat数据
  76 + * @param $project_id
  77 + * @param $total
  78 + * @return array|mixed
  79 + * @author zbj
  80 + * @date 2023/5/10
  81 + */
  82 + public function _data($project_id, $total)
  83 + {
  84 + // //外链数
  85 + $data['total'] = intval($total);
  86 + $model = ExternalLinksModel::where('project_id', $project_id)->first();
  87 + if ($model) {
  88 + //特殊处理的外链数
  89 +// $data['total'] = ($total > $model->total) ? intval($total) : $model->total; //特殊处理的
  90 +
  91 + //chat数据
  92 + $chat_data = Arr::s2a($model['data']);
  93 + if (empty($chat_data[date('Y-m-d')])) {
  94 + array_shift($chat_data);
  95 + }
  96 + } else {
  97 + //chat数据
  98 + for ($i = 1; $i < 12; $i++) {
  99 + $date = date("Y-m-d", strtotime(-7 * $i . 'days'));
  100 + $chat_data[$date] = ceil($total - ($total * rand(5, 10) / 100));
  101 + }
  102 + }
  103 + $chat_data[date('Y-m-d')] = $data['total'];
  104 + $data['data'] = $chat_data;
  105 + return $data;
  106 + }
  107 +
  108 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\QuanqiusouApi;
  6 +use App\Models\Project\DeployOptimize;
  7 +use App\Models\RankData\IndexedPages as IndexedPagesModel;
  8 +
  9 +/**
  10 + * Class IndexedPages
  11 + * @package App\Console\Commands
  12 + * @author zbj
  13 + * @date 2023/5/11
  14 + */
  15 +class IndexedPages extends BaseCommands
  16 +{
  17 + /**
  18 + * The name and signature of the console command.
  19 + *
  20 + * @var string
  21 + */
  22 + protected $signature = 'rank_data_indexed_pages';
  23 +
  24 + /**
  25 + * The console command description.
  26 + *
  27 + * @var string
  28 + */
  29 + protected $description = '排名数据-页面收录数';
  30 +
  31 + /**
  32 + * @throws \Exception
  33 + * @author zbj
  34 + * @date 2023/5/11
  35 + */
  36 + public function do(){
  37 + $error = 0;
  38 + $api = new QuanqiusouApi();
  39 + //有排名api编号的项目
  40 + $list = DeployOptimize::where('api_no', '>', 0)->pluck('api_no', 'project_id')->toArray();
  41 +
  42 + foreach ($list as $project_id => $api_no) {
  43 + $model = IndexedPagesModel::where('project_id', $project_id)->first();
  44 + if($model && $model->updated_date == getThisWeekStarDate()){
  45 + continue;
  46 + }
  47 +
  48 + if(!$model){
  49 + $model = new IndexedPagesModel();
  50 + }
  51 +
  52 + $res = $api->getSiteResPer($api_no);
  53 + if(!$res){
  54 + $error++;
  55 + continue;
  56 + }
  57 +
  58 + $model->project_id = $project_id;
  59 + $model->data = $res['data'];
  60 + $model->updated_date = date('Y-m-d');
  61 + $model->save();
  62 + }
  63 +
  64 + return !$error;
  65 + }
  66 +
  67 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\Arr;
  6 +use App\Helper\QuanqiusouApi;
  7 +use App\Models\Project\DeployBuild;
  8 +use App\Models\Project\DeployOptimize;
  9 +use App\Models\RankData\RankData as GoogleRankModel;
  10 +
  11 +/**
  12 + * Class GoogleRank
  13 + * @package App\Console\Commands
  14 + * @author zbj
  15 + * @date 2023/5/6
  16 + */
  17 +class RankData extends BaseCommands
  18 +{
  19 + /**
  20 + * The name and signature of the console command.
  21 + *
  22 + * @var string
  23 + */
  24 + protected $signature = 'rank_data';
  25 +
  26 + /**
  27 + * The console command description.
  28 + * The console command description.
  29 + *
  30 + * @var string
  31 + */
  32 + protected $description = '谷歌排名数据';
  33 +
  34 + /**
  35 + * @author zbj
  36 + * @date 2023/5/6
  37 + */
  38 + public function do()
  39 + {
  40 + $error = 0;
  41 + $api = new QuanqiusouApi();
  42 + //有排名api编号的项目
  43 + $list = DeployOptimize::where('api_no', '>' , 0)->select('api_no','minor_languages','project_id')->get();
  44 + //当日所有站点谷歌收录数据
  45 + $site_res = $api->getSiteRes();
  46 + if(!$site_res){
  47 + return false;
  48 + }
  49 + foreach ($list as $item){
  50 + $model = GoogleRankModel::where('project_id', $item['project_id'])->where('lang', '')->first();
  51 + if (!$model || $model->updated_date != date('Y-m-d')) {
  52 + $res = $api->getGoogleRank($item['api_no']);
  53 + if(!$res){
  54 + $error++;
  55 + continue;
  56 + }
  57 + //收录数
  58 + $indexed_pages_num = $site_res[$item['api_no']] ?? 0;
  59 + $this->save_rank($item['project_id'], $res, $indexed_pages_num);
  60 + }
  61 + //有小语种的
  62 + $lang_list = $api->getLangList();
  63 + if(!empty($lang_list[$item['api_no']])){
  64 + $model = GoogleRankModel::where('project_id', $item['project_id'])->where('lang', '<>', '')->first();
  65 + if (!$model || $model->updated_date != date('Y-m-d')) {
  66 + $res = $api->getGoogleRank($item['api_no'], 1);
  67 + if(!$res){
  68 + $error++;
  69 + continue;
  70 + }
  71 + $data = [];
  72 + //不同的小语种取出来
  73 + foreach ($res as $keyword => $v){
  74 + $data[Arr::last($v)['lang']][$keyword] = $v;
  75 + }
  76 + foreach ($data as $lang => $rank){
  77 + $this->save_rank($item['project_id'], $rank, 0, $lang);
  78 + }
  79 + }
  80 + }
  81 + }
  82 + return !$error;
  83 + }
  84 +
  85 + /**
  86 + * @param $project_id
  87 + * @param int $indexed_pages_num
  88 + * @param $data
  89 + * @param string $lang
  90 + * @author zbj
  91 + * @date 2023/5/8
  92 + */
  93 + public function save_rank($project_id, $data, int $indexed_pages_num = 0, string $lang = ''){
  94 + $without_project_ids = []; //不用处理排名的项目
  95 +
  96 + $first_num = $first_page_num = $first_three_pages_num = $first_five_pages_num = $first_ten_pages_num = 0;
  97 +
  98 + if(!$lang){
  99 + foreach ($data as &$ranks){
  100 + ksort($ranks);
  101 + foreach ($ranks as &$rank){
  102 + //处理排名
  103 + if(!in_array($project_id, $without_project_ids)){
  104 + if($rank['position'] >= 10){
  105 + $rank['position'] -= 5;
  106 + }
  107 + //todo 需要特殊处理排名的项目
  108 + }
  109 + }
  110 + $last = Arr::last($ranks);
  111 + //第一名
  112 + if($last['position'] == 1){
  113 + $first_num ++;
  114 + }
  115 + //排名第一页
  116 + if($last['position'] > 0 && $last['position'] <= 10){
  117 + $first_page_num ++;
  118 + }
  119 + //排名前三页
  120 + if($last['position'] > 0 && $last['position'] <= 30){
  121 + $first_three_pages_num ++;
  122 + }
  123 + //排名前五页
  124 + if($last['position'] > 0 && $last['position'] <= 50){
  125 + $first_five_pages_num ++;
  126 + }
  127 + //排名前十页
  128 + if($last['position'] > 0 && $last['position'] <= 100){
  129 + $first_ten_pages_num ++;
  130 + }
  131 + }
  132 + }
  133 +
  134 + $where = [
  135 + 'project_id' => $project_id,
  136 + 'lang' => $lang
  137 + ];
  138 + $model = GoogleRankModel::where($where)->first();
  139 + if(!$model){
  140 + $model = new GoogleRankModel();
  141 + }
  142 +
  143 + //关键词达标天数
  144 + if($model->updated_date != date('Y-m-d')){
  145 + //保证关键词数
  146 + $keyword_num = DeployBuild::where('project_id', $project_id)->value('keyword_num');
  147 + if($first_page_num >= $keyword_num){
  148 + $model->compliance_day = $model->compliance_day + 1;
  149 + }
  150 + }
  151 +
  152 + $model->project_id = $project_id;
  153 + $model->first_num = $first_num;
  154 + $model->first_page_num = $first_page_num;
  155 + $model->first_three_pages_num = $first_three_pages_num;
  156 + $model->first_five_pages_num = $first_five_pages_num;
  157 + $model->first_ten_pages_num = $first_ten_pages_num;
  158 + $model->indexed_pages_num = $indexed_pages_num;
  159 + $model->lang = $lang;
  160 + $model->data = $data;
  161 + $model->updated_date = date('Y-m-d');
  162 + @file_put_contents(storage_path('logs/lyh_error.log'), var_export($model, true) . PHP_EOL, FILE_APPEND);
  163 + $model->save();
  164 + }
  165 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +
  6 +use App\Helper\Arr;
  7 +use App\Helper\QuanqiusouApi;
  8 +use App\Models\Project\DeployOptimize;
  9 +use App\Models\RankData\RankWeek as RankWeekModel;
  10 +
  11 +/**
  12 + * Class WeekRank
  13 + * @package App\Console\Commands
  14 + * @author zbj
  15 + * @date 2023/5/11
  16 + */
  17 +class RankWeek extends BaseCommands
  18 +{
  19 + /**
  20 + * The name and signature of the console command.
  21 + *
  22 + * @var string
  23 + */
  24 + protected $signature = 'rank_data_week';
  25 +
  26 + /**
  27 + * The console command description.
  28 + *
  29 + * @var string
  30 + */
  31 + protected $description = '排名数据-每周排名数据';
  32 +
  33 + /**
  34 + * @author zbj
  35 + * @date 2023/5/6
  36 + */
  37 + public function do()
  38 + {
  39 + $error = 0;
  40 +
  41 + //获取每周排名数据
  42 + $api = new QuanqiusouApi();
  43 +
  44 + $res = $api->getGoogleRankWeek();
  45 + if (!$res) {
  46 + return false;
  47 + }
  48 +
  49 + $res = Arr::s2a($res);
  50 + //有排名api编号的项目
  51 + $list = DeployOptimize::where('api_no', '>', 0)->pluck('api_no', 'project_id')->toArray();
  52 +
  53 + foreach ($list as $project_id => $api_no) {
  54 + $rank_week = RankWeekModel::where('project_id', $project_id)->first();
  55 + if ($rank_week && $rank_week->updated_date == getThisWeekStarDate()) {
  56 + //本周数据已更新
  57 + continue;
  58 + }
  59 +
  60 + if (!$rank_week) {
  61 + $rank_week = new RankWeekModel();
  62 + }
  63 +
  64 + $rank_week->project_id = $project_id;
  65 + $rank_week->data = $res['data'][$api_no];
  66 + $rank_week->date = $res['date'];
  67 + $rank_week->updated_date = date('Y-m-d');
  68 + $rank_week->save();
  69 + }
  70 +
  71 + return !$error;
  72 + }
  73 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\SemrushApi;
  6 +use App\Models\RankData\RecommDomain as RecommDomainModel;
  7 +use App\Models\Project\DeployOptimize;
  8 +
  9 +/**
  10 + * Class RecommDomain
  11 + * @package App\Console\Commands
  12 + * @author zbj
  13 + * @date 2023/5/9
  14 + */
  15 +class RecommDomain extends BaseCommands
  16 +{
  17 + /**
  18 + * The name and signature of the console command.
  19 + *
  20 + * @var string
  21 + */
  22 + protected $signature = 'rank_data_recomm_domain';
  23 +
  24 + /**
  25 + * The console command description.
  26 + *
  27 + * @var string
  28 + */
  29 + protected $description = '排名数据-外链引荐域名数据';
  30 +
  31 + /**
  32 + * @author zbj
  33 + * @date 2023/5/6
  34 + */
  35 + public function do()
  36 + {
  37 + $error = 0;
  38 + $semrushApi = new SemrushApi();
  39 + //有排名api编号的项目
  40 + $list = DeployOptimize::where('api_no', '>', 0)->pluck('domain', 'project_id')->toArray();
  41 +
  42 + foreach ($list as $project_id => $domain) {
  43 + if(!$domain){
  44 + continue;
  45 + }
  46 + $model = RecommDomainModel::where('project_id', $project_id)->first();
  47 + if ($model && $model->updated_date == getThisWeekStarDate()) {
  48 + continue;
  49 + }
  50 + if (!$model) {
  51 + $model = new RecommDomainModel();
  52 + }
  53 +
  54 + //外链引荐域名
  55 + $data = $semrushApi->backlinks_refdomains($domain);
  56 + if (!$data) {
  57 + $error++;
  58 + continue;
  59 + }
  60 +
  61 + $model->project_id = $project_id;
  62 + $model->data = $data;
  63 + $model->updated_date = date('Y-m-d');
  64 + $model->save();
  65 + }
  66 + return !$error;
  67 + }
  68 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\Arr;
  6 +use App\Helper\GoogleSpeedApi;
  7 +use App\Models\Project\DeployOptimize;
  8 +use App\Models\RankData\Speed as GoogleSpeedModel;
  9 +
  10 +/**
  11 + * Class GoogleSpeed
  12 + * @package App\Console\Commands
  13 + * @author zbj
  14 + * @date 2023/5/10
  15 + */
  16 +class Speed extends BaseCommands
  17 +{
  18 + /**
  19 + * The name and signature of the console command.
  20 + *
  21 + * @var string
  22 + */
  23 + protected $signature = 'rank_data_speed';
  24 +
  25 + /**
  26 + * The console command description.
  27 + *
  28 + * @var string
  29 + */
  30 + protected $description = '排名数据-测速数据';
  31 +
  32 +
  33 + /**
  34 + * @author zbj
  35 + * @date 2023/5/10
  36 + */
  37 + public function do()
  38 + {
  39 + $error = 0;
  40 +
  41 + $googleSpeedApi = new GoogleSpeedApi();
  42 +
  43 + //有排名api编号的项目
  44 + $list = DeployOptimize::where('api_no', '>', 0)->pluck('domain', 'project_id')->toArray();
  45 +
  46 + foreach ($list as $project_id => $domain) {
  47 + $model = GoogleSpeedModel::where('project_id', $project_id)->first();
  48 + if ($model && $model->updated_date == getThisWeekStarDate()) {
  49 + //今周已更新 跳过
  50 + continue;
  51 + }
  52 +
  53 + $res = $googleSpeedApi->run($domain);
  54 + if (!$res) {
  55 + $error++;
  56 + continue;
  57 + }
  58 + if (!$model) {
  59 + $model = new GoogleSpeedModel;
  60 + }
  61 + $model->project_id = $project_id;
  62 + $model->data = $res;
  63 + $model->updated_date = date('Y-m-d');
  64 + $model->save();
  65 + }
  66 +
  67 + return !$error;
  68 + }
  69 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands;
  4 +
  5 +
  6 +use App\Helper\OaGlobalsoApi;
  7 +use App\Models\Channel\Channel;
  8 +use App\Models\Channel\User;
  9 +use App\Models\Channel\Zone;
  10 +use Illuminate\Console\Command;
  11 +
  12 +/**
  13 + * 渠道信息
  14 + * Class ChannelInfo
  15 + * @package App\Console\Commands
  16 + * @author zbj
  17 + * @date 2023/6/27
  18 + */
  19 +class SyncChannel extends Command
  20 +{
  21 + /**
  22 + * The name and signature of the console command.
  23 + *
  24 + * @var string
  25 + */
  26 + protected $signature = 'sync_channel';
  27 +
  28 + /**
  29 + * The console command description.
  30 + *
  31 + * @var string
  32 + */
  33 + protected $description = '更新渠道信息';
  34 +
  35 + /**
  36 + * Create a new command instance.
  37 + *
  38 + * @return void
  39 + */
  40 + public function __construct()
  41 + {
  42 + parent::__construct();
  43 + }
  44 +
  45 + /**
  46 + * @return bool
  47 + */
  48 + public function handle()
  49 + {
  50 + $api = new OaGlobalsoApi();
  51 + $res = $api->agents_lists();
  52 + if($res && !empty($res['data'])){
  53 + foreach ($res['data'] as $item){
  54 + $zone = Zone::sync($item['belong']);
  55 + $channel = Channel::sync($item, $zone->id);
  56 + foreach ($item['users'] as $user){
  57 + User::sync($user, $channel->id);
  58 + }
  59 + }
  60 + }
  61 + return true;
  62 + }
  63 +
  64 +
  65 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands;
  4 +
  5 +use App\Helper\Arr;
  6 +use App\Helper\Common;
  7 +use App\Helper\OaGlobalsoApi;
  8 +use App\Models\Channel\Channel;
  9 +use App\Models\Com\NoticeLog;
  10 +use App\Models\Project\After;
  11 +use App\Models\Project\DeployBuild;
  12 +use App\Models\Project\DeployOptimize;
  13 +use App\Models\Project\Payment;
  14 +use App\Models\Project\Project;
  15 +use App\Models\Project\ProjectRenew;
  16 +use App\Utils\LogUtils;
  17 +use Hashids\Hashids;
  18 +use Illuminate\Console\Command;
  19 +use Illuminate\Support\Facades\DB;
  20 +use Illuminate\Support\Facades\Http;
  21 +
  22 +/**
  23 + * 同步项目信息
  24 + * Class ChannelInfo
  25 + * @package App\Console\Commands
  26 + * @author zbj
  27 + * @date 2023/6/27
  28 + */
  29 +class SyncProject extends Command
  30 +{
  31 + /**
  32 + * The name and signature of the console command.
  33 + *
  34 + * @var string
  35 + */
  36 + protected $signature = 'sync_project';
  37 +
  38 + /**
  39 + * The console command description.
  40 + *
  41 + * @var string
  42 + */
  43 + protected $description = '同步项目信息';
  44 +
  45 + /**
  46 + * Create a new command instance.
  47 + *
  48 + * @return void
  49 + */
  50 + public function __construct()
  51 + {
  52 + parent::__construct();
  53 + }
  54 +
  55 + /**
  56 + * @return bool
  57 + */
  58 + public function handle()
  59 + {
  60 + $list = NoticeLog::where('type', NoticeLog::TYPE_PROJECT)->where('status', NoticeLog::STATUS_PENDING)->get();
  61 + foreach ($list as $item){
  62 + try {
  63 + $api = new OaGlobalsoApi();
  64 + $data = $api->order_info($item['data']['order_id']);
  65 + if(!$data || empty($data['data'])){
  66 + LogUtils::error('OaGlobalsoApi order_info error', $data);
  67 + $this->retry($item);
  68 + }
  69 + if($data['data']['order_type'] == '首次'){
  70 + $this->sync($data['data']);
  71 +
  72 + //同步aicc
  73 + if($data['data']['exclusive_aicc']){
  74 + $this->toAicc($data['data']);
  75 + }
  76 + //同步hagro
  77 + if($data['data']['exclusive_hagro']){
  78 + $this->toHagro($data['data']);
  79 + }
  80 + }
  81 + if($data['data']['order_type'] == '续费'){
  82 + $this->renewSync($data['data']);
  83 + }
  84 + $item->status = NoticeLog::STATUS_SUCCESS;
  85 + $item->save();
  86 + }catch (\Exception $e){
  87 + errorLog('项目同步失败', $item, $e);
  88 + $this->retry($item);
  89 + }
  90 + }
  91 + }
  92 +
  93 + /**
  94 + * @param NoticeLog $log
  95 + */
  96 + public function retry($log){
  97 + if($log->retry >= 3){
  98 + $log->status = NoticeLog::STATUS_FAIL;
  99 + }else{
  100 + $log->retry = $log->retry + 1;
  101 + }
  102 + $log->save();
  103 + }
  104 +
  105 + /**
  106 + * @remark :同步续费记录单
  107 + * @name :renewSync
  108 + * @author :lyh
  109 + * @method :post
  110 + * @time :2023/8/11 15:33
  111 + */
  112 + public function renewSync($param){
  113 + $title = date('Ymd') . '-' . $param['company_name'];;
  114 + $data = [
  115 + 'title' => '【续费单】'.$title,
  116 + 'company' => $param['company_name'],
  117 + 'lead_name' => $param['principal_name'],
  118 + 'mobile' => $param['principal_mobile'],
  119 + 'qq' => $param['customer_qq'],
  120 + 'channel' => json_encode(Channel::getProjectChannel($param['company_id'], $param['username_sales'])),
  121 + 'requirement' => $param['remark'],
  122 + 'cooperate_date' => date('Y-m-d', $param['create_time']),
  123 + 'service_duration' => $param['years'],
  124 + 'plan' => $this->versionData($param['plan_marketing']),
  125 +// 'api_no' => $param['id'], //改手动填
  126 + 'amount' => $param['plan_price'],
  127 + 'contract' => json_encode($param['files']),
  128 + 'bill' => json_encode($param['images']),
  129 + ];
  130 + $renewModel = new ProjectRenew();
  131 + $rs = $renewModel->add($data);
  132 + if($rs === false){
  133 + errorLog('项目续费单同步失败');
  134 + }
  135 + return true;
  136 + }
  137 +
  138 + /**
  139 + * @remark :获取版本
  140 + * @name :versionData
  141 + * @author :lyh
  142 + * @method :post
  143 + * @time :2023/8/9 14:46
  144 + */
  145 + public function versionData($param){
  146 + $data = Project::planMap();
  147 + $data = array_flip($data);
  148 + if(isset($data[$param])){
  149 + return $data[$param];
  150 + }else{
  151 + return 1;
  152 + }
  153 + }
  154 +
  155 + /**
  156 + * @remark :导入数据
  157 + * @name :sync
  158 + * @author :lyh
  159 + * @method :post
  160 + * @time :2023/8/9 15:04
  161 + */
  162 + public function sync($param){
  163 + $title = date('Ymd') . '-' . $param['company_name'];
  164 + $data = [
  165 + 'project'=>[
  166 + 'title' => $title,
  167 + 'company' => $param['company_name'],
  168 + 'lead_name' => $param['principal_name'],
  169 + 'mobile' => $param['principal_mobile'],
  170 + 'mysql_id'=>Project::MYSQL_ID,
  171 + 'qq' => $param['customer_qq'],
  172 + 'channel' => Channel::getProjectChannel($param['company_id'], $param['username_sales']),
  173 + 'requirement' => $param['remark'],
  174 + 'cooperate_date' => date('Y-m-d', $param['create_time']),
  175 + 'from_order_id' => $param['from_order_id'],
  176 + 'aicc' => $param['exclusive_aicc'],
  177 + "exclusive_aicc_day" => $param['exclusive_aicc_day'],
  178 + 'hagro' => $param['exclusive_hagro'],
  179 + "exclusive_hagro_day" => $param['exclusive_hagro_day'],
  180 + 'notice_order_id' => $param['id'],
  181 + ],
  182 + 'deploy_build' => [
  183 + 'service_duration' => $param['years'],
  184 + 'plan' => $this->versionData($param['plan_marketing']),
  185 + 'login_mobile'=>$param['principal_mobile']
  186 + ],
  187 + 'deploy_optimize' => [
  188 + 'api_no' => $param['id']
  189 + ],
  190 + 'project_after' => [],
  191 + 'payment' => [
  192 + 'amount' => $param['plan_price'],
  193 + ],
  194 + ];
  195 + if(!empty($param['files'])){
  196 + $data['payment']['contract'] = json_encode($param['files']);
  197 + }
  198 + if(!empty($param['images'])){
  199 + $data['payment']['bill'] = json_encode($param['images']);
  200 + }
  201 + DB::beginTransaction();
  202 + try {
  203 + $id = $this->saveProject($data['project']);
  204 + $this->setPostId($data['deploy_build']['plan'],$id);;
  205 + $this->savePayment($data['payment'],$id);
  206 + $this->saveDeployBuild($data['deploy_build'],$id);
  207 + $this->saveDeployOptimize($data['deploy_optimize'],$id);
  208 + $this->saveAfter($data['project_after'],$id);
  209 + DB::commit();
  210 + }catch (\Exception $e){
  211 + DB::rollBack();
  212 + errorLog('项目同步失败', $data, $e);
  213 + }
  214 + }
  215 +
  216 + /**
  217 + * @remark :设置post_id
  218 + * @name :setPostId
  219 + * @author :lyh
  220 + * @method :post
  221 + * @time :2023/8/9 14:47
  222 + */
  223 + public function setPostId($plan,$id){
  224 + $length = strlen((string)$id); // 获取变量的位数
  225 + $paddingLength = Project::TYPE_FIVE - $length; // 计算填充前面的 0 的位数
  226 + $zeros = str_repeat("0", $paddingLength);
  227 + $number = Project::TYPE_SIX.$plan.$zeros.$id;
  228 + $projectModel = new Project();
  229 + $projectModel->edit(['post_id'=>$number],['id'=>$id]);
  230 + return true;
  231 + }
  232 +
  233 + /**
  234 + * @remark :保存项目
  235 + * @name :saveProject
  236 + * @author :lyh
  237 + * @method :post
  238 + * @time :2023/8/30 15:53
  239 + */
  240 + public function saveProject($param){
  241 + if(isset($param['channel']) && !empty($param['channel'])){
  242 + $param['channel'] = Arr::a2s($param['channel']);
  243 + }
  244 + $projectModel = new Project();
  245 + return $projectModel->addReturnId($param);
  246 + }
  247 +
  248 + /**
  249 + * 保存优化部署
  250 + * @author zbj
  251 + * @date 2023/4/26
  252 + */
  253 + protected function saveAfter($param,$id){
  254 + $param['project_id'] = $id;
  255 + //查询数据是否存在
  256 + $afterModel = new After();
  257 + return $afterModel->add($param);
  258 + }
  259 +
  260 + /**
  261 + * @remark :保存付款续费
  262 + * @name :savePayment
  263 + * @author :lyh
  264 + * @method :post
  265 + * @time :2023/8/29 16:19
  266 + */
  267 + protected function savePayment($param,$id){
  268 + $param['project_id'] = $id;
  269 + $paymentModel= new Payment();
  270 + if(isset($param['contract']) && !empty($param['contract'])){
  271 + $param['contract'] = Arr::a2s($param['contract']);
  272 + }
  273 + if(isset($param['bill']) && !empty($param['bill'])){
  274 + $param['bill'] = Arr::a2s($param['bill']);
  275 + }
  276 + return $paymentModel->add($param);
  277 + }
  278 +
  279 + /**
  280 + * @remark :保存建站部署
  281 + * @name :saveDeployBuild
  282 + * @author :lyh
  283 + * @method :post
  284 + * @time :2023/8/29 16:19
  285 + */
  286 + protected function saveDeployBuild($param,$id){
  287 + $param['project_id'] = $id;
  288 + $hashids = new Hashids('test_domain', 5, 'abcdefghjkmnpqrstuvwxyz1234567890');
  289 + $code = $hashids->encode($id);
  290 + $param['test_domain'] = 'https://v6-' . $code . '.globalso.site/';
  291 + $deployBuildModel = new DeployBuild();
  292 + return $deployBuildModel->add($param);
  293 + }
  294 +
  295 + /**
  296 + * @remark :保存优化信息
  297 + * @name :saveDeployOptimize
  298 + * @author :lyh
  299 + * @method :post
  300 + * @time :2023/8/30 16:11
  301 + */
  302 + protected function saveDeployOptimize($param,$id){
  303 + $param['project_id'] = $id;
  304 + $deployOptimizeModel = new DeployOptimize();
  305 + return $deployOptimizeModel->add($param);
  306 + }
  307 +
  308 + /**
  309 + * 同步到AICC
  310 + * @param $data
  311 + * @author zbj
  312 + * @date 2023/9/1
  313 + */
  314 + protected function toAicc($data){
  315 + $url = 'https://biz.ai.cc/api/sync_company_for_order';
  316 + $param = [
  317 + 'company_name' => $data['company_name'],
  318 + 'company_address' => '',
  319 + 'company_tel' => $data['principal_mobile'],
  320 + 'company_email' => '',
  321 + 'remark' => $data['remark'],
  322 + 'level_id' => 6,
  323 + 'level_day' => $data['exclusive_aicc_day'] ?: 1,
  324 + 'from_order_id' => $data['from_order_id'],
  325 + ];
  326 +
  327 + //sign
  328 + ksort($param);
  329 + $tem = [];
  330 + foreach ($param as $key => $val) {
  331 + $tem[] = $key . '=' . urlencode($val);
  332 + }
  333 + $string = implode('&', $tem);
  334 + $key = md5('quanqiusou.com');
  335 + $param['sign'] = md5($string . $key);
  336 + $res = Http::withoutVerifying()->post($url, $param)->json();
  337 + if(empty($res['status']) || $res['status'] != 200){
  338 + LogUtils::error('ProjectToAicc error', $res);
  339 + }
  340 + }
  341 +
  342 + /**
  343 + * 同步到Hagro
  344 + * @param $data
  345 + * @author zbj
  346 + * @date 2023/9/1
  347 + */
  348 + protected function toHagro($data){
  349 + $url = 'https://beta.hagro.cn/globalso/create_project';
  350 + $param = [
  351 + 'company' => $data['company_name'],
  352 + 'phone' => $data['principal_mobile'],
  353 + 'planday' => $data['exclusive_aicc_day'] ?: 1,
  354 + 'from_order_id' => $data['from_order_id'],
  355 + ];
  356 + $common = new Common();
  357 + $token = $common->encrypt($param);
  358 + $res = Http::withoutVerifying()->get($url, ['token' => $token])->json();
  359 + if(empty($res['code']) || $res['code'] != 200){
  360 + LogUtils::error('ProjectToHagro error', $res);
  361 + }
  362 + }
  363 +}
@@ -7,6 +7,10 @@ @@ -7,6 +7,10 @@
7 */ 7 */
8 namespace App\Console\Commands\Test; 8 namespace App\Console\Commands\Test;
9 9
  10 +use App\Models\Blog\Blog;
  11 +use App\Models\Devops\ServerConfig;
  12 +use App\Models\File\Image;
  13 +use App\Services\ProjectServer;
10 use GuzzleHttp\Client; 14 use GuzzleHttp\Client;
11 use Illuminate\Console\Command; 15 use Illuminate\Console\Command;
12 use Illuminate\Support\Facades\DB; 16 use Illuminate\Support\Facades\DB;
@@ -42,10 +46,18 @@ class Demo extends Command @@ -42,10 +46,18 @@ class Demo extends Command
42 */ 46 */
43 public function handle() 47 public function handle()
44 { 48 {
45 - $sql = 'CREATE DATABASE database_name;';  
46 - $results = DB::select($sql);  
47 - dd($results);  
48 - return true; 49 + echo time() . PHP_EOL;
  50 + $blogModel = new Image();
  51 + $list = $blogModel->list();
  52 + echo time() . PHP_EOL;
  53 + dd(count($list));
  54 +
  55 + return;
  56 + preg_match_all("/\@include\(\"([a-z0-9_]+)\"\)/i",'
  57 +@include("asdf")@include("")@include("asdtrw2erf")
  58 + ',$include);
  59 +
  60 + print_r($include);
49 } 61 }
50 62
51 public function printMessage() 63 public function printMessage()
@@ -86,4 +98,4 @@ class Demo extends Command @@ -86,4 +98,4 @@ class Demo extends Command
86 } 98 }
87 dd(1); 99 dd(1);
88 } 100 }
89 -}  
  101 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\Test;
  4 +
  5 +
  6 +
  7 +
  8 +use App\Helper\Arr;
  9 +use Illuminate\Console\Command;
  10 +use Illuminate\Support\Facades\DB;
  11 +
  12 +class DiffDb extends Command
  13 +{
  14 + protected $signature = 'project:diff_db';
  15 +
  16 + /**
  17 + * The console command description.
  18 + *
  19 + * @var string
  20 + */
  21 + protected $description = '对比数据库结构';
  22 +
  23 + /**
  24 + * Create a new command instance.
  25 + *
  26 + * @return void
  27 + */
  28 + public function __construct()
  29 + {
  30 + parent::__construct();
  31 + }
  32 +
  33 + public function handle()
  34 + {
  35 + $custom_mysql_config = [
  36 + 'database.connections.custom_mysql.host' => '127.0.0.1',
  37 + 'database.connections.custom_mysql.port' => '3306',
  38 + 'database.connections.custom_mysql.database' => 'globalso_project_1',
  39 + 'database.connections.custom_mysql.username' => 'root',
  40 + 'database.connections.custom_mysql.password' => 'root',
  41 + ];
  42 + config($custom_mysql_config);
  43 +
  44 + $this->output->writeln("开始进行数据表对比!");
  45 + $tablesSource = DB::select("show tables");
  46 + $tablesRemote = DB::connection('custom_mysql')->select("show tables");
  47 + $tablesSource = array_map(function($item){
  48 + return Arr::first($item);
  49 + }, $tablesSource);
  50 + $tablesRemote = array_map(function($item){
  51 + return Arr::first($item);
  52 + }, $tablesRemote);
  53 +
  54 +
  55 + $tablesNotInRemote = [];
  56 + $tablesInRemote = [];
  57 +
  58 + foreach ($tablesSource as $t) {
  59 + if (!in_array($t, $tablesRemote)) {
  60 + $tablesNotInRemote[] = $t;
  61 + } else {
  62 + $tablesInRemote[] = $t;
  63 + }
  64 + }
  65 +
  66 + //print reports
  67 + echo "本地存在,但是不在custom_mysql中的表:" . PHP_EOL;
  68 + echo ">>>>>>==================================<<<<<<" . PHP_EOL;
  69 + foreach ($tablesNotInRemote as $t) {
  70 + echo $t . PHP_EOL;
  71 + }
  72 + echo ">>>>>>==================================<<<<<<" . PHP_EOL . PHP_EOL . PHP_EOL;
  73 +
  74 +
  75 + echo "本地与custom_mysql结构不一致的表:" . PHP_EOL;
  76 + echo ">>>>>>==================================<<<<<<" . PHP_EOL;
  77 +
  78 + $only127 = $onlyRemote = $modify127 = [];
  79 + foreach ($tablesInRemote as $t) {
  80 + $columns127 = DB::select("show columns from `{$t}`");
  81 + foreach ($columns127 as &$item){
  82 + $item = get_object_vars($item);
  83 + }
  84 + $columnsRemote = DB::connection('custom_mysql')->select("show columns from `{$t}`");
  85 + foreach ($columnsRemote as &$item){
  86 + $item = get_object_vars($item);
  87 + }
  88 +
  89 + $fields127 = $fieldsRemote = [];
  90 + foreach ($columns127 as $v) {
  91 + $fields127[$v['Field']] = $v;
  92 + }
  93 + foreach ($columnsRemote as $v) {
  94 + $fieldsRemote[$v['Field']] = $v;
  95 + }
  96 +
  97 + foreach ($fields127 as $f => $column) {
  98 + if (!isset($fieldsRemote[$f])) {
  99 + $only127[$t][] = $f;
  100 + } else if ($column !== $fieldsRemote[$f]) {
  101 + dump($column);
  102 + dump($fieldsRemote[$f]);
  103 + $modify127[$t][] = $f;
  104 + }
  105 + }
  106 +
  107 + foreach ($fieldsRemote as $f => $column) {
  108 + if (!isset($fields127[$f])) {
  109 + $onlyRemote[$t][] = $f;
  110 + }
  111 + }
  112 + }
  113 +
  114 + if (!empty($only127)) {
  115 + echo "只本地存在:" . PHP_EOL;
  116 + foreach ($only127 as $t => $columns) {
  117 + echo $t . ":";
  118 + foreach ($columns as $field) {
  119 + echo $field . "\t";
  120 + }
  121 + echo PHP_EOL;
  122 + }
  123 + }
  124 + if (!empty($onlyRemote)) {
  125 + echo "只custom_mysql存在:" . PHP_EOL;
  126 + foreach ($onlyRemote as $t => $columns) {
  127 + echo $t . ":";
  128 + foreach ($columns as $field) {
  129 + echo $field . "\t";
  130 + }
  131 + echo PHP_EOL;
  132 + }
  133 + }
  134 + if (!empty($modify127)) {
  135 + echo "本地更新:" . PHP_EOL;
  136 + foreach ($modify127 as $t => $columns) {
  137 + echo $t . ":";
  138 + foreach ($columns as $field) {
  139 + echo $field . "\t";
  140 + }
  141 + echo PHP_EOL;
  142 + }
  143 + }
  144 + echo ">>>>>>==================================<<<<<<" . PHP_EOL . PHP_EOL . PHP_EOL;
  145 + }
  146 +}
  1 +<?php
  2 +
  3 +namespace App\Console\Commands;
  4 +
  5 +use App\Helper\Arr;
  6 +use App\Models\Product\Category;
  7 +use App\Models\Product\Product;
  8 +use App\Models\RouteMap\RouteMap;
  9 +use GuzzleHttp\Client;
  10 +use GuzzleHttp\Promise\Utils;
  11 +use Illuminate\Console\Command;
  12 +use Illuminate\Support\Facades\DB;
  13 +use Illuminate\Support\Str;
  14 +
  15 +/**
  16 + * 网站引流
  17 + * Class Traffic
  18 + * @package App\Console\Commands
  19 + * @author zbj
  20 + * @date 2023/5/18
  21 + */
  22 +class WebTraffic extends Command
  23 +{
  24 + /**
  25 + * The name and signature of the console command.
  26 + *
  27 + * @var string
  28 + */
  29 + protected $signature = 'web_traffic {type}';
  30 +
  31 + /**
  32 + * The console command description.
  33 + *
  34 + * @var string
  35 + */
  36 + protected $description = '网站引流';
  37 +
  38 + /**
  39 + * Create a new command instance.
  40 + *
  41 + * @return void
  42 + */
  43 + public function __construct()
  44 + {
  45 + parent::__construct();
  46 + }
  47 +
  48 + /**
  49 + * google域名后缀
  50 + * @var string[]
  51 + */
  52 + protected $suffix = [
  53 + 'co.jp' => '日本',
  54 + 'com.tr' => '土耳其',
  55 + 'nl' => '荷兰',
  56 + 'ru' => '俄罗斯',
  57 + 'fr' => '法国',
  58 + 'co.kr' => '韩国',
  59 + 'fi' => '芬兰',
  60 + 'be' => '比利时',
  61 + 'lt' => '立陶宛',
  62 + 'es' => '西班牙',
  63 + 'it' => '意大利',
  64 + 'com.au' => '澳大利亚',
  65 + 'no' => '挪威',
  66 + 'al' => '阿尔巴尼亚',
  67 + 'pt' => '葡萄牙',
  68 + 'lv' => '拉脱维亚',
  69 + 'hu' => '匈牙利',
  70 + 'cz' => '捷克',
  71 + 'de' => '德国',
  72 + 'ca' => '加拿大',
  73 + 'co.in' => '印度',
  74 + 'co.uk' => '英国',
  75 + 'com.vn' => '越南',
  76 + 'com.br' => '巴西',
  77 + 'co.il' => '以色列',
  78 + 'pl' => '波兰',
  79 + 'com.eg' => '埃及',
  80 + 'co.th' => '泰国',
  81 + 'sk' => '斯洛伐克',
  82 + 'ro' => '罗马尼亚',
  83 + 'com.mx' => '墨西哥',
  84 + 'com.my' => '马来西亚',
  85 + 'com.pk' => '巴基斯坦',
  86 + 'co.nz' => '新西兰',
  87 + 'co.za' => '南非',
  88 + 'com.ar' => '阿根廷',
  89 + 'com.kw' => '科威特',
  90 + 'com.sg' => '新加坡',
  91 + 'com.co' => '哥伦比亚',
  92 + 'co.id' => '印度尼西亚',
  93 + 'gr' => '希腊',
  94 + 'bg' => '保加利亚',
  95 + 'mn' => '蒙古',
  96 + 'dk' => '丹麦',
  97 + 'com.sa' => '沙特阿拉伯',
  98 + 'com.pe' => '秘鲁',
  99 + 'com.ph' => '菲律宾',
  100 + 'com.ua' => '乌克兰',
  101 + 'ge' => '格鲁吉亚',
  102 + 'ae' => '阿拉伯联合酋长国',
  103 + 'tn' => '突尼斯',
  104 + ];
  105 +
  106 + /**
  107 + * 概率值
  108 + * @var int[]
  109 + */
  110 + protected $sjjg = [720, 280];//访问间隔占比 访问|不访问
  111 + //访问页面类型占比 产品详情页、单页|产品分类页
  112 + protected $ymzb = [
  113 + 'urls_cats' => 700,
  114 + 'urls_details' => 300
  115 + ];
  116 + protected $sdzb = [600, 200, 150, 50]; //访问页面深度占比 1页|2页|3-6页|7-11页
  117 + protected $yddzb = [1 => 700, 2 => 300]; //移动端占比 pc|mobile
  118 + //模拟访问来源占比 (美国)
  119 + protected $lyzb = [
  120 + 'https://www.google.com/' => 630,
  121 + 'http://www.google.com/' => 30,
  122 + 'http://www.bing.com/' => 20,
  123 + 'https://www.bing.com/' => 5,
  124 + 'https://www.youtube.com/' => 5,
  125 + 'https://search.yahoo.com/' => 5,
  126 + 'https://www.facebook.com/' => 5,
  127 + ];
  128 + protected $otherzb = [700, 300]; //模拟访问来源占比 (非美国) google.com|google.其他后缀
  129 +
  130 + protected $pc_ua = [
  131 + 0 => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
  132 + 1 => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  133 + 2 => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
  134 + ];
  135 +
  136 + protected $mobile_ua = [
  137 + 0 => 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19',
  138 + ];
  139 +
  140 + /**
  141 + * @return bool
  142 + */
  143 + public function handle()
  144 + {
  145 + $type = $this->argument('type');
  146 +
  147 + $this->sleep($type);
  148 +
  149 + $project_list = $this->getProjectList($type);
  150 + $project_chunk = array_chunk($project_list,500,true);
  151 +
  152 + foreach ($project_chunk as $chunk) {
  153 + $need_project = [];
  154 + foreach ($chunk as $project) {
  155 + //随机引流间隔
  156 + $res_sjjg = $this->get_rand($this->sjjg);
  157 + if ($res_sjjg == 1) {
  158 + continue;
  159 + }
  160 +
  161 + $project_urls = $this->getProductUrls($project['project_id']);
  162 + $project_urls['home'] = $project['domain'];
  163 + //随机访问页面
  164 + $project['visit_urls'] = $this->getVisitUrls($project_urls);
  165 + //随机客户端
  166 + $project['device_port'] = $this->get_rand($this->yddzb);
  167 + $project['user_agent'] = $project['device_port'] == 1 ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);
  168 +
  169 + $need_project[] = $project;
  170 + }
  171 +
  172 + //随机访问ip
  173 + $ips = $this->getIpAreas(count($need_project));
  174 + //最多10层深度
  175 + $client = new Client(['verify' => false]);
  176 + for ($j = 0; $j < 10; $j++) {
  177 + for ($j = 0; $j < 10; $j++) {
  178 + //并发请求
  179 + $promises = [];
  180 + foreach ($need_project as $project_key => $project) {
  181 + if (empty($project['visit_urls'][$j])) {
  182 + continue;
  183 + }
  184 +
  185 + $data = [
  186 + 'ip' => $ips[$project_key]['ip'],
  187 + 'referer' => $this->getReferer($ips[$project_key]['ip_area']),
  188 + 'url' => $project['visit_urls'][$j],
  189 + 'device_port' => $this->get_rand($this->yddzb)
  190 + ];
  191 + $promises[] = $client->postAsync($project['domain'] . 'api/customerVisit', ['form_params' => $data]);
  192 + }
  193 + Utils::settle($promises)->wait();
  194 +
  195 + //每个深度随机等待
  196 + sleep(rand(2, 10));
  197 + }
  198 + }
  199 + }
  200 + }
  201 +
  202 + /**
  203 + * 不同项目 休眠
  204 + */
  205 + protected function sleep($type){
  206 + if($type == 1){ //1-3个月的项目
  207 + sleep(rand(5,480));
  208 + }elseif($type == 2){ //4-8个月的项目
  209 + sleep(rand(5,240));
  210 + }elseif($type == 3){ // 大于9个月的项目
  211 + sleep(rand(5,120));
  212 + }
  213 + }
  214 +
  215 + /**
  216 + * 引流的项目
  217 + */
  218 + protected function getProjectList($type){
  219 + //todo 根据type获取需要引流的项目
  220 + return [
  221 + [
  222 + 'project_id' => 1,
  223 + 'domain' => 'https://demomark.globalso.com/',
  224 + ]
  225 + ];
  226 + }
  227 +
  228 + /**
  229 + * 获取产品分类、单页和详情链接
  230 + */
  231 + protected function getProductUrls($project_id){
  232 + //产品分类页面
  233 + $product_cate_ids = Category::where('project_id', $project_id)->where('status', Category::STATUS_ACTIVE)->pluck('id')->toArray();
  234 + $data['urls_cats'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PRODUCT_CATE)->whereIn('source_id', $product_cate_ids)->get()->toArray();
  235 + //单页面
  236 + //todo 发布状态的单页面id
  237 + $data['urls_page'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PAGE)->get()->toArray();
  238 + //产品详情页
  239 + $product_ids = Product::where('project_id', $project_id)->where('status', Product::STATUS_ON)->pluck('id')->toArray();
  240 + $data['urls_details'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PRODUCT)->whereIn('source_id', $product_ids)->get()->toArray();
  241 +
  242 + $data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
  243 + if(empty($data['urls_cats'])){
  244 + $data['urls_cats'] = $data['urls_details'];
  245 + }
  246 +
  247 + return $data;
  248 + }
  249 +
  250 + /**
  251 + * 获取地区IP
  252 + */
  253 + protected function getIpAreas($num)
  254 + {
  255 + //本地时间为7-23点的地区
  256 + $h = date('H');
  257 + $areas = [];
  258 + $list = DB::table('gl_area_timezone')->get();
  259 + foreach ($list as $v) {
  260 + $v = (array)$v;
  261 + $country_hour = $h + $v['diff'];
  262 + if ($country_hour < 0) {
  263 + $country_hour = 24 + $country_hour;
  264 + }
  265 + if ($country_hour >= 7 && $country_hour < 23) {
  266 + $areas[] = $v['name'];
  267 + }
  268 + }
  269 + //根据地区随机取该地区的IP
  270 + $data = DB::table('gl_xunpan_ipdata')->whereIn('ip_area', $areas)->inRandomOrder()->limit($num)->get();
  271 + return Arr::s2a(Arr::a2s($data));
  272 + }
  273 +
  274 + /**
  275 + * 概率算法
  276 + */
  277 + protected function get_rand($proArr) {
  278 + $result = '';
  279 + $proSum = array_sum($proArr);
  280 + foreach ($proArr as $key => $proCur) {
  281 + $randNum = mt_rand(1, $proSum);
  282 + if ($randNum <= $proCur) {
  283 + $result = $key;
  284 + break;
  285 + } else {
  286 + $proSum -= $proCur;
  287 + }
  288 + }
  289 + unset ($proArr);
  290 + return $result;
  291 + }
  292 +
  293 + /**
  294 + * 根据随机访问深度 随机获取访问页面
  295 + */
  296 + protected function getVisitUrls($project_urls){
  297 + //没有分类页 就只访问首页
  298 + if(!$project_urls['urls_cats']){
  299 + $url[] = $project_urls['home'];
  300 + return $url;
  301 + }
  302 + //随机访问深度
  303 + $res_sdzb = $this->get_rand($this->sdzb);
  304 + //随机访问页面类型
  305 + $res_ymzb = $this->get_rand($this->ymzb);
  306 +
  307 + $all_url = array_merge($project_urls['urls_cats'],$project_urls['urls_details']);
  308 + if(!$all_url){
  309 + $url[] = $project_urls['home'];
  310 + return $url;
  311 + }
  312 +
  313 + $url = [];
  314 + if($res_sdzb == 0){//深度一页
  315 + $url[] = $project_urls[$res_ymzb] ? Arr::random($project_urls[$res_ymzb])['route'] : '';
  316 + }elseif($res_sdzb == 1){//深度两页
  317 + $url[] = $project_urls['home'];
  318 + $url[] = $project_urls[$res_ymzb] ? Arr::random($project_urls[$res_ymzb])['route'] : '';
  319 + }elseif($res_sdzb == 2){//深度3-6页
  320 + $yms = rand(2,5); //随机页面数
  321 + $url = Arr::pluck(Arr::random($all_url, $yms), 'route');
  322 + $url = Arr::prepend($url, $project_urls['home']);//首页加到最前面去
  323 + }elseif($res_sdzb == 3){//深度7-11页
  324 + $yms = rand(6,10); //随机页面数
  325 + $url = Arr::pluck(Arr::random($all_url, $yms), 'route');
  326 + $url = Arr::prepend($url, $project_urls['home']);//首页加到最前面去
  327 + }
  328 + foreach ($url as &$v){
  329 + if(!Str::contains($v, $project_urls['home'])){
  330 + $v = $project_urls['home'] . $v;
  331 + }
  332 + }
  333 + return array_unique(array_filter($url));
  334 + }
  335 +
  336 + /**
  337 + * 获取访问来路
  338 + */
  339 + protected function getReferer($ip_area){
  340 + if($ip_area == '美国'){
  341 + $referer = $this->get_rand($this->lyzb);
  342 + }else{
  343 + $referer = 'https://www.google.com/';
  344 +
  345 + $suffix = array_search($ip_area, $this->suffix);
  346 + if($suffix){
  347 + $res_qtzb = $this->get_rand($this->otherzb);
  348 + if($res_qtzb == 1){
  349 + $referer = 'https://www.google.'.$suffix.'/';
  350 + }
  351 + }
  352 + }
  353 + return $referer;
  354 + }
  355 +}
@@ -16,6 +16,25 @@ class Kernel extends ConsoleKernel @@ -16,6 +16,25 @@ class Kernel extends ConsoleKernel
16 protected function schedule(Schedule $schedule) 16 protected function schedule(Schedule $schedule)
17 { 17 {
18 // $schedule->command('inspire')->hourly(); 18 // $schedule->command('inspire')->hourly();
  19 + $schedule->command('rank_data')->dailyAt('01:00')->withoutOverlapping(1); // 排名数据,每天凌晨执行一次
  20 + $schedule->command('rank_data_speed')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-测速数据,每周一凌晨执行一次
  21 + $schedule->command('rank_data_external_links')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-外链,每周一凌晨执行一次
  22 + $schedule->command('rank_data_indexed_pages')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-页面收录,每周一凌晨执行一次
  23 + $schedule->command('rank_data_recomm_domain')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-引荐域名,每周一凌晨执行一次
  24 + $schedule->command('rank_data_week')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据,每周一凌晨执行一次
  25 + $schedule->command('share_user')->dailyAt('01:00')->withoutOverlapping(1); // 清除用户ayr_share数据,每天凌晨1点执行一次
  26 + $schedule->command('count')->dailyAt('01:00')->withoutOverlapping(1); // 清除用户ayr_share数据,每天凌晨1点执行一次
  27 + $schedule->command('web_traffic 1')->everyThirtyMinutes(); // 引流 1-3个月的项目,半小时一次
  28 + $schedule->command('web_traffic 2')->cron('*/18 * * * *'); // 引流 4-8个月的项目,18分钟一次
  29 + $schedule->command('web_traffic 3')->cron('*/12 * * * *'); // 引流 大于9个月的项目,12分钟一次
  30 + $schedule->command('sync_channel')->dailyAt('06:00')->withoutOverlapping(1); // 渠道信息,每周执行一次
  31 + $schedule->command('sync_project')->everyMinute()->withoutOverlapping(1); //同步项目
  32 + $schedule->command('month_count')->monthlyOn(1,'01:00')->withoutOverlapping(1);//没月月初1号执行月统计记录
  33 + $schedule->command('forward_count')->monthlyOn(1,'01:00')->withoutOverlapping(1);//没月月初1号执行月统计转发询盘记录
  34 + $schedule->command('inquiry_delay')->everyMinute()->withoutOverlapping(1);//TODO::上线放开,转发询盘,每分钟执行一次
  35 + $schedule->command('inquiry_count')->dailyAt('01:00')->withoutOverlapping(1); // 询盘统计数据,每天凌晨执行一次
  36 +// // 更新域名|证书结束时间,每天凌晨1点执行一次
  37 +// $schedule->command('domain_time')->dailyAt('01:00')->withoutOverlapping(1);
19 } 38 }
20 39
21 /** 40 /**
@@ -18,4 +18,6 @@ final class Common extends Enum @@ -18,4 +18,6 @@ final class Common extends Enum
18 //端 18 //端
19 const A='a'; 19 const A='a';
20 const B='b'; 20 const B='b';
  21 +
  22 + const MANAGE_TOKEN = 'manage_token:';
21 } 23 }
@@ -21,4 +21,5 @@ class AsideGlobalException extends Exception @@ -21,4 +21,5 @@ class AsideGlobalException extends Exception
21 $this->message = Code::fromValue($code)->description; 21 $this->message = Code::fromValue($code)->description;
22 } 22 }
23 } 23 }
  24 +
24 } 25 }
@@ -21,4 +21,5 @@ class BsideGlobalException extends Exception @@ -21,4 +21,5 @@ class BsideGlobalException extends Exception
21 $this->message = Code::fromValue($code)->description; 21 $this->message = Code::fromValue($code)->description;
22 } 22 }
23 } 23 }
  24 +
24 } 25 }
@@ -3,13 +3,13 @@ @@ -3,13 +3,13 @@
3 namespace App\Exceptions; 3 namespace App\Exceptions;
4 4
5 use App\Enums\Common\Code; 5 use App\Enums\Common\Code;
6 -use App\Enums\Common\Common;  
7 use App\Services\DingService; 6 use App\Services\DingService;
8 use App\Utils\EncryptUtils; 7 use App\Utils\EncryptUtils;
9 use App\Utils\LogUtils; 8 use App\Utils\LogUtils;
10 use Illuminate\Database\Eloquent\ModelNotFoundException; 9 use Illuminate\Database\Eloquent\ModelNotFoundException;
11 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; 10 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
12 use Illuminate\Support\Arr; 11 use Illuminate\Support\Arr;
  12 +use Illuminate\Support\Facades\Cache;
13 use Illuminate\Support\Facades\Route; 13 use Illuminate\Support\Facades\Route;
14 use Illuminate\Validation\ValidationException; 14 use Illuminate\Validation\ValidationException;
15 use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; 15 use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
@@ -59,7 +59,6 @@ class Handler extends ExceptionHandler @@ -59,7 +59,6 @@ class Handler extends ExceptionHandler
59 */ 59 */
60 public function report(Throwable $exception) 60 public function report(Throwable $exception)
61 { 61 {
62 -  
63 //日志记录 62 //日志记录
64 $exceptionMessage = "错误CODE:" . $exception->getCode() . 63 $exceptionMessage = "错误CODE:" . $exception->getCode() .
65 "-----错误message:" . $exception->getMessage() . 64 "-----错误message:" . $exception->getMessage() .
@@ -111,31 +110,26 @@ class Handler extends ExceptionHandler @@ -111,31 +110,26 @@ class Handler extends ExceptionHandler
111 $code = $exception->getCode(); 110 $code = $exception->getCode();
112 }elseif ($exception instanceof BsideGlobalException) { 111 }elseif ($exception instanceof BsideGlobalException) {
113 $code = $exception->getCode(); 112 $code = $exception->getCode();
114 - } elseif ($exception instanceof ValidationException) { 113 + }elseif ($exception instanceof ValidationException) {
115 $code = Code::USER_PARAMS_ERROE(); 114 $code = Code::USER_PARAMS_ERROE();
116 - $message = Arr::first(Arr::first($exception->errors())); 115 + $message = $code->description = Arr::first(Arr::first($exception->errors()));
117 } elseif ($exception instanceof NotFoundHttpException || $exception instanceof MethodNotAllowedHttpException) { 116 } elseif ($exception instanceof NotFoundHttpException || $exception instanceof MethodNotAllowedHttpException) {
118 return response('404 Not Found', 404); 117 return response('404 Not Found', 404);
119 } else { 118 } else {
120 $code = Code::SYSTEM_ERROR(); 119 $code = Code::SYSTEM_ERROR();
121 } 120 }
122 - //钉钉通知错误信息  
123 - if (in_array(config('app.env'), ['test', 'production']) && (in_array(substr($code, 0, 1), ['B', 'C']))) {  
124 - $exceptionMessage = "路由:" . Route::current()->uri .  
125 - "-----错误CODE:" . $exception->getCode() .  
126 - "-----错误message:" . $exception->getMessage() .  
127 - '------错误文件:' . $exception->getFile() . '-------错误行数:' .  
128 - $exception->getLine();  
129 - (new DingService())->handle(['keyword' => "ERROR", 'msg' => config('app.env') . '环境报错:' . $exceptionMessage, 'isAtAll' => false]);  
130 - }  
131 //开启debug 错误原样输出 121 //开启debug 错误原样输出
132 $debub = config('app.debug'); 122 $debub = config('app.debug');
133 $message = $debub ? $message : ($code->description ?? $message); 123 $message = $debub ? $message : ($code->description ?? $message);
134 -  
135 $response = [ 124 $response = [
136 'code' => $code, 125 'code' => $code,
137 'message' => $message 126 'message' => $message
138 ]; 127 ];
  128 + // 调试模式
  129 + if(env('app_debug')){
  130 + $response['trace'] = $exception->getTrace();
  131 + }
  132 +
139 //加密返回 133 //加密返回
140 if (config('app.params_encrypt')) { 134 if (config('app.params_encrypt')) {
141 $k = config('app.params_encrypt_key'); 135 $k = config('app.params_encrypt_key');
1 -<?php  
2 -  
3 -namespace App\Files;  
4 -  
5 -use Illuminate\Http\Request;  
6 -  
7 -class Image  
8 -{  
9 - protected $request = [];  
10 -  
11 - public function __construct(Request $request)  
12 - {  
13 - $this->request = $request;  
14 - }  
15 -  
16 - /**  
17 - * @name :上传图片  
18 - * @return void  
19 - * @author :liyuhang  
20 - * @method  
21 - */  
22 - public function uploads(){  
23 - $url = './uploads/images/';  
24 - $param = $this->request->post();  
25 - if($this->request->hasFile('image') && $this->request->file('image')->isValid()){  
26 - $filename = date('ymdHis').rand(10000,99999).$this->request->file('image');  
27 - $this->request->file('image')->move('./uploads/images/',$filename);  
28 - }else{  
29 - return false;  
30 - }  
31 - return $url.$filename;  
32 - }  
33 -}  
  1 +<?php
  2 +
  3 +namespace App\Helper;
  4 +
  5 +class AliSms
  6 +{
  7 +
  8 + private $_msg = array( //状态对照
  9 + 1 => "发送成功",
  10 + 0 => "其他系统错误",
  11 + -1 => "短信余额不足",
  12 + -2 => "资金账户被锁定",
  13 + -3 => "用户被锁定",
  14 + -4 => "号码在黑名单内",
  15 + -5 => "用户名或密码不正确",
  16 + -6 => "号码不正确",
  17 + -7 => "接口连接失败",
  18 + -8 => "号码格式错误",
  19 + -9 => "通道编号错误",
  20 + -10 => "定时发送时间不正确",
  21 + -11 => "没有输入短信内容",
  22 + -12 => "短信内容超出长度限制",
  23 + -15 => "内容含非法关键字",
  24 + -16 => "超出发送时间范围",
  25 + -17 => "通道被关闭",
  26 + -18 => "短信内容没有签名",
  27 + -30 => "手机未认证",
  28 + -31 => "身份未认证",
  29 + -32 => "请勿重复发送",
  30 + -33 => "验证码已过期,请重新获取",
  31 + -34 => "手机号码格式不正确",
  32 + -35 => "验证码不正确",
  33 + );
  34 + // 保存错误信息
  35 + public $error;
  36 + public $_code = "";
  37 + public $_name = "";
  38 + public $_key_str = ""; // cache full name.
  39 + protected $_expire = 600; // 验证码过期时间(s)
  40 + public $_key = [
  41 + ];
  42 + // Access Key ID
  43 + private $accessKeyId = '';
  44 + // Access Key Secret
  45 + private $accessKeySecret = '';
  46 + // 签名
  47 + private $signName = '';
  48 + // 模版ID
  49 + public $templateCode = '';
  50 +
  51 + public function __construct($config = array())
  52 + {
  53 + $config = array(
  54 + 'accessKeyId' => config('aliyunsms.access_key'),
  55 + 'accessKeySecret' => config('aliyunsms.access_secret'),
  56 + 'signName' => config('aliyunsms.sign_name'),
  57 + 'templateCode' => config('aliyunsms.login_sms_temp'),
  58 + );
  59 + // 配置参数
  60 + $this->accessKeyId = $config['accessKeyId'];
  61 + $this->accessKeySecret = $config['accessKeySecret'];
  62 + $this->signName = $config['signName'];
  63 + $this->templateCode = $config['templateCode'];
  64 + }
  65 +
  66 + /**
  67 + * 规范化字符串以符合阿里云短信接口
  68 + * @param $string
  69 + * @return mixed|string
  70 + */
  71 + private function percentEncode($string)
  72 + {
  73 + $string = urlencode($string);
  74 + $string = preg_replace('/\+/', '%20', $string);
  75 + $string = preg_replace('/\*/', '%2A', $string);
  76 + $string = preg_replace('/%7E/', '~', $string);
  77 + return $string;
  78 + }
  79 +
  80 + /**
  81 + * 签名
  82 + *
  83 + * @param unknown $parameters
  84 + * @param unknown $accessKeySecret
  85 + * @return string
  86 + */
  87 + private function computeSignature($parameters, $accessKeySecret)
  88 + {
  89 + ksort($parameters);
  90 + $canonicalizedQueryString = '';
  91 + foreach ($parameters as $key => $value) {
  92 + $canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
  93 + }
  94 + $stringToSign = 'GET&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
  95 + $signature = base64_encode(hash_hmac('sha1', $stringToSign, $accessKeySecret . '&', true));
  96 + return $signature;
  97 + }
  98 +
  99 + /**
  100 + * 发送验证码 https://help.aliyun.com/document_detail/44364.html?spm=5176.doc44368.6.126.gSngXV
  101 + *
  102 + * @param unknown $mobile
  103 + * @param unknown $verify_code
  104 + *
  105 + */
  106 + public function send_sms($mobile, $paramstring)
  107 + {
  108 + $params = array(
  109 + // 公共参数
  110 + 'SignName' => $this->signName,
  111 + 'Format' => 'JSON',
  112 + 'Version' => '2016-09-27',
  113 + 'AccessKeyId' => $this->accessKeyId,
  114 + 'SignatureVersion' => '1.0',
  115 + 'SignatureMethod' => 'HMAC-SHA1',
  116 + 'SignatureNonce' => uniqid(),
  117 + 'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
  118 + // 接口参数
  119 + 'Action' => 'SingleSendSms',
  120 + 'TemplateCode' => $this->templateCode,
  121 + 'RecNum' => $mobile,
  122 + 'ParamString' => $paramstring,
  123 + );
  124 + // 计算签名并把签名结果加入请求参数
  125 + $params['Signature'] = $this->computeSignature($params, $this->accessKeySecret);
  126 +
  127 + // 发送请求
  128 + $url = 'https://sms.aliyuncs.com/?' . http_build_query($params);
  129 + $result = http_get($url); //TODO:上线前打开
  130 + if (isset($result['Code'])) {
  131 + $this->error = $this->getErrorMessage($result['Code']);
  132 + return false;
  133 + }
  134 + return true;
  135 + }
  136 +
  137 + /**
  138 + * 发送验证码 https://help.aliyun.com/document_detail/44364.html?spm=5176.doc44368.6.126.gSngXV
  139 + *
  140 + * @param unknown $mobile
  141 + * @param unknown $verify_code
  142 + *
  143 + */
  144 + public function send_verify($mobile)
  145 + {
  146 + if ($this->checkMobile($mobile) === false) {
  147 + $this->error = $this->_msg[-34];
  148 + return -34;
  149 + }
  150 + $session = cache($this->_key_str . $mobile);
  151 + if ($session && time() - $session['time'] < 60) {
  152 + if ($session['code'] == null) {
  153 + return true;
  154 + } else {
  155 + $this->error = $this->_msg[-32];
  156 + return -32;
  157 + }
  158 + }
  159 + $this->_code = rand(1000, 9999);
  160 + $params = array(
  161 + // 公共参数
  162 + 'SignName' => $this->signName,
  163 + 'Format' => 'JSON',
  164 + 'Version' => '2016-09-27',
  165 + 'AccessKeyId' => $this->accessKeyId,
  166 + 'SignatureVersion' => '1.0',
  167 + 'SignatureMethod' => 'HMAC-SHA1',
  168 + 'SignatureNonce' => uniqid(),
  169 + 'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
  170 + // 接口参数
  171 + 'Action' => 'SingleSendSms',
  172 + 'TemplateCode' => $this->templateCode,
  173 + 'RecNum' => $mobile,
  174 + 'ParamString' => '{"msgcode":"' . $this->_code . '"}',
  175 + );
  176 + // 计算签名并把签名结果加入请求参数
  177 + $params['Signature'] = $this->computeSignature($params, $this->accessKeySecret);
  178 + // 发送请求
  179 + $url = 'https://sms.aliyuncs.com/?' . http_build_query($params);
  180 + $result = http_get($url); //TODO:上线前打开
  181 + // $result =1;
  182 + if ($result) {
  183 + $session = array();
  184 + $session['code'] = $this->_code; // 把校验码保存到session
  185 + $session['time'] = time(); // 验证码创建时间
  186 + cache($this->_key_str . $mobile, $session, $this->_expire);
  187 + } else {
  188 + return $this->error = $this->_msg[0];
  189 + }
  190 + if (isset($result['Code'])) {
  191 + $this->error = $this->getErrorMessage($result['Code']);
  192 + return false;
  193 + }
  194 + return true;
  195 + }
  196 + /**
  197 + * 验证手机号码
  198 + */
  199 + public function checkMobile($tel)
  200 + {
  201 + if (preg_match("/^1[3,4,6,5,8,7,9][0-9]{1}[0-9]{8}$/", $tel)) {
  202 + //验证通过
  203 + return true;
  204 + } else {
  205 + $this->error = $this->_msg[-34];
  206 + //手机号码格式不对
  207 + return false;
  208 + }
  209 + }
  210 +
  211 + /**
  212 + * 验证码是否正确
  213 + * @param string $key 手机号码
  214 + * @param int|string $code 验证码
  215 + * @param int|string $type 类型 reg-注册时获取 sms-快速登录时 pwd-修改密码时 bind-绑定手机时 unbind-解绑时
  216 + * @return boolean 验证短信验证码是否正确
  217 + */
  218 + public function check($key, $code, $type = 'reg')
  219 + {
  220 + $this->_key_str = $type . '_' . $key;
  221 + $session = cache($this->_key_str);
  222 + if (empty($code) || empty($session)) {
  223 + $this->error = $this->_msg[-33] . $this->_key_str;
  224 + return false;
  225 + }
  226 + if (time() - $session['time'] > $this->_expire) {
  227 + cache($this->_key_str, null);
  228 + $this->error = $this->_msg[-33] . $this->_key_str;
  229 + return false;
  230 + }
  231 + if ($code == $session['code']) {
  232 + return true;
  233 + }
  234 + $this->error = $this->_msg[-35] . $this->_key_str;
  235 + return false;
  236 + }
  237 +
  238 + /**
  239 + * 验证成功后调用清空验证码
  240 + */
  241 + public function afterCheck()
  242 + {
  243 + cache($this->_key_str, null);
  244 + }
  245 +
  246 + /**
  247 + * 获取详细错误信息
  248 + *
  249 + * @param unknown $status
  250 + */
  251 + public function getErrorMessage($status)
  252 + {
  253 +
  254 + $message = array(
  255 + 'InvalidDayuStatus.Malformed' => '账户短信开通状态不正确',
  256 + 'InvalidSignName.Malformed' => '短信签名不正确或签名状态不正确',
  257 + 'InvalidTemplateCode.MalFormed' => '短信模板Code不正确或者模板状态不正确',
  258 + 'InvalidRecNum.Malformed' => '目标手机号不正确,单次发送数量不能超过100',
  259 + 'InvalidParamString.MalFormed' => '短信模板中变量不是json格式',
  260 + 'InvalidParamStringTemplate.Malformed' => '短信模板中变量与模板内容不匹配',
  261 + 'InvalidSendSms' => '1小时只能请求7次,谢谢',
  262 + 'InvalidDayu.Malformed' => '变量不能是url,可以将变量固化在模板中',
  263 + );
  264 + return $status;
  265 + }
  266 +
  267 + private function _addlog($name, $title)
  268 + {
  269 + $this->_keys["code"] = $this->_code;
  270 +// addlog($this->_keys, $title, 1, $this->_url);
  271 + }
  272 +}
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
3 namespace App\Helper; 3 namespace App\Helper;
4 4
5 5
  6 +use Illuminate\Support\Collection;
  7 +
6 /** 8 /**
7 * 数组类函数 9 * 数组类函数
8 * Class Arrays 10 * Class Arrays
@@ -125,4 +127,89 @@ class Arr extends \Illuminate\Support\Arr @@ -125,4 +127,89 @@ class Arr extends \Illuminate\Support\Arr
125 127
126 return $signle ? $rows[0] : $rows; 128 return $signle ? $rows[0] : $rows;
127 } 129 }
  130 +
  131 +
  132 + /**
  133 + * 数组转字符串
  134 + * @param $arr
  135 + * @return string
  136 + * @author zbj
  137 + * @date 2023/4/17
  138 + */
  139 + public static function a2s($arr): string
  140 + {
  141 + return json_encode($arr, JSON_UNESCAPED_UNICODE);
  142 + }
  143 +
  144 +
  145 + /**
  146 + * 字符串转数组
  147 + * @param $str
  148 + * @return array|mixed
  149 + * @author zbj
  150 + * @date 2023/4/17
  151 + */
  152 + public static function s2a($str)
  153 + {
  154 + if (is_array($str)) {
  155 + return $str;
  156 + }
  157 + return is_object($str) ? (array)$str : json_decode($str, true);
  158 + }
  159 +
  160 +
  161 + /**
  162 + * 数组转set形式字符串
  163 + * @param $arr
  164 + * @param string $format
  165 + * @return string
  166 + * @author zbj
  167 + * @date 2023/4/17
  168 + */
  169 + public static function arrToSet($arr, string $format = 'intval'): string
  170 + {
  171 + $arr = array_unique(array_filter(Arr::splitFilterToArray($arr, $format, ',')));
  172 + return $arr ? implode(',', $arr) : '';
  173 + }
  174 +
  175 + /**
  176 + * set形式字符串转数组
  177 + * @param $str
  178 + * @param string $format
  179 + * @return array
  180 + * @author zbj
  181 + * @date 2023/4/17
  182 + */
  183 + public static function setToArr($str, string $format = 'intval')
  184 + {
  185 + if (is_string($str)) {
  186 + return Arr::splitFilterToArray($str, $format, ',');
  187 + }
  188 + return $str ?: [];
  189 + }
  190 +
  191 +
  192 + /**
  193 + * 将数组设置成某个键的值
  194 + * @param $arr
  195 + * @param $key
  196 + * @return array
  197 + * @author zbj
  198 + * @date 2023/5/16
  199 + */
  200 + public static function setValueToKey($arr, $key)
  201 + {
  202 + $data = [];
  203 + if (!$arr) {
  204 + return $data;
  205 + }
  206 + foreach ($arr as $v) {
  207 + $data[$v[$key]] = $v;
  208 + }
  209 +
  210 + if ($arr instanceof Collection) {
  211 + $data = new Collection($data);
  212 + }
  213 + return $data;
  214 + }
128 } 215 }
  1 +<?php
  2 +
  3 +namespace App\Helper;
  4 +
  5 +use GuzzleHttp\Client;
  6 +
  7 +/**
  8 + * @name: ayr_share社交绑定
  9 + */
  10 +class AyrShare
  11 +{
  12 + public $path = 'https://app.ayrshare.com';
  13 + //api_key
  14 + public $api_key = 'G8GQW3X-XBTMGXW-QPDDZ9A-WE1Z5SB';
  15 + //系统设置
  16 + public $config = [
  17 + 'facebook'=>'#best https://www.facebook.com',
  18 + 'google'=>'#best https://www.google.com',
  19 + 'instagram'=>'#best https://www.instagram.com',
  20 + 'linkedin'=>'#best https://www.linkedin.com',
  21 + 'twitter'=>'#best https://www.twitter.com',
  22 + 'telegram'=>'#best https://www.telegram.com',
  23 + 'tiktok'=>'#bestvideo',
  24 + ];
  25 + //profile_key
  26 + public $profile_key = '';
  27 + //设置请求头
  28 + public $headers = [
  29 + 'Authorization' => 'Bearer ',
  30 + 'Content-Type' => 'application/json',
  31 + ];
  32 + //私钥
  33 + private $private_key = "-----BEGIN RSA PRIVATE KEY-----
  34 +MIICWgIBAAKBgGFatMeBeaw7QJrqmylMLZlwuuO0FA/EZg5/g7Rrqu+FgpwvFkJq
  35 +9twEZJY+aIdDH8/RVrCZQGR/xUxKw9v4ows+sLwi4g41m8KRKDXUcJwQvSlwsHAi
  36 +h9hPGZxDsRK0Nv4pZ7XqGgh0Wb0VypX/+Q1dhX9BnXQmvEKayk8GQWQxAgMBAAEC
  37 +gYAFqOJNnudV7fPpja4LjpQwEW+sATIRYJeWTC9587ByUE6xicM/hTxouhCm82Xc
  38 +Rzi4OjFR/vbRYOQ1dTtBtIi18fdRrseQNyR/N2NZjw1X8n5aZcw5NVaa3d3YTQNa
  39 +uzjnYF5eYSOD4pNKKIDc35VHdmvGCV/JXwQKMTgu1+4AAQJBAL5jjN3kvMKFF8vG
  40 +DyYR8k+wPG9iXAdR0HjVNB3OzxKVW0MTwM32pJBXCmF1MOziL8WC48VHQL48hVRa
  41 +52xRqAECQQCC53rrrOPhPCLIb6kBfgqnxCojqlUK9paFL7NYTPtLYcOajY6+NiKT
  42 +CG1gaOwZh4r34HF7I59l/Ds98Z4nQDwxAkAC4/oIiGeBQIoK8vfZ6R3XreJNAp5J
  43 +EinrG7mN1kz4iEH5c7xSpDL9agTjU+cpQYneIs2Yeit2d+7CSBsJXvgBAkBDFsfU
  44 +yYLxCJT7DN8dOK/VU6AVL1Luj3qNP+k2tB2GgNBzAWHK8ou9t2/3HU8DtofuikUe
  45 +yx8Cccca9B4OF8nBAkAgIUZKGmVNFcGnFFo55vSJInNXFo4HCJ2o4DunBORVtQ/j
  46 +zFePUMXy1bFghAfzNKlrc5XgH4ixeeMh3cDtU97K
  47 +-----END RSA PRIVATE KEY-----";
  48 +
  49 + /**
  50 + * @name :(创建子账户配置文件)post_create_profiles
  51 + * @author :lyh
  52 + * @method :post
  53 + * @time :2023/5/5 15:16
  54 + */
  55 + public function post_create_profiles($data){
  56 + $param = [
  57 + 'title'=>$data['title'],
  58 + ];
  59 + $url = $this->path.'/api/profiles/profile';
  60 + return $this->http_click('post',$url,$param);
  61 + }
  62 + /**
  63 + * @name :(删除子账户配置文件)deleted_profiles
  64 + * @author :lyh
  65 + * @method :post
  66 + * @time :2023/5/5 15:16
  67 + */
  68 + public function deleted_profiles($data){
  69 + $param = [
  70 +// 'title'=>$data['title'],
  71 + 'profileKey'=>$data['profileKey'],
  72 + ];
  73 + $url = $this->path.'/api/profiles/profile';
  74 + return $this->http_click('delete',$url,$param);
  75 + }
  76 +
  77 + /**
  78 + * @name :(跳转第三方生成jwt令牌)post_generate_jwt
  79 + * @author :lyh
  80 + * @method :post
  81 + * @time :2023/5/5 18:07 https://app.ayrshare.com/api/profiles/generateJWT
  82 + */
  83 + public function post_generate_jwt($data,$domain = 'globalso'){
  84 + $param = [
  85 + 'domain'=>$domain,
  86 + 'privateKey'=>$this->private_key,
  87 + 'profileKey'=>$data['profileKey'],
  88 + 'logout'=>true
  89 + ];
  90 + $url = $this->path.'/api/profiles/generateJWT';
  91 + return $this->http_click('post',$url,$param);
  92 + }
  93 +
  94 + /**
  95 + * @name :(获取指定api_key的配置文件)get_profiles_users
  96 + * @author :lyh
  97 + * @method :post
  98 + * @time :2023/5/6 16:44
  99 + */
  100 + public function get_profiles_users($api_key){
  101 + $this->headers['Authorization'] = $this->headers['Authorization'].$api_key;
  102 + $url = $this->path.'/api/user';
  103 + return $this->http_click('get',$url,[],$this->headers);
  104 + }
  105 +
  106 +
  107 + /**
  108 + * @name :(发帖)post_send_msg
  109 + * @author :lyh
  110 + * @method :post
  111 + * @time :2023/5/8 9:22
  112 + * @param :platforms: "facebook", "fbg", "twitter",
  113 + * "linkedin", "instagram","youtube", "reddit" ,"telegram""
  114 + */
  115 + public function post_send_msg($param,$api_key){
  116 + //平台参数处理
  117 + $param['idempotencyKey'] = uniqid().time();
  118 + $url = $this->path.'/api/post';
  119 + return $this->http_post_ayr($url,$param,$api_key);
  120 + }
  121 + public function http_post_ayr($url,$param,$api_key){
  122 + $curl = curl_init();
  123 + curl_setopt_array($curl, array(
  124 + CURLOPT_URL => $url,
  125 + CURLOPT_RETURNTRANSFER => true,
  126 + CURLOPT_ENCODING => '',
  127 + CURLOPT_MAXREDIRS => 10,
  128 + CURLOPT_TIMEOUT => 0,
  129 + CURLOPT_FOLLOWLOCATION => true,
  130 + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  131 + CURLOPT_CUSTOMREQUEST => 'POST',
  132 + CURLOPT_POSTFIELDS => http_build_query($param),
  133 + CURLOPT_HTTPHEADER => array(
  134 + 'Authorization: Bearer '.$api_key,
  135 + 'Accept-Encoding: gzip'
  136 + ),
  137 + ));
  138 + $response = curl_exec($curl);
  139 + curl_close($curl);
  140 + return $response;
  141 + }
  142 + /**
  143 + * @name :(上传图片或视频到ayr_share)post_media_upload
  144 + * @author :lyh
  145 + * @method :post
  146 + * @time :2023/5/8 9:47
  147 + * https://app.ayrshare.com/api/media/upload
  148 + */
  149 + public function post_media_upload($data,$api_key){
  150 + $param = [
  151 + 'file'=>$data['file'],//base64编码
  152 + ];
  153 + $this->headers['Authorization'] = $this->headers['Authorization'].$api_key;
  154 + $url = $this->path.'/api/media/upload';
  155 + return $this->http_click('post',$url,$param,$this->headers);
  156 + }
  157 +
  158 + /**
  159 + * @name :获取过去30天发布的历史记录(1-30)
  160 + * @author :lyh
  161 + * @method :get
  162 + * @time :2023/5/5 10:00
  163 + */
  164 + public function get_analytics_links($to_day){
  165 + $last_days = (string)$to_day;
  166 + $url = $this->path.'/analytics/links?lastDays='.$last_days;
  167 + return $this->http_click('get',$url);
  168 + }
  169 +
  170 + /**
  171 + * @name :(通过 Ayrshare 获取给定帖子的实时分析,例如点赞、印象、转推等)post_analytics
  172 + * @author :lyh
  173 + * @method :post
  174 + * @time :2023/5/5 11:56
  175 + */
  176 + public function post_analytics($id){
  177 + $param = [
  178 + 'id'=>$id,
  179 + 'platforms' => ['facebook', 'instagram', 'twitter', 'linkedin', 'pinterest', 'youtube', 'tiktok'],
  180 + ];
  181 + $url = $this->path.'/api/analytics/post';
  182 + return $this->http_click('post', $url, $param);
  183 + }
  184 + /**
  185 + * @name :(获取特定用户个人资料)analytics_post
  186 + * @author :lyh
  187 + * @method :post
  188 + * @time :2023/5/5 10:43
  189 + */
  190 + public function post_analytics_social(){
  191 + $post_data = [
  192 + 'platforms' => ['facebook', 'instagram', 'twitter', 'linkedin', 'pinterest', 'youtube', 'tiktok'],
  193 + ];
  194 + $url = $this->path.'/api/analytics/social';
  195 + return $this->http_click('post',$url,$post_data);
  196 + }
  197 +
  198 + /**
  199 + * @name :(设置自动计划)post_schedule_set
  200 + * @author :lyh
  201 + * @method :post
  202 + * @time :2023/5/5 13:58
  203 + */
  204 + public function post_schedule_set($data){
  205 + $param = [
  206 + 'schedule'=>["13:05Z", "20:14Z"],
  207 + 'title'=>$data['title'],
  208 + ];
  209 + $url = $this->path.'/api/auto-schedule/set';
  210 + return $this->http_click('post',$url,$param);
  211 + }
  212 +
  213 + /**
  214 + * @name :(删除自动计划)delete_schedule
  215 + * @author :lyh
  216 + * @method :post
  217 + * @time :2023/5/5 14:04
  218 + */
  219 + public function delete_schedule($data){
  220 + $param = [
  221 + 'title'=>$data['title'],
  222 + ];
  223 + $url = $this->path.'/api/auto-schedule/delete';
  224 + return $this->http_click('delete',$url,$param);
  225 + }
  226 +
  227 + /**
  228 + * @name :(列出自动计划)get_schedule_list
  229 + * @author :lyh
  230 + * @method :post
  231 + * @time :2023/5/5 14:08
  232 + */
  233 + public function get_schedule_list(){
  234 + $url = $this->path.'/api/auto-schedule/list';
  235 + return $this->http_click('get',$url);
  236 + }
  237 +
  238 + /**
  239 + * @name :(发布到用户个人资料)post_user
  240 + * @author :lyh
  241 + * @method :post
  242 + * @time :2023/5/5 15:00
  243 + */
  244 + public function post_profiles($data){
  245 + $param = [
  246 + 'post'=>$data['post'],
  247 + 'platforms'=>$data['platforms'],
  248 + 'profileKey'=>$this->profile_key,
  249 + 'mediaUrls'=>$data['mediaUrls']
  250 + ];
  251 + $url = $this->path.'/api/post';
  252 + return $this->http_click('post',$url,$param);
  253 + }
  254 +
  255 + /**
  256 + * 发送http post,get,put,delete请求
  257 + * @param type $url
  258 + * @param type $post_data
  259 + */
  260 + function http_click($method = 'post',$url, $param = [],$header = [])
  261 + {
  262 + if(!empty($param)){
  263 + $post_data['json'] = $param;
  264 + }
  265 + if(empty($header)){
  266 + $this->headers['Authorization'] = $this->headers['Authorization'].$this->api_key;
  267 + }
  268 + $post_data['headers'] = !empty($header) ? $header : $this->headers;
  269 + $client = new Client();
  270 + try {
  271 + $res = $client->request(strtoupper($method), $url, $post_data)->getBody()->getContents();
  272 + return (array)json_decode($res);
  273 + } catch (\Exception $e) {
  274 + return ["status"=>"fail","message"=>$e->getMessage()];
  275 + }
  276 + }
  277 +}
  1 +<?php
  2 +
  3 +namespace App\Helper;
  4 +
  5 +use App\Models\Ai\AiCommand as AiCommandModel;
  6 +use App\Models\User\UserLog as UserLogModel;
  7 +use App\Models\User\UserLogin as UserLoginModel;
  8 +use Illuminate\Encryption\Encrypter;
  9 +use Illuminate\Support\Facades\Cache;
  10 +
  11 +/**
  12 + * @name:
  13 + */
  14 +class Common
  15 +{
  16 + public $key = '66537a12d4fff992f6d8b67fdda6192f';
  17 + public $method = 'AES-256-CBC';
  18 + /**
  19 + * @name :生成用户操作日志
  20 + * @return void
  21 + * @author :liyuhang
  22 + * @method
  23 + */
  24 + public static function set_user_log($param = []){
  25 + $data = [
  26 + 'operator_id'=>$param['operator_id'],
  27 + 'model'=>$param['model'],
  28 + 'remark'=>$param['remark']
  29 + ];
  30 + $model = new UserLogModel();
  31 + return $model->add($data);
  32 + }
  33 +
  34 + /**
  35 + * @name :写入登录日志
  36 + * @return void
  37 + * @author :liyuhang
  38 + * @method
  39 + */
  40 + public static function set_user_login($param = []){
  41 + $data = [
  42 + 'user_id'=>$param['user_id'],
  43 + 'ip'=>$param['ip'],
  44 + 'project_id'=>$param['project_id'] ?: 0,
  45 + 'remark'=>$param['remark'] ?? '',
  46 + ];
  47 + $model = new UserLoginModel();
  48 + return $model->add($data);
  49 + }
  50 +
  51 + /**
  52 + * @name :ai自动生成
  53 + * @return mixed
  54 + * @author :liyuhang
  55 + * @method
  56 + */
  57 + public static function send_openai_msg($url,$param){
  58 + $url = HTTP_OPENAI_URL.$url;
  59 + $aiCommandModel = New AiCommandModel();
  60 + //指定库获取指令
  61 + $info = $aiCommandModel->read(['key'=>$param['key']]);
  62 + if($info === false){
  63 + response('指令不存在',400);
  64 + }
  65 + if (strpos($param['keywords'], '{') !== false && strpos($param['keywords'], '}') !== false) {
  66 + $pattern = '/\{([^}]+)\}/'; // 匹配大括号及其内容
  67 + if (preg_match($pattern, $param['keywords'], $matches)) {
  68 + $lang = $matches[1]; // 获取捕获的内容
  69 + }
  70 + } else {
  71 + //带原语种翻译
  72 + $result = Translate::translateSl($param['keywords'])->json();
  73 + if (isset($result['texts']['sl']) && isset(Translate::$tls_list[$result['texts']['sl']])) {
  74 + $lang = Translate::$tls_list[$result['texts']['sl']]['text'];
  75 + } else {
  76 + $lang = '中文';
  77 + }
  78 + }
  79 + $str = ',请使用'.$lang.'回答';
  80 + //替换关键字
  81 + $content = str_replace('$keyword$', $param['keywords'], $info['ai']);
  82 + $data = [
  83 + 'messages'=>[
  84 + ['role'=>'system','content'=>$info['scene']],
  85 + ['role'=>'assistant','content'=>$content.$str],
  86 + ]
  87 + ];
  88 + return http_post($url,json_encode($data));
  89 + }
  90 +
  91 + /**
  92 + * @name :获取缓存
  93 + * @return void
  94 + * @author :liyuhang
  95 + * @method
  96 + */
  97 + public static function get_user_cache($table,$id,$type = 'B'){
  98 + $data = [];
  99 + $cache = config('cache.user_is_cache');
  100 + if(isset($cache) && ($cache['is_cache'] == true)){
  101 + $key = 'cache_'.$table.'_'.$id.'_type';
  102 + $data = Cache::store('file')->get($key);
  103 + }
  104 + return $data;
  105 + }
  106 +
  107 + /**
  108 + * @name :写入缓存
  109 + * @return bool
  110 + * @author :liyuhang
  111 + * @method
  112 + */
  113 + public static function set_user_cache($data = [],$table,$id,$type = 'B'){
  114 + $cache = config('cache.user_is_cache');
  115 + if(isset($cache) && ($cache['is_cache'] == true)){
  116 + $key = 'cache_'.$table.'_'.$id.'_type';
  117 + Cache::store('file')->set($key,$data,3600);
  118 + }
  119 + return true;
  120 + }
  121 +
  122 + /**
  123 + * @name :清除缓存
  124 + * @return bool
  125 + * @author :liyuhang
  126 + * @method
  127 + */
  128 + public static function del_user_cache($table,$id,$type = 'B'){
  129 + $cache = config('cache.user_is_cache');
  130 + if(isset($cache) && ($cache['is_cache'] == true)){
  131 + if(is_array($id)){
  132 + foreach ($id as $v){
  133 + $key = 'cache_'.$table.'_'.$v.'_type';
  134 + Cache::store('file')->pull($key);
  135 + }
  136 + }else{
  137 + $key = 'cache_'.$table.'_'.$id.'_type';
  138 + }
  139 + Cache::store('file')->pull($key);
  140 + }
  141 + return true;
  142 + }
  143 +
  144 + /**
  145 + * @name :(多维数组去重)array_deduplication
  146 + * @author :lyh
  147 + * @method :post
  148 + * @time :2023/5/9 10:47
  149 + */
  150 + public static function uniqueMultiArray($arr) {
  151 + $arr = array_map('serialize', $arr);
  152 + $arr = array_unique($arr);
  153 + $arr = array_map('unserialize', $arr);
  154 + return $arr;
  155 + }
  156 +
  157 + /**
  158 + * @param $targetDateTime
  159 + * @name :(获取时间差,精确时分秒,返回天数)getDaysToTargetDate
  160 + * @author :lyh
  161 + * @method :post
  162 + * @time :2023/5/24 9:38
  163 + */
  164 + public static function getDaysToTargetDate($targetDateTime)
  165 + {
  166 + $currentTimestamp = time();
  167 + $targetTimestamp = strtotime($targetDateTime);
  168 + $days = floor(($currentTimestamp - $targetTimestamp) / (60 * 60 * 24));
  169 + return (int)$days;
  170 + }
  171 +
  172 + // 生成授授权码
  173 + public function encrypt($data)
  174 + {
  175 + $crypt = new Encrypter($this->key, $this->method);
  176 + return $crypt->encrypt($data);
  177 + }
  178 +
  179 + // 解密授权码
  180 + public function decrypt($string)
  181 + {
  182 + $crypt = new Encrypter($this->key, $this->method);
  183 + return $crypt->decrypt($string);
  184 + }
  185 +
  186 +}
  1 +<?php
  2 +
  3 +namespace App\Helper;
  4 +
  5 +use App\Models\WebSetting\WebSettingCountry;
  6 +
  7 +/**
  8 + * @name:多语言国家设置
  9 + */
  10 +class Country
  11 +{
  12 + public $tls_list = [
  13 + 'en' => [
  14 + 'text' => '英语',
  15 + 'lang_text' => 'English',
  16 + 'con_flag' => 'con_flag/en.jfif',
  17 + 'shop_lang' => 'en-gb',
  18 + ],
  19 + 'zh' => [
  20 + 'text' => '中文',
  21 + 'lang_text' => '简体中文',
  22 + 'con_flag' => 'con_flag/zh.jfif',
  23 + 'shop_lang' => 'zh-cn',
  24 + ],
  25 + 'fr' => [
  26 + 'text' => '法语',
  27 + 'lang_text' => 'En français',
  28 + 'con_flag' => '',
  29 +
  30 + ],
  31 + 'de' => [
  32 + 'text' => '德语',
  33 + 'lang_text' => 'Das ist Deutsch.',
  34 + 'con_flag' => '',
  35 +
  36 + ],
  37 + 'ko' => [
  38 + 'text' => '韩语',
  39 + 'lang_text' => '',
  40 + 'con_flag' => '',
  41 +
  42 + ],
  43 + 'ja' => [
  44 + 'text' => '日语',
  45 + 'lang_text' => '',
  46 + 'con_flag' => '',
  47 +
  48 + ],
  49 + 'es' => [
  50 + 'text' => '西班牙语',
  51 + 'lang_text' => 'Español.',
  52 + 'con_flag' => '',
  53 +
  54 + ],
  55 + 'ar' => [
  56 + 'text' => '阿拉伯语',
  57 + 'lang_text' => '',
  58 + 'con_flag' => '',
  59 +
  60 + ],
  61 + 'pt' => [
  62 + 'text' => '葡萄牙语(葡萄牙、巴西)',
  63 + 'lang_text' => 'Língua portuguesa',
  64 + 'con_flag' => '',
  65 +
  66 + ],
  67 + 'ru' => [
  68 + 'text' => '俄语',
  69 + 'lang_text' => '',
  70 + 'con_flag' => '',
  71 +
  72 + ],
  73 + 'af' => [
  74 + 'text' => '南非荷兰语',
  75 + 'lang_text' => '',
  76 + 'con_flag' => '',
  77 +
  78 + ],
  79 + 'sq' => [
  80 + 'text' => '阿尔巴尼亚语',
  81 + 'lang_text' => '',
  82 + 'con_flag' => '',
  83 +
  84 + ],
  85 + 'am' => [
  86 + 'text' => '阿姆哈拉语',
  87 + 'lang_text' => '',
  88 + 'con_flag' => '',
  89 +
  90 + ],
  91 + 'hy' => [
  92 + 'text' => '亚美尼亚语',
  93 + 'lang_text' => '',
  94 + 'con_flag' => '',
  95 +
  96 + ],
  97 + 'az' => [
  98 + 'text' => '阿塞拜疆语',
  99 + 'lang_text' => '',
  100 + 'con_flag' => '',
  101 +
  102 + ],
  103 + 'eu' => [
  104 + 'text' => '巴斯克语',
  105 + 'lang_text' => '',
  106 + 'con_flag' => '',
  107 +
  108 + ],
  109 + 'be' => [
  110 + 'text' => '白俄罗斯语',
  111 + 'lang_text' => '',
  112 + 'con_flag' => '',
  113 +
  114 + ],
  115 + 'bn' => [
  116 + 'text' => '孟加拉语',
  117 + 'lang_text' => '',
  118 + 'con_flag' => '',
  119 +
  120 + ],
  121 + 'bs' => [
  122 + 'text' => '波斯尼亚语',
  123 + 'lang_text' => '',
  124 + 'con_flag' => '',
  125 +
  126 + ],
  127 + 'bg' => [
  128 + 'text' => '保加利亚语',
  129 + 'lang_text' => '',
  130 + 'con_flag' => '',
  131 +
  132 + ],
  133 + 'ca' => [
  134 + 'text' => '加泰罗尼亚语',
  135 + 'lang_text' => '',
  136 + 'con_flag' => '',
  137 +
  138 + ],
  139 + 'ceb' => [
  140 + 'text' => '宿务语',
  141 + 'lang_text' => '',
  142 + 'con_flag' => '',
  143 +
  144 + ],
  145 + 'cn' => [
  146 + 'text' => '中文(简体)',
  147 + 'lang_text' => '简体中文',
  148 + 'con_flag' => 'con_flag/zh.jfif',
  149 + 'shop_lang' => 'zh-cn',
  150 + ],
  151 + 'tw' => [
  152 + 'text' => '中文(繁体)',
  153 + 'lang_text' => '繁体中文',
  154 + 'con_flag' => 'con_flag/zh.jfif',
  155 +
  156 + ],
  157 + 'co' => [
  158 + 'text' => '科西嘉语',
  159 + 'lang_text' => '',
  160 + 'con_flag' => '',
  161 +
  162 + ],
  163 + 'hr' => [
  164 + 'text' => '克罗地亚语',
  165 + 'lang_text' => '',
  166 + 'con_flag' => '',
  167 +
  168 + ],
  169 + 'cs' => [
  170 + 'text' => '捷克语',
  171 + 'lang_text' => '',
  172 + 'con_flag' => '',
  173 +
  174 + ],
  175 + 'da' => [
  176 + 'text' => '丹麦语',
  177 + 'lang_text' => '',
  178 + 'con_flag' => '',
  179 +
  180 + ],
  181 + 'nl' => [
  182 + 'text' => '荷兰语',
  183 + 'lang_text' => '',
  184 + 'con_flag' => '',
  185 +
  186 + ],
  187 + 'eo' => [
  188 + 'text' => '世界语',
  189 + 'lang_text' => '',
  190 + 'con_flag' => '',
  191 +
  192 + ],
  193 + 'et' => [
  194 + 'text' => '爱沙尼亚语',
  195 + 'lang_text' => '',
  196 + 'con_flag' => '',
  197 +
  198 + ],
  199 + 'fi' => [
  200 + 'text' => '芬兰语',
  201 + 'lang_text' => '',
  202 + 'con_flag' => '',
  203 +
  204 + ],
  205 + 'fy' => [
  206 + 'text' => '弗里斯兰语',
  207 + 'lang_text' => '',
  208 + 'con_flag' => '',
  209 +
  210 + ],
  211 + 'gl' => [
  212 + 'text' => '加利西亚语',
  213 + 'lang_text' => '',
  214 + 'con_flag' => '',
  215 +
  216 + ],
  217 + 'ka' => [
  218 + 'text' => '格鲁吉亚语',
  219 + 'lang_text' => '',
  220 + 'con_flag' => '',
  221 +
  222 + ],
  223 + 'el' => [
  224 + 'text' => '希腊语',
  225 + 'lang_text' => '',
  226 + 'con_flag' => '',
  227 +
  228 + ],
  229 + 'gu' => [
  230 + 'text' => '古吉拉特语',
  231 + 'lang_text' => '',
  232 + 'con_flag' => '',
  233 +
  234 + ],
  235 + 'ht' => [
  236 + 'text' => '海地克里奥尔语',
  237 + 'lang_text' => '',
  238 + 'con_flag' => '',
  239 +
  240 + ],
  241 + 'ha' => [
  242 + 'text' => '豪萨语',
  243 + 'lang_text' => '',
  244 + 'con_flag' => '',
  245 +
  246 + ],
  247 + 'haw' => [
  248 + 'text' => '夏威夷语',
  249 + 'lang_text' => '',
  250 + 'con_flag' => '',
  251 +
  252 + ],
  253 + 'iw' => [
  254 + 'text' => '希伯来语',
  255 + 'lang_text' => '',
  256 + 'con_flag' => '',
  257 +
  258 + ],
  259 + 'hi' => [
  260 + 'text' => '印地语',
  261 + 'lang_text' => '',
  262 + 'con_flag' => '',
  263 +
  264 + ],
  265 + 'hmn' => [
  266 + 'text' => '苗语',
  267 + 'lang_text' => '',
  268 + 'con_flag' => '',
  269 +
  270 + ],
  271 + 'hu' => [
  272 + 'text' => '匈牙利语',
  273 + 'lang_text' => '',
  274 + 'con_flag' => '',
  275 +
  276 + ],
  277 + 'is' => [
  278 + 'text' => '冰岛语',
  279 + 'lang_text' => '',
  280 + 'con_flag' => '',
  281 +
  282 + ],
  283 + 'ig' => [
  284 + 'text' => '伊博语',
  285 + 'lang_text' => '',
  286 + 'con_flag' => '',
  287 +
  288 + ],
  289 + 'id' => [
  290 + 'text' => '印度尼西亚语',
  291 + 'lang_text' => 'Bahasa Indonesia',
  292 + 'con_flag' => 'con_flag/id.jfif',
  293 + 'shop_lang' => 'id',
  294 + ],
  295 + 'ga' => [
  296 + 'text' => '爱尔兰语',
  297 + 'lang_text' => '',
  298 + 'con_flag' => '',
  299 +
  300 + ],
  301 + 'it' => [
  302 + 'text' => '意大利语',
  303 + 'lang_text' => 'Lingua italiana',
  304 + 'con_flag' => '',
  305 +
  306 + ],
  307 + 'jw' => [
  308 + 'text' => '爪哇语',
  309 + 'lang_text' => '',
  310 + 'con_flag' => '',
  311 +
  312 + ],
  313 + 'kn' => [
  314 + 'text' => '卡纳达语',
  315 + 'lang_text' => '',
  316 + 'con_flag' => '',
  317 +
  318 + ],
  319 + 'kk' => [
  320 + 'text' => '哈萨克语',
  321 + 'lang_text' => '',
  322 + 'con_flag' => '',
  323 +
  324 + ],
  325 + 'km' => [
  326 + 'text' => '高棉语',
  327 + 'lang_text' => '',
  328 + 'con_flag' => '',
  329 +
  330 + ],
  331 + 'rw' => [
  332 + 'text' => '卢旺达语',
  333 + 'lang_text' => '',
  334 + 'con_flag' => '',
  335 +
  336 + ],
  337 + 'ku' => [
  338 + 'text' => '库尔德语',
  339 + 'lang_text' => '',
  340 + 'con_flag' => '',
  341 +
  342 + ],
  343 + 'ky' => [
  344 + 'text' => '吉尔吉斯语',
  345 + 'lang_text' => '',
  346 + 'con_flag' => '',
  347 +
  348 + ],
  349 + 'lo' => [
  350 + 'text' => '老挝文',
  351 + 'lang_text' => '',
  352 + 'con_flag' => '',
  353 +
  354 + ],
  355 + 'la' => [
  356 + 'text' => '拉丁文',
  357 + 'lang_text' => '',
  358 + 'con_flag' => '',
  359 +
  360 + ],
  361 + 'lv' => [
  362 + 'text' => '拉脱维亚语',
  363 + 'lang_text' => '',
  364 + 'con_flag' => '',
  365 +
  366 + ],
  367 + 'lt' => [
  368 + 'text' => '立陶宛语',
  369 + 'lang_text' => '',
  370 + 'con_flag' => '',
  371 +
  372 + ],
  373 + 'lb' => [
  374 + 'text' => '卢森堡语',
  375 + 'lang_text' => '',
  376 + 'con_flag' => '',
  377 +
  378 + ],
  379 + 'mk' => [
  380 + 'text' => '马其顿语',
  381 + 'lang_text' => '',
  382 + 'con_flag' => '',
  383 +
  384 + ],
  385 + 'mg' => [
  386 + 'text' => '马尔加什语',
  387 + 'lang_text' => '',
  388 + 'con_flag' => '',
  389 +
  390 + ],
  391 + 'ms' => [
  392 + 'text' => '马来语',
  393 + 'lang_text' => 'Bahasa Melayu',
  394 + 'con_flag' => 'con_flag/ms.jfif',
  395 + 'shop_lang' => 'ms-my',
  396 + ],
  397 + 'ml' => [
  398 + 'text' => '马拉雅拉姆文',
  399 + 'lang_text' => '',
  400 + 'con_flag' => '',
  401 +
  402 + ],
  403 + 'mt' => [
  404 + 'text' => '马耳他语',
  405 + 'lang_text' => '',
  406 + 'con_flag' => '',
  407 +
  408 + ],
  409 + 'mi' => [
  410 + 'text' => '毛利语',
  411 + 'lang_text' => '',
  412 + 'con_flag' => '',
  413 +
  414 + ],
  415 + 'mr' => [
  416 + 'text' => '马拉地语',
  417 + 'lang_text' => '',
  418 + 'con_flag' => '',
  419 +
  420 + ],
  421 + 'mn' => [
  422 + 'text' => '蒙古文',
  423 + 'lang_text' => '',
  424 + 'con_flag' => '',
  425 +
  426 + ],
  427 + 'my' => [
  428 + 'text' => '缅甸语',
  429 + 'lang_text' => '',
  430 + 'con_flag' => '',
  431 +
  432 + ],
  433 + 'ne' => [
  434 + 'text' => '尼泊尔语',
  435 + 'lang_text' => '',
  436 + 'con_flag' => '',
  437 +
  438 + ],
  439 + 'no' => [
  440 + 'text' => '挪威语',
  441 + 'lang_text' => '',
  442 + 'con_flag' => '',
  443 +
  444 + ],
  445 + 'ny' => [
  446 + 'text' => '尼杨扎语(齐切瓦语)',
  447 + 'lang_text' => '',
  448 + 'con_flag' => '',
  449 +
  450 + ],
  451 + 'or' => [
  452 + 'text' => '奥里亚语(奥里亚)',
  453 + 'lang_text' => '',
  454 + 'con_flag' => '',
  455 +
  456 + ],
  457 + 'ps' => [
  458 + 'text' => '普什图语',
  459 + 'lang_text' => '',
  460 + 'con_flag' => '',
  461 +
  462 + ],
  463 + 'fa' => [
  464 + 'text' => '波斯语',
  465 + 'lang_text' => '',
  466 + 'con_flag' => '',
  467 +
  468 + ],
  469 + 'pl' => [
  470 + 'text' => '波兰语',
  471 + 'lang_text' => '',
  472 + 'con_flag' => '',
  473 +
  474 + ],
  475 + 'pa' => [
  476 + 'text' => '旁遮普语',
  477 + 'lang_text' => '',
  478 + 'con_flag' => '',
  479 +
  480 + ],
  481 + 'ro' => [
  482 + 'text' => '罗马尼亚语',
  483 + 'lang_text' => '',
  484 + 'con_flag' => '',
  485 +
  486 + ],
  487 + 'sm' => [
  488 + 'text' => '萨摩亚语',
  489 + 'lang_text' => '',
  490 + 'con_flag' => '',
  491 +
  492 + ],
  493 + 'gd' => [
  494 + 'text' => '苏格兰盖尔语',
  495 + 'lang_text' => '',
  496 + 'con_flag' => '',
  497 +
  498 + ],
  499 + 'sr' => [
  500 + 'text' => '塞尔维亚语',
  501 + 'lang_text' => '',
  502 + 'con_flag' => '',
  503 +
  504 + ],
  505 + 'st' => [
  506 + 'text' => '塞索托语',
  507 + 'lang_text' => '',
  508 + 'con_flag' => '',
  509 +
  510 + ],
  511 + 'sn' => [
  512 + 'text' => '修纳语',
  513 + 'lang_text' => '',
  514 + 'con_flag' => '',
  515 +
  516 + ],
  517 + 'sd' => [
  518 + 'text' => '信德语',
  519 + 'lang_text' => '',
  520 + 'con_flag' => '',
  521 +
  522 + ],
  523 + 'si' => [
  524 + 'text' => '僧伽罗语',
  525 + 'lang_text' => '',
  526 + 'con_flag' => '',
  527 +
  528 + ],
  529 + 'sk' => [
  530 + 'text' => '斯洛伐克语',
  531 + 'lang_text' => '',
  532 + 'con_flag' => '',
  533 +
  534 + ],
  535 + 'sl' => [
  536 + 'text' => '斯洛文尼亚语',
  537 + 'lang_text' => '',
  538 + 'con_flag' => '',
  539 +
  540 + ],
  541 + 'so' => [
  542 + 'text' => '索马里语',
  543 + 'lang_text' => '',
  544 + 'con_flag' => '',
  545 +
  546 + ],
  547 + 'su' => [
  548 + 'text' => '巽他语',
  549 + 'lang_text' => '',
  550 + 'con_flag' => '',
  551 +
  552 + ],
  553 + 'sw' => [
  554 + 'text' => '斯瓦希里语',
  555 + 'lang_text' => '',
  556 + 'con_flag' => '',
  557 +
  558 + ],
  559 + 'sv' => [
  560 + 'text' => '瑞典语',
  561 + 'lang_text' => '',
  562 + 'con_flag' => '',
  563 +
  564 + ],
  565 + 'tl' => [
  566 + 'text' => '塔加路语(菲律宾语)',
  567 + 'lang_text' => 'Pilipino',
  568 + 'con_flag' => 'con_flag/tl.jfif',
  569 + 'shop_lang' => 'tl',
  570 + ],
  571 + 'tg' => [
  572 + 'text' => '塔吉克语',
  573 + 'lang_text' => '',
  574 + 'con_flag' => '',
  575 +
  576 + ],
  577 + 'ta' => [
  578 + 'text' => '泰米尔语',
  579 + 'lang_text' => '',
  580 + 'con_flag' => '',
  581 +
  582 + ],
  583 + 'tt' => [
  584 + 'text' => '鞑靼语',
  585 + 'lang_text' => '',
  586 + 'con_flag' => '',
  587 +
  588 + ],
  589 + 'te' => [
  590 + 'text' => '泰卢固语',
  591 + 'lang_text' => '',
  592 + 'con_flag' => '',
  593 +
  594 + ],
  595 + 'th' => [
  596 + 'text' => '泰文',
  597 + 'lang_text' => 'ไทย',
  598 + 'con_flag' => 'con_flag/th.jfif',
  599 + 'shop_lang' => 'th',
  600 + ],
  601 + 'tr' => [
  602 + 'text' => '土耳其语',
  603 + 'lang_text' => '',
  604 + 'con_flag' => '',
  605 +
  606 + ],
  607 + 'tk' => [
  608 + 'text' => '土库曼语',
  609 + 'lang_text' => '',
  610 + 'con_flag' => '',
  611 +
  612 + ],
  613 + 'uk' => [
  614 + 'text' => '乌克兰语',
  615 + 'lang_text' => '',
  616 + 'con_flag' => '',
  617 +
  618 + ],
  619 + 'ur' => [
  620 + 'text' => '乌尔都语',
  621 + 'lang_text' => '',
  622 + 'con_flag' => '',
  623 +
  624 + ],
  625 + 'ug' => [
  626 + 'text' => '维吾尔语',
  627 + 'lang_text' => '',
  628 + 'con_flag' => '',
  629 +
  630 + ],
  631 + 'uz' => [
  632 + 'text' => '乌兹别克语',
  633 + 'lang_text' => '',
  634 + 'con_flag' => '',
  635 +
  636 + ],
  637 + 'vi' => [
  638 + 'text' => '越南语',
  639 + 'lang_text' => '',
  640 + 'con_flag' => '',
  641 +
  642 + ],
  643 + 'cy' => [
  644 + 'text' => '威尔士语',
  645 + 'lang_text' => '',
  646 + 'con_flag' => '',
  647 +
  648 + ],
  649 + 'xh' => [
  650 + 'text' => '班图语',
  651 + 'lang_text' => '',
  652 + 'con_flag' => '',
  653 +
  654 + ],
  655 + 'yi' => [
  656 + 'text' => '意第绪语',
  657 + 'lang_text' => '',
  658 + 'con_flag' => '',
  659 +
  660 + ],
  661 + 'yo' => [
  662 + 'text' => '约鲁巴语',
  663 + 'lang_text' => '',
  664 + 'con_flag' => '',
  665 +
  666 + ],
  667 + 'zu' => [
  668 + 'text' => '祖鲁语',
  669 + 'lang_text' => '',
  670 + 'con_flag' => '',
  671 + ],
  672 + ];
  673 +
  674 + /**
  675 + * @name :(获取翻译国家)set_country
  676 + * @author :lyh
  677 + * @method :post
  678 + * @time :2023/5/4 17:57
  679 + */
  680 + public function set_country(){
  681 + $data = [];
  682 + foreach ($this->tls_list as $k=>$v){
  683 + $data[] = ['name'=>$v['text'],'alias'=>$k,'image'=>$k.'.png','con_flag'=>$v['con_flag'],'lang_text'=>$v['lang_text']];
  684 + }
  685 + $webCountry = new WebSettingCountry();
  686 + $webCountry->insert($data);
  687 + return true;
  688 + }
  689 +}
  1 +<?php
  2 +
  3 +
  4 +namespace App\Helper;
  5 +
  6 +/**
  7 + * 计算文件hash
  8 + *
  9 + * 七牛云的计算规则
  10 + */
  11 +class FileEtag
  12 +{
  13 + const BLOCK_SIZE = 4194304; //4*1024*1024 分块上传块大小,该参数为接口规格,不能修改
  14 +
  15 + private static function packArray($v, $a)
  16 + {
  17 + return call_user_func_array('pack', array_merge(array($v), (array)$a));
  18 + }
  19 +
  20 + private static function blockCount($fsize)
  21 + {
  22 + return intval(($fsize + (self::BLOCK_SIZE - 1)) / self::BLOCK_SIZE);
  23 + }
  24 +
  25 + private static function calcSha1($data)
  26 + {
  27 + $sha1Str = sha1($data, true);
  28 + $err = error_get_last();
  29 + if ($err !== null) {
  30 + return array(null, $err);
  31 + }
  32 + $byteArray = unpack('C*', $sha1Str);
  33 + return array($byteArray, null);
  34 + }
  35 +
  36 + private static function base64_urlSafeEncode($data)
  37 + {
  38 + $find = array('+', '/');
  39 + $replace = array('-', '_');
  40 + return str_replace($find, $replace, base64_encode($data));
  41 + }
  42 +
  43 + public static function sum($filename)
  44 + {
  45 + $fhandler = fopen($filename, 'r');
  46 + $err = error_get_last();
  47 + if ($err !== null) {
  48 + return array(null, $err);
  49 + }
  50 +
  51 + $fstat = fstat($fhandler);
  52 + $fsize = $fstat['size'];
  53 + if ((int)$fsize === 0) {
  54 + fclose($fhandler);
  55 + return array('Fto5o-5ea0sNMlW_75VgGJCv2AcJ', null);
  56 + }
  57 + $blockCnt = self::blockCount($fsize);
  58 + $sha1Buf = array();
  59 +
  60 + if ($blockCnt <= 1) {
  61 + array_push($sha1Buf, 0x16);
  62 + $fdata = fread($fhandler, self::BLOCK_SIZE);
  63 + if ($err !== null) {
  64 + fclose($fhandler);
  65 + return array(null, $err);
  66 + }
  67 + list($sha1Code,) = self::calcSha1($fdata);
  68 + $sha1Buf = array_merge($sha1Buf, $sha1Code);
  69 + } else {
  70 + array_push($sha1Buf, 0x96);
  71 + $sha1BlockBuf = array();
  72 + for ($i = 0; $i < $blockCnt; $i++) {
  73 + $fdata = fread($fhandler, self::BLOCK_SIZE);
  74 + list($sha1Code, $err) = self::calcSha1($fdata);
  75 + if ($err !== null) {
  76 + fclose($fhandler);
  77 + return array(null, $err);
  78 + }
  79 + $sha1BlockBuf = array_merge($sha1BlockBuf, $sha1Code);
  80 + }
  81 + $tmpData = self::packArray('C*', $sha1BlockBuf);
  82 + list($sha1Final,) = self::calcSha1($tmpData);
  83 + $sha1Buf = array_merge($sha1Buf, $sha1Final);
  84 + }
  85 + $etag = self::base64_urlSafeEncode(self::packArray('C*', $sha1Buf));
  86 + return array($etag, null);
  87 + }
  88 +}
  1 +<?php
  2 +
  3 +
  4 +namespace App\Helper;
  5 +
  6 +use App\Utils\HttpUtils;
  7 +use GuzzleHttp\Exception\GuzzleException;
  8 +
  9 +
  10 +/**
  11 + * Class FormGlobalsoApi
  12 + * @package App\Helper
  13 + * @author zbj
  14 + * @date 2023/5/17
  15 + */
  16 +class FormGlobalsoApi
  17 +{
  18 + //接口地址
  19 + protected $url = 'https://form.globalso.com';
  20 +
  21 + /**
  22 + * 设置询盘通知
  23 + * @author zbj
  24 + * @date 2023/5/17
  25 + */
  26 + public function setInquiry($domain, $emails, $phones)
  27 + {
  28 + $api_url = $this->url . '/api/external-project/save/dc77a54480b184c4';
  29 +
  30 + $params = [
  31 + 'token' => md5($domain.$emails.$phones.date("Y-m-d")),
  32 + 'domain' => $domain,
  33 + 'email' => $emails,
  34 + 'phone' => $phones,
  35 + ];
  36 +
  37 + try {
  38 + $res = HttpUtils::get($api_url, $params);
  39 + $res = Arr::s2a($res);
  40 + } catch (\Exception | GuzzleException $e) {
  41 + errorLog('设置询盘通知', $params, $e);
  42 + return false;
  43 + }
  44 + return $res;
  45 + }
  46 +
  47 + /**
  48 + * 询盘列表
  49 + * @author zbj
  50 + * @date 2023/5/17
  51 + */
  52 + public function getInquiryList($domain, $search = '', $page = 1, $page_size = 20)
  53 + {
  54 + $api_url = $this->url . '/api/external-interface/6a1bd159b1fd60af';
  55 +
  56 + $params = [
  57 + 'token' => md5($domain.$search.date("Y-m-d")),
  58 + 'domain' => $domain,
  59 + 'limit' => $page_size,
  60 + 'page' => $page,
  61 + 'source' => '1,3' //来源类型 新项目用1,3
  62 + ];
  63 + if($search){
  64 + $params['name'] = $search;
  65 + }
  66 + try {
  67 + $res = HttpUtils::get($api_url, $params);
  68 + $res = Arr::s2a($res);
  69 + } catch (\Exception | GuzzleException $e) {
  70 + errorLog('询盘列表', $params, $e);
  71 + return false;
  72 + }
  73 + return $res;
  74 + }
  75 +
  76 + /**
  77 + * 设置询盘信息已读
  78 + * @author zbj
  79 + * @date 2023/5/17
  80 + */
  81 + public function saveInquiryRead($domain, $id)
  82 + {
  83 + $api_url = $this->url . '/api/external-interface/save/d1483a8e57cb485a';
  84 +
  85 + $params = [
  86 + 'token' => md5($domain.$id.date("Y-m-d")),
  87 + 'domain' => $domain,
  88 + 'id' => $id,
  89 + ];
  90 +
  91 + try {
  92 + $res = HttpUtils::get($api_url, $params);
  93 + $res = Arr::s2a($res);
  94 + } catch (\Exception | GuzzleException $e) {
  95 + errorLog('设置询盘信息已读', $params, $e);
  96 + return false;
  97 + }
  98 + return $res;
  99 + }
  100 +
  101 + /**
  102 + * 删除询盘信息
  103 + * @author zbj
  104 + * @date 2023/5/17
  105 + */
  106 + public function delInquiry($domain, $ids)
  107 + {
  108 + $api_url = $this->url . '/api/external-interface/del/c4b11cf6f1508489';
  109 + $ids = Arr::arrToSet($ids);
  110 + $params = [
  111 + 'token' => md5($domain.$ids.date("Y-m-d")),
  112 + 'domain' => $domain,
  113 + 'id' => $ids,
  114 + ];
  115 + try {
  116 + $res = HttpUtils::get($api_url, $params);
  117 + $res = Arr::s2a($res);
  118 + } catch (\Exception | GuzzleException $e) {
  119 + errorLog('删除询盘信息', $params, $e);
  120 + return false;
  121 + }
  122 + return $res;
  123 + }
  124 +}
  1 +<?php
  2 +
  3 +
  4 +namespace App\Helper;
  5 +
  6 +use App\Utils\HttpUtils;
  7 +use GuzzleHttp\Exception\GuzzleException;
  8 +
  9 +
  10 +/**
  11 + * Class PageSpeed
  12 + * @package App\Helper
  13 + * @author zbj
  14 + * @date 2023/5/10
  15 + */
  16 +class GoogleSpeedApi
  17 +{
  18 +
  19 + protected $areas = [
  20 + [
  21 + "area" => "洛杉矶",
  22 + "numericValue" => 0,
  23 + ],
  24 + [
  25 + "area" => "圣地亚哥",
  26 + "numericValue" => 0,
  27 + ],
  28 + [
  29 + "area" => "伦敦",
  30 + "numericValue" => 0,
  31 + ],
  32 + [
  33 + "area" => "西雅图",
  34 + "numericValue" => 0,
  35 + ],
  36 + [
  37 + "area" => "吉隆坡",
  38 + "numericValue" => 0,
  39 + ],
  40 + [
  41 + "area" => "雅加达",
  42 + "numericValue" => 0,
  43 + ],
  44 + [
  45 + "area" => "孟买",
  46 + "numericValue" => 0,
  47 + ],
  48 + [
  49 + "area" => "迪拜",
  50 + "numericValue" => 0,
  51 + ],
  52 + [
  53 + "area" => "法兰克福",
  54 + "numericValue" => 0,
  55 + ],
  56 + [
  57 + "area" => "新加坡",
  58 + "numericValue" => 0,
  59 + ],
  60 + [
  61 + "area" => "悉尼",
  62 + "numericValue" => 0,
  63 + ],
  64 + [
  65 + "area" => "东京",
  66 + "numericValue" => 0,
  67 + ],
  68 + [
  69 + "area" => "硅谷",
  70 + "numericValue" => 0,
  71 + ],
  72 + [
  73 + "area" => "弗吉尼亚",
  74 + "numericValue" => 0,
  75 + ],
  76 + [
  77 + "area" => "香港",
  78 + "numericValue" => 0,
  79 + ],
  80 + [
  81 + "area" => "圣保罗",
  82 + "numericValue" => 0,
  83 + ],
  84 + [
  85 + "area" => "雅典",
  86 + "numericValue" => 0,
  87 + ],
  88 + [
  89 + "area" => "巴黎",
  90 + "numericValue" => 0,
  91 + ],
  92 + [
  93 + "area" => "罗马",
  94 + "numericValue" => 0,
  95 + ],
  96 + [
  97 + "area" => "马德里",
  98 + "numericValue" => 0,
  99 + ],
  100 + ];
  101 +
  102 + /**
  103 + * @param $url
  104 + * @return array|false
  105 + * @author zbj
  106 + * @date 2023/5/10
  107 + */
  108 + function run($url)
  109 + {
  110 + try {
  111 + if($url){
  112 + $params = [
  113 + 'url' => $url
  114 + ];
  115 + $res = HttpUtils::get('http://pagespeed.quanqiusou.cn/api.php', $params);
  116 + if ($res) {
  117 + $res = Arr::s2a($res);
  118 + $area_data = Arr::s2a($res['area_data']);
  119 + }
  120 + $numericValue = $area_data[0]['numericValue'] ?? rand(500, 1000);
  121 + foreach ($this->areas as &$area) {
  122 + $start = -$numericValue * 0.5;
  123 + $end = $numericValue * 0.5;
  124 + $numer = rand($start, $end);
  125 + $area["numericValue"] = ceil($numericValue - $numer);
  126 + }
  127 + }
  128 + } catch (\Exception | GuzzleException $e) {
  129 + errorLog('测速失败', $params, $e);
  130 + }
  131 + return [
  132 + "url" => $url,
  133 + "area_data" => $this->areas,
  134 + "created_at" => date("Y-m-d H:i:s")
  135 + ];
  136 + }
  137 +}