This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

PHPとMySQLを組み合わせる

Last updated at Posted at 2024-02-26

phpからMySQLを操作

データベースへの接続には各種情報が必要

$mysqli = new mysqli("localhost", "user", "password", "database");
  • localhost
  • user
  • password
  • database

240225_02.png
240225_01.png

  • ↑↑↑↑MAMP画面の「Open WebStart page」押すとブラウザ開く
  • そのページの下部に情報が表示されている

240225_03.png

  • ↑↑↑↑接続するデータベース名は実際に作成したデータベースの名前

sample01.php

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    echo 'DBに接続しました';
?>
</body>

240225_04.png

  • http://localhost:8888/phpsql/sample01.php
  • 以上でひとまず接続はできる

240225_05.png

  • localhostでうまくいかない場合、IPアドレス指定でうまくいく場合がある。
  • ただwindowsの場合MAMPに記載がなかったが…

SQLの発行

  • phpからSQLを実行する方法
  • 一番シンプルなものがqueryメソッド

テーブルの作成

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('create table test(id INT)');
    echo 'テーブルを作成しました';
?>
</body>

240225_06.png

  • $db->query('create table test(id INT)');を追記
  • ブラウザで表示(接続)確認

240225_07.png

  • データベース確認すると「test」というテーブルが追加されている
  • idというカラムが「INT」でできている

テーブルの削除

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('drop table test');
    // $db->query('create table test(id INT)');
    echo 'テーブルを削除しました';
?>
</body>

240225_08.png
240225_09.png

  • $db->query('drop table test');→dropは削除となる
  • データベース見ると「test」のテーブルが削除されている

応用

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('drop table if exists test');
    $db->query('create table test(id INT)');
    echo 'テーブルを削除して、作成しました';
?>
</body>

240225_10.png
240225_11.png

  • testというテーブルがあれば、削除
  • testというテーブルを作成

という順序で記述されているのでデータベースにはtestテーブルが作成された状態

SQLのエラー表示に関して

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('dr table if exists test');
    $db->query('create table test(id INT)');
    echo 'テーブルを削除して、作成しました';
?>
</body>

240225_10.png

  • 「drop」がうまく記述されていないが、ページの表示にはエラーが出ない
  • phpのエラーは感知できるが、SQL文としてのエラーはphp側で通常チェックすることはできないので。
<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('drop table if exists test');
    $success = $db->query('cr table test(id INT)');
    if($success){
        echo 'テーブルを削除して、作成しました';
    }else{
        echo 'SQLが正常に動作しませんでした';
        echo $db->error;
    }
?>
</body>

240225_12.png

  • queryのメソッドは失敗すると「false」が返ってくる
  • 「success」の変数にqueryのメソッドを格納、true・false判定ができるようにしてif文に。
  • 「create」が正しく記述できていない形で、上記のように設定
  • 正常に動作しませんでした、という表示とともにエラー文も表示されている(エラー位置など)

正しく書くと…

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('drop table if exists test');
    $success = $db->query('create table test(id INT)');
    if($success){
        echo 'テーブルを削除して、作成しました';
    }else{
        echo 'SQLが正常に動作しませんでした';
        echo $db->error;
    }
?>
</body>

240225_13.png

240225_14.png

  • ちゃんと記述するとtestテーブル追加されている

  • queryメソッドは変数などと組み合わせると危険なので、あくまで例としてとらえておく

select構文の実行

結論

  • queryとfetch_assocを組み合わせるとページに表示する形を作ることができる

手順

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    var_dump($records);
?>
</body>

object(mysqli_result)#2 (5) { ["current_field"]=> int(0) ["field_count"]=> int(7) ["lengths"]=> NULL ["num_rows"]=> int(5) ["type"]=> int(0) }

  • select文を変数に格納してvar_dumpすると、レコードがとれていることがわかる

実際にテーブルの中身を表示させてみる

商品を表示
<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        while($record = $records->fetch_assoc())
        echo $record['item_name'] . '<br>';
    }
?>
</body>

