* @Date: 2022-04-13 09:54:31
* @LastEditTime: 2022-04-27 14:20:06
* @LastEditors: TaoLer
* @Description: 搜索引擎SEO优化设置
* @FilePath: \TaoLer\app\admin\controller\Seo.php
* Copyright (c) 2020~2022 http://www.aieok.com All rights reserved.
*/
declare(strict_types=1);
namespace app\admin\controller;
use app\common\controller\AdminController;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
use taoser\SetArr;
use app\admin\model\PushJscode;
class Seo extends AdminController
{
public function index()
{
// 站点地图
$xml = '';
$xmlArr = $this->getXmlFile(public_path());
foreach($xmlArr as $v) {
$map = $this->getIndexUrl().'/'.$v;
$xml .= $map."\n";
}
// robots
if(is_file($rob = public_path().'robots.txt')){
$robots = file_get_contents($rob);
} else {
$robots = '';
}
// push_js
$pushjs = new PushJscode();
$jscode = $pushjs->getAllCodes();
View::assign(['xml'=>$xml,'jscode'=>$jscode,'robots'=>$robots]);
return View::fetch();
}
public function push()
{
$data = Request::only(['start_id','end_id','time']);
if(empty(config('taoler.baidu.push_api'))) return json(['code'=>-1,'msg'=>'请先配置接口push_api']);
$urls = [];
if(empty($data['start_id']) || empty($data['end_id'])) {
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->whereTime('create_time', $data['time'])->column('id');
} else {
$artAllId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->where('id','between',[$data['start_id'],$data['end_id']])->whereTime('create_time', $data['time'])->column('id');
}
if(empty($artAllId)) return json(['code'=>-1,'msg'=>'没有查询到结果,无需推送']);
// 组装链接数组
foreach($artAllId as $aid) {
$urls[] = $this->getRouteUrl($aid);
}
// 百度接口单次最大提交200,进行分组
$urls = array_chunk($urls,2000);
$api = config('taoler.baidu.push_api');
$ch = curl_init();
foreach($urls as $url) {
$options = array(
CURLOPT_URL => $api,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => implode("\n", $url),
CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
if($result == false) {
return json(['code'=>-1,'msg'=>'接口失败']);
}
}
curl_close($ch);
$res = stripos($result,'error');
$data = json_decode($result);
if($res !== false) {
return json(['code'=>-1,'msg'=>$data->message]);
};
return json(['code'=>0,'msg'=>'成功推送'.$data->success.'条,今天剩余'.$data->remain]);
}
/**
* 百度接口配置
*
* @return void
*/
public function config()
{
$baidu = [];
$data = Request::only(['client_id','client_secret','push_api']);
foreach($data as $k => $v) {
if($v !== ''){
if($k == 'push_api') {
$baidu[$k] = "'$v'";
} else {
$baidu[$k] = $v;
}
}
}
$res = SetArr::name('taoler')->edit([
'baidu' => $baidu,
]);
if($res == true){
return json(['code'=>0,'msg'=>'设置成功']);
}
}
/**
* 百度谷歌sitemap生成xml文件
*
* @return void
*/
public function map()
{
$data = Request::only(['map_num','map_time','map_level']);
// 写文件字符串
$str = '';
// 标记第一次调用写ID
$flag= true;
// 写ID
$w_id = '';
// 生成新文件编号,防止重复写入,
$i = 1;
// 获取public下所有xml文件
$newFile = $this->getXmlFile(public_path());
// 没有xml文件时,不存在重写
if(empty($newFile)) {
$rewrite = false;
} else {
$xmlFile = end($newFile);
$strFile = file_get_contents(public_path().$xmlFile);
$num = substr_count($strFile, '');
// 是否有需要追加在文件,判断最新文件是否未写满
$rewrite = $num < $data['map_num'] ? true : false;
}
if($rewrite){
// 需要追加的数量
$limit = (int) $data['map_num'] - $num;
$name = pathinfo($xmlFile,PATHINFO_FILENAME);
$arr = explode('_', $name);
// 检验当天,避免重复生成
if($arr[0] == date('Y-d-m'))
{
$i = $arr[1] + 1;
}
} else {
$limit = (int) $data['map_num'];
}
// 最新ID
$maxId = Db::name('article')->where(['delete_time'=>0,'status'=>1])->max('id');
do
{
$wr_id = $flag ? config('taoler.sitemap.write_id') : $w_id;
$artAllId = Db::name('article')
->where(['delete_time'=>0,'status'=>1])
->where('id', '>', (int) $wr_id)
->order('id','asc')->limit($limit)->column('update_time','id');
if(empty($artAllId)) {
return json(['code'=>-1,'msg'=>'本次无需生成']);
} else {
// 本次最新文件ID
$last_id = array_key_last($artAllId);
// 循环拼接文件字符串
foreach($artAllId as $aid => $uptime) {
// url生成
$url = $this->getRouteUrl($aid);
$time = date('Y-m-d', $uptime);
// 组装字符串
$str .= <<
$url
$time
daily
0.5
\n
STR;
}
// 写文件
if($rewrite){
// 写入旧xml文件
$reps = $str.'';
$xml = preg_replace('/<\/urlset>/', $reps, $strFile);
$res = file_put_contents(public_path().$xmlFile, $xml);
if($res == false){
return json(['code'=>-1,'msg'=>$xmlFile.'写入失败']);
}
$limit = $data['map_num'];
$rewrite = false;
} else {
// 生成新xml
$xml = <<
\n$str
XML;
$res = file_put_contents(public_path().date('Y-m-d').'_'.$i.'.xml', $xml);
if($res == false){
return json(['code'=>-1,'msg'=>date('Y-m-d').'_'.$i.'.xml写入失败']);
}
}
// 重置标记内容
$str = '';
$i++;
$w_id = $last_id;
$flag = false;
}
}
while($last_id < (int) $maxId);
// 写配置,标记最后写入ID
$res = SetArr::name('taoler')->edit([
'sitemap' => [
'map_num' => $data['map_num'],
'write_id' => $last_id,
],
]);
if($res == false){
return json(['code'=>-1,'msg'=>'写xml配置失败']);
}
return json(['code'=>0,'msg'=>'本次成功生成'.count($artAllId).'条xml']);
}
/**
* 返回public目录下xml名称数组
*
* @param string $dir
* @return array
*/
public function getXmlFile(string $dir) : array
{
$arr = [];
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
if(is_file("$dir/$file") && !is_link($dir) && (pathinfo("$dir/$file", PATHINFO_EXTENSION)) == 'xml')
{
$arr[] = "$file";
}
}
return $arr;
}
/**
* 生成robots
*
* @return void
*/
public function robots()
{
if(Request::isPost()){
$txt = input('robots');
$xmlArr = $this->getXmlFile(public_path());
foreach($xmlArr as $v) {
$res = stripos($txt, $v);
if($res == false){
$map = $this->getIndexUrl().'/'.$v;
$txt .= "\nsitemap:".$map;
}
}
$res = file_put_contents(public_path().'robots.txt',$txt);
if($res == false){
return json(['code'=>-1,'msg'=>$v.'写入失败']);
}
return json(['code'=>0,'msg'=>'设置成功']);
}
}
/**
* 保存搜索平台js代码
*
* @return void
*/
public function savePushJs()
{
$data = Request::only(['name','jscode']);
if(empty($data['name'])) {
return json(['code'=>-1,'msg'=>'请术输入名称']);
}
if(empty($data['jscode'])){
return json(['code'=>-1,'msg'=>'请术输入代码']);
}
$push = new PushJscode();
$res = $push->saveCode($data);
if(!$res) {
return json(['code'=>-1,'msg'=>'保存失败']);
}
return json(['code'=>0,'msg'=>'保存成功']);
}
/**
* 删除平台js代码
*
* @return void
*/
public function delPushJs()
{
$id = (int) input('id');
$push = new PushJscode();
$res = $push->delCode($id);
if(!$res) {
return json(['code'=>-1,'msg'=>'删除失败']);
}
return json(['code'=>0,'msg'=>'删除成功']);
}
public function searchLog()
{
$time = input('search_time');
$logPath = app()->getRootPath().'runtime/log/browse/'.$time.'.log';
$logPath = str_replace('\\','/',$logPath);
if(!file_exists($logPath)) return json(['code'=>-1,'msg'=>'还没有要分析的日志哦']);
$log = file_get_contents($logPath);
$log = preg_replace('/\[info\][^\n]*compatible;/', '', $log);
// 正则蜘蛛
preg_match_all('/(.*?)(?:bingbot|Googlebot|Baiduspider|SemrushBot|AhrefsBot|MJ12bot)+[^\n]*\r?\n/',$log,$arr);
$string = '';
foreach($arr[0] as $str) {
$str = preg_replace('/\[(.*?)T/', '', $str);
$str = preg_replace('/\+08:00\]/', '', $str);
$string .= preg_replace('/\/(.*?)\)/', '', $str);
}
if(strlen($string)) {
return json(['code'=>0,'msg'=>'分析成功','data'=>$string]);
} else {
return json(['code'=>-1,'msg'=>'还没有蜘蛛来哦']);
}
}
}