文件上传成功:' . htmlspecialchars(basename($file['name'])) . ''; } else { echo ''; } } else { echo ''; } } if (isset($_FILES['configFileInput'])) { $file = $_FILES['configFileInput']; $uploadFilePath = $configDir . basename($file['name']); if ($file['error'] === UPLOAD_ERR_OK) { if (move_uploaded_file($file['tmp_name'], $uploadFilePath)) { echo ''; } else { echo ''; } } else { echo ''; } } if (isset($_POST['deleteFile'])) { $fileToDelete = $uploadDir . basename($_POST['deleteFile']); if (file_exists($fileToDelete) && unlink($fileToDelete)) { echo ''; } else { echo ''; } } if (isset($_POST['deleteConfigFile'])) { $fileToDelete = $configDir . basename($_POST['deleteConfigFile']); if (file_exists($fileToDelete) && unlink($fileToDelete)) { echo ''; } else { echo ''; } } if (isset($_POST['oldFileName'], $_POST['newFileName'], $_POST['fileType'])) { $oldFileName = basename($_POST['oldFileName']); $newFileName = basename($_POST['newFileName']); $fileType = $_POST['fileType']; if ($fileType === 'proxy') { $oldFilePath = $uploadDir. $oldFileName; $newFilePath = $uploadDir. $newFileName; } elseif ($fileType === 'config') { $oldFilePath = $configDir . $oldFileName; $newFilePath = $configDir . $newFileName; } else { echo '无效的文件类型'; exit; } if (file_exists($oldFilePath) && !file_exists($newFilePath)) { if (rename($oldFilePath, $newFilePath)) { echo ''; } else { echo ''; } } else { echo ''; } } if (isset($_POST['saveContent'], $_POST['fileName'], $_POST['fileType'])) { $fileToSave = ($_POST['fileType'] === 'proxy') ? $uploadDir . basename($_POST['fileName']) : $configDir . basename($_POST['fileName']); $contentToSave = $_POST['saveContent']; file_put_contents($fileToSave, $contentToSave); echo ''; } } function formatFileModificationTime($filePath) { if (file_exists($filePath)) { $fileModTime = filemtime($filePath); return date('Y-m-d H:i:s', $fileModTime); } else { return '文件不存在'; } } $proxyFiles = scandir($uploadDir); $configFiles = scandir($configDir); if ($proxyFiles !== false) { $proxyFiles = array_diff($proxyFiles, array('.', '..')); $proxyFiles = array_filter($proxyFiles, function($file) { return pathinfo($file, PATHINFO_EXTENSION) !== 'txt'; }); } else { $proxyFiles = []; } if ($configFiles !== false) { $configFiles = array_diff($configFiles, array('.', '..')); } else { $configFiles = []; } function formatSize($size) { $units = array('B', 'KB', 'MB', 'GB', 'TB'); $unit = 0; while ($size >= 1024 && $unit < count($units) - 1) { $size /= 1024; $unit++; } return round($size, 2) . ' ' . $units[$unit]; } if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['editFile'], $_GET['fileType'])) { $filePath = ($_GET['fileType'] === 'proxy') ? $uploadDir. basename($_GET['editFile']) : $configDir . basename($_GET['editFile']); if (file_exists($filePath)) { header('Content-Type: text/plain'); echo file_get_contents($filePath); exit; } else { echo '文件不存在'; exit; } } if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['downloadFile'], $_GET['fileType'])) { $fileType = $_GET['fileType']; $fileName = basename($_GET['downloadFile']); $filePath = ($fileType === 'proxy') ? $uploadDir . $fileName : $configDir . $fileName; if (file_exists($filePath)) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $fileName . '"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($filePath)); readfile($filePath); exit; } else { echo '文件不存在。'; } } ?> '', 'file_name' => "subscription_" . ($i + 1) . ".yaml", ]; } } if (isset($_POST['update'])) { $index = intval($_POST['index']); $url = trim($_POST['subscription_url'] ?? ''); $customFileName = trim($_POST['custom_file_name'] ?? "subscription_" . ($index + 1) . ".yaml"); $subscriptions[$index]['url'] = $url; $subscriptions[$index]['file_name'] = $customFileName; if (!empty($url)) { $tempPath = $subscriptionPath . $customFileName . ".temp"; $finalPath = $subscriptionPath . $customFileName; $command = "curl -s -L -o {$tempPath} {$url}"; exec($command . ' 2>&1', $output, $return_var); if ($return_var !== 0) { $command = "wget -q --show-progress -O {$tempPath} {$url}"; exec($command . ' 2>&1', $output, $return_var); } if ($return_var === 0) { $_SESSION['update_logs'] = []; storeUpdateLog("✅ 订阅 " . htmlspecialchars($url) . " 已下载并保存到临时文件: " . htmlspecialchars($tempPath)); $fileContent = file_get_contents($tempPath); if (base64_encode(base64_decode($fileContent, true)) === $fileContent) { $decodedContent = base64_decode($fileContent); if ($decodedContent !== false && strlen($decodedContent) > 0) { file_put_contents($finalPath, "# Clash Meta Config\n\n" . $decodedContent); storeUpdateLog("📂 Base64 解码成功,配置已保存到: " . htmlspecialchars($finalPath)); unlink($tempPath); $notificationMessage = '更新成功'; $updateCompleted = true; } else { storeUpdateLog("⚠️ Base64 解码失败,请检查订阅链接内容!"); unlink($tempPath); $notificationMessage = '更新失败'; } } elseif (substr($fileContent, 0, 2) === "\x1f\x8b") { $decompressedContent = gzdecode($fileContent); if ($decompressedContent !== false) { file_put_contents($finalPath, "# Clash Meta Config\n\n" . $decompressedContent); storeUpdateLog("📂 Gzip 解压成功,配置已保存到: " . htmlspecialchars($finalPath)); unlink($tempPath); $notificationMessage = '更新成功'; $updateCompleted = true; } else { storeUpdateLog("⚠️ Gzip 解压失败,请检查订阅链接格式!"); unlink($tempPath); $notificationMessage = '更新失败'; } } else { rename($tempPath, $finalPath); storeUpdateLog("✅ 订阅内容已成功下载,无需解码"); $notificationMessage = '更新成功'; $updateCompleted = true; } } else { storeUpdateLog("❌ 订阅更新失败!错误信息: " . implode("\n", $output)); unlink($tempPath); $notificationMessage = '更新失败'; } } else { storeUpdateLog("⚠️ 第" . ($index + 1) . "个订阅链接为空!"); $notificationMessage = '更新失败'; } file_put_contents($subscriptionFile, json_encode($subscriptions)); } ?> > "\$LOG_FILE" } log "开始处理订阅更新任务..." if [ ! -f "\$JSON_FILE" ]; then log "❌ 错误: JSON 文件不存在: \$JSON_FILE" exit 1 fi jq -c '.[]' "\$JSON_FILE" | while read -r ITEM; do URL=\$(echo "\$ITEM" | jq -r '.url') FILE_NAME=\$(echo "\$ITEM" | jq -r '.file_name') if [ -z "\$URL" ] || [ "\$URL" == "null" ]; then log "⚠️ 跳过空的订阅链接,文件名: \$FILE_NAME" continue fi if [ -z "\$FILE_NAME" ] || [ "\$FILE_NAME" == "null" ]; then log "❌ 错误: 文件名为空,跳过此链接: \$URL" continue fi SAVE_PATH="\$SAVE_DIR/\$FILE_NAME" TEMP_PATH="\$SAVE_PATH.temp" log "🔄 正在下载: \$URL 到临时文件: \$TEMP_PATH" curl -s -L -o "\$TEMP_PATH" "\$URL" if [ \$? -ne 0 ]; then wget -q -O "\$TEMP_PATH" "\$URL" fi if [ \$? -eq 0 ]; then log "✅ 文件下载成功: \$TEMP_PATH" if base64 -d "\$TEMP_PATH" > /dev/null 2>&1; then base64 -d "\$TEMP_PATH" > "\$SAVE_PATH" if [ \$? -eq 0 ]; then log "📂 Base64 解码成功,配置已保存: \$SAVE_PATH" rm -f "\$TEMP_PATH" else log "⚠️ Base64 解码失败: \$SAVE_PATH" rm -f "\$TEMP_PATH" fi elif file "\$TEMP_PATH" | grep -q "gzip compressed"; then gunzip -c "\$TEMP_PATH" > "\$SAVE_PATH" if [ \$? -eq 0 ]; then log "📂 Gzip 解压成功,配置已保存: \$SAVE_PATH" rm -f "\$TEMP_PATH" else log "⚠️ Gzip 解压失败: \$SAVE_PATH" rm -f "\$TEMP_PATH" fi else mv "\$TEMP_PATH" "\$SAVE_PATH" log "✅ 订阅内容已成功下载,无需解码" fi else log "❌ 订阅更新失败: \$URL" rm -f "\$TEMP_PATH" fi done log "🚀 所有订阅链接更新完成!" EOL; if (file_put_contents($shellScriptPath, $shellScriptContent) !== false) { chmod($shellScriptPath, 0755); echo "
Shell 脚本已创建成功!路径: $shellScriptPath
"; } else { echo "
无法创建 Shell 脚本,请检查权限。
"; } } } ?> Cron 表达式不能为空。"; exit; } $cronJob = "$cronExpression /etc/neko/core/update_mihomo.sh"; exec("crontab -l | grep -v '/etc/neko/core/update_mihomo.sh' | crontab -", $output, $returnVarRemove); if ($returnVarRemove === 0) { file_put_contents($CRON_LOG_FILE, date('[ H:i:s ] ') . "成功移除旧的 Cron 任务。\n", FILE_APPEND); } else { file_put_contents($CRON_LOG_FILE, date('[ H:i:s ] ') . "移除旧的 Cron 任务失败。\n", FILE_APPEND); } exec("(crontab -l; echo '$cronJob') | crontab -", $output, $returnVarAdd); if ($returnVarAdd === 0) { file_put_contents($CRON_LOG_FILE, date('[ H:i:s ] ') . "成功添加新的 Cron 任务: $cronJob\n", FILE_APPEND); echo "
Cron 任务已成功添加或更新!
"; } else { file_put_contents($CRON_LOG_FILE, date('[ H:i:s ] ') . "添加新的 Cron 任务失败。\n", FILE_APPEND); echo "
无法添加或更新 Cron 任务,请检查服务器权限。
"; } } } ?> 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb', 'geosite' => 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat', 'cache' => 'https://github.com/Thaolga/neko/raw/main/cache.db' ]; $download_directories = [ 'geoip' => '/etc/neko/', 'geosite' => '/etc/neko/', 'cache' => '/www/nekobox/' ]; if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['file'])) { $file = $_GET['file']; if (isset($file_urls[$file])) { $file_url = $file_urls[$file]; $destination_directory = $download_directories[$file]; $destination_path = $destination_directory . basename($file_url); if (download_file($file_url, $destination_path)) { echo "
文件成功下载到 $destination_path
"; } else { echo "
文件下载失败
"; } } else { echo "无效的文件请求"; } } function download_file($url, $destination) { $ch = curl_init($url); $fp = fopen($destination, 'wb'); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $result = curl_exec($ch); curl_close($ch); fclose($fp); return $result !== false; } ?> Mihomo - NekoBox
首页 文件管理 模板 一 模板 二 模板 三

文件管理

$file) { $filePath = $allFilePaths[$index]; $fileType = $fileTypes[$index]; ?>
文件名 大小 最后修改时间 文件类型 执行操作

Mihomo订阅管理

订阅链接

未找到订阅信息。

自动更新

打开文件助手