modscript.class.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. /*
  3. * This file is part of MODX Revolution.
  4. *
  5. * Copyright (c) MODX, LLC. All Rights Reserved.
  6. *
  7. * For complete copyright and license information, see the COPYRIGHT and LICENSE
  8. * files found in the top-level directory of this distribution.
  9. */
  10. /**
  11. * An element representing executable PHP script content.
  12. *
  13. * {@inheritdoc}
  14. *
  15. * @property int $id
  16. * @property string $name The name of the script
  17. * @property string $description The description of the script
  18. * @property int $editor_type Deprecated
  19. * @property int $category The Category this Script resides in
  20. * @abstract Implement a derivative class that defines a table for storage.
  21. * @package modx
  22. */
  23. class modScript extends modElement {
  24. /**
  25. * The name of the script
  26. * @var string $_scriptName
  27. */
  28. public $_scriptName= null;
  29. /**
  30. * The cache key of the script
  31. * @var string $_scriptCacheKey
  32. */
  33. public $_scriptCacheKey= null;
  34. /**
  35. * @var string The filename of the script to include.
  36. */
  37. protected $_scriptFilename;
  38. /**
  39. * Override set to properly strip invalid tags from script code
  40. *
  41. * {@inheritdoc}
  42. */
  43. public function set($k, $v= null, $vType= '') {
  44. if (in_array($k, array('snippet', 'plugincode', 'content'))) {
  45. $v= trim($v);
  46. if (strncmp($v, '<?', 2) == 0) {
  47. $v= substr($v, 2);
  48. if (strncmp($v, 'php', 3) == 0) $v= substr($v, 3);
  49. }
  50. if (substr($v, -2, 2) == '?>') $v= substr($v, 0, -2);
  51. $v= trim($v, " \n\r\0\x0B");
  52. }
  53. $set= parent::set($k, $v, $vType);
  54. return $set;
  55. }
  56. /**
  57. * Process specifically script-related functionality for modScript objects.
  58. *
  59. * {@inheritdoc}
  60. */
  61. public function process($properties= null, $content= null) {
  62. parent :: process($properties, $content);
  63. if (!$this->_processed) {
  64. $this->_scriptFilename = $this->loadScript();
  65. $this->_result= $this->_scriptFilename !== false && is_readable($this->_scriptFilename);
  66. if ($this->_result) {
  67. if (empty($this->xpdo->event)) $this->xpdo->event = new stdClass();
  68. $modx =& $this->xpdo;
  69. $scriptProperties = $this->xpdo->event->params= $this->_properties; /* store params inside event object */
  70. ob_start();
  71. unset($properties, $content);
  72. extract($scriptProperties, EXTR_SKIP);
  73. $includeResult= include $this->_scriptFilename;
  74. $includeResult= ($includeResult === null ? '' : $includeResult);
  75. if (ob_get_length()) {
  76. $this->_output = ob_get_contents() . $includeResult;
  77. } else {
  78. $this->_output= $includeResult;
  79. }
  80. ob_end_clean();
  81. if ($this->_output && is_string($this->_output)) {
  82. /* collect element tags in the evaluated content and process them */
  83. $maxIterations= intval($this->xpdo->getOption('parser_max_iterations',null,10));
  84. $this->xpdo->parser->processElementTags(
  85. $this->_tag,
  86. $this->_output,
  87. $this->xpdo->parser->isProcessingUncacheable(),
  88. $this->xpdo->parser->isRemovingUnprocessed(),
  89. '[[',
  90. ']]',
  91. array(),
  92. $maxIterations
  93. );
  94. }
  95. $this->filterOutput();
  96. unset ($this->xpdo->event->params);
  97. $this->cache();
  98. }
  99. }
  100. $this->_processed= true;
  101. $this->xpdo->parser->setProcessingElement(false);
  102. /* finally, return the processed element content */
  103. return $this->_output;
  104. }
  105. /**
  106. * Get the name of the script source file, written to the cache file system
  107. *
  108. * @return string The filename containing the function generated from the
  109. * script element.
  110. */
  111. public function getScriptCacheKey() {
  112. if ($this->_scriptCacheKey === null) {
  113. $this->_scriptCacheKey= str_replace('_', '/', $this->getScriptName());
  114. }
  115. return $this->_scriptCacheKey;
  116. }
  117. /**
  118. * Get the name of the function the script has been given.
  119. *
  120. * @return string The function name representing this script element.
  121. */
  122. public function getScriptName() {
  123. if ($this->_scriptName === null) {
  124. $className= $this->_class;
  125. $this->_scriptName= 'elements_' . strtolower($className) . '_' . $this->get('id');
  126. }
  127. return $this->_scriptName;
  128. }
  129. /**
  130. * Get the include filename for the script, generating it if it does not exist.
  131. *
  132. * @return string|bool The include filename of the script or false.
  133. */
  134. public function loadScript() {
  135. $includeFilename = $this->xpdo->getCachePath() . 'includes/' . $this->getScriptCacheKey() . '.include.cache.php';
  136. $result = is_readable($includeFilename);
  137. $outdated = false;
  138. $sourceFile = $this->getSourceFile();
  139. if ($this->isStatic() && $result && !empty($sourceFile) && is_readable($sourceFile)) {
  140. $includeMTime = filemtime($includeFilename);
  141. $sourceMTime = filemtime($sourceFile);
  142. $outdated = $sourceMTime > $includeMTime;
  143. }
  144. if (!$result || $outdated) {
  145. $script= false;
  146. if (!$outdated) {
  147. $script= $this->xpdo->cacheManager->get($this->getScriptCacheKey(), array(
  148. xPDO::OPT_CACHE_KEY => $this->xpdo->getOption('cache_scripts_key', null, 'scripts'),
  149. xPDO::OPT_CACHE_HANDLER => $this->xpdo->getOption('cache_scripts_handler', null, $this->xpdo->getOption(xPDO::OPT_CACHE_HANDLER)),
  150. xPDO::OPT_CACHE_FORMAT => (integer) $this->xpdo->getOption('cache_scripts_format', null, $this->xpdo->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)),
  151. ));
  152. }
  153. if (!$script) {
  154. $script= $this->xpdo->cacheManager->generateScript($this);
  155. }
  156. if (!empty($script)) {
  157. $options = array();
  158. $folderMode = $this->xpdo->getOption('new_cache_folder_permissions', null, false);
  159. if ($folderMode) $options['new_folder_permissions'] = $folderMode;
  160. $fileMode = $this->xpdo->getOption('new_cache_file_permissions', null, false);
  161. if ($fileMode) $options['new_file_permissions'] = $fileMode;
  162. $result = $this->xpdo->cacheManager->writeFile($includeFilename, "<?php\n" . $script, 'wb' , $options);
  163. }
  164. }
  165. if ($result !== false) {
  166. $result = $includeFilename;
  167. }
  168. return $result;
  169. }
  170. public function getFileContent(array $options = array()) {
  171. $content = parent::getFileContent($options);
  172. if (strncmp($content, '<?', 2) == 0) {
  173. $content= substr($content, 2);
  174. if (strncmp($content, 'php', 3) == 0) $content= substr($content, 3);
  175. }
  176. if (substr($content, -2, 2) == '?>') $content= substr($content, 0, -2);
  177. $content= trim($content, " \0\x0B");
  178. return $content;
  179. }
  180. public function setFileContent($content, array $options = array()) {
  181. $content = "<?php\n{$content}";
  182. return parent::setFileContent($content, $options);
  183. }
  184. }