類別設計目標
- 單一職責:封裝上傳、驗證、儲存、刪除全流程。
- 配置化:副檔名白名單、大小限制、儲存根目錄可外部注入。
- 安全第一:路徑遍歷防護、MIME 驗證、隨機檔名、權限控制。
- 易擴展:支援多儲存驅動(本地、S3、FTP)預留介面。
核心代碼 (upLoad.class.php)
<?php
class upLoad {
private $root = '/var/www/uploads'; // 儲存根目錄
private $typeWhitelist = ['jpg','jpeg','png','gif','pdf','zip'];
private $maxSize = 5 * 1024 * 1024; // 5MB
// ---------- 公開介面 ----------
public function init($fieldName, $maxSize = null) {
if (!isset($_FILES[$fieldName]) || $_FILES[$fieldName]['error'] !== UPLOAD_ERR_OK) {
return false;
}
$this->maxSize = $maxSize ?? $this->maxSize;
$file = $_FILES[$fieldName];
if (!$this->_checkType($file['name']) || !$this->_checkSize($file['size']) || $file['error'] !== 0) {
return false;
}
$destDir = $this->_createUserDir('user_' . session_id()); // 實際專案用 user_id
$newName = $this->_genRandomName($file['name']);
$destPath = $destDir . $newName;
return @move_uploaded_file($file['tmp_name'], $destPath) ? $newName : false;
}
public function deleteFile($relativePath) {
$full = $this->root . '/' . ltrim($relativePath, '/');
if ($this->_isInsideRoot($full) && is_file($full)) {
return @unlink($full);
}
return false;
}
public function deleteDir($relativePath) {
$full = $this->root . '/' . ltrim($relativePath, '/');
if ($this->_isInsideRoot($full) && is_dir($full)) {
return @rmdir($full); // 僅刪除空目錄,遞歸刪除需自行實現
}
return false;
}
// ---------- 內部邏輯 ----------
private function _checkType($fileName) {
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
// 可選:檢查多重副檔名 (evil.php.jpg)
if (substr_count($fileName, '.') > 1) return false;
return in_array($ext, $this->typeWhitelist);
}
private function _checkSize($size) {
return $size <= $this->maxSize;
}
private function _genRandomName($origName) {
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
return bin2hex(random_bytes(16)) . '.' . $ext;
}
private function _createUserDir($userId) {
$datePath = date('Y/m/d/');
$path = $this->root . '/' . $datePath . $userId . '/';
if (!is_dir($path)) {
mkdir($path, 0755, true); // 遞歸建立
}
return $path;
}
private function _isInsideRoot($path) {
$realRoot = realpath($this->root);
$realPath = realpath($path);
return $realPath && strpos($realPath, $realRoot) === 0;
}
}
?>
使用範例
<?php
require_once 'upLoad.class.php';
$uploader = new upLoad();
if ($savedName = $uploader->init('fileField')) {
echo "上傳成功,儲存為:$savedName";
} else {
echo "上傳失敗:" . $_FILES['fileField']['error'];
}
// 刪除範例
// $uploader->deleteFile('2024/05/20/user_abc123/a1b2c3d4.jpg');
?>
擴展建議
- 實作
StorageInterface,支援 AWS S3、阿里云 OSS、FTP 等雲端儲存。
- 加入圖片自動壓縮(Intervention/Image)、病毒掃描回調。
- 上傳日誌寫入資料庫:用戶、原始檔名、儲存路徑、大小、MIME、IP、時間。
- 大檔分片上傳:前端 Plupload/Uppy + 後端合併臨時分片。