127 lines
4.2 KiB
PHP
127 lines
4.2 KiB
PHP
<?php
|
||
// 保存视频到本地,并清理超过2天的旧视频(第三天自动清除第一天的视频)
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
|
||
function respond($ok, $message = '', $path = '') {
|
||
echo json_encode(['success' => $ok, 'message' => $message, 'path' => $path], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
exit;
|
||
}
|
||
|
||
// 递归删除目录及其内容(用于清理旧视频)
|
||
function rrmdir($dir) {
|
||
if (!is_dir($dir)) return;
|
||
$items = @scandir($dir);
|
||
if ($items === false) return;
|
||
foreach ($items as $item) {
|
||
if ($item === '.' || $item === '..') continue;
|
||
$full = $dir . DIRECTORY_SEPARATOR . $item;
|
||
if (is_dir($full)) {
|
||
rrmdir($full);
|
||
} else {
|
||
@unlink($full);
|
||
}
|
||
}
|
||
@rmdir($dir);
|
||
}
|
||
|
||
// 读取JSON输入
|
||
$raw = file_get_contents('php://input');
|
||
$data = json_decode($raw, true);
|
||
$url = $data['url'] ?? '';
|
||
$title = $data['title'] ?? '';
|
||
|
||
if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
|
||
respond(false, 'URL无效');
|
||
}
|
||
|
||
// 只允许 http/https
|
||
$scheme = parse_url($url, PHP_URL_SCHEME);
|
||
if (!in_array(strtolower($scheme), ['http','https'])) {
|
||
respond(false, '仅支持http/https视频地址');
|
||
}
|
||
|
||
$videosRoot = __DIR__ . '/../videos';
|
||
if (!is_dir($videosRoot)) {
|
||
@mkdir($videosRoot, 0777, true);
|
||
}
|
||
|
||
$today = (new DateTime('now'))->format('Y-m-d');
|
||
$targetDir = $videosRoot . '/' . $today;
|
||
if (!is_dir($targetDir)) {
|
||
@mkdir($targetDir, 0777, true);
|
||
}
|
||
|
||
// 生成文件名
|
||
$basename = basename(parse_url($url, PHP_URL_PATH) ?: 'video_' . time() . '.mp4');
|
||
if (strpos($basename, '.') === false) { $basename .= '.mp4'; }
|
||
$safeName = preg_replace('/[^\w\.-]+/u', '_', $basename);
|
||
$targetPath = $targetDir . '/' . $safeName;
|
||
|
||
// 如果文件已存在则跳过下载
|
||
$skipDownload = file_exists($targetPath);
|
||
$msg = '保存成功';
|
||
if ($skipDownload) {
|
||
$msg = '文件已存在,跳过下载';
|
||
} else {
|
||
// 下载保存
|
||
try {
|
||
$read = @fopen($url, 'rb');
|
||
if (!$read) { respond(false, '无法读取远程视频'); }
|
||
$write = @fopen($targetPath, 'wb');
|
||
if (!$write) { respond(false, '无法写入文件'); }
|
||
stream_copy_to_stream($read, $write);
|
||
fclose($read);
|
||
fclose($write);
|
||
} catch (Throwable $e) {
|
||
respond(false, '保存失败: ' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
$bytes = @filesize($targetPath) ?: 0;
|
||
try {
|
||
$statsRoot = __DIR__ . '/../stats';
|
||
if (!is_dir($statsRoot)) { @mkdir($statsRoot, 0777, true); }
|
||
$dailyPath = $statsRoot . '/daily.json';
|
||
$today = (new DateTime('now'))->format('Y-m-d');
|
||
$daily = [];
|
||
if (file_exists($dailyPath)) {
|
||
$rawDaily = @file_get_contents($dailyPath);
|
||
$decoded = json_decode($rawDaily, true);
|
||
if (is_array($decoded)) { $daily = $decoded; }
|
||
}
|
||
if (!isset($daily[$today]) || !is_array($daily[$today])) {
|
||
$daily[$today] = ['visits' => 0, 'video_plays' => 0, 'picture_shows' => 0, 'uv' => 0, 'bandwidth_in' => 0, 'bandwidth_out' => 0];
|
||
}
|
||
$daily[$today]['bandwidth_out'] += (int)$bytes;
|
||
@file_put_contents($dailyPath, json_encode($daily, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX);
|
||
} catch (Throwable $e) {}
|
||
|
||
// 恢复清理逻辑:仅保留最近两天的视频目录,删除更早的目录
|
||
try {
|
||
$dirs = @scandir($videosRoot);
|
||
if (is_array($dirs)) {
|
||
// 仅筛选形如 YYYY-MM-DD 的目录
|
||
$dateDirs = [];
|
||
foreach ($dirs as $d) {
|
||
if ($d === '.' || $d === '..') continue;
|
||
$path = $videosRoot . DIRECTORY_SEPARATOR . $d;
|
||
if (is_dir($path) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $d)) {
|
||
$dateDirs[] = $d;
|
||
}
|
||
}
|
||
// 按日期升序排序
|
||
sort($dateDirs);
|
||
// 保留最近两天(末尾两项),其它全部删除
|
||
if (count($dateDirs) > 2) {
|
||
$toDelete = array_slice($dateDirs, 0, count($dateDirs) - 2);
|
||
foreach ($toDelete as $del) {
|
||
rrmdir($videosRoot . DIRECTORY_SEPARATOR . $del);
|
||
}
|
||
}
|
||
}
|
||
} catch (Throwable $e) {
|
||
// 清理失败不影响主流程
|
||
}
|
||
|
||
respond(true, $msg, str_replace($_SERVER['DOCUMENT_ROOT'], '', $targetPath));
|