勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

formのinput="file"でディレクトリを選択させ、ディレクトリ内のファイルを全てアップロードする方法

  PHP HTML

フォームで複数のファイルをアップロードしたい場合、input="file"を複数設置するもしくはファイルをzip圧縮してもらってzipファイル形式でアップロードする方法を取っていた。調べたところinput="file"でディレクトリを選択させる方法が見つかった。以下に実装方法をメモ。

 

リファレンス

PHP側

https://www.php.net/manual/ja/features.file-upload.multiple.php

HTML側

https://developer.mozilla.org/ja/docs/Web/API/HTMLInputElement/webkitdirectory

input="file"にwebkitdirectoryプロパティを追加することでディレクトリが選択できるようになるみたい。

 

ソースコード

フォーム側(index.php)

<html lang="ja">
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="file[]" id="file" webkitdirectory>
        <input type="submit" name="submit" value="送信">
        <div id="hidden"></div>
    </form>
</body>
</html>

webkitdirectoryプロパティを付与するのとnameはfile[]と配列型にすること。

アップロード側(upload.php)

<?php
require_once 'class.upload.php';

$lang = 'ja_JP';

$file_ary = array();
$file_count = count($_FILES['file']['name']);
$file_keys = array_keys($_FILES['file']);

for( $i = 0; $i < $file_count; $i++ ){
    foreach( $file_keys as $key ) {
        $file_ary[$i][$key] = $_FILES['file'][$key][$i];
    }
}

$count = 0;
foreach( $file_ary as $file ){

    $count++;
    $handle = new \Verot\Upload\Upload($file, $lang);

    if( $handle->uploaded ){

        //ファイル名の変更
        $handle->file_new_name_body = date('YmdHis_' . $count);

        //同一ファイル名の場合は上書き
        $handle->file_overwrite = true;

        //アップロードするディレクトリ指定
        $handle->process('./file/');
        if( $handle->processed ){
            //成功処理
            echo 'success';

        }else{
            //エラー処理
            echo $handle->error;
        }

    }else{
        //エラー処理
        echo $handle->error;
    }

}

解説

複数ファイルを送信した際にPHP側では以下の形で受け取ることになる。

array(1) {
  ["file"]=>
  array(5) {
    ["name"]=>
    array(2) {
      [0]=>
      string(8) "test.txt"
      [1]=>
      string(9) "test2.txt"
    }
    ["type"]=>
    array(2) {
      [0]=>
      string(10) "text/plain"
      [1]=>
      string(10) "text/plain"
    }
    ["tmp_name"]=>
    array(2) {
      [0]=>
      string(14) "/tmp/phpCeNojc"
      [1]=>
      string(14) "/tmp/phpqrHtpX"
    }
    ["error"]=>
    array(2) {
      [0]=>
      int(0)
      [1]=>
      int(0)
    }
    ["size"]=>
    array(2) {
      [0]=>
      int(4)
      [1]=>
      int(5)
    }
  }
}

このような形だと処理しづらいので以下部分で整形している。

$file_ary = array();
$file_count = count($_FILES['file']['name']);
$file_keys = array_keys($_FILES['file']);

for( $i = 0; $i < $file_count; $i++ ){
    foreach( $file_keys as $key ) {
        $file_ary[$i][$key] = $_FILES['file'][$key][$i];
    }
}

整形後は以下のような見慣れた形になる。

array(2) {
  [0]=>
  array(5) {
    ["name"]=>
    string(8) "test.txt"
    ["type"]=>
    string(10) "text/plain"
    ["tmp_name"]=>
    string(14) "/tmp/phpqoEkKv"
    ["error"]=>
    int(0)
    ["size"]=>
    int(4)
  }
  [1]=>
  array(5) {
    ["name"]=>
    string(9) "test2.txt"
    ["type"]=>
    string(10) "text/plain"
    ["tmp_name"]=>
    string(14) "/tmp/phpfelQzi"
    ["error"]=>
    int(0)
    ["size"]=>
    int(5)
  }
}

 

所感

今回はディレクトリ内のファイルを全部アップロードするという形だったが、ディレクトリ構造丸ごとアップロードもできるらしい。こちらも後日試してみたいところ。

 - PHP HTML

  関連記事

lazyload.js等のライブラリを使わずHTMLのみで画像の遅延読み込みを行う方法

画像を遅延読み込みさせるとなるとだいぶ前に書いたlazyload.jsを用いる方 ...

FileReader APIを用いて画像をアップロードせずにサムネイル表示

以前にFile APIを用いてファイル名やサイズ、形式(拡張子)を取得するメモを ...

スマホでフォームの画像アップロード部分でカメラを起動させる方法

formの画像アップロード部分で、スマホの場合にカメラで撮影させたい。以下に対応 ...

ajaxを使わずに非同期っぽくsubmitする

ajaxを使わずに見た目はページ遷移せず、 画像を含めたformをsubmitし ...