#はじめに
multer はファイルアップロードでよく使われる Express.js ミドルウェアです。サンプルや関連記事も多くて安定した人気です。
multer ではファイルアップロードに関して次のことが可能です。
- 単一ファイルのアップロード
- 単一エレメントからの複数ファイルのアップロード
- 複数エレメントからの複数ファイルのアップロード
npmjs.com のサンプルや説明は簡単な物しかなかったので、上の3つのケースについて簡単に試してみました。
その前に multer の基本ですが次のようにします。
- multer モジュールをロードする。
const multer = require('multer'); - multer オブジェクトを初期化する。
const upload = multer({dest:updir}); // updir はアップロード先のフォルダ(フルパス)。省略した場合は、OS の一時フォルダが使用される。 - リクエストハンドラの第2引数には multer オブジェクトのオプションを設定する。
router.post('/single', upload.single('file1'), (req, res) => { .. });
#multer の初期化
multer を使う場合、アップロード先のフォルダを指定しておく必要があります。ただし、これは省略可能で省略すると OS で決まる一時フォルダが使用されます。
const path = require('path');
const multer = require('multer');
const updir = path.dirname(__dirname).replace(/\\/g, "/") + "/tmp"; // アプリケーションフォルダのサブディレクトリ "./tmp" をアップロード先にしている。
const upload = multer({dest:updir});
##単一ファイルのアップロード
フォームに 1 つの input[type="file"] エレメントがあり、multiple 属性がない場合の例です。POST ハンドラの第二引数に upload.single('file1') を指定します。ただし、"file1" は input[type="file"] エレメントの name 属性です。
router.post('/single', upload.single('file1'), (req, res) => {
const path = req.file.path.replace(/\\/g, "/");
if (path) {
const dest = updir + "/" + req.file.originalname;
fs.renameSync(path, dest); // 長い一時ファイル名を元のファイル名にリネームする。
res.render('upload', {message: `${dest} にアップロードされました。`});
}
else {
res.render('upload', {message: "エラー:アップロードできませんでした。"});
}
});
この時のフォームは次のような感じなります。
<form id="form1" method="POST" enctype="multipart/form-data" action="/upload/single">
<fieldset class="form-group">
<label for="file1">アップロードファイル (1)</label>
<input type="file" id="file1" name="file1" class="form-control" />
</fieldset>
<fieldset class="form-group">
<input type="submit" id="submitButton" name="submitButton" class="btn btn-primary" value=" 送信 " />
</fieldset>
</form>
<p class="message" id="message"><%= message %></p>
##複数ファイルのアップロード
複数ファイルをアップロードする場合は、post ハンドラの第二引数に upload.array('file1', MAXFILES) が必要です。'file1' はフォームの input[type="file"] の name 属性、MAXFILES はアップロードできるファイルの最大数です。upload は multer オブジェクトです。
const MAXFILES = 3;
router.post('/multiple', upload.array('file1', MAXFILES), (req, res) => {
const n = req.files.length;
try {
for (let i = 0; i < n; i++) {
const path = req.files[i].path.replace(/\\/g, "/");
const dest = updir + "/" + req.files[i].originalname;
fs.renameSync(path, dest); // 長い一時ファイル名を元のファイル名にリネームする。
}
res.render('upload', {message: `${n} 個のファイルがアップロードされました。`});
}
catch (err) {
res.render('upload', {message: "エラー:アップロードできませんでした。"});
}
});
この時のフォームは次のような感じなります。input[type="file"] タグに multiple 属性が付与されています。multiple 属性を設定すると、ファイル選択ダイアログで Ctrl キーを押しながら複数ファイルを選択できます。
<form id="form1" method="POST" enctype="multipart/form-data" action="/upload/multiple">
<fieldset class="form-group">
<label for="file1">アップロードファイル (1)</label>
<input type="file" id="file1" name="file1" class="form-control" multiple />
</fieldset>
<fieldset class="form-group">
<input type="submit" id="submitButton" name="submitButton" class="btn btn-primary" value=" 送信 " />
</fieldset>
</form>
<p class="message" id="message"><%= message %></p>
##複数エレメントからのアップロード
フォームには複数の input[type="file"] がある場合がありますが、そういう場合は post ハンドラの第二引数に upload.fields(namedOption) が必要です。upload は multer オブジェクトです。namedOption は、複数 input[type="file"] の指定とアップロードできるファイルの最大数の一覧です。
const MAXFILES = 3;
const namedOption = [
{'name':'file1', maxCount:1}, {'name':'file2', maxCount:MAXFILES}
];
router.post('/named', upload.fields(namedOption), (req, res) => {
// file1
const path1 = req.files['file1'][0].path.replace(/\\/g, "/");
if (path1) {
const dest1 = updir + "/" + req.files['file1'][0].originalname;
fs.renameSync(path1, dest1); // 長い一時ファイル名を元のファイル名にリネームする。
}
else {
res.render('upload', {message: "エラー:アップロードできませんでした。(file1)"});
return;
}
// file2
const n = req.files['file2'].length;
for (let i = 0; i < n; i++) {
let path2 = req.files['file2'][i].path.replace(/\\/g, "/");
let dest2 = updir + "/" + req.files['file2'][i].originalname;
fs.renameSync(path2, dest2);
}
res.render('upload', {message: `${n+1} 個のファイルがアップロードされました。`});
});
この時のフォームは次のような感じなります。input[type="file"] (name="file2") タグに multiple 属性が付与されています。multiple 属性を設定すると、ファイル選択ダイアログで Ctrl キーを押しながら複数ファイルを選択できます。
<form id="form1" method="POST" enctype="multipart/form-data" action="/upload/multiple">
<fieldset class="form-group">
<label for="file1">アップロードファイル (1)</label>
<input type="file" id="file1" name="file1" class="form-control" />
</fieldset>
<fieldset class="form-group">
<label for="file1">アップロードファイル (2)</label>
<input type="file" id="file2" name="file2" class="form-control" multiple />
</fieldset>
<fieldset class="form-group">
<input type="submit" id="submitButton" name="submitButton" class="btn btn-primary" value=" 送信 " />
</fieldset>
</form>
<p class="message" id="message"><%= message %></p>
ファイルアップロード express-form-data 編もあります。
終わり