本文目录导读:

我将为您设计一个PHP项目文件管理与预览系统,这个系统将包含文件浏览、上传、删除、预览等功能,并支持多种文件类型的预览。
完整文件管理预览系统
目录结构
file-manager/
├── index.php # 主入口
├── config.php # 配置文件
├── functions.php # 功能函数
├── css/
│ └── style.css # 样式文件
├── js/
│ └── main.js # JavaScript文件
└── uploads/ # 上传目录
配置文件 (config.php)
<?php
// 配置文件
define('BASE_PATH', __DIR__);
define('UPLOAD_DIR', BASE_PATH . '/uploads/');
define('MAX_FILE_SIZE', 50 * 1024 * 1024); // 50MB
// 允许的文件类型
$allowed_types = [
'image' => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'],
'document' => ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'],
'video' => ['mp4', 'avi', 'mov', 'wmv', 'flv'],
'audio' => ['mp3', 'wav', 'ogg', 'flac'],
'archive' => ['zip', 'rar', 'tar', 'gz', '7z'],
'code' => ['php', 'html', 'css', 'js', 'json', 'xml']
];
// 获取所有允许的文件类型
$all_extensions = [];
foreach ($allowed_types as $type => $extensions) {
$all_extensions = array_merge($all_extensions, $extensions);
}
// 文件图标映射
$file_icons = [
'image' => '🖼️',
'document' => '📄',
'video' => '🎬',
'audio' => '🎵',
'archive' => '📦',
'code' => '💻',
'default' => '📁'
];
功能函数 (functions.php)
<?php
require_once 'config.php';
// 获取文件类型分组
function getFileType($extension) {
global $allowed_types;
foreach ($allowed_types as $type => $extensions) {
if (in_array(strtolower($extension), $extensions)) {
return $type;
}
}
return 'default';
}
// 获取文件图标
function getFileIcon($filename) {
global $file_icons;
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$type = getFileType($extension);
return isset($file_icons[$type]) ? $file_icons[$type] : $file_icons['default'];
}
// 获取可预览的文件类型
function isPreviewable($filename) {
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$previewable_types = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp',
'pdf', 'txt', 'html', 'css', 'js', 'php', 'json', 'xml'];
return in_array($extension, $previewable_types);
}
// 格式化文件大小
function formatFileSize($bytes) {
if ($bytes === 0) return '0 B';
$k = 1024;
$sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = floor(log($bytes) / log($k));
return round($bytes / pow($k, $i), 2) . ' ' . $sizes[$i];
}
// 扫描目录
function scanDirectory($dir) {
$files = [];
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
return $files;
}
$items = scandir($dir);
foreach ($items as $item) {
if ($item == '.' || $item == '..') continue;
$path = $dir . '/' . $item;
$stat = stat($path);
$files[] = [
'name' => $item,
'path' => $path,
'size' => is_file($path) ? filesize($path) : 0,
'modified' => filemtime($path),
'is_dir' => is_dir($path),
'extension' => pathinfo($item, PATHINFO_EXTENSION),
'icon' => is_dir($path) ? '📁' : getFileIcon($item)
];
}
// 按类型排序:目录在前,文件在后,按名称排序
usort($files, function($a, $b) {
if ($a['is_dir'] != $b['is_dir']) {
return $b['is_dir'] - $a['is_dir'];
}
return strnatcasecmp($a['name'], $b['name']);
});
return $files;
}
// 文件上传处理
function handleFileUpload($file, $target_dir) {
if (!is_dir($target_dir)) {
mkdir($target_dir, 0777, true);
}
$filename = basename($file['name']);
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
// 验证文件类型
global $all_extensions;
if (!in_array($extension, $all_extensions)) {
return ['success' => false, 'message' => '不允许的文件类型'];
}
// 验证文件大小
if ($file['size'] > MAX_FILE_SIZE) {
return ['success' => false, 'message' => '文件太大'];
}
// 防止文件名冲突
$target_path = $target_dir . '/' . $filename;
$counter = 1;
while (file_exists($target_path)) {
$info = pathinfo($filename);
$target_path = $target_dir . '/' . $info['filename'] . '_' . $counter . '.' . $info['extension'];
$counter++;
}
if (move_uploaded_file($file['tmp_name'], $target_path)) {
return ['success' => true, 'message' => '上传成功', 'file' => basename($target_path)];
} else {
return ['success' => false, 'message' => '上传失败'];
}
}
// 删除文件
function deleteFile($path) {
if (!file_exists($path)) {
return ['success' => false, 'message' => '文件不存在'];
}
if (is_dir($path)) {
// 删除目录及其内容
if (deleteDirectory($path)) {
return ['success' => true, 'message' => '目录删除成功'];
} else {
return ['success' => false, 'message' => '目录删除失败'];
}
} else {
if (unlink($path)) {
return ['success' => true, 'message' => '文件删除成功'];
} else {
return ['success' => false, 'message' => '文件删除失败'];
}
}
}
// 递归删除目录
function deleteDirectory($dir) {
if (!file_exists($dir)) {
return true;
}
if (!is_dir($dir)) {
return unlink($dir);
}
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') {
continue;
}
if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
return false;
}
}
return rmdir($dir);
}
// 创建目录
function createDirectory($base_dir, $dir_name) {
$path = $base_dir . '/' . basename($dir_name);
if (file_exists($path)) {
return ['success' => false, 'message' => '目录已存在'];
}
if (mkdir($path, 0777, true)) {
return ['success' => true, 'message' => '目录创建成功'];
} else {
return ['success' => false, 'message' => '目录创建失败'];
}
}
// 处理AJAX请求
function handleAjaxRequest() {
$action = isset($_POST['action']) ? $_POST['action'] : '';
switch ($action) {
case 'list':
$dir = isset($_POST['path']) ? $_POST['path'] : UPLOAD_DIR;
$files = scanDirectory($dir);
echo json_encode(['success' => true, 'files' => $files, 'current_path' => realpath($dir)]);
break;
case 'upload':
if (isset($_FILES['file'])) {
$target_dir = isset($_POST['path']) ? $_POST['path'] : UPLOAD_DIR;
$result = handleFileUpload($_FILES['file'], $target_dir);
echo json_encode($result);
} else {
echo json_encode(['success' => false, 'message' => '没有文件']);
}
break;
case 'delete':
$path = isset($_POST['path']) ? $_POST['path'] : '';
if ($path && strpos(realpath($path), realpath(UPLOAD_DIR)) === 0) {
$result = deleteFile($path);
echo json_encode($result);
} else {
echo json_encode(['success' => false, 'message' => '无效的路径']);
}
break;
case 'create_dir':
$base_dir = isset($_POST['base_path']) ? $_POST['base_path'] : UPLOAD_DIR;
$dir_name = isset($_POST['dir_name']) ? $_POST['dir_name'] : '';
if ($dir_name) {
$result = createDirectory($base_dir, $dir_name);
echo json_encode($result);
} else {
echo json_encode(['success' => false, 'message' => '请输入目录名']);
}
break;
case 'preview':
$path = isset($_POST['path']) ? $_POST['path'] : '';
if ($path && file_exists($path) && is_file($path)) {
$content = getPreviewContent($path);
echo json_encode(['success' => true, 'content' => $content]);
} else {
echo json_encode(['success' => false, 'message' => '文件不存在']);
}
break;
default:
echo json_encode(['success' => false, 'message' => '未知操作']);
}
exit;
}
// 获取预览内容
function getPreviewContent($path) {
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
// 图片预览
if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'])) {
// 获取相对路径用于生成URL
$relative_path = str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath($path));
return '<img src="' . htmlspecialchars($relative_path) . '" alt="预览" style="max-width:100%;max-height:80vh;">';
}
// PDF预览
if ($extension === 'pdf') {
$relative_path = str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath($path));
return '<iframe src="' . htmlspecialchars($relative_path) . '" style="width:100%;height:80vh;" frameborder="0"></iframe>';
}
// 文本文件预览
if (in_array($extension, ['txt', 'php', 'html', 'css', 'js', 'json', 'xml'])) {
$content = file_get_contents($path);
$escaped_content = htmlspecialchars($content);
return '<pre style="background:#f4f4f4;padding:15px;border-radius:4px;overflow:auto;max-height:80vh;"><code>' . $escaped_content . '</code></pre>';
}
return '<p>无法预览此文件类型</p>';
}
// 处理请求
if (isset($_POST['action'])) {
handleAjaxRequest();
}
主页面 (index.php)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">文件管理系统</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<header>
<h1>📁 文件管理系统</h1>
<div class="header-actions">
<button onclick="showCreateDirModal()" class="btn btn-primary">📂 新建文件夹</button>
<label class="btn btn-success upload-btn">
📤 上传文件
<input type="file" id="fileInput" multiple onchange="uploadFiles()" style="display:none">
</label>
</div>
</header>
<nav class="breadcrumb" id="breadcrumb">
<!-- 面包屑导航会通过JavaScript动态生成 -->
</nav>
<div class="file-grid" id="fileGrid">
<!-- 文件列表会通过JavaScript动态生成 -->
</div>
<div id="loading" class="loading" style="display:none">
<div class="spinner"></div>
<span>加载中...</span>
</div>
</div>
<!-- 预览弹窗 -->
<div id="previewModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closePreview()">×</span>
<div id="previewContent"></div>
</div>
</div>
<!-- 新建文件夹弹窗 -->
<div id="createDirModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeCreateDirModal()">×</span>
<h3>新建文件夹</h3>
<input type="text" id="dirNameInput" placeholder="请输入文件夹名称">
<button onclick="createDirectory()" class="btn btn-primary">创建</button>
</div>
</div>
<!-- 右键菜单 -->
<div id="contextMenu" class="context-menu">
<ul>
<li onclick="previewFile()">👁️ 预览</li>
<li onclick="downloadFile()">⬇️ 下载</li>
<li onclick="deleteFile()">🗑️ 删除</li>
</ul>
</div>
<div id="notification" class="notification"></div>
<script src="js/main.js"></script>
</body>
</html>
CSS样式 (css/style.css)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f0f2f5;
color: #333;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
background: white;
padding: 20px 30px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
h1 {
font-size: 1.8em;
color: #1a73e8;
}
.header-actions {
display: flex;
gap: 10px;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s;
display: inline-flex;
align-items: center;
gap: 5px;
}
.btn-primary {
background: #1a73e8;
color: white;
}
.btn-primary:hover {
background: #1557b0;
}
.btn-success {
background: #34a853;
color: white;
}
.btn-success:hover {
background: #2d9249;
}
.btn-danger {
background: #ea4335;
color: white;
}
.btn-danger:hover {
background: #d33426;
}
.upload-btn {
cursor: pointer;
}
.breadcrumb {
background: white;
padding: 12px 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
}
.breadcrumb a {
color: #1a73e8;
text-decoration: none;
}
.breadcrumb a:hover {
text-decoration: underline;
}
.breadcrumb span {
color: #666;
margin: 0 5px;
}
.file-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 20px;
}
.file-item {
background: white;
border-radius: 10px;
padding: 20px 15px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
position: relative;
}
.file-item:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.file-item .file-icon {
font-size: 48px;
display: block;
margin-bottom: 10px;
}
.file-item .file-name {
font-size: 13px;
color: #333;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.file-item .file-size {
font-size: 11px;
color: #999;
margin-top: 5px;
}
.file-item .file-date {
font-size: 11px;
color: #999;
}
.file-item.selected {
background: #e8f0fe;
border: 2px solid #1a73e8;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
.spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #1a73e8;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 弹窗样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.6);
z-index: 1000;
animation: fadeIn 0.3s;
}
.modal-content {
background: white;
margin: 5% auto;
padding: 30px;
border-radius: 12px;
max-width: 800px;
width: 90%;
position: relative;
animation: slideIn 0.3s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideIn {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.close {
position: absolute;
right: 20px;
top: 15px;
font-size: 28px;
cursor: pointer;
color: #999;
}
.close:hover {
color: #333;
}
#previewContent {
margin-top: 20px;
}
#dirNameInput {
width: 100%;
padding: 12px;
margin: 15px 0;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 16px;
}
#dirNameInput:focus {
border-color: #1a73e8;
outline: none;
}
/* 右键菜单 */
.context-menu {
display: none;
position: fixed;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 999;
min-width: 150px;
}
.context-menu ul {
list-style: none;
padding: 8px 0;
}
.context-menu li {
padding: 10px 20px;
cursor: pointer;
transition: background 0.2s;
}
.context-menu li:hover {
background: #f0f2f5;
}
/* 通知 */
.notification {
position: fixed;
top: 20px;
right: 20px;
padding: 15px 25px;
border-radius: 8px;
color: white;
z-index: 2000;
animation: slideInRight 0.3s;
display: none;
}
.notification.success {
background: #34a853;
}
.notification.error {
background: #ea4335;
}
@keyframes slideInRight {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
/* 响应式设计 */
@media (max-width: 768px) {
header {
flex-direction: column;
gap: 15px;
text-align: center;
}
.file-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 15px;
}
.file-item .file-icon {
font-size: 36px;
}
}
JavaScript功能 (js/main.js)
// 当前位置
let currentPath = '';
let selectedFile = null;
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
loadFiles('');
// 点击其他地方关闭右键菜单
document.addEventListener('click', function(e) {
const contextMenu = document.getElementById('contextMenu');
if (contextMenu.style.display === 'block') {
contextMenu.style.display = 'none';
}
});
// 点击弹窗外部关闭
window.onclick = function(event) {
const previewModal = document.getElementById('previewModal');
const createDirModal = document.getElementById('createDirModal');
if (event.target == previewModal) {
closePreview();
}
if (event.target == createDirModal) {
closeCreateDirModal();
}
};
// 允许文件夹拖放上传
setupDragAndDrop();
});
// 加载文件列表
function loadFiles(path) {
currentPath = path;
showLoading(true);
const formData = new FormData();
formData.append('action', 'list');
formData.append('path', path);
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
showLoading(false);
if (data.success) {
renderFileGrid(data.files);
renderBreadcrumb(data.current_path);
} else {
showNotification('加载文件失败', 'error');
}
})
.catch(error => {
showLoading(false);
showNotification('网络错误', 'error');
});
}
// 渲染文件网格
function renderFileGrid(files) {
const grid = document.getElementById('fileGrid');
grid.innerHTML = '';
if (files.length === 0) {
grid.innerHTML = '<div class="empty-state">📂 此文件夹为空</div>';
return;
}
files.forEach(file => {
const item = document.createElement('div');
item.className = 'file-item';
item.dataset.path = file.path;
item.dataset.isDir = file.is_dir;
item.dataset.name = file.name;
item.innerHTML = `
<span class="file-icon">${file.icon}</span>
<div class="file-name">${file.name}</div>
<div class="file-size">${file.is_dir ? '文件夹' : formatFileSize(file.size)}</div>
<div class="file-date">${formatDate(file.modified)}</div>
`;
// 双击进入目录或预览文件
item.addEventListener('dblclick', function(e) {
if (file.is_dir) {
loadFiles(file.path);
} else {
previewFile(file.path);
}
});
// 单击选择
item.addEventListener('click', function(e) {
document.querySelectorAll('.file-item').forEach(el => el.classList.remove('selected'));
this.classList.add('selected');
selectedFile = file;
});
// 右键菜单
item.addEventListener('contextmenu', function(e) {
e.preventDefault();
selectedFile = file;
showContextMenu(e.pageX, e.pageY);
});
grid.appendChild(item);
});
}
// 渲染面包屑导航
function renderBreadcrumb(path) {
const breadcrumb = document.getElementById('breadcrumb');
const parts = path.split('/');
let html = '';
// 根目录
html += '<a href="#" onclick="loadFiles(\'\')">📁 根目录</a>';
// 路径部分
let currentPath = '';
for (let i = parts.length - 3; i < parts.length; i++) { // 跳过uploads前的路径
if (parts[i]) {
currentPath += '/' + parts[i];
html += '<span> / </span>';
if (i === parts.length - 1) {
html += `<span>📂 ${parts[i]}</span>`;
} else {
html += `<a href="#" onclick="loadFiles('${currentPath}')">${parts[i]}</a>`;
}
}
}
breadcrumb.innerHTML = html;
}
// 上传文件
function uploadFiles() {
const input = document.getElementById('fileInput');
const files = input.files;
if (files.length === 0) return;
showNotification('上传中...', '');
const formData = new FormData();
formData.append('action', 'upload');
formData.append('path', currentPath);
for (let i = 0; i < files.length; i++) {
formData.append('file[]', files[i]);
}
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification('上传成功!', 'success');
loadFiles(currentPath);
} else {
showNotification(data.message || '上传失败', 'error');
}
})
.catch(error => {
showNotification('上传失败', 'error');
});
input.value = '';
}
// 预览文件
function previewFile(path) {
if (!path && selectedFile) {
path = selectedFile.path;
}
if (!path) {
showNotification('请选择文件', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'preview');
formData.append('path', path);
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('previewContent').innerHTML = data.content;
document.getElementById('previewModal').style.display = 'block';
} else {
showNotification(data.message || '预览失败', 'error');
}
})
.catch(error => {
showNotification('预览失败', 'error');
});
}
// 下载文件
function downloadFile() {
if (selectedFile && !selectedFile.is_dir) {
window.location.href = 'download.php?file=' + encodeURIComponent(selectedFile.path);
} else {
showNotification('请选择一个文件下载', 'error');
}
}
// 删除文件
function deleteFile() {
if (!selectedFile) {
showNotification('请选择文件', 'error');
return;
}
if (!confirm(`确定要删除 "${selectedFile.name}" 吗?`)) {
return;
}
const formData = new FormData();
formData.append('action', 'delete');
formData.append('path', selectedFile.path);
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification(data.message, 'success');
loadFiles(currentPath);
} else {
showNotification(data.message || '删除失败', 'error');
}
})
.catch(error => {
showNotification('删除失败', 'error');
});
}
// 创建目录
function createDirectory() {
const dirName = document.getElementById('dirNameInput').value.trim();
if (!dirName) {
showNotification('请输入文件夹名称', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'create_dir');
formData.append('base_path', currentPath);
formData.append('dir_name', dirName);
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification(data.message, 'success');
loadFiles(currentPath);
closeCreateDirModal();
document.getElementById('dirNameInput').value = '';
} else {
showNotification(data.message || '创建失败', 'error');
}
})
.catch(error => {
showNotification('创建失败', 'error');
});
}
// 显示/隐藏加载动画
function showLoading(show) {
document.getElementById('loading').style.display = show ? 'block' : 'none';
}
// 显示通知
function showNotification(message, type) {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.className = 'notification ' + (type || '');
notification.style.display = 'block';
if (type) {
setTimeout(() => {
notification.style.display = 'none';
}, 3000);
}
}
// 显示右键菜单
function showContextMenu(x, y) {
const menu = document.getElementById('contextMenu');
menu.style.left = x + 'px';
menu.style.top = y + 'px';
menu.style.display = 'block';
}
// 关闭预览
function closePreview() {
document.getElementById('previewModal').style.display = 'none';
document.getElementById('previewContent').innerHTML = '';
}
// 显示新建文件夹弹窗
function showCreateDirModal() {
document.getElementById('createDirModal').style.display = 'block';
document.getElementById('dirNameInput').value = '';
document.getElementById('dirNameInput').focus();
}
// 关闭新建文件夹弹窗
function closeCreateDirModal() {
document.getElementById('createDirModal').style.display = 'none';
}
// 格式化文件大小
function formatFileSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 格式化日期
function formatDate(timestamp) {
const date = new Date(timestamp * 1000);
const now = new Date();
const diff = now - date;
if (diff < 60000) return '刚刚';
if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前';
if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前';
if (diff < 604800000) return Math.floor(diff / 86400000) + '天前';
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
}
// 设置拖放上传
function setupDragAndDrop() {
const container = document.querySelector('.container');
container.addEventListener('dragover', function(e) {
e.preventDefault();
this.style.borderColor = '#1a73e8';
});
container.addEventListener('dragleave', function(e) {
e.preventDefault();
this.style.borderColor = '';
});
container.addEventListener('drop', function(e) {
e.preventDefault();
this.style.borderColor = '';
const files = e.dataTransfer.files;
if (files.length > 0) {
uploadDroppedFiles(files);
}
});
}
// 上传拖放的文件
function uploadDroppedFiles(files) {
showNotification('上传中...', '');
const formData = new FormData();
formData.append('action', 'upload');
formData.append('path', currentPath);
for (let i = 0; i < files.length; i++) {
formData.append('file[]', files[i]);
}
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification('上传成功!', 'success');
loadFiles(currentPath);
} else {
showNotification(data.message || '上传失败', 'error');
}
})
.catch(error => {
showNotification('上传失败', 'error');
});
}
// 键盘快捷键
document.addEventListener('keydown', function(e) {
if (e.key === 'F5') {
e.preventDefault();
loadFiles(currentPath);
}
if (e.key === 'Delete' && selectedFile) {
deleteFile();
}
if (e.key === 'Escape') {
closePreview();
closeCreateDirModal();
}
});
下载文件 (download.php)
创建 download.php 文件来处理文件下载:
<?php
require_once 'config.php';
$file = isset($_GET['file']) ? $_GET['file'] : '';
if (!$file || !file_exists($file)) {
http_response_code(404);
echo '文件不存在';
exit;
}
// 安全检查 - 确保文件在uploads目录内
$real_path = realpath($file);
$upload_dir = realpath(UPLOAD_DIR);
if (strpos($real_path, $upload_dir) !== 0) {
http_response_code(403);
echo '无权访问';
exit;
}
$filename = basename($file);
$file_size = filesize($file);
// 设置下载头
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $file_size);
ob_clean();
flush();
readfile($file);
exit;
功能特点
- 文件浏览:网格视图显示文件和文件夹,支持排序
- 文件上传:支持多文件上传和拖放上传
- 文件预览:支持图片、PDF、文本文件预览
- 文件操作:双击进入目录,右键菜单提供预览、下载、删除
- 目录管理:创建新目录,面包屑导航
- 安全功能:文件类型验证、路径安全检查
- 响应式设计:适配各种屏幕尺寸
- 友好的UI:毛玻璃效果、动画过渡、通知提示
使用
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播