(第2回)PHPでSNSを作成してみる

(第2回)PHPでSNSを作成してみる

目次

はじめに
データベースに接続
名前のチェック
投稿内容のチェック
保存処理
今回つまづいたところ
次回予告

はじめに

前回の記事では、環境の設定から画面イメージの作成まで行いました。
今回は、実際に入力した内容がDBに保存される処理を紹介したいと思います。

データベースに接続

まずはデータ送信の受け皿となるDBとの接続処理を書いていきます。

前回作成したファイルはファイル形式がhtmlになっており、
このままでは静的サイト(常に同じ内容が表示されるサイト)になってしまうので、
動的サイト(アクセスや入力した内容等によって異なる表示がされるサイト)にするためにphpに変更します。

※動的サイトを作るには、php以外にもRubyやJavaScriptなども言語として活用されることが多いです。

前回のhtmlファイルの拡張子を.htmlから.phpに変更します。

phpの書き方に入る前に、Apacheのドキュメントルートの説明をしておきます。
ドキュメントルートとは、Webサーバ等が外部公開するファイルが置かれたディレクトリやフォルダです。
こちらの設定は、Apache24→conf→httpd.confで設定できます。

httpd.confを開いて、まず設定するのがSRVROOTです。
こちらの値を基にドキュメントルートが設定されているので、Apacheフォルダの配置場所と照らし合わせながら
確認します。

Define SRVROOT "c:/Apache24"

ServerRoot "${SRVROOT}"

私はCドライブ直下にApacheのフォルダを置いているため、上記のようにしています。

次にドキュメントルートですが、設定ファイル上では下記のように記載されています。

DocumentRoot "${SRVROOT}/htdocs"

先ほど設定した SRVROOT配下のhtdocsというフォルダに入っているファイルが外部公開ファイルとなります。
これで設定は完了となります。

ブラウザ上で表示されるかの確認は、”localhost/ファイル名”をブラウザのURLに入れると表示されます。
ここで表示されない場合に考えられるのは、

  • Apache (もしくは使用しているWebサーバー) が起動していない
  • 他に使用しているwebサーバーがlocalhostで出てくる

Apacheの起動の確認をするのと、他のWebサーバーが優先して、localhostで表示される場合は、
“localhost:ポート番号”で明示すると、指定したWebサーバのファイルがブラウザに表示されます。

設定確認は以上になり、いよいよコードを書いていきます。

phpの書き方ですが、phpコードの先頭に<?php を書きます。

書き終わりは?>で閉じます。

まずはサンプルファイルでphpが動作するのか確認してみます。

phpinfo.phpというファイルを作成し、下記のコードを書きます。

<?php phpinfo(); ?>

このコードで自分のPCに入っているphpの情報を見ることが出来ます。

上記画像のように、phpの各種設定やバージョン等確認することが出来ます。

このとき画像のような表示がされず、phpのソースが画面上に表示された場合は、Apacheのhttpd.confにphpの設定を組み込めていない場合があります。
下記のコードを、httpd.confの一番下に記載します。

LoadModule php7_module "C:/php/php7apache2_4.dll"
AddHandler application/x-httpd-php .php

# configure the path to php.ini
PHPIniDir "C:/php"

また、後程phpのコードで使用するのですが、mysqliというmysqlへのアクセスに使用するライブラリが使用できる状態になっているかも確認しておきます。
確認したところ問題なさそうですので、また後程コードを書いてみて、エラーが出ないか確認してみます。
これでphpが動作することも確認できましたので、掲示板機能の作成に移っていきます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>BBS</title>
</head>
<body>
    <h1>BBS</h1>
    <form action="bbs.php" method="post">
        名前: <input type="text" name="name" /><br>
        内容: <input type="text" name="comment" size="60" /><br>
        <input type="submit" name="submit" value="送信" />
    </form>
</body>
<?php

?>
</html>

