首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 圖片上傳類完整實作與前端調用指南

     編輯:PHP 相關知識

類別與前端完整配合範例

這篇文章提供了難得的「前後端完整配合」範例,從 HTML 表單、JS 處理到 PHP 後端類別,展示一個最小可行的圖片上傳功能閉環。

前端調用頁面 upphoto.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>圖片上傳測試</title>
</head>
<body>
    <form action="upphoto.php?action=act" method="post" enctype="multipart/form-data">
        圖片來源:<input type="file" name="photo" accept="image/*">
        <input type="submit" name="submit" value="上傳">
    </form>
    
    <?php
    if (isset($_GET['action']) && $_GET['action'] === 'act') {
        require_once 'uppoo.php';
        $up = new upphoto();
        
        $up->get_ph_tmpname($_FILES['photo']['tmp_name']);
        $up->get_ph_type($_FILES['photo']['type']);
        $up->get_ph_size($_FILES['photo']['size']);
        $up->get_ph_name($_FILES['photo']['name']);
        $up->save();
    }
    ?>
</body>
</html>

後端核心類 uppoo.php

<?php
class upphoto {
    // 設定屬性
    public $previewsize = 0.125;      // 預覽縮放比例
    public $preview = 0;              // 是否生成預覽
    public $ph_path = "./userimg/";   // 儲存路徑
    public $al_ph_type = [            // 允許 MIME
        'image/jpg','image/jpeg','image/png',
        'image/pjpeg','image/gif','image/bmp','image/x-png'
    ];
    public $al_ph_size = 1000000;     // 1MB
    
    // 執行時屬性
    public $ph_name;      // 完整儲存路徑
    public $ph_tmp_name;  // 暫存路徑
    public $ph_type;      // MIME 類型
    public $ph_size;      // 檔案大小
    public $imgsize;      // 圖片尺寸資訊
    public $datetime;     // 時間戳 (作為檔名基礎)
    
    public function __construct() {
        $this->set_datatime();
    }
    
    private function set_datatime() {
        $this->datetime = date("YmdHis");
    }
    
    // --- Setter 方法群 ---
    public function get_ph_type($t) { $this->ph_type = $t; }
    public function get_ph_size($s) { $this->ph_size = $s; }
    public function get_ph_tmpname($t) { 
        $this->ph_tmp_name = $t; 
        $this->imgsize = getimagesize($t); // 預先讀取尺寸
    }
    public function get_ph_name($n) {
        // 取得副檔名 (含點號)
        $ext = strrchr($n, ".");
        $this->ph_name = $this->ph_path . $this->datetime . $ext;
        return $this->ph_name;
    }
    
    // --- 核心驗證流程 ---
    private function check_path() {
        if (!file_exists($this->ph_path)) mkdir($this->ph_path, 0755, true);
    }
    
    private function check_size() {
        if ($this->ph_size > $this->al_ph_size) {
            $this->showerror("上傳圖片超過 1MB");
        }
    }
    
    private function check_type() {
        if (!in_array($this->ph_type, $this->al_ph_type)) {
            $this->showerror("上傳圖片類型錯誤");
        }
    }
    
    private function up_photo() {
        if (!move_uploaded_file($this->ph_tmp_name, $this->ph_name)) {
            $this->showerror("上傳檔案出錯");
        }
    }
    
    // --- 輔助功能 ---
    public function showphoto() {
        if ($this->preview == 1) {
            $w = $this->imgsize[0];
            $h = $this->imgsize[1];
            if ($w > 2000) { // 超大圖自動縮小預覽
                $w *= $this->previewsize;
                $h *= $this->previewsize;
            }
            echo "<img src='{$this->ph_name}' width='{$w}' height='{$h}'>";
        }
    }
    
    private function showerror($msg) {
        echo "<script>alert('$msg'); history.back();</script>";
        exit;
    }
    
    // --- 總管方法 ---
    public function save() {
        $this->check_path();
        $this->check_size();
        $this->check_type();
        $this->up_photo();
        $this->showphoto();
    }
}
?>

關鍵設計細節分析

1. Setter 模式的資料收集

採用分散的 setter 方法收集 $_FILES 資料,而非在建構子一次處理,優點是:

  • 靈活性高,可在儲存前插入額外邏輯 (如水印、病毒掃描)
  • 便於單元測試,可模擬各種輸入組合
  • 符合「命令查詢分離」原則

2. 時間戳命名策略

$ext = strrchr($phname, "."); // 從右側找第一個點
$ph_name = $ph_path . $datetime . $ext;
// 產生: ./userimg/20240115143025.jpg

注意:高併發下可能衝突,建議加入 microtime(true) 或 uniqid()。

3. 就地預覽機制

上傳成功後直接輸出 <img> 標籤,配合 getimagesize() 取得的尺寸資訊,實現無刷新預覽 (需前端配合 iframe 或 AJAX)。

現代化改造:AJAX 非同步上傳

<!-- 前端: upphoto_modern.php -->
<form id="uploadForm" enctype="multipart/form-data">
    <input type="file" name="photo" id="photo" accept="image/*">
    <button type="submit">上傳</button>
    <div id="preview"></div>
</form>

<script>
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('photo', document.getElementById('photo').files[0]);
    
    const res = await fetch('upload_api.php', {
        method: 'POST',
        body: formData
    });
    const data = await res.json();
    
    if (data.status === 'success') {
        document.getElementById('preview').innerHTML = 
            `<img src="${data.url}" style="max-width:300px">`;
    } else {
        alert(data.message);
    }
});
</script>
<?php
// 後端: upload_api.php
header('Content-Type: application/json');
require_once 'uppoo.php';

$up = new upphoto();
$up->preview = 0; // API 模式不輸出 HTML

try {
    $up->get_ph_tmpname($_FILES['photo']['tmp_name']);
    $up->get_ph_type($_FILES['photo']['type']);
    $up->get_ph_size($_FILES['photo']['size']);
    $up->get_ph_name($_FILES['photo']['name']);
    $up->save();
    
    echo json_encode([
        'status' => 'success',
        'url' => $up->ph_name,
        'size' => $up->imgsize
    ]);
} catch (Throwable $e) {
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
?>

安全性增強清單

風險對策
MIME 偽裝使用 finfo_file(FILEINFO_MIME_TYPE) 驗證真實類型
腳本偽裝成圖片上傳目錄設定 php_flag engine off 或移至 Webroot 外
檔名路徑遍歷使用 basename() + 白名單副檔名驗證
大檔案 DoS設定 upload_max_filesize、post_max_size、Nginx client_max_body_size
圖片炸彈使用 getimagesize() 檢查寬高限制 (如 < 5000px)

總結

這個範例雖然結構簡單,但完整展示了「表單提交 → 後端驗證 → 檔案儲存 → 回應前端」的標準流程。理解其運作機制,是進階學習雲端上傳、分片上傳、圖片處理管線的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved