画像ファイルの識別について - PHPプロ!Q&A掲示板

4966

  • 募集中!! 0P

画像ファイルの識別について

質問日時 / 2018年8月4日 18:02    回答数 / 8件

Questioner:  sheen55  このエントリーをはてなブックマークに追加 

キーワード / exif_imagetype    var_dump   

画像アップロードに関し、画像以外のファイルを区別したいと考えています。

exif_imagetype関数を利用して、falseになるファイルを拒否しようと考えましたが、

var_dumpでは、画像はint(数字)、画像以外はfalseが表示されますが、
下記のif文では、画像ファイルも含め、すべてがfalseとなってメッセージが出てしまいます。

初歩的な質問かもしれませんが、よろしくお願いいたします。
  1. var_dumpexif_imagetype($_FILES['sample_file']['tmp_name']));
  2.  
  3. if(exif_imagetype($_FILES['sample_file']['tmp_name']) == false){
  4. echo "「画像以外のファイル」は選択できません。";}


ツリー一覧

┗A01shimix質問に書かれている部分だけでは検証できません。
 ┗A01-1sheen55さっそくのご連絡ありがとうございます。 不手際でも
  ┗A01-1-1shimix$cleanにサニタイズ済みのPOSTデータを格納しているの
   ┣A01-1-1-1sheen55ご連絡ありがとうございます。 まだまだ、習った知
   ┗A01-1-1-2sheen55何度も申し訳ございません。 ご指摘いただいた、確
    ┗A01-1-1-2-1shimix>今回も同じ警告が出ます。 こちらで試した限りで
     ┗A01-1-1-2-1-1sheen55ご連絡ありがとうございます。 もう一度、最初から
      ┗A01-1-1-2-1-1-1shimixざっくりと書いてみましたので参考にしてください。

回答一覧

並び替え:

A01
answerershimix [8月6日 13:44]

質問に書かれている部分だけでは検証できません。

下記ソースで試しましたが、質問者さんが書かれている現象は再現できませんでした。
  1. <?php
  2. if (isset($_FILES['userfile'])) {
  3.     var_dump( exif_imagetype($_FILES['userfile']['tmp_name']));
  4.     if(exif_imagetype($_FILES['userfile']['tmp_name']) == false){
  5.       echo "「画像以外のファイル」は選択できません。";
  6.     }
  7. }
  8. ?>
  9. <form enctype="multipart/form-data" action="" method="POST">
  10. このファイルをアップロード: <input name="userfile" type="file" />
  11. <input type="submit" value="ファイルを送信" />
  12. </form>
現象が再現できる可能な限り短いソース(ミニマムソース)を提示してください。

この意見に回答する

ツリーへ TOPへ

A01-1
replyersheen55 [8月6日 16:52]