240225_15.png

  • $recordsに格納したSQL文がエラーなければtrueなので、if文の条件にする
  • fetch_assoc()はデータを1件取り出す、という処理
    fetchがデータの取り出し、assocが連想配列、みたいな意味
  • 連想配列の形で$recordsの配列の中に入っていく
  • そちらをechoで表示している
  • ※「item_name」はデータベースの内容に連動する(変更すると別のものを表示できる)

priceを表示

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        while($record = $records->fetch_assoc())
        echo $record['price'] . '<br>';
    }
?>
</body>

240225_16.png

  • echo $record['price'] . '<br>';
  • ここを「item_name」から「price」に変えるだけでpriceの値を表示できる

複数表示もできる

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        while($record = $records->fetch_assoc())
        echo $record['price'] . ',' .  $record['item_name'] . '<br>';
    }
?>
</body>

240225_17.png

  • priceとitem_nameどちらも表示
補足(while文)
  • while文は指定した条件式が真(true)の間、繰り返し実行
  • データを全部取り出し終わるとfalseが返るので処理が終わる
while (条件式){
  実行する処理1;
  実行する処理2;
}
補足(foreachでも書ける)
<body>
    <?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        while($record = $records->fetch_assoc()){
            echo $record['item_name'] . '<br>';
        }
    }
    ?>
</body>

↓↓↓↓↓↓↓↓↓このように書き替え可能

<body>
    <?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        foreach($records as $record) {
            echo $record['item_name'] . '<br>';
        }
    }
    ?>
</body>
  • 複数表示も同様に可
<body>
    <?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select * from my_items');
    if($records){
        foreach($records as $record) {
            echo $record['price'] . ',' .  $record['item_name'] . '<br>';
        }
    }
    ?>
</body>

スクリーンショット 2024-03-05 220817.png

countの結果を表示

  • select count(*) from my_items
  • こちら↑をデータベース上で実行するとこのように表示される
    240225_19.png

php上で実行したい

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select count(*) from my_items');
    if($records){
        while($record = $records->fetch_assoc())
        echo $record['count(*)'] . '<br>';
    }else{
        echo $db->error;
    }
?>
</body>

240225_18.png

  • 上記のように表示できる
  • データベース上で行っていた「as」を使ってわかりやすく管理したい
asの表記【count(*) ではなくcntとして表示】

select count(*) as cnt from my_items
image.png

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $records = $db->query('select count(*) as cnt from my_items');
    if($records){
        while($record = $records->fetch_assoc())
        echo $record['cnt'] . '<br>';
    }else{
        echo $db->error;
    }
?>
</body>

240225_21.png

  • select文にasの記述を追加
  • while文の表記もcntに変更できる
  • ページの表示は変わらず
  • 今回の変更はページ表示上は特にメリットないが、php内のコードとしてはcntにすることで管理がしやすくなっている

phpでデータベースにデータを挿入

  • まずデータベースに新しくテーブルを追加(memos)

240225_22.png
240225_23.png

memoにデータを挿入

insert into memos (memo) values ('メモです');
240225_24.png

作成したメモのテーブルにphpからデータを入れていく

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $db->query('insert into memos (memo) values("PHPからのメモです")');
    echo 'データを挿入しました';
?>
</body>

240225_25.png
240225_26.png

  • insert into memos (memo) values("PHPからのメモです")
  • こちらの記述でinsertが実行される
  • ※phpのクォーテーションとSQLのクォーテーションが混同しないために「'」「"」シングルダブルを使って記述している
  • データベース確認するとphp側の追加が反映されている

エラーの判定も置きたい場合

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $ret = $db->query('insert into memos (memo) values("PHPからのメモです")');
    if($ret){
        echo 'データを挿入しました';
    }else{
        echo $db->error;
    }
?>
</body>
  • insertをqueryメソッドで書くことはほぼ無い!
  • あくまで例として書いている状態

phpでSQLを組み立てる

  • prepareについて
<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $message = 'フォームから入力した値';
    $stmt = $db->prepare('insert into memos(memo) values(?)');
    $stmt->bind_param('s', $message);
    $ret = $stmt->execute();
    if($ret){
        echo 'データを挿入しました';
    }else{
        echo $db->error;
    }
?>
</body>

240225_27.png
240225_28.png

  • 以上でデータの挿入が行える
