作者 lyh

Merge branch 'master' of http://47.244.231.31:8099/zhl/globalso-v6 into lyh-server

  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2024/09/30
  6 + * Time: 11:51
  7 + */
  8 +namespace App\Console\Commands\Inquiry;
  9 +
  10 +use App\Helper\Common;
  11 +use App\Helper\Gpt;
  12 +use App\Helper\Translate;
  13 +use App\Helper\Validate;
  14 +use App\Models\Ai\AiCommand;
  15 +use App\Models\Inquiry\ReInquiryConfig;
  16 +use App\Models\Inquiry\ReInquiryDetail;
  17 +use App\Models\Inquiry\ReInquiryDetailLog;
  18 +use App\Models\Inquiry\ReInquiryForm;
  19 +use App\Models\Inquiry\ReInquiryTask;
  20 +use App\Models\Inquiry\ReInquiryText;
  21 +use App\Models\Project\InquiryFilterConfig;
  22 +use App\Models\Project\Project;
  23 +use App\Models\WebSetting\WebLanguage;
  24 +use Illuminate\Console\Command;
  25 +use Illuminate\Support\Arr;
  26 +use Illuminate\Support\Facades\Cache;
  27 +use Illuminate\Support\Facades\DB;
  28 +use Illuminate\Support\Facades\Http;
  29 +use Illuminate\Support\Facades\Log;
  30 +use Illuminate\Support\Str;
  31 +
  32 +/**
  33 + * Class RelayInquiry
  34 + * @package App\Console\Commands\Inquiry
  35 + */
  36 +class RelayInquiryTest extends Command
  37 +{
  38 + /**
  39 + * The name and signature of the console command.
  40 + *
  41 + * @var string
  42 + */
  43 + protected $signature = 'relay_inquiry_test';
  44 +
  45 + /**
  46 + * The console command description.
  47 + *
  48 + * @var string
  49 + */
  50 + protected $description = '重启失败的转发询盘';
  51 +
  52 + /**
  53 + * Create a new command instance.
  54 + *
  55 + * @return void
  56 + */
  57 + public function __construct()
  58 + {
  59 + parent::__construct();
  60 + }
  61 +
  62 + /**
  63 + * 模拟访问来源占比
  64 + * @var array
  65 + */
  66 + protected $lyzb = [
  67 + 'https://www.google.com/' => 630,
  68 + 'http://www.google.com/' => 30,
  69 + 'http://www.bing.com/' => 20,
  70 + 'https://www.bing.com/' => 5,
  71 + 'https://www.youtube.com/' => 5,
  72 + 'https://search.yahoo.com/' => 5,
  73 + 'https://www.facebook.com/' => 5,
  74 + ];
  75 +
  76 + /**
  77 + * 俄语站 模拟访问来源占比
  78 + * @var array
  79 + */
  80 + protected $eylyzb = [
  81 + 'https://www.yandex.com/' => 630,
  82 + 'https://www.google.com/' => 30,
  83 + 'http://www.google.com/' => 30,
  84 + 'http://www.bing.com/' => 20,
  85 + 'https://www.bing.com/' => 5,
  86 + 'https://www.youtube.com/' => 5,
  87 + 'https://search.yahoo.com/' => 5,
  88 + 'https://www.facebook.com/' => 5,
  89 + ];
  90 +
  91 + /**
  92 + * PC端访问头信息
  93 + * @var array
  94 + */
  95 + protected $pc_ua = [
  96 + 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',
  97 + 1 => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  98 + 2 => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
  99 + ];
  100 +
  101 + /**
  102 + * 移动端访问头信息
  103 + * @var array
  104 + */
  105 + protected $mobile_ua = [
  106 + 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',
  107 + ];
  108 +
  109 + /**
  110 + * google域名后缀
  111 + * @var string[]
  112 + */
  113 + protected $suffix = [
  114 + 'co.jp' => '日本',
  115 + 'com.tr' => '土耳其',
  116 + 'nl' => '荷兰',
  117 + 'ru' => '俄罗斯',
  118 + 'fr' => '法国',
  119 + 'co.kr' => '韩国',
  120 + 'fi' => '芬兰',
  121 + 'be' => '比利时',
  122 + 'lt' => '立陶宛',
  123 + 'es' => '西班牙',
  124 + 'it' => '意大利',
  125 + 'com.au' => '澳大利亚',
  126 + 'no' => '挪威',
  127 + 'al' => '阿尔巴尼亚',
  128 + 'pt' => '葡萄牙',
  129 + 'lv' => '拉脱维亚',
  130 + 'hu' => '匈牙利',
  131 + 'cz' => '捷克',
  132 + 'de' => '德国',
  133 + 'ca' => '加拿大',
  134 + 'co.in' => '印度',
  135 + 'co.uk' => '英国',
  136 + 'com.vn' => '越南',
  137 + 'com.br' => '巴西',
  138 + 'co.il' => '以色列',
  139 + 'pl' => '波兰',
  140 + 'com.eg' => '埃及',
  141 + 'co.th' => '泰国',
  142 + 'sk' => '斯洛伐克',
  143 + 'ro' => '罗马尼亚',
  144 + 'com.mx' => '墨西哥',
  145 + 'com.my' => '马来西亚',
  146 + 'com.pk' => '巴基斯坦',
  147 + 'co.nz' => '新西兰',
  148 + 'co.za' => '南非',
  149 + 'com.ar' => '阿根廷',
  150 + 'com.kw' => '科威特',
  151 + 'com.sg' => '新加坡',
  152 + 'com.co' => '哥伦比亚',
  153 + 'co.id' => '印度尼西亚',
  154 + 'gr' => '希腊',
  155 + 'bg' => '保加利亚',
  156 + 'mn' => '蒙古',
  157 + 'dk' => '丹麦',
  158 + 'com.sa' => '沙特阿拉伯',
  159 + 'com.pe' => '秘鲁',
  160 + 'com.ph' => '菲律宾',
  161 + 'com.ua' => '乌克兰',
  162 + 'ge' => '格鲁吉亚',
  163 + 'ae' => '阿拉伯联合酋长国',
  164 + 'tn' => '突尼斯',
  165 + ];
  166 +
  167 + protected $otherzb = [700, 300]; //模拟访问来源占比 (非美国) google.com|google.其他后缀
  168 +
  169 + /**
  170 + * 手机号过滤 0去掉+ 1不转发手机 2不处理
  171 + * @var int[]
  172 + */
  173 + protected $filter_phone = [30,12,58];
  174 +
  175 + /**
  176 + * 需要多个ip访问的国家
  177 + * @var
  178 + */
  179 + protected $multiple_ip_visit_country = [
  180 + '阿尔及利亚',
  181 + '埃及',
  182 + '埃塞俄比亚',
  183 + '安哥拉',
  184 + '贝宁',
  185 + '博茨瓦纳',
  186 + '布基纳法索',
  187 + '布隆迪',
  188 + '赤道几内亚',
  189 + '多哥',
  190 + '厄立特里亚',
  191 + '佛得角',
  192 + '冈比亚',
  193 + '刚果共和国',
  194 + '刚果民主共和国',
  195 + '吉布提',
  196 + '几内亚',
  197 + '几内亚比绍共和国',
  198 + '加纳',
  199 + '加蓬',
  200 + '津巴布韦',
  201 + '喀麦隆',
  202 + '科摩罗',
  203 + '科特迪瓦',
  204 + '肯尼亚',
  205 + '莱索托',
  206 + '利比里亚',
  207 + '利比亞',
  208 + '留尼汪',
  209 + '卢旺达',
  210 + '马达加斯加',
  211 + '马拉维',
  212 + '马里',
  213 + '马约特',
  214 + '毛里求斯',
  215 + '毛里塔尼亚',
  216 + '摩洛哥',
  217 + '莫桑比克',
  218 + '纳米比亚',
  219 + '南非',
  220 + '南苏丹',
  221 + '尼日尔',
  222 + '尼日利亚',
  223 + '塞拉利昂',
  224 + '塞内加尔',
  225 + '塞舌尔',
  226 + '圣多美和普林西比',
  227 + '圣赫勒拿',
  228 + '斯威士兰',
  229 + '索马里',
  230 + '坦桑尼亚',
  231 + '突尼斯',
  232 + '乌干达',
  233 + '西撒哈拉',
  234 + '赞比亚',
  235 + '乍得',
  236 + '中非共和国',
  237 + '阿富汗',
  238 + '阿联酋',
  239 + '阿曼',
  240 + '阿塞拜疆',
  241 + '澳门',
  242 + '巴基斯坦',
  243 + '巴勒斯坦',
  244 + '巴林',
  245 + '不丹',
  246 + '东帝汶',
  247 + '菲律宾',
  248 + '格鲁吉亚',
  249 + '哈萨克斯坦',
  250 + '韩国',
  251 + '吉尔吉斯斯坦',
  252 + '柬埔寨',
  253 + '卡塔尔',
  254 + '科威特',
  255 + '老挝',
  256 + '黎巴嫩',
  257 + '马尔代夫',
  258 + '马来西亚',
  259 + '蒙古',
  260 + '孟加拉国',
  261 + '缅甸',
  262 + '尼泊尔',
  263 + '日本',
  264 + '塞浦路斯',
  265 + '沙特阿拉伯',
  266 + '斯里兰卡',
  267 + '塔吉克斯坦',
  268 + '泰国',
  269 + '土耳其',
  270 + '土库曼斯坦',
  271 + '文莱',
  272 + '乌兹别克斯坦',
  273 + '新加坡',
  274 + '亚美尼亚',
  275 + '也门',
  276 + '伊拉克',
  277 + '以色列',
  278 + '印度尼西亚',
  279 + '约旦',
  280 + '越南',
  281 + ];
  282 +
  283 + /**
  284 + * @return bool
  285 + */
  286 + public function handle()
  287 + {
  288 + while (true) {
  289 + $inquiry = ReInquiryForm::where('created_at', '>', '2025-05-19 00:00:00')
  290 + ->where('created_at', '<', '2025-05-22 18:00:00')
  291 + ->where(['status' => ReInquiryForm::STATUS_FORGO])
  292 + ->where('remark', '超时72小时未处理!')
  293 + ->orderBy('id', 'asc')->get();
  294 +
  295 + if ($inquiry->isEmpty()){
  296 + $this->output('未发现待处理询盘!');
  297 + sleep(60);
  298 + continue;
  299 + }
  300 +
  301 + $this->output('开始处理本轮询盘!');
  302 + foreach ($inquiry as $key=>$val) {
  303 + $this->output('询盘ID:' . $val->id);
  304 +
  305 +
  306 + $detail_ids = ReInquiryDetail::where('form_id', $val->id)->pluck('id')->toArray();
  307 +
  308 + $inquiry_log = ReInquiryDetailLog::whereIn('detail_id', $detail_ids)->where('type', ReInquiryDetailLog::TYPE_INQUIRY)->first();
  309 + //有询盘的了 就跳过
  310 + if($inquiry_log){
  311 + continue;
  312 + }
  313 +
  314 + // 询盘对应广告
  315 + $ad_task = $this->getAdTask($val->ad_id);
  316 + // 没有获取到转发任务
  317 + if (empty($ad_task)) {
  318 + $val->status = ReInquiryForm::STATUS_FORGO;
  319 + $val->remark = '未找到需要转发的广告任务!';
  320 + $val->save();
  321 + continue;
  322 + }
  323 + // 未设置对法对象
  324 + $target_num_arr = array_map(function ($item) {
  325 + return count($item['target']) + count($item['shop_site']) + count($item['fob_pro']);
  326 + }, $ad_task);
  327 + if (!array_sum($target_num_arr)) {
  328 + $val->status = ReInquiryForm::STATUS_FORGO;
  329 + $val->remark = '广告任务转发对象为空!';
  330 + $val->save();
  331 + continue;
  332 + }
  333 + //是否要过滤
  334 + $filter_res = $this->filter($val);
  335 + if($filter_res !== true){
  336 + $val->status = ReInquiryForm::STATUS_FORGO;
  337 + $val->remark = $filter_res;
  338 + $val->save();
  339 + continue;
  340 + }
  341 + //验证手机号 无效 号码不推送
  342 + if(!Validate::phone($val->phone)){
  343 + $val->phone = '';
  344 + }
  345 + try {
  346 + $res = false;
  347 + foreach ($ad_task as $task){
  348 + $res += $this->relayDetail($task, $val);
  349 + $res += $this->relayShopDetail($task, $val);
  350 + $res += $this->relayFobDetail($task, $val);
  351 + }
  352 + $val->status = $res ? ReInquiryForm::STATUS_SUCCESS : ReInquiryForm::STATUS_FORGO;
  353 + $val->save();
  354 + } catch (\Exception $e) {
  355 + $this->logChannel()->info('执行询盘错误:',[$e->getMessage(), $e->getFile(), $e->getLine()]);
  356 + $this->output('执行询盘错误:' . $e->getMessage());
  357 + }
  358 + }
  359 + $this->output('本轮询盘处理结束!');
  360 + }
  361 + return true;
  362 + }
  363 +
  364 +
  365 + public function filter($data)
  366 + {
  367 + //通用过滤规则
  368 + $config = InquiryFilterConfig::getCacheInfoByProjectId(Project::DEMO_PROJECT_ID);
  369 + //FB询盘的全局过滤规则
  370 + $fb_config = ReInquiryConfig::getDefaultConfigCache(ReInquiryConfig::TYPE_FILTER_WORDS);
  371 +
  372 + $fb_config['filter_contents'] = array_filter(explode("\r\n", $fb_config['filter_contents']??''));
  373 + $fb_config['filter_emails'] = array_filter(explode("\r\n", $fb_config['filter_emails']??''));
  374 + $fb_config['filter_mobiles'] = array_filter(explode("\r\n", $fb_config['filter_mobiles']??''));
  375 + $fb_config['filter_names'] = array_filter(explode("\r\n", $fb_config['filter_names']??''));
  376 +
  377 + $config['filter_contents'] = array_unique(array_merge($fb_config['filter_contents'],$config['filter_contents']));
  378 + $config['filter_emails'] = array_unique(array_merge($fb_config['filter_emails'],$config['filter_emails']));
  379 + $config['filter_mobiles'] = array_unique(array_merge($fb_config['filter_mobiles'],$config['filter_mobiles']));
  380 + $config['filter_names'] = array_unique(array_merge($fb_config['filter_names'],$config['filter_names']));
  381 +
  382 + //过滤内容
  383 + if(!empty($data['message']) && !empty($config['filter_contents'])) {
  384 + foreach ($config['filter_contents'] as $filter_content) {
  385 + if (Str::contains(strtolower($data['message']), strtolower($filter_content))) {
  386 + return '过滤内容:' . $filter_content;
  387 + }
  388 + }
  389 + }
  390 + //过滤邮箱
  391 + if(!empty($data['email']) && !empty($config['filter_emails'])){
  392 + foreach ($config['filter_emails'] as $filter_email){
  393 + if(Str::contains(strtolower($data['email']), strtolower($filter_email))){
  394 + return '过滤邮箱:' . $filter_email;
  395 + }
  396 + }
  397 + //邮箱有效性
  398 + if(!Validate::email($data['email'])){
  399 + return '邮箱无效';
  400 + }
  401 + }
  402 + //过滤电话
  403 + if(!empty($data['phone']) && !empty($config['filter_mobiles'])){
  404 + foreach ($config['filter_mobiles'] as $filter_mobile){
  405 + if(Str::contains(strtolower($data['phone']), strtolower($filter_mobile))){
  406 + return '过滤电话:' . $filter_mobile;
  407 + }
  408 + }
  409 + }
  410 + //过滤姓名
  411 + if(!empty($data['full_name'] && !empty($config['filter_names']))){
  412 + foreach ($config['filter_names'] as $filter_name){
  413 + if(Str::contains(strtolower($data['full_name']), strtolower($filter_name))){
  414 + return '过滤姓名:' . $filter_name;
  415 + }
  416 + }
  417 + }
  418 + return true;
  419 + }
  420 +
  421 + /**
  422 + * 创建转发详情
  423 + * TODO 通过任务生成转发对象, 更具转发对象获取对应数据, 写入着陆记录
  424 + * @param $task
  425 + * @param $form
  426 + * @return bool
  427 + */
  428 + public function relayDetail($task, $form)
  429 + {
  430 + $this->output('获取转发对象');
  431 + if(empty($task['target'] )){
  432 + $this->output('没有独立站转发对象');
  433 + return 0;
  434 + }
  435 + //是否有必选的渠道 渠道有一个及以上必选 就在组内随机一个
  436 + $require_agent_group = [];
  437 + foreach ($task['target'] as $item) {
  438 + if (!empty($item['is_require'])) {
  439 + $require_agent_group[] = $item['agent_group'];
  440 + }
  441 + }
  442 + $require_agent_group = array_unique($require_agent_group);
  443 + $require_agent_group_data = collect($task['target'])->whereIn('agent_group', $require_agent_group)->groupBy('agent_group');
  444 + $require_data = $require_agent_group_data->keys()->random(count($require_agent_group))->map(function ($group) use ($require_agent_group_data) {
  445 + return $require_agent_group_data[$group]->random();
  446 + })->all();
  447 + //代理商组 一个组只发一个
  448 + $agent_group = collect($task['target'])->whereNotIn('agent_group', $require_agent_group)->groupBy('agent_group');
  449 + // 获取转发对象 重置num数量, array_rand数量不足会报错
  450 + $task['num'] = $task['num'] - count($require_agent_group);
  451 + $num = $task['num'] > count($agent_group) ? count($agent_group) : $task['num'];
  452 + $random_data = $agent_group->keys()->random($num)->map(function ($group) use ($agent_group) {
  453 + return $agent_group[$group]->random();
  454 + })->all();
  455 + $random_data = array_merge($require_data, $random_data);
  456 +
  457 + if (empty($random_data)) {
  458 + $this->logChannel()->info('当前任务未发现转发对象!', ['广告任务ID:' . $task['id'], '询盘ID:' . $form->id]);
  459 + $form->remark = $form->remark . '当前任务未发现转发对象,广告ID: ' . $form->ad_id . '!';
  460 + return false;
  461 + }
  462 + $this->logChannel()->info('随机域名', array_column($random_data, 'url'));
  463 + foreach ($random_data as $item) {
  464 + $times = 1;
  465 + $inquiry_time = 1;
  466 +
  467 + //需要多个ip访问的国家 随机2-5次访问,只有一次询盘
  468 + if (in_array($form->country_name, $this->multiple_ip_visit_country)) {
  469 + $times = mt_rand(1, 2); //随机次数
  470 + $inquiry_time = mt_rand(1, $times); //第几次询盘
  471 + $this->output('多次访问模拟:' . $times .',第' . $inquiry_time . '次询盘');
  472 + }
  473 + for ($i = 1; $i <= $times; $i++) {
  474 + $is_inquiry = ($inquiry_time == $i);
  475 + if($is_inquiry){
  476 + $this->output('第' . $i . '次询盘');
  477 + }
  478 + //手机号过滤
  479 + $phone = $form->phone;
  480 + $filter_phone = $this->get_rand($this->filter_phone);
  481 + if($filter_phone == 0){
  482 + $phone = trim(str_replace("+", '', $phone));
  483 + }elseif($filter_phone == 1){
  484 + $phone = '';
  485 + }
  486 +
  487 + // 推送站点
  488 + $domain = $item['url'];
  489 + $is_v6 = $item['is_v6'];
  490 + $re_website = 'https://' . $domain . '/';
  491 +
  492 + //urls
  493 + list($urls, $lang, $inquiry_product_url) = $this->getUrls($is_v6, $domain, $re_website, $form, $task);
  494 + if(!$urls){
  495 + continue;
  496 + }
  497 +
  498 + //ip
  499 + $ip_data = $this->getIpData($form->country_name);
  500 + $ip = $ip_data->ip;
  501 + $country_name = $ip_data->ip_area;
  502 +
  503 + //message
  504 + $message = '';
  505 + $message_id = 0;
  506 + $msg_lang = '';
  507 + if($is_inquiry) {
  508 + list($message, $message_id, $msg_lang) = $this->getMessage($task, $form->message, $domain, $inquiry_product_url);
  509 + }
  510 + $lang = $lang ?: $msg_lang;
  511 +
  512 + $this->output('获取转发设备信息');
  513 + // 客户端 头信息 来源
  514 + $device_port = $form->email ? '1' : '2'; //1 pc 2移动端
  515 + $user_agent = $form->email ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);
  516 + $referrer = $this->getReferer($country_name, $lang);
  517 + $this->output('写入数据');
  518 +
  519 + $pre = 0;
  520 + $start_time = strtotime($form->inquiry_date);
  521 + if($start_time < time()){
  522 + $start_time = time();
  523 + $seconds = rand(0, 72 * 3600); // 3天内发完
  524 + }else{
  525 + $seconds = rand(100, 2 * 3600);
  526 + }
  527 + $email = '';
  528 + if($is_inquiry) {
  529 + $exists = ReInquiryDetail::where('re_website', $domain)->where('email', $form->email)->first();
  530 + if ($exists) {
  531 + $this->output('转发站点邮件已存在');
  532 + // continue;
  533 + }
  534 + $email = $form->email;
  535 + }
  536 + dump(date('Y-m-d H:i:s', $start_time + $seconds));
  537 + // 写入推送详情
  538 + $re_detail = ReInquiryDetail::createInquiry($task['id'], $form->id, $domain, $country_name, $ip, $form->full_name, $email, $phone, $message, $message_id, $device_port,
  539 + $user_agent, $referrer, $urls, $is_v6, date('Y-m-d H:i:s', $start_time + $seconds));
  540 + foreach ($urls as $k=>$v){
  541 + $pre++;
  542 + $seconds += rand(5,60);
  543 + ReInquiryDetailLog::createInquiryLog($re_detail->id, ReInquiryDetailLog::TYPE_VISIT, $pre, $v, date('Y-m-d H:i:s', $start_time + $seconds));
  544 + // 最后一次访问询盘 加上询盘
  545 + if($is_inquiry && ($k+1) == count($urls)){
  546 + $this->output('第' . ($k+1) . '个链接询盘');
  547 + $seconds += rand(30,120);
  548 + $pre++;
  549 + ReInquiryDetailLog::createInquiryLog($re_detail->id, ReInquiryDetailLog::TYPE_INQUIRY, $pre, $v, date('Y-m-d H:i:s', $start_time + $seconds));
  550 + }
  551 + }
  552 + }
  553 + }
  554 + return true;
  555 + }
  556 +
  557 + public function relayShopDetail($task, $form)
  558 + {
  559 + $this->output('获取商城转发对象');
  560 +
  561 + if(empty($task['shop_site'])){
  562 + $this->output('没有商城转发对象');
  563 + return 0;
  564 + }
  565 +
  566 + $num = $task['num'] > count($task['shop_site']) ? count($task['shop_site']) : $task['num'];
  567 + $shop_site = collect($task['shop_site'])->random($num)->all();
  568 +
  569 + foreach ($shop_site as $item) {
  570 + //手机号过滤
  571 + $phone = $form->phone;
  572 + // 推送站点
  573 + $domain = $item;
  574 + $re_website = 'https://' . $domain . '/';
  575 + $paths = ['', 'contact-us'];
  576 + $url = $re_website . $paths[array_rand($paths)];
  577 + //ip
  578 + $ip_data = $this->getIpData($form->country_name);
  579 + $ip = $ip_data->ip;
  580 + $country_name = $ip_data->ip_area;
  581 +
  582 + //message
  583 + list($message, $message_id, $lang) = $this->getMessage($task, $form->message, $domain);
  584 +
  585 + $device_port = $form->email ? '1' : '2'; //1 pc 2移动端
  586 + $user_agent = $form->email ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);
  587 + $referrer = $this->getReferer($country_name, $lang);
  588 +
  589 + $start_time = strtotime($form->inquiry_date);
  590 + if($start_time < time()){
  591 + $start_time = time();
  592 + $seconds = rand(0, 48 * 3600); // 开始时间 从5-2小时后开始
  593 + }else{
  594 + $seconds = rand(100, 2 * 3600);
  595 + }
  596 + dump(date('Y-m-d H:i:s', $start_time + $seconds));
  597 + $exists = ReInquiryDetail::where('re_website', $domain)->where('email', $form->email)->first();
  598 + if($exists){
  599 + $this->output('转发站点邮件已存在');
  600 + continue;
  601 + }
  602 + $re_detail = ReInquiryDetail::createInquiry($task['id'], $form->id, $domain, $country_name, $ip, $form->full_name, $form->email, $phone, $message, $message_id,
  603 + $device_port, $user_agent, $referrer, [$url], 0, date('Y-m-d H:i:s', $start_time + $seconds), ReInquiryDetail::STATUS_INIT, 2);
  604 +
  605 + ReInquiryDetailLog::createInquiryLog($re_detail->id, ReInquiryDetailLog::TYPE_INQUIRY, 1, $url, date('Y-m-d H:i:s', $start_time + $seconds));
  606 + }
  607 + return true;
  608 + }
  609 +
  610 +
  611 + public function relayFobDetail($task, $form)
  612 + {
  613 + $this->output('获取FOB转发对象');
  614 +
  615 + if(empty($task['fob_pro'])){
  616 + $this->output('没有FOB转发对象');
  617 + return 0;
  618 + }
  619 +
  620 + foreach ($task['fob_pro'] as $item) {
  621 + //手机号过滤
  622 + $phone = $form->phone;
  623 + // 推送站点
  624 + $postid = $item;
  625 + //message
  626 + list($message, $message_id, $lang) = $this->getMessage($task, $form->message, $postid);
  627 +
  628 + $device_port = $form->email ? '1' : '2'; //1 pc 2移动端
  629 + $user_agent = $form->email ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);
  630 +
  631 + $start_time = strtotime($form->inquiry_date);
  632 + if($start_time < time()){
  633 + $start_time = time();
  634 + $seconds = rand(0, 10 * 3600); // 开始时间 从5-2小时后开始
  635 + }else{
  636 + $seconds = rand(100, 2 * 3600);
  637 + }
  638 + dump(date('Y-m-d H:i:s', $start_time + $seconds));
  639 + $exists = ReInquiryDetail::where('re_website', $postid)->where('email', $form->email)->first();
  640 + if($exists){
  641 + $this->output('转发站点邮件已存在');
  642 + continue;
  643 + }
  644 + $re_detail = ReInquiryDetail::createInquiry($task['id'], $form->id, $postid, $country_name??'', $ip??'', $form->full_name, $form->email, $phone,
  645 + $message, $message_id, $device_port, $user_agent, $referrer??'', [$postid], 0, date('Y-m-d H:i:s', $start_time + $seconds), ReInquiryDetail::STATUS_INIT, 3);
  646 +
  647 + ReInquiryDetailLog::createInquiryLog($re_detail->id, ReInquiryDetailLog::TYPE_INQUIRY, 1, $postid, date('Y-m-d H:i:s', $start_time + $seconds));
  648 + }
  649 + return true;
  650 + }
  651 +
  652 + public function getIpData($country_name){
  653 + $this->output('获取转发ip');
  654 + $country = $country_name;
  655 + // 有国家 通过国家查询, 如果没有获取到就随机获取
  656 + $where = [];
  657 + $country && $where['ip_area'] = $country;
  658 + $ip_data = DB::table('gl_xunpan_ipdata')->where($where)->inRandomOrder()->first();
  659 + if (empty($ip_data)) {
  660 + $ip_data = DB::table('gl_xunpan_ipdata')->inRandomOrder()->first();
  661 + }
  662 + return $ip_data;
  663 + }
  664 +
  665 + public function getMessage($task, $message, $domain, $inquiry_product_url = ''){
  666 + $this->output('转发内容');
  667 + $form_message = $message;
  668 + $message_id = 0;
  669 +
  670 + // TODO 当原始询盘内容长度大于15个字符, 60%几率直接发送原始内容。
  671 + if (strlen($message) >= 15) {
  672 + $not_use_probability = AiCommand::where('key', 'fb_inquiry_text')->value('not_use_probability');
  673 + $randomNumber = rand(0, 100);
  674 + if($randomNumber < $not_use_probability){
  675 + //原内容非英语,转为对应语种
  676 + if (is_numeric($form_message)) { //数字会被识别为中文
  677 + $lang = 'en';
  678 + } else {
  679 + $translateSl = Translate::translateSl($form_message);
  680 + $lang = $translateSl['texts']['sl'] ?? 'en';
  681 + }
  682 + return [$message, $message_id, $lang??''];
  683 + }
  684 + }
  685 +
  686 + //开启文案替换
  687 + if ($task['is_replace_text'] == 2) {
  688 + //AI生成
  689 + $error = 0;
  690 + while ($error<3){
  691 + $message = $this->ai_send($task['ai_param'], $message, $inquiry_product_url);
  692 + if(!$message){
  693 + $this->output('AI文案生成失败');
  694 + $error++;
  695 + if($error==2){
  696 + $task['is_replace_text'] = 1;
  697 + $this->output('AI文案生成失败,使用文案库');
  698 + }
  699 + }else{
  700 + break;
  701 + }
  702 + }
  703 + }
  704 + if ($task['is_replace_text'] == 1 || strlen($message) <= 4) {
  705 + //配置文案库替换或者字符少于4个,直接替换文案
  706 + $use_ids = ReInquiryDetail::where(['re_website' => $domain])->where('status', '<>', ReInquiryDetail::STATUS_FAIL)->pluck('text_id')->toArray();
  707 + $text = ReInquiryText::whereNotIn('id', $use_ids)->where('status', ReInquiryText::STATUS_USABLE)->inRandomOrder()->first();
  708 + $message = $text->content;
  709 + $message_id = $text->id;
  710 + // 获取后,使用次数+1
  711 + $text->use_time += 1;
  712 + $text->save();
  713 +
  714 + //原内容非英语,转为对应语种
  715 + if (is_numeric($form_message)) { //数字会被识别为中文
  716 + $lang = 'en';
  717 + } else {
  718 + $translateSl = Translate::translateSl($form_message);
  719 + $lang = $translateSl['texts']['sl'] ?? 'en';
  720 + }
  721 +
  722 + if ($lang != 'en' && !Str::contains($lang, 'zh')) {
  723 + $message = Translate::tran($message, $lang);
  724 + }
  725 + }
  726 + return [$message, $message_id, $lang??''];
  727 + }
  728 +
  729 + public function getUrls($is_v6, $domain, $re_website, $form, $task){
  730 + $this->output('转发对象:' . $domain);
  731 + $this->output('获取转发链接');
  732 + // v6:有邮箱推送主站,没有邮箱推送AMP站;v5:仅推送有邮箱到主站
  733 + $lang = '';
  734 + if ($is_v6) {
  735 + // 获取语种, 6.0是可以确定语种的
  736 + $project = Project::getProjectByDomain($domain);
  737 + if (empty($project)) {
  738 + $this->logChannel()->info('广告任务ID:' . $task['id'] . ', 转发对象:' . $re_website . '非v6链接,转发失败;', ['广告任务ID:' . $task['id'], '询盘ID:' . $form->id]);
  739 + return [[], $lang];
  740 + }
  741 + $lang = WebLanguage::getLangById($project->main_lang_id ?? 1)['short'];
  742 +
  743 + // 获取访问明细和着陆页
  744 + $product_url = $this->getLinksFromSitemap($re_website . 'product_sitemap.xml');
  745 + $product_cate_url = $this->getLinksFromSitemap($re_website . 'product_category_sitemap.xml');
  746 + $keywords_url = $this->getLinksFromSitemap($re_website . 'product_keywords_sitemap.xml');
  747 + $page_url = $this->getLinksFromSitemap($re_website . 'page_sitemap.xml');
  748 + } else {
  749 + if($form->email){
  750 + //通过sitemap拿访问页面
  751 + $product_url = $this->getLinksFromSitemap($re_website . 'sitemap_post.xml');
  752 + $product_cate_url = $this->getLinksFromSitemap($re_website . 'sitemap_category.xml');
  753 + $keywords_url = $this->getLinksFromSitemap($re_website . 'sitemap_post_tag.xml');
  754 + $page_url = $this->getLinksFromSitemap($re_website . 'sitemap_page.xml');
  755 + }else{
  756 + //m站先就往contact-us着陆
  757 + $product_url = $product_cate_url = $keywords_url = [];
  758 + $page_url = [$re_website . 'contact-us/'];
  759 + }
  760 + }
  761 +
  762 + // 所有可用url
  763 + $urls = $inquiry_urls = [];
  764 + //入口url 首页30%,单页10%,聚合页60%
  765 + $type = getRandByRatio([30,10,60]);
  766 + $inlet = $re_website;
  767 + $type == 1 && $inlet = $page_url ? Arr::random($page_url) : $re_website;
  768 + $type == 2 && $inlet = $keywords_url ? Arr::random($keywords_url) : $re_website;
  769 + $urls[] = $inquiry_urls[] = $inlet;
  770 + $all_urls = array_merge($urls, $product_url, $product_cate_url, $keywords_url, $page_url);
  771 + $inquiry_urls = array_merge($urls, $product_cate_url, $keywords_url, $page_url);
  772 +
  773 + // 随机访问1-6个页面
  774 + $deep = rand(1,6);
  775 + if($deep > 2) {
  776 + $visit_urls = Arr::random($all_urls, rand(1, count($all_urls) > 4 ? 4 : count($all_urls)));
  777 + $urls = array_merge($urls, $visit_urls);
  778 + }
  779 + if($deep > 1) {
  780 + // 推送着落页只能是 首页、产品分类、单页面、聚合页
  781 + if (!in_array(end($urls), $inquiry_urls)) {
  782 + $urls[] = Arr::random($inquiry_urls);
  783 + }
  784 + }
  785 + //着陆页是否是产品页面或产品列表页
  786 + $inquiry_product_url = '';
  787 + if(in_array(Arr::last($urls), $product_url) || in_array(Arr::last($urls), $product_cate_url)){
  788 + $inquiry_product_url = Arr::last($urls);
  789 + }
  790 +
  791 + return [$urls, $lang, $inquiry_product_url];
  792 + }
  793 + /**
  794 + * 获取待处理询盘表单
  795 + * @param int $num
  796 + * @return mixed
  797 + */
  798 + public function getInquiry($num = 10)
  799 + {
  800 + $result = ReInquiryForm::where(['status' => ReInquiryForm::STATUS_INIT])->orderBy('id', 'asc')->limit($num)->get();
  801 + return $result;
  802 + }
  803 +
  804 + /**
  805 + * 获取广告任务配置数据
  806 + * @param $ad_id
  807 + * @return array
  808 + */
  809 + public function getAdTask($ad_id)
  810 + {
  811 + $cache_key = 'inquiry_ads_tasks';
  812 + $ads = Cache::get($cache_key, function () use ($cache_key) {
  813 + $ads = ReInquiryTask::where(['status' => ReInquiryTask::STATUS_OPEN])->get(['id', 'ad_id', 'num', 'target', 'is_replace_text', 'ai_param', 'shop_site', 'fob_pro']);
  814 + $array = [];
  815 + foreach ($ads as $key=>$val) {
  816 + $ad_ids = explode(',', $val['ad_id']);
  817 + foreach ($ad_ids as $ad_id){
  818 + $array[$ad_id][] = $val;
  819 + }
  820 + }
  821 + if ($array)
  822 + Cache::put($cache_key, $array, 60);
  823 + return $array;
  824 + });
  825 + return empty($ads[$ad_id]) ? [] : $ads[$ad_id];
  826 + }
  827 +
  828 + /**
  829 + * 获取头信息
  830 + * @param $ip_area
  831 + * @param $lang
  832 + * @return int|string
  833 + */
  834 + public function getReferer($ip_area, $lang)
  835 + {
  836 + if($lang == 'ru'){
  837 + return $this->get_rand($this->eylyzb);
  838 + }
  839 + if($ip_area == '美国'){
  840 + $referer = $this->get_rand($this->lyzb);
  841 + }else{
  842 + $referer = 'https://www.google.com/';
  843 + $suffix = array_search($ip_area, $this->suffix);
  844 + if($suffix){
  845 + $res_qtzb = $this->get_rand($this->otherzb);
  846 + if($res_qtzb == 1){
  847 + $referer = 'https://www.google.'.$suffix.'/';
  848 + }
  849 + }
  850 + }
  851 + return $referer;
  852 + }
  853 +
  854 + /**
  855 + * 概率算法
  856 + * @param $proArr
  857 + * @return int|string
  858 + */
  859 + protected function get_rand($proArr)
  860 + {
  861 + $result = '';
  862 + $proSum = array_sum($proArr);
  863 + foreach ($proArr as $key => $proCur) {
  864 + $randNum = mt_rand(1, $proSum);
  865 + if ($randNum <= $proCur) {
  866 + $result = $key;
  867 + break;
  868 + } else {
  869 + $proSum -= $proCur;
  870 + }
  871 + }
  872 + unset ($proArr);
  873 + return $result;
  874 + }
  875 +
  876 + /**
  877 + * 获取sitemap内容
  878 + * @param $sitemapUrl
  879 + * @return array|mixed
  880 + */
  881 + function getLinksFromSitemap($sitemapUrl) {
  882 + try {
  883 + //忽略cert证书 先下载到临时文件
  884 + $result = Http::withoutVerifying()->get($sitemapUrl)->body();
  885 + $tempFilePath = tempnam(sys_get_temp_dir(), 'remote_file_');
  886 + file_put_contents($tempFilePath, $result);
  887 + $xml = simplexml_load_file($tempFilePath);
  888 + $links = [];
  889 + foreach ($xml->url as $url) {
  890 + $loc = (string) $url->loc;
  891 + if(!Str::contains($loc, ['404', 'thanks', 'test'])){
  892 + $links[] = $loc;
  893 + }
  894 + }
  895 + //随机取20个
  896 + $total = count($links);
  897 + return Arr::random($links, $total > 20 ? 20 : $total);
  898 + }catch (\Exception $e){
  899 + echo date('Y-m-d H:i:s') . 'sitemap获取失败:' . $e->getMessage() . PHP_EOL;
  900 + return $links??[];
  901 + }
  902 + }
  903 +
  904 + public function ai_send($ai_param, $incontent, $inquiry_product_url)
  905 + {
  906 + $ai_command = AiCommand::where('key', 'fb_inquiry_text')->value('ai');
  907 + if (!$ai_command) {
  908 + return '';
  909 + }
  910 + $translateSl = Translate::translateSl($incontent);
  911 + $lang = $translateSl['texts']['sl'] ?? 'en';
  912 + if ($lang == 'en' || $lang == 'ja' || $lang == 'ko' || Str::contains($lang, 'zh')) {
  913 + $language = '英文';
  914 + $lang = 'en';
  915 + }else{
  916 + $language = Translate::getTls($lang);
  917 + }
  918 +
  919 +
  920 +
  921 + //着陆页是否是产品页面或产品列表页
  922 + if($inquiry_product_url){
  923 + $title = Common::getUrlTitle($inquiry_product_url);
  924 + if($title){
  925 + $ai_command = str_replace('{mkeywords}', $title, $ai_command);
  926 + }
  927 + }
  928 + $ai_command = str_replace('{mkeywords}', Arr::random(explode("\r\n", $ai_param['mkeywords'])), $ai_command);
  929 + $ai_command = str_replace('{incontent}', Arr::random(explode("\r\n", $incontent)), $ai_command);
  930 + $ai_command = str_replace('{characters}', Arr::random(explode("\r\n", $ai_param['characters'])), $ai_command);
  931 +// $ai_command = str_replace('{language}', Arr::random(explode("\r\n", $language)), $ai_command);
  932 + $ai_command = str_replace('{language}', '英语', $ai_command); //输出英文 后面再翻译
  933 + $ai_command = str_replace('{inkeywords}', Arr::random(explode("\r\n", $ai_param['inkeywords'])), $ai_command);
  934 + $ai_command = str_replace('{suoxie}', Arr::random(explode("\r\n", $ai_param['suoxie'])), $ai_command);
  935 + //中括号里的根据概率使用
  936 + preg_match_all("/\[([^\]]+)\]/", $ai_command, $matches);
  937 + foreach ($matches[1] as $k => $match){
  938 + //按比例使用
  939 + $matche_arr = explode('|', $match);
  940 + $percentage = intval(trim($matche_arr[0], "%"));
  941 + if(rand(1,100) <= $percentage){
  942 + //使用
  943 + $ai_command = str_replace($matches[0][$k], $matche_arr[1], $ai_command);
  944 + }else{
  945 + //删除中括号
  946 + $ai_command = str_replace($matches[0][$k], '', $ai_command);
  947 + }
  948 + }
  949 +
  950 + $text = Gpt::instance()->openai_chat_qqs($ai_command);
  951 + if ($lang != 'en' && !Str::contains($lang, 'zh')) {
  952 + $text = Translate::tran($text, $lang);
  953 + }
  954 + $this->logChannel()->info("AI询盘文案", [$ai_command, $text]);
  955 + return Common::deal_str($text);
  956 + }
  957 +
  958 + /**
  959 + * @return \Psr\Log\LoggerInterface
  960 + */
  961 + public function logChannel()
  962 + {
  963 + return Log::channel('inquiry_relay');
  964 + }
  965 +
  966 + public function output($message)
  967 + {
  968 + echo date('Y-m-d H:i:s') . ' | ' . $message . PHP_EOL;
  969 + }
  970 +}
