最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用PHP與Apache實(shí)現(xiàn)服務(wù)器端文件管理的完整方案

 更新時間:2025年08月08日 09:58:17   作者:ttod_qzstudio  
作為前端開發(fā)者,你可能經(jīng)常需要與服務(wù)器文件系統(tǒng)交互,本文將詳細(xì)介紹如何通過PHP配合Apache實(shí)現(xiàn)服務(wù)器端文件管理功能,即使你沒有任何PHP經(jīng)驗(yàn),也能按照本教程實(shí)現(xiàn)完整解決方案,需要的朋友可以參考下

引言

作為前端開發(fā)者,你可能經(jīng)常需要與服務(wù)器文件系統(tǒng)交互。本文將詳細(xì)介紹如何通過PHP配合Apache實(shí)現(xiàn)服務(wù)器端文件管理功能。即使你沒有任何PHP經(jīng)驗(yàn),也能按照本教程實(shí)現(xiàn)完整解決方案!

系統(tǒng)準(zhǔn)備

PHP下載與安裝

訪問PHP官網(wǎng)下載頁面

選擇與Apache匹配的版本:

  • Apache版本:2.4.x
  • PHP版本:8.4.x TS (Thread Safe)(對應(yīng)64位Apache的文件名應(yīng)該類似:VS17 x64 Thread Safe,對應(yīng)32位Apache的文件名應(yīng)該類似:VS17 x86 Thread Safe)
  • 架構(gòu):x64(64位系統(tǒng))或x86(32位系統(tǒng))

解壓到目錄(如D:\php),目錄結(jié)構(gòu)應(yīng)包含:

php.exe
php8apache2_4.dll
php.ini-development
ext/ (擴(kuò)展目錄)

Apache配置PHP

編輯conf/httpd.conf文件:

# 加載PHP模塊
LoadModule php_module "D:/php/php8apache2_4.dll"

# 指定php.ini目錄
PHPIniDir "D:/php"

# 將.php文件交給PHP處理
AddHandler application/x-httpd-php .php

# 關(guān)聯(lián)文件擴(kuò)展名
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

驗(yàn)證配置

cd D:\Apache24\bin
httpd -t

看到"Syntax OK"表示配置正確,重啟Apache服務(wù):

httpd -k restart

文件管理API實(shí)現(xiàn)

創(chuàng)建file_manager.php文件:

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // 測試用,生產(chǎn)環(huán)境應(yīng)移除

// 安全配置
$BASE_DIR = realpath(__DIR__ . '/Resources');
$ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt', 'docx'];

// 路徑驗(yàn)證函數(shù)
function validatePath($path) {
    global $BASE_DIR;
    $realPath = realpath($BASE_DIR . '/' . $path);
    
    return ($realPath && strpos($realPath, $BASE_DIR) === 0) 
        ? $realPath : false;
}

