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

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

ただいまの
回答率

87.79%

PHPフォーム処理でファイルアップロード時に戻るボタンを使われてしまったときの対処

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,550

score 14

前提・実現したいこと

  • フォーム入力→確認画面→完了(完了メール)
  • 確認画面にアップロードしたファイル名(複数)を表示。
  • 確認画面で「履歴バック」をされたときには、ファイルを削除。

試したこと

PHPを書いたことがなく、下記サイトを参考にファイルアップロード付きメールフォームを作ってます。
https://gray-code.com/php/make-the-form-vol8/

それに改変していますが、これで一応最低限の一連はできています。
確認画面(複数ファイル表示)、ファイルアップロード、確認メール。

改変したこと:

  • 一時ファイルディレクトリと正式ディレクトリを用意。
  • ファイル名の頭にユーザー名を加えました。
例外について対処したい

今回やったやり方だと良くも悪くも「一旦ファイルをサーバにアップロード」しています。

フォームを入力し確認画面に進む。
その後ユーザーが「(履歴)戻る」をする。
そして“違う”ファイルを選択し再び確認画面に進み完了させる。

こうなるとサーバーには2つアップロードされることになります。
今はとにかく処理を成功させるために、
ファイル名にユーザー名を追加して、そのファイル名にユーザー名を含んでいるファイルは正式ディレクトリへ移動するという行為を踏んでいます。

この場合受け取った側が「どちらが正しいファイル」なのか?わからなくなってしまいます。
またユーザーにしてみれば、それはキャンセルしたつもりになってますよね。

参考にしたプログラムの書き方だと、グローバル変数とローカル変数の関係で?変数を引き継げません。
最初の段階でファイル名に何かコード名を付けて、それを含んでなければ削除ってことをすれば良さそうですが、さっぱりわかりません。

代わりにJqueryを使ってJavaScriptでやることも考えたのですが、
今度はc:\fakepath\が表示されてしまったり、スマートに行きません。
※確認画面にも「ファイル名を表示」させたいです。

サーバーはCentOS6 PHP7です。
よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

登録が確定し、登録を処理する段階でmove_uploaded_file()関数にてを実行すればいいのではないかと思います。

それまで$_FILES関数には一時ファイルやファイル名しか入っておらず、これらはアップロードされなかった場合はサーバーから消去されます。幸い、ファイル名称や一時ファイルはアップロードしなくても残るので、ページを遷移できます。

ファイルアップロードの時に確認画面を挟むときのやり方

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/05 20:45

    ありがとうございます。
    初歩的なところですいません。
    $_FILESってスーパーグローバル変数で違うローカルにいっても保持しているのかと思ったのですが、
    まずは確認画面でのファイル表示を諦め、
    if ~ (1) elseif (2)で進んでますが、
    (1)では何もせず(2)で処理を始めようとすると、
    もう$_FILESは空になってしまうんですね。

    参考先は同じPHPなのでしょうか?
    すいません、難しくて理解できないですね。

    キャンセル

  • 2019/04/08 19:07 編集

    $_SESSION['TEMPFILE'][$COUNT] = file_get_contents($_FILES['FILE_TYPE_NAME']['tmp_name'][$ct]);
    $_SESSION['FILENAME'][$COUNT] = $_FILES['FILE_TYPE_NAME']['name'][$COUNT];

    こんな感じにしてセッションに入れ確認画面に表示。
    完了画面を出すタイミングで

    file_put_contents(FILE_DIRECTORY.$_SESSION['FILENAME'][$COUNT],$_SESSION['TEMPFILE'][$COUNT]);
    $FILEOUTPUT[$COUNT] = $_SESSION['FILENAME'][$COUNT];

    としました。
    前半でfile_get_contentsでセッションへ。
    後半でfile_put_contentsでセッションから抜き出す。
    これでJPEGやPDFやZipファイルは正常にアップロードできています。

    そして最後の方で
    unset($_SESSION['FILENAME']);
    unset($_SESSION['TEMPFILE']);

    一応これで確認画面でのファイル名出力、
    さらにメールでのファイル名出力ができています。

    このやり方にしてから履歴バックしたら、
    戻ったときにファイル選択状態がクリアされるようになりました。
    以前は残ってることが多かったです。

    スマートなやり方じゃないとは思うんですが、
    これは問題が出てくるのでしょうか?

    キャンセル

  • 2019/04/09 09:29

    自分はその方法でも問題ないとは思いますが、もっと有識者の意見を訊きたいところですね。

    キャンセル

  • 2019/04/09 19:50 編集

    変なところ?でエラーが出ました。

    サーバにアップロードしたデータですが、
    Webブラウザでそのファイルの内容を覗いたりダウンロードするとき、SFTP/WebDAVクライアントでダウンロードしたときは問題ありません。

    Windows10でWebDAV(ネットワークドライブ)経由で、開いたりコピーしようとすると、ファイルを操作できないエラーが発生します。

    PDFだと
    「ファイル名、ディレクトリ名、またはボリュームラベルの構文が間違っています」

    .txtファイルだと、
    ファイル名、ディレクトリ名、またはボリュームラベルの構文が間違っています。

    これは俗に言われるWindows内蔵のWebDAVが悪いのでしょうか?
    ファイルの生成方法なのでしょうか?


    === 追記
    上記はファイル名に余計な文字を追記していたことでWindowsで問題が起きていました。それを取り除いて解決しています。

    キャンセル

