【PHP】PHPでメモアプリを作成【1】

# はじめに
PHPを勉強し始めて1か月ほどですが簡単なメモアプリの作成を行ったので、備忘録として記事を投稿していこうと思いました。(最低限の実装しか行っていないため、見た目などにはこだわっていません。また、記録のため、一つ一つのコードについて詳しく記述していくので長い記事になります。)

このメモアプリを通してSQLの操作、PHPからSQLへの連携などCRUDの概念について学べました。

本記事ではメモを作成して、それを一覧で表示させるところまでを記事にします。
## メモの記述

メモを記述するフォームを作成するinput.htmlファイルに以下のように記述。

```html:input.html
<!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>メモの入力</title>
</head>
<body>
  <form action="input_do.php" method="post">
    <textarea name="memo" cols="30" rows="10" placeholder="メモを入力してください"></textarea><br>
    <button type="submit">登録する</button>
  </form>
</body>
</html>
```

formタグのaction属性にphpファイルを指定するとそのphpファイルにformに入力した値を渡します。(今回はinput_do.php)また、methodはPOSTを指定。
method属性にはGETとPOSTの二つがあります。違いについては以下のようになります。


|GET|POST|
|:---:|:---:|
|送信内容がURLとして渡される|本文（本体）として送信される|

簡単に言うとformで送信した内容がURLに表示されるかされないかということです。
今回は危険性やURLが長くなることを防ぐためにPOSTとしました。

## DBの作成

データベースをMySQLで作成します。(mydbというフォルダにmemosというテーブルを作成)
カラムとしては3つで。通し番号のidと、メモの内容を記録するmemoと作成日時を記録するcreatedである。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964925/388423fa-f54e-3617-8dc7-2d0fb7b1985e.png)

## DBとPHPの接続

DBとPHPを接続するためだけのPHPファイルを作成します。
今後複数のファイルに渡ってメモアプリを作成する中で全ファイルにDBとの接続の記述を書くのは面倒であり、保守性が低いため、DB接続用のファイルを用意します。

```php:dbconnect.php
<?php
$db = new mysqli("localhost:9000", "root", "root", "mydb");
?>
```

$dbという変数にmysqliというオブジェクトのインスタンスを生成します。
引数は順に、localhost:ポート番号、ユーザ名、パスワード、データベース名となります。

## メモの一覧の表示

メモの一覧の表示をするphpファイルを作成します。
このページで搭載したい機能としては
* 登録されているメモの内容と日時を表示
* メモの作成ボタンの設置(input.htmlへの遷移)
* 5件ずつのメモでページを変更


```php:index.php
<?php
require('dbconnect.php');

//最大ページ数を求める
$counts = $db->query('select count(*) as cnt from memos');
$count = $counts->fetch_assoc();
$max_page = floor(($count['cnt']-1)/5 + 1);

$stmt = $db->prepare('select * from memos order by id desc limit ?, 5');
if (!$stmt){
  die($db->error);
}

$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
$page = ($page ?: 1);
$start = ($page-1)*5;
$stmt->bind_param('i', $start);
$result = $stmt->execute();
?>

<!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>めもちょー</title>
</head>
<body>
  <h1>メモ帳</h1>

<p>→<a href="input.html">新しいメモ</a></p>


<?php if (!$result): ?>
  <p>表示するメモがありません</p>
<?php endif; ?>
  <?php $stmt->bind_result($id, $memo, $created); ?>
  <?php  while($stmt->fetch()): ?>
    <div>
      <h2><a href="memo.php?id=<?php echo $id; ?>"><?php echo htmlspecialchars(mb_substr($memo,0,50)); ?></a></h2>
      <time><?php echo htmlspecialchars($created) ?></time>
    </div>
    <hr>
  <?php endwhile; ?>
  <p>
    <?php if($page > 1): ?>
      <a href="?page=<?php echo $page-1; ?>"><?php echo $page-1?>ページ目</a> | 
    <?php endif; ?>
    <?php if($page < $max_page): ?>
      <a href="?page=<?php echo $page+1; ?>"><?php echo $page+1?>ページ目</a>
    <?php endif; ?>
  </p>

</body>
</html>
```


上記コードから、搭載したい機能に関係するところを抜粋してまとめていきます。
「メモの作成ボタンの設置(input.htmlへの遷移)」について
```html
<p>→<a href="input.html">新しいメモ</a></p>
```
aタグのhref属性にinput.htmlを設定することで新しいメモを登録することができます。





「登録されているメモの内容と日時を表示」について

```php
<?php
require('dbconnect.php');
$stmt = $db->prepare('select * from memos order by id desc limit ?, 5');
if (!$stmt){
  die($db->error);
}
$stmt->bind_param('i', $start);
$result = $stmt->execute();
?>
<?php if (!$result): ?>
  <p>表示するメモがありません</p>
<?php endif; ?>
  <?php $stmt->bind_result($id, $memo, $created); ?>
  <?php  while($stmt->fetch()): ?>
    <div>
      <h2><a href="memo.php?id=<?php echo $id; ?>"><?php echo htmlspecialchars(mb_substr($memo,0,50)); ?></a></h2>
      <time><?php echo htmlspecialchars($created) ?></time>
    </div>
    <hr>
  <?php endwhile; ?>
```

requireでファイル名を指定することで、そのファイルに記述してあることが利用できます。
今回はdbconnect.phpをrequireしているため、この時点でDBへの接続が完了しています。

prepareメソッドによって引数に指定したSQL文をデータベースに対して発行してくれます。
上記SQL文は「memosに格納されているデータを降順で任意の数から5個だけ取り出す」という意味になります。もしデータベースサーバが文を準備できなかった場合prepareメソッドはFALSEを返り値として渡すためその際の処理をif文でどのようなerrorが発生したかを記述しています。
bind_pramメソッドによってSQL ステートメント中で、疑問符プレースホルダに値を渡すことができます。

またexecuteメソッドによってSQL文を実行します。これもまた、正常に実行できなかった場合FALSEが返されるため。メモがない旨を条件分岐で表示します。
ここで、bind_resultメソッドで取り出されたデータを$id,$memo,$createdという変数に格納します。
SQL文がSELECT文などのように結果がある場合はfetchでひとつづつデータを取り出す必要があります。そのためwhile文でfetchでデータを取り出せる間(存在するデータの数だけ)ループ処理を行います。

h2タグでメモの内容、timeタグでメモの日時を表示させています。bind_resultによってメモの内容は、変数memoに、メモの日時はcreatedに格納されているためこれをechoで呼び出せば表示することができます。
しかし、HTMLの中では特殊な意味を持つため直接書くことが出来ない < や > といった記号等を正しくメモの内容として表示させるためにhtmlspecialchars()を使用するとともに、非常に長い文字列をメモ内容としている場合に備えて、mb_substr()を用いて50文字を最大文字数としています。

まだ搭載していない機能もありますがメモ一覧の画面は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964925/e2cd5240-dbb6-4f8b-b9fc-da599c991d14.png)

## さいごに
それでは本記事ではここまでにしたいと思います。
* 次の記事では5件ずつでページを変更する方法
* メモの編集画面
* メモの削除
* メモの詳細画面

これらを記事にしたいと思います。
自身の頭の中の整理のために書いているため読みづらかったり分かりづらい点たくさんあると思いますが、参考になればうれしいです。