php文件上傳與下載(附封裝好的函數文件)

来源:https://www.cnblogs.com/chenyingying0/archive/2020/01/13/12189088.html
-Advertisement-
Play Games

單文件上傳前端頁面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Upload A File</title> </head> <body> <form action="upload.php" method= ...


單文件上傳
前端頁面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload A File</title>
    </head>
    <body>
        <form action="upload.php" method="post" enctype="multipart/form-data">
            <input type="hidden" name="MAX_FILE_SIZE" value="1024000" />
            <input type="file" name="test_pic" />
            <input type="submit" value="上傳" />
        </form>
    </body>
    </html>

後端實現upload.php

    <?php
    /**
     * Created by PhpStorm.
     * Date: 2018/11/11
     * Time: 14:06
     */

    // 接收$_FILES數組
    $key = 'test_pic';
    $mimeWhiteList = ['image/jpeg', 'image/png', 'image/gif'];//文件映射白名單
    $extWhiteList = ['jpeg', 'jpg', 'png', 'gif'];//文件擴展名白名單
    $allowSize = 2*1024*1024;
    $destDir = './uploads';

    $name = $_FILES[$key]['name']; // 源文件名稱
    $type = $_FILES[$key]['type']; // MIME 類型
    $tmpName = $_FILES[$key]['tmp_name']; // 臨時文件名稱
    $error = $_FILES[$key]['error']; // 錯誤信息
    $size = $_FILES[$key]['size']; // 文件大小 位元組

    // 處理錯誤
    // 0 - 無錯誤
    if ($error > UPLOAD_ERR_OK) {
        switch($error) {
            // 1 - 文件大小超出了php.ini當中的upload_max_filesize的大小
            case UPLOAD_ERR_INI_SIZE:
                exit('文件大小超出了php.ini當中的upload_max_filesize的大小');
            // 2 - 超出表單當中的MAX_FILE_SIZE的大小
            case UPLOAD_ERR_FORM_SIZE:
                exit('超出表單當中的MAX_FILE_SIZE的大小');
            // 3 - 部分文件被上傳
            case UPLOAD_ERR_PARTIAL:
                exit('部分文件被上傳');
            // 4 - 沒有文件被上傳
            case UPLOAD_ERR_NO_FILE:
                exit('沒有文件被上傳');
            // 6 - 臨時目錄不存在
            case UPLOAD_ERR_NO_TMP_DIR:
                exit('臨時目錄不存在');
            // 7 - 磁碟寫入失敗
            case UPLOAD_ERR_CANT_WRITE:
                exit('磁碟寫入失敗');
            // 8 - 文件上傳被PHP擴展阻止
            case UPLOAD_ERR_EXTENSION:
                exit('文件上傳被PHP擴展阻止');
            default:
                exit('未知錯誤');
        }
    }

    // 限制文件的MIME
    if (!in_array($type, $mimeWhiteList)) {
        exit('文件類型' . $type . '不被允許!');
    }

    // 限制文件的擴展名
    $ext = pathinfo($name, PATHINFO_EXTENSION);
    if (!in_array($ext, $extWhiteList)) {
        exit('文件擴展名' . $ext . '不被允許!');
    }

    // 限制文件大小
    if ($size > $allowSize) {
        exit('文件大小 ' . $size . ' 超出限定大小 ' . $allowSize . ' !');
    }

    // 生成新的隨機文件名稱
    // md5(rand());
    $fileName = uniqid() . '.' . $ext;

    // 移動臨時文件到指定目錄當中並重新命名文件名
    if (!file_exists($destDir)) {
        mkdir($destDir, 0777, true);
    }
    if (is_uploaded_file($tmpName) && move_uploaded_file($tmpName, $destDir . '/' . $fileName)) {
        echo "恭喜,文件上傳成功";
    } else {
        echo "很抱歉,文件上傳失敗";
    }

多文件上傳,指定文件數量
前端頁面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload Multiple Files</title>
    </head>
    <body>
    <form action="multiple_upload.php" method="post" enctype="multipart/form-data">
        <input type="hidden" name="MAX_FILE_SIZE" value="1024000" />
        <input type="file" name="test_pic1" />
        <input type="file" name="test_pic2" />
        <input type="file" name="test_pic3" />
        <input type="submit" value="上傳" />
    </form>
    </body>
    </html>

