cuerda blog

cuerda の開発者が考えていることを発信

連載 ChatGPTとCodexで進めるUbuntu開発環境移行

【第12回】WP-CLIとHTTPでライセンス判定が異なった原因を特定する

投稿日:

WP-CLI

みなさま、こんにちは。クエルダ開発担当の渡部公也です。

前回は、Ubuntuへ移したWordPressプラグイン「Cuerda-Feed-Total」で、WordPress内部のライセンス判定と、HTTP経由で取得したRSSの結果を比較しました。

WordPress内部では、LNRのライセンス状態がinvalidと判定されました。

一方、Docker上のWordPressへHTTPでアクセスすると、ステータス200の正常なRSSが返り、ライセンス無効を示す文言も含まれていませんでした。

二つの結果が一致しなかったため、前回はデータベース、テーマ、キャッシュ、プラグイン設定、PHPファイルなどを変更せず、安全に調査を停止しました。

今回は、WordPress内部のライセンス確認とHTTPリクエストが、どのような実行環境で動いているのかを比較します。

調査の結果、WP-CLIから確認した際には、通常のHTTPリクエストで設定されるホスト情報が存在していなかったことが分かりました。

不足していたホスト情報を一時的に補って同じ関数を実行すると、内部ライセンス判定もvalidとなり、HTTPレスポンスと一致しました。

前回確認した不一致

前回は、同じLNRライセンスについて、二つの方法で確認しました。

前回の確認結果
確認方法 結果
WP-CLIから内部関数を実行 invalid
HTTPでRSSへアクセス ステータス200のRSSを取得

HTTPで確認したURLは次のとおりです。

http://127.0.0.1:18083/?feed=cuerda_total&lnr=1

このURLは、Cuerda-Feed-Total専用のDocker環境へ接続しています。

Docker環境では、WordPress 7.0.1、PHP 8.5、MariaDB 11.8が動作し、Cuerda-Feed-Total 4.0.34が有効になっています。

RSSレスポンスには開始タグと終了タグがあり、本文は空ではなく、次のライセンスエラーも含まれていませんでした。

License invalid for ISP: lnr

この結果から、HTTPリクエスト内ではライセンスが有効として扱われている可能性が高いと考えられます。

一方、WP-CLIから直接確認した内部関数はinvalidを返しました。

今回は、同じ関数が異なる結果を返す理由を、実行環境の違いから調査します。

まず同じWordPressを確認しているか調べる

結果が一致しない場合、最初に確認するのは、二つの検査が同じWordPressを参照しているかという点です。

Ubuntuには、日常開発用のWordPressと、Cuerda-Feed-Total専用のDocker検証環境があります。

Ubuntu上の主なWordPress環境
環境 主な用途
wordpress-dev.test 通常のテーマやプラグイン開発
127.0.0.1:18083 Cuerda-Feed-Total専用のDocker検証

異なるWordPressやデータベースを参照していれば、ライセンス状態が一致しなくても不思議ではありません。

そのため、WP-CLIの確認も、HTTPレスポンスを返しているDockerコンテナ内で実行します。

最初にDocker Composeのディレクトリへ移動しました。

cd /mnt/studio317-data/development/docker/cuerda-feed-total

コンテナの状態を確認します。

docker compose ps

WordPressとMariaDBのコンテナが起動していることを確認したうえで、WordPressコンテナ内のWP-CLIを使用します。

コンテナ内のWordPress情報を確認する

WP-CLIが操作しているWordPressの情報を確認します。

docker compose exec wordpress \
wp option get siteurl \
--allow-root

WordPress本体の設置場所も確認しました。

docker compose exec wordpress \
wp eval 'echo ABSPATH, PHP_EOL;' \
--allow-root

続いて、Cuerda-Feed-Totalの状態を確認します。

docker compose exec wordpress \
wp plugin get cuerda-feed-total \
--fields=name,status,version \
--allow-root

確認したプラグインはバージョン4.0.34で、有効な状態でした。

HTTPリクエストを受け付けているWordPressと、内部ライセンス確認を実行しているWordPressは同じです。

異なるデータベースや別のプラグインコピーを参照していることが、不一致の原因ではありませんでした。

HTTPリクエストとCLI実行の違いを考える

同じWordPressとプラグインを使用しているにもかかわらず、結果が一致しませんでした。

次に注目したのは、PHPがどのような方法で実行されているかという違いです。

HTTPリクエスト
ブラウザやcurlからWebサーバーへアクセスし、Webサーバーを経由してPHPとWordPressが実行されます。
WP-CLI
ターミナルからPHPとWordPressを直接起動し、コマンドライン上で処理します。

どちらもWordPressを読み込みますが、PHPへ渡される実行環境は完全には同じではありません。

HTTPリクエストでは、アクセスされたホスト名、ポート、URL、リクエストメソッドなどの情報がWebサーバーから渡されます。

WP-CLIではWebサーバーを経由しないため、これらの情報が存在しないか、HTTPとは異なる値になる場合があります。

PHPのスーパーグローバル変数

PHPには、実行環境やHTTPリクエストに関する情報を保持するスーパーグローバル変数があります。

代表的なものが$_SERVERです。

HTTPリクエストでは、一般的に次のような情報が設定されます。

  • SERVER_NAME
  • HTTP_HOST
  • SERVER_PORT
  • REQUEST_METHOD
  • REQUEST_URI
  • REMOTE_ADDR

SERVER_NAMEは、Webサーバーが認識しているホスト名を表します。

今回のDocker環境へHTTPでアクセスした場合は、127.0.0.1がホスト情報として使用されます。

一方、WP-CLIはWebサーバーを経由しないため、SERVER_NAMEが設定されているとは限りません。

秘密情報を出さずに実行環境を比較する

今回確認したいのは、ライセンスキーや保存値ではなく、HTTPとWP-CLIでホスト情報が異なるかどうかです。

そこで、$_SERVERの全内容を表示するのではなく、必要な項目が存在するかと、そのホスト名だけを確認しました。

WP-CLIでSERVER_NAMEを確認します。

docker compose exec wordpress \
wp eval '
echo isset( $_SERVER["SERVER_NAME"] )
    ? $_SERVER["SERVER_NAME"]
    : "SERVER_NAME is not set";
echo PHP_EOL;
' \
--allow-root

確認したところ、通常のWP-CLI実行ではSERVER_NAMEが設定されていませんでした。

一方、HTTP経由でWordPressが実行される場合は、アクセス先に対応したホスト情報が設定されます。

実行方法によるSERVER_NAMEの違い
実行方法 SERVER_NAME
HTTPリクエスト 127.0.0.1
通常のWP-CLI 未設定

これが、二つのライセンス判定が一致しなかった原因候補となりました。

ライセンス判定とホスト名の関係

Webサイト向けのライセンスでは、登録されたサイトと現在実行しているサイトが一致するかを確認することがあります。

そのため、ライセンス確認処理では、WordPressに保存されているURLだけでなく、現在のHTTPリクエストのホスト情報が使われる場合があります。

Cuerda-Feed-Totalのライセンス判定でも、実行中のホスト情報が判定に関係していました。

HTTPリクエストではSERVER_NAMEが設定されているため、ライセンス確認に必要なサイト情報を取得できます。

通常のWP-CLIではSERVER_NAMEが未設定だったため、HTTPリクエストと同じ条件で判定できていませんでした。

つまり、最初に得られたinvalidという結果は、必ずしも保存されているライセンス自体が無効だったことを意味しません。

HTTPに存在するホスト情報が欠けた状態で関数を実行した結果でした。

WP-CLIへ一時的にホスト情報を設定する

原因候補を確認するため、WP-CLIの実行中だけSERVER_NAMEを設定し、同じライセンス確認関数を実行しました。

データベース、プラグイン設定、PHPファイルなどは変更しません。

docker compose exec wordpress \
wp eval '
$_SERVER["SERVER_NAME"] = "127.0.0.1";

$result = cuerda_check_license_status( "lnr" );

echo $result ? "valid" : "invalid";
echo PHP_EOL;
' 
--allow-root

この設定は、実行しているWP-CLIのプロセス内だけで有効です。

コマンドが終了すると失われるため、WordPressの設定やDocker環境へ恒久的な変更は残りません。

確認の結果、内部ライセンス判定はvalidになりました。

ライセンス確認に伴うHTTP通信も、正常なステータス200として処理されました。

内部判定とHTTPレスポンスが一致した

ホスト情報を補った後の結果をまとめると、次のとおりです。

ホスト情報を揃えた後の確認結果
確認方法 結果
WP-CLI、SERVER_NAMEなし invalid
WP-CLI、SERVER_NAME=127.0.0.1 valid
HTTPでRSSへアクセス ステータス200の正常なRSS

WP-CLIへHTTPと同じホスト情報を設定すると、内部ライセンス判定とHTTPレスポンスの結果が一致しました。

