PHP 單檔案上傳、多檔案上傳教學範例

PHP

使用 PHP 上傳檔案功能在客戶端、伺服器端的配置與限制,在以 PHP 實作單檔案和多檔案上傳功能,並提供 function 與 class 二種方式的範例程式碼下載。

使用瀏覽器【上傳檔案】到伺服器是一個經常使用的重要功能,例如讓使用者上傳圖片 (jpg、.png)、文件 (.txt、.doc、.xls)、影片 (.avi、.mp4) 等檔案類型,都會使用到【上傳檔案】功能。

檔案上傳原理

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

檔案上傳配置

客戶端

必要元件和配置。

  • <form>:表單元件。
  • <input type="file">:檔案上傳元件。
  • method="post":表單發送方式。
  • enctype="multipart/form-data":表單編碼方式 (發送到伺服器之前不進行編碼)。

伺服器端

設定檔路徑

不同的作業系統,PHP 設定檔路徑也不一樣。

  • Windows (XAMPP):C:\xampp\php\php.ini。
  • Linux:/etc/php.ini。

檔案上傳參數

PHP 檔案上傳參數
參數 說明
file_uploads 是否支持 HTTP 上傳
upload_tmp_dir 保存上傳檔案的臨時目錄
upload_max_filesize 允許上傳檔案容量的最大值
max_file_uploads 允許一次上傳的最大檔案數量
post_max_size POST 方式發送資料容量的最大值

資源限制參數

PHP 資源限制參數
參數 說明
max_execution_time Script 執行的時間上限 (秒,-1 為不限制),防止程式寫得不好而耗盡伺服器資源
max_input_time Script 解析輸入資料的時間上限 (秒,-1 為不限制)
memory_limit 每個 Web 請求的最大記憶體上限
max_input_nesting_level 表單資料最大 Array 深度層數
max_input_vars 表單可接收的變數最大數量 (包含 $_GET$_POST$_COOKIE),超時將導致 E_WARNING 的產生

客戶端檔案上傳限制

檔案容量限制:

  • type="hidden":在瀏覽器隱藏元件。
  • name="MAX_FILE_SIZE":PHP 利用 MAX_FILE_SIZE 取得 value 容量限制值 (須在 <input type="file"> 之前)。
<input name="MAX_FILE_SIZE" type="hidden" value="檔案容量限制">

檔案類型限制:

  • accept:可用逗號 , 分隔來指定多值,例如 accept="image/jpeg,image/gif,image/png"。
<input type="file" name="myFile" accept="檔案類型限制">

PHP 檔案上傳變數

PHP 變數 $_FILES 保存著上傳檔案的所有資訊。

PHP $_FILES 上傳檔案資訊
名稱 說明
name 上傳檔案的名稱
type 上傳檔案的 MIME (多用途網際網路郵件擴展) 類型
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 上傳檔案的容量大小

範例

單檔上傳 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;
}

多檔上傳

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;
    }
}

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 />';
        }
    }
}

下載

參考