@@ -48,7 +48,7 @@ class IndexedPages extends BaseCommands @@ -48,7 +48,7 @@ class IndexedPages extends BaseCommands
48 $project_ids[] = 2104; 48 $project_ids[] = 2104;
49 } 49 }
50 foreach ($project_ids as $project_id){ 50 foreach ($project_ids as $project_id){
51 - $rank_data = RankData::where('project_id', $project_id)->where('lang', '')->first(); 51 + $rank_data = RankData::where('project_id', $project_id)->where('api_no', $api_no)->where('lang', '')->first();
52 if($rank_data){ 52 if($rank_data){
53 $rank_data->indexed_pages_num = $num; 53 $rank_data->indexed_pages_num = $num;
54 $rank_data->save(); 54 $rank_data->save();
@@ -85,7 +85,7 @@ class HyStockData extends Command @@ -85,7 +85,7 @@ class HyStockData extends Command
85 // 解析响应结果 85 // 解析响应结果
86 $responseResult = json_decode($response, true); 86 $responseResult = json_decode($response, true);
87 if ($responseResult) { 87 if ($responseResult) {
88 - $data = $responseResult['result'][0]['data']; 88 + $data = $responseResult['result'][0]['data'] ?? [];
89 if ($data) { 89 if ($data) {
90 //获取最近一条 90 //获取最近一条
91 $stock = StockData::orderBy('id', 'desc')->first(); 91 $stock = StockData::orderBy('id', 'desc')->first();