Files
conservatorio-tomadini/libraries/fof40/View/Engine/CompilingEngine.php
2024-12-17 17:34:10 +01:00

272 lines
6.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\View\Engine;
defined('_JEXEC') || die;
use FOF40\Utils\Buffer;
use FOF40\View\Compiler\CompilerInterface;
use FOF40\View\Exception\PossiblySuhosin;
use Joomla\CMS\Filesystem\File;
/**
* View engine for compiling PHP template files.
*/
abstract class CompilingEngine extends AbstractEngine implements EngineInterface
{
/** @var CompilerInterface The compiler used by this engine */
protected $compiler;
/**
* 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),
];
}
/**
* 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);
$cachePath = $this->putToCache($path, $content);
$isPHPFile = substr($path, -4) == '.php';
// If we could cache it, return the cached file's path
if ($cachePath !== false)
{
// Bust the opcode cache for .php files
if ($isPHPFile)
{
$this->bustOpCache($path);
}
return [
'type' => 'path',
'content' => $cachePath,
];
}
// We could not write to the cache. Hm, can I use a stream wrapper?
$canUseStreams = Buffer::canRegisterWrapper();
if ($canUseStreams)
{
$id = $this->getIdentifier($path);
$streamPath = 'fof://' . $this->view->getContainer()->componentName . '/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,
];
}
// I couldn't use a stream wrapper. I have to give up.
throw new PossiblySuhosin;
}
/**
* 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.
*
* @since 3.3.1
*/
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 component's front- or backend?
$frontendPath = realpath($this->view->getContainer()->frontEndPath);
$backendPath = realpath($this->view->getContainer()->backEndPath);
$backPos = strpos($path, $backendPath);
$frontPos = strpos($path, $frontendPath);
if (($backPos !== 0) && ($frontPos !== 0))
{
// This is not a view template shipped with the component, i.e. it can't be precompiled
return false;
}
// Eliminate the component path from $path to get the relative path to the file
$componentPath = $frontendPath;
if ($backPos === 0)
{
$componentPath = $backendPath;
}
$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') && ($prefix !== 'tmpl'))
{
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);
}
protected function getIdentifier($path)
{
if (function_exists('sha1'))
{
return sha1($path);
}
return md5($path);
}
protected function getCachePath($path)
{
$id = $this->getIdentifier($path);
return JPATH_CACHE . '/' . $this->view->getContainer()->componentName . '/compiled_templates/' . $id . '.php';
}
protected function isCached($path)
{
if (!$this->compiler->isCacheable())
{
return false;
}
$cachePath = $this->getCachePath($path);
if (!file_exists($cachePath))
{
return false;
}
$cacheTime = filemtime($cachePath);
$fileTime = filemtime($path);
return $fileTime <= $cacheTime;
}
protected function getCached($path)
{
$cachePath = $this->getCachePath($path);
return file_get_contents($cachePath);
}
protected function putToCache($path, $content)
{
$cachePath = $this->getCachePath($path);
if (@file_put_contents($cachePath, $content))
{
return $cachePath;
}
if (File::write($cachePath, $content))
{
return $cachePath;
}
return false;
}
/**
* 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);
}
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);
}
}
}