エラー表示位置などを修正すると下記
<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $message = 'フォームから入力した値';
    $stmt = $db->prepare('insert into memos(memo) values(?)');
    if(!$stmt){
        die($db->error);
    }
    $stmt->bind_param('s', $message);
    $ret = $stmt->execute();
    if($ret){
        echo 'データを挿入しました';
    }else{
        echo $db->error;
    }
?>
</body>
  • $message = 'フォームから入力した値';
    →挿入するメッセージを設定

  • $stmt = $db->prepare('insert into memos(memo) values(?)');

    • prepareを使ってSQLを組み立てる
    • 「query」を用いると危険なのでprepareを用いる
    • prepareは「?」をSQLに入れることができる
    • 「?」の内容は後の記述で「bid_param」を使って指定することができる
    • インサート文に関してはテーブル名(カラム名)で省略せずに記述したパターンの書き方をしている
  • if(!$stmt){ die($db->error); }
    →SQL文が正しければこの判定は無視される
    「 - die」はメッセージを表示させてそのままプログラムを終了させる、という処理

  • $stmt->bind_param('s', $message);
    →「's'」stringという指定。文字列。
    ※数字は「'i'」。他にもいくつか種類あるが基本sかi。

  • $ret = $stmt->execute();
    →「execute();」はSQLを実行する、という意味

  • ややこしいけど覚えてしまえば大丈夫

複数追加もできる

240225_29.png

  • カラム名を複数に、valuesの「?」も複数にする
  • bind_paramの型指定、変数指定も対応した形に変更する

疑問

$stmt = $db->prepare('insert into memos(memo) values(?)');
$ret = $stmt->execute();
ここは実行ではなく格納にしかなっていないのでは?

結論

  • オブジェクトのメソッドは代入自体が実行となりそう

以下は検証

<body>
<?php
    $db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
    $message = 'フォームから入力の値02';
    $stmt = $db->prepare('insert into memos(memo) values(?)');
    if(!$stmt){
        die($db->error);
    }
    $stmt->bind_param('s', $message);
    $stmt->execute();
?>
</body>
  • このように書き換えても同じように実行はされた。
  • $ret = $stmt->execute();$stmt->execute();

オブジェクトの項目にさかのぼって検証

$parent = new ParentClass();
$child = new ChildClass();

$parent->kansuu01('私は');
$child->kansuu01('私は');

$parent->kansuu02();
$child->kansuu02();

240225_30.png

  • オブジェクトに設定されたメソッドを実行したファイル
変更してみる
$parent = new ParentClass();
$child = new ChildClass();

$test01 = $parent->kansuu01('私は');
$test02 = $child->kansuu01('私は');

$test03 = $parent->kansuu02();
$test04 = $child->kansuu02();

240225_30.png

  • メソッドをそれぞれ変数に格納する形にしてみたところ、まったく同じようにページが実行された
  • オブジェクトの場合は格納自体が実行となると考えてよさそう

フォームと連携したDB操作

input.html

<body>
    <form action="input_do.php" method="post">
        <textarea name="memo" cols="50" rows="10" placeholder="メモを入力してください"></textarea><br>
        <button type="submit">登録する</button>
    </form>
</body>

240225_31.png

  • input_do.phpと連携した簡単なフォームを作成
  • テキストエリアに文字を入力して登録するボタンを押すとデータベースにデータを追加する処理

input_do.php

<?php
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_SPECIAL_CHARS);
$db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
$stmt = $db->prepare('insert into memos(memo) values(?)');
if(!$stmt){
    die($db->error);
}
$stmt->bind_param('s', $memo);
$ret = $stmt->execute();
if($ret){
    echo '登録されました';
}else{
    echo $db->error;
}
?>
  • 基本的には前回までの内容と同じ。
  • 接続方法、内容も同じものになっている
  • $memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_SPECIAL_CHARS);
    →基本的には$memo = $_POST['memo'];と書いても接続はできる
    しかし危険なプログラムを記入されないような対策のためにfilter_inputで記述している
    ※書き方はルール、決まった形があるので、その都度調べるなりしたらよさそう
  • filter_input内の「memo」はinput.htmlのname=memoと対応する