これにより、ライセンス情報やRSSキャッシュが壊れていたのではなく、検査時の実行環境が異なっていたことが、不一致の原因だと判断できました。

なぜ最初の確認では気づけなかったのか

最初の内部確認では、ライセンス関数の戻り値だけを安全に確認しました。

秘密情報を表示せず、関数が返した状態だけをvalidまたはinvalidへ正規化するという方針自体は適切でした。

しかし、関数の入力は、引数として渡したlnrだけではありません。

関数内部で参照するWordPressの設定、現在のホスト名、PHPの実行環境なども、実質的な入力になります。

今回は、WP-CLIとHTTPでSERVER_NAMEの状態が異なっていました。

関数の戻り値だけを比較しても、暗黙的に参照している実行環境までは分かりません。

WP-CLIはブラウザの完全な代替ではない

WP-CLIは、WordPressの設定確認、プラグイン管理、データ操作、テストなどを効率よく行える便利なツールです。

しかし、ブラウザやcurlからのHTTPアクセスを完全に再現するものではありません。

特に、次のような処理では違いに注意する必要があります。

  • 現在のドメインやホスト名を使用する処理
  • HTTPヘッダーを確認する処理
  • リクエストメソッドによって分岐する処理
  • Cookieやログインセッションを使用する処理
  • リファラーやIPアドレスを使用する処理
  • WordPressの特定のHTTPフックで実行される処理
  • Webサーバーが設定する環境変数を使用する処理

WP-CLIで関数を直接実行できたとしても、HTTPと同じ条件で実行されているとは限りません。

Webリクエストに依存する処理は、WP-CLIとHTTPの両方から確認する必要があります。

WordPressのURL設定だけでは足りない場合がある

WordPressには、サイトURLとホームURLが保存されています。

wp option get siteurl
wp option get home

これらの値が正しければ、すべてのURL関連処理が同じ結果になるようにも見えます。

しかし、プラグインやテーマの実装によっては、WordPressの設定値ではなく、現在のリクエストに含まれるホスト情報を参照します。

サイトを識別する主な情報
情報 主な取得元
サイトURL WordPressのsiteurlオプション
ホームURL WordPressのhomeオプション
現在のホスト名 HTTPリクエストのSERVER_NAMEやHTTP_HOST

HTTPリクエストでは、保存されたサイトURLと現在のアクセス先が異なることもあります。

ライセンス、マルチサイト、プロキシ、CDN、複数ドメインなどを扱う処理では、どの情報を基準としているかを確認する必要があります。

データベースの修正が不要だと分かった

内部判定がinvalidだった時点では、ローカルWordPressへライセンス情報が正しく保存されていない可能性も考えられました。

しかし、HTTPと同じホスト情報を設定するとvalidになったため、データベースのライセンス値を書き換える必要はありません。

今回、次の操作は行いませんでした。

  • ライセンス情報の再登録
  • ライセンスキーの上書き
  • WordPressオプションの削除
  • データベースの直接編集
  • プラグインの再インストール

原因が実行環境にあるにもかかわらず、保存データを変更していた場合、正常なライセンス状態を壊していた可能性があります。

変更前に原因を特定したことで、不要なデータベース操作を避けられました。

キャッシュの削除も不要だった

Cuerda-Feed-Totalには、RSS生成の負荷を軽減するための内部キャッシュがあります。

前回の不一致から、古いRSSやライセンス状態がキャッシュに残っている可能性も考えられました。

しかし、ホスト情報を揃えるだけで内部判定が有効になったため、キャッシュが原因ではありませんでした。

そのため、次の操作も行っていません。

  • RSSキャッシュの削除
  • Transientの削除
  • WordPressオブジェクトキャッシュの消去
  • Dockerボリュームの初期化
  • MariaDBデータの削除

原因の確認前にキャッシュを削除していた場合、一時的に結果が変化し、実行環境の違いを見逃していた可能性があります。

テーマとRSS生成処理も変更しなかった

HTTP側では最初から正常なRSSが返っていました。

そのため、RSSテンプレートや本文生成処理を変更する根拠はありません。

今回の調査では、次の領域にも変更を加えていません。

  • 有効なWordPressテーマ
  • RSSテンプレート
  • 本文の変換処理
  • 配信先LNRの生成クラス
  • フィード登録処理
  • HTTPレスポンスのヘッダー

内部ライセンス確認とHTTPレスポンスが一致しなかった問題は、RSS生成コードの不具合ではありませんでした。

検査方法の条件が不足していたことが原因です。

