| @@ -258,9 +258,9 @@ | ||
| 258 | 258 | public function getURI() |
| 259 | 259 | { |
| 260 | 260 | return $this->getEnvValue('REQUEST_URI'); |
| 261 | 261 | } |
| 262 | - private function getEnvValue($key) | |
| 262 | + public function getEnvValue($key) | |
| 263 | 263 | { |
| 264 | 264 | if (isset($this->env[$key])) { |
| 265 | 265 | return $this->env[$key]; |
| 266 | 266 | } |
| @@ -329,9 +329,9 @@ | ||
| 329 | 329 | { |
| 330 | 330 | public static function get() |
| 331 | 331 | { |
| 332 | 332 | $request = \Kibo\Phast\HTTP\Request::fromGlobals(); |
| 333 | - return ['securityToken' => null, 'retrieverMap' => [$request->getHost() => $request->getDocumentRoot()], 'httpClient' => \Kibo\Phast\HTTP\CURLClient::class, 'cache' => ['cacheRoot' => sys_get_temp_dir() . '/phast-cache-' . (new \Kibo\Phast\Common\System())->getUserId(), 'shardingDepth' => 1, 'garbageCollection' => ['maxItems' => 100, 'probability' => 0.1, 'maxAge' => 86400 * 365], 'diskCleanup' => ['maxSize' => 500 * pow(1024, 2), 'probability' => 0.02, 'portionToFree' => 0.5]], 'servicesUrl' => '/phast.php', 'serviceRequestFormat' => \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH, 'compressServiceResponse' => true, 'optimizeHTMLDocumentsOnly' => true, 'outputServerSideStats' => true, 'documents' => ['maxBufferSizeToApply' => pow(1024, 2), 'baseUrl' => $request->getAbsoluteURI(), 'filters' => [\Kibo\Phast\Filters\HTML\CommentsRemoval\Filter::class => [], \Kibo\Phast\Filters\HTML\Minify\Filter::class => [], \Kibo\Phast\Filters\HTML\MinifyScripts\Filter::class => [], \Kibo\Phast\Filters\HTML\BaseURLSetter\Filter::class => [], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags\Filter::class => [], \Kibo\Phast\Filters\HTML\LazyImageLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\CSSInlining\Filter::class => ['optimizerSizeDiffThreshold' => 1024, 'whitelist' => ['~^https?://fonts\\.googleapis\\.com/~' => ['ieCompatible' => false], '~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~', '~^https?://maxcdn\\.bootstrapcdn\\.com/[^?#]*\\.css~', '~^https?://idangero\\.us/~', '~^https?://[^/]*\\.github\\.io/~', '~^https?://\\w+\\.typekit\\.net/~' => ['ieCompatible' => false], '~^https?://stackpath\\.bootstrapcdn\\.com/~', '~^https?://cdnjs\\.cloudflare\\.com/~']], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\CSS\Filter::class => [], \Kibo\Phast\Filters\HTML\DelayedIFrameLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\ScriptsProxyService\Filter::class => ['urlRefreshTime' => 7200], \Kibo\Phast\Filters\HTML\Diagnostics\Filter::class => ['enabled' => 'diagnostics'], \Kibo\Phast\Filters\HTML\ScriptsDeferring\Filter::class => [], \Kibo\Phast\Filters\HTML\PhastScriptsCompiler\Filter::class => []]], 'images' => ['enable-cache' => 'imgcache', 'api-mode' => false, 'factory' => \Kibo\Phast\Filters\Image\ImageFactory::class, 'maxImageInliningSize' => 512, 'whitelist' => ['~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~'], 'filters' => [\Kibo\Phast\Filters\Image\ImageAPIClient\Filter::class => ['api-url' => 'https://optimize.phast.io/?service=images', 'host-name' => $request->getHost(), 'request-uri' => $request->getURI(), 'plugin-version' => 'phast-core-1.0']]], 'styles' => ['filters' => [\Kibo\Phast\Filters\Text\Decode\Filter::class => [], \Kibo\Phast\Filters\CSS\ImportsStripper\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSMinifier\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSURLRewriter\Filter::class => [], \Kibo\Phast\Filters\CSS\ImageURLRewriter\Filter::class => ['maxImageInliningSize' => 512], \Kibo\Phast\Filters\CSS\FontSwap\Filter::class => []]], 'logging' => ['logWriters' => [['class' => \Kibo\Phast\Logging\LogWriters\PHPError\Writer::class, 'levelMask' => \Kibo\Phast\Logging\LogLevel::EMERGENCY | \Kibo\Phast\Logging\LogLevel::ALERT | \Kibo\Phast\Logging\LogLevel::CRITICAL | \Kibo\Phast\Logging\LogLevel::ERROR | \Kibo\Phast\Logging\LogLevel::WARNING], ['enabled' => 'diagnostics', 'class' => \Kibo\Phast\Logging\LogWriters\JSONLFile\Writer::class, 'logRoot' => sys_get_temp_dir() . '/phast-logs']]], 'switches' => ['phast' => true, 'diagnostics' => false], 'scripts' => ['removeLicenseHeaders' => false, 'whitelist' => ['~^https?://' . preg_quote($request->getHost(), '~') . '/~', '~^https?://(ssl|www)\\.google-analytics\\.com/(analytics\\.js|ga\\.js|gtm/js)($|\\?)~', '~^https?://www\\.googletagmanager\\.com/~', '~^https?://www\\.googleadservices\\.com/~', '~^https?://pixel\\.adcrowd\\.com/~', '~^https?://connect\\.facebook\\.net/~', '~^https?://static\\.hotjar\\.com/~', '~^https?://v2\\.zopim\\.com/~', '~^https?://stats\\.g\\.doubleclick\\.net/dc\\.js$~', '~^https?://s\\.pinimg\\.com/~']]]; | |
| 333 | + return ['securityToken' => null, 'retrieverMap' => [$request->getHost() => $request->getDocumentRoot()], 'httpClient' => \Kibo\Phast\HTTP\CURLClient::class, 'cache' => ['cacheRoot' => sys_get_temp_dir() . '/phast-cache-' . (new \Kibo\Phast\Common\System())->getUserId(), 'shardingDepth' => 1, 'garbageCollection' => ['maxItems' => 100, 'probability' => 0.1, 'maxAge' => 86400 * 365], 'diskCleanup' => ['maxSize' => 500 * pow(1024, 2), 'probability' => 0.02, 'portionToFree' => 0.5]], 'servicesUrl' => '/phast.php', 'serviceRequestFormat' => \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH, 'compressServiceResponse' => true, 'optimizeHTMLDocumentsOnly' => true, 'outputServerSideStats' => true, 'documents' => ['maxBufferSizeToApply' => pow(1024, 2), 'baseUrl' => $request->getAbsoluteURI(), 'filters' => [\Kibo\Phast\Filters\HTML\CommentsRemoval\Filter::class => [], \Kibo\Phast\Filters\HTML\MetaCharset\Filter::class => [], \Kibo\Phast\Filters\HTML\Minify\Filter::class => [], \Kibo\Phast\Filters\HTML\MinifyScripts\Filter::class => [], \Kibo\Phast\Filters\HTML\BaseURLSetter\Filter::class => [], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags\Filter::class => [], \Kibo\Phast\Filters\HTML\LazyImageLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\CSSInlining\Filter::class => ['optimizerSizeDiffThreshold' => 1024, 'whitelist' => ['~^https?://fonts\\.googleapis\\.com/~' => ['ieCompatible' => false], '~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~', '~^https?://maxcdn\\.bootstrapcdn\\.com/[^?#]*\\.css~', '~^https?://idangero\\.us/~', '~^https?://[^/]*\\.github\\.io/~', '~^https?://\\w+\\.typekit\\.net/~' => ['ieCompatible' => false], '~^https?://stackpath\\.bootstrapcdn\\.com/~', '~^https?://cdnjs\\.cloudflare\\.com/~']], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\CSS\Filter::class => [], \Kibo\Phast\Filters\HTML\DelayedIFrameLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\ScriptsProxyService\Filter::class => ['urlRefreshTime' => 7200], \Kibo\Phast\Filters\HTML\Diagnostics\Filter::class => ['enabled' => 'diagnostics'], \Kibo\Phast\Filters\HTML\ScriptsDeferring\Filter::class => [], \Kibo\Phast\Filters\HTML\PhastScriptsCompiler\Filter::class => []]], 'images' => ['enable-cache' => 'imgcache', 'api-mode' => false, 'factory' => \Kibo\Phast\Filters\Image\ImageFactory::class, 'maxImageInliningSize' => 512, 'whitelist' => ['~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~'], 'filters' => [\Kibo\Phast\Filters\Image\ImageAPIClient\Filter::class => ['api-url' => 'https://optimize.phast.io/?service=images', 'host-name' => $request->getHost(), 'request-uri' => $request->getURI(), 'plugin-version' => 'phast-core-1.0']]], 'styles' => ['filters' => [\Kibo\Phast\Filters\Text\Decode\Filter::class => [], \Kibo\Phast\Filters\CSS\ImportsStripper\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSMinifier\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSURLRewriter\Filter::class => [], \Kibo\Phast\Filters\CSS\ImageURLRewriter\Filter::class => ['maxImageInliningSize' => 512], \Kibo\Phast\Filters\CSS\FontSwap\Filter::class => []]], 'logging' => ['logWriters' => [['class' => \Kibo\Phast\Logging\LogWriters\PHPError\Writer::class, 'levelMask' => \Kibo\Phast\Logging\LogLevel::EMERGENCY | \Kibo\Phast\Logging\LogLevel::ALERT | \Kibo\Phast\Logging\LogLevel::CRITICAL | \Kibo\Phast\Logging\LogLevel::ERROR | \Kibo\Phast\Logging\LogLevel::WARNING], ['enabled' => 'diagnostics', 'class' => \Kibo\Phast\Logging\LogWriters\JSONLFile\Writer::class, 'logRoot' => sys_get_temp_dir() . '/phast-logs']]], 'switches' => ['phast' => true, 'diagnostics' => false], 'scripts' => ['removeLicenseHeaders' => false, 'whitelist' => ['~^https?://' . preg_quote($request->getHost(), '~') . '/~']]]; | |
| 334 | 334 | } |
| 335 | 335 | } |
| 336 | 336 | namespace Kibo\Phast\Environment; |
| 337 | 337 | |
| @@ -1153,10 +1153,14 @@ | ||
| 1153 | 1153 | $this->client = $client; |
| 1154 | 1154 | } |
| 1155 | 1155 | public function retrieve(\Kibo\Phast\ValueObjects\URL $url) |
| 1156 | 1156 | { |
| 1157 | + $cdnLoop = ['Phast']; | |
| 1158 | + if (!empty($_SERVER['HTTP_CDN_LOOP'])) { | |
| 1159 | + $cdnLoop[] = $_SERVER['HTTP_CDN_LOOP']; | |
| 1160 | + } | |
| 1157 | 1161 | try { |
| 1158 | - $response = $this->client->get($url, ['User-Agent' => 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0']); | |
| 1162 | + $response = $this->client->get($url, ['User-Agent' => 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0', 'CDN-Loop' => implode(', ', $cdnLoop)]); | |
| 1159 | 1163 | } catch (\Exception $e) { |
| 1160 | 1164 | $this->logger()->warning('Caught {cls} while fetching {url}: ({code}) {message}', ['cls' => get_class($e), 'url' => (string) $url, 'code' => $e->getCode(), 'message' => $e->getMessage()]); |
| 1161 | 1165 | return false; |
| 1162 | 1166 | } |
| @@ -1273,13 +1277,13 @@ | ||
| 1273 | 1277 | return $cb($file); |
| 1274 | 1278 | } |
| 1275 | 1279 | private function getExtensionForURL(\Kibo\Phast\ValueObjects\URL $url) |
| 1276 | 1280 | { |
| 1277 | - $dotPosition = strrpos($url->getPath(), '.'); | |
| 1281 | + $dotPosition = strrpos($url->getDecodedPath(), '.'); | |
| 1278 | 1282 | if ($dotPosition === false) { |
| 1279 | 1283 | return ''; |
| 1280 | 1284 | } |
| 1281 | - return strtolower(substr($url->getPath(), $dotPosition + 1)); | |
| 1285 | + return strtolower(substr($url->getDecodedPath(), $dotPosition + 1)); | |
| 1282 | 1286 | } |
| 1283 | 1287 | private function getFileForURL(\Kibo\Phast\ValueObjects\URL $url) |
| 1284 | 1288 | { |
| 1285 | 1289 | if (!isset($this->map[$url->getHost()])) { |
| @@ -1286,15 +1290,15 @@ | ||
| 1286 | 1290 | return false; |
| 1287 | 1291 | } |
| 1288 | 1292 | $submap = $this->map[$url->getHost()]; |
| 1289 | 1293 | if (!is_array($submap)) { |
| 1290 | - return $this->appendNormalized($submap, $url->getPath()); | |
| 1294 | + return $this->appendNormalized($submap, $url->getDecodedPath()); | |
| 1291 | 1295 | } |
| 1292 | 1296 | $selectedPath = null; |
| 1293 | 1297 | $selectedRoot = null; |
| 1294 | 1298 | foreach ($submap as $prefix => $root) { |
| 1295 | 1299 | $pattern = '~^(?=/)/*?(?:' . str_replace('~', '\\~', $prefix) . ')(?<path>/*(?<=/).*)~'; |
| 1296 | - if (preg_match($pattern, $url->getPath(), $match) && ($selectedPath === null || strlen($match['path']) < strlen($selectedPath))) { | |
| 1300 | + if (preg_match($pattern, $url->getDecodedPath(), $match) && ($selectedPath === null || strlen($match['path']) < strlen($selectedPath))) { | |
| 1297 | 1301 | $selectedRoot = $root; |
| 1298 | 1302 | $selectedPath = $match['path']; |
| 1299 | 1303 | } |
| 1300 | 1304 | } |
| @@ -1526,9 +1530,8 @@ | ||
| 1526 | 1530 | $this->cache = $cache; |
| 1527 | 1531 | } |
| 1528 | 1532 | public function transformElements(\Traversable $elements, \Kibo\Phast\Filters\HTML\HTMLPageContext $context) |
| 1529 | 1533 | { |
| 1530 | - $inTags = ['pre' => 0, 'textarea' => 0]; | |
| 1531 | 1534 | foreach ($elements as $element) { |
| 1532 | 1535 | if ($element instanceof \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag && $element->getTagName() === 'script' && ($content = $element->getTextContent()) !== '') { |
| 1533 | 1536 | $content = trim($content); |
| 1534 | 1537 | if ($this->isJSElement($element) && preg_match('~[()[\\]{};]\\s~', $content)) { |
| @@ -1800,9 +1803,10 @@ | ||
| 1800 | 1803 | if (preg_match($pattern, $url)) { |
| 1801 | 1804 | return true; |
| 1802 | 1805 | } |
| 1803 | 1806 | } |
| 1804 | - if ($this->retriever->getCacheSalt(\Kibo\Phast\ValueObjects\URL::fromString($url))) { | |
| 1807 | + $urlObject = \Kibo\Phast\ValueObjects\URL::fromString($url); | |
| 1808 | + if (preg_match('~\\.(jpe?g|gif|png)$~i', $urlObject->getPath()) && $this->retriever->getCacheSalt($urlObject)) { | |
| 1805 | 1809 | return true; |
| 1806 | 1810 | } |
| 1807 | 1811 | return false; |
| 1808 | 1812 | } |
| @@ -1894,16 +1898,9 @@ | ||
| 1894 | 1898 | } |
| 1895 | 1899 | private function rewriteSrc(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $img, \Kibo\Phast\Filters\HTML\HTMLPageContext $context, $attribute) |
| 1896 | 1900 | { |
| 1897 | 1901 | $url = $img->getAttribute($attribute); |
| 1898 | - $params = []; | |
| 1899 | - foreach (['width', 'height'] as $attr) { | |
| 1900 | - $value = $img->getAttribute($attr); | |
| 1901 | - if (preg_match('/^[1-9][0-9]*$/', $value)) { | |
| 1902 | - $params[$attr] = $value; | |
| 1903 | - } | |
| 1904 | - } | |
| 1905 | - $newURL = $this->rewriter->rewriteUrl($url, $context->getBaseUrl(), $params); | |
| 1902 | + $newURL = $this->rewriter->rewriteUrl($url, $context->getBaseUrl()); | |
| 1906 | 1903 | $img->setAttribute($attribute, $newURL); |
| 1907 | 1904 | } |
| 1908 | 1905 | private function rewriteSrcset(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $img, \Kibo\Phast\Filters\HTML\HTMLPageContext $context, $attribute) |
| 1909 | 1906 | { |
| @@ -2167,9 +2164,9 @@ | ||
| 2167 | 2164 | $bundlerMappings = \Kibo\Phast\Services\Bundler\ShortBundlerParamsParser::getParamsMappings(); |
| 2168 | 2165 | $jsMappings = array_combine(array_values($bundlerMappings), array_keys($bundlerMappings)); |
| 2169 | 2166 | $resourcesLoader = \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/resources-loader.js', "var Promise=phast.ES6Promise.Promise;phast.ResourceLoader=function(a,b){this.get=function(c){return b.get(c).then(function(d){if(typeof d!==\"string\"){throw new Error(\"response should be string\")}return d}).catch(function(){var e=a.get(c);e.then(function(f){b.set(c,f)});return e})}};phast.ResourceLoader.RequestParams={};phast.ResourceLoader.RequestParams.FaultyParams={};phast.ResourceLoader.RequestParams.fromString=function(g){try{return JSON.parse(g)}catch(h){return phast.ResourceLoader.RequestParams.FaultyParams}};phast.ResourceLoader.BundlerServiceClient=function(i,j,k){var l=phast.ResourceLoader.BundlerServiceClient.RequestsPack;var m=l.PackItem;var n;this.get=function(q){if(q===phast.ResourceLoader.RequestParams.FaultyParams){return Promise.reject(new Error(\"Parameters did not parse as JSON\"))}return new Promise(function(r,s){if(n===undefined){n=new l(j)}n.add(new m({success:r,error:s},q));setTimeout(o);if(n.toQuery().length>4500){console.log(\"[Phast] Resource loader: Pack got too big; flushing early...\");o()}})};function o(){if(n===undefined){return}var t=n;n=undefined;p(t)}function p(u){var v=phast.buildServiceUrl({serviceUrl:i,pathInfo:k},\"service=bundler&\"+u.toQuery());var w=function(){console.error(\"[Phast] Request to bundler failed with status\",y.status);console.log(\"URL:\",v);u.handleError()};var x=function(){if(y.status>=200&&y.status<300){u.handleResponse(y.responseText)}else{u.handleError()}};var y=new XMLHttpRequest;y.open(\"GET\",v);y.addEventListener(\"error\",w);y.addEventListener(\"abort\",w);y.addEventListener(\"load\",x);y.send()}};phast.ResourceLoader.BundlerServiceClient.RequestsPack=function(z){var A={};this.getLength=function(){var F=0;for(var G in A){F++}return F};this.add=function(H){var I;if(H.params.token){I=\"token=\"+H.params.token}else if(H.params.ref){I=\"ref=\"+H.params.ref}else{I=\"\"}if(!A[I]){A[I]={params:H.params,requests:[H.request]}}else{A[I].requests.push(H.request)}};this.toQuery=function(){var J=[],K=[],L=\"\";B().forEach(function(M){var N,O;for(var P in A[M].params){if(P===\"cacheMarker\"){K.push(A[M].params.cacheMarker);continue}N=z[P]?z[P]:P;if(P===\"strip-imports\"){O=encodeURIComponent(N)}else if(P===\"src\"){O=encodeURIComponent(N)+\"=\"+encodeURIComponent(C(A[M].params.src,L));L=A[M].params.src}else{O=encodeURIComponent(N)+\"=\"+encodeURIComponent(A[M].params[P])}J.push(O)}});if(K.length>0){J.unshift(\"c=\"+phast.hash(K.join(\"|\"),23045))}return E(J.join(\"&\"))};function B(){return Object.keys(A).sort(function(R,S){return Q(R,S)?1:Q(S,R)?-1:0});function Q(T,U){if(typeof A[T].params.src!==\"undefined\"&&typeof A[U].params.src!==\"undefined\"){return A[T].params.src>A[U].params.src}return T>U}}function C(V,W){var X=0,Y=Math.pow(36,2)-1;while(X<W.length&&V[X]===W[X]){X++}X=Math.min(X,Y);return D(X)+\"\"+V.substr(X)}function D(Z){var \$=[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\",\"k\",\"l\",\"m\",\"n\",\"o\",\"p\",\"q\",\"r\",\"s\",\"t\",\"u\",\"v\",\"w\",\"x\",\"y\",\"z\"];var _=Z%36;var aa=Math.floor((Z-_)/36);return \$[aa]+\$[_]}function E(ba){if(!/(^|&)s=/.test(ba)){return ba}return ba.replace(/(%..)|([A-M])|([N-Z])/gi,function(ca,da,ea,fa){if(da){return ca}return String.fromCharCode(ca.charCodeAt(0)+(ea?13:-13))})}this.handleResponse=function(ga){try{var ha=JSON.parse(ga)}catch(ja){this.handleError();return}var ia=B();if(ha.length!==ia.length){console.error(\"[Phast] Requested\",ia.length,\"items from bundler, but got\",ha.length,\"response(s)\");this.handleError();return}ha.forEach(function(ka,la){if(ka.status===200){A[ia[la]].requests.forEach(function(ma){ma.success(ka.content)})}else{A[ia[la]].requests.forEach(function(na){na.error(new Error(\"Got from bundler: \"+JSON.stringify(ka)))})}})}.bind(this);this.handleError=function(){for(var oa in A){A[oa].requests.forEach(function(pa){pa.error()})}}};phast.ResourceLoader.BundlerServiceClient.RequestsPack.PackItem=function(qa,ra){this.request=qa;this.params=ra};phast.ResourceLoader.IndexedDBStorage=function(sa){var ta=phast.ResourceLoader.IndexedDBStorage;var ua=ta.logPrefix;var va=ta.requestToPromise;var wa;Ba();this.get=function(Ca){return xa(\"readonly\").then(function(Da){return va(Da.get(Ca)).catch(ya(\"reading from store\"))})};this.store=function(Ea){return xa(\"readwrite\").then(function(Fa){return va(Fa.put(Ea)).catch(ya(\"writing to store\"))})};this.clear=function(){return xa(\"readwrite\").then(function(Ga){return va(Ga.clear())})};this.iterateOnAll=function(Ha){return xa(\"readonly\").then(function(Ia){return za(Ha,Ia.openCursor()).catch(ya(\"iterating on all\"))})};function xa(Ja){return wa.get().then(function(Ka){try{return Ka.transaction(sa.storeName,Ja).objectStore(sa.storeName)}catch(La){console.error(ua,\"Could not open store; recreating database:\",La);Aa();throw La}})}function ya(Ma){return function(Na){console.error(ua,\"Error \"+Ma+\":\",Na);Aa();throw Na}}function za(Oa,Pa){return new Promise(function(Qa,Ra){Pa.onsuccess=function(Sa){var Ta=Sa.target.result;if(Ta){Oa(Ta.value);Ta.continue()}else{Qa()}};Pa.onerror=Ra})}function Aa(){var Ua=wa.dropDB().then(Ba);wa={get:function(){return Promise.reject(new Error(\"Database is being dropped and recreated\"))},dropDB:function(){return Ua}}}function Ba(){wa=new phast.ResourceLoader.IndexedDBStorage.Connection(sa)}};phast.ResourceLoader.IndexedDBStorage.logPrefix=\"[Phast] Resource loader:\";phast.ResourceLoader.IndexedDBStorage.requestToPromise=function(Va){return new Promise(function(Wa,Xa){Va.onsuccess=function(){Wa(Va.result)};Va.onerror=function(){Xa(Va.error)}})};phast.ResourceLoader.IndexedDBStorage.ConnectionParams=function(){this.dbName=\"phastResourcesCache\";this.dbVersion=1;this.storeName=\"resources\"};phast.ResourceLoader.IndexedDBStorage.StoredResource=function(Ya,Za){this.token=Ya;this.content=Za};phast.ResourceLoader.IndexedDBStorage.Connection=function(\$a){var _a=phast.ResourceLoader.IndexedDBStorage.logPrefix;var ab=phast.ResourceLoader.IndexedDBStorage.requestToPromise;var bb;this.get=cb;this.dropDB=db;function cb(){if(!bb){bb=eb(\$a)}return bb}function db(){return cb().then(function(gb){console.error(_a,\"Dropping DB\");gb.close();bb=null;return ab(window.indexedDB.deleteDatabase(\$a.dbName))})}function eb(hb){if(typeof window.indexedDB===\"undefined\"){return Promise.reject(new Error(\"IndexedDB is not available\"))}var ib=window.indexedDB.open(hb.dbName,hb.dbVersion);ib.onupgradeneeded=function(){fb(ib.result,hb)};return ab(ib).then(function(jb){jb.onversionchange=function(){console.debug(_a,\"Closing DB\");jb.close();if(bb){bb=null}};return jb}).catch(function(kb){console.log(_a,\"IndexedDB cache is not available. This is usually due to using private browsing mode.\");throw kb})}function fb(lb,mb){lb.createObjectStore(mb.storeName,{keyPath:\"token\"})}};phast.ResourceLoader.StorageCache=function(nb,ob){var pb=phast.ResourceLoader.IndexedDBStorage.StoredResource;this.get=function(xb){return sb(rb(xb))};this.set=function(yb,zb){return tb(rb(yb),zb,false)};var qb=null;function rb(Ab){return JSON.stringify(Ab)}function sb(Bb){return ob.get(Bb).then(function(Cb){if(Cb){return Promise.resolve(Cb.content)}return Promise.resolve()})}function tb(Db,Eb,Fb){return wb().then(function(Gb){var Hb=Eb.length+Gb;if(Hb>nb.maxStorageSize){return Fb||Eb.length>nb.maxStorageSize?Promise.reject(new Error(\"Storage quota will be exceeded\")):ub(Db,Eb)}qb=Hb;var Ib=new pb(Db,Eb);return ob.store(Ib)})}function ub(Jb,Kb){return vb().then(function(){return tb(Jb,Kb,true)})}function vb(){return ob.clear().then(function(){qb=0})}function wb(){if(qb!==null){return Promise.resolve(qb)}var Lb=0;return ob.iterateOnAll(function(Mb){Lb+=Mb.content.length}).then(function(){qb=Lb;return Promise.resolve(qb)})}};phast.ResourceLoader.StorageCache.StorageCacheParams=function(){this.maxStorageSize=4.5*1024*1024};phast.ResourceLoader.BlackholeCache=function(){this.get=function(){return Promise.reject()};this.set=function(){return Promise.reject()}};phast.ResourceLoader.make=function(Nb,Ob,Pb){var Qb=Sb();var Rb=new phast.ResourceLoader.BundlerServiceClient(Nb,Ob,Pb);return new phast.ResourceLoader(Rb,Qb);function Sb(){var Tb=window.navigator.userAgent;if(/safari/i.test(Tb)&&!/chrome|android/i.test(Tb)){console.log(\"[Phast] Not using IndexedDB cache on Safari\");return new phast.ResourceLoader.BlackholeCache}else{var Ub=new phast.ResourceLoader.IndexedDBStorage.ConnectionParams;var Vb=new phast.ResourceLoader.IndexedDBStorage(Ub);var Wb=new phast.ResourceLoader.StorageCache.StorageCacheParams;return new phast.ResourceLoader.StorageCache(Wb,Vb)}}};\n"); |
| 2170 | 2167 | $resourcesLoader->setConfig('resourcesLoader', ['serviceUrl' => (string) $this->serviceUrl, 'shortParamsMappings' => $jsMappings, 'pathInfo' => $this->serviceRequestFormat === \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH]); |
| 2171 | - $scripts = array_merge([\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/runner.js', "phast.config=JSON.parse(atob(phast.config));while(phast.scripts.length){phast.scripts.shift()()}\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/es6-promise.js', "(function(a,b){typeof exports===\"object\"&&typeof module!==\"undefined\"?module.exports=b():typeof define===\"function\"&&define.amd?define(b):a.ES6Promise=b()})(phast,function(){\"use strict\";function c(ia){var ja=typeof ia;return ia!==null&&(ja===\"object\"||ja===\"function\")}function d(ka){return typeof ka===\"function\"}var e=void 0;if(Array.isArray){e=Array.isArray}else{e=function(la){return Object.prototype.toString.call(la)===\"[object Array]\"}}var f=e;var g=0;var h=void 0;var i=void 0;var j=function ma(na,oa){w[g]=na;w[g+1]=oa;g+=2;if(g===2){if(i){i(x)}else{z()}}};function k(pa){i=pa}function l(qa){j=qa}var m=typeof window!==\"undefined\"?window:undefined;var n=m||{};var o=n.MutationObserver||n.WebKitMutationObserver;var p=typeof self===\"undefined\"&&typeof process!==\"undefined\"&&{}.toString.call(process)===\"[object process]\";var q=typeof Uint8ClampedArray!==\"undefined\"&&typeof importScripts!==\"undefined\"&&typeof MessageChannel!==\"undefined\";function r(){return function(){return process.nextTick(x)}}function s(){if(typeof h!==\"undefined\"){return function(){h(x)}}return v()}function t(){var ra=0;var sa=new o(x);var ta=document.createTextNode(\"\");sa.observe(ta,{characterData:true});return function(){ta.data=ra=++ra%2}}function u(){var ua=new MessageChannel;ua.port1.onmessage=x;return function(){return ua.port2.postMessage(0)}}function v(){var va=setTimeout;return function(){return va(x,1)}}var w=new Array(1e3);function x(){for(var wa=0;wa<g;wa+=2){var xa=w[wa];var ya=w[wa+1];xa(ya);w[wa]=undefined;w[wa+1]=undefined}g=0}function y(){try{var za=Function(\"return this\")().require(\"vertx\");h=za.runOnLoop||za.runOnContext;return s()}catch(Aa){return v()}}var z=void 0;if(p){z=r()}else if(o){z=t()}else if(q){z=u()}else if(m===undefined&&typeof require===\"function\"){z=y()}else{z=v()}function A(Ba,Ca){var Da=this;var Ea=new this.constructor(D);if(Ea[C]===undefined){\$(Ea)}var Fa=Da._state;if(Fa){var Ga=arguments[Fa-1];j(function(){return W(Fa,Ea,Ga,Da._result)})}else{T(Da,Ea,Ba,Ca)}return Ea}function B(Ha){var Ia=this;if(Ha&&typeof Ha===\"object\"&&Ha.constructor===Ia){return Ha}var Ja=new Ia(D);P(Ja,Ha);return Ja}var C=Math.random().toString(36).substring(2);function D(){}var E=void 0;var F=1;var G=2;var H={error:null};function I(){return new TypeError(\"You cannot resolve a promise with itself\")}function J(){return new TypeError(\"A promises callback cannot return that same promise.\")}function K(Ka){try{return Ka.then}catch(La){H.error=La;return H}}function L(Ma,Na,Oa,Pa){try{Ma.call(Na,Oa,Pa)}catch(Qa){return Qa}}function M(Ra,Sa,Ta){j(function(Ua){var Va=false;var Wa=L(Ta,Sa,function(Xa){if(Va){return}Va=true;if(Sa!==Xa){P(Ua,Xa)}else{R(Ua,Xa)}},function(Ya){if(Va){return}Va=true;S(Ua,Ya)},\"Settle: \"+(Ua._label||\" unknown promise\"));if(!Va&&Wa){Va=true;S(Ua,Wa)}},Ra)}function N(Za,\$a){if(\$a._state===F){R(Za,\$a._result)}else if(\$a._state===G){S(Za,\$a._result)}else{T(\$a,undefined,function(_a){return P(Za,_a)},function(ab){return S(Za,ab)})}}function O(bb,cb,db){if(cb.constructor===bb.constructor&&db===A&&cb.constructor.resolve===B){N(bb,cb)}else{if(db===H){S(bb,H.error);H.error=null}else if(db===undefined){R(bb,cb)}else if(d(db)){M(bb,cb,db)}else{R(bb,cb)}}}function P(eb,fb){if(eb===fb){S(eb,I())}else if(c(fb)){O(eb,fb,K(fb))}else{R(eb,fb)}}function Q(gb){if(gb._onerror){gb._onerror(gb._result)}U(gb)}function R(hb,ib){if(hb._state!==E){return}hb._result=ib;hb._state=F;if(hb._subscribers.length!==0){j(U,hb)}}function S(jb,kb){if(jb._state!==E){return}jb._state=G;jb._result=kb;j(Q,jb)}function T(lb,mb,nb,ob){var pb=lb._subscribers;var qb=pb.length;lb._onerror=null;pb[qb]=mb;pb[qb+F]=nb;pb[qb+G]=ob;if(qb===0&&lb._state){j(U,lb)}}function U(rb){var sb=rb._subscribers;var tb=rb._state;if(sb.length===0){return}var ub=void 0,vb=void 0,wb=rb._result;for(var xb=0;xb<sb.length;xb+=3){ub=sb[xb];vb=sb[xb+tb];if(ub){W(tb,ub,vb,wb)}else{vb(wb)}}rb._subscribers.length=0}function V(yb,zb){try{return yb(zb)}catch(Ab){H.error=Ab;return H}}function W(Bb,Cb,Db,Eb){var Fb=d(Db),Gb=void 0,Hb=void 0,Ib=void 0,Jb=void 0;if(Fb){Gb=V(Db,Eb);if(Gb===H){Jb=true;Hb=Gb.error;Gb.error=null}else{Ib=true}if(Cb===Gb){S(Cb,J());return}}else{Gb=Eb;Ib=true}if(Cb._state!==E){}else if(Fb&&Ib){P(Cb,Gb)}else if(Jb){S(Cb,Hb)}else if(Bb===F){R(Cb,Gb)}else if(Bb===G){S(Cb,Gb)}}function X(Kb,Lb){try{Lb(function Mb(Nb){P(Kb,Nb)},function Ob(Pb){S(Kb,Pb)})}catch(Qb){S(Kb,Qb)}}var Y=0;function Z(){return Y++}function \$(Rb){Rb[C]=Y++;Rb._state=undefined;Rb._result=undefined;Rb._subscribers=[]}function _(){return new Error(\"Array Methods must be provided an Array\")}var aa=function(){function Sb(Tb,Ub){this._instanceConstructor=Tb;this.promise=new Tb(D);if(!this.promise[C]){\$(this.promise)}if(f(Ub)){this.length=Ub.length;this._remaining=Ub.length;this._result=new Array(this.length);if(this.length===0){R(this.promise,this._result)}else{this.length=this.length||0;this._enumerate(Ub);if(this._remaining===0){R(this.promise,this._result)}}}else{S(this.promise,_())}}Sb.prototype._enumerate=function Vb(Wb){for(var Xb=0;this._state===E&&Xb<Wb.length;Xb++){this._eachEntry(Wb[Xb],Xb)}};Sb.prototype._eachEntry=function Yb(Zb,\$b){var _b=this._instanceConstructor;var ac=_b.resolve;if(ac===B){var bc=K(Zb);if(bc===A&&Zb._state!==E){this._settledAt(Zb._state,\$b,Zb._result)}else if(typeof bc!==\"function\"){this._remaining--;this._result[\$b]=Zb}else if(_b===ga){var cc=new _b(D);O(cc,Zb,bc);this._willSettleAt(cc,\$b)}else{this._willSettleAt(new _b(function(dc){return dc(Zb)}),\$b)}}else{this._willSettleAt(ac(Zb),\$b)}};Sb.prototype._settledAt=function ec(fc,gc,hc){var ic=this.promise;if(ic._state===E){this._remaining--;if(fc===G){S(ic,hc)}else{this._result[gc]=hc}}if(this._remaining===0){R(ic,this._result)}};Sb.prototype._willSettleAt=function jc(kc,lc){var mc=this;T(kc,undefined,function(nc){return mc._settledAt(F,lc,nc)},function(oc){return mc._settledAt(G,lc,oc)})};return Sb}();function ba(pc){return new aa(this,pc).promise}function ca(qc){var rc=this;if(!f(qc)){return new rc(function(sc,tc){return tc(new TypeError(\"You must pass an array to race.\"))})}else{return new rc(function(uc,vc){var wc=qc.length;for(var xc=0;xc<wc;xc++){rc.resolve(qc[xc]).then(uc,vc)}})}}function da(yc){var zc=this;var Ac=new zc(D);S(Ac,yc);return Ac}function ea(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}function fa(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}var ga=function(){function Bc(Cc){this[C]=Z();this._result=this._state=undefined;this._subscribers=[];if(D!==Cc){typeof Cc!==\"function\"&&ea();this instanceof Bc?X(this,Cc):fa()}}Bc.prototype.catch=function Dc(Ec){return this.then(null,Ec)};Bc.prototype.finally=function Fc(Gc){var Hc=this;var Ic=Hc.constructor;return Hc.then(function(Jc){return Ic.resolve(Gc()).then(function(){return Jc})},function(Kc){return Ic.resolve(Gc()).then(function(){throw Kc})})};return Bc}();ga.prototype.then=A;ga.all=ba;ga.race=ca;ga.resolve=B;ga.reject=da;ga._setScheduler=k;ga._setAsap=l;ga._asap=j;function ha(){var Lc=void 0;if(typeof global!==\"undefined\"){Lc=global}else if(typeof self!==\"undefined\"){Lc=self}else{try{Lc=Function(\"return this\")()}catch(Oc){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}}var Mc=Lc.Promise;if(Mc){var Nc=null;try{Nc=Object.prototype.toString.call(Mc.resolve())}catch(Pc){}if(Nc===\"[object Promise]\"&&!Mc.cast){return}}Lc.Promise=ga}ga.polyfill=ha;ga.Promise=ga;return ga});\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/hash.js', "function murmurhash3_32_gc(a,b){var c,d,e,f,g,h,i,j,k,l;c=a.length&3;d=a.length-c;e=b;g=3432918353;i=461845907;l=0;while(l<d){k=a.charCodeAt(l)&255|(a.charCodeAt(++l)&255)<<8|(a.charCodeAt(++l)&255)<<16|(a.charCodeAt(++l)&255)<<24;++l;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k;e=e<<13|e>>>19;f=(e&65535)*5+(((e>>>16)*5&65535)<<16)&4294967295;e=(f&65535)+27492+(((f>>>16)+58964&65535)<<16)}k=0;switch(c){case 3:k^=(a.charCodeAt(l+2)&255)<<16;case 2:k^=(a.charCodeAt(l+1)&255)<<8;case 1:k^=a.charCodeAt(l)&255;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k}e^=a.length;e^=e>>>16;e=(e&65535)*2246822507+(((e>>>16)*2246822507&65535)<<16)&4294967295;e^=e>>>13;e=(e&65535)*3266489909+(((e>>>16)*3266489909&65535)<<16)&4294967295;e^=e>>>16;return e>>>0}phast.hash=murmurhash3_32_gc;\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/service-url.js', "phast.buildServiceUrl=function(a,b){if(a.pathInfo){return appendPathInfo(a.serviceUrl,buildQuery(b))}else{return appendQueryString(a.serviceUrl,buildQuery(b))}};function buildQuery(c){if(typeof c===\"string\"){return c}var d=[];for(var e in c){if(c.hasOwnProperty(e)){d.push(encodeURIComponent(e)+\"=\"+encodeURIComponent(c[e]))}}return d.join(\"&\")}function appendPathInfo(f,g){var h=btoa(g).replace(/=/g,\"\").replace(/\\//g,\"_\").replace(/\\+/g,\"-\");return f.replace(/\\?.*\$/,\"\").replace(/\\/__p__\\.js\$/,\"\")+\"/\"+h+\".q.js\"}function appendQueryString(i,j){var k=i.indexOf(\"?\")>-1?\"&\":\"?\";return i+k+j}\n"), $resourcesLoader, \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/phast.js', "var Promise=phast.ES6Promise;phast.ResourceLoader.instance=phast.ResourceLoader.make(phast.config.resourcesLoader.serviceUrl,phast.config.resourcesLoader.shortParamsMappings,phast.config.resourcesLoader.pathInfo);phast.forEachSelectedElement=function(a,b){Array.prototype.forEach.call(window.document.querySelectorAll(a),b)};phast.once=function(c){var d=false;return function(){if(!d){d=true;c.apply(this,Array.prototype.slice(arguments))}}};phast.on=function(e,f){return new Promise(function(g){e.addEventListener(f,g)})};phast.wait=function(h){return new Promise(function(i){setTimeout(i,h)})};phast.on(document,\"DOMContentLoaded\").then(function(){var j,k;function l(n){return n&&n.nodeType===8&&/^\\s*\\[Phast\\]/.test(n.textContent)}function m(o){while(o){if(l(o)){return o}o=o.nextSibling}return false}k=m(document.documentElement.nextSibling);if(k===false){k=m(document.body.firstChild)}if(k){j=k.textContent.replace(/^\\s+|\\s+\$/g,\"\").split(\"\\n\");console.groupCollapsed(j.shift());console.log(j.join(\"\\n\"));console.groupEnd()}});phast.on(document,\"DOMContentLoaded\").then(function(){var p=performance.timing;var q=[];q.push([\"Downloading phases:\"]);q.push([\" Look up hostname in DNS + %s ms\",t(p.domainLookupEnd-p.fetchStart)]);q.push([\" Establish connection + %s ms\",t(p.connectEnd-p.domainLookupEnd)]);q.push([\" Send request + %s ms\",t(p.requestStart-p.connectEnd)]);q.push([\" Receive first byte + %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Download page + %s ms\",t(p.responseEnd-p.responseStart)]);q.push([\"\"]);q.push([\"Totals:\"]);q.push([\" Time to first byte %s ms\",t(p.responseStart-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Total request time %s ms\",t(p.responseEnd-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseEnd-p.requestStart)]);q.push([\" \"]);var r=[];var s=[];q.forEach(function(u){r.push(u.shift());s=s.concat(u)});console.groupCollapsed(\"[Phast] Client-side performance metrics\");console.log.apply(console,[r.join(\"\\n\")].concat(s));console.groupEnd();function t(v){v=\"\"+v;while(v.length<4){v=\" \"+v}return v}});\n")], $scripts); | |
| 2168 | + $scripts = array_merge([\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/runner.js', "phast.config=JSON.parse(atob(phast.config));while(phast.scripts.length){phast.scripts.shift()()}\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/es6-promise.js', "(function(a,b){typeof exports===\"object\"&&typeof module!==\"undefined\"?module.exports=b():typeof define===\"function\"&&define.amd?define(b):a.ES6Promise=b()})(phast,function(){\"use strict\";function c(ia){var ja=typeof ia;return ia!==null&&(ja===\"object\"||ja===\"function\")}function d(ka){return typeof ka===\"function\"}var e=void 0;if(Array.isArray){e=Array.isArray}else{e=function(la){return Object.prototype.toString.call(la)===\"[object Array]\"}}var f=e;var g=0;var h=void 0;var i=void 0;var j=function ma(na,oa){w[g]=na;w[g+1]=oa;g+=2;if(g===2){if(i){i(x)}else{z()}}};function k(pa){i=pa}function l(qa){j=qa}var m=typeof window!==\"undefined\"?window:undefined;var n=m||{};var o=n.MutationObserver||n.WebKitMutationObserver;var p=typeof self===\"undefined\"&&typeof process!==\"undefined\"&&{}.toString.call(process)===\"[object process]\";var q=typeof Uint8ClampedArray!==\"undefined\"&&typeof importScripts!==\"undefined\"&&typeof MessageChannel!==\"undefined\";function r(){return function(){return process.nextTick(x)}}function s(){if(typeof h!==\"undefined\"){return function(){h(x)}}return v()}function t(){var ra=0;var sa=new o(x);var ta=document.createTextNode(\"\");sa.observe(ta,{characterData:true});return function(){ta.data=ra=++ra%2}}function u(){var ua=new MessageChannel;ua.port1.onmessage=x;return function(){return ua.port2.postMessage(0)}}function v(){var va=setTimeout;return function(){return va(x,1)}}var w=new Array(1e3);function x(){for(var wa=0;wa<g;wa+=2){var xa=w[wa];var ya=w[wa+1];xa(ya);w[wa]=undefined;w[wa+1]=undefined}g=0}function y(){try{var za=Function(\"return this\")().require(\"vertx\");h=za.runOnLoop||za.runOnContext;return s()}catch(Aa){return v()}}var z=void 0;if(p){z=r()}else if(o){z=t()}else if(q){z=u()}else if(m===undefined&&typeof require===\"function\"){z=y()}else{z=v()}function A(Ba,Ca){var Da=this;var Ea=new this.constructor(D);if(Ea[C]===undefined){\$(Ea)}var Fa=Da._state;if(Fa){var Ga=arguments[Fa-1];j(function(){return W(Fa,Ea,Ga,Da._result)})}else{T(Da,Ea,Ba,Ca)}return Ea}function B(Ha){var Ia=this;if(Ha&&typeof Ha===\"object\"&&Ha.constructor===Ia){return Ha}var Ja=new Ia(D);P(Ja,Ha);return Ja}var C=Math.random().toString(36).substring(2);function D(){}var E=void 0;var F=1;var G=2;var H={error:null};function I(){return new TypeError(\"You cannot resolve a promise with itself\")}function J(){return new TypeError(\"A promises callback cannot return that same promise.\")}function K(Ka){try{return Ka.then}catch(La){H.error=La;return H}}function L(Ma,Na,Oa,Pa){try{Ma.call(Na,Oa,Pa)}catch(Qa){return Qa}}function M(Ra,Sa,Ta){j(function(Ua){var Va=false;var Wa=L(Ta,Sa,function(Xa){if(Va){return}Va=true;if(Sa!==Xa){P(Ua,Xa)}else{R(Ua,Xa)}},function(Ya){if(Va){return}Va=true;S(Ua,Ya)},\"Settle: \"+(Ua._label||\" unknown promise\"));if(!Va&&Wa){Va=true;S(Ua,Wa)}},Ra)}function N(Za,\$a){if(\$a._state===F){R(Za,\$a._result)}else if(\$a._state===G){S(Za,\$a._result)}else{T(\$a,undefined,function(_a){return P(Za,_a)},function(ab){return S(Za,ab)})}}function O(bb,cb,db){if(cb.constructor===bb.constructor&&db===A&&cb.constructor.resolve===B){N(bb,cb)}else{if(db===H){S(bb,H.error);H.error=null}else if(db===undefined){R(bb,cb)}else if(d(db)){M(bb,cb,db)}else{R(bb,cb)}}}function P(eb,fb){if(eb===fb){S(eb,I())}else if(c(fb)){O(eb,fb,K(fb))}else{R(eb,fb)}}function Q(gb){if(gb._onerror){gb._onerror(gb._result)}U(gb)}function R(hb,ib){if(hb._state!==E){return}hb._result=ib;hb._state=F;if(hb._subscribers.length!==0){j(U,hb)}}function S(jb,kb){if(jb._state!==E){return}jb._state=G;jb._result=kb;j(Q,jb)}function T(lb,mb,nb,ob){var pb=lb._subscribers;var qb=pb.length;lb._onerror=null;pb[qb]=mb;pb[qb+F]=nb;pb[qb+G]=ob;if(qb===0&&lb._state){j(U,lb)}}function U(rb){var sb=rb._subscribers;var tb=rb._state;if(sb.length===0){return}var ub=void 0,vb=void 0,wb=rb._result;for(var xb=0;xb<sb.length;xb+=3){ub=sb[xb];vb=sb[xb+tb];if(ub){W(tb,ub,vb,wb)}else{vb(wb)}}rb._subscribers.length=0}function V(yb,zb){try{return yb(zb)}catch(Ab){H.error=Ab;return H}}function W(Bb,Cb,Db,Eb){var Fb=d(Db),Gb=void 0,Hb=void 0,Ib=void 0,Jb=void 0;if(Fb){Gb=V(Db,Eb);if(Gb===H){Jb=true;Hb=Gb.error;Gb.error=null}else{Ib=true}if(Cb===Gb){S(Cb,J());return}}else{Gb=Eb;Ib=true}if(Cb._state!==E){}else if(Fb&&Ib){P(Cb,Gb)}else if(Jb){S(Cb,Hb)}else if(Bb===F){R(Cb,Gb)}else if(Bb===G){S(Cb,Gb)}}function X(Kb,Lb){try{Lb(function Mb(Nb){P(Kb,Nb)},function Ob(Pb){S(Kb,Pb)})}catch(Qb){S(Kb,Qb)}}var Y=0;function Z(){return Y++}function \$(Rb){Rb[C]=Y++;Rb._state=undefined;Rb._result=undefined;Rb._subscribers=[]}function _(){return new Error(\"Array Methods must be provided an Array\")}var aa=function(){function Sb(Tb,Ub){this._instanceConstructor=Tb;this.promise=new Tb(D);if(!this.promise[C]){\$(this.promise)}if(f(Ub)){this.length=Ub.length;this._remaining=Ub.length;this._result=new Array(this.length);if(this.length===0){R(this.promise,this._result)}else{this.length=this.length||0;this._enumerate(Ub);if(this._remaining===0){R(this.promise,this._result)}}}else{S(this.promise,_())}}Sb.prototype._enumerate=function Vb(Wb){for(var Xb=0;this._state===E&&Xb<Wb.length;Xb++){this._eachEntry(Wb[Xb],Xb)}};Sb.prototype._eachEntry=function Yb(Zb,\$b){var _b=this._instanceConstructor;var ac=_b.resolve;if(ac===B){var bc=K(Zb);if(bc===A&&Zb._state!==E){this._settledAt(Zb._state,\$b,Zb._result)}else if(typeof bc!==\"function\"){this._remaining--;this._result[\$b]=Zb}else if(_b===ga){var cc=new _b(D);O(cc,Zb,bc);this._willSettleAt(cc,\$b)}else{this._willSettleAt(new _b(function(dc){return dc(Zb)}),\$b)}}else{this._willSettleAt(ac(Zb),\$b)}};Sb.prototype._settledAt=function ec(fc,gc,hc){var ic=this.promise;if(ic._state===E){this._remaining--;if(fc===G){S(ic,hc)}else{this._result[gc]=hc}}if(this._remaining===0){R(ic,this._result)}};Sb.prototype._willSettleAt=function jc(kc,lc){var mc=this;T(kc,undefined,function(nc){return mc._settledAt(F,lc,nc)},function(oc){return mc._settledAt(G,lc,oc)})};return Sb}();function ba(pc){return new aa(this,pc).promise}function ca(qc){var rc=this;if(!f(qc)){return new rc(function(sc,tc){return tc(new TypeError(\"You must pass an array to race.\"))})}else{return new rc(function(uc,vc){var wc=qc.length;for(var xc=0;xc<wc;xc++){rc.resolve(qc[xc]).then(uc,vc)}})}}function da(yc){var zc=this;var Ac=new zc(D);S(Ac,yc);return Ac}function ea(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}function fa(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}var ga=function(){function Bc(Cc){this[C]=Z();this._result=this._state=undefined;this._subscribers=[];if(D!==Cc){typeof Cc!==\"function\"&&ea();this instanceof Bc?X(this,Cc):fa()}}Bc.prototype.catch=function Dc(Ec){return this.then(null,Ec)};Bc.prototype.finally=function Fc(Gc){var Hc=this;var Ic=Hc.constructor;return Hc.then(function(Jc){return Ic.resolve(Gc()).then(function(){return Jc})},function(Kc){return Ic.resolve(Gc()).then(function(){throw Kc})})};return Bc}();ga.prototype.then=A;ga.all=ba;ga.race=ca;ga.resolve=B;ga.reject=da;ga._setScheduler=k;ga._setAsap=l;ga._asap=j;function ha(){var Lc=void 0;if(typeof global!==\"undefined\"){Lc=global}else if(typeof self!==\"undefined\"){Lc=self}else{try{Lc=Function(\"return this\")()}catch(Oc){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}}var Mc=Lc.Promise;if(Mc){var Nc=null;try{Nc=Object.prototype.toString.call(Mc.resolve())}catch(Pc){}if(Nc===\"[object Promise]\"&&!Mc.cast){return}}Lc.Promise=ga}ga.polyfill=ha;ga.Promise=ga;return ga});\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/hash.js', "function murmurhash3_32_gc(a,b){var c,d,e,f,g,h,i,j,k,l;c=a.length&3;d=a.length-c;e=b;g=3432918353;i=461845907;l=0;while(l<d){k=a.charCodeAt(l)&255|(a.charCodeAt(++l)&255)<<8|(a.charCodeAt(++l)&255)<<16|(a.charCodeAt(++l)&255)<<24;++l;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k;e=e<<13|e>>>19;f=(e&65535)*5+(((e>>>16)*5&65535)<<16)&4294967295;e=(f&65535)+27492+(((f>>>16)+58964&65535)<<16)}k=0;switch(c){case 3:k^=(a.charCodeAt(l+2)&255)<<16;case 2:k^=(a.charCodeAt(l+1)&255)<<8;case 1:k^=a.charCodeAt(l)&255;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k}e^=a.length;e^=e>>>16;e=(e&65535)*2246822507+(((e>>>16)*2246822507&65535)<<16)&4294967295;e^=e>>>13;e=(e&65535)*3266489909+(((e>>>16)*3266489909&65535)<<16)&4294967295;e^=e>>>16;return e>>>0}phast.hash=murmurhash3_32_gc;\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/service-url.js', "phast.buildServiceUrl=function(a,b){if(a.pathInfo){return appendPathInfo(a.serviceUrl,buildQuery(b))}else{return appendQueryString(a.serviceUrl,buildQuery(b))}};function buildQuery(c){if(typeof c===\"string\"){return c}var d=[];for(var e in c){if(c.hasOwnProperty(e)){d.push(encodeURIComponent(e)+\"=\"+encodeURIComponent(c[e]))}}return d.join(\"&\")}function appendPathInfo(f,g){var h=btoa(g).replace(/=/g,\"\").replace(/\\//g,\"_\").replace(/\\+/g,\"-\");var i=j(h+\".q.js\");return f.replace(/\\?.*\$/,\"\").replace(/\\/__p__\\.js\$/,\"\")+\"/\"+i;function j(l){return k(k(l).match(/[\\s\\S]{1,255}/g).join(\"/\"))}function k(m){return m.split(\"\").reverse().join(\"\")}}function appendQueryString(n,o){var p=n.indexOf(\"?\")>-1?\"&\":\"?\";return n+p+o}\n"), $resourcesLoader, \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/phast.js', "var Promise=phast.ES6Promise;phast.ResourceLoader.instance=phast.ResourceLoader.make(phast.config.resourcesLoader.serviceUrl,phast.config.resourcesLoader.shortParamsMappings,phast.config.resourcesLoader.pathInfo);phast.forEachSelectedElement=function(a,b){Array.prototype.forEach.call(window.document.querySelectorAll(a),b)};phast.once=function(c){var d=false;return function(){if(!d){d=true;c.apply(this,Array.prototype.slice(arguments))}}};phast.on=function(e,f){return new Promise(function(g){e.addEventListener(f,g)})};phast.wait=function(h){return new Promise(function(i){setTimeout(i,h)})};phast.on(document,\"DOMContentLoaded\").then(function(){var j,k;function l(n){return n&&n.nodeType===8&&/^\\s*\\[Phast\\]/.test(n.textContent)}function m(o){while(o){if(l(o)){return o}o=o.nextSibling}return false}k=m(document.documentElement.nextSibling);if(k===false){k=m(document.body.firstChild)}if(k){j=k.textContent.replace(/^\\s+|\\s+\$/g,\"\").split(\"\\n\");console.groupCollapsed(j.shift());console.log(j.join(\"\\n\"));console.groupEnd()}});phast.on(document,\"DOMContentLoaded\").then(function(){var p=performance.timing;var q=[];q.push([\"Downloading phases:\"]);q.push([\" Look up hostname in DNS + %s ms\",t(p.domainLookupEnd-p.fetchStart)]);q.push([\" Establish connection + %s ms\",t(p.connectEnd-p.domainLookupEnd)]);q.push([\" Send request + %s ms\",t(p.requestStart-p.connectEnd)]);q.push([\" Receive first byte + %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Download page + %s ms\",t(p.responseEnd-p.responseStart)]);q.push([\"\"]);q.push([\"Totals:\"]);q.push([\" Time to first byte %s ms\",t(p.responseStart-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Total request time %s ms\",t(p.responseEnd-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseEnd-p.requestStart)]);q.push([\" \"]);var r=[];var s=[];q.forEach(function(u){r.push(u.shift());s=s.concat(u)});console.groupCollapsed(\"[Phast] Client-side performance metrics\");console.log.apply(console,[r.join(\"\\n\")].concat(s));console.groupEnd();function t(v){v=\"\"+v;while(v.length<4){v=\" \"+v}return v}});\n")], $scripts); | |
| 2172 | 2169 | $compiled = $this->compileScripts($scripts); |
| 2173 | 2170 | return '(' . $compiled . ')(' . $this->compileConfig($scripts) . ');'; |
| 2174 | 2171 | } |
| 2175 | 2172 | /** |
| @@ -2317,8 +2314,29 @@ | ||
| 2317 | 2314 | { |
| 2318 | 2315 | return \Kibo\Phast\ValueObjects\URL::fromString($url)->withBase($this->context->getBaseUrl()); |
| 2319 | 2316 | } |
| 2320 | 2317 | } |
| 2318 | +namespace Kibo\Phast\Filters\HTML\MetaCharset; | |
| 2319 | + | |
| 2320 | +class Filter implements \Kibo\Phast\Filters\HTML\HTMLStreamFilter | |
| 2321 | +{ | |
| 2322 | + public function transformElements(\Traversable $elements, \Kibo\Phast\Filters\HTML\HTMLPageContext $context) | |
| 2323 | + { | |
| 2324 | + $didYield = false; | |
| 2325 | + foreach ($elements as $element) { | |
| 2326 | + if ($element instanceof \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag) { | |
| 2327 | + if ($element->tagName == 'meta' && array_keys($element->getAttributes()) == ['charset']) { | |
| 2328 | + continue; | |
| 2329 | + } | |
| 2330 | + if (!$didYield && !in_array($element->tagName, ['html', 'head', '!doctype'])) { | |
| 2331 | + (yield new \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag('meta', ['charset' => 'utf-8'])); | |
| 2332 | + $didYield = true; | |
| 2333 | + } | |
| 2334 | + } | |
| 2335 | + (yield $element); | |
| 2336 | + } | |
| 2337 | + } | |
| 2338 | +} | |
| 2321 | 2339 | namespace Kibo\Phast\Filters\HTML\BaseURLSetter; |
| 2322 | 2340 | |
| 2323 | 2341 | class Filter extends \Kibo\Phast\Filters\HTML\BaseHTMLStreamFilter |
| 2324 | 2342 | { |
| @@ -3380,8 +3398,452 @@ | ||
| 3380 | 3398 | { |
| 3381 | 3399 | return new \Kibo\Phast\Filters\Text\Decode\Filter(); |
| 3382 | 3400 | } |
| 3383 | 3401 | } |
| 3402 | +namespace Kibo\Phast\JSMin; | |
| 3403 | + | |
| 3404 | +class UnterminatedRegExpException extends \Exception | |
| 3405 | +{ | |
| 3406 | +} | |
| 3407 | +namespace Kibo\Phast\JSMin; | |
| 3408 | + | |
| 3409 | +class UnterminatedCommentException extends \Exception | |
| 3410 | +{ | |
| 3411 | +} | |
| 3412 | +namespace Kibo\Phast\JSMin; | |
| 3413 | + | |
| 3414 | +class UnterminatedStringException extends \Exception | |
| 3415 | +{ | |
| 3416 | +} | |
| 3417 | +namespace Kibo\Phast\JSMin; | |
| 3418 | + | |
| 3419 | +/** | |
| 3420 | + * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin. | |
| 3421 | + * | |
| 3422 | + * <code> | |
| 3423 | + * $minifiedJs = JSMin::minify($js); | |
| 3424 | + * </code> | |
| 3425 | + * | |
| 3426 | + * This is a modified port of jsmin.c. Improvements: | |
| 3427 | + * | |
| 3428 | + * Does not choke on some regexp literals containing quote characters. E.g. /'/ | |
| 3429 | + * | |
| 3430 | + * Spaces are preserved after some add/sub operators, so they are not mistakenly | |
| 3431 | + * converted to post-inc/dec. E.g. a + ++b -> a+ ++b | |
| 3432 | + * | |
| 3433 | + * Preserves multi-line comments that begin with /*! | |
| 3434 | + * | |
| 3435 | + * PHP 5 or higher is required. | |
| 3436 | + * | |
| 3437 | + * Permission is hereby granted to use this version of the library under the | |
| 3438 | + * same terms as jsmin.c, which has the following license: | |
| 3439 | + * | |
| 3440 | + * -- | |
| 3441 | + * Copyright (c) 2002 Douglas Crockford (www.crockford.com) | |
| 3442 | + * | |
| 3443 | + * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| 3444 | + * this software and associated documentation files (the "Software"), to deal in | |
| 3445 | + * the Software without restriction, including without limitation the rights to | |
| 3446 | + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
| 3447 | + * of the Software, and to permit persons to whom the Software is furnished to do | |
| 3448 | + * so, subject to the following conditions: | |
| 3449 | + * | |
| 3450 | + * The above copyright notice and this permission notice shall be included in all | |
| 3451 | + * copies or substantial portions of the Software. | |
| 3452 | + * | |
| 3453 | + * The Software shall be used for Good, not Evil. | |
| 3454 | + * | |
| 3455 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 3456 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 3457 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 3458 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 3459 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 3460 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 3461 | + * SOFTWARE. | |
| 3462 | + * -- | |
| 3463 | + * | |
| 3464 | + * @package JSMin | |
| 3465 | + * @author Ryan Grove <ryan@wonko.com> (PHP port) | |
| 3466 | + * @author Steve Clay <steve@mrclay.org> (modifications + cleanup) | |
| 3467 | + * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp) | |
| 3468 | + * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) | |
| 3469 | + * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port) | |
| 3470 | + * @license http://opensource.org/licenses/mit-license.php MIT License | |
| 3471 | + * @link http://code.google.com/p/jsmin-php/ | |
| 3472 | + */ | |
| 3473 | +class JSMin | |
| 3474 | +{ | |
| 3475 | + const ACTION_KEEP_A = 1; | |
| 3476 | + const ACTION_DELETE_A = 2; | |
| 3477 | + const ACTION_DELETE_A_B = 3; | |
| 3478 | + protected $a = "\n"; | |
| 3479 | + protected $b = ''; | |
| 3480 | + protected $input = ''; | |
| 3481 | + protected $inputIndex = 0; | |
| 3482 | + protected $inputLength = 0; | |
| 3483 | + protected $lookAhead = null; | |
| 3484 | + protected $output = ''; | |
| 3485 | + protected $lastByteOut = ''; | |
| 3486 | + protected $keptComment = ''; | |
| 3487 | + /** | |
| 3488 | + * Minify Javascript. | |
| 3489 | + * | |
| 3490 | + * @param string $js Javascript to be minified | |
| 3491 | + * | |
| 3492 | + * @return string | |
| 3493 | + */ | |
| 3494 | + public static function minify($js) | |
| 3495 | + { | |
| 3496 | + $jsmin = new \Kibo\Phast\JSMin\JSMin($js); | |
| 3497 | + return $jsmin->min(); | |
| 3498 | + } | |
| 3499 | + /** | |
| 3500 | + * @param string $input | |
| 3501 | + */ | |
| 3502 | + public function __construct($input) | |
| 3503 | + { | |
| 3504 | + $this->input = $input; | |
| 3505 | + } | |
| 3506 | + /** | |
| 3507 | + * Perform minification, return result | |
| 3508 | + * | |
| 3509 | + * @return string | |
| 3510 | + */ | |
| 3511 | + public function min() | |
| 3512 | + { | |
| 3513 | + if ($this->output !== '') { | |
| 3514 | + // min already run | |
| 3515 | + return $this->output; | |
| 3516 | + } | |
| 3517 | + $mbIntEnc = null; | |
| 3518 | + if (function_exists('mb_strlen') && (int) ini_get('mbstring.func_overload') & 2) { | |
| 3519 | + $mbIntEnc = mb_internal_encoding(); | |
| 3520 | + mb_internal_encoding('8bit'); | |
| 3521 | + } | |
| 3522 | + if (isset($this->input[0]) && $this->input[0] === "\357") { | |
| 3523 | + $this->input = substr($this->input, 3); | |
| 3524 | + } | |
| 3525 | + $this->input = str_replace("\r\n", "\n", $this->input); | |
| 3526 | + $this->inputLength = strlen($this->input); | |
| 3527 | + $this->action(self::ACTION_DELETE_A_B); | |
| 3528 | + while ($this->a !== null) { | |
| 3529 | + // determine next command | |
| 3530 | + $command = self::ACTION_KEEP_A; | |
| 3531 | + // default | |
| 3532 | + if ($this->isWhiteSpace($this->a)) { | |
| 3533 | + if (($this->lastByteOut === '+' || $this->lastByteOut === '-') && $this->b === $this->lastByteOut) { | |
| 3534 | + // Don't delete this space. If we do, the addition/subtraction | |
| 3535 | + // could be parsed as a post-increment | |
| 3536 | + } elseif (!$this->isAlphaNum($this->b)) { | |
| 3537 | + $command = self::ACTION_DELETE_A; | |
| 3538 | + } | |
| 3539 | + } elseif ($this->isLineTerminator($this->a)) { | |
| 3540 | + if ($this->isWhiteSpace($this->b)) { | |
| 3541 | + $command = self::ACTION_DELETE_A_B; | |
| 3542 | + // in case of mbstring.func_overload & 2, must check for null b, | |
| 3543 | + // otherwise mb_strpos will give WARNING | |
| 3544 | + } elseif ($this->b === null || false === strpos('{[(+-!~', $this->b) && !$this->isAlphaNum($this->b)) { | |
| 3545 | + $command = self::ACTION_DELETE_A; | |
| 3546 | + } | |
| 3547 | + } elseif (!$this->isAlphaNum($this->a)) { | |
| 3548 | + if ($this->isWhiteSpace($this->b) || $this->isLineTerminator($this->b) && false === strpos('}])+-"\'', $this->a)) { | |
| 3549 | + $command = self::ACTION_DELETE_A_B; | |
| 3550 | + } | |
| 3551 | + } | |
| 3552 | + $this->action($command); | |
| 3553 | + } | |
| 3554 | + $this->output = trim($this->output); | |
| 3555 | + if ($mbIntEnc !== null) { | |
| 3556 | + mb_internal_encoding($mbIntEnc); | |
| 3557 | + } | |
| 3558 | + return $this->output; | |
| 3559 | + } | |
| 3560 | + /** | |
| 3561 | + * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. | |
| 3562 | + * ACTION_DELETE_A = Copy B to A. Get the next B. | |
| 3563 | + * ACTION_DELETE_A_B = Get the next B. | |
| 3564 | + * | |
| 3565 | + * @param int $command | |
| 3566 | + * @throws UnterminatedRegExpException|UnterminatedStringException | |
| 3567 | + */ | |
| 3568 | + protected function action($command) | |
| 3569 | + { | |
| 3570 | + // make sure we don't compress "a + ++b" to "a+++b", etc. | |
| 3571 | + if ($command === self::ACTION_DELETE_A_B && $this->b === ' ' && ($this->a === '+' || $this->a === '-')) { | |
| 3572 | + // Note: we're at an addition/substraction operator; the inputIndex | |
| 3573 | + // will certainly be a valid index | |
| 3574 | + if ($this->input[$this->inputIndex] === $this->a) { | |
| 3575 | + // This is "+ +" or "- -". Don't delete the space. | |
| 3576 | + $command = self::ACTION_KEEP_A; | |
| 3577 | + } | |
| 3578 | + } | |
| 3579 | + switch ($command) { | |
| 3580 | + case self::ACTION_KEEP_A: | |
| 3581 | + // 1 | |
| 3582 | + $this->output .= $this->a; | |
| 3583 | + if ($this->keptComment) { | |
| 3584 | + $this->output = rtrim($this->output, "\n"); | |
| 3585 | + $this->output .= $this->keptComment; | |
| 3586 | + $this->keptComment = ''; | |
| 3587 | + } | |
| 3588 | + $this->lastByteOut = $this->a; | |
| 3589 | + // fallthrough intentional | |
| 3590 | + case self::ACTION_DELETE_A: | |
| 3591 | + // 2 | |
| 3592 | + $this->a = $this->b; | |
| 3593 | + if ($this->a === "'" || $this->a === '"' || $this->a === '`') { | |
| 3594 | + // string/template literal | |
| 3595 | + $delimiter = $this->a; | |
| 3596 | + $str = $this->a; | |
| 3597 | + // in case needed for exception | |
| 3598 | + for (;;) { | |
| 3599 | + $this->output .= $this->a; | |
| 3600 | + $this->lastByteOut = $this->a; | |
| 3601 | + $this->a = $this->get(); | |
| 3602 | + if ($this->a === $this->b) { | |
| 3603 | + // end quote | |
| 3604 | + break; | |
| 3605 | + } | |
| 3606 | + if ($delimiter === '`' && $this->isLineTerminator($this->a)) { | |
| 3607 | + // leave the newline | |
| 3608 | + } elseif ($this->isEOF($this->a)) { | |
| 3609 | + $byte = $this->inputIndex - 1; | |
| 3610 | + throw new \Kibo\Phast\JSMin\UnterminatedStringException("JSMin: Unterminated String at byte {$byte}: {$str}"); | |
| 3611 | + } | |
| 3612 | + $str .= $this->a; | |
| 3613 | + if ($this->a === '\\') { | |
| 3614 | + $this->output .= $this->a; | |
| 3615 | + $this->lastByteOut = $this->a; | |
| 3616 | + $this->a = $this->get(); | |
| 3617 | + $str .= $this->a; | |
| 3618 | + } | |
| 3619 | + } | |
| 3620 | + } | |
| 3621 | + // fallthrough intentional | |
| 3622 | + case self::ACTION_DELETE_A_B: | |
| 3623 | + // 3 | |
| 3624 | + $this->b = $this->next(); | |
| 3625 | + if ($this->b === '/' && $this->isRegexpLiteral()) { | |
| 3626 | + $this->output .= $this->a . $this->b; | |
| 3627 | + $pattern = '/'; | |
| 3628 | + // keep entire pattern in case we need to report it in the exception | |
| 3629 | + for (;;) { | |
| 3630 | + $this->a = $this->get(); | |
| 3631 | + $pattern .= $this->a; | |
| 3632 | + if ($this->a === '[') { | |
| 3633 | + for (;;) { | |
| 3634 | + $this->output .= $this->a; | |
| 3635 | + $this->a = $this->get(); | |
| 3636 | + $pattern .= $this->a; | |
| 3637 | + if ($this->a === ']') { | |
| 3638 | + break; | |
| 3639 | + } | |
| 3640 | + if ($this->a === '\\') { | |
| 3641 | + $this->output .= $this->a; | |
| 3642 | + $this->a = $this->get(); | |
| 3643 | + $pattern .= $this->a; | |
| 3644 | + } | |
| 3645 | + if ($this->isEOF($this->a)) { | |
| 3646 | + throw new \Kibo\Phast\JSMin\UnterminatedRegExpException("JSMin: Unterminated set in RegExp at byte " . $this->inputIndex . ": {$pattern}"); | |
| 3647 | + } | |
| 3648 | + } | |
| 3649 | + } | |
| 3650 | + if ($this->a === '/') { | |
| 3651 | + // end pattern | |
| 3652 | + break; | |
| 3653 | + // while (true) | |
| 3654 | + } elseif ($this->a === '\\') { | |
| 3655 | + $this->output .= $this->a; | |
| 3656 | + $this->a = $this->get(); | |
| 3657 | + $pattern .= $this->a; | |
| 3658 | + } elseif ($this->isEOF($this->a)) { | |
| 3659 | + $byte = $this->inputIndex - 1; | |
| 3660 | + throw new \Kibo\Phast\JSMin\UnterminatedRegExpException("JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); | |
| 3661 | + } | |
| 3662 | + $this->output .= $this->a; | |
| 3663 | + $this->lastByteOut = $this->a; | |
| 3664 | + } | |
| 3665 | + $this->b = $this->next(); | |
| 3666 | + } | |
| 3667 | + } | |
| 3668 | + } | |
| 3669 | + /** | |
| 3670 | + * @return bool | |
| 3671 | + */ | |
| 3672 | + protected function isRegexpLiteral() | |
| 3673 | + { | |
| 3674 | + if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) { | |
| 3675 | + // we can't divide after these tokens | |
| 3676 | + return true; | |
| 3677 | + } | |
| 3678 | + // check if first non-ws token is "/" (see starts-regex.js) | |
| 3679 | + $length = strlen($this->output); | |
| 3680 | + if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) { | |
| 3681 | + if ($length < 2) { | |
| 3682 | + // weird edge case | |
| 3683 | + return true; | |
| 3684 | + } | |
| 3685 | + } | |
| 3686 | + // if the "/" follows a keyword, it must be a regexp, otherwise it's best to assume division | |
| 3687 | + $subject = $this->output . trim($this->a); | |
| 3688 | + if (!preg_match('/(?:case|else|in|return|typeof)$/', $subject, $m)) { | |
| 3689 | + // not a keyword | |
| 3690 | + return false; | |
| 3691 | + } | |
| 3692 | + // can't be sure it's a keyword yet (see not-regexp.js) | |
| 3693 | + $charBeforeKeyword = substr($subject, 0 - strlen($m[0]) - 1, 1); | |
| 3694 | + if ($this->isAlphaNum($charBeforeKeyword)) { | |
| 3695 | + // this is really an identifier ending in a keyword, e.g. "xreturn" | |
| 3696 | + return false; | |
| 3697 | + } | |
| 3698 | + // it's a regexp. Remove unneeded whitespace after keyword | |
| 3699 | + if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) { | |
| 3700 | + $this->a = ''; | |
| 3701 | + } | |
| 3702 | + return true; | |
| 3703 | + } | |
| 3704 | + /** | |
| 3705 | + * Return the next character from stdin. Watch out for lookahead. If the character is a control character, | |
| 3706 | + * translate it to a space or linefeed. | |
| 3707 | + * | |
| 3708 | + * @return string | |
| 3709 | + */ | |
| 3710 | + protected function get() | |
| 3711 | + { | |
| 3712 | + $c = $this->lookAhead; | |
| 3713 | + $this->lookAhead = null; | |
| 3714 | + if ($c === null) { | |
| 3715 | + // getc(stdin) | |
| 3716 | + if ($this->inputIndex < $this->inputLength) { | |
| 3717 | + $c = $this->input[$this->inputIndex]; | |
| 3718 | + $this->inputIndex += 1; | |
| 3719 | + } else { | |
| 3720 | + $c = null; | |
| 3721 | + } | |
| 3722 | + } | |
| 3723 | + if ($c === "\r") { | |
| 3724 | + return "\n"; | |
| 3725 | + } | |
| 3726 | + return $c; | |
| 3727 | + } | |
| 3728 | + /** | |
| 3729 | + * Does $a indicate end of input? | |
| 3730 | + * | |
| 3731 | + * @param string $a | |
| 3732 | + * @return bool | |
| 3733 | + */ | |
| 3734 | + protected function isEOF($a) | |
| 3735 | + { | |
| 3736 | + return $a === null || $this->isLineTerminator($a); | |
| 3737 | + } | |
| 3738 | + /** | |
| 3739 | + * Get next char (without getting it). If is ctrl character, translate to a space or newline. | |
| 3740 | + * | |
| 3741 | + * @return string | |
| 3742 | + */ | |
| 3743 | + protected function peek() | |
| 3744 | + { | |
| 3745 | + $this->lookAhead = $this->get(); | |
| 3746 | + return $this->lookAhead; | |
| 3747 | + } | |
| 3748 | + /** | |
| 3749 | + * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. | |
| 3750 | + * | |
| 3751 | + * @param string $c | |
| 3752 | + * | |
| 3753 | + * @return bool | |
| 3754 | + */ | |
| 3755 | + protected function isAlphaNum($c) | |
| 3756 | + { | |
| 3757 | + return preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126; | |
| 3758 | + } | |
| 3759 | + /** | |
| 3760 | + * Consume a single line comment from input (possibly retaining it) | |
| 3761 | + */ | |
| 3762 | + protected function consumeSingleLineComment() | |
| 3763 | + { | |
| 3764 | + $comment = ''; | |
| 3765 | + while (true) { | |
| 3766 | + $get = $this->get(); | |
| 3767 | + $comment .= $get; | |
| 3768 | + if ($this->isEOF($get)) { | |
| 3769 | + // if IE conditional comment | |
| 3770 | + if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | |
| 3771 | + $this->keptComment .= "/{$comment}"; | |
| 3772 | + } | |
| 3773 | + return; | |
| 3774 | + } | |
| 3775 | + } | |
| 3776 | + } | |
| 3777 | + /** | |
| 3778 | + * Consume a multiple line comment from input (possibly retaining it) | |
| 3779 | + * | |
| 3780 | + * @throws UnterminatedCommentException | |
| 3781 | + */ | |
| 3782 | + protected function consumeMultipleLineComment() | |
| 3783 | + { | |
| 3784 | + $this->get(); | |
| 3785 | + $comment = ''; | |
| 3786 | + for (;;) { | |
| 3787 | + $get = $this->get(); | |
| 3788 | + if ($get === '*') { | |
| 3789 | + if ($this->peek() === '/') { | |
| 3790 | + // end of comment reached | |
| 3791 | + $this->get(); | |
| 3792 | + if (0 === strpos($comment, '!')) { | |
| 3793 | + // preserved by YUI Compressor | |
| 3794 | + if (!$this->keptComment) { | |
| 3795 | + // don't prepend a newline if two comments right after one another | |
| 3796 | + $this->keptComment = "\n"; | |
| 3797 | + } | |
| 3798 | + $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; | |
| 3799 | + } else { | |
| 3800 | + if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | |
| 3801 | + // IE conditional | |
| 3802 | + $this->keptComment .= "/*{$comment}*/"; | |
| 3803 | + } | |
| 3804 | + } | |
| 3805 | + return; | |
| 3806 | + } | |
| 3807 | + } elseif ($get === null) { | |
| 3808 | + throw new \Kibo\Phast\JSMin\UnterminatedCommentException("JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); | |
| 3809 | + } | |
| 3810 | + $comment .= $get; | |
| 3811 | + } | |
| 3812 | + } | |
| 3813 | + /** | |
| 3814 | + * Get the next character, skipping over comments. Some comments may be preserved. | |
| 3815 | + * | |
| 3816 | + * @return string | |
| 3817 | + */ | |
| 3818 | + protected function next() | |
| 3819 | + { | |
| 3820 | + $get = $this->get(); | |
| 3821 | + if ($get === '/') { | |
| 3822 | + switch ($this->peek()) { | |
| 3823 | + case '/': | |
| 3824 | + $this->consumeSingleLineComment(); | |
| 3825 | + $get = "\n"; | |
| 3826 | + break; | |
| 3827 | + case '*': | |
| 3828 | + $this->consumeMultipleLineComment(); | |
| 3829 | + $get = ' '; | |
| 3830 | + break; | |
| 3831 | + } | |
| 3832 | + } | |
| 3833 | + return $get; | |
| 3834 | + } | |
| 3835 | + protected function isWhiteSpace($s) | |
| 3836 | + { | |
| 3837 | + // https://www.ecma-international.org/ecma-262/#sec-white-space | |
| 3838 | + return $s !== null && strpos(" \t\v\f", $s) !== false; | |
| 3839 | + } | |
| 3840 | + protected function isLineTerminator($s) | |
| 3841 | + { | |
| 3842 | + // https://www.ecma-international.org/ecma-262/#sec-line-terminators | |
| 3843 | + return $s !== null && strpos("\n\r", $s) !== false; | |
| 3844 | + } | |
| 3845 | +} | |
| 3384 | 3846 | namespace Kibo\Phast\Parsing\HTML; |
| 3385 | 3847 | |
| 3386 | 3848 | class PCRETokenizer |
| 3387 | 3849 | { |
| @@ -4089,8 +4551,12 @@ | ||
| 4089 | 4551 | */ |
| 4090 | 4552 | public static function serve(callable $getConfig = null) |
| 4091 | 4553 | { |
| 4092 | 4554 | $httpRequest = \Kibo\Phast\HTTP\Request::fromGlobals(); |
| 4555 | + if ($httpRequest->getHeader('CDN-Loop') && preg_match('~(^|,)\\s*Phast\\b~', $httpRequest->getHeader('CDN-Loop'))) { | |
| 4556 | + http_response_code(508); | |
| 4557 | + die('Loop detected'); | |
| 4558 | + } | |
| 4093 | 4559 | $serviceRequest = \Kibo\Phast\Services\ServiceRequest::fromHTTPRequest($httpRequest); |
| 4094 | 4560 | $serviceParams = $serviceRequest->getParams(); |
| 4095 | 4561 | if (defined('PHAST_SERVICE')) { |
| 4096 | 4562 | $service = PHAST_SERVICE; |
| @@ -4100,11 +4566,15 @@ | ||
| 4100 | 4566 | } else { |
| 4101 | 4567 | $service = $serviceParams['service']; |
| 4102 | 4568 | } |
| 4103 | 4569 | if (isset($serviceParams['src']) && !headers_sent()) { |
| 4104 | - http_response_code(301); | |
| 4105 | - header('Location: ' . $serviceParams['src']); | |
| 4106 | - header('Cache-Control: max-age=86400'); | |
| 4570 | + if (self::isRewrittenRequest($httpRequest)) { | |
| 4571 | + http_response_code(500); | |
| 4572 | + } else { | |
| 4573 | + http_response_code(301); | |
| 4574 | + header('Location: ' . $serviceParams['src']); | |
| 4575 | + header('Cache-Control: max-age=86400'); | |
| 4576 | + } | |
| 4107 | 4577 | } |
| 4108 | 4578 | if ($getConfig === null) { |
| 4109 | 4579 | $config = []; |
| 4110 | 4580 | } else { |
| @@ -4118,14 +4588,17 @@ | ||
| 4118 | 4588 | \Kibo\Phast\Logging\Log::info('Starting service'); |
| 4119 | 4589 | $response = (new \Kibo\Phast\Services\Factory())->make($service, $runtimeConfig)->serve($serviceRequest); |
| 4120 | 4590 | \Kibo\Phast\Logging\Log::info('Service completed'); |
| 4121 | 4591 | } catch (\Kibo\Phast\Exceptions\UnauthorizedException $e) { |
| 4592 | + echo "Unauthorized\n"; | |
| 4122 | 4593 | \Kibo\Phast\Logging\Log::error('Unauthorized exception: {message}', ['message' => $e->getMessage()]); |
| 4123 | 4594 | exit; |
| 4124 | 4595 | } catch (\Kibo\Phast\Exceptions\ItemNotFoundException $e) { |
| 4596 | + echo "Item not found\n"; | |
| 4125 | 4597 | \Kibo\Phast\Logging\Log::error('Item not found: {message}', ['message' => $e->getMessage()]); |
| 4126 | 4598 | exit; |
| 4127 | 4599 | } catch (\Exception $e) { |
| 4600 | + echo "Internal error, see logs\n"; | |
| 4128 | 4601 | \Kibo\Phast\Logging\Log::critical('Unhandled exception: {type} Message: {message} File: {file} Line: {line}', ['type' => get_class($e), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]); |
| 4129 | 4602 | exit; |
| 4130 | 4603 | } |
| 4131 | 4604 | header_remove('Location'); |
| @@ -4131,8 +4604,12 @@ | ||
| 4131 | 4604 | header_remove('Location'); |
| 4132 | 4605 | header_remove('Cache-Control'); |
| 4133 | 4606 | self::output($httpRequest, $response, $runtimeConfig); |
| 4134 | 4607 | } |
| 4608 | + public static function isRewrittenRequest() | |
| 4609 | + { | |
| 4610 | + return !!\Kibo\Phast\Services\ServiceRequest::getRewrittenService(\Kibo\Phast\HTTP\Request::fromGlobals()); | |
| 4611 | + } | |
| 4135 | 4612 | public static function output(\Kibo\Phast\HTTP\Request $request, \Kibo\Phast\HTTP\Response $response, array $config, \Kibo\Phast\Common\ObjectifiedFunctions $funcs = null) |
| 4136 | 4613 | { |
| 4137 | 4614 | if (is_null($funcs)) { |
| 4138 | 4615 | $funcs = new \Kibo\Phast\Common\ObjectifiedFunctions(); |
| @@ -4295,15 +4772,33 @@ | ||
| 4295 | 4772 | } |
| 4296 | 4773 | } |
| 4297 | 4774 | namespace Kibo\Phast\Common; |
| 4298 | 4775 | |
| 4776 | +class JSMinifier extends \Kibo\Phast\JSMin\JSMin | |
| 4777 | +{ | |
| 4778 | + protected $removeLicenseHeaders; | |
| 4779 | + public function __construct($input, $removeLicenseHeaders = false) | |
| 4780 | + { | |
| 4781 | + parent::__construct($input); | |
| 4782 | + $this->removeLicenseHeaders = $removeLicenseHeaders; | |
| 4783 | + } | |
| 4784 | + protected function consumeMultipleLineComment() | |
| 4785 | + { | |
| 4786 | + parent::consumeMultipleLineComment(); | |
| 4787 | + if ($this->removeLicenseHeaders) { | |
| 4788 | + $this->keptComment = preg_replace('~/\\*!.*?\\*/~s', '', $this->keptComment); | |
| 4789 | + } | |
| 4790 | + } | |
| 4791 | +} | |
| 4792 | +namespace Kibo\Phast\Common; | |
| 4793 | + | |
| 4299 | 4794 | class OutputBufferHandler |
| 4300 | 4795 | { |
| 4301 | 4796 | use \Kibo\Phast\Logging\LoggingTrait; |
| 4302 | 4797 | const START_PATTERN = '~ |
| 4303 | 4798 | ( |
| 4304 | - \\s*+ <!doctype\\s++html> | | |
| 4305 | - \\s*+ <html> | | |
| 4799 | + \\s*+ <!doctype\\s++html\\b[^<>]*> | | |
| 4800 | + \\s*+ <html\\b[^<>]*> | | |
| 4306 | 4801 | \\s*+ <head> | |
| 4307 | 4802 | \\s*+ <!--.*?--> |
| 4308 | 4803 | )++ |
| 4309 | 4804 | ~xsiA'; |
| @@ -4326,9 +4821,9 @@ | ||
| 4326 | 4821 | public function install() |
| 4327 | 4822 | { |
| 4328 | 4823 | $ignoreHandlers = ['default output handler', 'ob_gzhandler']; |
| 4329 | 4824 | if (!array_diff(ob_list_handlers(), $ignoreHandlers)) { |
| 4330 | - while (@ob_end_clean()) { | |
| 4825 | + while (ob_get_level() && @ob_end_clean()) { | |
| 4331 | 4826 | } |
| 4332 | 4827 | } |
| 4333 | 4828 | ob_start([$this, 'handleChunk'], 2); |
| 4334 | 4829 | ob_implicit_flush(1); |
| @@ -4914,8 +5409,13 @@ | ||
| 4914 | 5409 | public function getPass() |
| 4915 | 5410 | { |
| 4916 | 5411 | return $this->pass; |
| 4917 | 5412 | } |
| 5413 | + /** @return string */ | |
| 5414 | + public function getDecodedPath() | |
| 5415 | + { | |
| 5416 | + return urldecode($this->path); | |
| 5417 | + } | |
| 4918 | 5418 | /** |
| 4919 | 5419 | * @return string |
| 4920 | 5420 | */ |
| 4921 | 5421 | public function getPath() |
| @@ -6190,8 +6690,12 @@ | ||
| 6190 | 6690 | /** |
| 6191 | 6691 | * @var string |
| 6192 | 6692 | */ |
| 6193 | 6693 | private $token; |
| 6694 | + /** | |
| 6695 | + * @var bool | |
| 6696 | + */ | |
| 6697 | + private $trusted = false; | |
| 6194 | 6698 | public function __construct() |
| 6195 | 6699 | { |
| 6196 | 6700 | if (!isset(self::$switches)) { |
| 6197 | 6701 | self::$switches = new \Kibo\Phast\Environment\Switches(); |
| @@ -6214,18 +6718,8 @@ | ||
| 6214 | 6718 | return self::$defaultSerializationMode; |
| 6215 | 6719 | } |
| 6216 | 6720 | public static function fromHTTPRequest(\Kibo\Phast\HTTP\Request $request) |
| 6217 | 6721 | { |
| 6218 | - $query = $request->getQuery(); | |
| 6219 | - if ($query->get('src')) { | |
| 6220 | - $query->set('src', preg_replace('~^hxxp(?=s?://)~', 'http', $query->get('src'))); | |
| 6221 | - } | |
| 6222 | - $pathInfo = $request->getPathInfo(); | |
| 6223 | - if ($pathParams = self::parseBase64PathInfo($pathInfo)) { | |
| 6224 | - $query->update($pathParams); | |
| 6225 | - } elseif ($pathInfo) { | |
| 6226 | - $query->update(self::parsePathInfo($pathInfo)); | |
| 6227 | - } | |
| 6228 | 6722 | $instance = new self(); |
| 6229 | 6723 | self::$switches = new \Kibo\Phast\Environment\Switches(); |
| 6230 | 6724 | $instance->httpRequest = $request; |
| 6231 | 6725 | if ($request->getCookie('phast')) { |
| @@ -6230,23 +6724,48 @@ | ||
| 6230 | 6724 | $instance->httpRequest = $request; |
| 6231 | 6725 | if ($request->getCookie('phast')) { |
| 6232 | 6726 | self::$switches = \Kibo\Phast\Environment\Switches::fromString($request->getCookie('phast')); |
| 6233 | 6727 | } |
| 6234 | - if ($token = $query->pop('token')) { | |
| 6235 | - $instance->token = $token; | |
| 6728 | + if ($service = self::getRewrittenService($request)) { | |
| 6729 | + $instance->query = \Kibo\Phast\ValueObjects\Query::fromAssoc(['service' => $service, 'src' => $request->getAbsoluteURI()]); | |
| 6730 | + $instance->trusted = true; | |
| 6731 | + } else { | |
| 6732 | + $query = $request->getQuery(); | |
| 6733 | + if ($query->get('src')) { | |
| 6734 | + $query->set('src', preg_replace('~^hxxp(?=s?://)~', 'http', $query->get('src'))); | |
| 6735 | + } | |
| 6736 | + $pathInfo = $request->getPathInfo(); | |
| 6737 | + if ($pathParams = self::parseBase64PathInfo($pathInfo)) { | |
| 6738 | + $query->update($pathParams); | |
| 6739 | + } elseif ($pathInfo) { | |
| 6740 | + $query->update(self::parsePathInfo($pathInfo)); | |
| 6741 | + } | |
| 6742 | + if ($token = $query->pop('token')) { | |
| 6743 | + $instance->token = $token; | |
| 6744 | + } | |
| 6745 | + $instance->query = $query; | |
| 6746 | + if ($query->get('phast')) { | |
| 6747 | + self::$propagatedSwitches = $query->get('phast'); | |
| 6748 | + $paramsSwitches = \Kibo\Phast\Environment\Switches::fromString($query->get('phast')); | |
| 6749 | + self::$switches = self::$switches->merge($paramsSwitches); | |
| 6750 | + } | |
| 6751 | + if ($query->get('documentRequestId')) { | |
| 6752 | + self::$documentRequestId = $query->get('documentRequestId'); | |
| 6753 | + } else { | |
| 6754 | + self::$documentRequestId = (string) mt_rand(0, 999999999); | |
| 6755 | + } | |
| 6236 | 6756 | } |
| 6237 | - $instance->query = $query; | |
| 6238 | - if ($query->get('phast')) { | |
| 6239 | - self::$propagatedSwitches = $query->get('phast'); | |
| 6240 | - $paramsSwitches = \Kibo\Phast\Environment\Switches::fromString($query->get('phast')); | |
| 6241 | - self::$switches = self::$switches->merge($paramsSwitches); | |
| 6757 | + return $instance; | |
| 6758 | + } | |
| 6759 | + public static function getRewrittenService(\Kibo\Phast\HTTP\Request $request) | |
| 6760 | + { | |
| 6761 | + if ($service = $request->getEnvValue('REDIRECT_PHAST_SERVICE')) { | |
| 6762 | + return $service; | |
| 6242 | 6763 | } |
| 6243 | - if ($query->get('documentRequestId')) { | |
| 6244 | - self::$documentRequestId = $query->get('documentRequestId'); | |
| 6245 | - } else { | |
| 6246 | - self::$documentRequestId = (string) mt_rand(0, 999999999); | |
| 6764 | + if ($service = $request->getEnvValue('PHAST_SERVICE')) { | |
| 6765 | + return $service; | |
| 6247 | 6766 | } |
| 6248 | - return $instance; | |
| 6767 | + return null; | |
| 6249 | 6768 | } |
| 6250 | 6769 | public function hasRequestSwitchesSet() |
| 6251 | 6770 | { |
| 6252 | 6771 | return !empty(self::$propagatedSwitches); |
| @@ -6322,9 +6841,9 @@ | ||
| 6322 | 6841 | * @return bool |
| 6323 | 6842 | */ |
| 6324 | 6843 | public function verify(\Kibo\Phast\Security\ServiceSignature $signature) |
| 6325 | 6844 | { |
| 6326 | - return $signature->verify($this->token, $this->getVerificationString()) || $signature->verify($this->token, $this->getVerificationStringWithoutStemSuffix()); | |
| 6845 | + return $this->trusted || $signature->verify($this->token, $this->getVerificationString()) || $signature->verify($this->token, $this->getVerificationStringWithoutStemSuffix()); | |
| 6327 | 6846 | } |
| 6328 | 6847 | private static function parsePathInfo($string) |
| 6329 | 6848 | { |
| 6330 | 6849 | $values = new \Kibo\Phast\ValueObjects\Query(); |
| @@ -6360,12 +6879,13 @@ | ||
| 6360 | 6879 | return $url->withPath($path)->toString(); |
| 6361 | 6880 | } |
| 6362 | 6881 | private static function parseBase64PathInfo($string) |
| 6363 | 6882 | { |
| 6364 | - if (!preg_match('~^/([a-z0-9_-]+)\\.q\\.js$~i', $string, $match)) { | |
| 6883 | + if (!preg_match('~^((/[a-z0-9_-]+)+)\\.q\\.js$~i', $string, $match)) { | |
| 6365 | 6884 | return null; |
| 6366 | 6885 | } |
| 6367 | - return \Kibo\Phast\ValueObjects\Query::fromString(\Kibo\Phast\Common\Base64url::decode($match[1])); | |
| 6886 | + $data = str_replace('/', '', $match[1]); | |
| 6887 | + return \Kibo\Phast\ValueObjects\Query::fromString(\Kibo\Phast\Common\Base64url::decode($data)); | |
| 6368 | 6888 | } |
| 6369 | 6889 | /** |
| 6370 | 6890 | * @param callable $paramsFilter |
| 6371 | 6891 | * @return string |
| @@ -6615,452 +7135,8 @@ | ||
| 6615 | 7135 | |
| 6616 | 7136 | class UndefinedObjectifiedFunction extends \RuntimeException |
| 6617 | 7137 | { |
| 6618 | 7138 | } |
| 6619 | -namespace JSMin; | |
| 6620 | - | |
| 6621 | -class UnterminatedCommentException extends \Exception | |
| 6622 | -{ | |
| 6623 | -} | |
| 6624 | -namespace JSMin; | |
| 6625 | - | |
| 6626 | -class UnterminatedRegExpException extends \Exception | |
| 6627 | -{ | |
| 6628 | -} | |
| 6629 | -namespace JSMin; | |
| 6630 | - | |
| 6631 | -/** | |
| 6632 | - * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin. | |
| 6633 | - * | |
| 6634 | - * <code> | |
| 6635 | - * $minifiedJs = JSMin::minify($js); | |
| 6636 | - * </code> | |
| 6637 | - * | |
| 6638 | - * This is a modified port of jsmin.c. Improvements: | |
| 6639 | - * | |
| 6640 | - * Does not choke on some regexp literals containing quote characters. E.g. /'/ | |
| 6641 | - * | |
| 6642 | - * Spaces are preserved after some add/sub operators, so they are not mistakenly | |
| 6643 | - * converted to post-inc/dec. E.g. a + ++b -> a+ ++b | |
| 6644 | - * | |
| 6645 | - * Preserves multi-line comments that begin with /*! | |
| 6646 | - * | |
| 6647 | - * PHP 5 or higher is required. | |
| 6648 | - * | |
| 6649 | - * Permission is hereby granted to use this version of the library under the | |
| 6650 | - * same terms as jsmin.c, which has the following license: | |
| 6651 | - * | |
| 6652 | - * -- | |
| 6653 | - * Copyright (c) 2002 Douglas Crockford (www.crockford.com) | |
| 6654 | - * | |
| 6655 | - * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| 6656 | - * this software and associated documentation files (the "Software"), to deal in | |
| 6657 | - * the Software without restriction, including without limitation the rights to | |
| 6658 | - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
| 6659 | - * of the Software, and to permit persons to whom the Software is furnished to do | |
| 6660 | - * so, subject to the following conditions: | |
| 6661 | - * | |
| 6662 | - * The above copyright notice and this permission notice shall be included in all | |
| 6663 | - * copies or substantial portions of the Software. | |
| 6664 | - * | |
| 6665 | - * The Software shall be used for Good, not Evil. | |
| 6666 | - * | |
| 6667 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 6668 | - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 6669 | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 6670 | - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 6671 | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 6672 | - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 6673 | - * SOFTWARE. | |
| 6674 | - * -- | |
| 6675 | - * | |
| 6676 | - * @package JSMin | |
| 6677 | - * @author Ryan Grove <ryan@wonko.com> (PHP port) | |
| 6678 | - * @author Steve Clay <steve@mrclay.org> (modifications + cleanup) | |
| 6679 | - * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp) | |
| 6680 | - * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) | |
| 6681 | - * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port) | |
| 6682 | - * @license http://opensource.org/licenses/mit-license.php MIT License | |
| 6683 | - * @link http://code.google.com/p/jsmin-php/ | |
| 6684 | - */ | |
| 6685 | -class JSMin | |
| 6686 | -{ | |
| 6687 | - const ACTION_KEEP_A = 1; | |
| 6688 | - const ACTION_DELETE_A = 2; | |
| 6689 | - const ACTION_DELETE_A_B = 3; | |
| 6690 | - protected $a = "\n"; | |
| 6691 | - protected $b = ''; | |
| 6692 | - protected $input = ''; | |
| 6693 | - protected $inputIndex = 0; | |
| 6694 | - protected $inputLength = 0; | |
| 6695 | - protected $lookAhead = null; | |
| 6696 | - protected $output = ''; | |
| 6697 | - protected $lastByteOut = ''; | |
| 6698 | - protected $keptComment = ''; | |
| 6699 | - /** | |
| 6700 | - * Minify Javascript. | |
| 6701 | - * | |
| 6702 | - * @param string $js Javascript to be minified | |
| 6703 | - * | |
| 6704 | - * @return string | |
| 6705 | - */ | |
| 6706 | - public static function minify($js) | |
| 6707 | - { | |
| 6708 | - $jsmin = new \JSMin\JSMin($js); | |
| 6709 | - return $jsmin->min(); | |
| 6710 | - } | |
| 6711 | - /** | |
| 6712 | - * @param string $input | |
| 6713 | - */ | |
| 6714 | - public function __construct($input) | |
| 6715 | - { | |
| 6716 | - $this->input = $input; | |
| 6717 | - } | |
| 6718 | - /** | |
| 6719 | - * Perform minification, return result | |
| 6720 | - * | |
| 6721 | - * @return string | |
| 6722 | - */ | |
| 6723 | - public function min() | |
| 6724 | - { | |
| 6725 | - if ($this->output !== '') { | |
| 6726 | - // min already run | |
| 6727 | - return $this->output; | |
| 6728 | - } | |
| 6729 | - $mbIntEnc = null; | |
| 6730 | - if (function_exists('mb_strlen') && (int) ini_get('mbstring.func_overload') & 2) { | |
| 6731 | - $mbIntEnc = mb_internal_encoding(); | |
| 6732 | - mb_internal_encoding('8bit'); | |
| 6733 | - } | |
| 6734 | - if (isset($this->input[0]) && $this->input[0] === "\357") { | |
| 6735 | - $this->input = substr($this->input, 3); | |
| 6736 | - } | |
| 6737 | - $this->input = str_replace("\r\n", "\n", $this->input); | |
| 6738 | - $this->inputLength = strlen($this->input); | |
| 6739 | - $this->action(self::ACTION_DELETE_A_B); | |
| 6740 | - while ($this->a !== null) { | |
| 6741 | - // determine next command | |
| 6742 | - $command = self::ACTION_KEEP_A; | |
| 6743 | - // default | |
| 6744 | - if ($this->isWhiteSpace($this->a)) { | |
| 6745 | - if (($this->lastByteOut === '+' || $this->lastByteOut === '-') && $this->b === $this->lastByteOut) { | |
| 6746 | - // Don't delete this space. If we do, the addition/subtraction | |
| 6747 | - // could be parsed as a post-increment | |
| 6748 | - } elseif (!$this->isAlphaNum($this->b)) { | |
| 6749 | - $command = self::ACTION_DELETE_A; | |
| 6750 | - } | |
| 6751 | - } elseif ($this->isLineTerminator($this->a)) { | |
| 6752 | - if ($this->isWhiteSpace($this->b)) { | |
| 6753 | - $command = self::ACTION_DELETE_A_B; | |
| 6754 | - // in case of mbstring.func_overload & 2, must check for null b, | |
| 6755 | - // otherwise mb_strpos will give WARNING | |
| 6756 | - } elseif ($this->b === null || false === strpos('{[(+-!~', $this->b) && !$this->isAlphaNum($this->b)) { | |
| 6757 | - $command = self::ACTION_DELETE_A; | |
| 6758 | - } | |
| 6759 | - } elseif (!$this->isAlphaNum($this->a)) { | |
| 6760 | - if ($this->isWhiteSpace($this->b) || $this->isLineTerminator($this->b) && false === strpos('}])+-"\'', $this->a)) { | |
| 6761 | - $command = self::ACTION_DELETE_A_B; | |
| 6762 | - } | |
| 6763 | - } | |
| 6764 | - $this->action($command); | |
| 6765 | - } | |
| 6766 | - $this->output = trim($this->output); | |
| 6767 | - if ($mbIntEnc !== null) { | |
| 6768 | - mb_internal_encoding($mbIntEnc); | |
| 6769 | - } | |
| 6770 | - return $this->output; | |
| 6771 | - } | |
| 6772 | - /** | |
| 6773 | - * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. | |
| 6774 | - * ACTION_DELETE_A = Copy B to A. Get the next B. | |
| 6775 | - * ACTION_DELETE_A_B = Get the next B. | |
| 6776 | - * | |
| 6777 | - * @param int $command | |
| 6778 | - * @throws UnterminatedRegExpException|UnterminatedStringException | |
| 6779 | - */ | |
| 6780 | - protected function action($command) | |
| 6781 | - { | |
| 6782 | - // make sure we don't compress "a + ++b" to "a+++b", etc. | |
| 6783 | - if ($command === self::ACTION_DELETE_A_B && $this->b === ' ' && ($this->a === '+' || $this->a === '-')) { | |
| 6784 | - // Note: we're at an addition/substraction operator; the inputIndex | |
| 6785 | - // will certainly be a valid index | |
| 6786 | - if ($this->input[$this->inputIndex] === $this->a) { | |
| 6787 | - // This is "+ +" or "- -". Don't delete the space. | |
| 6788 | - $command = self::ACTION_KEEP_A; | |
| 6789 | - } | |
| 6790 | - } | |
| 6791 | - switch ($command) { | |
| 6792 | - case self::ACTION_KEEP_A: | |
| 6793 | - // 1 | |
| 6794 | - $this->output .= $this->a; | |
| 6795 | - if ($this->keptComment) { | |
| 6796 | - $this->output = rtrim($this->output, "\n"); | |
| 6797 | - $this->output .= $this->keptComment; | |
| 6798 | - $this->keptComment = ''; | |
| 6799 | - } | |
| 6800 | - $this->lastByteOut = $this->a; | |
| 6801 | - // fallthrough intentional | |
| 6802 | - case self::ACTION_DELETE_A: | |
| 6803 | - // 2 | |
| 6804 | - $this->a = $this->b; | |
| 6805 | - if ($this->a === "'" || $this->a === '"' || $this->a === '`') { | |
| 6806 | - // string/template literal | |
| 6807 | - $delimiter = $this->a; | |
| 6808 | - $str = $this->a; | |
| 6809 | - // in case needed for exception | |
| 6810 | - for (;;) { | |
| 6811 | - $this->output .= $this->a; | |
| 6812 | - $this->lastByteOut = $this->a; | |
| 6813 | - $this->a = $this->get(); | |
| 6814 | - if ($this->a === $this->b) { | |
| 6815 | - // end quote | |
| 6816 | - break; | |
| 6817 | - } | |
| 6818 | - if ($delimiter === '`' && $this->isLineTerminator($this->a)) { | |
| 6819 | - // leave the newline | |
| 6820 | - } elseif ($this->isEOF($this->a)) { | |
| 6821 | - $byte = $this->inputIndex - 1; | |
| 6822 | - throw new \JSMin\UnterminatedStringException("JSMin: Unterminated String at byte {$byte}: {$str}"); | |
| 6823 | - } | |
| 6824 | - $str .= $this->a; | |
| 6825 | - if ($this->a === '\\') { | |
| 6826 | - $this->output .= $this->a; | |
| 6827 | - $this->lastByteOut = $this->a; | |
| 6828 | - $this->a = $this->get(); | |
| 6829 | - $str .= $this->a; | |
| 6830 | - } | |
| 6831 | - } | |
| 6832 | - } | |
| 6833 | - // fallthrough intentional | |
| 6834 | - case self::ACTION_DELETE_A_B: | |
| 6835 | - // 3 | |
| 6836 | - $this->b = $this->next(); | |
| 6837 | - if ($this->b === '/' && $this->isRegexpLiteral()) { | |
| 6838 | - $this->output .= $this->a . $this->b; | |
| 6839 | - $pattern = '/'; | |
| 6840 | - // keep entire pattern in case we need to report it in the exception | |
| 6841 | - for (;;) { | |
| 6842 | - $this->a = $this->get(); | |
| 6843 | - $pattern .= $this->a; | |
| 6844 | - if ($this->a === '[') { | |
| 6845 | - for (;;) { | |
| 6846 | - $this->output .= $this->a; | |
| 6847 | - $this->a = $this->get(); | |
| 6848 | - $pattern .= $this->a; | |
| 6849 | - if ($this->a === ']') { | |
| 6850 | - break; | |
| 6851 | - } | |
| 6852 | - if ($this->a === '\\') { | |
| 6853 | - $this->output .= $this->a; | |
| 6854 | - $this->a = $this->get(); | |
| 6855 | - $pattern .= $this->a; | |
| 6856 | - } | |
| 6857 | - if ($this->isEOF($this->a)) { | |
| 6858 | - throw new \JSMin\UnterminatedRegExpException("JSMin: Unterminated set in RegExp at byte " . $this->inputIndex . ": {$pattern}"); | |
| 6859 | - } | |
| 6860 | - } | |
| 6861 | - } | |
| 6862 | - if ($this->a === '/') { | |
| 6863 | - // end pattern | |
| 6864 | - break; | |
| 6865 | - // while (true) | |
| 6866 | - } elseif ($this->a === '\\') { | |
| 6867 | - $this->output .= $this->a; | |
| 6868 | - $this->a = $this->get(); | |
| 6869 | - $pattern .= $this->a; | |
| 6870 | - } elseif ($this->isEOF($this->a)) { | |
| 6871 | - $byte = $this->inputIndex - 1; | |
| 6872 | - throw new \JSMin\UnterminatedRegExpException("JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); | |
| 6873 | - } | |
| 6874 | - $this->output .= $this->a; | |
| 6875 | - $this->lastByteOut = $this->a; | |
| 6876 | - } | |
| 6877 | - $this->b = $this->next(); | |
| 6878 | - } | |
| 6879 | - } | |
| 6880 | - } | |
| 6881 | - /** | |
| 6882 | - * @return bool | |
| 6883 | - */ | |
| 6884 | - protected function isRegexpLiteral() | |
| 6885 | - { | |
| 6886 | - if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) { | |
| 6887 | - // we can't divide after these tokens | |
| 6888 | - return true; | |
| 6889 | - } | |
| 6890 | - // check if first non-ws token is "/" (see starts-regex.js) | |
| 6891 | - $length = strlen($this->output); | |
| 6892 | - if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) { | |
| 6893 | - if ($length < 2) { | |
| 6894 | - // weird edge case | |
| 6895 | - return true; | |
| 6896 | - } | |
| 6897 | - } | |
| 6898 | - // if the "/" follows a keyword, it must be a regexp, otherwise it's best to assume division | |
| 6899 | - $subject = $this->output . trim($this->a); | |
| 6900 | - if (!preg_match('/(?:case|else|in|return|typeof)$/', $subject, $m)) { | |
| 6901 | - // not a keyword | |
| 6902 | - return false; | |
| 6903 | - } | |
| 6904 | - // can't be sure it's a keyword yet (see not-regexp.js) | |
| 6905 | - $charBeforeKeyword = substr($subject, 0 - strlen($m[0]) - 1, 1); | |
| 6906 | - if ($this->isAlphaNum($charBeforeKeyword)) { | |
| 6907 | - // this is really an identifier ending in a keyword, e.g. "xreturn" | |
| 6908 | - return false; | |
| 6909 | - } | |
| 6910 | - // it's a regexp. Remove unneeded whitespace after keyword | |
| 6911 | - if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) { | |
| 6912 | - $this->a = ''; | |
| 6913 | - } | |
| 6914 | - return true; | |
| 6915 | - } | |
| 6916 | - /** | |
| 6917 | - * Return the next character from stdin. Watch out for lookahead. If the character is a control character, | |
| 6918 | - * translate it to a space or linefeed. | |
| 6919 | - * | |
| 6920 | - * @return string | |
| 6921 | - */ | |
| 6922 | - protected function get() | |
| 6923 | - { | |
| 6924 | - $c = $this->lookAhead; | |
| 6925 | - $this->lookAhead = null; | |
| 6926 | - if ($c === null) { | |
| 6927 | - // getc(stdin) | |
| 6928 | - if ($this->inputIndex < $this->inputLength) { | |
| 6929 | - $c = $this->input[$this->inputIndex]; | |
| 6930 | - $this->inputIndex += 1; | |
| 6931 | - } else { | |
| 6932 | - $c = null; | |
| 6933 | - } | |
| 6934 | - } | |
| 6935 | - if ($c === "\r") { | |
| 6936 | - return "\n"; | |
| 6937 | - } | |
| 6938 | - return $c; | |
| 6939 | - } | |
| 6940 | - /** | |
| 6941 | - * Does $a indicate end of input? | |
| 6942 | - * | |
| 6943 | - * @param string $a | |
| 6944 | - * @return bool | |
| 6945 | - */ | |
| 6946 | - protected function isEOF($a) | |
| 6947 | - { | |
| 6948 | - return $a === null || $this->isLineTerminator($a); | |
| 6949 | - } | |
| 6950 | - /** | |
| 6951 | - * Get next char (without getting it). If is ctrl character, translate to a space or newline. | |
| 6952 | - * | |
| 6953 | - * @return string | |
| 6954 | - */ | |
| 6955 | - protected function peek() | |
| 6956 | - { | |
| 6957 | - $this->lookAhead = $this->get(); | |
| 6958 | - return $this->lookAhead; | |
| 6959 | - } | |
| 6960 | - /** | |
| 6961 | - * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. | |
| 6962 | - * | |
| 6963 | - * @param string $c | |
| 6964 | - * | |
| 6965 | - * @return bool | |
| 6966 | - */ | |
| 6967 | - protected function isAlphaNum($c) | |
| 6968 | - { | |
| 6969 | - return preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126; | |
| 6970 | - } | |
| 6971 | - /** | |
| 6972 | - * Consume a single line comment from input (possibly retaining it) | |
| 6973 | - */ | |
| 6974 | - protected function consumeSingleLineComment() | |
| 6975 | - { | |
| 6976 | - $comment = ''; | |
| 6977 | - while (true) { | |
| 6978 | - $get = $this->get(); | |
| 6979 | - $comment .= $get; | |
| 6980 | - if ($this->isEOF($get)) { | |
| 6981 | - // if IE conditional comment | |
| 6982 | - if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | |
| 6983 | - $this->keptComment .= "/{$comment}"; | |
| 6984 | - } | |
| 6985 | - return; | |
| 6986 | - } | |
| 6987 | - } | |
| 6988 | - } | |
| 6989 | - /** | |
| 6990 | - * Consume a multiple line comment from input (possibly retaining it) | |
| 6991 | - * | |
| 6992 | - * @throws UnterminatedCommentException | |
| 6993 | - */ | |
| 6994 | - protected function consumeMultipleLineComment() | |
| 6995 | - { | |
| 6996 | - $this->get(); | |
| 6997 | - $comment = ''; | |
| 6998 | - for (;;) { | |
| 6999 | - $get = $this->get(); | |
| 7000 | - if ($get === '*') { | |
| 7001 | - if ($this->peek() === '/') { | |
| 7002 | - // end of comment reached | |
| 7003 | - $this->get(); | |
| 7004 | - if (0 === strpos($comment, '!')) { | |
| 7005 | - // preserved by YUI Compressor | |
| 7006 | - if (!$this->keptComment) { | |
| 7007 | - // don't prepend a newline if two comments right after one another | |
| 7008 | - $this->keptComment = "\n"; | |
| 7009 | - } | |
| 7010 | - $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; | |
| 7011 | - } else { | |
| 7012 | - if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | |
| 7013 | - // IE conditional | |
| 7014 | - $this->keptComment .= "/*{$comment}*/"; | |
| 7015 | - } | |
| 7016 | - } | |
| 7017 | - return; | |
| 7018 | - } | |
| 7019 | - } elseif ($get === null) { | |
| 7020 | - throw new \JSMin\UnterminatedCommentException("JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); | |
| 7021 | - } | |
| 7022 | - $comment .= $get; | |
| 7023 | - } | |
| 7024 | - } | |
| 7025 | - /** | |
| 7026 | - * Get the next character, skipping over comments. Some comments may be preserved. | |
| 7027 | - * | |
| 7028 | - * @return string | |
| 7029 | - */ | |
| 7030 | - protected function next() | |
| 7031 | - { | |
| 7032 | - $get = $this->get(); | |
| 7033 | - if ($get === '/') { | |
| 7034 | - switch ($this->peek()) { | |
| 7035 | - case '/': | |
| 7036 | - $this->consumeSingleLineComment(); | |
| 7037 | - $get = "\n"; | |
| 7038 | - break; | |
| 7039 | - case '*': | |
| 7040 | - $this->consumeMultipleLineComment(); | |
| 7041 | - $get = ' '; | |
| 7042 | - break; | |
| 7043 | - } | |
| 7044 | - } | |
| 7045 | - return $get; | |
| 7046 | - } | |
| 7047 | - protected function isWhiteSpace($s) | |
| 7048 | - { | |
| 7049 | - // https://www.ecma-international.org/ecma-262/#sec-white-space | |
| 7050 | - return $s !== null && strpos(" \t\v\f", $s) !== false; | |
| 7051 | - } | |
| 7052 | - protected function isLineTerminator($s) | |
| 7053 | - { | |
| 7054 | - // https://www.ecma-international.org/ecma-262/#sec-line-terminators | |
| 7055 | - return $s !== null && strpos("\n\r", $s) !== false; | |
| 7056 | - } | |
| 7057 | -} | |
| 7058 | -namespace JSMin; | |
| 7059 | - | |
| 7060 | -class UnterminatedStringException extends \Exception | |
| 7061 | -{ | |
| 7062 | -} | |
| 7063 | 7139 | namespace Kibo\PhastPlugins\SDK; |
| 7064 | 7140 | |
| 7065 | 7141 | /** |
| 7066 | 7142 | * Provides commonly needed URLs |
| @@ -8419,9 +8495,9 @@ | ||
| 8419 | 8495 | return $this->rootsProvider->getCacheRootCandidates(); |
| 8420 | 8496 | } |
| 8421 | 8497 | public function getCacheRoot() |
| 8422 | 8498 | { |
| 8423 | - $key = md5(@$_SERVER['DOCUMENT_ROOT']) . '.' . (new \Kibo\Phast\Common\System())->getUserId(); | |
| 8499 | + $key = $this->getKey(); | |
| 8424 | 8500 | $candidates = $this->getCacheRootCandidates(); |
| 8425 | 8501 | if ($result = $this->findExistingCacheRoot($key, $candidates)) { |
| 8426 | 8502 | return $result; |
| 8427 | 8503 | } |
| @@ -8433,27 +8509,41 @@ | ||
| 8433 | 8509 | public function hasCacheRoot() |
| 8434 | 8510 | { |
| 8435 | 8511 | return (bool) $this->getCacheRoot(); |
| 8436 | 8512 | } |
| 8513 | + public function getAllCacheRoots() | |
| 8514 | + { | |
| 8515 | + return $this->findAllExistingCacheRoots($this->getKey(), $this->getCacheRootCandidates()); | |
| 8516 | + } | |
| 8517 | + private function getKey() | |
| 8518 | + { | |
| 8519 | + return md5(@$_SERVER['DOCUMENT_ROOT']) . '.' . (new \Kibo\Phast\Common\System())->getUserId(); | |
| 8520 | + } | |
| 8437 | 8521 | private function findExistingCacheRoot($key, $candidates) |
| 8438 | 8522 | { |
| 8439 | - foreach ($candidates as $dir) { | |
| 8523 | + foreach ($this->findAllExistingCacheRoots($key, $candidates) as $checkDir) { | |
| 8524 | + if (!is_writable($checkDir)) { | |
| 8525 | + continue; | |
| 8526 | + } | |
| 8527 | + if (function_exists('posix_geteuid') && fileowner($checkDir) !== posix_geteuid()) { | |
| 8528 | + continue; | |
| 8529 | + } | |
| 8530 | + $this->createIndexFile($checkDir); | |
| 8531 | + return $checkDir; | |
| 8532 | + } | |
| 8533 | + return false; | |
| 8534 | + } | |
| 8535 | + private function findAllExistingCacheRoots($key, $candidates) | |
| 8536 | + { | |
| 8537 | + foreach ($this->getCacheRootCandidates() as $dir) { | |
| 8440 | 8538 | $checkDirs = ["{$dir}/{$key}", "{$dir}/phastpress.{$key}", "{$dir}/phast.{$key}"]; |
| 8441 | 8539 | foreach ($checkDirs as $checkDir) { |
| 8442 | 8540 | if (!is_dir($checkDir)) { |
| 8443 | 8541 | continue; |
| 8444 | 8542 | } |
| 8445 | - if (!is_writable($checkDir)) { | |
| 8446 | - continue; | |
| 8447 | - } | |
| 8448 | - if (function_exists('posix_geteuid') && fileowner($checkDir) !== posix_geteuid()) { | |
| 8449 | - continue; | |
| 8450 | - } | |
| 8451 | - $this->createIndexFile($checkDir); | |
| 8452 | - return $checkDir; | |
| 8543 | + (yield $checkDir); | |
| 8453 | 8544 | } |
| 8454 | 8545 | } |
| 8455 | - return false; | |
| 8456 | 8546 | } |
| 8457 | 8547 | private function createNewCacheRoot($key, $candidates) |
| 8458 | 8548 | { |
| 8459 | 8549 | foreach ($this->getCacheRootCandidates() as $dir) { |
| @@ -8537,9 +8627,9 @@ | ||
| 8537 | 8627 | class Translations |
| 8538 | 8628 | { |
| 8539 | 8629 | const DATA = array('en' => array('AdminPanel' => array('errors' => array('no-cache-root' => '@:plugin-name can not write to any cache directory! Please, make one of the following directories writable: {params}', 'no-service-config' => '@:plugin-name failed to create a service configuration in any of the following directories: {params}', 'network-error' => 'Failed to connect to plugin server! Please, try again later! {params}', 'cache' => '{params}'), 'warnings' => array('disabled' => '@:plugin-name optimizations are off!', 'admin-only' => '@:plugin-name optimizations will be applied only for logged-in users with the "Administrator" privilege. This is for previewing purposes. Select the "On" setting for "@:plugin-name optimizations" below to activate for all users! |
| 8540 | 8630 | ')), 'Backend' => array('install-notice' => 'Thank you for using <b>@:plugin-name</b>. Optimizations are <b>{pluginState}</b>. Go to <b><a href="{settingsUrl}">Settings</a></b> to configure <b>@:plugin-name</b>. |
| 8541 | -', 'status' => array('on' => 'on', 'off' => 'off', 'admin' => 'on for administrators')), 'Information' => array('additional' => 'Additional information'), 'Notification' => array('error' => 'error', 'warning' => 'warning', 'information' => 'information', 'success' => 'success'), 'OnOffSwitch' => array('on' => 'On', 'off' => 'Off'), 'SavingStatus' => array('saving' => 'Saving', 'saved' => 'Saved'), 'Settings' => array('common' => array('tip' => 'Tip:', 'on' => 'On:', 'off' => 'Off:'), 'sections' => array('plugin' => array('title' => 'Plugin', 'enabled' => array('name' => '@:plugin-name optimizations', 'description' => array('main' => 'Test your site {without} and {with}', 'without' => 'without @:plugin-name', 'with' => 'with @:plugin-name')), 'admin-only' => array('name' => 'Only optimize for administrators', 'description' => array('on' => 'Only privileged users will be served with optimized version', 'off' => 'All users will be served with optimized version', 'tip' => 'Use this to preview your site before launching the optimizations')), 'pathinfo' => array('name' => 'Remove query string from processed resources', 'description' => array('start' => 'Make sure that processed resources don\'t have query strings, for a higher score in GTmetrix.', 'on' => 'Use the path for requests for processed resources. This requires a server that supports "PATH_INFO".', 'off' => 'Use the GET parameters for requests for processed resources.')), 'footer-link' => array('name' => 'Let the world know about @:plugin-name', 'description' => 'Add a "Optimized by @:plugin-name" notice to the footer of your site and help spread the word.'), 'compress-service-response' => array('name' => 'Enable gzip compression on processed resources', 'description' => 'This compresses the optimized and bundled JavaScript and CSS generated by PhastPress. Disable this if your server already compresses PhastPress responses.')), 'images' => array('title' => 'Images', 'tags' => array('name' => 'Optimize images in tags', 'description' => 'Compress images with optimal settings. {newline} Resize images to fit {width}x{height} pixels or to the appropriate size for {imgTag} tags with {widthAttr} or {heightAttr}. {newline} Reload changed images while still leveraging browser caching.'), 'css' => array('name' => 'Optimize images in CSS', 'description' => array(0 => 'Compress images in stylesheets with optional settings and resizes the to fit {width}x{height} pixels.', 1 => 'Reload changed images while still leveraging browser caching.')), 'api' => array('name' => 'Use the Phast Image Optimization API', 'description' => array(0 => 'Optimize your images on our servers free of charge.', 1 => 'This will give you the best possible results without installing any software and will reduce the load on your hosting.')), 'lazy' => array('name' => 'Lazy load images', 'description' => array(0 => 'This adds the loading=lazy attribute to img tags so that images are only load once they are visible on the page.', 1 => 'This helps pass the "Defer offscreen images" audit in PageSpeed Insights.'))), 'html-filters' => array('title' => 'HTML, CSS & JS', 'css' => array('name' => 'Optimize CSS', 'description' => array(0 => 'Incline critical styles first and prevent unused styles from blocking the page load.', 1 => 'Minify stylesheets and leverage browser caching.', 2 => 'Inline Google Fonts CSS to speed up font loading.')), 'async-js' => array('name' => 'Load scripts asynchronously', 'description' => 'Allow the page to finish loading before all scripts have been executed.'), 'minify-js' => array('name' => 'Minify scripts and improve caching', 'description' => array(0 => 'Minify scripts and fix caching for Google Analytics and Hotjar.', 1 => 'Reload changed scripts while still leveraging browser caching.')), 'iframe' => array('name' => 'Defer IFrame loading', 'description' => 'Start loading IFrames after the page has finished loading.'), 'minify-html' => array('name' => 'Minify HTML', 'description' => 'Remove unnecessary whitespace from the HTML code of the page.'), 'minify-inline-scripts' => array('name' => 'Minify inline scripts and JSON', 'description' => 'Remove unnecessary whitespace from inline scripts and JSON data.')))))); | |
| 8631 | +', 'status' => array('on' => 'on', 'off' => 'off', 'admin' => 'on for administrators')), 'Information' => array('additional' => 'Additional information'), 'Notification' => array('error' => 'error', 'warning' => 'warning', 'information' => 'information', 'success' => 'success'), 'OnOffSwitch' => array('on' => 'On', 'off' => 'Off'), 'SavingStatus' => array('saving' => 'Saving', 'saved' => 'Saved'), 'Settings' => array('common' => array('tip' => 'Tip:', 'on' => 'On:', 'off' => 'Off:'), 'sections' => array('plugin' => array('title' => 'Plugin', 'enabled' => array('name' => '@:plugin-name optimizations', 'description' => array('main' => 'Test your site {without} and {with}', 'without' => 'without @:plugin-name', 'with' => 'with @:plugin-name')), 'admin-only' => array('name' => 'Only optimize for administrators', 'description' => array('on' => 'Only privileged users will be served with optimized version', 'off' => 'All users will be served with optimized version', 'tip' => 'Use this to preview your site before launching the optimizations')), 'pathinfo' => array('name' => 'Remove query string from processed resources', 'description' => array('start' => 'Make sure that processed resources don\'t have query strings, for a higher score in GTmetrix.', 'on' => 'Use the path for requests for processed resources. This requires a server that supports "PATH_INFO".', 'off' => 'Use the GET parameters for requests for processed resources.')), 'footer-link' => array('name' => 'Let the world know about @:plugin-name', 'description' => 'Add a "Optimized by @:plugin-name" notice to the footer of your site and help spread the word.'), 'compress-service-response' => array('name' => 'Enable gzip compression on processed resources', 'description' => 'This compresses the optimized and bundled JavaScript and CSS generated by PhastPress. Disable this if your server already compresses PhastPress responses.')), 'images' => array('title' => 'Images', 'tags' => array('name' => 'Optimize images in tags', 'description' => 'Compress images with optimal settings. {newline} Resize images to fit {width}x{height} pixels or to the appropriate size for {imgTag} tags with {widthAttr} or {heightAttr}. {newline} Reload changed images while still leveraging browser caching.'), 'css' => array('name' => 'Optimize images in CSS', 'description' => array(0 => 'Compress images in stylesheets with optional settings and resizes the to fit {width}x{height} pixels.', 1 => 'Reload changed images while still leveraging browser caching.')), 'api' => array('name' => 'Use the Phast Image Optimization API', 'description' => array(0 => 'Optimize your images on our servers free of charge.', 1 => 'This will give you the best possible results without installing any software and will reduce the load on your hosting.')), 'lazy' => array('name' => 'Lazy load images', 'description' => array(0 => 'This adds the loading=lazy attribute to img tags so that images are only load once they are visible on the page.', 1 => 'This helps pass the "Defer offscreen images" audit in PageSpeed Insights.'))), 'html-filters' => array('title' => 'HTML, CSS & JS', 'css' => array('name' => 'Optimize CSS', 'description' => array(0 => 'Incline critical styles first and prevent unused styles from blocking the page load.', 1 => 'Minify stylesheets and leverage browser caching.', 2 => 'Inline Google Fonts CSS to speed up font loading.')), 'async-js' => array('name' => 'Load scripts asynchronously', 'description' => 'Allow the page to finish loading before all scripts have been executed.'), 'minify-js' => array('name' => 'Minify scripts and improve caching', 'description' => array(0 => 'Minify scripts and set long cache durations.', 1 => 'Reload changed scripts while still leveraging browser caching.')), 'iframe' => array('name' => 'Defer IFrame loading', 'description' => 'Start loading IFrames after the page has finished loading.'), 'minify-html' => array('name' => 'Minify HTML', 'description' => 'Remove unnecessary whitespace from the HTML code of the page.'), 'minify-inline-scripts' => array('name' => 'Minify inline scripts and JSON', 'description' => 'Remove unnecessary whitespace from inline scripts and JSON data.')))))); | |
| 8542 | 8632 | } |
| 8543 | 8633 | namespace Kibo\PhastPlugins\SDK\AJAX; |
| 8544 | 8634 | |
| 8545 | 8635 | /** |
| @@ -8764,9 +8854,9 @@ | ||
| 8764 | 8854 | (yield $script); |
| 8765 | 8855 | } |
| 8766 | 8856 | protected function afterLoop() |
| 8767 | 8857 | { |
| 8768 | - $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/scripts-loader.js', "var Promise=phast.ES6Promise;phast.ScriptsLoader={};phast.ScriptsLoader.getScriptsInExecutionOrder=function(a,b){var c=a.querySelectorAll('script[type=\"text/phast\"]');var d=[],e=[];for(var f=0;f<c.length;f++){if(getSrc(c[f])!==undefined&&c[f].hasAttribute(\"defer\")){e.push(c[f])}else{d.push(c[f])}}return d.concat(e).map(function(g){return b.makeScriptFromElement(g)})};phast.ScriptsLoader.executeScripts=function(h){var i=h.map(function(k){return k.init()});var j=Promise.resolve();h.forEach(function(l){j=phast.ScriptsLoader.chainScript(j,l)});return j.then(function(){return Promise.all(i).catch(function(){})})};phast.ScriptsLoader.chainScript=function(m,n){var o;try{if(n.describe){o=n.describe()}else{o=\"unknown script\"}}catch(p){o=\"script.describe() failed\"}return m.then(function(){var q=n.execute();q.then(function(){console.debug(\"\342\234\223\",o)});return q}).catch(function(r){console.error(\"\342\234\230\",o);if(r){console.log(r)}})};var insertBefore=window.Element.prototype.insertBefore;phast.ScriptsLoader.Utilities=function(s){this._document=s;var t=0;function u(C){return new Promise(function(D){var E=\"PhastCompleteScript\"+ ++t;var F=s.createElement(\"script\");F.textContent=C;var G=s.createElement(\"script\");G.textContent=E+\"()\";window[E]=H;s.body.appendChild(F);s.body.appendChild(G);function H(){D();s.body.removeChild(F);s.body.removeChild(G);delete window[E]}})}function v(I){var J=s.createElement(I.nodeName);Array.prototype.forEach.call(I.attributes,function(K){J.setAttribute(K.nodeName,K.nodeValue)});return J}function w(L){L.removeAttribute(\"data-phast-params\");var M={};Array.prototype.map.call(L.attributes,function(N){return N.nodeName}).map(function(O){var P=O.match(/^data-phast-original-(.*)/i);if(P){M[P[1].toLowerCase()]=L.getAttribute(O);L.removeAttribute(O)}});Object.keys(M).sort().map(function(Q){L.setAttribute(Q,M[Q])});if(!(\"type\"in M)){L.removeAttribute(\"type\")}}function x(R,S){return new Promise(function(T,U){var V=S.getAttribute(\"src\");S.addEventListener(\"load\",T);S.addEventListener(\"error\",U);S.removeAttribute(\"src\");insertBefore.call(R.parentNode,S,R);R.parentNode.removeChild(R);if(V){S.setAttribute(\"src\",V)}})}function y(W,X){return A(W,function(){return u(X)})}function z(Y,Z){return A(Z,function(){return x(Y,Z)})}function A(\$,_){var aa=\$.nextElementSibling;var ba=Promise.resolve();s.write=function(fa){ca(fa)};s.writeln=function(ga){ca(ga+\"\\n\")};function ca(ha){var ia=s.createElement(\"div\");ia.innerHTML=ha;var ja=da(ia);if(aa&&aa.parentNode!==\$.parentNode){aa=\$.nextElementSibling}while(ia.firstChild){\$.parentNode.insertBefore(ia.firstChild,aa)}ja.map(ea)}function da(ka){return Array.prototype.slice.call(ka.getElementsByTagName(\"script\")).filter(function(la){var ma=la.getAttribute(\"type\");return!ma||/^(text|application)\\/javascript(;|\$)/i.test(ma)})}function ea(na){var oa=new phast.ScriptsLoader.Scripts.Factory(s);var pa=oa.makeScriptFromElement(na);ba=phast.ScriptsLoader.chainScript(ba,pa)}return _().then(function(){return ba}).finally(function(){delete s.write;delete s.writeln})}function B(qa){var ra=s.createElement(\"link\");ra.setAttribute(\"rel\",\"preload\");ra.setAttribute(\"as\",\"script\");ra.setAttribute(\"href\",qa);s.head.appendChild(ra)}this.executeString=u;this.copyElement=v;this.restoreOriginals=w;this.replaceElement=x;this.writeProtectAndExecuteString=y;this.writeProtectAndReplaceElement=z;this.addPreload=B};phast.ScriptsLoader.Scripts={};phast.ScriptsLoader.Scripts.InlineScript=function(sa,ta){this._utils=sa;this._element=ta;this.init=function(){return Promise.resolve()};this.execute=function(){var ua=ta.textContent.replace(/^\\s*<!--.*\\n/i,\"\");sa.restoreOriginals(ta);return sa.writeProtectAndExecuteString(ta,ua)};this.describe=function(){return\"inline script\"}};phast.ScriptsLoader.Scripts.AsyncBrowserScript=function(va,wa){var xa;this._utils=va;this._element=wa;this.init=function(){va.addPreload(getSrc(wa));return new Promise(function(ya){xa=ya})};this.execute=function(){var za=va.copyElement(wa);va.restoreOriginals(za);va.replaceElement(wa,za).then(xa).catch(xa);return Promise.resolve()};this.describe=function(){return\"async script at \"+getSrc(wa)}};phast.ScriptsLoader.Scripts.SyncBrowserScript=function(Aa,Ba){this._utils=Aa;this._element=Ba;this.init=function(){Aa.addPreload(getSrc(Ba));return Promise.resolve()};this.execute=function(){var Ca=Aa.copyElement(Ba);Aa.restoreOriginals(Ca);return Aa.writeProtectAndReplaceElement(Ba,Ca)};this.describe=function(){return\"sync script at \"+getSrc(Ba)}};phast.ScriptsLoader.Scripts.AsyncAJAXScript=function(Da,Ea,Fa,Ga){this._utils=Da;this._element=Ea;this._fetch=Fa;this._fallback=Ga;var Ha;var Ia;this.init=function(){Ha=Fa(Ea);return new Promise(function(Ja){Ia=Ja})};this.execute=function(){Ha.then(function(Ka){Da.restoreOriginals(Ea);return Da.executeString(Ka).then(Ia)}).catch(function(){Ga.init();return Ga.execute().then(Ia)});return Promise.resolve()};this.describe=function(){return\"bundled async script at \"+Ea.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.SyncAJAXScript=function(La,Ma,Na,Oa){this._utils=La;this._element=Ma;this._fetch=Na;this._fallback=Oa;var Pa;this.init=function(){Pa=Na(Ma);return Pa};this.execute=function(){return Pa.then(function(Qa){La.restoreOriginals(Ma);return La.writeProtectAndExecuteString(Ma,Qa)}).catch(function(){Oa.init();return Oa.execute()})};this.describe=function(){return\"bundled sync script at \"+Ma.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.Factory=function(Ra,Sa){var Ta=phast.ScriptsLoader.Scripts;var Ua=new phast.ScriptsLoader.Utilities(Ra);this.makeScriptFromElement=function(Ya){var Za;if(Va(Ya)){if(Xa(Ya)){Za=new Ta.AsyncBrowserScript(Ua,Ya);return Sa?new Ta.AsyncAJAXScript(Ua,Ya,Sa,Za):Za}Za=new Ta.SyncBrowserScript(Ua,Ya);return Sa?new Ta.SyncAJAXScript(Ua,Ya,Sa,Za):Za}if(Wa(Ya)){return new Ta.InlineScript(Ua,Ya)}if(Xa(Ya)){return new Ta.AsyncBrowserScript(Ua,Ya)}return new Ta.SyncBrowserScript(Ua,Ya)};function Va(\$a){return \$a.hasAttribute(\"data-phast-params\")}function Wa(_a){return!_a.hasAttribute(\"src\")}function Xa(ab){return ab.hasAttribute(\"async\")}};function getSrc(bb){if(bb.hasAttribute(\"data-phast-original-src\")){return bb.getAttribute(\"data-phast-original-src\")}else if(bb.hasAttribute(\"src\")){return bb.getAttribute(\"src\")}}\n")); | |
| 8858 | + $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/scripts-loader.js', "var Promise=phast.ES6Promise;var hasCurrentScript=!!document.currentScript;phast.ScriptsLoader={};phast.ScriptsLoader.getScriptsInExecutionOrder=function(a,b){var c=a.querySelectorAll('script[type=\"text/phast\"]');var d=[],e=[];for(var f=0;f<c.length;f++){if(getSrc(c[f])!==undefined&&c[f].hasAttribute(\"defer\")){e.push(c[f])}else{d.push(c[f])}}return d.concat(e).map(function(g){return b.makeScriptFromElement(g)})};phast.ScriptsLoader.executeScripts=function(h){var i=h.map(function(k){return k.init()});var j=Promise.resolve();h.forEach(function(l){j=phast.ScriptsLoader.chainScript(j,l)});return j.then(function(){return Promise.all(i).catch(function(){})})};phast.ScriptsLoader.chainScript=function(m,n){var o;try{if(n.describe){o=n.describe()}else{o=\"unknown script\"}}catch(p){o=\"script.describe() failed\"}return m.then(function(){var q=n.execute();q.then(function(){console.debug(\"\342\234\223\",o)});return q}).catch(function(r){console.error(\"\342\234\230\",o);if(r){console.log(r)}})};var insertBefore=window.Element.prototype.insertBefore;phast.ScriptsLoader.Utilities=function(s){this._document=s;var t=0;function u(C){return new Promise(function(D){var E=\"PhastCompleteScript\"+ ++t;var F=s.createElement(\"script\");F.textContent=C;var G=s.createElement(\"script\");G.textContent=E+\"()\";window[E]=H;s.body.appendChild(F);s.body.appendChild(G);function H(){D();s.body.removeChild(F);s.body.removeChild(G);delete window[E]}})}function v(I){var J=s.createElement(I.nodeName);Array.prototype.forEach.call(I.attributes,function(K){J.setAttribute(K.nodeName,K.nodeValue)});return J}function w(L){L.removeAttribute(\"data-phast-params\");var M={};Array.prototype.map.call(L.attributes,function(N){return N.nodeName}).map(function(O){var P=O.match(/^data-phast-original-(.*)/i);if(P){M[P[1].toLowerCase()]=L.getAttribute(O);L.removeAttribute(O)}});Object.keys(M).sort().map(function(Q){L.setAttribute(Q,M[Q])});if(!(\"type\"in M)){L.removeAttribute(\"type\")}}function x(R,S){return new Promise(function(T,U){var V=S.getAttribute(\"src\");S.addEventListener(\"load\",T);S.addEventListener(\"error\",U);S.removeAttribute(\"src\");insertBefore.call(R.parentNode,S,R);R.parentNode.removeChild(R);if(V){S.setAttribute(\"src\",V)}})}function y(W,X){return A(W,function(){return u(X)})}function z(Y,Z){return A(Z,function(){return x(Y,Z)})}function A(\$,_){var aa=\$.nextElementSibling;var ba=Promise.resolve();var ca;if(isAsync(\$)){ca=\"async\"}else if(isDefer(\$)){ca=\"defer\"}s.write=function(ga){if(ca){console.warn(\"document.write call from \"+ca+\" script ignored\");return}da(ga)};s.writeln=function(ha){if(ca){console.warn(\"document.writeln call from \"+ca+\" script ignored\");return}da(ha+\"\\n\")};if(hasCurrentScript){try{Object.defineProperty(s,\"currentScript\",{configurable:true,get:function(){return \$}})}catch(ia){console.error(\"[Phast] Unable to override document.currentScript on this browser: \",ia)}}function da(ja){var ka=s.createElement(\"div\");ka.innerHTML=ja;var la=ea(ka);if(aa&&aa.parentNode!==\$.parentNode){aa=\$.nextElementSibling}while(ka.firstChild){\$.parentNode.insertBefore(ka.firstChild,aa)}la.map(fa)}function ea(ma){return Array.prototype.slice.call(ma.getElementsByTagName(\"script\")).filter(function(na){var oa=na.getAttribute(\"type\");return!oa||/^(text|application)\\/javascript(;|\$)/i.test(oa)})}function fa(pa){var qa=new phast.ScriptsLoader.Scripts.Factory(s);var ra=qa.makeScriptFromElement(pa);ba=phast.ScriptsLoader.chainScript(ba,ra)}return _().then(function(){return ba}).finally(function(){delete s.write;delete s.writeln;if(hasCurrentScript){delete s.currentScript}})}function B(sa){var ta=s.createElement(\"link\");ta.setAttribute(\"rel\",\"preload\");ta.setAttribute(\"as\",\"script\");ta.setAttribute(\"href\",sa);s.head.appendChild(ta)}this.executeString=u;this.copyElement=v;this.restoreOriginals=w;this.replaceElement=x;this.writeProtectAndExecuteString=y;this.writeProtectAndReplaceElement=z;this.addPreload=B};phast.ScriptsLoader.Scripts={};phast.ScriptsLoader.Scripts.InlineScript=function(ua,va){this._utils=ua;this._element=va;this.init=function(){return Promise.resolve()};this.execute=function(){var wa=va.textContent.replace(/^\\s*<!--.*\\n/i,\"\");ua.restoreOriginals(va);return ua.writeProtectAndExecuteString(va,wa)};this.describe=function(){return\"inline script\"}};phast.ScriptsLoader.Scripts.AsyncBrowserScript=function(xa,ya){var za;this._utils=xa;this._element=ya;this.init=function(){xa.addPreload(getSrc(ya));return new Promise(function(Aa){za=Aa})};this.execute=function(){var Ba=xa.copyElement(ya);xa.restoreOriginals(Ba);xa.replaceElement(ya,Ba).then(za).catch(za);return Promise.resolve()};this.describe=function(){return\"async script at \"+getSrc(ya)}};phast.ScriptsLoader.Scripts.SyncBrowserScript=function(Ca,Da){this._utils=Ca;this._element=Da;this.init=function(){Ca.addPreload(getSrc(Da));return Promise.resolve()};this.execute=function(){var Ea=Ca.copyElement(Da);Ca.restoreOriginals(Ea);return Ca.writeProtectAndReplaceElement(Da,Ea)};this.describe=function(){return\"sync script at \"+getSrc(Da)}};phast.ScriptsLoader.Scripts.AsyncAJAXScript=function(Fa,Ga,Ha,Ia){this._utils=Fa;this._element=Ga;this._fetch=Ha;this._fallback=Ia;var Ja;var Ka;this.init=function(){Ja=Ha(Ga);return new Promise(function(La){Ka=La})};this.execute=function(){Ja.then(function(Ma){Fa.restoreOriginals(Ga);return Fa.writeProtectAndExecuteString(Ga,Ma).then(Ka)}).catch(function(){Ia.init();return Ia.execute().then(Ka)});return Promise.resolve()};this.describe=function(){return\"bundled async script at \"+Ga.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.SyncAJAXScript=function(Na,Oa,Pa,Qa){this._utils=Na;this._element=Oa;this._fetch=Pa;this._fallback=Qa;var Ra;this.init=function(){Ra=Pa(Oa);return Ra};this.execute=function(){return Ra.then(function(Sa){Na.restoreOriginals(Oa);return Na.writeProtectAndExecuteString(Oa,Sa)}).catch(function(){Qa.init();return Qa.execute()})};this.describe=function(){return\"bundled sync script at \"+Oa.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.Factory=function(Ta,Ua){var Va=phast.ScriptsLoader.Scripts;var Wa=new phast.ScriptsLoader.Utilities(Ta);this.makeScriptFromElement=function(Za){var \$a;if(Xa(Za)){if(isAsync(Za)){\$a=new Va.AsyncBrowserScript(Wa,Za);return Ua?new Va.AsyncAJAXScript(Wa,Za,Ua,\$a):\$a}\$a=new Va.SyncBrowserScript(Wa,Za);return Ua?new Va.SyncAJAXScript(Wa,Za,Ua,\$a):\$a}if(Ya(Za)){return new Va.InlineScript(Wa,Za)}if(isAsync(Za)){return new Va.AsyncBrowserScript(Wa,Za)}return new Va.SyncBrowserScript(Wa,Za)};function Xa(_a){return _a.hasAttribute(\"data-phast-params\")}function Ya(ab){return!ab.hasAttribute(\"src\")}};function getSrc(bb){if(bb.hasAttribute(\"data-phast-original-src\")){return bb.getAttribute(\"data-phast-original-src\")}else if(bb.hasAttribute(\"src\")){return bb.getAttribute(\"src\")}}function isAsync(cb){return cb.hasAttribute(\"async\")}function isDefer(db){return db.hasAttribute(\"defer\")}\n")); | |
| 8769 | 8859 | $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/rewrite.js', "var Promise=phast.ES6Promise;var go=phast.once(loadScripts);phast.on(document,\"DOMContentLoaded\").then(function(){if(phast.stylesLoading){phast.onStylesLoaded=go;setTimeout(go,4e3)}else{Promise.resolve().then(go)}});var loadFiltered=false;window.addEventListener(\"load\",function(a){if(!loadFiltered){a.stopImmediatePropagation()}loadFiltered=true});function loadScripts(){var b=new phast.ScriptsLoader.Scripts.Factory(document,fetchScript);var c=phast.ScriptsLoader.getScriptsInExecutionOrder(document,b);if(c.length===0){return}try{Object.defineProperty(document,\"readyState\",{configurable:true,get:function(){return\"loading\"}})}catch(d){console.error(\"[Phast] Unable to override document.readyState on this browser: \",d)}phast.ScriptsLoader.executeScripts(c).then(restoreReadyState)}function restoreReadyState(){window.requestAnimationFrame(function(){delete document[\"readyState\"];triggerEvent(document,\"readystatechange\");triggerEvent(document,\"DOMContentLoaded\");window.requestAnimationFrame(function(){if(loadFiltered){triggerEvent(window,\"load\")}else{loadFiltered=true}})})}function triggerEvent(e,f){var g=document.createEvent(\"Event\");g.initEvent(f,true,true);e.dispatchEvent(g)}function fetchScript(h){return phast.ResourceLoader.instance.get(phast.ResourceLoader.RequestParams.fromString(h.getAttribute(\"data-phast-params\")))}\n")); |
| 8770 | 8860 | } |
| 8771 | 8861 | private function rewrite(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $script) |
| 8772 | 8862 | { |
| @@ -8779,9 +8869,9 @@ | ||
| 8779 | 8869 | } |
| 8780 | 8870 | } |
| 8781 | 8871 | private function isDeferralDisabled(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $script) |
| 8782 | 8872 | { |
| 8783 | - return $script->hasAttribute('data-phast-no-defer') || $script->hasAttribute('data-pagespeed-no-defer') || $script->getAttribute('data-cfasync') === 'false'; | |
| 8873 | + return $script->hasAttribute('data-phast-no-defer') || $script->hasAttribute('data-pagespeed-no-defer') || $script->getAttribute('data-cfasync') === 'false' || preg_match('~^\\s*(?<q>[\'"])phast-no-defer\\k<q>~', $script->textContent); | |
| 8784 | 8874 | } |
| 8785 | 8875 | } |
| 8786 | 8876 | namespace Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags; |
| 8787 | 8877 | |
| @@ -9532,26 +9622,8 @@ | ||
| 9532 | 9622 | if ($this->textContent) { |
| 9533 | 9623 | $o .= " content=[{$this->textContent}]"; |
| 9534 | 9624 | } |
| 9535 | 9625 | return $o; |
| 9536 | - } | |
| 9537 | -} | |
| 9538 | -namespace Kibo\Phast\Common; | |
| 9539 | - | |
| 9540 | -class JSMinifier extends \JSMin\JSMin | |
| 9541 | -{ | |
| 9542 | - protected $removeLicenseHeaders; | |
| 9543 | - public function __construct($input, $removeLicenseHeaders = false) | |
| 9544 | - { | |
| 9545 | - parent::__construct($input); | |
| 9546 | - $this->removeLicenseHeaders = $removeLicenseHeaders; | |
| 9547 | - } | |
| 9548 | - protected function consumeMultipleLineComment() | |
| 9549 | - { | |
| 9550 | - parent::consumeMultipleLineComment(); | |
| 9551 | - if ($this->removeLicenseHeaders) { | |
| 9552 | - $this->keptComment = preg_replace('~/\\*!.*?\\*/~s', '', $this->keptComment); | |
| 9553 | - } | |
| 9554 | 9626 | } |
| 9555 | 9627 | } |
| 9556 | 9628 | namespace Kibo\Phast\Logging\LogWriters\Dummy; |
| 9557 | 9629 | |