Ubuntu 18.04でPHPを使用してMySQLにページネーションを実装する方法

著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにthe Apache Software Foundationを選択しました。

前書き

ページネーションは、レコードセットで返される行の数を別々の整然としたページに制限して、それらの間のナビゲーションを容易にする概念です。そのため、大きなデータセットがある場合、各ページで特定の行数のみを返すようにページネーションを設定できます。 たとえば、ページにリストされるアイテムの数を減らすことで、ウェブストアに何千もの製品が含まれる場合、ユーザーがすべての製品を表示する必要はほとんどないため、ページネーションは圧倒的なユーザーの回避に役立ちます。 別の例は、モバイルデバイスでレコードを表示するアプリケーションです。このような場合にページネーションを有効にすると、レコードが複数のページに分割され、画面に収まりやすくなります。

エンドユーザーにとっての視覚的な利点に加えて、ページネーションは、一度に返されるレコードの数を減らすため、アプリケーションを高速化します。 これにより、クライアントとサーバー間で送信する必要のあるデータが制限され、RAMなどのサーバーリソースの保持に役立ちます。

このチュートリアルでは、データベースに接続するためのPHPスクリプトを作成し、MySQLLIMIT clauseを使用してスクリプトへのページ付けを実装します。

前提条件

開始する前に、次のものが必要です。

[[step-1 -—- creating-a-database-user-and-a-test-database]] ==ステップ1—データベースユーザーとテストデータベースの作成

このチュートリアルでは、MySQLデータベースに接続してレコードを取得し、テーブル内のHTMLページに表示するPHPスクリプトを作成します。 Webブラウザから2つの異なる方法でPHPスクリプトをテストします。 最初に、ページネーションコードなしでスクリプトを作成して、レコードの表示方法を確認します。 次に、ページ編集コードをPHPファイルに追加して、ページネーションが実際にどのように機能するかを理解します。

PHPコードには、認証目的のMySQLユーザーと接続するサンプルデータベースが必要です。 この手順では、PHPスクリプトをテストするために、MySQLデータベース、サンプルデータベース、およびテーブルの非ルートユーザーを作成します。

サーバーへのログインを開始します。 次に、次のコマンドを使用してMySQLサーバーにログインします。

sudo mysql -u root -p

MySQLサーバーのrootパスワードを入力し、ENTERを押して続行します。 次に、MySQLプロンプトが表示されます。 このチュートリアルでtest_dbと呼ぶサンプルデータベースを作成するには、次のコマンドを実行します。

Create database test_db;

次の出力が表示されます。

OutputQuery OK, 1 row affected (0.00 sec)

次に、test_userを作成し、ユーザーにtest_dbに対するすべての特権を付与します。 PASSWORDを強い値に置き換えます。

GRANT ALL PRIVILEGES ON test_db.* TO 'test_user'@'localhost' IDENTIFIED BY 'PASSWORD';
OutputQuery OK, 1 row affected (0.00 sec)

次を使用してMySQL権限をリロードします。

FLUSH PRIVILEGES;
OutputQuery OK, 1 row affected (0.00 sec)

次に、test_dbデータベースに切り替えて、test_dbデータベースで直接作業を開始します。

Use test_db;
OutputDatabase changed

次に、productsテーブルを作成します。 表にはサンプル製品が含まれます。このチュートリアルでは、データ用に2列のみが必要です。 product_id列は、各レコードを一意に識別するための主キーとして機能します。 product_nameフィールドを使用して、各アイテムを名前で区別します。

Create table products (product_id BIGINT PRIMARY KEY, product_name VARCHAR(50) NOT NULL ) Engine = InnoDB;
OutputQuery OK, 0 rows affected (0.02 sec)

10個のテスト製品をproductsテーブルに追加するには、次のSQLステートメントを実行します。

Insert into products(product_id, product_name) values ('1', 'WIRELESS MOUSE');
Insert into products(product_id, product_name) values ('2', 'BLUETOOTH SPEAKER');
Insert into products(product_id, product_name) values ('3', 'GAMING KEYBOARD');
Insert into products(product_id, product_name) values ('4', '320GB FAST SSD');
Insert into products(product_id, product_name) values ('5', '17 INCHES TFT');
Insert into products(product_id, product_name) values ('6', 'SPECIAL HEADPHONES');
Insert into products(product_id, product_name) values ('7', 'HD GRAPHIC CARD');
Insert into products(product_id, product_name) values ('8', '80MM THERMAL PRINTER');
Insert into products(product_id, product_name) values ('9', 'HDMI TO VGA CONVERTER');
Insert into products(product_id, product_name) values ('10', 'FINGERPRINT SCANNER');

次の出力が表示されます。

OutputQuery OK, 1 row affected (0.02 sec)

以下を実行して、製品がテーブルに挿入されたことを確認します。

select * from products;

出力の製品は2つの列内に表示されます。

