【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?

フォームからの入力で登録ボタンを押して
MYSQLへデータの書き込み、そして削除ボタンを押して
データを削除するという勉強をしています。

削除の場合は、番号か名前、電話番号のいずれかを入力して
削除ボタンを押せば該当するデータが削除されるようにしたいのですが
番号指定以外の名前指定や電話番号指定での削除ができません。

「DELETE FROM address where no=$no or name='$name' or tel='$tel'」の
書き方に問題があるようですが
どのようにしたらよいのでしょうか?

----------------------------------------------
<html>
<body>
<form action="" method="post">
番号:<br><input type="text" name="no"><br>
氏名:<br><input type="text" name="name"><br>
電話番号:<br><input type="text" name="tel"><br><br>
<input type="submit" value="登録" name="submit">
<input type="submit" value="削除" name="submit">
</form>

<?php
error_reporting(1);

$con = mysql_connect("127.0.0.1", "root", "");
if(!$con){
exit("データベースに接続できませんでした。");
}

$result = mysql_select_db("test", $con);
if(!$result){
exit("データベースを選択できませんでした。");
}

$no = $_POST["no"];
$name = $_POST["name"];
$tel = $_POST["tel"];
$submit = $_POST["submit"];

if($no != null){
if($submit == "登録"){
$result = mysql_query("INSERT INTO address(no, name, tel)
VALUES ('$no', '$name', '$tel')", $con);
if($result){
echo "<p>登録が完了しました。<br>";
}else{
echo "<p>登録失敗</p>";
}
}elseif($submit == "削除"){
$result = mysql_query("DELETE FROM address where no=$no or name='$name' or tel='$tel'", $con);
if($result){
echo "<p>削除が完了しました。<br>";
}else{
echo "<p>削除失敗</p>";
}
}
}
?>
</body>
</html>

----------------------------------------------

あと「header("Location: {$_SERVER['PHP_SELF']}");」を使って
2重投稿を回避したいのですが
書く場所により「登録が完了しました。」「削除が完了しました。」の
メッセージが表示されなくなってしまいます。
どこに記入したらよいのでしょうか?

よろしくお願いいたします。

A 回答 (4件)

名前や電話番号はユニークであることが前提ですが、それは大丈夫ですかね(MySQLのテーブル設計でUniqueにしていますか)。



$sql = "DELETE FROM address where no=$no or name='$name' or tel='$tel'";
print $sql;

として、どういうSQL文になっているかを確認してください。おそらくは $no が空文字列なので(名前だけを入力したとしたら)

DELETE FROM address where no= or name='入力した名前' or tel=''

のようになっているハズです(SQL文としてダメ)。noが入力されていないときはwhereにnoを入れない(というか入力されたものだけをwhereで書く)ようにしてください(or で誤魔化すのは酷すぎます)。


あと、ネイティブなMySQL関数はすでに非推奨です。今から使うならPDOで(プレースホルダを使って)書いてください。何らかの事情でネイティブなMySQL関数を使うとしてもmysql_set_charsetでのcharset指定もなければmysql_real_escape_stringでエスケープもしていないのは異常です(セキュリティ的に「運用してはいけない」レベルのものになっています)。



>書く場所により「登録が完了しました。」「削除が完了しました。」の
>メッセージが表示されなくなってしまいます。

ブラウザにメッセージを返したら、locationヘッダでの遷移は出来ません。locationヘッダで遷移した先のページでメッセージを表示してください。

#二重投稿は登録や削除に失敗するだけですよね。
#無理に回避する必要もないと思いますけど・・・。
    • good
    • 0
この回答へのお礼

MYSQLはまだほんの少し目を通すくらいしか勉強していないため
詳しい設定方法などはわからないのですが
XamppのphpMyAdminから確認すると
ユニークの設定はno, neme, tel,とも自動にされているようです。

MYSQLでは「DELETE FROM address where no=$no or name='$name' or tel='$tel'」の文で
該当されるデータが上手く削除されるので良いと思って使ってみたのですが
あまり良くないのですね。
「"DELETE FROM address where no=$no or where name='$name' or where tel='$tel'"」に
変えてみたのですがやはり結果は上手くいきません。

mysql_setなどは非推奨になり、今更勉強する意味は
なくなってしまうようでせっかく
少し解りかけはじめたのに本当に残念です。

プレースホルダというのは
少し前に勉強して全く理解できなかったオブジェクト指向を使うようで
まだPHP自体を少ししか理解できていないレベルの私には
別の簡単なことから
手を付けていったほうが良いのかもしれません。

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

お礼日時:2014/03/15 12:21

>「"DELETE FROM address where no=$no or where name='$name' or where tel='$tel'"」に


>変えてみたのですがやはり結果は上手くいきません。

とりあえずはMySQLで「どういうSQL文になればいいのか」をちゃんと考えてください。

この例でいえば($no は整数値だとして)

$where = array();
if ($no !== '') { $where[] = sprintf("(no = %d)", intval($no));
if ($name !== '') { $where[] = sprintf("(name = '%s')", mysql_real_escape_string($name));
if ($tel !== '') { $where[] = sprintf("(tel = '%s')", mysql_real_escape_string($tel));
if (count($where) === 0) { die('abort'); } // エラー処理
$result = mysql_query("DELETE FROM address where " . implode(' or ', $where), $con);

くらいは最低限やらないとダメです(というか or で繋ぐというのもけっこうアバウトすぎる仕様だとは思いますけどね)。


>少し解りかけはじめたのに本当に残念です。

mysql_set_charsetやmysql_real_escape_stringまで覚えたのに・・・というなら解りますけど。まだ実用になるソースが書けないのですから、今のうちならいいでしょ。
    • good
    • 0
この回答へのお礼

シンプルな結果を出すのにも
構文は非常に複雑になってしまうのですね。

まだサンプルサイトの簡単な構文を見比べながら
勉強している状態で、mysql関数も非推奨になるといっても
練習ができただけでも良かったと思うことにします。

練習サイトや学習本などは最初は初歩からはじまっても
突然複雑で難しくなるものばかりで
思うように進歩がありません。

独学の場合、どうやったら効率の良い勉強ができ
継続できるかが一番の課題なのかもしれません。

お礼日時:2014/03/15 17:23

ポイントをいくつか



とりあえず動くようにするのであれば
DELETE構文自体はあっているので
$noをシングルクォーテーションでくくるだけでいいかもしれません

DELETE FROM address where no='$no' or name='$name' or tel='$tel'

プレースホルダーについてはおいおい学習してください

>少し解りかけはじめたのに本当に残念です。
mysql系の関数は多少の仕様変更でmysqli系の関数が引き継いでいます。
mysqli系の手続き型構文を学習すれば無駄にはなりません。
また要領さえつかめばmysqli系のオブジェクト型の構文にシフトできますし
PDOに移行してもいいでしょう。

>あと「header("Location: {$_SERVER['PHP_SELF']}");」を使って

まず$_SERVER['PHP_SELF']の使用はあまり勧められません
$_SERVER['SCRIPT_NAME']に移行を検討してみてください

また登録や失敗を表示することとheaderで飛ばすことは仕様が競合しています
飛ばす先をそれぞれseikou.htmとsippai.htmにするとか
mypage.php?result=seikou、mypage.php?result=sippaiのようにして
resultの値をみて表示をかえるなどで対応できます。
慣れてくればセッションで引き継いでもいいでしょう

さて、本題ですがテストとしては問題ありませんが、不特定多数が
利用するサービスとしては番号を指定して削除をユーザーが自由にできる仕様は
他人の書き込みを第三者が無条件に消せてしまうので問題です。
ログインして、そのユーザーIDを元に文書IDごとに削除可能かどうか判断するようにするか
その書き込みに対して削除パスワードを設定しておくなどシステムが必要になります
ゆくゆくはそのあたりまで学習なさるといいでしょう
    • good
    • 0
この回答へのお礼

ご指導の通りシングルクォーテーションなども
試してみたのですが結局上手くいきませんでした。

完全に理解して構文を書いているわけではなく
適当に足したり、変えてみたりして
結果がでるかどうか試しているような状態なので
なかなか進歩がないのかもしれません。

とにかくアドバイス感謝しています。
ありがとうございました!

お礼日時:2014/03/15 16:35

以下の記事をもって回答とさせていただきます。

ここで回答すべきことはほぼ全て網羅しているので。

Qiita - PHPでデータベースに接続するときのまとめ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71

2重投稿回避については、ユニークキー制約をつけるだけで問題解決しますよね。
    • good
    • 0
この回答へのお礼

ありがとうございます!

リンク先ざっと見させていただきました。
まだ全く理解できないようなレベルなので
今課題はあきらめることにしました。

1年後くらいに「あ~こうだったんだ!」思えるように
なれることを期待します。

お礼日時:2014/03/15 16:30

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!