PHP 檔案上傳、多檔案上傳

使用瀏覽器『上傳檔案』到伺服器,是一個經常使用的重要功能,例如讓使用者上傳圖片(jpg、.png)、文件(.txt、.doc、.xls)、影片(.avi、.mp4)......等檔案類型,都須使用到『上傳檔案』功能,該文章將詳細解說客戶端、伺服器端配置與限制,及實作 PHP 檔案上傳、PHP 多檔案上傳,並將程式碼封裝成 function 與 class 二種方式,將能免除爾後專案使用需重造輪子的麻煩。

php

檔案上傳原理

使用瀏覽器將『客戶端』的檔案上傳到『伺服器端』,在將『伺服器端』的臨時檔案移動到指定目錄即可。

檔案上傳配置

客戶端配置(必要元件和配置)

  • 表單頁面 <form>
  • 瀏覽檔案上傳元件 <input type="file">
  • 表單發送方式必須為 method="post"
  • 表單新增 enctype="multipart/form-data" 屬性與值,規定在發送到伺服器之前不對字符編碼(表單包含檔案上傳類型時,必須新增該屬性與值)

伺服器端配置

預設配置文件路徑

  • XAMPP:C:\xampp\php\php.ini
  • Linux:/etc/php.ini

檔案上傳配置

  • file_uploads=On:支持 HTTP 上傳
  • upload_tmp_dir="C:\xampp\tmp":保存上傳檔案的臨時目錄
  • upload_max_filesize=2M:允許上傳檔案容量的最大值
  • max_file_uploads=20:允許一次上傳的最大檔案數量
  • post_max_size=8M:POST 方式發送資料容量的最大值

資源限制配置

  • max_execution_time=30:設定了 Script 被解析器終止之前允許的最大執行時間,防止程式寫得不好而耗盡伺服器資源,單位: 秒(-1 為不限制)。簡單說就是允許 Script 執行的時間
  • max_input_time=60:Script 解析輸入資料允許的最大時間,單位: 秒。簡單說就是 Script 處理資料時間上限
  • memory_limit=128M:最大單線程的獨立內存使用量。也就是一個 Web 請求,給予線程最大內存使用量的定義
  • ; max_input_nesting_level=64:設定輸入變數的嵌套深度,例如 $_GET、$_POST(預設註解無限制)
  • ; max_input_vars=1000:接受多少輸入的變數(限制分別應用於 $_GET、$_POST 和 $_COOKIE 超全局變數)指今的使用減輕了以哈希碰撞來進行拒絶服務攻擊的可能性。如有超過指令指定數量的變數,將會導致 E_WARNING 的產生,更多的輸入變數將會從請求中截斷(預設註解無限制)

檔案上傳限制

客戶端限制(可直接修改瀏覽器代碼讓限制無效)

  • <input type="hidden" name="MAX_FILE_SIZE" value="最大量容限制數"> 透過定義 input 元素的類型 type="hidden" 隱藏限制上傳檔案的最大值(name 值必須指定為 MAX_FILE_SIZE 且該行必須寫在 <input type="file"> 前面)
  • <input type="file" name="myFile" accept="允許的 MIME 檔案類型"> 通過 accept 屬性限制上傳檔案類型(例如只允許圖像檔案 accept="image/jpeg,image/gif,image/png" 可用逗號“,”分隔指定多個)

伺服器端限制

  • 檢查檔案是否是通過 HTTP POST 上傳的
  • 允許上傳檔案的擴展名(image/jpeg,image/gif,image/png……)
  • 上傳檔案容量大小限制
  • 檢查是否為真實的圖片類型(只允許上傳圖片的話)

$_FILES:HTTP 檔案上傳變數

$_FILES 中保存著上傳檔案的資訊

  • name:上傳檔案的名稱
  • type:上傳檔案的 MIME(Multipurpose Internet Mail Extensions 多用途網際網路郵件擴展)類型
  • tmp_name:上傳到伺服器上的臨時檔案名(後續都須使用它來操作)
  • error:上傳檔案的錯誤代碼(提供『常數』及『數值』可用)
    • UPLOAD_ERR_OK:值為 0,沒有錯誤發生,檔案上傳成功
    • UPLOAD_ERR_INI_SIZE:值為 1,上傳的檔案超過了 php.ini 中 upload_max_filesize 允許上傳檔案容量的最大值
    • UPLOAD_ERR_SIZE:值為 2,上傳檔案的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值
    • UPLOAD_ERR_PARTIAL:值為 3,檔案只有部分被上傳
    • UPLOAD_ERR_NO_FILE:值為 4,沒有檔案被上傳(沒有選擇上傳檔案就送出表單)
    • UPLOAD_ERR_NO_TMP_DIR:值為 6,找不到臨時目錄
    • UPLOAD_ERR_CANT_WRITE:值為 7,檔案寫入失敗
    • UPLOAD_ERR_EXTENSION:值為 8,上傳的文件被 PHP 擴展程式中斷
  • size:上傳檔案的容量大小

程式碼

單一 PHP 檔案上傳 – 封装成 function

檔案上傳頁面 – upload.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>單一 PHP 檔案上傳 - 封装成 function</title>
</head>
<body>
    
<form action="doAction.php" method="post" enctype="multipart/form-data">
    <!-- 限制上傳檔案的最大值 -->
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152">

    <!-- accept 限制上傳檔案類型 -->
    <input type="file" name="myFile" accept="image/jpeg,image/jpg,image/gif,image/png">

    <input type="submit" value="上傳檔案">
</form>

</body>
</html>

表單接收頁面 – doAction.php

<?php
/**
 * 表單接收頁面
 */

// 網頁編碼宣告(防止產生亂碼)
header('content-type:text/html;charset=utf-8');
// 封裝好的單一 PHP 檔案上傳 function
include_once 'upload.func.php';
// 取得 HTTP 文件上傳變數
$fileInfo = $_FILES['myFile'];
// 呼叫封將好的 function
$newName = uploadFile($fileInfo);

print_r($newName);

函式 – upload.func.php

<?php
/**
 * string uploadFile(array $files, array $allowExt, number $maxSize, boolean $flag, string $uploadPath) 單一 PHP 檔案上傳
 *
 * @param files 透過 $_FILES 取得的 HTTP 檔案上傳的項目陣列
 * @param allowExt 允許上傳檔案的擴展名,預設 'jpeg', 'jpg', 'gif', 'png'
 * @param maxsize 上傳檔案容量大小限制,預設 2097152(2M * 1024 * 1024 = 2097152byte)
 * @param flag 檢查是否為真實的圖片類型(只允許上傳圖片的話),true(預設)檢查;false 不檢查
 * @param uploadPath 存放檔案的目錄,預設 uploads
 *
 * @return 回傳存放目錄 + md5 產生的檔案名稱 + 擴展名
 */
function uploadFile($fileInfo, $allowExt = array('jpeg', 'jpg', 'gif', 'png'), $maxSize = 2097152, $flag = true, $uploadPath = 'uploads') {
    // 存放錯誤訊息
    $mes = '';

    // 取得上傳檔案的擴展名
    $ext = pathinfo($fileInfo['name'], PATHINFO_EXTENSION); 

    // 確保檔案名稱唯一,防止重覆名稱產生覆蓋
    $uniName = md5(uniqid(microtime(true), true)) . '.' . $ext;
    $destination = $uploadPath . '/' . $uniName;
    
    // 判斷是否有錯誤
    if ($fileInfo['error'] > 0) {
        // 匹配的錯誤代碼
        switch ($fileInfo['error']) {
            case 1:
                $mes = '上傳的檔案超過了 php.ini 中 upload_max_filesize 允許上傳檔案容量的最大值';
                break;
            case 2:
                $mes = '上傳檔案的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值';
                break;
            case 3:
                $mes = '檔案只有部分被上傳';
                break;
            case 4:
                $mes = '沒有檔案被上傳(沒有選擇上傳檔案就送出表單)';
                break;
            case 6:
                $mes = '找不到臨時目錄';
                break;
            case 7:
                $mes = '檔案寫入失敗';
                break;
            case 8:
                $mes = '上傳的文件被 PHP 擴展程式中斷';
                break;
        }

        exit($mes);
    }

    // 檢查檔案是否是通過 HTTP POST 上傳的
    if (!is_uploaded_file($fileInfo['tmp_name']))
        exit('檔案不是通過 HTTP POST 方式上傳的');
    
    // 檢查上傳檔案是否為允許的擴展名
    if (!is_array($allowExt))  // 判斷參數是否為陣列
        exit('檔案類型型態必須為 array');
    else {
        if (!in_array($ext, $allowExt))  // 檢查陣列中是否有允許的擴展名
            exit('非法檔案類型');
    }

    // 檢查上傳檔案的容量大小是否符合規範
    if ($fileInfo['size'] > $maxSize)
        exit('上傳檔案容量超過限制');

    // 檢查是否為真實的圖片類型
    if ($flag && !@getimagesize($fileInfo['tmp_name']))
        exit('不是真正的圖片類型');

    // 檢查指定目錄是否存在,不存在就建立目錄
    if (!file_exists($uploadPath))
        mkdir($uploadPath, 0777, true);  // 建立目錄
    
    // 將檔案從臨時目錄移至指定目錄
    if (!@move_uploaded_file($fileInfo['tmp_name'], $destination))  // 如果移動檔案失敗
        exit('檔案移動失敗');

    return $destination;
}