// 獲取目錄結(jié)構(gòu)
function listDirectory($path) {
    $realPath = validatePath($path);
    if (!$realPath || !is_dir($realPath)) {
        return ['error' => '無效目錄路徑'];
    }

    $result = [];
    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($realPath, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($items as $item) {
        $relativePath = substr($item->getPathname(), strlen($realPath)) ?: '/';
        $relativePath = ltrim(str_replace('\\', '/', $relativePath), '/');
        
        $result[] = [
            'name' => $item->getFilename(),
            'path' => $relativePath,
            'type' => $item->isDir() ? 'directory' : 'file',
            'size' => $item->isFile() ? $item->getSize() : 0,
            'modified' => date('Y-m-d H:i:s', $item->getMTime())
        ];
    }

    return $result;
}

// 主請求處理
$response = ['status' => 'error', 'message' => '無效請求'];
$request = json_decode(file_get_contents('php://input'), true) ?? $_REQUEST;

try {
    if (!isset($request['action'])) {
        throw new Exception('未指定操作');
    }

    $action = $request['action'];
    
    switch ($action) {
        case 'list':
            $path = $request['path'] ?? '';
            $data = listDirectory($path);
            $response = ['status' => 'success', 'data' => $data];
            break;
            
        case 'create-folder':
            $path = $request['path'] ?? '';
            $name = $request['name'] ?? '';
            
            if (empty($name)) throw new Exception('文件夾名稱不能為空');
            
            $realPath = validatePath($path);
            if (!$realPath) throw new Exception('無效路徑');
            
            // 清理文件夾名稱
            $cleanName = preg_replace('/[^a-zA-Z0-9_-]/', '', $name);
            $newFolder = $realPath . DIRECTORY_SEPARATOR . $cleanName;
            
            if (file_exists($newFolder)) {
                throw new Exception('文件夾已存在');
            }
            
            if (!mkdir($newFolder, 0755)) {
                throw new Exception('創(chuàng)建文件夾失敗');
            }
            
            $response = ['status' => 'success', 'message' => '文件夾創(chuàng)建成功'];
            break;
            
        case 'delete-folder':
            $path = $request['path'] ?? '';
            $realPath = validatePath($path);
            
            if (!$realPath || !is_dir($realPath)) {
                throw new Exception('無效目錄路徑');
            }
            
            // 安全措施:防止刪除根目錄
            if ($realPath === $BASE_DIR) {
                throw new Exception('不能刪除根目錄');
            }
            
            // 遞歸刪除
            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($realPath, FilesystemIterator::SKIP_DOTS),
                RecursiveIteratorIterator::CHILD_FIRST
            );
            
            foreach ($files as $file) {
                if ($file->isDir()) {
                    rmdir($file->getRealPath());
                } else {
                    unlink($file->getRealPath());
                }
            }
            
            if (!rmdir($realPath)) {
                throw new Exception('刪除文件夾失敗');
            }
            
            $response = ['status' => 'success', 'message' => '文件夾已刪除'];
            break;
            
        case 'rename':
            $type = $request['type'] ?? 'file';
            $path = $request['path'] ?? '';
            $newName = $request['newName'] ?? '';
            
            if (empty($newName)) throw new Exception('新名稱不能為空');
            
            $realPath = validatePath($path);
            if (!$realPath) throw new Exception('無效路徑');
            
            // 清理新名稱
            $cleanName = preg_replace('/[^a-zA-Z0-9_.-]/', '', $newName);
            $newPath = dirname($realPath) . DIRECTORY_SEPARATOR . $cleanName;
            
            if (file_exists($newPath)) {
                throw new Exception('目標(biāo)名稱已存在');
            }
            
            if (!rename($realPath, $newPath)) {
                throw new Exception('重命名失敗');
            }
            
            $response = ['status' => 'success', 'message' => '重命名成功'];
            break;
            
        case 'upload-file':
            $targetPath = $request['path'] ?? '';
            $realPath = validatePath($targetPath);
            
            if (!$realPath || !is_dir($realPath)) {
                throw new Exception('無效目標(biāo)目錄');
            }
            
            if (empty($_FILES['file'])) {
                throw new Exception('未選擇上傳文件');
            }
            
            $file = $_FILES['file'];
            $filename = preg_replace('/[^a-zA-Z0-9_.-]/', '', basename($file['name']));
            $targetFile = $realPath . DIRECTORY_SEPARATOR . $filename;
            $ext = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
            
            // 文件類型驗(yàn)證
            if (!in_array($ext, $ALLOWED_EXTENSIONS)) {
                throw new Exception('不允許的文件類型: ' . $ext);
            }
            
            // 防止文件覆蓋
            if (file_exists($targetFile)) {
                $filename = time() . '_' . $filename;
                $targetFile = $realPath . DIRECTORY_SEPARATOR . $filename;
            }
            
            if (!move_uploaded_file($file['tmp_name'], $targetFile)) {
                throw new Exception('文件上傳失敗');
            }
            
            $response = ['status' => 'success', 'filename' => $filename, 'message' => '文件上傳成功'];
            break;
            
        case 'delete-file':
            $path = $request['path'] ?? '';
            $realPath = validatePath($path);
            
            if (!$realPath || !is_file($realPath)) {
                throw new Exception('無效文件路徑');
            }
            
            if (!unlink($realPath)) {
                throw new Exception('文件刪除失敗');
            }
            
            $response = ['status' => 'success', 'message' => '文件已刪除'];
            break;
            
        default:
            throw new Exception('未知操作: ' . $action);
    }
    
} catch (Exception $e) {
    $response = ['status' => 'error', 'message' => $e->getMessage()];
}

echo json_encode($response);
?>

測試頁面