まずは、MySQLへの接続処理を書いていきます。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>BBS</title>
    </head>
    <body>
        <h1>BBS</h1>
        <form action="bbs.php" method="post">
            名前: <input type="text" name="name" /><br>
            内容: <input type="text" name="comment" size="60" /><br>
            <input type="submit" name="submit" value="送信" />
        </form>
    </body>
    <?php
          //DBに接続
            $mysql = mysqli_connect('localhost', 'root', 'PASS', 'fp_bbs');
            if (!$mysql) {
                exit('DB接続エラー');
            } 
       mysqli_set_charset($mysql, 'utf8');
            //DBの選択
            $result = mysqli_select_db($mysql, 'fp_bbs');
            if (!$result) {
                exit('DB選択エラー');
            } 
            $errors = array();
    ?>
</html>

まず$で変数を宣言し、その中にMySQLへの接続情報を書き込みます。
接続情報は(ホストまたはIP, ユーザー名, パスワード, DB名)。
接続がエラーの場合は、exit()でプログラムが終了し、画面にエラーメッセージが出るようにしています。

MySQLへの接続が完了すれば、次は使用するDBの選択を書きます。
mysqli_select_db(接続情報, DB名)
これで使用するDBへのアクセスが完了となります。
またここで使用したmysqliが先ほど確認したライブラリ機能になります。
接続の処理も問題なくできたので、phpの設定も問題なさそうです。

名前のチェック

//名前のチェック
$name = null;
//名前がnullでないことをチェック
if(!isset($_POST['name']) || !strlen($_POST['name'])) {
  $errors['name'] = '名前を入力してください';
} else if (strlen($_POST['name']) > 40) {
   $errors['name'] = '名前は40文字以内で入力してください';
} else {
   $name = $_POST['name'];
}

名前のテキストボックスに入力した値が上記のチェックにひっかる場合、エラーの配列にメッセージを入れるようにします。
これは次回記事でエラーメッセージ表示の際に使う想定です。
エラーチェックの対象は、下記の点となります。

  • テキストボックスが空白でない
  • 文字が40文字を超えていないか(テーブル作成時にVARCHAR(40)を設定しているため)

投稿内容のチェック

 //コメントのチェック
$comment = null;
//名前がnullでないことをチェック
if(!isset($_POST['comment']) || !strlen($_POST['comment'])) {
 $errors['comment'] = 'コメントを入力してください';
} else if (strlen($_POST['comment']) > 200) {
  $errors['comment'] = 'コメントは200文字以内で入力してください';
} else {
  $comment = $_POST['comment'];
}

内容のチェックも名前のチェックとほぼ同じですが、テキストボックスの入力値に対して、チェックを入れます。
チェック箇所は下記になります。

  • テキストボックスが空白でない
  • 文字が200文字を超えていないか(テーブル作成時にVARCHAR(200)を設定しているため)

保存処理

上記で、テキストボックスの値によって、エラーの判定をしてきました。
ここからDBへの保存処理に移っていきますが、エラーがある状態で保存処理をしてしまうと、
プログラム上不具合の元となってしまうので、保存の条件として、エラーが一つもないことを条件とします。

//エラーがなければ保存
if (count($errors) === 0) {
 //保存するためのSQL分を作成
  $sql ='INSERT INTO post(Pname, comment, created_day)VALUES("'
   .mysqli_real_escape_string($mysql, $name).'","
  .mysqli_real_escape_string($mysql, $comment).'",\''
    .date('Y-m-d H:i:s').'\')';
                  
 //保存する
 mysqli_query($mysql, $sql);
}