Output+------------+-----------------------+
| product_id | product_name          |
+------------+-----------------------+
|          1 | WIRELESS MOUSE        |
|          2 | BLUETOOTH SPEAKER     |
|          3 | GAMING KEYBOARD       |
|          4 | 320GB FAST SSD        |
|          5 | 17 INCHES TFT         |
|          6 | SPECIAL HEADPHONES    |
|          7 | HD GRAPHIC CARD       |
|          8 | 80MM THERMAL PRINTER  |
|          9 | HDMI TO VGA CONVERTER |
|         10 | FINGERPRINT SCANNER   |
+------------+-----------------------+
10 rows in set (0.00 sec)

MySQLを終了します。

quit;

サンプルデータベース、テーブル、およびテストデータを配置したら、Webページにデータを表示するPHPスクリプトを作成できます。

[[step-2 -—- displaying-mysql-records-without-pagination]] ==ステップ2—ページネーションなしでMySQLレコードを表示する

次に、前の手順で作成したMySQLデータベースに接続するPHPスクリプトを作成し、Webブラウザーで製品を一覧表示します。 このステップでは、ページ分割の形式を使用せずにPHPコードを実行して、非分割レコードが単一ページにどのように表示されるかを示します。 このチュートリアルではテスト目的のレコードは10個しかありませんが、ページネーションなしのレコードを見ると、データをセグメント化することで最終的にユーザーエクスペリエンスが向上し、サーバーの負荷が軽減される理由がわかります。

次のコマンドを使用して、WebサイトのドキュメントルートにPHPスクリプトファイルを作成します。

sudo nano /var/www/html/pagination_test.php

次に、次のコンテンツをファイルに追加します。 PASSWORDを、前の手順でtest_userに割り当てた正しいパスワードの値に置き換えることを忘れないでください。

/var/www/html/pagination_test.php

setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);

    $sql="select * from products";

    $stmt = $pdo->prepare($sql);

    $stmt->execute();

    echo "";

    while ( ($row = $stmt->fetch(PDO::FETCH_ASSOC) ) !== false) {
        echo "";

        echo "";

        echo "";

        echo "";

    }

    echo "
".$row['product_id']."".$row['product_name']."
"; } catch(PDOException $e) { echo $e->getMessage(); } ?>

CTRL+XY、およびENTERを押してファイルを保存します。

このスクリプトでは、ステップ1で作成したデータベース資格情報を使用してPDO (PHP Data Object)ライブラリを使用してMySQLデータベースに接続しています。

PDOは、データベースに接続するための軽量のインターフェイスです。 データアクセス層はより移植性が高く、わずかなコードの書き換えだけで異なるデータベースで動作できます。 PDOは、prepared statementsをサポートしているため、セキュリティが強化されています。これは、クエリを安全な方法で高速に実行するための機能です。

次に、select * from productsステートメントを実行し、ページ付けなしでHTMLテーブルに製品を一覧表示するようにPDOAPIに指示します。 行$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);は、データ型がデータベースに表示されるとおりに返されることを保証します。 これは、PDOがproduct_idを整数として返し、product_nameを文字列として返すことを意味します。 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);は、エラーが発生した場合に例外をスローするようにPDOに指示します。 デバッグを容易にするために、PHPtry{}...catch{}ブロック内のエラーをキャッチしています。

作成した/var/www/html/pagination_test.php PHPスクリプトファイルを実行するには、次のURLにアクセスして、your-server-IPをサーバーのパブリックIPアドレスに置き換えます。

http://your-server-IP/pagination_test.php

製品の表を含むページが表示されます。

MySQL Records Displayed with a PHP script - No Pagination

PHPスクリプトは期待どおりに機能しています。すべての製品を1ページにリストします。 数千の製品がある場合、製品がデータベースからフェッチされ、PHPページにレンダリングされるため、これにより長いループが発生します。

この制限を克服するには、PHPスクリプトを変更し、MySQLLIMIT句といくつかのナビゲーションリンクを表の下部に含めて、ページ付け機能を追加します。

[[step-3 -—- implementing-pagination-with-php]] ==ステップ3—PHPを使用したページネーションの実装

このステップの目標は、テストデータを複数の管理可能なページに分割することです。 これにより、読みやすくなるだけでなく、サーバーのリソースをより効率的に使用できます。 前のステップで作成したPHPスクリプトを変更して、ページネーションに対応します。

これを行うには、MySQLLIMIT句を実装します。 これをスクリプトに追加する前に、MySQLLIMITの構文の例を見てみましょう。

Select [column1, column2, column n...] from [table name] LIMIT offset, records;

LIMIT句は、このステートメントの終わりに向かって示されているように、2つの引数を取ります。 offset値は、最初の行の前にスキップするレコードの数です。 recordsは、ページごとに表示するレコードの最大数を設定します。

ページネーションをテストするには、ページごとに3つのレコードを表示します。 ページの合計数を取得するには、テーブルの合計レコードをページごとに表示する行で分割する必要があります。 次に、次のPHPコードスニペットの例に示すように、PHPCeil関数を使用して、結果の値を最も近い整数に丸めます。

