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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

Q&A

解決済

2回答

2487閲覧

画像をアップロードする方法がわかりません

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

0グッド

0クリップ

投稿2019/01/14 14:42

編集2019/01/15 01:49

PHPで掲示板を作っています。

【開発環境】
win10
xammp7.2.13
PHP7

画像をtmpフォルダからuser_pictureフォルダに移したいのですがうまくいきません。

<?php session_start(); require('dbconnect.php'); if(isset($_SESSION['id']) && $_SESSION['time'] + 3600 > time()){ $_SESSION['time'] = time(); $members = $db->prepare('SELECT * FROM members WHERE id=?'); $members->execute(array($_SESSION['id'])); $member = $members->fetch(); }else{ header('Location: login.php'); exit(); } if(!empty($_POST)){ if($_POST['message'] !== ''){ //メッセージをDBへ挿入 $message = $db->prepare('INSERT INTO posts SET member_id=?, message=?'); $message->execute(array( $member['id'], $_POST['message'] )); } header('Location: index.php'); exit(); } if(!empty($_POST)){ if($_POST['image'] !== ''){ //ファイルの検査 $filename = $_FILES['image']['name']; if(!empty($filename)){ $exe = substr($filename, -3); if($exe != 'jpg' && $exe != 'gif' && $exe != 'png'){ $error['image'] = 'type'; }else{ //ファイルをアップロード $image = date('YmdHis') . $filename; move_uploaded_file($_FILES['image']['tmp_name'], 'user_picture/' . $image); $images = $image; //写真をDBへ挿入 $pic = $db->prepare('INSERT INTO posts SET member_id=?, picture=?'); $pic->execute(array( $member['id'], $_POST['image'])); } } } header('Location: index.php'); exit(); } $posts = $db->query('SELECT m.name, p.* FROM members m, posts p WHERE m.id=p.member_id ORDER BY p.id DESC'); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>掲示板</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div id="wrap"> <div id="head"> <h1>掲示板</h1> </div> <div id="content"> <div style="text-align: right"><a href="logout.php">ログアウト</a></div> <form action="" method="post" enctype="multipart/form-data"> <dl> <dt><?php print(htmlspecialchars($member['name'], ENT_QUOTES)); ?>さん、メッセージをどうぞ</dt> <dd> <textarea name="message" cols="50" rows="5"></textarea> <input type="hidden" name="reply_post_id" value="" /> </dd> <dd> <input type="file" name="image" size="35" value=""> <?php if($error['image'] === 'type'): ?> <p class="error">* 画像は「.jpg」「.gif」「.png」を指定してください</p> <?php endif; ?> </dd> </dl> <div> <p> <input type="submit" value="投稿する" /> </p> </div> </form> <!-- 投稿一覧 --> <?php foreach ($posts as $post): ?> <div class="msg"> <p><?php print(htmlspecialchars($post['message'], ENT_QUOTES)); ?><span class="name">(<?php print(htmlspecialchars($post['name'], ENT_QUOTES)); ?>)</span>[<a href="index.php?res=">Re</a>]</p> <?php if($images !== ''): ?> <p><img src="user_picture/<?php print(htmlspecialchars($post['picture'], ENT_QUOTES)); ?>" width="48" height="48" alt="" /></p> <?php endif; ?> <p class="day"><a href="view.php?id="></a> <a href="view.php?id="> 返信元のメッセージ</a> [<a href="delete.php?id=" style="color: #F33;">削除</a>] </p> </div> <?php endforeach; ?> <ul class="paging"> <li><a href="index.php?page=">前のページへ</a></li> <li><a href="index.php?page=">次のページへ</a></li> </ul> </div> </div> </body> </html>

データベースはbbsにmembersとpostsのテーブルがあります。

create table members( id int, name varchar(255), email varchar(255), password varchar(100) );
create table posts( id int, message text, member_id int, replay_message_id int, picture varchar(255) );

なぜアップロードされたファイルが移動しないのかわかりません。
回答よろしくお願いします。

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

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

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

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

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

Orlofsky

2019/01/14 15:20

テーブル定義はキャプチャーではなく、CREATE TABLE で提示した方が適切なコメントが付き易いです。
m.ts10806

2019/01/14 16:33

messageが未入力のときにしかimageに対する処理をしてませんが、それはそういう仕様でしょうか? postsには常にmessageかimageしか入らない仕様なのでしょうか。 imageは何をDBに保管したいのでしょうか
退会済みユーザー

退会済みユーザー

2019/01/15 01:30

>>messageが未入力のときにしかimageに対する処理をしてませんが、それはそういう仕様でしょうか? >>postsには常にmessageかimageしか入らない仕様なのでしょうか。 いえ、違います。例えば、メッセージだけ、写真だけ、または両方投稿できるようにしたいです。 >>imageは何をDBに保管したいのでしょうか jpg,png,gif形式のファイルを保存したいです。 text型なのかbolb型なのか、どちらが適切なのかわかりません。
退会済みユーザー

退会済みユーザー

2019/01/15 01:31

>>テーブル定義はキャプチャーではなく、CREATE TABLE で提示した方が適切なコメントが付き易いです。 そうなんですね!。ご指摘ありがとうございます。
退会済みユーザー

退会済みユーザー

2019/01/15 01:34

テスト環境のOS(Windowsだとか)、webサーバー(apache httpdだとか)とかも示してほしい。そういうの依存で点検するべきところが変わるので。
退会済みユーザー

退会済みユーザー

2019/01/15 01:44

>>テスト環境のOS(Windowsだとか)、webサーバー(apache httpdだとか)とかも示してほしい。そういうの依存で点検するべきところが変わるので。 わかりました!
m.ts10806

2019/01/15 01:46

>いえ、違います。例えば、メッセージだけ、写真だけ、または両方投稿できるようにしたいです。 ご自身が「messageが未入力のときにしかimageに対する処理をしていない」「postsには常にmessageかimageしか入らない」ように組まれているため、そのようにコメントしました。コードを見直してみてください。 あと「ファイル自身」なのか「拡張子」なのか「ファイルパス」なのかで違います。そのあたりは過去質問にも何度か出ているので確認してください。 (※ファイルの実体を保存するのはあまり良しとされていません)
guest

回答2

0

ベストアンサー

解説のため回答におこします。

messageが未入力のときにしかimageに対する処理をしていない

messageが入力された時点でmessageに対するinsert処理が実行されて、終わったらindex.phpにリダイレクトされるため、imageの処理にはいかないようになっています。

postsには常にmessageかimageしか入らない

messageが未入力のときにしかimageに対する処理をしていないの流れから、
どちらかに入るようにしか作られていないということです。

「メッセージだけ、写真だけ、または両方投稿」という仕様なのでしたら、
「送信されていない場合は空情報をinsert」という風にしないといけません。

また「ファイルがアップロードされているか」の検査は$_FILESからnameを取得してemptyかを見るのではなく
is_file_uploaded()という検査用の関数があります。
※上記のPHPマニュアルにもあるように引数はファイルの実体であるtmp_nameを渡さないといけません。

$_FILESのnameは「クライアントマシンの元のファイル名」が格納されています。
実際はuser_pictureの配下に日時をつけたファイルを格納するように作られていますから、クライアントマシンの元のファイル名を保持しても意味がありませんし、ファイル送信された情報を$_POSTで受け取ろうとしてもnullなので何も取得できません。

画像情報をDBに保存したい場合は下記の方法が主だと思います。

  1. ファイルの実体を取得してDBに直接入れる

->user_picture配下に設置した画像の実体をfile_get_contents()などで読み込んできて保存。
(base64_encode()でバイナリ変換しても良い)
0. ファイルのパスを保存
->user_picture/20190115111012.jpgのように保存先のパスそんまま
0. ファイル名だけ保存
->保存フォルダが決まっている場合はファイル名だけ
0. 拡張子だけ保存
->ファイル名がレコードのIDなどと紐付いている、且つ保存フォルダが決まっている場合は拡張子だけ保存しておけばOK
0. DBには何もしない
->ファイル名がレコードのIDなどと紐付いていて、且つ保存フォルダが決まっていて、且つ利用できる拡張子まで決まっている場合は何も保存しなくても良い

1.以外は「画像保存先の情報と紐付くような情報を保存しておく」ですね。
もちろん気をつけなければならないのは画像の保存場所です。
もし、パスそのままをWeb上から参照するのであれば、画像をドキュメントルート配下(ブラウザから参照できる場所)に保存しなければなりません。
Web上から参照させず、必要に応じて(リクエストに応じて。例えばログインしないと見せないとか)表示するのであれば非公開のフォルダに保存しておいて、正しいリクエストが来たときだけ画像の実体を取得してきて表示する方法もあります(バイナリデータとか、GDライブラリとか)

画像を保存する際にDBを絡めたい場合の是非や考え方は過去質問にあります。

何がいいかは一長一短です。仕様も関係してくるのでご自身で決めてください。
どのようなやり方でも要件を満たせればそれでOKです。

ただし、問題があって、ファイルは偽装が可能です。
substr()で後ろから3つとってきたとしてもそれが画像であるという確証はありません。
ファイルが破損しているか、別のファイルの拡張子をかえただけのものではないか、といった検証(バリデーション)は必須です(試しにExcelファイルの拡張子を[jpg]にしてみてください)

下記のような記事は読んでおいたほうが良いです。

色々踏まえて枠だけ作るとこんな感じ。(未検証)

php

1if($_SERVER["REQUEST_METHOD"] === "POST"){ 2 3 $message = null; 4 $image = null; 5 6 if($_POST['message'] !== ''){ 7 $message = $_POST['message']; 8 }//本当にこれだけならfilter_input()で良い 9 10 if(is_uploaded_file($_FILES["image"]["tmp_name"])){ 11 //ファイルアップロード処理 12 13 //↑が成功したらDBに保存する画像情報取得 14 } 15 16 //メッセージをDBへ挿入 17 $dbh = $db->prepare('INSERT INTO posts SET member_id=?, message=?, image=?'); 18 $dbh->execute(array( 19 $member['id'], 20 $message, 21 $image, 22 )); 23}

本来は文字数のチェックなども必要です。

投稿2019/01/15 02:34

m.ts10806

総合スコア80850

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

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

退会済みユーザー

退会済みユーザー

2019/01/15 04:53

ありがとうございます。おかげさまでファイルのアップロードは出来ました。
m.ts10806

2019/01/15 04:55

解決した方法や手段をもう少し具体的にコメントいただいた方が回答した者としては助かります。 自身の回答がどの程度理解されたとか、結構気になるものなので(理解されないまま同じような質問を立てられると残念な気持ちにもなりますし、ご自身の成長にも影響があるかと思います)
退会済みユーザー

退会済みユーザー

2019/01/15 06:54 編集

具体的には以下のように書きました。(見にくくてすみません) if(!empty($_POST)){ //ファイルをアップロード $tempfile = $_FILES['image']['tmp_name']; $images = $_FILES['image']['name']; $image = date('YmdHis') . $images; $filename = 'user_picture/' . $image; if(is_uploaded_file($tempfile)){ if(move_uploaded_file($tempfile, $filename)){ }else{ $error['image'] = 'failed'; } }else{ $error['image'] = 'blank'; } if($_POST['image'] !== ''){ //写真をDBへ挿入 $pic = $db->prepare('INSERT INTO posts SET member_id=?, picture=?'); $pic->execute(array( $member['id'], $_POST['image'] )); } if($_POST['message'] !== ''){ //メッセージをDBへ挿入 $message = $db->prepare('INSERT INTO posts SET member_id=?, message=?'); $message->execute(array( $member['id'], $_POST['message'] )); } header('Location: index1.php'); exit(); } これでuser_pictureフォルダには画像を保存することができました。しかし、今度はDBに画像を保存できなくてただいま試行錯誤中です^^;(メッセージは保存されるのですが、、、)
m.ts10806

2019/01/15 06:55

えーっと。 私の回答ほとんど無視されているような。
m.ts10806

2019/01/15 06:56

理解が難しいところがあれば聞いてくだされば良いのですが、 それもなしに自身のコードほぼそのままで突っ走られても困りますね。
退会済みユーザー

退会済みユーザー

2019/01/15 07:16

申し訳ありません。 mts10806さんのコードを参考にして書いたら if($_SERVER["REQUEST_METHOD"] === "POST"){ $message = null; $image = null; if($_POST['message'] !== ''){ $message = $_POST['message']; }//本当にこれだけならfilter_input()で良い if(is_uploaded_file($_FILES["image"]["tmp_name"])){ //ファイルアップロード処理 $tempfile = $_FILES['image']['tmp_name']; $images = $_FILES['image']['name']; $image = date('YmdHis') . $images; $filename = 'user_picture/' . $image; move_uploaded_file($tempfile, $filename); //↑が成功したらDBに保存する画像情報取得 } //メッセージをDBへ挿入 $dbh = $db->prepare('INSERT INTO posts SET member_id=?, message=?, image=?'); $dbh->execute(array( $member['id'], $message, $image, )); } このようになりました。 ただ、ブラウザの再読み込みを押すと「フォーム再送信の確認」とDBと投稿にメッセージが反映されなくなり、私の元のコードを変えてみました。
退会済みユーザー

退会済みユーザー

2019/01/15 07:17

後、DBに保存する画像情報取得というのがわかりませんでした。
m.ts10806

2019/01/15 07:28 編集

私の回答では質問者さんのコードではやりたいことができない理由をたくさん書いています。私の提示したサンプルコードの雛形をそのまま使わないまでも、まずはその理由をきちんと理解して組まないと回答が全く意味なくなりますし、コードは更にグチャグチャになります。 > ブラウザの再読み込みを押すと「フォーム再送信の確認」とDBと投稿 「フォーム再送信の確認」はF5でも押したのではないでしょうか。 普通に送信ボタンを押していたら起きないはずです。 気になるようでしたらご自身が入れられているindex.phpへのリダイレクトheaderを入れておけば良いとと思います。 > 後、DBに保存する画像情報取得というのがわかりませんでした。 ヒントを書いていますよ。 「user_picture配下に設置した画像の実体をfile_get_contents()などで読み込んできて保存。」 記事としては下記とか https://qiita.com/tadsan/items/bbc23ee596d55159f044 「ファイルそのものを保存」というより「ファイルをバイナリデータ化して保存」が通例かと思います。あくまで文字列に変換する形ですね。
guest

0

ディレクトリuser_picture/はフルパスで記載されていませんが、このディレクトリが存在し、Apacheを実行しているユーザーに書き込む権限があることを確認してください。
よくわからない場合は対象ディレクトリにEveryoneに全ての権限をつければ移動できると思います。

別途セキュリティについてはしっかりと設計してください。

投稿2019/01/15 01:57

moonphase

総合スコア6621

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問