$errorsにはエラーになった数だけ値が入ってきますので、エラーがない時だけ、保存処理が実行されます。
$sqlで値保存のために流すINSERT文を定義しておきます。
mysqli_queryでSQLを実行します。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>BBS</title>
    </head>
    <body>
        <h1>BBS</h1>
        <form action="bbs.php" method="post">
            名前: <input type="text" name="name" /><br>
            内容: <input type="text" name="comment" size="60" /><br>
            <input type="submit" name="submit" value="送信" />
        </form>
        <?php
            //DBに接続
            $mysql = mysqli_connect('localhost', 'root', 'AoFLS030cztQMGzd6i3e', 'fp_bbs');
            mysqli_set_charset($mysql, 'utf8');
            if (!$mysql) {
                exit('DB接続エラー');
            } 
            //DBの選択
            $result = mysqli_select_db($mysql, 'fp_bbs');
            if (!$result) {
                exit('DB選択エラー');
            } 
            $errors = array();

            //POSTなら保存処理
            if($_SERVER['REQUEST_METHOD'] === 'POST') {
                //名前のチェック
                $name = null;
                //名前がnullでないことをチェック
                if(!isset($_POST['name']) || !strlen($_POST['name'])) {
                    $errors['name'] = '名前を入力してください';
                } else if (strlen($_POST['name']) > 40) {
                    $errors['name'] = '名前は40文字以内で入力してください';
                } else {
                    $name = $_POST['name'];
                }
                 //コメントのチェック
                 $comment = null;
                 //名前がnullでないことをチェック
                 if(!isset($_POST['comment']) || !strlen($_POST['comment'])) {
                     $errors['comment'] = 'コメントを入力してください';
                 } else if (strlen($_POST['comment']) > 200) {
                     $errors['comment'] = 'コメントは200文字以内で入力してください';
                 } else {
                     $comment = $_POST['comment'];
                 }
                //エラーがなければ保存
                if (count($errors) === 0) {
                    //保存するためのSQL分を作成
                    $sql ='INSERT INTO post(Pname, comment, created_day)VALUES("'
                        .mysqli_real_escape_string($mysql, $name).'","'
                        .mysqli_real_escape_string($mysql, $comment).'",\''
                        .date('Y-m-d H:i:s').'\')';

                    //保存する
                    mysqli_query($mysql, $sql);
                }
            } 
        ?>
    </body>
</html>

全てのコードは上記になります。
今回追加したコードの前に、通信のメソッドが指定のものでなければ、動作しないようにコードを追加しています。

名前とひとことのメッセージを入れてみました。この内容で送信ボタンを押下したら、値がDBに保存されているかを確認します。
確認方法は、コマンドプロンプトで確認する方法とGUIツール(MySQLならWorkBenchなど)の2種類ありますが、今回は1件しか保存データがないので、コマンドプロンプトで確認します。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| fp_bbs             |
| information_schema |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
| world              |
+--------------------+
7 rows in set (0.00 sec)

mysql> use fp_bbs;
Database changed

mysql> show tables;
+------------------+
| Tables_in_fp_bbs |
+------------------+
| post             |
+------------------+
1 row in set (0.00 sec)
mysql> show fields from post;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| Pname       | varchar(40)  | YES  |     | NULL    |                |
| comment     | varchar(200) | YES  |     | NULL    |                |
| created_day | datetime     | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> select * from post;
+----+--------+--------------+---------------------+
| id | Pname  | comment      | created_day         |
+----+--------+--------------+---------------------+
| 1  | Yusuke | はじめまして  | 2019-09-06 13:55:28 |
+----+--------+--------------+---------------------+
1 row in set (0.00 sec)

DBの選択から、テーブルからデータの取り出しまでを、コマンドプロンプトで実行してみました。
入力した内容が、想定通りDBに保存されていることがわかります。
これで投稿した内容がDBに保存される処理は完成となります。

今回画面と処理を同じファイルに書き込んでおり、処理ごとに分割したほうが可読性も上がるため、下記のように役割毎にファイルを分割しました。

入力画面:bbs.php

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>BBS</title>
    </head>
    <body>
        <h1>BBS</h1>
        <form action="connectbbs.php" method="post">
            名前: <input type="text" name="name" /><br>
            内容: <input type="text" name="comment" size="60" /><br>
            <input type="submit" name="submit" value="送信" />
        </form>
    </body>
</html>

