Share a阅后即焚 source code

演示

代码

<?php
// 确保在文件最开头启动会话
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// 设置默认时区
date_default_timezone_set('Asia/Shanghai');

// 错误报告设置
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/php_errors.log');

// 配置
$CONFIG = [
    'db_path'        => __DIR__ . '/messages.db',
    'max_size'       => 10000,
    'max_lifetime'   => 86400,
    'cleanup_chance' => 20,
    'encrypt_key'    => 'your-secret-key-here' // 请更改为您的密钥
];

// 初始化数据库
function initDatabase($dbPath) {
    try {
        $db = new SQLite3($dbPath);
        $db->enableExceptions(true);
        
        // 创建消息表
        $db->exec("
            CREATE TABLE IF NOT EXISTS messages (
                id TEXT PRIMARY KEY,
                content TEXT NOT NULL,
                password TEXT,
                created_at INTEGER NOT NULL,
                expire_at INTEGER NOT NULL,
                viewed INTEGER DEFAULT 0
            )
        ");
        
        // 创建索引
        $db->exec("CREATE INDEX IF NOT EXISTS idx_expire_at ON messages(expire_at)");
        $db->exec("CREATE INDEX IF NOT EXISTS idx_viewed ON messages(viewed)");
        
        return $db;
    } catch (Exception $e) {
        error_log('Database initialization error: ' . $e->getMessage());
        throw new Exception('无法初始化数据库');
    }
}

// 获取数据库连接
function getDatabase() {
    global $CONFIG;
    static $db = null;
    
    if ($db === null) {
        $db = initDatabase($CONFIG['db_path']);
    }
    
    return $db;
}

// 统一JSON响应函数
function sendJsonResponse($success, $message = '', $data = []) {
    header('Content-Type: application/json');
    $response = [
        'success' => $success,
        'message' => $message,
        'data' => $data
    ];
    echo json_encode($response, JSON_UNESCAPED_UNICODE);
    exit;
}

// 加密函数
function encrypt($data, $key) {
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
    return base64_encode($iv . $encrypted);
}

// 解密函数
function decrypt($data, $key) {
    $data = base64_decode($data);
    $iv = substr($data, 0, openssl_cipher_iv_length('aes-256-cbc'));
    $data = substr($data, openssl_cipher_iv_length('aes-256-cbc'));
    return openssl_decrypt($data, 'aes-256-cbc', $key, 0, $iv);
}

// 获取当前URL
function getCurrentUrl() {
    $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
    return $protocol . $_SERVER['HTTP_HOST'] . strtok($_SERVER['REQUEST_URI'], '?');
}

// 清理过期消息
function cleanupOldMessages() {
    global $CONFIG;
    
    if (rand(1, 100) > $CONFIG['cleanup_chance']) {
        return;
    }
    
    try {
        $db = getDatabase();
        $stmt = $db->prepare("DELETE FROM messages WHERE expire_at < ?");
        $stmt->bindValue(1, time(), SQLITE3_INTEGER);
        $stmt->execute();
        
        // 清理已查看的消息(超过1小时)
        $stmt = $db->prepare("DELETE FROM messages WHERE viewed = 1 AND created_at < ?");
        $stmt->bindValue(1, time() - 3600, SQLITE3_INTEGER);
        $stmt->execute();
        
    } catch (Exception $e) {
        error_log('Cleanup error: ' . $e->getMessage());
    }
}

// 处理AJAX请求
if ($_SERVER['REQUEST_METHOD'] === 'POST' && 
    isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
    strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {

    try {
        // 获取并清理输入
        $content = trim($_POST['content'] ?? '');
        $password = trim($_POST['msg_password'] ?? '');
        $expire_hours = max(1, min(720, intval($_POST['expire_hours'] ?? 24)));

        // 验证输入
        if (empty($content)) {
            sendJsonResponse(false, '消息内容不能为空');
        }

        if (strlen($content) > $CONFIG['max_size']) {
            sendJsonResponse(false, '消息过长,最多允许' . $CONFIG['max_size'] . '个字符');
        }

        // 处理特殊字符
        $content = htmlspecialchars_decode($content);
        
        // 生成唯一ID
        $id = md5(uniqid(mt_rand(), true));

        // 准备存储数据
        $encryptedContent = encrypt($content, $CONFIG['encrypt_key']);
        $createdAt = time();
        $expireAt = $createdAt + ($expire_hours * 3600);
        $hashedPassword = !empty($password) ? password_hash($password, PASSWORD_DEFAULT) : null;

        // 存储消息到数据库
        $db = getDatabase();
        $stmt = $db->prepare("
            INSERT INTO messages (id, content, password, created_at, expire_at, viewed)
            VALUES (?, ?, ?, ?, ?, 0)
        ");
        
        $stmt->bindValue(1, $id, SQLITE3_TEXT);
        $stmt->bindValue(2, $encryptedContent, SQLITE3_TEXT);
        $stmt->bindValue(3, $hashedPassword, SQLITE3_TEXT);
        $stmt->bindValue(4, $createdAt, SQLITE3_INTEGER);
        $stmt->bindValue(5, $expireAt, SQLITE3_INTEGER);
        
        if (!$stmt->execute()) {
            throw new Exception('无法保存消息到数据库');
        }

        // 生成访问链接
        $url = getCurrentUrl() . '?id=' . $id;

        // 返回成功响应
        sendJsonResponse(true, '安全链接已生成', [
            'url' => $url,
            'expire_time' => date('Y-m-d H:i:s', $expireAt),
            'generation_time' => date('Y-m-d H:i:s', $createdAt)
        ]);
    } catch (Exception $e) {
        error_log('Error: ' . $e->getMessage());
        sendJsonResponse(false, '服务器内部错误: ' . $e->getMessage());
    }
}

// 处理消息查看请求
if (isset($_GET['id'])) {
    handleViewRequest();
    exit;
}

// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    handlePostRequest();
}

// 显示主页面
displayHomePage();

// 处理消息查看请求
function handleViewRequest() {
    global $CONFIG;

    // 安全过滤ID
    $id = preg_replace('/[^a-f0-9]/', '', $_GET['id']);
    if (strlen($id) !== 32) {
        displayError('无效的消息ID');
        return;
    }

    try {
        $db = getDatabase();
        $stmt = $db->prepare("SELECT * FROM messages WHERE id = ? AND viewed = 0");
        $stmt->bindValue(1, $id, SQLITE3_TEXT);
        $result = $stmt->execute();
        $message = $result->fetchArray(SQLITE3_ASSOC);
        
        if (!$message) {
            displayError('消息不存在或已被查看');
            return;
        }

        // 检查是否过期
        if ($message['expire_at'] < time()) {
            // 删除过期消息
            $stmt = $db->prepare("DELETE FROM messages WHERE id = ?");
            $stmt->bindValue(1, $id, SQLITE3_TEXT);
            $stmt->execute();
            
            displayError('消息已过期');
            return;
        }

        // 检查密码
        if (!empty($message['password']) && !isset($_POST['password'])) {
            displayPasswordForm($id);
            return;
        }

        if (!empty($message['password']) && !password_verify($_POST['password'], $message['password'])) {
            displayError('密码错误');
            displayPasswordForm($id);
            return;
        }

        // 解密内容
        $content = decrypt($message['content'], $CONFIG['encrypt_key']);

        // 标记消息为已查看
        $stmt = $db->prepare("UPDATE messages SET viewed = 1 WHERE id = ?");
        $stmt->bindValue(1, $id, SQLITE3_TEXT);
        $stmt->execute();

        // 显示消息
        displayMessage($content);

        // 随机清理旧消息
        cleanupOldMessages();

    } catch (Exception $e) {
        error_log('View message error: ' . $e->getMessage());
        displayError('服务器内部错误');
    }
}

// 显示主页面
function displayHomePage() {
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>阅后即焚</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
        <style>
            .status-dot {
                display: inline-block;
                width: 10px;
                height: 10px;
                border-radius: 50%;
                margin-right: 6px;
            }
            .status-valid { background-color: #10B981; }
            .status-expired { background-color: #EF4444; }
            .toast {
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                padding: 12px 20px;
                border-radius: 4px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 1000;
                animation: fadeInOut 3s forwards;
            }
            .toast-success {
                background-color: #10B981;
                color: white;
            }
            .toast-error {
                background-color: #EF4444;
                color: white;
            }
            @keyframes fadeInOut {
                0% { opacity: 0; transform: translateX(-50%) translateY(-20px); }
                10% { opacity: 1; transform: translateX(-50%) translateY(0); }
                90% { opacity: 1; transform: translateX(-50%) translateY(0); }
                100% { opacity: 0; transform: translateX(-50%) translateY(-20px); }
            }
            .fade-in {
                animation: fadeIn 0.5s;
            }
            @keyframes fadeIn {
                from { opacity: 0; transform: scale(0.95); }
                to { opacity: 1; transform: scale(1); }
            }
            .copied {
                background-color: #bbf7d0 !important;
                transition: background 0.3s;
            }
            .url-display {
                word-break: break-all;
                overflow-wrap: break-word;
                white-space: pre-wrap;
                padding: 8px;
                font-size: 14px;
                line-height: 1.4;
            }
        </style>
    </head>
    <body class="bg-gray-100 min-h-screen font-sans text-gray-800 py-4 px-4 sm:px-6">
        <div class="max-w-md mx-auto">
            <!-- 表单卡片 -->
            <div class="bg-white rounded-lg shadow p-4 mb-4">
                <h1 class="text-lg font-semibold text-center mb-4">阅后即焚</h1>
                <form id="message-form" class="space-y-3">
                    <div>
                        <label class="block text-sm text-gray-700 mb-1">
                            消息内容 <span class="text-red-500">*</span>
                        </label>
                        <textarea 
                            name="content" 
                            id="message_content"
                            class="w-full px-3 py-2 border rounded-md focus:ring-1 focus:ring-green-500 focus:border-green-500"
                            placeholder="输入您要分享的秘密消息"
                            required
                            rows="5"
                        ></textarea>
                        <p class="text-xs text-gray-500 mt-1">最多允许10000个字符</p>
                    </div>
                    <div>
                        <label class="block text-sm text-gray-700 mb-1">
                            过期时间(小时) <span class="text-red-500">*</span>
                        </label>
                        <input 
                            type="number" 
                            name="expire_hours" 
                            id="expire_hours"
                            class="w-full px-3 py-2 border rounded-md focus:ring-1 focus:ring-green-500 focus:border-green-500"
                            value="24"
                            min="1"
                            max="720"
                            required
                        >
                        <p class="text-xs text-gray-500 mt-1">范围:1-720小时(30天)</p>
                    </div>
                    <div>
                        <label class="block text-sm text-gray-700 mb-1">
                            密码保护(可选)
                        </label>
                        <input 
                            type="password" 
                            name="msg_password" 
                            id="msg_password"
                            class="w-full px-3 py-2 border rounded-md focus:ring-1 focus:ring-green-500 focus:border-green-500"
                            placeholder="设置查看密码"
                        >
                    </div>
                    <button 
                        type="submit" 
                        id="submit-btn"
                        class="w-full bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-md flex items-center justify-center transition-colors"
                    >
                        <div id="button-content">
                            生成安全链接
                        </div>
                    </button>
                </form>
            </div>
            <!-- 结果卡片 -->
            <div id="result-card" class="bg-white rounded-lg shadow p-4 hidden">
                <div class="mb-4">
                    <p class="text-xs text-gray-500 text-center mb-1">安全链接</p>
                    <div class="bg-gray-50 p-2 rounded-md">
                        <div 
                            onclick="copyToClipboard(this, '安全链接')"
                            id="message-url"
                            class="font-mono text-center cursor-pointer hover:bg-gray-100 transition-colors url-display"
                        >
                            请先输入消息内容
                        </div>
                    </div>
                    <p class="text-xs text-center mt-1 text-green-500">
                        <span class="status-dot status-valid"></span>
                        有效期至: <span id="expiration-date"></span> UTC+8
                    </p>
                </div>
                <div id="generation-time" class="text-xs text-gray-500 mt-3 text-center">
                    生成于: <span id="generation-time-value"></span> UTC+8
                </div>
            </div>
            <div class="text-center text-gray-500 text-xs mt-4">
                <p>阅后即焚 &copy; <?= date('Y') ?></p>
                <p class="mt-1"><?= $_SERVER['HTTP_HOST']; ?></p>
            </div>
        </div>

        <script>
            // 显示消息提示
            function showToast(message, isSuccess = true) {
                const toast = $('<div>').addClass(`toast ${isSuccess ? 'toast-success' : 'toast-error'}`)
                                      .text(message);
                $('body').append(toast);
                setTimeout(() => { toast.remove(); }, 3000);
            }

            // 复制到剪贴板并高亮
            function copyToClipboard(element, type) {
                const $el = $(element);
                const text = $el.text().trim();
                if (text.includes('请先输入')) return;
                navigator.clipboard.writeText(text).then(() => {
                    showToast(`${type}已复制`);
                    $el.addClass('copied');
                    setTimeout(() => $el.removeClass('copied'), 600);
                }).catch(err => {
                    showToast(`复制失败: ${err}`, false);
                });
            }

            // 处理表单提交
            $('#message-form').on('submit', function(e) {
                e.preventDefault();
                const $form = $(this);
                const $submitBtn = $('#submit-btn');
                // 禁用按钮并显示加载状态
                $submitBtn.prop('disabled', true).addClass('opacity-60 cursor-not-allowed');
                $submitBtn.find('#button-content').html(`
                    <svg class="animate-spin h-5 w-5 mr-2 text-white inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"></path>
                    </svg>处理中...
                `);
                $.ajax({
                    url: '',
                    method: 'POST',
                    data: $form.serialize(),
                    dataType: 'json',
                    beforeSend: function(xhr) {
                        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                    },
                    success: function(data) {
                        // 恢复按钮状态
                        $submitBtn.prop('disabled', false).removeClass('opacity-60 cursor-not-allowed');
                        $submitBtn.find('#button-content').html('生成安全链接');
                        if (data.success) {
                            // 显示结果卡片
                            $('#result-card').removeClass('hidden').addClass('fade-in');
                            setTimeout(() => $('#result-card').removeClass('fade-in'), 600);
                            $('#message-url').text(data.data.url);
                            $('#expiration-date').text(data.data.expire_time);
                            $('#generation-time-value').text(data.data.generation_time);
                            
                            showToast(data.message);
                        } else {
                            showToast(data.message || '操作失败', false);
                        }
                    },
                    error: function(xhr, status, error) {
                        // 恢复按钮状态
                        $submitBtn.prop('disabled', false).removeClass('opacity-60 cursor-not-allowed');
                        $submitBtn.find('#button-content').html('生成安全链接');
                        let errorMsg = '请求失败';
                        try {
                            const response = JSON.parse(xhr.responseText);
                            errorMsg = response.message || errorMsg;
                        } catch (e) {
                            if (xhr.responseText.includes('<!DOCTYPE')) {
                                errorMsg = '服务器返回了错误页面,请检查服务器日志';
                            } else {
                                errorMsg = xhr.responseText || errorMsg;
                            }
                        }
                        showToast(errorMsg, false);
                        console.error('AJAX Error:', status, error, xhr.responseText);
                    }
                });
            });
            
            // 自动聚焦消息内容输入框
            $('#message_content').focus();
        </script>
    </body>
    </html>
    <?php
}

function displayMessage($content) {
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>秘密消息 - 阅后即焚</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
        <style>
            .message-box {
                background-color: #f3f4f6;
                border-radius: 0.375rem;
                padding: 1rem;
                margin-bottom: 1rem;
                min-height: 4rem;
                word-break: break-word;
                white-space: pre-wrap;
                font-family: monospace;
            }
            .toast {
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                padding: 12px 20px;
                border-radius: 4px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 1000;
                animation: fadeInOut 3s forwards;
            }
            .toast-success {
                background-color: #10B981;
                color: white;
            }
            .toast-error {
                background-color: #EF4444;
                color: white;
            }
        </style>
    </head>
    <body class="bg-gray-100 min-h-screen font-sans text-gray-800 py-4 px-4 sm:px-6">
        <div class="max-w-md mx-auto">
            <div class="bg-white rounded-lg shadow p-4 mb-4">
                <h1 class="text-lg font-semibold text-center mb-4">秘密消息</h1>
                <div id="message-content" class="message-box"><?= htmlspecialchars($content) ?></div>
                <button 
                    onclick="copyMessage()"
                    class="w-full bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-md transition-colors"
                >
                    复制内容
                </button>
                <div class="mt-4 text-center text-sm text-red-500">
                    <span class="inline-block w-2 h-2 rounded-full bg-red-500 mr-1"></span>
                    此消息已被销毁,刷新页面将无法再次查看
                </div>
            </div>
        </div>

        <script>
            function showToast(message, isSuccess = true) {
                const toast = $('<div>').addClass(`toast ${isSuccess ? 'toast-success' : 'toast-error'}`)
                                      .text(message);
                $('body').append(toast);
                setTimeout(() => { toast.remove(); }, 3000);
            }

            function copyMessage() {
                const content = $('#message-content').text();
                navigator.clipboard.writeText(content).then(() => {
                    showToast('内容已复制');
                }).catch(err => {
                    showToast('复制失败: ' + err, false);
                });
            }
        </script>
    </body>
    </html>
    <?php
}

// 显示错误页面
function displayError($message) {
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>错误 - 阅后即焚</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
    </head>
    <body class="bg-gray-100 min-h-screen font-sans text-gray-800 py-4 px-4 sm:px-6">
        <div class="max-w-md mx-auto">
            <div class="bg-white rounded-lg shadow p-4 mb-4">
                <h1 class="text-lg font-semibold text-center mb-4">错误</h1>
                <div class="bg-red-50 text-red-700 p-4 rounded-md mb-4">
                    <?= htmlspecialchars($message) ?>
                </div>
                <a 
                    href="<?= htmlspecialchars(getCurrentUrl()) ?>" 
                    class="w-full block bg-gray-500 hover:bg-gray-600 text-white py-2 px-4 rounded-md text-center transition-colors"
                >
                    返回
                </a>
            </div>
            <div class="text-center text-gray-500 text-xs mt-4">
                <p>阅后即焚 &copy; <?= date('Y') ?></p>
                <p class="mt-1"><?= $_SERVER['HTTP_HOST']; ?></p>
            </div>
        </div>
    </body>
    </html>
    <?php
}

// 显示密码表单
function displayPasswordForm($id) {
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>需要密码 - 阅后即焚</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
    </head>
    <body class="bg-gray-100 min-h-screen font-sans text-gray-800 py-4 px-4 sm:px-6">
        <div class="max-w-md mx-auto">
            <div class="bg-white rounded-lg shadow p-4 mb-4">
                <h1 class="text-lg font-semibold text-center mb-4">需要密码</h1>
                <div class="bg-blue-50 text-blue-700 p-4 rounded-md mb-4">
                    此消息受密码保护,请输入密码查看
                </div>
                <form method="POST" action="?id=<?= htmlspecialchars($id) ?>" class="space-y-3">
                    <div>
                        <label class="block text-sm text-gray-700 mb-1">
                            密码 <span class="text-red-500">*</span>
                        </label>
                        <input 
                            type="password" 
                            name="password" 
                            class="w-full px-3 py-2 border rounded-md focus:ring-1 focus:ring-green-500 focus:border-green-500"
                            required
                        >
                    </div>
                    
                    <button 
                        type="submit" 
                        class="w-full bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-md transition-colors"
                    >
                        查看消息
                    </button>
                </form>
            </div>
            <div class="text-center text-gray-500 text-xs mt-4">
                <p>阅后即焚 &copy; <?= date('Y') ?></p>
                <p class="mt-1"><?= $_SERVER['HTTP_HOST']; ?></p>
            </div>
        </div>
    </body>
    </html>
    <?php
}

// 处理表单提交(非AJAX)
function handlePostRequest() {
    global $CONFIG;
    
    $content = trim($_POST['content'] ?? '');
    $password = trim($_POST['msg_password'] ?? '');
    $expire_hours = max(1, min(720, intval($_POST['expire_hours'] ?? 24)));
    
    if (empty($content)) {
        displayError('消息内容不能为空');
        return;
    }
    
    if (strlen($content) > $CONFIG['max_size']) {
        displayError('消息过长,最多允许' . $CONFIG['max_size'] . '个字符');
        return;
    }
    
    try {
        // 生成唯一ID
        $id = md5(uniqid(mt_rand(), true));
        
        // 准备存储数据
        $encryptedContent = encrypt($content, $CONFIG['encrypt_key']);
        $createdAt = time();
        $expireAt = $createdAt + ($expire_hours * 3600);
        $hashedPassword = !empty($password) ? password_hash($password, PASSWORD_DEFAULT) : null;

        // 存储消息到数据库
        $db = getDatabase();
        $stmt = $db->prepare("
            INSERT INTO messages (id, content, password, created_at, expire_at, viewed)
            VALUES (?, ?, ?, ?, ?, 0)
        ");
        
        $stmt->bindValue(1, $id, SQLITE3_TEXT);
        $stmt->bindValue(2, $encryptedContent, SQLITE3_TEXT);
        $stmt->bindValue(3, $hashedPassword, SQLITE3_TEXT);
        $stmt->bindValue(4, $createdAt, SQLITE3_INTEGER);
        $stmt->bindValue(5, $expireAt, SQLITE3_INTEGER);
        
        if (!$stmt->execute()) {
            throw new Exception('无法保存消息到数据库');
        }

        // 生成访问链接
        $url = getCurrentUrl() . '?id=' . $id;
        
        // 显示成功页面
        displaySuccess($url, $expire_hours);
        
    } catch (Exception $e) {
        error_log('Post request error: ' . $e->getMessage());
        displayError('服务器内部错误');
    }
}

// 显示成功页面
function displaySuccess($url, $expire_hours) {
    $_SESSION['result'] = [
        'status' => 'success',
        'message' => '安全链接已生成',
        'url' => $url,
        'expire_time' => date('Y-m-d H:i:s', time() + ($expire_hours * 3600)),
        'generation_time' => date('Y-m-d H:i:s')
    ];
    header('Location: ' . getCurrentUrl());
    exit;
}
10 Likes

怎么没有演示!

1 Like

自己测试:joy:

谢谢分享!

3 Likes

感谢分享。
NL有你更精彩。

1 Like

谢谢大佬分享

1 Like

这能部署到CF嘛

1 Like

谢谢分享1 :xhj10:
NL有你更精彩。

1 Like

Cloudflare Pages听说可以支持PHP

感谢分享!

1 Like

感谢分享 :+1:

1 Like

谢佬分享 放虚拟主机看下

1 Like