Last active
March 6, 2020 13:22
-
-
Save atsu666/8d090ea15b21a2a995b5c7bcc561ccf1 to your computer and use it in GitHub Desktop.
php/Services/Preview/Engine.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Acms\Services\Preview; | |
| use Acms\Services\Preview\Contracts\Base; | |
| use ACMS_Session; | |
| use App; | |
| use DB; | |
| use SQL; | |
| class Engine implements Base | |
| { | |
| /** | |
| * PHPセッションラッパー | |
| * | |
| * @var \ACMS_Session | |
| */ | |
| protected $session; | |
| /** | |
| * @var | |
| */ | |
| protected $get; | |
| /** | |
| * プレビュー共有URLの有効時間 | |
| * | |
| * @var int | |
| */ | |
| protected $lifetime; | |
| /** | |
| * 共有URL | |
| * | |
| * @var string | |
| */ | |
| protected $shareUrl; | |
| /** | |
| * 偽装UAをセッションに保存する時のキー名 | |
| * | |
| * @var string | |
| */ | |
| protected $previewFakeUaKeyName = 'preview_fake_ua'; | |
| /** | |
| * 偽装UAをセッションを確認するためのトークンのキー名 | |
| * | |
| * @var string | |
| */ | |
| protected $previewFakeUaTokenKeyName = 'preview_fake_ua_token'; | |
| /** | |
| * プレビュー共有するための認証トークンのキー名 | |
| * | |
| * @var string | |
| */ | |
| protected $previewShareUrlTokenKeyName = 'preview-token'; | |
| /** | |
| * プレビューモードか判定するために使うURLクエリパラメーター名 | |
| * | |
| * @var string | |
| */ | |
| protected $previewModeQueryParameter = 'acms-preview-mode'; | |
| /** | |
| * Engine constructor. | |
| * | |
| * @param int $lifetime | |
| * @param string $shareUrl | |
| */ | |
| public function __construct($lifetime, $shareUrl) | |
| { | |
| $app = App::getInstance(); | |
| $this->get = $app->getGetParameter(); | |
| $this->lifetime = $lifetime; | |
| $this->shareUrl = $shareUrl; | |
| } | |
| /** | |
| * プレビューモード中か判定 | |
| * | |
| * @return bool | |
| */ | |
| public function isPreviewMode() | |
| { | |
| if ($session = $this->getSession()) { | |
| $fakeUaToken = $session->get($this->previewFakeUaTokenKeyName, false); | |
| if ($fakeUaToken && $fakeUaToken === $this->get->get($this->previewModeQueryParameter)) { | |
| setConfig('x_frame_options', 'off'); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| /** | |
| * 偽装ユーザーエージェントの取得 | |
| * | |
| * @return string | bool | |
| */ | |
| public function getFakeUserAgent() | |
| { | |
| if ($this->isPreviewMode()) { | |
| $session = $this->getSession(); | |
| return $session->get('preview_fake_ua', false); | |
| } | |
| return false; | |
| } | |
| /** | |
| * プレビュー共有モードになれるか判定 | |
| * | |
| * @return bool | |
| */ | |
| public function isValidPreviewSharingUrl() | |
| { | |
| $previewToken = $this->get->get($this->previewShareUrlTokenKeyName); | |
| if (empty($previewToken)) { | |
| return false; | |
| } | |
| $SQL = SQL::newSelect('preview_share'); | |
| $SQL->addSelect('preview_share_uri'); | |
| $SQL->addWhereOpr('preview_share_expire', date('Y-m-d H:i:s', REQUEST_TIME), '>='); | |
| $SQL->addWhereOpr('preview_share_token', $previewToken); | |
| $url = DB::query($SQL->get(dsn()), 'one'); | |
| if (empty($url)) { | |
| return false; | |
| } | |
| return $this->shareUrlFormat(REQUEST_URL) === $url || (is_ajax() && $this->shareUrlFormat(htmlspecialchars_decode(REFERER, ENT_QUOTES)) === $url); | |
| } | |
| /** | |
| * プレビュー共有URLの取得 | |
| * | |
| * @param string $url | |
| * @return string | |
| */ | |
| public function getShareUrl($url) | |
| { | |
| $token = uniqueString() . uniqueString(); | |
| $SQL = SQL::newInsert('preview_share'); | |
| $SQL->addInsert('preview_share_uri', $this->shareUrlFormat($url)); | |
| $SQL->addInsert('preview_share_expire', date('Y-m-d H:i:s', REQUEST_TIME + $this->lifetime)); | |
| $SQL->addInsert('preview_share_token', $token); | |
| DB::query($SQL->get(dsn()), 'exec'); | |
| return $this->shareUrl . "?token={$token}"; | |
| } | |
| /** | |
| * 共有URLで実際に表示するiFrameのURL | |
| * | |
| * @return string | |
| */ | |
| public function getSharePreviewUrl() | |
| { | |
| $token = $this->get->get('token'); | |
| if (empty($token)) { | |
| throw new \RuntimeException('Empty token'); | |
| } | |
| $SQL = SQL::newSelect('preview_share'); | |
| $SQL->addSelect('preview_share_uri'); | |
| $SQL->addWhereOpr('preview_share_expire', date('Y-m-d H:i:s', REQUEST_TIME), '>='); | |
| $SQL->addWhereOpr('preview_share_token', $token); | |
| if ($url = DB::query($SQL->get(dsn()), 'one')) { | |
| $query = parse_url($url, PHP_URL_QUERY); | |
| if ($query) { | |
| $url .= "&preview-token={$token}"; | |
| } else { | |
| $url .= "?preview-token={$token}"; | |
| } | |
| return $url; | |
| } | |
| throw new \RuntimeException('Failed get preview url.'); | |
| } | |
| /** | |
| * 期限切れの共有URLを削除 | |
| */ | |
| public function expiredShareUrl() | |
| { | |
| $SQL = SQL::newDelete('preview_share'); | |
| $SQL->addWhereOpr('preview_share_expire', date('Y-m-d H:i:s', REQUEST_TIME - 1), '<'); | |
| DB::query($SQL->get(dsn()), 'exec'); | |
| } | |
| /** | |
| * プレビューモードを開始 | |
| * | |
| * @param string $fakeUserAgent | |
| * @param string $token | |
| * @return bool | |
| */ | |
| public function startPreviewMode($fakeUserAgent, $token) | |
| { | |
| if ($session = $this->getSession()) { | |
| if ($fakeUserAgent && $token) { | |
| $session->set($this->previewFakeUaKeyName, $fakeUserAgent); | |
| $session->set($this->previewFakeUaTokenKeyName, $token); | |
| } else { | |
| $session->delete($this->previewFakeUaKeyName); | |
| $session->delete($this->previewFakeUaTokenKeyName); | |
| } | |
| $session->save(); | |
| } | |
| } | |
| /** | |
| * プレビューモードを終了 | |
| * | |
| * @return bool | |
| */ | |
| public function endPreviewMode() | |
| { | |
| if ($session = $this->getSession()) { | |
| $session->delete($this->previewFakeUaKeyName); | |
| $session->delete($this->previewFakeUaTokenKeyName); | |
| $session->save(); | |
| } | |
| } | |
| /** | |
| * 共有URLから余分な文字列を削除 | |
| * | |
| * @param string $url | |
| * @return string | |
| */ | |
| protected function shareUrlFormat($url) | |
| { | |
| $url = preg_replace('/(\?|&|&)(acms-preview-mode|timestamp|preview-token)=[^&]+/', '', $url); | |
| return htmlspecialchars_decode($url, ENT_COMPAT); | |
| } | |
| /** | |
| * @return bool|mixed | |
| */ | |
| private function getSession() | |
| { | |
| if ($this->session) { | |
| return $this->session; | |
| } | |
| if (sessionWithContribution() || ACMS_POST === 'Preview_Mode' || isset($_GET['acms-preview-mode'])) { | |
| $this->session = ACMS_Session::singleton(array( | |
| 'sess_storage' => 'acms_preview', | |
| )); | |
| return $this->session; | |
| } | |
| return false; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment