- 投稿日:2020-07-15T22:15:45+09:00
【Laravel5.5】 tinkerコマンドで管理者ユーザー登録
やりたいこと
今回はタイトルにもある通り、tinkerコマンドを使い管理者(Admin側)でのユーザー登録の流れを解説しようと思います。
なぜコマンドで登録するのか
Laravelでは標準で用意されている会員登録機能が認証(Auth側)のみ用意されており、管理者ユーザーのテーブルで直接パスワードを入力してインサートしてもハッシュ化されていないためログインが出来ません。
そのためtinkerコマンドでハッシュ化したパスワードをインサートする必要が出てくる場合があります。コマンド操作流れ
tinkerphp artisan tinker Psy Shell v0.9.12 (PHP 7.1.29 — cli) by Justin Hileman >>> use App\Admin; >>> $admin = new Admin(); => App\Admin {#2914} >>> $admin->name = 'ユーザー名'; => "ユーザー名" >>> $admin->email = 'hoge@hoge.co.jp'; => "hoge@hoge.co.jp" //bcrypt関数でハッシュ化 >>> $admin->password = bcrypt('パスワード'); =>"ハッシュ化されたパスワード" >>> $admin->save(); => true //quitまたはexitでtinkerの終了 >>> quitこちらがtinkerコマンドでの管理者ユーザー登録の一連になります。
tinkerはメソッド等実行出来るのでデバッグや実際の動きを確認したり、
テーブルに登録されているユーザーの一覧を取得出来たり便利なので積極的に使いたいですね!以上になります!LGTMを押していただけると励みになります。
お疲れ様でした!
- 投稿日:2020-07-15T16:32:31+09:00
PHPでフレームワークを使用せずに投稿サイトを作る
やりたいこと
PHPで管理画面も含めた用語集サイトを作ります。
わかりやすさを優先して、最低限のソースコードにしています。
管理者パスワード設定もないので、第三者が勝手にコンテンツを変更できる仕様です。
セキュリティが緩いので個人情報を取り扱わないでください。仕様
- トップページ(index.php)は用語名、用語のフリガナの一覧を表示する。
- トップページの用語のハイパーリンクをクリックすると、用語詳細ページ(item.php)画面に遷移する。
- 用語詳細ページは、用語名、分類、用語のフリガナ、用語の内容を表示する。
- 管理画面で用語の新規登録、編集、削除ができる。
- 管理画面で用語の新規登録、編集、削除ボタンを押すと、確認ページ(xxxx_check.php)に遷移し実行ボタンを押すと、実行結果確認ページ(xxxx_done.php)に遷移する。
その他
サーバーはロリポップを契約、ドメインはムームードメインで取得しています。
ページ構成と画面遷移
ページ一覧
index.php
item.php
list.php
branch.php
add.php
add_check.php
add_done.php
edit.php
edit_check.php
edit_done.php
delete.php
delete_done.php
ng.php画面遷移図
各ページのソースコード
index.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <div class="wrapper"> <div id="site_title"><a href="https://XXXX.com/">Webサイトのタイトル</a></div> <div class="top_page_title_list"> <ul> <li> <?php try { //DB名、ユーザー名、パスワード $dsn = 'mysql:dbname=LAAXXXX-XXXX;host=mysqlXXX.phy.lolipop.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'LAAXXXX'; //''内にはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $PDO = new PDO($dsn, $user, $password); //MySQLのデータベースに接続 $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //PDOのエラーレポートを表示 $sql = 'SELECT * FROM contents ORDER BY name asc'; //SELECT文を変数に格納。 contentsテーブルてからname列の値を取り出し、name列順に並び替え $stmt = $PDO->query($sql); // SQLステートメントを実行し、結果を変数に格納 // foreach文で配列の中身を一行ずつ出力 foreach ($stmt as $row) { // 取り出した一行を名称とフリガナで表示し、ハイパーリンク設定 echo "<div class='title_name'><a href='http://XXXX.com/item.php?name=".$row['name']."'>".$row['name']. "<span class='reading'>(".$row['reading'].")</span></a></div>\n"; } } catch (PDOException $e) { exit('データベースに接続できませんでした。' . $e->getMessage()); } ?> </li> </ul> </div> </div> </body> </html>item.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <div class="wrapper"> <div id="site_title"><a href="https://XXXX.com/">Webサイトのタイトル</a></div> <div class="detail_page_contents"> <?php try { //URLのidの値を取得 $name = $_GET['name']; //DB名、ユーザー名、パスワード $dsn = 'mysql:dbname=LAAXXXX-XXXX;host=mysqlXXX.phy.lolipop.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'LAAXXXX'; //''内にはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $PDO = new PDO($dsn, $user, $password); //MySQLのデータベースに接続 $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $result = $PDO->query("SELECT * FROM contents WHERE name = '$name'"); while($row = $result->fetch(PDO::FETCH_ASSOC)){ echo "<p>分類 | ".$row['category']."</p>"; echo "<h1>".$row['name']." (".$row['reading'].")</span></h1>"; echo "<p>".nl2br($row['description'])."</p>"; //nl2br関数で改行を反映する } } catch (PDOException $e) { exit('データベースに接続できませんでした。' . $e->getMessage()); } ?> </div> </div> </div> </body> </html>list.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX-XXXX;host=mysqlXXX.phy.lolipop.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'LAAXXXX'; //''内にはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを読み込み $sql ='SELECT name FROM contents WHERE 1'; //'SELECT name FROM contents WHERE 1'を変数$sqlに格納する。contentsテーブルのnameカラムのすべての情報(Where 1で全部という意味)を取得する $stmt = $dbh->prepare($sql); // レコードを呼び出す準備。この行は定型文としてこのまま書く $stmt->execute(); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く // データベースから切断するプログラム $dbh = null; // 一覧を表示する print '用語一覧<br /><br />'; print '<form method="post" action="branch.php">'; While(true){ $rec = $stmt->fetch(PDO::FETCH_ASSOC); //$stmtから1レコードを取り出す if($rec==false){ //もし、$recがなければ(もうデータがなければ)、Whileから抜け出す break; } print '<input type="radio" name="name" value="'.$rec['name'].'">'; print $rec['name']; //もし、$recがあれば、$recのnameを表示 print "<br />\n"; //\nはソースコードの改行コード。\nはシングルクオテーションで囲うと文字として出力されてしまうので注意 // 上記3行は結合すると右記のように表示される。 <input type="radio" name="glossary" value="AA">AA<br /> } print '<input type="submit" name="add" value="追加">'; print '<input type="submit" name="edit" value="修正">'; print '<input type="submit" name="delete" value="削除">'; print '</form>'; } catch (Exception $e) { print 'ただいま障害により表示できません。'; exit(); //強制終了の命令 } ?> </body> </html>branch.php
branch.phpを使って、list.phpで押したボタンに応じて遷移先を制御する。
<?php if(isset($_POST['add'])==true){ //もし「追加」ボタンが押されていて header('Location:add.php'); exit(); } if(isset($_POST['edit'])==true){ //もし「修正」ボタンが押されていて if(isset($_POST['name'])==false){ //もしラジオボタンが何も選択されていなければ header('Location:ng.php'); exit(); } $name=$_POST['name']; header('Location:edit.php?name='.$name); exit(); } if(isset($_POST['delete'])==true){ //もし「修正」ボタンが押されていて if(isset($_POST['name'])==false){ //もしラジオボタンが何も選択されていなければ header('Location: ng.php'); exit(); } $name=$_POST['name']; header('Location:delete.php?name='.$name); exit(); } ?>add.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> 用語追加<br /> <br /> <form method="post" action="glossary_add_check.php"> <!--postメソッドで、glossary_add_check.phpに情報を引き渡す--> 用語名を入力してください。<br /> <input type="text" name="name" style="width:100px"><br /> <!--入力された値はtext型。値はnameと名づける--> 読み方を入力してください。英語はカナ、日本語は平仮名<br /> <input type="text" name="reading" style="width:100px"><br /> <!--入力された値はtext型。値はreadingと名づける--> カテゴリを入力してください。<br /> <input type="text" name="category" style="width:100px"><br /> <!--入力された値はtext型。値はcategoryと名づける。--> 用語の説明文を入力してください。<br /> <textarea name="description" style="width:500px; height:200px;" wrap="soft"></textarea> <br /> <input type="button" onclick="history.back()" value="戻る"> <!--戻るボタンをクリックすると、前の画面に遷移する--> <input type="submit" value="OK"> <!--OKボタンをクリックすると、glossary_add_check.phpに遷移する--> </form> </body> </html>add_check.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php $name=$_POST['name']; //前の画面から入力値を受け取り、$nameに格納 $reading=$_POST['reading']; //前の画面から入力値を受け取り、$readingに格納 $category=$_POST['category']; //前の画面から入力値を受け取り、$categoryに格納 $description=$_POST['description']; //前の画面から入力値を受け取り、$descriptionに格納 $name=htmlspecialchars($name,ENT_QUOTES,'UTF-8'); //文字列に変換(セキュリティ対策) $reading=htmlspecialchars($reading,ENT_QUOTES,'UTF-8'); //文字列に変換(セキュリティ対策) $category=htmlspecialchars($category,ENT_QUOTES,'UTF-8'); //文字列に変換(セキュリティ対策) $description=htmlspecialchars($description,ENT_QUOTES,'UTF-8'); //文字列に変換(セキュリティ対策) //$nameがカラならエラーメッセージを表示する //$nameが入力されていれば、$nameを表示する if($name==''){ print '用語名が入力されていません。<br />'; } else { print '用語名:'; print $name; print '<br />'; } //$readingがカラならエラーメッセージを表示する //$readingが入力されていれば、$readingを表示する if($reading==''){ print '読み方が入力されていません。<br />'; } else { print '読み方:'; print $reading; print '<br />'; } //$categoryがカラならエラーメッセージを表示する //$categoryが入力されていれば、$categoryを表示する if($category==''){ print 'カテゴリが入力されていません。<br />'; } else { print 'カテゴリ:'; print $category; print '<br />'; } //$descriptionがカラならエラーメッセージを表示する //$descriptionが入力されていれば、$categoryを表示する if($description==''){ print '用語説明が入力されていません。<br />'; } else { print '用語説明:'; print $description; print '<br />'; } //$name、$reading、$category、$descriptionのいずれかがカラなら、戻るボタンのみを表示する //入力項目が適切なら、戻るボタンとOKボタンを表示する。 if($name==''|| $reading==''||$category=='' || $description==''){ print '<form>'; print '<input type="button" onclick="history.back()" value="戻る">'; print '<form>'; } else { print '<form method="post" action="add_done.php">'; print '<input type="hidden" name="name" value="'.$name.'">'; //'<input type="hidden" name="name" value="'と$nameをドットで連結 print '<input type="hidden" name="reading" value="'.$reading.'">'; //'<input type="hidden" name="reading" value="'と$nameをドットで連結 print '<input type="hidden" name="category" value="'.$category.'">'; //'<input type="hidden" name="category" value="'と$categoryをドットで連結 print '<input type="hidden" name="description" value="'.$description.'">'; //'<input type="hidden" name="description" value="'と$descriptionをドットで連結 print '<input type="button" onclick="history.back()" value="戻る">'; print '<input type="submit" value="OK">'; print '</form>'; } ?> </body> </html>add_done.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { // POSTメソッドで前の画面の入力値を取得する $name = $_POST['name']; $reading = $_POST['reading']; $category = $_POST['category']; $description = $_POST['description']; // セキュリティ対策入力値を文字列に変換 $name = htmlspecialchars($name,ENT_QUOTES,'UTF-8'); $reading = htmlspecialchars($reading,ENT_QUOTES,'UTF-8'); $category = htmlspecialchars($category,ENT_QUOTES,'UTF-8'); $description = htmlspecialchars($description,ENT_QUOTES,'UTF-8'); //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX-XXXX;host=mysqlXXXX.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'LAAXXXX'; //rootにはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを追加 $sql ='INSERT INTO contents(name,reading,category,description) VALUES (?,?,?,?)'; //'INSERT INTO mst_staff(name,reading,category,description) VALUES (?,?,?,?)'を変数$sqlに格納する $stmt = $dbh->prepare($sql); // レコードを追加する準備。この行は定型文としてこのまま書く $data[] = $name; // 一つ目の?にセットしたいデータが入っている変数を書く $data[] = $reading; // 二つ目の?にセットしたいデータが入っている変数を書く $data[] = $category; // 三つ目の?にセットしたいデータが入っている変数を書く $data[] = $description; // 四つ目の?にセットしたいデータが入っている変数を書く $stmt->execute($data); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く // データベースから切断するプログラム $dbh = null; //結果を表示 print $name; print 'を追加しました。<br />'; } catch (Exception $e) { print 'ただいま障害により接続できません。'; exit(); //強制終了の命令 } ?> <a href="list.php">戻る</a> </body> </html>edit.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { $name=$_GET['name']; //前画面のlist.phpからGETでglossaryを受け取る //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX-XXXX;host=mysqlXXXX.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'LAAXXXX'; //''内にはにはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを読み込み $sql ='SELECT reading, category, description FROM contents WHERE name=?'; //'SELECT name FROM contents WHERE glossary=?'を変数$sqlに格納する。contentsテーブルのnameカラムのあとで指定する(?のこと)値の情報を取得する $stmt = $dbh->prepare($sql); // レコードを検索する準備。この行は定型文としてこのまま書く $data[] = $name; // 上の上の行の?の値を設定する $stmt->execute($data); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く $rec=$stmt->fetch(PDO::FETCH_ASSOC); $reading=$rec['reading']; $category=$rec['category']; $description=$rec['description']; // データベースから切断するプログラム $dbh = null; } catch (Exception $e) { print 'ただいま障害により表示できません。'; exit(); //強制終了の命令 } ?> Name<br /> <form method="post" action="edit_check.php"> <input type="text" name="name" value="<?php print $name; ?>"> <br /><br /> Reading<br /> <form method="post" action="edit_check.php"> <input type="text" name="reading" value="<?php print $reading; ?>"> <br /><br /> Category<br /> <form method="post" action="edit_check.php"> <input type="text" name="category" value="<?php print $category; ?>"> <br /><br /> Discription<br /> <form method="post" action="edit_check.php"> <textarea name="description" style="width:500px; height:200px;" wrap="soft"> <?php print $description; ?> </textarea> <br /> <input type="button" onclick="history.back()" value="戻る"> <input type="submit" value="OK"> </form> </body> </html>edit_check.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php $name=$_POST['name']; //前の画面から入力値を受け取り、$nameに格納 $reading=$_POST['reading']; //前の画面から入力値を受け取り、$readingに格納 $category=$_POST['category']; //前の画面から入力値を受け取り、$categoryに格納 $description=$_POST['description']; //前の画面から入力値を受け取り、$escriptionに格納 //$nameがカラならエラーメッセージを表示する //$nameが入力されていれば、$nameを表示する if($name==''){ print '用語名が入力されていません。<br />'; } else { print '用語名:'; print $name; print '<br /><br />'; } //$readingがカラならエラーメッセージを表示する //$readingが入力されていれば、$readingを表示する if($reading==''){ print '読み方が入力されていません。<br />'; } else { print '読み:'; print $reading; print '<br /><br />'; } //$categoryがカラならエラーメッセージを表示する //$categoryが入力されていれば、$categoryを表示する if($category==''){ print 'カテゴリが入力されていません。<br />'; } else { print 'カテゴリ:'; print $category; print '<br /><br />'; } //$descriptionがカラならエラーメッセージを表示する //$descriptionが入力されていれば、$categoryを表示する if($description==''){ print '用語説明が入力されていません。<br /><br />'; } else { print '用語説明:'; print $description; print '<br /><br />'; } //$name、$category、$descriptionのいずれかがカラなら、戻るボタンのみを表示する //入力項目が適切なら、戻るボタンとOKボタンを表示する。 if($name==''|| $reading==''|| $category=='' || $description==''){ print '<form>'; print '<input type="button" onclick="history.back()" value="戻る">'; print '<form>'; } else { print '<form method="post" action="edit_done.php">'; print '<input type="hidden" name="name" value="'.$name.'">'; //'<input type="hidden" name="name" value="'と$nameをドットで連結 print '<input type="hidden" name="reading" value="'.$reading.'">'; //'<input type="hidden" name="namereading" value="'と$readingをドットで連結 print '<input type="hidden" name="category" value="'.$category.'">'; //'<input type="hidden" name="category" value="'と$categoryをドットで連結 print '<input type="hidden" name="description" value="'.$description.'">'; //'<input type="hidden" name="description" value="'と$descriptionをドットで連結 print '<input type="button" onclick="history.back()" value="戻る">'; print '<input type="submit" value="OK">'; print '</form>'; } ?> </body> </html>edit_done.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { // POSTメソッドで前の画面の入力値を取得する $name = $_POST['name']; $reading = $_POST['reading']; $category = $_POST['category']; $description = $_POST['description']; //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX;host=mysqlXXXX.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'XXXX'; //rootにはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを追加 $sql ='UPDATE contents SET name=?,reading=?,category=?,description=? WHERE name=?'; //$sql ='UPDATE contents SET name=?,reading=?,category=?,description=? WHERE name=?'を変数$sqlに格納する $stmt = $dbh->prepare($sql); // レコードを追加する準備。この行は定型文としてこのまま書く $data[] = $name; // 一つ目の?にセットしたいデータが入っている変数を書く $data[] = $reading; // 二つ目の?にセットしたいデータが入っている変数を書く $data[] = $category; // 三つ目の?にセットしたいデータが入っている変数を書く $data[] = $description; // 四つ目の?にセットしたいデータが入っている変数を書く $data[] = $name; // 五つ目の?にセットしたいデータが入っている変数を書く $stmt->execute($data); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く // データベースから切断するプログラム $dbh = null; } catch (Exception $e) { print 'ただいま障害により接続できません。'; exit(); //強制終了の命令 } ?> 修正しました。 <br /><br /> <a href="list.php">戻る</a> </body> </html>delete.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { $name=$_GET['name']; //前画面のlist.phpからGETでnameを受け取る //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX;host=mysqlXXXX.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'XXXX'; //''内にはにはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを読み込み $sql ='SELECT reading, category, description FROM contents WHERE name=?'; //'SELECT name FROM contents WHERE glossary=?'を変数$sqlに格納する。contentsテーブルのnameカラムのあとで指定する(?のこと)値の情報を取得する $stmt = $dbh->prepare($sql); // レコードを検索する準備。この行は定型文としてこのまま書く $data[] = $name; // 上の上の行の?の値を設定する $stmt->execute($data); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く $rec=$stmt->fetch(PDO::FETCH_ASSOC); $category=$rec['reading']; $category=$rec['category']; $description=$rec['description']; // データベースから切断するプログラム $dbh = null; } catch (Exception $e) { print 'ただいま障害により表示できません。'; exit(); //強制終了の命令 } ?> 用語削除<br /><br /> 用語<br /> <?php print $name; ?> <br /> この用語を削除してよろしいですか?<br /><br /> <form method="post" action="delete_done.php"> <input type="hidden" name="name" style="width:200px" value="<?php print $name?>"><br /> <input type="button" onclick="history.back()" value="戻る"> <input type="submit" value="OK"> </form> </body> </html>delete_done.php
<!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> <?php //tryはデータベースの接続エラー対策 try { // POSTメソッドで前の画面の入力値を取得する $name = $_POST['name']; //データベースに接続 $dsn = 'mysql:dbname=LAAXXXX;host=mysqlXXXX.lan'; //データベース名。''内は一切スペースを入れてはいけない $user = 'XXXX'; //rootにはユーザ名を入力 $password = 'XXXX'; //''内にはパスワードを入力 $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //この行は定型文としてこのまま書く // SQL分を使ってレコードを追加 $sql ='DELETE FROM contents WHERE name=?'; //DELETE FROM contents WHERE name=?を変数$sqlに格納する $stmt = $dbh->prepare($sql); // レコードを追加する準備。この行は定型文としてこのまま書く $data[] = $name; // 一つ目の?にセットしたいデータが入っている変数を書く $stmt->execute($data); // SQL文で指令を出すための命令文。この行は定型文としてこのまま書く // データベースから切断するプログラム $dbh = null; } catch (Exception $e) { print 'ただいま障害により接続できません。'; exit(); //強制終了の命令 } ?> 削除しました。 <br /><br /> <a href="list.php">戻る</a> </body> </html>ng.php
<!DOCTYPE html> <html lang="ja"> <!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="description" content="Webサイトのコンテンツ内容"> <title>Webサイトのタイトル</title> <link rel="stylesheet" href="/main.css"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> </head> <body> 用語が選択されていません。 <a href="list.php">戻る</a> </body> </html>
- 投稿日:2020-07-15T16:06:11+09:00
?【CakePHP2】Controllerで動的に一時テーブルを作成し使用する方法
環境
PHP 7.2.21
CakePHP 2.10.18
MySQL 5.7.27やりたいこと
テンポラリテーブルを使いたい
やったこと
ModelをuseTable = falseで用意してControllerでテーブル作成しセット
Model
TemporaryTable.php<?php App::uses('AppModel', 'Model'); class TemporaryTable extends AppModel { public $useTable = false; public $primaryKey = ''; public $useDbConfig = ''; function setSource($tableName) { $this->setDataSource($this->useDbConfig); $db = ConnectionManager::getDataSource($this->useDbConfig); $db->cacheSources = ($this->cacheSources && $db->cacheSources); $this->table = $this->useTable = $tableName; $this->tableToModel[$this->table] = $this->alias; $this->schema(); } }Controller
HogeController.php<?php class HogeController extends AppController { public function index() { // TEMPORARY TABLE名 $tempTableName = 'temporary_table'; // database.phpのDBconfigをModelに設定 $this->TemporaryTable->useDbConfig = 'admin'; // TEMPORARY TABLEを作成 $this->TemporaryTable->query('CREATE TEMPORARY TABLE ' . $tempTableName . ' (id INT(11), name VARCHAR(256));'); // 作成したTEMPORARY TABLE名をModelに設定 $this->TemporaryTable->useTable = $tempTableName; // 先ずfindしてみる -> result:array(0) $data = $this->TemporaryTable->find('all'); // テストデータをsaveする $testData = [ 'id' => '1', 'name' => '_test', ]; $this->TemporaryTable->create(); $this->TemporaryTable->save($testData); // テストデータ2をsaveする $testData2 = [ 'id' => '2', 'name' => 'test_test', ]; $this->TemporaryTable->create(); $this->TemporaryTable->save($testData2); // 再度find -> result:array(2) $data = $this->TemporaryTable->find('all'); var_dump($data); /* find結果 Array ( [0] => Array ( [TemporaryTable] => Array ( [id] => 1 [name] => _test ) ) [1] => Array ( [TemporaryTable] => Array ( [id] => 2 [name] => test_test ) ) ) */ } }
- 投稿日:2020-07-15T15:58:33+09:00
Laravel バージョン確認コマンド
- 投稿日:2020-07-15T15:38:19+09:00
PHP『include()』と『require()』違い
- 投稿日:2020-07-15T14:55:14+09:00
Laravel npm installを実行しようとしたらエラーが出た話 超簡易版
目的
- Laravelアプリに必要なJSパッケージをインストールするためにnpm installを実行したがエラーが出た話をまとめる
問題までの経緯
Laravelアプリ名ディレクトリの一つ上の階層で下記コマンドを実行した。
$ npm install問題
下記エラーが発生しコマンドが正常実行されない。
npm WARN saveError ENOENT: no such file or directory, open '/usr/share/nginx/html/package.json' npm WARN enoent ENOENT: no such file or directory, open '/usr/share/nginx/html/package.json' npm WARN html No description npm WARN html No repository field. npm WARN html No README data npm WARN html No license field. audited 15 packages in 0.511s 3 packages are looking for funding run `npm fund` for details found 0 vulnerabilities問題解決までの経緯
$ npm install
を実行するディレクトリを間違えていた。- Laravelアプリ名ディレクトリに移動して
$ npm install
を実行したところ正常に実行された。
- 投稿日:2020-07-15T10:13:06+09:00
PHP タイムスタンプと日時を相互変換
PHPの日付関連パーサーによらず自前で変換するにはどうすればいいのか気になったので試しに作ってみたクラスです。
date_to_timestamp_class.php<?php class DateToTimestamp { private $offsetDays; public function __construct() { // 0001-01-01から1970-01-01までのオフセット日数 $this->offsetDays = 719163; } /** * 日時 -> UNIXタイムスタンプ変換 */ public function dateToTimestamp(...$args) { // 引数変数名リスト $vars = ['year', 'month', 'day', 'hour', 'minute', 'second']; // 第一引数が配列なら各引数に振り分け if(isset($args[0]) && is_array($args[0])) foreach($vars as $i => $vn) $args[$i] = func_get_arg(0)[$vn] ?? null; // 各引数を該当変数へ foreach($vars as $i => $vn) ${$vn} = $args[$i] ?? (int) date(['Y','m','d','H','i','s'][$i]); try { if(array_reduce([$year, $month, $day, $hour, $minute, $second], function($a, $b) { return $a += !is_numeric($b);} )) { throw new Exception(__METHOD__. ': Non-numeric value specified for argument.'); } } catch (Exception $e) { return $e->getmessage(); } // 月オーバーフロー補正 $year += floor(($month - 1) / 12); $month = ($month + 11) % 12 + 1; // 前年 $prevYear = $year - 1; // 0001-01-01からの日数 $absoluteDays = (365 * $prevYear) + floor($prevYear / 4) - floor($prevYear / 100) + floor($prevYear / 400) + array_sum(array_slice($this->monthLastDays($year), 0, $month - 1) ) + $day; return ($absoluteDays - $this->offsetDays) * 86400 // 日数を秒に変換 + $hour * 3600 + $minute * 60 + $second // 時分秒 + mktime(0, 0, 0, 1, 1, 1970); // 時差補正 } /** * UNIXタイムスタンプ -> 日時変換 */ public function timestampToDate( $format = null, $timestamp = null ) { $timestamp = $timestamp ?? time(); try { if($format === null) { throw new Exception(__METHOD__. ': Specify parameters for format string.'); } elseif(!is_numeric($timestamp)) { throw new Exception(__METHOD__. ': Non-numeric value specified for argument.'); } } catch (Exception $e) { return $e->getmessage(); } // 時差補正 $timestampTz = $timestamp - mktime(0, 0, 0, 1, 1, 1970); $tzDiff = date('Z'); $absTzDiff = abs($tzDiff); // 1日内の秒数 $seconds = $timestampTz % 86400; $seconds = $seconds < 0 ? 86400 + $seconds : $seconds; // 0001-01-01 00:00:00 を0とした通算日数 $absoluteDays = (int) (floor($timestampTz / 86400) + $this->offsetDays) - 1; // 曜日 $w = ($absoluteDays + 1) % 7; // 年算出 $r = [ 400 => 146097, // 400年 = 36524 * 4 + 1日 100 => 36524, // 100年 = 1461 * 25 - 1日 4 => 1461, // 4年 = 365 * 4 + 1日 1 => 365, ]; $y = []; // 通算日数マイナス補正 $absDaysMinusMagnification = 0; if($absoluteDays < 0) { $absDaysMinusMagnification = floor(($absoluteDays -1) / $r[400]); $absoluteDays = (($absoluteDays % $r[400]) + $r[400]) % $r[400]; $w = ($absoluteDays + 1) % 7; } foreach($r as $k => $v) { $y[$k] = floor($absoluteDays / $v) * $k; $absoluteDays %= $v; } // 閏年末日補正 if(($y[1] == 4 || ($y[400] % 400 == 0 && $y[100] == 400)) && $absoluteDays == 0) { $y[1]--; $absoluteDays = 365; } // 年月日取得 $year = array_sum($y) + 1; $absoluteDays += 1; $monthLastDays = $this->monthLastDays($year); for($month = 1; array_sum(array_slice($monthLastDays, 0, $month)) < $absoluteDays && $month < 13; $month++ ); // 年内日数 $day = $absoluteDays - array_sum(array_slice($monthLastDays, 0, $month - 1)); // 通算日数マイナス補正戻し if($absDaysMinusMagnification) { $year += 400 * $absDaysMinusMagnification; } // 時分秒取得 $hour = (($seconds % 86400) / 3600) % 24; $minute = ($seconds % 3600) / 60; $second = $seconds % 60; // フォーマット文字置換 $result = preg_replace('/(\w)/', ":$1:", $format); $result = preg_replace('/\\\\:(\w):/', "$1", $result); $result = str_replace(':Y:', sprintf($year < 0 ? '%05d' : '%04d', $year), $result); $result = str_replace(':m:', sprintf('%02d', $month), $result); $result = str_replace(':d:', sprintf('%02d', $day), $result); $result = str_replace(':H:', sprintf('%02d', $hour), $result); $result = str_replace(':i:', sprintf('%02d', $minute), $result); $result = str_replace(':s:', sprintf('%02d', $second), $result); $result = str_replace(':y:', sprintf('%02d', $year % 100), $result); $result = str_replace(':n:', $month, $result); $result = str_replace(':j:', $day, $result); $result = str_replace(':G:', $hour, $result); $result = str_replace(':h:', sprintf('%02d', ($hour + 11) % 12 + 1), $result); $result = str_replace(':g:', ($hour + 11) % 12 + 1, $result); $result = str_replace(':L:', $monthLastDays[1] === 29 ? 1 : 0, $result); $result = str_replace(':w:', $w, $result); $result = str_replace(':N:', ($w + 6) % 7 + 1, $result); $result = str_replace(':z:', $absoluteDays - 1, $result); $result = str_replace(':t:', $monthLastDays[$month - 1], $result); $result = str_replace(':U:', $timestamp, $result); $result = str_replace(':a:', $hour < 12 ? 'am' : 'pm', $result); $result = str_replace(':A:', $hour < 12 ? 'AM' : 'PM', $result); $result = str_replace(':l:', ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][$w], $result); $result = str_replace(':D:', ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][$w], $result); $result = str_replace(':F:', ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][$month - 1], $result); $result = str_replace(':M:', ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][$month - 1], $result); // ISO8601 $result = str_replace(':c:', sprintf($year < 0 ? '%05d' : '%04d', $year). sprintf('-%02d-%02d', $month, $day). 'T'. sprintf('%02d:%02d:%02d', $hour, $minute, $second). ($tzDiff < 0 ? '-' : '+'). sprintf('%02d:%02d', floor($absTzDiff / 3600) % 24, floor($absTzDiff / 60) % 60) , $result); // タイムゾーン関連等、日時計算を伴わないものはとりあえずdate()の結果を素通し $result = preg_replace_callback('/:([eIOPTZ]):/', function($m) { return date($m[1]);}, $result); return preg_replace('/:(\w):/', "$1", $result); } /** * 指定した年の各月末日を返す */ private function monthLastDays($year) { $year = (($year % 400) + 400) % 400; // マイナス補正 return [31, (!($year % 4) && ($year % 100) || !($year % 400)) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; } }素直にDateTimeImmutable等を使えばいいので利用価値はほとんどありませんが、参考に置いておきます。
もっとスマートに計算できる方法があるかもしれませんが、現状これで精一杯。
計算間違いもあるかもしれません。動作チェックサンプル
test.php<?php $timezone = 'UTC'; //$timezone = 'Asia/Tokyo'; //$timezone = 'Etc/Gmt-9'; require_once('./date_to_timestamp_class.php'); $d = new DateToTimestamp; date_default_timezone_set($timezone); $dti = new DateTimeImmutable; $dti->setTimezone(new DateTimeZone($timezone)); $time = time(); $format = 'Y-m-d H:i:s'; $endtime = $d->dateToTimestamp(-2000,1,1,0,0,0); do { printf("%d %s %s %s\n", $time, $res1 = $dti->setTimestamp($time)->format($format), $res2 = $d->timestampToDate($format, $time), $res1 == $res2 ? '-' : '*' // 差異チェック ); $time -= 86400 * 7; } while($time > $endtime); for($year = -1000; $year < 2100; $year++){ for($month = 1; $month <= 12; $month++){ foreach([-1, 0, 29, 40] as $day){ printf("%04d-%02d-%02d %s %s %s\n", $year,$month,$day, $res1 = $dti->setTime(0,0,0)->setDate($year,$month,$day)->getTimestamp(), $res2 = $d->dateToTimestamp($year,$month,$day, 0,0,0), $res1 == $res2 ? '-' : '*' ); } } }こちらのコメントで教えて頂いたタイムゾーンがAsia/Tokyoの場合の特例には対応していないので、該当範囲内では異なる結果になります。
- 投稿日:2020-07-15T08:36:11+09:00
Laravel MySQL 既存テーブルの任意の場所にカラムを追記する 簡易版
目的
- 途中でカラムを追加する際に既存カラムの間に新規カラムを追加する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 記載例
下記の様にカラムを追加するマイグレーションファイルに記載することにより任意のカラムの後に新規カラムを追加することができる。
$table->データ型('新規カラム名', オプション)->after('新規カラムを追加したい位置の一つ前ののカラム名');
- 投稿日:2020-07-15T08:23:13+09:00
【Laravel】プロフィール画像アップロード
実装したいこと
- usersテーブルにプロフィール画像を追加
- デフォルト画像を用意
- プロフィール画像変更
- 変更時、選択した画像を表示
- アップロード時、画像をリサイズ
前提
- Laravel7
- マイグレーション済み
- routes/web.phpにRoute::resource('user', 'UserController');を記述済み
実装
データベースに画像のファイル名を保存しておいて、そのファイル名をもとに画像の読み出しを行う、という戦略をとることとします。
画像の保存場所はpublic/storage/profiles/とします。このディレクトリにあらかじめデフォルトの画像を配置しておいてください。profile_imageカラムの追加
マイグレーションファイルを作成します。
% php artisan make:migration add_column_to_users_table --table=usersカラムを追加する処理を書きます。
database/migrations/20XX_00_00_000000_add_column_to_users_table.phpclass AddColumnToUsersTable extends Migration { public function up() { Schema::table('users', function (Blueprint $table) { $table->string('profile_image')->default('default.png'); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('profile_image'); }); } }マイグレーション
% php artisan migrateUser.phpの$fillableにカラムを追加
app/User.phpprotected $fillable = [ 'name', 'email', 'password', 'profile_image' ];画像の表示
画像の表示の一例を以下に示します
コントローラー
app/Http/Controllers/ProfileController.phppublic function profile() { $user = Auth::user(); return view('profile', ['user' => $user]); }ビュー
resources/views/profile.blade.php<img src="{{ asset('storage/profiles/'.$user->profile_image) }}" alt="プロフィール画像">プロフィール画像編集(アップロード)
ここで、Intervention Imageを用います。
Intervention Imageを使用するには、以下のコマンドを実行するだけでいいです。% composer require intervention/imageIntervention Imageの使い方は以下のブログを参考にしました。
「完全網羅!Intervention Image(PHP)で画像を編集する全実例」
公式はこちら。コントローラー
Intervention Imageでの処理は、saveProfileImage()内で行っています。
バリデーションはフォームリクエストUserRequestで行います。(省略)app/Http/Controllers/UserController.phppublic function edit($id) { $user = Auth::user(); return view('user.edit', ['user' => $user]); } public function update($id, UserRequest $request) { $user = Auth::user(); $form = $request->all(); $profileImage = $request->file('profile_image'); if ($profileImage != null) { $form['profile_image'] = $this->saveProfileImage($profileImage, $id); // return file name } unset($form['_token']); unset($form['_method']); $user->fill($form)->save(); return redirect('/home'); } private function saveProfileImage($image, $id) { // get instance $img = \Image::make($image); // resize $img->fit(100, 100, function($constraint){ $constraint->upsize(); }); // save $file_name = 'profile_'.$id.'.'.$image->getClientOriginalExtension(); $save_path = 'storage/profiles/'.$file_name; $img->save($save_path); // return file name return $file_name; }ビュー
- 現在のプロフィール画像を最初に表示
- プロフィール画像をクリックしたら、画像ファイルを選択できる
- 選択した画像ファイルが表示される
以上を満たすように実装します。
「選択画像が変化したらアップロードしようとしている画像を表示する」といった処理をJavaScriptで実装しています。ファイルをアップロードするためには、enctype="multipart/form-data"をformタグに追加する必要があります。
resources/views/user/edit.blade.php<form method="post" action="{{ route('user.update', ['user' => $user->id]) }}" enctype="multipart/form-data"> @csrf @method('PATCH') <label for="profile_image">プロフィール画像</label> <label for="profile_image" class="btn"> <img src="{{ asset('storage/profiles/'.$user->profile_image) }}" id="img"> <input id="profile_image" type="file" name="profile_image" onchange="previewImage(this);"> </label> <button type="submit" class="btn btn-primary"> 変更 </button> </form> <script> function previewImage(obj) { var fileReader = new FileReader(); fileReader.onload = (function() { document.getElementById('img').src = fileReader.result; }); fileReader.readAsDataURL(obj.files[0]); } </script>SASS(CSS)
input#profile_image { display: none; }おわり
画像のリサイズやJavaScriptの部分は一例に過ぎないので、他のサイトで別の方法をとてもいいかも
Intervention Imageは便利なので上で紹介したサイトで勉強してみては?
- 投稿日:2020-07-15T02:36:07+09:00
Laravelで同じURLにルーティングをする方法
概要
Laravelでルーティングをしようと思った際に困ったことがあり、ネットにあまり情報がなかったので備忘録として投稿しました。
初めてQiitaに投稿するので至らないところがあると思いますがご了承下さい。
また、PHPに触れるのも2,3週間ほどしか経っていないです。困ったこと
/routes/web.phpにルーティングについての記述をしていました。
/routes/web.phpRoute::get('/sql/hogehoge', function () { return view('sql/hogehoge'); }); Route::get('/sql/hogehoge/', 'SQLController@search'); Route::post('/sql/hogehoge/', 'SQLController@searchResults'); Route::get('/sql/hogehoge/', 'SQLController@index1_search'); Route::post('/sql/hogehoge/', 'SQLController@index1_searchResults');SQLController.phppublic function search(){ $sql = "SELECT name FROM tables"; $stmt = $pdo->prepare($sql); $stmt->execute(); return view('sql/hogehoge', [ 'names' => $stmt ]); } public function searchResults(){ $name_id = request('name'); return $name_id; } public function index1_search(){ $sql = "SELECT date FROM tables"; $stmt = $pdo->prepare($sql); $stmt->execute(); return view('sql/hogehoge', [ 'dates' => $stmt ]); } public function index1_searchResults(){ $date_id = request('date'); return $date_id; }Route::get()の第1引数にはURLを書きます。第2引数にはどこのメソッドで処理をするのか書きます。
上記の例ですとhttp://localhost/sql/hogehoge と検索したときにSQLController.phpにあるsearchメソッドが呼び出されて処理が行われるという意味になります。また、SQLController.phpで処理したデータを表示させるために以下のresult.php(仮称)を作成しました。
result.php<form action ="./SQLController" method="POST"> <label for="Hogehoge">Hogehoge</label> <select class="form-control" id="name" name="name"> <option value="" selected></option> <?php if(isset($names)) foreach ($names as $v) { ?> <option value=<?php echo $v["first"]; ?>><?php echo $v["last"]; ?></option> <?php } ?> </select> </form> <form action ="./SQLController" method="POST"> <label for="Tournament">Tournament</label> <select class="form-control" id="date" name="date"> <option value="" selected></option> <?php if(isset($dates)) foreach ($dates as $v) { ?> <option value=<?php echo $v["month"]; ?>><?php echo $v["year"]; ?></option> <?php } ?> </select> </form>だいぶ省略していますがこれを実行しようとするとプルダウンメニューがname用とdate用で2つでてくるのですが、なんとdate用のプルダウンメニューしかsqlの処理がなされませんでした。name用のプルダウンメニューには何も表示されませんでした。
原因
原因はweb.phpにありました。
/routes/web.phpRoute::get('/sql/hogehoge/', 'SQLController@search'); Route::post('/sql/hogehoge/', 'SQLController@searchResults'); Route::get('/sql/hogehoge/', 'SQLController@index1_search'); Route::post('/sql/hogehoge/', 'SQLController@index1_searchResults');上記ではRoute::getの第1引数が同じものを使っていることがわかると思います。
同じものを記述するとあとに記述したもの(ここではSQLController@index1_searchResults)が優先されて実行されるようです。
実際そのような結果が筆者は確認できました。解決方法
同じ第1引数を記述したことに原因があるのでそれについて変更を加えました。
web.phpは処理をするメソッドを一つにまとめました。/routes/web.phpRoute::get('/sql/hogehoge/', 'SQLController@search'); Route::post('/sql/hogehoge/', 'SQLController@searchResults');それにともないSQLController.phpのほうのメソッドも一つにまとめました。
SQLController.phppublic function search(){ $name_sql = "SELECT name FROM tables"; $name_stmt = $pdo->prepare($name_sql); $name_stmt->execute(); $date_sql = "SELECT date FROM tables"; $date_stmt = $pdo->prepare($date_sql); $date_stmt->execute(); return view('sql/hogehoge', [ 'names' => $name_stmt, 'dates' => $date_stmt ]); } public function searchResults(){ $name_id = request('name'); return [$name_id, $date_id]; }メソッドで複数の値を返したいときはreturn [];の形で書きます。
以上のようにしてみたら上手く複数のプルダウンメニューが表示できるようになりました。
おわりに
コードは適当に変数や値をつけてしまった部分があるので間違いがあると思います。
ほかにもいい方法があるのかもしれませんが、3,4時間ほど悩んでようやく解決できた苦痛を他の方々にも味わってほしくないと思い、ここに書き記しました。なにか間違い等ありましたら教えて下さい。また、ほかにもなにかいい方法がありましたら教えて下さい。
- 投稿日:2020-07-15T01:52:06+09:00
paizaラーニングを使ってみて良いなと思ったところ
paizaラーニングの良いなと思ったところについて書いていきます。
その1:開発環境を用意しなくていい
その2:取り扱っている講座が豊富で選びやすい
その3:とりあえず無料で始められるここからそれぞれの良いところを自分なりに少し掘り下げていきます。
その1:開発環境を用意しなくていい
paizaラーニングはpaiza.IOという、ブラウザで動くオンライン実行環境を使って
学習ができます。
paizaラーニングを始めるにあたって、特別な知識や経験は必要ないのです。その2:取り扱っている講座が豊富で選びやすい
paizaラーニングの講座は、「目的別」、「言語別」、「技術別」の大きく3種類に分かれており、自分が学びたいと思っている分野が選択しやすいです。その3:とりあえず無料で始められる
paizaラーニングは無料で利用ができます。(paizaのユーザー登録が必須です)
もちろん有料でないと完走できない講座もありますが、完全無料で完走ができる講座もあります。
paizaラーニングを通して、プログラミングの楽しさを感じられる人は、有料会員になって片っ端から講座を網羅するのも良いかもしれません。あとがき
paizaラーニングを使ってみて良いなと思ったところについて、書いてみました。今回の3点の中では、やはり無料で始められるのが大きい点ではないでしょうか。
パソコンとネット環境があれば、とりあえずプログラミングの勉強が始められるなんて、良い時代になったなと思います。最後に余談ですが、私は[PHP入門編]を完走しました。
https://twitter.com/2go_r2071/status/1283063220106752002なぜPHPを選んだかというと、業務で使っているソフトのコードの文法がPHPによく似ていたためです。
- 投稿日:2020-07-15T00:00:21+09:00
PHP タイムゾーンがAsia/Tokyoの場合、1888-01-01より前のdateの結果がおかしい
確認スクリプト
test.php<?php $format = 'Y-m-d H:i:s'; foreach(['Asia/Tokyo', 'Etc/GMT-9'] as $timezone) { date_default_timezone_set($timezone); echo "$timezone\n"; $datetime = new DateTimeImmutable(); echo " / timestamp / date / DateTimeImmutable\n"; for($i = 0; $i < 10; $i++) { $timestamp = -2587712405 + $i; printf("%4d / %d / %s / %s\n", $i, $timestamp, date($format, $timestamp), $datetime->setTimestamp($timestamp)->format($format) ); } echo "\n"; } foreach(['Asia/Tokyo', 'Etc/GMT-9'] as $timezone) { date_default_timezone_set($timezone); echo "$timezone\n"; echo strtotime('1887-12-31 23:59:59')."\n"; echo strtotime('1888-01-01 00:00:00')."\n\n"; }$ php -v PHP 7.4.4 (cli) (built: Mar 20 2020 13:47:45) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.4, Copyright (c), by Zend Technologies $ php test.php Asia/Tokyo / timestamp / date / DateTimeImmutable 0 / -2587712405 / 1888-01-01 00:18:54 / 1888-01-01 00:18:54 1 / -2587712404 / 1888-01-01 00:18:55 / 1888-01-01 00:18:55 2 / -2587712403 / 1888-01-01 00:18:56 / 1888-01-01 00:18:56 3 / -2587712402 / 1888-01-01 00:18:57 / 1888-01-01 00:18:57 4 / -2587712401 / 1888-01-01 00:18:58 / 1888-01-01 00:18:58 5 / -2587712400 / 1888-01-01 00:00:00 / 1888-01-01 00:00:00 6 / -2587712399 / 1888-01-01 00:00:01 / 1888-01-01 00:00:01 7 / -2587712398 / 1888-01-01 00:00:02 / 1888-01-01 00:00:02 8 / -2587712397 / 1888-01-01 00:00:03 / 1888-01-01 00:00:03 9 / -2587712396 / 1888-01-01 00:00:04 / 1888-01-01 00:00:04 Etc/GMT-9 / timestamp / date / DateTimeImmutable 0 / -2587712405 / 1887-12-31 23:59:55 / 1887-12-31 23:59:55 1 / -2587712404 / 1887-12-31 23:59:56 / 1887-12-31 23:59:56 2 / -2587712403 / 1887-12-31 23:59:57 / 1887-12-31 23:59:57 3 / -2587712402 / 1887-12-31 23:59:58 / 1887-12-31 23:59:58 4 / -2587712401 / 1887-12-31 23:59:59 / 1887-12-31 23:59:59 5 / -2587712400 / 1888-01-01 00:00:00 / 1888-01-01 00:00:00 6 / -2587712399 / 1888-01-01 00:00:01 / 1888-01-01 00:00:01 7 / -2587712398 / 1888-01-01 00:00:02 / 1888-01-01 00:00:02 8 / -2587712397 / 1888-01-01 00:00:03 / 1888-01-01 00:00:03 9 / -2587712396 / 1888-01-01 00:00:04 / 1888-01-01 00:00:04 Asia/Tokyo -2587713540 -2587712400 Etc/GMT-9 -2587712401 -2587712400タイムゾーンをEtc/GMT-9にすると大丈夫っぽい。
他のタイムゾーンは未確認。JavaScriptはどうなのか確認してみたら、同様のずれ。
(Chrome 83で確認){ for(let i = 0; i < 10; i++) { const timestamp = -2587712405 + i; console.log(timestamp * 1000, new Date(timestamp * 1000)); } }-2587712405000 Sun Jan 01 1888 00:18:54 GMT+0918 (日本標準時) -2587712404000 Sun Jan 01 1888 00:18:55 GMT+0918 (日本標準時) -2587712403000 Sun Jan 01 1888 00:18:56 GMT+0918 (日本標準時) -2587712402000 Sun Jan 01 1888 00:18:57 GMT+0918 (日本標準時) -2587712401000 Sun Jan 01 1888 00:18:58 GMT+0918 (日本標準時) -2587712400000 Sun Jan 01 1888 00:00:00 GMT+0900 (日本標準時) -2587712399000 Sun Jan 01 1888 00:00:01 GMT+0900 (日本標準時) -2587712398000 Sun Jan 01 1888 00:00:02 GMT+0900 (日本標準時) -2587712397000 Sun Jan 01 1888 00:00:03 GMT+0900 (日本標準時) -2587712396000 Sun Jan 01 1888 00:00:04 GMT+0900 (日本標準時)