/modx/core/model/modx/modx.class.php
https://bitbucket.org/argnist/mohana · PHP · 2187 lines · 1327 code · 101 blank · 759 comment · 321 complexity · 120bc3dd08dc7533b9e740b45bad4036 MD5 · raw file
Large files are truncated click here to view the full file
- <?php
- /*
- * MODX Revolution
- *
- * Copyright 2006-2011 by MODX, LLC.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- /**
- * This is the main file to include in your scripts to use MODX.
- *
- * For detailed information on using this class, see {@tutorial modx/modx.pkg}.
- *
- * @package modx
- */
- /* fix for PHP float bug: http://bugs.php.net/bug.php?id=53632 (php 4 <= 4.4.9 and php 5 <= 5.3.4) */
- if (strstr(str_replace('.','',serialize(array_merge($_GET, $_POST, $_COOKIE))), '22250738585072011')) {
- header('Status: 422 Unprocessable Entity');
- die();
- }
- if (!defined('MODX_CORE_PATH')) {
- define('MODX_CORE_PATH', dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR);
- }
- if (!defined('MODX_CONFIG_KEY')) {
- define('MODX_CONFIG_KEY', 'config');
- }
- require_once (MODX_CORE_PATH . 'xpdo/xpdo.class.php');
- /**
- * This is the MODX gateway class.
- *
- * It can be used to interact with the MODX framework and serves as a front
- * controller for handling requests to the virtual resources managed by the MODX
- * Content Management Framework.
- *
- * @package modx
- */
- class modX extends xPDO {
- const LOG_LEVEL_FATAL = 0;
- const LOG_LEVEL_ERROR = 1;
- const LOG_LEVEL_WARN = 2;
- const LOG_LEVEL_INFO = 3;
- const LOG_LEVEL_DEBUG = 4;
- const SESSION_STATE_UNAVAILABLE = -1;
- const SESSION_STATE_UNINITIALIZED = 0;
- const SESSION_STATE_INITIALIZED = 1;
- const SESSION_STATE_EXTERNAL = 2;
- /**
- * @var modContext The Context represents a unique section of the site which
- * this modX instance is controlling.
- */
- public $context= null;
- /**
- * @var array An array of secondary contexts loaded on demand.
- */
- public $contexts= array();
- /**
- * @var modRequest Represents a web request and provides helper methods for
- * dealing with request parameters and other attributes of a request.
- */
- public $request= null;
- /**
- * @var modResponse Represents a web response, providing helper methods for
- * managing response header attributes and the body containing the content of
- * the response.
- */
- public $response= null;
- /**
- * @var modParser The modParser registered for this modX instance,
- * responsible for content tag parsing, and loaded only on demand.
- */
- public $parser= null;
- /**
- * @var array An array of supplemental service classes for this modX instance.
- */
- public $services= array ();
- /**
- * @var array A listing of site Resources and Context-specific meta data.
- */
- public $resourceListing= null;
- /**
- * @var array A hierarchy map of Resources.
- */
- public $resourceMap= null;
- /**
- * @var array A lookup listing of Resource alias values and associated
- * Resource Ids
- */
- public $aliasMap= null;
- /**
- * @var modSystemEvent The current event being handled by modX.
- */
- public $event= null;
- /**
- * @var array A map of elements registered to specific events.
- */
- public $eventMap= null;
- /**
- * @var array A map of actions registered to the manager interface.
- */
- public $actionMap= null;
- /**
- * @var array A map of already processed Elements.
- */
- public $elementCache= array ();
- /**
- * @var array An array of key=> value pairs that can be used by any Resource
- * or Element.
- */
- public $placeholders= array ();
- /**
- * @var modResource An instance of the current modResource controlling the
- * request.
- */
- public $resource= null;
- /**
- * @var string The preferred Culture key for the current request.
- */
- public $cultureKey= '';
- /**
- * @var modLexicon Represents a localized dictionary of common words and phrases.
- */
- public $lexicon= null;
- /**
- * @var modUser The current user object, if one is authenticated for the
- * current request and context.
- */
- public $user= null;
- /**
- * @var array Represents the modContentType instances that can be delivered
- * by this modX deployment.
- */
- public $contentTypes= null;
- /**
- * @var mixed The resource id or alias being requested.
- */
- public $resourceIdentifier= null;
- /**
- * @var string The method to use to locate the Resource, 'id' or 'alias'.
- */
- public $resourceMethod= null;
- /**
- * @var boolean Indicates if the resource was generated during this request.
- */
- public $resourceGenerated= false;
- /**
- * @var array Version information for this MODX deployment.
- */
- public $version= null;
- /**
- * @var boolean Indicates if modX has been successfully initialized for a
- * modContext.
- */
- protected $_initialized= false;
- /**
- * @var array An array of javascript content to be inserted into the HEAD
- * of an HTML resource.
- */
- public $sjscripts= array ();
- /**
- * @var array An array of javascript content to be inserted into the BODY
- * of an HTML resource.
- */
- public $jscripts= array ();
- public $loadedjscripts= array ();
- /**
- * @var string Stores the virtual path for a request to MODX if the
- * friendly_alias_paths option is enabled.
- */
- public $virtualDir;
- /**
- * @var object An error_handler for the modX instance.
- */
- public $errorHandler= null;
- /**
- * @var array An array of regex patterns regulary cleansed from content.
- */
- public $sanitizePatterns = array(
- 'scripts' => '@<script[^>]*?>.*?</script>@si',
- 'entities' => '@&#(\d+);@e',
- 'tags' => '@\[\[(.[^\[\[]*?)\]\]@si',
- );
- /**
- * @var integer An integer representing the session state of modX.
- */
- protected $_sessionState= modX::SESSION_STATE_UNINITIALIZED;
- /**
- * @var array A config array that stores the bootstrap settings.
- */
- protected $_config= null;
- /**
- * @var array A config array that stores the system-wide settings.
- */
- public $_systemConfig= null;
- /**
- * @var array A config array that stores the user settings.
- */
- public $_userConfig= array();
- protected $_logSequence= 0;
- public $pluginCache= array();
- public $sourceCache= array(
- 'modChunk' => array()
- ,'modSnippet' => array()
- ,'modTemplateVar' => array()
- );
- /**#@+
- * @deprecated
- */
- public $Event= null;
- public $documentOutput= null;
- public $stopOnNotice= false;
- /**#@-*/
- /**
- * Harden the environment against common security flaws.
- *
- * @static
- */
- public static function protect() {
- if (isset ($_SERVER['QUERY_STRING']) && strpos(urldecode($_SERVER['QUERY_STRING']), chr(0)) !== false) die();
- if (@ ini_get('register_globals') && isset ($_REQUEST)) {
- while (list($key, $value)= each($_REQUEST)) {
- $GLOBALS[$key] = null;
- unset ($GLOBALS[$key]);
- }
- }
- $targets= array ('PHP_SELF', 'HTTP_USER_AGENT', 'HTTP_REFERER', 'QUERY_STRING');
- foreach ($targets as $target) {
- $_SERVER[$target] = isset ($_SERVER[$target]) ? htmlspecialchars($_SERVER[$target], ENT_QUOTES) : null;
- }
- }
- /**
- * Sanitize values of an array using regular expression patterns.
- *
- * @static
- * @param array $target The target array to sanitize.
- * @param array|string $patterns A regular expression pattern, or array of
- * regular expression patterns to apply to all values of the target.
- * @param integer $depth The maximum recursive depth to sanitize if the
- * target contains values that are arrays.
- * @return array The sanitized array.
- */
- public static function sanitize(array &$target, array $patterns= array(), $depth= 3, $nesting= 10) {
- while (list($key, $value)= each($target)) {
- if (is_array($value) && $depth > 0) {
- modX :: sanitize($value, $patterns, $depth-1);
- } elseif (is_string($value)) {
- if (!empty($patterns)) {
- foreach ($patterns as $pattern) {
- $nesting = ((integer) $nesting ? (integer) $nesting : 10);
- $iteration = 1;
- while ($iteration <= $nesting && preg_match($pattern, $value)) {
- $value= preg_replace($pattern, '', $value);
- $iteration++;
- }
- }
- }
- if (get_magic_quotes_gpc()) {
- $target[$key]= stripslashes($value);
- } else {
- $target[$key]= $value;
- }
- }
- }
- return $target;
- }
- /**
- * Sanitizes a string
- *
- * @param string $str The string to sanitize
- * @param array $chars An array of chars to remove
- * @param string $allowedTags A list of tags to allow.
- * @return string The sanitized string.
- */
- public function sanitizeString($str,$chars = array('/',"'",'"','(',')',';','>','<'),$allowedTags = '') {
- $str = str_replace($chars,'',strip_tags($str,$allowedTags));
- return preg_replace("/[^A-Za-z0-9_\-\.\/]/",'',$str);
- }
- /**
- * Turn an associative array into a valid query string.
- *
- * @static
- * @param array $parameters An associative array of parameters.
- * @return string A valid query string representing the parameters.
- */
- public static function toQueryString(array $parameters = array()) {
- $qs = array();
- foreach ($parameters as $paramKey => $paramVal) {
- $qs[] = urlencode($paramKey) . '=' . urlencode($paramVal);
- }
- return implode('&', $qs);
- }
- /**
- * Construct a new modX instance.
- *
- * @param string $configPath An absolute filesystem path to look for the config file.
- * @param array $options Options that can be passed to the instance.
- * @return modX A new modX instance.
- */
- public function __construct($configPath= '', array $options = array()) {
- global $database_dsn, $database_user, $database_password, $config_options, $table_prefix, $site_id, $uuid;
- modX :: protect();
- if (empty ($configPath)) {
- $configPath= MODX_CORE_PATH . 'config/';
- }
- if (@ include ($configPath . MODX_CONFIG_KEY . '.inc.php')) {
- $cachePath= MODX_CORE_PATH . 'cache/';
- if (MODX_CONFIG_KEY !== 'config') $cachePath .= MODX_CONFIG_KEY . '/';
- $options = array_merge(
- array (
- xPDO::OPT_CACHE_KEY => 'default',
- xPDO::OPT_CACHE_HANDLER => 'xPDOFileCache',
- xPDO::OPT_CACHE_PATH => $cachePath,
- xPDO::OPT_TABLE_PREFIX => $table_prefix,
- xPDO::OPT_HYDRATE_FIELDS => true,
- xPDO::OPT_HYDRATE_RELATED_OBJECTS => true,
- xPDO::OPT_HYDRATE_ADHOC_FIELDS => true,
- xPDO::OPT_LOADER_CLASSES => array('modAccessibleObject'),
- xPDO::OPT_VALIDATOR_CLASS => 'validation.modValidator',
- xPDO::OPT_VALIDATE_ON_SAVE => true,
- 'cache_system_settings' => true,
- 'cache_system_settings_key' => 'system_settings'
- ),
- $config_options,
- $options
- );
- parent :: __construct(
- $database_dsn,
- $database_user,
- $database_password,
- $options,
- array (
- PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
- PDO::ATTR_PERSISTENT => false,
- )
- );
- $this->setPackage('modx', MODX_CORE_PATH . 'model/', $table_prefix);
- $this->setLogTarget($this->getOption('log_target', null, 'FILE'));
- if (!empty($site_id)) $this->site_id = $site_id;
- if (!empty($uuid)) $this->uuid = $uuid;
- } else {
- $this->sendError($this->getOption('error_type', null, 'unavailable'), $options);
- }
- }
- /**
- * Initializes the modX engine.
- *
- * This includes preparing the session, pre-loading some common
- * classes and objects, the current site and context settings, extension
- * packages used to override session handling, error handling, or other
- * initialization classes
- *
- * @param string Indicates the context to initialize.
- * @return void
- */
- public function initialize($contextKey= 'web') {
- if (!$this->_initialized) {
- if (!$this->startTime) {
- $this->startTime= $this->getMicroTime();
- }
- $this->loadClass('modAccess');
- $this->loadClass('modAccessibleObject');
- $this->loadClass('modAccessibleSimpleObject');
- $this->loadClass('modResource');
- $this->loadClass('modElement');
- $this->loadClass('modScript');
- $this->loadClass('modPrincipal');
- $this->loadClass('modUser');
- $this->getCacheManager();
- $this->getConfig();
- $this->_initContext($contextKey);
- $this->_loadExtensionPackages();
- $this->_initSession();
- $this->_initErrorHandler();
- $this->_initCulture();
- $this->getService('registry', 'registry.modRegistry');
- if (is_array ($this->config)) {
- $this->setPlaceholders($this->config, '+');
- }
- $this->_initialized= true;
- }
- }
- /**
- * Loads any specified extension packages
- */
- protected function _loadExtensionPackages() {
- $extPackages = $this->getOption('extension_packages');
- if (empty($extPackages)) return;
- $extPackages = $this->fromJSON($extPackages);
- if (!empty($extPackages)) {
- foreach ($extPackages as $extPackage) {
- if (!is_array($extPackage)) continue;
- foreach ($extPackage as $packageName => $package) {
- if (!empty($package) && !empty($package['path'])) {
- $package['tablePrefix'] = !empty($package['tablePrefix']) ? $package['tablePrefix'] : null;
- $package['path'] = str_replace(array(
- '[[++core_path]]',
- '[[++base_path]]',
- '[[++assets_path]]',
- '[[++manager_path]]',
- ),array(
- $this->config['core_path'],
- $this->config['base_path'],
- $this->config['assets_path'],
- $this->config['manager_path'],
- ),$package['path']);
- $this->addPackage($packageName,$package['path'],$package['tablePrefix']);
- if (!empty($package['serviceName']) && !empty($package['serviceClass'])) {
- $packagePath = str_replace('//','/',$package['path'].$packageName.'/');
- $this->getService($package['serviceName'],$package['serviceClass'],$packagePath);
- }
- }
- }
- }
- }
- }
- /**
- * Sets the debugging features of the modX instance.
- *
- * @param boolean|int $debug Boolean or bitwise integer describing the
- * debug state and/or PHP error reporting level.
- * @param boolean $stopOnNotice Indicates if processing should stop when
- * encountering PHP errors of type E_NOTICE.
- * @return boolean|int The previous value.
- */
- public function setDebug($debug= true, $stopOnNotice= false) {
- $oldValue= $this->getDebug();
- if ($debug === true) {
- error_reporting(-1);
- parent :: setDebug(true);
- } elseif ($debug === false) {
- error_reporting(0);
- parent :: setDebug(false);
- } else {
- error_reporting(intval($debug));
- parent :: setDebug(intval($debug));
- }
- $this->stopOnNotice= $stopOnNotice;
- return $oldValue;
- }
- /**
- * Get an extended xPDOCacheManager instance responsible for MODX caching.
- *
- * @return object A modCacheManager registered for this modX instance.
- */
- public function getCacheManager($class= 'cache.xPDOCacheManager', $options = array('path' => XPDO_CORE_PATH, 'ignorePkg' => true)) {
- if ($this->cacheManager === null) {
- if ($this->loadClass($class, $options['path'], $options['ignorePkg'], true)) {
- $cacheManagerClass= $this->getOption('modCacheManager.class', null, 'modCacheManager');
- if ($className= $this->loadClass($cacheManagerClass, '', false, true)) {
- if ($this->cacheManager= new $className ($this)) {
- $this->_cacheEnabled= true;
- }
- }
- }
- }
- return $this->cacheManager;
- }
- /**
- * Gets the MODX parser.
- *
- * Returns an instance of modParser responsible for parsing tags in element
- * content, performing actions, returning content and/or sending other responses
- * in the process.
- *
- * @return object The modParser for this modX instance.
- */
- public function getParser() {
- return $this->getService('parser', 'modParser');
- }
- /**
- * Gets all of the parent resource ids for a given resource.
- *
- * @param integer $id The resource id for the starting node.
- * @param integer $height How many levels max to search for parents (default 10).
- * @param array $options An array of filtering options, such as 'context' to specify the context to grab from
- * @return array An array of all the parent resource ids for the specified resource.
- */
- public function getParentIds($id= null, $height= 10,array $options = array()) {
- $parentId= 0;
- $parents= array ();
- if ($id && $height > 0) {
- $context = '';
- if (!empty($options['context'])) {
- $this->getContext($options['context']);
- $context = $options['context'];
- }
- $resourceMap = !empty($context) && !empty($this->contexts[$context]->resourceMap) ? $this->contexts[$context]->resourceMap : $this->resourceMap;
- foreach ($resourceMap as $parentId => $mapNode) {
- if (array_search($id, $mapNode) !== false) {
- $parents[]= $parentId;
- break;
- }
- }
- if ($parentId && !empty($parents)) {
- $height--;
- $parents= array_merge($parents, $this->getParentIds($parentId,$height,$options));
- }
- }
- return $parents;
- }
- /**
- * Gets all of the child resource ids for a given resource.
- *
- * @see getTree for hierarchical node results
- * @param integer $id The resource id for the starting node.
- * @param integer $depth How many levels max to search for children (default 10).
- * @param array $options An array of filtering options, such as 'context' to specify the context to grab from
- * @return array An array of all the child resource ids for the specified resource.
- */
- public function getChildIds($id= null, $depth= 10,array $options = array()) {
- $children= array ();
- if ($id !== null && intval($depth) >= 1) {
- $id= is_int($id) ? $id : intval($id);
- $context = '';
- if (!empty($options['context'])) {
- $this->getContext($options['context']);
- $context = $options['context'];
- }
- $resourceMap = !empty($context) && !empty($this->contexts[$context]->resourceMap) ? $this->contexts[$context]->resourceMap : $this->resourceMap;
-
- if (isset ($resourceMap["{$id}"])) {
- if ($children= $resourceMap["{$id}"]) {
- foreach ($children as $child) {
- $processDepth = $depth - 1;
- if ($c= $this->getChildIds($child,$processDepth,$options)) {
- $children= array_merge($children, $c);
- }
- }
- }
- }
- }
- return $children;
- }
- /**
- * Get a site tree from a single or multiple modResource instances.
- *
- * @see getChildIds for linear results
- * @param int|array $id A single or multiple modResource ids to build the
- * tree from.
- * @param int $depth The maximum depth to build the tree (default 10).
- * @return array An array containing the tree structure.
- */
- public function getTree($id= null, $depth= 10) {
- $tree= array ();
- if ($id !== null) {
- if (is_array ($id)) {
- foreach ($id as $k => $v) {
- $tree[$v]= $this->getTree($v, $depth);
- }
- }
- elseif ($branch= $this->getChildIds($id, 1)) {
- foreach ($branch as $key => $child) {
- if ($depth > 0 && $leaf= $this->getTree($child, $depth--)) {
- $tree[$child]= $leaf;
- } else {
- $tree[$child]= $child;
- }
- }
- }
- }
- return $tree;
- }
- /**
- * Sets a placeholder value.
- *
- * @param string $key The unique string key which identifies the
- * placeholder.
- * @param mixed $value The value to set the placeholder to.
- */
- public function setPlaceholder($key, $value) {
- if (is_string($key)) {
- $this->placeholders["{$key}"]= $value;
- }
- }
- /**
- * Sets a collection of placeholders stored in an array or as object vars.
- *
- * An optional namespace parameter can be prepended to each placeholder key in the collection,
- * to isolate the collection of placeholders.
- *
- * Note that unlike toPlaceholders(), this function does not add separators between the
- * namespace and the placeholder key. Use toPlaceholders() when working with multi-dimensional
- * arrays or objects with variables other than scalars so each level gets delimited by a
- * separator.
- *
- * @param array|object $placeholders An array of values or object to set as placeholders.
- * @param string $namespace A namespace prefix to prepend to each placeholder key.
- */
- public function setPlaceholders($placeholders, $namespace= '') {
- $this->toPlaceholders($placeholders, $namespace, '');
- }
- /**
- * Sets placeholders from values stored in arrays and objects.
- *
- * Each recursive level adds to the prefix, building an access path using an optional separator.
- *
- * @param array|object $subject An array or object to process.
- * @param string $prefix An optional prefix to be prepended to the placeholder keys. Recursive
- * calls prepend the parent keys.
- * @param string $separator A separator to place in between the prefixes and keys. Default is a
- * dot or period: '.'.
- * @param boolean $restore Set to true if you want overwritten placeholder values returned.
- * @return array A multi-dimensional array containing up to two elements: 'keys' which always
- * contains an array of placeholder keys that were set, and optionally, if the restore parameter
- * is true, 'restore' containing an array of placeholder values that were overwritten by the method.
- */
- public function toPlaceholders($subject, $prefix= '', $separator= '.', $restore= false) {
- $keys = array();
- $restored = array();
- if (is_object($subject)) {
- if ($subject instanceof xPDOObject) {
- $subject= $subject->toArray();
- } else {
- $subject= get_object_vars($subject);
- }
- }
- if (is_array($subject)) {
- foreach ($subject as $key => $value) {
- $rv = $this->toPlaceholder($key, $value, $prefix, $separator, $restore);
- if (isset($rv['keys'])) {
- foreach ($rv['keys'] as $rvKey) $keys[] = $rvKey;
- }
- if ($restore === true && isset($rv['restore'])) {
- $restored = array_merge($restored, $rv['restore']);
- }
- }
- }
- $return = array('keys' => $keys);
- if ($restore === true) $return['restore'] = $restored;
- return $return;
- }
- /**
- * Recursively validates and sets placeholders appropriate to the value type passed.
- *
- * @param string $key The key identifying the value.
- * @param mixed $value The value to set.
- * @param string $prefix A string prefix to prepend to the key. Recursive calls prepend the
- * parent keys as well.
- * @param string $separator A separator placed in between the prefix and the key. Default is a
- * dot or period: '.'.
- * @param boolean $restore Set to true if you want overwritten placeholder values returned.
- * @return array A multi-dimensional array containing up to two elements: 'keys' which always
- * contains an array of placeholder keys that were set, and optionally, if the restore parameter
- * is true, 'restore' containing an array of placeholder values that were overwritten by the method.
- */
- public function toPlaceholder($key, $value, $prefix= '', $separator= '.', $restore= false) {
- $return = array('keys' => array());
- if ($restore === true) $return['restore'] = array();
- if (!empty($prefix) && !empty($separator)) {
- $prefix .= $separator;
- }
- if (is_array($value) || is_object($value)) {
- $return = $this->toPlaceholders($value, "{$prefix}{$key}", $separator, $restore);
- } elseif (is_scalar($value)) {
- $return['keys'][] = "{$prefix}{$key}";
- if ($restore === true && array_key_exists("{$prefix}{$key}", $this->placeholders)) {
- $return['restore']["{$prefix}{$key}"] = $this->getPlaceholder("{$prefix}{$key}");
- }
- $this->setPlaceholder("{$prefix}{$key}", $value);
- }
- return $return;
- }
- /**
- * Get a placeholder value by key.
- *
- * @param string $key The key of the placeholder to a return a value from.
- * @return mixed The value of the requested placeholder, or an empty string if not located.
- */
- public function getPlaceholder($key) {
- $placeholder= null;
- if (is_string($key) && array_key_exists($key, $this->placeholders)) {
- $placeholder= & $this->placeholders["{$key}"];
- }
- return $placeholder;
- }
- /**
- * Unset a placeholder value by key.
- *
- * @param string $key The key of the placeholder to unset.
- */
- public function unsetPlaceholder($key) {
- if (is_string($key) && array_key_exists($key, $this->placeholders)) {
- unset($this->placeholders[$key]);
- }
- }
- /**
- * Unset multiple placeholders, either by prefix or an array of keys.
- *
- * @param string|array $keys A string prefix or an array of keys indicating
- * the placeholders to unset.
- */
- public function unsetPlaceholders($keys) {
- if (is_array($keys)) {
- foreach ($keys as $key) {
- if (is_string($key)) $this->unsetPlaceholder($key);
- if (is_array($key)) $this->unsetPlaceholders($key);
- }
- } elseif (is_string($keys)) {
- $placeholderKeys = array_keys($this->placeholders);
- foreach ($placeholderKeys as $key) {
- if (strpos($key, $keys) === 0) $this->unsetPlaceholder($key);
- }
- }
- }
- /**
- * Generates a URL representing a specified resource.
- *
- * @param integer $id The id of a resource.
- * @param string $context Specifies a context to limit URL generation to.
- * @param string $args A query string to append to the generated URL.
- * @param mixed $scheme The scheme indicates in what format the URL is generated.<br>
- * <pre>
- * -1 : (default value) URL is relative to site_url
- * 0 : see http
- * 1 : see https
- * full : URL is absolute, prepended with site_url from config
- * abs : URL is absolute, prepended with base_url from config
- * http : URL is absolute, forced to http scheme
- * https : URL is absolute, forced to https scheme
- * </pre>
- * @return string The URL for the resource.
- */
- public function makeUrl($id, $context= '', $args= '', $scheme= -1) {
- $url= '';
- if ($validid = intval($id)) {
- $id = $validid;
- if ($context == '' || $this->context->get('key') == $context) {
- $url= $this->context->makeUrl($id, $args, $scheme);
- }
- if (empty($url) && ($context !== $this->context->get('key'))) {
- $ctx= null;
- if ($context == '') {
- if ($results = $this->query("SELECT context_key FROM " . $this->getTableName('modResource') . " WHERE id = {$id}")) {
- $contexts= $results->fetchAll(PDO::FETCH_COLUMN);
- if ($contextKey = reset($contexts)) {
- $ctx = $this->getContext($contextKey);
- }
- }
- } else {
- $ctx = $this->getContext($context);
- }
- if ($ctx) {
- $url= $ctx->makeUrl($id, $args, 'full');
- }
- }
- if (!empty($url) && $this->getOption('xhtml_urls',null,false)) {
- $url= preg_replace("/&(?!amp;)/","&", $url);
- }
- } else {
- $this->log(modX::LOG_LEVEL_ERROR, '`' . $id . '` is not a valid integer and may not be passed to makeUrl()');
- }
- return $url;
- }
- /**
- * Send the user to a type-specific core error page and halt PHP execution.
- *
- * @param string $type The type of error to present.
- * @param array $options An array of options to provide for the error file.
- */
- public function sendError($type = '', $options = array()) {
- if (!is_string($type) || empty($type)) $type = $this->getOption('error_type', $options, 'unavailable');
- while (@ob_end_clean()) {}
- if (file_exists(MODX_CORE_PATH . "error/{$type}.include.php")) {
- @include(MODX_CORE_PATH . "error/{$type}.include.php");
- }
- header($this->getOption('error_header', $options, 'HTTP/1.1 503 Service Unavailable'));
- $errorPageTitle = $this->getOption('error_pagetitle', $options, 'Error 503: Site temporarily unavailable');
- $errorMessage = $this->getOption('error_message', $options, '<h1>' . $this->getOption('site_name', $options, 'Error 503') . '</h1><p>Site temporarily unavailable.</p>');
- echo "<html><head><title>{$errorPageTitle}</title></head><body>{$errorMessage}</body></html>";
- @session_write_close();
- exit();
- }
- /**
- * Sends a redirect to the specified URL using the specified options.
- *
- * Valid 'type' option values include:
- * REDIRECT_REFRESH Uses the header refresh method
- * REDIRECT_META Sends a a META HTTP-EQUIV="Refresh" tag to the output
- * REDIRECT_HEADER Uses the header location method
- *
- * REDIRECT_HEADER is the default.
- *
- * @param string $url The URL to redirect the client browser to.
- * @param array|boolean $options An array of options for the redirect OR
- * indicates if redirect attempts should be counted and limited to 3 (latter is deprecated
- * usage; use count_attempts in options array).
- * @param string $type The type of redirection to attempt (deprecated, use type in
- * options array).
- * @param string $responseCode The type of HTTP response code HEADER to send for the
- * redirect (deprecated, use responseCode in options array)
- */
- public function sendRedirect($url, $options= false, $type= '', $responseCode = '') {
- if (!$this->getResponse()) {
- $this->log(modX::LOG_LEVEL_FATAL, "Could not load response class.");
- }
- $this->response->sendRedirect($url, $options, $type, $responseCode);
- }
- /**
- * Forwards the request to another resource without changing the URL.
- *
- * @param integer $id The resource identifier.
- * @param string $options An array of options for the process.
- */
- public function sendForward($id, $options = null) {
- if (!$this->getRequest()) {
- $this->log(modX::LOG_LEVEL_FATAL, "Could not load request class.");
- }
- $idInt = intval($id);
- if (is_string($options) && !empty($options)) {
- $options = array('response_code' => $options);
- } elseif (!is_array($options)) {
- $options = array();
- }
- $this->elementCache = array();
- if ($idInt > 0) {
- $merge = array_key_exists('merge', $options) && !empty($options['merge']);
- $currentResource = array();
- if ($merge) {
- $excludes = array_merge(
- explode(',', $this->getOption('forward_merge_excludes', $options, 'type,published,class_key,context_key')),
- array(
- 'content'
- ,'pub_date'
- ,'unpub_date'
- ,'richtext'
- ,'_content'
- ,'_processed'
- )
- );
- reset($this->resource->_fields);
- while (list($fkey, $fval) = each($this->resource->_fields)) {
- if (!in_array($fkey, $excludes)) {
- if (is_scalar($fval) && $fval !== '') {
- $currentResource[$fkey] = $fval;
- } elseif (is_array($fval) && count($fval) === 5 && $fval[1] !== '') {
- $currentResource[$fkey] = $fval;
- }
- }
- }
- }
- $this->resource= $this->request->getResource('id', $idInt, array('forward' => true));
- if ($this->resource) {
- if ($merge && !empty($currentResource)) {
- $this->resource->_fields = array_merge($this->resource->_fields, $currentResource);
- $this->elementCache = array();
- unset($currentResource);
- }
- $this->resourceIdentifier= $this->resource->get('id');
- $this->resourceMethod= 'id';
- if (isset($options['response_code']) && !empty($options['response_code'])) {
- header($options['response_code']);
- }
- $this->request->prepareResponse();
- exit();
- }
- $options= array_merge(
- array(
- 'error_type' => '404'
- ,'error_header' => $this->getOption('error_page_header', $options,'HTTP/1.1 404 Not Found')
- ,'error_pagetitle' => $this->getOption('error_page_pagetitle', $options,'Error 404: Page not found')
- ,'error_message' => $this->getOption('error_page_message', $options,'<h1>Page not found</h1><p>The page you requested was not found.</p>')
- ),
- $options
- );
- }
- $this->sendError($id, $options);
- }
- /**
- * Send the user to a MODX virtual error page.
- *
- * @uses invokeEvent() The OnPageNotFound event is invoked before the error page is forwarded
- * to.
- * @param array $options An array of options to provide for the OnPageNotFound event and error
- * page.
- */
- public function sendErrorPage($options = null) {
- if (!is_array($options)) $options = array();
- $options= array_merge(
- array(
- 'response_code' => $this->getOption('error_page_header', $options, 'HTTP/1.1 404 Not Found')
- ,'error_type' => '404'
- ,'error_header' => $this->getOption('error_page_header', $options, 'HTTP/1.1 404 Not Found')
- ,'error_pagetitle' => $this->getOption('error_page_pagetitle', $options, 'Error 404: Page not found')
- ,'error_message' => $this->getOption('error_page_message', $options, '<h1>Page not found</h1><p>The page you requested was not found.</p>')
- ),
- $options
- );
- $this->invokeEvent('OnPageNotFound', $options);
- $this->sendForward($this->getOption('error_page', $options, '404'), $options);
- }
- /**
- * Send the user to the MODX unauthorized page.
- *
- * @uses invokeEvent() The OnPageUnauthorized event is invoked before the unauthorized page is
- * forwarded to.
- * @param array $options An array of options to provide for the OnPageUnauthorized
- * event and unauthorized page.
- */
- public function sendUnauthorizedPage($options = null) {
- if (!is_array($options)) $options = array();
- $options= array_merge(
- array(
- 'response_code' => $this->getOption('unauthorized_page_header' ,$options ,'HTTP/1.1 401 Unauthorized')
- ,'error_type' => '401'
- ,'error_header' => $this->getOption('unauthorized_page_header', $options,'HTTP/1.1 401 Unauthorized')
- ,'error_pagetitle' => $this->getOption('unauthorized_page_pagetitle',$options, 'Error 401: Unauthorized')
- ,'error_message' => $this->getOption('unauthorized_page_message', $options,'<h1>Unauthorized</h1><p>You are not authorized to view the requested content.</p>')
- ),
- $options
- );
- $this->invokeEvent('OnPageUnauthorized', $options);
- $this->sendForward($this->getOption('unauthorized_page', $options, '401'), $options);
- }
- /**
- * Get the current authenticated User and assigns it to the modX instance.
- *
- * @param string $contextKey An optional context to get the user from.
- * @param boolean $forceLoadSettings If set to true, will load settings
- * regardless of whether the user has an authenticated context or not.
- * @return modUser The user object authenticated for the request.
- */
- public function getUser($contextKey= '',$forceLoadSettings = false) {
- if ($contextKey == '') {
- if ($this->context !== null) {
- $contextKey= $this->context->get('key');
- }
- }
- if ($this->user === null || !is_object($this->user)) {
- $this->user= $this->getAuthenticatedUser($contextKey);
- if ($contextKey !== 'mgr' && !$this->user) {
- $this->user= $this->getAuthenticatedUser('mgr');
- }
- }
- if ($this->user !== null && is_object($this->user)) {
- if ($this->user->hasSessionContext($contextKey) || $forceLoadSettings) {
- if (isset ($_SESSION["modx.{$contextKey}.user.config"])) {
- $this->_userConfig= $_SESSION["modx.{$contextKey}.user.config"];
- } else {
- $settings= $this->user->getMany('UserSettings');
- if (is_array($settings) && !empty ($settings)) {
- foreach ($settings as $setting) {
- $v= $setting->get('value');
- $matches= array();
- if (preg_match_all('~\{(.*?)\}~', $v, $matches, PREG_SET_ORDER)) {
- $matchValue= '';
- foreach ($matches as $match) {
- if (isset ($this->config["{$match[1]}"])) {
- $matchValue= $this->config["{$match[1]}"];
- } else {
- $matchValue= '';
- }
- $v= str_replace($match[0], $matchValue, $v);
- }
- }
- $this->_userConfig[$setting->get('key')]= $v;
- }
- }
- }
- if (is_array ($this->_userConfig) && !empty ($this->_userConfig)) {
- $_SESSION["modx.{$contextKey}.user.config"]= $this->_userConfig;
- $this->config= array_merge($this->config, $this->_userConfig);
- }
- }
- } else {
- $this->user = $this->newObject('modUser', array(
- 'id' => 0,
- 'username' => '(anonymous)'
- )
- );
- }
- ksort($this->config);
- $this->toPlaceholders($this->user->get(array('id','username')),'modx.user');
- return $this->user;
- }
- /**
- * Gets the user authenticated in the specified context.
- *
- * @param string $contextKey Optional context key; uses current context by default.
- * @return modUser|null The user object that is authenticated in the specified context,
- * or null if no user is authenticated.
- */
- public function getAuthenticatedUser($contextKey= '') {
- $user= null;
- if ($contextKey == '') {
- if ($this->context !== null) {
- $contextKey= $this->context->get('key');
- }
- }
- if ($contextKey && isset ($_SESSION['modx.user.contextTokens'][$contextKey])) {
- $user= $this->getObject('modUser', intval($_SESSION['modx.user.contextTokens'][$contextKey]), true);
- if ($user) {
- $user->getSessionContexts();
- }
- }
- return $user;
- }
- /**
- * Checks to see if the user has a session in the specified context.
- *
- * @param string $sessionContext The context to test for a session key in.
- * @return boolean True if the user is valid in the context specified.
- */
- public function checkSession($sessionContext= 'web') {
- $hasSession = false;
- if ($this->user !== null) {
- $hasSession = $this->user->hasSessionContext($sessionContext);
- }
- return $hasSession;
- }
- /**
- * Gets the modX core version data.
- *
- * @return array The version data loaded from the config version file.
- */
- public function getVersionData() {
- if ($this->version === null) {
- $this->version= @ include_once MODX_CORE_PATH . "docs/version.inc.php";
- }
- return $this->version;
- }
- /**
- * Reload the config settings.
- *
- * @return array An associative array of configuration key/values
- */
- public function reloadConfig() {
- $this->getCacheManager();
- $this->cacheManager->refresh();
- if (!$this->_loadConfig()) {
- $this->log(modX::LOG_LEVEL_ERROR, 'Could not reload core MODX configuration!');
- }
- return $this->config;
- }
- /**
- * Get the configuration for the site.
- *
- * @return array An associate array of configuration key/values
- */
- public function getConfig() {
- if (!$this->_initialized || !is_array($this->config) || empty ($this->config)) {
- if (!isset ($this->config['base_url']))
- $this->config['base_url']= MODX_BASE_URL;
- if (!isset ($this->config['base_path']))
- $this->config['base_path']= MODX_BASE_PATH;
- if (!isset ($this->config['core_path']))
- $this->config['core_path']= MODX_CORE_PATH;
- if (!isset ($this->config['url_scheme']))
- $this->config['url_scheme']= MODX_URL_SCHEME;
- if (!isset ($this->config['http_host']))
- $this->config['http_host']= MODX_HTTP_HOST;
- if (!isset ($this->config['site_url']))
- $this->config['site_url']= MODX_SITE_URL;
- if (!isset ($this->config['manager_path']))
- $this->config['manager_path']= MODX_MANAGER_PATH;
- if (!isset ($this->config['manager_url']))
- $this->config['manager_url']= MODX_MANAGER_URL;
- if (!isset ($this->config['assets_path']))
- $this->config['assets_path']= MODX_ASSETS_PATH;
- if (!isset ($this->config['assets_url']))
- $this->config['assets_url']= MODX_ASSETS_URL;
- if (!isset ($this->config['connectors_path']))
- $this->config['connectors_path']= MODX_CONNECTORS_PATH;
- if (!isset ($this->config['connectors_url']))
- $this->config['connectors_url']= MODX_CONNECTORS_URL;
- if (!isset ($this->config['processors_path']))
- $this->config['processors_path']= MODX_PROCESSORS_PATH;
- if (!isset ($this->config['request_param_id']))
- $this->config['request_param_id']= 'id';
- if (!isset ($this->config['request_param_alias']))
- $this->config['request_param_alias']= 'q';
- if (!isset ($this->config['https_port']))
- $this->config['https_port']= isset($GLOBALS['https_port']) ? $GLOBALS['https_port'] : 443;
- if (!isset ($this->config['error_handler_class']))
- $this->config['error_handler_class']= 'error.modErrorHandler';
- $this->_config= $this->config;
- if (!$this->_loadConfig()) {
- $this->log(modX::LOG_LEVEL_FATAL, "Could not load core MODX configuration!");
- return null;
- }
- }
- return $this->config;
- }
- /**
- * Initialize, cleanse, and process a request made to a modX site.
- *
- * @return mixed The result of the request handler.
- */
- public function handleRequest() {
- if ($this->getRequest()) {
- return $this->request->handleRequest();
- }
- }
- /**
- * Attempt to load the request handler class, if not already loaded.
- *
- * @access public
- * @param $string The class name of the response class to load. Defaults to
- * modRequest; is ignored if the Setting "modRequest.class" is set.
- * @param $path The absolute path by which to load the response class from.
- * Defaults to the current MODX model path.
- * @return boolean Returns true if a valid request handler object was
- * loaded on this or any previous call to the function, false otherwise.
- */
- public function getRequest($class= 'modRequest', $path= '') {
- if ($this->request === null || !($this->request instanceof modRequest)) {
- $requestClass = $this->getOption('modRequest.class',$this->config,$class);
- if ($className= $this->loadClass($requestClass, $path, !empty($path), true))
- $this->request= new $className ($this);
- }
- return is_object($this->request) && $this->request instanceof modRequest;
- }
- /**
- * Attempt to load the response handler class, if not already loaded.
- *
- * @access public
- * @param $string The class name of the response class to load. Defaults to
- * modResponse; is ignored if the Setting "modResponse.class" is set.
- * @param $path The absolute path by which to load the response class from.
- * Defaults to the current MODX model path.
- * @return boolean Returns true if a valid response handler object was
- * loaded on this or any previous call to the function, false otherwise.
- */
- public function getResponse($class= 'modResponse', $path= '') {
- $responseClass= $this->getOption('modResponse.class',$this->config,$class);
- $className= $this->loadClass($responseClass, $path, !empty($path), true);
- if ($this->response === null || !($this->response instanceof $className)) {
- if ($className) $this->response= new $className ($this);
- }
- return $this->response instanceof $className;
- }
- /**
- * Register CSS to be injected inside the HEAD tag of a resource.
- *
- * @param string $src The CSS to be injected before the closing HEAD tag in
- * an HTML response.
- */
- public function regClientCSS($src) {
- if (isset ($this->loadedjscripts[$src]) && $this->loadedjscripts[$src]) {
- return '';
- }
- $this->loadedjscripts[$src]= true;
- if (strpos(strtolower($src), "<style") !== false || strpos(strtolower($src), "<link") !== false) {
- $this->sjscripts[count($this->sjscripts)]= $src;
- } else {
- $this->sjscripts[count($this->sjscripts)]= '<link rel="stylesheet" href="' . $src . '" type="text/css" />';
- }
- }
- /**
- * Register JavaScript to be injected inside the HEAD tag of a resource.
- *
- * @param string $src The JavaScript to be injected before the closing HEAD
- * tag of an HTML response.
- * @param boolean $plaintext Optional param to treat th…