PATH:
home
/
vcomplcotr
/
www
/
wp-content
/
plugins
/
akeebabackupwp
/
app
/
vendor
/
akeeba
/
awf
/
src
/
Mvc
/
Engine
<?php /** * @package awf * @copyright Copyright (c)2014-2026 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU GPL version 3 or later */ namespace Awf\Mvc\Engine; use Awf\Filesystem\File; use Awf\Mvc\Compiler\CompilerInterface; use Awf\Utils\Buffer; use Awf\Utils\HashHelper; /** * View engine for compiling PHP template files. */ abstract class CompilingEngine extends AbstractEngine implements EngineInterface { /** @var CompilerInterface The compiler used by this engine */ protected $compiler = null; /** * Get the 3ναlυa+3d contents of the view template. (I use leetspeak here because of bad quality hosts with broken * scanners) * * @param string $path The path to the view template * @param array $forceParams Any additional information to pass to the view template engine * * @return array Content evaluation information */ public function get($path, array $forceParams = []) { // If it's cached return the path to the cached file's path if ($this->isCached($path)) { return [ 'type' => 'path', 'content' => $this->getCachePath($path), 'original' => $path, ]; } /** * Compile and cache the file. We also add the file path in a comment at the top of the file so phpStorm can * debug it. * * @see https://blog.jetbrains.com/phpstorm/2019/02/phpstorm-2019-1-eap-191-5849-26/ * @see https://laravel-news.com/laravel-5-8-blade-template-file-path */ $content = "<?php /* $path */ ?>\n"; $content .= $this->compile($path, $forceParams); $cacheFolder = $this->view->getContainer()->temporaryPath; $cachedFilePath = $this->putToCache($path, $content); $isPHPFile = substr($path, -4) == '.php'; // If we could cache it, return the cached file's path if ($cachedFilePath !== false) { // Bust the opcode cache for .php files if ($isPHPFile) { $this->bustOpCache($path); } return [ 'type' => 'path', 'content' => $cachedFilePath, 'original' => $path, ]; } // We could not write to the cache. Hm, can I use a stream wrapper? $canUseStreams = Buffer::canRegisterWrapper(); if ($canUseStreams) { $id = $this->getIdentifier($path); $streamPath = 'awf://' . $this->view->getContainer()->application_name . '/compiled_templates/' . $id . '.php'; file_put_contents($streamPath, $content); // Bust the opcode cache for .php files if ($isPHPFile) { $this->bustOpCache($path); } return [ 'type' => 'path', 'content' => $streamPath, 'original' => $path, ]; } // I couldn't use a stream wrapper. I have to give up. $errorMessage = "Could not write to your temporary directory “%s”. Please make it writeable to PHP by changing the permissions. Alternatively, ask your host to make sure that they have not disabled the stream_wrapper_register() function in PHP. Moreover, if your host is using the Suhosin patch for PHP ask them to whitelist the awf:// stream wrapper in their server's php.ini file. If you do not understand what this means please contact your host and paste this entire message to them."; throw new \RuntimeException(sprintf($errorMessage, $cacheFolder), 500); } /** * Returns the path where I can find a precompiled version of the uncompiled view template which lives in $path * * @param string $path The path to the uncompiled view template * * @return bool|string False if the view template is outside the component's front- or backend. */ public function getPrecompiledPath($path) { // Normalize the path to the file $path = realpath($path); if ($path === false) { // The file doesn't exist return false; } // Is this path under the application folder? $componentPath = realpath($this->view->getContainer()->basePath); $frontPos = strpos($path, $componentPath); if ($frontPos !== 0) { // This is not a view template shipped with the application, i.e. it can't be precompiled return false; } // Eliminate the component path from $path to get the relative path to the file $relativePath = ltrim(substr($path, strlen($componentPath)), '\\/'); // Break down the relative path to its parts $relativePath = str_replace('\\', '/', $relativePath); $pathParts = explode('/', $relativePath); // Remove the prefix $prefix = array_shift($pathParts); // If it's a legacy view, View, Views, or views prefix remove the 'tmpl' part if ($prefix != 'ViewTemplates') { unset($pathParts[1]); } // Get the last part and process the extension $viewFile = array_pop($pathParts); $extensionWithoutDot = $this->compiler->getFileExtension(); $pathParts[] = substr($viewFile, 0, -strlen($extensionWithoutDot)) . 'php'; $precompiledRelativePath = implode(DIRECTORY_SEPARATOR, $pathParts); return $componentPath . DIRECTORY_SEPARATOR . 'PrecompiledTemplates' . DIRECTORY_SEPARATOR . $precompiledRelativePath; } /** * A method to compile the raw view template into valid PHP * * @param string $path The path to the view template * @param array $forceParams Any additional information to pass to the view template compiler * * @return string The template compiled to executable PHP */ protected function compile($path, array $forceParams = []) { return $this->compiler->compile($path, $forceParams); } /** * Returns a unique identifier for the template file being compiled * * @param string $path The full path to the template file which needs to be compiled * * @return string The unique identifier of the file */ protected function getIdentifier($path) { if (function_exists('sha1')) { return HashHelper::sha1($path); } return HashHelper::md5($path); } /** * Returns the path to cached, compiled version of the template file. * * As of 1.2.0 the cached files are distributed into two subfolder levels for performance reasons, i.e. * `/path/to/tmp/compiled_templates/a/b/abcdef0123456789abcdef0123456789.php` instead of the legacy storage scheme * of `/path/to/tmp/compiled_templates/abcdef0123456789abcdef0123456789.php`. * * @param string $path The full path to the template file which needs to be compiled. * @param bool $legacy Should I use legacy storage (all compiled files in the same folder)? * * @return string The full path to the cached compiled file */ protected function getCachePath(string $path, bool $legacy = false): string { $id = $this->getIdentifier($path); // In legacy mode all files were under the same folder if ($legacy) { return sprintf( '%s/compiled_templates/%s.php', $this->view->getContainer()->temporaryPath, $id ); } // In modern mode files are distributed into two folder levels return sprintf( '%s/compiled_templates/%s/%s/%s.php', $this->view->getContainer()->temporaryPath, substr($id, 0, 1), substr($id, 1, 1), $id ); } /** * Do we have a cached, compiled version of the template file which is up-to-date with the uncompiled file (we check * the last modification timestamp)? * * @param string $path The full path to the template file which needs to be compiled * * @return bool True if we have a cached, compiled, up-to-date version of the file */ protected function isCached($path) { if (!$this->compiler->isCacheable()) { return false; } clearstatcache(); $cachePath = $this->getCachePath($path); if (!file_exists($cachePath)) { // If the legacy file does not exist we return false immediately. $oldCachePath = $this->getCachePath($path, true); if (!file_exists($oldCachePath)) { return false; } // Try to move the file from the legacy into the new location. $lastModTime = @filemtime($oldCachePath) ?: 0; $fs = $this->view->getContainer()->fileSystem; // If the move failed try to delete the old file and return false anyway; we'll have to recompile. if (!$fs->move($oldCachePath, $cachePath)) { $fs->delete($oldCachePath); return false; } /** * Try to change the last modification time of the file we moved if we're using the local filesystem. * Other filesystem adapters do not have the equivalent of touch() as it's not reliably implemented across * FTP / SFTP servers :( */ if ($fs instanceof File) { touch($cachePath, $lastModTime); } } $cacheTime = filemtime($cachePath) ?: 0; $fileTime = filemtime($path) ?: 0; return $fileTime <= $cacheTime; } /** * Get the cached, compiled version of the template file * * @param string $path The full path to the template file which needs to be compiled * * @return bool|string The ceched, compiled contents of the template file or boolean false if the file doesn't * exist */ protected function getCached($path) { $cachePath = $this->getCachePath($path); return file_get_contents($cachePath); } /** * Put the compiled version of a template file into the cache * * @param string $path The full path to the template file which needs to be compiled * @param string $content The compiled content to cache * * @return bool|string The path of the cached file, or boolean false if writing to the cache failed */ protected function putToCache($path, $content) { $cachePath = $this->getCachePath($path); $cacheFolder = dirname($cachePath); $this->makeCacheFolder($cacheFolder); if (@file_put_contents($cachePath, $content)) { return $cachePath; } if ($this->view->getContainer()->fileSystem->write($cachePath, $content)) { return $cachePath; } return false; } /** * Makes sure the cache folder actually exists * * @param string $cacheFolder The absolute filesystem path to the cache folder * * @return void */ private function makeCacheFolder($cacheFolder) { if (@is_dir($cacheFolder)) { return; } if (@mkdir($cacheFolder, 0755, true)) { return; } $this->view->getContainer()->fileSystem->mkdir($cacheFolder, 0644); } /** * Bust the opcode cache for a given .php file * * This method can address opcode caching with: * - Zend OPcache * - Alternative PHP Cache (now defunct) * - Windows Cache Extension for PHP (versions lower than 2.0.0) * - XCache (now defunct) * * @param string $path The file to bus the cache for * * @return void */ private function bustOpCache($path) { if (function_exists('opcache_invalidate')) { opcache_invalidate($path, true); } if (function_exists('apc_compile_file')) { apc_compile_file($path); } if (function_exists('wincache_refresh_if_changed')) { wincache_refresh_if_changed([$path]); } if (function_exists('xcache_asm')) { xcache_asm($path); } } }
[+]
..
[-] EngineInterface.php
[edit]
[-] AbstractEngine.php
[edit]
[-] BladeEngine.php
[edit]
[-] PhpEngine.php
[edit]
[-] CompilingEngine.php
[edit]