20211203のPHPに関する記事は10件です。

php: いろいろなリダイレクト

リダイレクトしたいURL https://sample.domain/xxx ↓ https://xxx.jp ★PHPでかく場合 /** * @Route("/xxx", name="xxx") */ public function index() { header('Location: https://xxx.jp', true, 301); exit; } ★Symfonyで書く場合 /** * @Route("/xxx", name="xxx") */ public function index() { return $this->redirect('https://xxx.jp', 301); } ★.htaccess でやる場合 (Rewrite Engine on の下に追記する) RewriteCond %{QUERY_STRING} ^$ RewriteRule ^xxx$ http://xxx.jp/? [R=301,L] RewriteCond %{QUERY_STRING} ^$ RewriteRule ^xxx/sub$ http://xxx.jp/sub? [R=301,L] ★AWSでやる場合 個人的には、AWS管理画面からリダイレクトさせた方が安全そう status:301(引っ越しました)を返せるリダイレクトが SEO的にも好ましいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】Str::isでは改行を扱えませんよという話

環境 PHP 8.0 Laravel 8.x Docker(Laravel Sailで構築した環境を使っています) 目的 Laravelのヘルパ関数Str::isを使っていてハマった時の備忘録にすること Str::isって何よ? ある文字列Aの中に、別の文字列Bが含まれているかどうか判定してくれるヘルパ関数です。いくつか例を挙げておきます。 use Illuminate\Support\Str; $matches = Str::is('foo*', 'foobar'); // true $matches = Str::is('baz*', 'foobar'); // false 引用元(一部改変):Laravel 8.x ヘルパ Str::is ある日のこと... しゃっちょさん「キーワードの判定が改行に反応してくれないんだけど...」 私が参画していたプロジェクトでは問題のStr::is関数を使って、キーワードが特定の文字列に含まれているかどうかを判定していました。そこで以下のような事象が上がってきたのです。 use Illuminate\Support\Str; $matches = Str::is('foo*', 'foo\nbar'); // false // !? キーワード判定される文字列に改行があると正しくキーワード判定されないのです。これは問題です。先ほどの引用元のドキュメントにも書いてありますが、アスタリスクはワイルドカードとして扱われるのでtrueが返って良さそうなものです。 さぁ調査だ なぜtrueが返らないのでしょうか?ドキュメントの記述はえらいあっさりしていて参考にならなかったのでLaravel本体のコードを確認してみることに。Str::is関数のコードを抜粋します。 public static function is($pattern, $value) { $patterns = Arr::wrap($pattern); if (empty($patterns)) { return false; } foreach ($patterns as $pattern) { if ($pattern == $value) { return true; } $pattern = preg_quote($pattern, '#'); $pattern = str_replace('\*', '.*', $pattern); // 【重要】このif文の条件式でキーワード判定をしている if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { return true; } } return false; } コードを見ると内部的にはStr::isはPHP組み込みのpreg_match関数を使ってキーワード判定をしているようです。どうやらこの辺に落とし穴がありそう。 解決策 解決策をbefore->afterで掲載します。 before(再掲) use Illuminate\Support\Str; $matches = Str::is('foo*', 'foo\nbar'); // false // !? after(文字列結合が冗長ですが分かりやすくする為にあえてこう書いています) use Illuminate\Support\Str; $matches = preg_match('/[\s\S]*'.'foo'.'[\s\S]*/', 'foo\nbar'); // true 参考:エスケープシーケンス「\s\S」を利用する なぜこれで解決するのか(原因も含めて) 問題のpreg_match関数が改行に反応しなかったのは先ほどのStr::is関数のコードの中のこの部分が原因でした。抜粋して再掲します。 $pattern = str_replace('\*', '.*', $pattern); 元の$patternに入っている\*を.*へ置換しています。PHPの正規表現では.は任意の1文字を表し、*は0回以上の繰り返しを表します。少なくとも正規表現をかじった程度の私のような人はそういう認識でしょう。よって最終的な$pattern変数では元々のLaravelでのコード内でのワイルドカード(*)が適切な正規表現(この場合は.*)に変換されているように見えます。 しかし、PHPの正規表現では.は改行を除く任意の1文字を表すのです。 すなわち.*したとしてもその先に1つでも改行があればマッチしないと判定されるということです。 解決策のコードではワイルドカードの部分で 空白、タブ、フォーム フィードなどの任意の空白文字を表す\s 空白以外の任意の文字を表す\S これらを組み合わせることで改行を含めた全ての文字に対応する文字通りの「ワイルドカード」を実現しています。あとはそれを*で繰り返すだけです。 最後に 間違いのご指摘や少しでも気になったことはコメントを頂けますととても嬉しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

?XdebugでStep Debuggingしよう!

この記事はミライトデザイン Advent Calendar 2021の4日目の記事です? 昨日は@Nyokki 大先生のMySQLのEXPLAIN ANALYZEの読み方を勉強したよ という記事でした! 皆さん読みましたよね!? なんでお前がミライトデザインのアドベントカレンダー参加してるんや!?って思うかもしれませんが エントリーは自由です、社内外の人たちと盛り上げていきたいです。 って書いてあったし、@hirodragon112ファンなので参加しましたw さて、何を書こうか迷っていましたが、ミライトデザインといえばPHPってイメージが強いのでPHPネタということでXdebugのことを書こうと思います。 最近の若いエンジニアはXdebug使わないし、知らないらしいのでXdebugの紹介を簡単に書いてみます。 (もしかしてPsySHあるし、そんなに需要なくなってきたりしている?) Xdebug is 何? 公式サイトによると Xdebug is an extension for PHP, and provides a range of features to improve the PHP development experience. つまり「debugは、PHPの拡張機能で、PHPの開発環境を改善するための様々な機能を提供します。」とのことです。 (ありがとうDeepL) 様々な機能というのは主に以下の5つになります。 Step Debugging Improvements to PHP's error reporting Tracing Profiling Code Coverage Analysis 一つ一つ内容を確認していきましょう。 Step Debugging Step Debugging メインの機能言っても過言ではない、ステップ実行です。 ブレークポイントと呼ばれるものをコードの行に設定するとその行でプログラムの実行が止まり、変数の状態を確認することができる機能です。 Improvements to PHP's error reporting Development Helpers var_dumpがリッチになったり、エラー時にスタックトレース表示してくれたりエラーをわかりやすくしてくれる機能ですね。 最近だとフレームワーク側でデバッグツールがよくなってきているので若干恩恵を受けづらくなっている気もしますが...。 Tracing Function Trace 引数と呼び出し場所を使用して、すべての関数呼び出しをディスクに書き込みます。オプションで、各関数のすべての変数割り当てと戻り値も含まれます。 どのように関数コールされているか、調査するときに便利ですね。 (ぶっちゃけ使ったこと無いです...) Profiling Profiling 視覚化ツールを使用して、PHPアプリケーションのパフォーマンスを分析し、ボトルネックを見つけることができます。 Webgrindと組み合わせて使うのが一般的なのかな? 昔はxhprofとか使ってたけど、今だとXdebugで良さそうな気もしています。 Code Coverage Analysis Code Coverage Analysis PHPUnitで単体テストを実行するときにコードベースのどの部分が実行されるかを示す機能。 これ地味に便利で、テスト漏れとか可視化されるので結構好きな機能一つです。 XdebugのStep Debuggingの良いところ・悪いところ さて、Xdebugの機能をざっと説明しましたがかなり幅広い機能が沢山ありますね。 Xdebug入れると遅いとかいう人もいらっしゃいますが、まあちょっと遅くても堅牢ならそのほうがいいのではって思ってしまう自分です。 全部の機能を細かく説明していくとかなりの量になってしまうので、今回はStep Debugging(ステップ実行)のことについてつらつら書いていきます。 良いところ Xdebugの一番重要な機能と言っても過言ではないStep Debugging。 ブレークポイントと呼ばれる、ソースコード上の処理を一時停止したい箇所にマークをし、実行時にブレークポイントの箇所で処理を止めて変数の中身を確認したりする機能です。 (赤い枠の右側の赤い丸がブレークポイント) どこかでエラーが発生しているけど、よくわからない場合や、どこでこのメソッド呼ばれてるんだ???みたいな状況に非常に有効です。 あとは、webフレームワークを理解するときにも大活躍します。 私はXdebugがあったからこそ、Symfonyへの理解を深めることができました。 個人的に良いと思う理由は以下の二点。 Variablesで実行時の変数を確認することができる Framesで実行順序が確認できる Variablesで実行時の変数を確認することができる 実行時に処理をとめて、変数の中身を確認することが出来ます。 var_dumpやLaravelのddで十分かもしれませんが、見やすさや、見れる変数の範囲を考えるとこちらのほうが遥かにいいかと思います。 Framesで実行順序が確認できる Frames実行時のスタックを知る事ができます。 この場合だとindex.phpから始まってProfileControllerの38行目が実行されていることがひと目で分かるかと思います。 また、各スタックをクリックすることでVariables側に変数を表示してくれます。 こういった側面があるのでフレームワークのソースコードはめちゃくちゃ追いやすいです。 とくにSymfonyみたいに抽象度の高いフレームワークだとめちゃくちゃ理解に役立ちますし、実際のプロジェクトでもソースコードの把握にすごく役立ちます。 悪いところ 設定が難しい。(どこが原因でうまく動かないのか原因の特定が難しい) パラメータの項目よくわからない。(とくにXdebug3になって変わってしまった) ローカルな開発環境がなく、Xdebug導入が難しい(よくある) といったところでしょうか? 正直な話n回設定することで覚えるのでここは頑張るしかないのかなと思ったりもします。 Docker+PHPStormな環境でXdebugの設定をする 一番重要なポイントですが、大事な内容は自分のブログにちょっと前に書いています。 Docker環境でphp8 + Xdebug3を設定する コチラを参考にしていただければと思います?‍♂️ 最後に 個人的にはもっとみんなが気軽にxdebugを使ったステップ実行をする未来になればいいなと10年ぐらい思い続けています。 なにか困ったことがあれば@polidog にメンションくれればある程度はヘルプしたいと思います。 良かった気軽にリプライくださいー! 明日は@tkek321さんのAWSに関する記事です!お楽しみに!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ファミレスのメニューもどき管理画面を作ってみた

