PHPで学ぶページングの実装!手順とサンプルコード10選

PHPとSQLを用いたページングの実装方法を解説するイラストPHP
この記事は約24分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

お手元のコードに、データを一覧表示する機能があるかもしれません。

しかし、大量のデータを一度に表示しようとすると、画面が煩雑になり、読み込みも遅くなります。

そこで必要になるのが「ページング」です。

この記事では、PHPとSQLを用いたページングの実装方法を10のサンプルコードとともにご紹介します。

読み終える頃には、ページングの基本からカスタマイズの方法まで、しっかりと理解し実装することができるでしょう。

●ページングとは

ページングとは、ウェブサイトやアプリケーションで、大量のデータを分割し、一部ずつ表示するためのテクニックです。

たとえば、商品の一覧ページで1000アイテムすべてを同時に表示する代わりに、ページングを使用して10アイテムずつ表示することができます。

○ページングの必要性

ページングは、主に次の3つの理由から必要とされます。

  1. ユーザビリティの向上:ユーザーは大量のデータを一度に処理するのに苦労します。
    ページングを使用することで、ユーザーが必要なデータを効率的に見つけることができます。
  2. パフォーマンスの向上:大量のデータを一度に取得、表示すると、ウェブページの読み込み速度が遅くなります。
    ページングを使用することで、必要なデータのみを取得し、パフォーマンスを向上させることができます。
  3. サーバーの負荷軽減:大量のデータを一度に取得すると、データベースサーバーに大きな負荷がかかります。
    ページングを使用することで、一度に取得するデータ量を制限し、サーバーの負荷を軽減することができます。

以上のように、ページングはユーザビリティの向上、パフォーマンスの向上、サーバーの負荷軽減という観点からウェブアプリケーションの開発において重要な役割を果たします。

●PHPとSQLによるページングの基本

PHPとSQLを用いてページングを実装する基本的な手順は次の通りです。

  1. データベースから取得するデータの総数を算出します。
  2. 1ページあたりに表示するデータの数(以下、ページサイズ)を決定します。
  3. 現在のページ番号(以下、ページ番号)を取得します。
  4. SQLのLIMIT句とOFFSET句を使用して、取得するデータの範囲を指定します。

●PHPでのページングの実装手順

ここでは、PHPとSQLを使用してページングを実装する具体的な手順を解説します。

次の手順に従ってコードを記述することで、ページング機能をウェブアプリケーションに追加することができます。

まずは、基本的なページングの実装から見ていきましょう。

○PHPでのページングの基本コード

このコードでは、まずデータベースから全データの件数を取得します。

その上で、1ページに表示するデータの件数(ページサイズ)と現在のページ番号を設定します。

その後、SQLのLIMIT句とOFFSET句を用いて、表示すべきデータの範囲を指定します。

ここで紹介するサンプルコードは、PHPとMySQLを使った最も基本的なページングの例です。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

この例では、まず全データの件数を取得しています。これにより、何ページ分のデータがあるのかを計算できます。

その後、1ページに表示するデータの件数と現在のページ番号を設定します。

そして、データの取得範囲を計算し、その範囲のデータをデータベースから取得します。

このコードを使用すると、ウェブページにアクセスする際にURLのクエリパラメータとしてページ番号を指定することで、該当するページのデータを取得することができます。

次に、さまざまなシチュエーションに対応するためのサンプルコードをいくつか見てみましょう。

○PHPでのページングのサンプルコード1

このコードでは、前述の基本的なページングに加え、前後のページへのリンクを生成しています。

ユーザーが次または前のページに簡単に移動できるようにすることで、ユーザビリティが向上します。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ページリンクの生成
$prevPageLink = $pageNum > 1 ? '?page=' . ($pageNum - 1) : '';
$nextPageLink = $pageNum < ceil($total / $pageSize) ? '?page=' . ($pageNum + 1) : '';
?>

このコードでは、前のページと次のページへのリンクを生成しています。

前のページへのリンクは現在のページ番号が1より大きい場合に、次のページへのリンクは現在のページ番号が最終ページより小さい場合に生成されます。

○PHPでのページングのサンプルコード2

このコードでは、前述のページング機能に加え、ページ番号の一覧を表示する機能を追加しています。

