てくてく

2023年8月24日1件]

個人サイトに連載系の小説を載せるとき、前ページや次ページのリンクをフッターに貼るのですが毎回毎回設定するの、ちょっと面倒になってきちゃったんですよね。
PHPのパーツ共通化利用してなんかいい感じにできないかな~と模索して、無事実装できたのでご紹介します。
なお、高速化などは考えておりませんのであしからず!
【2023/09/26追記】一部プログラムに不足があったので修正しました。

この記事で最終的にできるコト
前ページ/次ページのリンクを自動設定。

今回の確認環境
  • Windows10
  • Google Chrome
  • XAMPP v3.3.0(PHP8.2)
  • ロリポップサーバー(PHP8.2LiteSpeed版)

※XAMPP使用の場合、VirtualHost利用を前提として執筆しています。
VirtualHostは前記事(ローカルでもドメイン使用!?XAMPPのVirtualHostとはっ)を参照くださいませ。

今回のディレクトリ構成
サイトフォルダ
├novels
|├001.php
|├002.php
|├003.php
|└004.php
├parts
|├foot.php
|└head.php
└index.php

上記の中で前ページ/次ページを入れるのはnovelsフォルダ内のみです。
しかしフォルダによってfooterの中身を変えるのすら面倒なので、すべて同じfooterを使います。
処理の都合上、novelsフォルダ内は桁を揃えて連番にしてあります。

各ページ
今回パーツの共通化を前提としています。
よって各ページは下記のようにしております。

head.php
<!DOCTYPE html>
<html>
<head>
    <!-- 省略(headタグの中身) -->
</head>
<body>
    <header>
        <!-- 省略(headerタグの中身) -->
    </header>


foot.php
<!-- ここに処理を書きます。 -->
<footer>
    <nav>
        <ul>
            <!-- 前/次のリンク差し込み -->
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>

※最低限のみ載せたのでscript読み込みなど色々省いています。

共通化したパーツを読み込む各ページ
index.phpや001.phpなどです。
<?php include_once($_SERVER['DOCUMENT_ROOT']."/parts/head.php"); ?>
<!-- 省略(bodyタグでheaderより下、footerより上の中身) -->
<?php include_once($_SERVER['DOCUMENT_ROOT']."/parts/foot.php"); ?>



追記する処理と解説
foot.phpに追記していきます。
<!-- ▼▼ここから追記▼▼ -->
<?php
if(basename(getcwd()) === "novels"){
    $array = glob("*");
    $current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
    $is_prev = false;
    for($i = 0 ; $i < count($array) ; $i++ ){
        $filename = pathinfo($array[$i], PATHINFO_BASENAME);
        if($current === $filename){
            $is_prev = true;
            continue;
        }
        if(!$is_prev){
            $prev = $filename;
            continue;
        }
    /* 2023/09/26 修正部分 */
        $next = $filename;
        break;
    }
}
?>
<!-- ▲▲ここまで追記▲▲ -->
<footer>
    <nav>
        <ul>
            <!-- ▽▽ここから追記▽▽ -->
            <?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
            echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>
            <!-- △△ここまで追記△△ -->
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>


それでは一つずつ見ていきます。

if(basename(getcwd()) === "novels")
こちらの条件分で、現在開かれているファイルがnovelディレクトリ以下のものであれば処理をするようにします。
getcwd()は現在のディレクトリを出してくれる関数で、今回のディレクトリ構成だと「サイトフォルダ/novels」まで出してくれます。
ルートからはいらないので、basename()を使いディレクトリが「novels」であるかどうか確認するようにします。

$array = glob("*");
glob()は指定したパス以下のファイルをすべて取得してくれる便利な関数です。
今回はnovelsディレクトリ以下のファイルで呼び出されていることを前提に、現在のディレクトリの中身のみ取得します。*(アスタリスク)で現在のディレクトリの中身をすべて取得してくれます。

$current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
現在のファイル名を取得します。
pathinfo()は指定したパスからファイル名や拡張子などを取得してくれます。
$_SERVER['REQUEST_URI']はルートからファイルまでのパスを示しています。
PATHINFO_BASENAMEを第二引数に設定することで、ファイル名+拡張子のみを取得するようにします。
これにより$currentには「001.php」など現在開かれているファイル名のみが取得できます。
なお「.htaccess」などで拡張子を隠す処理をしている場合は、PATHINFO_BASENAMEPATHINFO_FILENAMEにするとファイル名のみで拡張子は抜いてくれます。