後端實現multiple_upload.php

    <?php
    /**
     * Created by PhpStorm.
     * Date: 2018/11/11
     * Time: 14:54
     */

    $errors = [];
    $mimeWhiteList = ['image/jpeg', 'image/png', 'image/gif'];
    $extWhiteList = ['jpeg', 'jpg', 'png', 'gif'];
    $allowSize = 2*1024*1024;
    $destDir = './uploads';

    foreach($_FILES as $key => $val) {
        // name type tmp_name error size
        // 接收$_FILES
        $name = $_FILES[$key]['name']; // 源文件名稱
        $type = $_FILES[$key]['type']; // MIME 類型
        $tmpName = $_FILES[$key]['tmp_name']; // 臨時文件名稱
        $error = $_FILES[$key]['error']; // 錯誤信息
        $size = $_FILES[$key]['size']; // 文件大小 位元組

        // 處理錯誤
        // 0 - 無錯誤
        if ($error > UPLOAD_ERR_OK) {
            switch($error) {
                // 1 - 文件大小超出了php.ini當中的upload_max_filesize的大小
                case UPLOAD_ERR_INI_SIZE:
                    $errors[$key] = '文件大小超出了php.ini當中的upload_max_filesize的大小';
                    continue 2;
                // 2 - 超出表單當中的MAX_FILE_SIZE的大小
                case UPLOAD_ERR_FORM_SIZE:
                    $errors[$key] = '超出表單當中的MAX_FILE_SIZE的大小';
                    continue 2;
                // 3 - 部分文件被上傳
                case UPLOAD_ERR_PARTIAL:
                    $errors[$key] = '部分文件被上傳';
                    continue 2;
                // 4 - 沒有文件被上傳
                case UPLOAD_ERR_NO_FILE:
                    $errors[$key] = '沒有文件被上傳';
                    continue 2;
                // 6 - 臨時目錄不存在
                case UPLOAD_ERR_NO_TMP_DIR:
                    $errors[$key] = '臨時目錄不存在';
                    continue 2;
                // 7 - 磁碟寫入失敗
                case UPLOAD_ERR_CANT_WRITE:
                    $errors[$key] = '磁碟寫入失敗';
                    continue 2;
                // 8 - 文件上傳被PHP擴展阻止
                case UPLOAD_ERR_EXTENSION:
                    $errors[$key] = '文件上傳被PHP擴展阻止';
                    continue 2;
                default:
                    $errors[$key] = '未知錯誤';
                    continue 2;
            }
        }

        // 限制MIME
        if (!in_array($type, $mimeWhiteList)) {
            $errors[$key] = '文件類型' . $type . '不被允許!';
            continue;
        }

        // 限制擴展名
        $ext = pathinfo($name, PATHINFO_EXTENSION);
        if (!in_array($ext, $extWhiteList)) {
            $errors[$key] = '文件擴展名' . $ext . '不被允許!';
            continue;
        }

        // 限制大小
        if ($size > $allowSize) {
            $errors[$key] = '文件大小 ' . $size . ' 超出限定大小 ' . $allowSize . ' !';
            continue;
        }

        // 生成隨機文件名稱
        $fileName = uniqid() . '.' . $ext;

        // 移動文件
        if (!file_exists($destDir)) {
            mkdir($destDir, 0777, true);
        }
        if (!is_uploaded_file($tmpName) || !move_uploaded_file($tmpName, $destDir . '/' . $fileName)) {
            $errors[$key] = "很抱歉,文件上傳失敗";
            continue;
        }
    }

    if (count($errors) > 0) {
        var_dump($errors);
    } else {
        echo "文件全部上傳成功";
    }

多文件上傳,不定文件數量
前端頁面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload Multiple Files</title>
    </head>
    <body>
    <form action="multiple_upload2.php" method="post" enctype="multipart/form-data">
        <input type="hidden" name="MAX_FILE_SIZE" value="6024000" />
        <input type="file" name="test_pic[]" />
        <input type="file" name="test_pic[]" />
        <input type="file" name="test_pic[]" />
        <input type="submit" value="上傳" />
    </form>
    </body>
    </html>