PHP 多檔案上傳 – 封装成 function

檔案上傳頁面 – upload.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>PHP 多檔案上傳 - 封装成 function</title>
</head>
<body>
    
<form action="doAction.php" method="post" enctype="multipart/form-data">
    <!-- 限制上傳檔案的最大值 -->
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152">

    <!-- accept 限制上傳檔案類型。多檔案上傳 name 的屬性值須定義為 array -->
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">

    <!-- 使用 html 5 實現單一上傳框可多選檔案方式,須新增 multiple 元素 -->
    <!-- <input type="file" name="myFile[]" id="" accept="image/jpeg,image/jpg,image/gif,image/png" multiple> -->

    <input type="submit" value="上傳檔案">
</form>

</body>
</html>

表單接收頁面 – doAction.php

<?php
/**
 * 表單接收頁面
 */

// 網頁編碼宣告(防止產生亂碼)
header('content-type:text/html;charset=utf-8');
// 封裝好的 PHP 多檔案上傳 function
include_once 'upload.func.php';
// 重新建構上傳檔案 array 格式
$files = getFiles();

// 依上傳檔案數執行
foreach ($files as $fileInfo) {
    // 呼叫封裝好的 function
    $res = uploadFile($fileInfo);

    // 顯示檔案上傳訊息
    echo $res['mes'] . '<br>';

    // 上傳成功,將實際儲存檔名存入 array(以便存入資料庫)
    if (!empty($res['dest'])) {
        $uploadFiles[] = $res['dest'];
    }
}

print_r($uploadFiles);

函式 – upload.func.php

<?php
/**
 * array getFiles() 判斷上傳『單一』或『多個』檔案,並重新建構上傳檔案 array 格式
 * 
 * @return 重新建構上傳檔案 array 格式
 */
function getFiles() {
    $i = 0;  // 遞增 array 數量

    foreach ($_FILES as $file) {
        // string 型態,表示上傳單一檔案
        if (is_string($file['name'])) {
            $files[$i] = $file;
            $i++;
        }
        // array 型態,表示上傳多個檔案
        elseif (is_array($file['name'])) {
            foreach ($file['name'] as $key => $value) {
                $files[$i]['name'] = $file['name'][$key];
                $files[$i]['type'] = $file['type'][$key];
                $files[$i]['tmp_name'] = $file['tmp_name'][$key];
                $files[$i]['error'] = $file['error'][$key];
                $files[$i]['size'] = $file['size'][$key];
                $i++;
            }
        }
    }

    return $files;
}

/**
 * string uploadFile(array $files, array $allowExt, number $maxSize, boolean $flag, string $uploadPath) PHP 多檔案上傳
 *
 * @param files 透過 $_FILES 取得的 HTTP 檔案上傳的項目陣列
 * @param allowExt 允許上傳檔案的擴展名,預設 'jpeg', 'jpg', 'gif', 'png'
 * @param maxsize 上傳檔案容量大小限制,預設 2097152(2M * 1024 * 1024 = 2097152byte)
 * @param flag 檢查是否為真實的圖片類型(只允許上傳圖片的話),true(預設)檢查;false 不檢查
 * @param uploadPath 存放檔案的目錄,預設 uploads
 *
 * @return 回傳存放目錄 + md5 產生的檔案名稱 + 擴展名
 */