0

確認画面で「履歴バック」をされたときには、ファイルを削除。 

これはブラウザの仕様によるけど、キャッシュが表示されると思うので無理じゃないかなぁ。。。

再投稿されたタイミングで削除できるように、セッションにアップロードの時のステータスを記録しておくと、登録前情報の削除はできるように思います。
*ちょっと仕様を勘違いしているかも^^;

参考にしたサイトの内容を斜めに読みましたが、いくつかのセキュリティ的な問題点を抱えています。
特に画像ファイルであることの確認をしていないことは致命的です。
もし現在インターネット上に公開中であればすぐに中止してサイト内のファイルにおかしな変化がないか確認したほうが良いです。
*雑にリスクを説明すると、php ファイルのアップロードが可能なので、php でできることが何でもできるようになります。(別のアップローダの設置、DB への接続、スパムの発射台、マイニングスクリプトの設置等々)

少し古い記事ですが、こちらを参考にしたほうが良いです。
ファイルアップロードの例外処理はこれぐらいしないと気が済まない

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/10 17:02

    参考サイトの先にあった「PSR-7」ですが、良さそうに思ったんですが自分のサーバー(共用レンタル)だと使えないようです。

    mimeタイプでのファイルチェックを付けました。
    if($_FILES['添付ファイル']['error'][$count] === UPLOAD_ERR_OK) {

    if(!isset($_FILES['添付ファイル']['error'][$count]) || !array_search(mime_content_type($_FILES['添付ファイル']['tmp_name'][$count]),$allow_mime_array) || $_FILES['添付ファイル']['size'][$count] === 0) {echo "アップ失敗";}
    else { アップロード成功していて、対応ファイルの時のプログラム }
    }

    一応これで動いています。

    > いくつかのセキュリティ的な問題点
    他に注意するところは何でしょうか?

    キャンセル

  • 2019/04/10 18:06

    mimeタイプの検証は、簡単に回避できるためセキュリティ的にはほとんど意味がありません。(やらないよりはやったほうが良いですが)

    画像ファイルの検証ができないのであれば、そのサーバでのファイルアップロード機能実装は諦めてください。

    > 他に注意するところは何でしょうか?
    そもそもバリデーションが出来てないので、細かい指摘をしても意味は無いのですが、
    ・htmlspecialchars の第三引数の指定がない
    ・images/test/ は多分公開ディレクトリで、直接アクセス可能
    等々。
    斜め読みなので、網羅的でも無ければ、検証もしていないですが、公開に耐えるものではないです。

    キャンセル

  • 2019/04/10 18:43

    > mimeタイプの検証は、簡単に回避できるためセキュリティ的にはほとんど意味がありません。

    これ、間違いです。
    $_FILES の内容で mime タイプチェックしていると読んでました。失礼^^;

    キャンセル

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

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • PHPに関する質問
  • PHPフォーム処理でファイルアップロード時に戻るボタンを使われてしまったときの対処