下記サンプルサイトは同じDBから書き出したメニュー注文ページです。 ▶︎サンプルサイト 下記の記事の続きです ▶︎ファミレスのメニューシステムもどき作ってみた やりたいこと DBの連携、入力、変更、削除をブラウザで操作 画像アップは別フォルダへ DB一覧書き出し バリデーションで同じ名前と画像はアップさせない 作成ファイル index.php(ログイン画面) logout.php(ログアウト画面) control_top.php(トップページと追加入力) change.php(変更UPDATE) change_check.php(UPDATEのバリデーション) delete.php(削除) db_join.php(インクルード用、DBの接続や共通で使う関数と配列を格納) select_cat.php(インクルード用、formのselectパーツ) select_mt.php(インクルード用、formのselectパーツ) 管理画面のUI jsで各操作をタブで切り替え 変更と削除はID検索で各ページにsubmitで移行。 ※管理画面はDBにアクセスしてデータの変更が出来てしまう為、セキュリティーの心配もあるので一般公開は控えています。 画像は最初DBに入れるつもりでしたが、XAMPでMySQLに入れようとしたらサイズの上限に引っかかりUP不可。 なのでUP専用のディレクトリを作りデータはそっちへ、画像の名前だけDBに保存しておくことに。 数と名前を合わせておかないと後々厄介なので、入れ替え、削除のあった時は同じく連動して合わせていく仕様に設計しました。 DBのカラムだけ配列として取得したい 1列の値だけ取り出す方法が分かりませんでした。 半日かけて調べてみたところarray_column()という関数を使えば出来るのでは? という方法に辿り着く。 control_top.php //商品名だけ配列化 $itemArray = array_column($data, 'item'); ///////省略///// //エラー対処 if(!check_word($item,25)){ $err['item'] = '空文字か入力値が超えています'; } elseif (in_array($item,$itemArray,true)) { //DBに同じ名前を入れさせない $err['item']= '同じ名の商品があります'; } else { $err['item']= ''; } 同じ商品名を被らせたくなかったので、DBのカラムに同じ商品名があるかチェック。 array_column(全配列の入った変数, ‘カラム名’)で商品名だけ配列化してif文で振り分け。 同じだったら省く仕組みです。 IDのカラムも配列に まずIDのカラム値を配列にします。 $id_Array = array_column($data, 'ID'); if(in_array($id,$id_Array))でDBから取り出したIDと入力されたIDを照合します。 change.php //inputから持ってきたname属性値 $id = html_escape($_POST['stockid']); //idを全角もOKにする $id = mb_convert_kana($id, 'n', 'UTF-8'); //DBより一覧表書き出し ID照合用 $sql_list = 'SELECT * FROM menulist'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 //FETCH_ASSOCで配列として書き出して代入 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row; } //IDのカラムだけ配列にする $id_Array = array_column($data, 'ID'); //DBとの検索IDを照合する、DBのID以外は全て弾くので空文字やテキストのバリデーションにもなる if(in_array($id,$id_Array,true)){ //DBよりID書き出し $sql_id = "SELECT * FROM menulist WHERE id = :id"; $stmt_id = $dbh->prepare($sql_id); $stmt_id->bindParam( ':id', $id, PDO::PARAM_INT); $stmt_id->execute(); //配列にする if($stmt_id) { $data = $stmt_id->fetch(PDO::FETCH_ASSOC); } $item = $data['item']; $select_cat = $data['category']; $select_mt = $data['material']; $plice = number_format($data['plice']); $change_img = $data['image']; $submit_btn = '<input class="toBtn" type="submit" value="変更">'; } else { $item = ''; $select_cat = ''; $select_mt = ''; $plice = ''; $change_img = ''; $submit_btn = '<p class="errComent">※ID欄が空かDBにないIDです。一覧に戻って選び直してください。</p>'; } DBのID以外は全て弾くので空文字や数字以外のテキストのバリデーションにもなりました。 change.php change_check.php change_check.phpではエラーがあったらDBに入れず、入力し直しへ。 エラーがなっかたら更新して完了を表示させます。 画像の入れ替え操作は苦労しました。 変更がある場合と無い場合を想定してファイルアップの有無を0で判断し、0でなかったら新しい画像をアップし古い画像は削除。 古い画像のままだったら、古い画像を削除して同じものを入れ直します。 なのでID検索時に古い画像のファイル名も取得して運んでいきます。 change_check.php if(isset($_FILES['stockimg'])){ $image = $_FILES['stockimg']; $image['name'] = html_escape($image['name']); //英小文字に変換 $image['name'] = strtolower($image['name']); //ファイル名と拡張子を切り分けて.を除去、ピリオドを重複させない為 $image_parts = pathinfo($image['name']); $extension = 'jpg'; $image_name = $image_parts['filename']; $image_name = str_replace('.','',$image_name); if($image['size'] > 1000000){ $err['imgsize'] = '画像が1MBを超えています'; } elseif(file_exists('./img_up/'.$image_name.'.'.$extension) === TRUE) { //file_exists関数でディレクトリ内を調べて、同じファイル名があった場合はアップさせない $err['imgsize'] = '同名のファイルがあります。違うファイル名にしてください。'; } else { $err['imgsize'] = ''; } } ///////省略///// //エラーが無かったら更新へ if($err['item']== '' && $err['imgsize'] == '' && $err['plice']== ''){ //ファイルアップがあった時の対処、0じゃなっかたらディレクトリにアップ、ここは苦労した if((int)$image_name !== 0){ move_uploaded_file($image['tmp_name'],'./img_up/'.$image_name.'.'.$extension); //画像が変更されたら古い画像はフォルダより削除 unlink('./img_up/'.$old_img); //DBに持っていくファイル名 $image = $image_name.'.'.$extension; //見本表示 $prev_img = '<p class="center">変更画像<br><img class="thumb12" src="'.$img_path.$image_name.'.'.$extension.'" alt=""></p>'; } else { //DBに持っていくファイル名を置かないとDBからファイル名が消えてしまう $image = $old_img; $prev_img = '<p>変更画像無し</p>'; } ファイルアップは前にプチ・クラウドストレージを作ったので、ベースはそこから引用してきました。 ▶︎プチ・クラウドストレージ作ってみた delete.phpもchange_check.phpとほぼ同じ作りです。 管理画面は注文ページより、ほぼ思うように作れました。 期間は2週間+α、かかりました。 作り終えて振り返り 調べていくとDB接続の書き方も人によりマチマチで「この方法知らない…」ということも多々遭遇。 関数、条件の立て方も同様で、長いと頭がクラクラしてきます。 システム構築の実務経験がないので、使う人の行動を想像しながら作りましたが 実務があったら、もっと配慮ができる設計が出来たのかなとも思っています。 以下サンプルコードです より実用的なコードに近づけるようご意見いただけると嬉しいです。 サンプルコード ・index.php(ログイン画面) ・logout.php(ログアウト画面) ・db_join.php(インクルード用、DBの接続や共通で使う関数と配列を格納) ・select_cat.php(インクルード用、formのselectパーツ) ・select_mt.php(インクルード用、formのselectパーツ) 上記5個のファイルは省略します。 control_top.php <?php //ログインしていないとアクセスさせない session_start(); session_regenerate_id(true); if(isset($_SESSION['login']) === false){ header('Location: index.php'); exit(); } try{ include_once(dirname(__FILE__).'/db_join.php'); //DBより一覧表書き出し $sql_list = 'SELECT * FROM menulist order by ID ASC'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row;//FETCH_ASSOCで配列として書き出して代入 } //DBのカラムに同じ商品名があるかチェック //商品名だけ配列化 $itemArray = array_column($data, 'item'); $item = ''; $category=''; $material = ''; $plice = ''; $err = ['item'=>'','cat'=>'','mat'=>'','plice'=>'','imgsize'=>'']; $dberr = ''; if($_SERVER['REQUEST_METHOD'] === 'POST'){ $item = html_escape($_POST['stock']); $category = html_escape($_POST['category']); $material = html_escape($_POST['material']); $plice = html_escape($_POST['stockplice']); $plice = mb_convert_kana($plice, 'n', 'UTF-8'); $image = $_FILES['stockimg']; $image['name'] = html_escape($image['name']); //英小文字に変換 $image['name'] = strtolower($image['name']); $plice = strtolower($plice); //ファイル名と拡張子を切り分けて.を除去、ピリオドを重複させない為 $image_parts = pathinfo($image['name']); //$extension = $image_parts['extension']; $extension = 'jpg'; $image_name = $image_parts['filename']; $image_name = str_replace('.','',$image_name); //base64でencode追加 $image_name = base64_encode($image_name); //エラー対処 if(!check_word($item,25)){ $err['item'] = '空文字か入力値が超えています'; } elseif (in_array($item,$itemArray,true)) { //DBに同じ名前を入れさせない $err['item']= '同じ名の商品があります'; } else { $err['item']= ''; } if($category === ''){ $err['cat'] = '選択してください'; } else { $err['cat']= ''; } if($material === ''){ $err['mat'] = '選択してください'; } else { $err['mat']= ''; } if(!check_word($plice,8)){ $err['plice'] = '空文字か入力値が超えています'; } else { $err['plice']= ''; } if($image['size'] > 1000000 && $image['size'] == 0){ $err['imgsize'] = '画像が選択されていないかサイズが1MBを超えています'; } elseif(file_exists('./img_up/'.$image_name.'.'.$extension) === TRUE) { //file_exists関数でディレクトリ内を調べて、同じファイル名があった場合はアップさせない $err['imgsize'] = '同名のファイルがあります。違うファイル名にしてください。'; } else { $err['imgsize'] = ''; } //empty($err)ではダメで下の書き方でtrueになった if($err['item']== '' && $err['cat']== '' && $err['mat']== '' && $err['imgsize'] == '' && $err['plice']== ''){ //デコードして画像アップ $image_name = base64_decode($image_name); move_uploaded_file($image['tmp_name'],'./img_up/'.$image_name.'.'.$extension); $dberr = '<img class="thumb" src="'.$img_path.$image_name.'.'.$extension.'" alt="">商品「'.$item.'」は正常にUPされました'; //DBに入力データを入れる $sql = "INSERT INTO menulist(item,image,category,material,plice) VALUE(:item,:image,:category,:material,:plice)"; $stmt_in = $dbh->prepare($sql); $stmt_in->bindValue(':item',$item,PDO::PARAM_STR); //DBには画像ファイル名のみUP $stmt_in->bindValue(':image',$image_name.'.'.$extension,PDO::PARAM_STR); $stmt_in->bindValue(':category',$category,PDO::PARAM_STR); $stmt_in->bindValue(':material',$material,PDO::PARAM_STR); $stmt_in->bindValue(':plice',$plice,PDO::PARAM_INT); $stmt_in->execute(); } //再読み込みを防ぐ為、同ページだけど飛ばす header('Location:/menulist/control/control_top.php'); } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DBテスト管理画面</title> <link rel="stylesheet" href="/menulist/common/sanitize.css"> <link rel="stylesheet" href="/menulist/common/style.css"> <link rel="stylesheet" href="/menulist/common/control.css"> <!--ファビコン32x32--> <link rel="shortcut icon" href="/menulist/favicon.ico" type="image/vnd.microsoft.icon"> </head> <body> <div id="wrapper"> <header id="header"> <p id="logout"><a href="logout.php">ログアウト</a></p> <h1 class="topTitle">DBテスト管理画面</h1> <p class="center notice1">入力の場合IDの設定は不要、金額は数値のみで<br>ブラウザの再読み込みはしないでください。エラーになります。</p> <p class="center notice2">IDで商品を検索してください</p> </header> <main id="main"> <ul class="formChange"> <li data-id="insart" class="act">入力</li> <li data-id="update">変更</li> <li data-id="deleteForm">削除</li> </ul> <!-- 追加入力 --> <form class="changeBox" id="insart" method="post" action="" enctype="multipart/form-data"> <div class="formLow"> <div class="stockId"> <p>ID</p> <p class="formInput">-</p> </div> <div class="stock"> <label>商品名</label> <input type="text" name="stock"> <p><?php echo $err['item']; ?></p> </div> <div class="stockCategory"> <label>カテゴリー</label> <select name="category"> <option value="" selected="selected">選択する</option> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/select_cat.php'); ?> </select> <p><?php echo $err['cat']; ?></p> </div> <div class="materialForm"> <label>素材</label> <select name="material"> <option value="" selected="selected">選択する</option> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/select_mt.php'); ?> </select> <p><?php echo $err['mat']; ?></p> </div> <div class="stockplice"> <label>金額</label> <input type="text" name="stockplice"> <p><?php echo $err['plice']; ?></p> </div> </div> <!-- //.formLow --> <div class="center"> <label>商品画像:サイズ横640px縦420px</label><br> <input type="file" name="stockimg"> <p><?php echo $err['imgsize']; ?></p> <?php echo $dberr; ?> </div> <input class="toBtn" type="submit" value="追加"> </form> <!-- //#insartBox --> <!-- 変更入力 --> <!-- 検索 --> <div id="update" class="changeBox"> <form method="post" action="/menulist/control/change.php"> <div class="formLow"> <label class="sarchId">ID</label> <input class="inputId" type="text" name="stockid"> </div> <input class="toBtn" type="submit" value="検索"> </form> </div> <!-- //#updateId --> <!-- 削除 --> <div id="deleteForm" class="changeBox"> <form method="post" action="/menulist/control/delete.php"> <div class="formLow"> <label class="sarchId">ID</label> <input class="inputId" type="text" name="stockid"> </div> <input class="toBtn" type="submit" value="検索"> </form> </div> <!-- //#deleteForm --> <!-- メニュー一覧データ --> <div class="stockBox"> <!-- カテゴリー絞り込みタグ --> <ul class="topNav"> <?php for($i = 0; $i < count($cat_list); $i++): ?> <li id="<?php echo 'cat_select_'.$i; ?>"><?php echo $cat_list[$i]; ?></li> <?php endfor; ?> <li id="all">ALL</li> </ul> <p class="totalStock"><span>全登録数</span><?php echo $count; ?>項目</p> <p id="catShow"></p> <table id="stockList"> <tr> <th class="stocklistId">ID</th><th class="stocklist">商品名</th><th class="stockImg">商品画像</th><th class="stocklisutoCat">カテゴリー</th><th class="stocklistMat">素材</th><th class="stocklistPlice">金額</th> </tr> <!-- foreachの外にforで囲み、カテゴリー数をループ --> <!-- foreachの中に$cat_list[$i]を入れるとエラーになる --> <?php for($i = 0; $i < count($cat_list); $i++): ?> <?php $cat_item = $cat_list[$i]; $cat_select = 'cat_select_'.$i; ?> <?php foreach($data as $row): ?> <?php if($row['category'] == $cat_item): ?> <tr class="<?php echo $cat_select; ?>"> <td class="stocklistId"><?php echo $row['ID']; ?></td> <td class="stocklist"><?php echo $row['item']; ?></td> <td class="stockImg"><img src="<?php echo $img_path.$row['image']; ?>" alt=""></td> <td class="stocklisutoCat"><?php echo $row['category']; ?></td> <td class="stocklistMat"><?php echo $row['material']; ?></td> <td class="stocklistPlice"><?php echo number_format($row['plice']); ?>円</td> </tr> <?php endif; ?> <?php endforeach; ?> <?php endfor; ?> </table> </div> <!-- //.stockBox --> </main> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //# wrapper--> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/control.js"></script> </body> </html> change.php <?php //ログインしていないとアクセスさせない session_start(); session_regenerate_id(true); if(isset($_SESSION['login']) === false){ header('Location: index.php'); exit(); } try { include_once(dirname(__FILE__).'/db_join.php'); $id = html_escape($_POST['stockid']); //idを全角もOKにする $id = mb_convert_kana($id, 'n', 'UTF-8'); //DBより一覧表書き出し ID照合用 $sql_list = 'SELECT * FROM menulist'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 //FETCH_ASSOCで配列として書き出して代入 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row; } //IDのカラムだけ配列にする $id_Array = array_column($data, 'ID'); //DBとの検索IDを照合する、DBのID以外は全て弾くので空文字やテキストのバリデーションにもなる if(in_array($id,$id_Array)){ //DBよりID書き出し $sql_id = "SELECT * FROM menulist WHERE id = :id"; $stmt_id = $dbh->prepare($sql_id); $stmt_id->bindParam( ':id', $id, PDO::PARAM_INT); $stmt_id->execute(); //配列にする if($stmt_id) { $data = $stmt_id->fetch(PDO::FETCH_ASSOC); } $item = $data['item']; $select_cat = $data['category']; $select_mt = $data['material']; $plice = number_format($data['plice']); $change_img = $data['image']; $submit_btn = '<input class="toBtn" type="submit" value="変更">'; } else { $item = ''; $select_cat = ''; $select_mt = ''; $plice = ''; $change_img = ''; $submit_btn = '<p class="errComent">※ID欄が空かDBにないIDです。一覧に戻って選び直してください。</p>'; } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DBテスト管理画面・変更</title> <link rel="stylesheet" href="/menulist/common/sanitize.css"> <link rel="stylesheet" href="/menulist/common/style.css"> <link rel="stylesheet" href="/menulist/common/control.css"> <!--ファビコン32x32--> <link rel="shortcut icon" href="/menulist/favicon.ico" type="image/vnd.microsoft.icon"> </head> <body> <div id="wrapper"> <header id="header"> <h1 class="topTitle">DBテスト管理画面・変更</h1> <p class="center notice1">変更箇所のみ書き換えてください</p> </header> <main id="main"> <!-- 変更 --> <form method="post" action="change_check.php" enctype="multipart/form-data"> <div class="formLow"> <div class="stockId"> <p>ID</p> <p class="formInput"><?php echo $id; ?></p> <input type="hidden" name="stockid" value="<?php echo $id; ?>"> </div> <div class="stock"> <label>商品名</label> <input type="text" name="stock" value="<?php echo $item; ?>"> </div> <div class="stockCategory"> <label>カテゴリー</label> <select name="category" value="<?php echo $select_cat; ?>"> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/select_cat.php'); ?> </select> </div> <div class="materialForm"> <label>素材</label> <select name="material" value="<?php echo $select_mt; ?>"> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/select_mt.php'); ?> </select> </div> <div class="stockplice"> <label>金額</label> <input type="text" name="stockplice" value="<?php echo $plice; ?>"> </div> </div> <!-- //.formLow --> <div class="center"> <label>商品画像:サイズ横640px縦420px<br><span class="text12">※変更のある場合のみUP</span></label><br> <input type="file" name="stockimg"> <p class="center"> <img class="thumb12" src="<?php echo $img_path.$change_img; ?>" alt=""> <!-- 削除のある場合に古い画像も持っていく --> <input type="hidden" name="old_img" value="<?php echo $change_img; ?>"> </p> <p class="text12 center mg0">変更前の画像です</p> </div> <?php echo $submit_btn; ?> </form> <div id="toList"><a href="/menulist/control/control_top.php">管理画面トップへ</a></div> </main> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //# wrapper--> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/control.js"></script> </body> </html> change_check.php <?php //ログインしていないとアクセスさせない session_start(); session_regenerate_id(true); if(isset($_SESSION['login']) === false){ header('Location: index.php'); exit(); } try { include_once(dirname(__FILE__).'/db_join.php'); $err = ['item'=>'','plice'=>'','imgsize'=>'']; $id = html_escape($_POST['stockid']); $item = html_escape($_POST['stock']); $category = html_escape($_POST['category']); $material = html_escape($_POST['material']); $plice = html_escape($_POST['stockplice']); $plice = mb_convert_kana($plice, 'n', 'UTF-8'); $old_img = html_escape($_POST['old_img']); if(isset($_FILES['stockimg'])){ $image = $_FILES['stockimg']; $image['name'] = html_escape($image['name']); //英小文字に変換 $image['name'] = strtolower($image['name']); //ファイル名と拡張子を切り分けて.を除去、ピリオドを重複させない為 $image_parts = pathinfo($image['name']); $extension = 'jpg'; $image_name = $image_parts['filename']; $image_name = str_replace('.','',$image_name); if($image['size'] > 1000000){ $err['imgsize'] = '画像が1MBを超えています'; } elseif(file_exists('./img_up/'.$image_name.'.'.$extension) === TRUE) { //file_exists関数でディレクトリ内を調べて、同じファイル名があった場合はアップさせない $err['imgsize'] = '同名のファイルがあります。違うファイル名にしてください。'; } else { $err['imgsize'] = ''; } } //var_dump(is_number($plice)); //エラー対処 if(!check_word($item,25)){ $err['item'] = '空文字か入力値が超えています'; } else { $err['item']= ''; } if(!check_word($plice,8)){ $err['plice'] = '空文字か入力値が超えています'; } elseif(is_numeric($plice) == FALSE) { //金額が数字じゃなかったらNG $err['plice'] = '数字を入力してください'; //金額変更でNGが出ると下記の変数に値が無くなるので対処 $prev_img = ''; } else { $err['plice']= ''; $plice = number_format($plice); } //エラーが無かったら更新へ if($err['item']== '' && $err['imgsize'] == '' && $err['plice']== ''){ //ファイルアップがあった時の対処、0じゃなっかたらディレクトリにアップ、ここは苦労した if((int)$image_name !== 0){ move_uploaded_file($image['tmp_name'],'./img_up/'.$image_name.'.'.$extension); //画像が変更されたら古い画像はフォルダより削除 unlink('./img_up/'.$old_img); //DBに持っていくファイル名 $image = $image_name.'.'.$extension; //見本表示 $prev_img = '<p class="center">変更画像<br><img class="thumb12" src="'.$img_path.$image_name.'.'.$extension.'" alt=""></p>'; } else { //DBに持っていくファイル名を置かないとDBからファイル名が消えてしまう $image = $old_img; $prev_img = '<p>変更画像無し</p>'; } //指定のidのDBを更新 $sql_up = 'UPDATE menulist SET item=:item,image=:image,category=:category,material=:material,plice=:plice WHERE id = :id'; $stmt_up = $dbh->prepare($sql_up); $stmt_up->bindParam( ':id', $id, PDO::PARAM_INT); $stmt_up->bindValue(':item',$item,PDO::PARAM_STR); $stmt_up->bindValue(':image',$image,PDO::PARAM_STR); $stmt_up->bindValue(':category',$category,PDO::PARAM_STR); $stmt_up->bindValue(':material',$material,PDO::PARAM_STR); $stmt_up->bindValue(':plice',$plice,PDO::PARAM_INT); $stmt_up->execute(); $notice = '以下の内容で更新しました'; $back_btn = '<div id="toList"><a href="/menulist/control/control_top.php">管理画面トップへ</a></div>'; } else { $notice = 'エラーがあります。戻って修正してください。'; //お手軽にhistory.back使いましたが「フォーム再送信の確認」が出る可能性有り //かといってa hrefだと入力値が消える。手間だけどもう一つ入力値を持っていった再入力用ページを作る? $back_btn = '<div id="toList"><a onclick="history.back()">修正する</a></div>'; } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DBテスト管理画面・変更確認</title> <link rel="stylesheet" href="/menulist/common/sanitize.css"> <link rel="stylesheet" href="/menulist/common/style.css"> <link rel="stylesheet" href="/menulist/common/control.css"> <!--ファビコン32x32--> <link rel="shortcut icon" href="/menulist/favicon.ico" type="image/vnd.microsoft.icon"> </head> <body> <div id="wrapper"> <header id="header"> <h1 class="topTitle">DBテスト管理画面・変更確認</h1> <p class="center notice1"><?php echo $notice; ?></p> </header> <main id="main"> <div class="formLow"> <div class="stockId"> <p>ID</p> <p class="formInput"><?php echo $id; ?></p> </div> <div class="stock"> <label>商品名</label> <p class="formInput"><?php echo $item; ?></p> <p><?php echo $err['item']; ?></p> </div> <div class="stockCategory"> <label>カテゴリー</label> <p class="formInput"><?php echo $category; ?></p> </div> <div class="materialForm"> <label>素材</label> <p class="formInput"><?php echo $material; ?></p> </div> <div class="stockplice"> <label>金額</label> <p class="formInput"><?php echo $plice; ?></p> <p><?php echo $err['plice']; ?></p> </div> </div> <!-- //.formLow --> <div class="center"> <?php echo $prev_img; ?> <p class="center"><?php echo $err['imgsize']; ?></p> </div> <?php echo $back_btn; ?> </main> </div> <!-- //#wrapper --> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //# wrapper--> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/control.js"></script> </body> </html> delete.php <?php //ログインしていないとアクセスさせない session_start(); session_regenerate_id(true); if(isset($_SESSION['login']) === false){ header('Location: index.php'); exit(); } try { include_once(dirname(__FILE__).'/db_join.php'); $id = html_escape($_POST['stockid']); $id = mb_convert_kana($id, 'n', 'UTF-8'); //DBより一覧表書き出し ID照合用 $sql_list = 'SELECT * FROM menulist'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row;//FETCH_ASSOCで配列として書き出して代入 } //IDのカラムだけ配列にする $id_Array = array_column($data, 'ID'); //DBとの検索IDを照合する if(in_array($id,$id_Array)){ $sql_id = "SELECT * FROM menulist WHERE id = :id"; $stmt_id = $dbh->prepare($sql_id); $stmt_id->bindParam(':id', $id, PDO::PARAM_INT); $stmt_id->execute(); //配列にする if($stmt_id) { $data = $stmt_id->fetch(PDO::FETCH_ASSOC); } $item = $data['item']; $plice = number_format($data['plice']); $select_cat = $data['category']; $select_mt = $data['material']; $change_img = $data['image']; $submit_btn = '<input class="toBtn" type="submit" value="削除">'; } else { $item = ''; $select_cat = ''; $select_mt = ''; $plice = ''; $change_img = ''; $submit_btn = '<p class="errComent">※DBにないIDです。一覧に戻って選び直してください。</p>'; } if($_SERVER['REQUEST_METHOD'] === 'POST'){ //isset置かないとNoticeが出る if(isset($_POST['deleteid'])){ $id = html_escape($_POST['deleteid']); $image = html_escape($_POST['deleteimg']); //DBより削除 $sql_delete = "DELETE FROM menulist WHERE id = :id"; $stmt_delete = $dbh->prepare($sql_delete); $stmt_delete->bindParam( ':id', $id, PDO::PARAM_INT); $stmt_delete->execute(); //画像フォルダからも削除 unlink('./img_up/'.$image); //実行されたらトップに飛ばす header('Location:/menulist/control/control_top.php'); } } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DBテスト管理画面・変更</title> <link rel="stylesheet" href="/menulist/common/sanitize.css"> <link rel="stylesheet" href="/menulist/common/style.css"> <link rel="stylesheet" href="/menulist/common/control.css"> <!--ファビコン32x32--> <link rel="shortcut icon" href="/menulist/favicon.ico" type="image/vnd.microsoft.icon"> </head> <body> <div id="wrapper"> <header id="header"> <h1 class="topTitle">DBテスト管理画面・削除</h1> <p class="center notice1">以下のメニューを削除します</p> </header> <main id="main"> <!-- 変更 --> <form method="post" action=""> <div class="stockBox"> <table> <tr> <th>ID</th><th>商品名</th><th>商品画像</th><th>カテゴリー</th><th>素材</th><th>金額</th> </tr> <tr> <td class="stocklistId"><?php echo $id; ?><input type="hidden" name="deleteid" value="<?php echo $id; ?>"></td> <td class="stocklist"><?php echo $item; ?></td> <td class="stockImg"><img src="<?php echo $img_path.$change_img; ?>" alt=""><input type="hidden" name="deleteimg" value="<?php echo $change_img; ?>"></td> <td class="stocklisutoCat"><?php echo $select_cat; ?></td> <td class="stocklistMat"><?php echo $select_mt; ?></td> <td class="stocklistPlice"><?php echo $plice ; ?>円</td> </tr> </table> </div> <?php echo $submit_btn; ?> </form> <div id="toList"><a href="/menulist/control/control_top.php">管理画面トップへ</a></div> </main> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //# wrapper--> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/control.js"></script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ajaxでControllerに飛ばした処理がDELETEだけ動かない

