作者 李美松

新增网站流量统计

1 <?php 1 <?php
2 2
3 -namespace App\Console\Commands\Domain; 3 +namespace App\Console\Commands\Bside\Domain;
4 4
5 use App\Exceptions\AsideGlobalException; 5 use App\Exceptions\AsideGlobalException;
6 use App\Exceptions\BsideGlobalException; 6 use App\Exceptions\BsideGlobalException;
7 -use App\Helper\AyrShare as AyrShareHelper;  
8 use App\Http\Logic\Aside\Domain\DomainInfoLogic; 7 use App\Http\Logic\Aside\Domain\DomainInfoLogic;
9 -use App\Models\AyrShare\AyrRelease as AyrReleaseModel;  
10 -use Carbon\Carbon;  
11 -use App\Models\AyrShare\AyrShare as AyrShareModel;  
12 use Illuminate\Console\Command; 8 use Illuminate\Console\Command;
13 9
14 class DomainTime extends Command 10 class DomainTime extends Command
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\Bside\Statistics;
  4 +
  5 +use App\Models\Bside\Statistics\TrafficStatistics;
  6 +use App\Models\CustomerVisit\CustomerVisit;
  7 +use Illuminate\Console\Command;
  8 +
  9 +class StatisticsTrend 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 = 'statistics_trend';
  18 +
  19 + /**
  20 + * The console command description.
  21 + *
  22 + * @var string
  23 + */
  24 + protected $description = '统计当天流量趋势数据PV|IP数量';
  25 +
  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->statistics_trend();
  35 + }
  36 +
  37 + /**
  38 + * 统计当天流量趋势数据PV|IP数量
  39 + * @return int|mixed
  40 + */
  41 + protected function statistics_trend()
  42 + {
  43 + $customerVisit = new CustomerVisit();
  44 + $date = date('Y-m-d');
  45 + $ip_count = $customerVisit->getDayIPCount();
  46 + $pv_count = $customerVisit->getDayPVCount();
  47 + $trafficStatistics = new TrafficStatistics();
  48 + $trafficStatistics->type = TrafficStatistics::TYPE_TREND;
  49 + $trafficStatistics->
  50 + $data = [
  51 + 'date' => $date,
  52 + 'ip_count' => $ip_count,
  53 + 'pv_count' => $pv_count,
  54 + ];
  55 +// $res = $customerVisit->insert($data);
  56 + if ($res) {
  57 + $this->info('统计当天流量趋势数据PV|IP数量成功');
  58 + } else {
  59 + $this->error++;
  60 + $this->info('统计当天流量趋势数据PV|IP数量失败');
  61 + }
  62 + return $this->error;
  63 + }
  64 +}
  1 +<?php
  2 +
  3 +namespace App\Http\Controllers\Bside;
  4 +
  5 +
  6 +use App\Models\CustomerVisit\CustomerVisit;
  7 +use GuzzleHttp\Client;
  8 +use GuzzleHttp\Exception\GuzzleException;
  9 +use Illuminate\Http\JsonResponse;
  10 +use Psr\Container\ContainerExceptionInterface;
  11 +use Psr\Container\NotFoundExceptionInterface;
  12 +
  13 +/**
  14 + * 流量统计
  15 + * Class StatisticsController
  16 + * @package App\Http\Controllers\Bside
  17 + */
  18 +class StatisticsController extends BaseController
  19 +{
  20 + private $customerVisit;
  21 +
  22 + public function __construct()
  23 + {
  24 + $this->customerVisit = new CustomerVisit();
  25 + }
  26 +
  27 + /**
  28 + * 访问来源
  29 + * @return JsonResponse
  30 + */
  31 + public function source()
  32 + {
  33 + $pv_count = $this->customerVisit->getMonthPVCount();
  34 + $ip_count = $this->customerVisit->getMonthIPCount();
  35 + $lists = $this->customerVisit->getUrlCount();
  36 + return $this->success(compact('pv_count', 'ip_count', 'lists'));
  37 + }
  38 +
  39 + /**
  40 + * 地域分布
  41 + * @return JsonResponse
  42 + */
  43 + public function distribution()
  44 + {
  45 + $pv_count = $this->customerVisit->getMonthPVCount();
  46 + $ip_count = $this->customerVisit->getMonthIPCount();
  47 + $lists = $this->customerVisit->getCountryCount();
  48 + return $this->success(compact('pv_count', 'ip_count', 'lists'));
  49 + }
  50 +
  51 + /**
  52 + * 受访页面
  53 + * @return JsonResponse
  54 + */
  55 + public function page()
  56 + {
  57 + $pv_count = $this->customerVisit->getMonthPVCount();
  58 + $ip_count = $this->customerVisit->getMonthIPCount();
  59 + $lists = $this->customerVisit->getPageCount();
  60 + return $this->success(compact('pv_count', 'ip_count', 'lists'));
  61 + }
  62 +
  63 + /**
  64 + * 访问终端
  65 + * @return JsonResponse
  66 + */
  67 + public function terminal()
  68 + {
  69 + $pv_count = $this->customerVisit->getMonthPVCount();
  70 + $ip_count = $this->customerVisit->getMonthIPCount();
  71 + $pc_count = $this->customerVisit->getTerminalPcCount();
  72 + $mobile_count = $this->customerVisit->getTerminalMobileCount();
  73 + $lists = $this->customerVisit->getCountryCount();
  74 + return $this->success(compact('pv_count', 'ip_count', 'pc_count', 'mobile_count', 'lists'));
  75 + }
  76 +
  77 + /**
  78 + * 流量趋势
  79 + * @return JsonResponse
  80 + * @throws ContainerExceptionInterface
  81 + * @throws GuzzleException
  82 + * @throws NotFoundExceptionInterface
  83 + */
  84 + public function trend()
  85 + {
  86 +// dd($this->customerVisit->getDayIPCount());
  87 + $pv_count = $this->customerVisit->getMonthPVCount();
  88 + $ip_count = $this->customerVisit->getMonthIPCount();
  89 + $inquiry = $this->getCache('inquiry_information');
  90 + $inquiry_count = $inquiry['count'] ?? 0;
  91 + $lists = $inquiry['lists'] ?? [];
  92 + return $this->success(compact('pv_count', 'ip_count', 'inquiry_count', 'lists'));
  93 + }
  94 +
  95 + /**
  96 + * 获取缓存
  97 + * @param string $key 缓存键名
  98 + * @param float|int $time 缓存时间,默认2小时
  99 + * @return mixed
  100 + * @throws ContainerExceptionInterface
  101 + * @throws GuzzleException
  102 + * @throws NotFoundExceptionInterface
  103 + */
  104 + public function getCache(string $key, $time = 60 * 60 * 2)
  105 + {
  106 + $domain = request()->getHttpHost(); //'www.wowstainless.com';
  107 + $sta_date = date('Y-m-01');
  108 + $key = $key . '_' . $this->stringUnderlineLowercase($domain) . '_' . str_replace('-', '_', $sta_date);
  109 + $value = cache()->get($key);
  110 + if (!$value) {
  111 + $value = $this->getInquiryInformation($domain, $sta_date);
  112 + cache()->put($key, $value, $time);
  113 + }
  114 + return $value;
  115 + }
  116 +
  117 + /**
  118 + * 正则 - 名字转为小写并将空格转为下划线
  119 + * @param $name
  120 + * @return string
  121 + */
  122 + public function stringUnderlineLowercase($name)
  123 + {
  124 + return trim(strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $name)));
  125 + }
  126 +
  127 + /**
  128 + * 获取第三方询盘信息
  129 + * @return array|string
  130 + * @throws GuzzleException
  131 + */
  132 + public function getInquiryInformation($domain, $sta_date)
  133 + {
  134 + $token = md5($domain . date("Y-m-d"));
  135 + $source = '1,3';
  136 + $url = "https://form.globalso.com/api/external-interface/country_con/15243d63ed5a5738?domain={$domain}&token={$token}&source={$source}&sta_date={$sta_date}";
  137 + $client = new Client(['verify' => false]);
  138 + $http = $client->get($url);
  139 + $data = [];
  140 + if ($http->getStatusCode() != 200) {
  141 + return $data;
  142 + }
  143 + $content = $http->getBody()->getContents();
  144 + $json = json_decode($content, true);
  145 + if ($json['status'] != 200) {
  146 + return $content;
  147 + }
  148 + $data['count'] = $json['data']['count'];
  149 + $data['lists'] = $json['data']['data'];
  150 + return $data;
  151 + }
  152 +}
