448 lines
15 KiB
PHP
Executable File
448 lines
15 KiB
PHP
Executable File
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Services;
|
||
|
||
//use App\Models\BoxCountry as ModelCountry;
|
||
use App\Models\DogOption as ModelDogOption;
|
||
use App\Models\Article as ModelArticle;
|
||
use App\Services\TomTool\Flow;
|
||
|
||
final class Article
|
||
{
|
||
|
||
// public function cacheToArticle($aParam)
|
||
// {
|
||
// $oArticleCache = ModelArticleCache::where("status", 1)->get();
|
||
// }
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public function contentReplace($sType, $sContent)
|
||
{
|
||
$sResult = $sContent;
|
||
|
||
if ($sType == "str") {
|
||
$sResult = str_replace("翻翻墙", "{{sSiteName}}", $sContent);
|
||
}
|
||
|
||
return $sResult;
|
||
}
|
||
|
||
// 原型转format
|
||
public function format($sFromType, $sArticle)
|
||
{
|
||
$sArticleNew = $sArticle;
|
||
|
||
if ($sFromType == "ffq_tg") {
|
||
// $sArticleNew = $this->format_ffq_tg($sArticle);
|
||
$sArticleNew = $this->tgToSchema($sArticle);
|
||
// $this->
|
||
}
|
||
|
||
return $sArticleNew;
|
||
|
||
}
|
||
|
||
public function tgToSchema_row($sArticleContent)
|
||
{
|
||
// $oResult = new Result("tgToSchema_row");
|
||
// $oResult->kv("name", "none");
|
||
// $oResult->kv("content_type", "none");
|
||
|
||
// $aResultDefault = [
|
||
// "name" => "none",
|
||
// "content_type" => "none",
|
||
// ];
|
||
|
||
$oResult = Flow::make("tgToSchema_row");
|
||
|
||
$sArticleNew = $sArticle;
|
||
$aArticleCache = json_decode($sArticle, true);
|
||
// $aResult = [];
|
||
// $aResultMix = [];
|
||
|
||
// default 必有
|
||
// $aResult["name"] = "none"; // 主要
|
||
// $aResult["code"] = 0;
|
||
// $aResult["content_type"] = "none"; // 主要
|
||
// $aProcess[] = "start";
|
||
|
||
if (isset($aArticleCache["message"]["document"]["mime_type"])) { // 包含文件
|
||
$oResult->addProcess("is_document");
|
||
|
||
// $oResult->arr($aResultDefault);
|
||
// $oResult->kv("content_type", "str");
|
||
|
||
|
||
$sDocumentType = $aArticleCache["message"]["document"]["mime_type"];
|
||
|
||
if (strpos($sDocumentType, "image") !== false) { // 包含图片
|
||
$oResult->addProcess("is_image");
|
||
|
||
$aData = [];
|
||
$aData["content_type"] = "img";
|
||
$aData["title"] = $aArticleCache["message"]["document"]["file_name"];
|
||
$aData["img"]["base"] = "";
|
||
$aData["img"]["thumb"] = "";
|
||
$aData["name"] = "img_cesu";
|
||
|
||
$sImgId = $aArticleCache["message"]["document"]["file_id"];
|
||
$sImgThumbId = $aArticleCache["message"]["document"]["thumb"]["file_id"];
|
||
|
||
$aImgId = [
|
||
"base" => $sImgId,
|
||
"thumb" => $sImgThumbId,
|
||
];
|
||
|
||
// $oResult->kv("content_type", "img");
|
||
|
||
foreach ($aImgId as $k => $aImgIdRow) {
|
||
// 第一步:获取 file_path
|
||
$getFileUrl = "https://api.telegram.org/bot".$_ENV["telegram_token"]."/getFile?file_id=".$aImgIdRow;
|
||
$response = file_get_contents($getFileUrl);
|
||
$data = json_decode($response, true);
|
||
|
||
if (!$data['ok']) {
|
||
return $oResult->fail("获取图标路径失败:".$sArticleContent);
|
||
}
|
||
|
||
$filePath = $data['result']['file_path'];
|
||
|
||
// 第二步:下载文件内容
|
||
$downloadUrl = "https://api.telegram.org/file/bot".$_ENV["telegram_token"]."/".$filePath;
|
||
$imageData = file_get_contents($downloadUrl);
|
||
|
||
if ($imageData === false) {
|
||
return $oResult->fail("下载图片失败:".$sArticleContent);
|
||
}
|
||
|
||
// 第三步:保存到服务器
|
||
$savePath = 'upload/';
|
||
if (!is_dir($savePath)) {
|
||
if (!mkdir($savePath, 0777, true)) {
|
||
return $oResult->fail("目录创建失败:".$sArticleContent);
|
||
}
|
||
}
|
||
|
||
$fileName = basename($filePath);
|
||
$fileName = uniqid('ffq_tg-' . $k . ':', true) . $fileName; // 加前缀并提高熵值
|
||
$fullPath = $savePath . $fileName;
|
||
|
||
if (file_put_contents($fullPath, $imageData) === false) {
|
||
return $oResult->fail("下载图片失败:".$sArticleContent);
|
||
}
|
||
|
||
if (!file_exists($fullPath)) {
|
||
return $oResult->fail("文件未成功保存:".$sArticleContent);
|
||
}
|
||
|
||
$sSavePath = rtrim($_ENV["APP_URL"], '/') . '/' . $fullPath;
|
||
$sArticleNew = $sSavePath;
|
||
$aData["img"][$k] = $sArticleNew;
|
||
|
||
// $oResult->setData($aData);
|
||
|
||
$oArticleCache = new ModelArticleCache();
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// $aResult["code"] = 1;
|
||
// $aResult["process"] = $aProcess;
|
||
// $aResultMix[] = $aResult;
|
||
|
||
}
|
||
|
||
if (isset($aArticleCache["message"]["caption"])) { // 包含文档
|
||
|
||
$sStr = $aArticleCache["message"]["caption"];
|
||
|
||
$aProcess = "is_caption";
|
||
$aResult = [];
|
||
$aResult["code"] = 1;
|
||
$aResult["content_type"] = "str";
|
||
$aResult["content"] = $sStr;
|
||
$aResult["name"] = "str";
|
||
$aResult["process"] = $aProcess;
|
||
|
||
$aResultMix[] = $aResult;
|
||
|
||
}
|
||
|
||
return $aResultMix;
|
||
|
||
}
|
||
|
||
// private function saveViewByCache($aArticleCache);
|
||
|
||
// 原型转format
|
||
public function format_ffq_tg($sArticle)
|
||
{
|
||
|
||
$sArticleNew = $sArticle;
|
||
$aArticleCache = json_decode($sArticle, true);
|
||
$aResult = [];
|
||
$aResultMix = [];
|
||
|
||
// default 必有
|
||
$aResult["name"] = "none"; // 主要
|
||
$aResult["code"] = 0;
|
||
$aResult["content_type"] = "none"; // 主要
|
||
$aResult["process"][] = "start";
|
||
|
||
if (isset($aArticleCache["message"]["document"]["mime_type"])) { // 包含文档
|
||
$aResult = [];
|
||
$aResult["process"][] = "is_document";
|
||
$aResult["code"] = 0;
|
||
$aResult["content_type"] = "str";
|
||
|
||
$sDocumentType = $aArticleCache["message"]["document"]["mime_type"];
|
||
|
||
if (strpos($sDocumentType, "image") !== false) { // 包含图片
|
||
$aResult["process"][] = "is_image";
|
||
$aResult["title"] = $aArticleCache["message"]["document"]["file_name"];
|
||
$aResult["img"]["base"] = "";
|
||
$aResult["img"]["thumb"] = "";
|
||
$aResult["name"] = "img_cesu";
|
||
|
||
$sImgId = $aArticleCache["message"]["document"]["file_id"];
|
||
$sImgThumbId = $aArticleCache["message"]["document"]["thumb"]["file_id"];
|
||
|
||
$aImgId = [
|
||
"base" => $sImgId,
|
||
"thumb" => $sImgThumbId,
|
||
];
|
||
|
||
$aResult["content_type"] = "img";
|
||
|
||
foreach ($aImgId as $k => $aImgIdRow) {
|
||
// 第一步:获取 file_path
|
||
$getFileUrl = "https://api.telegram.org/bot".$_ENV["telegram_token"]."/getFile?file_id=".$aImgIdRow;
|
||
$response = file_get_contents($getFileUrl);
|
||
$data = json_decode($response, true);
|
||
|
||
if (!$data['ok']) {
|
||
// die("获取文件路径失败!");
|
||
return "获取图标途径失败:".$sArticle;
|
||
}
|
||
|
||
$filePath = $data['result']['file_path'];
|
||
|
||
// 第二步:下载文件内容
|
||
$downloadUrl = "https://api.telegram.org/file/bot".$_ENV["telegram_token"]."/".$filePath;
|
||
$imageData = file_get_contents($downloadUrl);
|
||
|
||
if ($imageData === false) {
|
||
// die("下载图片失败!");
|
||
return "下载图片失败:".$sArticle;
|
||
}
|
||
|
||
// 第三步:保存到服务器
|
||
$savePath = 'upload/';
|
||
if (!is_dir($savePath)) {
|
||
mkdir($savePath, 0777, true);
|
||
}
|
||
|
||
$fileName = basename($filePath);
|
||
$fileName = uniqid('ffq_tg-'.$k.':', true).$fileName; // 加前缀并提高熵值
|
||
file_put_contents($savePath . $fileName, $imageData);
|
||
|
||
$sSavePath = $_ENV["APP_URL"].'/'.$savePath.$fileName;
|
||
|
||
$sArticleNew = $sSavePath;
|
||
|
||
$aResult["img"][$k] = $sArticleNew;
|
||
// $aResult["content"][$k] = $sArticleNew;
|
||
|
||
}
|
||
|
||
$aResult["code"] = 1;
|
||
$aResultMix[] = $aResult;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (isset($aArticleCache["message"]["caption"])) { // 包含文档
|
||
|
||
$sStr = $aArticleCache["message"]["caption"];
|
||
|
||
// 组1,字符串
|
||
$aResult = [];
|
||
$aResult["process"][] = "is_caption";
|
||
$aResult["code"] = 1;
|
||
$aResult["content_type"] = "str";
|
||
$aResult["content"] = $sStr;
|
||
$aResult["name"] = "str";
|
||
$aResultMix[] = $aResult;
|
||
|
||
// 组1.1,标题
|
||
$aName = $this->getStrName($sStr);
|
||
if ($aName["code"] >= 1) {
|
||
|
||
if ($aName["code"] == 2) {
|
||
$sName = "none";
|
||
$sTitle = "⚠️⚠️⚠️ name强行截取,要fixName()更正:".$aName["value"];
|
||
} else {
|
||
$sName = $aName["value"];
|
||
$sTitle = $this->nameToTitle($sName);
|
||
}
|
||
|
||
$aResult = [];
|
||
$aResult["process"][] = "add_name";
|
||
$aResult["code"] = 1;
|
||
$aResult["content_type"] = "str";
|
||
$aResult["content"] = $sName;
|
||
$aResult["name"] = "name";
|
||
$aResultMix[] = $aResult;
|
||
|
||
$aResult = [];
|
||
$aResult["process"][] = "add_title";
|
||
$aResult["code"] = 1;
|
||
$aResult["content_type"] = "str";
|
||
$aResult["content"] = $sTitle;
|
||
$aResult["name"] = "title";
|
||
$aResultMix[] = $aResult;
|
||
}
|
||
|
||
// 组2,找到论坛地址
|
||
preg_match('/论坛[::]\s*(https?:\/\/[^\s]*?\.html)/u', $sStr, $matches);
|
||
if (isset($matches[1])) {
|
||
$aResult = [];
|
||
$aResult["process"][] = "have_luntan";
|
||
$aResult["code"] = 0;
|
||
$aResult["content_type"] = "table";
|
||
$aResult["content"] = "无";
|
||
$aResult["title"] = "套餐价格";
|
||
$aResult["name"] = "plan_price";
|
||
|
||
$url = $matches[1];
|
||
|
||
// 初始化 cURL
|
||
$ch = curl_init($url);
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_FOLLOWLOCATION => true,
|
||
CURLOPT_TIMEOUT => 10,
|
||
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/115.0 Safari/537.36',
|
||
]);
|
||
|
||
$html = curl_exec($ch);
|
||
curl_close($ch);
|
||
|
||
if ($html === false) {
|
||
// die("无法获取网页内容");
|
||
$aResult["process"][] = "无法读取网页内容";
|
||
$aResult["code"] = 1;
|
||
$aResult["content"] = "⚠️⚠️⚠️ 无法读取网页内容";
|
||
$aResultMix[] = $aResult;
|
||
return $aResultMix;
|
||
}
|
||
|
||
// 解析 HTML
|
||
libxml_use_internal_errors(true);
|
||
$dom = new \DOMDocument();
|
||
$dom->loadHTML($html);
|
||
libxml_clear_errors();
|
||
|
||
$xpath = new \DOMXPath($dom);
|
||
|
||
// 找到第一个 class 为 markdown-body 的 div
|
||
$markdownDiv = $xpath->query('//div[contains(@class, "markdown-body")]')->item(0);
|
||
if (!$markdownDiv) {
|
||
// die("未找到 class 为 'markdown-body' 的 div");
|
||
$aResult["process"][] = "未找到 class 为 'markdown-body' 的 div";
|
||
$aResult["code"] = 1;
|
||
$aResult["content"] = "⚠️⚠️⚠️ 未找到 class 为 'markdown-body' 的 div";
|
||
$aResultMix[] = $aResult;
|
||
return $aResultMix;
|
||
}
|
||
|
||
// 找到该 div 中的第一个 table
|
||
$table = null;
|
||
foreach ($markdownDiv->getElementsByTagName('table') as $t) {
|
||
$table = $t;
|
||
break;
|
||
}
|
||
|
||
if (!$table) {
|
||
// die("未找到 table 标签");
|
||
$aResult["process"][] = "未找到 table 标签";
|
||
$aResult["code"] = 1;
|
||
$aResult["content"] = "⚠️⚠️⚠️ 未找到 table 标签";
|
||
$aResultMix[] = $aResult;
|
||
return $aResultMix;
|
||
}
|
||
|
||
$aResult["code"] = 1;
|
||
$aResult["content"] = $dom->saveHTML($table);
|
||
|
||
$aResultMix[] = $aResult;
|
||
}
|
||
|
||
}
|
||
|
||
return $aResultMix;
|
||
|
||
}
|
||
|
||
private function getStrName($str) {
|
||
|
||
$aData["code"] = 0;
|
||
$aData["value"] = "";
|
||
|
||
if (preg_match('/#(.*?)#/', $str, $matches)) {
|
||
$aData["code"] = 1;
|
||
$aData["value"] = trim($matches[1]);
|
||
return $aData;
|
||
}
|
||
|
||
$aData["code"] = 2;
|
||
$aData["value"] = trim(mb_substr($str, 0, 20));
|
||
|
||
return $aData;
|
||
}
|
||
|
||
private function nameToTitle($sName)
|
||
{
|
||
$sTitle = $sName;
|
||
|
||
$iCesuCount = ModelArticle::where("name", $sName)->count();
|
||
|
||
if ($iCesuCount > 0) {
|
||
$sWrap = ModelDogOption::_hit("article", "ffq_tg-title_wrap");
|
||
|
||
if (!$sWrap) {
|
||
return "未设置dog_option::ffq_tg-title_wrap";
|
||
}
|
||
|
||
$sTitle = str_replace('{{name}}', $sName, $sWrap);
|
||
|
||
$sTitle = str_replace('{{cesu_count}}', (string) $iCesuCount, $sTitle);
|
||
|
||
} else {
|
||
$sWrap = ModelDogOption::_hit("article", "ffq_tg-title_wrap-first");
|
||
|
||
if (!$sWrap) {
|
||
return "未设置dog_option::ffq_tg-title_wrap-first";
|
||
}
|
||
|
||
$sTitle = str_replace('{{name}}', $sName, $sWrap);
|
||
|
||
}
|
||
|
||
return $sTitle;
|
||
}
|
||
|
||
}
|