Engine
in package
implements
Base
Table of Contents
Interfaces
Constants
- PREVIEW_SHARE_ADMIN = 'preview_share'
- プレビュー共有ページのADMIN
- PREVIEW_SHARE_TPL = 'admin/preview/share.html'
- プレビュー共有ページのテンプレート
Properties
- $get : Field
- $lifetime : int
- プレビュー共有URLの有効時間
- $previewFakeUaKeyName : string
- 偽装UAをセッションに保存する時のキー名
- $previewFakeUaTokenKeyName : string
- 偽装UAをセッションを確認するためのトークンのキー名
- $previewModeQueryParameter : string
- プレビューモードか判定するために使うURLクエリパラメーター名
- $previewShareUrlTokenKeyName : string
- プレビュー共有するための認証トークンのキー名
- $session : Session
- PHPセッションラッパー
- $shareUrl : string
- 共有URL
- $sharedUrlItself : bool
- isValidPreviewSharingUrl() 内で確定した「リクエストURLそのものが共有URLと一致したか」
- $validPreviewSharingUrl : bool|null
- isValidPreviewSharingUrl() の結果のメモ化(1 リクエスト中は再計算しない)
Methods
- __construct() : mixed
- Engine constructor.
- endPreviewMode() : void
- プレビューモードを終了
- expiredShareUrl() : mixed
- 期限切れの共有URLを削除
- getFakeUserAgent() : string|false
- 偽装ユーザーエージェントの取得
- getPreviewShareTpl() : string
- getSharePreviewUrl() : string
- 共有URLで実際に表示するiFrameのURL
- getShareUrl() : string
- プレビュー共有URLの取得
- isPreviewMode() : bool
- プレビューモード中か判定
- isPreviewShareAdmin() : bool
- isShareableUrl() : bool
- 共有してよい URL か
- isSharedUrlItself() : bool
- なりすまし権限(SUID)を与えてよいリクエストか
- isValidPreviewSharingUrl() : bool
- プレビュー共有モードになれるか判定
- shareabilityError() : string|null
- 共有できない理由(利用者向けメッセージ)を返す。共有してよい URL なら null
- startPreviewMode() : void
- プレビューモードを開始
- currentRequestUrl() : string
- 現在のリクエストURL
- shareUrlFormat() : string
- 共有URLから余分な文字列を削除
- getSession() : bool|mixed
- hasLivingPreviewSession() : bool
- 生存中のプレビュー共有セッションがあるか
Constants
PREVIEW_SHARE_ADMIN
プレビュー共有ページのADMIN
protected
mixed
PREVIEW_SHARE_ADMIN
= 'preview_share'
PREVIEW_SHARE_TPL
プレビュー共有ページのテンプレート
protected
mixed
PREVIEW_SHARE_TPL
= 'admin/preview/share.html'
Properties
$get
protected
Field
$get
$lifetime
プレビュー共有URLの有効時間
protected
int
$lifetime
$previewFakeUaKeyName
偽装UAをセッションに保存する時のキー名
protected
string
$previewFakeUaKeyName
= 'preview_fake_ua'
$previewFakeUaTokenKeyName
偽装UAをセッションを確認するためのトークンのキー名
protected
string
$previewFakeUaTokenKeyName
= 'preview_fake_ua_token'
$previewModeQueryParameter
プレビューモードか判定するために使うURLクエリパラメーター名
protected
string
$previewModeQueryParameter
= 'acms-preview-mode'
$previewShareUrlTokenKeyName
プレビュー共有するための認証トークンのキー名
protected
string
$previewShareUrlTokenKeyName
= 'preview-token'
$session
PHPセッションラッパー
protected
Session
$session
$shareUrl
共有URL
protected
string
$shareUrl
$sharedUrlItself
isValidPreviewSharingUrl() 内で確定した「リクエストURLそのものが共有URLと一致したか」
private
bool
$sharedUrlItself
= false
$validPreviewSharingUrl
isValidPreviewSharingUrl() の結果のメモ化(1 リクエスト中は再計算しない)
private
bool|null
$validPreviewSharingUrl
= null
Why not 型付きプロパティ(PHP 7.4+)にしない: 302x 以外の系列(301x は PHP 7.3、 300x は PHP 7.2.5 以上をサポート)にも同種の修正をバックポートする前提があり、 型付きプロパティを使うとそれらの系列でパースエラーになる。
Methods
__construct()
Engine constructor.
public
__construct(int $lifetime, string $shareUrl[, Field|null $getParameter = null ]) : mixed
Why not グローバルな App::getInstance()->getGetParameter() 決定的固定にする: テストで
preview-token の有無を出し分けたいとき、$_GET を書き換えずに済む注入経路が必要。
実運用(PreviewServiceProvider)は第 3 引数を渡さないため、既定の挙動は変わらない。
Parameters
- $lifetime : int
- $shareUrl : string
- $getParameter : Field|null = null
endPreviewMode()
プレビューモードを終了
public
endPreviewMode() : void
expiredShareUrl()
期限切れの共有URLを削除
public
expiredShareUrl() : mixed
getFakeUserAgent()
偽装ユーザーエージェントの取得
public
getFakeUserAgent() : string|false
Return values
string|falsegetPreviewShareTpl()
public
getPreviewShareTpl() : string
Return values
stringgetSharePreviewUrl()
共有URLで実際に表示するiFrameのURL
public
getSharePreviewUrl() : string
Why not isValidPreviewSharingUrl() と同じ再検証を省く: ここも DB の保存値をそのまま iframe 先として返す読み出し経路であり、旧基準で保存された行(後から拒否対象に加わった URL 等)があると素の保存値を検証なしで表示してしまう。読み出し経路ごとに基準が ずれるとドリフト要因になるため、同じ shareabilityError() を通す。
Return values
stringgetShareUrl()
プレビュー共有URLの取得
public
getShareUrl(string $url[, mixed $lifetime = false ]) : string
Parameters
- $url : string
- $lifetime : mixed = false
Return values
stringisPreviewMode()
プレビューモード中か判定
public
isPreviewMode() : bool
Return values
boolisPreviewShareAdmin()
public
isPreviewShareAdmin(string $admin) : bool
Parameters
- $admin : string
Return values
boolisShareableUrl()
共有してよい URL か
public
isShareableUrl(string $url) : bool
Parameters
- $url : string
Return values
boolisSharedUrlItself()
なりすまし権限(SUID)を与えてよいリクエストか
public
isSharedUrlItself() : bool
Why not URL 一致だけを条件にしない: REQUEST_URL はメソッドに依らず同一なので、 URL 一致のみを見ると POST でも成立してしまう。共有ページで採取した formToken を 添えて POST すれば、任意の管理系ハンドラがルート主管理者権限で実行できてしまう (CSRF トークンは攻撃者自身のセッションで発行されたものなので障壁にならない)。 閲覧に必要な GET だけに絞る。
Return values
boolisValidPreviewSharingUrl()
プレビュー共有モードになれるか判定
public
isValidPreviewSharingUrl() : bool
Why not 呼び出しごとに再計算する: isPreviewMode() 経由で 1 リクエスト中に何度も呼ばれ、 DB 参照とセッション書き込みを毎回伴う。加えて isSharedUrlItself() が参照する sharedUrlItself は本メソッドの実行中にしか確定しないため、再計算するたびに 上書きされてしまうと同一リクエスト内でも値が安定しない。
Return values
boolshareabilityError()
共有できない理由(利用者向けメッセージ)を返す。共有してよい URL なら null
public
shareabilityError(string $url) : string|null
Why not 経路ごとに isSafeUrl() と isShareableUrl() を並べて書かない: 発行(getShareUrl)・ プレビュー成立判定(isValidPreviewSharingUrl)・iframe 先の取得(getSharePreviewUrl)・ POST ハンドラのバリデーションが同じ 2 条件を個別に持つと、片方だけ基準が変わったときに 経路ごとの判定がドリフトする。理由を文字列で返すことで、判定を 1 箇所に集約したまま 発行時だけは「なぜ共有できないか」を利用者に伝えられる。
Parameters
- $url : string
Return values
string|nullstartPreviewMode()
プレビューモードを開始
public
startPreviewMode(string $fakeUserAgent, string $token) : void
Parameters
- $fakeUserAgent : string
- $token : string
currentRequestUrl()
現在のリクエストURL
protected
currentRequestUrl() : string
Why not REQUEST_URL を直接参照する: グローバル定数はテストから差し替えられない (プロセス起動時の bootstrap で一度だけ定義され、以降 CLI/テストプロセス内で再定義できない)。 protected にして無名サブクラスからオーバーライドできる形にすることで、 「有効な共有トークン・URL 一致がある状態」を統合テストで作れるようにする。
Return values
stringshareUrlFormat()
共有URLから余分な文字列を削除
protected
shareUrlFormat(string $url) : string
Why not 正規表現による文字列置換のままにしない: /(\?|&)key=val/ の除去は、除去対象が
クエリの唯一のパラメータだった場合に ? 自体も一緒に消してしまい、
?acms-preview-mode=T&foo=bar が &foo=bar(? を欠いたまま path に連結される)という
壊れた形になる。parse_url / parse_str で一度分解してから再構成することで、
除去後にクエリが空なら ? を付けない・複数回通しても同じ結果になる(冪等)ことを保証する。
Parameters
- $url : string
Return values
stringgetSession()
private
getSession() : bool|mixed
Return values
bool|mixedhasLivingPreviewSession()
生存中のプレビュー共有セッションがあるか
private
hasLivingPreviewSession() : bool
Why not 無条件に Session::handle() を呼ばない: セッション未開始のクライアントに対しても 呼ぶと、有効なトークンを知っているだけで session_start() と Set-Cookie の送出(DB セッション 使用時は GET_LOCK を伴うトランザクション直列化)を強制できてしまう。既にセッション Cookie を 持っている場合だけ実体を見に行く。