phpでselect構文を表示

240302_01.png

  • このようにブラウザにメモ一覧を表示させたい
<?php
$db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
$memos = $db->query('select * from memos order by id desc');
if(!$memos){
    die($db->error);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>メモ帳</h1>
    <?php while($memo = $memos->fetch_assoc()): ?>
    <div>
        <h2><a href="#"><?php echo htmlspecialchars($memo['memo']); ?></a></h2>
        <time><?php echo htmlspecialchars($memo['created']); ?></time>
    </div>
    <hr>
    <?php endwhile; ?>
</body>
</html>
  • 以上のように記述する
<?php while($memo = $memos->fetch_assoc()): ?>
    <div>
        <h2><a href="#"><?php echo htmlspecialchars($memo['memo']); ?></a></h2>
        <time><?php echo htmlspecialchars($memo['created']); ?></time>
    </div>
    <hr>
    <?php endwhile; ?>
  • $memo['memo']メモのカラムと$memo['created']のカラムを連想配列で取り出す
  • echoで表示する
  • htmlspecialchars「htmlspecialchars」の記述を付けるとXSS攻撃を防ぐことができる

DB接続の共通パーツ化

  • これまでの手順だと、index.php、index_do.phpのどちらにもDB接続の記述が書かれていた
  • 共通箇所はまとめて各ファイルで参照するのがよい

dbconnect.php

<?php
$db = new mysqli('localhost:8889', 'root', 'root', 'db_test');
?>
  • dbconnect.phpを作成して、これまで各ファイルに記述していた接続情報を移植

index.php

<?php

require('dbconnect.php');

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

index_do.php

<?php
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_SPECIAL_CHARS);

require('dbconnect.php');



  • index.php、index_do.phpでdb接続情報を削除
  • require('dbconnect.php');→それぞれ呼び出し記述を追加する

見出しを一部だけ表示させる

240302_03.png

  • 文字数が多いテキストを登録すると表示画面が冗長になる
