• 首页 > 内容
  • 给飞牛添加一个web的shell执行工具 root权限-作死版

    给飞牛添加一个web的shell执行工具 root权限-作死版(图1)

    给飞牛添加一个web的shell执行工具 root权限-作死版(图2)

    给飞牛添加一个web的shell执行工具 root权限-作死版(图3)

    给飞牛添加一个web的shell执行工具 root权限-作死版(图4)

    这个代码实现了一个功能丰富的 Shell 命令执行工具,提供了命令执行、脚本管理、定时任务调度等功能。下面是对其核心功能的详细介绍:  

    主要功能模块 

    1. **用户认证系统**

      - 支持用户名密码登录(默认用户:admin/admin123)

       - 基于会话的身份验证机制

      - 可配置是否需要认证

    2.  **命令执行模块**

       - 提供文本框输入任意 Shell 命令

       - 实时显示命令执行结果和返回状态

       - 记录命令执行时间

       - 限制最大输出大小(1MB)防止内存溢出

    3. **脚本管理系统**

       - 保存常用命令为脚本文件

       - 加载已保存的脚本

       - 删除不需要的脚本

       - 显示脚本列表(按修改时间排序)

       - 支持上传和下载脚本文件

    4. **定时任务管理**

       - 基于 cron 表达式的定时任务设置

       - 提供常用 cron 预设模板(每分钟、每小时等)

       - 显示定时任务列表及状态

       - 计算并显示下次执行时间

       - 添加/删除定时任务

       - 检测任务运行状态(运行中/待执行)

    5. **日志与历史记录**

       - 记录所有命令执行日志

       - 显示最近 5 条执行历史

       - 日志包含时间、IP、用户、状态和命令内容

    6. **界面与用户体验**

       - 深色/浅色主题切换(保存用户偏好)

       - 响应式设计,适配不同屏幕尺寸

       - 命令文本框快捷操作(清空、全选)

       - 直观的视觉反馈(成功/失败状态提示)

    ### 安全特性

    尽管代码中强调"完全取消命令限制",但仍包含以下安全措施:

    1. 基于会话的用户认证

    2. 脚本名称的正则表达式验证

    3. 日志记录所有操作

    4. 输出内容大小限制

    5. 定时任务添加时的格式验证

    6. 明确的安全警告提示

    ### 技术实现细节

    1. **后端技术**

       - 使用 PHP 实现所有功能

       - 通过 `exec()` 函数执行 Shell 命令

       - 使用 `crontab` 命令管理定时任务

       - 基于文件系统的脚本存储

    2. **前端技术**

       - 纯 HTML/CSS/JavaScript 实现

       - 原生 JavaScript 处理所有交互逻辑

       - 本地存储保存主题偏好

       - 表格展示数据列表

    3. **依赖管理**

       - 使用 Composer 管理第三方依赖

       - 支持 `mtdowling/cron-expression` 库解析 cron 表达式

    这个工具非常适合开发和测试环境使用,但由于其高风险特性,强烈建议不要在生产环境或可公开访问的服务器上部署。其次这个工具需要安装 `mtdowling/cron-expression` 库来解析和计算 cron 表达式的下次执行时间。你可以通过 Composer 来安装这个依赖。

    安装步骤

    1. 首先确保你的服务器上已经安装了 Composer。如果没有安装,可以按照 [官方文档](https://getcomposer.org/download/) 进行安装。

    2. 在项目根目录下创建一个 `composer.json` 文件,内容如下:


    {    "require": {        "mtdowling/cron-expression": "^1.3"    }}


    3. 在终端中执行以下命令安装依赖:

    composer install

    这将会在项目目录下创建一个 `vendor` 目录,并安装所需的库。

    ### 工具已有的自动加载支持

    注意到代码中已经有自动加载 Composer 依赖的部分:


    // 自动加载Composer依赖if (file_exists(__DIR__ . '/vendor/autoload.php')) {    require_once __DIR__ . '/vendor/autoload.php';}


    所以只要按照上述步骤安装了库,工具就能正常使用 cron 表达式解析功能了。

    ### 功能说明

    安装这个库后,定时任务管理模块将能够:

    1. 准确计算每个 cron 表达式的下次执行时间

    2. 在任务列表中显示状态信息(运行中/待执行)

    3. 提供更友好的定时任务配置体验

    再次提醒,这个工具完全取消了命令限制,存在极高的安全风险,请务必仅在受信任的环境中使用。


    <?php
    // shell_executor.php
    session_start();
    date_default_timezone_set('Asia/Shanghai');
    // 配置参数(完全取消命令限制,极度危险!)
    $config = [
        'scripts_dir' => __DIR__ . '/scripts/', // 脚本存储目录
        'max_output_size' => 1024 * 1024, // 1MB
        'log_file' => __DIR__ . '/shell_execution.log',
        'require_auth' => true,
        'username' => 'admin',
        'password' => password_hash('admin123', PASSWORD_DEFAULT),
    ];
    // 自动加载Composer依赖
    if (file_exists(__DIR__ . '/vendor/autoload.php')) {
        require_once __DIR__ . '/vendor/autoload.php';

    // 创建脚本目录(如果不存在)
    if (!file_exists($config['scripts_dir'])) {
        mkdir($config['scripts_dir'], 0755, true);

    // 认证处理
    if ($config['require_auth'] && !isset($_SESSION['authenticated'])) {
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username'], $_POST['password'])) {
            if ($_POST['username'] === $config['username'] && password_verify($_POST['password'], $config['password'])) {
                $_SESSION['authenticated'] = true;
                header('Location: ' . $_SERVER['PHP_SELF']);
                exit;
            } else {
                $auth_error = '用户名或密码错误';
            }
        } else {
            ?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>Shell执行工具 - 登录</title>
        <style>
            body { font-family: Arial, sans-serif; max-width: 400px; margin: 50px auto; }
            .login-box { padding: 20px; border: 1px solid #ddd; border-radius: 5px; }
            .error { color: red; margin-bottom: 10px; }
            input { width: 100%; padding: 8px; margin-bottom: 10px; box-sizing: border-box; }
            button { width: 100%; padding: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
        </style>
    </head>
    <body>
        <div class="login-box">
            <h2>Shell执行工具登录</h2>
            <?php if (isset($auth_error)): ?>
                <div class="error"><?php echo htmlspecialchars($auth_error); ?></div>
            <?php endif; ?>
            <form method="post">
                <input type="text" name="username" placeholder="用户名" required>
                <input type="password" name="password" placeholder="密码" required>
                <button type="submit">登录</button>
            </form>
        </div>
    </body>
    </html>
            <?php
            exit;
        }

    // 记录日志
    function log_action($command, $output, $success) {
        global $config;
        $log_entry = date('Y-m-d H:i:s') . ' - ' . 
                     (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'CLI') . ' - ' .
                     (isset($_SESSION['authenticated']) ? $_SESSION['username'] : 'guest') . ' - ' .
                     ($success ? 'SUCCESS' : 'ERROR') . ' - ' .
                     $command . PHP_EOL;
        // 限制日志中输出内容的大小
        $output = substr($output, 0, 1024);
        $log_entry .= "Output: " . $output . PHP_EOL . str_repeat('-', 50) . PHP_EOL;
        file_put_contents($config['log_file'], $log_entry, FILE_APPEND);

    // 脚本管理功能
    $script_message = '';
    $scripts = [];
    // 保存脚本
    if (isset($_POST['save_script'])) {
        $script_name = trim($_POST['script_name']);
        $script_content = trim($_POST['command']);
        if (empty($script_name)) {
            $script_message = "错误: 请输入脚本名称";
        } elseif (preg_match('/[^a-zA-Z0-9_\-\.]/', $script_name)) {
            $script_message = "错误: 脚本名称只能包含字母、数字、下划线、连字符和点";
        } else {
            $script_path = $config['scripts_dir'] . $script_name . '.sh';
            if (file_put_contents($script_path, $script_content) !== false) {
                $script_message = "脚本已保存: $script_name.sh";
            } else {
                $script_message = "错误: 无法保存脚本";
            }
        }

    // 删除脚本
    if (isset($_GET['delete_script'])) {
        $script_name = basename($_GET['delete_script']);
        $script_path = $config['scripts_dir'] . $script_name;
        if (file_exists($script_path) && is_writable($script_path)) {
            unlink($script_path);
            $script_message = "脚本已删除: $script_name";
        } else {
            $script_message = "错误: 无法删除脚本";
        }

    // 加载脚本
    if (isset($_GET['load_script'])) {
        $script_name = basename($_GET['load_script']);
        $script_path = $config['scripts_dir'] . $script_name;
        if (file_exists($script_path) && is_readable($script_path)) {
            $_POST['command'] = file_get_contents($script_path);
        } else {
            $script_message = "错误: 无法加载脚本";
        }

    // 获取脚本列表
    if ($handle = opendir($config['scripts_dir'])) {
        while (false !== ($entry = readdir($handle))) {
            if ($entry != "." && $entry != ".." && pathinfo($entry, PATHINFO_EXTENSION) == 'sh') {
                $scripts[] = [
                    'name' => pathinfo($entry, PATHINFO_FILENAME),
                    'path' => $entry,
                    'size' => filesize($config['scripts_dir'] . $entry),
                    'mtime' => filemtime($config['scripts_dir'] . $entry)
                ];
            }
        }
        closedir($handle);
        // 按修改时间排序(最新的在前)
        usort($scripts, function($a, $b) {
            return $b['mtime'] - $a['mtime'];
        });

    // 定时任务管理功能
    $cron_message = '';
    $cron_jobs = [];
    // 定时任务预设模板
    $cron_presets = [
        'every_minute' => ['label' => '每分钟', 'expression' => '* * * * *'],
        'every_5_minutes' => ['label' => '每5分钟', 'expression' => '*/5 * * * *'],
        'every_10_minutes' => ['label' => '每10分钟', 'expression' => '*/10 * * * *'],
        'every_30_minutes' => ['label' => '每30分钟', 'expression' => '*/30 * * * *'],
        'every_hour' => ['label' => '每小时', 'expression' => '0 * * * *'],
        'every_2_hours' => ['label' => '每2小时', 'expression' => '0 */2 * * *'],
        'every_6_hours' => ['label' => '每6小时', 'expression' => '0 */6 * * *'],
        'daily_midnight' => ['label' => '每天午夜', 'expression' => '0 0 * * *'],
        'daily_morning' => ['label' => '每天早上6点', 'expression' => '0 6 * * *'],
        'daily_evening' => ['label' => '每天晚上8点', 'expression' => '0 20 * * *'],
        'weekly' => ['label' => '每周日午夜', 'expression' => '0 0 * * 0'],
        'monthly' => ['label' => '每月1日午夜', 'expression' => '0 0 1 * *'],
    ];
    // 获取当前定时任务列表
    function get_cron_jobs() {
        exec('crontab -l 2>&1', $output, $return_var);
        if ($return_var !== 0) return [];
        $jobs = [];
        foreach ($output as $line) {
            $line = trim($line);
            if (!empty($line) && strpos($line, '#') !== 0) { // 过滤注释和空行
                $jobs[] = $line;
            }
        }
        return $jobs;

    // 计算cron表达式的下次执行时间
    function get_next_run_time($cron_expr) {
        // 解析cron表达式
        $parts = explode(' ', $cron_expr);
        if (count($parts) != 5) return '无效表达式';
        list($minutes, $hours, $days, $months, $weeks) = $parts;
        // 使用cron-expression库计算下次执行时间
        // 注意: 实际环境中需要安装mtdowling/cron-expression库
        // composer require mtdowling/cron-expression
        try {
            if (class_exists('\Cron\CronExpression')) {
                $cron = \Cron\CronExpression::factory("$minutes $hours $days $months $weeks");
                return $cron->getNextRunDate()->format('Y-m-d H:i:s');
            } else {
                return '需要安装cron-expression库';
            }
        } catch (Exception $e) {
            return '计算失败';
        }

    // 检查任务是否正在运行
    function is_job_running($command) {
        // 简单检查进程是否存在
        $escaped_cmd = escapeshellarg('%' . $command . '%');
        exec("ps aux | grep $escaped_cmd | grep -v grep", $output);
        return count($output) > 0;

    // 添加定时任务
    if (isset($_POST['add_cron'])) {
        $schedule = trim($_POST['cron_schedule']);
        $command = trim($_POST['command']);
        if (empty($schedule) || empty($command)) {
            $cron_message = "错误: 定时规则和命令不能为空";
        } else {
            // 验证cron表达式格式(简易验证)
            if (!preg_match('/^(\*|(\d+|\*\/\d+)) (\*|(\d+|\*\/\d+)) (\*|(\d+|\*\/\d+)) (\*|(\d+|\*\/\d+)) (\*|(\d+|\*\/\d+))$/', $schedule)) {
                $cron_message = "错误: 定时规则格式无效(分 时 日 月 周)";
            } else {
                // 备份当前crontab
                $current_cron = implode("\n", get_cron_jobs()) . "\n";
                // 添加新任务(带注释标识为该工具添加)
                $new_cron = $current_cron . "# Added by ShellExecutor\n" . $schedule . " " . $command . "\n";
                // 写入crontab
                $tmp_file = tempnam(sys_get_temp_dir(), 'cron');
                file_put_contents($tmp_file, $new_cron);
                exec("crontab " . $tmp_file, $output, $return_var);
                unlink($tmp_file);
                if ($return_var === 0) {
                    $cron_message = "定时任务添加成功";
                } else {
                    $cron_message = "错误: 无法添加定时任务(返回码: $return_var)";
                }
            }
        }

    // 删除定时任务
    if (isset($_GET['delete_cron'])) {
        $cron_index = intval($_GET['delete_cron']);
        $current_jobs = get_cron_jobs();
        if (isset($current_jobs[$cron_index])) {
            // 排除要删除的任务
            $new_jobs = [];
            foreach ($current_jobs as $i => $job) {
                if ($i !== $cron_index) $new_jobs[] = $job;
            }
            // 写入新的crontab
            $tmp_file = tempnam(sys_get_temp_dir(), 'cron');
            file_put_contents($tmp_file, implode("\n", $new_jobs) . "\n");
            exec("crontab " . $tmp_file, $output, $return_var);
            unlink($tmp_file);
            if ($return_var === 0) {
                $cron_message = "定时任务删除成功";
            } else {
                $cron_message = "错误: 无法删除定时任务(返回码: $return_var)";
            }
        } else {
            $cron_message = "错误: 定时任务不存在";
        }

    // 获取当前定时任务
    $cron_jobs = get_cron_jobs();
    // 执行命令
    $result = ['output' => '', 'success' => false, 'execution_time' => 0];
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['command']) && !isset($_POST['save_script']) && !isset($_POST['add_cron'])) {
        $command = trim($_POST['command']);
        // 完全取消所有命令限制,直接执行用户输入的命令
        $start_time = microtime(true);
        exec($command . ' 2>&1', $output_lines, $return_var);
        $end_time = microtime(true);
        $result['execution_time'] = round($end_time - $start_time, 3);
        $result['output'] = implode("\n", $output_lines);
        $result['success'] = ($return_var === 0);
        // 限制输出大小
        if (strlen($result['output']) > $config['max_output_size']) {
            $result['output'] = substr($result['output'], 0, $config['max_output_size']) . "\n\n... 输出内容过大,已截断";
        }
        log_action($command, $result['output'], $result['success']);

    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>Shell执行工具</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; }
            .container { max-width: 1200px; margin: 0 auto; }
            .header { background-color: #333; color: white; padding: 15px; border-radius: 5px 5px 0 0; }
            .content { background-color: white; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
            .command-box { margin-bottom: 20px; }
            textarea { width: 100%; height: 150px; padding: 10px; margin-bottom: 10px; box-sizing: border-box; border: 1px solid #ddd; border-radius: 4px; font-family: monospace; }
            .button-group { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
            button, input[type="submit"] { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
            button:hover, input[type="submit"]:hover { background-color: #45a049; }
            .btn-danger { background-color: #f44336; }
            .btn-danger:hover { background-color: #d32f2f; }
            .btn-primary { background-color: #2196F3; }
            .btn-primary:hover { background-color: #0b7dda; }
            .btn-secondary { background-color: #607D8B; }
            .btn-secondary:hover { background-color: #4b636e; }
            .btn-cron { background-color: #FF9800; }
            .btn-cron:hover { background-color: #F57C00; }
            .result-box { margin-top: 20px; }
            .result-header { font-weight: bold; margin-bottom: 10px; }
            .result-output { background-color: #f9f9f9; border: 1px solid #ddd; padding: 10px; min-height: 100px; max-height: 400px; overflow: auto; font-family: monospace; white-space: pre-wrap; }
            .status { margin-top: 10px; padding: 5px; border-radius: 3px; }
            .success { background-color: #d4edda; color: #155724; }
            .error { background-color: #f8d7da; color: #721c24; }
            .footer { margin-top: 20px; text-align: center; color: #666; font-size: 0.9em; }
            .history { margin-top: 20px; }
            .history table { width: 100%; border-collapse: collapse; }
            .history th, .history td { border: 1px solid #ddd; padding: 8px; text-align: left; }
            .history th { background-color: #f2f2f2; }
            .scripts { margin-top: 20px; }
            .scripts table { width: 100%; border-collapse: collapse; }
            .scripts th, .scripts td { border: 1px solid #ddd; padding: 8px; text-align: left; }
            .scripts th { background-color: #f2f2f2; }
            .script-form { margin-top: 10px; }
            .script-form input[type="text"] { padding: 8px; border: 1px solid #ddd; border-radius: 4px; width: 200px; margin-right: 10px; }
            .message { padding: 10px; margin-bottom: 10px; border-radius: 4px; }
            .message-success { background-color: #d4edda; color: #155724; }
            .message-error { background-color: #f8d7da; color: #721c24; }
            .upload-form { margin-top: 10px; }
            .upload-form input[type="file"] { margin-right: 10px; }
            .cron-form { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 10px; }
            .cron-form input[type="text"] { padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
            .cron-examples { margin-top: 5px; font-size: 0.9em; color: #666; }
            .cron-table { margin-top: 10px; width: 100%; border-collapse: collapse; }
            .cron-table th, .cron-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
            .cron-table th { background-color: #f2f2f2; }
            .preset-buttons { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 5px; }
            .preset-btn { padding: 5px 10px; background-color: #e0e0e0; border: none; border-radius: 4px; cursor: pointer; }
            .preset-btn:hover { background-color: #d0d0d0; }
            .status-badge {
                display: inline-block;
                padding: 2px 8px;
                border-radius: 4px;
                font-size: 0.9em;
                font-weight: bold;
            }
            .status-active {
                background-color: #d4edda;
                color: #155724;
            }
            .status-inactive {
                background-color: #f8d7da;
                color: #721c24;
            }
            .status-pending {
                background-color: #fff3cd;
                color: #856404;
            }
            /* 深色主题样式 */
            .dark-theme {
                background-color: #1e1e1e;
                color: #e0e0e0;
            }
            .dark-theme .content {
                background-color: #2d2d2d;
                color: #e0e0e0;
            }
            .dark-theme .header {
                background-color: #1a1a1a;
            }
            .dark-theme textarea,
            .dark-theme input,
            .dark-theme select {
                background-color: #3a3a3a;
                color: #e0e0e0;
                border-color: #555;
            }
            .dark-theme .result-output {
                background-color: #3a3a3a;
                color: #e0e0e0;
                border-color: #555;
            }
            .dark-theme .scripts table,
            .dark-theme .history table,
            .dark-theme .cron-table {
                color: #e0e0e0;
            }
            .dark-theme .scripts th,
            .dark-theme .history th,
            .dark-theme .cron-table th {
                background-color: #3a3a3a;
            }
            .dark-theme .scripts td,
            .dark-theme .history td,
            .dark-theme .cron-table td {
                border-color: #555;
            }
            .dark-theme .preset-btn {
                background-color: #4a4a4a;
                color: #e0e0e0;
            }
            .dark-theme .preset-btn:hover {
                background-color: #5a5a5a;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>Shell执行工具</h1>
            </div>
            <div class="content">
                <?php if (!empty($script_message)): ?>
                <div class="message <?php echo strpos($script_message, '错误') !== false ? 'message-error' : 'message-success'; ?>">
                    <?php echo htmlspecialchars($script_message); ?>
                </div>
                <?php endif; ?>
                <?php if (!empty($cron_message)): ?>
                <div class="message <?php echo strpos($cron_message, '错误') !== false ? 'message-error' : 'message-success'; ?>">
                    <?php echo htmlspecialchars($cron_message); ?>
                </div>
                <?php endif; ?>
                <div class="button-group">
                    <button id="clear-btn">清空命令</button>
                    <button id="select-all-btn">全选命令</button>
                    <button id="toggle-theme-btn">切换主题</button>
                </div>
                <div class="command-box">
                    <form method="post" enctype="multipart/form-data">
                        <textarea name="command" placeholder="输入要执行的Shell命令..."><?php echo isset($_POST['command']) ? htmlspecialchars($_POST['command']) : ''; ?></textarea>
                        <div class="button-group">
                            <input type="submit" value="执行命令">
                            <div class="script-form">
                                <input type="text" name="script_name" placeholder="脚本名称">
                                <input type="submit" name="save_script" value="保存为脚本" class="btn-primary">
                            </div>
                            <div class="upload-form">
                                <input type="file" name="upload_script" accept=".sh">
                                <input type="submit" name="upload" value="导入脚本" class="btn-secondary">
                            </div>
                        </div>
                        <!-- 改进的定时任务表单 -->
                        <div class="cron-form">
                            <select id="cron_preset" style="padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
                                <option value="">-- 选择预设定时规则 --</option>
                                <?php foreach ($cron_presets as $key => $preset): ?>
                                    <option value="<?php echo htmlspecialchars($preset['expression']); ?>"><?php echo htmlspecialchars($preset['label']); ?></option>
                                <?php endforeach; ?>
                            </select>
                            <input type="text" name="cron_schedule" id="cron_schedule" placeholder="定时规则 (分 时 日 月 周)" style="flex: 1;">
                            <input type="submit" name="add_cron" value="添加定时任务" class="btn-cron">
                        </div>
                        <div class="preset-buttons">
                            <strong>常用预设:</strong>
                            <?php foreach (array_slice($cron_presets, 0, 6) as $key => $preset): ?>
                                <button type="button" class="preset-btn" data-cron="<?php echo htmlspecialchars($preset['expression']); ?>"><?php echo htmlspecialchars($preset['label']); ?></button>
                            <?php endforeach; ?>
                        </div>
                        <div class="cron-examples">
                            <p>或者手动输入定时规则(高级用户):</p>
                            <ul>
                                <li><code>* * * * *</code> - 每分钟执行一次</li>
                                <li><code>0 * * * *</code> - 每小时执行一次</li>
                                <li><code>0 0 * * *</code> - 每天凌晨执行一次</li>
                            </ul>
                        </div>
                    </form>
                </div>
                <?php if (isset($result['output'])): ?>
                <div class="result-box">
                    <div class="result-header">
                        执行结果 (耗时: <?php echo $result['execution_time']; ?> 秒)
                    </div>
                    <div class="result-output">
                        <?php echo htmlspecialchars($result['output']); ?>
                    </div>
                    <div class="status <?php echo $result['success'] ? 'success' : 'error'; ?>">
                        <?php echo $result['success'] ? '命令执行成功 (返回码: 0)' : '命令执行失败 (返回码: ' . (isset($return_var) ? $return_var : '未知') . ')'; ?>
                    </div>
                </div>
                <?php endif; ?>
                <!-- 改进的定时任务列表 -->
                <div class="scripts">
                    <h3>定时任务列表</h3>
                    <?php if (!empty($cron_jobs)): ?>
                    <table class="cron-table">
                        <tr>
                            <th>序号</th>
                            <th>定时规则</th>
                            <th>命令</th>
                            <th>下次执行时间</th>
                            <th>状态</th>
                            <th>操作</th>
                        </tr>
                        <?php foreach ($cron_jobs as $index => $job): ?>
                        <tr>
                            <td><?php echo $index + 1; ?></td>
                            <td><?php echo htmlspecialchars(implode(' ', array_slice(explode(' ', $job), 0, 5))); ?></td>
                            <td><?php echo htmlspecialchars(implode(' ', array_slice(explode(' ', $job), 5))); ?></td>
                            <td>
                                <?php
                                $schedule = implode(' ', array_slice(explode(' ', $job), 0, 5));
                                echo get_next_run_time($schedule);
                                ?>
                            </td>
                            <td>
                                <?php
                                $command = implode(' ', array_slice(explode(' ', $job), 5));
                                $is_running = is_job_running($command);
                                $next_run = get_next_run_time($schedule);
                                if ($next_run === '无效表达式' || $next_run === '计算失败' || $next_run === '需要安装cron-expression库') {
                                    echo '<span class="status-badge status-inactive">无效</span>';
                                } elseif ($is_running) {
                                    echo '<span class="status-badge status-active">运行中</span>';
                                } else {
                                    echo '<span class="status-badge status-pending">待执行</span>';
                                }
                                ?>
                            </td>
                            <td>
                                <a href="?delete_cron=<?php echo $index; ?>" class="btn-danger" onclick="return confirm('确定要删除这个定时任务吗?')">删除</a>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                    <?php else: ?>
                    <p>暂无定时任务</p>
                    <?php endif; ?>
                </div>
                <div class="scripts">
                    <h3>已保存的脚本</h3>
                    <?php if (!empty($scripts)): ?>
                    <table>
                        <tr>
                            <th>名称</th>
                            <th>大小</th>
                            <th>修改时间</th>
                            <th>操作</th>
                        </tr>
                        <?php foreach ($scripts as $script): ?>
                        <tr>
                            <td><?php echo htmlspecialchars($script['name']); ?></td>
                            <td><?php echo round($script['size'] / 1024, 2); ?> KB</td>
                            <td><?php echo date('Y-m-d H:i:s', $script['mtime']); ?></td>
                            <td>
                                <a href="?load_script=<?php echo urlencode($script['path']); ?>" class="btn-primary">加载</a>
                                <a href="?delete_script=<?php echo urlencode($script['path']); ?>" class="btn-danger" onclick="return confirm('确定要删除这个脚本吗?')">删除</a>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </table>
                    <?php else: ?>
                    <p>暂无保存的脚本</p>
                    <?php endif; ?>
                </div>
                <div class="history">
                    <h3>最近执行历史</h3>
                    <?php
                    if (file_exists($config['log_file'])) {
                        $log_lines = array_reverse(file($config['log_file'], FILE_IGNORE_NEW_LINES));
                        $history = [];
                        foreach ($log_lines as $line) {
                            if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - (.*?) - (.*?) - (SUCCESS|ERROR) - (.*)$/', $line, $matches)) {
                                $history[] = [
                                    'time' => $matches[1],
                                    'ip' => $matches[2],
                                    'user' => $matches[3],
                                    'status' => $matches[4],
                                    'command' => $matches[5]
                                ];
                                if (count($history) >= 5) break;
                            }
                        }
                        if (!empty($history)) {
                            echo '<table>';
                            echo '<tr><th>时间</th><th>IP地址</th><th>用户</th><th>状态</th><th>命令</th></tr>';
                            foreach ($history as $entry) {
                                $status_class = $entry['status'] === 'SUCCESS' ? 'success' : 'error';
                                echo '<tr>';
                                echo '<td>' . htmlspecialchars($entry['time']) . '</td>';
                                echo '<td>' . htmlspecialchars($entry['ip']) . '</td>';
                                echo '<td>' . htmlspecialchars($entry['user']) . '</td>';
                                echo '<td class="' . $status_class . '">' . htmlspecialchars($entry['status']) . '</td>';
                                echo '<td>' . htmlspecialchars($entry['command']) . '</td>';
                                echo '</tr>';
                            }
                            echo '</table>';
                        } else {
                            echo '<p>暂无执行历史</p>';
                        }
                    } else {
                        echo '<p>日志文件不存在或无法访问</p>';
                    }
                    ?>
                </div>
            </div>
            <div class="footer">
                <p><strong>警告:此工具已完全取消所有命令限制,存在致命安全风险!</strong></p>
                <p>请勿在任何与公共网络连接的服务器上使用此工具,可能导致服务器被入侵和数据泄露!</p>
                <?php if ($config['require_auth']): ?>
                <p><a href="?logout=1">退出登录</a></p>
                <?php endif; ?>
            </div>
        </div>
        <script>
            // 清空命令文本框
            document.getElementById('clear-btn').addEventListener('click', function() {
                document.querySelector('textarea[name="command"]').value = '';
            });
            // 全选命令文本框内容
            document.getElementById('select-all-btn').addEventListener('click', function() {
                const textarea = document.querySelector('textarea[name="command"]');
                textarea.select();
            });
            // 切换深色/浅色主题
            document.getElementById('toggle-theme-btn').addEventListener('click', function() {
                document.body.classList.toggle('dark-theme');
                // 保存主题偏好到localStorage
                const isDarkTheme = document.body.classList.contains('dark-theme');
                localStorage.setItem('shellExecutorTheme', isDarkTheme ? 'dark' : 'light');
            });
            // 加载保存的主题偏好
            document.addEventListener('DOMContentLoaded', function() {
                const savedTheme = localStorage.getItem('shellExecutorTheme');
                if (savedTheme === 'dark') {
                    document.body.classList.add('dark-theme');
                }
            });
            // 预设按钮点击事件
            document.querySelectorAll('.preset-btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    const cronExpr = this.getAttribute('data-cron');
                    document.getElementById('cron_schedule').value = cronExpr;
                });
            });
            // 预设选择器变更事件
            document.getElementById('cron_preset').addEventListener('change', function() {
                const selectedValue = this.value;
                if (selectedValue) {
                    document.getElementById('cron_schedule').value = selectedValue;
                }
            });
            // 文件上传处理
            document.querySelector('input[name="upload_script"]').addEventListener('change', function(e) {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        document.querySelector('textarea[name="command"]').value = e.target.result;
                    };
                    reader.readAsText(file);
                }
            });
        </script>
    </body>
    </html>

    下载地址:

    (图5)Shell 命令执行工具.rar


    加载中~

    版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 1963849530@qq.com 举报,一经查实,本站将立刻删除。如若转载,请注明出处:https://lzq520.cn/narong/135.html

    相关推荐

    加载中~