Skip to content

Instantly share code, notes, and snippets.

@atsu666
Created February 26, 2021 02:17
Show Gist options
  • Select an option

  • Save atsu666/f3c2e476b096ba2c582dda54ef7a6ab4 to your computer and use it in GitHub Desktop.

Select an option

Save atsu666/f3c2e476b096ba2c582dda54ef7a6ab4 to your computer and use it in GitHub Desktop.
php/Services/StaticExport/Compiler/SourceResolver.php
<?php
namespace Acms\Services\StaticExport\Compiler;
use Acms\Services\StaticExport\Contracts\Resolver;
use ACMS_RAM;
class SourceResolver extends Resolver
{
/**
* @var string
*/
protected $destinationOffsetDir;
/**
* @var string
*/
protected $destinationPath;
/**
* @var string
*/
protected $destinationDomain;
/**
* @var string
*/
protected $destinationBlogCode;
/**
* @var int
*/
protected $offset;
/**
* @param string $html
* @param string $document_root
* @param string $offset_dir
* @param string $domain
* @param string $blog_code
*
* @return string
*/
public function resolve($html, $document_root, $offset_dir, $domain, $blog_code)
{
$this->destinationOffsetDir = $offset_dir;
$this->destinationPath = $document_root . $offset_dir;
$this->destinationDomain = $domain;
$this->destinationBlogCode = $blog_code;
$blogPath = ACMS_RAM::blogDomain(BID);
if (DIR_OFFSET) {
$blogPath .= '/' . DIR_OFFSET;
}
$regex = $this->getRegex();
$this->offset = 0;
while ( preg_match($regex, $html, $match, PREG_OFFSET_CAPTURE, $this->offset) ) {
// 置き換え対象文字列の$html全体からみたときのオフセット文字数を取得
$this->offset = $match[0][1] + strlen($match[0][0]);
// マッチ箇所を1文字列チャンクあたり,5回まで検出する
// マッチポイントが検出されたらbreakして,$mptはつぎのwhileループに持ち越す
for ( $mpt = 1; $mpt <= 6; $mpt++ ) {
if ( !empty($match[$mpt][0]) ) {
break;
}
}
$path = trim($match[$mpt][0], '\'"');
$path = preg_replace('@(https?)?://' . $blogPath . '/?@', '/', $path);
$this->replacer($path, $html, $match, $mpt);
}
$regex = '@<\s*(?:img|input|script|frame|iframe)(?:"[^"]*"|\'[^\']*\'|[^\'">])*data-src\s*=\s*("[^"]+"|\'[^\']+\'|[^\'"\s>]+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>@';
$this->offset = 0;
while ( preg_match($regex, $html, $match, PREG_OFFSET_CAPTURE, $this->offset) ) {
$this->offset = $match[0][1] + strlen($match[0][0]);
$path = trim($match[1][0], '\'"');
$path = preg_replace('@(https?)?://' . $blogPath . '/?@', '/', $path);
$this->replacer($path, $html, $match, 1);
}
return $html;
}
/**
* @return string
*/
protected function getRegex()
{
$extension = '(?:acms)';
if ( defined('REWRITE_PATH_EXTENSION') ) {
$extension = '(?:acms|' . REWRITE_PATH_EXTENSION . ')';
}
$regex = '@' .
// src属性をもつHTML要素
'<\s*(?:img|input|script|frame|iframe)(?:"[^"]*"|\'[^\']*\'|[^\'">])*[\s]+src\s*=\s*("[^"]+"|\'[^\']+\'|[^\'"\s>]+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>|' .
// link要素(href属性)
'<\s*link(?:"[^"]*"|\'[^\']*\'|[^\'">])*href\s*=\s*("[^"]+"|\'[^\']+\'|[^\'"\s>]+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>|' .
// object, applet要素(arcvhie属性)
'<\s*(?:object|applet)(?:"[^"]*"|\'[^\']*\'|[^\'">])*archives\s*=\s*("[^"]+"|\'[^\']+\'|[^\'"\s>]+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>|' .
// background属性
'<\s*\w+(?:"[^"]*"|\'[^\']*\'|[^\'">])*background\s*=\s*("[^"]+"|\'[^\']+\'|[^\'"\s>]+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>|' .
// css url属性
'\s*url\s*\(("[^"]+"|\'[^\']+\'|[^\'"\)]+)\)|' .
// a要素
'<\s*a(?:"[^"]*"|\'[^\']*\'|[^\'">])*href\s*=\s*("[^"]+\.' . $extension . '"|\'[^\']+\.' . $extension . '\'|[^\'"\s>]\.' . $extension . '+)(?:"[^"]*"|\'[^\']*\'|[^\'">])*>' .
'@i';
return $regex;
}
/**
* パスの書き換え
*
* @param string $path 置き換え対象パス
* @param string $html 全体html
* @param array $match
* @param int $mpt
*/
protected function replacer($path, & $html, $match, $mpt)
{
$path = trim($path);
$_path = explode('?', $path);
$_path = $_path[0];
// 何らかのスキーマ http:// 等から始まっていたら次のマッチポイントへ
if ( is_int(strpos($path, '://')) || substr($path, 0, 2) === '//' ) {
return;
}
// / をなくしたときに,何も残らなければ ただのルートパス指定とみなして次のマッチポイントへ
if ( !str_replace('/', '', $_path) ) {
return;
}
if ( '/' == substr($path, 0, 1) ) {
$path = substr($path, 1);
$_path = explode('?', $path);
$_path = $_path[0];
if ( $this->acmsJsReplace($path, $_path, $html, $match, $mpt) ) return;
if ( $this->matchingPath($path, $_path, $html, $match, $mpt) ) return;
}
}
/**
* acms.jsのクエリのドメイン書き換え処理
*
* @param string $path
* @param string $format_path
* @param string $html
* @param array $match
* @param int $mpt
* @return boolean
*/
protected function acmsJsReplace($path, $format_path, & $html, $match, $mpt)
{
if ( $format_path === 'acms.js' ) {
$offset = strlen($match[$mpt][0]);
$path = preg_replace('/domains=([^&]+)/', 'domains=' . $this->destinationDomain, $path);
if ($this->destinationOffsetDir) {
$path = preg_replace('/scriptRoot=([^&]+)/', 'scriptRoot=/' . $this->destinationOffsetDir, $path);
if (strpos($path,'offset=') === false) {
$path .= '&offset=' . $this->destinationOffsetDir;
} else {
$path = preg_replace('/offset=([^&]+)/', 'offset=' . $this->destinationOffsetDir, $path);
}
}
$html = substr_replace($html, '"/' . $this->destinationOffsetDir . $path . '"', $match[$mpt][1], $offset);
$this->offset -= ($offset - strlen($path));
return true;
}
return false;
}
/**
* パスの書き換え
*
* @param string $path
* @param string $format_path
* @param string $html
* @param array $match
* @param int $mpt
* @return boolean
*/
protected function matchingPath($path, $format_path, & $html, $match, $mpt)
{
$_path = explode('?', $path);
$query = isset($_path[1]) ? '?' . $_path[1] : '';
$split_path = preg_split('@/@', $format_path, -1, PREG_SPLIT_NO_EMPTY);
$rewrite = false;
while ( true ) {
$tmp = join('/', $split_path);
// 書き出し先にあったら
foreach (array('', $this->destinationBlogCode) as $bcd) {
if ( is_readable($this->destinationPath . $bcd . $tmp) ) {
$offset = strlen($match[$mpt][0]);
if ( $mpt === 5 ) {
$html = substr_replace($html, '/' . $this->destinationOffsetDir . $bcd . $tmp . $query . '', $match[$mpt][1], $offset);
} else {
$html = substr_replace($html, '"/' . $this->destinationOffsetDir . $bcd . $tmp . $query . '"', $match[$mpt][1], $offset);
}
$this->offset -= ($offset - strlen($tmp . $query));
$rewrite = true;
break 2;
}
}
if ( !(array_shift($split_path)) ) break;
}
if ( !$rewrite ) {
// ToDo: 書き換え失敗のエラーハンドリングをする
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment