PHP&SQL

01このLessonの目的

ここではこれまで学んできたPHPとSQLの連携について学んでいきます。

登録できなかった登録フォームが登録できるようになり、一気にWebアプリケーションらしいものになります。

02メモ帳を作成する

ここからはシンプルなメモ帳を作成していきます。

HTML&CSSで作ったメモ帳を実際に表示・登録・編集・削除できるようにします。

03Cloud9で環境構築を行う

まずは「Cloud9」でPHPの動く環境を作成しましょう。

これから作成していくメモ帳用のファイルを作成します。

以下のような構造で新規ファイルを作成してください。ファイルは空で作成してください。

Lesson8_PHP_SQL
  └──memo_php
      ├── css
      │   └── style.css 以下をコピー
      ├── index.php
      └── dbConnection.php

style.css

body{
    background-color: #edf2f4;
}

.container{
    max-width: 980px;
    margin-right: auto;
    margin-left: auto;
}

.memo_area{
    display: flex;
    justify-content: space-between;
}

.memo_form{
    text-align: center;
    width: 40%;
}

.memo_form input[type="submit"]{
    border-radius: 5px;
    border: none;
    padding: 5px 20px;
    background-color: #38B000;
    color: #fefefe;
    font-weight: bold;
}

.memo_form h2{
    text-align: center;
}

.memo_text{
    display: block;
    margin: 0 auto 15px;
    border: none;
    height: 20px;
}

.memo_show{
    width: 60%;
}

.memo_item{
    background-color: #fefefe;
    display: flex;
    width: 100%;
    margin-top: 10px;
    padding: 5px 10px;
    border-radius: 5px;
}

.memo_title{
    width: 90%;
}

.memo_title p{
    margin: 0;
}

.memo_title time{
    font-size: 10px;
}

.btn_area{
    display: flex;
    margin: auto;
}

.edit_form{
    margin-right: 10px;
}

.edit_form input,
.del_area input {
    border-radius: 5px;
    padding: 5px 12px;
    border: none;
}
.memo_form input[type="submit"]:hover,
.edit_form input:hover,
.del_area input:hover{
    opacity: .8;
}

.edit_form input{
    background-color: #38B000;
    color: #fefefe;
    font-weight: bold;
}

.del_area input{
    background-color: #d64045;
    color: #fefefe;
    font-weight: bold;
}

index.php に以下のコードをコピー&ペーストしてください。

index.php

<?php
	echo 'Webサーバーが起動しています!';
?>

<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>メモ帳</title>
</head>
<body>
    <div class="container">
        <div class="memo_area">
            <div class="memo_form">
                <h2>メモを追加</h2>
                <form action="">
                    <input class="memo_text" type="text" name="" id="">
                    <input type="submit" value="追加">
                </form>
            </div>
            <div class="memo_show">
                <div class="memo_item">
                    <div class="memo_title">
                        <time>2022.10.10</time>
                        <p>サッカー</p>
                    </div>
                    <div class="btn_area">
                        <div class="edit_form">
                            <form action="">
                                <input type="submit" value="編集">
                            </form>
                        </div>
                        <div class="del_area">
                            <form action="">
                                <input type="submit" value="削除">
                            </form>
                        </div>
                    </div>
                </div>
                <div class="memo_item">
                    <div class="memo_title">
                        <time>2022.10.10</time>
                        <p>大阪旅行</p>
                    </div>
                    <div class="btn_area">
                        <div class="edit_form">
                            <form action="">
                                <input type="submit" value="編集">
                            </form>
                        </div>
                        <div class="del_area">
                            <form action="">
                                <input type="submit" value="削除">
                            </form>
                        </div>
                    </div>
                </div>
                <div class="memo_item">
                    <div class="memo_title">
                        <time>2022.10.10</time>
                        <p>メモ内容</p>
                    </div>
                    <div class="btn_area">
                        <div class="edit_form">
                            <form action="">
                                <input type="submit" value="編集">
                            </form>
                        </div>
                        <div class="del_area">
                            <form action="">
                                <input type="submit" value="削除">
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

ファイルが作成できたら「Cloud9」でindex.phpを開きましょう。

まずはWebサーバーを起動します。

※上の画像には2行目までしかコピーされていませんが、上の解説通り追加するようにして下さい。

「Cloud9」のRunボタンがヘッダー部分にあるのでクリックしましょう。

クリックするとターミナルが表示され、Webサーバーが起動します。

それでは先ほど作成した index.php が画面に表示されるか確認しましょう。

「Preview」から「Preview Running Application」を選択しましょう。

選択するとブラウザウインドが表示されます。