ユーザーが直接特定のページにジャンプできるようにすることで、ユーザビリティがさらに向上します。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ページリンクの生成
$prevPageLink = $pageNum > 1 ? '?page=' . ($pageNum - 1) : '';
$nextPageLink = $pageNum < ceil($total / $pageSize) ? '?page=' . ($pageNum + 1) : '';

// ページ番号一覧の生成
$pageList = range(1, ceil($total / $pageSize));
?>

このコードでは、ページリンクの生成に加えて、全ページの番号一覧を生成しています。

これにより、ユーザーはページリンクをクリックするだけで直接任意のページにジャンプすることができます。

これらのサンプルコードは、PHPとMySQLを用いた基本的なページングの実装方法を示しています。

しかし、実際のウェブアプリケーションでは、さまざまな要件に応じてページングの仕組みをカスタマイズする必要があります。

次節では、より高度な要件に対応するためのページングの応用例とそのサンプルコードを紹介します。

●ページングの応用例とサンプルコード

○サンプルコード4:フィルタリングを伴うページング

このコードでは、データのフィルタリングを伴うページングを実装しています。

例えば、特定のカテゴリのアイテムだけを表示するようなケースに対応できます。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// カテゴリの設定
$category = isset($_GET['category']) ? $_GET['category'] : '';

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items WHERE category = :category";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':category', $category, PDO::PARAM_STR);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT * FROM items WHERE category = :category LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':category', $category, PDO::PARAM_STR);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

このコードでは、特定のカテゴリのアイテムのみを取得しています。

そのためのカテゴリをURLのクエリパラメータとして指定することで、そのカテゴリのアイテムをページングで表示することができます。

同様に、他のパラメータ(例えば価格範囲や発売日など)をフィルタリング条件として設定することも可能です。

その場合は、上記のコードを適切に修正してください。

○サンプルコード5:複数テーブルのページング

複数のテーブルからデータを取得する必要がある場合もあります。

下記のコードは、JOINを使用して複数のテーブルからデータを取得し、その結果をページングする例です。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items JOIN categories ON items.category_id = categories.id";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT items.*, categories.name AS category_name FROM items JOIN categories ON items.category_id = categories.id LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

このコードでは、アイテムテーブルとカテゴリテーブルをJOINして、アイテムとそれらのカテゴリ名を一緒に取得しています。

その結果を基にページングを行っています。

○サンプルコード6:動的なページング

次に、ユーザーがページサイズを動的に設定できるようにするページングの実装例を見てみましょう。

これにより、ユーザーは自分の好みや必要に応じて、1ページあたりに表示するアイテムの数を調整できます。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// 全データの件数を取得
$sql = "SELECT COUNT(*) FROM items";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$total = $stmt->fetchColumn();

// ページサイズとページ番号を設定
$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;

// データの取得範囲を計算
$offset = ($pageNum - 1) * $pageSize;

// データの取得
$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

このコードでは、URLのクエリパラメータからページサイズを取得しています。

その値を使ってデータを取得し、結果をページングします。

○サンプルコード7:Ajaxを使用したページング

ここでは、Ajaxを使用してページングを実装する例を見ていきましょう。

Ajaxを使うことで、ページ全体をリロードせずに、必要なデータのみを取得して表示を更新することができます。

<?php
// dbconnect.php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// fetch_items.php
$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;
$offset = ($pageNum - 1) * $pageSize;

$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo json_encode($items);
?>
// main.js
$(document).ready(function() {
    $('#nextPage').click(function() {
        var pageNum = parseInt($('#pageNum').val()) + 1;
        $('#pageNum').val(pageNum);

        $.ajax({
            url: 'fetch_items.php?page=' + pageNum,
            type: 'GET',
            dataType: 'json',
            success: function(data) {
                // ここにデータを表示するコードを記述
            }
        });
    });
});

このコードでは、PHPとAjaxを使って、ユーザーが「次のページ」ボタンをクリックすると次のページのアイテムを非同期に取得して表示を更新するページングを実装しています。

この例では、JavaScriptのAjaxリクエストを使用して、次のページのデータをサーバーから非同期に取得し、成功時にそのデータを使用してページの一部を更新しています。

このようなページングの実装は、ユーザーがページ全体をリロードせずにデータの更新を見ることができるため、ユーザーエクスペリエンスを向上させることができます。