はじめに  この前、ajaxを使用し、画面内でデータ更新を行う処理を作成しました。  その際、新規(CREATE)と更新(UPDATE)の処理は動くのに削除(DELETE)の処理だけなかなか動かずに時間を取られてしまったので備忘録です。 結論  結論から先に言います。  新規や更新処理の時にエラーチェックで使用していたRequestの判定を削除処理でも使いまわした結果、削除処理では使用していなかった引数のチェック処理が勝手に走っていたため、インスタンスエラーが起きていました。  原因をいろいろ探しまわった時に、DELETE処理はajaxのPOSTでは飛ばないというような記述があり、データの飛ばし方に拘っていた結果、気づくのが遅れた初歩的なミスでした。  ちなみに返ってきていたエラーは422エラーでした。  動き自体は正しいのですが、Request処理が内部的に処理できなかったためこのエラーが返ってきていたのかなあと思います。 コード  新規・更新処理時に使っていたコードがこれです。 hogehoge.js // 新規・更新 $.ajax({ url: "hogehoge/update", type: "POST", dataType: "json", data:{ Id: document.getElementById('Id').value, Nm: document.getElementById('Nm').value, hoge: document.getElementById('hoge').value } }).done(function(result) { // 成功時 // 完了メッセージ表示 var message = '更新が完了しました。'; console.log(message); }).fail(function() { // 失敗時 // エラーメッセージ表示 var message = 'エラーが発生しました。'; console.log(message); }); web.php Route::post('hogehoge/update', [HogehogeController::class, 'updateHogehoge']); HogehogeController.php public function updateHogehoge(HogehogeRequest $request) { DB::connection('db')->beginTransaction(); try { $DATABASE= new DATABASE(); $DATABASE->fill([ 'ID' => $request->ID, 'NAME' => $request->NAME, 'HOGEHOGE' => $request->HOGEHOGE, ]); $DATABASE->save(); // コミット DB::connection('db')->commit(); return true; } catch (Exception $ex) { // ロールバック DB::connection('db')->rollback(); return false; } }  これらのコードは動きました。  削除処理時に使っていたコードがこれです。 hogehoge.js // 削除 $.ajax({ url: "hogehoge/delete", type: "POST", dataType: "json", data:{ Id: document.getElementById('Id').value } }).done(function(result) { // 成功時 // 完了メッセージ表示 var message = '削除が完了しました。'; console.log(message); }).fail(function() { // 失敗時 // エラーメッセージ表示 var message = 'エラーが発生しました。'; console.log(message); }); web.php Route::post('hogehoge/delete', [HogehogeController::class, 'deleteHogehoge']); HogehogeController.php public function deleteHogehoge(HogehogeRequest $request) { // レコード削除 DATABASE::where('ID', '=', $request->Id)->delete(); // コミット DB::connection('db')->commit(); }  これらのコードが422エラーを返していた訳ですね。  このコントローラーのプロシージャで受け取った際に、requestのエラーの判定をHogehogeRequestで行っていたのですが、削除の際、不要になって削っていたNmやHogehogeといった引数(?)の判定もHogehogeRequest内で行っていました。  だって主キーだけで削除できるんだから他の渡しても意味ないじゃん……。  とどのつまり、このHogehogeRequestを指定せずに普通のRequestを指定すれば良かったわけですね。  直すとしたら…… public function deleteHogehoge(HogehogeRequest $request) {  ここを…… public function deleteHogehoge(Request $request) {  こんな感じ……? さいごに  結局のところ、凡ミスには気を付けようねってことですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでNoSQLデータベース(簡易)を作る