function uploadFile($fileInfo, $allowExt = array('jpeg', 'jpg', 'gif', 'png'), $maxSize = 2097152, $flag = true, $uploadPath = 'uploads') {
    // 存放錯誤訊息
    $res = array();

    // 取得上傳檔案的擴展名
    $ext = pathinfo($fileInfo['name'], PATHINFO_EXTENSION); 

    // 確保檔案名稱唯一,防止重覆名稱產生覆蓋
    $uniName = md5(uniqid(microtime(true), true)) . '.' . $ext;
    $destination = $uploadPath . '/' . $uniName;
    
    // 判斷是否有錯誤
    if ($fileInfo['error'] > 0) {
        // 匹配的錯誤代碼
        switch ($fileInfo['error']) {
            case 1:
                $res['mes'] = $fileInfo['name'] . ' 上傳的檔案超過了 php.ini 中 upload_max_filesize 允許上傳檔案容量的最大值';
                break;
            case 2:
                $res['mes'] = $fileInfo['name'] . ' 上傳檔案的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值';
                break;
            case 3:
                $res['mes'] = $fileInfo['name'] . ' 檔案只有部分被上傳';
                break;
            case 4:
                $res['mes'] = $fileInfo['name'] . ' 沒有檔案被上傳(沒有選擇上傳檔案就送出表單)';
                break;
            case 6:
                $res['mes'] = $fileInfo['name'] . ' 找不到臨時目錄';
                break;
            case 7:
                $res['mes'] = $fileInfo['name'] . ' 檔案寫入失敗';
                break;
            case 8:
                $res['mes'] = $fileInfo['name'] . ' 上傳的文件被 PHP 擴展程式中斷';
                break;
        }

        // 直接 return 無需在往下執行
        return $res;
    }

    // 檢查檔案是否是通過 HTTP POST 上傳的
    if (!is_uploaded_file($fileInfo['tmp_name']))
        $res['mes'] = $fileInfo['name'] . ' 檔案不是通過 HTTP POST 方式上傳的';
    
    // 檢查上傳檔案是否為允許的擴展名
    if (!is_array($allowExt))  // 判斷參數是否為陣列
        $res['mes'] = $fileInfo['name'] . ' 檔案類型型態必須為 array';
    else {
        if (!in_array($ext, $allowExt))  // 檢查陣列中是否有允許的擴展名
            $res['mes'] = $fileInfo['name'] . ' 非法檔案類型';
    }

    // 檢查上傳檔案的容量大小是否符合規範
    if ($fileInfo['size'] > $maxSize)
        $res['mes'] = $fileInfo['name'] . ' 上傳檔案容量超過限制';

    // 檢查是否為真實的圖片類型
    if ($flag && !@getimagesize($fileInfo['tmp_name']))
        $res['mes'] = $fileInfo['name'] . ' 不是真正的圖片類型';

    // array 有值表示上述其中一項檢查有誤,直接 return 無需在往下執行
    if (!empty($res))
        return $res;
    else {
        // 檢查指定目錄是否存在,不存在就建立目錄
        if (!file_exists($uploadPath))
            mkdir($uploadPath, 0777, true);
        
        // 將檔案從臨時目錄移至指定目錄
        if (!@move_uploaded_file($fileInfo['tmp_name'], $destination))  // 如果移動檔案失敗
            $res['mes'] = $fileInfo['name'] . ' 檔案移動失敗';

        $res['mes'] = $fileInfo['name'] . ' 上傳成功';
        $res['dest'] = $destination;

        return $res;
    }
}

PHP 多檔案上傳 – 封装成 class

檔案上傳頁面 – upload.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>PHP 多檔案上傳 - 封装成 class</title>
</head>
<body>
    
