文件上传
This commit is contained in:
parent
80ef98ed7e
commit
96fe9915d9
188
files.php
Normal file
188
files.php
Normal file
@ -0,0 +1,188 @@
|
||||
<?php
|
||||
// upload.php
|
||||
session_start();
|
||||
|
||||
// 配置参数
|
||||
$config = [
|
||||
'max_file_size' => 50 * 1024 * 1024, // 50MB
|
||||
'allowed_types' => [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'application/pdf',
|
||||
'text/plain'
|
||||
],
|
||||
'upload_dir' => __DIR__ . '/uploads/',
|
||||
'csrf_token' => 'secure_token_here' // 生产环境应使用更安全的生成方式
|
||||
];
|
||||
|
||||
// 处理文件上传
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF 验证
|
||||
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $config['csrf_token']) {
|
||||
$error = '无效的请求令牌';
|
||||
} else {
|
||||
try {
|
||||
// 验证上传文件
|
||||
$uploadedFile = $_FILES['file'] ?? null;
|
||||
|
||||
if (!$uploadedFile || $uploadedFile['error'] !== UPLOAD_ERR_OK) {
|
||||
throw new RuntimeException(handleUploadError($uploadedFile['error']));
|
||||
}
|
||||
|
||||
// 验证文件大小
|
||||
if ($uploadedFile['size'] > $config['max_file_size']) {
|
||||
throw new RuntimeException('文件大小超过50MB限制');
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($uploadedFile['tmp_name']);
|
||||
|
||||
if (!in_array($mimeType, $config['allowed_types'])) {
|
||||
throw new RuntimeException('不支持的文件类型');
|
||||
}
|
||||
|
||||
// 创建上传目录
|
||||
if (!is_dir($config['upload_dir']) && !mkdir($config['upload_dir'], 0755, true)) {
|
||||
throw new RuntimeException('无法创建上传目录');
|
||||
}
|
||||
|
||||
// 生成安全文件名
|
||||
$extension = pathinfo($uploadedFile['name'], PATHINFO_EXTENSION);
|
||||
$safeName = sprintf('%s.%s', bin2hex(random_bytes(8)), $extension);
|
||||
$targetPath = $config['upload_dir'] . $safeName;
|
||||
|
||||
// 移动文件
|
||||
if (!move_uploaded_file($uploadedFile['tmp_name'], $targetPath)) {
|
||||
throw new RuntimeException('文件保存失败');
|
||||
}
|
||||
|
||||
$success = sprintf('文件上传成功!文件名:%s', htmlspecialchars($safeName));
|
||||
} catch (RuntimeException $e) {
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleUploadError($code) {
|
||||
switch ($code) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
return '文件大小超过服务器限制';
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
return '文件只有部分被上传';
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
return '没有文件被上传';
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
return '缺少临时文件夹';
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
return '写入磁盘失败';
|
||||
default:
|
||||
return '未知上传错误';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>安全文件上传系统</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.upload-container {
|
||||
max-width: 800px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
background: #f8f9fa;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 15px rgba(0,0,0,0.1);
|
||||
}
|
||||
.preview-box {
|
||||
border: 2px dashed #6c757d;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
margin: 1rem 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.preview-box:hover {
|
||||
border-color: #0d6efd;
|
||||
background: rgba(13, 110, 253, 0.05);
|
||||
}
|
||||
#file-input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="upload-container">
|
||||
<h2 class="mb-4 text-center">安全文件上传系统</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success"><?= $success ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= $config['csrf_token'] ?>">
|
||||
|
||||
<div class="preview-box">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" class="bi bi-cloud-upload mb-3" viewBox="0 0 16 16">
|
||||
<path d="M4.406 1.342A5.53 5.53 0 0 1 8 0c2.69 0 4.923 2 5.166 4.579C14.758 4.804 16 6.137 16 7.773 16 9.569 14.502 11 12.687 11H10a.5.5 0 0 1 0-1h2.688C13.979 10 15 8.988 15 7.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 2.825 10.328 1 8 1a4.53 4.53 0 0 0-2.941 1.1c-.757.652-1.153 1.438-1.153 2.055v.448l-.445.049C2.064 4.805 1 5.952 1 7.318 1 8.785 2.23 10 3.781 10H6a.5.5 0 0 1 0 1H3.781C1.708 11 0 9.366 0 7.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383z"/>
|
||||
<path d="M7.646 4.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V14.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3z"/>
|
||||
</svg>
|
||||
<h5>选择要上传的文件</h5>
|
||||
<p class="text-muted">支持格式:JPEG, PNG, PDF, TXT</p>
|
||||
<label for="file-input" class="btn btn-primary mt-2">
|
||||
<i class="bi bi-folder2-open"></i> 浏览文件
|
||||
</label>
|
||||
<div id="file-name" class="mt-2"></div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
name="file"
|
||||
id="file-input"
|
||||
class="form-control"
|
||||
required
|
||||
accept=".jpg,.jpeg,.png,.pdf,.txt"
|
||||
>
|
||||
|
||||
<div class="d-grid gap-2 mt-4">
|
||||
<button type="submit" class="btn btn-success btn-lg">
|
||||
<i class="bi bi-upload"></i> 开始上传
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 文件选择交互
|
||||
document.getElementById('file-input').addEventListener('change', function(e) {
|
||||
const fileName = e.target.files[0]?.name || '未选择文件';
|
||||
document.getElementById('file-name').textContent = `已选择文件:${fileName}`;
|
||||
});
|
||||
|
||||
// 前端大小验证
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
const fileInput = document.getElementById('file-input');
|
||||
if (fileInput.files[0]?.size > <?= $config['max_file_size'] ?>) {
|
||||
alert('文件大小超过50MB限制');
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user