はじめに こんにちは。初投稿のまろという者です。 Qiitaでは主にPHP系の投稿をしていこうと思ってます。 今回は、PHPでNoSQLのDBMSを作るわけです。 XMLじゃなくてJSONを使います。 概要 NoSQLのDBMS JSONを用いる データをそのまま保存 コード いきなりコードです。 dbms.php <?php // クラス「DBMS」の定義 class DBMS{ // ファイルパス変数の定義 private $path; // コンストラクタの起動 function __construct($path){ $this->path = $path; } // ファイルパスの変更関数 function PATH($path){ $this->path = $path; } // ファイル内容を変換して取得 function GET(){ return json_decode(file_get_contents($this->path), true); } // ファイル内容を変換して書き換え function POST($data){ $fp = fopen($this->path, 'cb'); if($fp){ if(flock($fp, LOCK_SH)){ if(fwrite($fp, json_encode($data))){ if(flock($fp, LOCK_UN)){ if(fclose($fp)){ return true; } } } } } return false; } } ?> てな感じです。JSONで、テキストをデータ形式で返してくれて、データをテキスト(JSON)で書き込む感じで、さらにどんなデータでも対応。 こんなDBMSが欲しかった... まあ、普通に使えると思います!少し処理系は置いといて。 また実際にこれを使用すると、 使用例 $db = new DBMS('/db/age.json'); $age = $db->GET(); echo '現在田中さんは'.$age['田中さん'].'歳です'; // 現在田中さんは38歳です $age['田中さん'] = 39; if($db->POST($age)){ $age = $db->GET(); echo '無事田中さんが39歳の誕生日を迎えました'; // 無事田中さんが39歳の誕生日を迎えました }else{ echo '残念田中さんもう一度38歳で頑張りましょう'; // 残念田中さんもう一度38歳で頑張りましょう } はい。田中さんごめんなさい(誰や) 終わりに 今回はPHPでNoSQL DBMSを作ってみました。 思ってたんとちゃう…と思ったそこの君!ごめんなさい(?) 使ってみてね〜
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