後端實現multiple_upload2.php

    <?php
    /**
     * Created by PhpStorm.
     * Date: 2018/11/11
     * Time: 15:12
     */

    $key = 'test_pic';
    $mimeWhiteList = ['image/jpeg', 'image/png', 'image/gif'];
    $extWhiteList = ['jpeg', 'jpg', 'png', 'gif'];
    $allowSize = 2*1024*1024;
    $destDir = './uploads';

    // 接收和處理$_FILES
    if (!empty($_FILES[$key])) {
        $files = [];
        foreach($_FILES[$key]['name'] as $k => $v) {
            $files[$k]['name'] = $v;
            $files[$k]['type'] = $_FILES[$key]['type'][$k];
            $files[$k]['tmp_name'] = $_FILES[$key]['tmp_name'][$k];
            $files[$k]['error'] = $_FILES[$key]['error'][$k];
            $files[$k]['size'] = $_FILES[$key]['size'][$k];
        }
    }

    $errors = [];
    foreach($files as $file) {
        // name type error size
        $name = $file['name']; // 源文件名稱
        $type = $file['type']; // MIME 類型
        $tmpName = $file['tmp_name']; // 臨時文件名稱
        $error = $file['error']; // 錯誤信息
        $size = $file['size']; // 文件大小 位元組

        // 處理錯誤
        // 0 - 無錯誤
        if ($error > UPLOAD_ERR_OK) {
            switch($error) {
                // 1 - 文件大小超出了php.ini當中的upload_max_filesize的大小
                case UPLOAD_ERR_INI_SIZE:
                    $errors[$key] = $name . '文件大小超出了php.ini當中的upload_max_filesize的大小';
                    continue 2;
                // 2 - 超出表單當中的MAX_FILE_SIZE的大小
                case UPLOAD_ERR_FORM_SIZE:
                    $errors[$key] =  $name . '超出表單當中的MAX_FILE_SIZE的大小';
                    continue 2;
                // 3 - 部分文件被上傳
                case UPLOAD_ERR_PARTIAL:
                    $errors[$key] = $name . '部分文件被上傳';
                    continue 2;
                // 4 - 沒有文件被上傳
                case UPLOAD_ERR_NO_FILE:
                    $errors[$key] = $name . '沒有文件被上傳';
                    continue 2;
                // 6 - 臨時目錄不存在
                case UPLOAD_ERR_NO_TMP_DIR:
                    $errors[$key] = $name . '臨時目錄不存在';
                    continue 2;
                // 7 - 磁碟寫入失敗
                case UPLOAD_ERR_CANT_WRITE:
                    $errors[$key] = $name . '磁碟寫入失敗';
                    continue 2;
                // 8 - 文件上傳被PHP擴展阻止
                case UPLOAD_ERR_EXTENSION:
                    $errors[$key] = $name . '文件上傳被PHP擴展阻止';
                    continue 2;
                default:
                    $errors[$key] = $name . '未知錯誤';
                    continue 2;
            }
        }

        // 限制MIME類型
        if (!in_array($type, $mimeWhiteList)) {
            $errors[$key] = '文件類型' . $type . '不被允許!';
            continue;
        }

        // 限制擴展名
        $ext = pathinfo($name, PATHINFO_EXTENSION);
        if (!in_array($ext, $extWhiteList)) {
            $errors[$key] = '文件擴展名' . $ext . '不被允許!';
            continue;
        }

        // 限制文件大小
        if ($size > $allowSize) {
            $errors[$key] = '文件大小 ' . $size . ' 超出限定大小 ' . $allowSize . ' !';
            continue;
        }

        // 生成隨機文件名稱
        $fileName = uniqid() . '.' . $ext;

        // 移動文件
        if (!file_exists($destDir)) {
            mkdir($destDir, 0777, true);
        }
        if (!is_uploaded_file($tmpName) || !move_uploaded_file($tmpName, $destDir . '/' . $fileName)) {
            $errors[$key] = "很抱歉,文件上傳失敗";
            continue;
        }
    }

    if (count($errors) > 0) {
        var_dump($errors);
    } else {
        echo "文件全部上傳成功";
    }