DBとの接続処理部分:connectbbs.php

 <?php
    //DBに接続
    $mysql = mysqli_connect('localhost', 'root', 'AoFLS030cztQMGzd6i3e', 'fp_bbs');
    if (!$mysql) {
        exit('DB接続エラー');
    } 
    mysqli_set_charset($mysql, 'utf8');
    //DBの選択
    $result = mysqli_select_db($mysql, 'fp_bbs');
    if (!$result) {
        exit('DB選択エラー');
    } 
    $errors = array();

    //POSTなら保存処理
    if($_SERVER['REQUEST_METHOD'] === 'POST') {
        //名前のチェック
        $name = null;
        //名前がnull出ないことをチェック
        if(!isset($_POST['name']) || !strlen($_POST['name'])) {
            $errors['name'] = '名前を入力してください';
        } else if (strlen($_POST['name']) > 40) {
            $errors['name'] = '名前は40文字以内で入力してください';
        } else {
            $name = $_POST['name'];
        }
            //コメントのチェック
            $comment = null;
            //名前がnullでないことをチェック
            if(!isset($_POST['comment']) || !strlen($_POST['comment'])) {
                $errors['comment'] = 'コメントを入力してください';
            } else if (strlen($_POST['comment']) > 200) {
                $errors['comment'] = 'コメントは200文字以内で入力してください';
            } else {
                $comment = $_POST['comment'];
            }
        //エラーがなければ保存
        if (count($errors) === 0) {
            //保存するためのSQL文を作成
            $sql ='INSERT INTO post(Pname, comment, created_day)VALUES("'
                .mysqli_real_escape_string($mysql, $name).'","'
                .mysqli_real_escape_string($mysql, $comment).'",\''
                .date('Y-m-d H:i:s').'\')';

            //保存する
            mysqli_query($mysql, $sql);
        }else{
            var_dump($errors);
        }
    }
    include 'bbs.php';
?>

php終了タグの前に include ‘bbs.php’ を入力することで、画面側へと遷移させています。
エラー表示は、次回追加するものの、エラー時の処理が機能しているかを確認するため、
var_dumpの処理を入れています。引数を$errorsにすることで、エラーメッセージをすべて表示することが出来ます。
下記の画像は、名前と内容を未入力の状態で送信した際に、表示されたエラー内容になります。

今回つまづいたところ

今回下記の点で、解決に少し時間がかかりました。

  • mysqli関数が未定義のエラー
  • PHPからMySQLへの接続ができない

まず1点目に関しては、設定ファイルであるphp.iniのmysqliの拡張機能がコメント化されている場合があるので、その場合は、コメントアウトを外して機能を有効化させます。

;extension=mysqli → extension=mysqli

デフォルトで有効になっているものだと思い、この点に気づくのに少し時間がかかってしまいました。
もしmysqli関数が未定義ですというエラーが出た場合は、この箇所を修正すると解決すると思われます。

2点目に関しては、PHPでMySQLに接続ができない時に確認した方が良い点です。
そもそもDB接続の処理から何も処理が流れず、エラーも出ないなどの場合はこの点が、あてはまるかもしれません。

解決法としては、コマンドプロンプトにてプラグインの認証方法を変更する作業を行います。

mysql> select User, Plugin from mysql.user;
+------------------+-----------------------+
| User             | Plugin                |
+------------------+-----------------------+
| sample_user      | mysql_native_password |
| mysql.infoschema | mysql_native_password |
| mysql.session    | mysql_native_password |
| mysql.sys        | mysql_native_password |
| root             | caching_sha2_password |
+------------------+-----------------------+
5 rows in set (0.01 sec)

こちらで使用するユーザーのパスワードが「mysql_native_password」になっていない場合は変更しないと、接続エラーになります(今回はrootユーザー)。

ALTER USER 変更したいユーザー名@localhost IDENTIFIED mysql_native_password BY '設定しているパスワード';

こちらで設定変更ができ、接続が可能となるはずです。

コード以外で詰まったところがあったので、紹介しました。
コードの動作以外で詰まるところがあった場合は、こちらも参考にしてみてください。

次回予告

次回は、投稿した内容がリアルタイムに表示されていく機能を作るのと、エラーが出た際に、該当するエラーメッセージを表示する機能を作成し、一旦簡易掲示板機能は完成としたいと思います。