研修で色んなことやった

初めに 内定先研修?(バイト)で内定先で夏休みから少しづつ働いてきたのでどんなことやったのーだとかこれ大変だったなぁとかを話す会 目次 C#以外の言語を触った感想 今は何してんの? 大変だった話、苦労したこと ゲーム会社で少し働いた感想 C#以外の言語を触った感想 とりあえずやった言語が PHP.MySQL.Jsva.Python.Linux この5言語を研修で触りました。 PHPで困ったこと変数名に $をつけないといけないところ Javaで困ったこと何も定義されてないときはnullではなくundefinedだというところ MySQL.Linuxはほとんど学校で習った基礎的な内容 Pythonは簡単に書きすぎて他の言語書くときに困った(セミコロンつけないとか、ifとかforに{}いらないので付け忘れたりとか) 今は何してんの? 細かくは言えないですが、負荷テストの処理書いてたりしてます LocustっていうPythonでコードを書いてそのコードに〇〇人って人数を流したらどれくらい負荷がかかっているか見れるやつ LaravelはPHPのワークフレーム、一番人気らしい 左がLocust 右がLaravel 大変だった話、苦労したこと 大変だったのがわからないことがわからないです。 具体的に言うとUnityだと〇〇っていう処理作る時にある程度知識があるからわからなくても簡単に調べれるけれど 全く知識のない言語で作り方がわからない場合どうやって作ればいいかわからない。どうやって質問すればいいかわからないというなにがわかっていて何がわからないのかがわからない。ワカランワカラン(´;ω;`)ってなってました このワカランワカラン状態で質問をしても何が聞きたいのかわからないという相手もワカランワカランという最悪の状況が生まれます。 その時にマネージャーに教えてもらったのがエンジニアとして痛感した「良い質問」と「悪い質問」という記事 https://hara-chan.com/recommend/se-good-bad-question この記事を見てからは抽象的な質問をすることはなくなりました。万歳(/・ω・)/ ゲーム会社で働いた感想 ゲーム会社は圧倒的自由 作業中音楽聞いててもいいし、お菓子食べてもいいし、飲み物飲んでもいいし。。。 あとチャットがすごいラフというかギャグ挟んだりしながら会話してくたりいい意味で話しやすい環境を作ってくれている わからない所をチャットに書いたらすぐに返信くれるし、チャットじゃ理解できなかったら口頭で教えてくれるし 一番いいのが飲食店のバイトと違って体が疲れない!8時間働いても時間があっという間 CODEの23卒の人へ入社待ってます(#^^#)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPStromでCodeShinifferを利用し、カスタムルールを読ませる。

CodeShiniffer追加まで カスタムルールの適用 下図の青いPHP_CodeShiniffer inspectionを押す Config standardをカスタムに変更する。 config standard横の三点リーダを押し、ファイルを指定する。 適用すると、phpstormがルールを読み込んでくれます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PhpStormでCodeShinifferを利用し、カスタムルールを読ませる。

CodeShiniffer追加まで カスタムルールの適用 下図の青いPHP_CodeShiniffer inspectionを押す Config standardをカスタムに変更する。 config standard横の三点リーダを押し、ファイルを指定する。 適用すると、PhpStormがルールを読み込んでくれます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ファミレスのメニューシステムもどき作ってみた