$total_pages=ceil($total_records/$per_page);

以下は、完全なページネーションコードを使用したPHPスクリプトの修正バージョンです。 ページネーションコードとナビゲーションコードを含めるには、/var/www/html/pagination_test.phpファイルを開きます。

sudo nano /var/www/html/pagination_test.php

次に、強調表示された次のコードをファイルに追加します。

/var/www/html/pagination_test.php

setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);

    /* Begin Paging Info */

    $page=1;

    if (isset($_GET['page'])) {
        $page=filter_var($_GET['page'], FILTER_SANITIZE_NUMBER_INT);
    }

    $per_page=3;

    $sqlcount="select count(*) as total_records from products";
    $stmt = $pdo->prepare($sqlcount);
    $stmt->execute();
    $row = $stmt->fetch();
    $total_records= $row['total_records'];

    $total_pages=ceil($total_records/$per_page);

    $offset=($page-1)*$per_page;

    /* End Paging Info */

    $sql="select * from products limit $offset,$per_page";

    $stmt = $pdo->prepare($sql);

    $stmt->execute();


    echo "";

    while ( ($row = $stmt->fetch(PDO::FETCH_ASSOC) ) !== false) {
        echo "";

        echo "";

        echo "";

        echo "";

    }

    echo "
".$row['product_id']."".$row['product_name']."
"; /* Begin Navigation */ echo ""; echo ""; if( $page-1>=1) { echo ""; } if( $page+1<=$total_pages) { echo ""; } echo ""; echo "
PreviousNext
"; /* End Navigation */ } catch(PDOException $e) { echo $e->getMessage(); } ?>

ファイルでは、追加のパラメーターを使用してページングを実行しました。

  • $page:この変数は、スクリプトの現在のページを保持します。 ページ間を移動するとき、スクリプトは$_GET['page']変数を使用してpageという名前のURLパラメーターを取得します。

  • $per_page:この変数は、ページごとに表示する最大レコードを保持します。 あなたの場合、各ページに3つの製品をリストしたいと思います。

  • $total_records:製品を一覧表示する前に、SQLステートメントを実行して、ターゲットテーブル内のレコードの総数を取得し、それを$total_records変数に割り当てます。

  • $offset:この変数は、最初の行の前にスキップするレコードの合計を表します。 この値は、式$offset=($page-1)*$per_pageを使用してPHPスクリプトによって動的に計算されます。 この式をPHPページネーションプロジェクトに適合させることができます。 必要に応じて$per_page変数を変更できることを忘れないでください。 たとえば、モバイルデバイス用のウェブサイトまたは別の金額を実行している場合は、値を50に変更して、ページごとに50個のアイテムを表示できます。

ここでも、ブラウザでIPアドレスにアクセスし、your_server_ipをサーバーのパブリックIPアドレスに置き換えます。

http://your_server_ip/pagination_test.php

ページの下部にいくつかのナビゲーションボタンが表示されます。 最初のページでは、Previousボタンは表示されません。 Nextページボタンが表示されない最後のページでも同じケースが発生します。 また、各ページにアクセスすると、pageURLパラメーターがどのように変化するかに注意してください。

MySQL Records Displayed with a PHP script with Pagination - Page 1

MySQL Records Displayed with a PHP script with Pagination - Page 2

Final page of MySQL Records Displayed with a PHP script with Pagination - Page 4

ページの下部にあるナビゲーションリンクは、ファイルから次のPHPコードスニペットを使用して実現されます。

/var/www/html/pagination_test.php

. . .
    if( $page-1>=1) {
        echo "Previous";
    }

    if( $page+1<=$total_pages) {
        echo "Next";
    }
. . .

ここで、$page変数は現在のページ番号を表します。 次に、前のページを取得するために、コードは変数から1を引きます。 したがって、2ページ目にいる場合、数式(2-1)1の結果を示し、これがリンクに表示される前のページになります。 ただし、1以上の結果が得られた場合にのみ、前のページが表示されることに注意してください。

同様に、次のページに移動するには、$page変数に1を追加し、page URLパラメーターに追加する$pageの結果が以下であることを確認する必要があります。 PHPコードで計算した合計ページ数。

この時点で、PHPスクリプトはページネーションを処理しており、レコードナビゲーションを改善するためにMySQLLIMIT句を実装できます。

結論

このチュートリアルでは、Ubuntu 18.04サーバー上のPHPでMySQLのページングを実装しました。 PHPスクリプトを使用してページネーションを含めることにより、これらの手順をより大きなレコードセットで使用できます。 Webサイトまたはアプリケーションでページネーションを使用することで、ユーザーナビゲーションを改善し、サーバーでリソースを最適に使用できます。

ここから、これらのチュートリアルを使用して、データベースおよびその他のデータベースタスクのさらなる最適化を検討できます。

Related