さっそくのご連絡ありがとうございます。
不手際でもうしわけございません。よろしくお願いいたします。
  1. <?php
  2. var_dump( getimagesize($_FILES['attachment_file']['tmp_name']));
  3. var_dump( exif_imagetype($_FILES['attachment_file']['tmp_name']));
  4. define( "FILE_DIR""images/test/");
  5.  
  6. $page_flag = 0;
  7. $clean = array();
  8. $error = array();
  9.  
  10. // サニタイズ
  11. if( !empty($_POST) ) {
  12.   foreach( $_POST as $key => $value ) {
  13.     $clean[$key] = htmlspecialchars( $valueENT_QUOTES);
  14.   }
  15. }
  16.  
  17.  
  18. if( !empty($clean['btn_confirm']) ) {
  19.  
  20.   $error = validation($clean);
  21.  
  22.   if( empty($error) ) {
  23.     $page_flag = 1;
  24.   }
  25. }
  26. function validation($data) {
  27.  
  28.   $error = array();
  29.  
  30.  
  31.  
  32.   // お問い合わせ内容のバリデーション
  33.   if( empty($data['attachment_file']) ) {
  34.   $error[] = "「画像ファイルの添付」は必ず入力してください。";
  35. }elseif(exif_imagetype($_FILES['attachment_file']['tmp_name']) == false){
  36.  $error[] = "「画像以外のファイル」は選択できません。";
  37.   }
  38.  
  39.  
  40.  
  41.   return $error;
  42. }
  43. ?>
  44.  
  45. <!DOCTYPE>
  46. <!DOCTYPE html>
  47. <html lang="ja">
  48. <head>
  49.   <meta charset="UTF-8">
  50. <title>お問い合わせフォーム</title>
  51. <style rel="stylesheet" type="text/css">
  52. body {
  53.   padding: 20px;
  54.   text-align: center;
  55. }
  56. .error_list {
  57.   padding: 10px 30px;
  58.   color: #ff2e5a;
  59.   font-size: 86%;
  60.   text-align: left;
  61.   border: 1px solid #ff2e5a;
  62.   border-radius: 5px;
  63. }
  64. </style>
  65. </head>
  66. <body>
  67. <h1>お問い合わせフォーム</h1>
  68. <?php if( $page_flag === 1 )?>
  69.   <form method="post" action="">
  70.  
  71.   <?php if( !empty($clean['attachment_file']) )?>
  72.   <div class="element_wrap">
  73.     <label>画像ファイルの添付</label>
  74.     <p><img src="<?php echo FILE_DIR.$clean['attachment_file']?>"></p>
  75.   </div>
  76.   <?php endif?>
  77.  
  78.     <input type="submit" name="btn_back" value="戻る">
  79.     <input type="submit" name="btn_submit" value="送信">
  80.     <?php if( !empty($clean['attachment_file']) )?>
  81.     <input type="hidden" name="attachment_file" value="<?php echo $clean['attachment_file']?>">
  82.   <?php endif?>
  83.   </form>
  84. <?php elseif( $page_flag === 2 )?>
  85. <p>送信が完了しました。</p>
  86. <?php else?>
  87.   <?php if( !empty($error) )?>
  88.   <ul class="error_list">
  89.   <?php foreach( $error as $value )?>
  90.     <li><?php echo $value?></li>
  91.   <?php endforeach?>
  92.   </ul>
  93. <?php endif?>
  94.  
  95. <form method="post" action="" enctype="multipart/form-data">
  96.       <div class="element_wrap">
  97.     <label>画像ファイルの添付</label>
  98.     <input type="file" name="attachment_file"><?php if( !empty($clean['attachment_file']) ){ echo $clean['attachment_file']} ?>
  99.  
  100.   <input type="submit" name="btn_confirm" value="入力内容を確認する">
  101. </form>
  102. <?php endif?>
  103. </body>
  104. </html>

この意見に回答する

ツリーへ TOPへ

A01-1-1 満足
replyershimix [8月7日 02:32]

$cleanにサニタイズ済みのPOSTデータを格納しているのだと思いますが、$_FILESは対象外ですよね(POSTされるファイルの情報は$_POSTとは別に$_FILESに格納されます)。

なので

$error = validation($clean);

ではなく

$error = validation($_FILES);

でないと意味がありません。


なお、サニタイズと言いつつ「htmlspecialcharsを通す」ようですが、htmlspecialcharsは表示するときに行うエスケープです。データ受け取り時に行うべきではありません。特に今回はあとでtext/plainなメール(ですよね?)で使うという前提がありますから(受け取り時の)htmlspecialcharsは不適切です。


あと(余計なお世話ですが)確認画面に遷移するときに、添付ファイルをどうするかは考慮されていますでしょうか?$_FILES['attachment_file']['tmp_name']はphpスクリプトの終了と同時になくなってしまいますので「どう保存するか」「クライアントとどう紐付けるか」が問題になってきます。おそらくはセッションを使うのが手っ取り早いだろうと思いますが・・・

この意見に回答する

ツリーへ TOPへ

A01-1-1-1
replyersheen55 [8月7日 07:52]

ご連絡ありがとうございます。

まだまだ、習った知識をつなぎ合わせているだけで、まともなものになっていないことを痛感いたしました。

ご指摘いただいたことを参考にさせて頂き、もう一度作り直してみます。

ありがとうございました。

この意見に回答する

ツリーへ TOPへ

A01-1-1-2
replyersheen55 [8月7日 16:34]

何度も申し訳ございません。

