質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

3回答

554閲覧

【 PHP】アップロード制限の方法

Masa-Y

総合スコア30

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2019/05/10 07:56

編集2019/05/11 05:08

メールフォームにファイルアップロード機能を実装する練習をしています。
1 index.phpで入力→
2 confirm.phpに遷移、送信。→送信しました。
という流れですが、
ファイルサイズに制限をかけて、
画像を選びなおすようにエラー表示させたいです。
ファイル選択は必須項目としているので、
サイズが大きすぎますというメッセージを表示しつつ、
制限値内の画像を選びなおさないと、2の確認画面に進めないようにしたいです。

【試したこと】
イメージ説明
上のindex.phpで、inputのMAX_FILE_SIZEを入れることで
value値より大きい画像は無効になりましたが、
confirm.phpへは進めてしまい、画像0KBとして送信できてしまいます。

この場合、どのような方法があるでしょうか。

php

1【confirm.php】 2<?php 3 4function h($str) { 5 return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); 6} 7 8// 変数の初期化 9$page_flag = 0; 10 11if( !empty($_POST['confirm']) ) { 12 $page_flag = 1; 13 14 try { 15 // 未定義である・複数ファイルである・$_FILES Corruption 攻撃を受けた 16 // どれかに該当していれば不正なパラメータとして処理する 17 if (!isset($_FILES['upfile']['error']) || !is_int($_FILES['upfile']['error'])) { 18 throw new RuntimeException('パラメータが不正です'); 19 } 20 // $_FILES['upfile']['error'] の値を確認 21 switch ($_FILES['upfile']['error']) { 22 case UPLOAD_ERR_OK: // OK 23 break; 24 case UPLOAD_ERR_NO_FILE: // ファイル未選択 25 throw new RuntimeException('ファイルが選択されていません'); 26 case UPLOAD_ERR_INI_SIZE: // php.ini定義の最大サイズ超過 27 case UPLOAD_ERR_FORM_SIZE: // フォーム定義の最大サイズ超過 (設定した場合のみ) 28 throw new RuntimeException('ファイルサイズが大きすぎます'); 29 default: 30 throw new RuntimeException('その他のエラーが発生しました'); 31 } 32 // ここで定義するサイズ上限のオーバーチェック 33 // (必要がある場合のみ) 34 if ($_FILES['upfile']['size'] > 1000000) { 35 throw new RuntimeException('ファイルサイズが大きすぎます'); 36 } 37 // $_FILES['upfile']['mime']の値はブラウザ側で偽装可能なので 38 // MIMEタイプに対応する拡張子を自前で取得する 39 if (!$ext = array_search( 40 mime_content_type($_FILES['upfile']['tmp_name']), 41 array( 42 'gif' => 'image/gif', 43 'jpg' => 'image/jpeg', 44 'png' => 'image/png', 45 ), 46 true 47 )) { 48 throw new RuntimeException('ファイル形式が不正です'); 49 } 50 // ファイルデータからSHA-1ハッシュを取ってファイル名を決定し,保存する 51 if (!move_uploaded_file( 52 $_FILES['upfile']['tmp_name'], 53 $path = sprintf('./files/%s.%s', 54 sha1_file($_FILES['upfile']['tmp_name']), 55 $ext 56 ) 57 )) { 58 throw new RuntimeException('ファイル保存時にエラーが発生しました'); 59 } 60 // ファイルのパーミッションを確実に0644に設定する 61 chmod($path, 0644); 62 echo 'ファイルは正常にアップロードされました'; 63 } catch (RuntimeException $e) { 64 echo $e->getMessage(); 65 } 66

イメージ説明
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

[ PHP ] アップロードファイルサイズに制限をかける ( MAX_FILE_SIZE ) – 行け!偏差値40プログラマー
サイズはゼロでも、エラーのステータスをセットで確認するしかないのでは。

イメージ説明

投稿2019/05/10 08:01

編集2019/05/10 08:03
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Masa-Y

2019/05/10 09:28

回答ありがとうございます。参考にしてみます。
guest

0

MAX_FILE_SIZEを越えると0になるのはそういう仕様なので、
MAX_FILE_SIZEをもう少し大きくして手動で制限サイズによるバリデーションをかけてチェックするしかないと思います。

#アップロード例外処理サンプルを参照

※0KBファイルってそれはそれで危険なので弾いても良いと思います。

追加質問があるようなので追記。


ファイルがサーバーに保存されるのもこのタイミングではなく、次のページにしたい

ファイルの実体はinput type=fileがform送信された時点でテンポラリファイルとして既に送信されています。なので「確認画面から送信完了画面にいくときに保存」ということは基本的にできません。
1つのやり方としては「一時ディレクトリ」と「本番ディレクトリ」で分けるやり方です。

move_uploaded_file()を記述するタイミングが誤っているのでしょうか。