<form action="doAction.php" method="post" enctype="multipart/form-data">
    <!-- 限制上傳檔案的最大值 -->
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152">

    <!-- accept 限制上傳檔案類型。多檔案上傳 name 的屬性值須定義為 array -->
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">
    <input type="file" name="myFile[]" accept="image/jpeg,image/jpg,image/gif,image/png" style="display: block;margin-bottom: 5px;">

    <!-- 使用 html 5 實現單一上傳框可多選檔案方式,須新增 multiple 元素 -->
    <!-- <input type="file" name="myFile[]" id="" accept="image/jpeg,image/jpg,image/gif,image/png" multiple> -->

    <input type="submit" value="上傳檔案">
</form>

</body>
</html>

表單接收頁面 – doAction.php

<?php
/**
 * 表單接收頁面
 */

// 網頁編碼宣告(防止產生亂碼)
header('content-type:text/html;charset=utf-8');
// 封裝好的 PHP 多檔案上傳 class
include_once 'upload.class.php';

$upload = new Upload();
$upload->callUploadFile();

echo $upload->getDestination();  // 取得實際儲存檔名路徑

類別 – upload.class.php

<?php
/**
 * 單一及多檔案上傳
 *
 * @author  smalljacky 
 * @version 1.0
 */

class Upload
{
    /**
     * 檢查上傳檔案是否為允許的類型
     *
     * @var array
     */
    private $allowMIME;

    /**
     * 允許上傳檔案的擴展名
     *
     * @var array
     */
    private $allowExt;

    /**
     * 上傳檔案容量大小限制
     *
     * @var int
     */
    private $maxSize;

    /**
     * 檢查是否為真實的圖片類型(只允許上傳圖片的話)
     *
     * @var boolean
     */
    private $flag;

    /**
     * 存放檔案的目錄
     *
     * @var string
     */
    private $uploadPath;

    /**
     * $_FILES 取得的 HTTP 檔案上傳項目
     *
     * @var array
     */
    private $fileInfo;

    /**
     * 上傳檔案訊息
     *
     * @var array
     */
    private $res;

    /**
     * 實際儲存檔名路徑
     *
     * @var array
     */
    private $uploadFiles;

    /**
     * 儲存擴展名
     *
     * @var string
     */
    private $ext;

    /**
     * 檔案限制設定
     *
     * @param  array $allowMIME
     * @param  array $allowExt
     * @param  int $maxSize
     * @param  boolean $flag
     * @param  string $uploadPath
     */
    public function __construct(array $allowMIME = array('image/jpeg', 'image/png', 'image/gif'), array $allowExt = array('jpeg', 'jpg', 'gif', 'png'), $maxSize = 2097152, $flag = true, $uploadPath = 'uploads')
    {
        $this->fileInfo = $this->getFiles();
        $this->allowMIME = $allowMIME;
        $this->allowExt = $allowExt;
        $this->maxSize = $maxSize;
        $this->flag = $flag;
        $this->uploadPath = $uploadPath;
    }

    /**
     * 將實際儲存檔名存入 array
     *
     * @return void
     */
    public function callUploadFile()
    {
        $res = '';

        foreach ($this->fileInfo as $file) {
            $res = $this->uploadFile($file);
            $this->showMessage();   // 顯示上傳訊息

            if (!empty($this->res['dest'])) {
                $this->uploadFiles[] = $res['dest'];
            }

            $this->res = array();  // 清除所有訊息
        }
    }

    /**
     * 取得實際儲存檔名路徑
     *
     * @return array
     */
    public function getDestination()
    {
        if (!empty($this->uploadFiles)) {
            print_r($this->uploadFiles);
        }
    }

    /**
     * 判斷上傳單一或多個檔案,並重新建構上傳檔案的 array
     * 
     * @return array
     */
    protected function getFiles()
    {
        $i = 0;  // 遞增 array 數量

        foreach ($_FILES as $file) {
            // string 型態,表示上傳單一檔案
            if (is_string($file['name'])) {
                $files[$i] = $file;
                $i++;
            }
            // array 型態,表示上傳多個檔案
            elseif (is_array($file['name'])) {
                foreach ($file['name'] as $key => $value) {
                    $files[$i]['name'] = $file['name'][$key];
                    $files[$i]['type'] = $file['type'][$key];
                    $files[$i]['tmp_name'] = $file['tmp_name'][$key];
                    $files[$i]['error'] = $file['error'][$key];
                    $files[$i]['size'] = $file['size'][$key];
                    $i++;
                }
            }
            return $files;
        }
    }

