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

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

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

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

Twig

Twig は、簡潔で可読性の高いテンプレートを記述することができ、 シンプルに記述することを目的として作られた PHPテンプレートエンジンです。

Q&A

解決済

2回答

2399閲覧

move_uploaded_file関数でファイルを移動したあと画像が表示できない、多次元連想配列の余計な配列の階層を排除したい

arahito

総合スコア18

PHP

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

Twig

Twig は、簡潔で可読性の高いテンプレートを記述することができ、 シンプルに記述することを目的として作られた PHPテンプレートエンジンです。

0グッド

1クリップ

投稿2019/04/10 06:28

編集2019/04/10 07:23

前提・実現したいこと

ここに質問の内容を詳しく書いてください。
PHPで投稿フォームからDBにデータを登録するのですが、投稿されたデータを連想配列に格納して、PDOクラスを使ってprepared、executeしてデータを登録しようと考えています。

発生している問題・エラーメッセージ

1,move_uploaded_file関数でファイルを任意のディレクトリへ移動、ファイル名も正しく命名されているのですが、絶対パスを用いてファイルを指定しても画像を表示することができません。 ファイルが移動されていても正しく移動されていなければ、ファイルパスを指定しても表示できないのでしょうか? 2, ポストされた値を連想配列に格納したもの$dataArrをvar_dumpすると以下のようになります。 array(10) { ["gift_name"]=> string(18) "スタバカード" ["detail"]=> string(49) "スタバで使えるギフトカード3000円分" ["price"]=> string(4) "3000" ["rel"]=> string(6) "友達" ["sex"]=> string(6) "男性" ["age"]=> string(2) "28" ["scene"]=> string(9) "誕生日" ["reason"]=> string(27) "スタバが好きだから" ["whereBuy"]=> string(36) "スターバックス二子玉川店" [0]=> array(1) { ["image"]=> array(5) { ["name"]=> string(13) "IMG_4787.HEIC" ["type"]=> string(10) "image/heic" ["tmp_name"]=> string(36) "/Applications/MAMP/tmp/php/php37MztZ" ["error"]=> int(0) ["size"]=> int(1410017) } } } この時、$dataArr[0] = [0]=> array(1) { ["image"]=> array(5) { ["name"]=> string(13) "IMG_4787.HEIC" ["type"]=> string(10) "image/heic" ["tmp_name"]=> string(36) "/Applications/MAMP/tmp/php/php37MztZ" ["error"]=> int(0) ["size"]=> int(1410017) } } となっている部分を["image] => array(5) { ["name"]=> string(13) "IMG_4787.HEIC" ["type"]=> string(10) "image/heic" ["tmp_name"]=> string(36) "/Applications/MAMP/tmp/php/php37MztZ" ["error"]=> int(0) ["size"]=> int(1410017) } }にしたいのですが、多次元連想配列の階層?を一つ浅くする方法はあるのでしょうか。言語化するのが難しく検索に困っています。

該当のソースコード

form.html.twig

コード

<body> <br> <br> <div class="border col-5"> <br> <h2>Gift</h2> <br> <div class="row mb-10"> <div class="col-md"> <input type="hidden" name="entry_url" id="entry_url" value="{{constant('gift\Bootstrap::ENTRY_URL')}}"> <form method="post" action="giftconfirm.php" enctype="multipart/form-data"> <div class="form-group" > <label> 写真:</label> <input type="file" name="image" /> <br><span class="red" >{{errArr.image}}</span> <br><p>{{ImgMsg}}</p> </div>

---省略---
<button type="submit" name="back" class="btn btn-outline-secondary btn-block">戻る</button>
</div>
<div class="col-5">
<button type="submit" name="confirm" class="btn btn-outline-primary btn-block">確認</button>
</div>
<br>
<br>
<br>
</div>
</form>
</div>
</div>
</div>

</body> ``` confirm.html.twig (投稿確認画面)
<input type="hidden" name="entry_url" id="entry_url" value="{{constant('gift\Bootstrap::ENTRY_URL')}}"> <form method="post" action="giftconfirm.php"> <table> <tr> <th>写真:</th> <td><img src="{{IMAGE}}" /></td> </tr> ---省略--- <div> <input type="submit" name="back" value="戻る" /> <input type="submit" name="complete" value="登録完了" /> {% for key,value in dataArr %} <!-- ↓下記メソッドで配列か否かチェックしている --> {% if value is iterable %} {% for v in value %} <input type="hidden" name="{{key}}[]" value="{{v}}" /> {% endfor %} {% else %} <input type="hidden" name="{{key}}" value="{{value}}" /> {% endif %} {% endfor %} </div>
```giftconfirm.php
<?php namespace gift; require_once dirname(__FILE__) . '/Bootstrap.class.php'; use gift\lib\Session; use gift\lib\PDODatabase; use gift\lib\Common; $db = new PDODatabase(Bootstrap::DB_HOST, Bootstrap::DB_USER, Bootstrap::DB_PASS,Bootstrap::DB_NAME,Bootstrap::DB_TYPE); $common = new Common(); $ses = new Session($db); $loader = new \Twig_Loader_Filesystem(Bootstrap::TEMPLATE_DIR); $twig = new \Twig_Environment($loader,[ 'cache' => Bootstrap::CACHE_DIR ]); $_SESSION['IMAGE'] = ''; //モード判定(どの画面から来たかの判断) //登録画面から来た場合 if (isset($_POST['confirm']) === true) { $mode = 'confirm'; } //戻る場合 if (isset($_POST['back']) === true) { $mode = 'back'; } //登録完了 if (isset($_POST['complete']) === true) { $mode = 'complete'; } //ボタンのモードによって処理を変える switch ($mode) { case 'confirm'://新規登録 //データを受け継ぐ //↓この情報は入力には必要ない unset($_POST['confirm']); // var_dump($_FILES); $dataArr = $_POST; $dataArr[] = $_FILES; var_dump($dataArr); // var_dump($dataArr[0]['image']['type']); //エラーメッセージの配列作成 $errArr = $common->errorGiftCheck($dataArr); // var_dump($errArr['image']); $err_check = $common->getErrorFlg($errArr); //err_check = false →エラーがありますよ! //err_check = true →エラーがないですよ! //エラーがなければconfirm.tpl あるとregist.tpl // var_dump($errArr); $path = str_replace('/Applications/MAMP/tmp/php/','', $_FILES['image']['tmp_name']); $_SESSION['IMAGE'] = Bootstrap::TMP_FILE_DIR . $path . '.jpg'; echo 'セッションイメージ'; var_dump($_SESSION['IMAGE']); var_dump($_FILES['image']['tmp_name']); $template = ($err_check === true) ? 'gift_confirm.html.twig' : 'gift_form.html.twig'; break; ---省略--- case'complete': //登録完了 $dataArr = $_POST; //↓この情報はいらないので外しておく unset($dataArr['complete']); var_dump($dataArr); // $table = 'user_tb'; // $errArr = $common->errorGiftCheck($dataArr); // $err_check = $common->getErrorFlg(); // $res = $db->insert($table, $dataArr); // if ($res === true) { // //登録成功時は完成ページへ // header('Location: ' . Bootstrap::ENTRY_URL . 'complete.php'); // } else { // //登録失敗時は登録画面に戻る // $template = 'gift_form.html.twig'; // foreach ($dataArr as $key => $value) { // $errArr[$key] = ''; // } // } break; } $relArr = [ '友達', '家族', '親戚', '上司・先輩', '部下・後輩', 'その他' ]; $sceneArr = [ '誕生日', '門出', '記念日', 'お祝い(就職、入学、結婚)', 'お礼', '挨拶', 'その他' ]; $context['dataArr'] = $dataArr; $context['errArr'] = $errArr; $context['relArr'] = $relArr; $context['sceneArr'] = $sceneArr; $context['IMAGE'] = $_SESSION['IMAGE']; $template = $twig->loadTemplate($template); $template->display($context); ``` ``` ```Common.class.php ``` <?php private function ImageCheck($dataArr) { var_dump($dataArr); // var_dump($_POST); if (isset($dataArr[0]['image']) !== 0){ $tmp_image = $dataArr[0]['image']; // var_dump($_POST['image']); // var_dump($tmp_image); // エラーなく、サイズが0でないか if ($tmp_image['error'] === 0 && $tmp_image['size'] !== 0) { //正しくサーバーにアップされているかどうか if (is_uploaded_file($tmp_image['tmp_name']) === true){ echo 'ファイルはアップロードされている'; } // }else{ // echo 'ファイルはアップロードされていない'; // } //画像情報を取得する $image_info = getimagesize($tmp_image['tmp_name']); $image_mime = $image_info['mime']; //画像サイズが利用できるサイズ以内かどうか if ($tmp_image['size'] > 10485760) { $ImgErrMsg = 'アップロードできる画像のサイズは、10MBまでです'; // 画像の形式が利用できるタイプかどうか } elseif (preg_match('/^image/jpeg|image/HEIC$/', $image_mime) === 0) { $ImgErrMsg = 'アップロードできる画像の形式は、JPEGまたはHEIC形式だけです'; } $str = $tmp_image['tmp_name']; $path = str_replace('/Applications/MAMP/tmp/php/','', $str); //パスを作るために、一時ファイル名の内のディレクトリの部分を取り除く $res = move_uploaded_file($tmp_image['tmp_name'], Bootstrap::TMP_FILE_DIR . $path . '.jpg'); } else { $ImgErrMsg = 'アップロードに失敗しました'; } } else { $this->errArr['image'] = 'ファイルを選択して下さい'; } } ```

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

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

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

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

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

m.ts10806

2019/04/10 06:29

「任意のディレクトリ」はブラウザから参照可能な場所なのでしょうか。
m.ts10806

2019/04/10 06:30

新しく質問をたてられたようですが、 https://teratail.com/questions/183743 質問は編集できるので「間違えた」「誤字った」「途中で投稿してしまった」としても新しく質問を立てる必要はありません。 回答がつく前でしたら質問詳細ページから削除依頼が行えますので、どちらか削除依頼をしておいてください。
m.ts10806

2019/04/10 06:59

ちなみに「画像を表示しているところ」のコードはどこでしょうか? 今回提示されたコードの中には見当たらないような
arahito

2019/04/10 07:13

ご指摘ありがとうございます。 初めて質問しました。 もう一つの方には削除依頼しました。 confirm.html.twig追加しました。
m.ts10806

2019/04/10 07:23

インデントがなくなりましたね。teratailのバグかな(何度か見たことがあります)
arahito

2019/04/10 07:25

任意のディレクトリはphpファイルと同じ階層にあります。
guest

回答2

0

ベストアンサー

大事なのは「ブラウザから参照可能な場所かどうか」です。
phpプログラム自体はブラウザから参照できる必要はないのでWebサーバー内であればどこに置いても参照させられます。
画像はブラウザから参照させるものでしたらブラウザからアクセス可能なディレクトリ(つまりDocumentRoot)配下にあるのが原則です。
※もちろんphpから画像を読み込ませるのであればこの限りではありません。

見たところ「Bootstrap::TMP_FILE_DIR」に保存しているようですが、このディレクトリはブラウザから参照できる場所なのでしょうか?
ブラウザから参照できないのであれば、当然、imgタグで参照させようとしても読み込みはできません。

あと、既に指摘うけていますが、「tmp_name」をそのまま使うものではありません。
一時ファイルの名称だからです。システム側から払い出すのが通例です。

各種チェック(脆弱性対策など)も含めると下記のような記事が参考になると思います。

上記でも「自前で一意なファイル名を生成するのが最善の策」とありますし、例でもsha1_file()でハッシュ値とってます。

投稿2019/04/10 07:34

m.ts10806

総合スコア80765

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

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

arahito

2019/04/10 07:46 編集

各種チェック参考にします。 MACでMAMPを使用しているのですが、 TMP_FILE_DIR = '/Applications/MAMP/htdocs/gift/upfiles/tmp/'であり、 phpファイルは/Applications/MAMP/htdocs/gift/giftconfirm.php 画像は/Applications/MAMP/htdocs/gift/upfiles/tmp/画像 に置いてあります。 htdocs以下にあればブラウザから参照できる場所にあるという認識で合っていますか?
m.ts10806

2019/04/10 07:50

DocumentRootは /Applications/MAMP/htdocs/ ということでしょうか。 で、あればDocumentRootからの絶対パス、またはimgタグが実行されるプログラムからの相対パスにする必要があるので、 <img src="/gift/upfiles/tmp/画像ファイル名"> のようになるはずです。(絶対パスの場合) ブラウザからURLを実行して画像が表示されることを確認してください。 今もしTMP_FILE_DIRのままなら下記のようになってませんか? <img src="/Applications/MAMP/htdocs/gift/upfiles/tmp/画像ファイル名"> ブラウザのアドレスバーに下記のようにURL打ってみて表示されるほうが正しいものです。 http://ドメイン/Applications/MAMP/htdocs/gift/upfiles/tmp/画像ファイル名 http://ドメイン/gift/upfiles/tmp/画像ファイル名
guest

0

move_uploaded_file()
↓↓↓
move_upload_file()

※すみません、勘違い

なお、ユーザーがおくってくるファイル名を信用してはいけません
適当なエンティティ処理をかけて他バイト文字を廃してください
ファイル名が競合したときにどうするかは別途検討してください

投稿2019/04/10 06:54

編集2019/04/10 07:20
yambejp

総合スコア114572

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

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

yambejp

2019/04/10 07:00

ありゃ・・・ 「move_upload-file」に引っ張られちゃいました ソースの方はあってますね、ごめんなさい
m.ts10806

2019/04/10 07:18

あ、タイトルか; そっちには気づきませんでした…
arahito

2019/04/10 07:20

投稿日時をファイル名に含ませる予定でしたが、確認画面で画像を表示させることを考えた時に、投稿日時でファイル名を名付けると、すぐに呼び出したいのにdbからセレクトしなければならなくなるので$_SESSIONにファイルパスを持たせて確認画面で表示、確認画面をへて登録ボタンが押される時に再度move_uploaded_fileでファイルを移動、名前や詳細などの値と一緒にDBにinsertしようと思ったのですが、二度デマですかね、、?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問