一時的な確認と恒久的な修正を分ける

今回は、WP-CLIのプロセス内でSERVER_NAMEを設定し、原因を確認しました。

$_SERVER["SERVER_NAME"] = "127.0.0.1";

これは診断のための一時的な操作です。

プラグインのPHPファイルへ、この値を固定して追加したわけではありません。

本番環境や別の開発環境では、ホスト名が127.0.0.1とは限らないためです。

また、プラグイン側で無条件にSERVER_NAMEを補うと、本来とは異なるホストとしてライセンスを判定する危険があります。

今回の操作の分類
操作 扱い
WP-CLI内でSERVER_NAMEを一時設定 診断のために実施
プラグインへ127.0.0.1を固定記述 実施しない
データベースのライセンス値を変更 実施しない
RSS生成処理を変更 実施しない

原因確認用の操作と、製品コードへ残す変更は分けて考えます。

検査コマンドへホスト情報を含める

今後、WP-CLIからCuerda-Feed-Totalのライセンス状態を確認する場合は、HTTPリクエストと同じホスト情報を明示する必要があります。

例えば、ローカルDocker環境では次のように確認できます。

docker compose exec wordpress \
wp eval '
$_SERVER["SERVER_NAME"] = "127.0.0.1";

$status = cuerda_check_license_status( "lnr" );

echo $status ? "valid" : "invalid";
echo PHP_EOL;
' 
--allow-root

ただし、実際のプラグインが返す値の型や仕様に応じて、安全な正規化処理を使用します。

検査用のコマンドでは、次の情報を出力しません。

  • ライセンスキー
  • トークン
  • 外部ライセンスサーバーのレスポンス本文
  • 認証ヘッダー
  • データベースへ保存された秘密情報

必要なのは、HTTPと同じ条件で判定した最終結果だけです。

Codexの安全条件も見直す

前回のCodexへの依頼では、内部ライセンス状態がvalid以外であれば、RSSの修正や環境変更へ進まないよう指定しました。

安全に停止できた点は適切でした。

一方、今後は内部確認を行う際に、実行環境も条件へ含める必要があります。

lnrの内部ライセンス状態を確認してください。

確認は、HTTPレスポンスを返しているDocker上のWordPressで行ってください。
WP-CLI実行時は、通常のHTTPアクセスと同じSERVER_NAMEを一時的に設定してください。

確認結果はvalid、invalid、unknown、errorへ正規化し、
ライセンスキー、トークン、APIレスポンス本文は出力しないでください。

PHPファイル、データベース、テーマ、プラグイン設定、
キャッシュは変更しないでください。

単に「内部関数を実行する」と指定するだけでなく、どのWordPressで、どのホスト情報を使用するかまで明確にします。

Codexの報告だけで判断しない

Codexは、最初の確認で内部ライセンス状態をinvalidと正しく報告しました。

しかし、その結果は、通常のWP-CLI実行環境における事実です。

Codexが誤った値を報告したわけではありません。

問題は、その確認条件がHTTPリクエストと同じではなかったことです。

AIからの報告を評価する際は、結果だけでなく、次の内容も確認します。

  • どの環境で実行したか
  • どのコマンドを使用したか
  • どの入力値を使用したか
  • 暗黙的に参照している環境情報は何か
  • 比較対象と同じ条件になっているか

正確なコマンド結果でも、比較条件が異なれば、誤った結論につながる可能性があります。

確認結果を再現できる形で記録する

原因が分かった後は、結果だけでなく、再現条件も記録します。

今回記録する主な診断情報
項目 内容
対象環境 Cuerda-Feed-Total専用Docker環境
HTTP URL 127.0.0.1:18083
対象ISP lnr
通常のWP-CLI SERVER_NAME未設定、判定invalid
HTTPリクエスト SERVER_NAMEが127.0.0.1、正常RSS
条件を揃えたWP-CLI SERVER_NAMEを127.0.0.1へ設定、判定valid
恒久的な環境変更 なし

将来同じ現象が発生した場合も、この記録から検査条件を再現できます。

HTTP側のRSSをもう一度確認する

内部ライセンス判定の条件を揃えた後、HTTP側のRSSも再確認しました。

curl -sS \
-o /tmp/cuerda-lnr-response.xml \
-w 'HTTP=%{http_code}\n' \
'http://127.0.0.1:18083/?feed=cuerda_total&lnr=1'

レスポンスが空ではないことを確認します。

test -s /tmp/cuerda-lnr-response.xml \
&& echo "response is not empty"

