core/model/modx/modscript.class.php
<?php
/*
* This file is part of MODX Revolution.
*
* Copyright (c) MODX, LLC. All Rights Reserved.
*
* For complete copyright and license information, see the COPYRIGHT and LICENSE
* files found in the top-level directory of this distribution.
*/
/**
* An element representing executable PHP script content.
*
* {@inheritdoc}
*
* @property int $id
* @property string $name The name of the script
* @property string $description The description of the script
* @property int $editor_type Deprecated
* @property int $category The Category this Script resides in
* @abstract Implement a derivative class that defines a table for storage.
* @package modx
*/
class modScript extends modElement {
/**
* The name of the script
* @var string $_scriptName
*/
public $_scriptName= null;
/**
* The cache key of the script
* @var string $_scriptCacheKey
*/
public $_scriptCacheKey= null;
/**
* @var string The filename of the script to include.
*/
protected $_scriptFilename;
/**
* Override set to properly strip invalid tags from script code
*
* {@inheritdoc}
*/
public function set($k, $v= null, $vType= '') {
if (in_array($k, array('snippet', 'plugincode', 'content'))) {
$v= trim($v);
if (strncmp($v, '<?', 2) == 0) {
$v= substr($v, 2);
if (strncmp($v, 'php', 3) == 0) $v= substr($v, 3);
}
if (substr($v, -2, 2) == '?>') $v= substr($v, 0, -2);
$v= trim($v, " \n\r\0\x0B");
}
$set= parent::set($k, $v, $vType);
return $set;
}
/**
* Process specifically script-related functionality for modScript objects.
*
* {@inheritdoc}
*/
public function process($properties= null, $content= null) {
parent :: process($properties, $content);
if (!$this->_processed) {
$this->_scriptFilename = $this->loadScript();
$this->_result= $this->_scriptFilename !== false && is_readable($this->_scriptFilename);
if ($this->_result) {
if (empty($this->xpdo->event)) $this->xpdo->event = new stdClass();
$modx =& $this->xpdo;
$scriptProperties = $this->xpdo->event->params= $this->_properties; /* store params inside event object */
ob_start();
unset($properties, $content);
extract($scriptProperties, EXTR_SKIP);
$includeResult= include $this->_scriptFilename;
$includeResult= ($includeResult === null ? '' : $includeResult);
if (ob_get_length()) {
$this->_output = ob_get_contents() . $includeResult;
} else {
$this->_output= $includeResult;
}
ob_end_clean();
if ($this->_output && is_string($this->_output)) {
/* collect element tags in the evaluated content and process them */
$maxIterations= intval($this->xpdo->getOption('parser_max_iterations',null,10));
$this->xpdo->parser->processElementTags(
$this->_tag,
$this->_output,
$this->xpdo->parser->isProcessingUncacheable(),
$this->xpdo->parser->isRemovingUnprocessed(),
'[[',
']]',
array(),
$maxIterations
);
}
$this->filterOutput();
unset ($this->xpdo->event->params);
$this->cache();
}
}
$this->_processed= true;
$this->xpdo->parser->setProcessingElement(false);
/* finally, return the processed element content */
return $this->_output;
}
/**
* Get the name of the script source file, written to the cache file system
*
* @return string The filename containing the function generated from the
* script element.
*/
public function getScriptCacheKey() {
if ($this->_scriptCacheKey === null) {
$this->_scriptCacheKey= str_replace('_', '/', $this->getScriptName());
}
return $this->_scriptCacheKey;
}
/**
* Get the name of the function the script has been given.
*
* @return string The function name representing this script element.
*/
public function getScriptName() {
if ($this->_scriptName === null) {
$className= $this->_class;
$this->_scriptName= 'elements_' . strtolower($className) . '_' . $this->get('id');
}
return $this->_scriptName;
}
/**
* Get the include filename for the script, generating it if it does not exist.
*
* @return string|bool The include filename of the script or false.
*/
public function loadScript() {
$includeFilename = $this->xpdo->getCachePath() . 'includes/' . $this->getScriptCacheKey() . '.include.cache.php';
$result = is_readable($includeFilename);
$outdated = false;
$sourceFile = $this->getSourceFile();
if ($this->isStatic() && $result && !empty($sourceFile) && is_readable($sourceFile)) {
$includeMTime = filemtime($includeFilename);
$sourceMTime = filemtime($sourceFile);
$outdated = $sourceMTime > $includeMTime;
}
if (!$result || $outdated) {
$script= false;
if (!$outdated) {
$script= $this->xpdo->cacheManager->get($this->getScriptCacheKey(), array(
xPDO::OPT_CACHE_KEY => $this->xpdo->getOption('cache_scripts_key', null, 'scripts'),
xPDO::OPT_CACHE_HANDLER => $this->xpdo->getOption('cache_scripts_handler', null, $this->xpdo->getOption(xPDO::OPT_CACHE_HANDLER)),
xPDO::OPT_CACHE_FORMAT => (integer) $this->xpdo->getOption('cache_scripts_format', null, $this->xpdo->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)),
));
}
if (!$script) {
$script= $this->xpdo->cacheManager->generateScript($this);
}
if (!empty($script)) {
$options = array();
$folderMode = $this->xpdo->getOption('new_cache_folder_permissions', null, false);
if ($folderMode) $options['new_folder_permissions'] = $folderMode;
$fileMode = $this->xpdo->getOption('new_cache_file_permissions', null, false);
if ($fileMode) $options['new_file_permissions'] = $fileMode;
$result = $this->xpdo->cacheManager->writeFile($includeFilename, "<?php\n" . $script, 'wb' , $options);
}
}
if ($result !== false) {
$result = $includeFilename;
}
return $result;
}
public function getFileContent(array $options = array()) {
$content = parent::getFileContent($options);
if (strncmp($content, '<?', 2) == 0) {
$content= substr($content, 2);
if (strncmp($content, 'php', 3) == 0) $content= substr($content, 3);
}
if (substr($content, -2, 2) == '?>') $content= substr($content, 0, -2);
$content= trim($content, " \0\x0B");
return $content;
}
public function setFileContent($content, array $options = array()) {
$content = "<?php\n{$content}";
return parent::setFileContent($content, $options);
}
}