move_uploaded_file()にこだわる開発者が多いのは仕方がないことではありますが、、
上記のとおりmove_uploaded_file()を実行しなくてもテンポラリファイルアップロードはフォームのSUBMIT時点で行われているので
move_uploaded_file()がやっていることって実質ファイルのリネームです。
私が提示したmpywさんの記事にmove_uploaded_file じゃなくて rename じゃだめ?というのがあります。

そもそもPHPマニュアルにあるように** アップロードされたファイルを新しい位置に移動する**のがmove_uploaded_file()です。
「アップロードを行う関数」ではありません。関数をよく読んでみましょう。
move uploaded fileですからね。ファイルのアップロード自体はこの関数関係ないです。アップロードされたファイルをどう扱うか。なので。

ということで、テンポラリファイルに対してバリデーションを行って弾いて再入力を促すようにすること(入力画面再描画が望ましい)、
バリデーションOKのファイルであればファイルを一時フォルダに移動し、確認画面を表示
→送信ボタンを押下で本番用フォルダに移動
という流れです。

ちなみに確認画面でキャンセルとか画面閉じたりしたら一時フォルダにゴミがたまっていくので、
一時フォルダに保存する際はセッションで一意な名前のファイル名をつけておくとかして、利用者と紐づくようにしておき、削除するような仕組みが必要になります。
日時バッチ用意して全削除でも良いですけどそのときに誰も確認画面で送信しようとしてないという保証はないのでやはり紐づけは必要。でもやっぱり定期にクロールして削除する仕組みは必要。
間違ってもtmp_nameをhiddenに置いておくなんてことをしてはいけません。テンポラリなので(そこは調べてください)
もちろんnameをそのまま保存するのもいけません。(参考

というか、そもそも提示のコードって私が提示したmpywさんの記事ほぼそのままなので、それぞれがどういう意図で組まれているのかを理解するのが先のように思います。
自身のやりたいことや既にあるコードにそのまま埋め込むのはおそらく無理です。全ての機能を採用するかどうかも検討が必要ですし、いったん自身のコードから離れて記事のコードをミニマムコードに採用して使ってみて挙動確認や調整をしてからでないと使いこなせないと思います。

投稿2019/05/10 08:04

編集2019/05/11 05:52
m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Masa-Y

2019/05/10 09:28

回答ありがとうございます。参考にしてみます。
guest

0

Javascriptを使って、以下のように実装することができました。
自分自身メールフォームはPHPという固定観念があったように思います
何かあればアドバイスいただけると助かります、
どうもありがとうございました。

イメージ説明
イメージ説明

投稿2019/05/11 00:06

Masa-Y

総合スコア30

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/05/11 00:19

JavaScriptのチェックは改竄可能なので簡単に破れますよ。 これをベストアンサーであげてしまうと脆弱性のあるフォームの実装につながるので低評価しました。
Masa-Y

2019/05/11 00:31

MAX_FILE_SIZEのチェックは入っていますが、 confirm.phpでも例外処理など組むべきということでしょうか。
m.ts10806

2019/05/11 00:34

私の回答および回答にリンクさせた記事は読まれたのでしょうか? サーバーへ情報を送る以上はサーバーサイドでのバリデーションは省略することはできません。
Masa-Y

2019/05/11 00:42

わかりました、もう一度やってみます。
Masa-Y

2019/05/11 05:10 編集

confirm.phpで例外処理を追加しました。 追加の画像を載せましたので、確認していただけないでしょうか。 例外処理メッセージは表示されているんですが、 できればここではなくて この次の「送信完了しました。」 が表示されるタイミングで表示させたいです。 それから、ファイルがサーバーに保存されるのもこのタイミングではなく、 次のページにしたいです。 そうでないと、 送信ボタンを押す前にファイルはサーバーに保存されてしまい、 ここで送信を中止したとしてもデータはサーバーに残ってしまいます。 move_uploaded_file()を記述するタイミングが誤っているのでしょうか。
m.ts10806

2019/05/11 05:29

質問なのであれば文章も本文に追記いただきたいところ。 この回答のコメントで続けたとして後の人のためにはならないからです。 つまり質問本文に追記→その質問を受け取った回答者が回答に追記(または新しい回答を投稿)という流れが望ましいです。 「ファイルサイズに制限をかけて、画像を選びなおすようにエラー表示させたいです。」と 「例外処理メッセージを「送信完了しました。」が表示されるタイミングで表示させたい」 はタイミングが交差しています。 選びなおさせたいのであれば「完了させました」を出すべきではないですし、「確認画面」すら表示させるのもおかしいです。 確認画面は「入力を受け付けたうえで入力内容が送りたい内容かユーザーに確認させる画面」ですので。 ほかについては質問に追記されてから私の回答に追記します。
Masa-Y

2019/05/11 05:35

そうですね...。 一度整理して、質問を投稿し直そうと思います。 お忙しいのにありがとうございました。
m.ts10806

2019/05/11 05:39

回答に追記はしておくので、そちらを読んでからのほうがいいです。 この質問、まだきちんと締まってないので。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問