<h2><a href="#"><?php echo htmlspecialchars(mb_substr($memo['memo'], 0, 50)); ?></a></h2>
  • $memo['memo'](mb_substr($memo['memo'], 0, 50)
  • 「mb_substr」→文字数の表示を制限できる
  • 「0」→開始位置、「50」→文字数制限

240302_02.png

  • 50文字制限できる

メモ詳細画面を作成

240302_04.png

<?php
    require('dbconnect.php');
    $stmt = $db->prepare('select * from memos where id=?');
    if(!$stmt){
        die($db->error);
    }
    $id = 8;
    $stmt->bind_param('i', $id);
    $stmt->execute();

    $stmt->bind_result($id, $memo, $created);
    $stmt->fetch();
    ?>

    <div><?php echo htmlspecialchars($memo); ?></div>
  • メモのデータを指定して表示させるファイルを作成(memo.php)

  • $id = 8;の値を変更すると対象のメモが表示される

  • $stmt->bind_param('i', 8);→本来このように直接値を指定したいがbind_paramの特性で直接値を指定できない

  • $id = 8; $stmt->bind_param('i', $id);よって、いったん変数に格納する形で記述している

  • queryを使った場合のデータの取り出し方はfetch_assocを使用していた

  • ↑↑↑prepareを使った場合の値の取り出し方はbind_resultを用いる

  • bind_result($id, $memo, $created);変数をの値を指定していく
    ※データベースから渡ってくる各値をどの変数に格納するかを指定している(渡ってくるのは同じ名前id、memo、createdのカラム)

  • fecthはfecth_assocと同じようなもの、データベースからデータを取り出す

詳細ページをURLごとに呼び出す

240302_05.png
240302_06.png

  • http://localhost:8888/phpsql/memo/memo.php?id=2
  • http://localhost:8888/phpsql/memo/memo.php?id=8
  • URL末尾が変わると表示するメモを変更した状態になる
<body>
    <?php
    require('dbconnect.php');
    $stmt = $db->prepare('select * from memos where id=?');
    if(!$stmt){
        die($db->error);
    }
    $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
    if (!$id) { // ここから追加
        echo '表示するメモを指定してください';
        exit();
    } 
    $stmt->bind_param('i', $id);
    $stmt->execute();

    $stmt->bind_result($id, $memo, $created);
    $result = $stmt->fetch();
    if (!$result) { // ここから追加
        echo '指定されたメモは見つかりませんでした';
        exit();
    }
    ?>

    <div><?php echo htmlspecialchars($memo); ?></div>
</body>

変更箇所

  • $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
  • idをこのように変更する
 if (!$id) { // ここから追加
        echo '表示するメモを指定してください';
        exit();
    } 
  • ここはid記入漏れの確認
$stmt->bind_result($id, $memo, $created);
$result = $stmt->fetch();
if (!$result) { // ここから追加
  echo '指定されたメモは見つかりませんでした';
  exit();
}
  • ここは指定されたidのデータが無い場合の確認

メモ一覧からメモ詳細へのリンク

240302_07.png

  • メモ一覧から各メモ詳細にリンクをつけたい

index.php

<body>
    <h1>メモ帳</h1>
    <p><a href="input.html">新しいメモ</a>
    <?php while($memo = $memos->fetch_assoc()): ?>
    <div>
        <h2><a href="memo.php?id=<?php echo $memo['id']; ?>"><?php echo htmlspecialchars(mb_substr($memo['memo'], 0, 50)); ?></a></h2>
        <time><?php echo htmlspecialchars($memo['created']); ?></time>
    </div>
    <hr>
    <?php endwhile; ?>
</body>
  • <h2><a href="#"><?php echo htmlspecialchars(mb_substr($memo['memo'], 0, 50)); ?></a></h2>
    ↑↑↑こちらを変更する
  • <a href="memo.php?id=<?php echo $memo['id']; ?>"><?php echo htmlspecialchars(mb_substr($memo['memo'], 0, 50)); ?></a>
  • aタグの中身を<a href="memo.php?id=<?php echo $memo['id']; ?>">に変更
  • memo.php?=の末尾を各idで取得できるような書き方で設定($memo['id']で取得できるということ)

一覧のページネーションを作成

240302_08.png
240302_09.png

  • このようにURL末尾にidをつけることによって5件ずつメモを表示させたい

ひとまずすべての変更は下記(index.php)

<?php

require('dbconnect.php');

$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);
$start = ($page - 1) * 5;
$stmt->bind_param('i', $start);
$stmt->execute();
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>メモ帳</h1>
    <p><a href="input.html">新しいメモ</a>
    <?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; ?>
</body>
</html>
  • $stmt = $db->prepare('select * from memos order by id desc limit ?, 5');
    ↑↑↑select文を修正。「limit」使用して、5件までの表示にしている。
    対象のページidを?に当てはめて変更が効くように設定(?は開始位置)
    下部に処理実行可否のif文も記述
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
$start = ($page - 1) * 5;
$stmt->bind_param('i', $start);
$stmt->execute();
  • $page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
    ↑↑↑filter_input→POST や GET などの変数をフィルタリングする
    filter_input内の「page」はURLに表示されるパラメータの「page」
    FILTER_SANITIZE_NUMBER_INT→数字しか受け取れないようにする処理

  • $start = ($page - 1) * 5;
    ↑↑↑5件ずつ表示なので、5、10、15と件数を設定するための記述
    1→0、2→5、3→10、4→15というように。

<?php $stmt->bind_result($id, $memo, $created); ?>
<?php while($stmt->fetch()): ?>
  • ここでバインドしている。
    bind_resultにすることによってfetch_assoc()からfetch()に変更する
    これによって$id$memo$createdにそれぞれデータベースからの値が入る
    各値も直接記述できる
    • $memo['id']$id
    • $memo['memo']$memo
    • $memo['created']$created

URLパラメータの省略

240302_10.png

  • URL末尾のパラメータを省くと、何も表示されない
  • パラメータない場合は最初のページを表示させたい
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
if(!$page){
    $page = 1;
}
  • pageのidが入っていなければ強制的に1を入れる、というだけの処理

ページネーションのリンク作成

