ラボ > PHP:HTML、Javascript絡み、Javascript関連:form、HTML:form関連

JS・PHP・HTML 大きいファイルをアップロード(JSのライブラリは無し)

分割アップロードとか・・・そんなヤツ。ライブラリは使わない。

作成日:2021-11-22, 更新日:2024-03-29

基本

JSのライブラリとかを使えばラク・・・なんだけど、環境や大人の事情によって使えないライブラリの使用がNGというコトもある

やりたいこと

  • 大きいファイルをアップ
  • その後、form送信

流れ

  1. 送信ボタンでまずファイルを分割して、アップロード(※ファイルは分割したままでOK)
  2. 分割アップロードが終わったら、form全体を送信

送信ボタンでまずファイルを分割して、アップロード

「await fetch()」とか使っているが詳細不明。
ajaxでやったほうが理解しやすいけど、時間的な問題でどっかのサイトで見つけたソースをベースにカスタマイズ

分割アップロードが終わったら、form全体を送信

アップされたファイルから何かしたいなら、ココで処理。

サンプル

HTML + JS

<form method="post" action="uploads.php">
  <input type="text" name="hoge" />
  <input type="file" name="ori_file" />
  <input type="button" value="送信" />
</form>

<script>
  let chunk_upload = async function(elm){
    let slice_size = 5 * 1024 * 1024; // 分割サイズ(5MB)

    let file = elm.prop('files')[0];
    let size = file.size;
    let count = Math.ceil(size / slice_size);
    let postForm = null;
    let splitData = null;
    let result = null;
    let flg_err = false;
    for (let k=0; k < count; k++) {
      if ( flg_err ) {
        break;
      }

      splitData = file.slice(k * slice_size, (k + 1) * slice_size);
      postForm = new FormData();
      postForm.append('chunk_file', splitData); // 分割したファイルデータ
      postForm.append('chunk', k);

      result = await fetch('chunk_upload.php', {
        body: postForm,
        method: 'POST',
        headers: { Accept: 'application/json' }
      }).then(res => res.json()) // ← 決め打ちで必要っぽい
      .then(result => { // ← PHPで出力したJSONはココにいる
        if ( result.err != undefined && result.err != '' ) {
          alert(result.err);
          flg_err = true;
        }
      });
      await new Promise(res => setTimeout(() => {
        res(); // ← 詳細不明。コイツがいないとダメっぽい
      }, 1000));
    }

    if ( !flg_err ) {
      jQuery('[name="ori_file"]').val(''); // formからfileを削除
      $('form').submit(); // 残りをform送信
    }
    return false;
  }

  jQuery('[type="button"]').on('click', function(){
    if ( jQuery('[name="ori_file"]').val() == '' ) {
      alert('ファイルを選択してください。');
      return false;
    }
    chunk_upload(jQuery(jQuery('[name="ori_file"]')[0]));
  });
</script>

chunk_upload.php

分割されたファイルを任意のトコに保存。

// function exceptions_error_handler($severity, $message, $filename, $lineno) { // 全体で設定済みなら不要
//   throw new ErrorException($message, 0, $severity, $filename, $lineno);
// }

function temporary_chunk_upload() {
  $result = array(
    'err' => '',
  );

  $chunk = (int) $_POST['chunk'];
  $to_path   = __DIR__ . 'uploads';
  $fileName  = 'chunk' . $chunk . '.txt'; // chunk0.txt、chunk1.txt・・・みたいな感じにしたい
  $file_path = $to_path . '/' . $fileName;

  try {
    // waringも例外に飛ばす
    // set_error_handler('exceptions_error_handler', E_WARNING); // 全体で設定されているならこのまま

    if( $_FILES['chunk_file']['tmp_name'] == '' ) {
      throw new Exception('ファイルを指定してください。');
    }
    $url = $_FILES['chunk_file']['tmp_name'];

    file_put_contents($file_path, @file_get_contents($url)); // ファイルを合体させるなら上書き設定
  }
  catch (Exception $e) {
    $result['err'] = $e->getMessage();
  }

  echo json_encode($result);
  exit;
}
temporary_chunk_upload();

uploads.php

ファイルのアップが終わったあとのform送信の受け口

// ▼分割したファイルはココの中にいる
$from_path = __DIR__ . 'uploads';

// ▼formに入力された値
$post_hoge = $_POST['hoge'];

関連項目