フォームでファイルを添付してもらう仕組みをHTMLで書く場合、タグそのものは数行で終わります。実際に時間がかかるのはその先で、サイズの上限をどこに置くか、送られてきたものをどう検証するか、どこに保存して誰が見られるようにするかを全部自分で決めることになります。この記事では、HTMLで書ける範囲をはっきりさせたうえで、その外側にある判断を順番に並べます。受付をひとりで回している人が、自分で作るべきか既製のものを使うべきかを決められるところまでを扱います。
HTMLで書けるのは「選ばせるところ」まで
まず、HTMLの役割を正確に押さえます。HTMLが担当しているのは、ファイルを選ぶ画面を出すことと、選ばれたものをサーバーへ運ぶ形式を指定することの2つだけです。それ以外は全部、受け取る側の仕事になります。
最小の形は次のようになります。
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="doc">履歴書(PDF、10MBまで)</label>
<input type="file" id="doc" name="doc" accept=".pdf,application/pdf" required>
<button type="submit">送信する</button>
</form>
この中で外せないのが enctype の指定です。フォームの送信方式を multipart/form-data にしていないと、ファイルの中身は送られず、ファイル名だけが文字として飛びます。ファイル添付が動かないという相談で、ここが抜けているだけというのは珍しくありません。あわせて method は post です。
accept 属性は、ファイルを選ぶ画面で表示を絞り込むための指定です。拡張子で書く方法と、MIMEタイプで書く方法があり、両方を並べて書けます。ここで押さえておきたいのは、accept は選ぶ画面を助けるだけで、送られてくるものを保証しないという点です。回答者がファイルの種類の表示を切り替えれば、指定していない種類のファイルも選べます。検証は受け取る側で必ず行います。
複数のファイルを受け取るなら multiple を付けます。ただし、何件まで許すのかはHTMLでは決められません。件数の上限も受け取る側で数えます。スマートフォンでカメラを直接起動させたい場合は capture 属性を使いますが、端末やブラウザによって挙動が変わるので、必ず実機で確かめます。
名前の付け方にも注意が要ります。input の name 属性は、受け取る側でその値を探すための鍵になります。複数の添付を受ける場合、名前を配列として受け取れる形にしておかないと、最後の1件だけが残って前の分が消えることがあります。1つの欄で複数選ばせるのか、欄を分けて1件ずつ受けるのかは、受け取る側の書き方とセットで決めます。
もう1つ、入力欄には必ずラベルを添えます。「ファイルを選択」というボタンの文字はブラウザが出すもので、こちらでは変えられません。何を出せばよいのかは、その隣のラベルと説明文でしか伝えられません。受け付ける形式と上限を、この位置に必ず書いておきます。
送る側の指定と、受け取る側の検証は別物
HTMLに書いた制限は、すべて回避できます。ブラウザの開発者ツールで属性を書き換えることも、フォームの画面を通さずに直接リクエストを送ることもできます。だから、受け取る側の検証は「もう一度、全部やる」のが前提です。
検証する項目は4つあります。
・サイズ。受け取った実際のバイト数で判定する ・種類。拡張子だけでなく、中身の先頭のバイト列も見る ・件数。複数受け取る設定なら、上限を超えていないかを数える ・エラーの有無。アップロードそのものが途中で失敗していないかを確かめる
種類の検証で、拡張子だけを見るのは危険です。拡張子は誰でも書き換えられます。画像として受け取ったつもりのファイルが、実際には実行できるスクリプトだった、という事故はここから起きます。中身の先頭を読んで種類を判定する仕組みは、たいていのサーバー言語に用意されています。
サイズの検証は、受け取る前に止まる場合と、受け取ったあとで判定する場合の2つがあります。サーバー側の上限を超えた分は、こちらのプログラムに届く前に切られます。切られたときにどんな応答を返すかを決めておかないと、回答者の画面には何も出ずに真っ白なページが出ます。
件数の検証も忘れがちです。複数の添付を許す欄では、1件も来ない場合、想定より多く来る場合の両方を試します。上限を決めずに受け取る作りにしておくと、まとめて数十件の画像が送られてきたときに、保存先も画面も一度に重くなります。件数の上限は、受け取ったあとに人が確認できる数から逆算します。1件の申し込みにつき5件までにしておけば、目視の確認が現実的な時間で終わります。
エラーの有無の確認も、意外に抜けます。アップロードが途中で失敗した場合、受け取る側にはファイルの入れ物だけが渡り、中身が空、あるいは途中までという状態になります。この状態を成功として扱うと、受付の一覧には書類が届いたことになっているのに、開くと壊れているという食い違いが生まれます。受け取った直後にサイズがゼロでないことと、種類の判定が通ることの2つを確かめておけば、ここは防げます。
任意の欄として添付を受ける場合、空欄で送られたときの扱いも決めます。空欄をエラーにしてしまうと、添付の要らない問い合わせができなくなります。逆に、空欄をそのまま通す作りにすると、必須のはずの書類が抜けたまま受け付けられます。必須と任意のどちらなのかは、受付の型ごとに決めます。問い合わせの窓口なら任意、応募の受付なら必須にするのが一般的です。この線引きは問い合わせの受付と採用の応募受付でそれぞれ整理しています。
上限は3か所にあり、いちばん小さい値で止まる
自分でフォームを作る場合、サイズの上限は少なくとも3か所に存在します。HTMLや画面側の案内、言語の実行環境、Webサーバーの3つです。3つのうち、いちばん小さい値が実際の上限になります。
PHPで受ける場合、公式マニュアルの設定一覧には、1ファイルあたりの上限にあたる upload_max_filesize の既定値が「2M」、送信全体の上限にあたる post_max_size の既定値が「8M」、同時に扱えるファイル数の max_file_uploads が20と記載されています。何も変えていない環境では、2MBを超えるファイルはそこで止まります。スマートフォンで撮った写真1枚が2MBを超えることは普通にあるので、写真を受け取る用途では最初に当たる壁です。
Webサーバー側にも上限があります。nginxの公式ドキュメントには次のように書かれています。
Sets the maximum allowed size of the client request body. If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client. Please be aware that browsers cannot correctly display this error. 出典: nginx.org
同じページで、この設定の既定値は1メガバイトと書かれています。注目したいのは最後の一文で、このエラーはブラウザが正しく表示できないと明記されている点です。つまり上限を超えたとき、回答者の画面には親切なメッセージではなく、意味の分からない画面が出ます。何が起きたのか分からないまま離脱するので、受付側には何も残りません。
だから上限を決めるときは、3か所を同じ値以上にそろえたうえで、超えたときの画面を自分で用意します。画面には、上限の数字と、代わりの連絡先を書きます。ここまでやって初めて「上限を設定した」と言えます。
上限をどこに置くかの目安としては、履歴書や職務経歴書のような書類なら10MB、写真を複数枚受け取るなら1枚あたり20MB程度を見ておくと、実務ではほぼ収まります。動画を受け取るなら桁が変わるので、そもそもメールやフォームで運ぶ設計を見直したほうが早くなります。
送信を押してから届くまでの間に起きること
添付つきのフォームで最も体験が悪くなるのは、送信を押したあとの数十秒です。文字だけのフォームなら一瞬で終わりますが、ファイルが乗ると回線の速さがそのまま待ち時間になります。ここで何も表示しないと、回答者は失敗したと判断してもう一度押します。
回線の目安を持っておくと、設計の判断がしやすくなります。上りの速度が10メガビット毎秒の回線で10MBのファイルを送ると、理屈のうえでも10秒前後かかります。実際には他の通信と分け合うので、それより長くなります。外出先のモバイル回線ではさらに伸びます。30秒を超えて何の反応もない画面を見せると、たいていの人は操作をやり直します。
やり直しが起きると、同じ申し込みが2件届きます。受付側では、どちらが正しいのか、両方に返信すべきなのかを判断する仕事が増えます。防ぐには3つの手当てが要ります。
・送信ボタンを押した直後にボタンを無効にして、二度押しできないようにする ・送信中であることを画面に出す。進み方が分かる表示があればなお良い ・受け取った側で、同じ内容の重複を見分けられるようにしておく
3つ目は画面の話ではなく、受け取ったあとの話です。連絡先と送信の時刻が近い2件を見分けられるようにしておかないと、重複の判定は目視になります。
もう1つ、送信の途中で通信が切れた場合の扱いも決めます。途中まで届いたファイルは、サイズだけそろっていて開けないことがあります。開けるかどうかを受け取った直後に確かめる手順を入れておかないと、選考や審査の当日になって気づくことになります。
大きなファイルを扱う予定があるなら、そもそもフォームで運ばない選択も検討します。動画や大量の写真を毎回受け取る窓口では、受付では連絡先と概要だけを取り、実物は別の手段で受け取る形に分けたほうが、双方の待ち時間が短くなります。
保存先とファイル名を先に決める
受け取ったファイルをどこに置くかは、あとから変えるのがいちばん大変な部分です。最初に決めます。
置き場所の原則は、Webから直接開ける場所に置かないことです。公開ディレクトリの下に置くと、URLを推測できた人が誰でもファイルを開けます。履歴書や身分証の画像がそこにあると、事故の規模が大きくなります。公開ディレクトリの外に置き、閲覧はログインした担当者だけが通れる経路から行う形にします。
ファイル名も、送られてきたままにしません。理由は3つあります。1つ目は、同じ名前のファイルが必ず重なるからです。応募の受付では「履歴書.pdf」という名前が大量に届きます。2つ目は、ファイル名に使われた記号や日本語が、保存先や書き出しの経路で崩れることがあるからです。3つ目は、ファイル名そのものを信用してはいけないからです。名前に細工をして、意図しない場所へ保存させる手口があります。
実務としては、保存名は推測できない文字列で付け直し、元のファイル名は別に記録として持ちます。そのうえで、どの申し込みに紐づいたファイルなのかを一緒に保存します。ここまでを最初に決めておかないと、後から「このファイルは誰の分か」を突き合わせる作業が発生します。応募が50件を超えると、この突き合わせだけで半日が消えます。
保存期間も先に決めます。受け取った書類をいつまで持つのか、選考が終わったらいつ消すのかを決めていないと、消す担当がいないまま残り続けます。個人情報を含む書類では、保管の期間と消し方まで含めて手順にしておく必要があります。何をどこまで書くべきかは扱う情報と業種で変わるので、判断に迷う場合は所管の窓口や専門家に確かめてください。制度そのものの案内は個人情報保護委員会が出しています。
メールに添付して飛ばす方式の限界
自分でフォームを作るとき、いちばん手軽に見えるのが、受け取ったファイルをそのまま担当者宛のメールに添付して送る方式です。保存の仕組みを作らなくて済むので、最初の1本はこれで動きます。ただし限界が3つあります。
1つ目が容量です。WordPressのプラグインで同じ方式を採っているContact Form 7の公式ドキュメントには、メールに添付するファイルの合計サイズには25MBの上限があり、設定がこれを超える場合は警告が出る、と書かれています。あわせて、大量のデータを運ぶことはメールの仕組みが本来想定している目的ではないため、専用のサービスを使うよう案内しています。この考え方は、自分で書いた仕組みでも同じです。プラグインを使う場合の細かい挙動はContact Form 7との比較に整理しています。
2つ目が、記録が残らないことです。メールで飛ばす方式では、受け取ったファイルは送信のあとに消される作りになっていることが多く、受信箱にしか残りません。担当者が誤ってメールを消したら、その応募の書類はもう戻りません。同じ理由で、後から「あの人の書類をもう一度見たい」と思ったときに、探す先が受信箱の検索だけになります。
3つ目が、複数人での運用に耐えないことです。届いたメールは全員に同じように見えるので、誰が対応するのかがメールの中では決まりません。返信したかどうかも受信箱からは読み取れません。受付を2人以上で回している時点で、この方式は破綻し始めます。
メールで飛ばすのは、届いたことに気づくための通知としては優れています。書類の保管と対応の管理を兼ねさせようとすると壊れます。この2つを分けて考えると、判断がはっきりします。
エラーのときに何を見せるかまでが、フォームの仕事
自分で書いたフォームで抜けやすいのが、うまくいかなかったときの画面です。成功したときの画面は必ず作りますが、失敗したときの画面は後回しになります。ところが受付の現場で問い合わせを生むのは、失敗したときの画面のほうです。
見せるべきものは3つあります。何が起きたのか、どうすれば通るのか、それでも駄目なときはどこに連絡すればよいのか、です。「エラーが発生しました」だけの画面は、この3つのどれも満たしていません。上限を超えたなら「10MBを超えています。ファイルを小さくするか、お電話でご相談ください」と書きます。種類が違うなら、受け付けている形式を並べて書きます。
さらに、失敗したときに入力済みの内容が消えないようにします。氏名も連絡先も本文も全部打ち直しになると、そこで離脱する人が出ます。特にスマートフォンからの入力では、打ち直しの負担が大きく、離脱率に直結します。ファイル欄の選択状態はブラウザの仕様で戻せないことがありますが、それ以外の欄は保持できます。
ログの残し方も決めておきます。誰がいつ何で失敗したのかが残っていないと、問い合わせを受けても再現できません。個人情報そのものではなく、時刻、エラーの種類、ファイルのサイズと種類だけを残しておけば、切り分けには足ります。
そして、失敗の件数を数えておきます。数えていない窓口では、失敗は「たまに起きること」として扱われます。数えると、上限に当たっている件数が想像よりずっと多いことに気づきます。上限を1段上げるだけで問い合わせが半分になる、という判断はここから出ます。
HTMLで自分で作るか、既製のものを使うかの分かれ目
自分で書く選択が正しい場面と、そうでない場面があります。判断の材料は4つです。
1つ目は、受け付ける件数です。年に数回、社内の数人から集めるだけなら、自分で書いた仕組みで十分です。毎日届く窓口になると、保存、検索、対応状況の管理が必要になり、作るものが一気に増えます。
2つ目は、扱う情報の重さです。氏名と連絡先だけなら、必要な備えは限られます。身分証の画像や、健康に関する情報を受け取るなら、保管、権限、消去、記録の4つを自分で設計し、維持し続けることになります。
3つ目は、作った人が居続けるかどうかです。ここは金額に換算しにくいぶん、判断から漏れます。自分で書いた仕組みには、実行環境が上がったときや保存先の仕様が変わったときに、必ず手を入れる日が来ます。そのとき手を入れられる人が社内にいるかどうかで、続けられるかが決まります。自分で書いた仕組みは、書いた人以外には直せません。担当が変わったときに誰も触れなくなり、動いているから放置される状態になります。動いているように見えて、実は通知だけ止まっていた、という事故はここから起きます。
4つ目は、受け取ったあとに何をするかです。ファイルを受け取って終わりなら、自分で書く価値があります。受け取ってから返信し、状況を追い、複数人で分担するなら、必要なのはフォームではなく受付の管理です。送信されたあとの道具がそろっているかどうかが、この段階での分かれ目になります。何が最初からそろっていると楽になるのかはできることで確かめられます。実際の画面は動くところを見るで見られます。
既製のツールを使う場合も、添付の条件は仕組みによって違います。回答者にログインを求めるかどうか、上限をいくつに設定できるか、保存先がどこになるかの3点は必ず確認してください。Googleフォームでは、アップロードの設問に回答する際に回答者がGoogleアカウントにログインする必要があると公式ヘルプに明記されています。この点の詳しい違いはGoogleフォームとの比較にまとめています。Microsoft Formsでは、ファイルのアップロード設問は組織内限定の設定でのみ利用できると公式ドキュメントに書かれており、社外から受け取る用途には条件が付きます。こちらはMicrosoft Formsとの比較で扱っています。
スマートフォンからの添付で起きること
いま、応募や問い合わせの多くはスマートフォンから送られてきます。パソコンで作って確認したフォームが、スマートフォンでは思った通りに動かないことがあるので、実機での確認は必須です。
まず、選べるものが違います。端末の中に入っている写真は選べても、メールに添付されて届いた書類は、いったん端末に保存されていないと選択の画面に出てきません。「書類が選べない」という相談の多くはこれです。案内文に「メールで届いた書類は、いったん端末に保存してから選んでください」と1行あるだけで、問い合わせが減ります。
次に、写真のサイズです。最近の端末で撮った写真は1枚で数メガバイトになります。書類を撮影して送ってもらう受付では、上限を小さくしすぎると、ほぼ全員が引っかかります。逆に上限を上げると、今度は送信の待ち時間が伸びます。書類の撮影を求めるなら、上限は20MB程度を見ておくと、撮り直しの案内をせずに済みます。
3つ目が、複数枚の選択です。写真を複数選ぶ操作は端末によって手順が違います。1枚ずつしか選べないと思い込んで、1枚だけ送って終える人もいます。複数受け取る欄には、何枚まで出せるのかと、まとめて選べることを書いておきます。
4つ目が、途中で他のアプリに切り替わったときです。ファイルを選ぶために別のアプリを開き、戻ってきたときに入力内容が消えている、という現象があります。長いフォームで添付を最後に置いていると、ここで全部やり直しになります。添付の欄は、入力項目の中で早い位置に置くほうが安全です。
最後に、確認の方法です。開発用の画面の表示を小さくして確かめるやり方では、この4つはどれも見つかりません。実際の端末で、ログインしていない状態で、公開用のURLを開いて、最後まで送信してみるところまでを1度は通してください。
受付の型ごとに、添付の作り込みどころが違う
同じ添付つきフォームでも、受付の型によって力を入れる場所が変わります。
締切のある受付では、締切の直前に送信が集中します。同じ時刻に大きなファイルが並んで届くので、上限の設定と、失敗したときの画面がそのまま完了率に効きます。締切をまたいだ扱いも先に決めておきます。この点は助成金・公募の受付に整理しています。
定員のある受付では、添付の有無で申し込みの成立が変わらないようにしておくのが安全です。添付に失敗した人の申し込みが丸ごと消える作りだと、定員の数え方まで狂います。イベントで決めておくことはイベントの申し込みに、回ごとの申し込みを扱う場合は講座の受講申し込みにまとめています。
書類の内容が審査に直結する受付では、届いた直後に開けるかどうかの確認が要ります。図面のような大きなファイルを受け取る施設利用の申請では、上限の設定を先に確かめておきます。継続的な関係が始まる会員の入会申し込みでは、同じ人から何度も書類が届くので、いつの分なのかが分かる形で残す必要があります。
写真や動画が届く修理・サポートの受付では、容量が読めません。受け付ける秒数や解像度の目安を案内に書いておくと、上限に当たる件数が目に見えて減ります。
内部の整理から見える、自分で作る場合の落とし穴
比較の記事と料金の説明と一問一答を、どういう質問に答えるために置いているかを整理していくと、自分でフォームを作った人がどこで詰まるのかがはっきりしてきます。
いちばん多いのは、作ったあとの相談です。フォームは動いている、ファイルも届いている、それでも回らない、という相談です。詰まっているのは送信の仕組みではなく、届いたものを誰が持っていて、返したかどうかがどこに残っているかの部分です。この2つは、HTMLをどれだけ丁寧に書いても出てきません。
2つ目に多いのが、上限と保存先の後追いです。最初は小さく作って、あとから上限を上げようとすると、3か所の設定に加えて、保存先の容量、書き出しの手順、古いファイルの消し方まで芋づるで出てきます。最初に決めておけば10分の作業が、後からだと1日仕事になります。
3つ目が、有料と無料の線をどこで越えるかという相談です。自分で作る場合の費用は、動かし始めるまでの手間だけに見えます。実際には、上限を上げたときの調整、保存先の容量、事故が起きたときの調査と説明が、あとから毎回かかります。自分で作る場合の費用はサーバー代だけに見えますが、実際には保守と、事故が起きたときの対応がそこに乗ります。既製のものを使う場合の線がどこにあるかは料金で確かめられます。横並びで眺めたい場合は他のサービスとの比較に一覧を置いています。細かい条件の質問はよくある質問にまとめてあります。
順番として確実なのは、HTMLを書く前に、上限、保存先、保存期間、そして受け取ったあとに誰が何をするかの4つを決めることです。この4つが決まっていれば、HTMLは10分で書けます。決まっていないままタグから書き始めると、動くものはできても、運用が始まった週に作り直しになります。
Q1. HTMLでファイル添付を作るとき、最低限必要な書き方は何ですか?
フォームのタグに enctype="multipart/form-data" と method="post" を指定し、入力欄を input type="file" にすることです。これが抜けているとファイルの中身は送られず、ファイル名だけが文字として飛びます。受け付ける種類を絞りたいときは accept 属性を添えますが、これは選ぶ画面を助ける指定であり、検証は受け取る側で必ず行います。
Q2. accept属性を指定すれば、他の種類のファイルは送られてきませんか?
送られてくることがあります。accept はファイルを選ぶ画面の表示を絞り込む指定で、回答者が表示を切り替えれば他の種類も選べます。フォームの画面を通さずに直接送ることもできます。拡張子だけでなくファイルの中身の先頭を見て種類を判定する検証を、受け取る側に必ず入れてください。
Q3. アップロードの上限はどこで決まりますか?
少なくとも3か所にあり、いちばん小さい値が実際の上限になります。PHPでは1ファイルの upload_max_filesize が既定で2M、送信全体の post_max_size が既定で8Mと公式マニュアルに記載されています。nginxのリクエスト本文の上限は既定で1メガバイトで、超えると413が返ります。このエラーはブラウザが正しく表示できないと公式に明記されています。
Q4. 受け取ったファイルはどこに保存すればよいですか?
Webから直接開ける公開ディレクトリの外に置き、閲覧はログインした担当者だけが通れる経路にします。ファイル名は送られてきたままにせず、推測できない文字列で付け直したうえで、元の名前とどの申し込みの分かを記録として持ちます。保存期間と消し方も、運用を始める前に手順として決めておきます。