このままでは小さくて見にくいので最大画面で見れるようにしましょう。

下記画像の部分をクリックしてください。

するとプレビュー画面用のタブが立ち上がります。

これで見やすくなりましたね。開発を進める際には、画面に意図した通りの表示ができているか確認がしやすいよう、プレビュー画面は別タブで開いておくようにしましょう。

プレビューは開けましたが「404」エラーになっています。

これはパスがあっていないためエラーになっています。

ではURLを以下のように変更してください。

https://{省略}.vfs.cloud9.ap-northeast-1.amazonaws.com/Lesson8_PHP_SQL/memo_php/index.php

パスを「Lesson8_PHP_SQL/memo_php」フォルダ直下の「index.php」を参照するように変更しました。

URLにアクセスすると、

無事に「index.php」ファイルの中身が表示されるようになりました!

サーバーを停止する場合は、「Stop」ボタンをクリックするかターミナル内で「Ctrl」を押しながら「C」を入力しましょう。

作業を終了した場合は、必ずサーバーを停止するようにしましょう。

04Cloud9にデータベースを追加する

先ほどの作業でサーバーには接続できましたが、DBには接続できていません。

このままではデータを保存できないため、ページを読み込むたびにメモがすべて消えてしまうことになります。

メモを保存できるようにDBを作成し、PHPと接続していきます。

では、Cloud9で新しくターミナルを開きましょう。

下記の手順でターミナルを開いてください。

ターミナルが新しく開けたら、下記のコマンドを実行しMySQLを起動しましょう。

sudo service mysql start

下記コマンドを実行し、SQLサーバに接続しましょう。

sudo mysql -u root

mysql>が最後の行に表示されていたら、無事にSQLサーバに接続できています。

続いてユーザーを作成していきます。

// ユーザーを作成
create user user@localhost identified by 'pass';
// 権限を付与
grant all on *.* to user@localhost;

これでユーザーを追加することができました。

設定を反映させるために一度MySQLを再起動しましょう。

以下のコマンドを順に実行してください。

// MySQLからログアウト
exit
// MySQLサーバーを再起動
sudo service mysql restart
// MySQLへログイン
sudo mysql -u root
// ユーザー一覧を取得
SELECT Host, User FROM mysql.user

無事に先ほど作成したユーザーが追加できていますね。

では続いてデータベースを作成していきます。

下記コマンドを実行し、データベースを作成してください。

CREATE DATABASE memo_php;

「Query OK, 1 row affected」が表示されれば無事に作成できているはずです。

実際に確認してみましょう。

下記コマンドを実行し、データベースの一覧を確認しましょう。

show databases;

「memo_php」が追加されていますね。

これでデータベースを作成することができました。

続いて作成したデータベースとPHPを接続していきましょう。

05データベースとPHPを接続する

PHPからデータベースへの接続を行います。

最初に作成した「dbConnection.php」に下記のコードを追加してください。

<?php
try {
    /*DBへ接続*/
    $host = 'localhost';
    $username = 'user';
    $password = 'pass';
    $dbName = 'memo_php';

    $dbh = new PDO("mysql:host=localhost; dbname=$dbName; charset=utf8", $username, $password);
    echo '接続成功';
} catch (PDOException $e) {

    echo $e->getMessage();
}

次にindex.phpの先頭に以下のコードを追加してください。

<?php
    include './dbConnection.php';
?>

ページを読み込んでみると、以下の画像のように「接続成功」と表示されます。

これでPHPからデータベースへの接続ができました。では、コードの解説をしていきます。

まずはindex.phpのinclude './dbConnection.php';についてです。

ここではdbConnection.phpを読み込み、index.php上で使えるようにしています。

index.phpに直接dbConnection.phpの内容を記述しているのと同じ状態になります。

なぜファイルを分けるのでしょうか? それは、機能ごとにファイルを分けた方が後から改修しやすく、保守性が高まるためです。

ファイルを分けずに全て同じファイルに記述していくとコード数が増え、読みにくく、追加しにくいコードになってしまいます。

続いてdbConnection.phpの内容についてです。

まずは、try catch文について説明します。

try { /*DBへ接続*/
    $host = 'localhost';
    $username = 'user';
    $password = 'pass';
    $dbName = 'memo_php';

    $dbh = new PDO("mysql:host=localhost; dbname=$dbName; charset=utf8", $username, $password);
    echo '接続成功';
} catch (PDOException $e) {
    echo $e->getMessage();
}

コードではこの部分です。

try catch文は、例外が発生する可能性のある処理をtryブロックの中に記述し、例外が発生した時に実行する特別な処理をcatchブロックの中に記述します。