ご指摘いただいた、確認画面でのアップロードの件ですが、作ってみるとやはり今回も同じ警告が出ます。ご指導いただけると幸いです。
  1. <?php
  2. var_dump( getimagesize($_FILES['attachment_file']['tmp_name']));
  3. var_dump( exif_imagetype($_FILES['attachment_file']['tmp_name']));
  4. define( "FILE_DIR""images/test/");
  5.  
  6. $page_flag = 0;
  7. $clean = array();
  8. $error = array();
  9.  
  10. // ファイルのアップロード
  11.   if( !empty($_FILES['attachment_file']['tmp_name']) ) {
  12.  
  13.     $upload_res = move_uploaded_file( $_FILES['attachment_file']['tmp_name']FILE_DIR.$_FILES['attachment_file']['name']);
  14.  
  15.     if( $upload_res !== true ) {
  16.       $error[] = 'ファイルのアップロードに失敗しました。';
  17.     }
  18.   }
  19.  
  20. if( !empty($clean['btn_confirm']) ) {
  21.  
  22.   $error = validation($_FILES);
  23.  
  24.   if( empty($error) ) {
  25.     $page_flag = 1;
  26.   }
  27. }
  28. function validation($data) {
  29.  
  30.   $error = array();
  31.  
  32.  
  33.  
  34.   // お問い合わせ内容のバリデーション
  35.   if( empty($data['attachment_file']) ) {
  36.   $error[] = "「画像ファイルの添付」は必ず入力してください。";
  37. }elseif(exif_imagetype($_FILES['attachment_file']['tmp_name']) == false){
  38.  $error[] = "「画像以外のファイル」は選択できません。";
  39.   }
  40.  
  41.  
  42.  
  43.   return $error;
  44. }
  45.  
  46.  
  47. ?>
  48.  
  49. <!DOCTYPE>
  50. <!DOCTYPE html>
  51. <html lang="ja">
  52. <head>
  53.   <meta charset="UTF-8">
  54. <title>お問い合わせフォーム</title>
  55. <style rel="stylesheet" type="text/css">
  56. body {
  57.   padding: 20px;
  58.   text-align: center;
  59. }
  60. .error_list {
  61.   padding: 10px 30px;
  62.   color: #ff2e5a;
  63.   font-size: 86%;
  64.   text-align: left;
  65.   border: 1px solid #ff2e5a;
  66.   border-radius: 5px;
  67. }
  68. </style>
  69. </head>
  70. <body>
  71. <h1>お問い合わせフォーム</h1>
  72. <?php if( $page_flag === 1 )?>
  73.   <form method="post" action="">
  74.  
  75.   <?php if( !empty($clean['attachment_file']) )?>
  76.   <div class="element_wrap">
  77.     <label>画像ファイルの添付</label>
  78.     <p><img src="<?php echo FILE_DIR.$clean['attachment_file']?>"></p>
  79.   </div>
  80.   <?php endif?>
  81.  
  82.     <input type="submit" name="btn_back" value="戻る">
  83.     <input type="submit" name="btn_submit" value="送信">
  84.     <?php if( !empty($clean['attachment_file']) )?>
  85.     <input type="hidden" name="attachment_file" value="<?php echo $clean['attachment_file']?>">
  86.   <?php endif?>
  87.   </form>
  88. <?php elseif( $page_flag === 2 )?>
  89. <p>送信が完了しました。</p>
  90. <?php else?>
  91.   <?php if( !empty($error) )?>
  92.   <ul class="error_list">
  93.   <?php foreach( $error as $value )?>
  94.     <li><?php echo $value?></li>
  95.   <?php endforeach?>
  96.   </ul>
  97. <?php endif?>
  98.  
  99. <form method="post" action="" enctype="multipart/form-data">
  100.       <div class="element_wrap">
  101.     <label>画像ファイルの添付</label>
  102.     <input type="file" name="attachment_file"><?php if( !empty($clean['attachment_file']) ){ echo $clean['attachment_file']} ?>
  103.  
  104.   <input type="submit" name="btn_confirm" value="入力内容を確認する">
  105. </form>
  106. <?php endif?>
  107. </body>
  108. </html>

この意見に回答する

ツリーへ TOPへ

A01-1-1-2-1
replyershimix [8月7日 18:12]

>今回も同じ警告が出ます。

こちらで試した限りでは「同じ警告」は出ません。

画面遷移がうまく出来ない($page_flag のカウントが想定したとおりになっていない?)というのはありますが・・・



まだ$clean['attachment_file']を使っている部分があります。$cleanへの代入は全部カットされているのに、使う側が残っているのはダメですよね。

まして(ソース上では$cleanですが)$_FILES['attachment_file']という「配列」をそのままechoしているのはダメです。

∴ 再考してください

この意見に回答する

ツリーへ TOPへ

A01-1-1-2-1-1
replyersheen55 [8月7日 18:20]

ご連絡ありがとうございます。

