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

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

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

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

Q&A

解決済

2回答

2946閲覧

move_uploaded_fileに関して困っています。

退会済みユーザー

退会済みユーザー

総合スコア0

PHP

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

0グッド

0クリップ

投稿2016/08/01 16:27

php

1 <?php 2 if(isset($_FILES['file'])){ 3 4 $name = $_FILES['file']['name']; 5 $type = explode('.',$name); 6 $type = end($type); 7 $size = $_FILES['file']['size']; 8 $tmp = $_FILES['file']['tmp_name']; 9 $random_name = rand(); 10 11 if($type != 'mp4' && $type != 'MP4'){ 12 $message = "This format is not supported."; 13 }else{ 14 move_uploaded_file($tmp,'files/'.$random_name.'.'.$type); 15 try{ 16 $pdo = new PDO('mysql:host=127.0.0.1; dbname=データベース名;','root'); 17 $stmt = $pdo -> prepare ("INSERT INTO files VALUES('','$name','files/$random_name.$type')"); 18 $stmt -> execute(); 19 20 $message = "Succesfully Uploaded."; 21 22 }catch(PDOException $e){ 23 exit('failed connecting to DB.'.$e -> getMessage()); 24 } 25 } 26 27 echo "$message <br/><br/>"; 28 } 29 ?>

このコードに関してですが、すべてちゃんと動いてくれてます。
ただ一つ困っているのが、

ファイルをセットし、サブミットしてからリロードするたびに動画ファイルが'files/'にアップロードされてしまいます。

これはこういうものなのでしょうか?それとも改良の余地があるのでしょうか?
また、この疑問が伝わるかが心配なので、わからないようであれば、ご指摘していただけるとありがたいです。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

webアプリケーションって仕組み的にはそういうものです。
ファイルアップロードに限らず、あらゆるリクエストで同じことが発生します。

ただ、防止する方法はあって、
PHP 多重送信防止で検索すると色々と出てきます。

方向性としては

  • 処理成功時に成功ページにリダイレクトさせることでリロードしてもリダイレクト部分がリロードされるようにする
  • 処理時に処理内容を記憶しておいて(トークン等を使うことが多いです)、2回目は問答無用でエラーにする

という感じですね。
前者は簡易的な実装で、リダイレクトより前に戻るボタンで戻ってから進んだりして、同じリクエストを複数回送信すると登録できてしまうので、厳密に実装したいなら後者の方向性になります。

投稿2016/08/01 16:31

編集2016/08/01 16:41
tanat

総合スコア18713

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

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

退会済みユーザー

退会済みユーザー

2016/08/01 16:54

とても勉強になります...!! まだ初心者なので難しい用語はわからないですが、検索してみたら解決できました! ありがとうございました。
guest

0

質問に直接無関係な面もありますが,セキュリティ等改善すべき点がいくつかあるので,遅いながら回答させていただきます.

評価基準

★☆☆: よりよい書き方が考えられる
★★☆: エラーリスクがある
★★★: 脆弱性がある

★★☆ $_FILES['file']が存在していても期待した構造とは限らない

html

1<input type="file" name="file">

から送信された場合,

php

1$_FILES = [ 2 'file' => [ 3 'error' => ..., 4 'tmp_name' => '...', 5 ... 6 ], 7];

のような構造になりますが,HTTPリクエストはこのHTMLフォームから送信されるとは限りません.任意のプログラムから悪意のあるリクエストを飛ばすことも簡単にできます.そのため,例えば

html

1<input type="file" name="file[x][y][z]">`

に相当するリクエストが飛んできたとしましょう.このとき,$_FILESの構造はこのようになってしまいます.

php

1$_FILES = [ 2 'file' => [ 3 'error' => [ 4 'x' => [ 5 'y' => [ 6 'z' => [ 7 ..., 8 ], 9 ], 10 ], 11 ], 12 'tmp_name' => [ 13 'x' => [ 14 'y' => [ 15 'z' => [ 16 ..., 17 ], 18 ], 19 ], 20 ], 21 ... 22 ], 23];

こんなリクエストに対して具体的に「ここがおかしいよ!」とまで律儀なエラーメッセージを出す必要はありませんが,少なくともどんなリクエストがきてもサーバ側でエラーが発生しないようにコードを書くべきです.簡易的な解決策としては,issetのチェックを以下のように変更することが挙げられるでしょう.

php

1if (isset($_FILES['file']) && is_int($_FILES['file']['error'])) { 2 ... 3}

より詳しい方法については「ファイルアップロードの例外処理はこれぐらいしないと気が済まない」でまとめています.

★★☆ アップロードのエラーはチェックする

上記の構造のチェックに加えて, $_FILES['file']['error']UPLOAD_ERR_OK になっているかどうかの確認も必要です.失敗している場合は move_uploaded_file のコールでエラーが発生するでしょう.

★☆☆ 拡張子を信じてはいけない

拡張子はあくまで参考程度の情報で,偽装されている場合やそもそもファイル名にドットが含まれていない場合すら考えられます.必ずしも中身までチェックする必要はないですが,簡易的にデータタイプをチェックしておきたいならばmime_content_type関数を使うとよいでしょう.

php

1$mime = mime_content_type($_FILES['file']['tmp_name']); // "video/mp4"

但し…

  • ファイルを設置するためにその拡張子を使うのであれば,拡張子のチェックは必須です.
  • .phpなどアクセスするだけで何かが実行されてしまう拡張子は除外する必要がありますが,どちらかというと提示されているコードのように.mp4だけを認める,といった感じでホワイトリスト式にするほうが正解です.この点は評価できると思います.
  • $_FILES['file']['type']にもMIMEタイプが含まれていますが,こちらはWebブラウザの自己申告に基づくものなので,信用できる値ではありません.
randは言うほどランダムではない
  • せっかくアルファベットも使えるのに,数字だけにしてしまうとランダム性**(エントロピー)**が小さくなってしまいます.
  • rand は乱数の精度が悪いと言われています.

ランダムなファイル名を作りたいのであれば,「ランダムなパスワードを1行で生成する with openssl」のようにするといいかと思います.

また,ファイルデータを削除不可,あるいは共有している人間がいなくなるまで実体の削除は行わないようにする場合,重複したアップロードで二重にファイルを作らせないこともできます.ファイルデータから一意なハッシュ値を取ってファイル名に使いましょう.

php

1$hash = sha1_file($_FILES['file']['tmp_name']);
★★★ データベース関連の扱いが不適切

「PHPでデータベースに接続するときのまとめ」の「初心者がやりがちなミス」をご覧ください.

  • データベースで使用する文字コードの指定をしていない
  • "SELECT * FROM users WHERE id = '$id'" のように変数展開を使ってSQL文を組み立てている

投稿2016/08/02 20:14

mpyw

総合スコア5223

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

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

退会済みユーザー

退会済みユーザー

2016/08/04 06:36

評価ありがとうございます。 時間がかかると思いますが、改善していきたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問