240302_11.png

  • ページ下部にページネーション付けたい
  • 1ページは2ページ目のみ表示
  • 最終ページは前ページのみ表示にしたい
<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>
  • 表示はこのような形(if文で表示切替)
  • 最初のページは単純に1以下なら、という条件
  • 最終ページは合計ページ数を計算したうえで条件に組み込む
/* 最大ページ数を求める */
$counts = $db->query('select count(*) as cnt from memos');
$count = $counts->fetch_assoc();
$max_page = floor(($count['cnt']+1)/5+1);
  • なかなかややこしい計算だいぶむずかしい
    240302_12.png

編集画面を作る

update.phpを作成

<?php
require('dbconnect.php');
$stmt = $db->prepare('select * from memos where id=?');
if(!$stmt){
    die($db->error);
}
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
$stmt->bind_param('i', $id);
$stmt->execute();

$stmt->bind_result($id, $memo, $created);
$result = $stmt->fetch();
if(!$result){
    die('メモの指定が正しくありません');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>メモの編集</title>
</head>
<body>
    <form action="update_do.php" method="post">
        <input type="hidden" name="id" value="<?php echo $id; ?>">
        <textarea name="memo" cols="50" rows="10" placeholder="メモを入力してください"><?php echo htmlspecialchars($memo); ?></textarea><br>
        <button type="submit">編集する</button>
    </form>
</body>
</html>
$stmt = $db->prepare('select * from memos where id=?');
if(!$stmt){
    die($db->error);
}
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
$stmt->bind_param('i', $id);
$stmt->execute();

$stmt->bind_result($id, $memo, $created);
$result = $stmt->fetch();
if(!$result){
    die('メモの指定が正しくありません');
}
  • このあたりでデータの取得

$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
ここでページURLのidをそのまま取得

<input type="hidden" name="id" value="<?php echo $id; ?>">
        <textarea name="memo" cols="50" rows="10" placeholder="メモを入力してください"><?php echo htmlspecialchars($memo); ?></textarea><br>
  • このあたりで出力
  • 特に難しいことなく、取得したデータもとに$id$memo記述してるだけ
<input type="hidden" name="id" value="<?php echo $id; ?>">
  • インターネットは次のページにしかデータを持ち越すことができない
  • その場合、クッキー、ローカルストレージなど用いる
  • その他の方法として、隠し項目を設定する方法がある。
  • 見えない形のinput項目を設定することでページをまたいでデータを利用できる。
  • ユーザーが見えない形でデータの受け渡しを行いたい場合にhiddenで設定するパターンはよくある

update_do.phpを作成

<?php
require('dbconnect.php');

$stmt = $db->prepare('update memos set memo=? where id=?');
if(!$stmt){
    die($db->error);
}
$id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT);
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_STRING);
$stmt->bind_param('si', $memo, $id);
$success = $stmt->execute();
if(!$success){
  die($db->error);
}
header('Location: memo.php?id=' . $id);
?>
  • ↑↑↑これが完成形
$id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT);
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_STRING);
  • これがupdate.phpから受け取る値
header('Location: memo.php?id=' . $id);
  • headerは別のページにジャンプする、というファンクション
  • メモの詳細ページに自動で移動するように文字列連結で記述している

削除機能追加

240302_15.png

<p><a href="update.php?id=<?php echo $id; ?>">編集する</a> | 
    <a href="delete.php?id=<?php echo $id; ?>">削除する</a> | <a href="/memo">一覧へ</a></p>
  • memo.phpに追記
  • 削除に関する記述を追加(削除する)
  • delete.phpにリンクを追加
<?php
require('dbconnect.php');

$stmt = $db->prepare('delete from memos where id=?');
if(!$stmt){
    die($db->error);
}
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
if(!$db){
    echo 'メモが正しく指定されていません';
    exit();
}
$stmt->bind_param('i', $id);
$success = $stmt->execute();
if(!$success){
    die($db->error);
}

header('Location: index.php');
?>
  • delete.phpを追加

  • ほとんどこれまでと同じ接続情報

  • $stmt = $db->prepare('delete from memos where id=?');
    ここが削除処理になっている

  • header('Location: index.php');

  • 処理が終わったらTOPページに戻る処理

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up