    /**
     * 單一及多檔案上傳,並回傳存放目錄 + md5 產生的檔案名稱 + 擴展名
     *
     * @return array
     */
    private function uploadFile($file)
    {
        $uniName = '';
        $destination = '';

        if ($this->checkError($file) && $this->checkHttpPost($file) && $this->checkMIME($file) && $this->checkExt($file) && $this->checkSize($file) && $this->checkTrueImg($file)) {
            $this->checkUploadPath();
            $uniName = $this->getUniName();
            $destination = $this->uploadPath . '/' . $uniName . '.' . $this->ext;
            
            if (!@move_uploaded_file($file['tmp_name'], $destination)) {
                $this->res['error'] = $file['name'] . '檔案移動失敗';
            } else {
                $this->res['succ'] = $file['name'] . '上傳成功';
                $this->res['dest'] = $destination;
            }
        }
        return $this->res;
    }

    /**
     * 檢查上傳檔案是否有錯誤
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    protected function checkError($file)
    {
        if ($file['error'] > 0) {
            switch ($file['error']) {
                case 1:
                    $this->res['error'] = $file['name'] . ' 上傳的檔案超過了 php.ini 中 upload_max_filesize 允許上傳檔案容量的最大值';
                    break;
                case 2:
                    $this->res['error'] = $file['name'] . ' 上傳檔案的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值';
                    break;
                case 3:
                    $this->res['error'] = $file['name'] . ' 檔案只有部分被上傳';
                    break;
                case 4:
                    $this->res['error'] = $file['name'] . ' 沒有檔案被上傳(沒有選擇上傳檔案就送出表單)';
                    break;
                case 6:
                    $this->res['error'] = $file['name'] . ' 找不到臨時目錄';
                    break;
                case 7:
                    $this->res['error'] = $file['name'] . ' 檔案寫入失敗';
                    break;
                case 8:
                    $this->res['error'] = $file['name'] . ' 上傳的文件被 PHP 擴展程式中斷';
                    break;
            }
            return false;
        }
        return true;
    }

    /**
     * 檢查檔案是否是通過 HTTP POST 上傳的
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    private function checkHttpPost($file)
    {
        if (!is_uploaded_file($file['tmp_name'])) {
            $this->res['error'] = $file['name'] . '檔案不是通過 HTTP POST 方式上傳的';
            return false;
        }
        return true;
    }

    /**
     * 檢查上傳檔案是否為允許的類型
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    private function checkMIME($file)
    {
        if (!in_array($file['type'], $this->allowMIME)) {
            $this->res['error'] = $file['name'] . '不是允許的檔案類型';
            return false;
        }
        return true;
    }

    /**
     * 檢查上傳檔案是否為允許的擴展名
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    private function checkExt($file)
    {
        $this->ext = pathinfo($file['name'], PATHINFO_EXTENSION);  // 取得上傳檔案的擴展名

        // 檢查上傳檔案是否為允許的擴展名、及參數是否為陣列
        if (!is_array($this->allowExt)) {  
            $this->res['error'] = $file['name'] . ' 檔案類型型態必須為 array';
            return false;
        } else {
            // 檢查陣列中是否有允許的擴展名
            if (!in_array($this->ext, $this->allowExt)) {
                $this->res['error'] = $file['name'] . ' 非法檔案類型';
                return false;
            }
        }
        return true;
    }

    /**
     * 檢查上傳檔案的容量大小是否符合規範
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    private function checkSize($file)
    {
        if ($file['size'] > $this->maxSize) {
            $this->res['error'] = $file['name'] . '上傳檔案容量超過限制';
            return false;
        }
        return true;
    }

    /**
     * 檢查是否為真實的圖片類型
     *
     * @param  array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
     * @return boolean
     */
    private function checkTrueImg(array $file)
    {
        if ($this->flag) {
            if (!@getimagesize($file['tmp_name'])) {
                $this->res['error'] = $file['name'] . '不是真正的圖片類型';
                return false;
            }
            return true;
        }
    }

    /**
     * 檢查指定目錄是否存在,不存在就建立目錄
     *
     * @return void
     */
    private function checkUploadPath()
    {
        if (!file_exists($this->uploadPath)) {
            mkdir($this->uploadPath, 0777, true);
        }
    }

