てくてく

2023年8月2件]

個人サイトに連載系の小説を載せるとき、前ページや次ページのリンクをフッターに貼るのですが毎回毎回設定するの、ちょっと面倒になってきちゃったんですよね。
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倍早い
お久しぶりです!本当にお久しぶりです!
忙しい(メンタル)でなかなか更新できませんでした……。
この数ヶ月で色んなことを学び、どれもこれも記事にしたい気持ちと「このレベルで記事にしていいのだろうか…」な気持ちに挟まれていました。
今は落ち着いてきたので、「ええい誰がなんと言おうと”現在(いま)”の自分がタメになったなら記事にしてしまえ!!」と強気な気持ちになってきました。
これからまた記事を投稿できていけたらと思いますのでよろしくお願いします。

さて、てがろぐをXAMPPで確認したいっ!にてXAMPPの設定や使い方をご紹介しました。
こちらではhttp://localhost/site/からサイト別に分けられたフォルダを選択することでサイトの確認をしていました。つまりURLが「http://localhost/site/フォルダ名/index.html」のような形になるわけです。
しかし実際のサイト運営は「https://example.com/index.html」のようなドメインですよね。
なるべく実際の環境に近いほうが良いに決まってるっ!
あと最近、PHP触るようになってローカル用のドメイン使用がとても便利だと気づきました。
今回はローカル環境でもドメインっぽいものがつかえる、XAMPPのVirtualHostの設定方法をご紹介します!

