1. 程式人生 > 實用技巧 >PHP 檔案的上傳與下載

PHP 檔案的上傳與下載

檔案上傳與下載

檔案上傳

  • 檔案上傳表單
    • 表單的提交方式必須為POST
    • enctype="multipart/form-data"
      • 說明瀏覽器可以提供檔案上傳功能
      • 該屬性提示表單中有二進位制檔案資料
      • <input type="hidden" name="max_file_size" value="30000">
        • 可以指定允許上傳檔案的最大尺寸
        • MAX_FILE_SIZE必須在檔案域的上面。
<!-- form.html -->
<form action="upload.php" enctype="multipart/form-data" method="post">
  <input type="hidden" name="max_file_size" value="30000">
  選擇檔案:<input type="file" name="userfile">
  <input type="submit" value="上傳檔案">
</form>
  • 檔案域 表單的enctype屬性

    • 預設情況下,表單傳遞是字元流,不能傳遞二進位制流
    • 通過設定表單的enctype屬性傳遞複合資料
    • enctype屬性的值有
      • application/x-www-form-urlencoded (預設)表示傳遞的是帶格式的文字資料
      • multipart/form-data 複合的表單資料(字串\檔案),檔案上傳必須設定此值
      • text/plain 用於向伺服器傳遞無格式的文字資料,主要使用者電子郵件
  • PHP處理上傳檔案

    • PHP會自動生成一個$_FILES二維陣列,該陣列儲存了上傳檔案的資訊
# upload.php
<?php
    $name= $_FILES['userfile']['name'];
    $type= $_FILES['userfile']['type'];
    $size= $_FILES['userfile']['size'];
    $tmpName= $_FILES['userfile']['tmp_name'];
    $error= $_FILES['userfile']['error'];
    echo "{$name}<br>{$type}<br>{$size}<br>{$tmpName}<br>{$error}";
?>
  • $_FILES['userfile'] 鍵值說明

    • $_FILES['userfile']['name'] 上傳檔案的名稱
    • $_FILES['userfile']['type'] 上傳檔案的MIME型別(image/jpeg、image/gif、image/png)
    • $_FILES['userfile']['size'] 上傳檔案的大小,以位元組為單位
    • $_FILES['userfile']['tmp_name'] 檔案上傳時的臨時檔案
    • $_FILES[][‘error’] 錯誤編碼(值有0、1、2、3、4、6、7)
      • 0 - 正確
      • 4 - 沒有檔案上傳
      • 1 - 檔案大小超過了php.ini中允許的最大值 upload_max_filesize = 2M
      • 2 - 檔案大小超過了表單允許的最大值
      • 3 - 只有部分檔案上傳
      • 6 - 找不到臨時檔案
      • 7 - 檔案寫入失敗
  • 與檔案上傳有關的配置

    • post_max_size = 8M 表單允許的最大值
    • upload_max_filesize = 2M 允許上傳的檔案大小
    • upload_tmp_dir =F:\wamp\tmp 指定臨時檔案地址,如果不知道作業系統指定
    • file_uploads = On 是否允許檔案上傳
    • max_file_uploads = 20 允許同時上傳20個檔案
<?php
  echo ini_get('post_max_size');
  echo ini_get('upload_max_filesize');
  echo ini_get('upload_tmp_dir');
  echo ini_get('file_uploads');
  echo ini_get('max_file_uploads');
?>
  • 將上傳檔案移動到指定位置
    • move_uploaded_file() 臨時地址,目標地址
    • 上傳的同名的檔案要給覆蓋
# upload.php
<?php
  mkdir('D:\Program Files\xampp\htdocs\uploads');
  $newDir= "uploads/".$_FILES['userfile']['name'];
  if(!empty($_POST)) {
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上傳成功";
      };
    }else{
      echo '上傳有誤';
      echo '錯誤碼:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>

優化檔案上傳

  • 更改檔名
    • 通過時間戳做檔名
    • 通過uniqid()實現
      • uniqid() 生成唯一的ID
      • uniqid('goods_') 帶有字首
      • uniqid('goods_',true) 唯一ID+隨機數
# upload.php
<?php
    # 判斷是否存在目錄
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
        mkdir($dir);
    }
    # 通過時間戳做檔名
    $newName= time().rand(100,999).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 上傳服務處理
    if(!empty($_POST)) {
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上傳成功";
            };
        }else{
            echo '上傳有誤';
            echo '錯誤碼:'.$_FILES['userfile']['error'];
            exit;
        }
    }
?>
# upload.php
<?php
    # 判斷是否存在目錄
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
        mkdir($dir);
    }
    # 通過uniqid()實現
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 上傳服務處理
    if(!empty($_POST)) {
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上傳成功";
            };
        }else{
            echo '上傳有誤';
            echo '錯誤碼:'.$_FILES['userfile']['error'];
            exit;
        }
    }
?>
  • 驗證檔案格式
    • 將檔案的字尾和允許的字尾對比 (不能識別檔案偽裝)
    • 通過$_FIELS[]['type']型別判斷 (不能識別檔案偽裝)
    • 在php.ini中開啟fileinfo擴充套件 (可以防止檔案偽裝)