    /**
     * 產生唯一的檔案名稱
     *
     * @return string
     */
    private function getUniName()
    {
        return md5(uniqid(microtime(true), true));
    }

    /**
     * 顯示上傳訊息
     *
     * @return void
     */
    private function showMessage()
    {
        if (!empty($this->res['error'])) {
            echo '<span style="color: #ff0000;">' . $this->res['error'] . '</span><br />';
        } else {
            echo '<span style="color: #0000ff;">' . $this->res['succ'] . '</span><br />';
        }
    }
}


12 則評論 to “PHP 檔案上傳、多檔案上傳”

  1. 洪榮隆 說道:

    先進大大好:
    我是php初學者,
    學習您發表的PHP 檔案上傳、多檔案上傳 範例,受益匪淺銘記在心,唯執行
    多檔案上傳 – 封装成 function之upload.func.php
    後出現錯誤 Parse error: syntax error, unexpected ‘dest’ (T_STRING) in upload-multi/function-upload.func.php on line 118
    雖然很用心去找有關$res[‘dest’] 的設定,都無法解決,懇請大大指導,
    再次感謝.

    • SmallJacky 說道:

      我下載後執行並無 error。
      你應該是有修改程式但沒修改好,因為你錯誤訊息顯示的檔案名稱與我原先定義的也不一樣了。
      建議你下載後不作修改先執行看看是否正常,在修改成你所需的方式。

      如還有任何問題,可再提問,謝謝!

  2. 洪榮隆 說道:

    大大感謝您回復:
    重新下載後不作修改先執行真的是OK.
    因為上傅相片副檔名大寫(.JPG),被判定為非法檔案類型。
    執行結果:(成功執行完成)
    沒有檔案被上傳(沒有選擇上傳檔案就送出表單)
    沒有檔案被上傳(沒有選擇上傳檔案就送出表單)
    IMG_0621.jpg 上傳成功
    IMG_0621 1.JPG 非法檔案類型
    Array ( [0] => uploads/876bc42264d9f2ec3fe2765c7890fb5d.jpg )
    於是我嘗試修改upload.func.php 第43行,function uploadFile($fileInfo, $allowExt = array(‘jpeg’, ‘jpg’, ‘gif’, ‘png’)…….中$allowExt 加入大寫副檔名
    $allowExt = array(‘jpeg’, ‘jpg’, ‘gif’, ‘png’, ‘JPEG’, ‘JPG’, ‘GIF’, ‘PNG’) 後就不行了。
    執行結果:
    Parse error: syntax error, unexpected ‘dest’ (T_STRING) in C:\AppServ\www\T1\upload-multi-function\upload.func.php on line 118
    請大大再次指導,謝謝!

    • SmallJacky 說道:

      你不能針對「副檔名」大小寫修改,而是要針對上傳檔案的「副檔名」做修改,

      小提醒:
      1. 如果要將檔名存到 DB 時的「副檔名」有大小寫,那要讀出資料是不是又要判斷「擴展名」的大小寫。
      2. 存放至伺服器檔案,建議都使用小寫(除非特別需求)

      PS:嘗試修改第 48 行,將「副檔名」轉換為小寫。

      如還有任何問題,可再提問,謝謝!

  3. PEI P 說道:

    版主你好~~
    可以請教關於PHP製作網站的一些問題嗎?
    就是我想在網站從管理者的角度嵌入YOUTUBE的影片
    (管理者也是使用者的一個,不能開後台)
    我該怎麼讓那段程式碼寫進後台並能讓影片視窗呈現在網站上呢?

  4. PEI P 說道:

    謝謝版主的耐心回復><

  5. PEI P 說道:

    謝謝版主的耐心回復><
    阿阿,版主不好意思,我好像真的說得有點模糊
    網站有後台,就是想要問是否可以從後台直接將程式碼藉由輸入的方式寫進整個網站的程式碼裡面,具體來說,就是今天我是網站的管理者,我從YOUTUBE取得嵌入的程式後,輸入後可以直接看到那個影片這樣(^^)v
    謝謝版主:)

  6. 訪客 說道:

    非常感謝

發表迴響