この記事で最終的にできるコト
XAMPPのVirtualHostが使用できる。つまり、ローカル環境でドメイン(例:http://example.com/)によるアクセスができる。
なお、このやり方を使うとドメインでの確認が可能になりますが、スマホからの確認はまた別の設定をしないといけません。そこまで設定ができなかったので今回その方法は紹介しません。
予めご了承くださいませ。

今回の環境
  • Windows10
  • Google Chrome
  • XAMPP v3.3.0


準備
XAMPPの設定を変更していくので、オリジナルのバックアップは取っておきましょう。変更するのは下記のファイルです。
  • httpd.conf(xampp\apache\conf内)
  • httpd-vhosts.conf(xampp\apache\conf\extra内)
  • hosts(C:\Windows\System32\drivers\etc内)

てがろぐをXAMPPで確認したいっ!でhttpd.confのバックアップがある人はそれでも大丈夫です。

今回のディレクトリ構成
C:\
└xampp

D:\
サイト保管フォルダ
├サイトA/index.html
├サイトB/index.html
└サイトC/index.html
別のドライブにサイトデータを入れており、各サイトごとデータがフォルダに入っている状態です。
ドライブが同じでも大丈夫です。

XAMPPの設定
それでは早速設定をしていきます。

httpd.conf
VirtualHostを使用する設定をします。
520行目あたりに
# Virtual hosts
Include conf/extra/httpd-vhosts.conf

とあります。デフォルトで上記のようになっていたらこのままで大丈夫です。もし
#Include conf/extra/httpd-vhosts.conf
とコメントアウトされていたら使えるようにするため#を削除しましょう。

httpd-vhosts.conf
VirtualHostの設定をしていきます。
こちら開くと分かりますが、すべてコメントアウトされている状態です。
まず、20行目辺りに
#
# Use name-based virtual hosting.
#
##NameVirtualHost *:80

とありますので、
NameVirtualHost *:80
と最初の#を削除して使えるようにします。
これはポート80を使用するためのものです。今回はコメントアウトされているものをそのまま使いますが、必要に応じて数字を変更してみてください。

そこから下にはVirtualHostの例がコメントアウトで書かれています。「どこにあるファイルをルートとしてドメイン設定するか、エラーログは、アクセスログは」などの設定方法が書かれているものです。
今回はこのあたりまるっと無視します。
一番下の行に追記していきましょう。
<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトA"
    ServerName localhost-siteA.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトA">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

こんな感じで追記しました。追加したいサイトの数だけ書きます。
一つずつ見ていきます。

<VirtualHost *:80>
httpd-vhosts.confで設定したポート番号をここに設定します。

DocumentRoot "D:\サイト保管フォルダ\サイトA"
ドキュメントルートとなるディレクトリまでのパスをここに入れます。サイトAフォルダの下にindex.htmlがあるので、サイトAまで設定すれば自動的にindex.htmlが表示されるようになります。

ServerName localhost-siteA.com
ここにURLに表示するサーバー名を記載します。
今回の場合、ここで設定することでhttp://localhost-siteA.com/へアクセスするとローカルにあるファイルを表示することができます。
ここでドメインまで付けるとChromeの場合アラートが出る可能性があります。アクセスに気をつけた方がいいような旨です。放置して大丈夫ですが怖い人はドメイン部分(.com)は消して設定するといいかも知れません。

<Directory "D:\サイト保管フォルダ\サイトA">
DocumentRootと同じパスを設定します。一致しないと動かないので注意!

Options Indexes FollowSymLinks ExecCGI
サイトアクセスに関わるオプション設定です。Optionsの設定がない場合はデフォルトで一つを除きすべて許可されているらしいです。が、レンタルサーバーによって許可されていないものもあるので、明示しておいたほうがいいかな?と思ってます。
Optionsの詳細はこちらが詳しいので細かく決めたい人は参照くださいませ。
今回記載したものについては
  • Indexes:ファイルが指定されなかった時、ファイルを一覧表示してくれる(indexファイルのみ指定がなくてもアクセスされるようになってます)
  • FollowSymLinks:シンボリックリンクがたどれます。それだけでなく.htaccessファイルでRewriteEngine onにしている場合、このオプションをつけないと403エラー(閲覧禁止)になります。例えば拡張子を削除している場合なんかはこのオプションが必要になります。
  • ExecCGI:CGIの実行ができます。てがろぐ利用の場合は必ず付けましょう。

今回私の環境では使わないので省きましたが、SSIを利用している場合はIncludesも追加しておきましょう。

AllowOverride All
.htaccessの設定をどれだけ反映させるか、みたいなやつです。詳細はこちらが詳しいので参照くださいませ。
今回はとくに細かく設定しなくて良さげだったので全部許可にしてあります。

Require all granted
アクセス制限に関する記述です。今回は全部OKにしてあります。
例えば「自分のPCからだけ!同一LANの他のPCからのアクセスは嫌!!!」といった場合はIPアドレスでアクセス制限などができます。
個人でやっている限りであればそこまで気にしなくていいのかな~とは思うのですが、たとえば「実は…マイクラサーバー持っててポート開放してるから色んな人がうちのLANに入ってくるんだ……」みたいな場合は設定したほうがいいかもしれないです。今回の記述だと誰でもオッケ~な設定なので、自衛の必要がある人は設定しましょう。
設定方法はこちらが詳しいです。

PCの設定
hosts
コマンドで打って変更するやり方もあるのですが、メモ帳などで変更したほうがやりやすいので私はその方法でやりました。
拡張子がついていませんが、メモ帳などに投げれば開かれます。
コメントアウトされているものは触らず、一番下に追記します。
127.0.0.1 localhost-siteA.com
コメントアウトされている例がこのIPアドレスなので、このアドレスをそのまま使いました。
アドレスの後ろには設定したサーバー名を記述します。
最後に保存して終了です!
ただし、メモ帳などで開くと「権限がないので失敗しました。管理者として再試行しますか?」といった表示されるかと思いますので管理者として保存するようにしましょう。

最終的な記述
変更箇所が多かったので、最後に今回の環境だとどういう記述になったのかさらっと載せます。

httpd.conf
# Virtual hosts
Include conf/extra/httpd-vhosts.conf


httpd-vhosts.conf
#
# Use name-based virtual hosting.
#
NameVirtualHost *:80

~中略~

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトA"
    ServerName localhost-siteA.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトA">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトB"
    ServerName localhost-siteB.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトB">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトC"
    ServerName localhost-siteC.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトC">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>


hosts
127.0.0.1 localhost-siteA.com
127.0.0.1 localhost-siteB.com
127.0.0.1 localhost-siteC.com


これで「http://localhost-siteA.com/」や「localhost-siteA.com」にアクセスすればローカルにあるサイトが表示されます。

最後に
PHPでどうしてもドメインを取得したいときに、これまでの環境だと難しかったのですがこれでめでたく使えるようになりました。
単にてがろぐ使用だけならここまで設定しなくてもいいのですが、PHPなどサーバーサイドを記述していてもっと込み入ったことをしたい場合は是非ご参考くださいませ!

関連記事
てがろぐをXAMPPで確認したいっ!

参考リンクまとめ
※敬称略
XAMPP
てがろぐ(にししふぁくとりー)
Free Style:XAMPPでバーチャルホストを設定して複数のドメインを使う方法
buralog:【Apache】XAMPPでバーチャルホストを設定する方法
Qiita:XAMPPで任意のディレクトリをバーチャルホストにする方法
JavaDrive:Optionsディレクティブ:ディレクトリで使用可能な機能を設定する
           AllowOverrideディレクティブ:.htaccessを使った設定の上書きを許可する
           Requireディレクティブ:アクセスの許可や拒否などのアクセス制限を行う
フリーランスさばいばる:RewriteEngine onで403エラーの解決方法

DASHBOARD

つぶやき

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

全文検索

カレンダー

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

Thanks !

Link

Contact

目次