創(chuàng)建file_manager_test.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件管理器測試</title>
    <style>
        :root {
            --primary: #3498db;
            --success: #2ecc71;
            --danger: #e74c3c;
            --dark: #34495e;
            --light: #f8f9fa;
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 10px;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
            padding: 30px;
        }
        
        header {
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 1px solid #eee;
        }
        
        h1 {
            color: var(--dark);
            margin-bottom: 10px;
        }
        
        .subtitle {
            color: #7f8c8d;
            font-weight: 400;
        }
        
        .section {
            margin-bottom: 30px;
            padding: 25px;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            background: var(--light);
            transition: all 0.3s ease;
        }
        
        .section:hover {
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
            border-color: #d1d9e0;
        }
        
        .section h2 {
            color: var(--dark);
            margin-top: 0;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px dashed #ddd;
            display: flex;
            align-items: center;
        }
        
        .section h2 i {
            margin-right: 10px;
            color: var(--primary);
        }
        
        .form-group {
            margin-bottom: 20px;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
        }
        
        label {
            display: inline-block;
            width: 150px;
            font-weight: 600;
            color: #555;
        }
        
        input[type="text"],
        input[type="file"] {
            width: calc(100% - 160px);
            padding: 12px 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
            transition: border 0.3s;
        }
        
        input[type="text"]:focus,
        input[type="file"]:focus {
            border-color: var(--primary);
            outline: none;
            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
        }
        
        button {
            padding: 12px 25px;
            background: var(--primary);
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: all 0.3s;
            margin-top: 10px;
        }
        
        button:hover {
            background: #2980b9;
            transform: translateY(-2px);
        }
        
        .delete-btn {
            background: var(--danger);
        }
        
        .delete-btn:hover {
            background: #c0392b;
        }
        
        .radio-group {
            display: flex;
            gap: 20px;
            margin-left: 150px;
            width: calc(100% - 150px);
        }
        
        .radio-group label {
            width: auto;
            display: flex;
            align-items: center;
            gap: 5px;
            font-weight: normal;
        }
        
        .response {
            margin-top: 20px;
            padding: 15px;
            border-radius: 4px;
            display: none;
        }
        
        .success {
            background-color: rgba(46, 204, 113, 0.1);
            border: 1px solid var(--success);
            color: #27ae60;
            display: block;
        }
        
        .error {
            background-color: rgba(231, 76, 60, 0.1);
            border: 1px solid var(--danger);
            color: #c0392b;
            display: block;
        }
        
        pre {
            background: #2d2d2d;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 4px;
            max-height: 400px;
            overflow: auto;
            margin-top: 15px;
            font-family: 'Consolas', monospace;
        }
        
        @media (max-width: 768px) {
            .form-group {
                flex-direction: column;
                align-items: flex-start;
            }
            
            label {
                width: 100%;
                margin-bottom: 8px;
            }
            
            input[type="text"],
            input[type="file"] {
                width: 100%;
            }
            
            .radio-group {
                margin-left: 0;
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>服務(wù)器文件管理器測試</h1>
            <p class="subtitle">通過PHP與Apache實(shí)現(xiàn)安全的服務(wù)器端文件操作</p>
        </header>
        
        <!-- 列出目錄內(nèi)容 -->
        <div class="section">
            <h2><i class="fas fa-folder-open"></i> 列出目錄內(nèi)容</h2>
            <div class="form-group">
                <label for="listPath">目錄路徑:</label>
                <input type="text" id="listPath" placeholder="例如: docs/images (留空顯示根目錄)">
            </div>
            <button onclick="listDirectory()">列出目錄</button>
            <div class="response">
                <pre id="listResult">目錄內(nèi)容將顯示在這里...</pre>
            </div>
        </div>
        
        <!-- 創(chuàng)建文件夾 -->
        <div class="section">
            <h2><i class="fas fa-folder-plus"></i> 創(chuàng)建文件夾</h2>
            <div class="form-group">
                <label for="createPath">父目錄路徑:</label>
                <input type="text" id="createPath" placeholder="例如: docs">
            </div>
            <div class="form-group">
                <label for="folderName">文件夾名稱:</label>
                <input type="text" id="folderName" placeholder="例如: new_folder">
            </div>
            <button onclick="createFolder()">創(chuàng)建文件夾</button>
            <div class="response" id="createResponse"></div>
        </div>
        
        <!-- 刪除文件夾 -->
        <div class="section">
            <h2><i class="fas fa-trash-alt"></i> 刪除文件夾</h2>
            <div class="form-group">
                <label for="deleteFolderPath">文件夾路徑:</label>
                <input type="text" id="deleteFolderPath" placeholder="例如: docs/old_folder">
            </div>
            <button class="delete-btn" onclick="deleteFolder()">刪除文件夾</button>
            <div class="response" id="deleteFolderResponse"></div>
        </div>
        
        <!-- 重命名文件/文件夾 -->
        <div class="section">
            <h2><i class="fas fa-i-cursor"></i> 重命名項(xiàng)目</h2>
            <div class="form-group">
                <label for="renamePath">當(dāng)前路徑:</label>
                <input type="text" id="renamePath" placeholder="例如: docs/image.jpg">
            </div>
            <div class="form-group">
                <label for="newName">新名稱:</label>
                <input type="text" id="newName" placeholder="例如: new_image.jpg">
            </div>
            <div class="form-group">
                <label>類型:</label>
                <div class="radio-group">
                    <label><input type="radio" name="renameType" value="file" checked> 文件</label>
                    <label><input type="radio" name="renameType" value="folder"> 文件夾</label>
                </div>
            </div>
            <button onclick="renameItem()">重命名</button>
            <div class="response" id="renameResponse"></div>
        </div>
        
        <!-- 上傳文件 -->
        <div class="section">
            <h2><i class="fas fa-upload"></i> 上傳文件</h2>
            <div class="form-group">
                <label for="uploadPath">目標(biāo)目錄:</label>
                <input type="text" id="uploadPath" placeholder="例如: docs/uploads">
            </div>
            <div class="form-group">
                <label for="fileInput">選擇文件:</label>
                <input type="file" id="fileInput">
            </div>
            <button onclick="uploadFile()">上傳文件</button>
            <div class="response" id="uploadResponse"></div>
        </div>
        
        <!-- 刪除文件 -->
        <div class="section">
            <h2><i class="fas fa-trash-alt"></i> 刪除文件</h2>
            <div class="form-group">
                <label for="deleteFilePath">文件路徑:</label>
                <input type="text" id="deleteFilePath" placeholder="例如: docs/file.txt">
            </div>
            <button class="delete-btn" onclick="deleteFile()">刪除文件</button>
            <div class="response" id="deleteFileResponse"></div>
        </div>
    </div>

    <!-- Font Awesome 圖標(biāo) -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js"></script>
    
    <script>
        const API_URL = 'file_manager.php';
        
        // 顯示響應(yīng)消息
        function showResponse(element, message, isSuccess = true) {
            element.textContent = message;
            element.className = 'response ' + (isSuccess ? 'success' : 'error');
            element.style.display = 'block';
            
            // 3秒后淡出
            setTimeout(() => {
                element.style.opacity = '1';
                let opacity = 1;
                const fadeOut = setInterval(() => {
                    opacity -= 0.05;
                    element.style.opacity = opacity;
                    if (opacity <= 0) {
                        clearInterval(fadeOut);
                        element.style.display = 'none';
                    }
                }, 50);
            }, 3000);
        }
        
        // 調(diào)用API
        async function callApi(data, files) {
            const formData = new FormData();
            
            // 添加表單數(shù)據(jù)
            for (const key in data) {
                formData.append(key, data[key]);
            }
            
            // 添加文件
            if (files) {
                for (const file of files) {
                    formData.append('file', file);
                }
            }
            
            try {
                const response = await fetch(API_URL, {
                    method: 'POST',
                    body: formData
                });
                
                return await response.json();
            } catch (error) {
                return {
                    status: 'error',
                    message: '網(wǎng)絡(luò)錯誤: ' + error.message
                };
            }
        }
        
        // 列出目錄內(nèi)容
        async function listDirectory() {
            const path = document.getElementById('listPath').value || '';
            const result = document.getElementById('listResult');
            
            result.textContent = '加載中...';
            
            const response = await callApi({
                action: 'list',
                path: path
            });
            
            if (response.status === 'success') {
                result.textContent = JSON.stringify(response.data, null, 2);
            } else {
                result.textContent = '錯誤: ' + response.message;
            }
        }
        
        // 創(chuàng)建文件夾
        async function createFolder() {
            const path = document.getElementById('createPath').value || '';
            const name = document.getElementById('folderName').value;
            const responseEl = document.getElementById('createResponse');
            
            if (!name) {
                showResponse(responseEl, '文件夾名稱不能為空', false);
                return;
            }
            
            const response = await callApi({
                action: 'create-folder',
                path: path,
                name: name
            });
            
            showResponse(
                responseEl, 
                response.status === 'success' 
                    ? '? ' + response.message 
                    : '? 錯誤: ' + response.message,
                response.status === 'success'
            );
        }
        
        // 刪除文件夾
        async function deleteFolder() {
            const path = document.getElementById('deleteFolderPath').value;
            const responseEl = document.getElementById('deleteFolderResponse');
            
            if (!path) {
                showResponse(responseEl, '文件夾路徑不能為空', false);
                return;
            }
            
            if (!confirm(`確定要刪除文件夾 "${path}" 及其所有內(nèi)容嗎?`)) {
                return;
            }
            
            const response = await callApi({
                action: 'delete-folder',
                path: path
            });
            
            showResponse(
                responseEl, 
                response.status === 'success' 
                    ? '? ' + response.message 
                    : '? 錯誤: ' + response.message,
                response.status === 'success'
            );
        }
        
        // 重命名項(xiàng)目
        async function renameItem() {
            const path = document.getElementById('renamePath').value;
            const newName = document.getElementById('newName').value;
            const type = document.querySelector('input[name="renameType"]:checked').value;
            const responseEl = document.getElementById('renameResponse');
            
            if (!path || !newName) {
                showResponse(responseEl, '路徑和新名稱不能為空', false);
                return;
            }
            
            const response = await callApi({
                action: 'rename',
                path: path,
                newName: newName,
                type: type
            });
            
            showResponse(
                responseEl, 
                response.status === 'success' 
                    ? '? ' + response.message 
                    : '? 錯誤: ' + response.message,
                response.status === 'success'
            );
        }
        
        // 上傳文件
        async function uploadFile() {
            const path = document.getElementById('uploadPath').value || '';
            const fileInput = document.getElementById('fileInput');
            const responseEl = document.getElementById('uploadResponse');
            
            if (!fileInput.files || fileInput.files.length === 0) {
                showResponse(responseEl, '請選擇要上傳的文件', false);
                return;
            }
            
            const response = await callApi({
                action: 'upload-file',
                path: path
            }, [fileInput.files[0]]);
            
            showResponse(
                responseEl, 
                response.status === 'success' 
                    ? `? ${response.message} - 文件名: ${response.filename}` 
                    : '? 錯誤: ' + response.message,
                response.status === 'success'
            );
        }
        
        // 刪除文件
        async function deleteFile() {
            const path = document.getElementById('deleteFilePath').value;
            const responseEl = document.getElementById('deleteFileResponse');
            
            if (!path) {
                showResponse(responseEl, '文件路徑不能為空', false);
                return;
            }
            
            if (!confirm(`確定要刪除文件 "${path}" 嗎?`)) {
                return;
            }
            
            const response = await callApi({
                action: 'delete-file',
                path: path
            });
            
            showResponse(
                responseEl, 
                response.status === 'success' 
                    ? '? ' + response.message 
                    : '? 錯誤: ' + response.message,
                response.status === 'success'
            );
        }
    </script>
</body>
</html>

關(guān)鍵注意事項(xiàng)

安全配置

  • 生產(chǎn)環(huán)境中移除Access-Control-Allow-Origin: *
  • 添加身份驗(yàn)證(如Basic Auth或API密鑰)
  • 限制允許的文件擴(kuò)展名
  • 設(shè)置文件上傳大小限制(在php.ini中配置)

權(quán)限設(shè)置

  • Windows:為Resources目錄添加Apache用戶(如SYSTEM)的完全控制權(quán)限

  • Linux:chown -R www-data:www-data Resources && chmod -R 755 Resources

路徑說明

  • 列出Resources根目錄:輸入框留空
  • 列出子目錄:直接輸入子目錄名(如uploads
  • 不要使用前導(dǎo)斜杠(如/uploads

測試流程

創(chuàng)建Resources目錄并設(shè)置權(quán)限

上傳file_manager.phpfile_manager_test.html到Apache文檔根目錄

訪問http://localhost/file_manager_test.html

測試各項(xiàng)功能:

  • 列出目錄(留空)
  • 創(chuàng)建測試文件夾
  • 上傳文件
  • 重命名/刪除操作

補(bǔ)充:

由于前面的php提供的目錄樹形式過于扁平,這里提供一個返回樹形結(jié)構(gòu)的目錄的json的php文件。如果要基于這個php文件進(jìn)行測試,在測試文件file-manager-test.html里面 action:'list'的地方改成action:'get-tree'就可以了。

改進(jìn)后的file_manager.php:

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

// 配置安全選項(xiàng)
$BASE_DIR = realpath(__DIR__ . '/Resources');
$ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'glb', 'gltf', 'fbx', 'obj', 'txt', 'md'];

// 遞歸獲取目錄結(jié)構(gòu)
function getDirectoryTree($path) {
    $realPath = realpath($path);
    if (!$realPath || !is_dir($realPath)) {
        return null;
    }

    $result = [
        'name' => basename($realPath),
        'path' => str_replace($GLOBALS['BASE_DIR'], '', $realPath) ?: '/',
        'type' => 'directory',
        'children' => []
    ];

    $items = scandir($realPath);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') continue;
        
        $itemPath = $realPath . DIRECTORY_SEPARATOR . $item;
        if (is_dir($itemPath)) {
            $result['children'][] = getDirectoryTree($itemPath);
        } else {
            $ext = strtolower(pathinfo($itemPath, PATHINFO_EXTENSION));
            $result['children'][] = [
                'name' => $item,
                'path' => str_replace($GLOBALS['BASE_DIR'], '', $itemPath),
                'type' => 'file',
                'size' => filesize($itemPath),
                'modified' => filemtime($itemPath),
                'extension' => $ext
            ];
        }
    }

    return $result;
}

// 處理請求
$response = ['status' => 'error', 'message' => 'Invalid request'];
$request = json_decode(file_get_contents('php://input'), true) ?? $_REQUEST;

try {
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        exit(0);
    }

    if (!isset($request['action'])) {
        throw new Exception('No action specified');
    }

    $action = $request['action'];
    
    switch ($action) {
        case 'get-tree':
            $tree = getDirectoryTree($BASE_DIR);
            if ($tree) {
                $response = ['status' => 'success', 'data' => $tree];
            } else {
                throw new Exception('Failed to load directory tree');
            }
            break;
            
        case 'get-files':
            $path = $request['path'] ?? '/';
            $realPath = realpath($BASE_DIR . $path);
            
            if (!$realPath || !is_dir($realPath)) {
                throw new Exception('Invalid directory path');
            }
            
            $files = [];
            $items = scandir($realPath);
            foreach ($items as $item) {
                if ($item === '.' || $item === '..') continue;
                
                $itemPath = $realPath . DIRECTORY_SEPARATOR . $item;
                if (!is_dir($itemPath)) {
                    $ext = strtolower(pathinfo($itemPath, PATHINFO_EXTENSION));
                    $files[] = [
                        'name' => $item,
                        'path' => $path . '/' . $item,
                        'type' => 'file',
                        'size' => filesize($itemPath),
                        'modified' => filemtime($itemPath),
                        'extension' => $ext
                    ];
                }
            }
            
            $response = ['status' => 'success', 'files' => $files];
            break;
            
        case 'create-folder':
            $path = $request['path'] ?? '';
            $name = $request['name'] ?? '';
            
            if (empty($name)) throw new Exception('Folder name is required');
            
            $realPath = validatePath($path);
            if (!$realPath) throw new Exception('Invalid path');
            
            $newFolder = $realPath . DIRECTORY_SEPARATOR . preg_replace('/[^a-zA-Z0-9_-]/', '', $name);
            
            if (file_exists($newFolder)) {
                throw new Exception('Folder already exists');
            }
            
            if (!mkdir($newFolder)) {
                throw new Exception('Failed to create folder');
            }
            
            $response = ['status' => 'success', 'message' => 'Folder created'];
            break;
            
        case 'delete-folder':
            $path = $request['path'] ?? '';
            $realPath = validatePath($path);
            
            if (!$realPath || !is_dir($realPath)) {
                throw new Exception('Invalid directory path');
            }
            
            // 安全措施:防止刪除根目錄
            if ($realPath === $BASE_DIR) {
                throw new Exception('Cannot delete base directory');
            }
            
            // 遞歸刪除目錄
            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($realPath, FilesystemIterator::SKIP_DOTS),
                RecursiveIteratorIterator::CHILD_FIRST
            );
            
            foreach ($files as $file) {
                if ($file->isDir()) {
                    rmdir($file->getRealPath());
                } else {
                    unlink($file->getRealPath());
                }
            }
            
            if (!rmdir($realPath)) {
                throw new Exception('Failed to delete folder');
            }
            
            $response = ['status' => 'success', 'message' => 'Folder deleted'];
            break;
            
        case 'rename':
            $type = $request['type'] ?? ''; // 'file' or 'folder'
            $path = $request['path'] ?? '';
            $newName = $request['newName'] ?? '';
            
            if (empty($newName)) throw new Exception('New name is required');
            
            $realPath = validatePath($path);
            if (!$realPath) throw new Exception('Invalid path');
            
            $newPath = dirname($realPath) . DIRECTORY_SEPARATOR . preg_replace('/[^a-zA-Z0-9_.-]/', '', $newName);
            
            if (file_exists($newPath)) {
                throw new Exception('Target name already exists');
            }
            
            if (!rename($realPath, $newPath)) {
                throw new Exception('Rename failed');
            }
            
            $response = ['status' => 'success', 'message' => 'Renamed successfully'];
            break;
            
        case 'upload-file':
            $targetPath = $request['path'] ?? '';
            $realPath = validatePath($targetPath);
            
            if (!$realPath || !is_dir($realPath)) {
                throw new Exception('Invalid target directory');
            }
            
            if (empty($_FILES['file'])) {
                throw new Exception('No file uploaded');
            }
            
            $file = $_FILES['file'];
            $filename = preg_replace('/[^a-zA-Z0-9_.-]/', '', basename($file['name']));
            $targetFile = $realPath . DIRECTORY_SEPARATOR . $filename;
            $ext = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
            
            // 驗(yàn)證文件類型
            if (!in_array($ext, $ALLOWED_EXTENSIONS)) {
                throw new Exception('File type not allowed');
            }
            
            // 防止覆蓋現(xiàn)有文件
            if (file_exists($targetFile)) {
                $filename = time() . '_' . $filename;
                $targetFile = $realPath . DIRECTORY_SEPARATOR . $filename;
            }
            
            if (!move_uploaded_file($file['tmp_name'], $targetFile)) {
                throw new Exception('File upload failed');
            }
            
            $response = ['status' => 'success', 'filename' => $filename, 'message' => 'File uploaded'];
            break;
            
        case 'delete-file':
            $path = $request['path'] ?? '';
            $realPath = validatePath($path);
            
            if (!$realPath || !is_file($realPath)) {
                throw new Exception('Invalid file path');
            }
            
            if (!unlink($realPath)) {
                throw new Exception('File deletion failed');
            }
            
            $response = ['status' => 'success', 'message' => 'File deleted'];
            break;
            
        default:
            throw new Exception('Unknown action');
    }
    
} catch (Exception $e) {
    $response = ['status' => 'error', 'message' => $e->getMessage()];
}

