push
首次推送
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* @description 项目的基础控制器,负责处理所有控制器的基础逻辑。
|
||||
* @author https://t.me/CCfork
|
||||
* @copyright Copyright (c) 2025, https://t.me/CCfork
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
defined('IN_APP') or die('Direct access is not allowed.');
|
||||
|
||||
class BaseController extends Controller {
|
||||
public function __construct(){
|
||||
parent::__construct();
|
||||
$this->checkAuth();
|
||||
}
|
||||
|
||||
final protected function checkAuth(){
|
||||
if (C('NEED_LOGIN') !== true) return;
|
||||
|
||||
$controllerName = C('CONTROLLER_NAME');
|
||||
$ACTION_NAME = C('ACTION_NAME');
|
||||
|
||||
$islogined = !empty($_SESSION['user_authenticated']);
|
||||
if (!$islogined) {
|
||||
if($controllerName !== 'Login'){
|
||||
return $this->redirect('index.php/Login');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* @description 项目的编辑器控制器,负责显示和处理规则编辑器。
|
||||
* 该控制器处理规则文件的加载、编辑和保存功能。
|
||||
* @author https://t.me/CCfork
|
||||
* @copyright Copyright (c) 2025, https://t.me/CCfork
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
defined('IN_APP') or die('Direct access is not allowed.');
|
||||
|
||||
/**
|
||||
* 负责显示和处理规则编辑器的控制器
|
||||
*/
|
||||
class EditController extends BaseController {
|
||||
|
||||
/**
|
||||
* 默认方法,根据文件类型显示不同的编辑器
|
||||
* 访问URL: index.php/Edit?file=...
|
||||
*/
|
||||
public function indexAction(){
|
||||
$file_content = '""';
|
||||
$file_path_for_js = '""';
|
||||
$full_path = '';
|
||||
$requested_file = '';
|
||||
|
||||
if (isset($_GET['file'])) {
|
||||
$base_dir = realpath(ROOT_PATH . '/box');
|
||||
$requested_file = str_replace(['../', '..\\'], '', $_GET['file']);
|
||||
$full_path = realpath($base_dir . '/' . $requested_file);
|
||||
|
||||
if ($full_path && strpos($full_path, $base_dir) === 0 && file_exists($full_path)) {
|
||||
$content = file_get_contents($full_path);
|
||||
|
||||
$data = json_decode($content);
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_object($data) && isset($data->spider) && is_string($data->spider)) {
|
||||
$spiderParts = explode(';md5;', $data->spider);
|
||||
$jarRelativePath = $spiderParts[0];
|
||||
|
||||
$jsonDir = dirname($full_path);
|
||||
$jarAbsolutePath = realpath($jsonDir . '/' . $jarRelativePath);
|
||||
|
||||
if ($jarAbsolutePath && is_readable($jarAbsolutePath)) {
|
||||
$md5 = md5_file($jarAbsolutePath);
|
||||
$data->spider = $jarRelativePath . ';md5;' . $md5;
|
||||
$content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
|
||||
$file_content = json_encode($content);
|
||||
$file_path_for_js = json_encode($requested_file);
|
||||
} else {
|
||||
$error_message = '错误:文件未找到或路径无效。路径: ' . htmlspecialchars($requested_file);
|
||||
$file_content = json_encode($error_message);
|
||||
}
|
||||
} else {
|
||||
$file_content = json_encode('错误:未指定要编辑的文件。');
|
||||
}
|
||||
|
||||
$this->assign('file_content_for_js', $file_content);
|
||||
$this->assign('file_path_for_js', $file_path_for_js);
|
||||
$this->assign('file_path', $full_path ? formatPathForVSCode($full_path) : '');
|
||||
|
||||
$file_extension = strtolower(pathinfo($requested_file, PATHINFO_EXTENSION));
|
||||
$api = $_GET['api'] ?? '';
|
||||
|
||||
if ($api === 'csp_XYQHiker'){
|
||||
return $this->display('Edit/XYQHiker');
|
||||
}
|
||||
|
||||
if (in_array($file_extension, ['json', 'js', 'py', 'php']) || $api === 'editor') {
|
||||
$this->assign('file_extension', $file_extension);
|
||||
return $this->display('Edit/editor');
|
||||
}
|
||||
|
||||
$this->display('Edit/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件保存请求
|
||||
* 访问URL: index.php/Edit/save
|
||||
*/
|
||||
public function saveAction() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['success' => false, 'message' => '无效的请求方法']);
|
||||
return;
|
||||
}
|
||||
|
||||
$filePath = $_POST['filePath'] ?? null;
|
||||
$fileContent = $_POST['fileContent'] ?? null;
|
||||
|
||||
if (!$filePath || $fileContent === null) {
|
||||
echo json_encode(['success' => false, 'message' => '文件路径或内容不能为空']);
|
||||
return;
|
||||
}
|
||||
|
||||
$baseDir = realpath(ROOT_PATH . '/box');
|
||||
$sanitizedPath = str_replace(['../', '..\\'], '', $filePath);
|
||||
$targetPath = $baseDir . DIRECTORY_SEPARATOR . $sanitizedPath;
|
||||
|
||||
if (strpos(realpath(dirname($targetPath)), $baseDir) !== 0) {
|
||||
echo json_encode(['success' => false, 'message' => '错误:禁止访问此路径']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = file_put_contents($targetPath, $fileContent);
|
||||
if ($result === false) {
|
||||
throw new Exception('无法写入文件,请检查服务器上 /box 目录及其子文件的写入权限。');
|
||||
}
|
||||
echo json_encode(['success' => true, 'message' => '文件 ' . htmlspecialchars(basename($targetPath)) . ' 保存成功!']);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'message' => '保存失败:' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* @description 项目的首页控制器,负责处理首页的显示逻辑。
|
||||
* @author https://t.me/CCfork
|
||||
* @copyright Copyright (c) 2025, https://t.me/CCfork
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
defined('IN_APP') or die('Direct access is not allowed.');
|
||||
|
||||
class IndexController extends BaseController {
|
||||
|
||||
public function indexAction(){
|
||||
$this->display('Index/index');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* @description 项目的登录控制器,负责处理用户登录和登出逻辑。
|
||||
* @author https://t.me/CCfork
|
||||
* @copyright Copyright (c) 2025, https://t.me/CCfork
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
defined('IN_APP') or die('Direct access is not allowed.');
|
||||
|
||||
class LoginController extends BaseController {
|
||||
|
||||
public function indexAction(){
|
||||
$this->display('Login/index');
|
||||
}
|
||||
|
||||
public function doLoginAction(){
|
||||
$password = $_POST['password'] ?? '';
|
||||
$correct_password = C('PASSWORD');
|
||||
|
||||
if (!empty($password) && $password === $correct_password) {
|
||||
$_SESSION['user_authenticated'] = true;
|
||||
$this->redirect('/');
|
||||
} else {
|
||||
$this->assign('error', '密码错误,请重试。');
|
||||
$this->display('Login/index');
|
||||
}
|
||||
}
|
||||
|
||||
public function logoutAction(){
|
||||
session_destroy();
|
||||
$this->redirect('/');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* @description 项目的核心控制器,负责处理远程URL的代理加载、文件列表、文件检查和配置保存等功能。
|
||||
* @author https://t.me/CCfork
|
||||
* @copyright Copyright (c) 2025, https://t.me/CCfork
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
defined('IN_APP') or die('Direct access is not allowed.');
|
||||
|
||||
class ProxyController extends BaseController {
|
||||
|
||||
private $baseSaveDir = './box/';
|
||||
private $cacheDir = './cache/';
|
||||
private $cacheTtl = 3600;
|
||||
|
||||
/**
|
||||
* 构造函数,确保目录存在
|
||||
*/
|
||||
public function __construct(){
|
||||
parent::__construct();
|
||||
if (!is_dir($this->baseSaveDir)) mkdir($this->baseSaveDir, 0755, true);
|
||||
if (!is_dir($this->cacheDir)) mkdir($this->cacheDir, 0755, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理远程URL加载 (默认Action)
|
||||
* 访问URL: index.php/Proxy/load?target_url=...
|
||||
* (已优化本地文件加载逻辑,可自动计算spider的MD5)
|
||||
*/
|
||||
public function loadAction() {
|
||||
if (!isset($_GET['target_url'])) {
|
||||
$this->ajaxReturn(['error' => '缺少目标URL (target_url) 参数']);
|
||||
}
|
||||
|
||||
$targetUrl = $_GET['target_url'];
|
||||
$serverHost = $_SERVER['HTTP_HOST'];
|
||||
|
||||
if (strpos($targetUrl, $serverHost) !== false && strpos($targetUrl, '/box/') !== false) {
|
||||
$urlParts = parse_url($targetUrl);
|
||||
$localPath = realpath(ROOT_PATH . $urlParts['path']);
|
||||
|
||||
if ($localPath && file_exists($localPath) && strpos($localPath, realpath(ROOT_PATH)) === 0) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$content = file_get_contents($localPath);
|
||||
$data = json_decode($content);
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_object($data) && isset($data->spider) && is_string($data->spider)) {
|
||||
$spiderParts = explode(';md5;', $data->spider);
|
||||
$jarRelativePath = $spiderParts[0];
|
||||
|
||||
$jsonDir = dirname($localPath);
|
||||
$jarAbsolutePath = realpath($jsonDir . '/' . $jarRelativePath);
|
||||
|
||||
if ($jarAbsolutePath && is_readable($jarAbsolutePath)) {
|
||||
$md5 = md5_file($jarAbsolutePath);
|
||||
$data->spider = $jarRelativePath . ';md5;' . $md5;
|
||||
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
$data->spider = $jarRelativePath;
|
||||
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
} else {
|
||||
echo $content;
|
||||
}
|
||||
exit;
|
||||
} else {
|
||||
$this->ajaxReturn(['error' => '本地文件未找到或路径无效']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_dir($this->cacheDir)) mkdir($this->cacheDir, 0755, true);
|
||||
|
||||
$cacheHash = md5($targetUrl);
|
||||
$cacheFilePath = $this->cacheDir . $cacheHash . '.cache';
|
||||
|
||||
if (file_exists($cacheFilePath) && (time() - filemtime($cacheFilePath) < $this->cacheTtl)) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo file_get_contents($cacheFilePath);
|
||||
exit;
|
||||
}
|
||||
|
||||
$result = httpCurl(['url' => $targetUrl]);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
$this->ajaxReturn(['error' => 'cURL 请求失败: ' . $result['error']]);
|
||||
} else {
|
||||
$httpCode = $result['info']['http_code'];
|
||||
$contentType = $result['info']['content_type'];
|
||||
|
||||
if ($httpCode >= 200 && $httpCode < 400) {
|
||||
file_put_contents($cacheFilePath, $result['body']);
|
||||
if ($contentType) header('Content-Type: ' . $contentType);
|
||||
else header('Content-Type: application/json; charset=utf-8');
|
||||
echo $result['body'];
|
||||
exit;
|
||||
} else {
|
||||
http_response_code($httpCode);
|
||||
echo "无法从目标服务器获取内容。服务器返回错误: HTTP " . $httpCode;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出文件
|
||||
* 访问URL: index.php/Proxy/listFiles
|
||||
*/
|
||||
public function listFilesAction() {
|
||||
if (!is_dir($this->baseSaveDir)) {
|
||||
$this->ajaxReturn([]);
|
||||
}
|
||||
|
||||
function scan_directory_recursive($dir, $baseDir) {
|
||||
$result = [];
|
||||
$items = array_diff(scandir($dir), ['.', '..']);
|
||||
foreach ($items as $item) {
|
||||
$path = $dir . '/' . $item;
|
||||
$relativePath = str_replace($baseDir, '', $path);
|
||||
if (is_dir($path)) {
|
||||
$result[] = ['name' => $item, 'type' => 'dir', 'path' => ltrim($relativePath, '/'), 'children' => scan_directory_recursive($path, $baseDir)];
|
||||
} else {
|
||||
$result[] = ['name' => $item, 'type' => 'file', 'path' => ltrim($relativePath, '/')];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
$fileTree = scan_directory_recursive(rtrim($this->baseSaveDir, '/'), rtrim($this->baseSaveDir, '/') . '/');
|
||||
$this->ajaxReturn($fileTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
* 访问URL: index.php/Proxy/checkFileExists?path=...
|
||||
*/
|
||||
public function checkFileExistsAction(){
|
||||
$filePath = isset($_GET['path']) ? sanitize_path($_GET['path']) : '';
|
||||
$fullPath = $this->baseSaveDir . $filePath;
|
||||
$this->ajaxReturn(['exists' => file_exists($fullPath), 'path' => $filePath]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置文件
|
||||
* 访问URL: index.php/Proxy/saveConfig (POST请求)
|
||||
*/
|
||||
public function saveConfigAction() {
|
||||
if (!isset($_POST['dir'], $_POST['filename'], $_POST['content'])) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '缺少保存配置的参数']);
|
||||
}
|
||||
|
||||
$targetDir = $this->baseSaveDir . sanitize_path($_POST['dir']) . '/';
|
||||
$filename = sanitize_path($_POST['filename']);
|
||||
|
||||
if (!is_dir($targetDir)) mkdir($targetDir, 0755, true);
|
||||
|
||||
if (file_put_contents($targetDir . $filename, $_POST['content']) !== false) {
|
||||
$this->ajaxReturn(['success' => true, 'message' => '配置文件保存成功']);
|
||||
} else {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '配置文件写入失败,请检查目录权限']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载资源文件
|
||||
* 访问URL: index.php/Proxy/downloadAsset (POST请求)
|
||||
*/
|
||||
public function downloadAssetAction() {
|
||||
if (!isset($_POST['source_url'], $_POST['target_dir'], $_POST['relative_path'])) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '缺少下载资源的参数']);
|
||||
}
|
||||
|
||||
$sourceUrl = $_POST['source_url'];
|
||||
$targetDir = sanitize_path($_POST['target_dir']);
|
||||
$relativePath = sanitize_path($_POST['relative_path']);
|
||||
$localFullPath = $this->baseSaveDir . $targetDir . '/' . $relativePath;
|
||||
$localDir = dirname($localFullPath);
|
||||
|
||||
if (!is_dir($localDir)) {
|
||||
if (!mkdir($localDir, 0755, true)) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '创建目录失败: ' . $localDir]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = httpCurl(['url' => $sourceUrl]);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => 'cURL下载失败: ' . $result['error']]);
|
||||
} else {
|
||||
if (file_put_contents($localFullPath, $result['body']) !== false) {
|
||||
$this->ajaxReturn(['success' => true, 'message' => '资源下载成功: ' . $localFullPath]);
|
||||
} else {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '文件写入本地失败']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user