もう一度、最初から再考してみます。

ありがとうございました。

この意見に回答する

ツリーへ TOPへ

A01-1-1-2-1-1-1
replyershimix [8月7日 21:00]

ざっくりと書いてみましたので参考にしてください。
  1. <?php
  2. session_start();
  3. define( 'SAVE_DIR''images/test/');
  4. $page = 0;
  5. $errmsg = array();
  6.  
  7. // 最初のPOSTデータ
  8. if (isset($_POST['btn_confirm'])) {
  9.   if (empty($_FILES['userfile'])) {
  10.     $errmsg[] = '画像ファイルは必須です';
  11.   } else {
  12.     $type = exif_imagetype($_FILES['userfile']['tmp_name']);
  13.     if ($type !== false) {
  14.       $img = file_get_contents($_FILES['userfile']['tmp_name']);
  15.       $ext = image_type_to_extension($typetrue);
  16.       $mime = image_type_to_mime_type($type);
  17.     } else {
  18.       $errmsg[] = '画像ファイルを選択してください';
  19.     }
  20.   }
  21.   if (count($errmsg) === 0) {
  22.     $_SESSION['img'] = $img;
  23.     $_SESSION['ext'] = $ext;
  24.     $_SESSION['mime'] = $mime;
  25.     $page = 1;
  26.   }
  27. }
  28. // 送信処理
  29. if (isset($_POST['btn_submit'])) {
  30.   $fname = SAVE_DIR . md5($_SESSION['img']) . $_SESSION['ext'];
  31.   file_put_contents($fname$_SESSION['img']);
  32.   // 実際のお問い合わせフォームの処理はここに記述する
  33.   $page = 2;
  34. }
  35. ?>
  36. <!DOCTYPE html>
  37. <html lang="ja">
  38. <head>
  39. <meta charset="UTF-8">
  40. <title>お問い合わせフォーム</title>
  41. <style rel="stylesheet" type="text/css">
  42. body {
  43.   padding: 20px;
  44.   text-align: center;
  45. }
  46. .error_list {
  47.   padding: 10px 30px;
  48.   color: #ff2e5a;
  49.   font-size: 86%;
  50.   text-align: left;
  51.   border: 1px solid #ff2e5a;
  52.   border-radius: 5px;
  53. }
  54. </style>
  55. </head>
  56. <body>
  57. <h1>お問い合わせフォーム</h1>
  58. <?php
  59. if (count($errmsg) > 0 ) {
  60.   printf('<div class="error_list">%s</div>'implode('<br>'$errmsg));
  61. }
  62. switch ($page) {
  63.   case 0:
  64.     ?>
  65.     <!-- page 0 -->
  66.     <form method="post" action="" enctype="multipart/form-data">
  67.     <div>
  68.     <label>画像ファイルの添付</label>
  69.     <input type="file" name="userfile">
  70.     <input type="submit" name="btn_confirm" value="入力内容を確認する">
  71.     </form>
  72.     <?php
  73.     break;
  74.   case 1:
  75.     ?>
  76.     <!-- page 1 -->
  77.     <div>
  78.     <label>画像ファイルの添付</label>
  79.     <p><img src="<?= 'data:' . $mime . ';base64,' . base64_encode($img)?>"></p>
  80.     </div>
  81.     <form method="post" action="">
  82.     <input type="submit" name="btn_back" value="戻る">
  83.     <input type="submit" name="btn_submit" value="送信">
  84.     </form>
  85.     <?php
  86.     break;
  87.   case 2:
  88.     ?>
  89.     <!-- page 2 -->
  90.     <div>
  91.     <p>送信が完了しました。</p>
  92.     <p><?= $fname?></p>
  93.     <a href="">back</a>
  94.     </div>
  95.     <?php
  96.     break;
  97. }
画面遷移時には画像データ(及び拡張子とmimeタイプ)をセッションに保存して持ち回ります(img要素のsrc属性にはdataスキームで埋め込むという力業)。
保存するときには画像データのmd5値をファイル名にしています。万一ファイル名が同一になっても、それは同じデータとみなせるので上書きしても問題ありませんので。

なお元のファイル名はキレイサッパリなくなってしまうので、保存しておきたかったら(ファイル名も)セッションで持ち回っておいて、なんらかの形で保存ファイル名と関連付ける必要があります。まぁ元ファイル名ってそこまで重要じゃないと思いますけどね(汗

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)