在〈PHP 單檔案上傳、多檔案上傳教學範例〉中有 36 則留言

  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'] 的設定,都無法解決,懇請大大指導,
    再次感謝.

    • 我下載後執行並無 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:AppServwwwT1upload-multi-functionupload.func.php on line 118
    請大大再次指導,謝謝!

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

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

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

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

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

    • 您好,請問:

      1. 網站只有前台沒有後台?
      2. 管理者可在前台將資料寫入 DB?

      我的解讀如果正確?
      我認為必須要有後台管理介面,來 CRUD。

      PS:您或許可以在講的清楚明白一點,要問的問題。

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

  5. 從文中受益良多。

    有一問題想請教,如果上傳檔案不是用WEB BROSWER,那要怎麼做 (比如手機內有自己寫的APP, 想在APP內把自己存下的一些檔案, 上傳至SERVER )

    GOOGLE了半天,有人想用get ( not post) 但被一堆人"強烈"建議不要用get. 那這樣有什麼是好的方法?

    • 一樣跟 Browser 一樣使用 POST 方式應該就可以了。

  6. 我直接下載 PHP 多檔案上傳 – 封装成 function 下來使用 可是她顯示 PHP Warning: mkdir(): Permission denied in C:inetpubwwwrootupload-multi-functionupload.func.php on line 111 錯誤

    • 它所提示的是您沒有權限,因此無法新增目錄,並非 Code 造成。
      請檢查您的權限設定是否有誤。

  7. Smalljacky 大大

    請問你有外接幫人設計網頁嗎?我有一個php 多檔案上傳網頁的想給你做。

    謝謝

    • 可以先了解 project 詳細內容嗎?
      我已將 LINE ID EMail 給您了。

      謝謝!

  8. 請問在多檔案上傳 的部分
    要在何處加判斷,才能使只要其中一個檔案不符合檢查條件或上傳失敗
    就所有其他檔案的上傳都停止動作呢?

    非常感謝~

    • 我大概修改,你可在自行調整,請確認了解整個程式流程,即可自行增修功能。

      以 "多檔上傳 class" 為例,於 upload.class.php:

      新增一 method,程式碼如下:
      /**
      * 確認所有檔案都是合法的
      *
      * @param array $files 透過 $_FILES 取得的 HTTP 檔案上傳的項目 array
      * @return boolean
      */
      public function checkAllFile()
      {
      $boo = true;
      foreach ($this->fileInfo as $file) {
      if ( $file['tmp_name'] && !( $this->checkError($file) && $this->checkHttpPost($file) && $this->checkMIME($file) && $this->checkExt($file) && $this->checkSize($file) && $this->checkTrueImg($file) ) ) {
      $boo = false;
      }
      }

      return $boo;
      }

      修改原 method:
      /**
      * 將實際儲存檔名存入 array
      *
      * @return void
      */
      public function callUploadFile()
      {
      if ( $this->checkAllFile() ) {
      $res = '';

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

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

      $this->res = array(); // 清除所有訊息
      }
      } else {
      $this->uploadFiles[] = '有不合法檔案,因此未上傳任何檔案';
      }
      }

    • 補充說明:原理其實就是先判斷所有的檔案格式是否符合條件,如有一個不符合就回傳 false。

      • 感謝版主您的耐心答覆,因為對class用法不熟,原本我是採用function的方式。
        後來看了您以class封裝的方式給的建議,

        花了幾天時間研究,終於搞懂class的大概用法了

        也成功的讓某一個上傳有問題就其他上傳都停止,
        然後再從upload.php上以get_object_var去讀取checkAllFile的布林值,
        去判斷上傳是否停止後接續要處理的其他動作

        我不知道用get_object_var的方式是否正確或恰當,
        不過總算是達成目的了

        獲益良多,非常感謝^_^

      • 什麼檔名都能上傳,您指的是副檔名嗎?
        要發問,請盡可能表達清楚問題,謝謝!

          • 在使用函數時於指定的參數 allowExt,自行定義能上傳的副檔名格式即可。
            程式碼都有加上註解了,請務必自己也清楚了解運作方式,別只是會使用而己,對日後不會有所幫助。

  9. 版主大大您好,想請問若是想把能上傳的圖片檔改成音檔,請問是否可行呢?例如把上傳的jpg 檔改成wav檔上傳,謝謝您

    • 可行。
      將您要允許的副檔名,加到陣列變數 $allowExt 內即可。

      • 您好,我現在可以成功的上傳音檔了,非常感謝,想另外請問您能夠不要更改檔名,將我的檔名維持原狀嗎?謝謝

        • 將 $uniName 改為 $uniName = $_FILES['name'];

          PS:通常伺服器都是使用產生唯一值的檔名存放並存入資料庫,因為使用者一定會上傳到相同名稱的檔案。

  10. 感謝 腳印哥的教學,對我幫助非常大,在這裡卡住很久
    而且註解的那麼詳細!! 我來好好研究研究,非常感謝腳印哥

發表留言