文件上傳類封裝 UploadFile.php
支持多文件或者單文件

    <?php
    /**
     * Created by PhpStorm.
     * Date: 2018/11/11
     * Time: 22:01
     */

    class UploadFile
    {

        /**
         *
         */
        const UPLOAD_ERROR = [
            UPLOAD_ERR_INI_SIZE => '文件大小超出了php.ini當中的upload_max_filesize的值',
            UPLOAD_ERR_FORM_SIZE => '文件大小超出了MAX_FILE_SIZE的值',
            UPLOAD_ERR_PARTIAL => '文件只有部分被上傳',
            UPLOAD_ERR_NO_FILE => '沒有文件被上傳',
            UPLOAD_ERR_NO_TMP_DIR => '找不到臨時目錄',
            UPLOAD_ERR_CANT_WRITE => '寫入磁碟失敗',
            UPLOAD_ERR_EXTENSION => '文件上傳被擴展阻止',
        ];

        /**
         * @var
         */
        protected $field_name;

        /**
         * @var string
         */
        protected $destination_dir;

        /**
         * @var array
         */
        protected $allow_mime;

        /**
         * @var array
         */
        protected $allow_ext;

        /**
         * @var
         */
        protected $file_org_name;

        /**
         * @var
         */
        protected $file_type;

        /**
         * @var
         */
        protected $file_tmp_name;

        /**
         * @var
         */
        protected $file_error;

        /**
         * @var
         */
        protected $file_size;

        /**
         * @var array
         */
        protected $errors;

        /**
         * @var
         */
        protected $extension;

        /**
         * @var
         */
        protected $file_new_name;

        /**
         * @var float|int
         */
        protected $allow_size;

        /**
         * UploadFile constructor.
         * @param $keyName
         * @param string $destinationDir
         * @param array $allowMime
         * @param array $allowExt
         * @param float|int $allowSize
         */
        public function __construct($keyName, $destinationDir = './uploads', $allowMime = ['image/jpeg', 'image/gif'], $allowExt = ['gif', 'jpeg'], $allowSize = 2*1024*1024)
        {
            $this->field_name = $keyName;
            $this->destination_dir = $destinationDir;
            $this->allow_mime = $allowMime;
            $this->allow_ext = $allowExt;
            $this->allow_size = $allowSize;
        }

        /**
         * @param $destinationDir
         */
        public function setDestinationDir($destinationDir)
        {
            $this->destination_dir = $destinationDir;
        }

        /**
         * @param $allowMime
         */
        public function setAllowMime($allowMime)
        {
            $this->allow_mime = $allowMime;
        }

        /**
         * @param $allowExt
         */
        public function setAllowExt($allowExt)
        {
            $this->allow_ext = $allowExt;
        }

        /**
         * @param $allowSize
         */
        public function setAllowSize($allowSize)
        {
            $this->allow_size = $allowSize;
        }

        /**
         * @return bool
         */
        public function upload()
        {
            // 判斷是否為多文件上傳
            $files = [];
            if (is_array($_FILES[$this->field_name]['name'])) {
                foreach($_FILES[$this->field_name]['name'] as $k => $v) {
                    $files[$k]['name'] = $v;
                    $files[$k]['type'] = $_FILES[$this->field_name]['type'][$k];
                    $files[$k]['tmp_name'] = $_FILES[$this->field_name]['tmp_name'][$k];
                    $files[$k]['error'] = $_FILES[$this->field_name]['error'][$k];
                    $files[$k]['size'] = $_FILES[$this->field_name]['size'][$k];
                }
            } else {
                $files[] = $_FILES[$this->field_name];
            }

            foreach($files as $key => $file) {
                // 接收$_FILES參數
                $this->setFileInfo($key, $file);

                // 檢查錯誤
                $this->checkError($key);

                // 檢查MIME類型
                $this->checkMime($key);

                // 檢查擴展名
                $this->checkExt($key);

                // 檢查文件大小
                $this->checkSize($key);

                // 生成新的文件名稱
                $this->generateNewName($key);

                if (count((array)$this->getError($key)) > 0) {
                    continue;
                }
                // 移動文件
                $this->moveFile($key);
            }
            if (count((array)$this->errors) > 0) {
                return false;
            }
            return true;
        }

        /**
         * @return array
         */
        public function getErrors()
        {
            return $this->errors;
        }

        /**
         * @param $key
         * @return mixed
         */
        protected function getError($key)
        {
            return $this->errors[$key];
        }

        /**
         *
         */
        protected function setFileInfo($key, $file)
        {
            // $_FILES  name type temp_name error size
            $this->file_org_name[$key] = $file['name'];
            $this->file_type[$key] = $file['type'];
            $this->file_tmp_name[$key] = $file['tmp_name'];
            $this->file_error[$key] = $file['error'];
            $this->file_size[$key] = $file['size'];
        }


        /**
         * @param $key
         * @param $error
         */
        protected function setError($key, $error)
        {
            $this->errors[$key][] = $error;
        }


        /**
         * @param $key
         * @return bool
         */
        protected function checkError($key)
        {
            if ($this->file_error > UPLOAD_ERR_OK) {
                switch($this->file_error) {
                    case UPLOAD_ERR_INI_SIZE:
                    case UPLOAD_ERR_FORM_SIZE:
                    case UPLOAD_ERR_PARTIAL:
                    case UPLOAD_ERR_NO_FILE:
                    case UPLOAD_ERR_NO_TMP_DIR:
                    case UPLOAD_ERR_CANT_WRITE:
                    case UPLOAD_ERR_EXTENSION:
                        $this->setError($key, self::UPLOAD_ERROR[$this->file_error]);
                        return false;
                }
            }
            return true;
        }


        /**
         * @param $key
         * @return bool
         */
        protected function checkMime($key)
        {
            if (!in_array($this->file_type[$key], $this->allow_mime)) {
                $this->setError($key, '文件類型' . $this->file_type[$key] . '不被允許!');
                return false;
            }
            return true;
        }


        /**
         * @param $key
         * @return bool
         */
        protected function checkExt($key)
        {
            $this->extension[$key] = pathinfo($this->file_org_name[$key],
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • go語言基礎 雖然這本書是講goweb,但還是吧go語言基礎過了一遍,由於我之前已經對go語言基礎做了一遍系統的學習,這裡就當簡單回顧一下,不再寫過多筆記了,之前的寫的博客都有基礎知識,O(∩_∩)O哈哈~ Go是天生支持UTF 8的,任何字元都可以直接輸出,你甚至可以用UTF 8中的任何字元作為標 ...
  • 最近寫了個單元測試,遞歸調用方法,把同一個文件夾里所有的txt合併輸出到一個txt文件。參考了兩個博客,分別是已有的方法,還有個就是檢測txt文件所用編碼的技術貼。如果不檢測txt文件的編碼,那麼轉換出的txt文件大概率會亂碼。一開始嘗試UTF-8和GBK等編碼格式轉換後都是亂碼,一度以為是方法的問 ...
  • pip install pillow 基本使用 ...
  • 安裝go及配置go 安裝go 寫這篇博客時,我的電腦的windows已經安裝過了go,用的是標準包安裝,不過我的linux操作系統還沒安裝,可以考慮用第三方工具安裝,因為看了goweb這本書,我才知道安裝go有三種方式。這本書對三種操作系統的安裝方式都有介紹 Go源碼安裝:這是一種標準的軟體安裝方式 ...
  • 前言 前段時間做了一個圖床的小項目,安全框架使用的是 。為了使用戶 小時訪問,決定把項目由單機升級為集群部署架構。但是安全框架 只有單機存儲的 ,儘管 有基於 的組播/廣播實現,然而集群的分佈往往是跨網段的,甚至是跨地域的,所以尋求新的方案。 架構 方案 使用 集中存儲,實現分散式集群共用用戶信息, ...
  • 楊輝三角 楊輝三角,是二項式繫數在三角形中的一種幾何排列,中國南宋數學家楊輝1261年所著的《詳解九章演算法》一書中出現。在歐洲,帕斯卡(1623 1662)在1654年發現這一規律,所以這個表又叫做帕斯卡三角形。帕斯卡的發現比楊輝要遲393年,比賈憲遲600年。 如圖: 它的規律是,除了每一行的第一 ...
  • #定義嵌套函數 def func1(): print('this is func1') def func2(): print('this is func2')#調用1func1()輸出:this is func1上面沒有輸出this is func2,說明嵌套子函數func2()沒有被調用原因:一個 ...
  • 定時任務我想大家都不預設,現在流行的框架spring就帶了定時任何 我的個人網站(http://www.yzcopen.com)上用戶上傳的文件都是用這套定時任務執行定時清除 第一步:在applicationContext.xml中加增加以下配置代碼 <!--要調度的對象--> <bean id=" ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...