$is_prev = false;
for($i = 0 ; $i < count($array) ; $i++ ){
    $filename = pathinfo($array[$i], PATHINFO_BASENAME);
    if($current === $filename){
        $is_prev = true;
        continue;
    }
    if(!$is_prev){
        $prev = $filename;
        continue;
    }
  /* 2023/09/26 修正部分 */
    $next = $filename;
    break;
}


$is_prevは前ページがあるかどうかです。先にfalseで初期化しておきます。
ループで取得したファイルの数だけ処理を回します。
$filenameでファイル名+拡張子を取得し、その後は現在ファイル($current)と一致するかどうか判定します。
if($current === $filename):一致したら前ページの設定は済んでいるとして$is_prevtrueにしてから次のループへ移動します。
if(!$is_prev):一致していない且つ前ページの設定が済んでいなければ$prevにファイル名を設定し次のループへ移動します。
if ($i !== count($array) - 1):一致しない且つ前ページの設定は済んでいる、且つファイルが最後でない場合は次ページを設定してループを抜けます。
【2023/09/26修正】ページ数が3ページしか無いとき、2ページ目から3ページ目へのリンクが表示されない条件文だったので修正しました。
修正前は「最後のファイルでなければ次ページを設定」としていましたが、次ページを設定した時点でループを抜けるようにしました。


一番最初のファイル(001.php)には前ページがないので、ファイルが一致した時点で前ページ設定済みとみなし次のループへ行きます。そして次は002.phpファイルなので、次ページ設定の条件文に入り、次ページ設定をしてループを抜ける流れになります。
一番最後のファイル(004.php)であればループの回数とファイルの個数-1が一致して次ページを設定せずループを終了します。
(ファイルの個数は4つだけど配列では0から数えるので$iが3であれば最後のループということになります)

【2023/09/26修正】次ページが設定された時点でループを抜けるようにしたので、最後のページまで確認しないようにしました。
現在ページが最後のファイルと同じだった場合、if($current === $filename)を満たして次のループに行こうとしますがforの条件がページ数分回すことなのでループが終了します。
現在ページが最後のファイルでない且つ前ページの設定が済んでいる場合は、次ページを設定してループを抜けるように修正しました。


<?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>

isset()は値が設定されているかどうかの関数です。
NULLかどうかや空かどうかではなく、undefinedかどうかの違いです。
isset($prev)で前ページが設定されていたら"<li class='prev'><a href='{$prev}'></a></li>"で前ページのリンクを差し込みます。されていなければ何も表示しません。
同じようにisset($next)で次ページが設定されていたら"<li class='next'><a href='{$next}'></a></li>"で次ページのリンクを差し込みます。されていなければ何も表示しません。

処理まとめ
最終的にfoot.phpはこのようになります。
<?php
if(basename(getcwd()) === "novels"){
    $array = glob("*");
    $current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
    $is_prev = false;
    for($i = 0 ; $i < count($array) ; $i++ ){
        $filename = pathinfo($array[$i], PATHINFO_BASENAME);
        if($current === $filename){
            $is_prev = true;
            continue;
        }
        if(!$is_prev){
            $prev = $filename;
            continue;
        }
        /* 2023/09/26 修正部分 */
        $next = $filename;
        break;
    }
}
?>
<footer>
    <nav>
        <ul>
            <?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
            echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>


最後に
今回は高速化や桁を揃えていない連番を無視して実装してあります。
もし桁が不揃い場合はこちらの記事がわかりやすいので参考にしてみてください。
高速化については、個人サイトの範囲ならそこまで気にしなくていいかなとは思いますがglob()よりopendir()のほうが早い!というこちらの記事もあるので参考にしてみてください。
これで小説ページを追加するたびに前次リンクを追加しなくて済む!わーい!!と喜んでいるとーれでございました!

参考リンクまとめ
敬称略
php:pathinfo
二色人日記:【PHP】特定のディレクトリ内の連番が振られている画像を順番に出力する方法
あたまのなかがとっちらか~る:PHPでファイル一覧を取得するならglobよりopendirのほうが27倍早い

DASHBOARD

つぶやき

アカウント作成しました!
Twitter(現X)

全文検索

カレンダー

日付一覧を表示
2023年8月
12345
6789101112
13141516171819
20212223242526
2728293031

Thanks !

Link

Contact

目次