@@ -10,6 +10,8 @@ use App\Http\Logic\Aside\BaseLogic; @@ -10,6 +10,8 @@ use App\Http\Logic\Aside\BaseLogic;
10 use App\Http\Logic\Aside\Devops\ServerInformationLogic; 10 use App\Http\Logic\Aside\Devops\ServerInformationLogic;
11 use App\Models\Aside\Domain\DomainInfo; 11 use App\Models\Aside\Domain\DomainInfo;
12 use App\Models\Aside\Domain\DomainInfoLog; 12 use App\Models\Aside\Domain\DomainInfoLog;
  13 +use GuzzleHttp\Client;
  14 +use GuzzleHttp\Exception\GuzzleException;
13 use Illuminate\Database\Eloquent\Builder; 15 use Illuminate\Database\Eloquent\Builder;
14 use Illuminate\Database\Eloquent\Collection; 16 use Illuminate\Database\Eloquent\Collection;
15 use Illuminate\Database\Eloquent\Model; 17 use Illuminate\Database\Eloquent\Model;
@@ -74,7 +76,7 @@ class DomainInfoLogic extends BaseLogic @@ -74,7 +76,7 @@ class DomainInfoLogic extends BaseLogic
74 $request = $this->param; 76 $request = $this->param;
75 $this->extracted($request, $domain, $original); 77 $this->extracted($request, $domain, $original);
76 // 检查ip是否存在 78 // 检查ip是否存在
77 - if(array_key_exists('domain', $request)){ 79 + if (array_key_exists('domain', $request)) {
78 if ($domain->domain != $request['domain']) { 80 if ($domain->domain != $request['domain']) {
79 if ($this->checkDomain($request['domain'])) { 81 if ($this->checkDomain($request['domain'])) {
80 $this->fail('域名信息修改失败,域名已存在', Code::USER_ERROR); 82 $this->fail('域名信息修改失败,域名已存在', Code::USER_ERROR);
@@ -254,15 +256,23 @@ class DomainInfoLogic extends BaseLogic @@ -254,15 +256,23 @@ class DomainInfoLogic extends BaseLogic
254 256
255 /** 257 /**
256 * 域名到期时间 258 * 域名到期时间
  259 + * @param $domain
257 * @return array 260 * @return array
  261 + * @throws GuzzleException
258 */ 262 */
259 public function getDomainTime($domain) 263 public function getDomainTime($domain)
260 { 264 {
261 - $conJson = file_get_contents("http://openai.waimaoq.com/v1/whois_api?domain={$domain}");  
262 - $conArr = json_decode($conJson, true); 265 + $url = "http://openai.waimaoq.com/v1/whois_api?domain={$domain}";
  266 + $client = new Client(['verify' => false]);
  267 + $http = $client->get($url);
263 $data = []; 268 $data = [];
264 - if ($conArr['code'] == 200) {  
265 - $con = $conArr['text']; 269 + if ($http->getStatusCode() != 200) {
  270 + return $data;
  271 + }
  272 + $content = $http->getBody()->getContents();
  273 + $json = json_decode($content, true);
  274 + if ($json['code'] == 200) {
  275 + $con = $json['text'];
266 $data['domain'] = $domain; 276 $data['domain'] = $domain;
267 $data['validFrom'] = $con['creation_date']; 277 $data['validFrom'] = $con['creation_date'];
268 $data['validTo'] = $con['expiration_date']; 278 $data['validTo'] = $con['expiration_date'];
  1 +<?php
  2 +
  3 +namespace App\Models\Bside\Statistics;
  4 +
  5 +use App\Models\Base;
  6 +
  7 +/**
  8 + * 流量统计
  9 + */
  10 +class TrafficStatistics extends Base
  11 +{
  12 + protected $table = 'gl_traffic_statistics';
  13 +
  14 + /** @var int 访问来源 */
  15 + const TYPE_SOURCE = 1;
  16 + /** @var int 地域分布 */
  17 + const TYPE_DISTRIBUTION = 2;
  18 + /** @var int 受访页面 */
  19 + const TYPE_PAGE = 3;
  20 + /** @var int 访问终端 */
  21 + const TYPE_TERMINAL = 4;
  22 + /** @var int 流量趋势 */
  23 + const TYPE_TREND = 5;
  24 +}
  1 +<?php
  2 +
  3 +namespace App\Models\Bside\Statistics;
  4 +
  5 +use App\Models\Base;
  6 +
  7 +/**
  8 + * 流量统计
  9 + */
  10 +class TrafficTrends extends Base
  11 +{
  12 + protected $table = 'gl_traffic_trends';
  13 +}
@@ -3,8 +3,156 @@ @@ -3,8 +3,156 @@
3 namespace App\Models\CustomerVisit; 3 namespace App\Models\CustomerVisit;
4 4
5 use App\Models\Base; 5 use App\Models\Base;
  6 +use Illuminate\Database\Eloquent\Collection;
  7 +use Illuminate\Database\Eloquent\Factories\HasFactory;
6 8
7 class CustomerVisit extends Base 9 class CustomerVisit extends Base
8 { 10 {
  11 + use HasFactory;
  12 +
9 protected $table = 'gl_customer_visit'; 13 protected $table = 'gl_customer_visit';
  14 +
  15 + const LIMIT = 15;
  16 +
  17 + /** @var int PC端 */
  18 + const TERMINAL_PC = 1;
  19 + /** @var int 移动端 */
  20 + const TERMINAL_MOBILE = 2;
  21 +
  22 + public function queryField($field, $action = 'count', $whereDay = false)
  23 + {
  24 + $query = $this->query()
  25 + ->selectRaw("{$action}({$field}) as count")
  26 + ->whereYear('updated_date', '=', date("Y"))
  27 + ->whereMonth('updated_date', '=', date("m"));
  28 + if ($whereDay) {
  29 + $query->whereDay('updated_date', '=', date("d"));
  30 + }
  31 + return (int)$query->value('count') ?? 0;
  32 + }
  33 +
  34 +
  35 + public function queryTerminal($field, $action = self::TERMINAL_PC)
  36 + {
  37 + return (int)$this->query()
  38 + ->selectRaw("count(*) as count")
  39 + ->where($field, '=', $action)
  40 + ->whereYear('updated_date', '=', date("Y"))
  41 + ->whereMonth('updated_date', '=', date("m"))
  42 + ->value('count') ?? 0;
  43 + }
  44 +
  45 + public function getRankingData($field, $limit = self::LIMIT)
  46 + {
  47 + return $this->query()
  48 + ->selectRaw('count(*) as count, ' . $field . ' as request')
  49 + ->whereYear('updated_date', '=', date("Y"))
  50 + ->whereMonth('updated_date', '=', date("m"))
  51 + ->groupBy($field)
  52 + ->orderBy('count', 'desc')
  53 + ->limit($limit)
  54 + ->get();
  55 + }
  56 +
  57 + public function getSum($field)
  58 + {
  59 + return $this->queryField($field, 'sum');
  60 + }
  61 +
  62 + public function getCount($field)
  63 + {
  64 + return $this->queryField($field);
  65 + }
  66 +
  67 + public function returnLists(Collection $data, int $limit = self::LIMIT)
  68 + {
  69 + $lists = $data->toArray();
  70 + $lists = $lists ? array_slice($lists, 0, $limit) : [];
  71 + $count = $data->count();
  72 + return compact('lists', 'count');
  73 + }
  74 +
  75 + /**
  76 + * 查询当月流量的浏览量
  77 + * @return int
  78 + */
  79 + public function getMonthPVCount()
  80 + {
  81 + return $this->getSum('depth');
  82 + }
  83 +
  84 + /**
  85 + * 查询当月流量的访客量
  86 + * @return int
  87 + */
  88 + public function getMonthIPCount()
  89 + {
  90 + return $this->getCount('ip');
  91 + }
  92 +
  93 + /**
  94 + * 查询当月TOP15访问来源
  95 + * @param int $limit
  96 + * @return array
  97 + */
  98 + public function getUrlCount(int $limit = self::LIMIT)
  99 + {
  100 + return $this->getRankingData('referrer_url', $limit);
  101 + }
  102 +
  103 + /**
  104 + * 查询当月TOP15访问国家来源
  105 + * @param int $limit
  106 + * @return array
  107 + */
  108 + public function getCountryCount(int $limit = self::LIMIT)
  109 + {
  110 + return $this->getRankingData('country', $limit);
  111 + }
  112 +
  113 + /**
  114 + * 查询当月TOP15受访页面
  115 + * @param int $limit
  116 + * @return array
  117 + */
  118 + public function getPageCount(int $limit = self::LIMIT)
  119 + {
  120 + return $this->getRankingData('url', $limit);
  121 + }
  122 +
  123 + /**
  124 + * 查询当月TOP15访问终端
  125 + * @return int
  126 + */
  127 + public function getTerminalPcCount()
  128 + {
  129 + return $this->queryTerminal('device_port');
  130 + }
  131 +
  132 + /**
  133 + * 查询当月TOP15访问终端
  134 + * @return int
  135 + */
  136 + public function getTerminalMobileCount()
  137 + {
  138 + return $this->queryTerminal('device_port', self::TERMINAL_MOBILE);
  139 + }
  140 +
  141 + /**
  142 + * 查询当日流量的浏览量
  143 + * @return int
  144 + */
  145 + public function getDayPVCount()
  146 + {
  147 + return $this->queryField('depth', 'sum', true);
  148 + }
  149 +
  150 + /**
  151 + * 查询当日流量的访客量
  152 + * @return int
  153 + */
  154 + public function getDayIPCount()
  155 + {
  156 + return $this->queryField('ip', 'count', true);
  157 + }
10 } 158 }
@@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
19 "mrgoon/aliyun-sms": "^2.0" 19 "mrgoon/aliyun-sms": "^2.0"
20 }, 20 },
21 "require-dev": { 21 "require-dev": {
  22 + "barryvdh/laravel-ide-helper": "^2.13",
22 "facade/ignition": "^2.5", 23 "facade/ignition": "^2.5",
23 "fakerphp/faker": "^1.9.1", 24 "fakerphp/faker": "^1.9.1",
24 "laravel/sail": "^1.0.1", 25 "laravel/sail": "^1.0.1",
@@ -106,7 +106,7 @@ return [ @@ -106,7 +106,7 @@ return [
106 | 106 |
107 */ 107 */
108 108
109 - 'faker_locale' => 'en_US', 109 + 'faker_locale' => 'zh_CN',
110 110
111 /* 111 /*
112 |-------------------------------------------------------------------------- 112 |--------------------------------------------------------------------------
@@ -5,6 +5,14 @@ @@ -5,6 +5,14 @@
5 5
6 use Illuminate\Support\Facades\Route; 6 use Illuminate\Support\Facades\Route;
7 7
  8 +Route::prefix('stat')->group(function () {
  9 + Route::get('/source', [\App\Http\Controllers\Bside\StatisticsController::class, 'source'])->name('stat_source');
  10 + Route::get('/distribution', [\App\Http\Controllers\Bside\StatisticsController::class, 'distribution'])->name('stat_distribution');
  11 + Route::get('/page', [\App\Http\Controllers\Bside\StatisticsController::class, 'page'])->name('stat_page');
  12 + Route::get('/terminal', [\App\Http\Controllers\Bside\StatisticsController::class, 'terminal'])->name('stat_terminal');
  13 + Route::get('/trend', [\App\Http\Controllers\Bside\StatisticsController::class, 'trend'])->name('stat_trend');
  14 +});
  15 +
8 //必须登录验证的路由组 16 //必须登录验证的路由组
9 Route::middleware(['bloginauth'])->group(function () { 17 Route::middleware(['bloginauth'])->group(function () {
10 //登录用户编辑个人资料 18 //登录用户编辑个人资料
@@ -242,20 +250,19 @@ Route::middleware(['bloginauth'])->group(function () { @@ -242,20 +250,19 @@ Route::middleware(['bloginauth'])->group(function () {
242 250
243 Route::post('/chunk/create', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_save'])->name('admin.template.chunk_create'); 251 Route::post('/chunk/create', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_save'])->name('admin.template.chunk_create');
244 Route::post('/chunk/update', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_save'])->name('admin.template.chunk_update'); 252 Route::post('/chunk/update', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_save'])->name('admin.template.chunk_update');
245 - Route::delete('/chunk/delete/{chunk_id}', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_delete'])->where('chunk_id','\d+')->name('admin.template.chunk_delete'); 253 + Route::delete('/chunk/delete/{chunk_id}', [\App\Http\Controllers\Aside\TemplateController::class, 'chunk_delete'])->where('chunk_id', '\d+')->name('admin.template.chunk_delete');
246 254
247 255
248 }); 256 });
249 257
250 258
251 -  
252 // 自定义页面,专题页 259 // 自定义页面,专题页
253 Route::prefix('custom')->group(function () { 260 Route::prefix('custom')->group(function () {
254 Route::get('/', [\App\Http\Controllers\Bside\CustomController::class, 'index'])->name('bside_custom'); 261 Route::get('/', [\App\Http\Controllers\Bside\CustomController::class, 'index'])->name('bside_custom');
255 Route::post('/create', [\App\Http\Controllers\Bside\CustomController::class, 'save'])->name('bside_custom_create'); 262 Route::post('/create', [\App\Http\Controllers\Bside\CustomController::class, 'save'])->name('bside_custom_create');
256 Route::post('/update', [\App\Http\Controllers\Bside\CustomController::class, 'save'])->name('bside_custom_update'); 263 Route::post('/update', [\App\Http\Controllers\Bside\CustomController::class, 'save'])->name('bside_custom_update');
257 Route::delete('/delete', [\App\Http\Controllers\Bside\CustomController::class, 'delete'])->name('bside_custom_delete'); 264 Route::delete('/delete', [\App\Http\Controllers\Bside\CustomController::class, 'delete'])->name('bside_custom_delete');
258 - Route::any('/html/{id}', [\App\Http\Controllers\Bside\CustomController::class, 'html'])->where('id','\d+')->name('bside_custom_delete'); 265 + Route::any('/html/{id}', [\App\Http\Controllers\Bside\CustomController::class, 'html'])->where('id', '\d+')->name('bside_custom_delete');
259 }); 266 });
260 267
261 // 导航栏编辑 268 // 导航栏编辑
@@ -295,6 +302,6 @@ Route::group([], function () { @@ -295,6 +302,6 @@ Route::group([], function () {
295 Route::any('/login', [\App\Http\Controllers\Bside\ComController::class, 'login'])->name('login'); 302 Route::any('/login', [\App\Http\Controllers\Bside\ComController::class, 'login'])->name('login');
296 Route::any('/sendLoginSms', [\App\Http\Controllers\Bside\ComController::class, 'sendLoginSms'])->name('sendLoginSms'); 303 Route::any('/sendLoginSms', [\App\Http\Controllers\Bside\ComController::class, 'sendLoginSms'])->name('sendLoginSms');
297 Route::get('/file/download', [\App\Http\Controllers\Bside\FileController::class, 'download'])->name('file_download'); 304 Route::get('/file/download', [\App\Http\Controllers\Bside\FileController::class, 'download'])->name('file_download');
298 - Route::any('/image/{hash}/{w?}/{h?}', [\App\Http\Controllers\File\ImageController::class,'index'])->name('image_show');  
299 - Route::any('/file_hash/{hash}', [\App\Http\Controllers\File\FileController::class,'index'])->name('file_show'); 305 + Route::any('/image/{hash}/{w?}/{h?}', [\App\Http\Controllers\File\ImageController::class, 'index'])->name('image_show');
  306 + Route::any('/file_hash/{hash}', [\App\Http\Controllers\File\FileController::class, 'index'])->name('file_show');
300 }); 307 });