# # upload.php
<?php
  if(!empty($_POST)) {
    # 判斷是否存在目錄
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通過uniqid()實現重新命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 檔名拓展名驗證
    $allow= array('.jpg','.png','.gif');
    $ext= strrchr($_FILES['userfile']['name'],'.');
    if(!in_array($ext,$allow)){
      echo '檔案上傳不合法';
      exit;
    }
    # 上傳服務處理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上傳成功";
      };
    }else{
      echo '上傳有誤';
      echo '錯誤碼:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
# upload.php
<?php
  if(!empty($_POST)) {
    # 判斷是否存在目錄
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通過uniqid()實現重新命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 檔名拓展名驗證
    $allow= array('image/jpeg','image/png','image/gif');
    $ext= $_FILES['userfile']['type'];
    if(!in_array($ext,$allow)){
      echo '檔案上傳不合法';
      exit;
    }
    # 上傳服務處理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上傳成功";
      };
    }else{
      echo '上傳有誤';
      echo '錯誤碼:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
# upload.php
<?php
  if(!empty($_POST)) {
    # 判斷是否存在目錄
    $dir= 'D:\Program Files\xampp\htdocs\uploads';
    if(!is_dir($dir)){
      mkdir($dir);
    }
    # 通過uniqid()實現重新命名
    $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
    $newDir= "uploads/".$newName;
    # 檔名拓展名驗證
    $info=finfo_open(FILEINFO_MIME_TYPE);
    $ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
    $allow= array('image/jpeg','image/png','image/gif');
    if(!in_array($ext,$allow)){
      echo '檔案上傳不合法';
      exit;
    }
    # 上傳服務處理
    if($_FILES['userfile']['error']== 0){  
      if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
        echo "上傳成功";
      };
    }else{
      echo '上傳有誤';
      echo '錯誤碼:'.$_FILES['userfile']['error'];
      exit;
    }
  }
?>
  • 優化檔案上傳
<?php
    if(!empty($_POST)) {
        # 判斷是否存在目錄
        $dir= 'D:\Program Files\xampp\htdocs\uploads';
        if(!is_dir($dir)){
            mkdir($dir);
        }
        # 通過uniqid()實現重新命名
        $newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.'); 
        $newDir= "uploads/".$newName;
        # 檔名拓展名驗證
        $info=finfo_open(FILEINFO_MIME_TYPE);
        $ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
        $allow= array('image/jpeg','image/png','image/gif');
        if(!in_array($ext,$allow)){
            echo '只能上傳 '.implode(' , ',$allow).' 等檔案格式';
            exit;
        }
        # 驗證檔案大小
        $fileSize= ini_get('upload_max_filesize');
        if(substr($fileSize, -1, 1)== 'k'){
            $fileSize= (integer)$fileSize* 1024;
        }elseif(substr($fileSize, -1, 1)== 'M'){
            $fileSize= (integer)$fileSize* 1024* 1024;
        }elseif(substr($fileSize, -1, 1)== 'G'){
            $fileSize= (integer)$fileSize* 1024* 1024* 1024;
        }elseif(substr($fileSize, -1, 1)== 'T'){
            $fileSize= (integer)$fileSize* 1024* 1024* 1024* 1024;
        }
        if($_FILES['userfile']['size']> $fileSize){
            echo '檔案大小不能超過'.number_format($fileSize/1024, 1).'K';
            exit;
        }
        # 驗證是否是http上傳
        if(!is_uploaded_file($_FILES['userfile']['tmp_name'])){
            echo '檔案不是HTTP POST上傳的<br>';
            exit;
        }
        # 上傳服務處理
        if($_FILES['userfile']['error']== 0){  
            if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
                echo "上傳成功";
            };
        }else{
            switch($_FILES['userfile']['error']) {
                case 1:
                    echo '檔案大小超過了php.ini中允許的最大值,最大值是:'.ini_get('upload_max_filesize');
                    break;  
                case 2:
                    echo '檔案大小超過了表單允許的最大值';
                    break; 
                case 3:
                    echo '只有部分檔案上傳';
                    break; 
                case 4:
                    echo '沒有檔案上傳';
                    break; 
                case 6:
                    echo '找不到臨時檔案';
                    break; 
                case 7:
                    echo '檔案寫入失敗';
                    break; 
                default:
                    echo '未知錯誤';
                    break; 
            }
        }
    }
?>

檔案下載

<?php
    header('Content-Type:text/html; charset=utf-8');
    define('ROOT_PATH', dirname(__FILE__));

    function downfile($file_path){
        $file_path= iconv('utf-8', 'gb2312', $file_path);
        if(!file_exists($file_path)){
            exit('檔案不存在!');
        }

        $file_name= basename($file_path);
        $file_size= filesize($file_path);
        $file= fopen($file_path, 'r');
        header("Content-type: application/octet-stream");
        header("Content-Disposition: attachment; filename={$file_name}");

        $buffer= 1024;
        $file_count= 0;

        while(!feof($file) && ($file_size- $file_count> 0)){
            $file_data= fread($file, $buffer);
            $file_count+= $buffer;
            echo $file_data;
        }

        fclose($file);
    }
    downfile(ROOT_PATH.".\img\pigger.jpg");
?>