echo json_encode($response);
?>

以上就是使用PHP與Apache實(shí)現(xiàn)服務(wù)器端文件管理的完整方案的詳細(xì)內(nèi)容,更多關(guān)于PHP Apache服務(wù)器端文件管理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • PHP獲取表單數(shù)據(jù)與HTML嵌入PHP腳本的實(shí)現(xiàn)

    PHP獲取表單數(shù)據(jù)與HTML嵌入PHP腳本的實(shí)現(xiàn)

    下面小編就為大家?guī)硪黄狿HP獲取表單數(shù)據(jù)與HTML嵌入PHP腳本的實(shí)現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 最新評論

    泽普县| 张家川| 鹤岗市| 遂宁市| 伽师县| 平湖市| 会泽县| 陆河县| 寿阳县| 永兴县| 隆子县| 西华县| 竹北市| 乌拉特前旗| 渭南市| 崇阳县| 九龙坡区| 平罗县| 阿拉善左旗| 宣汉县| 垫江县| 沙坪坝区| 炉霍县| 岳阳县| 泗水县| 静安区| 双辽市| 乌苏市| 灯塔市| 青龙| 锡林浩特市| 凤冈县| 淮阳县| 镇巴县| 耒阳市| 汾阳市| 碌曲县| 安龙县| 巢湖市| 新和县| 长汀县|