しかし、Ajaxを使ったページングは、その実装が少し複雑になることと、JavaScriptが無効になっているユーザーには動作しないという欠点があります。

○サンプルコード8:検索結果のページング

検索機能とページングを組み合わせることは、ウェブアプリケーションにおける一般的なシナリオです。

ここでは、PHPとSQLを使用して検索結果をページングする方法を見ていきます。

<?php
// dbconnect.php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

// search_items.php
$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;
$search = isset($_GET['search']) ? $_GET['search'] : '';
$offset = ($pageNum - 1) * $pageSize;

$sql = "SELECT * FROM items WHERE name LIKE :search LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':search', '%'.$search.'%', PDO::PARAM_STR);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo json_encode($items);
?>

このサンプルコードでは、クエリパラメータを使用して検索ワードを指定し、その検索ワードにマッチする結果をページングして取得しています。

この例では、PDOのbindValueメソッドを使用して、SQLクエリ内の検索パラメータに値をバインドし、その値でアイテムを検索しています。

この実装では、ユーザーが検索ワードを指定し、その検索ワードに一致するアイテムをページ単位で表示できます。

この方法は、大量の検索結果を一度に表示するのではなく、検索結果をページ単位で表示することで、ユーザーエクスペリエンスを向上させます。

しかしながら、この方法ではSQLのLIKE句を使用しているため、大規模なデータベースではパフォーマンスに影響を及ぼす可能性があります。

また、サーバーサイドでページングのロジックを処理するため、クライアントサイドではそれをうまく表示する必要があります。

○サンプルコード9:無限スクロールの実装

無限スクロールとは、ユーザーがページの最下部に到達すると自動的に新しいコンテンツを読み込むテクニックです。

これにより、ユーザーが明示的に次のページに移動する手間を省くことができます。

下記のコードは、PHPとAjaxを組み合わせた無限スクロールの基本的な実装を表しています。

// server.php
<?php
// dbconnect.php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;
$offset = ($pageNum - 1) * $pageSize;

$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo json_encode($items);
?>

このPHPスクリプトは、前述のページングスクリプトと同様に動作しますが、Ajaxを使ってデータをフェッチします。

つまり、サーバーからデータを取得し、クライアントサイドでそのデータを表示します。

しかし、その表示方法はAjaxを利用して、ユーザーがスクロールダウンすると自動的に新しいデータをロードします。

このスクリプトでは、まずデータベースからアイテムを取得し、それをJSON形式でエンコードして送信します。

その後、クライアント側のスクリプトがこのJSONデータを受け取り、HTML要素を生成してページに表示します。

そして、ユーザーがページの最下部にスクロールすると、新たにサーバーからデータをフェッチし、ページに追加します。

このサンプルコードでは、ユーザーがページの最下部に到達したときに自動的に新しいデータをロードします。

これにより、ユーザーがページの最下部に到達すると自動的に新しいデータがロードされ、これが無限に続くため、無限スクロールと呼ばれます。

○サンプルコード10:SEO対策を考慮したページングの実装

ここでは、SEO対策を考慮したページングの実装方法について紹介します。

ページングを行うとき、検索エンジンが各ページの内容を適切に理解できるようにすることが重要です。

そのためには、各ページにユニークなURLと明確なページ番号を設定することが求められます。

下記のコードは、各ページにユニークなURLと明確なページ番号を設定する方法を表しています。

// server.php
<?php
// dbconnect.php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;
$offset = ($pageNum - 1) * $pageSize;

$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);

$prev = $pageNum > 1 ? $pageNum - 1 : null;
$next = count($items) == $pageSize ? $pageNum + 1 : null;

$result = [
    'items' => $items,
    'prev' => $prev,
    'next' => $next
];

echo json_encode($result);
?>

このPHPスクリプトでは、検索エンジンにとって理解しやすい構造を持つページングを実装しています。

具体的には、ページ番号を含むユニークなURLと、明確な前後のページへのリンクを設定しています。

このスクリプトでは、まずデータベースからアイテムを取得します。

次に、前のページと次のページの番号を算出します。

そして、アイテムのデータと共に、前のページと次のページへのリンクを含む結果をJSON形式でエンコードして送信します。

このサンプルコードのキーは、各ページが明確に識別可能なURLを持ち、それが前のページや次のページと関連付けられることです。

