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

ThinkPHP 圖片上傳完整實作:縮略圖、水印、資料庫記錄一體化

     編輯:PHP 相關知識

ThinkPHP 內建 UploadFile 與 Image 類庫,提供強大的檔案上傳、縮略圖生成、水印添加功能。本文以完整模組為例,示範從資料表設計、配置、控制器、視圖到業務邏輯的端到端實作。

1. 資料表設計

CREATE TABLE `tp_image` (
    `id`          INT(11)      NOT NULL AUTO_INCREMENT,
    `image`       VARCHAR(200) NOT NULL COMMENT '儲存檔名(不含路徑)',
    `create_time` INT(11)      NOT NULL COMMENT '上傳時間戳',
    PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

2. 應用配置 Conf/config.php

<?php
return [
    'URL_MODEL'       => 2,        // PATHINFO 模式
    'DB_TYPE'         => 'mysql',
    'DB_HOST'         => 'localhost',
    'DB_NAME'         => 'thinkphp',
    'DB_USER'         => 'root',
    'DB_PWD'          => '',
    'DB_PORT'         => '3306',
    'DB_PREFIX'       => 'tp_',
    'SHOW_PAGE_TRACE' => true,     // 開發環境開啟 Trace

    // 模板路徑替換:__UPLOAD__ → /Uploads
    'TMPL_PARSE_STRING' => [
        '__UPLOAD__' => __ROOT__ . '/Uploads',
    ],
];

3. 控制器 Lib/Action/ImageAction.class.php

<?php
class ImageAction extends Action {
    /** 列表頁:顯示最新上傳圖片 */
    public function index() {
        $image = M('Image');
        $data  = $image->order('create_time DESC')->find();
        $this->assign('data', $data);
        $this->display();
    }

    /** 上傳入口:驗證檔案後轉交 _upload() */
    public function upload() {
        if (!empty($_FILES)) {
            $this->_upload();
        } else {
            $this->error('未收到上傳檔案');
        }
    }

    /** 核心上傳邏輯 */
    protected function _upload() {
        import('@.ORG.UploadFile');
        $upload = new UploadFile();

        // 基礎設定
        $upload->maxSize        = 3 * 1024 * 1024;          // 3MB
        $upload->allowExts      = ['jpg', 'gif', 'png', 'jpeg'];
        $upload->savePath       = './Uploads/';
        $upload->saveRule       = 'uniqid';                 // 唯一檔名
        $upload->thumb          = true;                     // 啟用縮略圖
        $upload->imageClassPath = '@.ORG.Image';
        $upload->thumbPrefix    = 'm_,s_';                  // 兩組前綴:中圖、小圖
        $upload->thumbMaxWidth  = '400,100';
        $upload->thumbMaxHeight = '400,100';
        $upload->thumbRemoveOrigin = true;                  // 刪除原圖

        // 執行上傳
        if (!$upload->upload()) {
            $this->error($upload->getErrorMsg());
        }

        $info = $upload->getUploadFileInfo();
        // $info[0] 包含:savepath, savename, name, type, size, extension...

        // 給中圖 (m_) 添加水印
        import('@.ORG.Image');
        Image::water(
            $info[0]['savepath'] . 'm_' . $info[0]['savename'],
            APP_PATH . 'Tpl/Public/Images/logo.png'
        );

        // 寫入資料庫
        $model = M('Image');
        $data = [
            'image'       => $info[0]['savename'],
            'create_time' => NOW_TIME,
        ];
        if ($model->add($data)) {
            $this->success('上傳成功!');
        } else {
            $this->error('資料庫寫入失敗');
        }
    }
}
?>

4. 視圖 Tpl/Image/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>圖片上傳示例</title>
    <style>
        #img { height: 22px; border: 2px solid #000; }
        #btn { height: 30px; width: 100px; }
    </style>
</head>
<body>
    <div class="result">
        允許:gif、png、jpg。生成 2 張縮略圖(中圖帶水印),刪除原圖。
    </div><br>

    <notempty name="data">
        <img src="__UPLOAD__/m_{$data.image}" alt="中圖(含水印)">
        <img src="__UPLOAD__/s_{$data.image}" alt="小圖">
    </notempty>

    <form action="__URL__/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="image" id="img" required>
        <input type="submit" value="上傳" id="btn">
    </form>
</body>
</html>

關鍵技術點解析

縮略圖命名規則

thumbPrefix => 'm_,s_' 會產生:

  • 原圖:abc123.jpg(若 thumbRemoveOrigin=false 保留)
  • 中圖:m_abc123.jpg(400x400,帶水印)
  • 小圖:s_abc123.jpg(100x100)

水印添加時機

必須在 $upload->upload() 成功後、縮略圖已生成時呼叫 Image::water(),目標檔案為 m_ 前綴的縮略圖。

路徑處理最佳實踐

  • 資料庫僅儲存檔名(savename),不儲存完整路徑
  • 視圖中使用 __UPLOAD__ 模板變數拼接 URL,支援遷移存儲路徑(如遷移至 OSS/CDN)
  • 上傳目錄 ./Uploads/ 需給 Web 使用者寫入權限:chown www:www Uploads && chmod 755 Uploads

安全性加固建議

<?php
// 1. 檔案型別二次驗證(防偽裝副檔名)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime  = finfo_file($finfo, $_FILES['image']['tmp_name']);
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowedMimes)) {
    $this->error('檔案型別不允許');
}

// 2. 檔案內容掃描(可整合 ClamAV)
// 3. 重新命名:已使用 uniqid(),避免覆蓋與遍歷
// 4. 存儲分離:生產環境建議掛載獨立磁碟或使用 S3/OSS
?>

常見問題排查

現象可能原因解決方案
上傳失敗「目錄不可寫」目錄權限不足或 open_basedir 限制檢查 php.ini open_basedir、目錄擁有者權限
縮略圖未生成GD 擴展未安裝或版本過舊php -m | grep gd 確認;安裝 php-gd
水印位置偏移原圖尺寸小於水印圖Image 類會自動縮放水印,檢查 logo.png 尺寸
中文檔名亂碼檔案系統編碼不一致強制使用 uniqid()/md5() 重命名,不保留原檔名

這套方案在 ThinkPHP 3.2.x 驗證通過,ThinkPHP 5/6/8 同理可用,只需調整命名空間引入方式(use think\facade\Filesystem 等)。掌握核心參數與流程,即可快速構建穩健的圖片上傳服務。

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