118 lines
4.8 KiB
PHP
118 lines
4.8 KiB
PHP
<?php
|
||
|
||
namespace App\Helpers;
|
||
|
||
use function Hyperf\Support\env;
|
||
class ArticleHelper
|
||
{
|
||
public static function saveImagesFromArticle(string $html, string $savePath = '', string $srcPrefix = '/uploads/')
|
||
{
|
||
if (!$savePath) {
|
||
$savePath = env('UPLOAD_ROOT', '');
|
||
if (!$savePath) {
|
||
throw new \Exception('找不到存储图片的路径信息。');
|
||
}
|
||
}
|
||
|
||
// 创建保存图片的目录,如果没有的话
|
||
if (!file_exists($savePath)) {
|
||
mkdir($savePath, 0777, true);
|
||
}
|
||
|
||
// 正则匹配所有 img 标签的 src 属性
|
||
preg_match_all('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $html, $matches);
|
||
|
||
// $matches[1] 包含所有 img 标签的图片 URL
|
||
$imageUrls = $matches[1];
|
||
|
||
// 遍历所有图片 URL 下载并保存
|
||
foreach ($imageUrls as $imageUrl) {
|
||
// 解析图片的文件名
|
||
$imageName = basename(parse_url($imageUrl, PHP_URL_PATH));
|
||
|
||
// 获取文件扩展名(如果没有扩展名,需要根据图片内容判断)
|
||
$extension = pathinfo($imageName, PATHINFO_EXTENSION);
|
||
if (empty($extension)) {
|
||
$imageContent = file_get_contents(trim($imageUrl, '/'));
|
||
$finfo = finfo_open(FILEINFO_MIME_TYPE); // 获取 MIME 类型
|
||
$mimeType = finfo_buffer($finfo, $imageContent);
|
||
finfo_close($finfo);
|
||
|
||
// 根据 MIME 类型设置文件扩展名
|
||
if ($mimeType == 'image/jpeg') {
|
||
$extension = 'jpg';
|
||
} elseif ($mimeType == 'image/png') {
|
||
$extension = 'png';
|
||
} elseif ($mimeType == 'image/gif') {
|
||
$extension = 'gif';
|
||
} elseif ($mimeType == 'image/webp') { // 添加对 webp 的支持
|
||
$extension = 'webp';
|
||
} else {
|
||
continue; // 如果无法判断,跳过这张图片
|
||
}
|
||
|
||
// 用新的扩展名更新文件名
|
||
$imageName .= '.' . $extension;
|
||
}
|
||
|
||
// 本地保存路径
|
||
$localPath = $savePath . '/' . $imageName;
|
||
|
||
// 使用带 Cookie 的 cURL 下载图片
|
||
$result = self::downloadImageWithCookie($imageUrl, $localPath);
|
||
if ($result) {
|
||
// 更新 HTML 中 img 标签的 src 为本地路径
|
||
$html = str_replace($imageUrl, $srcPrefix . $imageName, $html);
|
||
}
|
||
}
|
||
|
||
return $html;
|
||
}
|
||
|
||
private static function downloadImageWithCookie($imageUrl, $savePath) {
|
||
// 2. 构造 HTTP 请求头 (Headers)
|
||
// 复制浏览器中的大部分 Header,提高请求成功率
|
||
$headers = [
|
||
'accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
|
||
'accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||
'cache-control: no-cache',
|
||
'cookie: ASP.NET_SessionId=tcth0to5f4rctrr2ejcxoley; User_Behavior_Cache=JXO3LM97XAP5BK1EKNAENZ76L2ZOT9DY; _gid=GA1.2.1692255419.1753689656; _ga=GA1.1.574649996.1753689655; _ga_L98EL3NEEE=GS2.1.s1753694736$o2$g1$t1753695112$j60$l0$h0',
|
||
'pragma: no-cache',
|
||
'referer: https://news.vobao.com/',
|
||
'sec-ch-ua: "Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"',
|
||
'sec-ch-ua-mobile: ?0',
|
||
'sec-ch-ua-platform: "Windows"',
|
||
'sec-fetch-dest: image',
|
||
'sec-fetch-mode: no-cors',
|
||
'sec-fetch-site: same-site',
|
||
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0',
|
||
];
|
||
|
||
// 3. 初始化 cURL
|
||
$ch = curl_init();
|
||
|
||
// 4. 设置 cURL 选项
|
||
curl_setopt($ch, CURLOPT_URL, $imageUrl); // 设置请求URL
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 设置请求头
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将结果作为字符串返回,而不是直接输出
|
||
curl_setopt($ch, CURLOPT_HEADER, false); // 不返回响应头部分
|
||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
|
||
curl_setopt($ch, CURLOPT_ENCODING, ''); // 处理所有受支持的编码,如gzip
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用SSL证书验证 (在某些环境下需要)
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 设置超时时间为30秒
|
||
|
||
// 5. 执行 cURL 请求
|
||
$imageData = curl_exec($ch);
|
||
|
||
// 6. 检查是否有错误发生
|
||
if (curl_errno($ch)) {
|
||
echo 'cURL 请求错误: ' . curl_error($ch);
|
||
return false;
|
||
}
|
||
|
||
// 8. 关闭 cURL 句柄
|
||
curl_close($ch);
|
||
|
||
return file_put_contents($savePath, $imageData);
|
||
}
|
||
} |