RSSの基本構造も確認しました。

grep -q '<rss' /tmp/cuerda-lnr-response.xml \
&& echo "RSS start tag found"

grep -q '' /tmp/cuerda-lnr-response.xml 
&& echo "RSS end tag found"

ライセンス無効の文言がないことも確認します。

grep -Fq \
'License invalid for ISP: lnr' \
/tmp/cuerda-lnr-response.xml \
&& echo "license error found" \
|| echo "license error not found"

HTTP側は引き続き正常なRSSを返し、ホスト情報を揃えた内部判定もvalidとなりました。

確認後に一時ファイルを削除する

HTTPレスポンスとして保存したRSSには、WordPressの投稿内容や配信用データが含まれる可能性があります。

確認が完了した後、不要な一時ファイルを削除しました。

rm -f /tmp/cuerda-lnr-response.xml

一時ファイルはGitリポジトリやChatGPT共有用ディレクトリへ移動していません。

ライセンスキーやトークンも、コマンド結果や作業記録へ出力していません。

Gitの状態が変わっていないことを確認する

今回の調査では、プラグインのPHPファイルを変更していません。

最後にGitの状態を確認しました。

cd /mnt/studio317-data/development/projects/cuerda-feed-total

git status --short --branch
git diff
git diff --check

ソースコードへ未コミットの変更がなく、調査前の基準状態が維持されていることを確認しました。

データベース、テーマ、プラグイン設定、RSSキャッシュ、Dockerボリュームについても変更していません。

今回の原因

今回の不一致の原因は、WP-CLIとHTTPで、PHPの実行環境が異なっていたことです。

通常のHTTPリクエストでは、次のホスト情報が設定されていました。

SERVER_NAME=127.0.0.1

一方、通常のWP-CLI実行ではSERVER_NAMEが設定されていませんでした。

Cuerda-Feed-Totalのライセンス判定はホスト情報を参照するため、WP-CLIではHTTPと同じ条件で確認できていませんでした。

WP-CLIのプロセス内でSERVER_NAME127.0.0.1へ設定すると、内部ライセンス判定はvalidとなり、HTTP側の正常なRSSと一致しました。

ライセンスデータ、キャッシュ、RSS生成処理の不具合ではなく、診断時の実行条件の違いが原因でした。

安全に停止したことが原因特定につながった

前回、内部ライセンス状態がinvalidだった時点で、データベースやキャッシュを変更せず停止しました。

その結果、原因となっていた実行環境の違いを、元の状態のまま調査できました。

仮に最初の段階で次の操作を行っていた場合、原因の特定が難しくなっていた可能性があります。

  • ライセンスキーを再登録する
  • ライセンス関連のオプションを削除する
  • キャッシュをすべて消去する
  • プラグインを再インストールする
  • RSS生成コードを変更する
  • ライセンス判定を一時的に無効化する

安全条件を満たさない場合に停止することは、単に慎重なだけではありません。

問題の状態を保存し、原因を調査できるようにするという意味もあります。

今回の到達点

今回は、WordPress内部のライセンス判定がinvalidである一方、HTTPでは正常なRSSが返る原因を調査しました。

内部確認とHTTP確認は、同じDocker上のWordPress、同じデータベース、同じCuerda-Feed-Total 4.0.34を使用していました。

しかし、通常のWP-CLIではSERVER_NAMEが設定されておらず、HTTPリクエストでは127.0.0.1が設定されていました。

WP-CLIの実行中だけSERVER_NAME127.0.0.1へ設定してライセンス関数を実行すると、内部判定はvalidとなりました。

これにより、ライセンス情報、データベース、RSSキャッシュ、テーマ、RSS生成コードを変更することなく、不一致の原因を特定できました。

また、WP-CLIの結果をHTTPの結果と比較する場合は、ホスト名などの実行環境も揃える必要があることが分かりました。

前回安全に調査を停止したことで、元の状態を壊さずに原因を再現し、正しい検査方法を確認できました。

次回の予定

次回からは、Ubuntuへ移したCuerda-Feed-Totalで、実際の機能改善へ進みます。

WordPressの投稿本文をそのままRSSへ出力する現在の方法に加えて、使用中のテーマにRSS本文専用のテンプレートを用意し、投稿ごとに複雑な本文構成を生成できる仕組みを検討します。

WordPressの通常画面と同じようにテーマ側で本文を組み立てた後、Cuerda-Feed-Totalの既存処理へ渡し、各配信先のレギュレーションに合わせて変換できる構成を整理します。