今回例外が発生した場合は、echo $e->getMessage();が実行されるということがわかります。

実際の処理は、try{}の中に書くので、DB接続情報はこのようにtry{}の中に書かれています。

テーブルを作成する

今回作成するテーブルは以下のカラムを持たせます。

  • id 今回の主キー
  • body メモの内容
  • date メモが登録されたときの日付
  • invalid 論理削除判定カラム(0:未削除 1:削除済)

では実際にテーブルを作成していきます。

「Lesson8_PHP_SQL」フォルダの中に新しく「sql」フォルダを作成してください。

作成できたら「sql」フォルダの中に「memo.sql」ファイルを新規作成し、以下のコードをコピペしてください。

memo.sql

DROP TABLE IF EXISTS `memo_php`.`memo`;
CREATE TABLE `memo_php`.`memo` (
    `id` INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `body` VARCHAR(100) NOT NULL,
    `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `invalid` INT NOT NULL DEFAULT 0
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

作成したファイルの構成は以下です。

Lesson8_PHP_SQL
  ├──memo_php
  └── sql
      └── memo.sql

それでは先ほど作成したsqlファイルを実行してテーブルを作成していきましょう。

まずは以下コマンドを実行し、MySQLにログインしましょう。

※すでにログインしている場合は不要です。

MySQLにログイン

sudo mysql -u root

ログインできたら以下のコマンドを実行してください。

source Lesson8_PHP_SQL/sql/memo.sql

「Query OK, 0 rows affected」と表示されればOKです。

エラーが出る場合はファイル名やパスが間違っている可能性があるので、ファイル名やパスを見直してみましょう。

ではテーブルが実際に作成されたかどうかを確認しましょう。

下記コマンドを順に実行していきます。

データベース一覧を表示

show databases;

データベースを選択

use memo_php;

テーブル一覧を表示

show tables;

無事に「memo」テーブルが表示されています。

テーブルの構成を確認してみましょう。

describe memo;

上記画像のようになっていればテーブル作成は完了です。

データベースの中身を画面に表示する

ここではデータベースに登録されているメモを実際に画面に表示させてみます。

dbConnection.phpのecho '接続成功';コメントアウトしておいてください

では新たにindex.phpと同じ階層に「select.php」を新規作成しましょう。

memo_php
├── css
│   └── style.css
├── index.php
├── select.php
└── dbConnection.php

作成したら以下のコードをコピーしましょう。

select.php

<?php
    $sql = "SELECT * FROM memo";
    $memo_list = $dbh->query($sql);

index.php

<?php
    include './dbConnection.php';
    // この部分を追加
    include './select.php';

// mem0_showクラス部分を上書き
<div class="memo_show">
     <?php foreach($memo_list as $memo): ?>
     <div class="memo_item">
          <div class="memo_title">
             <time><?php echo $memo['date'] ?></time>
             <p><?php echo $memo['body'] ?></p>
          </div>
          <div class="btn_area">
             <div class="edit_form">
                <form action="">
                     <input type="submit" value="編集">
                </form>
             </div>
             <div class="del_area">
                 <form action="">
                     <input type="submit" value="削除">
                 </form>
             </div>
         </div>
     </div>
     <?php endforeach; ?>
</div>

ここまでコピーできたら画面を読み込んでみましょう。

画面上にデータベースに登録されたデータが表示されていますね。

これで表示されるまでの処理は完了です。

コードについて解説していきます。

$sql = "SELECT * FROM memo";
$memo_list = $dbh->query($sql);

まずはこの部分です。

$sqlという変数にSQL文を代入しています。

SQL文はシンプルにmemoテーブルから全てのデータを取得するという内容になります。

次に$dbh->query($sql)の部分です。

ここでは先ほどのSQL文をPHPから実行しています。これまでターミナルで行っていたことをPHP上で行っています。

これで実行されたSQLの結果が$memo_listの中に格納されます。

続いてこの部分です。

<div class="memo_show">
     <?php foreach($memo_list as $memo): ?>
     <div class="memo_item">
          <div class="memo_title">
             <time><?php echo $memo['date'] ?></time>
             <p><?php echo $memo['body'] ?></p>
          </div>
          <div class="btn_area">
             <div class="edit_form">
                <form action="">
                     <input type="submit" value="編集">
                </form>
             </div>
             <div class="del_area">
                 <form action="">
                     <input type="submit" value="削除">
                 </form>
             </div>
         </div>
     </div>
     <?php endforeach; ?>
</div>

まずは<?php foreach($memo_list as $memo): ?>の部分です。

ここでは、

$sql = "SELECT * FROM memo";
$memo_list = $dbh->query($sql);

で取得したデータベースから取得したメモ内容を1つ1つループさせています。

メモの内容の1つが$memoに格納されています。

具体的には、$memoには、

$menu = [
	'id' => 1,
  'body' => 'メモ',
	'date' => '2023-01-04 19:26:20',
  'invalid' => 0
];

というデータが入っています。

これはデータベースのデータが配列として$memoに格納されています。

最後に、

<time><?php echo $memo['date'] ?></time>
<p><?php echo $memo['body'] ?></p>

この部分です。

配列から日時とメモ内容を取得し、echoで表示させています。

これで表示の部分まではできました!

Git

バージョン管理もおこないます。

バージョン管理を行うことで、どのような変更が行われたか把握しやすくするためです。

以下のコマンドを順に実行して下さい。

memo_phpディレクトリに移動

cd ~/environment/memo_php

初期化

git init

ここまでの変更点をコミット

git add .

git commit -m "表示"

// デフォルトのmasterブランチをmainブランチに名前を変更
git branch -M main

以上を実行することで、ローカルのmasterブランチにここまでの変更点を反映することができました。

次はメモを追加する部分を実装していきましょう。

06メモを追加する

では新たにindex.phpと同じ階層に「insert.php」を作成してください。

memo_php
├── css
│   └── style.css
├── index.php
├── insert.php
├── select.php
└── dbConnection.php

作成できたら以下のコードをコピーしましょう。

insert.php

<?php
    //コメントの内容をDBに追加する
    if (isset($_POST["body"])) {

        $body = $_POST["body"];
        $date = date("Y/m/d H:i:s");

        /*sql文*/
        $sql = "INSERT INTO memo(
            body, date
        )VALUES(
            '$body', '$date'
        )";

        /*bindValue関数でバインドする*/
        $result = $dbh->prepare($sql);
        $result->execute();
    }

index.php

<?php
    include './dbConnection.php';
		// ここに追加
    include './insert.php';
    include './select.php';

index.phpにある下記部分を修正

<body>
    <div class="container">
        <div class="memo_form">
          <h2>メモを追加</h2>
          <form method="post" action="index.php">
	     // nameにbodyを追加
             <input class="memo_text" type="text" name="body">
             <input type="submit" value="追加">
          </form>
        </div>

追加できたら画面を読み込んで、実際に何かメモを追加してみましょう。

追加したメモが表示されていたらOKです。

表示されない場合は追加したコードをもう一度確認してみましょう。

ではコードの解説です。

if (isset($_POST["body"]))まずはこの部分ですが、name属性が「body」である要素がPOSTされたときにtrueになるようになっています。

もう少し丁寧に説明します。

$_POSTはPOST通信のデータを受け取ることができます。今回は、index.phpで<form method="post" action="index.php">とmethod=”post”でPOST通信を指定しています。

追加ボタンが押されると、<form></form>の中のinputタグの情報が送信されます。

今回のinputは<input class="memo_text" type="text" name="body">のみです。

inputタグの情報は$_POST[”name属性の名前”]で取得できます。

isset()は引数が空かどうかを判別します。

今回は$_POST[”body”]が空かどうかを判別しています。

空の時は、情報が送信されていない時です。つまり画面が読み込まれたり、削除ボタンが押されたときなどです。

追加ボタンが押された時のみisset()はtrueになります。

$body = $_POST["body"];
$date = date("Y/m/d H:i:s");

続いてこの部分ですが、$_POST["body"]でメモ追加テキストボックスの情報を取得し、$bodyに格納しています。

次にdate("Y/m/d H:i:s")で現在の時間を取得しています。

最後に、

$sql = "INSERT INTO memo( body, date )VALUES( '$body', '$date' )";

この部分です。

メモの情報をDBに追加するSQL文です。

SQLのレッスンで解説しているためここでは詳しく解説しません。

最後にこの部分ですが、先ほど作成した$sqlを実行しています。

/*bindValue関数でバインドする*/
$result = $dbh->prepare($sql);
$result->execute();

$result = $dbh->prepare($sql);ですが、SQL文を**prepare()**にセットし、SQL実行のための準備を行っています。

そして、$result->execute();でSQLを実行しています。

ここはあまり深く考えず、SQLを実行するにはこの2行が必要なんだ、くらいに思っておいてください。

Git

// 前のcommitからの差分を確認
git diff

git add .

git commit -m "追加"

07メモを削除する

では新たにindex.phpと同じ階層に「delete.php」を作成してください。

memo_php
├── css
│   └── style.css
├── index.php
├── delete.php // 追加
├── insert.php
├── select.php
└── dbConnection.php

作成できたら以下のコードをコピーしましょう。

<?php

// 対象のメモを削除する
if (isset($_POST["delete_id"])) {

    $delete_id = $_POST["delete_id"];

    /*sql文*/
    $sql = "DELETE FROM memo WHERE id = '$delete_id'";

    /*bindValue関数でバインドする*/
    $result = $dbh->prepare($sql);
    $result->execute();
}

index.php

<div class="del_area">
     <form action="index.php" method="post">
          <input type="hidden" name="delete_id" value="<?php echo $memo['id'] ?>">
          <input type="submit" value="削除">
     </form>
</div>

まずは、<input type="hidden" name="delete_id" value="<?php $memo['id'] ?>">の部分です。

削除ボタンが押されたときに、どのメモが押されたのかを判別しないといけません。

そこで、判別に使うのは「memo」テーブルのidです。

idをinputタグのvalueに設定することで、どのメモの削除ボタンが押されたかを判別することができます。

また、typeをhiddenにすることで画面に表示されなくなります。

では、画面を読み込んでメモを削除してみましょう。

無事に削除されたらOKです。

Git

// 前のcommitからの差分を確認
git diff

git add .

git commit -m "削除"

08メモを編集する

では新たにindex.phpと同じ階層に「edit.php」を作成してください。

memo_php
├── css
│   └── style.css
├── index.php
├── delete.php
├── edit.php // 追加
├── update.php // 追加
├── insert.php
├── select.php
└── dbConnection.php

作成できたら以下のコードをコピーしましょう。

edit.php

<?phpinclude './dbConnection.php';
if (isset($_POST["edit_id"])) {

    $edit_id = $_POST["edit_id"];

    /*sql文*/
    $sql = "SELECT * FROM memo WHERE id = '$edit_id'";

    $memo_info = $dbh->query($sql)->fetch();
}
?>
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>メモ帳 | 編集</title>
    <link rel="stylesheet" href="./css/style.css">
</head>

<body>
<div class="memo_form">
    <h2>メモを追加</h2>
    <form action="index.php" method="post">
        <input class="memo_text" type="text" name="edit_body" value="<?php echo $memo_info['body'] ?>">
        <input class="memo_id" type="hidden" name="memo_id" value="<?php echo $memo_info['id'] ?>">
        <input type="submit" value="追加">
    </form>
</div>
</body>

</html>

index.php

<div class="edit_form">
     <form action="edit.php" method="post">
         <input type="hidden" name="edit_id" value="<?php echo $memo['id'] ?>">
         <input type="submit" value="編集">
     </form>
</div>

update.php

<?php

// 対象のメモを上書きする
if (isset($_POST["memo_id"])) {

    $body = $_POST["edit_body"];
    $memo_id= $_POST["memo_id"];

    /*sql文*/
    $sql = "UPDATE memo SET body = '$body' WHERE id = '$memo_id'";

    /*bindValue関数でバインドする*/
    $result = $dbh->prepare($sql);
    $result->execute();
}

まず<input type="hidden" name="edit_id" value="<?php echo $memo['id'] ?>">の部分ですが、先ほどと同じく編集対象のメモのIDを取得しています。

そして、取得したIDを<form action="edit.php" method="post">でedit.phpにデータを送信しています。

"UPDATE memo SET body = '$body' WHERE id = '$memo_id'";ではSQLのUPDATE文を用いてbodyを上書きしています。

Git

// 前のcommitからの差分を確認
git diff

git add .

git commit -m "追加"

ここでは加えて、Githubにリモートリポジトリを作成して、そこにpushをしてもらいます。

リモートリポジトリの作成方法とpushの方法は、Gitの教材を参考にしてください。

リモートリポジトリの名称は自由につけてくださってかまいませんが、「kadai-phpsql」などの教材のリポジトリか分かりやすい名称がおすすめです。

09課題

ここまで、表示・削除・編集機能について作成してきました。

ここからは追加機能として2つの実装をしてもらいます。

追加機能は、

  • 検索機能
  • オリジナル機能

この2つです。

オリジナル機能については、なんでも構いません。

自分で考えた機能を1つ実装してみましょう。

検索機能

メモを追加する部分の↧に検索ボックスを追加しましょう。

追加した検索ボックスに検索ワードを入力して「検索」ボタンをクリックすると、検索された文字を含むメモのみが表示されるように改修してください。

また、適宜コミットやリモートリポジトリへのpushをすることで、元に戻したい時に後戻りしやすくなります。

実装しやすくするためにも、Gitの様々な機能を利用してみてください。


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です