編集のシーンでだけ入力漏れがないかバリデーションをする
新規登録でもしたい
→
関数化すれば使いまわせる
名前と値段は必須ねというやつ
優先順位としては送信していいかどうかよりも前だ
e.preventDefault();の綴りを2回間違ってるので
Defaultの綴りに注意
こういう分岐:
未入力ある?
はい→alert表示、プリベントデフォルト
いいえ→
ホントに編集していい?
はい→実行
いいえ→プリベントデフォルト
こういう感じ
ここまで
lunch.js
$(function(){
//console.log("hoge");
//バリデーション
function check(){
var chk;
if($('#menu').val() == '' || $('#price').val()==''){//空なら
chk = false;
}else{
chk=true;
}
return chk;
}
//編集ボタン
$('#sub1').on('click',function(e){
var chk=check();//上で宣言したのを実行
//バリデーション
if(!chk){
//未入力項目あり
alert('未入力項目あるよ');
e.preventDefault();//イベント無効化
}else{
//入力OK,編集していいかどうか確認
var flag=confirm('編集してよろしいかな');
if(!flag){//いいえを押された
e.preventDefault();
}
}
});
//削除ボタン
$('#sub2').on('click',function(e){
var flag=confirm('削除してよろしいかな');
if(!flag){//いいえを押された
e.preventDefault();
}
});
});
さて新規と、編集削除の分岐をしますよ
form.phpに戻るよ
</table>
<?php if(empty($id)): ?>
<p>
<input type="submit" name="sub3" id="sub3" value="新規作成">
</p>
<?php else: ?>
<p>
<input type="submit" name="sub1" id="sub1" value="編集">
<input type="submit" name="sub2" id="sub2" value="削除">
</p>
<?php endif ?>
id="sub3"を付け加えたので、
jsにも付け加え
//新規作成ボタン
$('#sub3').on('click',function(e){
var chk=check();
if(!chk){
alert('未入力項目あるよ');
e.preventDefault();
}else{
var flag=confirm('登録してよろしいかな');
if(!flag){
e.preventDefault();
}
}
});
外部からのアタックにチケットの発行は有効なので
ランダムな数をつくってhiddenでこそっとわたして
sessionととんできたのと比較する
自分で予定しているフォームからきていることを確認する
チケットの半券システム
echo time();
1900年だかから何秒経過したか
時間だけだとアタックしやすいので、
$ran = rand(1,100);
$salt="hogemakino";
$ticket =md5($ran.time().$salt);
echo $ticket ;
ソルトが大事
time()だけではアタックされるしrandomだけでも弱い
検証で確認すること
<input type="submit" name="sub" id="sub3" value="新規作成">
新規、編集、削除3つのボタンのnameを全部subに変えますよ
すべて整っている前提で、
switchぶんで分岐しますよ
caseごとにbreakを忘れずに
ここまで
exec.php
<?php
print_r($_POST);
session_start();
if($_SESSION["ticket"] != $_POST["ticket"]){//チケットの半券一致せず
exit();
}
require_once("class/lunch.class.php");
$obj = new Lunch();
switch($_POST["sub"]){
case "新規作成"://飛んできたvalueが新規
$obj->setMenu($_POST["menu"], $_POST["price"], $_POST["c_id"]);
break;
case "編集":
$obj->updateMenu($_POST["menu"], $_POST["price"], $_POST["c_id"], $_POST["id"]);
break;
case "削除":
$obj->deleteMenu($_POST["id"]);
break;
}
//header("Location:list.php");
//exit();
?>
form.php
<?php
session_start();
$ran = rand(1,100);
$salt="hogemakino";
$ticket =md5($ran.time().$salt);
//echo $ticket ;
$_SESSION["ticket"] = $ticket;//session側でチケット発行
//新規でも編集でもこのファイルを使いたい
require_once("class/lunch.class.php");
$obj = new Lunch();
if(!empty($_GET["id"])){
//編集の場合
//getで送られてくるidを事前につかまえる
$id=intval($_GET["id"]);
$title="編集";//タイトルも分岐によって変わる
$arr = $obj->getMenuById($id);
$menu = htmlspecialchars($arr["menu"],ENT_QUOTES);
$price = $arr["price"];
$c_id = $arr["c_id"];
}else{
//新規作成の場合
$title="新規作成";
$menu = "";
$price ="";
$c_id=0;//A.I.(オートインクリメント)は1から始まる。わざとありえない番号を初期値にしておく
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>メニュー<?php echo $title; ?></title>
<link rel="stylesheet" href="css/style.css">
<script src="../jquery-3.4.1.min.js"></script>
</head>
<body>
<div id="container">
<h1>メニュー<?php echo $title; ?></h1>
<form action="exec.php" method="post">
<table>
<tr>
<th><label for="menu">メニュー</label></th>
<td><input type="text" name="menu" id="menu" value="<?php echo $menu; ?>"></td>
</tr>
<tr>
<th><label for="price">価格</label></th>
<td><input type="text" name="price" id="price" value="<?php echo $price; ?>"></td>
</tr>
<tr>
<th><label for="c_id">カテゴリ</label></th>
<td>
<?php $obj->makeCatSelect($c_id); ?>
</td>
</tr>
</table>
<?php if(empty($id)): ?>
<p>
<input type="submit" name="sub" id="sub3" value="新規作成">
</p>
<?php else: ?>
<p>
<input type="submit" name="sub" id="sub1" value="編集">
<input type="submit" name="sub" id="sub2" value="削除">
<input type="hidden" name="id" value="<?php echo $id; ?>">
</p>
<?php endif ?>
<input type="hidden" name="ticket" value="<?php echo $ticket;/*form側でもチケット発行*/ ?>">
</form>
<script src="js/lunch.js"></script>
</body>
</html>
lunch.js
$(function(){
//console.log("hoge");
//バリデーション
function check(){
var chk;
if($('#menu').val() == '' || $('#price').val()==''){//空なら
chk = false;
}else{
chk=true;
}
return chk;
}
//編集ボタン
$('#sub1').on('click',function(e){
var chk=check();//上で宣言したのを実行
//バリデーション
if(!chk){
//未入力項目あり
alert('未入力項目あるよ');
e.preventDefault();//イベント無効化
}else{
//入力OK,編集していいかどうか確認
var flag=confirm('編集してよろしいかな');
if(!flag){//いいえを押された
e.preventDefault();
}
}
});
//削除ボタン
$('#sub2').on('click',function(e){
var flag=confirm('削除してよろしいかな');
if(!flag){//いいえを押された
e.preventDefault();
}
});
//新規作成ボタン
$('#sub3').on('click',function(e){
var chk=check();
if(!chk){
alert('未入力項目あるよ');
e.preventDefault();
}else{
var flag=confirm('登録してよろしいかな');
if(!flag){
e.preventDefault();
}
}
});
});
lunch.class.php
<?php
class Lunch{
private $pdo;//外から直接アクセスはできないように
public function __construct(){//コンストラクタ。初期化されたときに動く
// -----------------
//環境によって変更
// -----------------
$host="localhost";
$dbuser="root";
$dbpass="";
$dbname="lunch";
// -----------------
$dsn = "mysql:host={$host}; dbname={$dbname}; charset=utf8";
$this->pdo=new PDO($dsn,$dbuser,$dbpass); //$pdoとは書かない
}//constructの終わり
public function getAllMenu(){//publicでないと外から呼び出せない
$sql = "SELECT * FROM foods";
$rs = $this->pdo->query($sql);
$rows = $rs->fetchAll(PDO::FETCH_ASSOC);
return $rows;//戻り値
}
public function getMenubyId($id=1){//指定したid番号を取得、引き取るid番号が仮引数の$id
$sql="SELECT * FROM foods WHERE id=:id";
$stmt = $this->pdo->prepare($sql);
$stmt->bindvalue(":id",$id,PDO::PARAM_INT);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row;
}
public function setMenu($menu,$price,$c_id){//idはオートインクリメントなので必要ない
$sql = "INSERT INTO foods(menu,price,c_id) VALUES (:menu,:price,:c_id)";//メニューと値段とカテゴリidを追加
$stmt = $this->pdo->prepare($sql);//クラス内の変数なのでstmtやsqlのスコープはここだけ
$stmt->bindvalue(":menu",$menu,PDO::PARAM_STR);
$stmt->bindvalue(":price",$price,PDO::PARAM_INT);
$stmt->bindvalue(":c_id",$c_id,PDO::PARAM_INT);
$stmt->execute();
//戻り値は要らない
}
public function updateMenu($menu,$price,$c_id,$id){//どれがupdateされるか分からないので3つとも仮引数を用意
//主キーである$idがないと全部書き換わってしまうのでどこのレコードか指定するため今回4つプロパティが要る
$sql = "UPDATE foods SET menu=:menu, price=:price, c_id=:c_id WHERE id=:id";
$stmt = $this->pdo->prepare($sql);
$stmt->bindvalue(":menu",$menu,PDO::PARAM_STR);
$stmt->bindvalue(":price",$price,PDO::PARAM_INT);
$stmt->bindvalue(":c_id",$c_id,PDO::PARAM_INT);
$stmt->bindvalue(":id",$id,PDO::PARAM_INT);//idも必要ですよ
$stmt->execute();
}
public function deleteMenu($id){//パラメータは主キーであるidだけでいい
$sql = "DELETE FROM foods WHERE id=:id";
$stmt = $this->pdo->prepare($sql);
$stmt->bindvalue(":id",$id,PDO::PARAM_INT);
$stmt->execute();
}
//セレクトプルダウンに表示
public function makeCatSelect($c_id){
$sql = "SELECT * FROM cats";
$rs = $this->pdo->query($sql);//レコードセットの中に結果セットを入れる形
echo "<SELECT name=\"c_id\" id=\"c_id\">\n";
//ダミーのオプション
echo "<option value=\"\">以下から選択</option>\n";
while($row = $rs->fetch(PDO::FETCH_ASSOC)){
$selStr = $c_id==$row["c_id"] ? " selected" : "";//三項演算。selectedか何もないか。あるにせよないにせよechoする。一致すればselected、なければ""
//option value="1"うどん</option>みたいなのを出力したい
echo "<option value=\"{$row["c_id"]}\"{$selStr}>";
echo htmlspecialchars($row["cat"],ENT_QUOTES);
echo "</option>\n";
}
echo "</select>\n";
}
}
?>
style.php
body{
background:#eff;
}
#container{
width:80%;
margin:auto;
}
table{
border-collapse:collapse;
}
th,td{
padding:0.3rem 0.5rem;
text-align:left;
background:#fff;
border:solid 1px #555;
}
th{
background:#ccc;
}
なおばりばりとエラーがでたが原因は
switch($_POST["sub"]){
case "新規作成"://飛んできたvalueが新規
$obj->setMenu($_POST["menu"], $_POST["$price"], $_POST["$c_id"]);
break;
$_POST["$price"]じゃなくて、
$_POST["price"]
$がいらなかった