ラボ > PHP:HTML、Javascript絡み、ファイル関連、HTML:form関連

PHP formタグからのファイル受け取り

formでファイルを送信して、PHPで受け取る

作成日:2017-12-18, 更新日:2022-02-08

基本

html側(formタグ)

formタグに「enctype="multipart/form-data"」が必要。

<form method="post" action="〇〇〇" enctype="multipart/form-data">
   <input type="file" name="〇〇〇" />
</form>

※post送信。

PHP側

$file = $_FILES[〇〇〇];

name属性の値をキーにした配列で格納され、下記のような感じ。
・$_FILES[〇〇〇]['name']:ファイル名
・$_FILES[〇〇〇]['type']:ファイルのMIMEタイプ
・$_FILES[〇〇〇]['tmp_name']:一時保存ファイル名
・$_FILES[〇〇〇]['error']:アップロード時のエラーコード
・$_FILES[〇〇〇]['size']:ファイルサイズ(バイト単位)

処理

try {
   $name = 〇〇〇; // 対象のinputタグのname属性の値
   
   if ( isset($_FILES[$name]) ) {
      throw new RuntimeException('ファイルなし');
   }
   
   $upFile = $_FILES[$name];
   
   // =======================================
   // ▼ファイルを受信できたかチェック
   if (isset($upFile['error']) && is_int($upFile['error'])) {
      switch ($upFile['error']) {
         case UPLOAD_ERR_OK: // OK
         break;
         
         case UPLOAD_ERR_NO_FILE:    // ファイル未選択
            throw new RuntimeException('ファイルが選択されていません');
         break;
         
         case UPLOAD_ERR_INI_SIZE:   // php.ini定義の最大サイズ超過
         case UPLOAD_ERR_FORM_SIZE:  // フォーム定義の最大サイズ超過
            throw new RuntimeException('ファイルサイズが大きすぎます');
         break;
         
         default:
            throw new RuntimeException('その他のエラーが発生しました');
         break;
      }
      
      // ここで定義するサイズ上限のオーバーチェック(必要がある場合のみ)
      if ( 1000000 < $upFile['size'] ) { // バイト指定。「1000000」は約1MB(※1MB=(1024*1024)バイト)
         throw new RuntimeException('ファイルサイズが大きすぎます');
      }
   }
   else {
      throw new RuntimeException('原因不明');
   }
   
   // =======================================
   // ▼MIMEタイプチェック
   // $_FILES['upfile']['mime']の値はブラウザ側で偽装可能なのでMIMEタイプを自前でチェックする
   
   // 画像系のチェック
   $type = @exif_imagetype($_FILES['upfile']['tmp_name']);
   $chkMime = array(
      IMAGETYPE_GIF,
      IMAGETYPE_JPEG,
      IMAGETYPE_PNG,
   );
   if (!in_array($type, $chkMime, true)) {
      throw new RuntimeException('画像形式が未対応です');
   }
   
   // // ▼画像系以外のチェック
   //
   // // mimeチェックをしっかりとしない場合:拡張子のチェックのみ
   // // ※特定の人しか使わないならこういうのでも良いと思う:速度優先
   // if ( substr($upFile['name'], strpos($upFile['name'], '.') + 1) != 'zip' ) {
   //    throw new RuntimeException('ファイル形式が未対応です');
   // }
   // 
   // // // mimeチェックをしっかりとする場合
   // // $finfo    = finfo_open(FILEINFO_MIME_TYPE);
   // // $mimeType = finfo_buffer($finfo, @file_get_contents($upZip['tmp_name']));
   // // finfo_close($finfo);
   // // $chkMime = array(
   // //    'application/x-compress', 
   // //    'application/x-zip-compressed', 
   // //    'application/zip', 
   // // );
   // // if (!in_array($mimeType, $chkMime, true )) {
   // //    throw new RuntimeException('ファイル形式が未対応です');
   // // }
   
   // =======================================
   // ▼ファイルをサーバにup
   // ファイル名:ファイルデータからSHA-1ハッシュを取ってファイル名を決定する
   $fileName = sha1_file($upFile['tmp_name']) . time() . image_type_to_extension($type);
   
   // ファイルの保存先
   $path = './〇〇〇/' . $fileName;
   
   if ( !move_uploaded_file($upFile['tmp_name'], $path) ) {
      // ファイルのアップロード(move_uploaded_file())とは
      // 「一時ファイル($upFile['tmp_name'])をサーバに移動」
      // という意味になるそうだ。
      throw new RuntimeException('ファイル保存時にエラーが発生しました');
   }
   
   // ファイルのパーミッションを確実に0644に設定する
   chmod($path, 0644);
   
}
catch (RuntimeException $e) {
   echo $e->getMessage();
   exit;
}

※「$upFile」にformからやってきたファイルの諸々が格納されているので保存以外に好きにする。
※「$upFile['tmp_name']」がファイル本体になる。

関連項目