しばらくぶりにシステム作ってみました。 飲食店のチェーン店でタブレットのメニューシステムを見てた時、「作れそうかも」と思ったこと。 ですがPHPはまだまだ初心者。想像しながらの穴だらけ試作システムです。 DBも初めて連携しました。 やりたいこと - DBからメニューを書出し - メニュー注文機能の作成(追加、変更、削除) - 検索システム ブラウザからDBにメニューを入れる管理システムも作ってみました。 ▶︎ファミレスのメニューもどき管理画面を作ってみた 下記が相関関係図です。 トップページ index.php XDでざっくりデザイン作成後、HTMLとCSSで組み立て。 こんな感じのUIです。 メニューボックスをクリックするとメニュー注文へ。 ▶︎サンプルサイトはこちら 共通のDB接続はパーツ化してインクルード。 DBからSELECTで全データを取得後配列化。 index.php //DB接続のインクルードは省略 //DBより一覧表書き出し $sql_list = 'SELECT * FROM menulist order by ID ASC'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row; メニュー一覧はカテゴリーごとにまとめたかったので、それぞれforeachでループしました。 カテゴリーの順番も任意で。 メインの後にドリンクがくると何かしっくりいかないし、やはりサラダ、スープ、前菜など順番は大切かなと。 foreachの中にifでカテゴリーごとにループさせるのは分かったのですが、 if($row['category'] == 'メイン') だといちいちカテゴリーごとにブロックを書かないといけないので、面倒い。時間を置いて考えて、for文で試してみました。 $cat_listという配列を手作り。任意の順番で並べたかったので下記のように記述。 $cat_list = ['メイン','サラダ','スープ','サイドメニュー','麺・パスタ','デザート','ドリンク']; それぞれのsectionに同一ページスクロール用のidも付けたかったのでid用の配列も作成。 $cat_listの内容と順番を合わせておきます。 $category_id = ['mainmenu','salad','soup','sideMenu','pasta','dessert','drink']; forの$iはforeachの中で使うとうまく出力しなかったので外側で変数に代入。 $cat_item = $cat_list[$i]; index.php <?php for($i = 0; $i < count($cat_list); $i++): ?> <!-- $iはforeachの中に入れるとちゃんと表示されないので外で変数にした --> <?php $cat_item = $cat_list[$i]; ?> <!-- idを付与 --> <section id="<?php echo $category_id[$i]; ?>"> <h2 class="catTitle"><span>Category</span><?php echo $cat_list[$i]; ?></h2> <ul class="menuBox"> <?php foreach($data as $row): ?> <!-- カテゴリーごとにまとめて書き出し --> <?php if($row['category'] == $cat_item): ?> <li class="selectOrder"> <div class="img"> <img src="<?php echo $img_path.$row['image']; ?>" alt=""> <p class="cart">注文する</p> </div> <div class="details"> <p class="material"><?php echo $row['material']; ?></p> <p class="menuName">商品名<span><?php echo $row['item']; ?></span></p> <dl> <dt>金額</dt> <dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd> </dl> </div> </li> <!-- //.selectOrder --> <?php endif; ?> <?php endforeach; ?> </ul> </section> <?php endfor; ?> 思うようにリスト化出来ました。 嬉しい。 注文確認フォーム 注文確認フォームは移行せず、同一ページ内で最初は非表示にしてメニューBOXがクリックされたらformが表示。 選んだアイテムだけが書き出されるようjsで操作。 ここはcount数で悩まされました。 jsで++countを置いているので、初期値を-1に <input id="count" type="hidden" name="count_menu" value="-1"> bace.js //submitで持っていく値の個数と番号の変数 let count; //商品をクリックしたら注文リストへ jQuery('.selectOrder').on('click',function(){ //選んだ商品データを変数に入れておく const orderName = jQuery('.menuName span',this).text(); const orderImg = jQuery('.img img',this).attr('src'); const orderPlice = jQuery('.orderPlic',this).text(); //カウントを取得しておかないとおかしくなる count = jQuery('#count').attr('value'); //count位置重要 ++count; //TOP注文リスト表示、メニュー一覧非表示 jQuery('#orderBox').css('display','block'); jQuery('#header,#main').css('display','none'); //追加・変更ページ jQuery('#orderChangeBox').css('display','block'); jQuery('#headerChange,#mainChange').css('display','none'); //注文の商品名、値段、画像、個数を書き出し、カウント数と合わせておく //tableの中に要素書き出し jQuery('#orderMenu,#changeMenu').append('<tr><th class="orderName">'+orderName+'</th><td class="orderImg"><img src="'+orderImg+'" alt=""></td><td class="orderOneplice">'+orderPlice+'円<span class="smallText">(税込)</span><img src="image/icon_x.svg" alt=""></td><td class="num"><input type="number" name="num'+count+'" min="1" max="50" value="1">個</td><td><p class="deleteMenu">削除<img src="image/icon_x.svg" alt=""></p></td></tr>'); //name属性+カウント数でgetで持っていく値と数を指定 jQuery('#count').before('<input type="hidden" name="title'+count+'" value="'+orderName+'"><input type="hidden" name="plice'+count+'" value="'+orderPlice+'"><input type="hidden" name="img'+count+'" value="'+orderImg+'">'); jQuery('#count').attr('value',count); }); //MENU削除 jQuery(document).on('click', '.deleteMenu', function(){ //デリートボタンを押したtrのみを削除 jQuery(this).parents('tr').remove(); //現在のカウントを取得 count = jQuery('#count').attr('value'); //削除によって揃わなくなった個数と順番の連動を合わせる for(let i=0; i < count; ++i){ jQuery('input[name^="title"]').eq(i).attr('name','title'+i); jQuery('input[name^="plice"]').eq(i).attr('name','plice'+i); jQuery('input[name^="num"]').eq(i).attr('name','num'+i); jQuery('input[name^="img"]').eq(i).attr('name','img'+i); } //1個ずつ持っていく数を減らす --count; jQuery('#count').attr('value',count); //確認リストから商品がなくなったらメニュー一覧を表示 if(count < 0){ jQuery('#orderBox,#orderChangeBox').css('display','none'); jQuery('#header,#main,#headerChange,#mainChange').css('display','block'); } }); jQueryでappendメソッドで後から追加した要素にclickイベントを効かせるようにするには要素に対してではなく、documentに対してイベントを設定しないとダメみたいです。 受け取り先の$_GETでは for($i = 0; $i < $count_menu+1; $i++) こうすると数が合うようになりました。 order.php $count_menu = isset($_GET['count_menu']); //XSS関数作成html_escape() $count_menu = html_escape($_GET['count_menu']); $count_menu = (int)$count_menu; $order_name = []; $one_plice = []; $num = []; $sub_plise = []; $order_img = []; //設定したカウント数でname値を書き出し配列へ入れる for($i = 0; $i < $count_menu+1; $i++){ $order_name[$i] = html_escape($_GET['title'.$i]); $one_plice[$i] = html_escape($_GET['plice'.$i]); $order_img[$i] = html_escape($_GET['img'.$i]); //文字列内にある”,”を""に変換 $one_plice[$i] = str_replace(',', '',$one_plice[$i]); $one_plice[$i] = (int)$one_plice[$i]; $num[$i] = html_escape($_GET['num'.$i]); $num[$i] = (int)$num[$i]; //値段と個数を掛けておく $sub_plise[$i] = $one_plice[$i] * $num[$i]; } 決定的な問題は検索機能だった TOPページの注文表示はjsのclickイベント表示、検索機能はformのsubmitで表示。 いずれも同一ページ内での操作。 clickイベントでアイテムがあった場合、検索すると再読み込みになってデフォルトに戻る。 要はclickで溜まったアイテムは消えて、検索結果から選んだアイテムに上書きされてしまいました。 最初はTOPページの注文表でリストを作り、追加変更が決まったらオーダー画面へ移行だった。 それが、TOPページの注文表で一つメニューを選んだら、オーダー画面に移行。その後追加変更ページという中途半端なフローになってしまいました。 もともとオーダー画面から追加変更ページに戻る設計は考えていました。 合計を見てから、「やっぱり変えたい」というお客さんはいると思うので。 その場合、データはJSONに格納します。ページ以降するたびformでname値を持っていくのはややこしいので。 追加変更ページ ここは検索機能を削除したトップページと同じ作り。 ただ、メニュー一覧は非表示で注文リストが表示された状態。 オーダーから移行してきたら注文リストへ行きたかったので。 検索機能は一番最後に作ったので、最後の最後で苦肉の策でした。 出来れば金額とキーワード検索も試したかったのですが、とてもそれどころじゃなかったです… 以下サンプルコードです。 共通インクルードファイル db_join.php <?php //DBに接続 $dsn = 'mysql:dbname=sample;host=localhost;charset=utf8'; $user ='root'; $password = ''; $dbh = new PDO($dsn,$user,$password); $dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); //DBへ格納した画像パス $img_path = '/menulist/control/img_up/'; //XSS function html_escape($word){ return htmlspecialchars($word,ENT_QUOTES,'UTF-8'); } //エラーチェック function check_word($word,$length){ if(mb_strlen($word) === 0 || mb_strlen($word) > $length){ return FALSE; } else{ return TRUE; } } //書き出し一覧のカテゴリーループに使う配列 $cat_list = ['メイン','サラダ','スープ','サイドメニュー','麺・パスタ','デザート','ドリンク']; //一覧の#セレクタ、同一スクロール用配列 $category_id = ['mainmenu','salad','soup','sideMenu','pasta','dessert','drink']; select_cat.php <?php //カテゴリーoption $cat_item = ['メイン','サラダ','スープ','サイドメニュー','麺・パスタ','デザート','ドリンク']; $selected = ''; ?> <?php for($i=0; $i < count($cat_item); $i++): ?> <?php if(isset($select_cat)){ if($select_cat === $cat_item[$i]){ $selected = 'selected="selected"'; } else { $selected = ''; } } ?> <option value="<?php echo $cat_item[$i]; ?>" <?php echo $selected; ?>><?php echo $cat_item[$i]; ?></option> <?php endfor; ?> ※select_mt.phpは素材のoption書出しインクルードファイルで、作りはselect_cat.phpと同じです。 index.php <?php try{ include_once(dirname(__FILE__).'/control/db_join.php'); //DBより一覧表書き出し $sql_list = 'SELECT * FROM menulist order by ID ASC'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row;//FETCH_ASSOCで配列として書き出して代入 } //検索フォーム $cat_name = ''; $mt_name = ''; $sarch_plice = ''; $sarch_cat = ' none'; $sarch_mt = ' none'; $sarch_cat_mt = ' none'; $sarch_class = 'none'; if($_SERVER['REQUEST_METHOD'] === 'GET'){ if(isset($_GET['cat'])){ $cat_name = html_escape($_GET['cat']); $sarch_class = ''; } if(isset($_GET['material'])){ $mt_name = html_escape($_GET['material']); $sarch_class = ''; } if($cat_name && $mt_name== ''){ $sarch_cat = ''; $sarch_mt = ' none'; $sarch_cat_mt = ' none'; } elseif($mt_name && $cat_name == '') { $sarch_mt = ''; $sarch_cat = ' none'; $sarch_cat_mt = ' none'; } elseif($cat_name !== '' && $mt_name !== ''){ $sarch_cat_mt = ''; $sarch_mt = ' none'; $sarch_cat = ' none'; } else { $sarch_cat_mt = ' none'; $sarch_mt = ' none'; $sarch_cat = ' none'; } } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DBテストメインメニュー</title> <link rel="stylesheet" href="/menulist/common/sanitize.css"> <link rel="stylesheet" href="/menulist/common/style.css"> <!--ファビコン32x32--> <link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon"> </head> <body> <div id="wrapper"> <header id="header"> <h1 class="topTitle">DBテストメニュー</h1> <p class="center">同一ページスクロール</p> <nav> <!-- 同一ページスクロール --> <ul class="topNav"> <!-- $cat_list配列はdb_join.phpに記述 --> <!-- href=#だと検索の時、挙動が怪しいのでdata属性にした リンクに飛ぶせい?--> <?php for($i = 0; $i < count($cat_list); $i++): ?> <li> <a data-id="<?php echo $category_id[$i]; ?>"><?php echo $cat_list[$i]; ?></a> </li> <?php endfor; ?> </ul> </nav> <!-- 検索ボタン --> <div id="sarch" class="btn"><a href="dummy.html">検索BOX</a></div> <!-- 検索BOX --> <div id="sarchBox"> <h3>AND検索BOX</h3> <form id="andSarch" method="get" action=""> <div id="ones"> <div id="sarchCat" class="ones__div"> <p class="onesText">カテゴリー</p> <select name="cat"> <option value="" selected="selected">選択する</option> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/control/select_cat.php'); ?> </select> </div> <!-- //.ones__div --> <img src="image/icon_plus.svg" alt=""> <div id="sarchMaterial" class="ones__div"> <p class="onesText">素材</p> <select name="material"> <option value="" selected="selected">選択する</option> <!-- selectはインクルード --> <?php include_once(dirname(__FILE__).'/control/select_mt.php'); ?> </select> </div> <!-- //.ones__div --> </div> <!-- //#ones --> <div id="btn"><input type="submit" value="この条件で検索する"></div> </form> <!-- 検索結果 --> <section id="sarchMenu" class="<?php echo $sarch_class; ?>"> <?php include_once(dirname(__FILE__).'/sarch_box.php'); ?> </section> <!-- // #sarchMenu--> </div> <!-- // #sarchBox--> </header> <main id="main"> <!-- $cat_list配列はdb_join.phpに記述 --> <?php for($i = 0; $i < count($cat_list); $i++): ?> <!-- $iはforeachの中に入れるとちゃんと表示されないので外で変数にした --> <?php $cat_item = $cat_list[$i]; ?> <section id="<?php echo $category_id[$i]; ?>"> <h2 class="catTitle"><span>Category</span><?php echo $cat_list[$i]; ?></h2> <ul class="menuBox"> <?php foreach($data as $row): ?> <?php if($row['category'] == $cat_item): ?> <li class="selectOrder"> <div class="img"> <img src="<?php echo $img_path.$row['image']; ?>" alt=""> <p class="cart">注文する</p> </div> <div class="details"> <p class="material"><?php echo $row['material']; ?></p> <p class="menuName">商品名<span><?php echo $row['item']; ?></span></p> <dl> <dt>金額</dt> <dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd> </dl> </div> </li> <!-- //.selectOrder --> <?php endif; ?> <?php endforeach; ?> </ul> </section> <?php endfor; ?> </main> <!-- 注文確認フォーム --> <div id="orderBox"> <h2 class="topTitle">注文へ</h2> <p class="center">個数の変更ができます。まずは「注文確認」ボタンを押してください。<br>注文リストで追加変更ができます。<br>キャンセルする場合は削除ボタンを押してください。</p> <form method="get" action="/menulist/order.php"> <table class="orderMenu" id="orderMenu"> <!-- jsより書き出し --> </table> <input id="count" type="hidden" name="count_menu" value="-1"> <!-- countは-1にしないとオーダー画面で数が合わない click時にjsで++countにしている--> <input class="toBtn" type="submit" value="注文確認"> </form> </div> <!-- //#orderBox --> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //#wrapper --> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/base.js"></script> </body> </html> 検索BOXインクルードファイル sarch_box.php <h2 class="catTitle"><span>SARCH</span>検索結果</h2> <p id="sarchCount"></p> <!-- カテゴリーの検索結果 --> <ul class="menuBox<?php echo $sarch_cat; ?>"> <?php foreach($data as $row): ?> <?php if($row['category'] == $cat_name): ?> <li class="selectOrder"> <div class="img"> <img src="<?php echo $img_path.$row['image']; ?>" alt=""> <p class="cart">注文する</p> </div> <div class="details"> <p class="material"><?php echo $row['material']; ?></p> <p class="menuName">商品名<span><?php echo $row['item']; ?></span></p> <dl> <dt>金額</dt> <dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd> </dl> </div> </li> <?php endif; ?> <?php endforeach; ?> </ul> <!-- 素材の検索結果 --> <ul class="menuBox<?php echo $sarch_mt; ?>"> <?php foreach($data as $row): ?> <?php if($row['material'] == $mt_name): ?> <li class="selectOrder"> <div class="img"> <img src="<?php echo $img_path.$row['image']; ?>" alt=""> <p class="cart">注文する</p> </div> <div class="details"> <p class="material"><?php echo $row['material']; ?></p> <p class="menuName">商品名<span><?php echo $row['item']; ?></span></p> <dl> <dt>金額</dt> <dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd> </dl> </div> </li> <!-- //.selectOrder --> <?php endif; ?> <?php endforeach; ?> </ul> <!-- カテゴリーand素材の検索結果 --> <ul class="menuBox<?php echo $sarch_cat_mt; ?>"> <?php foreach($data as $row): ?> <?php if($row['category'] == $cat_name && $row['material'] == $mt_name): ?> <li class="selectOrder"> <div class="img"> <img src="<?php echo $img_path.$row['image']; ?>" alt=""> <p class="cart">注文する</p> </div> <div class="details"> <p class="material"><?php echo $row['material']; ?></p> <p class="menuName">商品名<span><?php echo $row['item']; ?></span></p> <dl> <dt>金額</dt> <dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd> </dl> </div> </li> <!-- //.selectOrder --> <?php endif; ?> <?php endforeach; ?> </ul> base.js jQuery(function(){ jQuery('#orderBox').css('display','none'); //同一ページスクロール jQuery('.topNav a[data-id]').on ('click',function() { let dataID= jQuery(this).attr('data-id'); let position = jQuery('#'+dataID).offset().top-20; // スムーススクロール jQuery('body,html').animate({scrollTop:position}, 500, 'swing'); }); //検索ボタン jQuery('#sarchBox').css('display','block'); jQuery('#sarch a').on('click',function(){ if(jQuery('#sarchBox').css('display') == 'block'){ jQuery('#sarchBox').slideUp('first'); jQuery(this).css('background','#FA9600 url(/menulist/image/icon_plus_wh.svg) 338px center no-repeat'); return false; } else { jQuery('#sarchBox').slideDown('first'); jQuery(this).css('background','#FA9600 url(/menulist/image/icon_minus_wh.svg) 338px center no-repeat'); return false; } }); //検索件数表示 let sarchLi = jQuery('#sarchMenu .menuBox').find('li'); let liNone = jQuery('#sarchMenu ul.none').find('li'); let sarchCount = sarchLi.length - liNone.length; if(sarchCount != 0){ jQuery('#sarchCount').text(sarchCount+'件見つかりました'); } else { jQuery('#sarchCount').text('該当メニューは見つかりませんでした'); } //submitで持っていく値の個数と番号の変数 let count; //商品をクリックしたら注文リストへ jQuery('.selectOrder').on('click',function(){ //選んだ商品データを変数に入れておく const orderName = jQuery('.menuName span',this).text(); const orderImg = jQuery('.img img',this).attr('src'); const orderPlice = jQuery('.orderPlic',this).text(); //カウントを取得しておかないとおかしくなる count = jQuery('#count').attr('value'); //count位置重要 ++count; //注文リスト表示 jQuery('#orderBox').css('display','block'); jQuery('#header,#main').css('display','none'); //変更ページ jQuery('#orderChangeBox').css('display','block'); jQuery('#headerChange,#mainChange').css('display','none'); //注文の商品名、値段、画像、個数を書き出し、カウント数と合わせておく jQuery('#orderMenu,#changeMenu').append('<tr><th class="orderName">'+orderName+'</th><td class="orderImg"><img src="'+orderImg+'" alt=""></td><td class="orderOneplice">'+orderPlice+'円<span class="smallText">(税込)</span><img src="image/icon_x.svg" alt=""></td><td class="num"><input type="number" name="num'+count+'" min="1" max="50" value="1">個</td><td><p class="deleteMenu">削除<img src="image/icon_x.svg" alt=""></p></td></tr>'); //name属性+カウント数でgetで持っていく値と数を指定 jQuery('#count').before('<input type="hidden" name="title'+count+'" value="'+orderName+'"><input type="hidden" name="plice'+count+'" value="'+orderPlice+'"><input type="hidden" name="img'+count+'" value="'+orderImg+'">'); jQuery('#count').attr('value',count); }); //MENU削除 jQuery(document).on('click', '.deleteMenu', function(){ //デリートボタンを押したtrのみを削除 jQuery(this).parents('tr').remove(); //現在のカウントを取得 count = jQuery('#count').attr('value'); //削除によって揃わなくなった個数と順番の連動を合わせる for(let i=0; i < count; ++i){ jQuery('input[name^="title"]').eq(i).attr('name','title'+i); jQuery('input[name^="plice"]').eq(i).attr('name','plice'+i); jQuery('input[name^="num"]').eq(i).attr('name','num'+i); jQuery('input[name^="img"]').eq(i).attr('name','img'+i); } //1個ずつ持っていく数を減らす --count; jQuery('#count').attr('value',count); //確認リストから商品がなくなったら注文リストへ移行 if(count < 0){ jQuery('#orderBox,#orderChangeBox').css('display','none'); jQuery('#header,#main,#headerChange,#mainChange').css('display','block'); } }); //変更メニューページ jQuery('#headerChange,#mainChange').css('display','none'); //追加ボタン jQuery('#toList').on('click',function(){ jQuery('#orderBox').css('display','none'); jQuery('#header,#main').css('display','block'); //変更ページ jQuery('#orderChangeBox').css('display','none'); jQuery('#headerChange,#mainChange').css('display','block'); }); }); 注文確認ページorder.php JSONは空ファイルを用意しておきます。 order.php <?php //XSS function html_escape($word){ return htmlspecialchars($word,ENT_QUOTES,'UTF-8'); } $count_menu = isset($_GET['count_menu']); $count_menu = html_escape($_GET['count_menu']); $count_menu = (int)$count_menu; $order_name = []; $one_plice = []; $num = []; $sub_plise = []; $order_img = []; //設定したカウント数でname値を書き出し配列へ入れる for($i = 0; $i < $count_menu+1; $i++){ $order_name[$i] = html_escape($_GET['title'.$i]); $one_plice[$i] = html_escape($_GET['plice'.$i]); $order_img[$i] = html_escape($_GET['img'.$i]); //文字列内にある”,”を""に変換 $one_plice[$i] = str_replace(',', '',$one_plice[$i]); $one_plice[$i] = (int)$one_plice[$i]; $num[$i] = html_escape($_GET['num'.$i]); $num[$i] = (int)$num[$i]; $sub_plise[$i] = $one_plice[$i] * $num[$i]; } //配列の値の合計を計算 $total_plice = array_sum($sub_plise); //JSONに入れる為、配列へ $order = [$order_name,$num,$one_plice,$order_img]; //JSON形式に変換 $json = json_encode($order,JSON_UNESCAPED_UNICODE); //JSONへ格納 file_put_contents('./order.json',$json); ?> <!DOCTYPE html> <html lang="ja"> <head> <!-- 省略 --> </head> <body> <div id="wrapper"> <header id="header"> <h1 class="topTitle">注文確認</h1> <p class="center">確定ボタンで注文完了です。<br>変更される場合は「追加・変更」で戻ってください。</p> </header> <main id="main"> <form method="get" action="thanks.php"> <table class="orderMenu"> <?php for($i = 0; $i < $count_menu+1; $i++): ?> <tr> <th><?php echo $order_name[$i]; ?><input type="hidden" name="order_name<?php echo $i; ?>" value="<?php echo $order_name[$i]; ?>"></th> <!-- number_format3桁区切り --> <td class="plice"><?php echo number_format($one_plice[$i]); ?>円<span class="smallText">(税込)</span><img src="image/icon_x.svg" alt=""><input type="hidden" name="one_plice<?php echo $i; ?>" value="<?php echo $one_plice[$i]; ?>"></td> <td class="num"><?php echo $num[$i]; ?>個<input type="hidden" name="num<?php echo $i; ?>" value="<?php echo $num[$i]; ?>"></td> <td class="plice"><?php echo number_format($sub_plise[$i]); ?>円<span class="smallText">(税込)</span><input type="hidden" name="sub_plise<?php echo $i; ?>" value="<?php echo $sub_plise[$i]; ?>"></td> </tr> <?php endfor; ?> </table> <div id="total"><span>合計</span><?php echo number_format($total_plice); ?>円<span class="smallText">(税込)</span><input type="hidden" name="total_plice" value="<?php echo $total_plice; ?>"></div> <!-- メニューのクリックは無いのでcount-1の調整はいらない --> <input id="count" type="hidden" name="count_menu" value="<?php echo $count_menu; ?>"> <input class="toBtn" type="submit" value="注文確定する"> </form> <div id="toList"><a href="order_change.php">追加・変更する</a></div> </main> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //#wrapper --> </body> </html> order_change.php <?php try{ include_once(dirname(__FILE__).'/control/db_join.php'); //DBより一覧表書き出し $sql_list = 'SELECT * FROM menulist order by ID ASC'; $stmt = $dbh->prepare($sql_list); $stmt->execute(); $data =array(); $count = $stmt->rowCount();//レコード数取得 while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ $data[] = $row;//FETCH_ASSOCで配列として書き出して代入 } //jsonファイルを取得 $json =file_get_contents('./order.json'); $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); $json = json_decode($json,true); //jsonの中に入ったアイテム数、タイトルから取得 $count_menu = count($json[0]); //var_dump($json); //PHPではJSON形式のデータをそのまま扱うことができないので配列の形にする必要があり //https://hacknote.jp/archives/42243/ $order_name =array(); $num = array(); $one_plice = array(); $order_img = array(); //foreachだと値を書き出せなかった for($i = 0; $i < $count_menu; $i++){ array_push($order_name,$json[0][$i]); array_push($num,$json[1][$i]); array_push($one_plice,$json[2][$i]); array_push($order_img,$json[3][$i]); } } catch (PDOException $e){ print($e->getMessage()); die(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <!-- 省略 --> </head> <body> <div id="wrapper"> <header id="headerChange"> <h1 class="topTitle">DBテスト変更メニュー</h1> <p class="center">ブラウザの再読み込みボタンは使わないでください。エラーになります。</p> <nav> <ul class="topNav"> <!-- $cat_list配列はdb_join.phpに記述 --> <?php for($i = 0; $i < count($cat_list); $i++): ?> <li> <a data-id="<?php echo $category_id[$i]; ?>"><?php echo $cat_list[$i]; ?></a> </li> <?php endfor; ?> </ul> </nav> </header> <main id="mainChange"> <!-- ここはindex.phpと同じなので省略します --> </main> <div id="orderChangeBox"> <h2 class="topTitle">注文リスト</h2> <p class="center">メニューの追加と個数の変更ができます。追加はメニュー画面へ戻ってください。<br>メニューが決まりましたら注文確定ボタンへ、キャンセルしたいメニューは削除を押してください。</p> <form method="get" action="order.php"> <table class="orderMenu" id="changeMenu"> <?php for($i = 0; $i < $count_menu; $i++): ?> <tr> <th class="orderName"> <?php echo $order_name[$i]; ?> <input type="hidden" name="title<?php echo $i; ?>" value="<?php echo $order_name[$i]; ?>"> </th> <td class="orderImg"> <img src="<?php echo $order_img[$i]; ?>" alt=""> <input type="hidden" name="img<?php echo $i; ?>" value="<?php echo $order_img[$i]; ?>"> </td> <td class="orderOneplice"> <?php echo $one_plice[$i]; ?>円<span class="smallText">(税込)</span><img src="/menulist/image/icon_x.svg" alt=""> <input type="hidden" name="plice<?php echo $i; ?>" value="<?php echo $one_plice[$i]; ?>"> </td> <td class="num"> <input type="number" name="num<?php echo $i; ?>" min="1" max="50" value="<?php echo $num[$i]; ?>">個 </td> <td> <p class="deleteMenu">削除<img src="/menulist/image/icon_x.svg" alt=""></p> </td> </tr> <?php endfor; ?> </table> <input id="count" type="hidden" name="count_menu" value="<?php echo $count_menu-1; ?>"> <div id="toList">メニューを見る</div> <input class="toBtn" type="submit" value="合計を見る"> <div id="toList"><a href="/menulist/">メニューをリセットする</a></div> </form> </div> <!-- //#orderBox --> <footer id="footer"> <small>DBテストメニューsystem</small> </footer> </div> <!-- //#wrapper --> <script src="/menulist/common/jquery-3.6.0.min.js"></script> <script src="/menulist/common/base.js"></script> </body> </html> thanks.phpは特に気になることはなく、データの表示だけなので省略します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む