JS・PHP・HTML 大きいファイルをアップロード(JSのライブラリは無し)
分割アップロードとか・・・そんなヤツ。ライブラリは使わない。
作成日:2021-11-22, 更新日:2024-03-29
基本
JSのライブラリとかを使えばラク・・・なんだけど、環境や大人の事情によって使えないライブラリの使用がNGというコトもある
やりたいこと
- 大きいファイルをアップ
- その後、form送信
流れ
- 送信ボタンでまずファイルを分割して、アップロード(※ファイルは分割したままでOK)
- 分割アップロードが終わったら、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'];