これにより、検索エンジンがウェブサイトの構造を理解しやすくなります。

また、ユーザーが直接特定のページにアクセスできるようになります。

●ページングの注意点と対策

ページングを行う際にはいくつかの注意点があります。

まず、ページングはユーザーフレンドリーであることが重要です。

つまり、ユーザーが自分がどのページにいるのか、全体のページ数はいくつなのかを瞬時に理解できるような設計が求められます。

これを実現するためには、現在のページ番号を明確に表示し、前後のページへのリンクを設置することが重要です。

次に、ページングの設計は検索エンジンに対してもフレンドリーであることが重要です。

つまり、各ページがユニークなURLを持ち、前後のページとリンクで繋がっていることが求められます。

これにより、検索エンジンがサイトの構造を理解しやすくなり、それぞれのページが正しくインデックスされる確率が上がります。

ただし、注意が必要なのは、ページングを行うことでコンテンツが分割されるため、各ページのコンテンツが薄くなってしまう可能性があるということです。

検索エンジンは充実したコンテンツを好みますので、各ページが独立して価値のある情報を提供していることが重要です。

これに対する一つの対策は、各ページに独自のメタディスクリプションとタイトルタグを設定することです。

これにより、各ページが一意で価値のあるものであることを検索エンジンに伝えることができます。

また、大量のページを持つサイトでは、ページングを適切に管理しないと、検索エンジンのクローラがサイトを効率よく巡回できなくなる可能性があります。

これを防ぐためには、rel=”prev”とrel=”next”リンク属性を使用して、各ページの前後の関係を明示すると良いでしょう。

以上のように、ユーザーフレンドリーでありながら検索エンジンにも配慮したページングを実装することが、ウェブサイトのユーザビリティとSEO対策の両方を向上させる鍵となります。

だからこそ、ページングの実装はウェブ開発の中でも重要な要素の一つなのです。

●PHPとSQLでのページングのカスタマイズ

次に、PHPとSQLを使用してページングをカスタマイズする方法を見てみましょう。

下記のサンプルコードでは、リクエストパラメータに基づいてページサイズを動的に変更する方法を表しています。

<?php
$pdo = new PDO('mysql:dbname=database;host=localhost', 'username', 'password');

$pageSize = isset($_GET['size']) ? $_GET['size'] : 10;
$pageNum = isset($_GET['page']) ? $_GET['page'] : 1;
$offset = ($pageNum - 1) * $pageSize;

$sql = "SELECT * FROM items LIMIT $offset, $pageSize";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

このコードでは、$_GET[‘size’]の値を使ってページサイズを設定しています。

$_GET[‘size’]がセットされていない場合、デフォルトのページサイズとして10が使用されます。

これにより、ユーザーがURLパラメータを通じてページングの挙動をカスタマイズすることが可能になります。

このようなカスタマイズは、ユーザーが自分のニーズに合わせてページングの挙動を調整できるため、ユーザビリティの向上に寄与します。

また、ページサイズの調整が可能なページングは、大量のデータを扱うウェブサイトで特に有用です。

まとめ

今回はPHPとSQLを使用して、データのページングを実装する方法について解説しました。

ユーザーフレンドリーで、検索エンジンにもフレンドリーなページングを実装することで、ウェブサイトのユーザビリティとSEO対策の両方を向上させることができます。

具体的には、現在のページ番号を明確に表示し、前後のページへのリンクを設置すること、各ページがユニークなURLを持ち、前後のページとリンクで繋がっていること、各ページに独自のメタディスクリプションとタイトルタグを設定することなどが重要なポイントとなります。

また、リクエストパラメータに基づいてページサイズを動的に変更するサンプルコードを紹介しました。

これにより、ユーザーがURLパラメータを通じてページングの挙動をカスタマイズすることが可能となります。

最後に、ページングはユーザビリティとSEO対策の両面で重要な役割を果たすことを理解しておくことが大切です。

どのようにページングを設計し、どのように実装するかは、ウェブサイトの利便性とその検索エンジンでのパフォーマンスに大きく影響を与えます。

これらの要点を理解し、ページングの実装に活用してみてください。初心者でも理解できるように説明した今回の記事が、PHPでのページング実装を学ぶ一助となれば幸いです。