getting cakephp set up with its own web server(s) and docroot
This commit is contained in:
675
web-cake/html/cake/libs/cache.php
Normal file
675
web-cake/html/cake/libs/cache.php
Normal file
@@ -0,0 +1,675 @@
|
||||
<?php
|
||||
/**
|
||||
* Caching for CakePHP.
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0.4933
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Caching for CakePHP.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Cache {
|
||||
|
||||
/**
|
||||
* Cache configuration stack
|
||||
* Keeps the permanent/default settings for each cache engine.
|
||||
* These settings are used to reset the engines after temporary modification.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__config = array();
|
||||
|
||||
/**
|
||||
* Holds name of the current configuration name being used.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__name = 'default';
|
||||
|
||||
/**
|
||||
* Whether to reset the settings with the next call to Cache::set();
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__reset = false;
|
||||
|
||||
/**
|
||||
* Engine instances keyed by configuration name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_engines = array();
|
||||
|
||||
/**
|
||||
* Returns a singleton instance
|
||||
*
|
||||
* @return object
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
if (!$instance) {
|
||||
$instance[0] =& new Cache();
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache configuration to use. config() can
|
||||
* both create new configurations, return the settings for already configured
|
||||
* configurations. It also sets the 'default' configuration to use for subsequent
|
||||
* operations.
|
||||
*
|
||||
* To create a new configuration:
|
||||
*
|
||||
* `Cache::config('my_config', array('engine' => 'File', 'path' => TMP));`
|
||||
*
|
||||
* To get the settings for a configuration, and set it as the currently selected configuration
|
||||
*
|
||||
* `Cache::config('default');`
|
||||
*
|
||||
* @see app/config/core.php for configuration settings
|
||||
* @param string $name Name of the configuration
|
||||
* @param array $settings Optional associative array of settings passed to the engine
|
||||
* @return array(engine, settings) on success, false on failure
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function config($name = null, $settings = array()) {
|
||||
$self =& Cache::getInstance();
|
||||
if (is_array($name)) {
|
||||
$settings = $name;
|
||||
}
|
||||
|
||||
if ($name === null || !is_string($name)) {
|
||||
$name = $self->__name;
|
||||
}
|
||||
|
||||
$current = array();
|
||||
if (isset($self->__config[$name])) {
|
||||
$current = $self->__config[$name];
|
||||
}
|
||||
|
||||
if (!empty($settings)) {
|
||||
$self->__config[$name] = array_merge($current, $settings);
|
||||
}
|
||||
|
||||
if (empty($self->__config[$name]['engine'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$engine = $self->__config[$name]['engine'];
|
||||
$self->__name = $name;
|
||||
|
||||
if (!isset($self->_engines[$name])) {
|
||||
$self->_buildEngine($name);
|
||||
$settings = $self->__config[$name] = $self->settings($name);
|
||||
} elseif ($settings = $self->set($self->__config[$name])) {
|
||||
$self->__config[$name] = $settings;
|
||||
}
|
||||
return compact('engine', 'settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and builds the instance of the required engine class.
|
||||
*
|
||||
* @param string $name Name of the config array that needs an engine instance built
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _buildEngine($name) {
|
||||
$config = $this->__config[$name];
|
||||
|
||||
list($plugin, $class) = pluginSplit($config['engine']);
|
||||
$cacheClass = $class . 'Engine';
|
||||
if (!class_exists($cacheClass) && $this->__loadEngine($class, $plugin) === false) {
|
||||
return false;
|
||||
}
|
||||
$cacheClass = $class . 'Engine';
|
||||
$this->_engines[$name] =& new $cacheClass();
|
||||
if ($this->_engines[$name]->init($config)) {
|
||||
if (time() % $this->_engines[$name]->settings['probability'] === 0) {
|
||||
$this->_engines[$name]->gc();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the currently configured Cache settings.
|
||||
*
|
||||
* @return array Array of configured Cache config names.
|
||||
*/
|
||||
function configured() {
|
||||
$self =& Cache::getInstance();
|
||||
return array_keys($self->__config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a cache engine. Deletes the cache configuration information
|
||||
* If the deleted configuration is the last configuration using an certain engine,
|
||||
* the Engine instance is also unset.
|
||||
*
|
||||
* @param string $name A currently configured cache config you wish to remove.
|
||||
* @return boolen success of the removal, returns false when the config does not exist.
|
||||
*/
|
||||
function drop($name) {
|
||||
$self =& Cache::getInstance();
|
||||
if (!isset($self->__config[$name])) {
|
||||
return false;
|
||||
}
|
||||
unset($self->__config[$name]);
|
||||
unset($self->_engines[$name]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find and include a file for a cache engine and returns object instance
|
||||
*
|
||||
* @param $name Name of the engine (without 'Engine')
|
||||
* @return mixed $engine object or null
|
||||
* @access private
|
||||
*/
|
||||
function __loadEngine($name, $plugin = null) {
|
||||
if ($plugin) {
|
||||
return App::import('Lib', $plugin . '.cache' . DS . $name, false);
|
||||
} else {
|
||||
$core = App::core();
|
||||
$path = $core['libs'][0] . 'cache' . DS . strtolower($name) . '.php';
|
||||
if (file_exists($path)) {
|
||||
require $path;
|
||||
return true;
|
||||
}
|
||||
return App::import('Lib', 'cache' . DS . $name, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily change settings to current config options. if no params are passed, resets settings if needed
|
||||
* Cache::write() will reset the configuration changes made
|
||||
*
|
||||
* @param mixed $settings Optional string for simple name-value pair or array
|
||||
* @param string $value Optional for a simple name-value pair
|
||||
* @return array Array of settings.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function set($settings = array(), $value = null) {
|
||||
$self =& Cache::getInstance();
|
||||
if (!isset($self->__config[$self->__name]) || !isset($self->_engines[$self->__name])) {
|
||||
return false;
|
||||
}
|
||||
$name = $self->__name;
|
||||
if (!empty($settings)) {
|
||||
$self->__reset = true;
|
||||
}
|
||||
|
||||
if ($self->__reset === true) {
|
||||
if (empty($settings)) {
|
||||
$self->__reset = false;
|
||||
$settings = $self->__config[$name];
|
||||
} else {
|
||||
if (is_string($settings) && $value !== null) {
|
||||
$settings = array($settings => $value);
|
||||
}
|
||||
$settings = array_merge($self->__config[$name], $settings);
|
||||
if (isset($settings['duration']) && !is_numeric($settings['duration'])) {
|
||||
$settings['duration'] = strtotime($settings['duration']) - time();
|
||||
}
|
||||
}
|
||||
$self->_engines[$name]->settings = $settings;
|
||||
}
|
||||
return $self->settings($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection
|
||||
*
|
||||
* Permanently remove all expired and deleted data
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function gc() {
|
||||
$self =& Cache::getInstance();
|
||||
$self->_engines[$self->__name]->gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache. Will automatically use the currently
|
||||
* active cache configuration. To set the currently active configuration use
|
||||
* Cache::config()
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Writing to the active cache config:
|
||||
*
|
||||
* `Cache::write('cached_data', $data);`
|
||||
*
|
||||
* Writing to a specific cache config:
|
||||
*
|
||||
* `Cache::write('cached_data', $data, 'long_term');`
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached - anything except a resource
|
||||
* @param string $config Optional string configuration name to write to.
|
||||
* @return boolean True if the data was successfully cached, false on failure
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function write($key, $value, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$key = $self->_engines[$config]->key($key);
|
||||
|
||||
if (!$key || is_resource($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = $self->_engines[$config]->write($settings['prefix'] . $key, $value, $settings['duration']);
|
||||
$self->set();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache. Will automatically use the currently
|
||||
* active cache configuration. To set the currently active configuration use
|
||||
* Cache::config()
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Reading from the active cache configuration.
|
||||
*
|
||||
* `Cache::read('my_data');`
|
||||
*
|
||||
* Reading from a specific cache configuration.
|
||||
*
|
||||
* `Cache::read('my_data', 'long_term');`
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param string $config optional name of the configuration to use.
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function read($key, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$key = $self->_engines[$config]->key($key);
|
||||
if (!$key) {
|
||||
return false;
|
||||
}
|
||||
$success = $self->_engines[$config]->read($settings['prefix'] . $key);
|
||||
|
||||
if ($config !== null && $config !== $self->__name) {
|
||||
$self->set();
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment a number under the key and return incremented value.
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to add
|
||||
* @param string $config Optional string configuration name. If not specified the current
|
||||
* default config will be used.
|
||||
* @return mixed new value, or false if the data doesn't exist, is not integer,
|
||||
* or if there was an error fetching it.
|
||||
* @access public
|
||||
*/
|
||||
function increment($key, $offset = 1, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$key = $self->_engines[$config]->key($key);
|
||||
|
||||
if (!$key || !is_integer($offset) || $offset < 0) {
|
||||
return false;
|
||||
}
|
||||
$success = $self->_engines[$config]->increment($settings['prefix'] . $key, $offset);
|
||||
$self->set();
|
||||
return $success;
|
||||
}
|
||||
/**
|
||||
* Decrement a number under the key and return decremented value.
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to substract
|
||||
* @param string $config Optional string configuration name, if not specified the current
|
||||
* default config will be used.
|
||||
* @return mixed new value, or false if the data doesn't exist, is not integer,
|
||||
* or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function decrement($key, $offset = 1, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$key = $self->_engines[$config]->key($key);
|
||||
|
||||
if (!$key || !is_integer($offset) || $offset < 0) {
|
||||
return false;
|
||||
}
|
||||
$success = $self->_engines[$config]->decrement($settings['prefix'] . $key, $offset);
|
||||
$self->set();
|
||||
return $success;
|
||||
}
|
||||
/**
|
||||
* Delete a key from the cache. Will automatically use the currently
|
||||
* active cache configuration. To set the currently active configuration use
|
||||
* Cache::config()
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Deleting from the active cache configuration.
|
||||
*
|
||||
* `Cache::delete('my_data');`
|
||||
*
|
||||
* Deleting from a specific cache configuration.
|
||||
*
|
||||
* `Cache::delete('my_data', 'long_term');`
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param string $config name of the configuration to use
|
||||
* @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function delete($key, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$key = $self->_engines[$config]->key($key);
|
||||
if (!$key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = $self->_engines[$config]->delete($settings['prefix'] . $key);
|
||||
$self->set();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache.
|
||||
*
|
||||
* @param boolean $check if true will check expiration, otherwise delete all
|
||||
* @param string $config name of the configuration to use
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function clear($check = false, $config = null) {
|
||||
$self =& Cache::getInstance();
|
||||
if (!$config) {
|
||||
$config = $self->__name;
|
||||
}
|
||||
$settings = $self->settings($config);
|
||||
|
||||
if (empty($settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$self->isInitialized($config)) {
|
||||
return false;
|
||||
}
|
||||
$success = $self->_engines[$config]->clear($check);
|
||||
$self->set();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Cache has initialized a working config for the given name.
|
||||
*
|
||||
* @param string $engine Name of the engine
|
||||
* @param string $config Name of the configuration setting
|
||||
* @return bool Whether or not the config name has been initialized.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isInitialized($name = null) {
|
||||
if (Configure::read('Cache.disable')) {
|
||||
return false;
|
||||
}
|
||||
$self =& Cache::getInstance();
|
||||
if (!$name && isset($self->__config[$self->__name])) {
|
||||
$name = $self->__name;
|
||||
}
|
||||
return isset($self->_engines[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the settings for current cache engine. If no name is supplied the settings
|
||||
* for the 'active default' configuration will be returned. To set the 'active default'
|
||||
* configuration use `Cache::config()`
|
||||
*
|
||||
* @param string $engine Name of the configuration to get settings for.
|
||||
* @return array list of settings for this engine
|
||||
* @see Cache::config()
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function settings($name = null) {
|
||||
$self =& Cache::getInstance();
|
||||
if (!$name && isset($self->__config[$self->__name])) {
|
||||
$name = $self->__name;
|
||||
}
|
||||
if (!empty($self->_engines[$name])) {
|
||||
return $self->_engines[$name]->settings();
|
||||
}
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage engine for CakePHP caching
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CacheEngine {
|
||||
|
||||
/**
|
||||
* Settings of current engine instance
|
||||
*
|
||||
* @var int
|
||||
* @access public
|
||||
*/
|
||||
var $settings = array();
|
||||
|
||||
/**
|
||||
* Initialize the cache engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
*
|
||||
* @param array $params Associative array of parameters for the engine
|
||||
* @return boolean True if the engine has been succesfully initialized, false if not
|
||||
* @access public
|
||||
*/
|
||||
function init($settings = array()) {
|
||||
$this->settings = array_merge(
|
||||
array('prefix' => 'cake_', 'duration'=> 3600, 'probability'=> 100),
|
||||
$this->settings,
|
||||
$settings
|
||||
);
|
||||
if (!is_numeric($this->settings['duration'])) {
|
||||
$this->settings['duration'] = strtotime($this->settings['duration']) - time();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection
|
||||
*
|
||||
* Permanently remove all expired and deleted data
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function gc() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value for a key into cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached
|
||||
* @param mixed $duration How long to cache the data, in seconds
|
||||
* @return boolean True if the data was succesfully cached, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function write($key, &$value, $duration) {
|
||||
trigger_error(sprintf(__('Method write() not implemented in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function read($key) {
|
||||
trigger_error(sprintf(__('Method read() not implemented in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment a number under the key and return incremented value
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to add
|
||||
* @return New incremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function increment($key, $offset = 1) {
|
||||
trigger_error(sprintf(__('Method increment() not implemented in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
/**
|
||||
* Decrement a number under the key and return decremented value
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $value How much to substract
|
||||
* @return New incremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function decrement($key, $offset = 1) {
|
||||
trigger_error(sprintf(__('Method decrement() not implemented in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache
|
||||
*
|
||||
* @param boolean $check if true will check expiration, otherwise delete all
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function clear($check) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Engine settings
|
||||
*
|
||||
* @return array settings
|
||||
* @access public
|
||||
*/
|
||||
function settings() {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a safe key for use with cache engine storage engines.
|
||||
*
|
||||
* @param string $key the key passed over
|
||||
* @return mixed string $key or false
|
||||
* @access public
|
||||
*/
|
||||
function key($key) {
|
||||
if (empty($key)) {
|
||||
return false;
|
||||
}
|
||||
$key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
123
web-cake/html/cake/libs/cache/apc.php
vendored
Normal file
123
web-cake/html/cake/libs/cache/apc.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* APC storage engine for cache.
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
* @since CakePHP(tm) v 1.2.0.4933
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* APC storage engine for cache
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
*/
|
||||
class ApcEngine extends CacheEngine {
|
||||
|
||||
/**
|
||||
* Initialize the Cache Engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
|
||||
*
|
||||
* @param array $setting array of setting for the engine
|
||||
* @return boolean True if the engine has been successfully initialized, false if not
|
||||
* @see CacheEngine::__defaults
|
||||
* @access public
|
||||
*/
|
||||
function init($settings = array()) {
|
||||
parent::init(array_merge(array('engine' => 'Apc', 'prefix' => Inflector::slug(APP_DIR) . '_'), $settings));
|
||||
return function_exists('apc_cache_info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return boolean True if the data was succesfully cached, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function write($key, &$value, $duration) {
|
||||
$expires = time() + $duration;
|
||||
apc_store($key.'_expires', $expires, $duration);
|
||||
return apc_store($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function read($key) {
|
||||
$time = time();
|
||||
$cachetime = intval(apc_fetch($key.'_expires'));
|
||||
if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
|
||||
return false;
|
||||
}
|
||||
return apc_fetch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to increment
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New incremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function increment($key, $offset = 1) {
|
||||
return apc_inc($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to substract
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New decremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function decrement($key, $offset = 1) {
|
||||
return apc_dec($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
return apc_delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache
|
||||
*
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function clear() {
|
||||
return apc_clear_cache('user');
|
||||
}
|
||||
}
|
||||
272
web-cake/html/cake/libs/cache/file.php
vendored
Normal file
272
web-cake/html/cake/libs/cache/file.php
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
/**
|
||||
* File Storage engine for cache
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
* @since CakePHP(tm) v 1.2.0.4933
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
if (!class_exists('File')) {
|
||||
require LIBS . 'file.php';
|
||||
}
|
||||
/**
|
||||
* File Storage engine for cache
|
||||
*
|
||||
* @todo use the File and Folder classes (if it's not a too big performance hit)
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
*/
|
||||
class FileEngine extends CacheEngine {
|
||||
|
||||
/**
|
||||
* Instance of File class
|
||||
*
|
||||
* @var File
|
||||
* @access protected
|
||||
*/
|
||||
var $_File = null;
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* - path = absolute path to cache directory, default => CACHE
|
||||
* - prefix = string prefix for filename, default => cake_
|
||||
* - lock = enable file locking on write, default => false
|
||||
* - serialize = serialize the data, default => true
|
||||
*
|
||||
* @var array
|
||||
* @see CacheEngine::__defaults
|
||||
* @access public
|
||||
*/
|
||||
var $settings = array();
|
||||
|
||||
/**
|
||||
* True unless FileEngine::__active(); fails
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
*/
|
||||
var $_init = true;
|
||||
|
||||
/**
|
||||
* Initialize the Cache Engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
|
||||
*
|
||||
* @param array $setting array of setting for the engine
|
||||
* @return boolean True if the engine has been successfully initialized, false if not
|
||||
* @access public
|
||||
*/
|
||||
function init($settings = array()) {
|
||||
parent::init(array_merge(
|
||||
array(
|
||||
'engine' => 'File', 'path' => CACHE, 'prefix'=> 'cake_', 'lock'=> false,
|
||||
'serialize'=> true, 'isWindows' => false
|
||||
),
|
||||
$settings
|
||||
));
|
||||
if (!isset($this->_File)) {
|
||||
$this->_File =& new File($this->settings['path'] . DS . 'cake');
|
||||
}
|
||||
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$this->settings['isWindows'] = true;
|
||||
}
|
||||
|
||||
$path = $this->_File->Folder->cd($this->settings['path']);
|
||||
if ($path) {
|
||||
$this->settings['path'] = $path;
|
||||
}
|
||||
return $this->__active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection. Permanently remove all expired and deleted data
|
||||
*
|
||||
* @return boolean True if garbage collection was succesful, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function gc() {
|
||||
return $this->clear(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $data Data to be cached
|
||||
* @param mixed $duration How long to cache the data, in seconds
|
||||
* @return boolean True if the data was succesfully cached, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function write($key, &$data, $duration) {
|
||||
if ($data === '' || !$this->_init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_setKey($key) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lineBreak = "\n";
|
||||
|
||||
if ($this->settings['isWindows']) {
|
||||
$lineBreak = "\r\n";
|
||||
}
|
||||
|
||||
if (!empty($this->settings['serialize'])) {
|
||||
if ($this->settings['isWindows']) {
|
||||
$data = str_replace('\\', '\\\\\\\\', serialize($data));
|
||||
} else {
|
||||
$data = serialize($data);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->settings['lock']) {
|
||||
$this->_File->lock = true;
|
||||
}
|
||||
$expires = time() + $duration;
|
||||
$contents = $expires . $lineBreak . $data . $lineBreak;
|
||||
$success = $this->_File->write($contents);
|
||||
$this->_File->close();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function read($key) {
|
||||
if ($this->_setKey($key) === false || !$this->_init || !$this->_File->exists()) {
|
||||
return false;
|
||||
}
|
||||
if ($this->settings['lock']) {
|
||||
$this->_File->lock = true;
|
||||
}
|
||||
$time = time();
|
||||
$cachetime = intval($this->_File->read(11));
|
||||
|
||||
if ($cachetime !== false && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
|
||||
$this->_File->close();
|
||||
return false;
|
||||
}
|
||||
$data = $this->_File->read(true);
|
||||
|
||||
if ($data !== '' && !empty($this->settings['serialize'])) {
|
||||
if ($this->settings['isWindows']) {
|
||||
$data = str_replace('\\\\\\\\', '\\', $data);
|
||||
}
|
||||
$data = unserialize((string)$data);
|
||||
}
|
||||
$this->_File->close();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
if ($this->_setKey($key) === false || !$this->_init) {
|
||||
return false;
|
||||
}
|
||||
return $this->_File->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all values from the cache
|
||||
*
|
||||
* @param boolean $check Optional - only delete expired cache items
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function clear($check) {
|
||||
if (!$this->_init) {
|
||||
return false;
|
||||
}
|
||||
$dir = dir($this->settings['path']);
|
||||
if ($check) {
|
||||
$now = time();
|
||||
$threshold = $now - $this->settings['duration'];
|
||||
}
|
||||
$prefixLength = strlen($this->settings['prefix']);
|
||||
while (($entry = $dir->read()) !== false) {
|
||||
if (substr($entry, 0, $prefixLength) !== $this->settings['prefix']) {
|
||||
continue;
|
||||
}
|
||||
if ($this->_setKey($entry) === false) {
|
||||
continue;
|
||||
}
|
||||
if ($check) {
|
||||
$mtime = $this->_File->lastChange();
|
||||
|
||||
if ($mtime === false || $mtime > $threshold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$expires = $this->_File->read(11);
|
||||
$this->_File->close();
|
||||
|
||||
if ($expires > $now) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$this->_File->delete();
|
||||
}
|
||||
$dir->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute file for a given key
|
||||
*
|
||||
* @param string $key The key
|
||||
* @return mixed Absolute cache file for the given key or false if erroneous
|
||||
* @access private
|
||||
*/
|
||||
function _setKey($key) {
|
||||
$this->_File->Folder->cd($this->settings['path']);
|
||||
if ($key !== $this->_File->name) {
|
||||
$this->_File->name = $key;
|
||||
$this->_File->path = null;
|
||||
}
|
||||
if (!$this->_File->Folder->inPath($this->_File->pwd(), true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine is cache directory is writable
|
||||
*
|
||||
* @return boolean
|
||||
* @access private
|
||||
*/
|
||||
function __active() {
|
||||
if ($this->_init && !is_writable($this->settings['path'])) {
|
||||
$this->_init = false;
|
||||
trigger_error(sprintf(__('%s is not writable', true), $this->settings['path']), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
217
web-cake/html/cake/libs/cache/memcache.php
vendored
Normal file
217
web-cake/html/cake/libs/cache/memcache.php
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* Memcache storage engine for cache
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
* @since CakePHP(tm) v 1.2.0.4933
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memcache storage engine for cache. Memcache has some limitations in the amount of
|
||||
* control you have over expire times far in the future. See MemcacheEngine::write() for
|
||||
* more information.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
*/
|
||||
class MemcacheEngine extends CacheEngine {
|
||||
|
||||
/**
|
||||
* Memcache wrapper.
|
||||
*
|
||||
* @var Memcache
|
||||
* @access private
|
||||
*/
|
||||
var $__Memcache = null;
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* - servers = string or array of memcache servers, default => 127.0.0.1. If an
|
||||
* array MemcacheEngine will use them as a pool.
|
||||
* - compress = boolean, default => false
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $settings = array();
|
||||
|
||||
/**
|
||||
* Initialize the Cache Engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
|
||||
*
|
||||
* @param array $setting array of setting for the engine
|
||||
* @return boolean True if the engine has been successfully initialized, false if not
|
||||
* @access public
|
||||
*/
|
||||
function init($settings = array()) {
|
||||
if (!class_exists('Memcache')) {
|
||||
return false;
|
||||
}
|
||||
parent::init(array_merge(array(
|
||||
'engine'=> 'Memcache',
|
||||
'prefix' => Inflector::slug(APP_DIR) . '_',
|
||||
'servers' => array('127.0.0.1'),
|
||||
'compress'=> false
|
||||
), $settings)
|
||||
);
|
||||
|
||||
if ($this->settings['compress']) {
|
||||
$this->settings['compress'] = MEMCACHE_COMPRESSED;
|
||||
}
|
||||
if (!is_array($this->settings['servers'])) {
|
||||
$this->settings['servers'] = array($this->settings['servers']);
|
||||
}
|
||||
if (!isset($this->__Memcache)) {
|
||||
$return = false;
|
||||
$this->__Memcache =& new Memcache();
|
||||
foreach ($this->settings['servers'] as $server) {
|
||||
list($host, $port) = $this->_parseServerString($server);
|
||||
if ($this->__Memcache->addServer($host, $port)) {
|
||||
$return = true;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the server address into the host/port. Handles both IPv6 and IPv4
|
||||
* addresses
|
||||
*
|
||||
* @param string $server The server address string.
|
||||
* @return array Array containing host, port
|
||||
*/
|
||||
function _parseServerString($server) {
|
||||
if (substr($server, 0, 1) == '[') {
|
||||
$position = strpos($server, ']:');
|
||||
if ($position !== false) {
|
||||
$position++;
|
||||
}
|
||||
} else {
|
||||
$position = strpos($server, ':');
|
||||
}
|
||||
$port = 11211;
|
||||
$host = $server;
|
||||
if ($position !== false) {
|
||||
$host = substr($server, 0, $position);
|
||||
$port = substr($server, $position + 1);
|
||||
}
|
||||
return array($host, $port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache. When using memcache as your cache engine
|
||||
* remember that the Memcache pecl extension does not support cache expiry times greater
|
||||
* than 30 days in the future. If you wish to create cache entries that do not expire, set the duration
|
||||
* to `0` in your cache configuration.
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return boolean True if the data was succesfully cached, false on failure
|
||||
* @see http://php.net/manual/en/memcache.set.php
|
||||
* @access public
|
||||
*/
|
||||
function write($key, &$value, $duration) {
|
||||
return $this->__Memcache->set($key, $value, $this->settings['compress'], $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function read($key) {
|
||||
return $this->__Memcache->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to increment
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New incremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function increment($key, $offset = 1) {
|
||||
if ($this->settings['compress']) {
|
||||
trigger_error(sprintf(__('Method increment() not implemented for compressed cache in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
return $this->__Memcache->increment($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to substract
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New decremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function decrement($key, $offset = 1) {
|
||||
if ($this->settings['compress']) {
|
||||
trigger_error(sprintf(__('Method decrement() not implemented for compressed cache in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
return $this->__Memcache->decrement($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
return $this->__Memcache->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache
|
||||
*
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function clear() {
|
||||
return $this->__Memcache->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a server in connection pool
|
||||
*
|
||||
* @param string $host host ip address or name
|
||||
* @param integer $port Server port
|
||||
* @return boolean True if memcache server was connected
|
||||
* @access public
|
||||
*/
|
||||
function connect($host, $port = 11211) {
|
||||
if ($this->__Memcache->getServerStatus($host, $port) === 0) {
|
||||
if ($this->__Memcache->connect($host, $port)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
183
web-cake/html/cake/libs/cache/xcache.php
vendored
Normal file
183
web-cake/html/cake/libs/cache/xcache.php
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* Xcache storage engine for cache.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
* @since CakePHP(tm) v 1.2.0.4947
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Xcache storage engine for cache
|
||||
*
|
||||
* @link http://trac.lighttpd.net/xcache/ Xcache
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.cache
|
||||
*/
|
||||
class XcacheEngine extends CacheEngine {
|
||||
|
||||
/**
|
||||
* Settings
|
||||
*
|
||||
* - PHP_AUTH_USER = xcache.admin.user, default cake
|
||||
* - PHP_AUTH_PW = xcache.admin.password, default cake
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $settings = array();
|
||||
|
||||
/**
|
||||
* Initialize the Cache Engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
|
||||
*
|
||||
* @param array $setting array of setting for the engine
|
||||
* @return boolean True if the engine has been successfully initialized, false if not
|
||||
* @access public
|
||||
*/
|
||||
function init($settings) {
|
||||
parent::init(array_merge(array(
|
||||
'engine' => 'Xcache', 'prefix' => Inflector::slug(APP_DIR) . '_', 'PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password'
|
||||
), $settings)
|
||||
);
|
||||
return function_exists('xcache_info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return boolean True if the data was succesfully cached, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function write($key, &$value, $duration) {
|
||||
$expires = time() + $duration;
|
||||
xcache_set($key . '_expires', $expires, $duration);
|
||||
return xcache_set($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
* @access public
|
||||
*/
|
||||
function read($key) {
|
||||
if (xcache_isset($key)) {
|
||||
$time = time();
|
||||
$cachetime = intval(xcache_get($key . '_expires'));
|
||||
if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
|
||||
return false;
|
||||
}
|
||||
return xcache_get($key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of an integer cached key
|
||||
* If the cache key is not an integer it will be treated as 0
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to increment
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New incremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function increment($key, $offset = 1) {
|
||||
return xcache_inc($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value of an integer cached key.
|
||||
* If the cache key is not an integer it will be treated as 0
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param integer $offset How much to substract
|
||||
* @param integer $duration How long to cache the data, in seconds
|
||||
* @return New decremented value, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function decrement($key, $offset = 1) {
|
||||
return xcache_dec($key, $offset);
|
||||
}
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
return xcache_unset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache
|
||||
*
|
||||
* @return boolean True if the cache was succesfully cleared, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function clear() {
|
||||
$this->__auth();
|
||||
$max = xcache_count(XC_TYPE_VAR);
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
xcache_clear_cache(XC_TYPE_VAR, $i);
|
||||
}
|
||||
$this->__auth(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates and reverses $_SERVER authentication values
|
||||
* Makes necessary changes (and reverting them back) in $_SERVER
|
||||
*
|
||||
* This has to be done because xcache_clear_cache() needs to pass Basic Http Auth
|
||||
* (see xcache.admin configuration settings)
|
||||
*
|
||||
* @param boolean Revert changes
|
||||
* @access private
|
||||
*/
|
||||
function __auth($reverse = false) {
|
||||
static $backup = array();
|
||||
$keys = array('PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password');
|
||||
foreach ($keys as $key => $setting) {
|
||||
if ($reverse) {
|
||||
if (isset($backup[$key])) {
|
||||
$_SERVER[$key] = $backup[$key];
|
||||
unset($backup[$key]);
|
||||
} else {
|
||||
unset($_SERVER[$key]);
|
||||
}
|
||||
} else {
|
||||
$value = env($key);
|
||||
if (!empty($value)) {
|
||||
$backup[$key] = $value;
|
||||
}
|
||||
if (!empty($this->settings[$setting])) {
|
||||
$_SERVER[$key] = $this->settings[$setting];
|
||||
} else if (!empty($this->settings[$key])) {
|
||||
$_SERVER[$key] = $this->settings[$key];
|
||||
} else {
|
||||
$_SERVER[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
291
web-cake/html/cake/libs/cake_log.php
Normal file
291
web-cake/html/cake/libs/cake_log.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
/**
|
||||
* Logging.
|
||||
*
|
||||
* Log messages to text files.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
/**
|
||||
* Set up error level constants to be used within the framework if they are not defined within the
|
||||
* system.
|
||||
*
|
||||
*/
|
||||
if (!defined('LOG_WARNING')) {
|
||||
define('LOG_WARNING', 3);
|
||||
}
|
||||
if (!defined('LOG_NOTICE')) {
|
||||
define('LOG_NOTICE', 4);
|
||||
}
|
||||
if (!defined('LOG_DEBUG')) {
|
||||
define('LOG_DEBUG', 5);
|
||||
}
|
||||
if (!defined('LOG_INFO')) {
|
||||
define('LOG_INFO', 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs messages to configured Log adapters. One or more adapters can be configured
|
||||
* using CakeLogs's methods. If you don't configure any adapters, and write to the logs
|
||||
* a default FileLog will be autoconfigured for you.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CakeLog {
|
||||
|
||||
/**
|
||||
* An array of connected streams.
|
||||
* Each stream represents a callable that will be called when write() is called.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_streams = array();
|
||||
|
||||
/**
|
||||
* Get an instance
|
||||
*
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
if (!isset($instance[0])) {
|
||||
$instance[0] =& new CakeLog();
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure and add a new logging stream to CakeLog
|
||||
* You can use add loggers from app/libs use app.loggername, or any plugin/libs using plugin.loggername.
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* {{{
|
||||
* CakeLog::config('second_file', array(
|
||||
* 'engine' => 'FileLog',
|
||||
* 'path' => '/var/logs/my_app/'
|
||||
* ));
|
||||
* }}}
|
||||
*
|
||||
* Will configure a FileLog instance to use the specified path. All options that are not `engine`
|
||||
* are passed onto the logging adapter, and handled there. Any class can be configured as a logging
|
||||
* adapter as long as it implements a `write` method with the following signature.
|
||||
*
|
||||
* `write($type, $message)`
|
||||
*
|
||||
* For an explaination of these parameters, see CakeLog::write()
|
||||
*
|
||||
* @param string $key The keyname for this logger, used to remove the logger later.
|
||||
* @param array $config Array of configuration information for the logger
|
||||
* @return boolean success of configuration.
|
||||
* @static
|
||||
*/
|
||||
function config($key, $config) {
|
||||
if (empty($config['engine'])) {
|
||||
trigger_error(__('Missing logger classname', true), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$self =& CakeLog::getInstance();
|
||||
$className = $self->_getLogger($config['engine']);
|
||||
if (!$className) {
|
||||
return false;
|
||||
}
|
||||
unset($config['engine']);
|
||||
$self->_streams[$key] = new $className($config);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to import a logger class from the various paths it could be on.
|
||||
* Checks that the logger class implements a write method as well.
|
||||
*
|
||||
* @param string $loggerName the plugin.className of the logger class you want to build.
|
||||
* @return mixed boolean false on any failures, string of classname to use if search was successful.
|
||||
* @access protected
|
||||
*/
|
||||
function _getLogger($loggerName) {
|
||||
list($plugin, $loggerName) = pluginSplit($loggerName);
|
||||
|
||||
if ($plugin) {
|
||||
App::import('Lib', $plugin . '.log/' . $loggerName);
|
||||
} else {
|
||||
if (!App::import('Lib', 'log/' . $loggerName)) {
|
||||
App::import('Core', 'log/' . $loggerName);
|
||||
}
|
||||
}
|
||||
if (!class_exists($loggerName)) {
|
||||
trigger_error(sprintf(__('Could not load logger class %s', true), $loggerName), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
if (!is_callable(array($loggerName, 'write'))) {
|
||||
trigger_error(
|
||||
sprintf(__('logger class %s does not implement a write method.', true), $loggerName),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return $loggerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keynames of the currently active streams
|
||||
*
|
||||
* @return array Array of configured log streams.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function configured() {
|
||||
$self =& CakeLog::getInstance();
|
||||
return array_keys($self->_streams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a stream from the active streams. Once a stream has been removed
|
||||
* it will no longer have messages sent to it.
|
||||
*
|
||||
* @param string $keyname Key name of a configured stream to remove.
|
||||
* @return void
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function drop($streamName) {
|
||||
$self =& CakeLog::getInstance();
|
||||
unset($self->_streams[$streamName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the automatic/default stream a FileLog.
|
||||
*
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _autoConfig() {
|
||||
if (!class_exists('FileLog')) {
|
||||
App::import('Core', 'log/FileLog');
|
||||
}
|
||||
$this->_streams['default'] =& new FileLog(array('path' => LOGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given message and type to all of the configured log adapters.
|
||||
* Configured adapters are passed both the $type and $message variables. $type
|
||||
* is one of the following strings/values.
|
||||
*
|
||||
* ### Types:
|
||||
*
|
||||
* - `LOG_WARNING` => 'warning',
|
||||
* - `LOG_NOTICE` => 'notice',
|
||||
* - `LOG_INFO` => 'info',
|
||||
* - `LOG_DEBUG` => 'debug',
|
||||
* - `LOG_ERR` => 'error',
|
||||
* - `LOG_ERROR` => 'error'
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Write a message to the 'warning' log:
|
||||
*
|
||||
* `CakeLog::write('warning', 'Stuff is broken here');`
|
||||
*
|
||||
* @param string $type Type of message being written
|
||||
* @param string $message Message content to log
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function write($type, $message) {
|
||||
if (!defined('LOG_ERROR')) {
|
||||
define('LOG_ERROR', 2);
|
||||
}
|
||||
if (!defined('LOG_ERR')) {
|
||||
define('LOG_ERR', LOG_ERROR);
|
||||
}
|
||||
$levels = array(
|
||||
LOG_WARNING => 'warning',
|
||||
LOG_NOTICE => 'notice',
|
||||
LOG_INFO => 'info',
|
||||
LOG_DEBUG => 'debug',
|
||||
LOG_ERR => 'error',
|
||||
LOG_ERROR => 'error'
|
||||
);
|
||||
|
||||
if (is_int($type) && isset($levels[$type])) {
|
||||
$type = $levels[$type];
|
||||
}
|
||||
$self =& CakeLog::getInstance();
|
||||
if (empty($self->_streams)) {
|
||||
$self->_autoConfig();
|
||||
}
|
||||
$keys = array_keys($self->_streams);
|
||||
foreach ($keys as $key) {
|
||||
$logger =& $self->_streams[$key];
|
||||
$logger->write($type, $message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* An error_handler that will log errors to file using CakeLog::write();
|
||||
* You can control how verbose and what type of errors this error_handler will
|
||||
* catch using `Configure::write('log', $value)`. See core.php for more information.
|
||||
*
|
||||
*
|
||||
* @param integer $code Code of error
|
||||
* @param string $description Error description
|
||||
* @param string $file File on which error occurred
|
||||
* @param integer $line Line that triggered the error
|
||||
* @param array $context Context
|
||||
* @return void
|
||||
*/
|
||||
function handleError($code, $description, $file = null, $line = null, $context = null) {
|
||||
if ($code === 2048 || $code === 8192) {
|
||||
return;
|
||||
}
|
||||
switch ($code) {
|
||||
case E_PARSE:
|
||||
case E_ERROR:
|
||||
case E_CORE_ERROR:
|
||||
case E_COMPILE_ERROR:
|
||||
case E_USER_ERROR:
|
||||
$error = 'Fatal Error';
|
||||
$level = LOG_ERROR;
|
||||
break;
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_RECOVERABLE_ERROR:
|
||||
$error = 'Warning';
|
||||
$level = LOG_WARNING;
|
||||
break;
|
||||
case E_NOTICE:
|
||||
case E_USER_NOTICE:
|
||||
$error = 'Notice';
|
||||
$level = LOG_NOTICE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
$message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
|
||||
CakeLog::write($level, $message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
|
||||
set_error_handler(array('CakeLog', 'handleError'));
|
||||
}
|
||||
791
web-cake/html/cake/libs/cake_session.php
Normal file
791
web-cake/html/cake/libs/cake_session.php
Normal file
@@ -0,0 +1,791 @@
|
||||
<?php
|
||||
/**
|
||||
* Session class for Cake.
|
||||
*
|
||||
* Cake abstracts the handling of sessions.
|
||||
* There are several convenient methods to access session information.
|
||||
* This class is the implementation of those methods.
|
||||
* They are mostly used by the Session Component.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v .0.10.0.1222
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Session class for Cake.
|
||||
*
|
||||
* Cake abstracts the handling of sessions. There are several convenient methods to access session information.
|
||||
* This class is the implementation of those methods. They are mostly used by the Session Component.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CakeSession extends Object {
|
||||
|
||||
/**
|
||||
* True if the Session is still valid
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $valid = false;
|
||||
|
||||
/**
|
||||
* Error messages for this session
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $error = false;
|
||||
|
||||
/**
|
||||
* User agent string
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_userAgent = '';
|
||||
|
||||
/**
|
||||
* Path to where the session is active.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $path = '/';
|
||||
|
||||
/**
|
||||
* Error number of last occurred error
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $lastError = null;
|
||||
|
||||
/**
|
||||
* 'Security.level' setting, "high", "medium", or "low".
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $security = null;
|
||||
|
||||
/**
|
||||
* Start time for this session.
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $time = false;
|
||||
|
||||
/**
|
||||
* Time when this session becomes invalid.
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $sessionTime = false;
|
||||
|
||||
/**
|
||||
* The number of seconds to set for session.cookie_lifetime. 0 means
|
||||
* at browser close.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $cookieLifeTime = false;
|
||||
|
||||
/**
|
||||
* Keeps track of keys to watch for writes on
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $watchKeys = array();
|
||||
|
||||
/**
|
||||
* Current Session id
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $id = null;
|
||||
|
||||
/**
|
||||
* Hostname
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $host = null;
|
||||
|
||||
/**
|
||||
* Session timeout multiplier factor
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $timeout = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $base The base path for the Session
|
||||
* @param boolean $start Should session be started right now
|
||||
* @access public
|
||||
*/
|
||||
function __construct($base = null, $start = true) {
|
||||
App::import('Core', array('Set', 'Security'));
|
||||
$this->time = time();
|
||||
|
||||
if (Configure::read('Session.checkAgent') === true || Configure::read('Session.checkAgent') === null) {
|
||||
if (env('HTTP_USER_AGENT') != null) {
|
||||
$this->_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
|
||||
}
|
||||
}
|
||||
if (Configure::read('Session.save') === 'database') {
|
||||
$modelName = Configure::read('Session.model');
|
||||
$database = Configure::read('Session.database');
|
||||
$table = Configure::read('Session.table');
|
||||
|
||||
if (empty($database)) {
|
||||
$database = 'default';
|
||||
}
|
||||
$settings = array(
|
||||
'class' => 'Session',
|
||||
'alias' => 'Session',
|
||||
'table' => 'cake_sessions',
|
||||
'ds' => $database
|
||||
);
|
||||
if (!empty($modelName)) {
|
||||
$settings['class'] = $modelName;
|
||||
}
|
||||
if (!empty($table)) {
|
||||
$settings['table'] = $table;
|
||||
}
|
||||
ClassRegistry::init($settings);
|
||||
}
|
||||
if ($start === true) {
|
||||
if (!empty($base)) {
|
||||
$this->path = $base;
|
||||
if (strpos($base, 'index.php') !== false) {
|
||||
$this->path = str_replace('index.php', '', $base);
|
||||
}
|
||||
if (strpos($base, '?') !== false) {
|
||||
$this->path = str_replace('?', '', $base);
|
||||
}
|
||||
}
|
||||
$this->host = env('HTTP_HOST');
|
||||
|
||||
if (strpos($this->host, ':') !== false) {
|
||||
$this->host = substr($this->host, 0, strpos($this->host, ':'));
|
||||
}
|
||||
}
|
||||
if (isset($_SESSION) || $start === true) {
|
||||
if (!class_exists('Security')) {
|
||||
App::import('Core', 'Security');
|
||||
}
|
||||
$this->sessionTime = $this->time + (Security::inactiveMins() * Configure::read('Session.timeout'));
|
||||
$this->security = Configure::read('Security.level');
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Session.
|
||||
*
|
||||
* @return boolean True if session was started
|
||||
* @access public
|
||||
*/
|
||||
function start() {
|
||||
if ($this->started()) {
|
||||
return true;
|
||||
}
|
||||
if (function_exists('session_write_close')) {
|
||||
session_write_close();
|
||||
}
|
||||
$this->__initSession();
|
||||
$this->__startSession();
|
||||
return $this->started();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if Session has been started.
|
||||
*
|
||||
* @access public
|
||||
* @return boolean True if session has been started.
|
||||
*/
|
||||
function started() {
|
||||
if (isset($_SESSION) && session_id()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given variable is set in session.
|
||||
*
|
||||
* @param string $name Variable name to check for
|
||||
* @return boolean True if variable is there
|
||||
* @access public
|
||||
*/
|
||||
function check($name) {
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
$result = Set::classicExtract($_SESSION, $name);
|
||||
return isset($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Session id
|
||||
*
|
||||
* @param id $name string
|
||||
* @return string Session id
|
||||
* @access public
|
||||
*/
|
||||
function id($id = null) {
|
||||
if ($id) {
|
||||
$this->id = $id;
|
||||
session_id($this->id);
|
||||
}
|
||||
if ($this->started()) {
|
||||
return session_id();
|
||||
} else {
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a variable from session.
|
||||
*
|
||||
* @param string $name Session variable to remove
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function delete($name) {
|
||||
if ($this->check($name)) {
|
||||
if (in_array($name, $this->watchKeys)) {
|
||||
trigger_error(sprintf(__('Deleting session key {%s}', true), $name), E_USER_NOTICE);
|
||||
}
|
||||
$this->__overwrite($_SESSION, Set::remove($_SESSION, $name));
|
||||
return ($this->check($name) == false);
|
||||
}
|
||||
$this->__setError(2, sprintf(__("%s doesn't exist", true), $name));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself
|
||||
*
|
||||
* @param array $old Set of old variables => values
|
||||
* @param array $new New set of variable => value
|
||||
* @access private
|
||||
*/
|
||||
function __overwrite(&$old, $new) {
|
||||
if (!empty($old)) {
|
||||
foreach ($old as $key => $var) {
|
||||
if (!isset($new[$key])) {
|
||||
unset($old[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($new as $key => $var) {
|
||||
$old[$key] = $var;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return error description for given error number.
|
||||
*
|
||||
* @param integer $errorNumber Error to set
|
||||
* @return string Error as string
|
||||
* @access private
|
||||
*/
|
||||
function __error($errorNumber) {
|
||||
if (!is_array($this->error) || !array_key_exists($errorNumber, $this->error)) {
|
||||
return false;
|
||||
} else {
|
||||
return $this->error[$errorNumber];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last occurred error as a string, if any.
|
||||
*
|
||||
* @return mixed Error description as a string, or false.
|
||||
* @access public
|
||||
*/
|
||||
function error() {
|
||||
if ($this->lastError) {
|
||||
return $this->__error($this->lastError);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if session is valid.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function valid() {
|
||||
if ($this->read('Config')) {
|
||||
if ((Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read('Config.userAgent')) && $this->time <= $this->read('Config.time')) {
|
||||
if ($this->error === false) {
|
||||
$this->valid = true;
|
||||
}
|
||||
} else {
|
||||
$this->valid = false;
|
||||
$this->__setError(1, 'Session Highjacking Attempted !!!');
|
||||
}
|
||||
}
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given session variable, or all of them, if no parameters given.
|
||||
*
|
||||
* @param mixed $name The name of the session variable (or a path as sent to Set.extract)
|
||||
* @return mixed The value of the session variable
|
||||
* @access public
|
||||
*/
|
||||
function read($name = null) {
|
||||
if (is_null($name)) {
|
||||
return $this->__returnSessionVars();
|
||||
}
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
$result = Set::classicExtract($_SESSION, $name);
|
||||
|
||||
if (!is_null($result)) {
|
||||
return $result;
|
||||
}
|
||||
$this->__setError(2, "$name doesn't exist");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all session variables.
|
||||
*
|
||||
* @return mixed Full $_SESSION array, or false on error.
|
||||
* @access private
|
||||
*/
|
||||
function __returnSessionVars() {
|
||||
if (!empty($_SESSION)) {
|
||||
return $_SESSION;
|
||||
}
|
||||
$this->__setError(2, "No Session vars set");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Session to write a notification when a certain session path or subpath is written to
|
||||
*
|
||||
* @param mixed $var The variable path to watch
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function watch($var) {
|
||||
if (empty($var)) {
|
||||
return false;
|
||||
}
|
||||
if (!in_array($var, $this->watchKeys, true)) {
|
||||
$this->watchKeys[] = $var;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Session to stop watching a given key path
|
||||
*
|
||||
* @param mixed $var The variable path to watch
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function ignore($var) {
|
||||
if (!in_array($var, $this->watchKeys)) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->watchKeys as $i => $key) {
|
||||
if ($key == $var) {
|
||||
unset($this->watchKeys[$i]);
|
||||
$this->watchKeys = array_values($this->watchKeys);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes value to given session variable name.
|
||||
*
|
||||
* @param mixed $name Name of variable
|
||||
* @param string $value Value to write
|
||||
* @return boolean True if the write was successful, false if the write failed
|
||||
* @access public
|
||||
*/
|
||||
function write($name, $value) {
|
||||
if (empty($name)) {
|
||||
return false;
|
||||
}
|
||||
if (in_array($name, $this->watchKeys)) {
|
||||
trigger_error(sprintf(__('Writing session key {%s}: %s', true), $name, Debugger::exportVar($value)), E_USER_NOTICE);
|
||||
}
|
||||
$this->__overwrite($_SESSION, Set::insert($_SESSION, $name, $value));
|
||||
return (Set::classicExtract($_SESSION, $name) === $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to destroy invalid sessions.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function destroy() {
|
||||
if ($this->started()) {
|
||||
session_destroy();
|
||||
}
|
||||
$_SESSION = null;
|
||||
$this->__construct($this->path);
|
||||
$this->start();
|
||||
$this->renew();
|
||||
$this->_checkValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a session, based on Cake core settings.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __initSession() {
|
||||
$iniSet = function_exists('ini_set');
|
||||
if ($iniSet && env('HTTPS')) {
|
||||
ini_set('session.cookie_secure', 1);
|
||||
}
|
||||
if ($iniSet && ($this->security === 'high' || $this->security === 'medium')) {
|
||||
ini_set('session.referer_check', $this->host);
|
||||
}
|
||||
|
||||
if ($this->security == 'high') {
|
||||
$this->cookieLifeTime = 0;
|
||||
} else {
|
||||
$this->cookieLifeTime = Configure::read('Session.timeout') * (Security::inactiveMins() * 60);
|
||||
}
|
||||
|
||||
switch (Configure::read('Session.save')) {
|
||||
case 'cake':
|
||||
if (empty($_SESSION)) {
|
||||
if ($iniSet) {
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('url_rewriter.tags', '');
|
||||
ini_set('session.serialize_handler', 'php');
|
||||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.name', Configure::read('Session.cookie'));
|
||||
ini_set('session.cookie_lifetime', $this->cookieLifeTime);
|
||||
ini_set('session.cookie_path', $this->path);
|
||||
ini_set('session.auto_start', 0);
|
||||
ini_set('session.save_path', TMP . 'sessions');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'database':
|
||||
if (empty($_SESSION)) {
|
||||
if (Configure::read('Session.model') === null) {
|
||||
trigger_error(__("You must set the all Configure::write('Session.*') in core.php to use database storage"), E_USER_WARNING);
|
||||
$this->_stop();
|
||||
}
|
||||
if ($iniSet) {
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('url_rewriter.tags', '');
|
||||
ini_set('session.save_handler', 'user');
|
||||
ini_set('session.serialize_handler', 'php');
|
||||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.name', Configure::read('Session.cookie'));
|
||||
ini_set('session.cookie_lifetime', $this->cookieLifeTime);
|
||||
ini_set('session.cookie_path', $this->path);
|
||||
ini_set('session.auto_start', 0);
|
||||
}
|
||||
}
|
||||
session_set_save_handler(
|
||||
array('CakeSession','__open'),
|
||||
array('CakeSession', '__close'),
|
||||
array('CakeSession', '__read'),
|
||||
array('CakeSession', '__write'),
|
||||
array('CakeSession', '__destroy'),
|
||||
array('CakeSession', '__gc')
|
||||
);
|
||||
break;
|
||||
case 'php':
|
||||
if (empty($_SESSION)) {
|
||||
if ($iniSet) {
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('session.name', Configure::read('Session.cookie'));
|
||||
ini_set('session.cookie_lifetime', $this->cookieLifeTime);
|
||||
ini_set('session.cookie_path', $this->path);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'cache':
|
||||
if (empty($_SESSION)) {
|
||||
if (!class_exists('Cache')) {
|
||||
require LIBS . 'cache.php';
|
||||
}
|
||||
if ($iniSet) {
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('url_rewriter.tags', '');
|
||||
ini_set('session.save_handler', 'user');
|
||||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.name', Configure::read('Session.cookie'));
|
||||
ini_set('session.cookie_lifetime', $this->cookieLifeTime);
|
||||
ini_set('session.cookie_path', $this->path);
|
||||
}
|
||||
}
|
||||
session_set_save_handler(
|
||||
array('CakeSession','__open'),
|
||||
array('CakeSession', '__close'),
|
||||
array('Cache', 'read'),
|
||||
array('Cache', 'write'),
|
||||
array('Cache', 'delete'),
|
||||
array('Cache', 'gc')
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$config = CONFIGS . Configure::read('Session.save') . '.php';
|
||||
|
||||
if (is_file($config)) {
|
||||
require($config);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to start a session
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __startSession() {
|
||||
if (headers_sent()) {
|
||||
if (empty($_SESSION)) {
|
||||
$_SESSION = array();
|
||||
}
|
||||
return true;
|
||||
} elseif (!isset($_SESSION)) {
|
||||
session_cache_limiter ("must-revalidate");
|
||||
session_start();
|
||||
header ('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
|
||||
return true;
|
||||
} else {
|
||||
session_start();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a new session.
|
||||
*
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _checkValid() {
|
||||
if ($this->read('Config')) {
|
||||
if ((Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read('Config.userAgent')) && $this->time <= $this->read('Config.time')) {
|
||||
$time = $this->read('Config.time');
|
||||
$this->write('Config.time', $this->sessionTime);
|
||||
if (Configure::read('Security.level') === 'high') {
|
||||
$check = $this->read('Config.timeout');
|
||||
$check -= 1;
|
||||
$this->write('Config.timeout', $check);
|
||||
|
||||
if (time() > ($time - (Security::inactiveMins() * Configure::read('Session.timeout')) + 2) || $check < 1) {
|
||||
$this->renew();
|
||||
$this->write('Config.timeout', 10);
|
||||
}
|
||||
}
|
||||
$this->valid = true;
|
||||
} else {
|
||||
$this->destroy();
|
||||
$this->valid = false;
|
||||
$this->__setError(1, 'Session Highjacking Attempted !!!');
|
||||
}
|
||||
} else {
|
||||
$this->write('Config.userAgent', $this->_userAgent);
|
||||
$this->write('Config.time', $this->sessionTime);
|
||||
$this->write('Config.timeout', 10);
|
||||
$this->valid = true;
|
||||
$this->__setError(1, 'Session is valid');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to restart a session.
|
||||
*
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __regenerateId() {
|
||||
$oldSessionId = session_id();
|
||||
if ($oldSessionId) {
|
||||
if (session_id() != ''|| isset($_COOKIE[session_name()])) {
|
||||
setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
|
||||
}
|
||||
session_regenerate_id(true);
|
||||
if (PHP_VERSION < 5.1) {
|
||||
$sessionPath = session_save_path();
|
||||
if (empty($sessionPath)) {
|
||||
$sessionPath = '/tmp';
|
||||
}
|
||||
$newSessid = session_id();
|
||||
|
||||
if (function_exists('session_write_close')) {
|
||||
session_write_close();
|
||||
}
|
||||
$this->__initSession();
|
||||
session_id($oldSessionId);
|
||||
session_start();
|
||||
session_destroy();
|
||||
$file = $sessionPath . DS . 'sess_' . $oldSessionId;
|
||||
@unlink($file);
|
||||
$this->__initSession();
|
||||
session_id($newSessid);
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts this session.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function renew() {
|
||||
$this->__regenerateId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to set an internal error message.
|
||||
*
|
||||
* @param integer $errorNumber Number of the error
|
||||
* @param string $errorMessage Description of the error
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __setError($errorNumber, $errorMessage) {
|
||||
if ($this->error === false) {
|
||||
$this->error = array();
|
||||
}
|
||||
$this->error[$errorNumber] = $errorMessage;
|
||||
$this->lastError = $errorNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called on open of a database session.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __open() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called on close of a database session.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __close() {
|
||||
$probability = mt_rand(1, 150);
|
||||
if ($probability <= 3) {
|
||||
switch (Configure::read('Session.save')) {
|
||||
case 'cache':
|
||||
Cache::gc();
|
||||
break;
|
||||
default:
|
||||
CakeSession::__gc();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to read from a database session.
|
||||
*
|
||||
* @param mixed $id The key of the value to read
|
||||
* @return mixed The value of the key or false if it does not exist
|
||||
* @access private
|
||||
*/
|
||||
function __read($id) {
|
||||
$model =& ClassRegistry::getObject('Session');
|
||||
|
||||
$row = $model->find('first', array(
|
||||
'conditions' => array($model->primaryKey => $id)
|
||||
));
|
||||
|
||||
if (empty($row[$model->alias]['data'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $row[$model->alias]['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function called on write for database sessions.
|
||||
*
|
||||
* @param integer $id ID that uniquely identifies session in database
|
||||
* @param mixed $data The value of the data to be saved.
|
||||
* @return boolean True for successful write, false otherwise.
|
||||
* @access private
|
||||
*/
|
||||
function __write($id, $data) {
|
||||
$expires = time() + Configure::read('Session.timeout') * Security::inactiveMins();
|
||||
$model =& ClassRegistry::getObject('Session');
|
||||
$return = $model->save(array($model->primaryKey => $id) + compact('data', 'expires'));
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called on the destruction of a database session.
|
||||
*
|
||||
* @param integer $id ID that uniquely identifies session in database
|
||||
* @return boolean True for successful delete, false otherwise.
|
||||
* @access private
|
||||
*/
|
||||
function __destroy($id) {
|
||||
$model =& ClassRegistry::getObject('Session');
|
||||
$return = $model->delete($id);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function called on gc for database sessions.
|
||||
*
|
||||
* @param integer $expires Timestamp (defaults to current time)
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __gc($expires = null) {
|
||||
$model =& ClassRegistry::getObject('Session');
|
||||
|
||||
if (!$expires) {
|
||||
$expires = time();
|
||||
}
|
||||
|
||||
$return = $model->deleteAll(array($model->alias . ".expires <" => $expires), false, false);
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
304
web-cake/html/cake/libs/cake_socket.php
Normal file
304
web-cake/html/cake/libs/cake_socket.php
Normal file
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
/**
|
||||
* Cake Socket connection class.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Core', 'Validation');
|
||||
|
||||
/**
|
||||
* Cake network socket connection class.
|
||||
*
|
||||
* Core base class for network communication.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CakeSocket extends Object {
|
||||
|
||||
/**
|
||||
* Object description
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $description = 'Remote DataSource Network Socket Interface';
|
||||
|
||||
/**
|
||||
* Base configuration settings for the socket connection
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'protocol' => 'tcp',
|
||||
'port' => 80,
|
||||
'timeout' => 30
|
||||
);
|
||||
|
||||
/**
|
||||
* Configuration settings for the socket connection
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $config = array();
|
||||
|
||||
/**
|
||||
* Reference to socket connection resource
|
||||
*
|
||||
* @var resource
|
||||
* @access public
|
||||
*/
|
||||
var $connection = null;
|
||||
|
||||
/**
|
||||
* This boolean contains the current state of the CakeSocket class
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $connected = false;
|
||||
|
||||
/**
|
||||
* This variable contains an array with the last error number (num) and string (str)
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $lastError = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config Socket configuration, which will be merged with the base configuration
|
||||
* @see CakeSocket::$_baseConfig
|
||||
*/
|
||||
function __construct($config = array()) {
|
||||
parent::__construct();
|
||||
|
||||
$this->config = array_merge($this->_baseConfig, $config);
|
||||
if (!is_numeric($this->config['protocol'])) {
|
||||
$this->config['protocol'] = getprotobyname($this->config['protocol']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect the socket to the given host and port.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function connect() {
|
||||
if ($this->connection != null) {
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
$scheme = null;
|
||||
if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') {
|
||||
$scheme = 'ssl://';
|
||||
}
|
||||
|
||||
if ($this->config['persistent'] == true) {
|
||||
$tmp = null;
|
||||
$this->connection = @pfsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
|
||||
} else {
|
||||
$this->connection = @fsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
|
||||
}
|
||||
|
||||
if (!empty($errNum) || !empty($errStr)) {
|
||||
$this->setLastError($errStr, $errNum);
|
||||
}
|
||||
|
||||
$this->connected = is_resource($this->connection);
|
||||
if ($this->connected) {
|
||||
stream_set_timeout($this->connection, $this->config['timeout']);
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host name of the current connection.
|
||||
*
|
||||
* @return string Host name
|
||||
* @access public
|
||||
*/
|
||||
function host() {
|
||||
if (Validation::ip($this->config['host'])) {
|
||||
return gethostbyaddr($this->config['host']);
|
||||
} else {
|
||||
return gethostbyaddr($this->address());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP address of the current connection.
|
||||
*
|
||||
* @return string IP address
|
||||
* @access public
|
||||
*/
|
||||
function address() {
|
||||
if (Validation::ip($this->config['host'])) {
|
||||
return $this->config['host'];
|
||||
} else {
|
||||
return gethostbyname($this->config['host']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all IP addresses associated with the current connection.
|
||||
*
|
||||
* @return array IP addresses
|
||||
* @access public
|
||||
*/
|
||||
function addresses() {
|
||||
if (Validation::ip($this->config['host'])) {
|
||||
return array($this->config['host']);
|
||||
} else {
|
||||
return gethostbynamel($this->config['host']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error as a string.
|
||||
*
|
||||
* @return string Last error
|
||||
* @access public
|
||||
*/
|
||||
function lastError() {
|
||||
if (!empty($this->lastError)) {
|
||||
return $this->lastError['num'] . ': ' . $this->lastError['str'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last error.
|
||||
*
|
||||
* @param integer $errNum Error code
|
||||
* @param string $errStr Error string
|
||||
* @access public
|
||||
*/
|
||||
function setLastError($errNum, $errStr) {
|
||||
$this->lastError = array('num' => $errNum, 'str' => $errStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to the socket.
|
||||
*
|
||||
* @param string $data The data to write to the socket
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function write($data) {
|
||||
if (!$this->connected) {
|
||||
if (!$this->connect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return fwrite($this->connection, $data, strlen($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from the socket. Returns false if no data is available or no connection could be
|
||||
* established.
|
||||
*
|
||||
* @param integer $length Optional buffer length to read; defaults to 1024
|
||||
* @return mixed Socket data
|
||||
* @access public
|
||||
*/
|
||||
function read($length = 1024) {
|
||||
if (!$this->connected) {
|
||||
if (!$this->connect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!feof($this->connection)) {
|
||||
$buffer = fread($this->connection, $length);
|
||||
$info = stream_get_meta_data($this->connection);
|
||||
if ($info['timed_out']) {
|
||||
$this->setLastError(E_WARNING, __('Connection timed out', true));
|
||||
return false;
|
||||
}
|
||||
return $buffer;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort socket operation.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function abort() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the socket from the current connection.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function disconnect() {
|
||||
if (!is_resource($this->connection)) {
|
||||
$this->connected = false;
|
||||
return true;
|
||||
}
|
||||
$this->connected = !fclose($this->connection);
|
||||
|
||||
if (!$this->connected) {
|
||||
$this->connection = null;
|
||||
}
|
||||
return !$this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor, used to disconnect from current connection.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __destruct() {
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of this Socket instance to it's initial state (before Object::__construct got executed)
|
||||
*
|
||||
* @return boolean True on success
|
||||
* @access public
|
||||
*/
|
||||
function reset($state = null) {
|
||||
if (empty($state)) {
|
||||
static $initalState = array();
|
||||
if (empty($initalState)) {
|
||||
$initalState = get_class_vars(__CLASS__);
|
||||
}
|
||||
$state = $initalState;
|
||||
}
|
||||
|
||||
foreach ($state as $property => $value) {
|
||||
$this->{$property} = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
364
web-cake/html/cake/libs/class_registry.php
Normal file
364
web-cake/html/cake/libs/class_registry.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
/**
|
||||
* Class collections.
|
||||
*
|
||||
* A repository for class objects, each registered with a key.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.9.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class Collections.
|
||||
*
|
||||
* A repository for class objects, each registered with a key.
|
||||
* If you try to add an object with the same key twice, nothing will come of it.
|
||||
* If you need a second instance of an object, give it another key.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class ClassRegistry {
|
||||
|
||||
/**
|
||||
* Names of classes with their objects.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__objects = array();
|
||||
|
||||
/**
|
||||
* Names of class names mapped to the object in the registry.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__map = array();
|
||||
|
||||
/**
|
||||
* Default constructor parameter settings, indexed by type
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__config = array();
|
||||
|
||||
/**
|
||||
* Return a singleton instance of the ClassRegistry.
|
||||
*
|
||||
* @return ClassRegistry instance
|
||||
* @access public
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
if (!$instance) {
|
||||
$instance[0] =& new ClassRegistry();
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class, registers the object in the registry and returns instance of the object.
|
||||
*
|
||||
* Examples
|
||||
* Simple Use: Get a Post model instance ```ClassRegistry::init('Post');```
|
||||
*
|
||||
* Exapanded: ```array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry', 'type' => 'TypeOfClass');```
|
||||
*
|
||||
* Model Classes can accept optional ```array('id' => $id, 'table' => $table, 'ds' => $ds, 'alias' => $alias);```
|
||||
*
|
||||
* When $class is a numeric keyed array, multiple class instances will be stored in the registry,
|
||||
* no instance of the object will be returned
|
||||
* {{{
|
||||
* array(
|
||||
* array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry', 'type' => 'TypeOfClass'),
|
||||
* array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry', 'type' => 'TypeOfClass'),
|
||||
* array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry', 'type' => 'TypeOfClass')
|
||||
* );
|
||||
* }}}
|
||||
* @param mixed $class as a string or a single key => value array instance will be created,
|
||||
* stored in the registry and returned.
|
||||
* @param string $type TypeOfClass
|
||||
* @return object instance of ClassName
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &init($class, $type = null) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$id = $false = false;
|
||||
$true = true;
|
||||
|
||||
if (!$type) {
|
||||
$type = 'Model';
|
||||
}
|
||||
|
||||
if (is_array($class)) {
|
||||
$objects = $class;
|
||||
if (!isset($class[0])) {
|
||||
$objects = array($class);
|
||||
}
|
||||
} else {
|
||||
$objects = array(array('class' => $class));
|
||||
}
|
||||
$defaults = isset($_this->__config[$type]) ? $_this->__config[$type] : array();
|
||||
$count = count($objects);
|
||||
|
||||
foreach ($objects as $key => $settings) {
|
||||
if (is_array($settings)) {
|
||||
$pluginPath = null;
|
||||
$settings = array_merge($defaults, $settings);
|
||||
$class = $settings['class'];
|
||||
|
||||
list($plugin, $class) = pluginSplit($class);
|
||||
if ($plugin) {
|
||||
$pluginPath = $plugin . '.';
|
||||
}
|
||||
|
||||
if (empty($settings['alias'])) {
|
||||
$settings['alias'] = $class;
|
||||
}
|
||||
$alias = $settings['alias'];
|
||||
|
||||
if ($model =& $_this->__duplicate($alias, $class)) {
|
||||
$_this->map($alias, $class);
|
||||
return $model;
|
||||
}
|
||||
|
||||
if (class_exists($class) || App::import($type, $pluginPath . $class)) {
|
||||
${$class} =& new $class($settings);
|
||||
} elseif ($type === 'Model') {
|
||||
if ($plugin && class_exists($plugin . 'AppModel')) {
|
||||
$appModel = $plugin . 'AppModel';
|
||||
} else {
|
||||
$appModel = 'AppModel';
|
||||
}
|
||||
$settings['name'] = $class;
|
||||
${$class} =& new $appModel($settings);
|
||||
}
|
||||
|
||||
if (!isset(${$class})) {
|
||||
trigger_error(sprintf(__('(ClassRegistry::init() could not create instance of %1$s class %2$s ', true), $class, $type), E_USER_WARNING);
|
||||
return $false;
|
||||
}
|
||||
|
||||
if ($type !== 'Model') {
|
||||
$_this->addObject($alias, ${$class});
|
||||
} else {
|
||||
$_this->map($alias, $class);
|
||||
}
|
||||
} elseif (is_numeric($settings)) {
|
||||
trigger_error(__('(ClassRegistry::init() Attempted to create instance of a class with a numeric name', true), E_USER_WARNING);
|
||||
return $false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count > 1) {
|
||||
return $true;
|
||||
}
|
||||
return ${$class};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add $object to the registry, associating it with the name $key.
|
||||
*
|
||||
* @param string $key Key for the object in registry
|
||||
* @param mixed $object Object to store
|
||||
* @return boolean True if the object was written, false if $key already exists
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function addObject($key, &$object) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$key = Inflector::underscore($key);
|
||||
if (!isset($_this->__objects[$key])) {
|
||||
$_this->__objects[$key] =& $object;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove object which corresponds to given key.
|
||||
*
|
||||
* @param string $key Key of object to remove from registry
|
||||
* @return void
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function removeObject($key) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$key = Inflector::underscore($key);
|
||||
if (isset($_this->__objects[$key])) {
|
||||
unset($_this->__objects[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given key is present in the ClassRegistry.
|
||||
*
|
||||
* @param string $key Key to look for
|
||||
* @return boolean true if key exists in registry, false otherwise
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isKeySet($key) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$key = Inflector::underscore($key);
|
||||
if (isset($_this->__objects[$key])) {
|
||||
return true;
|
||||
} elseif (isset($_this->__map[$key])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all keys from the registry.
|
||||
*
|
||||
* @return array Set of keys stored in registry
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function keys() {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
return array_keys($_this->__objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return object which corresponds to given key.
|
||||
*
|
||||
* @param string $key Key of object to look for
|
||||
* @return mixed Object stored in registry or boolean false if the object does not exist.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getObject($key) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$key = Inflector::underscore($key);
|
||||
$return = false;
|
||||
if (isset($_this->__objects[$key])) {
|
||||
$return =& $_this->__objects[$key];
|
||||
} else {
|
||||
$key = $_this->__getMap($key);
|
||||
if (isset($_this->__objects[$key])) {
|
||||
$return =& $_this->__objects[$key];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default constructor parameter for an object type
|
||||
*
|
||||
* @param string $type Type of object. If this parameter is omitted, defaults to "Model"
|
||||
* @param array $param The parameter that will be passed to object constructors when objects
|
||||
* of $type are created
|
||||
* @return mixed Void if $param is being set. Otherwise, if only $type is passed, returns
|
||||
* the previously-set value of $param, or null if not set.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function config($type, $param = array()) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
|
||||
if (empty($param) && is_array($type)) {
|
||||
$param = $type;
|
||||
$type = 'Model';
|
||||
} elseif (is_null($param)) {
|
||||
unset($_this->__config[$type]);
|
||||
} elseif (empty($param) && is_string($type)) {
|
||||
return isset($_this->__config[$type]) ? $_this->__config[$type] : null;
|
||||
}
|
||||
$_this->__config[$type] = $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if $alias is a duplicate $class Object
|
||||
*
|
||||
* @param string $alias
|
||||
* @param string $class
|
||||
* @return boolean
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
function &__duplicate($alias, $class) {
|
||||
$duplicate = false;
|
||||
if ($this->isKeySet($alias)) {
|
||||
$model =& $this->getObject($alias);
|
||||
if (is_object($model) && (is_a($model, $class) || $model->alias === $class)) {
|
||||
$duplicate =& $model;
|
||||
}
|
||||
unset($model);
|
||||
}
|
||||
return $duplicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key name pair to the registry to map name to class in the registry.
|
||||
*
|
||||
* @param string $key Key to include in map
|
||||
* @param string $name Key that is being mapped
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function map($key, $name) {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$key = Inflector::underscore($key);
|
||||
$name = Inflector::underscore($name);
|
||||
if (!isset($_this->__map[$key])) {
|
||||
$_this->__map[$key] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all keys from the map in the registry.
|
||||
*
|
||||
* @return array Keys of registry's map
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function mapKeys() {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
return array_keys($_this->__map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of a class in the registry.
|
||||
*
|
||||
* @param string $key Key to find in map
|
||||
* @return string Mapped value
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
function __getMap($key) {
|
||||
if (isset($this->__map[$key])) {
|
||||
return $this->__map[$key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes all objects from the ClassRegistry.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function flush() {
|
||||
$_this =& ClassRegistry::getInstance();
|
||||
$_this->__objects = array();
|
||||
$_this->__map = array();
|
||||
}
|
||||
}
|
||||
1313
web-cake/html/cake/libs/configure.php
Normal file
1313
web-cake/html/cake/libs/configure.php
Normal file
File diff suppressed because it is too large
Load Diff
36
web-cake/html/cake/libs/controller/app_controller.php
Normal file
36
web-cake/html/cake/libs/controller/app_controller.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Application level Controller
|
||||
*
|
||||
* This file is application-wide controller file. You can put all
|
||||
* application-wide controller-related methods here.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a placeholder class.
|
||||
* Create the same file in app/app_controller.php
|
||||
*
|
||||
* Add your application-wide methods in the class below, your controllers
|
||||
* will inherit them.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @link http://book.cakephp.org/view/957/The-App-Controller
|
||||
*/
|
||||
class AppController extends Controller {
|
||||
}
|
||||
263
web-cake/html/cake/libs/controller/component.php
Normal file
263
web-cake/html/cake/libs/controller/component.php
Normal file
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @since CakePHP(tm) v TBD
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handler for Controller::$components
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @link http://book.cakephp.org/view/993/Components
|
||||
*/
|
||||
class Component extends Object {
|
||||
|
||||
/**
|
||||
* Contains various controller variable information (plugin, name, base).
|
||||
*
|
||||
* @var object
|
||||
* @access private
|
||||
*/
|
||||
var $__controllerVars = array('plugin' => null, 'name' => null, 'base' => null);
|
||||
|
||||
/**
|
||||
* List of loaded components.
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
var $_loaded = array();
|
||||
|
||||
/**
|
||||
* List of components attached directly to the controller, which callbacks
|
||||
* should be executed on.
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
var $_primary = array();
|
||||
|
||||
/**
|
||||
* Settings for loaded components.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__settings = array();
|
||||
|
||||
/**
|
||||
* Used to initialize the components for current controller.
|
||||
*
|
||||
* @param object $controller Controller with components to load
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function init(&$controller) {
|
||||
if (!is_array($controller->components)) {
|
||||
return;
|
||||
}
|
||||
$this->__controllerVars = array(
|
||||
'plugin' => $controller->plugin, 'name' => $controller->name,
|
||||
'base' => $controller->base
|
||||
);
|
||||
|
||||
$this->_loadComponents($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the Controller::beforeFilter().
|
||||
*
|
||||
* @param object $controller Controller with components to initialize
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/998/MVC-Class-Access-Within-Components
|
||||
*/
|
||||
function initialize(&$controller) {
|
||||
foreach (array_keys($this->_loaded) as $name) {
|
||||
$component =& $this->_loaded[$name];
|
||||
|
||||
if (method_exists($component,'initialize') && $component->enabled === true) {
|
||||
$settings = array();
|
||||
if (isset($this->__settings[$name])) {
|
||||
$settings = $this->__settings[$name];
|
||||
}
|
||||
$component->initialize($controller, $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the Controller::beforeFilter() and before the controller action
|
||||
*
|
||||
* @param object $controller Controller with components to startup
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/998/MVC-Class-Access-Within-Components
|
||||
* @deprecated See Component::triggerCallback()
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
$this->triggerCallback('startup', $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the Controller::beforeRender(), after the view class is loaded, and before the
|
||||
* Controller::render()
|
||||
*
|
||||
* @param object $controller Controller with components to beforeRender
|
||||
* @return void
|
||||
* @access public
|
||||
* @deprecated See Component::triggerCallback()
|
||||
*/
|
||||
function beforeRender(&$controller) {
|
||||
$this->triggerCallback('beforeRender', $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before Controller::redirect().
|
||||
*
|
||||
* @param object $controller Controller with components to beforeRedirect
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function beforeRedirect(&$controller, $url, $status = null, $exit = true) {
|
||||
$response = array();
|
||||
|
||||
foreach ($this->_primary as $name) {
|
||||
$component =& $this->_loaded[$name];
|
||||
|
||||
if ($component->enabled === true && method_exists($component, 'beforeRedirect')) {
|
||||
$resp = $component->beforeRedirect($controller, $url, $status, $exit);
|
||||
if ($resp === false) {
|
||||
return false;
|
||||
}
|
||||
$response[] = $resp;
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after Controller::render() and before the output is printed to the browser.
|
||||
*
|
||||
* @param object $controller Controller with components to shutdown
|
||||
* @return void
|
||||
* @access public
|
||||
* @deprecated See Component::triggerCallback()
|
||||
*/
|
||||
function shutdown(&$controller) {
|
||||
$this->triggerCallback('shutdown', $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a callback on all primary components. Will fire $callback on all components
|
||||
* that have such a method. You can implement and fire custom callbacks in addition to the
|
||||
* standard ones.
|
||||
*
|
||||
* example use, from inside a controller:
|
||||
*
|
||||
* `$this->Component->triggerCallback('beforeFilter', $this);`
|
||||
*
|
||||
* will trigger the beforeFilter callback on all components that have implemented one. You
|
||||
* can trigger any method in this fashion.
|
||||
*
|
||||
* @param Controller $controller Controller instance
|
||||
* @param string $callback Callback to trigger.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function triggerCallback($callback, &$controller) {
|
||||
foreach ($this->_primary as $name) {
|
||||
$component =& $this->_loaded[$name];
|
||||
if (method_exists($component, $callback) && $component->enabled === true) {
|
||||
$component->{$callback}($controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads components used by this component.
|
||||
*
|
||||
* @param object $object Object with a Components array
|
||||
* @param object $parent the parent of the current object
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _loadComponents(&$object, $parent = null) {
|
||||
$base = $this->__controllerVars['base'];
|
||||
$normal = Set::normalize($object->components);
|
||||
foreach ((array)$normal as $component => $config) {
|
||||
$plugin = isset($this->__controllerVars['plugin']) ? $this->__controllerVars['plugin'] . '.' : null;
|
||||
list($plugin, $component) = pluginSplit($component, true, $plugin);
|
||||
$componentCn = $component . 'Component';
|
||||
|
||||
if (!class_exists($componentCn)) {
|
||||
if (is_null($plugin) || !App::import('Component', $plugin . $component)) {
|
||||
if (!App::import('Component', $component)) {
|
||||
$this->cakeError('missingComponentFile', array(array(
|
||||
'className' => $this->__controllerVars['name'],
|
||||
'component' => $component,
|
||||
'file' => Inflector::underscore($component) . '.php',
|
||||
'base' => $base,
|
||||
'code' => 500
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists($componentCn)) {
|
||||
$this->cakeError('missingComponentClass', array(array(
|
||||
'className' => $this->__controllerVars['name'],
|
||||
'component' => $component,
|
||||
'file' => Inflector::underscore($component) . '.php',
|
||||
'base' => $base,
|
||||
'code' => 500
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($parent === null) {
|
||||
$this->_primary[] = $component;
|
||||
}
|
||||
|
||||
if (isset($this->_loaded[$component])) {
|
||||
$object->{$component} =& $this->_loaded[$component];
|
||||
|
||||
if (!empty($config) && isset($this->__settings[$component])) {
|
||||
$this->__settings[$component] = array_merge($this->__settings[$component], $config);
|
||||
} elseif (!empty($config)) {
|
||||
$this->__settings[$component] = $config;
|
||||
}
|
||||
} else {
|
||||
if ($componentCn === 'SessionComponent') {
|
||||
$object->{$component} =& new $componentCn($base);
|
||||
} else {
|
||||
$object->{$component} =& new $componentCn();
|
||||
}
|
||||
$object->{$component}->enabled = true;
|
||||
$this->_loaded[$component] =& $object->{$component};
|
||||
if (!empty($config)) {
|
||||
$this->__settings[$component] = $config;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($object->{$component}->components) && is_array($object->{$component}->components) && (!isset($object->{$component}->{$parent}))) {
|
||||
$this->_loadComponents($object->{$component}, $component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
638
web-cake/html/cake/libs/controller/components/acl.php
Normal file
638
web-cake/html/cake/libs/controller/components/acl.php
Normal file
@@ -0,0 +1,638 @@
|
||||
<?php
|
||||
/**
|
||||
* Access Control List factory class.
|
||||
*
|
||||
* Permissions system.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Access Control List factory class.
|
||||
*
|
||||
* Uses a strategy pattern to allow custom ACL implementations to be used with the same component interface.
|
||||
* You can define by changing `Configure::write('Acl.classname', 'DbAcl');` in your core.php. Concrete ACL
|
||||
* implementations should extend `AclBase` and implement the methods it defines.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1242/Access-Control-Lists
|
||||
*/
|
||||
class AclComponent extends Object {
|
||||
|
||||
/**
|
||||
* Instance of an ACL class
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
var $_Instance = null;
|
||||
|
||||
/**
|
||||
* Constructor. Will return an instance of the correct ACL class as defined in `Configure::read('Acl.classname')`
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
$name = Inflector::camelize(strtolower(Configure::read('Acl.classname')));
|
||||
if (!class_exists($name)) {
|
||||
if (App::import('Component', $name)) {
|
||||
list($plugin, $name) = pluginSplit($name);
|
||||
$name .= 'Component';
|
||||
} else {
|
||||
trigger_error(sprintf(__('Could not find %s.', true), $name), E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
$this->_Instance =& new $name();
|
||||
$this->_Instance->initialize($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup is not used
|
||||
*
|
||||
* @param object $controller Controller using this component
|
||||
* @return boolean Proceed with component usage (true), or fail (false)
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty class defintion, to be overridden in subclasses.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
function _initACL() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL check instance. Check methods
|
||||
* are used to check whether or not an ARO can access an ACO
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function check($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->check($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL allow instance. Allow methods
|
||||
* are used to grant an ARO access to an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function allow($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL deny instance. Deny methods
|
||||
* are used to remove permission from an ARO to access an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function deny($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL inherit instance. Inherit methods
|
||||
* modify the permission for an ARO to be that of its parent object.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function inherit($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->inherit($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL grant instance. An alias for AclComponent::allow()
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function grant($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->grant($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL grant instance. An alias for AclComponent::deny()
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function revoke($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->revoke($aro, $aco, $action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Control List abstract class. Not to be instantiated.
|
||||
* Subclasses of this class are used by AclComponent to perform ACL checks in Cake.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @abstract
|
||||
*/
|
||||
class AclBase extends Object {
|
||||
|
||||
/**
|
||||
* This class should never be instantiated, just subclassed.
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
if (strcasecmp(get_class($this), "AclBase") == 0 || !is_subclass_of($this, "AclBase")) {
|
||||
trigger_error(__("[acl_base] The AclBase class constructor has been called, or the class was instantiated. This class must remain abstract. Please refer to the Cake docs for ACL configuration.", true), E_USER_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty method to be overridden in subclasses
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @access public
|
||||
*/
|
||||
function check($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty method to be overridden in subclasses
|
||||
*
|
||||
* @param object $component Component
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$component) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DbAcl implements an ACL control system in the database. ARO's and ACO's are
|
||||
* structured into trees and a linking table is used to define permissions. You
|
||||
* can install the schema for DbAcl with the Schema Shell.
|
||||
*
|
||||
* `$aco` and `$aro` parameters can be slash delimited paths to tree nodes.
|
||||
*
|
||||
* eg. `controllers/Users/edit`
|
||||
*
|
||||
* Would point to a tree structure like
|
||||
*
|
||||
* {{{
|
||||
* controllers
|
||||
* Users
|
||||
* edit
|
||||
* }}}
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class DbAcl extends AclBase {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
if (!class_exists('AclNode')) {
|
||||
require LIBS . 'model' . DS . 'db_acl.php';
|
||||
}
|
||||
$this->Aro =& ClassRegistry::init(array('class' => 'Aro', 'alias' => 'Aro'));
|
||||
$this->Aco =& ClassRegistry::init(array('class' => 'Aco', 'alias' => 'Aco'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the containing component and sets the Aro/Aco objects to it.
|
||||
*
|
||||
* @param AclComponent $component
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$component) {
|
||||
$component->Aro =& $this->Aro;
|
||||
$component->Aco =& $this->Aco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given $aro has access to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return boolean Success (true if ARO has access to action in ACO, false otherwise)
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1249/Checking-Permissions-The-ACL-Component
|
||||
*/
|
||||
function check($aro, $aco, $action = "*") {
|
||||
if ($aro == null || $aco == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
|
||||
$aroPath = $this->Aro->node($aro);
|
||||
$acoPath = $this->Aco->node($aco);
|
||||
|
||||
if (empty($aroPath) || empty($acoPath)) {
|
||||
trigger_error(__("DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ", true) . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($acoPath == null || $acoPath == array()) {
|
||||
trigger_error(__("DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ", true) . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
$aroNode = $aroPath[0];
|
||||
$acoNode = $acoPath[0];
|
||||
|
||||
if ($action != '*' && !in_array('_' . $action, $permKeys)) {
|
||||
trigger_error(sprintf(__("ACO permissions key %s does not exist in DbAcl::check()", true), $action), E_USER_NOTICE);
|
||||
return false;
|
||||
}
|
||||
|
||||
$inherited = array();
|
||||
$acoIDs = Set::extract($acoPath, '{n}.' . $this->Aco->alias . '.id');
|
||||
|
||||
$count = count($aroPath);
|
||||
for ($i = 0 ; $i < $count; $i++) {
|
||||
$permAlias = $this->Aro->Permission->alias;
|
||||
|
||||
$perms = $this->Aro->Permission->find('all', array(
|
||||
'conditions' => array(
|
||||
"{$permAlias}.aro_id" => $aroPath[$i][$this->Aro->alias]['id'],
|
||||
"{$permAlias}.aco_id" => $acoIDs
|
||||
),
|
||||
'order' => array($this->Aco->alias . '.lft' => 'desc'),
|
||||
'recursive' => 0
|
||||
));
|
||||
|
||||
if (empty($perms)) {
|
||||
continue;
|
||||
} else {
|
||||
$perms = Set::extract($perms, '{n}.' . $this->Aro->Permission->alias);
|
||||
foreach ($perms as $perm) {
|
||||
if ($action == '*') {
|
||||
|
||||
foreach ($permKeys as $key) {
|
||||
if (!empty($perm)) {
|
||||
if ($perm[$key] == -1) {
|
||||
return false;
|
||||
} elseif ($perm[$key] == 1) {
|
||||
$inherited[$key] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($inherited) === count($permKeys)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
switch ($perm['_' . $action]) {
|
||||
case -1:
|
||||
return false;
|
||||
case 0:
|
||||
continue;
|
||||
break;
|
||||
case 1:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1248/Assigning-Permissions
|
||||
*/
|
||||
function allow($aro, $aco, $actions = "*", $value = 1) {
|
||||
$perms = $this->getAclLink($aro, $aco);
|
||||
$permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
|
||||
$save = array();
|
||||
|
||||
if ($perms == false) {
|
||||
trigger_error(__('DbAcl::allow() - Invalid node', true), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
if (isset($perms[0])) {
|
||||
$save = $perms[0][$this->Aro->Permission->alias];
|
||||
}
|
||||
|
||||
if ($actions == "*") {
|
||||
$permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
|
||||
$save = array_combine($permKeys, array_pad(array(), count($permKeys), $value));
|
||||
} else {
|
||||
if (!is_array($actions)) {
|
||||
$actions = array('_' . $actions);
|
||||
}
|
||||
if (is_array($actions)) {
|
||||
foreach ($actions as $action) {
|
||||
if ($action{0} != '_') {
|
||||
$action = '_' . $action;
|
||||
}
|
||||
if (in_array($action, $permKeys)) {
|
||||
$save[$action] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']);
|
||||
|
||||
if ($perms['link'] != null && !empty($perms['link'])) {
|
||||
$save['id'] = $perms['link'][0][$this->Aro->Permission->alias]['id'];
|
||||
} else {
|
||||
unset($save['id']);
|
||||
$this->Aro->Permission->id = null;
|
||||
}
|
||||
return ($this->Aro->Permission->save($save) !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1248/Assigning-Permissions
|
||||
*/
|
||||
function deny($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let access for $aro to action $action in $aco be inherited
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function inherit($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @see allow()
|
||||
* @access public
|
||||
*/
|
||||
function grant($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @return boolean Success
|
||||
* @see deny()
|
||||
* @access public
|
||||
*/
|
||||
function revoke($aro, $aco, $action = "*") {
|
||||
return $this->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of access-control links between the given Aro and Aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @return array Indexed array with: 'aro', 'aco' and 'link'
|
||||
* @access public
|
||||
*/
|
||||
function getAclLink($aro, $aco) {
|
||||
$obj = array();
|
||||
$obj['Aro'] = $this->Aro->node($aro);
|
||||
$obj['Aco'] = $this->Aco->node($aco);
|
||||
|
||||
if (empty($obj['Aro']) || empty($obj['Aco'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'aro' => Set::extract($obj, 'Aro.0.'.$this->Aro->alias.'.id'),
|
||||
'aco' => Set::extract($obj, 'Aco.0.'.$this->Aco->alias.'.id'),
|
||||
'link' => $this->Aro->Permission->find('all', array('conditions' => array(
|
||||
$this->Aro->Permission->alias . '.aro_id' => Set::extract($obj, 'Aro.0.'.$this->Aro->alias.'.id'),
|
||||
$this->Aro->Permission->alias . '.aco_id' => Set::extract($obj, 'Aco.0.'.$this->Aco->alias.'.id')
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys used in an ACO
|
||||
*
|
||||
* @param array $keys Permission model info
|
||||
* @return array ACO keys
|
||||
* @access protected
|
||||
*/
|
||||
function _getAcoKeys($keys) {
|
||||
$newKeys = array();
|
||||
$keys = array_keys($keys);
|
||||
foreach ($keys as $key) {
|
||||
if (!in_array($key, array('id', 'aro_id', 'aco_id'))) {
|
||||
$newKeys[] = $key;
|
||||
}
|
||||
}
|
||||
return $newKeys;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IniAcl implements an access control system using an INI file. An example
|
||||
* of the ini file used can be found in /config/acl.ini.php.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.iniacl
|
||||
*/
|
||||
class IniAcl extends AclBase {
|
||||
|
||||
/**
|
||||
* Array with configuration, parsed from ini file
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $config = null;
|
||||
|
||||
/**
|
||||
* The constructor must be overridden, as AclBase is abstract.
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main ACL check function. Checks to see if the ARO (access request object) has access to the
|
||||
* ACO (access control object).Looks at the acl.ini.php file for permissions
|
||||
* (see instructions in /config/acl.ini.php).
|
||||
*
|
||||
* @param string $aro ARO
|
||||
* @param string $aco ACO
|
||||
* @param string $aco_action Action
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function check($aro, $aco, $aco_action = null) {
|
||||
if ($this->config == null) {
|
||||
$this->config = $this->readConfigFile(CONFIGS . 'acl.ini.php');
|
||||
}
|
||||
$aclConfig = $this->config;
|
||||
|
||||
if (isset($aclConfig[$aro]['deny'])) {
|
||||
$userDenies = $this->arrayTrim(explode(",", $aclConfig[$aro]['deny']));
|
||||
|
||||
if (array_search($aco, $userDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['allow'])) {
|
||||
$userAllows = $this->arrayTrim(explode(",", $aclConfig[$aro]['allow']));
|
||||
|
||||
if (array_search($aco, $userAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['groups'])) {
|
||||
$userGroups = $this->arrayTrim(explode(",", $aclConfig[$aro]['groups']));
|
||||
|
||||
foreach ($userGroups as $group) {
|
||||
if (array_key_exists($group, $aclConfig)) {
|
||||
if (isset($aclConfig[$group]['deny'])) {
|
||||
$groupDenies=$this->arrayTrim(explode(",", $aclConfig[$group]['deny']));
|
||||
|
||||
if (array_search($aco, $groupDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$group]['allow'])) {
|
||||
$groupAllows = $this->arrayTrim(explode(",", $aclConfig[$group]['allow']));
|
||||
|
||||
if (array_search($aco, $groupAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an INI file and returns an array that reflects the INI file's section structure. Double-quote friendly.
|
||||
*
|
||||
* @param string $fileName File
|
||||
* @return array INI section structure
|
||||
* @access public
|
||||
*/
|
||||
function readConfigFile($fileName) {
|
||||
$fileLineArray = file($fileName);
|
||||
|
||||
foreach ($fileLineArray as $fileLine) {
|
||||
$dataLine = trim($fileLine);
|
||||
$firstChar = substr($dataLine, 0, 1);
|
||||
|
||||
if ($firstChar != ';' && $dataLine != '') {
|
||||
if ($firstChar == '[' && substr($dataLine, -1, 1) == ']') {
|
||||
$sectionName = preg_replace('/[\[\]]/', '', $dataLine);
|
||||
} else {
|
||||
$delimiter = strpos($dataLine, '=');
|
||||
|
||||
if ($delimiter > 0) {
|
||||
$key = strtolower(trim(substr($dataLine, 0, $delimiter)));
|
||||
$value = trim(substr($dataLine, $delimiter + 1));
|
||||
|
||||
if (substr($value, 0, 1) == '"' && substr($value, -1) == '"') {
|
||||
$value = substr($value, 1, -1);
|
||||
}
|
||||
|
||||
$iniSetting[$sectionName][$key]=stripcslashes($value);
|
||||
} else {
|
||||
if (!isset($sectionName)) {
|
||||
$sectionName = '';
|
||||
}
|
||||
|
||||
$iniSetting[$sectionName][strtolower(trim($dataLine))]='';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $iniSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes trailing spaces on all array elements (to prepare for searching)
|
||||
*
|
||||
* @param array $array Array to trim
|
||||
* @return array Trimmed array
|
||||
* @access public
|
||||
*/
|
||||
function arrayTrim($array) {
|
||||
foreach ($array as $key => $value) {
|
||||
$array[$key] = trim($value);
|
||||
}
|
||||
array_unshift($array, "");
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
958
web-cake/html/cake/libs/controller/components/auth.php
Normal file
958
web-cake/html/cake/libs/controller/components/auth.php
Normal file
@@ -0,0 +1,958 @@
|
||||
<?php
|
||||
/**
|
||||
* Authentication component
|
||||
*
|
||||
* Manages user logins and permissions.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
App::import('Core', array('Router', 'Security'), false);
|
||||
|
||||
/**
|
||||
* Authentication control component class
|
||||
*
|
||||
* Binds access control with user authentication and session management.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1250/Authentication
|
||||
*/
|
||||
class AuthComponent extends Object {
|
||||
|
||||
/**
|
||||
* Maintains current user login state.
|
||||
*
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $_loggedIn = false;
|
||||
|
||||
/**
|
||||
* Other components utilized by AuthComponent
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $components = array('Session', 'RequestHandler');
|
||||
|
||||
/**
|
||||
* A reference to the object used for authentication
|
||||
*
|
||||
* @var object
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1278/authenticate
|
||||
*/
|
||||
var $authenticate = null;
|
||||
|
||||
/**
|
||||
* The name of the component to use for Authorization or set this to
|
||||
* 'controller' will validate against Controller::isAuthorized()
|
||||
* 'actions' will validate Controller::action against an AclComponent::check()
|
||||
* 'crud' will validate mapActions against an AclComponent::check()
|
||||
* array('model'=> 'name'); will validate mapActions against model $name::isAuthorized(user, controller, mapAction)
|
||||
* 'object' will validate Controller::action against object::isAuthorized(user, controller, action)
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1275/authorize
|
||||
*/
|
||||
var $authorize = false;
|
||||
|
||||
/**
|
||||
* The name of an optional view element to render when an Ajax request is made
|
||||
* with an invalid or expired session
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1277/ajaxLogin
|
||||
*/
|
||||
var $ajaxLogin = null;
|
||||
|
||||
/**
|
||||
* The name of the element used for SessionComponent::setFlash
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $flashElement = 'default';
|
||||
|
||||
/**
|
||||
* The name of the model that represents users which will be authenticated. Defaults to 'User'.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1266/userModel
|
||||
*/
|
||||
var $userModel = 'User';
|
||||
|
||||
/**
|
||||
* Additional query conditions to use when looking up and authenticating users,
|
||||
* i.e. array('User.is_active' => 1).
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1268/userScope
|
||||
*/
|
||||
var $userScope = array();
|
||||
|
||||
/**
|
||||
* Allows you to specify non-default login name and password fields used in
|
||||
* $userModel, i.e. array('username' => 'login_name', 'password' => 'passwd').
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1267/fields
|
||||
*/
|
||||
var $fields = array('username' => 'username', 'password' => 'password');
|
||||
|
||||
/**
|
||||
* The session key name where the record of the current user is stored. If
|
||||
* unspecified, it will be "Auth.{$userModel name}".
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1276/sessionKey
|
||||
*/
|
||||
var $sessionKey = null;
|
||||
|
||||
/**
|
||||
* If using action-based access control, this defines how the paths to action
|
||||
* ACO nodes is computed. If, for example, all controller nodes are nested
|
||||
* under an ACO node named 'Controllers', $actionPath should be set to
|
||||
* "Controllers/".
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1279/actionPath
|
||||
*/
|
||||
var $actionPath = null;
|
||||
|
||||
/**
|
||||
* A URL (defined as a string or array) to the controller action that handles
|
||||
* logins.
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1269/loginAction
|
||||
*/
|
||||
var $loginAction = null;
|
||||
|
||||
/**
|
||||
* Normally, if a user is redirected to the $loginAction page, the location they
|
||||
* were redirected from will be stored in the session so that they can be
|
||||
* redirected back after a successful login. If this session value is not
|
||||
* set, the user will be redirected to the page specified in $loginRedirect.
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1270/loginRedirect
|
||||
*/
|
||||
var $loginRedirect = null;
|
||||
|
||||
/**
|
||||
* The default action to redirect to after the user is logged out. While AuthComponent does
|
||||
* not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
|
||||
* Defaults to AuthComponent::$loginAction.
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
* @see AuthComponent::$loginAction
|
||||
* @see AuthComponent::logout()
|
||||
* @link http://book.cakephp.org/view/1271/logoutRedirect
|
||||
*/
|
||||
var $logoutRedirect = null;
|
||||
|
||||
/**
|
||||
* The name of model or model object, or any other object has an isAuthorized method.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $object = null;
|
||||
|
||||
/**
|
||||
* Error to display when user login fails. For security purposes, only one error is used for all
|
||||
* login failures, so as not to expose information on why the login failed.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1272/loginError
|
||||
*/
|
||||
var $loginError = null;
|
||||
|
||||
/**
|
||||
* Error to display when user attempts to access an object or action to which they do not have
|
||||
* acccess.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1273/authError
|
||||
*/
|
||||
var $authError = null;
|
||||
|
||||
/**
|
||||
* Determines whether AuthComponent will automatically redirect and exit if login is successful.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1274/autoRedirect
|
||||
*/
|
||||
var $autoRedirect = true;
|
||||
|
||||
/**
|
||||
* Controller actions for which user validation is not required.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see AuthComponent::allow()
|
||||
* @link http://book.cakephp.org/view/1251/Setting-Auth-Component-Variables
|
||||
*/
|
||||
var $allowedActions = array();
|
||||
|
||||
/**
|
||||
* Maps actions to CRUD operations. Used for controller-based validation ($validate = 'controller').
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see AuthComponent::mapActions()
|
||||
*/
|
||||
var $actionMap = array(
|
||||
'index' => 'read',
|
||||
'add' => 'create',
|
||||
'edit' => 'update',
|
||||
'view' => 'read',
|
||||
'remove' => 'delete'
|
||||
);
|
||||
|
||||
/**
|
||||
* Form data from Controller::$data
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $data = array();
|
||||
|
||||
/**
|
||||
* Parameter data from Controller::$params
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $params = array();
|
||||
|
||||
/**
|
||||
* Method list for bound controller
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_methods = array();
|
||||
|
||||
/**
|
||||
* Initializes AuthComponent for use in the controller
|
||||
*
|
||||
* @param object $controller A reference to the instantiating controller object
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$controller, $settings = array()) {
|
||||
$this->params = $controller->params;
|
||||
$crud = array('create', 'read', 'update', 'delete');
|
||||
$this->actionMap = array_merge($this->actionMap, array_combine($crud, $crud));
|
||||
$this->_methods = $controller->methods;
|
||||
|
||||
$prefixes = Router::prefixes();
|
||||
if (!empty($prefixes)) {
|
||||
foreach ($prefixes as $prefix) {
|
||||
$this->actionMap = array_merge($this->actionMap, array(
|
||||
$prefix . '_index' => 'read',
|
||||
$prefix . '_add' => 'create',
|
||||
$prefix . '_edit' => 'update',
|
||||
$prefix . '_view' => 'read',
|
||||
$prefix . '_remove' => 'delete',
|
||||
$prefix . '_create' => 'create',
|
||||
$prefix . '_read' => 'read',
|
||||
$prefix . '_update' => 'update',
|
||||
$prefix . '_delete' => 'delete'
|
||||
));
|
||||
}
|
||||
}
|
||||
$this->_set($settings);
|
||||
if (Configure::read() > 0) {
|
||||
App::import('Debugger');
|
||||
Debugger::checkSecurityKeys();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution method. Handles redirecting of invalid users, and processing
|
||||
* of login form data.
|
||||
*
|
||||
* @param object $controller A reference to the instantiating controller object
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
$isErrorOrTests = (
|
||||
strtolower($controller->name) == 'cakeerror' ||
|
||||
(strtolower($controller->name) == 'tests' && Configure::read() > 0)
|
||||
);
|
||||
if ($isErrorOrTests) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$methods = array_flip($controller->methods);
|
||||
$action = strtolower($controller->params['action']);
|
||||
$isMissingAction = (
|
||||
$controller->scaffold === false &&
|
||||
!isset($methods[$action])
|
||||
);
|
||||
|
||||
if ($isMissingAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->__setDefaults()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->data = $controller->data = $this->hashPasswords($controller->data);
|
||||
$url = '';
|
||||
|
||||
if (isset($controller->params['url']['url'])) {
|
||||
$url = $controller->params['url']['url'];
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$loginAction = Router::normalize($this->loginAction);
|
||||
|
||||
$allowedActions = array_map('strtolower', $this->allowedActions);
|
||||
$isAllowed = (
|
||||
$this->allowedActions == array('*') ||
|
||||
in_array($action, $allowedActions)
|
||||
);
|
||||
|
||||
if ($loginAction != $url && $isAllowed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($loginAction == $url) {
|
||||
$model =& $this->getModel();
|
||||
if (empty($controller->data) || !isset($controller->data[$model->alias])) {
|
||||
if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
|
||||
$this->Session->write('Auth.redirect', $controller->referer(null, true));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$isValid = !empty($controller->data[$model->alias][$this->fields['username']]) &&
|
||||
!empty($controller->data[$model->alias][$this->fields['password']]);
|
||||
|
||||
if ($isValid) {
|
||||
$username = $controller->data[$model->alias][$this->fields['username']];
|
||||
$password = $controller->data[$model->alias][$this->fields['password']];
|
||||
|
||||
$data = array(
|
||||
$model->alias . '.' . $this->fields['username'] => $username,
|
||||
$model->alias . '.' . $this->fields['password'] => $password
|
||||
);
|
||||
|
||||
if ($this->login($data)) {
|
||||
if ($this->autoRedirect) {
|
||||
$controller->redirect($this->redirect(), null, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->Session->setFlash($this->loginError, $this->flashElement, array(), 'auth');
|
||||
$controller->data[$model->alias][$this->fields['password']] = null;
|
||||
return false;
|
||||
} else {
|
||||
if (!$this->user()) {
|
||||
if (!$this->RequestHandler->isAjax()) {
|
||||
$this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth');
|
||||
if (!empty($controller->params['url']) && count($controller->params['url']) >= 2) {
|
||||
$query = $controller->params['url'];
|
||||
unset($query['url'], $query['ext']);
|
||||
$url .= Router::queryString($query, array());
|
||||
}
|
||||
$this->Session->write('Auth.redirect', $url);
|
||||
$controller->redirect($loginAction);
|
||||
return false;
|
||||
} elseif (!empty($this->ajaxLogin)) {
|
||||
$controller->viewPath = 'elements';
|
||||
echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
|
||||
$this->_stop();
|
||||
return false;
|
||||
} else {
|
||||
$controller->redirect(null, 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->authorize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extract($this->__authType());
|
||||
switch ($type) {
|
||||
case 'controller':
|
||||
$this->object =& $controller;
|
||||
break;
|
||||
case 'crud':
|
||||
case 'actions':
|
||||
if (isset($controller->Acl)) {
|
||||
$this->Acl =& $controller->Acl;
|
||||
} else {
|
||||
trigger_error(__('Could not find AclComponent. Please include Acl in Controller::$components.', true), E_USER_WARNING);
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
if (!isset($object)) {
|
||||
$hasModel = (
|
||||
isset($controller->{$controller->modelClass}) &&
|
||||
is_object($controller->{$controller->modelClass})
|
||||
);
|
||||
$isUses = (
|
||||
!empty($controller->uses) && isset($controller->{$controller->uses[0]}) &&
|
||||
is_object($controller->{$controller->uses[0]})
|
||||
);
|
||||
|
||||
if ($hasModel) {
|
||||
$object = $controller->modelClass;
|
||||
} elseif ($isUses) {
|
||||
$object = $controller->uses[0];
|
||||
}
|
||||
}
|
||||
$type = array('model' => $object);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->isAuthorized($type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth');
|
||||
$controller->redirect($controller->referer(), null, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to introspect the correct values for object properties including
|
||||
* $userModel and $sessionKey.
|
||||
*
|
||||
* @param object $controller A reference to the instantiating controller object
|
||||
* @return boolean
|
||||
* @access private
|
||||
*/
|
||||
function __setDefaults() {
|
||||
if (empty($this->userModel)) {
|
||||
trigger_error(__("Could not find \$userModel. Please set AuthComponent::\$userModel in beforeFilter().", true), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
list($plugin, $model) = pluginSplit($this->userModel);
|
||||
$defaults = array(
|
||||
'loginAction' => array(
|
||||
'controller' => Inflector::underscore(Inflector::pluralize($model)),
|
||||
'action' => 'login',
|
||||
'plugin' => Inflector::underscore($plugin),
|
||||
),
|
||||
'sessionKey' => 'Auth.' . $model,
|
||||
'logoutRedirect' => $this->loginAction,
|
||||
'loginError' => __('Login failed. Invalid username or password.', true),
|
||||
'authError' => __('You are not authorized to access that location.', true)
|
||||
);
|
||||
foreach ($defaults as $key => $value) {
|
||||
if (empty($this->{$key})) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given user is authorized to perform an action. The type of
|
||||
* authorization used is based on the value of AuthComponent::$authorize or the
|
||||
* passed $type param.
|
||||
*
|
||||
* Types:
|
||||
* 'controller' will validate against Controller::isAuthorized() if controller instance is
|
||||
* passed in $object
|
||||
* 'actions' will validate Controller::action against an AclComponent::check()
|
||||
* 'crud' will validate mapActions against an AclComponent::check()
|
||||
* array('model'=> 'name'); will validate mapActions against model
|
||||
* $name::isAuthorized(user, controller, mapAction)
|
||||
* 'object' will validate Controller::action against
|
||||
* object::isAuthorized(user, controller, action)
|
||||
*
|
||||
* @param string $type Type of authorization
|
||||
* @param mixed $object object, model object, or model name
|
||||
* @param mixed $user The user to check the authorization of
|
||||
* @return boolean True if $user is authorized, otherwise false
|
||||
* @access public
|
||||
*/
|
||||
function isAuthorized($type = null, $object = null, $user = null) {
|
||||
if (empty($user) && !$this->user()) {
|
||||
return false;
|
||||
} elseif (empty($user)) {
|
||||
$user = $this->user();
|
||||
}
|
||||
|
||||
extract($this->__authType($type));
|
||||
|
||||
if (!$object) {
|
||||
$object = $this->object;
|
||||
}
|
||||
|
||||
$valid = false;
|
||||
switch ($type) {
|
||||
case 'controller':
|
||||
$valid = $object->isAuthorized();
|
||||
break;
|
||||
case 'actions':
|
||||
$valid = $this->Acl->check($user, $this->action());
|
||||
break;
|
||||
case 'crud':
|
||||
if (!isset($this->actionMap[$this->params['action']])) {
|
||||
trigger_error(
|
||||
sprintf(__('Auth::startup() - Attempted access of un-mapped action "%1$s" in controller "%2$s"', true), $this->params['action'], $this->params['controller']),
|
||||
E_USER_WARNING
|
||||
);
|
||||
} else {
|
||||
$valid = $this->Acl->check(
|
||||
$user,
|
||||
$this->action(':controller'),
|
||||
$this->actionMap[$this->params['action']]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
$action = $this->params['action'];
|
||||
if (isset($this->actionMap[$action])) {
|
||||
$action = $this->actionMap[$action];
|
||||
}
|
||||
if (is_string($object)) {
|
||||
$object = $this->getModel($object);
|
||||
}
|
||||
case 'object':
|
||||
if (!isset($action)) {
|
||||
$action = $this->action(':action');
|
||||
}
|
||||
if (empty($object)) {
|
||||
trigger_error(sprintf(__('Could not find %s. Set AuthComponent::$object in beforeFilter() or pass a valid object', true), get_class($object)), E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
if (method_exists($object, 'isAuthorized')) {
|
||||
$valid = $object->isAuthorized($user, $this->action(':controller'), $action);
|
||||
} elseif ($object) {
|
||||
trigger_error(sprintf(__('%s::isAuthorized() is not defined.', true), get_class($object)), E_USER_WARNING);
|
||||
}
|
||||
break;
|
||||
case null:
|
||||
case false:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
trigger_error(__('Auth::isAuthorized() - $authorize is set to an incorrect value. Allowed settings are: "actions", "crud", "model" or null.', true), E_USER_WARNING);
|
||||
break;
|
||||
}
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authorization type
|
||||
*
|
||||
* @param string $auth Type of authorization
|
||||
* @return array Associative array with: type, object
|
||||
* @access private
|
||||
*/
|
||||
function __authType($auth = null) {
|
||||
if ($auth == null) {
|
||||
$auth = $this->authorize;
|
||||
}
|
||||
$object = null;
|
||||
if (is_array($auth)) {
|
||||
$type = key($auth);
|
||||
$object = $auth[$type];
|
||||
} else {
|
||||
$type = $auth;
|
||||
return compact('type');
|
||||
}
|
||||
return compact('type', 'object');
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of actions in the current controller for which authentication is not required, or
|
||||
* no parameters to allow all actions.
|
||||
*
|
||||
* @param mixed $action Controller action name or array of actions
|
||||
* @param string $action Controller action name
|
||||
* @param string ... etc.
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1257/allow
|
||||
*/
|
||||
function allow() {
|
||||
$args = func_get_args();
|
||||
if (empty($args) || $args == array('*')) {
|
||||
$this->allowedActions = $this->_methods;
|
||||
} else {
|
||||
if (isset($args[0]) && is_array($args[0])) {
|
||||
$args = $args[0];
|
||||
}
|
||||
$this->allowedActions = array_merge($this->allowedActions, array_map('strtolower', $args));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes items from the list of allowed actions.
|
||||
*
|
||||
* @param mixed $action Controller action name or array of actions
|
||||
* @param string $action Controller action name
|
||||
* @param string ... etc.
|
||||
* @return void
|
||||
* @see AuthComponent::allow()
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1258/deny
|
||||
*/
|
||||
function deny() {
|
||||
$args = func_get_args();
|
||||
if (isset($args[0]) && is_array($args[0])) {
|
||||
$args = $args[0];
|
||||
}
|
||||
foreach ($args as $arg) {
|
||||
$i = array_search(strtolower($arg), $this->allowedActions);
|
||||
if (is_int($i)) {
|
||||
unset($this->allowedActions[$i]);
|
||||
}
|
||||
}
|
||||
$this->allowedActions = array_values($this->allowedActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps action names to CRUD operations. Used for controller-based authentication.
|
||||
*
|
||||
* @param array $map Actions to map
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1260/mapActions
|
||||
*/
|
||||
function mapActions($map = array()) {
|
||||
$crud = array('create', 'read', 'update', 'delete');
|
||||
foreach ($map as $action => $type) {
|
||||
if (in_array($action, $crud) && is_array($type)) {
|
||||
foreach ($type as $typedAction) {
|
||||
$this->actionMap[$typedAction] = $action;
|
||||
}
|
||||
} else {
|
||||
$this->actionMap[$action] = $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually log-in a user with the given parameter data. The $data provided can be any data
|
||||
* structure used to identify a user in AuthComponent::identify(). If $data is empty or not
|
||||
* specified, POST data from Controller::$data will be used automatically.
|
||||
*
|
||||
* After (if) login is successful, the user record is written to the session key specified in
|
||||
* AuthComponent::$sessionKey.
|
||||
*
|
||||
* @param mixed $data User object
|
||||
* @return boolean True on login success, false on failure
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1261/login
|
||||
*/
|
||||
function login($data = null) {
|
||||
$this->__setDefaults();
|
||||
$this->_loggedIn = false;
|
||||
|
||||
if (empty($data)) {
|
||||
$data = $this->data;
|
||||
}
|
||||
|
||||
if ($user = $this->identify($data)) {
|
||||
$this->Session->write($this->sessionKey, $user);
|
||||
$this->_loggedIn = true;
|
||||
}
|
||||
return $this->_loggedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a user out, and returns the login action to redirect to.
|
||||
*
|
||||
* @param mixed $url Optional URL to redirect the user to after logout
|
||||
* @return string AuthComponent::$loginAction
|
||||
* @see AuthComponent::$loginAction
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1262/logout
|
||||
*/
|
||||
function logout() {
|
||||
$this->__setDefaults();
|
||||
$this->Session->delete($this->sessionKey);
|
||||
$this->Session->delete('Auth.redirect');
|
||||
$this->_loggedIn = false;
|
||||
return Router::normalize($this->logoutRedirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user from the session.
|
||||
*
|
||||
* @param string $key field to retrive. Leave null to get entire User record
|
||||
* @return mixed User record. or null if no user is logged in.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1264/user
|
||||
*/
|
||||
function user($key = null) {
|
||||
$this->__setDefaults();
|
||||
if (!$this->Session->check($this->sessionKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($key == null) {
|
||||
$model =& $this->getModel();
|
||||
return array($model->alias => $this->Session->read($this->sessionKey));
|
||||
} else {
|
||||
$user = $this->Session->read($this->sessionKey);
|
||||
if (isset($user[$key])) {
|
||||
return $user[$key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If no parameter is passed, gets the authentication redirect URL.
|
||||
*
|
||||
* @param mixed $url Optional URL to write as the login redirect URL.
|
||||
* @return string Redirect URL
|
||||
* @access public
|
||||
*/
|
||||
function redirect($url = null) {
|
||||
if (!is_null($url)) {
|
||||
$redir = $url;
|
||||
$this->Session->write('Auth.redirect', $redir);
|
||||
} elseif ($this->Session->check('Auth.redirect')) {
|
||||
$redir = $this->Session->read('Auth.redirect');
|
||||
$this->Session->delete('Auth.redirect');
|
||||
|
||||
if (Router::normalize($redir) == Router::normalize($this->loginAction)) {
|
||||
$redir = $this->loginRedirect;
|
||||
}
|
||||
} else {
|
||||
$redir = $this->loginRedirect;
|
||||
}
|
||||
return Router::normalize($redir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a user against an abstract object.
|
||||
*
|
||||
* @param mixed $object The object to validate the user against.
|
||||
* @param mixed $user Optional. The identity of the user to be validated.
|
||||
* Uses the current user session if none specified. For
|
||||
* valid forms of identifying users, see
|
||||
* AuthComponent::identify().
|
||||
* @param string $action Optional. The action to validate against.
|
||||
* @see AuthComponent::identify()
|
||||
* @return boolean True if the user validates, false otherwise.
|
||||
* @access public
|
||||
*/
|
||||
function validate($object, $user = null, $action = null) {
|
||||
if (empty($user)) {
|
||||
$user = $this->user();
|
||||
}
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
return $this->Acl->check($user, $object, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the ACO node bound to a controller/action.
|
||||
*
|
||||
* @param string $action Optional. The controller/action path to validate the
|
||||
* user against. The current request action is used if
|
||||
* none is specified.
|
||||
* @return boolean ACO node path
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1256/action
|
||||
*/
|
||||
function action($action = ':plugin/:controller/:action') {
|
||||
$plugin = empty($this->params['plugin']) ? null : Inflector::camelize($this->params['plugin']) . '/';
|
||||
return str_replace(
|
||||
array(':controller', ':action', ':plugin/'),
|
||||
array(Inflector::camelize($this->params['controller']), $this->params['action'], $plugin),
|
||||
$this->actionPath . $action
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the model object specified, and attempts
|
||||
* to load it if it is not found.
|
||||
*
|
||||
* @param string $name Model name (defaults to AuthComponent::$userModel)
|
||||
* @return object A reference to a model object
|
||||
* @access public
|
||||
*/
|
||||
function &getModel($name = null) {
|
||||
$model = null;
|
||||
if (!$name) {
|
||||
$name = $this->userModel;
|
||||
}
|
||||
|
||||
if (PHP5) {
|
||||
$model = ClassRegistry::init($name);
|
||||
} else {
|
||||
$model =& ClassRegistry::init($name);
|
||||
}
|
||||
|
||||
if (empty($model)) {
|
||||
trigger_error(__('Auth::getModel() - Model is not set or could not be found', true), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies a user based on specific criteria.
|
||||
*
|
||||
* @param mixed $user Optional. The identity of the user to be validated.
|
||||
* Uses the current user session if none specified.
|
||||
* @param array $conditions Optional. Additional conditions to a find.
|
||||
* @return array User record data, or null, if the user could not be identified.
|
||||
* @access public
|
||||
*/
|
||||
function identify($user = null, $conditions = null) {
|
||||
if ($conditions === false) {
|
||||
$conditions = null;
|
||||
} elseif (is_array($conditions)) {
|
||||
$conditions = array_merge((array)$this->userScope, $conditions);
|
||||
} else {
|
||||
$conditions = $this->userScope;
|
||||
}
|
||||
$model =& $this->getModel();
|
||||
if (empty($user)) {
|
||||
$user = $this->user();
|
||||
if (empty($user)) {
|
||||
return null;
|
||||
}
|
||||
} elseif (is_object($user) && is_a($user, 'Model')) {
|
||||
if (!$user->exists()) {
|
||||
return null;
|
||||
}
|
||||
$user = $user->read();
|
||||
$user = $user[$model->alias];
|
||||
} elseif (is_array($user) && isset($user[$model->alias])) {
|
||||
$user = $user[$model->alias];
|
||||
}
|
||||
|
||||
if (is_array($user) && (isset($user[$this->fields['username']]) || isset($user[$model->alias . '.' . $this->fields['username']]))) {
|
||||
if (isset($user[$this->fields['username']]) && !empty($user[$this->fields['username']]) && !empty($user[$this->fields['password']])) {
|
||||
if (trim($user[$this->fields['username']]) == '=' || trim($user[$this->fields['password']]) == '=') {
|
||||
return false;
|
||||
}
|
||||
$find = array(
|
||||
$model->alias.'.'.$this->fields['username'] => $user[$this->fields['username']],
|
||||
$model->alias.'.'.$this->fields['password'] => $user[$this->fields['password']]
|
||||
);
|
||||
} elseif (isset($user[$model->alias . '.' . $this->fields['username']]) && !empty($user[$model->alias . '.' . $this->fields['username']])) {
|
||||
if (trim($user[$model->alias . '.' . $this->fields['username']]) == '=' || trim($user[$model->alias . '.' . $this->fields['password']]) == '=') {
|
||||
return false;
|
||||
}
|
||||
$find = array(
|
||||
$model->alias.'.'.$this->fields['username'] => $user[$model->alias . '.' . $this->fields['username']],
|
||||
$model->alias.'.'.$this->fields['password'] => $user[$model->alias . '.' . $this->fields['password']]
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$data = $model->find('first', array(
|
||||
'conditions' => array_merge($find, $conditions),
|
||||
'recursive' => 0
|
||||
));
|
||||
if (empty($data) || empty($data[$model->alias])) {
|
||||
return null;
|
||||
}
|
||||
} elseif (!empty($user) && is_string($user)) {
|
||||
$data = $model->find('first', array(
|
||||
'conditions' => array_merge(array($model->escapeField() => $user), $conditions),
|
||||
));
|
||||
if (empty($data) || empty($data[$model->alias])) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
if (!empty($data[$model->alias][$this->fields['password']])) {
|
||||
unset($data[$model->alias][$this->fields['password']]);
|
||||
}
|
||||
return $data[$model->alias];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash any passwords found in $data using $userModel and $fields['password']
|
||||
*
|
||||
* @param array $data Set of data to look for passwords
|
||||
* @return array Data with passwords hashed
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1259/hashPasswords
|
||||
*/
|
||||
function hashPasswords($data) {
|
||||
if (is_object($this->authenticate) && method_exists($this->authenticate, 'hashPasswords')) {
|
||||
return $this->authenticate->hashPasswords($data);
|
||||
}
|
||||
|
||||
if (is_array($data)) {
|
||||
$model =& $this->getModel();
|
||||
|
||||
if(isset($data[$model->alias])) {
|
||||
if (isset($data[$model->alias][$this->fields['username']]) && isset($data[$model->alias][$this->fields['password']])) {
|
||||
$data[$model->alias][$this->fields['password']] = $this->password($data[$model->alias][$this->fields['password']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a password with the application's salt value (as defined with Configure::write('Security.salt');
|
||||
*
|
||||
* @param string $password Password to hash
|
||||
* @return string Hashed password
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1263/password
|
||||
*/
|
||||
function password($password) {
|
||||
return Security::hash($password, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component shutdown. If user is logged in, wipe out redirect.
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @access public
|
||||
*/
|
||||
function shutdown(&$controller) {
|
||||
if ($this->_loggedIn) {
|
||||
$this->Session->delete('Auth.redirect');
|
||||
}
|
||||
}
|
||||
}
|
||||
471
web-cake/html/cake/libs/controller/components/cookie.php
Normal file
471
web-cake/html/cake/libs/controller/components/cookie.php
Normal file
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/**
|
||||
* Cookie Component
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 1.2.0.4213
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load Security class
|
||||
*/
|
||||
App::import('Core', 'Security');
|
||||
|
||||
/**
|
||||
* Cookie Component.
|
||||
*
|
||||
* Cookie handling for the controller.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1280/Cookies
|
||||
*
|
||||
*/
|
||||
class CookieComponent extends Object {
|
||||
|
||||
/**
|
||||
* The name of the cookie.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->name = 'CookieName';
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'CakeCookie';
|
||||
|
||||
/**
|
||||
* The time a cookie will remain valid.
|
||||
*
|
||||
* Can be either integer Unix timestamp or a date string.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->time = '5 Days';
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
*/
|
||||
var $time = null;
|
||||
|
||||
/**
|
||||
* Cookie path.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->path = '/';
|
||||
*
|
||||
* The path on the server in which the cookie will be available on.
|
||||
* If var $cookiePath is set to '/foo/', the cookie will only be available
|
||||
* within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
|
||||
* The default value is the entire domain.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $path = '/';
|
||||
|
||||
/**
|
||||
* Domain path.
|
||||
*
|
||||
* The domain that the cookie is available.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->domain = '.example.com';
|
||||
*
|
||||
* To make the cookie available on all subdomains of example.com.
|
||||
* Set $this->Cookie->domain = '.example.com'; in your controller beforeFilter
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $domain = '';
|
||||
|
||||
/**
|
||||
* Secure HTTPS only cookie.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->secure = true;
|
||||
*
|
||||
* Indicates that the cookie should only be transmitted over a secure HTTPS connection.
|
||||
* When set to true, the cookie will only be set if a secure connection exists.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $secure = false;
|
||||
|
||||
/**
|
||||
* Encryption key.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->key = 'SomeRandomString';
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $key = null;
|
||||
|
||||
/**
|
||||
* Values stored in the cookie.
|
||||
*
|
||||
* Accessed in the controller using $this->Cookie->read('Name.key');
|
||||
*
|
||||
* @see CookieComponent::read();
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__values = array();
|
||||
|
||||
/**
|
||||
* Type of encryption to use.
|
||||
*
|
||||
* Currently only one method is available
|
||||
* Defaults to Security::cipher();
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @todo add additional encryption methods
|
||||
*/
|
||||
var $__type = 'cipher';
|
||||
|
||||
/**
|
||||
* Used to reset cookie time if $expire is passed to CookieComponent::write()
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__reset = null;
|
||||
|
||||
/**
|
||||
* Expire time of the cookie
|
||||
*
|
||||
* This is controlled by CookieComponent::time;
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__expires = 0;
|
||||
|
||||
/**
|
||||
* Main execution method.
|
||||
*
|
||||
* @param object $controller A reference to the instantiating controller object
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$controller, $settings) {
|
||||
$this->key = Configure::read('Security.salt');
|
||||
$this->_set($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start CookieComponent for use in the controller
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function startup() {
|
||||
$this->__expire($this->time);
|
||||
|
||||
if (isset($_COOKIE[$this->name])) {
|
||||
$this->__values = $this->__decrypt($_COOKIE[$this->name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the $_COOKIE[$key];
|
||||
*
|
||||
* Optional [Name.], reguired key, optional $value, optional $encrypt, optional $expires
|
||||
* $this->Cookie->write('[Name.]key, $value);
|
||||
*
|
||||
* By default all values are encrypted.
|
||||
* You must pass $encrypt false to store values in clear test
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* @param mixed $key Key for the value
|
||||
* @param mixed $value Value
|
||||
* @param boolean $encrypt Set to true to encrypt value, false otherwise
|
||||
* @param string $expires Can be either Unix timestamp, or date string
|
||||
* @access public
|
||||
*/
|
||||
function write($key, $value = null, $encrypt = true, $expires = null) {
|
||||
if (is_null($encrypt)) {
|
||||
$encrypt = true;
|
||||
}
|
||||
$this->__encrypted = $encrypt;
|
||||
$this->__expire($expires);
|
||||
|
||||
if (!is_array($key)) {
|
||||
$key = array($key => $value);
|
||||
}
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
if (strpos($name, '.') === false) {
|
||||
$this->__values[$name] = $value;
|
||||
$this->__write("[$name]", $value);
|
||||
|
||||
} else {
|
||||
$names = explode('.', $name, 2);
|
||||
if (!isset($this->__values[$names[0]])) {
|
||||
$this->__values[$names[0]] = array();
|
||||
}
|
||||
$this->__values[$names[0]] = Set::insert($this->__values[$names[0]], $names[1], $value);
|
||||
$this->__write('[' . implode('][', $names) . ']', $value);
|
||||
}
|
||||
}
|
||||
$this->__encrypted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the value of the $_COOKIE[$key];
|
||||
*
|
||||
* Optional [Name.], reguired key
|
||||
* $this->Cookie->read(Name.key);
|
||||
*
|
||||
* @param mixed $key Key of the value to be obtained. If none specified, obtain map key => values
|
||||
* @return string or null, value for specified key
|
||||
* @access public
|
||||
*/
|
||||
function read($key = null) {
|
||||
if (empty($this->__values) && isset($_COOKIE[$this->name])) {
|
||||
$this->__values = $this->__decrypt($_COOKIE[$this->name]);
|
||||
}
|
||||
|
||||
if (is_null($key)) {
|
||||
return $this->__values;
|
||||
}
|
||||
|
||||
if (strpos($key, '.') !== false) {
|
||||
$names = explode('.', $key, 2);
|
||||
$key = $names[0];
|
||||
}
|
||||
if (!isset($this->__values[$key])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!empty($names[1])) {
|
||||
return Set::extract($this->__values[$key], $names[1]);
|
||||
}
|
||||
return $this->__values[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cookie value
|
||||
*
|
||||
* Optional [Name.], reguired key
|
||||
* $this->Cookie->read('Name.key);
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* @param string $key Key of the value to be deleted
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function delete($key) {
|
||||
if (empty($this->__values)) {
|
||||
$this->read();
|
||||
}
|
||||
if (strpos($key, '.') === false) {
|
||||
unset($this->__values[$key]);
|
||||
$this->__delete("[$key]");
|
||||
return;
|
||||
}
|
||||
$names = explode('.', $key, 2);
|
||||
$this->__values[$names[0]] = Set::remove($this->__values[$names[0]], $names[1]);
|
||||
$this->__delete('[' . implode('][', $names) . ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy current cookie
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function destroy() {
|
||||
if (isset($_COOKIE[$this->name])) {
|
||||
$this->__values = $this->__decrypt($_COOKIE[$this->name]);
|
||||
}
|
||||
|
||||
foreach ($this->__values as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
unset($this->__values[$name][$key]);
|
||||
$this->__delete("[$name][$key]");
|
||||
}
|
||||
}
|
||||
unset($this->__values[$name]);
|
||||
$this->__delete("[$name]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will allow overriding default encryption method.
|
||||
*
|
||||
* @param string $type Encryption method
|
||||
* @access public
|
||||
* @todo NOT IMPLEMENTED
|
||||
*/
|
||||
function type($type = 'cipher') {
|
||||
$this->__type = 'cipher';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expire time for a session variable.
|
||||
*
|
||||
* Creates a new expire time for a session variable.
|
||||
* $expire can be either integer Unix timestamp or a date string.
|
||||
*
|
||||
* Used by write()
|
||||
* CookieComponent::write(string, string, boolean, 8400);
|
||||
* CookieComponent::write(string, string, boolean, '5 Days');
|
||||
*
|
||||
* @param mixed $expires Can be either Unix timestamp, or date string
|
||||
* @return int Unix timestamp
|
||||
* @access private
|
||||
*/
|
||||
function __expire($expires = null) {
|
||||
$now = time();
|
||||
if (is_null($expires)) {
|
||||
return $this->__expires;
|
||||
}
|
||||
$this->__reset = $this->__expires;
|
||||
|
||||
if ($expires == 0) {
|
||||
return $this->__expires = 0;
|
||||
}
|
||||
|
||||
if (is_integer($expires) || is_numeric($expires)) {
|
||||
return $this->__expires = $now + intval($expires);
|
||||
}
|
||||
return $this->__expires = strtotime($expires, $now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cookie
|
||||
*
|
||||
* @param string $name Name for cookie
|
||||
* @param string $value Value for cookie
|
||||
* @access private
|
||||
*/
|
||||
function __write($name, $value) {
|
||||
setcookie($this->name . $name, $this->__encrypt($value), $this->__expires, $this->path, $this->domain, $this->secure);
|
||||
|
||||
if (!is_null($this->__reset)) {
|
||||
$this->__expires = $this->__reset;
|
||||
$this->__reset = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie expire time to remove cookie value
|
||||
*
|
||||
* @param string $name Name of cookie
|
||||
* @access private
|
||||
*/
|
||||
function __delete($name) {
|
||||
setcookie($this->name . $name, '', time() - 42000, $this->path, $this->domain, $this->secure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts $value using var $type method in Security class
|
||||
*
|
||||
* @param string $value Value to encrypt
|
||||
* @return string encrypted string
|
||||
* @access private
|
||||
*/
|
||||
function __encrypt($value) {
|
||||
if (is_array($value)) {
|
||||
$value = $this->__implode($value);
|
||||
}
|
||||
|
||||
if ($this->__encrypted === true) {
|
||||
$type = $this->__type;
|
||||
$value = "Q2FrZQ==." .base64_encode(Security::$type($value, $this->key));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts $value using var $type method in Security class
|
||||
*
|
||||
* @param array $values Values to decrypt
|
||||
* @return string decrypted string
|
||||
* @access private
|
||||
*/
|
||||
function __decrypt($values) {
|
||||
$decrypted = array();
|
||||
$type = $this->__type;
|
||||
|
||||
foreach ($values as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
$pos = strpos($val, 'Q2FrZQ==.');
|
||||
$decrypted[$name][$key] = $this->__explode($val);
|
||||
|
||||
if ($pos !== false) {
|
||||
$val = substr($val, 8);
|
||||
$decrypted[$name][$key] = $this->__explode(Security::$type(base64_decode($val), $this->key));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$pos = strpos($value, 'Q2FrZQ==.');
|
||||
$decrypted[$name] = $this->__explode($value);
|
||||
|
||||
if ($pos !== false) {
|
||||
$value = substr($value, 8);
|
||||
$decrypted[$name] = $this->__explode(Security::$type(base64_decode($value), $this->key));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implode method to keep keys are multidimensional arrays
|
||||
*
|
||||
* @param array $array Map of key and values
|
||||
* @return string String in the form key1|value1,key2|value2
|
||||
* @access private
|
||||
*/
|
||||
function __implode($array) {
|
||||
$string = '';
|
||||
foreach ($array as $key => $value) {
|
||||
$string .= ',' . $key . '|' . $value;
|
||||
}
|
||||
return substr($string, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode method to return array from string set in CookieComponent::__implode()
|
||||
*
|
||||
* @param string $string String in the form key1|value1,key2|value2
|
||||
* @return array Map of key and values
|
||||
* @access private
|
||||
*/
|
||||
function __explode($string) {
|
||||
$array = array();
|
||||
foreach (explode(',', $string) as $pair) {
|
||||
$key = explode('|', $pair);
|
||||
if (!isset($key[1])) {
|
||||
return $key[0];
|
||||
}
|
||||
$array[$key[0]] = $key[1];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
962
web-cake/html/cake/libs/controller/components/email.php
Executable file
962
web-cake/html/cake/libs/controller/components/email.php
Executable file
@@ -0,0 +1,962 @@
|
||||
<?php
|
||||
/**
|
||||
* Email Component
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 1.2.0.3467
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Core', 'Multibyte');
|
||||
|
||||
/**
|
||||
* EmailComponent
|
||||
*
|
||||
* This component is used for handling Internet Message Format based
|
||||
* based on the standard outlined in http://www.rfc-editor.org/rfc/rfc2822.txt
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1283/Email
|
||||
*
|
||||
*/
|
||||
class EmailComponent extends Object{
|
||||
|
||||
/**
|
||||
* Recipient of the email
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $to = null;
|
||||
|
||||
/**
|
||||
* The mail which the email is sent from
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $from = null;
|
||||
|
||||
/**
|
||||
* The email the recipient will reply to
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $replyTo = null;
|
||||
|
||||
/**
|
||||
* The read receipt email
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $readReceipt = null;
|
||||
|
||||
/**
|
||||
* The mail that will be used in case of any errors like
|
||||
* - Remote mailserver down
|
||||
* - Remote user has exceeded his quota
|
||||
* - Unknown user
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $return = null;
|
||||
|
||||
/**
|
||||
* Carbon Copy
|
||||
*
|
||||
* List of email's that should receive a copy of the email.
|
||||
* The Recipient WILL be able to see this list
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $cc = array();
|
||||
|
||||
/**
|
||||
* Blind Carbon Copy
|
||||
*
|
||||
* List of email's that should receive a copy of the email.
|
||||
* The Recipient WILL NOT be able to see this list
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $bcc = array();
|
||||
|
||||
/**
|
||||
* The subject of the email
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $subject = null;
|
||||
|
||||
/**
|
||||
* Associative array of a user defined headers
|
||||
* Keys will be prefixed 'X-' as per RFC2822 Section 4.7.5
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $headers = array();
|
||||
|
||||
/**
|
||||
* List of additional headers
|
||||
*
|
||||
* These will NOT be used if you are using safemode and mail()
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $additionalParams = null;
|
||||
|
||||
/**
|
||||
* Layout for the View
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $layout = 'default';
|
||||
|
||||
/**
|
||||
* Template for the view
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $template = null;
|
||||
|
||||
/**
|
||||
* as per RFC2822 Section 2.1.1
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $lineLength = 70;
|
||||
|
||||
/**
|
||||
* @deprecated see lineLength
|
||||
*/
|
||||
var $_lineLength = null;
|
||||
|
||||
/**
|
||||
* What format should the email be sent in
|
||||
*
|
||||
* Supported formats:
|
||||
* - text
|
||||
* - html
|
||||
* - both
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $sendAs = 'text';
|
||||
|
||||
/**
|
||||
* What method should the email be sent by
|
||||
*
|
||||
* Supported methods:
|
||||
* - mail
|
||||
* - smtp
|
||||
* - debug
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $delivery = 'mail';
|
||||
|
||||
/**
|
||||
* charset the email is sent in
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* List of files that should be attached to the email.
|
||||
*
|
||||
* Can be both absolute and relative paths
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $attachments = array();
|
||||
|
||||
/**
|
||||
* What mailer should EmailComponent identify itself as
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $xMailer = 'CakePHP Email Component';
|
||||
|
||||
/**
|
||||
* The list of paths to search if an attachment isnt absolute
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $filePaths = array();
|
||||
|
||||
/**
|
||||
* List of options to use for smtp mail method
|
||||
*
|
||||
* Options is:
|
||||
* - port
|
||||
* - host
|
||||
* - timeout
|
||||
* - username
|
||||
* - password
|
||||
* - client
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1290/Sending-A-Message-Using-SMTP
|
||||
*/
|
||||
var $smtpOptions = array();
|
||||
|
||||
/**
|
||||
* Placeholder for any errors that might happen with the
|
||||
* smtp mail methods
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $smtpError = null;
|
||||
|
||||
/**
|
||||
* Contains the rendered plain text message if one was sent.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $textMessage = null;
|
||||
|
||||
/**
|
||||
* Contains the rendered HTML message if one was sent.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $htmlMessage = null;
|
||||
|
||||
/**
|
||||
* Whether to generate a Message-ID header for the
|
||||
* e-mail. True to generate a Message-ID, False to let
|
||||
* it be handled by sendmail (or similar) or a string
|
||||
* to completely override the Message-ID.
|
||||
*
|
||||
* @var mixed
|
||||
* @access public
|
||||
*/
|
||||
var $messageId = true;
|
||||
|
||||
/**
|
||||
* Temporary store of message header lines
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__header = array();
|
||||
|
||||
/**
|
||||
* If set, boundary to use for multipart mime messages
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__boundary = null;
|
||||
|
||||
/**
|
||||
* Temporary store of message lines
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__message = array();
|
||||
|
||||
/**
|
||||
* Variable that holds SMTP connection
|
||||
*
|
||||
* @var resource
|
||||
* @access private
|
||||
*/
|
||||
var $__smtpConnection = null;
|
||||
|
||||
/**
|
||||
* Initialize component
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$controller, $settings = array()) {
|
||||
$this->Controller =& $controller;
|
||||
if (Configure::read('App.encoding') !== null) {
|
||||
$this->charset = Configure::read('App.encoding');
|
||||
}
|
||||
$this->_set($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup component
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {}
|
||||
|
||||
/**
|
||||
* Send an email using the specified content, template and layout
|
||||
*
|
||||
* @param mixed $content Either an array of text lines, or a string with contents
|
||||
* If you are rendering a template this variable will be sent to the templates as `$content`
|
||||
* @param string $template Template to use when sending email
|
||||
* @param string $layout Layout to use to enclose email body
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function send($content = null, $template = null, $layout = null) {
|
||||
$this->_createHeader();
|
||||
|
||||
if ($template) {
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
if ($layout) {
|
||||
$this->layout = $layout;
|
||||
}
|
||||
|
||||
if (is_array($content)) {
|
||||
$content = implode("\n", $content) . "\n";
|
||||
}
|
||||
|
||||
$this->htmlMessage = $this->textMessage = null;
|
||||
if ($content) {
|
||||
if ($this->sendAs === 'html') {
|
||||
$this->htmlMessage = $content;
|
||||
} elseif ($this->sendAs === 'text') {
|
||||
$this->textMessage = $content;
|
||||
} else {
|
||||
$this->htmlMessage = $this->textMessage = $content;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->sendAs === 'text') {
|
||||
$message = $this->_wrap($content);
|
||||
} else {
|
||||
$message = $this->_wrap($content, 998);
|
||||
}
|
||||
|
||||
if ($this->template === null) {
|
||||
$message = $this->_formatMessage($message);
|
||||
} else {
|
||||
$message = $this->_render($message);
|
||||
}
|
||||
|
||||
$message[] = '';
|
||||
$this->__message = $message;
|
||||
|
||||
if (!empty($this->attachments)) {
|
||||
$this->_attachFiles();
|
||||
}
|
||||
|
||||
if (!is_null($this->__boundary)) {
|
||||
$this->__message[] = '';
|
||||
$this->__message[] = '--' . $this->__boundary . '--';
|
||||
$this->__message[] = '';
|
||||
}
|
||||
|
||||
|
||||
$_method = '_' . $this->delivery;
|
||||
$sent = $this->$_method();
|
||||
|
||||
$this->__header = array();
|
||||
$this->__message = array();
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all EmailComponent internal variables to be able to send out a new email.
|
||||
*
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1285/Sending-Multiple-Emails-in-a-loop
|
||||
*/
|
||||
function reset() {
|
||||
$this->template = null;
|
||||
$this->to = array();
|
||||
$this->from = null;
|
||||
$this->replyTo = null;
|
||||
$this->return = null;
|
||||
$this->cc = array();
|
||||
$this->bcc = array();
|
||||
$this->subject = null;
|
||||
$this->additionalParams = null;
|
||||
$this->smtpError = null;
|
||||
$this->attachments = array();
|
||||
$this->htmlMessage = null;
|
||||
$this->textMessage = null;
|
||||
$this->messageId = true;
|
||||
$this->__header = array();
|
||||
$this->__boundary = null;
|
||||
$this->__message = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the contents using the current layout and template.
|
||||
*
|
||||
* @param string $content Content to render
|
||||
* @return array Email ready to be sent
|
||||
* @access private
|
||||
*/
|
||||
function _render($content) {
|
||||
$viewClass = $this->Controller->view;
|
||||
|
||||
if ($viewClass != 'View') {
|
||||
list($plugin, $viewClass) = pluginSplit($viewClass);
|
||||
$viewClass = $viewClass . 'View';
|
||||
App::import('View', $this->Controller->view);
|
||||
}
|
||||
|
||||
$View = new $viewClass($this->Controller, false);
|
||||
$View->layout = $this->layout;
|
||||
$msg = array();
|
||||
|
||||
$content = implode("\n", $content);
|
||||
|
||||
if ($this->sendAs === 'both') {
|
||||
$htmlContent = $content;
|
||||
if (!empty($this->attachments)) {
|
||||
$msg[] = '--' . $this->__boundary;
|
||||
$msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $this->__boundary . '"';
|
||||
$msg[] = '';
|
||||
}
|
||||
$msg[] = '--alt-' . $this->__boundary;
|
||||
$msg[] = 'Content-Type: text/plain; charset=' . $this->charset;
|
||||
$msg[] = 'Content-Transfer-Encoding: 7bit';
|
||||
$msg[] = '';
|
||||
|
||||
$content = $View->element('email' . DS . 'text' . DS . $this->template, array('content' => $content), true);
|
||||
$View->layoutPath = 'email' . DS . 'text';
|
||||
$content = explode("\n", $this->textMessage = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($content)));
|
||||
|
||||
$msg = array_merge($msg, $content);
|
||||
|
||||
$msg[] = '';
|
||||
$msg[] = '--alt-' . $this->__boundary;
|
||||
$msg[] = 'Content-Type: text/html; charset=' . $this->charset;
|
||||
$msg[] = 'Content-Transfer-Encoding: 7bit';
|
||||
$msg[] = '';
|
||||
|
||||
$htmlContent = $View->element('email' . DS . 'html' . DS . $this->template, array('content' => $htmlContent), true);
|
||||
$View->layoutPath = 'email' . DS . 'html';
|
||||
$htmlContent = explode("\n", $this->htmlMessage = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($htmlContent)));
|
||||
$msg = array_merge($msg, $htmlContent);
|
||||
$msg[] = '';
|
||||
$msg[] = '--alt-' . $this->__boundary . '--';
|
||||
$msg[] = '';
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
if (!empty($this->attachments)) {
|
||||
if ($this->sendAs === 'html') {
|
||||
$msg[] = '';
|
||||
$msg[] = '--' . $this->__boundary;
|
||||
$msg[] = 'Content-Type: text/html; charset=' . $this->charset;
|
||||
$msg[] = 'Content-Transfer-Encoding: 7bit';
|
||||
$msg[] = '';
|
||||
} else {
|
||||
$msg[] = '--' . $this->__boundary;
|
||||
$msg[] = 'Content-Type: text/plain; charset=' . $this->charset;
|
||||
$msg[] = 'Content-Transfer-Encoding: 7bit';
|
||||
$msg[] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$content = $View->element('email' . DS . $this->sendAs . DS . $this->template, array('content' => $content), true);
|
||||
$View->layoutPath = 'email' . DS . $this->sendAs;
|
||||
$content = explode("\n", $rendered = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($content)));
|
||||
|
||||
if ($this->sendAs === 'html') {
|
||||
$this->htmlMessage = $rendered;
|
||||
} else {
|
||||
$this->textMessage = $rendered;
|
||||
}
|
||||
|
||||
$msg = array_merge($msg, $content);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create unique boundary identifier
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _createboundary() {
|
||||
$this->__boundary = md5(uniqid(time()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets headers for the message
|
||||
*
|
||||
* @access public
|
||||
* @param array Associative array containing headers to be set.
|
||||
*/
|
||||
function header($headers) {
|
||||
foreach ($headers as $header => $value) {
|
||||
$this->__header[] = sprintf('%s: %s', trim($header), trim($value));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create emails headers including (but not limited to) from email address, reply to,
|
||||
* bcc and cc.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _createHeader() {
|
||||
$headers = array();
|
||||
|
||||
if ($this->delivery == 'smtp') {
|
||||
if (is_array($this->to)) {
|
||||
$headers['To'] = implode(', ', array_map(array($this, '_formatAddress'), $this->to));
|
||||
} else {
|
||||
$headers['To'] = $this->_formatAddress($this->to);
|
||||
}
|
||||
}
|
||||
$headers['From'] = $this->_formatAddress($this->from);
|
||||
|
||||
if (!empty($this->replyTo)) {
|
||||
$headers['Reply-To'] = $this->_formatAddress($this->replyTo);
|
||||
}
|
||||
if (!empty($this->return)) {
|
||||
$headers['Return-Path'] = $this->_formatAddress($this->return);
|
||||
}
|
||||
if (!empty($this->readReceipt)) {
|
||||
$headers['Disposition-Notification-To'] = $this->_formatAddress($this->readReceipt);
|
||||
}
|
||||
|
||||
if (!empty($this->cc)) {
|
||||
$headers['cc'] = implode(', ', array_map(array($this, '_formatAddress'), $this->cc));
|
||||
}
|
||||
|
||||
if (!empty($this->bcc) && $this->delivery != 'smtp') {
|
||||
$headers['Bcc'] = implode(', ', array_map(array($this, '_formatAddress'), $this->bcc));
|
||||
}
|
||||
if ($this->delivery == 'smtp') {
|
||||
$headers['Subject'] = $this->_encode($this->subject);
|
||||
}
|
||||
|
||||
if ($this->messageId !== false) {
|
||||
if ($this->messageId === true) {
|
||||
$headers['Message-ID'] = '<' . String::UUID() . '@' . env('HTTP_HOST') . '>';
|
||||
} else {
|
||||
$headers['Message-ID'] = $this->messageId;
|
||||
}
|
||||
}
|
||||
|
||||
$headers['X-Mailer'] = $this->xMailer;
|
||||
|
||||
if (!empty($this->headers)) {
|
||||
foreach ($this->headers as $key => $val) {
|
||||
$headers['X-' . $key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->attachments)) {
|
||||
$this->_createBoundary();
|
||||
$headers['MIME-Version'] = '1.0';
|
||||
$headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->__boundary . '"';
|
||||
$headers[] = 'This part of the E-mail should never be seen. If';
|
||||
$headers[] = 'you are reading this, consider upgrading your e-mail';
|
||||
$headers[] = 'client to a MIME-compatible client.';
|
||||
} elseif ($this->sendAs === 'text') {
|
||||
$headers['Content-Type'] = 'text/plain; charset=' . $this->charset;
|
||||
} elseif ($this->sendAs === 'html') {
|
||||
$headers['Content-Type'] = 'text/html; charset=' . $this->charset;
|
||||
} elseif ($this->sendAs === 'both') {
|
||||
$headers['Content-Type'] = 'multipart/alternative; boundary="alt-' . $this->__boundary . '"';
|
||||
}
|
||||
|
||||
$headers['Content-Transfer-Encoding'] = '7bit';
|
||||
|
||||
$this->header($headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the message by seeing if it has attachments.
|
||||
*
|
||||
* @param string $message Message to format
|
||||
* @access private
|
||||
*/
|
||||
function _formatMessage($message) {
|
||||
if (!empty($this->attachments)) {
|
||||
$prefix = array('--' . $this->__boundary);
|
||||
if ($this->sendAs === 'text') {
|
||||
$prefix[] = 'Content-Type: text/plain; charset=' . $this->charset;
|
||||
} elseif ($this->sendAs === 'html') {
|
||||
$prefix[] = 'Content-Type: text/html; charset=' . $this->charset;
|
||||
} elseif ($this->sendAs === 'both') {
|
||||
$prefix[] = 'Content-Type: multipart/alternative; boundary="alt-' . $this->__boundary . '"';
|
||||
}
|
||||
$prefix[] = 'Content-Transfer-Encoding: 7bit';
|
||||
$prefix[] = '';
|
||||
$message = array_merge($prefix, $message);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach files by adding file contents inside boundaries.
|
||||
*
|
||||
* @access private
|
||||
* @TODO: modify to use the core File class?
|
||||
*/
|
||||
function _attachFiles() {
|
||||
$files = array();
|
||||
foreach ($this->attachments as $filename => $attachment) {
|
||||
$file = $this->_findFiles($attachment);
|
||||
if (!empty($file)) {
|
||||
if (is_int($filename)) {
|
||||
$filename = basename($file);
|
||||
}
|
||||
$files[$filename] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($files as $filename => $file) {
|
||||
$handle = fopen($file, 'rb');
|
||||
$data = fread($handle, filesize($file));
|
||||
$data = chunk_split(base64_encode($data)) ;
|
||||
fclose($handle);
|
||||
|
||||
$this->__message[] = '--' . $this->__boundary;
|
||||
$this->__message[] = 'Content-Type: application/octet-stream';
|
||||
$this->__message[] = 'Content-Transfer-Encoding: base64';
|
||||
$this->__message[] = 'Content-Disposition: attachment; filename="' . basename($filename) . '"';
|
||||
$this->__message[] = '';
|
||||
$this->__message[] = $data;
|
||||
$this->__message[] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the specified attachment in the list of file paths
|
||||
*
|
||||
* @param string $attachment Attachment file name to find
|
||||
* @return string Path to located file
|
||||
* @access private
|
||||
*/
|
||||
function _findFiles($attachment) {
|
||||
if (file_exists($attachment)) {
|
||||
return $attachment;
|
||||
}
|
||||
foreach ($this->filePaths as $path) {
|
||||
if (file_exists($path . DS . $attachment)) {
|
||||
$file = $path . DS . $attachment;
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the message using EmailComponent::$lineLength
|
||||
*
|
||||
* @param string $message Message to wrap
|
||||
* @param integer $lineLength Max length of line
|
||||
* @return array Wrapped message
|
||||
* @access protected
|
||||
*/
|
||||
function _wrap($message, $lineLength = null) {
|
||||
$message = $this->_strip($message, true);
|
||||
$message = str_replace(array("\r\n","\r"), "\n", $message);
|
||||
$lines = explode("\n", $message);
|
||||
$formatted = array();
|
||||
|
||||
if ($this->_lineLength !== null) {
|
||||
trigger_error(__('_lineLength cannot be accessed please use lineLength', true), E_USER_WARNING);
|
||||
$this->lineLength = $this->_lineLength;
|
||||
}
|
||||
|
||||
if (!$lineLength) {
|
||||
$lineLength = $this->lineLength;
|
||||
}
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (substr($line, 0, 1) == '.') {
|
||||
$line = '.' . $line;
|
||||
}
|
||||
$formatted = array_merge($formatted, explode("\n", wordwrap($line, $lineLength, "\n", true)));
|
||||
}
|
||||
$formatted[] = '';
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the specified string using the current charset
|
||||
*
|
||||
* @param string $subject String to encode
|
||||
* @return string Encoded string
|
||||
* @access private
|
||||
*/
|
||||
function _encode($subject) {
|
||||
$subject = $this->_strip($subject);
|
||||
|
||||
$nl = "\r\n";
|
||||
if ($this->delivery == 'mail') {
|
||||
$nl = '';
|
||||
}
|
||||
$internalEncoding = function_exists('mb_internal_encoding');
|
||||
if ($internalEncoding) {
|
||||
$restore = mb_internal_encoding();
|
||||
mb_internal_encoding($this->charset);
|
||||
}
|
||||
$return = mb_encode_mimeheader($subject, $this->charset, 'B', $nl);
|
||||
if ($internalEncoding) {
|
||||
mb_internal_encoding($restore);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string as an email address
|
||||
*
|
||||
* @param string $string String representing an email address
|
||||
* @return string Email address suitable for email headers or smtp pipe
|
||||
* @access private
|
||||
*/
|
||||
function _formatAddress($string, $smtp = false) {
|
||||
$hasAlias = preg_match('/((.*)\s)?<(.+)>/', $string, $matches);
|
||||
if ($smtp && $hasAlias) {
|
||||
return $this->_strip('<' . $matches[3] . '>');
|
||||
} elseif ($smtp) {
|
||||
return $this->_strip('<' . $string . '>');
|
||||
}
|
||||
if ($hasAlias && !empty($matches[2])) {
|
||||
return $this->_strip($matches[2] . ' <' . $matches[3] . '>');
|
||||
}
|
||||
return $this->_strip($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove certain elements (such as bcc:, to:, %0a) from given value.
|
||||
* Helps prevent header injection / mainipulation on user content.
|
||||
*
|
||||
* @param string $value Value to strip
|
||||
* @param boolean $message Set to true to indicate main message content
|
||||
* @return string Stripped value
|
||||
* @access private
|
||||
*/
|
||||
function _strip($value, $message = false) {
|
||||
$search = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
|
||||
$search .= '|charset\=|mime-version\:|multipart/mixed|(?:[^a-z]to|b?cc)\:.*';
|
||||
|
||||
if ($message !== true) {
|
||||
$search .= '|\r|\n';
|
||||
}
|
||||
$search = '#(?:' . $search . ')#i';
|
||||
while (preg_match($search, $value)) {
|
||||
$value = preg_replace($search, '', $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for PHP mail function used for sending out emails
|
||||
*
|
||||
* @return bool Success
|
||||
* @access private
|
||||
*/
|
||||
function _mail() {
|
||||
$header = implode("\r\n", $this->__header);
|
||||
$message = implode("\r\n", $this->__message);
|
||||
if (is_array($this->to)) {
|
||||
$to = implode(', ', array_map(array($this, '_formatAddress'), $this->to));
|
||||
} else {
|
||||
$to = $this->to;
|
||||
}
|
||||
if (ini_get('safe_mode')) {
|
||||
return @mail($to, $this->_encode($this->subject), $message, $header);
|
||||
}
|
||||
return @mail($to, $this->_encode($this->subject), $message, $header, $this->additionalParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends out email via SMTP
|
||||
*
|
||||
* @return bool Success
|
||||
* @access private
|
||||
*/
|
||||
function _smtp() {
|
||||
App::import('Core', array('CakeSocket'));
|
||||
|
||||
$defaults = array(
|
||||
'host' => 'localhost',
|
||||
'port' => 25,
|
||||
'protocol' => 'smtp',
|
||||
'timeout' => 30
|
||||
);
|
||||
$this->smtpOptions = array_merge($defaults, $this->smtpOptions);
|
||||
$this->__smtpConnection =& new CakeSocket($this->smtpOptions);
|
||||
|
||||
if (!$this->__smtpConnection->connect()) {
|
||||
$this->smtpError = $this->__smtpConnection->lastError();
|
||||
return false;
|
||||
} elseif (!$this->_smtpSend(null, '220')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$httpHost = env('HTTP_HOST');
|
||||
|
||||
if (isset($this->smtpOptions['client'])) {
|
||||
$host = $this->smtpOptions['client'];
|
||||
} elseif (!empty($httpHost)) {
|
||||
$host = $httpHost;
|
||||
} else {
|
||||
$host = 'localhost';
|
||||
}
|
||||
|
||||
if (!$this->_smtpSend("EHLO {$host}", '250') && !$this->_smtpSend("HELO {$host}", '250')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->smtpOptions['username']) && isset($this->smtpOptions['password'])) {
|
||||
$authRequired = $this->_smtpSend('AUTH LOGIN', '334|503');
|
||||
if ($authRequired == '334') {
|
||||
if (!$this->_smtpSend(base64_encode($this->smtpOptions['username']), '334')) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->_smtpSend(base64_encode($this->smtpOptions['password']), '235')) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($authRequired != '503') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_smtpSend('MAIL FROM: ' . $this->_formatAddress($this->from, true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_array($this->to)) {
|
||||
$tos = array($this->to);
|
||||
} else {
|
||||
$tos = $this->to;
|
||||
}
|
||||
foreach ($tos as $to) {
|
||||
if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($to, true))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->cc as $cc) {
|
||||
if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($cc, true))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach ($this->bcc as $bcc) {
|
||||
if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($bcc, true))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_smtpSend('DATA', '354')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$header = implode("\r\n", $this->__header);
|
||||
$message = implode("\r\n", $this->__message);
|
||||
if (!$this->_smtpSend($header . "\r\n\r\n" . $message . "\r\n\r\n\r\n.")) {
|
||||
return false;
|
||||
}
|
||||
$this->_smtpSend('QUIT', false);
|
||||
|
||||
$this->__smtpConnection->disconnect();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected method for sending data to SMTP connection
|
||||
*
|
||||
* @param string $data data to be sent to SMTP server
|
||||
* @param mixed $checkCode code to check for in server response, false to skip
|
||||
* @return bool Success
|
||||
* @access protected
|
||||
*/
|
||||
function _smtpSend($data, $checkCode = '250') {
|
||||
if (!is_null($data)) {
|
||||
$this->__smtpConnection->write($data . "\r\n");
|
||||
}
|
||||
while ($checkCode !== false) {
|
||||
$response = '';
|
||||
$startTime = time();
|
||||
while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->smtpOptions['timeout'])) {
|
||||
$response .= $this->__smtpConnection->read();
|
||||
}
|
||||
if (substr($response, -2) !== "\r\n") {
|
||||
$this->smtpError = 'timeout';
|
||||
return false;
|
||||
}
|
||||
$response = end(explode("\r\n", rtrim($response, "\r\n")));
|
||||
|
||||
if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
|
||||
if ($code[2] === '-') {
|
||||
continue;
|
||||
}
|
||||
return $code[1];
|
||||
}
|
||||
$this->smtpError = $response;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set as controller flash message a debug message showing current settings in component
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function _debug() {
|
||||
$nl = "\n";
|
||||
$header = implode($nl, $this->__header);
|
||||
$message = implode($nl, $this->__message);
|
||||
$fm = '<pre>';
|
||||
|
||||
if (is_array($this->to)) {
|
||||
$to = implode(', ', array_map(array($this, '_formatAddress'), $this->to));
|
||||
} else {
|
||||
$to = $this->to;
|
||||
}
|
||||
$fm .= sprintf('%s %s%s', 'To:', $to, $nl);
|
||||
$fm .= sprintf('%s %s%s', 'From:', $this->from, $nl);
|
||||
$fm .= sprintf('%s %s%s', 'Subject:', $this->_encode($this->subject), $nl);
|
||||
$fm .= sprintf('%s%3$s%3$s%s', 'Header:', $header, $nl);
|
||||
$fm .= sprintf('%s%3$s%3$s%s', 'Parameters:', $this->additionalParams, $nl);
|
||||
$fm .= sprintf('%s%3$s%3$s%s', 'Message:', $message, $nl);
|
||||
$fm .= '</pre>';
|
||||
|
||||
if (isset($this->Controller->Session)) {
|
||||
$this->Controller->Session->setFlash($fm, 'default', null, 'email');
|
||||
return true;
|
||||
}
|
||||
return $fm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,826 @@
|
||||
<?php
|
||||
/**
|
||||
* Request object for handling alternative HTTP requests
|
||||
*
|
||||
* Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
|
||||
* and the like. These units have no use for Ajax requests, and this Component can tell how Cake
|
||||
* should respond to the different needs of a handheld computer and a desktop machine.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 0.10.4.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Request object for handling HTTP requests
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1291/Request-Handling
|
||||
*
|
||||
*/
|
||||
class RequestHandlerComponent extends Object {
|
||||
|
||||
/**
|
||||
* The layout that will be switched to for Ajax requests
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @see RequestHandler::setAjax()
|
||||
*/
|
||||
var $ajaxLayout = 'ajax';
|
||||
|
||||
/**
|
||||
* Determines whether or not callbacks will be fired on this component
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $enabled = true;
|
||||
|
||||
/**
|
||||
* Holds the content-type of the response that is set when using
|
||||
* RequestHandler::respondAs()
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__responseTypeSet = null;
|
||||
|
||||
/**
|
||||
* Holds the copy of Controller::$params
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $params = array();
|
||||
|
||||
/**
|
||||
* Friendly content-type mappings used to set response types and determine
|
||||
* request types. Can be modified with RequestHandler::setContent()
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
* @see RequestHandlerComponent::setContent
|
||||
*/
|
||||
var $__requestContent = array(
|
||||
'javascript' => 'text/javascript',
|
||||
'js' => 'text/javascript',
|
||||
'json' => 'application/json',
|
||||
'css' => 'text/css',
|
||||
'html' => array('text/html', '*/*'),
|
||||
'text' => 'text/plain',
|
||||
'txt' => 'text/plain',
|
||||
'csv' => array('application/vnd.ms-excel', 'text/plain'),
|
||||
'form' => 'application/x-www-form-urlencoded',
|
||||
'file' => 'multipart/form-data',
|
||||
'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
|
||||
'xhtml-mobile' => 'application/vnd.wap.xhtml+xml',
|
||||
'xml' => array('application/xml', 'text/xml'),
|
||||
'rss' => 'application/rss+xml',
|
||||
'atom' => 'application/atom+xml',
|
||||
'amf' => 'application/x-amf',
|
||||
'wap' => array(
|
||||
'text/vnd.wap.wml',
|
||||
'text/vnd.wap.wmlscript',
|
||||
'image/vnd.wap.wbmp'
|
||||
),
|
||||
'wml' => 'text/vnd.wap.wml',
|
||||
'wmlscript' => 'text/vnd.wap.wmlscript',
|
||||
'wbmp' => 'image/vnd.wap.wbmp',
|
||||
'pdf' => 'application/pdf',
|
||||
'zip' => 'application/x-zip',
|
||||
'tar' => 'application/x-tar'
|
||||
);
|
||||
|
||||
/**
|
||||
* List of regular expressions for matching mobile device's user agent string
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $mobileUA = array(
|
||||
'Android',
|
||||
'AvantGo',
|
||||
'BlackBerry',
|
||||
'DoCoMo',
|
||||
'iPod',
|
||||
'iPhone',
|
||||
'J2ME',
|
||||
'MIDP',
|
||||
'NetFront',
|
||||
'Nokia',
|
||||
'Opera Mini',
|
||||
'PalmOS',
|
||||
'PalmSource',
|
||||
'portalmmm',
|
||||
'Plucker',
|
||||
'ReqwirelessWeb',
|
||||
'SonyEricsson',
|
||||
'Symbian',
|
||||
'UP\.Browser',
|
||||
'webOS',
|
||||
'Windows CE',
|
||||
'Xiino'
|
||||
);
|
||||
|
||||
/**
|
||||
* Content-types accepted by the client. If extension parsing is enabled in the
|
||||
* Router, and an extension is detected, the corresponding content-type will be
|
||||
* used as the overriding primary content-type accepted.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
* @see Router::parseExtensions()
|
||||
*/
|
||||
var $__acceptTypes = array();
|
||||
|
||||
/**
|
||||
* The template to use when rendering the given content type.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__renderType = null;
|
||||
|
||||
/**
|
||||
* Contains the file extension parsed out by the Router
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @see Router::parseExtensions()
|
||||
*/
|
||||
var $ext = null;
|
||||
|
||||
/**
|
||||
* Flag set when MIME types have been initialized
|
||||
*
|
||||
* @var boolean
|
||||
* @access private
|
||||
* @see RequestHandler::__initializeTypes()
|
||||
*/
|
||||
var $__typesInitialized = false;
|
||||
|
||||
/**
|
||||
* Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
$this->__acceptTypes = explode(',', env('HTTP_ACCEPT'));
|
||||
|
||||
foreach ($this->__acceptTypes as $i => $type) {
|
||||
if (strpos($type, ';')) {
|
||||
$type = explode(';', $type);
|
||||
$this->__acceptTypes[$i] = $type[0];
|
||||
}
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the component, gets a reference to Controller::$parameters, and
|
||||
* checks to see if a file extension has been parsed by the Router. If yes, the
|
||||
* corresponding content-type is pushed onto the list of accepted content-types
|
||||
* as the first item.
|
||||
*
|
||||
* @param object $controller A reference to the controller
|
||||
* @param array $settings Array of settings to _set().
|
||||
* @return void
|
||||
* @see Router::parseExtensions()
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$controller, $settings = array()) {
|
||||
if (isset($controller->params['url']['ext'])) {
|
||||
$this->ext = $controller->params['url']['ext'];
|
||||
}
|
||||
$this->_set($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* The startup method of the RequestHandler enables several automatic behaviors
|
||||
* related to the detection of certain properties of the HTTP request, including:
|
||||
*
|
||||
* - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
|
||||
* - If Router::parseExtensions() is enabled, the layout and template type are
|
||||
* switched based on the parsed extension. For example, if controller/action.xml
|
||||
* is requested, the view path becomes <i>app/views/controller/xml/action.ctp</i>.
|
||||
* - If a helper with the same name as the extension exists, it is added to the controller.
|
||||
* - If the extension is of a type that RequestHandler understands, it will set that
|
||||
* Content-type in the response header.
|
||||
* - If the XML data is POSTed, the data is parsed into an XML object, which is assigned
|
||||
* to the $data property of the controller, which can then be saved to a model object.
|
||||
*
|
||||
* @param object $controller A reference to the controller
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
if (!$this->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->__initializeTypes();
|
||||
$controller->params['isAjax'] = $this->isAjax();
|
||||
$isRecognized = (
|
||||
!in_array($this->ext, array('html', 'htm')) &&
|
||||
in_array($this->ext, array_keys($this->__requestContent))
|
||||
);
|
||||
|
||||
if (!empty($this->ext) && $isRecognized) {
|
||||
$this->renderAs($controller, $this->ext);
|
||||
} elseif ($this->isAjax()) {
|
||||
$this->renderAs($controller, 'ajax');
|
||||
} elseif (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
|
||||
$this->respondAs('html', array('charset' => Configure::read('App.encoding')));
|
||||
}
|
||||
|
||||
if ($this->requestedWith('xml')) {
|
||||
if (!class_exists('XmlNode')) {
|
||||
App::import('Core', 'Xml');
|
||||
}
|
||||
$xml = new Xml(trim(file_get_contents('php://input')));
|
||||
|
||||
if (count($xml->children) == 1 && is_object($dataNode = $xml->child('data'))) {
|
||||
$controller->data = $dataNode->toArray();
|
||||
} else {
|
||||
$controller->data = $xml->toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles (fakes) redirects for Ajax requests using requestAction()
|
||||
*
|
||||
* @param object $controller A reference to the controller
|
||||
* @param mixed $url A string or array containing the redirect location
|
||||
* @param mixed HTTP Status for redirect
|
||||
* @access public
|
||||
*/
|
||||
function beforeRedirect(&$controller, $url, $status = null) {
|
||||
if (!$this->isAjax()) {
|
||||
return;
|
||||
}
|
||||
foreach ($_POST as $key => $val) {
|
||||
unset($_POST[$key]);
|
||||
}
|
||||
if (is_array($url)) {
|
||||
$url = Router::url($url + array('base' => false));
|
||||
}
|
||||
if (!empty($status)) {
|
||||
$statusCode = $controller->httpCodes($status);
|
||||
$code = key($statusCode);
|
||||
$msg = $statusCode[$code];
|
||||
$controller->header("HTTP/1.1 {$code} {$msg}");
|
||||
}
|
||||
echo $this->requestAction($url, array('return', 'bare' => false));
|
||||
$this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current HTTP request is Ajax, false otherwise
|
||||
*
|
||||
* @return boolean True if call is Ajax
|
||||
* @access public
|
||||
*/
|
||||
function isAjax() {
|
||||
return env('HTTP_X_REQUESTED_WITH') === "XMLHttpRequest";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current HTTP request is coming from a Flash-based client
|
||||
*
|
||||
* @return boolean True if call is from Flash
|
||||
* @access public
|
||||
*/
|
||||
function isFlash() {
|
||||
return (preg_match('/^(Shockwave|Adobe) Flash/', env('HTTP_USER_AGENT')) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current request is over HTTPS, false otherwise.
|
||||
*
|
||||
* @return bool True if call is over HTTPS
|
||||
* @access public
|
||||
*/
|
||||
function isSSL() {
|
||||
return env('HTTPS');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an XML response, false otherwise
|
||||
*
|
||||
* @return boolean True if client accepts an XML response
|
||||
* @access public
|
||||
*/
|
||||
function isXml() {
|
||||
return $this->prefers('xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an RSS response, false otherwise
|
||||
*
|
||||
* @return boolean True if client accepts an RSS response
|
||||
* @access public
|
||||
*/
|
||||
function isRss() {
|
||||
return $this->prefers('rss');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an Atom response, false otherwise
|
||||
*
|
||||
* @return boolean True if client accepts an RSS response
|
||||
* @access public
|
||||
*/
|
||||
function isAtom() {
|
||||
return $this->prefers('atom');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user agent string matches a mobile web browser, or if the
|
||||
* client accepts WAP content.
|
||||
*
|
||||
* @return boolean True if user agent is a mobile web browser
|
||||
* @access public
|
||||
* @deprecated Use of constant REQUEST_MOBILE_UA is deprecated and will be removed in future versions
|
||||
*/
|
||||
function isMobile() {
|
||||
if (defined('REQUEST_MOBILE_UA')) {
|
||||
$regex = '/' . REQUEST_MOBILE_UA . '/i';
|
||||
} else {
|
||||
$regex = '/' . implode('|', $this->mobileUA) . '/i';
|
||||
}
|
||||
|
||||
if (preg_match($regex, env('HTTP_USER_AGENT')) || $this->accepts('wap')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the client accepts WAP content
|
||||
*
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function isWap() {
|
||||
return $this->prefers('wap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a POST request
|
||||
*
|
||||
* @return boolean True if call is a POST
|
||||
* @access public
|
||||
*/
|
||||
function isPost() {
|
||||
return (strtolower(env('REQUEST_METHOD')) == 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a PUT request
|
||||
*
|
||||
* @return boolean True if call is a PUT
|
||||
* @access public
|
||||
*/
|
||||
function isPut() {
|
||||
return (strtolower(env('REQUEST_METHOD')) == 'put');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a GET request
|
||||
*
|
||||
* @return boolean True if call is a GET
|
||||
* @access public
|
||||
*/
|
||||
function isGet() {
|
||||
return (strtolower(env('REQUEST_METHOD')) == 'get');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a DELETE request
|
||||
*
|
||||
* @return boolean True if call is a DELETE
|
||||
* @access public
|
||||
*/
|
||||
function isDelete() {
|
||||
return (strtolower(env('REQUEST_METHOD')) == 'delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Prototype version if call is Ajax, otherwise empty string.
|
||||
* The Prototype library sets a special "Prototype version" HTTP header.
|
||||
*
|
||||
* @return string Prototype version of component making Ajax call
|
||||
* @access public
|
||||
*/
|
||||
function getAjaxVersion() {
|
||||
if (env('HTTP_X_PROTOTYPE_VERSION') != null) {
|
||||
return env('HTTP_X_PROTOTYPE_VERSION');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds/sets the Content-type(s) for the given name. This method allows
|
||||
* content-types to be mapped to friendly aliases (or extensions), which allows
|
||||
* RequestHandler to automatically respond to requests of that type in the
|
||||
* startup method.
|
||||
*
|
||||
* @param string $name The name of the Content-type, i.e. "html", "xml", "css"
|
||||
* @param mixed $type The Content-type or array of Content-types assigned to the name,
|
||||
* i.e. "text/html", or "application/xml"
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function setContent($name, $type = null) {
|
||||
if (is_array($name)) {
|
||||
$this->__requestContent = array_merge($this->__requestContent, $name);
|
||||
return;
|
||||
}
|
||||
$this->__requestContent[$name] = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server name from which this request was referred
|
||||
*
|
||||
* @return string Server address
|
||||
* @access public
|
||||
*/
|
||||
function getReferer() {
|
||||
if (env('HTTP_HOST') != null) {
|
||||
$sessHost = env('HTTP_HOST');
|
||||
}
|
||||
|
||||
if (env('HTTP_X_FORWARDED_HOST') != null) {
|
||||
$sessHost = env('HTTP_X_FORWARDED_HOST');
|
||||
}
|
||||
return trim(preg_replace('/(?:\:.*)/', '', $sessHost));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets remote client IP
|
||||
*
|
||||
* @return string Client IP address
|
||||
* @access public
|
||||
*/
|
||||
function getClientIP($safe = true) {
|
||||
if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) {
|
||||
$ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
|
||||
} else {
|
||||
if (env('HTTP_CLIENT_IP') != null) {
|
||||
$ipaddr = env('HTTP_CLIENT_IP');
|
||||
} else {
|
||||
$ipaddr = env('REMOTE_ADDR');
|
||||
}
|
||||
}
|
||||
|
||||
if (env('HTTP_CLIENTADDRESS') != null) {
|
||||
$tmpipaddr = env('HTTP_CLIENTADDRESS');
|
||||
|
||||
if (!empty($tmpipaddr)) {
|
||||
$ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr);
|
||||
}
|
||||
}
|
||||
return trim($ipaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which content types the client accepts. Acceptance is based on
|
||||
* the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
|
||||
* header.
|
||||
*
|
||||
* @param mixed $type Can be null (or no parameter), a string type name, or an
|
||||
* array of types
|
||||
* @return mixed If null or no parameter is passed, returns an array of content
|
||||
* types the client accepts. If a string is passed, returns true
|
||||
* if the client accepts it. If an array is passed, returns true
|
||||
* if the client accepts one or more elements in the array.
|
||||
* @access public
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
function accepts($type = null) {
|
||||
$this->__initializeTypes();
|
||||
|
||||
if ($type == null) {
|
||||
return $this->mapType($this->__acceptTypes);
|
||||
|
||||
} elseif (is_array($type)) {
|
||||
foreach ($type as $t) {
|
||||
if ($this->accepts($t) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} elseif (is_string($type)) {
|
||||
|
||||
if (!isset($this->__requestContent[$type])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $this->__requestContent[$type];
|
||||
|
||||
if (is_array($content)) {
|
||||
foreach ($content as $c) {
|
||||
if (in_array($c, $this->__acceptTypes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (in_array($content, $this->__acceptTypes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the content type of the data the client has sent (i.e. in a POST request)
|
||||
*
|
||||
* @param mixed $type Can be null (or no parameter), a string type name, or an array of types
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function requestedWith($type = null) {
|
||||
if (!$this->isPost() && !$this->isPut()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
list($contentType) = explode(';', env('CONTENT_TYPE'));
|
||||
if ($type == null) {
|
||||
return $this->mapType($contentType);
|
||||
} elseif (is_array($type)) {
|
||||
foreach ($type as $t) {
|
||||
if ($this->requestedWith($t)) {
|
||||
return $this->mapType($t);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} elseif (is_string($type)) {
|
||||
return ($type == $this->mapType($contentType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which content-types the client prefers. If no parameters are given,
|
||||
* the content-type that the client most likely prefers is returned. If $type is
|
||||
* an array, the first item in the array that the client accepts is returned.
|
||||
* Preference is determined primarily by the file extension parsed by the Router
|
||||
* if provided, and secondarily by the list of content-types provided in
|
||||
* HTTP_ACCEPT.
|
||||
*
|
||||
* @param mixed $type An optional array of 'friendly' content-type names, i.e.
|
||||
* 'html', 'xml', 'js', etc.
|
||||
* @return mixed If $type is null or not provided, the first content-type in the
|
||||
* list, based on preference, is returned.
|
||||
* @access public
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
function prefers($type = null) {
|
||||
$this->__initializeTypes();
|
||||
$accept = $this->accepts();
|
||||
|
||||
if ($type == null) {
|
||||
if (empty($this->ext)) {
|
||||
if (is_array($accept)) {
|
||||
return $accept[0];
|
||||
}
|
||||
return $accept;
|
||||
}
|
||||
return $this->ext;
|
||||
}
|
||||
|
||||
$types = $type;
|
||||
if (is_string($type)) {
|
||||
$types = array($type);
|
||||
}
|
||||
|
||||
if (count($types) === 1) {
|
||||
if (!empty($this->ext)) {
|
||||
return ($types[0] == $this->ext);
|
||||
}
|
||||
return ($types[0] == $accept[0]);
|
||||
}
|
||||
$accepts = array();
|
||||
|
||||
foreach ($types as $type) {
|
||||
if (in_array($type, $accept)) {
|
||||
$accepts[] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($accepts) === 0) {
|
||||
return false;
|
||||
} elseif (count($types) === 1) {
|
||||
return ($types[0] === $accepts[0]);
|
||||
} elseif (count($accepts) === 1) {
|
||||
return $accepts[0];
|
||||
}
|
||||
|
||||
$acceptedTypes = array();
|
||||
foreach ($this->__acceptTypes as $type) {
|
||||
$acceptedTypes[] = $this->mapType($type);
|
||||
}
|
||||
$accepts = array_intersect($acceptedTypes, $accepts);
|
||||
return $accepts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the layout and template paths for the content type defined by $type.
|
||||
*
|
||||
* @param object $controller A reference to a controller object
|
||||
* @param string $type Type of response to send (e.g: 'ajax')
|
||||
* @return void
|
||||
* @access public
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
* @see RequestHandlerComponent::respondAs()
|
||||
*/
|
||||
function renderAs(&$controller, $type) {
|
||||
$this->__initializeTypes();
|
||||
$options = array('charset' => 'UTF-8');
|
||||
|
||||
if (Configure::read('App.encoding') !== null) {
|
||||
$options = array('charset' => Configure::read('App.encoding'));
|
||||
}
|
||||
|
||||
if ($type == 'ajax') {
|
||||
$controller->layout = $this->ajaxLayout;
|
||||
return $this->respondAs('html', $options);
|
||||
}
|
||||
$controller->ext = '.ctp';
|
||||
|
||||
if (empty($this->__renderType)) {
|
||||
$controller->viewPath .= DS . $type;
|
||||
} else {
|
||||
$remove = preg_replace("/([\/\\\\]{$this->__renderType})$/", DS . $type, $controller->viewPath);
|
||||
$controller->viewPath = $remove;
|
||||
}
|
||||
$this->__renderType = $type;
|
||||
$controller->layoutPath = $type;
|
||||
|
||||
if (isset($this->__requestContent[$type])) {
|
||||
$this->respondAs($type, $options);
|
||||
}
|
||||
|
||||
$helper = ucfirst($type);
|
||||
$isAdded = (
|
||||
in_array($helper, $controller->helpers) ||
|
||||
array_key_exists($helper, $controller->helpers)
|
||||
);
|
||||
|
||||
if (!$isAdded) {
|
||||
if (App::import('Helper', $helper)) {
|
||||
$controller->helpers[] = $helper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response header based on type map index name. If DEBUG is greater than 2, the header
|
||||
* is not set.
|
||||
*
|
||||
* @param mixed $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
|
||||
* like 'application/x-shockwave'.
|
||||
* @param array $options If $type is a friendly type name that is associated with
|
||||
* more than one type of content, $index is used to select which content-type to use.
|
||||
* @return boolean Returns false if the friendly type name given in $type does
|
||||
* not exist in the type map, or if the Content-type header has
|
||||
* already been set by this method.
|
||||
* @access public
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
function respondAs($type, $options = array()) {
|
||||
$this->__initializeTypes();
|
||||
if (!array_key_exists($type, $this->__requestContent) && strpos($type, '/') === false) {
|
||||
return false;
|
||||
}
|
||||
$defaults = array('index' => 0, 'charset' => null, 'attachment' => false);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if (strpos($type, '/') === false && isset($this->__requestContent[$type])) {
|
||||
$cType = null;
|
||||
if (is_array($this->__requestContent[$type]) && isset($this->__requestContent[$type][$options['index']])) {
|
||||
$cType = $this->__requestContent[$type][$options['index']];
|
||||
} elseif (is_array($this->__requestContent[$type]) && isset($this->__requestContent[$type][0])) {
|
||||
$cType = $this->__requestContent[$type][0];
|
||||
} elseif (isset($this->__requestContent[$type])) {
|
||||
$cType = $this->__requestContent[$type];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($cType)) {
|
||||
if ($this->prefers($cType)) {
|
||||
$cType = $this->prefers($cType);
|
||||
} else {
|
||||
$cType = $cType[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$cType = $type;
|
||||
}
|
||||
|
||||
if ($cType != null) {
|
||||
$header = 'Content-type: ' . $cType;
|
||||
|
||||
if (!empty($options['charset'])) {
|
||||
$header .= '; charset=' . $options['charset'];
|
||||
}
|
||||
if (!empty($options['attachment'])) {
|
||||
$this->_header("Content-Disposition: attachment; filename=\"{$options['attachment']}\"");
|
||||
}
|
||||
if (Configure::read() < 2 && !defined('CAKEPHP_SHELL')) {
|
||||
$this->_header($header);
|
||||
}
|
||||
$this->__responseTypeSet = $cType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for header() so calls can be easily tested.
|
||||
*
|
||||
* @param string $header The header to be sent.
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _header($header) {
|
||||
header($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current response type (Content-type header), or null if none has been set
|
||||
*
|
||||
* @return mixed A string content type alias, or raw content type if no alias map exists,
|
||||
* otherwise null
|
||||
* @access public
|
||||
*/
|
||||
function responseType() {
|
||||
if ($this->__responseTypeSet == null) {
|
||||
return null;
|
||||
}
|
||||
return $this->mapType($this->__responseTypeSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a content-type back to an alias
|
||||
*
|
||||
* @param mixed $type Content type
|
||||
* @return mixed Alias
|
||||
* @access public
|
||||
*/
|
||||
function mapType($ctype) {
|
||||
if (is_array($ctype)) {
|
||||
$out = array();
|
||||
foreach ($ctype as $t) {
|
||||
$out[] = $this->mapType($t);
|
||||
}
|
||||
return $out;
|
||||
} else {
|
||||
$keys = array_keys($this->__requestContent);
|
||||
$count = count($keys);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$name = $keys[$i];
|
||||
$type = $this->__requestContent[$name];
|
||||
|
||||
if (is_array($type) && in_array($ctype, $type)) {
|
||||
return $name;
|
||||
} elseif (!is_array($type) && $type == $ctype) {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
return $ctype;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes MIME types
|
||||
*
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __initializeTypes() {
|
||||
if ($this->__typesInitialized) {
|
||||
return;
|
||||
}
|
||||
if (isset($this->__requestContent[$this->ext])) {
|
||||
$content = $this->__requestContent[$this->ext];
|
||||
if (is_array($content)) {
|
||||
$content = $content[0];
|
||||
}
|
||||
array_unshift($this->__acceptTypes, $content);
|
||||
}
|
||||
$this->__typesInitialized = true;
|
||||
}
|
||||
}
|
||||
751
web-cake/html/cake/libs/controller/components/security.php
Normal file
751
web-cake/html/cake/libs/controller/components/security.php
Normal file
@@ -0,0 +1,751 @@
|
||||
<?php
|
||||
/**
|
||||
* Security Component
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 0.10.8.2156
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Core', array('String', 'Security'));
|
||||
|
||||
/**
|
||||
* SecurityComponent
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1296/Security-Component
|
||||
*/
|
||||
class SecurityComponent extends Object {
|
||||
|
||||
/**
|
||||
* The controller method that will be called if this request is black-hole'd
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $blackHoleCallback = null;
|
||||
|
||||
/**
|
||||
* List of controller actions for which a POST request is required
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requirePost()
|
||||
*/
|
||||
var $requirePost = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a GET request is required
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireGet()
|
||||
*/
|
||||
var $requireGet = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a PUT request is required
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requirePut()
|
||||
*/
|
||||
var $requirePut = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a DELETE request is required
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireDelete()
|
||||
*/
|
||||
var $requireDelete = array();
|
||||
|
||||
/**
|
||||
* List of actions that require an SSL-secured connection
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireSecure()
|
||||
*/
|
||||
var $requireSecure = array();
|
||||
|
||||
/**
|
||||
* List of actions that require a valid authentication key
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
var $requireAuth = array();
|
||||
|
||||
/**
|
||||
* List of actions that require an HTTP-authenticated login (basic or digest)
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireLogin()
|
||||
*/
|
||||
var $requireLogin = array();
|
||||
|
||||
/**
|
||||
* Login options for SecurityComponent::requireLogin()
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireLogin()
|
||||
*/
|
||||
var $loginOptions = array('type' => '', 'prompt' => null);
|
||||
|
||||
/**
|
||||
* An associative array of usernames/passwords used for HTTP-authenticated logins.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireLogin()
|
||||
*/
|
||||
var $loginUsers = array();
|
||||
|
||||
/**
|
||||
* Controllers from which actions of the current controller are allowed to receive
|
||||
* requests.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
var $allowedControllers = array();
|
||||
|
||||
/**
|
||||
* Actions from which actions of the current controller are allowed to receive
|
||||
* requests.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
var $allowedActions = array();
|
||||
|
||||
/**
|
||||
* Form fields to disable
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $disabledFields = array();
|
||||
|
||||
/**
|
||||
* Whether to validate POST data. Set to false to disable for data coming from 3rd party
|
||||
* services, etc.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $validatePost = true;
|
||||
|
||||
/**
|
||||
* Other components used by the Security component
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $components = array('RequestHandler', 'Session');
|
||||
|
||||
/**
|
||||
* Holds the current action of the controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_action = null;
|
||||
|
||||
/**
|
||||
* Initialize the SecurityComponent
|
||||
*
|
||||
* @param object $controller Controller instance for the request
|
||||
* @param array $settings Settings to set to the component
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function initialize(&$controller, $settings = array()) {
|
||||
$this->_set($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component startup. All security checking happens here.
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
$this->_action = strtolower($controller->action);
|
||||
$this->_methodsRequired($controller);
|
||||
$this->_secureRequired($controller);
|
||||
$this->_authRequired($controller);
|
||||
$this->_loginRequired($controller);
|
||||
|
||||
$isPost = ($this->RequestHandler->isPost() || $this->RequestHandler->isPut());
|
||||
$isRequestAction = (
|
||||
!isset($controller->params['requested']) ||
|
||||
$controller->params['requested'] != 1
|
||||
);
|
||||
|
||||
if ($isPost && $isRequestAction && $this->validatePost) {
|
||||
if ($this->_validatePost($controller) === false) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_generateToken($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a POST request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1299/requirePost
|
||||
*/
|
||||
function requirePost() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Post', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a GET request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function requireGet() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Get', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a PUT request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function requirePut() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Put', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a DELETE request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function requireDelete() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Delete', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a request that is SSL-secured, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1300/requireSecure
|
||||
*/
|
||||
function requireSecure() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Secure', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require an authenticated request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1301/requireAuth
|
||||
*/
|
||||
function requireAuth() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Auth', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require an HTTP-authenticated request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1302/requireLogin
|
||||
*/
|
||||
function requireLogin() {
|
||||
$args = func_get_args();
|
||||
$base = $this->loginOptions;
|
||||
|
||||
foreach ($args as $i => $arg) {
|
||||
if (is_array($arg)) {
|
||||
$this->loginOptions = $arg;
|
||||
unset($args[$i]);
|
||||
}
|
||||
}
|
||||
$this->loginOptions = array_merge($base, $this->loginOptions);
|
||||
$this->_requireMethod('Login', $args);
|
||||
|
||||
if (isset($this->loginOptions['users'])) {
|
||||
$this->loginUsers =& $this->loginOptions['users'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to validate the login credentials for an HTTP-authenticated request
|
||||
*
|
||||
* @param string $type Either 'basic', 'digest', or null. If null/empty, will try both.
|
||||
* @return mixed If successful, returns an array with login name and password, otherwise null.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1303/loginCredentials-string-type
|
||||
*/
|
||||
function loginCredentials($type = null) {
|
||||
switch (strtolower($type)) {
|
||||
case 'basic':
|
||||
$login = array('username' => env('PHP_AUTH_USER'), 'password' => env('PHP_AUTH_PW'));
|
||||
if (!empty($login['username'])) {
|
||||
return $login;
|
||||
}
|
||||
break;
|
||||
case 'digest':
|
||||
default:
|
||||
$digest = null;
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.1') != -1) {
|
||||
$digest = env('PHP_AUTH_DIGEST');
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Authorization']) && !empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') {
|
||||
$digest = substr($headers['Authorization'], 7);
|
||||
}
|
||||
} else {
|
||||
// Server doesn't support digest-auth headers
|
||||
trigger_error(__('SecurityComponent::loginCredentials() - Server does not support digest authentication', true), E_USER_WARNING);
|
||||
}
|
||||
|
||||
if (!empty($digest)) {
|
||||
return $this->parseDigestAuthData($digest);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the text of an HTTP-authentication request header from an array of options.
|
||||
*
|
||||
* @param array $options Set of options for header
|
||||
* @return string HTTP-authentication request header
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1304/loginRequest-array-options
|
||||
*/
|
||||
function loginRequest($options = array()) {
|
||||
$options = array_merge($this->loginOptions, $options);
|
||||
$this->_setLoginDefaults($options);
|
||||
$auth = 'WWW-Authenticate: ' . ucfirst($options['type']);
|
||||
$out = array('realm="' . $options['realm'] . '"');
|
||||
|
||||
if (strtolower($options['type']) == 'digest') {
|
||||
$out[] = 'qop="auth"';
|
||||
$out[] = 'nonce="' . uniqid("") . '"';
|
||||
$out[] = 'opaque="' . md5($options['realm']) . '"';
|
||||
}
|
||||
|
||||
return $auth . ' ' . implode(',', $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an HTTP digest authentication response, and returns an array of the data, or null on failure.
|
||||
*
|
||||
* @param string $digest Digest authentication response
|
||||
* @return array Digest authentication parameters
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1305/parseDigestAuthData-string-digest
|
||||
*/
|
||||
function parseDigestAuthData($digest) {
|
||||
if (substr($digest, 0, 7) == 'Digest ') {
|
||||
$digest = substr($digest, 7);
|
||||
}
|
||||
$keys = array();
|
||||
$match = array();
|
||||
$req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1);
|
||||
preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER);
|
||||
|
||||
foreach ($match as $i) {
|
||||
$keys[$i[1]] = $i[3];
|
||||
unset($req[$i[1]]);
|
||||
}
|
||||
|
||||
if (empty($req)) {
|
||||
return $keys;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash to be compared with an HTTP digest-authenticated response
|
||||
*
|
||||
* @param array $data HTTP digest response data, as parsed by SecurityComponent::parseDigestAuthData()
|
||||
* @return string Digest authentication hash
|
||||
* @access public
|
||||
* @see SecurityComponent::parseDigestAuthData()
|
||||
* @link http://book.cakephp.org/view/1306/generateDigestResponseHash-array-data
|
||||
*/
|
||||
function generateDigestResponseHash($data) {
|
||||
return md5(
|
||||
md5($data['username'] . ':' . $this->loginOptions['realm'] . ':' . $this->loginUsers[$data['username']]) .
|
||||
':' . $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' .
|
||||
md5(env('REQUEST_METHOD') . ':' . $data['uri'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Black-hole an invalid request with a 404 error or custom callback. If SecurityComponent::$blackHoleCallback
|
||||
* is specified, it will use this callback by executing the method indicated in $error
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @param string $error Error method
|
||||
* @return mixed If specified, controller blackHoleCallback's response, or no return otherwise
|
||||
* @access public
|
||||
* @see SecurityComponent::$blackHoleCallback
|
||||
* @link http://book.cakephp.org/view/1307/blackHole-object-controller-string-error
|
||||
*/
|
||||
function blackHole(&$controller, $error = '') {
|
||||
if ($this->blackHoleCallback == null) {
|
||||
$code = 404;
|
||||
if ($error == 'login') {
|
||||
$code = 401;
|
||||
$controller->header($this->loginRequest());
|
||||
}
|
||||
$controller->redirect(null, $code, true);
|
||||
} else {
|
||||
return $this->_callback($controller, $this->blackHoleCallback, array($error));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a $method HTTP request, or empty for all actions
|
||||
*
|
||||
* @param string $method The HTTP method to assign controller actions to
|
||||
* @param array $actions Controller actions to set the required HTTP method to.
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _requireMethod($method, $actions = array()) {
|
||||
if (isset($actions[0]) && is_array($actions[0])) {
|
||||
$actions = $actions[0];
|
||||
}
|
||||
$this->{'require' . $method} = (empty($actions)) ? array('*'): $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if HTTP methods are required
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool true if $method is required
|
||||
* @access protected
|
||||
*/
|
||||
function _methodsRequired(&$controller) {
|
||||
foreach (array('Post', 'Get', 'Put', 'Delete') as $method) {
|
||||
$property = 'require' . $method;
|
||||
if (is_array($this->$property) && !empty($this->$property)) {
|
||||
$require = array_map('strtolower', $this->$property);
|
||||
|
||||
if (in_array($this->_action, $require) || $this->$property == array('*')) {
|
||||
if (!$this->RequestHandler->{'is' . $method}()) {
|
||||
if (!$this->blackHole($controller, strtolower($method))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if access requires secure connection
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool true if secure connection required
|
||||
* @access protected
|
||||
*/
|
||||
function _secureRequired(&$controller) {
|
||||
if (is_array($this->requireSecure) && !empty($this->requireSecure)) {
|
||||
$requireSecure = array_map('strtolower', $this->requireSecure);
|
||||
|
||||
if (in_array($this->_action, $requireSecure) || $this->requireSecure == array('*')) {
|
||||
if (!$this->RequestHandler->isSSL()) {
|
||||
if (!$this->blackHole($controller, 'secure')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication is required
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool true if authentication required
|
||||
* @access protected
|
||||
*/
|
||||
function _authRequired(&$controller) {
|
||||
if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($controller->data)) {
|
||||
$requireAuth = array_map('strtolower', $this->requireAuth);
|
||||
|
||||
if (in_array($this->_action, $requireAuth) || $this->requireAuth == array('*')) {
|
||||
if (!isset($controller->data['_Token'] )) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tData = unserialize($this->Session->read('_Token'));
|
||||
|
||||
if (!empty($tData['allowedControllers']) && !in_array($controller->params['controller'], $tData['allowedControllers']) || !empty($tData['allowedActions']) && !in_array($controller->params['action'], $tData['allowedActions'])) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if login is required
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool true if login is required
|
||||
* @access protected
|
||||
*/
|
||||
function _loginRequired(&$controller) {
|
||||
if (is_array($this->requireLogin) && !empty($this->requireLogin)) {
|
||||
$requireLogin = array_map('strtolower', $this->requireLogin);
|
||||
|
||||
if (in_array($this->_action, $requireLogin) || $this->requireLogin == array('*')) {
|
||||
$login = $this->loginCredentials($this->loginOptions['type']);
|
||||
|
||||
if ($login == null) {
|
||||
$controller->header($this->loginRequest());
|
||||
|
||||
if (!empty($this->loginOptions['prompt'])) {
|
||||
$this->_callback($controller, $this->loginOptions['prompt']);
|
||||
} else {
|
||||
$this->blackHole($controller, 'login');
|
||||
}
|
||||
} else {
|
||||
if (isset($this->loginOptions['login'])) {
|
||||
$this->_callback($controller, $this->loginOptions['login'], array($login));
|
||||
} else {
|
||||
if (strtolower($this->loginOptions['type']) == 'digest') {
|
||||
if ($login && isset($this->loginUsers[$login['username']])) {
|
||||
if ($login['response'] == $this->generateDigestResponseHash($login)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->blackHole($controller, 'login');
|
||||
} else {
|
||||
if (
|
||||
!(in_array($login['username'], array_keys($this->loginUsers)) &&
|
||||
$this->loginUsers[$login['username']] == $login['password'])
|
||||
) {
|
||||
$this->blackHole($controller, 'login');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate submitted form
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool true if submitted form is valid
|
||||
* @access protected
|
||||
*/
|
||||
function _validatePost(&$controller) {
|
||||
if (empty($controller->data)) {
|
||||
return true;
|
||||
}
|
||||
$data = $controller->data;
|
||||
|
||||
if (!isset($data['_Token']) || !isset($data['_Token']['fields']) || !isset($data['_Token']['key'])) {
|
||||
return false;
|
||||
}
|
||||
$token = $data['_Token']['key'];
|
||||
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tokenData = unserialize($this->Session->read('_Token'));
|
||||
|
||||
if ($tokenData['expires'] < time() || $tokenData['key'] !== $token) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$locked = null;
|
||||
$check = $controller->data;
|
||||
$token = urldecode($check['_Token']['fields']);
|
||||
|
||||
if (strpos($token, ':')) {
|
||||
list($token, $locked) = explode(':', $token, 2);
|
||||
}
|
||||
unset($check['_Token']);
|
||||
|
||||
$locked = str_rot13($locked);
|
||||
if (preg_match('/(\A|;|{|})O\:[0-9]+/', $locked)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lockedFields = array();
|
||||
$fields = Set::flatten($check);
|
||||
$fieldList = array_keys($fields);
|
||||
$locked = unserialize($locked);
|
||||
$multi = array();
|
||||
|
||||
foreach ($fieldList as $i => $key) {
|
||||
if (preg_match('/\.\d+$/', $key)) {
|
||||
$multi[$i] = preg_replace('/\.\d+$/', '', $key);
|
||||
unset($fieldList[$i]);
|
||||
}
|
||||
}
|
||||
if (!empty($multi)) {
|
||||
$fieldList += array_unique($multi);
|
||||
}
|
||||
|
||||
foreach ($fieldList as $i => $key) {
|
||||
$isDisabled = false;
|
||||
$isLocked = (is_array($locked) && in_array($key, $locked));
|
||||
|
||||
if (!empty($this->disabledFields)) {
|
||||
foreach ((array)$this->disabledFields as $disabled) {
|
||||
$disabled = explode('.', $disabled);
|
||||
$field = array_values(array_intersect(explode('.', $key), $disabled));
|
||||
$isDisabled = ($field === $disabled);
|
||||
if ($isDisabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isDisabled || $isLocked) {
|
||||
unset($fieldList[$i]);
|
||||
if ($isLocked) {
|
||||
$lockedFields[$key] = $fields[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($fieldList, SORT_STRING);
|
||||
ksort($lockedFields, SORT_STRING);
|
||||
|
||||
$fieldList += $lockedFields;
|
||||
$check = Security::hash(serialize($fieldList) . Configure::read('Security.salt'));
|
||||
return ($token === $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add authentication key for new form posts
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return bool Success
|
||||
* @access protected
|
||||
*/
|
||||
function _generateToken(&$controller) {
|
||||
if (isset($controller->params['requested']) && $controller->params['requested'] === 1) {
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tokenData = unserialize($this->Session->read('_Token'));
|
||||
$controller->params['_Token'] = $tokenData;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$authKey = Security::generateAuthKey();
|
||||
$expires = strtotime('+' . Security::inactiveMins() . ' minutes');
|
||||
$token = array(
|
||||
'key' => $authKey,
|
||||
'expires' => $expires,
|
||||
'allowedControllers' => $this->allowedControllers,
|
||||
'allowedActions' => $this->allowedActions,
|
||||
'disabledFields' => $this->disabledFields
|
||||
);
|
||||
|
||||
if (!isset($controller->data)) {
|
||||
$controller->data = array();
|
||||
}
|
||||
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tokenData = unserialize($this->Session->read('_Token'));
|
||||
$valid = (
|
||||
isset($tokenData['expires']) &&
|
||||
$tokenData['expires'] > time() &&
|
||||
isset($tokenData['key'])
|
||||
);
|
||||
|
||||
if ($valid) {
|
||||
$token['key'] = $tokenData['key'];
|
||||
}
|
||||
}
|
||||
$controller->params['_Token'] = $token;
|
||||
$this->Session->write('_Token', serialize($token));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default login options for an HTTP-authenticated request
|
||||
*
|
||||
* @param array $options Default login options
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _setLoginDefaults(&$options) {
|
||||
$options = array_merge(array(
|
||||
'type' => 'basic',
|
||||
'realm' => env('SERVER_NAME'),
|
||||
'qop' => 'auth',
|
||||
'nonce' => String::uuid()
|
||||
), array_filter($options));
|
||||
$options = array_merge(array('opaque' => md5($options['realm'])), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a controller callback method
|
||||
*
|
||||
* @param object $controller Controller to run callback on
|
||||
* @param string $method Method to execute
|
||||
* @param array $params Parameters to send to method
|
||||
* @return mixed Controller callback method's response
|
||||
* @access protected
|
||||
*/
|
||||
function _callback(&$controller, $method, $params = array()) {
|
||||
if (is_callable(array($controller, $method))) {
|
||||
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
295
web-cake/html/cake/libs/controller/components/session.php
Normal file
295
web-cake/html/cake/libs/controller/components/session.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
/**
|
||||
* SessionComponent. Provides access to Sessions from the Controller layer
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @since CakePHP(tm) v 0.10.0.1232
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
if (!class_exists('cakesession')) {
|
||||
require LIBS . 'cake_session.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Session Component.
|
||||
*
|
||||
* Session handling from the controller.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
* @link http://book.cakephp.org/view/1310/Sessions
|
||||
*
|
||||
*/
|
||||
class SessionComponent extends CakeSession {
|
||||
|
||||
/**
|
||||
* Used to determine if methods implementation is used, or bypassed
|
||||
*
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $__active = true;
|
||||
|
||||
/**
|
||||
* Used to determine if request are from an Ajax request
|
||||
*
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $__bare = 0;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $base The base path for the Session
|
||||
*/
|
||||
function __construct($base = null) {
|
||||
if (Configure::read('Session.start') === true) {
|
||||
parent::__construct($base);
|
||||
} else {
|
||||
$this->__active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup method.
|
||||
*
|
||||
* @param object $controller Instantiating controller
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function startup(&$controller) {
|
||||
if ($this->started() === false && $this->__active === true) {
|
||||
$this->__start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts Session on if 'Session.start' is set to false in core.php
|
||||
*
|
||||
* @param string $base The base path for the Session
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function activate($base = null) {
|
||||
if ($this->__active === true) {
|
||||
return;
|
||||
}
|
||||
parent::__construct($base);
|
||||
$this->__active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to write a value to a session key.
|
||||
*
|
||||
* In your controller: $this->Session->write('Controller.sessKey', 'session value');
|
||||
*
|
||||
* @param string $name The name of the key your are setting in the session.
|
||||
* This should be in a Controller.key format for better organizing
|
||||
* @param string $value The value you want to store in a session.
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1312/write
|
||||
*/
|
||||
function write($name, $value = null) {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $key => $value) {
|
||||
if (parent::write($key, $value) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (parent::write($name, $value) === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read a session values for a key or return values for all keys.
|
||||
*
|
||||
* In your controller: $this->Session->read('Controller.sessKey');
|
||||
* Calling the method without a param will return all session vars
|
||||
*
|
||||
* @param string $name the name of the session key you want to read
|
||||
* @return mixed value from the session vars
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1314/read
|
||||
*/
|
||||
function read($name = null) {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
return parent::read($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for SessionComponent::del();
|
||||
*
|
||||
* In your controller: $this->Session->delete('Controller.sessKey');
|
||||
*
|
||||
* @param string $name the name of the session key you want to delete
|
||||
* @return boolean true is session variable is set and can be deleted, false is variable was not set.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1316/delete
|
||||
*/
|
||||
function delete($name) {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
return parent::delete($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if a session variable is set
|
||||
*
|
||||
* In your controller: $this->Session->check('Controller.sessKey');
|
||||
*
|
||||
* @param string $name the name of the session key you want to check
|
||||
* @return boolean true is session variable is set, false if not
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1315/check
|
||||
*/
|
||||
function check($name) {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
return parent::check($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the last error in a session.
|
||||
*
|
||||
* In your controller: $this->Session->error();
|
||||
*
|
||||
* @return string Last session error
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1318/error
|
||||
*/
|
||||
function error() {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
return parent::error();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to set a session variable that can be used to output messages in the view.
|
||||
*
|
||||
* In your controller: $this->Session->setFlash('This has been saved');
|
||||
*
|
||||
* Additional params below can be passed to customize the output, or the Message.[key]
|
||||
*
|
||||
* @param string $message Message to be flashed
|
||||
* @param string $element Element to wrap flash message in.
|
||||
* @param array $params Parameters to be sent to layout as view variables
|
||||
* @param string $key Message key, default is 'flash'
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1313/setFlash
|
||||
*/
|
||||
function setFlash($message, $element = 'default', $params = array(), $key = 'flash') {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
$this->write('Message.' . $key, compact('message', 'element', 'params'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to renew a session id
|
||||
*
|
||||
* In your controller: $this->Session->renew();
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function renew() {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
parent::renew();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check for a valid session.
|
||||
*
|
||||
* In your controller: $this->Session->valid();
|
||||
*
|
||||
* @return boolean true is session is valid, false is session is invalid
|
||||
* @access public
|
||||
*/
|
||||
function valid() {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
return parent::valid();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to destroy sessions
|
||||
*
|
||||
* In your controller: $this->Session->destroy();
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1317/destroy
|
||||
*/
|
||||
function destroy() {
|
||||
if ($this->__active === true) {
|
||||
$this->__start();
|
||||
parent::destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Session id
|
||||
*
|
||||
* If $id is passed in a beforeFilter, the Session will be started
|
||||
* with the specified id
|
||||
*
|
||||
* @param $id string
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function id($id = null) {
|
||||
return parent::id($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts Session if SessionComponent is used in Controller::beforeFilter(),
|
||||
* or is called from
|
||||
*
|
||||
* @return boolean
|
||||
* @access private
|
||||
*/
|
||||
function __start() {
|
||||
if ($this->started() === false) {
|
||||
if (!$this->id() && parent::start()) {
|
||||
parent::_checkValid();
|
||||
} else {
|
||||
parent::start();
|
||||
}
|
||||
}
|
||||
return $this->started();
|
||||
}
|
||||
}
|
||||
1324
web-cake/html/cake/libs/controller/controller.php
Normal file
1324
web-cake/html/cake/libs/controller/controller.php
Normal file
File diff suppressed because it is too large
Load Diff
85
web-cake/html/cake/libs/controller/pages_controller.php
Normal file
85
web-cake/html/cake/libs/controller/pages_controller.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Static content controller.
|
||||
*
|
||||
* This file will render views from views/pages/
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static content controller
|
||||
*
|
||||
* Override this controller by placing a copy in controllers directory of an application
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @link http://book.cakephp.org/view/958/The-Pages-Controller
|
||||
*/
|
||||
class PagesController extends AppController {
|
||||
|
||||
/**
|
||||
* Controller name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'Pages';
|
||||
|
||||
/**
|
||||
* Default helper
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $helpers = array('Html', 'Session');
|
||||
|
||||
/**
|
||||
* This controller does not use a model
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $uses = array();
|
||||
|
||||
/**
|
||||
* Displays a view
|
||||
*
|
||||
* @param mixed What page to display
|
||||
* @access public
|
||||
*/
|
||||
function display() {
|
||||
$path = func_get_args();
|
||||
|
||||
$count = count($path);
|
||||
if (!$count) {
|
||||
$this->redirect('/');
|
||||
}
|
||||
$page = $subpage = $title_for_layout = null;
|
||||
|
||||
if (!empty($path[0])) {
|
||||
$page = $path[0];
|
||||
}
|
||||
if (!empty($path[1])) {
|
||||
$subpage = $path[1];
|
||||
}
|
||||
if (!empty($path[$count - 1])) {
|
||||
$title_for_layout = Inflector::humanize($path[$count - 1]);
|
||||
}
|
||||
$this->set(compact('page', 'subpage', 'title_for_layout'));
|
||||
$this->render(implode('/', $path));
|
||||
}
|
||||
}
|
||||
613
web-cake/html/cake/libs/controller/scaffold.php
Normal file
613
web-cake/html/cake/libs/controller/scaffold.php
Normal file
@@ -0,0 +1,613 @@
|
||||
<?php
|
||||
/**
|
||||
* Scaffold.
|
||||
*
|
||||
* Automatic forms and actions generation for rapid web application development.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
* @since Cake v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scaffolding is a set of automatic actions for starting web development work faster.
|
||||
*
|
||||
* Scaffold inspects your database tables, and making educated guesses, sets up a
|
||||
* number of pages for each of your Models. These pages have data forms that work,
|
||||
* and afford the web developer an early look at the data, and the possibility to over-ride
|
||||
* scaffolded actions with custom-made ones.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
*/
|
||||
class Scaffold extends Object {
|
||||
|
||||
/**
|
||||
* Controller object
|
||||
*
|
||||
* @var Controller
|
||||
* @access public
|
||||
*/
|
||||
var $controller = null;
|
||||
|
||||
/**
|
||||
* Name of the controller to scaffold
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = null;
|
||||
|
||||
/**
|
||||
* Action to be performed.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $action = null;
|
||||
|
||||
/**
|
||||
* Name of current model this view context is attached to
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $model = null;
|
||||
|
||||
/**
|
||||
* Path to View.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $viewPath;
|
||||
|
||||
/**
|
||||
* Path parts for creating links in views.
|
||||
*
|
||||
* @var string Base URL
|
||||
* @access public
|
||||
*/
|
||||
var $base = null;
|
||||
|
||||
/**
|
||||
* Name of layout to use with this View.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $layout = 'default';
|
||||
|
||||
/**
|
||||
* Array of parameter data
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $params;
|
||||
|
||||
/**
|
||||
* File extension. Defaults to Cake's template ".ctp".
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $ext = '.ctp';
|
||||
|
||||
/**
|
||||
* Sub-directory for this view file.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $subDir = null;
|
||||
|
||||
/**
|
||||
* Plugin name.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $plugin = null;
|
||||
|
||||
/**
|
||||
* valid session.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $_validSession = null;
|
||||
|
||||
/**
|
||||
* List of variables to collect from the associated controller
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__passedVars = array(
|
||||
'action', 'base', 'webroot', 'layout', 'name',
|
||||
'viewPath', 'ext', 'params', 'data', 'plugin', 'cacheAction'
|
||||
);
|
||||
|
||||
/**
|
||||
* Title HTML element for current scaffolded view
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $scaffoldTitle = null;
|
||||
|
||||
/**
|
||||
* Construct and set up given controller with given parameters.
|
||||
*
|
||||
* @param string $controller_class Name of controller
|
||||
* @param array $params Parameters for scaffolding
|
||||
*/
|
||||
function __construct(&$controller, $params) {
|
||||
$this->controller =& $controller;
|
||||
|
||||
$count = count($this->__passedVars);
|
||||
for ($j = 0; $j < $count; $j++) {
|
||||
$var = $this->__passedVars[$j];
|
||||
$this->{$var} = $controller->{$var};
|
||||
}
|
||||
|
||||
$this->redirect = array('action' => 'index');
|
||||
|
||||
$this->modelClass = $controller->modelClass;
|
||||
$this->modelKey = $controller->modelKey;
|
||||
|
||||
if (!is_object($this->controller->{$this->modelClass})) {
|
||||
return $this->cakeError('missingModel', array(array(
|
||||
'className' => $this->modelClass, 'webroot' => '', 'base' => $controller->base
|
||||
)));
|
||||
}
|
||||
|
||||
$this->ScaffoldModel =& $this->controller->{$this->modelClass};
|
||||
$this->scaffoldTitle = Inflector::humanize($this->viewPath);
|
||||
$this->scaffoldActions = $controller->scaffold;
|
||||
$title_for_layout = __('Scaffold :: ', true) . Inflector::humanize($this->action) . ' :: ' . $this->scaffoldTitle;
|
||||
$modelClass = $this->controller->modelClass;
|
||||
$primaryKey = $this->ScaffoldModel->primaryKey;
|
||||
$displayField = $this->ScaffoldModel->displayField;
|
||||
$singularVar = Inflector::variable($modelClass);
|
||||
$pluralVar = Inflector::variable($this->controller->name);
|
||||
$singularHumanName = Inflector::humanize(Inflector::underscore($modelClass));
|
||||
$pluralHumanName = Inflector::humanize(Inflector::underscore($this->controller->name));
|
||||
$scaffoldFields = array_keys($this->ScaffoldModel->schema());
|
||||
$associations = $this->__associations();
|
||||
|
||||
$this->controller->set(compact(
|
||||
'title_for_layout', 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
|
||||
'singularHumanName', 'pluralHumanName', 'scaffoldFields', 'associations'
|
||||
));
|
||||
|
||||
if ($this->controller->view) {
|
||||
$this->controller->view = 'Scaffold';
|
||||
}
|
||||
$this->_validSession = (
|
||||
isset($this->controller->Session) && $this->controller->Session->valid() != false
|
||||
);
|
||||
$this->__scaffold($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a scaffold method passing it through the Controller::afterFilter()
|
||||
*
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _output() {
|
||||
$this->controller->afterFilter();
|
||||
echo($this->controller->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view action of scaffolded model.
|
||||
*
|
||||
* @param array $params Parameters for scaffolding
|
||||
* @return mixed A rendered view of a row from Models database table
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldView($params) {
|
||||
if ($this->controller->_beforeScaffold('view')) {
|
||||
|
||||
$message = __(sprintf("No id set for %s::view()", Inflector::humanize($this->modelKey)), true);
|
||||
if (isset($params['pass'][0])) {
|
||||
$this->ScaffoldModel->id = $params['pass'][0];
|
||||
} elseif ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
return $this->controller->flash($message, '/' . Inflector::underscore($this->controller->viewPath));
|
||||
}
|
||||
$this->ScaffoldModel->recursive = 1;
|
||||
$this->controller->data = $this->ScaffoldModel->read();
|
||||
$this->controller->set(
|
||||
Inflector::variable($this->controller->modelClass), $this->controller->data
|
||||
);
|
||||
$this->controller->render($this->action, $this->layout);
|
||||
$this->_output();
|
||||
} elseif ($this->controller->_scaffoldError('view') === false) {
|
||||
return $this->__scaffoldError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders index action of scaffolded model.
|
||||
*
|
||||
* @param array $params Parameters for scaffolding
|
||||
* @return mixed A rendered view listing rows from Models database table
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldIndex($params) {
|
||||
if ($this->controller->_beforeScaffold('index')) {
|
||||
$this->ScaffoldModel->recursive = 0;
|
||||
$this->controller->set(
|
||||
Inflector::variable($this->controller->name), $this->controller->paginate()
|
||||
);
|
||||
$this->controller->render($this->action, $this->layout);
|
||||
$this->_output();
|
||||
} elseif ($this->controller->_scaffoldError('index') === false) {
|
||||
return $this->__scaffoldError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an add or edit action for scaffolded model.
|
||||
*
|
||||
* @param string $action Action (add or edit)
|
||||
* @return mixed A rendered view with a form to edit or add a record in the Models database table
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldForm($action = 'edit') {
|
||||
$this->controller->viewVars['scaffoldFields'] = array_merge(
|
||||
$this->controller->viewVars['scaffoldFields'],
|
||||
array_keys($this->ScaffoldModel->hasAndBelongsToMany)
|
||||
);
|
||||
$this->controller->render($action, $this->layout);
|
||||
$this->_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves or updates the scaffolded model.
|
||||
*
|
||||
* @param array $params Parameters for scaffolding
|
||||
* @param string $action add or edt
|
||||
* @return mixed Success on save/update, add/edit form if data is empty or error if save or update fails
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldSave($params = array(), $action = 'edit') {
|
||||
$formAction = 'edit';
|
||||
$success = __('updated', true);
|
||||
if ($action === 'add') {
|
||||
$formAction = 'add';
|
||||
$success = __('saved', true);
|
||||
}
|
||||
|
||||
if ($this->controller->_beforeScaffold($action)) {
|
||||
if ($action == 'edit') {
|
||||
if (isset($params['pass'][0])) {
|
||||
$this->ScaffoldModel->id = $params['pass'][0];
|
||||
}
|
||||
|
||||
if (!$this->ScaffoldModel->exists()) {
|
||||
$message = __(sprintf("Invalid id for %s::edit()", Inflector::humanize($this->modelKey), true));
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
$this->_output();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->controller->data)) {
|
||||
if ($action == 'create') {
|
||||
$this->ScaffoldModel->create();
|
||||
}
|
||||
|
||||
if ($this->ScaffoldModel->save($this->controller->data)) {
|
||||
if ($this->controller->_afterScaffoldSave($action)) {
|
||||
$message = __(
|
||||
sprintf('The %1$s has been %2$s', Inflector::humanize($this->modelKey), $success),
|
||||
true
|
||||
);
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
return $this->_output();
|
||||
}
|
||||
} else {
|
||||
return $this->controller->_afterScaffoldSaveError($action);
|
||||
}
|
||||
} else {
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash(__('Please correct errors below.', true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->controller->data)) {
|
||||
if ($this->ScaffoldModel->id) {
|
||||
$this->controller->data = $this->ScaffoldModel->read();
|
||||
} else {
|
||||
$this->controller->data = $this->ScaffoldModel->create();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->ScaffoldModel->belongsTo as $assocName => $assocData) {
|
||||
$varName = Inflector::variable(Inflector::pluralize(
|
||||
preg_replace('/(?:_id)$/', '', $assocData['foreignKey'])
|
||||
));
|
||||
$this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));
|
||||
}
|
||||
foreach ($this->ScaffoldModel->hasAndBelongsToMany as $assocName => $assocData) {
|
||||
$varName = Inflector::variable(Inflector::pluralize($assocName));
|
||||
$this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));
|
||||
}
|
||||
|
||||
return $this->__scaffoldForm($formAction);
|
||||
} elseif ($this->controller->_scaffoldError($action) === false) {
|
||||
return $this->__scaffoldError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a delete on given scaffolded Model.
|
||||
*
|
||||
* @param array $params Parameters for scaffolding
|
||||
* @return mixed Success on delete, error if delete fails
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldDelete($params = array()) {
|
||||
if ($this->controller->_beforeScaffold('delete')) {
|
||||
$message = __(
|
||||
sprintf("No id set for %s::delete()", Inflector::humanize($this->modelKey)), true
|
||||
);
|
||||
if (isset($params['pass'][0])) {
|
||||
$id = $params['pass'][0];
|
||||
} elseif ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
return $this->_output();
|
||||
}
|
||||
|
||||
if ($this->ScaffoldModel->delete($id)) {
|
||||
$message = __(
|
||||
sprintf('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id),
|
||||
true
|
||||
);
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
return $this->_output();
|
||||
}
|
||||
} else {
|
||||
$message = __(sprintf(
|
||||
'There was an error deleting the %1$s with id: %2$d',
|
||||
Inflector::humanize($this->modelClass), $id
|
||||
), true);
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
return $this->_output();
|
||||
}
|
||||
}
|
||||
} elseif ($this->controller->_scaffoldError('delete') === false) {
|
||||
return $this->__scaffoldError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a scaffold error
|
||||
*
|
||||
* @return mixed A rendered view showing the error
|
||||
* @access private
|
||||
*/
|
||||
function __scaffoldError() {
|
||||
return $this->controller->render('error', $this->layout);
|
||||
$this->_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* When methods are now present in a controller
|
||||
* scaffoldView is used to call default Scaffold methods if:
|
||||
* `var $scaffold;` is placed in the controller's class definition.
|
||||
*
|
||||
* @param array $params Parameters for scaffolding
|
||||
* @return mixed A rendered view of scaffold action, or showing the error
|
||||
* @access private
|
||||
*/
|
||||
function __scaffold($params) {
|
||||
$db = &ConnectionManager::getDataSource($this->ScaffoldModel->useDbConfig);
|
||||
$prefixes = Configure::read('Routing.prefixes');
|
||||
$scaffoldPrefix = $this->scaffoldActions;
|
||||
|
||||
if (isset($db)) {
|
||||
if (empty($this->scaffoldActions)) {
|
||||
$this->scaffoldActions = array(
|
||||
'index', 'list', 'view', 'add', 'create', 'edit', 'update', 'delete'
|
||||
);
|
||||
} elseif (!empty($prefixes) && in_array($scaffoldPrefix, $prefixes)) {
|
||||
$this->scaffoldActions = array(
|
||||
$scaffoldPrefix . '_index',
|
||||
$scaffoldPrefix . '_list',
|
||||
$scaffoldPrefix . '_view',
|
||||
$scaffoldPrefix . '_add',
|
||||
$scaffoldPrefix . '_create',
|
||||
$scaffoldPrefix . '_edit',
|
||||
$scaffoldPrefix . '_update',
|
||||
$scaffoldPrefix . '_delete'
|
||||
);
|
||||
}
|
||||
|
||||
if (in_array($params['action'], $this->scaffoldActions)) {
|
||||
if (!empty($prefixes)) {
|
||||
$params['action'] = str_replace($scaffoldPrefix . '_', '', $params['action']);
|
||||
}
|
||||
switch ($params['action']) {
|
||||
case 'index':
|
||||
case 'list':
|
||||
$this->__scaffoldIndex($params);
|
||||
break;
|
||||
case 'view':
|
||||
$this->__scaffoldView($params);
|
||||
break;
|
||||
case 'add':
|
||||
case 'create':
|
||||
$this->__scaffoldSave($params, 'add');
|
||||
break;
|
||||
case 'edit':
|
||||
case 'update':
|
||||
$this->__scaffoldSave($params, 'edit');
|
||||
break;
|
||||
case 'delete':
|
||||
$this->__scaffoldDelete($params);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return $this->cakeError('missingAction', array(array(
|
||||
'className' => $this->controller->name . "Controller",
|
||||
'base' => $this->controller->base,
|
||||
'action' => $this->action,
|
||||
'webroot' => $this->controller->webroot
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return $this->cakeError('missingDatabase', array(array(
|
||||
'webroot' => $this->controller->webroot
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns associations for controllers models.
|
||||
*
|
||||
* @return array Associations for model
|
||||
* @access private
|
||||
*/
|
||||
function __associations() {
|
||||
$keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
|
||||
$associations = array();
|
||||
|
||||
foreach ($keys as $key => $type) {
|
||||
foreach ($this->ScaffoldModel->{$type} as $assocKey => $assocData) {
|
||||
$associations[$type][$assocKey]['primaryKey'] =
|
||||
$this->ScaffoldModel->{$assocKey}->primaryKey;
|
||||
|
||||
$associations[$type][$assocKey]['displayField'] =
|
||||
$this->ScaffoldModel->{$assocKey}->displayField;
|
||||
|
||||
$associations[$type][$assocKey]['foreignKey'] =
|
||||
$assocData['foreignKey'];
|
||||
|
||||
$associations[$type][$assocKey]['controller'] =
|
||||
Inflector::pluralize(Inflector::underscore($assocData['className']));
|
||||
|
||||
if ($type == 'hasAndBelongsToMany') {
|
||||
$associations[$type][$assocKey]['with'] = $assocData['with'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $associations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scaffold View.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller
|
||||
*/
|
||||
if (!class_exists('ThemeView')) {
|
||||
App::import('View', 'Theme');
|
||||
}
|
||||
|
||||
/**
|
||||
* ScaffoldView provides specific view file loading features for scaffolded views.
|
||||
*
|
||||
* @package cake.libs.view
|
||||
*/
|
||||
class ScaffoldView extends ThemeView {
|
||||
|
||||
/**
|
||||
* Override _getViewFileName Appends special scaffolding views in.
|
||||
*
|
||||
* @param string $name name of the view file to get.
|
||||
* @return string action
|
||||
* @access protected
|
||||
*/
|
||||
function _getViewFileName($name = null) {
|
||||
if ($name === null) {
|
||||
$name = $this->action;
|
||||
}
|
||||
$name = Inflector::underscore($name);
|
||||
$prefixes = Configure::read('Routing.prefixes');
|
||||
|
||||
if (!empty($prefixes)) {
|
||||
foreach ($prefixes as $prefix) {
|
||||
if (strpos($name, $prefix . '_') !== false) {
|
||||
$name = substr($name, strlen($prefix) + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($name === 'add') {
|
||||
$name = 'edit';
|
||||
}
|
||||
|
||||
$scaffoldAction = 'scaffold.' . $name;
|
||||
|
||||
if (!is_null($this->subDir)) {
|
||||
$subDir = strtolower($this->subDir) . DS;
|
||||
} else {
|
||||
$subDir = null;
|
||||
}
|
||||
|
||||
$names[] = $this->viewPath . DS . $subDir . $scaffoldAction;
|
||||
$names[] = 'scaffolds' . DS . $subDir . $name;
|
||||
|
||||
$paths = $this->_paths($this->plugin);
|
||||
$exts = array($this->ext);
|
||||
if ($this->ext !== '.ctp') {
|
||||
array_push($exts, '.ctp');
|
||||
}
|
||||
foreach ($exts as $ext) {
|
||||
foreach ($paths as $path) {
|
||||
foreach ($names as $name) {
|
||||
if (file_exists($path . $name . $ext)) {
|
||||
return $path . $name . $ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($name === 'scaffolds' . DS . $subDir . 'error') {
|
||||
return LIBS . 'view' . DS . 'errors' . DS . 'scaffold_error.ctp';
|
||||
}
|
||||
|
||||
return $this->_missingView($paths[0] . $name . $this->ext, 'missingView');
|
||||
}
|
||||
}
|
||||
708
web-cake/html/cake/libs/debugger.php
Normal file
708
web-cake/html/cake/libs/debugger.php
Normal file
@@ -0,0 +1,708 @@
|
||||
<?php
|
||||
/**
|
||||
* Framework debugging and PHP error-handling class
|
||||
*
|
||||
* Provides enhanced logging, stack traces, and rendering debug views
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.4560
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libraries.
|
||||
*
|
||||
*/
|
||||
if (!class_exists('Object')) {
|
||||
require_once LIBS . 'object.php';
|
||||
}
|
||||
if (!class_exists('CakeLog')) {
|
||||
require_once LIBS . 'cake_log.php';
|
||||
}
|
||||
if (!class_exists('String')) {
|
||||
require_once LIBS . 'string.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide custom logging and error handling.
|
||||
*
|
||||
* Debugger overrides PHP's default error handling to provide stack traces and enhanced logging
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
class Debugger extends Object {
|
||||
|
||||
/**
|
||||
* A list of errors generated by the application.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $errors = array();
|
||||
|
||||
/**
|
||||
* Contains the base URL for error code documentation.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $helpPath = null;
|
||||
|
||||
/**
|
||||
* The current output format.
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_outputFormat = 'js';
|
||||
|
||||
/**
|
||||
* Templates used when generating trace or error strings. Can be global or indexed by the format
|
||||
* value used in $_outputFormat.
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_templates = array(
|
||||
'log' => array(
|
||||
'trace' => '{:reference} - {:path}, line {:line}',
|
||||
'error' => "{:error} ({:code}): {:description} in [{:file}, line {:line}]"
|
||||
),
|
||||
'js' => array(
|
||||
'error' => '',
|
||||
'info' => '',
|
||||
'trace' => '<pre class="stack-trace">{:trace}</pre>',
|
||||
'code' => '',
|
||||
'context' => '',
|
||||
'links' => array()
|
||||
),
|
||||
'html' => array(
|
||||
'trace' => '<pre class="cake-debug trace"><b>Trace</b> <p>{:trace}</p></pre>',
|
||||
'context' => '<pre class="cake-debug context"><b>Context</b> <p>{:context}</p></pre>'
|
||||
),
|
||||
'txt' => array(
|
||||
'error' => "{:error}: {:code} :: {:description} on line {:line} of {:path}\n{:info}",
|
||||
'context' => "Context:\n{:context}\n",
|
||||
'trace' => "Trace:\n{:trace}\n",
|
||||
'code' => '',
|
||||
'info' => ''
|
||||
),
|
||||
'base' => array(
|
||||
'traceLine' => '{:reference} - {:path}, line {:line}'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds current output data when outputFormat is false.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $_data = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
$docRef = ini_get('docref_root');
|
||||
|
||||
if (empty($docRef) && function_exists('ini_set')) {
|
||||
ini_set('docref_root', 'http://php.net/');
|
||||
}
|
||||
if (!defined('E_RECOVERABLE_ERROR')) {
|
||||
define('E_RECOVERABLE_ERROR', 4096);
|
||||
}
|
||||
if (!defined('E_DEPRECATED')) {
|
||||
define('E_DEPRECATED', 8192);
|
||||
}
|
||||
|
||||
$e = '<pre class="cake-debug">';
|
||||
$e .= '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-trace\')';
|
||||
$e .= '.style.display = (document.getElementById(\'{:id}-trace\').style.display == ';
|
||||
$e .= '\'none\' ? \'\' : \'none\');"><b>{:error}</b> ({:code})</a>: {:description} ';
|
||||
$e .= '[<b>{:path}</b>, line <b>{:line}</b>]';
|
||||
|
||||
$e .= '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">';
|
||||
$e .= '{:links}{:info}</div>';
|
||||
$e .= '</pre>';
|
||||
$this->_templates['js']['error'] = $e;
|
||||
|
||||
$t = '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">';
|
||||
$t .= '{:context}{:code}{:trace}</div>';
|
||||
$this->_templates['js']['info'] = $t;
|
||||
|
||||
$links = array();
|
||||
$link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-code\')';
|
||||
$link .= '.style.display = (document.getElementById(\'{:id}-code\').style.display == ';
|
||||
$link .= '\'none\' ? \'\' : \'none\')">Code</a>';
|
||||
$links['code'] = $link;
|
||||
|
||||
$link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-context\')';
|
||||
$link .= '.style.display = (document.getElementById(\'{:id}-context\').style.display == ';
|
||||
$link .= '\'none\' ? \'\' : \'none\')">Context</a>';
|
||||
$links['context'] = $link;
|
||||
|
||||
$links['help'] = '<a href="{:helpPath}{:code}" target="_blank">Help</a>';
|
||||
$this->_templates['js']['links'] = $links;
|
||||
|
||||
$this->_templates['js']['context'] = '<pre id="{:id}-context" class="cake-context" ';
|
||||
$this->_templates['js']['context'] .= 'style="display: none;">{:context}</pre>';
|
||||
|
||||
$this->_templates['js']['code'] = '<div id="{:id}-code" class="cake-code-dump" ';
|
||||
$this->_templates['js']['code'] .= 'style="display: none;"><pre>{:code}</pre></div>';
|
||||
|
||||
$e = '<pre class="cake-debug"><b>{:error}</b> ({:code}) : {:description} ';
|
||||
$e .= '[<b>{:path}</b>, line <b>{:line}]</b></pre>';
|
||||
$this->_templates['html']['error'] = $e;
|
||||
|
||||
$this->_templates['html']['context'] = '<pre class="cake-debug context"><b>Context</b> ';
|
||||
$this->_templates['html']['context'] .= '<p>{:context}</p></pre>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the Debugger singleton object instance.
|
||||
*
|
||||
* @return object
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getInstance($class = null) {
|
||||
static $instance = array();
|
||||
if (!empty($class)) {
|
||||
if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) {
|
||||
$instance[0] = & new $class();
|
||||
if (Configure::read() > 0) {
|
||||
Configure::version(); // Make sure the core config is loaded
|
||||
$instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$instance) {
|
||||
$instance[0] =& new Debugger();
|
||||
if (Configure::read() > 0) {
|
||||
Configure::version(); // Make sure the core config is loaded
|
||||
$instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath');
|
||||
}
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and outputs the contents of the supplied variable.
|
||||
*
|
||||
* @param $var mixed the variable to dump
|
||||
* @return void
|
||||
* @see Debugger::exportVar()
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function dump($var) {
|
||||
$_this =& Debugger::getInstance();
|
||||
pr($_this->exportVar($var));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entry in the log file. The log entry will contain a stack trace from where it was called.
|
||||
* as well as export the variable using exportVar. By default the log is written to the debug log.
|
||||
*
|
||||
* @param $var mixed Variable or content to log
|
||||
* @param $level int type of log to use. Defaults to LOG_DEBUG
|
||||
* @return void
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function log($var, $level = LOG_DEBUG) {
|
||||
$_this =& Debugger::getInstance();
|
||||
$source = $_this->trace(array('start' => 1)) . "\n";
|
||||
CakeLog::write($level, "\n" . $source . $_this->exportVar($var));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides PHP's default error handling.
|
||||
*
|
||||
* @param integer $code Code of error
|
||||
* @param string $description Error description
|
||||
* @param string $file File on which error occurred
|
||||
* @param integer $line Line that triggered the error
|
||||
* @param array $context Context
|
||||
* @return boolean true if error was handled
|
||||
* @access public
|
||||
*/
|
||||
function handleError($code, $description, $file = null, $line = null, $context = null) {
|
||||
if (error_reporting() == 0 || $code === 2048 || $code === 8192) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_this =& Debugger::getInstance();
|
||||
|
||||
if (empty($file)) {
|
||||
$file = '[internal]';
|
||||
}
|
||||
if (empty($line)) {
|
||||
$line = '??';
|
||||
}
|
||||
$path = $_this->trimPath($file);
|
||||
|
||||
$info = compact('code', 'description', 'file', 'line');
|
||||
if (!in_array($info, $_this->errors)) {
|
||||
$_this->errors[] = $info;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($code) {
|
||||
case E_PARSE:
|
||||
case E_ERROR:
|
||||
case E_CORE_ERROR:
|
||||
case E_COMPILE_ERROR:
|
||||
case E_USER_ERROR:
|
||||
$error = 'Fatal Error';
|
||||
$level = LOG_ERROR;
|
||||
break;
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_RECOVERABLE_ERROR:
|
||||
$error = 'Warning';
|
||||
$level = LOG_WARNING;
|
||||
break;
|
||||
case E_NOTICE:
|
||||
case E_USER_NOTICE:
|
||||
$error = 'Notice';
|
||||
$level = LOG_NOTICE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
$helpCode = null;
|
||||
if (!empty($_this->helpPath) && preg_match('/.*\[([0-9]+)\]$/', $description, $codes)) {
|
||||
if (isset($codes[1])) {
|
||||
$helpID = $codes[1];
|
||||
$description = trim(preg_replace('/\[[0-9]+\]$/', '', $description));
|
||||
}
|
||||
}
|
||||
|
||||
$data = compact(
|
||||
'level', 'error', 'code', 'helpID', 'description', 'file', 'path', 'line', 'context'
|
||||
);
|
||||
echo $_this->_output($data);
|
||||
|
||||
if (Configure::read('log')) {
|
||||
$tpl = $_this->_templates['log']['error'];
|
||||
$options = array('before' => '{:', 'after' => '}');
|
||||
CakeLog::write($level, String::insert($tpl, $data, $options));
|
||||
}
|
||||
|
||||
if ($error == 'Fatal Error') {
|
||||
exit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a stack trace based on the supplied options.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `depth` - The number of stack frames to return. Defaults to 999
|
||||
* - `format` - The format you want the return. Defaults to the currently selected format. If
|
||||
* format is 'array' or 'points' the return will be an array.
|
||||
* - `args` - Should arguments for functions be shown? If true, the arguments for each method call
|
||||
* will be displayed.
|
||||
* - `start` - The stack frame to start generating a trace from. Defaults to 0
|
||||
*
|
||||
* @param array $options Format for outputting stack trace
|
||||
* @return mixed Formatted stack trace
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function trace($options = array()) {
|
||||
$_this =& Debugger::getInstance();
|
||||
$defaults = array(
|
||||
'depth' => 999,
|
||||
'format' => $_this->_outputFormat,
|
||||
'args' => false,
|
||||
'start' => 0,
|
||||
'scope' => null,
|
||||
'exclude' => null
|
||||
);
|
||||
$options += $defaults;
|
||||
|
||||
$backtrace = debug_backtrace();
|
||||
$count = count($backtrace);
|
||||
$back = array();
|
||||
|
||||
$_trace = array(
|
||||
'line' => '??',
|
||||
'file' => '[internal]',
|
||||
'class' => null,
|
||||
'function' => '[main]'
|
||||
);
|
||||
|
||||
for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) {
|
||||
$trace = array_merge(array('file' => '[internal]', 'line' => '??'), $backtrace[$i]);
|
||||
|
||||
if (isset($backtrace[$i + 1])) {
|
||||
$next = array_merge($_trace, $backtrace[$i + 1]);
|
||||
$reference = $next['function'];
|
||||
|
||||
if (!empty($next['class'])) {
|
||||
$reference = $next['class'] . '::' . $reference . '(';
|
||||
if ($options['args'] && isset($next['args'])) {
|
||||
$args = array();
|
||||
foreach ($next['args'] as $arg) {
|
||||
$args[] = Debugger::exportVar($arg);
|
||||
}
|
||||
$reference .= join(', ', $args);
|
||||
}
|
||||
$reference .= ')';
|
||||
}
|
||||
} else {
|
||||
$reference = '[main]';
|
||||
}
|
||||
if (in_array($reference, array('call_user_func_array', 'trigger_error'))) {
|
||||
continue;
|
||||
}
|
||||
if ($options['format'] == 'points' && $trace['file'] != '[internal]') {
|
||||
$back[] = array('file' => $trace['file'], 'line' => $trace['line']);
|
||||
} elseif ($options['format'] == 'array') {
|
||||
$back[] = $trace;
|
||||
} else {
|
||||
if (isset($_this->_templates[$options['format']]['traceLine'])) {
|
||||
$tpl = $_this->_templates[$options['format']]['traceLine'];
|
||||
} else {
|
||||
$tpl = $_this->_templates['base']['traceLine'];
|
||||
}
|
||||
$trace['path'] = Debugger::trimPath($trace['file']);
|
||||
$trace['reference'] = $reference;
|
||||
unset($trace['object'], $trace['args']);
|
||||
$back[] = String::insert($tpl, $trace, array('before' => '{:', 'after' => '}'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['format'] == 'array' || $options['format'] == 'points') {
|
||||
return $back;
|
||||
}
|
||||
return implode("\n", $back);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortens file paths by replacing the application base path with 'APP', and the CakePHP core
|
||||
* path with 'CORE'.
|
||||
*
|
||||
* @param string $path Path to shorten
|
||||
* @return string Normalized path
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function trimPath($path) {
|
||||
if (!defined('CAKE_CORE_INCLUDE_PATH') || !defined('APP')) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if (strpos($path, APP) === 0) {
|
||||
return str_replace(APP, 'APP' . DS, $path);
|
||||
} elseif (strpos($path, CAKE_CORE_INCLUDE_PATH) === 0) {
|
||||
return str_replace(CAKE_CORE_INCLUDE_PATH, 'CORE', $path);
|
||||
} elseif (strpos($path, ROOT) === 0) {
|
||||
return str_replace(ROOT, 'ROOT', $path);
|
||||
}
|
||||
$corePaths = App::core('cake');
|
||||
|
||||
foreach ($corePaths as $corePath) {
|
||||
if (strpos($path, $corePath) === 0) {
|
||||
return str_replace($corePath, 'CORE' .DS . 'cake' .DS, $path);
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs an excerpt from a file and highlights a given line of code
|
||||
*
|
||||
* @param string $file Absolute path to a PHP file
|
||||
* @param integer $line Line number to highlight
|
||||
* @param integer $context Number of lines of context to extract above and below $line
|
||||
* @return array Set of lines highlighted
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function excerpt($file, $line, $context = 2) {
|
||||
$data = $lines = array();
|
||||
if (!file_exists($file)) {
|
||||
return array();
|
||||
}
|
||||
$data = @explode("\n", file_get_contents($file));
|
||||
|
||||
if (empty($data) || !isset($data[$line])) {
|
||||
return;
|
||||
}
|
||||
for ($i = $line - ($context + 1); $i < $line + $context; $i++) {
|
||||
if (!isset($data[$i])) {
|
||||
continue;
|
||||
}
|
||||
$string = str_replace(array("\r\n", "\n"), "", highlight_string($data[$i], true));
|
||||
if ($i == $line) {
|
||||
$lines[] = '<span class="code-highlight">' . $string . '</span>';
|
||||
} else {
|
||||
$lines[] = $string;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a variable to a string for debug output.
|
||||
*
|
||||
* @param string $var Variable to convert
|
||||
* @return string Variable as a formatted string
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function exportVar($var, $recursion = 0) {
|
||||
$_this =& Debugger::getInstance();
|
||||
switch (strtolower(gettype($var))) {
|
||||
case 'boolean':
|
||||
return ($var) ? 'true' : 'false';
|
||||
break;
|
||||
case 'integer':
|
||||
case 'double':
|
||||
return $var;
|
||||
break;
|
||||
case 'string':
|
||||
if (trim($var) == "") {
|
||||
return '""';
|
||||
}
|
||||
return '"' . h($var) . '"';
|
||||
break;
|
||||
case 'object':
|
||||
return get_class($var) . "\n" . $_this->__object($var);
|
||||
case 'array':
|
||||
$out = "array(";
|
||||
$vars = array();
|
||||
foreach ($var as $key => $val) {
|
||||
if ($recursion >= 0) {
|
||||
if (is_numeric($key)) {
|
||||
$vars[] = "\n\t" . $_this->exportVar($val, $recursion - 1);
|
||||
} else {
|
||||
$vars[] = "\n\t" .$_this->exportVar($key, $recursion - 1)
|
||||
. ' => ' . $_this->exportVar($val, $recursion - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
$n = null;
|
||||
if (!empty($vars)) {
|
||||
$n = "\n";
|
||||
}
|
||||
return $out . implode(",", $vars) . "{$n})";
|
||||
break;
|
||||
case 'resource':
|
||||
return strtolower(gettype($var));
|
||||
break;
|
||||
case 'null':
|
||||
return 'null';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles object to string conversion.
|
||||
*
|
||||
* @param string $var Object to convert
|
||||
* @return string
|
||||
* @access private
|
||||
* @see Debugger::exportVar()
|
||||
*/
|
||||
function __object($var) {
|
||||
$out = array();
|
||||
|
||||
if (is_object($var)) {
|
||||
$className = get_class($var);
|
||||
$objectVars = get_object_vars($var);
|
||||
|
||||
foreach ($objectVars as $key => $value) {
|
||||
if (is_object($value)) {
|
||||
$value = get_class($value) . ' object';
|
||||
} elseif (is_array($value)) {
|
||||
$value = 'array';
|
||||
} elseif ($value === null) {
|
||||
$value = 'NULL';
|
||||
} elseif (in_array(gettype($value), array('boolean', 'integer', 'double', 'string', 'array', 'resource'))) {
|
||||
$value = Debugger::exportVar($value);
|
||||
}
|
||||
$out[] = "$className::$$key = " . $value;
|
||||
}
|
||||
}
|
||||
return implode("\n", $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches output format, updates format strings
|
||||
*
|
||||
* @param string $format Format to use, including 'js' for JavaScript-enhanced HTML, 'html' for
|
||||
* straight HTML output, or 'txt' for unformatted text.
|
||||
* @param array $strings Template strings to be used for the output format.
|
||||
* @access protected
|
||||
*/
|
||||
function output($format = null, $strings = array()) {
|
||||
$_this =& Debugger::getInstance();
|
||||
$data = null;
|
||||
|
||||
if (is_null($format)) {
|
||||
return $_this->_outputFormat;
|
||||
}
|
||||
|
||||
if (!empty($strings)) {
|
||||
if (isset($_this->_templates[$format])) {
|
||||
if (isset($strings['links'])) {
|
||||
$_this->_templates[$format]['links'] = array_merge(
|
||||
$_this->_templates[$format]['links'],
|
||||
$strings['links']
|
||||
);
|
||||
unset($strings['links']);
|
||||
}
|
||||
$_this->_templates[$format] = array_merge($_this->_templates[$format], $strings);
|
||||
} else {
|
||||
$_this->_templates[$format] = $strings;
|
||||
}
|
||||
return $_this->_templates[$format];
|
||||
}
|
||||
|
||||
if ($format === true && !empty($_this->_data)) {
|
||||
$data = $_this->_data;
|
||||
$_this->_data = array();
|
||||
$format = false;
|
||||
}
|
||||
$_this->_outputFormat = $format;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders error messages
|
||||
*
|
||||
* @param array $data Data about the current error
|
||||
* @access private
|
||||
*/
|
||||
function _output($data = array()) {
|
||||
$defaults = array(
|
||||
'level' => 0,
|
||||
'error' => 0,
|
||||
'code' => 0,
|
||||
'helpID' => null,
|
||||
'description' => '',
|
||||
'file' => '',
|
||||
'line' => 0,
|
||||
'context' => array()
|
||||
);
|
||||
$data += $defaults;
|
||||
|
||||
$files = $this->trace(array('start' => 2, 'format' => 'points'));
|
||||
$code = $this->excerpt($files[0]['file'], $files[0]['line'] - 1, 1);
|
||||
$trace = $this->trace(array('start' => 2, 'depth' => '20'));
|
||||
$insertOpts = array('before' => '{:', 'after' => '}');
|
||||
$context = array();
|
||||
$links = array();
|
||||
$info = '';
|
||||
|
||||
foreach ((array)$data['context'] as $var => $value) {
|
||||
$context[] = "\${$var}\t=\t" . $this->exportVar($value, 1);
|
||||
}
|
||||
|
||||
switch ($this->_outputFormat) {
|
||||
case false:
|
||||
$this->_data[] = compact('context', 'trace') + $data;
|
||||
return;
|
||||
case 'log':
|
||||
$this->log(compact('context', 'trace') + $data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->_outputFormat) || !isset($this->_templates[$this->_outputFormat])) {
|
||||
$this->_outputFormat = 'js';
|
||||
}
|
||||
|
||||
$data['id'] = 'cakeErr' . count($this->errors);
|
||||
$tpl = array_merge($this->_templates['base'], $this->_templates[$this->_outputFormat]);
|
||||
$insert = array('context' => join("\n", $context), 'helpPath' => $this->helpPath) + $data;
|
||||
|
||||
$detect = array('help' => 'helpID', 'context' => 'context');
|
||||
|
||||
if (isset($tpl['links'])) {
|
||||
foreach ($tpl['links'] as $key => $val) {
|
||||
if (isset($detect[$key]) && empty($insert[$detect[$key]])) {
|
||||
continue;
|
||||
}
|
||||
$links[$key] = String::insert($val, $insert, $insertOpts);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('code', 'context', 'trace') as $key) {
|
||||
if (empty($$key) || !isset($tpl[$key])) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($$key)) {
|
||||
$$key = join("\n", $$key);
|
||||
}
|
||||
$info .= String::insert($tpl[$key], compact($key) + $insert, $insertOpts);
|
||||
}
|
||||
$links = join(' | ', $links);
|
||||
unset($data['context']);
|
||||
|
||||
echo String::insert($tpl['error'], compact('links', 'info') + $data, $insertOpts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the application's salt and cipher seed value has been changed from the default value.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function checkSecurityKeys() {
|
||||
if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') {
|
||||
trigger_error(__('Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application', true), E_USER_NOTICE);
|
||||
}
|
||||
|
||||
if (Configure::read('Security.cipherSeed') === '76859309657453542496749683645') {
|
||||
trigger_error(__('Please change the value of \'Security.cipherSeed\' in app/config/core.php to a numeric (digits only) seed value specific to your application', true), E_USER_NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given debugger object as the current error handler, taking over control from the
|
||||
* previous handler in a stack-like hierarchy.
|
||||
*
|
||||
* @param object $debugger A reference to the Debugger object
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class
|
||||
*/
|
||||
function invoke(&$debugger) {
|
||||
set_error_handler(array(&$debugger, 'handleError'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
|
||||
Debugger::invoke(Debugger::getInstance());
|
||||
}
|
||||
462
web-cake/html/cake/libs/error.php
Normal file
462
web-cake/html/cake/libs/error.php
Normal file
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
/**
|
||||
* Error handler
|
||||
*
|
||||
* Provides Error Capturing for Framework errors.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.10.5.1732
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Controller', 'App');
|
||||
|
||||
/**
|
||||
* Error Handling Controller
|
||||
*
|
||||
* Controller used by ErrorHandler to render error views.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CakeErrorController extends AppController {
|
||||
var $name = 'CakeError';
|
||||
|
||||
/**
|
||||
* Uses Property
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $uses = array();
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
$this->_set(Router::getPaths());
|
||||
$this->params = Router::getParams();
|
||||
$this->constructClasses();
|
||||
$this->Component->initialize($this);
|
||||
$this->_set(array('cacheAction' => false, 'viewPath' => 'errors'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error Handler.
|
||||
*
|
||||
* Captures and handles all cakeError() calls.
|
||||
* Displays helpful framework errors when debug > 1.
|
||||
* When debug < 1 cakeError() will render 404 or 500 errors.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class ErrorHandler extends Object {
|
||||
|
||||
/**
|
||||
* Controller instance.
|
||||
*
|
||||
* @var Controller
|
||||
* @access public
|
||||
*/
|
||||
var $controller = null;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $method Method producing the error
|
||||
* @param array $messages Error messages
|
||||
*/
|
||||
function __construct($method, $messages) {
|
||||
App::import('Core', 'Sanitize');
|
||||
static $__previousError = null;
|
||||
|
||||
if ($__previousError != array($method, $messages)) {
|
||||
$__previousError = array($method, $messages);
|
||||
$this->controller =& new CakeErrorController();
|
||||
} else {
|
||||
$this->controller =& new Controller();
|
||||
$this->controller->viewPath = 'errors';
|
||||
}
|
||||
$options = array('escape' => false);
|
||||
$messages = Sanitize::clean($messages, $options);
|
||||
|
||||
if (!isset($messages[0])) {
|
||||
$messages = array($messages);
|
||||
}
|
||||
|
||||
if (method_exists($this->controller, 'apperror')) {
|
||||
return $this->controller->appError($method, $messages);
|
||||
}
|
||||
|
||||
if (!in_array(strtolower($method), array_map('strtolower', get_class_methods($this)))) {
|
||||
$method = 'error';
|
||||
}
|
||||
|
||||
if ($method !== 'error') {
|
||||
if (Configure::read('debug') == 0) {
|
||||
$parentClass = get_parent_class($this);
|
||||
if (strtolower($parentClass) != 'errorhandler') {
|
||||
$method = 'error404';
|
||||
}
|
||||
$parentMethods = array_map('strtolower', get_class_methods($parentClass));
|
||||
if (in_array(strtolower($method), $parentMethods)) {
|
||||
$method = 'error404';
|
||||
}
|
||||
if (isset($messages[0]['code']) && $messages[0]['code'] == 500) {
|
||||
$method = 'error500';
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->dispatchMethod($method, $messages);
|
||||
$this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error page (e.g. 404 Not found).
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function error($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
$this->controller->set(array(
|
||||
'code' => $code,
|
||||
'name' => $name,
|
||||
'message' => $message,
|
||||
'title' => $code . ' ' . $name
|
||||
));
|
||||
$this->_outputMessage('error404');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to display a 404 page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function error404($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
if (!isset($url)) {
|
||||
$url = $this->controller->here;
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$this->controller->header("HTTP/1.0 404 Not Found");
|
||||
$this->controller->set(array(
|
||||
'code' => '404',
|
||||
'name' => __('Not Found', true),
|
||||
'message' => h($url),
|
||||
'base' => $this->controller->base
|
||||
));
|
||||
$this->_outputMessage('error404');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to display a 500 page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function error500($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
if (!isset($url)) {
|
||||
$url = $this->controller->here;
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$this->controller->header("HTTP/1.0 500 Internal Server Error");
|
||||
$this->controller->set(array(
|
||||
'code' => '500',
|
||||
'name' => __('An Internal Error Has Occurred', true),
|
||||
'message' => h($url),
|
||||
'base' => $this->controller->base
|
||||
));
|
||||
$this->_outputMessage('error500');
|
||||
}
|
||||
/**
|
||||
* Renders the Missing Controller web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingController($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$controllerName = str_replace('Controller', '', $className);
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'controllerName' => $controllerName,
|
||||
'title' => __('Missing Controller', true)
|
||||
));
|
||||
$this->_outputMessage('missingController');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Action web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingAction($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$controllerName = str_replace('Controller', '', $className);
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'controllerName' => $controllerName,
|
||||
'action' => $action,
|
||||
'title' => __('Missing Method in Controller', true)
|
||||
));
|
||||
$this->_outputMessage('missingAction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Private Action web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function privateAction($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'action' => $action,
|
||||
'title' => __('Trying to access private method in class', true)
|
||||
));
|
||||
$this->_outputMessage('privateAction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Table web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingTable($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->header("HTTP/1.0 500 Internal Server Error");
|
||||
$this->controller->set(array(
|
||||
'code' => '500',
|
||||
'model' => $className,
|
||||
'table' => $table,
|
||||
'title' => __('Missing Database Table', true)
|
||||
));
|
||||
$this->_outputMessage('missingTable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Database web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingDatabase($params = array()) {
|
||||
$this->controller->header("HTTP/1.0 500 Internal Server Error");
|
||||
$this->controller->set(array(
|
||||
'code' => '500',
|
||||
'title' => __('Scaffold Missing Database Connection', true)
|
||||
));
|
||||
$this->_outputMessage('missingScaffolddb');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing View web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingView($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'action' => $action,
|
||||
'file' => $file,
|
||||
'title' => __('Missing View', true)
|
||||
));
|
||||
$this->_outputMessage('missingView');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Layout web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingLayout($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->layout = 'default';
|
||||
$this->controller->set(array(
|
||||
'file' => $file,
|
||||
'title' => __('Missing Layout', true)
|
||||
));
|
||||
$this->_outputMessage('missingLayout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Database Connection web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingConnection($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->header("HTTP/1.0 500 Internal Server Error");
|
||||
$this->controller->set(array(
|
||||
'code' => '500',
|
||||
'model' => $className,
|
||||
'title' => __('Missing Database Connection', true)
|
||||
));
|
||||
$this->_outputMessage('missingConnection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Helper file web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingHelperFile($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'helperClass' => Inflector::camelize($helper) . "Helper",
|
||||
'file' => $file,
|
||||
'title' => __('Missing Helper File', true)
|
||||
));
|
||||
$this->_outputMessage('missingHelperFile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Helper class web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingHelperClass($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'helperClass' => Inflector::camelize($helper) . "Helper",
|
||||
'file' => $file,
|
||||
'title' => __('Missing Helper Class', true)
|
||||
));
|
||||
$this->_outputMessage('missingHelperClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Behavior file web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingBehaviorFile($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'behaviorClass' => Inflector::camelize($behavior) . "Behavior",
|
||||
'file' => $file,
|
||||
'title' => __('Missing Behavior File', true)
|
||||
));
|
||||
$this->_outputMessage('missingBehaviorFile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Behavior class web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingBehaviorClass($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'behaviorClass' => Inflector::camelize($behavior) . "Behavior",
|
||||
'file' => $file,
|
||||
'title' => __('Missing Behavior Class', true)
|
||||
));
|
||||
$this->_outputMessage('missingBehaviorClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Component file web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingComponentFile($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'component' => $component,
|
||||
'file' => $file,
|
||||
'title' => __('Missing Component File', true)
|
||||
));
|
||||
$this->_outputMessage('missingComponentFile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Component class web page.
|
||||
*
|
||||
* @param array $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingComponentClass($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'controller' => $className,
|
||||
'component' => $component,
|
||||
'file' => $file,
|
||||
'title' => __('Missing Component Class', true)
|
||||
));
|
||||
$this->_outputMessage('missingComponentClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Missing Model class web page.
|
||||
*
|
||||
* @param unknown_type $params Parameters for controller
|
||||
* @access public
|
||||
*/
|
||||
function missingModel($params) {
|
||||
extract($params, EXTR_OVERWRITE);
|
||||
|
||||
$this->controller->set(array(
|
||||
'model' => $className,
|
||||
'title' => __('Missing Model', true)
|
||||
));
|
||||
$this->_outputMessage('missingModel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Output message
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
function _outputMessage($template) {
|
||||
$this->controller->render($template);
|
||||
$this->controller->afterFilter();
|
||||
echo $this->controller->output;
|
||||
}
|
||||
}
|
||||
544
web-cake/html/cake/libs/file.php
Normal file
544
web-cake/html/cake/libs/file.php
Normal file
@@ -0,0 +1,544 @@
|
||||
<?php
|
||||
/**
|
||||
* Convenience class for reading, writing and appending to files.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libraries.
|
||||
*
|
||||
*/
|
||||
if (!class_exists('Object')) {
|
||||
require LIBS . 'object.php';
|
||||
}
|
||||
if (!class_exists('Folder')) {
|
||||
require LIBS . 'folder.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience class for reading, writing and appending to files.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class File extends Object {
|
||||
|
||||
/**
|
||||
* Folder object of the File
|
||||
*
|
||||
* @var Folder
|
||||
* @access public
|
||||
*/
|
||||
var $Folder = null;
|
||||
|
||||
/**
|
||||
* Filename
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = null;
|
||||
|
||||
/**
|
||||
* file info
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $info = array();
|
||||
|
||||
/**
|
||||
* Holds the file handler resource if the file is opened
|
||||
*
|
||||
* @var resource
|
||||
* @access public
|
||||
*/
|
||||
var $handle = null;
|
||||
|
||||
/**
|
||||
* enable locking for file reading and writing
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $lock = null;
|
||||
|
||||
/**
|
||||
* path property
|
||||
*
|
||||
* Current file's absolute path
|
||||
*
|
||||
* @var mixed null
|
||||
* @access public
|
||||
*/
|
||||
var $path = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $path Path to file
|
||||
* @param boolean $create Create file if it does not exist (if true)
|
||||
* @param integer $mode Mode to apply to the folder holding the file
|
||||
* @access private
|
||||
*/
|
||||
function __construct($path, $create = false, $mode = 0755) {
|
||||
parent::__construct();
|
||||
$this->Folder =& new Folder(dirname($path), $create, $mode);
|
||||
if (!is_dir($path)) {
|
||||
$this->name = basename($path);
|
||||
}
|
||||
$this->pwd();
|
||||
$create && !$this->exists() && $this->safe($path) && $this->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current file if it is opened
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __destruct() {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the File.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function create() {
|
||||
$dir = $this->Folder->pwd();
|
||||
if (is_dir($dir) && is_writable($dir) && !$this->exists()) {
|
||||
$old = umask(0);
|
||||
if (touch($this->path)) {
|
||||
umask($old);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the current file with a given $mode
|
||||
*
|
||||
* @param string $mode A valid 'fopen' mode string (r|w|a ...)
|
||||
* @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't
|
||||
* @return boolean True on success, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function open($mode = 'r', $force = false) {
|
||||
if (!$force && is_resource($this->handle)) {
|
||||
return true;
|
||||
}
|
||||
clearstatcache();
|
||||
if ($this->exists() === false) {
|
||||
if ($this->create() === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->handle = fopen($this->path, $mode);
|
||||
if (is_resource($this->handle)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of this File as a string.
|
||||
*
|
||||
* @param string $bytes where to start
|
||||
* @param string $mode A `fread` compatible mode.
|
||||
* @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't
|
||||
* @return mixed string on success, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function read($bytes = false, $mode = 'rb', $force = false) {
|
||||
if ($bytes === false && $this->lock === null) {
|
||||
return file_get_contents($this->path);
|
||||
}
|
||||
if ($this->open($mode, $force) === false) {
|
||||
return false;
|
||||
}
|
||||
if ($this->lock !== null && flock($this->handle, LOCK_SH) === false) {
|
||||
return false;
|
||||
}
|
||||
if (is_int($bytes)) {
|
||||
return fread($this->handle, $bytes);
|
||||
}
|
||||
|
||||
$data = '';
|
||||
while (!feof($this->handle)) {
|
||||
$data .= fgets($this->handle, 4096);
|
||||
}
|
||||
|
||||
if ($this->lock !== null) {
|
||||
flock($this->handle, LOCK_UN);
|
||||
}
|
||||
if ($bytes === false) {
|
||||
$this->close();
|
||||
}
|
||||
return trim($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the offset for the currently opened file.
|
||||
*
|
||||
* @param mixed $offset The $offset in bytes to seek. If set to false then the current offset is returned.
|
||||
* @param integer $seek PHP Constant SEEK_SET | SEEK_CUR | SEEK_END determining what the $offset is relative to
|
||||
* @return mixed True on success, false on failure (set mode), false on failure or integer offset on success (get mode)
|
||||
* @access public
|
||||
*/
|
||||
function offset($offset = false, $seek = SEEK_SET) {
|
||||
if ($offset === false) {
|
||||
if (is_resource($this->handle)) {
|
||||
return ftell($this->handle);
|
||||
}
|
||||
} elseif ($this->open() === true) {
|
||||
return fseek($this->handle, $offset, $seek) === 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a ascii string for writing. Converts line endings to the
|
||||
* correct terminator for the current platform. If windows "\r\n" will be used
|
||||
* all other platforms will use "\n"
|
||||
*
|
||||
* @param string $data Data to prepare for writing.
|
||||
* @return string The with converted line endings.
|
||||
* @access public
|
||||
*/
|
||||
function prepare($data, $forceWindows = false) {
|
||||
$lineBreak = "\n";
|
||||
if (DIRECTORY_SEPARATOR == '\\' || $forceWindows === true) {
|
||||
$lineBreak = "\r\n";
|
||||
}
|
||||
return strtr($data, array("\r\n" => $lineBreak, "\n" => $lineBreak, "\r" => $lineBreak));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write given data to this File.
|
||||
*
|
||||
* @param string $data Data to write to this File.
|
||||
* @param string $mode Mode of writing. {@link http://php.net/fwrite See fwrite()}.
|
||||
* @param string $force force the file to open
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function write($data, $mode = 'w', $force = false) {
|
||||
$success = false;
|
||||
if ($this->open($mode, $force) === true) {
|
||||
if ($this->lock !== null) {
|
||||
if (flock($this->handle, LOCK_EX) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrite($this->handle, $data) !== false) {
|
||||
$success = true;
|
||||
}
|
||||
if ($this->lock !== null) {
|
||||
flock($this->handle, LOCK_UN);
|
||||
}
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append given data string to this File.
|
||||
*
|
||||
* @param string $data Data to write
|
||||
* @param string $force force the file to open
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function append($data, $force = false) {
|
||||
return $this->write($data, 'a', $force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current file if it is opened.
|
||||
*
|
||||
* @return boolean True if closing was successful or file was already closed, otherwise false
|
||||
* @access public
|
||||
*/
|
||||
function close() {
|
||||
if (!is_resource($this->handle)) {
|
||||
return true;
|
||||
}
|
||||
return fclose($this->handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the File.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function delete() {
|
||||
clearstatcache();
|
||||
if ($this->exists()) {
|
||||
return unlink($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File info.
|
||||
*
|
||||
* @return string The File extension
|
||||
* @access public
|
||||
*/
|
||||
function info() {
|
||||
if ($this->info == null) {
|
||||
$this->info = pathinfo($this->path);
|
||||
}
|
||||
if (!isset($this->info['filename'])) {
|
||||
$this->info['filename'] = $this->name();
|
||||
}
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File extension.
|
||||
*
|
||||
* @return string The File extension
|
||||
* @access public
|
||||
*/
|
||||
function ext() {
|
||||
if ($this->info == null) {
|
||||
$this->info();
|
||||
}
|
||||
if (isset($this->info['extension'])) {
|
||||
return $this->info['extension'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File name without extension.
|
||||
*
|
||||
* @return string The File name without extension.
|
||||
* @access public
|
||||
*/
|
||||
function name() {
|
||||
if ($this->info == null) {
|
||||
$this->info();
|
||||
}
|
||||
if (isset($this->info['extension'])) {
|
||||
return basename($this->name, '.'.$this->info['extension']);
|
||||
} elseif ($this->name) {
|
||||
return $this->name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* makes filename safe for saving
|
||||
*
|
||||
* @param string $name The name of the file to make safe if different from $this->name
|
||||
* @param strin $ext The name of the extension to make safe if different from $this->ext
|
||||
* @return string $ext the extension of the file
|
||||
* @access public
|
||||
*/
|
||||
function safe($name = null, $ext = null) {
|
||||
if (!$name) {
|
||||
$name = $this->name;
|
||||
}
|
||||
if (!$ext) {
|
||||
$ext = $this->ext();
|
||||
}
|
||||
return preg_replace( "/(?:[^\w\.-]+)/", "_", basename($name, $ext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get md5 Checksum of file with previous check of Filesize
|
||||
*
|
||||
* @param mixed $maxsize in MB or true to force
|
||||
* @return string md5 Checksum {@link http://php.net/md5_file See md5_file()}
|
||||
* @access public
|
||||
*/
|
||||
function md5($maxsize = 5) {
|
||||
if ($maxsize === true) {
|
||||
return md5_file($this->path);
|
||||
}
|
||||
|
||||
$size = $this->size();
|
||||
if ($size && $size < ($maxsize * 1024) * 1024) {
|
||||
return md5_file($this->path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path of the File.
|
||||
*
|
||||
* @return string Full path to file
|
||||
* @access public
|
||||
*/
|
||||
function pwd() {
|
||||
if (is_null($this->path)) {
|
||||
$this->path = $this->Folder->slashTerm($this->Folder->pwd()) . $this->name;
|
||||
}
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File exists.
|
||||
*
|
||||
* @return boolean true if it exists, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function exists() {
|
||||
return (file_exists($this->path) && is_file($this->path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "chmod" (permissions) of the File.
|
||||
*
|
||||
* @return string Permissions for the file
|
||||
* @access public
|
||||
*/
|
||||
function perms() {
|
||||
if ($this->exists()) {
|
||||
return substr(sprintf('%o', fileperms($this->path)), -4);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Filesize
|
||||
*
|
||||
* @return integer size of the file in bytes, or false in case of an error
|
||||
* @access public
|
||||
*/
|
||||
function size() {
|
||||
if ($this->exists()) {
|
||||
return filesize($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is writable.
|
||||
*
|
||||
* @return boolean true if its writable, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function writable() {
|
||||
return is_writable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is executable.
|
||||
*
|
||||
* @return boolean true if its executable, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function executable() {
|
||||
return is_executable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is readable.
|
||||
*
|
||||
* @return boolean true if file is readable, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function readable() {
|
||||
return is_readable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File's owner.
|
||||
*
|
||||
* @return integer the Fileowner
|
||||
* @access public
|
||||
*/
|
||||
function owner() {
|
||||
if ($this->exists()) {
|
||||
return fileowner($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File's group.
|
||||
*
|
||||
* @return integer the Filegroup
|
||||
* @access public
|
||||
*/
|
||||
function group() {
|
||||
if ($this->exists()) {
|
||||
return filegroup($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last access time.
|
||||
*
|
||||
* @return integer timestamp Timestamp of last access time
|
||||
* @access public
|
||||
*/
|
||||
function lastAccess() {
|
||||
if ($this->exists()) {
|
||||
return fileatime($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last modified time.
|
||||
*
|
||||
* @return integer timestamp Timestamp of last modification
|
||||
* @access public
|
||||
*/
|
||||
function lastChange() {
|
||||
if ($this->exists()) {
|
||||
return filemtime($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current folder.
|
||||
*
|
||||
* @return Folder Current folder
|
||||
* @access public
|
||||
*/
|
||||
function &Folder() {
|
||||
return $this->Folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the File to $dest
|
||||
*
|
||||
* @param string $dest destination for the copy
|
||||
* @param boolean $overwrite Overwrite $dest if exists
|
||||
* @return boolean Succes
|
||||
* @access public
|
||||
*/
|
||||
function copy($dest, $overwrite = true) {
|
||||
if (!$this->exists() || is_file($dest) && !$overwrite) {
|
||||
return false;
|
||||
}
|
||||
return copy($this->path, $dest);
|
||||
}
|
||||
}
|
||||
787
web-cake/html/cake/libs/folder.php
Normal file
787
web-cake/html/cake/libs/folder.php
Normal file
@@ -0,0 +1,787 @@
|
||||
<?php
|
||||
/**
|
||||
* Convenience class for handling directories.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libraries.
|
||||
*
|
||||
*/
|
||||
if (!class_exists('Object')) {
|
||||
require LIBS . 'object.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Folder structure browser, lists folders and files.
|
||||
* Provides an Object interface for Common directory related tasks.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Folder extends Object {
|
||||
|
||||
/**
|
||||
* Path to Folder.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $path = null;
|
||||
|
||||
/**
|
||||
* Sortedness. Whether or not list results
|
||||
* should be sorted by name.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $sort = false;
|
||||
|
||||
/**
|
||||
* Mode to be used on create. Does nothing on windows platforms.
|
||||
*
|
||||
* @var integer
|
||||
* @access public
|
||||
*/
|
||||
var $mode = 0755;
|
||||
|
||||
/**
|
||||
* Holds messages from last method.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__messages = array();
|
||||
|
||||
/**
|
||||
* Holds errors from last method.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__errors = false;
|
||||
|
||||
/**
|
||||
* Holds array of complete directory paths.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__directories;
|
||||
|
||||
/**
|
||||
* Holds array of complete file paths.
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__files;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $path Path to folder
|
||||
* @param boolean $create Create folder if not found
|
||||
* @param mixed $mode Mode (CHMOD) to apply to created folder, false to ignore
|
||||
*/
|
||||
function __construct($path = false, $create = false, $mode = false) {
|
||||
parent::__construct();
|
||||
if (empty($path)) {
|
||||
$path = TMP;
|
||||
}
|
||||
if ($mode) {
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
if (!file_exists($path) && $create === true) {
|
||||
$this->create($path, $this->mode);
|
||||
}
|
||||
if (!Folder::isAbsolute($path)) {
|
||||
$path = realpath($path);
|
||||
}
|
||||
if (!empty($path)) {
|
||||
$this->cd($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current path.
|
||||
*
|
||||
* @return string Current path
|
||||
* @access public
|
||||
*/
|
||||
function pwd() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change directory to $path.
|
||||
*
|
||||
* @param string $path Path to the directory to change to
|
||||
* @return string The new path. Returns false on failure
|
||||
* @access public
|
||||
*/
|
||||
function cd($path) {
|
||||
$path = $this->realpath($path);
|
||||
if (is_dir($path)) {
|
||||
return $this->path = $path;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the contents of the current directory.
|
||||
* The returned array holds two arrays: One of directories and one of files.
|
||||
*
|
||||
* @param boolean $sort Whether you want the results sorted, set this and the sort property
|
||||
* to false to get unsorted results.
|
||||
* @param mixed $exceptions Either an array or boolean true will not grab dot files
|
||||
* @param boolean $fullPath True returns the full path
|
||||
* @return mixed Contents of current directory as an array, an empty array on failure
|
||||
* @access public
|
||||
*/
|
||||
function read($sort = true, $exceptions = false, $fullPath = false) {
|
||||
$dirs = $files = array();
|
||||
|
||||
if (!$this->pwd()) {
|
||||
return array($dirs, $files);
|
||||
}
|
||||
if (is_array($exceptions)) {
|
||||
$exceptions = array_flip($exceptions);
|
||||
}
|
||||
$skipHidden = isset($exceptions['.']) || $exceptions === true;
|
||||
|
||||
if (false === ($dir = @opendir($this->path))) {
|
||||
return array($dirs, $files);
|
||||
}
|
||||
|
||||
while (false !== ($item = readdir($dir))) {
|
||||
if ($item === '.' || $item === '..' || ($skipHidden && $item[0] === '.') || isset($exceptions[$item])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = Folder::addPathElement($this->path, $item);
|
||||
if (is_dir($path)) {
|
||||
$dirs[] = $fullPath ? $path : $item;
|
||||
} else {
|
||||
$files[] = $fullPath ? $path : $item;
|
||||
}
|
||||
}
|
||||
|
||||
if ($sort || $this->sort) {
|
||||
sort($dirs);
|
||||
sort($files);
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
return array($dirs, $files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all matching files in current directory.
|
||||
*
|
||||
* @param string $pattern Preg_match pattern (Defaults to: .*)
|
||||
* @param boolean $sort Whether results should be sorted.
|
||||
* @return array Files that match given pattern
|
||||
* @access public
|
||||
*/
|
||||
function find($regexpPattern = '.*', $sort = false) {
|
||||
list($dirs, $files) = $this->read($sort);
|
||||
return array_values(preg_grep('/^' . $regexpPattern . '$/i', $files)); ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all matching files in and below current directory.
|
||||
*
|
||||
* @param string $pattern Preg_match pattern (Defaults to: .*)
|
||||
* @param boolean $sort Whether results should be sorted.
|
||||
* @return array Files matching $pattern
|
||||
* @access public
|
||||
*/
|
||||
function findRecursive($pattern = '.*', $sort = false) {
|
||||
if (!$this->pwd()) {
|
||||
return array();
|
||||
}
|
||||
$startsOn = $this->path;
|
||||
$out = $this->_findRecursive($pattern, $sort);
|
||||
$this->cd($startsOn);
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private helper function for findRecursive.
|
||||
*
|
||||
* @param string $pattern Pattern to match against
|
||||
* @param boolean $sort Whether results should be sorted.
|
||||
* @return array Files matching pattern
|
||||
* @access private
|
||||
*/
|
||||
function _findRecursive($pattern, $sort = false) {
|
||||
list($dirs, $files) = $this->read($sort);
|
||||
$found = array();
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (preg_match('/^' . $pattern . '$/i', $file)) {
|
||||
$found[] = Folder::addPathElement($this->path, $file);
|
||||
}
|
||||
}
|
||||
$start = $this->path;
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$this->cd(Folder::addPathElement($start, $dir));
|
||||
$found = array_merge($found, $this->findRecursive($pattern, $sort));
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given $path is a Windows path.
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return boolean true if windows path, false otherwise
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isWindowsPath($path) {
|
||||
return (bool)preg_match('/^[A-Z]:\\\\/i', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given $path is an absolute path.
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return bool true if path is absolute.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isAbsolute($path) {
|
||||
return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return string Set of slashes ("\\" or "/")
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function normalizePath($path) {
|
||||
return Folder::correctSlashFor($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return string Set of slashes ("\\" or "/")
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function correctSlashFor($path) {
|
||||
return (Folder::isWindowsPath($path)) ? '\\' : '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $path with added terminating slash (corrected for Windows or other OS).
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return string Path with ending slash
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function slashTerm($path) {
|
||||
if (Folder::isSlashTerm($path)) {
|
||||
return $path;
|
||||
}
|
||||
return $path . Folder::correctSlashFor($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $path with $element added, with correct slash in-between.
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param string $element Element to and at end of path
|
||||
* @return string Combined path
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function addPathElement($path, $element) {
|
||||
return rtrim($path, DS) . DS . $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is in a given CakePath.
|
||||
*
|
||||
* @param string $path The path to check.
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function inCakePath($path = '') {
|
||||
$dir = substr(Folder::slashTerm(ROOT), 0, -1);
|
||||
$newdir = $dir . $path;
|
||||
|
||||
return $this->inPath($newdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is in given path.
|
||||
*
|
||||
* @param string $path The path to check that the current pwd() resides with in.
|
||||
* @param boolean $reverse
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function inPath($path = '', $reverse = false) {
|
||||
$dir = Folder::slashTerm($path);
|
||||
$current = Folder::slashTerm($this->pwd());
|
||||
|
||||
if (!$reverse) {
|
||||
$return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current);
|
||||
} else {
|
||||
$return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir);
|
||||
}
|
||||
return (bool)$return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the mode on a directory structure recursively. This includes changing the mode on files as well.
|
||||
*
|
||||
* @param string $path The path to chmod
|
||||
* @param integer $mode octal value 0755
|
||||
* @param boolean $recursive chmod recursively, set to false to only change the current directory.
|
||||
* @param array $exceptions array of files, directories to skip
|
||||
* @return boolean Returns TRUE on success, FALSE on failure
|
||||
* @access public
|
||||
*/
|
||||
function chmod($path, $mode = false, $recursive = true, $exceptions = array()) {
|
||||
if (!$mode) {
|
||||
$mode = $this->mode;
|
||||
}
|
||||
|
||||
if ($recursive === false && is_dir($path)) {
|
||||
if (@chmod($path, intval($mode, 8))) {
|
||||
$this->__messages[] = sprintf(__('%s changed to %s', true), $path, $mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->__errors[] = sprintf(__('%s NOT changed to %s', true), $path, $mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
$paths = $this->tree($path);
|
||||
|
||||
foreach ($paths as $type) {
|
||||
foreach ($type as $key => $fullpath) {
|
||||
$check = explode(DS, $fullpath);
|
||||
$count = count($check);
|
||||
|
||||
if (in_array($check[$count - 1], $exceptions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (@chmod($fullpath, intval($mode, 8))) {
|
||||
$this->__messages[] = sprintf(__('%s changed to %s', true), $fullpath, $mode);
|
||||
} else {
|
||||
$this->__errors[] = sprintf(__('%s NOT changed to %s', true), $fullpath, $mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->__errors)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of nested directories and files in each directory
|
||||
*
|
||||
* @param string $path the directory path to build the tree from
|
||||
* @param mixed $exceptions Array of files to exclude, defaults to excluding hidden files.
|
||||
* @param string $type either file or dir. null returns both files and directories
|
||||
* @return mixed array of nested directories and files in each directory
|
||||
* @access public
|
||||
*/
|
||||
function tree($path, $exceptions = true, $type = null) {
|
||||
$original = $this->path;
|
||||
$path = rtrim($path, DS);
|
||||
if (!$this->cd($path)) {
|
||||
if ($type === null) {
|
||||
return array(array(), array());
|
||||
}
|
||||
return array();
|
||||
}
|
||||
$this->__files = array();
|
||||
$this->__directories = array($this->realpath($path));
|
||||
$directories = array();
|
||||
|
||||
if ($exceptions === false) {
|
||||
$exceptions = true;
|
||||
}
|
||||
while (!empty($this->__directories)) {
|
||||
$dir = array_pop($this->__directories);
|
||||
$this->__tree($dir, $exceptions);
|
||||
$directories[] = $dir;
|
||||
}
|
||||
|
||||
if ($type === null) {
|
||||
return array($directories, $this->__files);
|
||||
}
|
||||
if ($type === 'dir') {
|
||||
return $directories;
|
||||
}
|
||||
$this->cd($original);
|
||||
|
||||
return $this->__files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to list directories and files in each directory
|
||||
*
|
||||
* @param string $path The Path to read.
|
||||
* @param mixed $exceptions Array of files to exclude from the read that will be performed.
|
||||
* @access private
|
||||
*/
|
||||
function __tree($path, $exceptions) {
|
||||
$this->path = $path;
|
||||
list($dirs, $files) = $this->read(false, $exceptions, true);
|
||||
$this->__directories = array_merge($this->__directories, $dirs);
|
||||
$this->__files = array_merge($this->__files, $files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory structure recursively. Can be used to create
|
||||
* deep path structures like `/foo/bar/baz/shoe/horn`
|
||||
*
|
||||
* @param string $pathname The directory structure to create
|
||||
* @param integer $mode octal value 0755
|
||||
* @return boolean Returns TRUE on success, FALSE on failure
|
||||
* @access public
|
||||
*/
|
||||
function create($pathname, $mode = false) {
|
||||
if (is_dir($pathname) || empty($pathname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$mode) {
|
||||
$mode = $this->mode;
|
||||
}
|
||||
|
||||
if (is_file($pathname)) {
|
||||
$this->__errors[] = sprintf(__('%s is a file', true), $pathname);
|
||||
return false;
|
||||
}
|
||||
$pathname = rtrim($pathname, DS);
|
||||
$nextPathname = substr($pathname, 0, strrpos($pathname, DS));
|
||||
|
||||
if ($this->create($nextPathname, $mode)) {
|
||||
if (!file_exists($pathname)) {
|
||||
$old = umask(0);
|
||||
if (mkdir($pathname, $mode)) {
|
||||
umask($old);
|
||||
$this->__messages[] = sprintf(__('%s created', true), $pathname);
|
||||
return true;
|
||||
} else {
|
||||
umask($old);
|
||||
$this->__errors[] = sprintf(__('%s NOT created', true), $pathname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size in bytes of this Folder and its contents.
|
||||
*
|
||||
* @param string $directory Path to directory
|
||||
* @return int size in bytes of current folder
|
||||
* @access public
|
||||
*/
|
||||
function dirsize() {
|
||||
$size = 0;
|
||||
$directory = Folder::slashTerm($this->path);
|
||||
$stack = array($directory);
|
||||
$count = count($stack);
|
||||
for ($i = 0, $j = $count; $i < $j; ++$i) {
|
||||
if (is_file($stack[$i])) {
|
||||
$size += filesize($stack[$i]);
|
||||
} elseif (is_dir($stack[$i])) {
|
||||
$dir = dir($stack[$i]);
|
||||
if ($dir) {
|
||||
while (false !== ($entry = $dir->read())) {
|
||||
if ($entry === '.' || $entry === '..') {
|
||||
continue;
|
||||
}
|
||||
$add = $stack[$i] . $entry;
|
||||
|
||||
if (is_dir($stack[$i] . $entry)) {
|
||||
$add = Folder::slashTerm($add);
|
||||
}
|
||||
$stack[] = $add;
|
||||
}
|
||||
$dir->close();
|
||||
}
|
||||
}
|
||||
$j = count($stack);
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively Remove directories if the system allows.
|
||||
*
|
||||
* @param string $path Path of directory to delete
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function delete($path = null) {
|
||||
if (!$path) {
|
||||
$path = $this->pwd();
|
||||
}
|
||||
if (!$path) {
|
||||
return null;
|
||||
}
|
||||
$path = Folder::slashTerm($path);
|
||||
if (is_dir($path) === true) {
|
||||
$normalFiles = glob($path . '*');
|
||||
$hiddenFiles = glob($path . '\.?*');
|
||||
|
||||
$normalFiles = $normalFiles ? $normalFiles : array();
|
||||
$hiddenFiles = $hiddenFiles ? $hiddenFiles : array();
|
||||
|
||||
$files = array_merge($normalFiles, $hiddenFiles);
|
||||
if (is_array($files)) {
|
||||
foreach ($files as $file) {
|
||||
if (preg_match('/(\.|\.\.)$/', $file)) {
|
||||
continue;
|
||||
}
|
||||
if (is_file($file) === true) {
|
||||
if (@unlink($file)) {
|
||||
$this->__messages[] = sprintf(__('%s removed', true), $file);
|
||||
} else {
|
||||
$this->__errors[] = sprintf(__('%s NOT removed', true), $file);
|
||||
}
|
||||
} elseif (is_dir($file) === true && $this->delete($file) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$path = substr($path, 0, strlen($path) - 1);
|
||||
if (rmdir($path) === false) {
|
||||
$this->__errors[] = sprintf(__('%s NOT removed', true), $path);
|
||||
return false;
|
||||
} else {
|
||||
$this->__messages[] = sprintf(__('%s removed', true), $path);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive directory copy.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `to` The directory to copy to.
|
||||
* - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
|
||||
* - `chmod` The mode to copy the files/directories with.
|
||||
* - `skip` Files/directories to skip.
|
||||
*
|
||||
* @param mixed $options Either an array of options (see above) or a string of the destination directory.
|
||||
* @return bool Success
|
||||
* @access public
|
||||
*/
|
||||
function copy($options = array()) {
|
||||
if (!$this->pwd()) {
|
||||
return false;
|
||||
}
|
||||
$to = null;
|
||||
if (is_string($options)) {
|
||||
$to = $options;
|
||||
$options = array();
|
||||
}
|
||||
$options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options);
|
||||
|
||||
$fromDir = $options['from'];
|
||||
$toDir = $options['to'];
|
||||
$mode = $options['mode'];
|
||||
|
||||
if (!$this->cd($fromDir)) {
|
||||
$this->__errors[] = sprintf(__('%s not found', true), $fromDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_dir($toDir)) {
|
||||
$this->create($toDir, $mode);
|
||||
}
|
||||
|
||||
if (!is_writable($toDir)) {
|
||||
$this->__errors[] = sprintf(__('%s not writable', true), $toDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
$exceptions = array_merge(array('.', '..', '.svn'), $options['skip']);
|
||||
if ($handle = @opendir($fromDir)) {
|
||||
while (false !== ($item = readdir($handle))) {
|
||||
if (!in_array($item, $exceptions)) {
|
||||
$from = Folder::addPathElement($fromDir, $item);
|
||||
$to = Folder::addPathElement($toDir, $item);
|
||||
if (is_file($from)) {
|
||||
if (copy($from, $to)) {
|
||||
chmod($to, intval($mode, 8));
|
||||
touch($to, filemtime($from));
|
||||
$this->__messages[] = sprintf(__('%s copied to %s', true), $from, $to);
|
||||
} else {
|
||||
$this->__errors[] = sprintf(__('%s NOT copied to %s', true), $from, $to);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dir($from) && !file_exists($to)) {
|
||||
$old = umask(0);
|
||||
if (mkdir($to, $mode)) {
|
||||
umask($old);
|
||||
$old = umask(0);
|
||||
chmod($to, $mode);
|
||||
umask($old);
|
||||
$this->__messages[] = sprintf(__('%s created', true), $to);
|
||||
$options = array_merge($options, array('to'=> $to, 'from'=> $from));
|
||||
$this->copy($options);
|
||||
} else {
|
||||
$this->__errors[] = sprintf(__('%s not created', true), $to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->__errors)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive directory move.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `to` The directory to copy to.
|
||||
* - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
|
||||
* - `chmod` The mode to copy the files/directories with.
|
||||
* - `skip` Files/directories to skip.
|
||||
*
|
||||
* @param array $options (to, from, chmod, skip)
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function move($options) {
|
||||
$to = null;
|
||||
if (is_string($options)) {
|
||||
$to = $options;
|
||||
$options = (array)$options;
|
||||
}
|
||||
$options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options);
|
||||
|
||||
if ($this->copy($options)) {
|
||||
if ($this->delete($options['from'])) {
|
||||
return $this->cd($options['to']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get messages from latest method
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function messages() {
|
||||
return $this->__messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* get error from latest method
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function errors() {
|
||||
return $this->__errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real path (taking ".." and such into account)
|
||||
*
|
||||
* @param string $path Path to resolve
|
||||
* @return string The resolved path
|
||||
*/
|
||||
function realpath($path) {
|
||||
$path = str_replace('/', DS, trim($path));
|
||||
if (strpos($path, '..') === false) {
|
||||
if (!Folder::isAbsolute($path)) {
|
||||
$path = Folder::addPathElement($this->path, $path);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
$parts = explode(DS, $path);
|
||||
$newparts = array();
|
||||
$newpath = '';
|
||||
if ($path[0] === DS) {
|
||||
$newpath = DS;
|
||||
}
|
||||
|
||||
while (($part = array_shift($parts)) !== NULL) {
|
||||
if ($part === '.' || $part === '') {
|
||||
continue;
|
||||
}
|
||||
if ($part === '..') {
|
||||
if (!empty($newparts)) {
|
||||
array_pop($newparts);
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$newparts[] = $part;
|
||||
}
|
||||
$newpath .= implode(DS, $newparts);
|
||||
|
||||
return Folder::slashTerm($newpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given $path ends in a slash (i.e. is slash-terminated).
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @return boolean true if path ends with slash, false otherwise
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isSlashTerm($path) {
|
||||
$lastChar = $path[strlen($path) - 1];
|
||||
return $lastChar === '/' || $lastChar === '\\';
|
||||
}
|
||||
}
|
||||
1081
web-cake/html/cake/libs/http_socket.php
Normal file
1081
web-cake/html/cake/libs/http_socket.php
Normal file
File diff suppressed because it is too large
Load Diff
566
web-cake/html/cake/libs/i18n.php
Normal file
566
web-cake/html/cake/libs/i18n.php
Normal file
@@ -0,0 +1,566 @@
|
||||
<?php
|
||||
/**
|
||||
* Internationalization
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0.4116
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libraries.
|
||||
*/
|
||||
App::import('Core', array('l10n', 'Multibyte'));
|
||||
|
||||
/**
|
||||
* I18n handles translation of Text and time format strings.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class I18n extends Object {
|
||||
|
||||
/**
|
||||
* Instance of the I10n class for localization
|
||||
*
|
||||
* @var I10n
|
||||
* @access public
|
||||
*/
|
||||
var $l10n = null;
|
||||
|
||||
/**
|
||||
* Current domain of translation
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $domain = null;
|
||||
|
||||
/**
|
||||
* Current category of translation
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $category = 'LC_MESSAGES';
|
||||
|
||||
/**
|
||||
* Current language used for translations
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__lang = null;
|
||||
|
||||
/**
|
||||
* Translation strings for a specific domain read from the .mo or .po files
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__domains = array();
|
||||
|
||||
/**
|
||||
* Set to true when I18N::__bindTextDomain() is called for the first time.
|
||||
* If a translation file is found it is set to false again
|
||||
*
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $__noLocale = false;
|
||||
|
||||
/**
|
||||
* Set to true when I18N::__bindTextDomain() is called for the first time.
|
||||
* If a translation file is found it is set to false again
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__categories = array(
|
||||
'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME', 'LC_MESSAGES'
|
||||
);
|
||||
|
||||
/**
|
||||
* Return a static instance of the I18n class
|
||||
*
|
||||
* @return object I18n
|
||||
* @access public
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
if (!$instance) {
|
||||
$instance[0] =& new I18n();
|
||||
$instance[0]->l10n =& new L10n();
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the translation functions in basics.php
|
||||
* Can also be used like I18n::translate(); but only if the App::import('I18n'); has been used to load the class.
|
||||
*
|
||||
* @param string $singular String to translate
|
||||
* @param string $plural Plural string (if any)
|
||||
* @param string $domain Domain The domain of the translation. Domains are often used by plugin translations
|
||||
* @param string $category Category The integer value of the category to use.
|
||||
* @param integer $count Count Count is used with $plural to choose the correct plural form.
|
||||
* @return string translated string.
|
||||
* @access public
|
||||
*/
|
||||
function translate($singular, $plural = null, $domain = null, $category = 6, $count = null) {
|
||||
$_this =& I18n::getInstance();
|
||||
|
||||
if (strpos($singular, "\r\n") !== false) {
|
||||
$singular = str_replace("\r\n", "\n", $singular);
|
||||
}
|
||||
if ($plural !== null && strpos($plural, "\r\n") !== false) {
|
||||
$plural = str_replace("\r\n", "\n", $plural);
|
||||
}
|
||||
|
||||
if (is_numeric($category)) {
|
||||
$_this->category = $_this->__categories[$category];
|
||||
}
|
||||
$language = Configure::read('Config.language');
|
||||
|
||||
if (!empty($_SESSION['Config']['language'])) {
|
||||
$language = $_SESSION['Config']['language'];
|
||||
}
|
||||
|
||||
if (($_this->__lang && $_this->__lang !== $language) || !$_this->__lang) {
|
||||
$lang = $_this->l10n->get($language);
|
||||
$_this->__lang = $lang;
|
||||
}
|
||||
|
||||
if (is_null($domain)) {
|
||||
$domain = 'default';
|
||||
}
|
||||
|
||||
$_this->domain = $domain . '_' . $_this->l10n->lang;
|
||||
|
||||
if (empty($_this->__domains[$domain][$_this->__lang])) {
|
||||
$_this->__domains[$domain][$_this->__lang] = Cache::read($_this->domain, '_cake_core_');
|
||||
}
|
||||
|
||||
if (empty($_this->__domains[$domain][$_this->__lang][$_this->category])) {
|
||||
$_this->__bindTextDomain($domain);
|
||||
Cache::write($_this->domain, $_this->__domains[$domain][$_this->__lang], '_cake_core_');
|
||||
}
|
||||
|
||||
if ($_this->category == 'LC_TIME') {
|
||||
return $_this->__translateTime($singular,$domain);
|
||||
}
|
||||
|
||||
if (!isset($count)) {
|
||||
$plurals = 0;
|
||||
} elseif (!empty($_this->__domains[$domain][$_this->__lang][$_this->category]["%plural-c"]) && $_this->__noLocale === false) {
|
||||
$header = $_this->__domains[$domain][$_this->__lang][$_this->category]["%plural-c"];
|
||||
$plurals = $_this->__pluralGuess($header, $count);
|
||||
} else {
|
||||
if ($count != 1) {
|
||||
$plurals = 1;
|
||||
} else {
|
||||
$plurals = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_this->__domains[$domain][$_this->__lang][$_this->category][$singular])) {
|
||||
if (($trans = $_this->__domains[$domain][$_this->__lang][$_this->category][$singular]) || ($plurals) && ($trans = $_this->__domains[$domain][$_this->__lang][$_this->category][$plural])) {
|
||||
if (is_array($trans)) {
|
||||
if (isset($trans[$plurals])) {
|
||||
$trans = $trans[$plurals];
|
||||
}
|
||||
}
|
||||
if (strlen($trans)) {
|
||||
return $trans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($plurals)) {
|
||||
return $plural;
|
||||
}
|
||||
return $singular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the domains internal data array. Useful for testing i18n.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function clear() {
|
||||
$self =& I18n::getInstance();
|
||||
$self->__domains = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the plural form of a string.
|
||||
*
|
||||
* @param string $header Type
|
||||
* @param integrer $n Number
|
||||
* @return integer plural match
|
||||
* @access private
|
||||
*/
|
||||
function __pluralGuess($header, $n) {
|
||||
if (!is_string($header) || $header === "nplurals=1;plural=0;" || !isset($header[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($header === "nplurals=2;plural=n!=1;") {
|
||||
return $n != 1 ? 1 : 0;
|
||||
} elseif ($header === "nplurals=2;plural=n>1;") {
|
||||
return $n > 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (strpos($header, "plurals=3")) {
|
||||
if (strpos($header, "100!=11")) {
|
||||
if (strpos($header, "10<=4")) {
|
||||
return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
} elseif (strpos($header, "100<10")) {
|
||||
return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
}
|
||||
return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n != 0 ? 1 : 2);
|
||||
} elseif (strpos($header, "n==2")) {
|
||||
return $n == 1 ? 0 : ($n == 2 ? 1 : 2);
|
||||
} elseif (strpos($header, "n==0")) {
|
||||
return $n == 1 ? 0 : ($n == 0 || ($n % 100 > 0 && $n % 100 < 20) ? 1 : 2);
|
||||
} elseif (strpos($header, "n>=2")) {
|
||||
return $n == 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
|
||||
} elseif (strpos($header, "10>=2")) {
|
||||
return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
}
|
||||
return $n % 10 == 1 ? 0 : ($n % 10 == 2 ? 1 : 2);
|
||||
} elseif (strpos($header, "plurals=4")) {
|
||||
if (strpos($header, "100==2")) {
|
||||
return $n % 100 == 1 ? 0 : ($n % 100 == 2 ? 1 : ($n % 100 == 3 || $n % 100 == 4 ? 2 : 3));
|
||||
} elseif (strpos($header, "n>=3")) {
|
||||
return $n == 1 ? 0 : ($n == 2 ? 1 : ($n == 0 || ($n >= 3 && $n <= 10) ? 2 : 3));
|
||||
} elseif (strpos($header, "100>=1")) {
|
||||
return $n == 1 ? 0 : ($n == 0 || ($n % 100 >= 1 && $n % 100 <= 10) ? 1 : ($n % 100 >= 11 && $n % 100 <= 20 ? 2 : 3));
|
||||
}
|
||||
} elseif (strpos($header, "plurals=5")) {
|
||||
return $n == 1 ? 0 : ($n == 2 ? 1 : ($n >= 3 && $n <= 6 ? 2 : ($n >= 7 && $n <= 10 ? 3 : 4)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given domain to a file in the specified directory.
|
||||
*
|
||||
* @param string $domain Domain to bind
|
||||
* @return string Domain binded
|
||||
* @access private
|
||||
*/
|
||||
function __bindTextDomain($domain) {
|
||||
$this->__noLocale = true;
|
||||
$core = true;
|
||||
$merge = array();
|
||||
$searchPaths = App::path('locales');
|
||||
$plugins = App::objects('plugin');
|
||||
|
||||
if (!empty($plugins)) {
|
||||
foreach ($plugins as $plugin) {
|
||||
$plugin = Inflector::underscore($plugin);
|
||||
if ($plugin === $domain) {
|
||||
$searchPaths[] = App::pluginPath($plugin) . DS . 'locale' . DS;
|
||||
$searchPaths = array_reverse($searchPaths);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($searchPaths as $directory) {
|
||||
|
||||
foreach ($this->l10n->languagePath as $lang) {
|
||||
$file = $directory . $lang . DS . $this->category . DS . $domain;
|
||||
$localeDef = $directory . $lang . DS . $this->category;
|
||||
|
||||
if ($core) {
|
||||
$app = $directory . $lang . DS . $this->category . DS . 'core';
|
||||
|
||||
if (file_exists($fn = "$app.mo")) {
|
||||
$this->__loadMo($fn, $domain);
|
||||
$this->__noLocale = false;
|
||||
$merge[$domain][$this->__lang][$this->category] = $this->__domains[$domain][$this->__lang][$this->category];
|
||||
$core = null;
|
||||
} elseif (file_exists($fn = "$app.po") && ($f = fopen($fn, "r"))) {
|
||||
$this->__loadPo($f, $domain);
|
||||
$this->__noLocale = false;
|
||||
$merge[$domain][$this->__lang][$this->category] = $this->__domains[$domain][$this->__lang][$this->category];
|
||||
$core = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($fn = "$file.mo")) {
|
||||
$this->__loadMo($fn, $domain);
|
||||
$this->__noLocale = false;
|
||||
break 2;
|
||||
} elseif (file_exists($fn = "$file.po") && ($f = fopen($fn, "r"))) {
|
||||
$this->__loadPo($f, $domain);
|
||||
$this->__noLocale = false;
|
||||
break 2;
|
||||
} elseif (is_file($localeDef) && ($f = fopen($localeDef, "r"))) {
|
||||
$this->__loadLocaleDefinition($f, $domain);
|
||||
$this->__noLocale = false;
|
||||
return $domain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->__domains[$domain][$this->__lang][$this->category])) {
|
||||
$this->__domains[$domain][$this->__lang][$this->category] = array();
|
||||
return $domain;
|
||||
}
|
||||
|
||||
if ($head = $this->__domains[$domain][$this->__lang][$this->category][""]) {
|
||||
foreach (explode("\n", $head) as $line) {
|
||||
$header = strtok($line,":");
|
||||
$line = trim(strtok("\n"));
|
||||
$this->__domains[$domain][$this->__lang][$this->category]["%po-header"][strtolower($header)] = $line;
|
||||
}
|
||||
|
||||
if (isset($this->__domains[$domain][$this->__lang][$this->category]["%po-header"]["plural-forms"])) {
|
||||
$switch = preg_replace("/(?:[() {}\\[\\]^\\s*\\]]+)/", "", $this->__domains[$domain][$this->__lang][$this->category]["%po-header"]["plural-forms"]);
|
||||
$this->__domains[$domain][$this->__lang][$this->category]["%plural-c"] = $switch;
|
||||
unset($this->__domains[$domain][$this->__lang][$this->category]["%po-header"]);
|
||||
}
|
||||
$this->__domains = Set::pushDiff($this->__domains, $merge);
|
||||
|
||||
if (isset($this->__domains[$domain][$this->__lang][$this->category][null])) {
|
||||
unset($this->__domains[$domain][$this->__lang][$this->category][null]);
|
||||
}
|
||||
}
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the binary .mo file for translation and sets the values for this translation in the var I18n::__domains
|
||||
*
|
||||
* @param resource $file Binary .mo file to load
|
||||
* @param string $domain Domain where to load file in
|
||||
* @access private
|
||||
*/
|
||||
function __loadMo($file, $domain) {
|
||||
$data = file_get_contents($file);
|
||||
|
||||
if ($data) {
|
||||
$header = substr($data, 0, 20);
|
||||
$header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
|
||||
extract($header);
|
||||
|
||||
if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) {
|
||||
for ($n = 0; $n < $count; $n++) {
|
||||
$r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
|
||||
$msgid = substr($data, $r["offs"], $r["len"]);
|
||||
unset($msgid_plural);
|
||||
|
||||
if (strpos($msgid, "\000")) {
|
||||
list($msgid, $msgid_plural) = explode("\000", $msgid);
|
||||
}
|
||||
$r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8));
|
||||
$msgstr = substr($data, $r["offs"], $r["len"]);
|
||||
|
||||
if (strpos($msgstr, "\000")) {
|
||||
$msgstr = explode("\000", $msgstr);
|
||||
}
|
||||
$this->__domains[$domain][$this->__lang][$this->category][$msgid] = $msgstr;
|
||||
|
||||
if (isset($msgid_plural)) {
|
||||
$this->__domains[$domain][$this->__lang][$this->category][$msgid_plural] =& $this->__domains[$domain][$this->__lang][$this->category][$msgid];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the text .po file for translation and sets the values for this translation in the var I18n::__domains
|
||||
*
|
||||
* @param resource $file Text .po file to load
|
||||
* @param string $domain Domain to load file in
|
||||
* @return array Binded domain elements
|
||||
* @access private
|
||||
*/
|
||||
function __loadPo($file, $domain) {
|
||||
$type = 0;
|
||||
$translations = array();
|
||||
$translationKey = "";
|
||||
$plural = 0;
|
||||
$header = "";
|
||||
|
||||
do {
|
||||
$line = trim(fgets($file));
|
||||
if ($line == "" || $line[0] == "#") {
|
||||
continue;
|
||||
}
|
||||
if (preg_match("/msgid[[:space:]]+\"(.+)\"$/i", $line, $regs)) {
|
||||
$type = 1;
|
||||
$translationKey = stripcslashes($regs[1]);
|
||||
} elseif (preg_match("/msgid[[:space:]]+\"\"$/i", $line, $regs)) {
|
||||
$type = 2;
|
||||
$translationKey = "";
|
||||
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && ($type == 1 || $type == 2 || $type == 3)) {
|
||||
$type = 3;
|
||||
$translationKey .= stripcslashes($regs[1]);
|
||||
} elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
|
||||
$translations[$translationKey] = stripcslashes($regs[1]);
|
||||
$type = 4;
|
||||
} elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
|
||||
$type = 4;
|
||||
$translations[$translationKey] = "";
|
||||
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 4 && $translationKey) {
|
||||
$translations[$translationKey] .= stripcslashes($regs[1]);
|
||||
} elseif (preg_match("/msgid_plural[[:space:]]+\".*\"$/i", $line, $regs)) {
|
||||
$type = 6;
|
||||
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 6 && $translationKey) {
|
||||
$type = 6;
|
||||
} elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
|
||||
$plural = $regs[1];
|
||||
$translations[$translationKey][$plural] = stripcslashes($regs[2]);
|
||||
$type = 7;
|
||||
} elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
|
||||
$plural = $regs[1];
|
||||
$translations[$translationKey][$plural] = "";
|
||||
$type = 7;
|
||||
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 7 && $translationKey) {
|
||||
$translations[$translationKey][$plural] .= stripcslashes($regs[1]);
|
||||
} elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && $type == 2 && !$translationKey) {
|
||||
$header .= stripcslashes($regs[1]);
|
||||
$type = 5;
|
||||
} elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && !$translationKey) {
|
||||
$header = "";
|
||||
$type = 5;
|
||||
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 5) {
|
||||
$header .= stripcslashes($regs[1]);
|
||||
} else {
|
||||
unset($translations[$translationKey]);
|
||||
$type = 0;
|
||||
$translationKey = "";
|
||||
$plural = 0;
|
||||
}
|
||||
} while (!feof($file));
|
||||
fclose($file);
|
||||
$merge[""] = $header;
|
||||
return $this->__domains[$domain][$this->__lang][$this->category] = array_merge($merge ,$translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a locale definition file following the POSIX standard
|
||||
*
|
||||
* @param resource $file file handler
|
||||
* @param string $domain Domain where locale definitions will be stored
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __loadLocaleDefinition($file, $domain = null) {
|
||||
$comment = '#';
|
||||
$escape = '\\';
|
||||
$currentToken = false;
|
||||
$value = '';
|
||||
while ($line = fgets($file)) {
|
||||
$line = trim($line);
|
||||
if (empty($line) || $line[0] === $comment) {
|
||||
continue;
|
||||
}
|
||||
$parts = preg_split("/[[:space:]]+/",$line);
|
||||
if ($parts[0] === 'comment_char') {
|
||||
$comment = $parts[1];
|
||||
continue;
|
||||
}
|
||||
if ($parts[0] === 'escape_char') {
|
||||
$escape = $parts[1];
|
||||
continue;
|
||||
}
|
||||
$count = count($parts);
|
||||
if ($count == 2) {
|
||||
$currentToken = $parts[0];
|
||||
$value = $parts[1];
|
||||
} elseif ($count == 1) {
|
||||
$value .= $parts[0];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
$len = strlen($value) - 1;
|
||||
if ($value[$len] === $escape) {
|
||||
$value = substr($value, 0, $len);
|
||||
continue;
|
||||
}
|
||||
|
||||
$mustEscape = array($escape . ',' , $escape . ';', $escape . '<', $escape . '>', $escape . $escape);
|
||||
$replacements = array_map('crc32', $mustEscape);
|
||||
$value = str_replace($mustEscape, $replacements, $value);
|
||||
$value = explode(';', $value);
|
||||
$this->__escape = $escape;
|
||||
foreach ($value as $i => $val) {
|
||||
$val = trim($val, '"');
|
||||
$val = preg_replace_callback('/(?:<)?(.[^>]*)(?:>)?/', array(&$this, '__parseLiteralValue'), $val);
|
||||
$val = str_replace($replacements, $mustEscape, $val);
|
||||
$value[$i] = $val;
|
||||
}
|
||||
if (count($value) == 1) {
|
||||
$this->__domains[$domain][$this->__lang][$this->category][$currentToken] = array_pop($value);
|
||||
} else {
|
||||
$this->__domains[$domain][$this->__lang][$this->category][$currentToken] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auxiliary function to parse a symbol from a locale definition file
|
||||
*
|
||||
* @param string $string Symbol to be parsed
|
||||
* @return string parsed symbol
|
||||
* @access private
|
||||
*/
|
||||
function __parseLiteralValue($string) {
|
||||
$string = $string[1];
|
||||
if (substr($string, 0, 2) === $this->__escape . 'x') {
|
||||
$delimiter = $this->__escape . 'x';
|
||||
return join('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string)))));
|
||||
}
|
||||
if (substr($string, 0, 2) === $this->__escape . 'd') {
|
||||
$delimiter = $this->__escape . 'd';
|
||||
return join('', array_map('chr', array_filter(explode($delimiter, $string))));
|
||||
}
|
||||
if ($string[0] === $this->__escape && isset($string[1]) && is_numeric($string[1])) {
|
||||
$delimiter = $this->__escape;
|
||||
return join('', array_map('chr', array_filter(explode($delimiter, $string))));
|
||||
}
|
||||
if (substr($string, 0, 3) === 'U00') {
|
||||
$delimiter = 'U00';
|
||||
return join('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string)))));
|
||||
}
|
||||
if (preg_match('/U([0-9a-fA-F]{4})/', $string, $match)) {
|
||||
return Multibyte::ascii(array(hexdec($match[1])));
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Time format definition from corresponding domain
|
||||
*
|
||||
* @param string $format Format to be translated
|
||||
* @param string $domain Domain where format is stored
|
||||
* @return mixed translated format string if only value or array of translated strings for corresponding format.
|
||||
* @access private
|
||||
*/
|
||||
function __translateTime($format, $domain) {
|
||||
if (!empty($this->__domains[$domain][$this->__lang]['LC_TIME'][$format])) {
|
||||
if (($trans = $this->__domains[$domain][$this->__lang][$this->category][$format])) {
|
||||
return $trans;
|
||||
}
|
||||
}
|
||||
return $format;
|
||||
}
|
||||
}
|
||||
626
web-cake/html/cake/libs/inflector.php
Normal file
626
web-cake/html/cake/libs/inflector.php
Normal file
@@ -0,0 +1,626 @@
|
||||
<?php
|
||||
/**
|
||||
* Pluralize and singularize English words.
|
||||
*
|
||||
* Used by Cake's naming conventions throughout the framework.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pluralize and singularize English words.
|
||||
*
|
||||
* Inflector pluralizes and singularizes English nouns.
|
||||
* Used by Cake's naming conventions throughout the framework.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @link http://book.cakephp.org/view/1478/Inflector
|
||||
*/
|
||||
class Inflector {
|
||||
|
||||
/**
|
||||
* Plural inflector rules
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_plural = array(
|
||||
'rules' => array(
|
||||
'/(s)tatus$/i' => '\1\2tatuses',
|
||||
'/(quiz)$/i' => '\1zes',
|
||||
'/^(ox)$/i' => '\1\2en',
|
||||
'/([m|l])ouse$/i' => '\1ice',
|
||||
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
|
||||
'/(x|ch|ss|sh)$/i' => '\1es',
|
||||
'/([^aeiouy]|qu)y$/i' => '\1ies',
|
||||
'/(hive)$/i' => '\1s',
|
||||
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
|
||||
'/sis$/i' => 'ses',
|
||||
'/([ti])um$/i' => '\1a',
|
||||
'/(p)erson$/i' => '\1eople',
|
||||
'/(m)an$/i' => '\1en',
|
||||
'/(c)hild$/i' => '\1hildren',
|
||||
'/(buffal|tomat)o$/i' => '\1\2oes',
|
||||
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
|
||||
'/us$/i' => 'uses',
|
||||
'/(alias)$/i' => '\1es',
|
||||
'/(ax|cris|test)is$/i' => '\1es',
|
||||
'/s$/' => 's',
|
||||
'/^$/' => '',
|
||||
'/$/' => 's',
|
||||
),
|
||||
'uninflected' => array(
|
||||
'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'people'
|
||||
),
|
||||
'irregular' => array(
|
||||
'atlas' => 'atlases',
|
||||
'beef' => 'beefs',
|
||||
'brother' => 'brothers',
|
||||
'child' => 'children',
|
||||
'corpus' => 'corpuses',
|
||||
'cow' => 'cows',
|
||||
'ganglion' => 'ganglions',
|
||||
'genie' => 'genies',
|
||||
'genus' => 'genera',
|
||||
'graffito' => 'graffiti',
|
||||
'hoof' => 'hoofs',
|
||||
'loaf' => 'loaves',
|
||||
'man' => 'men',
|
||||
'money' => 'monies',
|
||||
'mongoose' => 'mongooses',
|
||||
'move' => 'moves',
|
||||
'mythos' => 'mythoi',
|
||||
'niche' => 'niches',
|
||||
'numen' => 'numina',
|
||||
'occiput' => 'occiputs',
|
||||
'octopus' => 'octopuses',
|
||||
'opus' => 'opuses',
|
||||
'ox' => 'oxen',
|
||||
'penis' => 'penises',
|
||||
'person' => 'people',
|
||||
'sex' => 'sexes',
|
||||
'soliloquy' => 'soliloquies',
|
||||
'testis' => 'testes',
|
||||
'trilby' => 'trilbys',
|
||||
'turf' => 'turfs'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Singular inflector rules
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_singular = array(
|
||||
'rules' => array(
|
||||
'/(s)tatuses$/i' => '\1\2tatus',
|
||||
'/^(.*)(menu)s$/i' => '\1\2',
|
||||
'/(quiz)zes$/i' => '\\1',
|
||||
'/(matr)ices$/i' => '\1ix',
|
||||
'/(vert|ind)ices$/i' => '\1ex',
|
||||
'/^(ox)en/i' => '\1',
|
||||
'/(alias)(es)*$/i' => '\1',
|
||||
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
|
||||
'/([ftw]ax)es/i' => '\1',
|
||||
'/(cris|ax|test)es$/i' => '\1is',
|
||||
'/(shoe|slave)s$/i' => '\1',
|
||||
'/(o)es$/i' => '\1',
|
||||
'/ouses$/' => 'ouse',
|
||||
'/([^a])uses$/' => '\1us',
|
||||
'/([m|l])ice$/i' => '\1ouse',
|
||||
'/(x|ch|ss|sh)es$/i' => '\1',
|
||||
'/(m)ovies$/i' => '\1\2ovie',
|
||||
'/(s)eries$/i' => '\1\2eries',
|
||||
'/([^aeiouy]|qu)ies$/i' => '\1y',
|
||||
'/([lr])ves$/i' => '\1f',
|
||||
'/(tive)s$/i' => '\1',
|
||||
'/(hive)s$/i' => '\1',
|
||||
'/(drive)s$/i' => '\1',
|
||||
'/([^fo])ves$/i' => '\1fe',
|
||||
'/(^analy)ses$/i' => '\1sis',
|
||||
'/(analy|ba|diagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
|
||||
'/([ti])a$/i' => '\1um',
|
||||
'/(p)eople$/i' => '\1\2erson',
|
||||
'/(m)en$/i' => '\1an',
|
||||
'/(c)hildren$/i' => '\1\2hild',
|
||||
'/(n)ews$/i' => '\1\2ews',
|
||||
'/eaus$/' => 'eau',
|
||||
'/^(.*us)$/' => '\\1',
|
||||
'/s$/i' => ''
|
||||
),
|
||||
'uninflected' => array(
|
||||
'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', '.*ss'
|
||||
),
|
||||
'irregular' => array(
|
||||
'waves' => 'wave'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Words that should not be inflected
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_uninflected = array(
|
||||
'Amoyese', 'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus',
|
||||
'carp', 'chassis', 'clippers', 'cod', 'coitus', 'Congoese', 'contretemps', 'corps',
|
||||
'debris', 'diabetes', 'djinn', 'eland', 'elk', 'equipment', 'Faroese', 'flounder',
|
||||
'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
|
||||
'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings',
|
||||
'jackanapes', 'Kiplingese', 'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media',
|
||||
'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese',
|
||||
'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese',
|
||||
'proceedings', 'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors',
|
||||
'sea[- ]bass', 'series', 'Shavese', 'shears', 'siemens', 'species', 'swine', 'testes',
|
||||
'trousers', 'trout','tuna', 'Vermontese', 'Wenchowese', 'whiting', 'wildebeest',
|
||||
'Yengeese'
|
||||
);
|
||||
|
||||
/**
|
||||
* Default map of accented and special characters to ASCII characters
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_transliteration = array(
|
||||
'/ä|æ|ǽ/' => 'ae',
|
||||
'/ö|œ/' => 'oe',
|
||||
'/ü/' => 'ue',
|
||||
'/Ä/' => 'Ae',
|
||||
'/Ü/' => 'Ue',
|
||||
'/Ö/' => 'Oe',
|
||||
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A',
|
||||
'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a',
|
||||
'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
|
||||
'/ç|ć|ĉ|ċ|č/' => 'c',
|
||||
'/Ð|Ď|Đ/' => 'D',
|
||||
'/ð|ď|đ/' => 'd',
|
||||
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E',
|
||||
'/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e',
|
||||
'/Ĝ|Ğ|Ġ|Ģ/' => 'G',
|
||||
'/ĝ|ğ|ġ|ģ/' => 'g',
|
||||
'/Ĥ|Ħ/' => 'H',
|
||||
'/ĥ|ħ/' => 'h',
|
||||
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I',
|
||||
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i',
|
||||
'/Ĵ/' => 'J',
|
||||
'/ĵ/' => 'j',
|
||||
'/Ķ/' => 'K',
|
||||
'/ķ/' => 'k',
|
||||
'/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L',
|
||||
'/ĺ|ļ|ľ|ŀ|ł/' => 'l',
|
||||
'/Ñ|Ń|Ņ|Ň/' => 'N',
|
||||
'/ñ|ń|ņ|ň|ʼn/' => 'n',
|
||||
'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O',
|
||||
'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o',
|
||||
'/Ŕ|Ŗ|Ř/' => 'R',
|
||||
'/ŕ|ŗ|ř/' => 'r',
|
||||
'/Ś|Ŝ|Ş|Š/' => 'S',
|
||||
'/ś|ŝ|ş|š|ſ/' => 's',
|
||||
'/Ţ|Ť|Ŧ/' => 'T',
|
||||
'/ţ|ť|ŧ/' => 't',
|
||||
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
|
||||
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u',
|
||||
'/Ý|Ÿ|Ŷ/' => 'Y',
|
||||
'/ý|ÿ|ŷ/' => 'y',
|
||||
'/Ŵ/' => 'W',
|
||||
'/ŵ/' => 'w',
|
||||
'/Ź|Ż|Ž/' => 'Z',
|
||||
'/ź|ż|ž/' => 'z',
|
||||
'/Æ|Ǽ/' => 'AE',
|
||||
'/ß/'=> 'ss',
|
||||
'/IJ/' => 'IJ',
|
||||
'/ij/' => 'ij',
|
||||
'/Œ/' => 'OE',
|
||||
'/ƒ/' => 'f'
|
||||
);
|
||||
|
||||
/**
|
||||
* Cached array identity map of pluralized words.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_pluralized = array();
|
||||
|
||||
/**
|
||||
* Cached array identity map of singularized words.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_singularized = array();
|
||||
|
||||
/**
|
||||
* Cached Underscore Inflections
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_underscore = array();
|
||||
|
||||
/**
|
||||
* Cached Camelize Inflections
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_camelize = array();
|
||||
|
||||
/**
|
||||
* Classify cached inflecctions
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_classify = array();
|
||||
|
||||
/**
|
||||
* Tablize cached inflections
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_tableize = array();
|
||||
|
||||
/**
|
||||
* Humanize cached inflections
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_humanize = array();
|
||||
|
||||
/**
|
||||
* Gets a reference to the Inflector object instance
|
||||
*
|
||||
* @return object
|
||||
* @access public
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
|
||||
if (!$instance) {
|
||||
$instance[0] =& new Inflector();
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache inflected values, and return if already available
|
||||
*
|
||||
* @param string $type Inflection type
|
||||
* @param string $key Original value
|
||||
* @param string $value Inflected value
|
||||
* @return string Inflected value, from cache
|
||||
* @access protected
|
||||
*/
|
||||
function _cache($type, $key, $value = false) {
|
||||
$key = '_' . $key;
|
||||
$type = '_' . $type;
|
||||
if ($value !== false) {
|
||||
$this->{$type}[$key] = $value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!isset($this->{$type}[$key])) {
|
||||
return false;
|
||||
}
|
||||
return $this->{$type}[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom inflection $rules, of either 'plural', 'singular' or 'transliteration' $type.
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* {{{
|
||||
* Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables'));
|
||||
* Inflector::rules('plural', array(
|
||||
* 'rules' => array('/^(inflect)ors$/i' => '\1ables'),
|
||||
* 'uninflected' => array('dontinflectme'),
|
||||
* 'irregular' => array('red' => 'redlings')
|
||||
* ));
|
||||
* Inflector::rules('transliteration', array('/å/' => 'aa'));
|
||||
* }}}
|
||||
*
|
||||
* @param string $type The type of inflection, either 'plural', 'singular' or 'transliteration'
|
||||
* @param array $rules Array of rules to be added.
|
||||
* @param boolean $reset If true, will unset default inflections for all
|
||||
* new rules that are being defined in $rules.
|
||||
* @access public
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
function rules($type, $rules, $reset = false) {
|
||||
$_this =& Inflector::getInstance();
|
||||
$var = '_'.$type;
|
||||
|
||||
switch ($type) {
|
||||
case 'transliteration':
|
||||
if ($reset) {
|
||||
$_this->_transliteration = $rules;
|
||||
} else {
|
||||
$_this->_transliteration = $rules + $_this->_transliteration;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach ($rules as $rule => $pattern) {
|
||||
if (is_array($pattern)) {
|
||||
if ($reset) {
|
||||
$_this->{$var}[$rule] = $pattern;
|
||||
} else {
|
||||
$_this->{$var}[$rule] = array_merge($pattern, $_this->{$var}[$rule]);
|
||||
}
|
||||
unset($rules[$rule], $_this->{$var}['cache' . ucfirst($rule)]);
|
||||
if (isset($_this->{$var}['merged'][$rule])) {
|
||||
unset($_this->{$var}['merged'][$rule]);
|
||||
}
|
||||
if ($type === 'plural') {
|
||||
$_this->_pluralized = $_this->_tableize = array();
|
||||
} elseif ($type === 'singular') {
|
||||
$_this->_singularized = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
$_this->{$var}['rules'] = array_merge($rules, $_this->{$var}['rules']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $word in plural form.
|
||||
*
|
||||
* @param string $word Word in singular
|
||||
* @return string Word in plural
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function pluralize($word) {
|
||||
$_this =& Inflector::getInstance();
|
||||
|
||||
if (isset($_this->_pluralized[$word])) {
|
||||
return $_this->_pluralized[$word];
|
||||
}
|
||||
|
||||
if (!isset($_this->_plural['merged']['irregular'])) {
|
||||
$_this->_plural['merged']['irregular'] = $_this->_plural['irregular'];
|
||||
}
|
||||
|
||||
if (!isset($_this->plural['merged']['uninflected'])) {
|
||||
$_this->_plural['merged']['uninflected'] = array_merge($_this->_plural['uninflected'], $_this->_uninflected);
|
||||
}
|
||||
|
||||
if (!isset($_this->_plural['cacheUninflected']) || !isset($_this->_plural['cacheIrregular'])) {
|
||||
$_this->_plural['cacheUninflected'] = '(?:' . implode('|', $_this->_plural['merged']['uninflected']) . ')';
|
||||
$_this->_plural['cacheIrregular'] = '(?:' . implode('|', array_keys($_this->_plural['merged']['irregular'])) . ')';
|
||||
}
|
||||
|
||||
if (preg_match('/(.*)\\b(' . $_this->_plural['cacheIrregular'] . ')$/i', $word, $regs)) {
|
||||
$_this->_pluralized[$word] = $regs[1] . substr($word, 0, 1) . substr($_this->_plural['merged']['irregular'][strtolower($regs[2])], 1);
|
||||
return $_this->_pluralized[$word];
|
||||
}
|
||||
|
||||
if (preg_match('/^(' . $_this->_plural['cacheUninflected'] . ')$/i', $word, $regs)) {
|
||||
$_this->_pluralized[$word] = $word;
|
||||
return $word;
|
||||
}
|
||||
|
||||
foreach ($_this->_plural['rules'] as $rule => $replacement) {
|
||||
if (preg_match($rule, $word)) {
|
||||
$_this->_pluralized[$word] = preg_replace($rule, $replacement, $word);
|
||||
return $_this->_pluralized[$word];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $word in singular form.
|
||||
*
|
||||
* @param string $word Word in plural
|
||||
* @return string Word in singular
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function singularize($word) {
|
||||
$_this =& Inflector::getInstance();
|
||||
|
||||
if (isset($_this->_singularized[$word])) {
|
||||
return $_this->_singularized[$word];
|
||||
}
|
||||
|
||||
if (!isset($_this->_singular['merged']['uninflected'])) {
|
||||
$_this->_singular['merged']['uninflected'] = array_merge($_this->_singular['uninflected'], $_this->_uninflected);
|
||||
}
|
||||
|
||||
if (!isset($_this->_singular['merged']['irregular'])) {
|
||||
$_this->_singular['merged']['irregular'] = array_merge($_this->_singular['irregular'], array_flip($_this->_plural['irregular']));
|
||||
}
|
||||
|
||||
if (!isset($_this->_singular['cacheUninflected']) || !isset($_this->_singular['cacheIrregular'])) {
|
||||
$_this->_singular['cacheUninflected'] = '(?:' . join( '|', $_this->_singular['merged']['uninflected']) . ')';
|
||||
$_this->_singular['cacheIrregular'] = '(?:' . join( '|', array_keys($_this->_singular['merged']['irregular'])) . ')';
|
||||
}
|
||||
|
||||
if (preg_match('/(.*)\\b(' . $_this->_singular['cacheIrregular'] . ')$/i', $word, $regs)) {
|
||||
$_this->_singularized[$word] = $regs[1] . substr($word, 0, 1) . substr($_this->_singular['merged']['irregular'][strtolower($regs[2])], 1);
|
||||
return $_this->_singularized[$word];
|
||||
}
|
||||
|
||||
if (preg_match('/^(' . $_this->_singular['cacheUninflected'] . ')$/i', $word, $regs)) {
|
||||
$_this->_singularized[$word] = $word;
|
||||
return $word;
|
||||
}
|
||||
|
||||
foreach ($_this->_singular['rules'] as $rule => $replacement) {
|
||||
if (preg_match($rule, $word)) {
|
||||
$_this->_singularized[$word] = preg_replace($rule, $replacement, $word);
|
||||
return $_this->_singularized[$word];
|
||||
}
|
||||
}
|
||||
$_this->_singularized[$word] = $word;
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given lower_case_and_underscored_word as a CamelCased word.
|
||||
*
|
||||
* @param string $lower_case_and_underscored_word Word to camelize
|
||||
* @return string Camelized word. LikeThis.
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function camelize($lowerCaseAndUnderscoredWord) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) {
|
||||
$result = str_replace(' ', '', Inflector::humanize($lowerCaseAndUnderscoredWord));
|
||||
$_this->_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given camelCasedWord as an underscored_word.
|
||||
*
|
||||
* @param string $camelCasedWord Camel-cased word to be "underscorized"
|
||||
* @return string Underscore-syntaxed version of the $camelCasedWord
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function underscore($camelCasedWord) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $camelCasedWord))) {
|
||||
$result = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord));
|
||||
$_this->_cache(__FUNCTION__, $camelCasedWord, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given underscored_word_group as a Human Readable Word Group.
|
||||
* (Underscores are replaced by spaces and capitalized following words.)
|
||||
*
|
||||
* @param string $lower_case_and_underscored_word String to be made more readable
|
||||
* @return string Human-readable string
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function humanize($lowerCaseAndUnderscoredWord) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) {
|
||||
$result = ucwords(str_replace('_', ' ', $lowerCaseAndUnderscoredWord));
|
||||
$_this->_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns corresponding table name for given model $className. ("people" for the model class "Person").
|
||||
*
|
||||
* @param string $className Name of class to get database table name for
|
||||
* @return string Name of the database table for given class
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function tableize($className) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $className))) {
|
||||
$result = Inflector::pluralize(Inflector::underscore($className));
|
||||
$_this->_cache(__FUNCTION__, $className, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Cake model class name ("Person" for the database table "people".) for given database table.
|
||||
*
|
||||
* @param string $tableName Name of database table to get class name for
|
||||
* @return string Class name
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function classify($tableName) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $tableName))) {
|
||||
$result = Inflector::camelize(Inflector::singularize($tableName));
|
||||
$_this->_cache(__FUNCTION__, $tableName, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns camelBacked version of an underscored string.
|
||||
*
|
||||
* @param string $string
|
||||
* @return string in variable form
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function variable($string) {
|
||||
$_this =& Inflector::getInstance();
|
||||
if (!($result = $_this->_cache(__FUNCTION__, $string))) {
|
||||
$string2 = Inflector::camelize(Inflector::underscore($string));
|
||||
$replace = strtolower(substr($string2, 0, 1));
|
||||
$result = preg_replace('/\\w/', $replace, $string2, 1);
|
||||
$_this->_cache(__FUNCTION__, $string, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with all spaces converted to underscores (by default), accented
|
||||
* characters converted to non-accented characters, and non word characters removed.
|
||||
*
|
||||
* @param string $string the string you want to slug
|
||||
* @param string $replacement will replace keys in map
|
||||
* @param array $map extra elements to map to the replacement
|
||||
* @deprecated $map param will be removed in future versions. Use Inflector::rules() instead
|
||||
* @return string
|
||||
* @access public
|
||||
* @static
|
||||
* @link http://book.cakephp.org/view/1479/Class-methods
|
||||
*/
|
||||
function slug($string, $replacement = '_', $map = array()) {
|
||||
$_this =& Inflector::getInstance();
|
||||
|
||||
if (is_array($replacement)) {
|
||||
$map = $replacement;
|
||||
$replacement = '_';
|
||||
}
|
||||
$quotedReplacement = preg_quote($replacement, '/');
|
||||
|
||||
$merge = array(
|
||||
'/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
|
||||
'/\\s+/' => $replacement,
|
||||
sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
|
||||
);
|
||||
|
||||
$map = $map + $_this->_transliteration + $merge;
|
||||
return preg_replace(array_keys($map), array_values($map), $string);
|
||||
}
|
||||
}
|
||||
488
web-cake/html/cake/libs/l10n.php
Normal file
488
web-cake/html/cake/libs/l10n.php
Normal file
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
/**
|
||||
* Localization
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0.4116
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Localization
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class L10n extends Object {
|
||||
|
||||
/**
|
||||
* The language for current locale
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $language = 'English (United States)';
|
||||
|
||||
/**
|
||||
* Locale search paths
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $languagePath = array('eng');
|
||||
|
||||
/**
|
||||
* ISO 639-3 for current locale
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $lang = 'eng';
|
||||
|
||||
/**
|
||||
* Locale
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $locale = 'en_us';
|
||||
|
||||
/**
|
||||
* Default ISO 639-3 language.
|
||||
*
|
||||
* DEFAULT_LANGUAGE is defined in an application this will be set as a fall back
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $default = null;
|
||||
|
||||
/**
|
||||
* Encoding used for current locale
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* Text direction for current locale
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $direction = 'ltr';
|
||||
|
||||
/**
|
||||
* Set to true if a locale is found
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $found = false;
|
||||
|
||||
/**
|
||||
* Maps ISO 639-3 to I10n::__l10nCatalog
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__l10nMap = array(/* Afrikaans */ 'afr' => 'af',
|
||||
/* Albanian */ 'alb' => 'sq',
|
||||
/* Arabic */ 'ara' => 'ar',
|
||||
/* Armenian - Armenia */ 'hye' => 'hy',
|
||||
/* Basque */ 'baq' => 'eu',
|
||||
/* Bosnian */ 'bos' => 'bs',
|
||||
/* Bulgarian */ 'bul' => 'bg',
|
||||
/* Byelorussian */ 'bel' => 'be',
|
||||
/* Catalan */ 'cat' => 'ca',
|
||||
/* Chinese */ 'chi' => 'zh',
|
||||
/* Chinese */ 'zho' => 'zh',
|
||||
/* Croatian */ 'hrv' => 'hr',
|
||||
/* Czech */ 'cze' => 'cs',
|
||||
/* Czech */ 'ces' => 'cs',
|
||||
/* Danish */ 'dan' => 'da',
|
||||
/* Dutch (Standard) */ 'dut' => 'nl',
|
||||
/* Dutch (Standard) */ 'nld' => 'nl',
|
||||
/* English */ 'eng' => 'en',
|
||||
/* Estonian */ 'est' => 'et',
|
||||
/* Faeroese */ 'fao' => 'fo',
|
||||
/* Farsi */ 'fas' => 'fa',
|
||||
/* Farsi */ 'per' => 'fa',
|
||||
/* Finnish */ 'fin' => 'fi',
|
||||
/* French (Standard) */ 'fre' => 'fr',
|
||||
/* French (Standard) */ 'fra' => 'fr',
|
||||
/* Gaelic (Scots) */ 'gla' => 'gd',
|
||||
/* Galician */ 'glg' => 'gl',
|
||||
/* German (Standard) */ 'deu' => 'de',
|
||||
/* German (Standard) */ 'ger' => 'de',
|
||||
/* Greek */ 'gre' => 'el',
|
||||
/* Greek */ 'ell' => 'el',
|
||||
/* Hebrew */ 'heb' => 'he',
|
||||
/* Hindi */ 'hin' => 'hi',
|
||||
/* Hungarian */ 'hun' => 'hu',
|
||||
/* Icelandic */ 'ice' => 'is',
|
||||
/* Icelandic */ 'isl' => 'is',
|
||||
/* Indonesian */ 'ind' => 'id',
|
||||
/* Irish */ 'gle' => 'ga',
|
||||
/* Italian */ 'ita' => 'it',
|
||||
/* Japanese */ 'jpn' => 'ja',
|
||||
/* Korean */ 'kor' => 'ko',
|
||||
/* Latvian */ 'lav' => 'lv',
|
||||
/* Lithuanian */ 'lit' => 'lt',
|
||||
/* Macedonian */ 'mac' => 'mk',
|
||||
/* Macedonian */ 'mkd' => 'mk',
|
||||
/* Malaysian */ 'may' => 'ms',
|
||||
/* Malaysian */ 'msa' => 'ms',
|
||||
/* Maltese */ 'mlt' => 'mt',
|
||||
/* Norwegian */ 'nor' => 'no',
|
||||
/* Norwegian Bokmal */ 'nob' => 'nb',
|
||||
/* Norwegian Nynorsk */ 'nno' => 'nn',
|
||||
/* Polish */ 'pol' => 'pl',
|
||||
/* Portuguese (Portugal) */ 'por' => 'pt',
|
||||
/* Rhaeto-Romanic */ 'roh' => 'rm',
|
||||
/* Romanian */ 'rum' => 'ro',
|
||||
/* Romanian */ 'ron' => 'ro',
|
||||
/* Russian */ 'rus' => 'ru',
|
||||
/* Sami (Lappish) */ 'smi' => 'sz',
|
||||
/* Serbian */ 'scc' => 'sr',
|
||||
/* Serbian */ 'srp' => 'sr',
|
||||
/* Slovak */ 'slo' => 'sk',
|
||||
/* Slovak */ 'slk' => 'sk',
|
||||
/* Slovenian */ 'slv' => 'sl',
|
||||
/* Sorbian */ 'wen' => 'sb',
|
||||
/* Spanish (Spain - Traditional) */ 'spa' => 'es',
|
||||
/* Swedish */ 'swe' => 'sv',
|
||||
/* Thai */ 'tha' => 'th',
|
||||
/* Tsonga */ 'tso' => 'ts',
|
||||
/* Tswana */ 'tsn' => 'tn',
|
||||
/* Turkish */ 'tur' => 'tr',
|
||||
/* Ukrainian */ 'ukr' => 'uk',
|
||||
/* Urdu */ 'urd' => 'ur',
|
||||
/* Venda */ 'ven' => 've',
|
||||
/* Vietnamese */ 'vie' => 'vi',
|
||||
/* Welsh */ 'cym' => 'cy',
|
||||
/* Xhosa */ 'xho' => 'xh',
|
||||
/* Yiddish */ 'yid' => 'yi',
|
||||
/* Zulu */ 'zul' => 'zu');
|
||||
|
||||
/**
|
||||
* HTTP_ACCEPT_LANGUAGE catalog
|
||||
*
|
||||
* holds all information related to a language
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__l10nCatalog = array('af' => array('language' => 'Afrikaans', 'locale' => 'afr', 'localeFallback' => 'afr', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ar' => array('language' => 'Arabic', 'locale' => 'ara', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-ae' => array('language' => 'Arabic (U.A.E.)', 'locale' => 'ar_ae', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-bh' => array('language' => 'Arabic (Bahrain)', 'locale' => 'ar_bh', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-dz' => array('language' => 'Arabic (Algeria)', 'locale' => 'ar_dz', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-eg' => array('language' => 'Arabic (Egypt)', 'locale' => 'ar_eg', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-iq' => array('language' => 'Arabic (Iraq)', 'locale' => 'ar_iq', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-jo' => array('language' => 'Arabic (Jordan)', 'locale' => 'ar_jo', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-kw' => array('language' => 'Arabic (Kuwait)', 'locale' => 'ar_kw', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-lb' => array('language' => 'Arabic (Lebanon)', 'locale' => 'ar_lb', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-ly' => array('language' => 'Arabic (Libya)', 'locale' => 'ar_ly', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-ma' => array('language' => 'Arabic (Morocco)', 'locale' => 'ar_ma', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-om' => array('language' => 'Arabic (Oman)', 'locale' => 'ar_om', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-qa' => array('language' => 'Arabic (Qatar)', 'locale' => 'ar_qa', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-sa' => array('language' => 'Arabic (Saudi Arabia)', 'locale' => 'ar_sa', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-sy' => array('language' => 'Arabic (Syria)', 'locale' => 'ar_sy', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-tn' => array('language' => 'Arabic (Tunisia)', 'locale' => 'ar_tn', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'ar-ye' => array('language' => 'Arabic (Yemen)', 'locale' => 'ar_ye', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'be' => array('language' => 'Byelorussian', 'locale' => 'bel', 'localeFallback' => 'bel', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'bg' => array('language' => 'Bulgarian', 'locale' => 'bul', 'localeFallback' => 'bul', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'bs' => array('language' => 'Bosnian', 'locale' => 'bos', 'localeFallback' => 'bos', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ca' => array('language' => 'Catalan', 'locale' => 'cat', 'localeFallback' => 'cat', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'cs' => array('language' => 'Czech', 'locale' => 'cze', 'localeFallback' => 'cze', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'da' => array('language' => 'Danish', 'locale' => 'dan', 'localeFallback' => 'dan', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de-at' => array('language' => 'German (Austria)', 'locale' => 'de_at', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de-ch' => array('language' => 'German (Swiss)', 'locale' => 'de_ch', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de-de' => array('language' => 'German (Germany)', 'locale' => 'de_de', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de-li' => array('language' => 'German (Liechtenstein)', 'locale' => 'de_li', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'de-lu' => array('language' => 'German (Luxembourg)', 'locale' => 'de_lu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'e' => array('language' => 'Greek', 'locale' => 'gre', 'localeFallback' => 'gre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'el' => array('language' => 'Greek', 'locale' => 'gre', 'localeFallback' => 'gre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en' => array('language' => 'English', 'locale' => 'eng', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-au' => array('language' => 'English (Australian)', 'locale' => 'en_au', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-bz' => array('language' => 'English (Belize)', 'locale' => 'en_bz', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-ca' => array('language' => 'English (Canadian)', 'locale' => 'en_ca', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-gb' => array('language' => 'English (British)', 'locale' => 'en_gb', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-ie' => array('language' => 'English (Ireland)', 'locale' => 'en_ie', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-jm' => array('language' => 'English (Jamaica)', 'locale' => 'en_jm', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-nz' => array('language' => 'English (New Zealand)', 'locale' => 'en_nz', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-tt' => array('language' => 'English (Trinidad)', 'locale' => 'en_tt', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-us' => array('language' => 'English (United States)', 'locale' => 'en_us', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'en-za' => array('language' => 'English (South Africa)', 'locale' => 'en_za', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es' => array('language' => 'Spanish (Spain - Traditional)', 'locale' => 'spa', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-ar' => array('language' => 'Spanish (Argentina)', 'locale' => 'es_ar', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-bo' => array('language' => 'Spanish (Bolivia)', 'locale' => 'es_bo', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-cl' => array('language' => 'Spanish (Chile)', 'locale' => 'es_cl', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-co' => array('language' => 'Spanish (Colombia)', 'locale' => 'es_co', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-cr' => array('language' => 'Spanish (Costa Rica)', 'locale' => 'es_cr', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-do' => array('language' => 'Spanish (Dominican Republic)', 'locale' => 'es_do', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-ec' => array('language' => 'Spanish (Ecuador)', 'locale' => 'es_ec', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-es' => array('language' => 'Spanish (Spain)', 'locale' => 'es_es', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-gt' => array('language' => 'Spanish (Guatemala)', 'locale' => 'es_gt', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-hn' => array('language' => 'Spanish (Honduras)', 'locale' => 'es_hn', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-mx' => array('language' => 'Spanish (Mexican)', 'locale' => 'es_mx', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-ni' => array('language' => 'Spanish (Nicaragua)', 'locale' => 'es_ni', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-pa' => array('language' => 'Spanish (Panama)', 'locale' => 'es_pa', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-pe' => array('language' => 'Spanish (Peru)', 'locale' => 'es_pe', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-pr' => array('language' => 'Spanish (Puerto Rico)', 'locale' => 'es_pr', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-py' => array('language' => 'Spanish (Paraguay)', 'locale' => 'es_py', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-sv' => array('language' => 'Spanish (El Salvador)', 'locale' => 'es_sv', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-uy' => array('language' => 'Spanish (Uruguay)', 'locale' => 'es_uy', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'es-ve' => array('language' => 'Spanish (Venezuela)', 'locale' => 'es_ve', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'et' => array('language' => 'Estonian', 'locale' => 'est', 'localeFallback' => 'est', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'eu' => array('language' => 'Basque', 'locale' => 'baq', 'localeFallback' => 'baq', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fa' => array('language' => 'Farsi', 'locale' => 'per', 'localeFallback' => 'per', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'fi' => array('language' => 'Finnish', 'locale' => 'fin', 'localeFallback' => 'fin', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fo' => array('language' => 'Faeroese', 'locale' => 'fao', 'localeFallback' => 'fao', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr' => array('language' => 'French (Standard)', 'locale' => 'fre', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ga' => array('language' => 'Irish', 'locale' => 'gle', 'localeFallback' => 'gle', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'gd' => array('language' => 'Gaelic (Scots)', 'locale' => 'gla', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'gd-ie' => array('language' => 'Gaelic (Irish)', 'locale' => 'gd_ie', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'gl' => array('language' => 'Galician', 'locale' => 'glg', 'localeFallback' => 'glg', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'he' => array('language' => 'Hebrew', 'locale' => 'heb', 'localeFallback' => 'heb', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
'hi' => array('language' => 'Hindi', 'locale' => 'hin', 'localeFallback' => 'hin', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'hr' => array('language' => 'Croatian', 'locale' => 'hrv', 'localeFallback' => 'hrv', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'hu' => array('language' => 'Hungarian', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'in' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'is' => array('language' => 'Icelandic', 'locale' => 'ice', 'localeFallback' => 'ice', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ko' => array('language' => 'Korean', 'locale' => 'kor', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
|
||||
'ko-kp' => array('language' => 'Korea (North)', 'locale' => 'ko_kp', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
|
||||
'ko-kr' => array('language' => 'Korea (South)', 'locale' => 'ko_kr', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
|
||||
'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'),
|
||||
'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ms' => array('language' => 'Malaysian', 'locale' => 'may', 'localeFallback' => 'may', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'mt' => array('language' => 'Maltese', 'locale' => 'mlt', 'localeFallback' => 'mlt', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'n' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'nb' => array('language' => 'Norwegian Bokmal', 'locale' => 'nob', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'nn' => array('language' => 'Norwegian Nynorsk', 'locale' => 'nno', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'p' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'pl' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'pt' => array('language' => 'Portuguese (Portugal)', 'locale' => 'por', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ro' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ru' => array('language' => 'Russian', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ru-mo' => array('language' => 'Russian (Moldavia)', 'locale' => 'ru_mo', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sk' => array('language' => 'Slovak', 'locale' => 'slo', 'localeFallback' => 'slo', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sl' => array('language' => 'Slovenian', 'locale' => 'slv', 'localeFallback' => 'slv', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sq' => array('language' => 'Albanian', 'locale' => 'alb', 'localeFallback' => 'alb', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sr' => array('language' => 'Serbian', 'locale' => 'scc', 'localeFallback' => 'scc', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sv' => array('language' => 'Swedish', 'locale' => 'swe', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sv-fi' => array('language' => 'Swedish (Finland)', 'locale' => 'sv_fi', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sx' => array('language' => 'Sutu', 'locale' => 'sx', 'localeFallback' => 'sx', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'sz' => array('language' => 'Sami (Lappish)', 'locale' => 'smi', 'localeFallback' => 'smi', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'th' => array('language' => 'Thai', 'locale' => 'tha', 'localeFallback' => 'tha', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'tn' => array('language' => 'Tswana', 'locale' => 'tsn', 'localeFallback' => 'tsn', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'tr' => array('language' => 'Turkish', 'locale' => 'tur', 'localeFallback' => 'tur', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ts' => array('language' => 'Tsonga', 'locale' => 'tso', 'localeFallback' => 'tso', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'uk' => array('language' => 'Ukrainian', 'locale' => 'ukr', 'localeFallback' => 'ukr', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'ur' => array('language' => 'Urdu', 'locale' => 'urd', 'localeFallback' => 'urd', 'charset' => 'utf-8', 'direction' => 'rtl'),
|
||||
've' => array('language' => 'Venda', 'locale' => 'ven', 'localeFallback' => 'ven', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'vi' => array('language' => 'Vietnamese', 'locale' => 'vie', 'localeFallback' => 'vie', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'cy' => array('language' => 'Welsh', 'locale' => 'cym', 'localeFallback' => 'cym', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'xh' => array('language' => 'Xhosa', 'locale' => 'xho', 'localeFallback' => 'xho', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'yi' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'zh' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'chi', 'charset' => 'GB2312', 'direction' => 'ltr'),
|
||||
'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
|
||||
'zu' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr'));
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
function __construct() {
|
||||
if (defined('DEFAULT_LANGUAGE')) {
|
||||
$this->default = DEFAULT_LANGUAGE;
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the settings for $language.
|
||||
* If $language is null it attempt to get settings from L10n::__autoLanguage(); if this fails
|
||||
* the method will get the settings from L10n::__setLanguage();
|
||||
*
|
||||
* @param string $language Language (if null will use DEFAULT_LANGUAGE if defined)
|
||||
* @access public
|
||||
*/
|
||||
function get($language = null) {
|
||||
if ($language !== null) {
|
||||
return $this->__setLanguage($language);
|
||||
} elseif ($this->__autoLanguage() === false) {
|
||||
return $this->__setLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class vars to correct values for $language.
|
||||
* If $language is null it will use the DEFAULT_LANGUAGE if defined
|
||||
*
|
||||
* @param string $language Language (if null will use DEFAULT_LANGUAGE if defined)
|
||||
* @access private
|
||||
*/
|
||||
function __setLanguage($language = null) {
|
||||
$langKey = null;
|
||||
if ($language !== null && isset($this->__l10nMap[$language]) && isset($this->__l10nCatalog[$this->__l10nMap[$language]])) {
|
||||
$langKey = $this->__l10nMap[$language];
|
||||
} else if ($language !== null && isset($this->__l10nCatalog[$language])) {
|
||||
$langKey = $language;
|
||||
} else if (defined('DEFAULT_LANGUAGE')) {
|
||||
$langKey = $language = DEFAULT_LANGUAGE;
|
||||
}
|
||||
|
||||
if ($langKey !== null && isset($this->__l10nCatalog[$langKey])) {
|
||||
$this->language = $this->__l10nCatalog[$langKey]['language'];
|
||||
$this->languagePath = array(
|
||||
$this->__l10nCatalog[$langKey]['locale'],
|
||||
$this->__l10nCatalog[$langKey]['localeFallback']
|
||||
);
|
||||
$this->lang = $language;
|
||||
$this->locale = $this->__l10nCatalog[$langKey]['locale'];
|
||||
$this->charset = $this->__l10nCatalog[$langKey]['charset'];
|
||||
$this->direction = $this->__l10nCatalog[$langKey]['direction'];
|
||||
} else {
|
||||
$this->lang = $language;
|
||||
$this->languagePath = array($language);
|
||||
}
|
||||
|
||||
if ($this->default) {
|
||||
if (isset($this->__l10nMap[$this->default]) && isset($this->__l10nCatalog[$this->__l10nMap[$this->default]])) {
|
||||
$this->languagePath[] = $this->__l10nCatalog[$this->__l10nMap[$this->default]]['localeFallback'];
|
||||
} else if (isset($this->__l10nCatalog[$this->default])) {
|
||||
$this->languagePath[] = $this->__l10nCatalog[$this->default]['localeFallback'];
|
||||
}
|
||||
}
|
||||
$this->found = true;
|
||||
|
||||
if (Configure::read('Config.language') === null) {
|
||||
Configure::write('Config.language', $this->lang);
|
||||
}
|
||||
|
||||
if ($language) {
|
||||
return $language;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the locale settings based on the HTTP_ACCEPT_LANGUAGE variable
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __autoLanguage() {
|
||||
$_detectableLanguages = preg_split('/[,;]/', env('HTTP_ACCEPT_LANGUAGE'));
|
||||
foreach ($_detectableLanguages as $key => $langKey) {
|
||||
$langKey = strtolower($langKey);
|
||||
if (strpos($langKey, '_') !== false) {
|
||||
$langKey = str_replace('_', '-', $langKey);
|
||||
}
|
||||
|
||||
if (isset($this->__l10nCatalog[$langKey])) {
|
||||
$this->__setLanguage($langKey);
|
||||
return true;
|
||||
} else if (strpos($langKey, '-') !== false) {
|
||||
$langKey = substr($langKey, 0, 2);
|
||||
if (isset($this->__l10nCatalog[$langKey])) {
|
||||
$this->__setLanguage($langKey);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find locale for language, or language for locale
|
||||
*
|
||||
* @param mixed $mixed 2/3 char string (language/locale), array of those strings, or null
|
||||
* @return mixed string language/locale, array of those values, whole map as an array,
|
||||
* or false when language/locale doesn't exist
|
||||
* @access public
|
||||
*/
|
||||
function map($mixed = null) {
|
||||
if (is_array($mixed)) {
|
||||
$result = array();
|
||||
foreach ($mixed as $_mixed) {
|
||||
if ($_result = $this->map($_mixed)) {
|
||||
$result[$_mixed] = $_result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
} else if (is_string($mixed)) {
|
||||
if (strlen($mixed) === 2 && in_array($mixed, $this->__l10nMap)) {
|
||||
return array_search($mixed, $this->__l10nMap);
|
||||
} else if (isset($this->__l10nMap[$mixed])) {
|
||||
return $this->__l10nMap[$mixed];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $this->__l10nMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find catalog record for requested language
|
||||
*
|
||||
* @param mixed $language string requested language, array of requested languages, or null for whole catalog
|
||||
* @return mixed array catalog record for requested language, array of catalog records, whole catalog,
|
||||
* or false when language doesn't exist
|
||||
* @access public
|
||||
*/
|
||||
function catalog($language = null) {
|
||||
if (is_array($language)) {
|
||||
$result = array();
|
||||
foreach ($language as $_language) {
|
||||
if ($_result = $this->catalog($_language)) {
|
||||
$result[$_language] = $_result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
} else if (is_string($language)) {
|
||||
if (isset($this->__l10nCatalog[$language])) {
|
||||
return $this->__l10nCatalog[$language];
|
||||
} else if (isset($this->__l10nMap[$language]) && isset($this->__l10nCatalog[$this->__l10nMap[$language]])) {
|
||||
return $this->__l10nCatalog[$this->__l10nMap[$language]];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $this->__l10nCatalog;
|
||||
}
|
||||
}
|
||||
77
web-cake/html/cake/libs/log/file_log.php
Normal file
77
web-cake/html/cake/libs/log/file_log.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* File Storage stream for Logging
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.log
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
if (!class_exists('File')) {
|
||||
require LIBS . 'file.php';
|
||||
}
|
||||
/**
|
||||
* File Storage stream for Logging. Writes logs to different files
|
||||
* based on the type of log it is.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.log
|
||||
*/
|
||||
class FileLog {
|
||||
|
||||
/**
|
||||
* Path to save log files on.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_path = null;
|
||||
|
||||
/**
|
||||
* Constructs a new File Logger.
|
||||
*
|
||||
* Options
|
||||
*
|
||||
* - `path` the path to save logs on.
|
||||
*
|
||||
* @param array $options Options for the FileLog, see above.
|
||||
* @return void
|
||||
*/
|
||||
function FileLog($options = array()) {
|
||||
$options += array('path' => LOGS);
|
||||
$this->_path = $options['path'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements writing to log files.
|
||||
*
|
||||
* @param string $type The type of log you are making.
|
||||
* @param string $message The message you want to log.
|
||||
* @return boolean success of write.
|
||||
*/
|
||||
function write($type, $message) {
|
||||
$debugTypes = array('notice', 'info', 'debug');
|
||||
|
||||
if ($type == 'error' || $type == 'warning') {
|
||||
$filename = $this->_path . 'error.log';
|
||||
} elseif (in_array($type, $debugTypes)) {
|
||||
$filename = $this->_path . 'debug.log';
|
||||
} else {
|
||||
$filename = $this->_path . $type . '.log';
|
||||
}
|
||||
$output = date('Y-m-d H:i:s') . ' ' . ucfirst($type) . ': ' . $message . "\n";
|
||||
$log = new File($filename, true);
|
||||
if ($log->writable()) {
|
||||
return $log->append($output);
|
||||
}
|
||||
}
|
||||
}
|
||||
302
web-cake/html/cake/libs/magic_db.php
Normal file
302
web-cake/html/cake/libs/magic_db.php
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* MagicDb parser and file analyzer
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
if (!class_exists('Object')) {
|
||||
require LIBS . 'object.php';
|
||||
}
|
||||
if (!class_exists('File')) {
|
||||
require LIBS . 'file.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to parse and use the MagicDb for file type analysis
|
||||
*
|
||||
* @package cake.tests
|
||||
* @subpackage cake.tests.cases.libs
|
||||
*/
|
||||
class MagicDb extends Object {
|
||||
|
||||
/**
|
||||
* Holds the parsed MagicDb for this class instance
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $db = array();
|
||||
|
||||
/**
|
||||
* Reads a MagicDb from various formats
|
||||
*
|
||||
* @var $magicDb mixed Can be an array containing the db, a magic db as a string, or a filename pointing to a magic db in .db or magic.db.php format
|
||||
* @return boolean Returns false if reading / validation failed or true on success.
|
||||
* @author Felix
|
||||
*/
|
||||
function read($magicDb = null) {
|
||||
if (!is_string($magicDb) && !is_array($magicDb)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($magicDb) || strpos($magicDb, '# FILE_ID DB') === 0) {
|
||||
$data = $magicDb;
|
||||
} else {
|
||||
$File =& new File($magicDb);
|
||||
if (!$File->exists()) {
|
||||
return false;
|
||||
}
|
||||
if ($File->ext() == 'php') {
|
||||
include($File->pwd());
|
||||
$data = $magicDb;
|
||||
} else {
|
||||
// @TODO: Needs test coverage
|
||||
$data = $File->read();
|
||||
}
|
||||
}
|
||||
|
||||
$magicDb = $this->toArray($data);
|
||||
if (!$this->validates($magicDb)) {
|
||||
return false;
|
||||
}
|
||||
return !!($this->db = $magicDb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a MagicDb $data string into an array or returns the current MagicDb instance as an array
|
||||
*
|
||||
* @param string $data A MagicDb string to turn into an array
|
||||
* @return array A parsed MagicDb array or an empty array if the $data param was invalid. Returns the db property if $data is not set.
|
||||
* @access public
|
||||
*/
|
||||
function toArray($data = null) {
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
if ($data === null) {
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
if (strpos($data, '# FILE_ID DB') !== 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$lines = explode("\r\n", $data);
|
||||
$db = array();
|
||||
|
||||
$validHeader = count($lines) > 3
|
||||
&& preg_match('/^# Date:([0-9]{4}-[0-9]{2}-[0-9]{2})$/', $lines[1], $date)
|
||||
&& preg_match('/^# Source:(.+)$/', $lines[2], $source)
|
||||
&& strlen($lines[3]) == 0;
|
||||
if (!$validHeader) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$db = array('header' => array('Date' => $date[1], 'Source' => $source[1]), 'database' => array());
|
||||
$lines = array_splice($lines, 3);
|
||||
|
||||
$format = array();
|
||||
while (!empty($lines)) {
|
||||
$line = array_shift($lines);
|
||||
if (isset($line[0]) && $line[0] == '#' || empty($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columns = explode("\t", $line);
|
||||
if (in_array($columns[0]{0}, array('>', '&'))) {
|
||||
$format[] = $columns;
|
||||
} elseif (!empty($format)) {
|
||||
$db['database'][] = $format;
|
||||
$format = array($columns);
|
||||
} else {
|
||||
$format = array($columns);
|
||||
}
|
||||
}
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the MagicDb instance or the passed $magicDb is valid
|
||||
*
|
||||
* @param mixed $magicDb A $magicDb string / array to validate (optional)
|
||||
* @return boolean True if the $magicDb / instance db validates, false if not
|
||||
* @access public
|
||||
*/
|
||||
function validates($magicDb = null) {
|
||||
if (is_null($magicDb)) {
|
||||
$magicDb = $this->db;
|
||||
} elseif (!is_array($magicDb)) {
|
||||
$magicDb = $this->toArray($magicDb);
|
||||
}
|
||||
|
||||
return isset($magicDb['header'], $magicDb['database']) && is_array($magicDb['header']) && is_array($magicDb['database']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a given $file using the currently loaded MagicDb information based on the desired $options
|
||||
*
|
||||
* @param string $file Absolute path to the file to analyze
|
||||
* @param array $options TBT
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function analyze($file, $options = array()) {
|
||||
if (!is_string($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
$MagicFileResource =& new MagicFileResource($file);
|
||||
foreach ($this->db['database'] as $format) {
|
||||
$magic = $format[0];
|
||||
$match = $MagicFileResource->test($magic);
|
||||
if ($match === false) {
|
||||
continue;
|
||||
}
|
||||
$matches[] = $magic;
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented class
|
||||
*
|
||||
* @package cake.tests
|
||||
* @subpackage cake.tests.cases.libs
|
||||
*/
|
||||
class MagicFileResource extends Object{
|
||||
|
||||
/**
|
||||
* undocumented variable
|
||||
*
|
||||
* @var unknown
|
||||
* @access public
|
||||
*/
|
||||
var $resource = null;
|
||||
|
||||
/**
|
||||
* undocumented variable
|
||||
*
|
||||
* @var unknown
|
||||
* @access public
|
||||
*/
|
||||
var $offset = 0;
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $file
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function __construct($file) {
|
||||
if (file_exists($file)) {
|
||||
$this->resource =& new File($file);
|
||||
} else {
|
||||
$this->resource = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $magic
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function test($magic) {
|
||||
$offset = null;
|
||||
$type = null;
|
||||
$expected = null;
|
||||
$comment = null;
|
||||
if (isset($magic[0])) {
|
||||
$offset = $magic[0];
|
||||
}
|
||||
if (isset($magic[1])) {
|
||||
$type = $magic[1];
|
||||
}
|
||||
if (isset($magic[2])) {
|
||||
$expected = $magic[2];
|
||||
}
|
||||
if (isset($magic[3])) {
|
||||
$comment = $magic[3];
|
||||
}
|
||||
$val = $this->extract($offset, $type, $expected);
|
||||
return $val == $expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $type
|
||||
* @param unknown $length
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function read($length = null) {
|
||||
if (!is_object($this->resource)) {
|
||||
return substr($this->resource, $this->offset, $length);
|
||||
}
|
||||
return $this->resource->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $type
|
||||
* @param unknown $expected
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function extract($offset, $type, $expected) {
|
||||
switch ($type) {
|
||||
case 'string':
|
||||
$this->offset($offset);
|
||||
$val = $this->read(strlen($expected));
|
||||
if ($val === $expected) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $offset
|
||||
* @param unknown $whence
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function offset($offset = null) {
|
||||
if (is_null($offset)) {
|
||||
if (!is_object($this->resource)) {
|
||||
return $this->offset;
|
||||
}
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
if (!ctype_digit($offset)) {
|
||||
return false;
|
||||
}
|
||||
if (is_object($this->resource)) {
|
||||
$this->resource->offset($offset);
|
||||
} else {
|
||||
$this->offset = $offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
web-cake/html/cake/libs/model/app_model.php
Normal file
35
web-cake/html/cake/libs/model/app_model.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Application model for Cake.
|
||||
*
|
||||
* This file is application-wide model file. You can put all
|
||||
* application-wide model-related methods here.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Application model for Cake.
|
||||
*
|
||||
* This is a placeholder class.
|
||||
* Create the same file in app/app_model.php
|
||||
* Add your application-wide methods to the class, your models will inherit them.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class AppModel extends Model {
|
||||
}
|
||||
123
web-cake/html/cake/libs/model/behaviors/acl.php
Normal file
123
web-cake/html/cake/libs/model/behaviors/acl.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* ACL behavior class.
|
||||
*
|
||||
* Enables objects to easily tie into an ACL system
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2006-2010, Cake Software Foundation, Inc.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
|
||||
* @link http://cakephp.org CakePHP Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @since CakePHP v 1.2.0.4487
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* ACL behavior
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @link http://book.cakephp.org/view/1320/ACL
|
||||
*/
|
||||
class AclBehavior extends ModelBehavior {
|
||||
|
||||
/**
|
||||
* Maps ACL type options to ACL models
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $__typeMaps = array('requester' => 'Aro', 'controlled' => 'Aco');
|
||||
|
||||
/**
|
||||
* Sets up the configuation for the model, and loads ACL models if they haven't been already
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function setup(&$model, $config = array()) {
|
||||
if (is_string($config)) {
|
||||
$config = array('type' => $config);
|
||||
}
|
||||
$this->settings[$model->name] = array_merge(array('type' => 'requester'), (array)$config);
|
||||
$this->settings[$model->name]['type'] = strtolower($this->settings[$model->name]['type']);
|
||||
|
||||
$type = $this->__typeMaps[$this->settings[$model->name]['type']];
|
||||
if (!class_exists('AclNode')) {
|
||||
require LIBS . 'model' . DS . 'db_acl.php';
|
||||
}
|
||||
if (PHP5) {
|
||||
$model->{$type} = ClassRegistry::init($type);
|
||||
} else {
|
||||
$model->{$type} =& ClassRegistry::init($type);
|
||||
}
|
||||
if (!method_exists($model, 'parentNode')) {
|
||||
trigger_error(sprintf(__('Callback parentNode() not defined in %s', true), $model->alias), E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Aro/Aco node for this model
|
||||
*
|
||||
* @param mixed $ref
|
||||
* @return array
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1322/node
|
||||
*/
|
||||
function node(&$model, $ref = null) {
|
||||
$type = $this->__typeMaps[$this->settings[$model->name]['type']];
|
||||
if (empty($ref)) {
|
||||
$ref = array('model' => $model->name, 'foreign_key' => $model->id);
|
||||
}
|
||||
return $model->{$type}->node($ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ARO/ACO node bound to this record
|
||||
*
|
||||
* @param boolean $created True if this is a new record
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterSave(&$model, $created) {
|
||||
$type = $this->__typeMaps[$this->settings[$model->name]['type']];
|
||||
$parent = $model->parentNode();
|
||||
if (!empty($parent)) {
|
||||
$parent = $this->node($model, $parent);
|
||||
}
|
||||
$data = array(
|
||||
'parent_id' => isset($parent[0][$type]['id']) ? $parent[0][$type]['id'] : null,
|
||||
'model' => $model->alias,
|
||||
'foreign_key' => $model->id
|
||||
);
|
||||
if (!$created) {
|
||||
$node = $this->node($model);
|
||||
$data['id'] = isset($node[0][$type]['id']) ? $node[0][$type]['id'] : null;
|
||||
}
|
||||
$model->{$type}->create();
|
||||
$model->{$type}->save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the ARO/ACO node bound to the deleted record
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterDelete(&$model) {
|
||||
$type = $this->__typeMaps[$this->settings[$model->name]['type']];
|
||||
$node = Set::extract($this->node($model), "0.{$type}.id");
|
||||
if (!empty($node)) {
|
||||
$model->{$type}->delete($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
453
web-cake/html/cake/libs/model/behaviors/containable.php
Normal file
453
web-cake/html/cake/libs/model/behaviors/containable.php
Normal file
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
/**
|
||||
* Behavior for binding management.
|
||||
*
|
||||
* Behavior to simplify manipulating a model's bindings when doing a find operation
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.console.libs
|
||||
* @since CakePHP(tm) v 1.2.0.5669
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to allow for dynamic and atomic manipulation of a Model's associations used for a find call. Most useful for limiting
|
||||
* the amount of associations and data returned.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.console.libs
|
||||
* @link http://book.cakephp.org/view/1323/Containable
|
||||
*/
|
||||
class ContainableBehavior extends ModelBehavior {
|
||||
|
||||
/**
|
||||
* Types of relationships available for models
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $types = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
|
||||
|
||||
/**
|
||||
* Runtime configuration for this behavior
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $runtime = array();
|
||||
|
||||
/**
|
||||
* Initiate behavior for the model using specified settings.
|
||||
*
|
||||
* Available settings:
|
||||
*
|
||||
* - recursive: (boolean, optional) set to true to allow containable to automatically
|
||||
* determine the recursiveness level needed to fetch specified models,
|
||||
* and set the model recursiveness to this level. setting it to false
|
||||
* disables this feature. DEFAULTS TO: true
|
||||
* - notices: (boolean, optional) issues E_NOTICES for bindings referenced in a
|
||||
* containable call that are not valid. DEFAULTS TO: true
|
||||
* - autoFields: (boolean, optional) auto-add needed fields to fetch requested
|
||||
* bindings. DEFAULTS TO: true
|
||||
*
|
||||
* @param object $Model Model using the behavior
|
||||
* @param array $settings Settings to override for model.
|
||||
* @access public
|
||||
*/
|
||||
function setup(&$Model, $settings = array()) {
|
||||
if (!isset($this->settings[$Model->alias])) {
|
||||
$this->settings[$Model->alias] = array('recursive' => true, 'notices' => true, 'autoFields' => true);
|
||||
}
|
||||
if (!is_array($settings)) {
|
||||
$settings = array();
|
||||
}
|
||||
$this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs before a find() operation. Used to allow 'contain' setting
|
||||
* as part of the find call, like this:
|
||||
*
|
||||
* `Model->find('all', array('contain' => array('Model1', 'Model2')));`
|
||||
*
|
||||
* {{{
|
||||
* Model->find('all', array('contain' => array(
|
||||
* 'Model1' => array('Model11', 'Model12'),
|
||||
* 'Model2',
|
||||
* 'Model3' => array(
|
||||
* 'Model31' => 'Model311',
|
||||
* 'Model32',
|
||||
* 'Model33' => array('Model331', 'Model332')
|
||||
* )));
|
||||
* }}}
|
||||
*
|
||||
* @param object $Model Model using the behavior
|
||||
* @param array $query Query parameters as set by cake
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function beforeFind(&$Model, $query) {
|
||||
$reset = (isset($query['reset']) ? $query['reset'] : true);
|
||||
$noContain = ((isset($this->runtime[$Model->alias]['contain']) && empty($this->runtime[$Model->alias]['contain'])) || (isset($query['contain']) && empty($query['contain'])));
|
||||
$contain = array();
|
||||
if (isset($this->runtime[$Model->alias]['contain'])) {
|
||||
$contain = $this->runtime[$Model->alias]['contain'];
|
||||
unset($this->runtime[$Model->alias]['contain']);
|
||||
}
|
||||
if (isset($query['contain'])) {
|
||||
$contain = array_merge($contain, (array)$query['contain']);
|
||||
}
|
||||
if ($noContain || !$contain || in_array($contain, array(null, false), true) || (isset($contain[0]) && $contain[0] === null)) {
|
||||
if ($noContain) {
|
||||
$query['recursive'] = -1;
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
if ((isset($contain[0]) && is_bool($contain[0])) || is_bool(end($contain))) {
|
||||
$reset = is_bool(end($contain))
|
||||
? array_pop($contain)
|
||||
: array_shift($contain);
|
||||
}
|
||||
$containments = $this->containments($Model, $contain);
|
||||
$map = $this->containmentsMap($containments);
|
||||
|
||||
$mandatory = array();
|
||||
foreach ($containments['models'] as $name => $model) {
|
||||
$instance =& $model['instance'];
|
||||
$needed = $this->fieldDependencies($instance, $map, false);
|
||||
if (!empty($needed)) {
|
||||
$mandatory = array_merge($mandatory, $needed);
|
||||
}
|
||||
if ($contain) {
|
||||
$backupBindings = array();
|
||||
foreach ($this->types as $relation) {
|
||||
if (!empty($instance->__backAssociation[$relation])) {
|
||||
$backupBindings[$relation] = $instance->__backAssociation[$relation];
|
||||
} else {
|
||||
$backupBindings[$relation] = $instance->{$relation};
|
||||
}
|
||||
}
|
||||
foreach ($this->types as $type) {
|
||||
$unbind = array();
|
||||
foreach ($instance->{$type} as $assoc => $options) {
|
||||
if (!isset($model['keep'][$assoc])) {
|
||||
$unbind[] = $assoc;
|
||||
}
|
||||
}
|
||||
if (!empty($unbind)) {
|
||||
if (!$reset && empty($instance->__backOriginalAssociation)) {
|
||||
$instance->__backOriginalAssociation = $backupBindings;
|
||||
} else if ($reset && empty($instance->__backContainableAssociation)) {
|
||||
$instance->__backContainableAssociation = $backupBindings;
|
||||
}
|
||||
$instance->unbindModel(array($type => $unbind), $reset);
|
||||
}
|
||||
foreach ($instance->{$type} as $assoc => $options) {
|
||||
if (isset($model['keep'][$assoc]) && !empty($model['keep'][$assoc])) {
|
||||
if (isset($model['keep'][$assoc]['fields'])) {
|
||||
$model['keep'][$assoc]['fields'] = $this->fieldDependencies($containments['models'][$assoc]['instance'], $map, $model['keep'][$assoc]['fields']);
|
||||
}
|
||||
if (!$reset && empty($instance->__backOriginalAssociation)) {
|
||||
$instance->__backOriginalAssociation = $backupBindings;
|
||||
} else if ($reset) {
|
||||
$instance->__backAssociation[$type] = $backupBindings[$type];
|
||||
}
|
||||
$instance->{$type}[$assoc] = array_merge($instance->{$type}[$assoc], $model['keep'][$assoc]);
|
||||
}
|
||||
if (!$reset) {
|
||||
$instance->__backInnerAssociation[] = $assoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->settings[$Model->alias]['recursive']) {
|
||||
$query['recursive'] = (isset($query['recursive'])) ? $query['recursive'] : $containments['depth'];
|
||||
}
|
||||
|
||||
$autoFields = ($this->settings[$Model->alias]['autoFields']
|
||||
&& !in_array($Model->findQueryType, array('list', 'count'))
|
||||
&& !empty($query['fields']));
|
||||
if (!$autoFields) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$query['fields'] = (array)$query['fields'];
|
||||
foreach (array('hasOne', 'belongsTo') as $type) {
|
||||
if (!empty($Model->{$type})) {
|
||||
foreach ($Model->{$type} as $assoc => $data) {
|
||||
if ($Model->useDbConfig == $Model->{$assoc}->useDbConfig && !empty($data['fields'])) {
|
||||
foreach ((array) $data['fields'] as $field) {
|
||||
$query['fields'][] = (strpos($field, '.') === false ? $assoc . '.' : '') . $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($mandatory[$Model->alias])) {
|
||||
foreach ($mandatory[$Model->alias] as $field) {
|
||||
if ($field == '--primaryKey--') {
|
||||
$field = $Model->primaryKey;
|
||||
} else if (preg_match('/^.+\.\-\-[^-]+\-\-$/', $field)) {
|
||||
list($modelName, $field) = explode('.', $field);
|
||||
if ($Model->useDbConfig == $Model->{$modelName}->useDbConfig) {
|
||||
$field = $modelName . '.' . (
|
||||
($field === '--primaryKey--') ? $Model->$modelName->primaryKey : $field
|
||||
);
|
||||
} else {
|
||||
$field = null;
|
||||
}
|
||||
}
|
||||
if ($field !== null) {
|
||||
$query['fields'][] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
$query['fields'] = array_unique($query['fields']);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets original associations on models that may have receive multiple,
|
||||
* subsequent unbindings.
|
||||
*
|
||||
* @param object $Model Model on which we are resetting
|
||||
* @param array $results Results of the find operation
|
||||
* @param bool $primary true if this is the primary model that issued the find operation, false otherwise
|
||||
* @access public
|
||||
*/
|
||||
function afterFind(&$Model, $results, $primary) {
|
||||
if (!empty($Model->__backContainableAssociation)) {
|
||||
foreach ($Model->__backContainableAssociation as $relation => $bindings) {
|
||||
$Model->{$relation} = $bindings;
|
||||
unset($Model->__backContainableAssociation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds all relations from a model except the specified ones. Calling this function without
|
||||
* parameters unbinds all related models.
|
||||
*
|
||||
* @param object $Model Model on which binding restriction is being applied
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1323/Containable#Using-Containable-1324
|
||||
*/
|
||||
function contain(&$Model) {
|
||||
$args = func_get_args();
|
||||
$contain = call_user_func_array('am', array_slice($args, 1));
|
||||
$this->runtime[$Model->alias]['contain'] = $contain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently restore the original binding settings of given model, useful
|
||||
* for restoring the bindings after using 'reset' => false as part of the
|
||||
* contain call.
|
||||
*
|
||||
* @param object $Model Model on which to reset bindings
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function resetBindings(&$Model) {
|
||||
if (!empty($Model->__backOriginalAssociation)) {
|
||||
$Model->__backAssociation = $Model->__backOriginalAssociation;
|
||||
unset($Model->__backOriginalAssociation);
|
||||
}
|
||||
$Model->resetAssociations();
|
||||
if (!empty($Model->__backInnerAssociation)) {
|
||||
$assocs = $Model->__backInnerAssociation;
|
||||
unset($Model->__backInnerAssociation);
|
||||
foreach ($assocs as $currentModel) {
|
||||
$this->resetBindings($Model->$currentModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process containments for model.
|
||||
*
|
||||
* @param object $Model Model on which binding restriction is being applied
|
||||
* @param array $contain Parameters to use for restricting this model
|
||||
* @param array $containments Current set of containments
|
||||
* @param bool $throwErrors Wether unexisting bindings show throw errors
|
||||
* @return array Containments
|
||||
* @access public
|
||||
*/
|
||||
function containments(&$Model, $contain, $containments = array(), $throwErrors = null) {
|
||||
$options = array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery');
|
||||
$keep = array();
|
||||
$depth = array();
|
||||
if ($throwErrors === null) {
|
||||
$throwErrors = (empty($this->settings[$Model->alias]) ? true : $this->settings[$Model->alias]['notices']);
|
||||
}
|
||||
foreach ((array)$contain as $name => $children) {
|
||||
if (is_numeric($name)) {
|
||||
$name = $children;
|
||||
$children = array();
|
||||
}
|
||||
if (preg_match('/(?<!\.)\(/', $name)) {
|
||||
$name = str_replace('(', '.(', $name);
|
||||
}
|
||||
if (strpos($name, '.') !== false) {
|
||||
$chain = explode('.', $name);
|
||||
$name = array_shift($chain);
|
||||
$children = array(implode('.', $chain) => $children);
|
||||
}
|
||||
|
||||
$children = (array)$children;
|
||||
foreach ($children as $key => $val) {
|
||||
if (is_string($key) && is_string($val) && !in_array($key, $options, true)) {
|
||||
$children[$key] = (array) $val;
|
||||
}
|
||||
}
|
||||
|
||||
$keys = array_keys($children);
|
||||
if ($keys && isset($children[0])) {
|
||||
$keys = array_merge(array_values($children), $keys);
|
||||
}
|
||||
|
||||
foreach ($keys as $i => $key) {
|
||||
if (is_array($key)) {
|
||||
continue;
|
||||
}
|
||||
$optionKey = in_array($key, $options, true);
|
||||
if (!$optionKey && is_string($key) && preg_match('/^[a-z(]/', $key) && (!isset($Model->{$key}) || !is_object($Model->{$key}))) {
|
||||
$option = 'fields';
|
||||
$val = array($key);
|
||||
if ($key{0} == '(') {
|
||||
$val = preg_split('/\s*,\s*/', substr(substr($key, 1), 0, -1));
|
||||
} elseif (preg_match('/ASC|DESC$/', $key)) {
|
||||
$option = 'order';
|
||||
$val = $Model->{$name}->alias.'.'.$key;
|
||||
} elseif (preg_match('/[ =!]/', $key)) {
|
||||
$option = 'conditions';
|
||||
$val = $Model->{$name}->alias.'.'.$key;
|
||||
}
|
||||
$children[$option] = is_array($val) ? $val : array($val);
|
||||
$newChildren = null;
|
||||
if (!empty($name) && !empty($children[$key])) {
|
||||
$newChildren = $children[$key];
|
||||
}
|
||||
unset($children[$key], $children[$i]);
|
||||
$key = $option;
|
||||
$optionKey = true;
|
||||
if (!empty($newChildren)) {
|
||||
$children = Set::merge($children, $newChildren);
|
||||
}
|
||||
}
|
||||
if ($optionKey && isset($children[$key])) {
|
||||
if (!empty($keep[$name][$key]) && is_array($keep[$name][$key])) {
|
||||
$keep[$name][$key] = array_merge((isset($keep[$name][$key]) ? $keep[$name][$key] : array()), (array) $children[$key]);
|
||||
} else {
|
||||
$keep[$name][$key] = $children[$key];
|
||||
}
|
||||
unset($children[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($Model->{$name}) || !is_object($Model->{$name})) {
|
||||
if ($throwErrors) {
|
||||
trigger_error(sprintf(__('Model "%s" is not associated with model "%s"', true), $Model->alias, $name), E_USER_WARNING);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$containments = $this->containments($Model->{$name}, $children, $containments);
|
||||
$depths[] = $containments['depth'] + 1;
|
||||
if (!isset($keep[$name])) {
|
||||
$keep[$name] = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($containments['models'][$Model->alias])) {
|
||||
$containments['models'][$Model->alias] = array('keep' => array(),'instance' => &$Model);
|
||||
}
|
||||
|
||||
$containments['models'][$Model->alias]['keep'] = array_merge($containments['models'][$Model->alias]['keep'], $keep);
|
||||
$containments['depth'] = empty($depths) ? 0 : max($depths);
|
||||
return $containments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate needed fields to fetch the required bindings for the given model.
|
||||
*
|
||||
* @param object $Model Model
|
||||
* @param array $map Map of relations for given model
|
||||
* @param mixed $fields If array, fields to initially load, if false use $Model as primary model
|
||||
* @return array Fields
|
||||
* @access public
|
||||
*/
|
||||
function fieldDependencies(&$Model, $map, $fields = array()) {
|
||||
if ($fields === false) {
|
||||
foreach ($map as $parent => $children) {
|
||||
foreach ($children as $type => $bindings) {
|
||||
foreach ($bindings as $dependency) {
|
||||
if ($type == 'hasAndBelongsToMany') {
|
||||
$fields[$parent][] = '--primaryKey--';
|
||||
} else if ($type == 'belongsTo') {
|
||||
$fields[$parent][] = $dependency . '.--primaryKey--';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
if (empty($map[$Model->alias])) {
|
||||
return $fields;
|
||||
}
|
||||
foreach ($map[$Model->alias] as $type => $bindings) {
|
||||
foreach ($bindings as $dependency) {
|
||||
$innerFields = array();
|
||||
switch ($type) {
|
||||
case 'belongsTo':
|
||||
$fields[] = $Model->{$type}[$dependency]['foreignKey'];
|
||||
break;
|
||||
case 'hasOne':
|
||||
case 'hasMany':
|
||||
$innerFields[] = $Model->$dependency->primaryKey;
|
||||
$fields[] = $Model->primaryKey;
|
||||
break;
|
||||
}
|
||||
if (!empty($innerFields) && !empty($Model->{$type}[$dependency]['fields'])) {
|
||||
$Model->{$type}[$dependency]['fields'] = array_unique(array_merge($Model->{$type}[$dependency]['fields'], $innerFields));
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_unique($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the map of containments
|
||||
*
|
||||
* @param array $containments Containments
|
||||
* @return array Built containments
|
||||
* @access public
|
||||
*/
|
||||
function containmentsMap($containments) {
|
||||
$map = array();
|
||||
foreach ($containments['models'] as $name => $model) {
|
||||
$instance =& $model['instance'];
|
||||
foreach ($this->types as $type) {
|
||||
foreach ($instance->{$type} as $assoc => $options) {
|
||||
if (isset($model['keep'][$assoc])) {
|
||||
$map[$name][$type] = isset($map[$name][$type]) ? array_merge($map[$name][$type], (array)$assoc) : (array)$assoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
}
|
||||
540
web-cake/html/cake/libs/model/behaviors/translate.php
Normal file
540
web-cake/html/cake/libs/model/behaviors/translate.php
Normal file
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
/**
|
||||
* Translate behavior
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @since CakePHP(tm) v 1.2.0.4525
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translate behavior
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @link http://book.cakephp.org/view/1328/Translate
|
||||
*/
|
||||
class TranslateBehavior extends ModelBehavior {
|
||||
|
||||
/**
|
||||
* Used for runtime configuration of model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $runtime = array();
|
||||
|
||||
/**
|
||||
* Callback
|
||||
*
|
||||
* $config for TranslateBehavior should be
|
||||
* array( 'fields' => array('field_one',
|
||||
* 'field_two' => 'FieldAssoc', 'field_three'))
|
||||
*
|
||||
* With above example only one permanent hasMany will be joined (for field_two
|
||||
* as FieldAssoc)
|
||||
*
|
||||
* $config could be empty - and translations configured dynamically by
|
||||
* bindTranslation() method
|
||||
*
|
||||
* @param Model $model Model the behavior is being attached to.
|
||||
* @param array $config Array of configuration information.
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function setup(&$model, $config = array()) {
|
||||
$db =& ConnectionManager::getDataSource($model->useDbConfig);
|
||||
if (!$db->connected) {
|
||||
trigger_error(
|
||||
sprintf(__('Datasource %s for TranslateBehavior of model %s is not connected', true), $model->useDbConfig, $model->alias),
|
||||
E_USER_ERROR
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->settings[$model->alias] = array();
|
||||
$this->runtime[$model->alias] = array('fields' => array());
|
||||
$this->translateModel($model);
|
||||
return $this->bindTranslation($model, $config, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup Callback unbinds bound translations and deletes setting information.
|
||||
*
|
||||
* @param Model $model Model being detached.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function cleanup(&$model) {
|
||||
$this->unbindTranslation($model);
|
||||
unset($this->settings[$model->alias]);
|
||||
unset($this->runtime[$model->alias]);
|
||||
}
|
||||
|
||||
/**
|
||||
* beforeFind Callback
|
||||
*
|
||||
* @param Model $model Model find is being run on.
|
||||
* @param array $query Array of Query parameters.
|
||||
* @return array Modified query
|
||||
* @access public
|
||||
*/
|
||||
function beforeFind(&$model, $query) {
|
||||
$locale = $this->_getLocale($model);
|
||||
if (empty($locale)) {
|
||||
return $query;
|
||||
}
|
||||
$db =& ConnectionManager::getDataSource($model->useDbConfig);
|
||||
$RuntimeModel =& $this->translateModel($model);
|
||||
if (!empty($RuntimeModel->tablePrefix)) {
|
||||
$tablePrefix = $RuntimeModel->tablePrefix;
|
||||
} else {
|
||||
$tablePrefix = $db->config['prefix'];
|
||||
}
|
||||
|
||||
if (is_string($query['fields']) && 'COUNT(*) AS '.$db->name('count') == $query['fields']) {
|
||||
$query['fields'] = 'COUNT(DISTINCT('.$db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count';
|
||||
$query['joins'][] = array(
|
||||
'type' => 'INNER',
|
||||
'alias' => $RuntimeModel->alias,
|
||||
'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier($RuntimeModel->alias.'.foreign_key'),
|
||||
$RuntimeModel->alias.'.model' => $model->name,
|
||||
$RuntimeModel->alias.'.locale' => $locale
|
||||
)
|
||||
);
|
||||
return $query;
|
||||
}
|
||||
$autoFields = false;
|
||||
|
||||
if (empty($query['fields'])) {
|
||||
$query['fields'] = array($model->alias.'.*');
|
||||
|
||||
$recursive = $model->recursive;
|
||||
if (isset($query['recursive'])) {
|
||||
$recursive = $query['recursive'];
|
||||
}
|
||||
|
||||
if ($recursive >= 0) {
|
||||
foreach (array('hasOne', 'belongsTo') as $type) {
|
||||
foreach ($model->{$type} as $key => $value) {
|
||||
|
||||
if (empty($value['fields'])) {
|
||||
$query['fields'][] = $key.'.*';
|
||||
} else {
|
||||
foreach ($value['fields'] as $field) {
|
||||
$query['fields'][] = $key.'.'.$field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$autoFields = true;
|
||||
}
|
||||
$fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
|
||||
$addFields = array();
|
||||
if (is_array($query['fields'])) {
|
||||
foreach ($fields as $key => $value) {
|
||||
$field = (is_numeric($key)) ? $value : $key;
|
||||
|
||||
if (in_array($model->alias.'.*', $query['fields']) || $autoFields || in_array($model->alias.'.'.$field, $query['fields']) || in_array($field, $query['fields'])) {
|
||||
$addFields[] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($addFields) {
|
||||
foreach ($addFields as $field) {
|
||||
foreach (array($field, $model->alias.'.'.$field) as $_field) {
|
||||
$key = array_search($_field, $query['fields']);
|
||||
|
||||
if ($key !== false) {
|
||||
unset($query['fields'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($locale)) {
|
||||
foreach ($locale as $_locale) {
|
||||
$query['fields'][] = 'I18n__'.$field.'__'.$_locale.'.content';
|
||||
$query['joins'][] = array(
|
||||
'type' => 'LEFT',
|
||||
'alias' => 'I18n__'.$field.'__'.$_locale,
|
||||
'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
|
||||
'I18n__'.$field.'__'.$_locale.'.model' => $model->name,
|
||||
'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $field,
|
||||
'I18n__'.$field.'__'.$_locale.'.locale' => $_locale
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$query['fields'][] = 'I18n__'.$field.'.content';
|
||||
$query['joins'][] = array(
|
||||
'type' => 'LEFT',
|
||||
'alias' => 'I18n__'.$field,
|
||||
'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"),
|
||||
'I18n__'.$field.'.model' => $model->name,
|
||||
'I18n__'.$field.'.'.$RuntimeModel->displayField => $field
|
||||
)
|
||||
);
|
||||
|
||||
if (is_string($query['conditions'])) {
|
||||
$query['conditions'] = $db->conditions($query['conditions'], true, false, $model) . ' AND '.$db->name('I18n__'.$field.'.locale').' = \''.$locale.'\'';
|
||||
} else {
|
||||
$query['conditions'][$db->name("I18n__{$field}.locale")] = $locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_array($query['fields'])) {
|
||||
$query['fields'] = array_merge($query['fields']);
|
||||
}
|
||||
$this->runtime[$model->alias]['beforeFind'] = $addFields;
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* afterFind Callback
|
||||
*
|
||||
* @param Model $model Model find was run on
|
||||
* @param array $results Array of model results.
|
||||
* @param boolean $primary Did the find originate on $model.
|
||||
* @return array Modified results
|
||||
* @access public
|
||||
*/
|
||||
function afterFind(&$model, $results, $primary) {
|
||||
$this->runtime[$model->alias]['fields'] = array();
|
||||
$locale = $this->_getLocale($model);
|
||||
|
||||
if (empty($locale) || empty($results) || empty($this->runtime[$model->alias]['beforeFind'])) {
|
||||
return $results;
|
||||
}
|
||||
$beforeFind = $this->runtime[$model->alias]['beforeFind'];
|
||||
|
||||
foreach ($results as $key => $row) {
|
||||
$results[$key][$model->alias]['locale'] = (is_array($locale)) ? @$locale[0] : $locale;
|
||||
|
||||
foreach ($beforeFind as $field) {
|
||||
if (is_array($locale)) {
|
||||
foreach ($locale as $_locale) {
|
||||
if (!isset($results[$key][$model->alias][$field]) && !empty($results[$key]['I18n__'.$field.'__'.$_locale]['content'])) {
|
||||
$results[$key][$model->alias][$field] = $results[$key]['I18n__'.$field.'__'.$_locale]['content'];
|
||||
}
|
||||
unset($results[$key]['I18n__'.$field.'__'.$_locale]);
|
||||
}
|
||||
|
||||
if (!isset($results[$key][$model->alias][$field])) {
|
||||
$results[$key][$model->alias][$field] = '';
|
||||
}
|
||||
} else {
|
||||
$value = '';
|
||||
if (!empty($results[$key]['I18n__'.$field]['content'])) {
|
||||
$value = $results[$key]['I18n__'.$field]['content'];
|
||||
}
|
||||
$results[$key][$model->alias][$field] = $value;
|
||||
unset($results[$key]['I18n__'.$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* beforeValidate Callback
|
||||
*
|
||||
* @param Model $model Model invalidFields was called on.
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function beforeValidate(&$model) {
|
||||
$locale = $this->_getLocale($model);
|
||||
if (empty($locale)) {
|
||||
return true;
|
||||
}
|
||||
$fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
|
||||
$tempData = array();
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
$field = (is_numeric($key)) ? $value : $key;
|
||||
|
||||
if (isset($model->data[$model->alias][$field])) {
|
||||
$tempData[$field] = $model->data[$model->alias][$field];
|
||||
if (is_array($model->data[$model->alias][$field])) {
|
||||
if (is_string($locale) && !empty($model->data[$model->alias][$field][$locale])) {
|
||||
$model->data[$model->alias][$field] = $model->data[$model->alias][$field][$locale];
|
||||
} else {
|
||||
$values = array_values($model->data[$model->alias][$field]);
|
||||
$model->data[$model->alias][$field] = $values[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->runtime[$model->alias]['beforeSave'] = $tempData;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* afterSave Callback
|
||||
*
|
||||
* @param Model $model Model the callback is called on
|
||||
* @param boolean $created Whether or not the save created a record.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterSave(&$model, $created) {
|
||||
if (!isset($this->runtime[$model->alias]['beforeSave'])) {
|
||||
return true;
|
||||
}
|
||||
$locale = $this->_getLocale($model);
|
||||
$tempData = $this->runtime[$model->alias]['beforeSave'];
|
||||
unset($this->runtime[$model->alias]['beforeSave']);
|
||||
$conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
|
||||
$RuntimeModel =& $this->translateModel($model);
|
||||
|
||||
foreach ($tempData as $field => $value) {
|
||||
unset($conditions['content']);
|
||||
$conditions['field'] = $field;
|
||||
if (is_array($value)) {
|
||||
$conditions['locale'] = array_keys($value);
|
||||
} else {
|
||||
$conditions['locale'] = $locale;
|
||||
if (is_array($locale)) {
|
||||
$value = array($locale[0] => $value);
|
||||
} else {
|
||||
$value = array($locale => $value);
|
||||
}
|
||||
}
|
||||
$translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')));
|
||||
foreach ($value as $_locale => $_value) {
|
||||
$RuntimeModel->create();
|
||||
$conditions['locale'] = $_locale;
|
||||
$conditions['content'] = $_value;
|
||||
if (array_key_exists($_locale, $translations)) {
|
||||
$RuntimeModel->save(array($RuntimeModel->alias => array_merge($conditions, array('id' => $translations[$_locale]))));
|
||||
} else {
|
||||
$RuntimeModel->save(array($RuntimeModel->alias => $conditions));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* afterDelete Callback
|
||||
*
|
||||
* @param Model $model Model the callback was run on.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterDelete(&$model) {
|
||||
$RuntimeModel =& $this->translateModel($model);
|
||||
$conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
|
||||
$RuntimeModel->deleteAll($conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected locale for model
|
||||
*
|
||||
* @param Model $model Model the locale needs to be set/get on.
|
||||
* @return mixed string or false
|
||||
* @access protected
|
||||
*/
|
||||
function _getLocale(&$model) {
|
||||
if (!isset($model->locale) || is_null($model->locale)) {
|
||||
if (!class_exists('I18n')) {
|
||||
App::import('Core', 'i18n');
|
||||
}
|
||||
$I18n =& I18n::getInstance();
|
||||
$I18n->l10n->get(Configure::read('Config.language'));
|
||||
$model->locale = $I18n->l10n->locale;
|
||||
}
|
||||
|
||||
return $model->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance of model for translations.
|
||||
*
|
||||
* If the model has a translateModel property set, this will be used as the class
|
||||
* name to find/use. If no translateModel property is found 'I18nModel' will be used.
|
||||
*
|
||||
* @param Model $model Model to get a translatemodel for.
|
||||
* @return object
|
||||
* @access public
|
||||
*/
|
||||
function &translateModel(&$model) {
|
||||
if (!isset($this->runtime[$model->alias]['model'])) {
|
||||
if (!isset($model->translateModel) || empty($model->translateModel)) {
|
||||
$className = 'I18nModel';
|
||||
} else {
|
||||
$className = $model->translateModel;
|
||||
}
|
||||
|
||||
if (PHP5) {
|
||||
$this->runtime[$model->alias]['model'] = ClassRegistry::init($className, 'Model');
|
||||
} else {
|
||||
$this->runtime[$model->alias]['model'] =& ClassRegistry::init($className, 'Model');
|
||||
}
|
||||
}
|
||||
if (!empty($model->translateTable) && $model->translateTable !== $this->runtime[$model->alias]['model']->useTable) {
|
||||
$this->runtime[$model->alias]['model']->setSource($model->translateTable);
|
||||
} elseif (empty($model->translateTable) && empty($model->translateModel)) {
|
||||
$this->runtime[$model->alias]['model']->setSource('i18n');
|
||||
}
|
||||
$model =& $this->runtime[$model->alias]['model'];
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind translation for fields, optionally with hasMany association for
|
||||
* fake field
|
||||
*
|
||||
* @param object instance of model
|
||||
* @param mixed string with field or array(field1, field2=>AssocName, field3)
|
||||
* @param boolean $reset
|
||||
* @return bool
|
||||
*/
|
||||
function bindTranslation(&$model, $fields, $reset = true) {
|
||||
if (is_string($fields)) {
|
||||
$fields = array($fields);
|
||||
}
|
||||
$associations = array();
|
||||
$RuntimeModel =& $this->translateModel($model);
|
||||
$default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$field = $value;
|
||||
$association = null;
|
||||
} else {
|
||||
$field = $key;
|
||||
$association = $value;
|
||||
}
|
||||
|
||||
if (array_key_exists($field, $this->settings[$model->alias])) {
|
||||
unset($this->settings[$model->alias][$field]);
|
||||
} elseif (in_array($field, $this->settings[$model->alias])) {
|
||||
$this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
|
||||
}
|
||||
|
||||
if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
|
||||
unset($this->runtime[$model->alias]['fields'][$field]);
|
||||
} elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
|
||||
$this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
|
||||
}
|
||||
|
||||
if (is_null($association)) {
|
||||
if ($reset) {
|
||||
$this->runtime[$model->alias]['fields'][] = $field;
|
||||
} else {
|
||||
$this->settings[$model->alias][] = $field;
|
||||
}
|
||||
} else {
|
||||
if ($reset) {
|
||||
$this->runtime[$model->alias]['fields'][$field] = $association;
|
||||
} else {
|
||||
$this->settings[$model->alias][$field] = $association;
|
||||
}
|
||||
|
||||
foreach (array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany') as $type) {
|
||||
if (isset($model->{$type}[$association]) || isset($model->__backAssociation[$type][$association])) {
|
||||
trigger_error(
|
||||
sprintf(__('Association %s is already binded to model %s', true), $association, $model->alias),
|
||||
E_USER_ERROR
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$associations[$association] = array_merge($default, array('conditions' => array(
|
||||
'model' => $model->alias,
|
||||
$RuntimeModel->displayField => $field
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($associations)) {
|
||||
$model->bindModel(array('hasMany' => $associations), $reset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind translation for fields, optionally unbinds hasMany association for
|
||||
* fake field
|
||||
*
|
||||
* @param object $model instance of model
|
||||
* @param mixed $fields string with field, or array(field1, field2=>AssocName, field3), or null for
|
||||
* unbind all original translations
|
||||
* @return bool
|
||||
*/
|
||||
function unbindTranslation(&$model, $fields = null) {
|
||||
if (empty($fields) && empty($this->settings[$model->alias])) {
|
||||
return false;
|
||||
}
|
||||
if (empty($fields)) {
|
||||
return $this->unbindTranslation($model, $this->settings[$model->alias]);
|
||||
}
|
||||
|
||||
if (is_string($fields)) {
|
||||
$fields = array($fields);
|
||||
}
|
||||
$RuntimeModel =& $this->translateModel($model);
|
||||
$associations = array();
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$field = $value;
|
||||
$association = null;
|
||||
} else {
|
||||
$field = $key;
|
||||
$association = $value;
|
||||
}
|
||||
|
||||
if (array_key_exists($field, $this->settings[$model->alias])) {
|
||||
unset($this->settings[$model->alias][$field]);
|
||||
} elseif (in_array($field, $this->settings[$model->alias])) {
|
||||
$this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
|
||||
}
|
||||
|
||||
if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
|
||||
unset($this->runtime[$model->alias]['fields'][$field]);
|
||||
} elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
|
||||
$this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
|
||||
}
|
||||
|
||||
if (!is_null($association) && (isset($model->hasMany[$association]) || isset($model->__backAssociation['hasMany'][$association]))) {
|
||||
$associations[] = $association;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($associations)) {
|
||||
$model->unbindModel(array('hasMany' => $associations), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
|
||||
|
||||
/**
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
*/
|
||||
class I18nModel extends AppModel {
|
||||
var $name = 'I18nModel';
|
||||
var $useTable = 'i18n';
|
||||
var $displayField = 'field';
|
||||
}
|
||||
}
|
||||
977
web-cake/html/cake/libs/model/behaviors/tree.php
Normal file
977
web-cake/html/cake/libs/model/behaviors/tree.php
Normal file
@@ -0,0 +1,977 @@
|
||||
<?php
|
||||
/**
|
||||
* Tree behavior class.
|
||||
*
|
||||
* Enables a model object to act as a node-based tree.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2006-2010, Cake Software Foundation, Inc.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
|
||||
* @link http://cakephp.org CakePHP Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @since CakePHP v 1.2.0.4487
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tree Behavior.
|
||||
*
|
||||
* Enables a model object to act as a node-based tree. Using Modified Preorder Tree Traversal
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Tree_traversal
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.behaviors
|
||||
* @link http://book.cakephp.org/view/1339/Tree
|
||||
*/
|
||||
class TreeBehavior extends ModelBehavior {
|
||||
|
||||
/**
|
||||
* Errors
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $errors = array();
|
||||
|
||||
/**
|
||||
* Defaults
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_defaults = array(
|
||||
'parent' => 'parent_id', 'left' => 'lft', 'right' => 'rght',
|
||||
'scope' => '1 = 1', 'type' => 'nested', '__parentChange' => false, 'recursive' => -1
|
||||
);
|
||||
|
||||
/**
|
||||
* Initiate Tree behavior
|
||||
*
|
||||
* @param object $Model instance of model
|
||||
* @param array $config array of configuration settings.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function setup(&$Model, $config = array()) {
|
||||
if (!is_array($config)) {
|
||||
$config = array('type' => $config);
|
||||
}
|
||||
$settings = array_merge($this->_defaults, $config);
|
||||
|
||||
if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) {
|
||||
$data = $Model->getAssociated($settings['scope']);
|
||||
$parent =& $Model->{$settings['scope']};
|
||||
$settings['scope'] = $Model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey;
|
||||
$settings['recursive'] = 0;
|
||||
}
|
||||
$this->settings[$Model->alias] = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* After save method. Called after all saves
|
||||
*
|
||||
* Overriden to transparently manage setting the lft and rght fields if and only if the parent field is included in the
|
||||
* parameters to be saved.
|
||||
*
|
||||
* @param AppModel $Model Model instance.
|
||||
* @param boolean $created indicates whether the node just saved was created or updated
|
||||
* @return boolean true on success, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function afterSave(&$Model, $created) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
if ($created) {
|
||||
if ((isset($Model->data[$Model->alias][$parent])) && $Model->data[$Model->alias][$parent]) {
|
||||
return $this->_setParent($Model, $Model->data[$Model->alias][$parent], $created);
|
||||
}
|
||||
} elseif ($__parentChange) {
|
||||
$this->settings[$Model->alias]['__parentChange'] = false;
|
||||
return $this->_setParent($Model, $Model->data[$Model->alias][$parent]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delete method. Called before all deletes
|
||||
*
|
||||
* Will delete the current node and all children using the deleteAll method and sync the table
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @return boolean true to continue, false to abort the delete
|
||||
* @access public
|
||||
*/
|
||||
function beforeDelete(&$Model) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
list($name, $data) = array($Model->alias, $Model->read());
|
||||
$data = $data[$name];
|
||||
|
||||
if (!$data[$right] || !$data[$left]) {
|
||||
return true;
|
||||
}
|
||||
$diff = $data[$right] - $data[$left] + 1;
|
||||
|
||||
if ($diff > 2) {
|
||||
if (is_string($scope)) {
|
||||
$scope = array($scope);
|
||||
}
|
||||
$scope[]["{$Model->alias}.{$left} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1);
|
||||
$Model->deleteAll($scope);
|
||||
}
|
||||
$this->__sync($Model, $diff, '-', '> ' . $data[$right]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before save method. Called before all saves
|
||||
*
|
||||
* Overriden to transparently manage setting the lft and rght fields if and only if the parent field is included in the
|
||||
* parameters to be saved. For newly created nodes with NO parent the left and right field values are set directly by
|
||||
* this method bypassing the setParent logic.
|
||||
*
|
||||
* @since 1.2
|
||||
* @param AppModel $Model Model instance
|
||||
* @return boolean true to continue, false to abort the save
|
||||
* @access public
|
||||
*/
|
||||
function beforeSave(&$Model) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
|
||||
$this->_addToWhitelist($Model, array($left, $right));
|
||||
if (!$Model->id) {
|
||||
if (array_key_exists($parent, $Model->data[$Model->alias]) && $Model->data[$Model->alias][$parent]) {
|
||||
$parentNode = $Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $Model->data[$Model->alias][$parent]),
|
||||
'fields' => array($Model->primaryKey, $right), 'recursive' => $recursive
|
||||
));
|
||||
if (!$parentNode) {
|
||||
return false;
|
||||
}
|
||||
list($parentNode) = array_values($parentNode);
|
||||
$Model->data[$Model->alias][$left] = 0; //$parentNode[$right];
|
||||
$Model->data[$Model->alias][$right] = 0; //$parentNode[$right] + 1;
|
||||
} else {
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive);
|
||||
$Model->data[$Model->alias][$left] = $edge + 1;
|
||||
$Model->data[$Model->alias][$right] = $edge + 2;
|
||||
}
|
||||
} elseif (array_key_exists($parent, $Model->data[$Model->alias])) {
|
||||
if ($Model->data[$Model->alias][$parent] != $Model->field($parent)) {
|
||||
$this->settings[$Model->alias]['__parentChange'] = true;
|
||||
}
|
||||
if (!$Model->data[$Model->alias][$parent]) {
|
||||
$Model->data[$Model->alias][$parent] = null;
|
||||
$this->_addToWhitelist($Model, $parent);
|
||||
} else {
|
||||
$values = $Model->find('first', array(
|
||||
'conditions' => array($scope,$Model->escapeField() => $Model->id),
|
||||
'fields' => array($Model->primaryKey, $parent, $left, $right ), 'recursive' => $recursive)
|
||||
);
|
||||
|
||||
if ($values === false) {
|
||||
return false;
|
||||
}
|
||||
list($node) = array_values($values);
|
||||
|
||||
$parentNode = $Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $Model->data[$Model->alias][$parent]),
|
||||
'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
|
||||
));
|
||||
if (!$parentNode) {
|
||||
return false;
|
||||
}
|
||||
list($parentNode) = array_values($parentNode);
|
||||
|
||||
if (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
|
||||
return false;
|
||||
} elseif ($node[$Model->primaryKey] == $parentNode[$Model->primaryKey]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of child nodes
|
||||
*
|
||||
* If the direct parameter is set to true, only the direct children are counted (based upon the parent_id field)
|
||||
* If false is passed for the id parameter, all top level nodes are counted, or all nodes are counted.
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to read or false to read all top level nodes
|
||||
* @param boolean $direct whether to count direct, or all, children
|
||||
* @return integer number of child nodes
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1347/Counting-children
|
||||
*/
|
||||
function childcount(&$Model, $id = null, $direct = false) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
if ($id === null && $Model->id) {
|
||||
$id = $Model->id;
|
||||
} elseif (!$id) {
|
||||
$id = null;
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
|
||||
if ($direct) {
|
||||
return $Model->find('count', array('conditions' => array($scope, $Model->escapeField($parent) => $id)));
|
||||
}
|
||||
|
||||
if ($id === null) {
|
||||
return $Model->find('count', array('conditions' => $scope));
|
||||
} elseif (isset($Model->data[$Model->alias][$left]) && isset($Model->data[$Model->alias][$right])) {
|
||||
$data = $Model->data[$Model->alias];
|
||||
} else {
|
||||
$data = $Model->find('first', array('conditions' => array($scope, $Model->escapeField() => $id), 'recursive' => $recursive));
|
||||
if (!$data) {
|
||||
return 0;
|
||||
}
|
||||
$data = $data[$Model->alias];
|
||||
}
|
||||
return ($data[$right] - $data[$left] - 1) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the child nodes of the current model
|
||||
*
|
||||
* If the direct parameter is set to true, only the direct children are returned (based upon the parent_id field)
|
||||
* If false is passed for the id parameter, top level, or all (depending on direct parameter appropriate) are counted.
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to read
|
||||
* @param boolean $direct whether to return only the direct, or all, children
|
||||
* @param mixed $fields Either a single string of a field name, or an array of field names
|
||||
* @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC") defaults to the tree order
|
||||
* @param integer $limit SQL LIMIT clause, for calculating items per page.
|
||||
* @param integer $page Page number, for accessing paged data
|
||||
* @param integer $recursive The number of levels deep to fetch associated records
|
||||
* @return array Array of child nodes
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1346/Children
|
||||
*/
|
||||
function children(&$Model, $id = null, $direct = false, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
$overrideRecursive = $recursive;
|
||||
|
||||
if ($id === null && $Model->id) {
|
||||
$id = $Model->id;
|
||||
} elseif (!$id) {
|
||||
$id = null;
|
||||
}
|
||||
$name = $Model->alias;
|
||||
extract($this->settings[$Model->alias]);
|
||||
|
||||
if (!is_null($overrideRecursive)) {
|
||||
$recursive = $overrideRecursive;
|
||||
}
|
||||
if (!$order) {
|
||||
$order = $Model->alias . '.' . $left . ' asc';
|
||||
}
|
||||
if ($direct) {
|
||||
$conditions = array($scope, $Model->escapeField($parent) => $id);
|
||||
return $Model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
$conditions = $scope;
|
||||
} else {
|
||||
$result = array_values((array)$Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $id),
|
||||
'fields' => array($left, $right),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
|
||||
if (empty($result) || !isset($result[0])) {
|
||||
return array();
|
||||
}
|
||||
$conditions = array($scope,
|
||||
$Model->escapeField($right) . ' <' => $result[0][$right],
|
||||
$Model->escapeField($left) . ' >' => $result[0][$left]
|
||||
);
|
||||
}
|
||||
return $Model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for returning a hierarchical array used for HTML select boxes
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $conditions SQL conditions as a string or as an array('field' =>'value',...)
|
||||
* @param string $keyPath A string path to the key, i.e. "{n}.Post.id"
|
||||
* @param string $valuePath A string path to the value, i.e. "{n}.Post.title"
|
||||
* @param string $spacer The character or characters which will be repeated
|
||||
* @param integer $recursive The number of levels deep to fetch associated records
|
||||
* @return array An associative array of records, where the id is the key, and the display field is the value
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1348/generatetreelist
|
||||
*/
|
||||
function generatetreelist(&$Model, $conditions = null, $keyPath = null, $valuePath = null, $spacer = '_', $recursive = null) {
|
||||
$overrideRecursive = $recursive;
|
||||
extract($this->settings[$Model->alias]);
|
||||
if (!is_null($overrideRecursive)) {
|
||||
$recursive = $overrideRecursive;
|
||||
}
|
||||
|
||||
if ($keyPath == null && $valuePath == null && $Model->hasField($Model->displayField)) {
|
||||
$fields = array($Model->primaryKey, $Model->displayField, $left, $right);
|
||||
} else {
|
||||
$fields = null;
|
||||
}
|
||||
|
||||
if ($keyPath == null) {
|
||||
$keyPath = '{n}.' . $Model->alias . '.' . $Model->primaryKey;
|
||||
}
|
||||
|
||||
if ($valuePath == null) {
|
||||
$valuePath = array('{0}{1}', '{n}.tree_prefix', '{n}.' . $Model->alias . '.' . $Model->displayField);
|
||||
|
||||
} elseif (is_string($valuePath)) {
|
||||
$valuePath = array('{0}{1}', '{n}.tree_prefix', $valuePath);
|
||||
|
||||
} else {
|
||||
$valuePath[0] = '{' . (count($valuePath) - 1) . '}' . $valuePath[0];
|
||||
$valuePath[] = '{n}.tree_prefix';
|
||||
}
|
||||
$order = $Model->alias . '.' . $left . ' asc';
|
||||
$results = $Model->find('all', compact('conditions', 'fields', 'order', 'recursive'));
|
||||
$stack = array();
|
||||
|
||||
foreach ($results as $i => $result) {
|
||||
while ($stack && ($stack[count($stack) - 1] < $result[$Model->alias][$right])) {
|
||||
array_pop($stack);
|
||||
}
|
||||
$results[$i]['tree_prefix'] = str_repeat($spacer,count($stack));
|
||||
$stack[] = $result[$Model->alias][$right];
|
||||
}
|
||||
if (empty($results)) {
|
||||
return array();
|
||||
}
|
||||
return Set::combine($results, $keyPath, $valuePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent node
|
||||
*
|
||||
* reads the parent id and returns this node
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to read
|
||||
* @param integer $recursive The number of levels deep to fetch associated records
|
||||
* @return array Array of data for the parent node
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1349/getparentnode
|
||||
*/
|
||||
function getparentnode(&$Model, $id = null, $fields = null, $recursive = null) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
$overrideRecursive = $recursive;
|
||||
if (empty ($id)) {
|
||||
$id = $Model->id;
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
if (!is_null($overrideRecursive)) {
|
||||
$recursive = $overrideRecursive;
|
||||
}
|
||||
$parentId = $Model->find('first', array('conditions' => array($Model->primaryKey => $id), 'fields' => array($parent), 'recursive' => -1));
|
||||
|
||||
if ($parentId) {
|
||||
$parentId = $parentId[$Model->alias][$parent];
|
||||
$parent = $Model->find('first', array('conditions' => array($Model->escapeField() => $parentId), 'fields' => $fields, 'recursive' => $recursive));
|
||||
|
||||
return $parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the given node
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to read
|
||||
* @param mixed $fields Either a single string of a field name, or an array of field names
|
||||
* @param integer $recursive The number of levels deep to fetch associated records
|
||||
* @return array Array of nodes from top most parent to current node
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1350/getpath
|
||||
*/
|
||||
function getpath(&$Model, $id = null, $fields = null, $recursive = null) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
$overrideRecursive = $recursive;
|
||||
if (empty ($id)) {
|
||||
$id = $Model->id;
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
if (!is_null($overrideRecursive)) {
|
||||
$recursive = $overrideRecursive;
|
||||
}
|
||||
$result = $Model->find('first', array('conditions' => array($Model->escapeField() => $id), 'fields' => array($left, $right), 'recursive' => $recursive));
|
||||
if ($result) {
|
||||
$result = array_values($result);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
$item = $result[0];
|
||||
$results = $Model->find('all', array(
|
||||
'conditions' => array($scope, $Model->escapeField($left) . ' <=' => $item[$left], $Model->escapeField($right) . ' >=' => $item[$right]),
|
||||
'fields' => $fields, 'order' => array($Model->escapeField($left) => 'asc'), 'recursive' => $recursive
|
||||
));
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the node without changing the parent.
|
||||
*
|
||||
* If the node is the last child, or is a top level node with no subsequent node this method will return false
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to move
|
||||
* @param mixed $number how many places to move the node or true to move to last position
|
||||
* @return boolean true on success, false on failure
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1352/moveDown
|
||||
*/
|
||||
function movedown(&$Model, $id = null, $number = 1) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
if (!$number) {
|
||||
return false;
|
||||
}
|
||||
if (empty ($id)) {
|
||||
$id = $Model->id;
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
list($node) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $id),
|
||||
'fields' => array($Model->primaryKey, $left, $right, $parent), 'recursive' => $recursive
|
||||
)));
|
||||
if ($node[$parent]) {
|
||||
list($parentNode) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
|
||||
'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
|
||||
)));
|
||||
if (($node[$right] + 1) == $parentNode[$right]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$nextNode = $Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField($left) => ($node[$right] + 1)),
|
||||
'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive)
|
||||
);
|
||||
if ($nextNode) {
|
||||
list($nextNode) = array_values($nextNode);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive);
|
||||
$this->__sync($Model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right]);
|
||||
$this->__sync($Model, $nextNode[$left] - $node[$left], '-', 'BETWEEN ' . $nextNode[$left] . ' AND ' . $nextNode[$right]);
|
||||
$this->__sync($Model, $edge - $node[$left] - ($nextNode[$right] - $nextNode[$left]), '-', '> ' . $edge);
|
||||
|
||||
if (is_int($number)) {
|
||||
$number--;
|
||||
}
|
||||
if ($number) {
|
||||
$this->moveDown($Model, $id, $number);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the node without changing the parent.
|
||||
*
|
||||
* If the node is the first child, or is a top level node with no previous node this method will return false
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to move
|
||||
* @param mixed $number how many places to move the node, or true to move to first position
|
||||
* @return boolean true on success, false on failure
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1353/moveUp
|
||||
*/
|
||||
function moveup(&$Model, $id = null, $number = 1) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
if (!$number) {
|
||||
return false;
|
||||
}
|
||||
if (empty ($id)) {
|
||||
$id = $Model->id;
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
list($node) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $id),
|
||||
'fields' => array($Model->primaryKey, $left, $right, $parent ), 'recursive' => $recursive
|
||||
)));
|
||||
if ($node[$parent]) {
|
||||
list($parentNode) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
|
||||
'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
|
||||
)));
|
||||
if (($node[$left] - 1) == $parentNode[$left]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$previousNode = $Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField($right) => ($node[$left] - 1)),
|
||||
'fields' => array($Model->primaryKey, $left, $right),
|
||||
'recursive' => $recursive
|
||||
));
|
||||
|
||||
if ($previousNode) {
|
||||
list($previousNode) = array_values($previousNode);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive);
|
||||
$this->__sync($Model, $edge - $previousNode[$left] +1, '+', 'BETWEEN ' . $previousNode[$left] . ' AND ' . $previousNode[$right]);
|
||||
$this->__sync($Model, $node[$left] - $previousNode[$left], '-', 'BETWEEN ' .$node[$left] . ' AND ' . $node[$right]);
|
||||
$this->__sync($Model, $edge - $previousNode[$left] - ($node[$right] - $node[$left]), '-', '> ' . $edge);
|
||||
if (is_int($number)) {
|
||||
$number--;
|
||||
}
|
||||
if ($number) {
|
||||
$this->moveUp($Model, $id, $number);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover a corrupted tree
|
||||
*
|
||||
* The mode parameter is used to specify the source of info that is valid/correct. The opposite source of data
|
||||
* will be populated based upon that source of info. E.g. if the MPTT fields are corrupt or empty, with the $mode
|
||||
* 'parent' the values of the parent_id field will be used to populate the left and right fields. The missingParentAction
|
||||
* parameter only applies to "parent" mode and determines what to do if the parent field contains an id that is not present.
|
||||
*
|
||||
* @todo Could be written to be faster, *maybe*. Ideally using a subquery and putting all the logic burden on the DB.
|
||||
* @param AppModel $Model Model instance
|
||||
* @param string $mode parent or tree
|
||||
* @param mixed $missingParentAction 'return' to do nothing and return, 'delete' to
|
||||
* delete, or the id of the parent to set as the parent_id
|
||||
* @return boolean true on success, false on failure
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1628/Recover
|
||||
*/
|
||||
function recover(&$Model, $mode = 'parent', $missingParentAction = null) {
|
||||
if (is_array($mode)) {
|
||||
extract (array_merge(array('mode' => 'parent'), $mode));
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
$Model->recursive = $recursive;
|
||||
if ($mode == 'parent') {
|
||||
$Model->bindModel(array('belongsTo' => array('VerifyParent' => array(
|
||||
'className' => $Model->alias,
|
||||
'foreignKey' => $parent,
|
||||
'fields' => array($Model->primaryKey, $left, $right, $parent),
|
||||
))));
|
||||
$missingParents = $Model->find('list', array(
|
||||
'recursive' => 0,
|
||||
'conditions' => array($scope, array(
|
||||
'NOT' => array($Model->escapeField($parent) => null), $Model->VerifyParent->escapeField() => null
|
||||
))
|
||||
));
|
||||
$Model->unbindModel(array('belongsTo' => array('VerifyParent')));
|
||||
if ($missingParents) {
|
||||
if ($missingParentAction == 'return') {
|
||||
foreach ($missingParents as $id => $display) {
|
||||
$this->errors[] = 'cannot find the parent for ' . $Model->alias . ' with id ' . $id . '(' . $display . ')';
|
||||
|
||||
}
|
||||
return false;
|
||||
} elseif ($missingParentAction == 'delete') {
|
||||
$Model->deleteAll(array($Model->primaryKey => array_flip($missingParents)));
|
||||
} else {
|
||||
$Model->updateAll(array($parent => $missingParentAction), array($Model->escapeField($Model->primaryKey) => array_flip($missingParents)));
|
||||
}
|
||||
}
|
||||
$count = 1;
|
||||
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey), 'order' => $left)) as $array) {
|
||||
$Model->id = $array[$Model->alias][$Model->primaryKey];
|
||||
$lft = $count++;
|
||||
$rght = $count++;
|
||||
$Model->save(array($left => $lft, $right => $rght), array('callbacks' => false));
|
||||
}
|
||||
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
|
||||
$Model->create();
|
||||
$Model->id = $array[$Model->alias][$Model->primaryKey];
|
||||
$this->_setParent($Model, $array[$Model->alias][$parent]);
|
||||
}
|
||||
} else {
|
||||
$db =& ConnectionManager::getDataSource($Model->useDbConfig);
|
||||
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
|
||||
$path = $this->getpath($Model, $array[$Model->alias][$Model->primaryKey]);
|
||||
if ($path == null || count($path) < 2) {
|
||||
$parentId = null;
|
||||
} else {
|
||||
$parentId = $path[count($path) - 2][$Model->alias][$Model->primaryKey];
|
||||
}
|
||||
$Model->updateAll(array($parent => $db->value($parentId, $parent)), array($Model->escapeField() => $array[$Model->alias][$Model->primaryKey]));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder method.
|
||||
*
|
||||
* Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters.
|
||||
* This method does not change the parent of any node.
|
||||
*
|
||||
* Requires a valid tree, by default it verifies the tree before beginning.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - 'id' id of record to use as top node for reordering
|
||||
* - 'field' Which field to use in reordeing defaults to displayField
|
||||
* - 'order' Direction to order either DESC or ASC (defaults to ASC)
|
||||
* - 'verify' Whether or not to verify the tree before reorder. defaults to true.
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param array $options array of options to use in reordering.
|
||||
* @return boolean true on success, false on failure
|
||||
* @link http://book.cakephp.org/view/1355/reorder
|
||||
* @link http://book.cakephp.org/view/1629/Reorder
|
||||
*/
|
||||
function reorder(&$Model, $options = array()) {
|
||||
$options = array_merge(array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true), $options);
|
||||
extract($options);
|
||||
if ($verify && !$this->verify($Model)) {
|
||||
return false;
|
||||
}
|
||||
$verify = false;
|
||||
extract($this->settings[$Model->alias]);
|
||||
$fields = array($Model->primaryKey, $field, $left, $right);
|
||||
$sort = $field . ' ' . $order;
|
||||
$nodes = $this->children($Model, $id, true, $fields, $sort, null, null, $recursive);
|
||||
|
||||
$cacheQueries = $Model->cacheQueries;
|
||||
$Model->cacheQueries = false;
|
||||
if ($nodes) {
|
||||
foreach ($nodes as $node) {
|
||||
$id = $node[$Model->alias][$Model->primaryKey];
|
||||
$this->moveDown($Model, $id, true);
|
||||
if ($node[$Model->alias][$left] != $node[$Model->alias][$right] - 1) {
|
||||
$this->reorder($Model, compact('id', 'field', 'order', 'verify'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$Model->cacheQueries = $cacheQueries;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the current node from the tree, and reparent all children up one level.
|
||||
*
|
||||
* If the parameter delete is false, the node will become a new top level node. Otherwise the node will be deleted
|
||||
* after the children are reparented.
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $id The ID of the record to remove
|
||||
* @param boolean $delete whether to delete the node after reparenting children (if any)
|
||||
* @return boolean true on success, false on failure
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1354/removeFromTree
|
||||
*/
|
||||
function removefromtree(&$Model, $id = null, $delete = false) {
|
||||
if (is_array($id)) {
|
||||
extract (array_merge(array('id' => null), $id));
|
||||
}
|
||||
extract($this->settings[$Model->alias]);
|
||||
|
||||
list($node) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $id),
|
||||
'fields' => array($Model->primaryKey, $left, $right, $parent),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
|
||||
if ($node[$right] == $node[$left] + 1) {
|
||||
if ($delete) {
|
||||
return $Model->delete($id);
|
||||
} else {
|
||||
$Model->id = $id;
|
||||
return $Model->saveField($parent, null);
|
||||
}
|
||||
} elseif ($node[$parent]) {
|
||||
list($parentNode) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
|
||||
'fields' => array($Model->primaryKey, $left, $right),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
} else {
|
||||
$parentNode[$right] = $node[$right] + 1;
|
||||
}
|
||||
|
||||
$db =& ConnectionManager::getDataSource($Model->useDbConfig);
|
||||
$Model->updateAll(
|
||||
array($parent => $db->value($node[$parent], $parent)),
|
||||
array($Model->escapeField($parent) => $node[$Model->primaryKey])
|
||||
);
|
||||
$this->__sync($Model, 1, '-', 'BETWEEN ' . ($node[$left] + 1) . ' AND ' . ($node[$right] - 1));
|
||||
$this->__sync($Model, 2, '-', '> ' . ($node[$right]));
|
||||
$Model->id = $id;
|
||||
|
||||
if ($delete) {
|
||||
$Model->updateAll(
|
||||
array(
|
||||
$Model->escapeField($left) => 0,
|
||||
$Model->escapeField($right) => 0,
|
||||
$Model->escapeField($parent) => null
|
||||
),
|
||||
array($Model->escapeField() => $id)
|
||||
);
|
||||
return $Model->delete($id);
|
||||
} else {
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive);
|
||||
if ($node[$right] == $edge) {
|
||||
$edge = $edge - 2;
|
||||
}
|
||||
$Model->id = $id;
|
||||
return $Model->save(
|
||||
array($left => $edge + 1, $right => $edge + 2, $parent => null),
|
||||
array('callbacks' => false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current tree is valid.
|
||||
*
|
||||
* Returns true if the tree is valid otherwise an array of (type, incorrect left/right index, message)
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @return mixed true if the tree is valid or empty, otherwise an array of (error type [index, node],
|
||||
* [incorrect left/right index,node id], message)
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1630/Verify
|
||||
*/
|
||||
function verify(&$Model) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
if (!$Model->find('count', array('conditions' => $scope))) {
|
||||
return true;
|
||||
}
|
||||
$min = $this->__getMin($Model, $scope, $left, $recursive);
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive);
|
||||
$errors = array();
|
||||
|
||||
for ($i = $min; $i <= $edge; $i++) {
|
||||
$count = $Model->find('count', array('conditions' => array(
|
||||
$scope, 'OR' => array($Model->escapeField($left) => $i, $Model->escapeField($right) => $i)
|
||||
)));
|
||||
if ($count != 1) {
|
||||
if ($count == 0) {
|
||||
$errors[] = array('index', $i, 'missing');
|
||||
} else {
|
||||
$errors[] = array('index', $i, 'duplicate');
|
||||
}
|
||||
}
|
||||
}
|
||||
$node = $Model->find('first', array('conditions' => array($scope, $Model->escapeField($right) . '< ' . $Model->escapeField($left)), 'recursive' => 0));
|
||||
if ($node) {
|
||||
$errors[] = array('node', $node[$Model->alias][$Model->primaryKey], 'left greater than right.');
|
||||
}
|
||||
|
||||
$Model->bindModel(array('belongsTo' => array('VerifyParent' => array(
|
||||
'className' => $Model->alias,
|
||||
'foreignKey' => $parent,
|
||||
'fields' => array($Model->primaryKey, $left, $right, $parent)
|
||||
))));
|
||||
|
||||
foreach ($Model->find('all', array('conditions' => $scope, 'recursive' => 0)) as $instance) {
|
||||
if (is_null($instance[$Model->alias][$left]) || is_null($instance[$Model->alias][$right])) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
|
||||
'has invalid left or right values');
|
||||
} elseif ($instance[$Model->alias][$left] == $instance[$Model->alias][$right]) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
|
||||
'left and right values identical');
|
||||
} elseif ($instance[$Model->alias][$parent]) {
|
||||
if (!$instance['VerifyParent'][$Model->primaryKey]) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
|
||||
'The parent node ' . $instance[$Model->alias][$parent] . ' doesn\'t exist');
|
||||
} elseif ($instance[$Model->alias][$left] < $instance['VerifyParent'][$left]) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
|
||||
'left less than parent (node ' . $instance['VerifyParent'][$Model->primaryKey] . ').');
|
||||
} elseif ($instance[$Model->alias][$right] > $instance['VerifyParent'][$right]) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
|
||||
'right greater than parent (node ' . $instance['VerifyParent'][$Model->primaryKey] . ').');
|
||||
}
|
||||
} elseif ($Model->find('count', array('conditions' => array($scope, $Model->escapeField($left) . ' <' => $instance[$Model->alias][$left], $Model->escapeField($right) . ' >' => $instance[$Model->alias][$right]), 'recursive' => 0))) {
|
||||
$errors[] = array('node', $instance[$Model->alias][$Model->primaryKey], 'The parent field is blank, but has a parent');
|
||||
}
|
||||
}
|
||||
if ($errors) {
|
||||
return $errors;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent of the given node
|
||||
*
|
||||
* The force parameter is used to override the "don't change the parent to the current parent" logic in the event
|
||||
* of recovering a corrupted table, or creating new nodes. Otherwise it should always be false. In reality this
|
||||
* method could be private, since calling save with parent_id set also calls setParent
|
||||
*
|
||||
* @param AppModel $Model Model instance
|
||||
* @param mixed $parentId
|
||||
* @return boolean true on success, false on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _setParent(&$Model, $parentId = null, $created = false) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
list($node) = array_values($Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $Model->id),
|
||||
'fields' => array($Model->primaryKey, $parent, $left, $right),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
$edge = $this->__getMax($Model, $scope, $right, $recursive, $created);
|
||||
|
||||
if (empty ($parentId)) {
|
||||
$this->__sync($Model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
|
||||
$this->__sync($Model, $node[$right] - $node[$left] + 1, '-', '> ' . $node[$left], $created);
|
||||
} else {
|
||||
$values = $Model->find('first', array(
|
||||
'conditions' => array($scope, $Model->escapeField() => $parentId),
|
||||
'fields' => array($Model->primaryKey, $left, $right),
|
||||
'recursive' => $recursive
|
||||
));
|
||||
|
||||
if ($values === false) {
|
||||
return false;
|
||||
}
|
||||
$parentNode = array_values($values);
|
||||
|
||||
if (empty($parentNode) || empty($parentNode[0])) {
|
||||
return false;
|
||||
}
|
||||
$parentNode = $parentNode[0];
|
||||
|
||||
if (($Model->id == $parentId)) {
|
||||
return false;
|
||||
|
||||
} elseif (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
|
||||
return false;
|
||||
}
|
||||
if (empty ($node[$left]) && empty ($node[$right])) {
|
||||
$this->__sync($Model, 2, '+', '>= ' . $parentNode[$right], $created);
|
||||
$result = $Model->save(
|
||||
array($left => $parentNode[$right], $right => $parentNode[$right] + 1, $parent => $parentId),
|
||||
array('validate' => false, 'callbacks' => false)
|
||||
);
|
||||
$Model->data = $result;
|
||||
} else {
|
||||
$this->__sync($Model, $edge - $node[$left] +1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
|
||||
$diff = $node[$right] - $node[$left] + 1;
|
||||
|
||||
if ($node[$left] > $parentNode[$left]) {
|
||||
if ($node[$right] < $parentNode[$right]) {
|
||||
$this->__sync($Model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
|
||||
$this->__sync($Model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
|
||||
} else {
|
||||
$this->__sync($Model, $diff, '+', 'BETWEEN ' . $parentNode[$right] . ' AND ' . $node[$right], $created);
|
||||
$this->__sync($Model, $edge - $parentNode[$right] + 1, '-', '> ' . $edge, $created);
|
||||
}
|
||||
} else {
|
||||
$this->__sync($Model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
|
||||
$this->__sync($Model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the maximum index value in the table.
|
||||
*
|
||||
* @param AppModel $Model
|
||||
* @param string $scope
|
||||
* @param string $right
|
||||
* @return int
|
||||
* @access private
|
||||
*/
|
||||
function __getMax($Model, $scope, $right, $recursive = -1, $created = false) {
|
||||
$db =& ConnectionManager::getDataSource($Model->useDbConfig);
|
||||
if ($created) {
|
||||
if (is_string($scope)) {
|
||||
$scope .= " AND {$Model->alias}.{$Model->primaryKey} <> ";
|
||||
$scope .= $db->value($Model->id, $Model->getColumnType($Model->primaryKey));
|
||||
} else {
|
||||
$scope['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id;
|
||||
}
|
||||
}
|
||||
$name = $Model->alias . '.' . $right;
|
||||
list($edge) = array_values($Model->find('first', array(
|
||||
'conditions' => $scope,
|
||||
'fields' => $db->calculate($Model, 'max', array($name, $right)),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
return (empty($edge[$right])) ? 0 : $edge[$right];
|
||||
}
|
||||
|
||||
/**
|
||||
* get the minimum index value in the table.
|
||||
*
|
||||
* @param AppModel $Model
|
||||
* @param string $scope
|
||||
* @param string $right
|
||||
* @return int
|
||||
* @access private
|
||||
*/
|
||||
function __getMin($Model, $scope, $left, $recursive = -1) {
|
||||
$db =& ConnectionManager::getDataSource($Model->useDbConfig);
|
||||
$name = $Model->alias . '.' . $left;
|
||||
list($edge) = array_values($Model->find('first', array(
|
||||
'conditions' => $scope,
|
||||
'fields' => $db->calculate($Model, 'min', array($name, $left)),
|
||||
'recursive' => $recursive
|
||||
)));
|
||||
return (empty($edge[$left])) ? 0 : $edge[$left];
|
||||
}
|
||||
|
||||
/**
|
||||
* Table sync method.
|
||||
*
|
||||
* Handles table sync operations, Taking account of the behavior scope.
|
||||
*
|
||||
* @param AppModel $Model
|
||||
* @param integer $shift
|
||||
* @param string $direction
|
||||
* @param array $conditions
|
||||
* @param string $field
|
||||
* @access private
|
||||
*/
|
||||
function __sync(&$Model, $shift, $dir = '+', $conditions = array(), $created = false, $field = 'both') {
|
||||
$ModelRecursive = $Model->recursive;
|
||||
extract($this->settings[$Model->alias]);
|
||||
$Model->recursive = $recursive;
|
||||
|
||||
if ($field == 'both') {
|
||||
$this->__sync($Model, $shift, $dir, $conditions, $created, $left);
|
||||
$field = $right;
|
||||
}
|
||||
if (is_string($conditions)) {
|
||||
$conditions = array("{$Model->alias}.{$field} {$conditions}");
|
||||
}
|
||||
if (($scope != '1 = 1' && $scope !== true) && $scope) {
|
||||
$conditions[] = $scope;
|
||||
}
|
||||
if ($created) {
|
||||
$conditions['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id;
|
||||
}
|
||||
$Model->updateAll(array($Model->alias . '.' . $field => $Model->escapeField($field) . ' ' . $dir . ' ' . $shift), $conditions);
|
||||
$Model->recursive = $ModelRecursive;
|
||||
}
|
||||
}
|
||||
693
web-cake/html/cake/libs/model/cake_schema.php
Normal file
693
web-cake/html/cake/libs/model/cake_schema.php
Normal file
@@ -0,0 +1,693 @@
|
||||
<?php
|
||||
/**
|
||||
* Schema database management for CakePHP.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
* @since CakePHP(tm) v 1.2.0.5550
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Core', array('Model', 'ConnectionManager'));
|
||||
|
||||
/**
|
||||
* Base Class for Schema management
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class CakeSchema extends Object {
|
||||
|
||||
/**
|
||||
* Name of the App Schema
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = null;
|
||||
|
||||
/**
|
||||
* Path to write location
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $path = null;
|
||||
|
||||
/**
|
||||
* File to write
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $file = 'schema.php';
|
||||
|
||||
/**
|
||||
* Connection used for read
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $connection = 'default';
|
||||
|
||||
/**
|
||||
* plugin name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $plugin = null;
|
||||
|
||||
/**
|
||||
* Set of tables
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $tables = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options optional load object properties
|
||||
*/
|
||||
function __construct($options = array()) {
|
||||
parent::__construct();
|
||||
|
||||
if (empty($options['name'])) {
|
||||
$this->name = preg_replace('/schema$/i', '', get_class($this));
|
||||
}
|
||||
if (!empty($options['plugin'])) {
|
||||
$this->plugin = $options['plugin'];
|
||||
}
|
||||
|
||||
if (strtolower($this->name) === 'cake') {
|
||||
$this->name = Inflector::camelize(Inflector::slug(Configure::read('App.dir')));
|
||||
}
|
||||
|
||||
if (empty($options['path'])) {
|
||||
if (is_dir(CONFIGS . 'schema')) {
|
||||
$this->path = CONFIGS . 'schema';
|
||||
} else {
|
||||
$this->path = CONFIGS . 'sql';
|
||||
}
|
||||
}
|
||||
|
||||
$options = array_merge(get_object_vars($this), $options);
|
||||
$this->_build($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds schema object properties
|
||||
*
|
||||
* @param array $data loaded object properties
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _build($data) {
|
||||
$file = null;
|
||||
foreach ($data as $key => $val) {
|
||||
if (!empty($val)) {
|
||||
if (!in_array($key, array('plugin', 'name', 'path', 'file', 'connection', 'tables', '_log'))) {
|
||||
$this->tables[$key] = $val;
|
||||
unset($this->{$key});
|
||||
} elseif ($key !== 'tables') {
|
||||
if ($key === 'name' && $val !== $this->name && !isset($data['file'])) {
|
||||
$file = Inflector::underscore($val) . '.php';
|
||||
}
|
||||
$this->{$key} = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file_exists($this->path . DS . $file) && is_file($this->path . DS . $file)) {
|
||||
$this->file = $file;
|
||||
} elseif (!empty($this->plugin)) {
|
||||
$this->path = App::pluginPath($this->plugin) . 'config' . DS . 'schema';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Before callback to be implemented in subclasses
|
||||
*
|
||||
* @param array $events schema object properties
|
||||
* @return boolean Should process continue
|
||||
* @access public
|
||||
*/
|
||||
function before($event = array()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* After callback to be implemented in subclasses
|
||||
*
|
||||
* @param array $events schema object properties
|
||||
* @access public
|
||||
*/
|
||||
function after($event = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads database and creates schema tables
|
||||
*
|
||||
* @param array $options schema object properties
|
||||
* @return array Set of name and tables
|
||||
* @access public
|
||||
*/
|
||||
function &load($options = array()) {
|
||||
if (is_string($options)) {
|
||||
$options = array('path' => $options);
|
||||
}
|
||||
|
||||
$this->_build($options);
|
||||
extract(get_object_vars($this));
|
||||
|
||||
$class = $name .'Schema';
|
||||
|
||||
if (!class_exists($class)) {
|
||||
if (file_exists($path . DS . $file) && is_file($path . DS . $file)) {
|
||||
require_once($path . DS . $file);
|
||||
} elseif (file_exists($path . DS . 'schema.php') && is_file($path . DS . 'schema.php')) {
|
||||
require_once($path . DS . 'schema.php');
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists($class)) {
|
||||
$Schema =& new $class($options);
|
||||
return $Schema;
|
||||
}
|
||||
$false = false;
|
||||
return $false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads database and creates schema tables
|
||||
*
|
||||
* Options
|
||||
*
|
||||
* - 'connection' - the db connection to use
|
||||
* - 'name' - name of the schema
|
||||
* - 'models' - a list of models to use, or false to ignore models
|
||||
*
|
||||
* @param array $options schema object properties
|
||||
* @return array Array indexed by name and tables
|
||||
* @access public
|
||||
*/
|
||||
function read($options = array()) {
|
||||
extract(array_merge(
|
||||
array(
|
||||
'connection' => $this->connection,
|
||||
'name' => $this->name,
|
||||
'models' => true,
|
||||
),
|
||||
$options
|
||||
));
|
||||
$db =& ConnectionManager::getDataSource($connection);
|
||||
|
||||
App::import('Model', 'AppModel');
|
||||
if (isset($this->plugin)) {
|
||||
App::import('Model', Inflector::camelize($this->plugin) . 'AppModel');
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
$currentTables = $db->listSources();
|
||||
|
||||
$prefix = null;
|
||||
if (isset($db->config['prefix'])) {
|
||||
$prefix = $db->config['prefix'];
|
||||
}
|
||||
|
||||
if (!is_array($models) && $models !== false) {
|
||||
if (isset($this->plugin)) {
|
||||
$models = App::objects('model', App::pluginPath($this->plugin) . 'models' . DS, false);
|
||||
} else {
|
||||
$models = App::objects('model');
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($models)) {
|
||||
foreach ($models as $model) {
|
||||
$importModel = $model;
|
||||
if (isset($this->plugin)) {
|
||||
$importModel = $this->plugin . '.' . $model;
|
||||
}
|
||||
if (!App::import('Model', $importModel)) {
|
||||
continue;
|
||||
}
|
||||
$vars = get_class_vars($model);
|
||||
if (empty($vars['useDbConfig']) || $vars['useDbConfig'] != $connection) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PHP5) {
|
||||
$Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection));
|
||||
} else {
|
||||
$Object =& ClassRegistry::init(array('class' => $model, 'ds' => $connection));
|
||||
}
|
||||
|
||||
if (is_object($Object) && $Object->useTable !== false) {
|
||||
$fulltable = $table = $db->fullTableName($Object, false);
|
||||
if ($prefix && strpos($table, $prefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
$table = str_replace($prefix, '', $table);
|
||||
|
||||
if (in_array($fulltable, $currentTables)) {
|
||||
$key = array_search($fulltable, $currentTables);
|
||||
if (empty($tables[$table])) {
|
||||
$tables[$table] = $this->__columns($Object);
|
||||
$tables[$table]['indexes'] = $db->index($Object);
|
||||
$tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
|
||||
unset($currentTables[$key]);
|
||||
}
|
||||
if (!empty($Object->hasAndBelongsToMany)) {
|
||||
foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) {
|
||||
if (isset($assocData['with'])) {
|
||||
$class = $assocData['with'];
|
||||
}
|
||||
if (is_object($Object->$class)) {
|
||||
$withTable = $db->fullTableName($Object->$class, false);
|
||||
if (in_array($withTable, $currentTables)) {
|
||||
$key = array_search($withTable, $currentTables);
|
||||
$tables[$withTable] = $this->__columns($Object->$class);
|
||||
$tables[$withTable]['indexes'] = $db->index($Object->$class);
|
||||
$tables[$withTable]['tableParameters'] = $db->readTableParameters($withTable);
|
||||
unset($currentTables[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($currentTables)) {
|
||||
foreach ($currentTables as $table) {
|
||||
if ($prefix) {
|
||||
if (strpos($table, $prefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
$table = str_replace($prefix, '', $table);
|
||||
}
|
||||
$Object = new AppModel(array(
|
||||
'name' => Inflector::classify($table), 'table' => $table, 'ds' => $connection
|
||||
));
|
||||
|
||||
$systemTables = array(
|
||||
'aros', 'acos', 'aros_acos', Configure::read('Session.table'), 'i18n'
|
||||
);
|
||||
|
||||
if (in_array($table, $systemTables)) {
|
||||
$tables[$Object->table] = $this->__columns($Object);
|
||||
$tables[$Object->table]['indexes'] = $db->index($Object);
|
||||
$tables[$Object->table]['tableParameters'] = $db->readTableParameters($table);
|
||||
} elseif ($models === false) {
|
||||
$tables[$table] = $this->__columns($Object);
|
||||
$tables[$table]['indexes'] = $db->index($Object);
|
||||
$tables[$table]['tableParameters'] = $db->readTableParameters($table);
|
||||
} else {
|
||||
$tables['missing'][$table] = $this->__columns($Object);
|
||||
$tables['missing'][$table]['indexes'] = $db->index($Object);
|
||||
$tables['missing'][$table]['tableParameters'] = $db->readTableParameters($table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksort($tables);
|
||||
return compact('name', 'tables');
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes schema file from object or options
|
||||
*
|
||||
* @param mixed $object schema object or options array
|
||||
* @param array $options schema object properties to override object
|
||||
* @return mixed false or string written to file
|
||||
* @access public
|
||||
*/
|
||||
function write($object, $options = array()) {
|
||||
if (is_object($object)) {
|
||||
$object = get_object_vars($object);
|
||||
$this->_build($object);
|
||||
}
|
||||
|
||||
if (is_array($object)) {
|
||||
$options = $object;
|
||||
unset($object);
|
||||
}
|
||||
|
||||
extract(array_merge(
|
||||
get_object_vars($this), $options
|
||||
));
|
||||
|
||||
$out = "class {$name}Schema extends CakeSchema {\n";
|
||||
|
||||
$out .= "\tvar \$name = '{$name}';\n\n";
|
||||
|
||||
if ($path !== $this->path) {
|
||||
$out .= "\tvar \$path = '{$path}';\n\n";
|
||||
}
|
||||
|
||||
if ($file !== $this->file) {
|
||||
$out .= "\tvar \$file = '{$file}';\n\n";
|
||||
}
|
||||
|
||||
if ($connection !== 'default') {
|
||||
$out .= "\tvar \$connection = '{$connection}';\n\n";
|
||||
}
|
||||
|
||||
$out .= "\tfunction before(\$event = array()) {\n\t\treturn true;\n\t}\n\n\tfunction after(\$event = array()) {\n\t}\n\n";
|
||||
|
||||
if (empty($tables)) {
|
||||
$this->read();
|
||||
}
|
||||
|
||||
foreach ($tables as $table => $fields) {
|
||||
if (!is_numeric($table) && $table !== 'missing') {
|
||||
$out .= $this->generateTable($table, $fields);
|
||||
}
|
||||
}
|
||||
$out .= "}\n";
|
||||
|
||||
$File =& new File($path . DS . $file, true);
|
||||
$header = '$Id';
|
||||
$content = "<?php \n/* SVN FILE: {$header}$ */\n/* {$name} schema generated on: " . date('Y-m-d H:m:s') . " : ". time() . "*/\n{$out}?>";
|
||||
$content = $File->prepare($content);
|
||||
if ($File->write($content)) {
|
||||
return $content;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the code for a table. Takes a table name and $fields array
|
||||
* Returns a completed variable declaration to be used in schema classes
|
||||
*
|
||||
* @param string $table Table name you want returned.
|
||||
* @param array $fields Array of field information to generate the table with.
|
||||
* @return string Variable declaration for a schema class
|
||||
*/
|
||||
function generateTable($table, $fields) {
|
||||
$out = "\tvar \${$table} = array(\n";
|
||||
if (is_array($fields)) {
|
||||
$cols = array();
|
||||
foreach ($fields as $field => $value) {
|
||||
if ($field != 'indexes' && $field != 'tableParameters') {
|
||||
if (is_string($value)) {
|
||||
$type = $value;
|
||||
$value = array('type'=> $type);
|
||||
}
|
||||
$col = "\t\t'{$field}' => array('type' => '" . $value['type'] . "', ";
|
||||
unset($value['type']);
|
||||
$col .= join(', ', $this->__values($value));
|
||||
} elseif ($field == 'indexes') {
|
||||
$col = "\t\t'indexes' => array(";
|
||||
$props = array();
|
||||
foreach ((array)$value as $key => $index) {
|
||||
$props[] = "'{$key}' => array(" . join(', ', $this->__values($index)) . ")";
|
||||
}
|
||||
$col .= join(', ', $props);
|
||||
} elseif ($field == 'tableParameters') {
|
||||
//@todo add charset, collate and engine here
|
||||
$col = "\t\t'tableParameters' => array(";
|
||||
$props = array();
|
||||
foreach ((array)$value as $key => $param) {
|
||||
$props[] = "'{$key}' => '$param'";
|
||||
}
|
||||
$col .= join(', ', $props);
|
||||
}
|
||||
$col .= ")";
|
||||
$cols[] = $col;
|
||||
}
|
||||
$out .= join(",\n", $cols);
|
||||
}
|
||||
$out .= "\n\t);\n";
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two sets of schemas
|
||||
*
|
||||
* @param mixed $old Schema object or array
|
||||
* @param mixed $new Schema object or array
|
||||
* @return array Tables (that are added, dropped, or changed)
|
||||
* @access public
|
||||
*/
|
||||
function compare($old, $new = null) {
|
||||
if (empty($new)) {
|
||||
$new =& $this;
|
||||
}
|
||||
if (is_array($new)) {
|
||||
if (isset($new['tables'])) {
|
||||
$new = $new['tables'];
|
||||
}
|
||||
} else {
|
||||
$new = $new->tables;
|
||||
}
|
||||
|
||||
if (is_array($old)) {
|
||||
if (isset($old['tables'])) {
|
||||
$old = $old['tables'];
|
||||
}
|
||||
} else {
|
||||
$old = $old->tables;
|
||||
}
|
||||
$tables = array();
|
||||
foreach ($new as $table => $fields) {
|
||||
if ($table == 'missing') {
|
||||
continue;
|
||||
}
|
||||
if (!array_key_exists($table, $old)) {
|
||||
$tables[$table]['add'] = $fields;
|
||||
} else {
|
||||
$diff = $this->_arrayDiffAssoc($fields, $old[$table]);
|
||||
if (!empty($diff)) {
|
||||
$tables[$table]['add'] = $diff;
|
||||
}
|
||||
$diff = $this->_arrayDiffAssoc($old[$table], $fields);
|
||||
if (!empty($diff)) {
|
||||
$tables[$table]['drop'] = $diff;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $field => $value) {
|
||||
if (isset($old[$table][$field])) {
|
||||
$diff = $this->_arrayDiffAssoc($value, $old[$table][$field]);
|
||||
if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') {
|
||||
$tables[$table]['change'][$field] = array_merge($old[$table][$field], $diff);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($add[$table][$field])) {
|
||||
$wrapper = array_keys($fields);
|
||||
if ($column = array_search($field, $wrapper)) {
|
||||
if (isset($wrapper[$column - 1])) {
|
||||
$tables[$table]['add'][$field]['after'] = $wrapper[$column - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($old[$table]['indexes']) && isset($new[$table]['indexes'])) {
|
||||
$diff = $this->_compareIndexes($new[$table]['indexes'], $old[$table]['indexes']);
|
||||
if ($diff) {
|
||||
if (!isset($tables[$table])) {
|
||||
$tables[$table] = array();
|
||||
}
|
||||
if (isset($diff['drop'])) {
|
||||
$tables[$table]['drop']['indexes'] = $diff['drop'];
|
||||
}
|
||||
if ($diff && isset($diff['add'])) {
|
||||
$tables[$table]['add']['indexes'] = $diff['add'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($old[$table]['tableParameters']) && isset($new[$table]['tableParameters'])) {
|
||||
$diff = $this->_compareTableParameters($new[$table]['tableParameters'], $old[$table]['tableParameters']);
|
||||
if ($diff) {
|
||||
$tables[$table]['change']['tableParameters'] = $diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended array_diff_assoc noticing change from/to NULL values
|
||||
*
|
||||
* It behaves almost the same way as array_diff_assoc except for NULL values: if
|
||||
* one of the values is not NULL - change is detected. It is useful in situation
|
||||
* where one value is strval('') ant other is strval(null) - in string comparing
|
||||
* methods this results as EQUAL, while it is not.
|
||||
*
|
||||
* @param array $array1 Base array
|
||||
* @param array $array2 Corresponding array checked for equality
|
||||
* @return array Difference as array with array(keys => values) from input array
|
||||
* where match was not found.
|
||||
* @access protected
|
||||
*/
|
||||
function _arrayDiffAssoc($array1, $array2) {
|
||||
$difference = array();
|
||||
foreach ($array1 as $key => $value) {
|
||||
if (!array_key_exists($key, $array2)) {
|
||||
$difference[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
$correspondingValue = $array2[$key];
|
||||
if (is_null($value) !== is_null($correspondingValue)) {
|
||||
$difference[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
if (is_bool($value) !== is_bool($correspondingValue)) {
|
||||
$difference[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
$compare = strval($value);
|
||||
$correspondingValue = strval($correspondingValue);
|
||||
if ($compare === $correspondingValue) {
|
||||
continue;
|
||||
}
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
return $difference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats Schema columns from Model Object
|
||||
*
|
||||
* @param array $values options keys(type, null, default, key, length, extra)
|
||||
* @return array Formatted values
|
||||
* @access public
|
||||
*/
|
||||
function __values($values) {
|
||||
$vals = array();
|
||||
if (is_array($values)) {
|
||||
foreach ($values as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$vals[] = "'{$key}' => array('" . implode("', '", $val) . "')";
|
||||
} else if (!is_numeric($key)) {
|
||||
$val = var_export($val, true);
|
||||
$vals[] = "'{$key}' => {$val}";
|
||||
}
|
||||
}
|
||||
}
|
||||
return $vals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats Schema columns from Model Object
|
||||
*
|
||||
* @param array $Obj model object
|
||||
* @return array Formatted columns
|
||||
* @access public
|
||||
*/
|
||||
function __columns(&$Obj) {
|
||||
$db =& ConnectionManager::getDataSource($Obj->useDbConfig);
|
||||
$fields = $Obj->schema(true);
|
||||
$columns = $props = array();
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($Obj->primaryKey == $name) {
|
||||
$value['key'] = 'primary';
|
||||
}
|
||||
if (!isset($db->columns[$value['type']])) {
|
||||
trigger_error(sprintf(__('Schema generation error: invalid column type %s does not exist in DBO', true), $value['type']), E_USER_NOTICE);
|
||||
continue;
|
||||
} else {
|
||||
$defaultCol = $db->columns[$value['type']];
|
||||
if (isset($defaultCol['limit']) && $defaultCol['limit'] == $value['length']) {
|
||||
unset($value['length']);
|
||||
} elseif (isset($defaultCol['length']) && $defaultCol['length'] == $value['length']) {
|
||||
unset($value['length']);
|
||||
}
|
||||
unset($value['limit']);
|
||||
}
|
||||
|
||||
if (isset($value['default']) && ($value['default'] === '' || $value['default'] === false)) {
|
||||
unset($value['default']);
|
||||
}
|
||||
if (empty($value['length'])) {
|
||||
unset($value['length']);
|
||||
}
|
||||
if (empty($value['key'])) {
|
||||
unset($value['key']);
|
||||
}
|
||||
$columns[$name] = $value;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two schema files table Parameters
|
||||
*
|
||||
* @param array $new New indexes
|
||||
* @param array $old Old indexes
|
||||
* @return mixed False on failure, or an array of parameters to add & drop.
|
||||
*/
|
||||
function _compareTableParameters($new, $old) {
|
||||
if (!is_array($new) || !is_array($old)) {
|
||||
return false;
|
||||
}
|
||||
$change = $this->_arrayDiffAssoc($new, $old);
|
||||
return $change;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two schema indexes
|
||||
*
|
||||
* @param array $new New indexes
|
||||
* @param array $old Old indexes
|
||||
* @return mixed false on failure or array of indexes to add and drop
|
||||
*/
|
||||
function _compareIndexes($new, $old) {
|
||||
if (!is_array($new) || !is_array($old)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$add = $drop = array();
|
||||
|
||||
$diff = $this->_arrayDiffAssoc($new, $old);
|
||||
if (!empty($diff)) {
|
||||
$add = $diff;
|
||||
}
|
||||
|
||||
$diff = $this->_arrayDiffAssoc($old, $new);
|
||||
if (!empty($diff)) {
|
||||
$drop = $diff;
|
||||
}
|
||||
|
||||
foreach ($new as $name => $value) {
|
||||
if (isset($old[$name])) {
|
||||
$newUnique = isset($value['unique']) ? $value['unique'] : 0;
|
||||
$oldUnique = isset($old[$name]['unique']) ? $old[$name]['unique'] : 0;
|
||||
$newColumn = $value['column'];
|
||||
$oldColumn = $old[$name]['column'];
|
||||
|
||||
$diff = false;
|
||||
|
||||
if ($newUnique != $oldUnique) {
|
||||
$diff = true;
|
||||
} elseif (is_array($newColumn) && is_array($oldColumn)) {
|
||||
$diff = ($newColumn !== $oldColumn);
|
||||
} elseif (is_string($newColumn) && is_string($oldColumn)) {
|
||||
$diff = ($newColumn != $oldColumn);
|
||||
} else {
|
||||
$diff = true;
|
||||
}
|
||||
if ($diff) {
|
||||
$drop[$name] = null;
|
||||
$add[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_filter(compact('add', 'drop'));
|
||||
}
|
||||
}
|
||||
295
web-cake/html/cake/libs/model/connection_manager.php
Normal file
295
web-cake/html/cake/libs/model/connection_manager.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
/**
|
||||
* Datasource connection manager
|
||||
*
|
||||
* Provides an interface for loading and enumerating connections defined in app/config/database.php
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
* @since CakePHP(tm) v 0.10.x.1402
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
require LIBS . 'model' . DS . 'datasources' . DS . 'datasource.php';
|
||||
include_once CONFIGS . 'database.php';
|
||||
|
||||
/**
|
||||
* Manages loaded instances of DataSource objects
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class ConnectionManager extends Object {
|
||||
|
||||
/**
|
||||
* Holds a loaded instance of the Connections object
|
||||
*
|
||||
* @var DATABASE_CONFIG
|
||||
* @access public
|
||||
*/
|
||||
var $config = null;
|
||||
|
||||
/**
|
||||
* Holds instances DataSource objects
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_dataSources = array();
|
||||
|
||||
/**
|
||||
* Contains a list of all file and class names used in Connection settings
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_connectionsEnum = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
if (class_exists('DATABASE_CONFIG')) {
|
||||
$this->config =& new DATABASE_CONFIG();
|
||||
$this->_getConnectionObjects();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the ConnectionManger object instance
|
||||
*
|
||||
* @return object Instance
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
|
||||
if (!$instance) {
|
||||
$instance[0] =& new ConnectionManager();
|
||||
}
|
||||
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to a DataSource object
|
||||
*
|
||||
* @param string $name The name of the DataSource, as defined in app/config/database.php
|
||||
* @return object Instance
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getDataSource($name) {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
|
||||
if (!empty($_this->_dataSources[$name])) {
|
||||
$return =& $_this->_dataSources[$name];
|
||||
return $return;
|
||||
}
|
||||
|
||||
if (empty($_this->_connectionsEnum[$name])) {
|
||||
trigger_error(sprintf(__("ConnectionManager::getDataSource - Non-existent data source %s", true), $name), E_USER_ERROR);
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$conn = $_this->_connectionsEnum[$name];
|
||||
$class = $conn['classname'];
|
||||
|
||||
if ($_this->loadDataSource($name) === null) {
|
||||
trigger_error(sprintf(__("ConnectionManager::getDataSource - Could not load class %s", true), $class), E_USER_ERROR);
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$_this->_dataSources[$name] =& new $class($_this->config->{$name});
|
||||
$_this->_dataSources[$name]->configKeyName = $name;
|
||||
|
||||
$return =& $_this->_dataSources[$name];
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of available DataSource connections
|
||||
*
|
||||
* @return array List of available connections
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function sourceList() {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
return array_keys($_this->_dataSources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a DataSource name from an object reference.
|
||||
*
|
||||
* **Warning** this method may cause fatal errors in PHP4.
|
||||
*
|
||||
* @param object $source DataSource object
|
||||
* @return string Datasource name, or null if source is not present
|
||||
* in the ConnectionManager.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function getSourceName(&$source) {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
foreach ($_this->_dataSources as $name => $ds) {
|
||||
if ($ds == $source) {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the DataSource class for the given connection name
|
||||
*
|
||||
* @param mixed $connName A string name of the connection, as defined in app/config/database.php,
|
||||
* or an array containing the filename (without extension) and class name of the object,
|
||||
* to be found in app/models/datasources/ or cake/libs/model/datasources/.
|
||||
* @return boolean True on success, null on failure or false if the class is already loaded
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function loadDataSource($connName) {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
|
||||
if (is_array($connName)) {
|
||||
$conn = $connName;
|
||||
} else {
|
||||
$conn = $_this->_connectionsEnum[$connName];
|
||||
}
|
||||
|
||||
if (class_exists($conn['classname'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($conn['parent'])) {
|
||||
$_this->loadDataSource($conn['parent']);
|
||||
}
|
||||
|
||||
$conn = array_merge(array('plugin' => null, 'classname' => null, 'parent' => null), $conn);
|
||||
$class = "{$conn['plugin']}.{$conn['classname']}";
|
||||
|
||||
if (!App::import('Datasource', $class, !is_null($conn['plugin']))) {
|
||||
trigger_error(sprintf(__('ConnectionManager::loadDataSource - Unable to import DataSource class %s', true), $class), E_USER_ERROR);
|
||||
return null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of connections
|
||||
*
|
||||
* @return array An associative array of elements where the key is the connection name
|
||||
* (as defined in Connections), and the value is an array with keys 'filename' and 'classname'.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function enumConnectionObjects() {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
|
||||
return $_this->_connectionsEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically creates a DataSource object at runtime, with the given name and settings
|
||||
*
|
||||
* @param string $name The DataSource name
|
||||
* @param array $config The DataSource configuration settings
|
||||
* @return object A reference to the DataSource object, or null if creation failed
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &create($name = '', $config = array()) {
|
||||
$_this =& ConnectionManager::getInstance();
|
||||
|
||||
if (empty($name) || empty($config) || array_key_exists($name, $_this->_connectionsEnum)) {
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$_this->config->{$name} = $config;
|
||||
$_this->_connectionsEnum[$name] = $_this->__connectionData($config);
|
||||
$return =& $_this->getDataSource($name);
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of class and file names associated with the user-defined DataSource connections
|
||||
*
|
||||
* @return void
|
||||
* @access protected
|
||||
* @static
|
||||
*/
|
||||
function _getConnectionObjects() {
|
||||
$connections = get_object_vars($this->config);
|
||||
|
||||
if ($connections != null) {
|
||||
foreach ($connections as $name => $config) {
|
||||
$this->_connectionsEnum[$name] = $this->__connectionData($config);
|
||||
}
|
||||
} else {
|
||||
$this->cakeError('missingConnection', array(array('code' => 500, 'className' => 'ConnectionManager')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file, class name, and parent for the given driver.
|
||||
*
|
||||
* @return array An indexed array with: filename, classname, plugin and parent
|
||||
* @access private
|
||||
*/
|
||||
function __connectionData($config) {
|
||||
if (!isset($config['datasource'])) {
|
||||
$config['datasource'] = 'dbo';
|
||||
}
|
||||
$filename = $classname = $parent = $plugin = null;
|
||||
|
||||
if (!empty($config['driver'])) {
|
||||
$parent = $this->__connectionData(array('datasource' => $config['datasource']));
|
||||
$parentSource = preg_replace('/_source$/', '', $parent['filename']);
|
||||
|
||||
list($plugin, $classname) = pluginSplit($config['driver']);
|
||||
if ($plugin) {
|
||||
$source = Inflector::underscore($classname);
|
||||
} else {
|
||||
$source = $parentSource . '_' . $config['driver'];
|
||||
$classname = Inflector::camelize(strtolower($source));
|
||||
}
|
||||
$filename = $parentSource . DS . $source;
|
||||
} else {
|
||||
list($plugin, $classname) = pluginSplit($config['datasource']);
|
||||
if ($plugin) {
|
||||
$filename = Inflector::underscore($classname);
|
||||
} else {
|
||||
$filename = Inflector::underscore($config['datasource']);
|
||||
}
|
||||
if (substr($filename, -7) != '_source') {
|
||||
$filename .= '_source';
|
||||
}
|
||||
$classname = Inflector::camelize(strtolower($filename));
|
||||
}
|
||||
return compact('filename', 'classname', 'parent', 'plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __destruct() {
|
||||
if (Configure::read('Session.save') == 'database' && function_exists('session_write_close')) {
|
||||
session_write_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
596
web-cake/html/cake/libs/model/datasources/datasource.php
Normal file
596
web-cake/html/cake/libs/model/datasources/datasource.php
Normal file
@@ -0,0 +1,596 @@
|
||||
<?php
|
||||
/**
|
||||
* DataSource base class
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources
|
||||
* @since CakePHP(tm) v 0.10.5.1790
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* DataSource base class
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources
|
||||
*/
|
||||
class DataSource extends Object {
|
||||
|
||||
/**
|
||||
* Are we connected to the DataSource?
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $connected = false;
|
||||
|
||||
/**
|
||||
* Print full query debug info?
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $fullDebug = false;
|
||||
|
||||
/**
|
||||
* Error description of last query
|
||||
*
|
||||
* @var unknown_type
|
||||
* @access public
|
||||
*/
|
||||
var $error = null;
|
||||
|
||||
/**
|
||||
* String to hold how many rows were affected by the last SQL operation.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $affected = null;
|
||||
|
||||
/**
|
||||
* Number of rows in current resultset
|
||||
*
|
||||
* @var int
|
||||
* @access public
|
||||
*/
|
||||
var $numRows = null;
|
||||
|
||||
/**
|
||||
* Time the last query took
|
||||
*
|
||||
* @var int
|
||||
* @access public
|
||||
*/
|
||||
var $took = null;
|
||||
|
||||
/**
|
||||
* The starting character that this DataSource uses for quoted identifiers.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $startQuote = null;
|
||||
|
||||
/**
|
||||
* The ending character that this DataSource uses for quoted identifiers.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $endQuote = null;
|
||||
|
||||
/**
|
||||
* Result
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_result = null;
|
||||
|
||||
/**
|
||||
* Queries count.
|
||||
*
|
||||
* @var int
|
||||
* @access protected
|
||||
*/
|
||||
var $_queriesCnt = 0;
|
||||
|
||||
/**
|
||||
* Total duration of all queries.
|
||||
*
|
||||
* @var unknown_type
|
||||
* @access protected
|
||||
*/
|
||||
var $_queriesTime = null;
|
||||
|
||||
/**
|
||||
* Log of queries executed by this DataSource
|
||||
*
|
||||
* @var unknown_type
|
||||
* @access protected
|
||||
*/
|
||||
var $_queriesLog = array();
|
||||
|
||||
/**
|
||||
* Maximum number of items in query log
|
||||
*
|
||||
* This is to prevent query log taking over too much memory.
|
||||
*
|
||||
* @var int Maximum number of queries in the queries log.
|
||||
* @access protected
|
||||
*/
|
||||
var $_queriesLogMax = 200;
|
||||
|
||||
/**
|
||||
* Caches serialzed results of executed queries
|
||||
*
|
||||
* @var array Maximum number of queries in the queries log.
|
||||
* @access protected
|
||||
*/
|
||||
var $_queryCache = array();
|
||||
|
||||
/**
|
||||
* The default configuration of a specific DataSource
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_baseConfig = array();
|
||||
|
||||
/**
|
||||
* Holds references to descriptions loaded by the DataSource
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__descriptions = array();
|
||||
|
||||
/**
|
||||
* Holds a list of sources (tables) contained in the DataSource
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_sources = null;
|
||||
|
||||
/**
|
||||
* A reference to the physical connection of this DataSource
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $connection = null;
|
||||
|
||||
/**
|
||||
* The DataSource configuration
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $config = array();
|
||||
|
||||
/**
|
||||
* The DataSource configuration key name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $configKeyName = null;
|
||||
|
||||
/**
|
||||
* Whether or not this DataSource is in the middle of a transaction
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
*/
|
||||
var $_transactionStarted = false;
|
||||
|
||||
/**
|
||||
* Whether or not source data like available tables and schema descriptions
|
||||
* should be cached
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $cacheSources = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config Array of configuration information for the datasource.
|
||||
* @return void.
|
||||
*/
|
||||
function __construct($config = array()) {
|
||||
parent::__construct();
|
||||
$this->setConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches/returns cached results for child instances
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return array Array of sources available in this datasource.
|
||||
* @access public
|
||||
*/
|
||||
function listSources($data = null) {
|
||||
if ($this->cacheSources === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->_sources !== null) {
|
||||
return $this->_sources;
|
||||
}
|
||||
|
||||
$key = ConnectionManager::getSourceName($this) . '_' . $this->config['database'] . '_list';
|
||||
$key = preg_replace('/[^A-Za-z0-9_\-.+]/', '_', $key);
|
||||
$sources = Cache::read($key, '_cake_model_');
|
||||
|
||||
if (empty($sources)) {
|
||||
$sources = $data;
|
||||
Cache::write($key, $data, '_cake_model_');
|
||||
}
|
||||
|
||||
$this->_sources = $sources;
|
||||
return $sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for DboSource::listSources(). Returns source names in lowercase.
|
||||
*
|
||||
* @param boolean $reset Whether or not the source list should be reset.
|
||||
* @return array Array of sources available in this datasource
|
||||
* @access public
|
||||
*/
|
||||
function sources($reset = false) {
|
||||
if ($reset === true) {
|
||||
$this->_sources = null;
|
||||
}
|
||||
return array_map('strtolower', $this->listSources());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Model description (metadata) or null if none found.
|
||||
*
|
||||
* @param Model $model
|
||||
* @return array Array of Metadata for the $model
|
||||
* @access public
|
||||
*/
|
||||
function describe(&$model) {
|
||||
if ($this->cacheSources === false) {
|
||||
return null;
|
||||
}
|
||||
$table = $model->tablePrefix . $model->table;
|
||||
|
||||
if (isset($this->__descriptions[$table])) {
|
||||
return $this->__descriptions[$table];
|
||||
}
|
||||
$cache = $this->__cacheDescription($table);
|
||||
|
||||
if ($cache !== null) {
|
||||
$this->__descriptions[$table] =& $cache;
|
||||
return $cache;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a transaction
|
||||
*
|
||||
* @return boolean Returns true if a transaction is not in progress
|
||||
* @access public
|
||||
*/
|
||||
function begin(&$model) {
|
||||
return !$this->_transactionStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit a transaction
|
||||
*
|
||||
* @return boolean Returns true if a transaction is in progress
|
||||
* @access public
|
||||
*/
|
||||
function commit(&$model) {
|
||||
return $this->_transactionStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback a transaction
|
||||
*
|
||||
* @return boolean Returns true if a transaction is in progress
|
||||
* @access public
|
||||
*/
|
||||
function rollback(&$model) {
|
||||
return $this->_transactionStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts column types to basic types
|
||||
*
|
||||
* @param string $real Real column type (i.e. "varchar(255)")
|
||||
* @return string Abstract column type (i.e. "string")
|
||||
* @access public
|
||||
*/
|
||||
function column($real) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create new records. The "C" CRUD.
|
||||
*
|
||||
* To-be-overridden in subclasses.
|
||||
*
|
||||
* @param Model $model The Model to be created.
|
||||
* @param array $fields An Array of fields to be saved.
|
||||
* @param array $values An Array of values to save.
|
||||
* @return boolean success
|
||||
* @access public
|
||||
*/
|
||||
function create(&$model, $fields = null, $values = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read records from the Datasource. The "R" in CRUD
|
||||
*
|
||||
* To-be-overridden in subclasses.
|
||||
*
|
||||
* @param Model $model The model being read.
|
||||
* @param array $queryData An array of query data used to find the data you want
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function read(&$model, $queryData = array()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a record(s) in the datasource.
|
||||
*
|
||||
* To-be-overridden in subclasses.
|
||||
*
|
||||
* @param Model $model Instance of the model class being updated
|
||||
* @param array $fields Array of fields to be updated
|
||||
* @param array $values Array of values to be update $fields to.
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
*/
|
||||
function update(&$model, $fields = null, $values = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a record(s) in the datasource.
|
||||
*
|
||||
* To-be-overridden in subclasses.
|
||||
*
|
||||
* @param Model $model The model class having record(s) deleted
|
||||
* @param mixed $id Primary key of the model
|
||||
* @access public
|
||||
*/
|
||||
function delete(&$model, $id = null) {
|
||||
if ($id == null) {
|
||||
$id = $model->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return mixed Last ID key generated in previous INSERT
|
||||
* @access public
|
||||
*/
|
||||
function lastInsertId($source = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return integer Number of rows returned by last operation
|
||||
* @access public
|
||||
*/
|
||||
function lastNumRows($source = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return integer Number of rows affected by last query.
|
||||
* @access public
|
||||
*/
|
||||
function lastAffected($source = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the conditions for the Datasource being available
|
||||
* are satisfied. Often used from connect() to check for support
|
||||
* before establishing a connection.
|
||||
*
|
||||
* @return boolean Whether or not the Datasources conditions for use are met.
|
||||
* @access public
|
||||
*/
|
||||
function enabled() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Returns true if the DataSource supports the given interface (method)
|
||||
*
|
||||
* @param string $interface The name of the interface (method)
|
||||
* @return boolean True on success
|
||||
* @access public
|
||||
*/
|
||||
function isInterfaceSupported($interface) {
|
||||
static $methods = false;
|
||||
if ($methods === false) {
|
||||
$methods = array_map('strtolower', get_class_methods($this));
|
||||
}
|
||||
return in_array(strtolower($interface), $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration for the DataSource.
|
||||
* Merges the $config information with the _baseConfig and the existing $config property.
|
||||
*
|
||||
* @param array $config The configuration array
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function setConfig($config = array()) {
|
||||
$this->config = array_merge($this->_baseConfig, $this->config, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the DataSource description
|
||||
*
|
||||
* @param string $object The name of the object (model) to cache
|
||||
* @param mixed $data The description of the model, usually a string or array
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
function __cacheDescription($object, $data = null) {
|
||||
if ($this->cacheSources === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($data !== null) {
|
||||
$this->__descriptions[$object] =& $data;
|
||||
}
|
||||
|
||||
$key = ConnectionManager::getSourceName($this) . '_' . $object;
|
||||
$cache = Cache::read($key, '_cake_model_');
|
||||
|
||||
if (empty($cache)) {
|
||||
$cache = $data;
|
||||
Cache::write($key, $cache, '_cake_model_');
|
||||
}
|
||||
|
||||
return $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces `{$__cakeID__$}` and `{$__cakeForeignKey__$}` placeholders in query data.
|
||||
*
|
||||
* @param string $query Query string needing replacements done.
|
||||
* @param array $data Array of data with values that will be inserted in placeholders.
|
||||
* @param string $association Name of association model being replaced
|
||||
* @param unknown_type $assocData
|
||||
* @param Model $model Instance of the model to replace $__cakeID__$
|
||||
* @param Model $linkModel Instance of model to replace $__cakeForeignKey__$
|
||||
* @param array $stack
|
||||
* @return string String of query data with placeholders replaced.
|
||||
* @access public
|
||||
* @todo Remove and refactor $assocData, ensure uses of the method have the param removed too.
|
||||
*/
|
||||
function insertQueryData($query, $data, $association, $assocData, &$model, &$linkModel, $stack) {
|
||||
$keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}');
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$val = null;
|
||||
|
||||
if (strpos($query, $key) !== false) {
|
||||
switch ($key) {
|
||||
case '{$__cakeID__$}':
|
||||
if (isset($data[$model->alias]) || isset($data[$association])) {
|
||||
if (isset($data[$model->alias][$model->primaryKey])) {
|
||||
$val = $data[$model->alias][$model->primaryKey];
|
||||
} elseif (isset($data[$association][$model->primaryKey])) {
|
||||
$val = $data[$association][$model->primaryKey];
|
||||
}
|
||||
} else {
|
||||
$found = false;
|
||||
foreach (array_reverse($stack) as $assoc) {
|
||||
if (isset($data[$assoc]) && isset($data[$assoc][$model->primaryKey])) {
|
||||
$val = $data[$assoc][$model->primaryKey];
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$val = '';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '{$__cakeForeignKey__$}':
|
||||
foreach ($model->__associations as $id => $name) {
|
||||
foreach ($model->$name as $assocName => $assoc) {
|
||||
if ($assocName === $association) {
|
||||
if (isset($assoc['foreignKey'])) {
|
||||
$foreignKey = $assoc['foreignKey'];
|
||||
|
||||
if (isset($data[$model->alias][$foreignKey])) {
|
||||
$val = $data[$model->alias][$foreignKey];
|
||||
} elseif (isset($data[$association][$foreignKey])) {
|
||||
$val = $data[$association][$foreignKey];
|
||||
} else {
|
||||
$found = false;
|
||||
foreach (array_reverse($stack) as $assoc) {
|
||||
if (isset($data[$assoc]) && isset($data[$assoc][$foreignKey])) {
|
||||
$val = $data[$assoc][$foreignKey];
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$val = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (empty($val) && $val !== '0') {
|
||||
return false;
|
||||
}
|
||||
$query = str_replace($key, $this->value($val, $model->getColumnType($model->primaryKey)), $query);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* To-be-overridden in subclasses.
|
||||
*
|
||||
* @param Model $model Model instance
|
||||
* @param string $key Key name to make
|
||||
* @return string Key name for model.
|
||||
* @access public
|
||||
*/
|
||||
function resolveKey(&$model, $key) {
|
||||
return $model->alias . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current datasource.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function __destruct() {
|
||||
if ($this->_transactionStarted) {
|
||||
$null = null;
|
||||
$this->rollback($null);
|
||||
}
|
||||
if ($this->connected) {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
788
web-cake/html/cake/libs/model/datasources/dbo/dbo_mssql.php
Normal file
788
web-cake/html/cake/libs/model/datasources/dbo/dbo_mssql.php
Normal file
@@ -0,0 +1,788 @@
|
||||
<?php
|
||||
/**
|
||||
* MS SQL layer for DBO
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
* @since CakePHP(tm) v 0.10.5.1790
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* MS SQL layer for DBO
|
||||
*
|
||||
* Long description for class
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboMssql extends DboSource {
|
||||
|
||||
/**
|
||||
* Driver description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $description = "MS SQL DBO Driver";
|
||||
|
||||
/**
|
||||
* Starting quote character for quoted identifiers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $startQuote = "[";
|
||||
|
||||
/**
|
||||
* Ending quote character for quoted identifiers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $endQuote = "]";
|
||||
|
||||
/**
|
||||
* Creates a map between field aliases and numeric indexes. Workaround for the
|
||||
* SQL Server driver's 30-character column name limitation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $__fieldMappings = array();
|
||||
|
||||
/**
|
||||
* Base configuration settings for MS SQL driver
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => true,
|
||||
'host' => 'localhost',
|
||||
'login' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'cake',
|
||||
'port' => '1433',
|
||||
);
|
||||
|
||||
/**
|
||||
* MS SQL column definition
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $columns = array(
|
||||
'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
|
||||
'string' => array('name' => 'varchar', 'limit' => '255'),
|
||||
'text' => array('name' => 'text'),
|
||||
'integer' => array('name' => 'int', 'formatter' => 'intval'),
|
||||
'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
|
||||
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
|
||||
'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
|
||||
'binary' => array('name' => 'image'),
|
||||
'boolean' => array('name' => 'bit')
|
||||
);
|
||||
|
||||
/**
|
||||
* Index of basic SQL commands
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_commands = array(
|
||||
'begin' => 'BEGIN TRANSACTION',
|
||||
'commit' => 'COMMIT',
|
||||
'rollback' => 'ROLLBACK'
|
||||
);
|
||||
|
||||
/**
|
||||
* Define if the last query had error
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__lastQueryHadError = false;
|
||||
/**
|
||||
* MS SQL DBO driver constructor; sets SQL Server error reporting defaults
|
||||
*
|
||||
* @param array $config Configuration data from app/config/databases.php
|
||||
* @return boolean True if connected successfully, false on error
|
||||
*/
|
||||
function __construct($config, $autoConnect = true) {
|
||||
if ($autoConnect) {
|
||||
if (!function_exists('mssql_min_message_severity')) {
|
||||
trigger_error(__("PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/", true), E_USER_WARNING);
|
||||
}
|
||||
mssql_min_message_severity(15);
|
||||
mssql_min_error_severity(2);
|
||||
}
|
||||
return parent::__construct($config, $autoConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the database using options in the given configuration array.
|
||||
*
|
||||
* @return boolean True if the database could be connected, else false
|
||||
*/
|
||||
function connect() {
|
||||
$config = $this->config;
|
||||
|
||||
$os = env('OS');
|
||||
if (!empty($os) && strpos($os, 'Windows') !== false) {
|
||||
$sep = ',';
|
||||
} else {
|
||||
$sep = ':';
|
||||
}
|
||||
$this->connected = false;
|
||||
|
||||
if (is_numeric($config['port'])) {
|
||||
$port = $sep . $config['port']; // Port number
|
||||
} elseif ($config['port'] === null) {
|
||||
$port = ''; // No port - SQL Server 2005
|
||||
} else {
|
||||
$port = '\\' . $config['port']; // Named pipe
|
||||
}
|
||||
|
||||
if (!$config['persistent']) {
|
||||
$this->connection = mssql_connect($config['host'] . $port, $config['login'], $config['password'], true);
|
||||
} else {
|
||||
$this->connection = mssql_pconnect($config['host'] . $port, $config['login'], $config['password']);
|
||||
}
|
||||
|
||||
if (mssql_select_db($config['database'], $this->connection)) {
|
||||
$this->_execute("SET DATEFORMAT ymd");
|
||||
$this->connected = true;
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that MsSQL is installed/loaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function enabled() {
|
||||
return extension_loaded('mssql');
|
||||
}
|
||||
/**
|
||||
* Disconnects from database.
|
||||
*
|
||||
* @return boolean True if the database could be disconnected, else false
|
||||
*/
|
||||
function disconnect() {
|
||||
@mssql_free_result($this->results);
|
||||
$this->connected = !@mssql_close($this->connection);
|
||||
return !$this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @return resource Result resource identifier
|
||||
* @access protected
|
||||
*/
|
||||
function _execute($sql) {
|
||||
$result = @mssql_query($sql, $this->connection);
|
||||
$this->__lastQueryHadError = ($result === false);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sources (tables) in the database.
|
||||
*
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listSources() {
|
||||
$cache = parent::listSources();
|
||||
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
$result = $this->fetchAll('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES', false);
|
||||
|
||||
if (!$result || empty($result)) {
|
||||
return array();
|
||||
} else {
|
||||
$tables = array();
|
||||
|
||||
foreach ($result as $table) {
|
||||
$tables[] = $table[0]['TABLE_NAME'];
|
||||
}
|
||||
|
||||
parent::listSources($tables);
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the fields in given table name.
|
||||
*
|
||||
* @param Model $model Model object to describe
|
||||
* @return array Fields in table. Keys are name and type
|
||||
*/
|
||||
function describe(&$model) {
|
||||
$cache = parent::describe($model);
|
||||
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
|
||||
$table = $this->fullTableName($model, false);
|
||||
$cols = $this->fetchAll("SELECT COLUMN_NAME as Field, DATA_TYPE as Type, COL_LENGTH('" . $table . "', COLUMN_NAME) as Length, IS_NULLABLE As [Null], COLUMN_DEFAULT as [Default], COLUMNPROPERTY(OBJECT_ID('" . $table . "'), COLUMN_NAME, 'IsIdentity') as [Key], NUMERIC_SCALE as Size FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" . $table . "'", false);
|
||||
|
||||
$fields = false;
|
||||
foreach ($cols as $column) {
|
||||
$field = $column[0]['Field'];
|
||||
$fields[$field] = array(
|
||||
'type' => $this->column($column[0]['Type']),
|
||||
'null' => (strtoupper($column[0]['Null']) == 'YES'),
|
||||
'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column[0]['Default']),
|
||||
'length' => intval($column[0]['Length']),
|
||||
'key' => ($column[0]['Key'] == '1') ? 'primary' : false
|
||||
);
|
||||
if ($fields[$field]['default'] === 'null') {
|
||||
$fields[$field]['default'] = null;
|
||||
} else {
|
||||
$this->value($fields[$field]['default'], $fields[$field]['type']);
|
||||
}
|
||||
|
||||
if ($fields[$field]['key'] && $fields[$field]['type'] == 'integer') {
|
||||
$fields[$field]['length'] = 11;
|
||||
} elseif (!$fields[$field]['key']) {
|
||||
unset($fields[$field]['key']);
|
||||
}
|
||||
if (in_array($fields[$field]['type'], array('date', 'time', 'datetime', 'timestamp'))) {
|
||||
$fields[$field]['length'] = null;
|
||||
}
|
||||
}
|
||||
$this->__cacheDescription($this->fullTableName($model, false), $fields);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted and escaped string of $data for use in an SQL statement.
|
||||
*
|
||||
* @param string $data String to be prepared for use in an SQL statement
|
||||
* @param string $column The column into which this data will be inserted
|
||||
* @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
|
||||
* @return string Quoted and escaped data
|
||||
*/
|
||||
function value($data, $column = null, $safe = false) {
|
||||
$parent = parent::value($data, $column, $safe);
|
||||
|
||||
if ($parent != null) {
|
||||
return $parent;
|
||||
}
|
||||
if ($data === null) {
|
||||
return 'NULL';
|
||||
}
|
||||
if (in_array($column, array('integer', 'float', 'binary')) && $data === '') {
|
||||
return 'NULL';
|
||||
}
|
||||
if ($data === '') {
|
||||
return "''";
|
||||
}
|
||||
|
||||
switch ($column) {
|
||||
case 'boolean':
|
||||
$data = $this->boolean((bool)$data);
|
||||
break;
|
||||
default:
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$data = stripslashes(str_replace("'", "''", $data));
|
||||
} else {
|
||||
$data = str_replace("'", "''", $data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($column, array('integer', 'float', 'binary')) && is_numeric($data)) {
|
||||
return $data;
|
||||
}
|
||||
return "'" . $data . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the fields list of an SQL query.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string $alias Alias tablename
|
||||
* @param mixed $fields
|
||||
* @return array
|
||||
*/
|
||||
function fields(&$model, $alias = null, $fields = array(), $quote = true) {
|
||||
if (empty($alias)) {
|
||||
$alias = $model->alias;
|
||||
}
|
||||
$fields = parent::fields($model, $alias, $fields, false);
|
||||
$count = count($fields);
|
||||
|
||||
if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) {
|
||||
$result = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$prepend = '';
|
||||
|
||||
if (strpos($fields[$i], 'DISTINCT') !== false) {
|
||||
$prepend = 'DISTINCT ';
|
||||
$fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
|
||||
}
|
||||
$fieldAlias = count($this->__fieldMappings);
|
||||
|
||||
if (!preg_match('/\s+AS\s+/i', $fields[$i])) {
|
||||
if (substr($fields[$i], -1) == '*') {
|
||||
if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
|
||||
$build = explode('.', $fields[$i]);
|
||||
$AssociatedModel = $model->{$build[0]};
|
||||
} else {
|
||||
$AssociatedModel = $model;
|
||||
}
|
||||
|
||||
$_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
|
||||
$result = array_merge($result, $_fields);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($fields[$i], '.') === false) {
|
||||
$this->__fieldMappings[$alias . '__' . $fieldAlias] = $alias . '.' . $fields[$i];
|
||||
$fieldName = $this->name($alias . '.' . $fields[$i]);
|
||||
$fieldAlias = $this->name($alias . '__' . $fieldAlias);
|
||||
} else {
|
||||
$build = explode('.', $fields[$i]);
|
||||
$this->__fieldMappings[$build[0] . '__' . $fieldAlias] = $fields[$i];
|
||||
$fieldName = $this->name($build[0] . '.' . $build[1]);
|
||||
$fieldAlias = $this->name(preg_replace("/^\[(.+)\]$/", "$1", $build[0]) . '__' . $fieldAlias);
|
||||
}
|
||||
if ($model->getColumnType($fields[$i]) == 'datetime') {
|
||||
$fieldName = "CONVERT(VARCHAR(20), {$fieldName}, 20)";
|
||||
}
|
||||
$fields[$i] = "{$fieldName} AS {$fieldAlias}";
|
||||
}
|
||||
$result[] = $prepend . $fields[$i];
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and executes an SQL INSERT statement for given model, fields, and values.
|
||||
* Removes Identity (primary key) column from update data before returning to parent, if
|
||||
* value is empty.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $fields
|
||||
* @param array $values
|
||||
* @param mixed $conditions
|
||||
* @return array
|
||||
*/
|
||||
function create(&$model, $fields = null, $values = null) {
|
||||
if (!empty($values)) {
|
||||
$fields = array_combine($fields, $values);
|
||||
}
|
||||
$primaryKey = $this->_getPrimaryKey($model);
|
||||
|
||||
if (array_key_exists($primaryKey, $fields)) {
|
||||
if (empty($fields[$primaryKey])) {
|
||||
unset($fields[$primaryKey]);
|
||||
} else {
|
||||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' ON');
|
||||
}
|
||||
}
|
||||
$result = parent::create($model, array_keys($fields), array_values($fields));
|
||||
if (array_key_exists($primaryKey, $fields) && !empty($fields[$primaryKey])) {
|
||||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' OFF');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and executes an SQL UPDATE statement for given model, fields, and values.
|
||||
* Removes Identity (primary key) column from update data before returning to parent.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $fields
|
||||
* @param array $values
|
||||
* @param mixed $conditions
|
||||
* @return array
|
||||
*/
|
||||
function update(&$model, $fields = array(), $values = null, $conditions = null) {
|
||||
if (!empty($values)) {
|
||||
$fields = array_combine($fields, $values);
|
||||
}
|
||||
if (isset($fields[$model->primaryKey])) {
|
||||
unset($fields[$model->primaryKey]);
|
||||
}
|
||||
if (empty($fields)) {
|
||||
return true;
|
||||
}
|
||||
return parent::update($model, array_keys($fields), array_values($fields), $conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message from previous database operation.
|
||||
*
|
||||
* @return string Error message with error number
|
||||
*/
|
||||
function lastError() {
|
||||
if ($this->__lastQueryHadError) {
|
||||
$error = mssql_get_last_message();
|
||||
if ($error && !preg_match('/contexto de la base de datos a|contesto di database|changed database|contexte de la base de don|datenbankkontext/i', $error)) {
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of affected rows in previous database operation. If no previous operation exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of affected rows
|
||||
*/
|
||||
function lastAffected() {
|
||||
if ($this->_result) {
|
||||
return mssql_rows_affected($this->connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of rows in previous resultset. If no previous resultset exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of rows in resultset
|
||||
*/
|
||||
function lastNumRows() {
|
||||
if ($this->_result) {
|
||||
return @mssql_num_rows($this->_result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return in
|
||||
*/
|
||||
function lastInsertId($source = null) {
|
||||
$id = $this->fetchRow('SELECT SCOPE_IDENTITY() AS insertID', false);
|
||||
return $id[0]['insertID'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a limit statement in the correct format for the particular database.
|
||||
*
|
||||
* @param integer $limit Limit of results returned
|
||||
* @param integer $offset Offset from which to start results
|
||||
* @return string SQL limit/offset statement
|
||||
*/
|
||||
function limit($limit, $offset = null) {
|
||||
if ($limit) {
|
||||
$rt = '';
|
||||
if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
|
||||
$rt = ' TOP';
|
||||
}
|
||||
$rt .= ' ' . $limit;
|
||||
if (is_int($offset) && $offset > 0) {
|
||||
$rt .= ' OFFSET ' . $offset;
|
||||
}
|
||||
return $rt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts database-layer column types to basic types
|
||||
*
|
||||
* @param string $real Real database-layer column type (i.e. "varchar(255)")
|
||||
* @return string Abstract column type (i.e. "string")
|
||||
*/
|
||||
function column($real) {
|
||||
if (is_array($real)) {
|
||||
$col = $real['name'];
|
||||
|
||||
if (isset($real['limit'])) {
|
||||
$col .= '(' . $real['limit'] . ')';
|
||||
}
|
||||
return $col;
|
||||
}
|
||||
$col = str_replace(')', '', $real);
|
||||
$limit = null;
|
||||
if (strpos($col, '(') !== false) {
|
||||
list($col, $limit) = explode('(', $col);
|
||||
}
|
||||
|
||||
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
|
||||
return $col;
|
||||
}
|
||||
if ($col == 'bit') {
|
||||
return 'boolean';
|
||||
}
|
||||
if (strpos($col, 'int') !== false) {
|
||||
return 'integer';
|
||||
}
|
||||
if (strpos($col, 'char') !== false) {
|
||||
return 'string';
|
||||
}
|
||||
if (strpos($col, 'text') !== false) {
|
||||
return 'text';
|
||||
}
|
||||
if (strpos($col, 'binary') !== false || $col == 'image') {
|
||||
return 'binary';
|
||||
}
|
||||
if (in_array($col, array('float', 'real', 'decimal', 'numeric'))) {
|
||||
return 'float';
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param unknown_type $results
|
||||
*/
|
||||
function resultSet(&$results) {
|
||||
$this->results =& $results;
|
||||
$this->map = array();
|
||||
$numFields = mssql_num_fields($results);
|
||||
$index = 0;
|
||||
$j = 0;
|
||||
|
||||
while ($j < $numFields) {
|
||||
$column = mssql_field_name($results, $j);
|
||||
|
||||
if (strpos($column, '__')) {
|
||||
if (isset($this->__fieldMappings[$column]) && strpos($this->__fieldMappings[$column], '.')) {
|
||||
$map = explode('.', $this->__fieldMappings[$column]);
|
||||
} elseif (isset($this->__fieldMappings[$column])) {
|
||||
$map = array(0, $this->__fieldMappings[$column]);
|
||||
} else {
|
||||
$map = array(0, $column);
|
||||
}
|
||||
$this->map[$index++] = $map;
|
||||
} else {
|
||||
$this->map[$index++] = array(0, $column);
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds final SQL statement
|
||||
*
|
||||
* @param string $type Query type
|
||||
* @param array $data Query data
|
||||
* @return string
|
||||
*/
|
||||
function renderStatement($type, $data) {
|
||||
switch (strtolower($type)) {
|
||||
case 'select':
|
||||
extract($data);
|
||||
$fields = trim($fields);
|
||||
|
||||
if (strpos($limit, 'TOP') !== false && strpos($fields, 'DISTINCT ') === 0) {
|
||||
$limit = 'DISTINCT ' . trim($limit);
|
||||
$fields = substr($fields, 9);
|
||||
}
|
||||
|
||||
if (preg_match('/offset\s+([0-9]+)/i', $limit, $offset)) {
|
||||
$limit = preg_replace('/\s*offset.*$/i', '', $limit);
|
||||
preg_match('/top\s+([0-9]+)/i', $limit, $limitVal);
|
||||
$offset = intval($offset[1]) + intval($limitVal[1]);
|
||||
$rOrder = $this->__switchSort($order);
|
||||
list($order2, $rOrder) = array($this->__mapFields($order), $this->__mapFields($rOrder));
|
||||
return "SELECT * FROM (SELECT {$limit} * FROM (SELECT TOP {$offset} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}) AS Set1 {$rOrder}) AS Set2 {$order2}";
|
||||
} else {
|
||||
return "SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}";
|
||||
}
|
||||
break;
|
||||
case "schema":
|
||||
extract($data);
|
||||
|
||||
foreach ($indexes as $i => $index) {
|
||||
if (preg_match('/PRIMARY KEY/', $index)) {
|
||||
unset($indexes[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('columns', 'indexes') as $var) {
|
||||
if (is_array(${$var})) {
|
||||
${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
|
||||
}
|
||||
}
|
||||
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
|
||||
break;
|
||||
default:
|
||||
return parent::renderStatement($type, $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the sort direction of ORDER statements to get paging offsets to work correctly
|
||||
*
|
||||
* @param string $order
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function __switchSort($order) {
|
||||
$order = preg_replace('/\s+ASC/i', '__tmp_asc__', $order);
|
||||
$order = preg_replace('/\s+DESC/i', ' ASC', $order);
|
||||
return preg_replace('/__tmp_asc__/', ' DESC', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates field names used for filtering and sorting to shortened names using the field map
|
||||
*
|
||||
* @param string $sql A snippet of SQL representing an ORDER or WHERE statement
|
||||
* @return string The value of $sql with field names replaced
|
||||
* @access private
|
||||
*/
|
||||
function __mapFields($sql) {
|
||||
if (empty($sql) || empty($this->__fieldMappings)) {
|
||||
return $sql;
|
||||
}
|
||||
foreach ($this->__fieldMappings as $key => $val) {
|
||||
$sql = preg_replace('/' . preg_quote($val) . '/', $this->name($key), $sql);
|
||||
$sql = preg_replace('/' . preg_quote($this->name($val)) . '/', $this->name($key), $sql);
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all result rows for a given SQL query.
|
||||
* Returns false if no rows matched.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @param boolean $cache Enables returning/storing cached query results
|
||||
* @return array Array of resultset rows, or false if no rows matched
|
||||
*/
|
||||
function read(&$model, $queryData = array(), $recursive = null) {
|
||||
$results = parent::read($model, $queryData, $recursive);
|
||||
$this->__fieldMappings = array();
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next row from the current result set
|
||||
*
|
||||
* @return unknown
|
||||
*/
|
||||
function fetchResult() {
|
||||
if ($row = mssql_fetch_row($this->results)) {
|
||||
$resultRow = array();
|
||||
$i = 0;
|
||||
|
||||
foreach ($row as $index => $field) {
|
||||
list($table, $column) = $this->map[$index];
|
||||
$resultRow[$table][$column] = $row[$index];
|
||||
$i++;
|
||||
}
|
||||
return $resultRow;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts multiple values into a table
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $fields
|
||||
* @param array $values
|
||||
* @access protected
|
||||
*/
|
||||
function insertMulti($table, $fields, $values) {
|
||||
$primaryKey = $this->_getPrimaryKey($table);
|
||||
$hasPrimaryKey = $primaryKey != null && (
|
||||
(is_array($fields) && in_array($primaryKey, $fields)
|
||||
|| (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
|
||||
);
|
||||
|
||||
if ($hasPrimaryKey) {
|
||||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
|
||||
}
|
||||
parent::insertMulti($table, $fields, $values);
|
||||
if ($hasPrimaryKey) {
|
||||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a database-native column schema string
|
||||
*
|
||||
* @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
|
||||
* where options can be 'default', 'length', or 'key'.
|
||||
* @return string
|
||||
*/
|
||||
function buildColumn($column) {
|
||||
$result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', parent::buildColumn($column));
|
||||
if (strpos($result, 'DEFAULT NULL') !== false) {
|
||||
$result = str_replace('DEFAULT NULL', 'NULL', $result);
|
||||
} else if (array_keys($column) == array('type', 'name')) {
|
||||
$result .= ' NULL';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format indexes for create table
|
||||
*
|
||||
* @param array $indexes
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
function buildIndex($indexes, $table = null) {
|
||||
$join = array();
|
||||
|
||||
foreach ($indexes as $name => $value) {
|
||||
if ($name == 'PRIMARY') {
|
||||
$join[] = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
|
||||
} else if (isset($value['unique']) && $value['unique']) {
|
||||
$out = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE";
|
||||
|
||||
if (is_array($value['column'])) {
|
||||
$value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
|
||||
} else {
|
||||
$value['column'] = $this->name($value['column']);
|
||||
}
|
||||
$out .= "({$value['column']});";
|
||||
$join[] = $out;
|
||||
}
|
||||
}
|
||||
return $join;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure it will return the primary key
|
||||
*
|
||||
* @param mixed $model
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
function _getPrimaryKey($model) {
|
||||
if (is_object($model)) {
|
||||
$schema = $model->schema();
|
||||
} else {
|
||||
$schema = $this->describe($model);
|
||||
}
|
||||
|
||||
foreach ($schema as $field => $props) {
|
||||
if (isset($props['key']) && $props['key'] == 'primary') {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
799
web-cake/html/cake/libs/model/datasources/dbo/dbo_mysql.php
Normal file
799
web-cake/html/cake/libs/model/datasources/dbo/dbo_mysql.php
Normal file
@@ -0,0 +1,799 @@
|
||||
<?php
|
||||
/**
|
||||
* MySQL layer for DBO
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
* @since CakePHP(tm) v 0.10.5.1790
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides common base for MySQL & MySQLi connections
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboMysqlBase extends DboSource {
|
||||
|
||||
/**
|
||||
* Description property.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $description = "MySQL DBO Base Driver";
|
||||
|
||||
/**
|
||||
* Start quote
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $startQuote = "`";
|
||||
|
||||
/**
|
||||
* End quote
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $endQuote = "`";
|
||||
|
||||
/**
|
||||
* use alias for update and delete. Set to true if version >= 4.1
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
*/
|
||||
var $_useAlias = true;
|
||||
|
||||
/**
|
||||
* Index of basic SQL commands
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_commands = array(
|
||||
'begin' => 'START TRANSACTION',
|
||||
'commit' => 'COMMIT',
|
||||
'rollback' => 'ROLLBACK'
|
||||
);
|
||||
|
||||
/**
|
||||
* List of engine specific additional field parameters used on table creating
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $fieldParameters = array(
|
||||
'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'),
|
||||
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'),
|
||||
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault')
|
||||
);
|
||||
|
||||
/**
|
||||
* List of table engine specific parameters used on table creating
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $tableParameters = array(
|
||||
'charset' => array('value' => 'DEFAULT CHARSET', 'quote' => false, 'join' => '=', 'column' => 'charset'),
|
||||
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => '=', 'column' => 'Collation'),
|
||||
'engine' => array('value' => 'ENGINE', 'quote' => false, 'join' => '=', 'column' => 'Engine')
|
||||
);
|
||||
|
||||
/**
|
||||
* MySQL column definition
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $columns = array(
|
||||
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
|
||||
'string' => array('name' => 'varchar', 'limit' => '255'),
|
||||
'text' => array('name' => 'text'),
|
||||
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
|
||||
'float' => array('name' => 'float', 'formatter' => 'floatval'),
|
||||
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
|
||||
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
|
||||
'binary' => array('name' => 'blob'),
|
||||
'boolean' => array('name' => 'tinyint', 'limit' => '1')
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an array of the fields in given table name.
|
||||
*
|
||||
* @param string $tableName Name of database table to inspect
|
||||
* @return array Fields in table. Keys are name and type
|
||||
*/
|
||||
function describe(&$model) {
|
||||
$cache = parent::describe($model);
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
$fields = false;
|
||||
$cols = $this->query('SHOW FULL COLUMNS FROM ' . $this->fullTableName($model));
|
||||
|
||||
foreach ($cols as $column) {
|
||||
$colKey = array_keys($column);
|
||||
if (isset($column[$colKey[0]]) && !isset($column[0])) {
|
||||
$column[0] = $column[$colKey[0]];
|
||||
}
|
||||
if (isset($column[0])) {
|
||||
$fields[$column[0]['Field']] = array(
|
||||
'type' => $this->column($column[0]['Type']),
|
||||
'null' => ($column[0]['Null'] == 'YES' ? true : false),
|
||||
'default' => $column[0]['Default'],
|
||||
'length' => $this->length($column[0]['Type']),
|
||||
);
|
||||
if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) {
|
||||
$fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']];
|
||||
}
|
||||
foreach ($this->fieldParameters as $name => $value) {
|
||||
if (!empty($column[0][$value['column']])) {
|
||||
$fields[$column[0]['Field']][$name] = $column[0][$value['column']];
|
||||
}
|
||||
}
|
||||
if (isset($fields[$column[0]['Field']]['collate'])) {
|
||||
$charset = $this->getCharsetName($fields[$column[0]['Field']]['collate']);
|
||||
if ($charset) {
|
||||
$fields[$column[0]['Field']]['charset'] = $charset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->__cacheDescription($this->fullTableName($model, false), $fields);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and executes an SQL UPDATE statement for given model, fields, and values.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $fields
|
||||
* @param array $values
|
||||
* @param mixed $conditions
|
||||
* @return array
|
||||
*/
|
||||
function update(&$model, $fields = array(), $values = null, $conditions = null) {
|
||||
if (!$this->_useAlias) {
|
||||
return parent::update($model, $fields, $values, $conditions);
|
||||
}
|
||||
|
||||
if ($values == null) {
|
||||
$combined = $fields;
|
||||
} else {
|
||||
$combined = array_combine($fields, $values);
|
||||
}
|
||||
|
||||
$alias = $joins = false;
|
||||
$fields = $this->_prepareUpdateFields($model, $combined, empty($conditions), !empty($conditions));
|
||||
$fields = implode(', ', $fields);
|
||||
$table = $this->fullTableName($model);
|
||||
|
||||
if (!empty($conditions)) {
|
||||
$alias = $this->name($model->alias);
|
||||
if ($model->name == $model->alias) {
|
||||
$joins = implode(' ', $this->_getJoins($model));
|
||||
}
|
||||
}
|
||||
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
|
||||
|
||||
if ($conditions === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->execute($this->renderStatement('update', compact('table', 'alias', 'joins', 'fields', 'conditions')))) {
|
||||
$model->onError();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and executes an SQL DELETE statement for given id/conditions on given model.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param mixed $conditions
|
||||
* @return boolean Success
|
||||
*/
|
||||
function delete(&$model, $conditions = null) {
|
||||
if (!$this->_useAlias) {
|
||||
return parent::delete($model, $conditions);
|
||||
}
|
||||
$alias = $this->name($model->alias);
|
||||
$table = $this->fullTableName($model);
|
||||
$joins = implode(' ', $this->_getJoins($model));
|
||||
|
||||
if (empty($conditions)) {
|
||||
$alias = $joins = false;
|
||||
}
|
||||
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
|
||||
|
||||
if ($conditions === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
|
||||
$model->onError();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database encoding
|
||||
*
|
||||
* @param string $enc Database encoding
|
||||
*/
|
||||
function setEncoding($enc) {
|
||||
return $this->_execute('SET NAMES ' . $enc) != false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the indexes in given datasource name.
|
||||
*
|
||||
* @param string $model Name of model to inspect
|
||||
* @return array Fields in table. Keys are column and unique
|
||||
*/
|
||||
function index($model) {
|
||||
$index = array();
|
||||
$table = $this->fullTableName($model);
|
||||
if ($table) {
|
||||
$indexes = $this->query('SHOW INDEX FROM ' . $table);
|
||||
if (isset($indexes[0]['STATISTICS'])) {
|
||||
$keys = Set::extract($indexes, '{n}.STATISTICS');
|
||||
} else {
|
||||
$keys = Set::extract($indexes, '{n}.0');
|
||||
}
|
||||
foreach ($keys as $i => $key) {
|
||||
if (!isset($index[$key['Key_name']])) {
|
||||
$col = array();
|
||||
$index[$key['Key_name']]['column'] = $key['Column_name'];
|
||||
$index[$key['Key_name']]['unique'] = intval($key['Non_unique'] == 0);
|
||||
} else {
|
||||
if (!is_array($index[$key['Key_name']]['column'])) {
|
||||
$col[] = $index[$key['Key_name']]['column'];
|
||||
}
|
||||
$col[] = $key['Column_name'];
|
||||
$index[$key['Key_name']]['column'] = $col;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a MySQL Alter Table syntax for the given Schema comparison
|
||||
*
|
||||
* @param array $compare Result of a CakeSchema::compare()
|
||||
* @return array Array of alter statements to make.
|
||||
*/
|
||||
function alterSchema($compare, $table = null) {
|
||||
if (!is_array($compare)) {
|
||||
return false;
|
||||
}
|
||||
$out = '';
|
||||
$colList = array();
|
||||
foreach ($compare as $curTable => $types) {
|
||||
$indexes = $tableParameters = $colList = array();
|
||||
if (!$table || $table == $curTable) {
|
||||
$out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
|
||||
foreach ($types as $type => $column) {
|
||||
if (isset($column['indexes'])) {
|
||||
$indexes[$type] = $column['indexes'];
|
||||
unset($column['indexes']);
|
||||
}
|
||||
if (isset($column['tableParameters'])) {
|
||||
$tableParameters[$type] = $column['tableParameters'];
|
||||
unset($column['tableParameters']);
|
||||
}
|
||||
switch ($type) {
|
||||
case 'add':
|
||||
foreach ($column as $field => $col) {
|
||||
$col['name'] = $field;
|
||||
$alter = 'ADD ' . $this->buildColumn($col);
|
||||
if (isset($col['after'])) {
|
||||
$alter .= ' AFTER ' . $this->name($col['after']);
|
||||
}
|
||||
$colList[] = $alter;
|
||||
}
|
||||
break;
|
||||
case 'drop':
|
||||
foreach ($column as $field => $col) {
|
||||
$col['name'] = $field;
|
||||
$colList[] = 'DROP ' . $this->name($field);
|
||||
}
|
||||
break;
|
||||
case 'change':
|
||||
foreach ($column as $field => $col) {
|
||||
if (!isset($col['name'])) {
|
||||
$col['name'] = $field;
|
||||
}
|
||||
$colList[] = 'CHANGE ' . $this->name($field) . ' ' . $this->buildColumn($col);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$colList = array_merge($colList, $this->_alterIndexes($curTable, $indexes));
|
||||
$colList = array_merge($colList, $this->_alterTableParameters($curTable, $tableParameters));
|
||||
$out .= "\t" . join(",\n\t", $colList) . ";\n\n";
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a MySQL "drop table" statement for the given Schema object
|
||||
*
|
||||
* @param object $schema An instance of a subclass of CakeSchema
|
||||
* @param string $table Optional. If specified only the table name given will be generated.
|
||||
* Otherwise, all tables defined in the schema are generated.
|
||||
* @return string
|
||||
*/
|
||||
function dropSchema($schema, $table = null) {
|
||||
if (!is_a($schema, 'CakeSchema')) {
|
||||
trigger_error(__('Invalid schema object', true), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
$out = '';
|
||||
foreach ($schema->tables as $curTable => $columns) {
|
||||
if (!$table || $table == $curTable) {
|
||||
$out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate MySQL table parameter alteration statementes for a table.
|
||||
*
|
||||
* @param string $table Table to alter parameters for.
|
||||
* @param array $parameters Parameters to add & drop.
|
||||
* @return array Array of table property alteration statementes.
|
||||
* @todo Implement this method.
|
||||
*/
|
||||
function _alterTableParameters($table, $parameters) {
|
||||
if (isset($parameters['change'])) {
|
||||
return $this->buildTableParameters($parameters['change']);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate MySQL index alteration statements for a table.
|
||||
*
|
||||
* @param string $table Table to alter indexes for
|
||||
* @param array $new Indexes to add and drop
|
||||
* @return array Index alteration statements
|
||||
*/
|
||||
function _alterIndexes($table, $indexes) {
|
||||
$alter = array();
|
||||
if (isset($indexes['drop'])) {
|
||||
foreach($indexes['drop'] as $name => $value) {
|
||||
$out = 'DROP ';
|
||||
if ($name == 'PRIMARY') {
|
||||
$out .= 'PRIMARY KEY';
|
||||
} else {
|
||||
$out .= 'KEY ' . $name;
|
||||
}
|
||||
$alter[] = $out;
|
||||
}
|
||||
}
|
||||
if (isset($indexes['add'])) {
|
||||
foreach ($indexes['add'] as $name => $value) {
|
||||
$out = 'ADD ';
|
||||
if ($name == 'PRIMARY') {
|
||||
$out .= 'PRIMARY ';
|
||||
$name = null;
|
||||
} else {
|
||||
if (!empty($value['unique'])) {
|
||||
$out .= 'UNIQUE ';
|
||||
}
|
||||
}
|
||||
if (is_array($value['column'])) {
|
||||
$out .= 'KEY '. $name .' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
|
||||
} else {
|
||||
$out .= 'KEY '. $name .' (' . $this->name($value['column']) . ')';
|
||||
}
|
||||
$alter[] = $out;
|
||||
}
|
||||
}
|
||||
return $alter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts multiple values into a table
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $fields
|
||||
* @param array $values
|
||||
*/
|
||||
function insertMulti($table, $fields, $values) {
|
||||
$table = $this->fullTableName($table);
|
||||
if (is_array($fields)) {
|
||||
$fields = implode(', ', array_map(array(&$this, 'name'), $fields));
|
||||
}
|
||||
$values = implode(', ', $values);
|
||||
$this->query("INSERT INTO {$table} ({$fields}) VALUES {$values}");
|
||||
}
|
||||
/**
|
||||
* Returns an detailed array of sources (tables) in the database.
|
||||
*
|
||||
* @param string $name Table name to get parameters
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listDetailedSources($name = null) {
|
||||
$condition = '';
|
||||
if (is_string($name)) {
|
||||
$condition = ' LIKE ' . $this->value($name);
|
||||
}
|
||||
$result = $this->query('SHOW TABLE STATUS FROM ' . $this->name($this->config['database']) . $condition . ';');
|
||||
if (!$result) {
|
||||
return array();
|
||||
} else {
|
||||
$tables = array();
|
||||
foreach ($result as $row) {
|
||||
$tables[$row['TABLES']['Name']] = $row['TABLES'];
|
||||
if (!empty($row['TABLES']['Collation'])) {
|
||||
$charset = $this->getCharsetName($row['TABLES']['Collation']);
|
||||
if ($charset) {
|
||||
$tables[$row['TABLES']['Name']]['charset'] = $charset;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_string($name)) {
|
||||
return $tables[$name];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts database-layer column types to basic types
|
||||
*
|
||||
* @param string $real Real database-layer column type (i.e. "varchar(255)")
|
||||
* @return string Abstract column type (i.e. "string")
|
||||
*/
|
||||
function column($real) {
|
||||
if (is_array($real)) {
|
||||
$col = $real['name'];
|
||||
if (isset($real['limit'])) {
|
||||
$col .= '('.$real['limit'].')';
|
||||
}
|
||||
return $col;
|
||||
}
|
||||
|
||||
$col = str_replace(')', '', $real);
|
||||
$limit = $this->length($real);
|
||||
if (strpos($col, '(') !== false) {
|
||||
list($col, $vals) = explode('(', $col);
|
||||
}
|
||||
|
||||
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
|
||||
return $col;
|
||||
}
|
||||
if (($col == 'tinyint' && $limit == 1) || $col == 'boolean') {
|
||||
return 'boolean';
|
||||
}
|
||||
if (strpos($col, 'int') !== false) {
|
||||
return 'integer';
|
||||
}
|
||||
if (strpos($col, 'char') !== false || $col == 'tinytext') {
|
||||
return 'string';
|
||||
}
|
||||
if (strpos($col, 'text') !== false) {
|
||||
return 'text';
|
||||
}
|
||||
if (strpos($col, 'blob') !== false || $col == 'binary') {
|
||||
return 'binary';
|
||||
}
|
||||
if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) {
|
||||
return 'float';
|
||||
}
|
||||
if (strpos($col, 'enum') !== false) {
|
||||
return "enum($vals)";
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL DBO driver object
|
||||
*
|
||||
* Provides connection and SQL generation for MySQL RDMS
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboMysql extends DboMysqlBase {
|
||||
|
||||
/**
|
||||
* Datasource description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $description = "MySQL DBO Driver";
|
||||
|
||||
/**
|
||||
* Base configuration settings for MySQL driver
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => true,
|
||||
'host' => 'localhost',
|
||||
'login' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'cake',
|
||||
'port' => '3306'
|
||||
);
|
||||
|
||||
/**
|
||||
* Connects to the database using options in the given configuration array.
|
||||
*
|
||||
* @return boolean True if the database could be connected, else false
|
||||
*/
|
||||
function connect() {
|
||||
$config = $this->config;
|
||||
$this->connected = false;
|
||||
|
||||
if (!$config['persistent']) {
|
||||
$this->connection = mysql_connect($config['host'] . ':' . $config['port'], $config['login'], $config['password'], true);
|
||||
$config['connect'] = 'mysql_connect';
|
||||
} else {
|
||||
$this->connection = mysql_pconnect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
|
||||
}
|
||||
|
||||
if (mysql_select_db($config['database'], $this->connection)) {
|
||||
$this->connected = true;
|
||||
}
|
||||
|
||||
if (!empty($config['encoding'])) {
|
||||
$this->setEncoding($config['encoding']);
|
||||
}
|
||||
|
||||
$this->_useAlias = (bool)version_compare(mysql_get_server_info($this->connection), "4.1", ">=");
|
||||
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the MySQL extension is installed/loaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function enabled() {
|
||||
return extension_loaded('mysql');
|
||||
}
|
||||
/**
|
||||
* Disconnects from database.
|
||||
*
|
||||
* @return boolean True if the database could be disconnected, else false
|
||||
*/
|
||||
function disconnect() {
|
||||
if (isset($this->results) && is_resource($this->results)) {
|
||||
mysql_free_result($this->results);
|
||||
}
|
||||
$this->connected = !@mysql_close($this->connection);
|
||||
return !$this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @return resource Result resource identifier
|
||||
* @access protected
|
||||
*/
|
||||
function _execute($sql) {
|
||||
return mysql_query($sql, $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sources (tables) in the database.
|
||||
*
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listSources() {
|
||||
$cache = parent::listSources();
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
|
||||
|
||||
if (!$result) {
|
||||
return array();
|
||||
} else {
|
||||
$tables = array();
|
||||
|
||||
while ($line = mysql_fetch_row($result)) {
|
||||
$tables[] = $line[0];
|
||||
}
|
||||
parent::listSources($tables);
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted and escaped string of $data for use in an SQL statement.
|
||||
*
|
||||
* @param string $data String to be prepared for use in an SQL statement
|
||||
* @param string $column The column into which this data will be inserted
|
||||
* @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
|
||||
* @return string Quoted and escaped data
|
||||
*/
|
||||
function value($data, $column = null, $safe = false) {
|
||||
$parent = parent::value($data, $column, $safe);
|
||||
|
||||
if ($parent != null) {
|
||||
return $parent;
|
||||
}
|
||||
if ($data === null || (is_array($data) && empty($data))) {
|
||||
return 'NULL';
|
||||
}
|
||||
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
|
||||
return "''";
|
||||
}
|
||||
if (empty($column)) {
|
||||
$column = $this->introspectType($data);
|
||||
}
|
||||
|
||||
switch ($column) {
|
||||
case 'boolean':
|
||||
return $this->boolean((bool)$data);
|
||||
break;
|
||||
case 'integer':
|
||||
case 'float':
|
||||
if ($data === '') {
|
||||
return 'NULL';
|
||||
}
|
||||
if (is_float($data)) {
|
||||
return sprintf('%F', $data);
|
||||
}
|
||||
if ((is_int($data) || $data === '0') || (
|
||||
is_numeric($data) && strpos($data, ',') === false &&
|
||||
$data[0] != '0' && strpos($data, 'e') === false)
|
||||
) {
|
||||
return $data;
|
||||
}
|
||||
default:
|
||||
return "'" . mysql_real_escape_string($data, $this->connection) . "'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message from previous database operation.
|
||||
*
|
||||
* @return string Error message with error number
|
||||
*/
|
||||
function lastError() {
|
||||
if (mysql_errno($this->connection)) {
|
||||
return mysql_errno($this->connection).': '.mysql_error($this->connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of affected rows in previous database operation. If no previous operation exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of affected rows
|
||||
*/
|
||||
function lastAffected() {
|
||||
if ($this->_result) {
|
||||
return mysql_affected_rows($this->connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of rows in previous resultset. If no previous resultset exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of rows in resultset
|
||||
*/
|
||||
function lastNumRows() {
|
||||
if ($this->hasResult()) {
|
||||
return mysql_num_rows($this->_result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return in
|
||||
*/
|
||||
function lastInsertId($source = null) {
|
||||
$id = $this->fetchRow('SELECT LAST_INSERT_ID() AS insertID', false);
|
||||
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
|
||||
return $id[0]['insertID'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param unknown_type $results
|
||||
*/
|
||||
function resultSet(&$results) {
|
||||
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
|
||||
mysql_free_result($this->results);
|
||||
}
|
||||
$this->results =& $results;
|
||||
$this->map = array();
|
||||
$numFields = mysql_num_fields($results);
|
||||
$index = 0;
|
||||
$j = 0;
|
||||
|
||||
while ($j < $numFields) {
|
||||
$column = mysql_fetch_field($results, $j);
|
||||
if (!empty($column->table) && strpos($column->name, $this->virtualFieldSeparator) === false) {
|
||||
$this->map[$index++] = array($column->table, $column->name);
|
||||
} else {
|
||||
$this->map[$index++] = array(0, $column->name);
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next row from the current result set
|
||||
*
|
||||
* @return unknown
|
||||
*/
|
||||
function fetchResult() {
|
||||
if ($row = mysql_fetch_row($this->results)) {
|
||||
$resultRow = array();
|
||||
$i = 0;
|
||||
foreach ($row as $index => $field) {
|
||||
list($table, $column) = $this->map[$index];
|
||||
$resultRow[$table][$column] = $row[$index];
|
||||
$i++;
|
||||
}
|
||||
return $resultRow;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database encoding
|
||||
*
|
||||
* @return string The database encoding
|
||||
*/
|
||||
function getEncoding() {
|
||||
return mysql_client_encoding($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query charset by collation
|
||||
*
|
||||
* @param string $name Collation name
|
||||
* @return string Character set name
|
||||
*/
|
||||
function getCharsetName($name) {
|
||||
if ((bool)version_compare(mysql_get_server_info($this->connection), "5", ">=")) {
|
||||
$cols = $this->query('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= ' . $this->value($name) . ';');
|
||||
if (isset($cols[0]['COLLATIONS']['CHARACTER_SET_NAME'])) {
|
||||
return $cols[0]['COLLATIONS']['CHARACTER_SET_NAME'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
338
web-cake/html/cake/libs/model/datasources/dbo/dbo_mysqli.php
Normal file
338
web-cake/html/cake/libs/model/datasources/dbo/dbo_mysqli.php
Normal file
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
/**
|
||||
* MySQLi layer for DBO
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
* @since CakePHP(tm) v 1.1.4.2974
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Datasource', 'DboMysql');
|
||||
|
||||
/**
|
||||
* MySQLi DBO driver object
|
||||
*
|
||||
* Provides connection and SQL generation for MySQL RDMS using PHP's MySQLi Interface
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboMysqli extends DboMysqlBase {
|
||||
|
||||
/**
|
||||
* Datasource Description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $description = "Mysqli DBO Driver";
|
||||
|
||||
/**
|
||||
* Base configuration settings for Mysqli driver
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => true,
|
||||
'host' => 'localhost',
|
||||
'login' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'cake',
|
||||
'port' => '3306'
|
||||
);
|
||||
|
||||
/**
|
||||
* Connects to the database using options in the given configuration array.
|
||||
*
|
||||
* @return boolean True if the database could be connected, else false
|
||||
*/
|
||||
function connect() {
|
||||
$config = $this->config;
|
||||
$this->connected = false;
|
||||
|
||||
if (is_numeric($config['port'])) {
|
||||
$config['socket'] = null;
|
||||
} else {
|
||||
$config['socket'] = $config['port'];
|
||||
$config['port'] = null;
|
||||
}
|
||||
|
||||
$this->connection = mysqli_connect($config['host'], $config['login'], $config['password'], $config['database'], $config['port'], $config['socket']);
|
||||
|
||||
if ($this->connection !== false) {
|
||||
$this->connected = true;
|
||||
}
|
||||
|
||||
$this->_useAlias = (bool)version_compare(mysqli_get_server_info($this->connection), "4.1", ">=");
|
||||
|
||||
if (!empty($config['encoding'])) {
|
||||
$this->setEncoding($config['encoding']);
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that MySQLi is installed/enabled
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function enabled() {
|
||||
return extension_loaded('mysqli');
|
||||
}
|
||||
/**
|
||||
* Disconnects from database.
|
||||
*
|
||||
* @return boolean True if the database could be disconnected, else false
|
||||
*/
|
||||
function disconnect() {
|
||||
if (isset($this->results) && is_resource($this->results)) {
|
||||
mysqli_free_result($this->results);
|
||||
}
|
||||
$this->connected = !@mysqli_close($this->connection);
|
||||
return !$this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @return resource Result resource identifier
|
||||
* @access protected
|
||||
*/
|
||||
function _execute($sql) {
|
||||
if (preg_match('/^\s*call/i', $sql)) {
|
||||
return $this->_executeProcedure($sql);
|
||||
}
|
||||
return mysqli_query($this->connection, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement (procedure call).
|
||||
*
|
||||
* @param string $sql SQL statement (procedure call)
|
||||
* @return resource Result resource identifier for first recordset
|
||||
* @access protected
|
||||
*/
|
||||
function _executeProcedure($sql) {
|
||||
$answer = mysqli_multi_query($this->connection, $sql);
|
||||
|
||||
$firstResult = mysqli_store_result($this->connection);
|
||||
|
||||
if (mysqli_more_results($this->connection)) {
|
||||
while ($lastResult = mysqli_next_result($this->connection));
|
||||
}
|
||||
return $firstResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sources (tables) in the database.
|
||||
*
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listSources() {
|
||||
$cache = parent::listSources();
|
||||
if ($cache !== null) {
|
||||
return $cache;
|
||||
}
|
||||
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
|
||||
|
||||
if (!$result) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
|
||||
while ($line = mysqli_fetch_row($result)) {
|
||||
$tables[] = $line[0];
|
||||
}
|
||||
parent::listSources($tables);
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted and escaped string of $data for use in an SQL statement.
|
||||
*
|
||||
* @param string $data String to be prepared for use in an SQL statement
|
||||
* @param string $column The column into which this data will be inserted
|
||||
* @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
|
||||
* @return string Quoted and escaped data
|
||||
*/
|
||||
function value($data, $column = null, $safe = false) {
|
||||
$parent = parent::value($data, $column, $safe);
|
||||
|
||||
if ($parent != null) {
|
||||
return $parent;
|
||||
}
|
||||
if ($data === null || (is_array($data) && empty($data))) {
|
||||
return 'NULL';
|
||||
}
|
||||
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
|
||||
return "''";
|
||||
}
|
||||
if (empty($column)) {
|
||||
$column = $this->introspectType($data);
|
||||
}
|
||||
|
||||
switch ($column) {
|
||||
case 'boolean':
|
||||
return $this->boolean((bool)$data);
|
||||
break;
|
||||
case 'integer' :
|
||||
case 'float' :
|
||||
case null :
|
||||
if ($data === '') {
|
||||
return 'NULL';
|
||||
}
|
||||
if ((is_int($data) || is_float($data) || $data === '0') || (
|
||||
is_numeric($data) && strpos($data, ',') === false &&
|
||||
$data[0] != '0' && strpos($data, 'e') === false)) {
|
||||
return $data;
|
||||
}
|
||||
default:
|
||||
$data = "'" . mysqli_real_escape_string($this->connection, $data) . "'";
|
||||
break;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message from previous database operation.
|
||||
*
|
||||
* @return string Error message with error number
|
||||
*/
|
||||
function lastError() {
|
||||
if (mysqli_errno($this->connection)) {
|
||||
return mysqli_errno($this->connection).': '.mysqli_error($this->connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of affected rows in previous database operation. If no previous operation exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of affected rows
|
||||
*/
|
||||
function lastAffected() {
|
||||
if ($this->_result) {
|
||||
return mysqli_affected_rows($this->connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of rows in previous resultset. If no previous resultset exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of rows in resultset
|
||||
*/
|
||||
function lastNumRows() {
|
||||
if ($this->hasResult()) {
|
||||
return mysqli_num_rows($this->_result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param unknown_type $source
|
||||
* @return in
|
||||
*/
|
||||
function lastInsertId($source = null) {
|
||||
$id = $this->fetchRow('SELECT LAST_INSERT_ID() AS insertID', false);
|
||||
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
|
||||
return $id[0]['insertID'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param unknown_type $results
|
||||
*/
|
||||
function resultSet(&$results) {
|
||||
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
|
||||
mysqli_free_result($this->results);
|
||||
}
|
||||
$this->results =& $results;
|
||||
$this->map = array();
|
||||
$numFields = mysqli_num_fields($results);
|
||||
$index = 0;
|
||||
$j = 0;
|
||||
while ($j < $numFields) {
|
||||
$column = mysqli_fetch_field_direct($results, $j);
|
||||
if (!empty($column->table)) {
|
||||
$this->map[$index++] = array($column->table, $column->name);
|
||||
} else {
|
||||
$this->map[$index++] = array(0, $column->name);
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next row from the current result set
|
||||
*
|
||||
* @return unknown
|
||||
*/
|
||||
function fetchResult() {
|
||||
if ($row = mysqli_fetch_row($this->results)) {
|
||||
$resultRow = array();
|
||||
foreach ($row as $index => $field) {
|
||||
$table = $column = null;
|
||||
if (count($this->map[$index]) === 2) {
|
||||
list($table, $column) = $this->map[$index];
|
||||
}
|
||||
$resultRow[$table][$column] = $row[$index];
|
||||
}
|
||||
return $resultRow;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database encoding
|
||||
*
|
||||
* @return string The database encoding
|
||||
*/
|
||||
function getEncoding() {
|
||||
return mysqli_client_encoding($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query charset by collation
|
||||
*
|
||||
* @param string $name Collation name
|
||||
* @return string Character set name
|
||||
*/
|
||||
function getCharsetName($name) {
|
||||
if ((bool)version_compare(mysqli_get_server_info($this->connection), "5", ">=")) {
|
||||
$cols = $this->query('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= ' . $this->value($name) . ';');
|
||||
if (isset($cols[0]['COLLATIONS']['CHARACTER_SET_NAME'])) {
|
||||
return $cols[0]['COLLATIONS']['CHARACTER_SET_NAME'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result is valid
|
||||
*
|
||||
* @return boolean True if the result is valid, else false
|
||||
*/
|
||||
function hasResult() {
|
||||
return is_object($this->_result);
|
||||
}
|
||||
}
|
||||
1159
web-cake/html/cake/libs/model/datasources/dbo/dbo_oracle.php
Normal file
1159
web-cake/html/cake/libs/model/datasources/dbo/dbo_oracle.php
Normal file
File diff suppressed because it is too large
Load Diff
977
web-cake/html/cake/libs/model/datasources/dbo/dbo_postgres.php
Normal file
977
web-cake/html/cake/libs/model/datasources/dbo/dbo_postgres.php
Normal file
@@ -0,0 +1,977 @@
|
||||
<?php
|
||||
/**
|
||||
* PostgreSQL layer for DBO.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
* @since CakePHP(tm) v 0.9.1.114
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* PostgreSQL layer for DBO.
|
||||
*
|
||||
* Long description for class
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboPostgres extends DboSource {
|
||||
|
||||
/**
|
||||
* Driver description
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $description = "PostgreSQL DBO Driver";
|
||||
|
||||
/**
|
||||
* Index of basic SQL commands
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_commands = array(
|
||||
'begin' => 'BEGIN',
|
||||
'commit' => 'COMMIT',
|
||||
'rollback' => 'ROLLBACK'
|
||||
);
|
||||
|
||||
/**
|
||||
* Base driver configuration settings. Merged with user settings.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => true,
|
||||
'host' => 'localhost',
|
||||
'login' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'cake',
|
||||
'schema' => 'public',
|
||||
'port' => 5432,
|
||||
'encoding' => ''
|
||||
);
|
||||
|
||||
var $columns = array(
|
||||
'primary_key' => array('name' => 'serial NOT NULL'),
|
||||
'string' => array('name' => 'varchar', 'limit' => '255'),
|
||||
'text' => array('name' => 'text'),
|
||||
'integer' => array('name' => 'integer', 'formatter' => 'intval'),
|
||||
'float' => array('name' => 'float', 'formatter' => 'floatval'),
|
||||
'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
|
||||
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
|
||||
'binary' => array('name' => 'bytea'),
|
||||
'boolean' => array('name' => 'boolean'),
|
||||
'number' => array('name' => 'numeric'),
|
||||
'inet' => array('name' => 'inet')
|
||||
);
|
||||
|
||||
/**
|
||||
* Starting Quote
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $startQuote = '"';
|
||||
|
||||
/**
|
||||
* Ending Quote
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $endQuote = '"';
|
||||
|
||||
/**
|
||||
* Contains mappings of custom auto-increment sequences, if a table uses a sequence name
|
||||
* other than what is dictated by convention.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_sequenceMap = array();
|
||||
|
||||
/**
|
||||
* Connects to the database using options in the given configuration array.
|
||||
*
|
||||
* @return True if successfully connected.
|
||||
*/
|
||||
function connect() {
|
||||
$config = $this->config;
|
||||
$conn = "host='{$config['host']}' port='{$config['port']}' dbname='{$config['database']}' ";
|
||||
$conn .= "user='{$config['login']}' password='{$config['password']}'";
|
||||
|
||||
if (!$config['persistent']) {
|
||||
$this->connection = pg_connect($conn, PGSQL_CONNECT_FORCE_NEW);
|
||||
} else {
|
||||
$this->connection = pg_pconnect($conn);
|
||||
}
|
||||
$this->connected = false;
|
||||
|
||||
if ($this->connection) {
|
||||
$this->connected = true;
|
||||
$this->_execute("SET search_path TO " . $config['schema']);
|
||||
}
|
||||
if (!empty($config['encoding'])) {
|
||||
$this->setEncoding($config['encoding']);
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if PostgreSQL is enabled/loaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function enabled() {
|
||||
return extension_loaded('pgsql');
|
||||
}
|
||||
/**
|
||||
* Disconnects from database.
|
||||
*
|
||||
* @return boolean True if the database could be disconnected, else false
|
||||
*/
|
||||
function disconnect() {
|
||||
if ($this->hasResult()) {
|
||||
pg_free_result($this->_result);
|
||||
}
|
||||
if (is_resource($this->connection)) {
|
||||
$this->connected = !pg_close($this->connection);
|
||||
} else {
|
||||
$this->connected = false;
|
||||
}
|
||||
return !$this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @return resource Result resource identifier
|
||||
*/
|
||||
function _execute($sql) {
|
||||
return pg_query($this->connection, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
|
||||
*
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listSources() {
|
||||
$cache = parent::listSources();
|
||||
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
|
||||
$schema = $this->config['schema'];
|
||||
$sql = "SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = '{$schema}';";
|
||||
$result = $this->fetchAll($sql, false);
|
||||
|
||||
if (!$result) {
|
||||
return array();
|
||||
} else {
|
||||
$tables = array();
|
||||
|
||||
foreach ($result as $item) {
|
||||
$tables[] = $item[0]['name'];
|
||||
}
|
||||
|
||||
parent::listSources($tables);
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the fields in given table name.
|
||||
*
|
||||
* @param string $tableName Name of database table to inspect
|
||||
* @return array Fields in table. Keys are name and type
|
||||
*/
|
||||
function &describe(&$model) {
|
||||
$fields = parent::describe($model);
|
||||
$table = $this->fullTableName($model, false);
|
||||
$this->_sequenceMap[$table] = array();
|
||||
|
||||
if ($fields === null) {
|
||||
$cols = $this->fetchAll(
|
||||
"SELECT DISTINCT column_name AS name, data_type AS type, is_nullable AS null,
|
||||
column_default AS default, ordinal_position AS position, character_maximum_length AS char_length,
|
||||
character_octet_length AS oct_length FROM information_schema.columns
|
||||
WHERE table_name = " . $this->value($table) . " AND table_schema = " .
|
||||
$this->value($this->config['schema'])." ORDER BY position",
|
||||
false
|
||||
);
|
||||
|
||||
foreach ($cols as $column) {
|
||||
$colKey = array_keys($column);
|
||||
|
||||
if (isset($column[$colKey[0]]) && !isset($column[0])) {
|
||||
$column[0] = $column[$colKey[0]];
|
||||
}
|
||||
|
||||
if (isset($column[0])) {
|
||||
$c = $column[0];
|
||||
|
||||
if (!empty($c['char_length'])) {
|
||||
$length = intval($c['char_length']);
|
||||
} elseif (!empty($c['oct_length'])) {
|
||||
if ($c['type'] == 'character varying') {
|
||||
$length = null;
|
||||
$c['type'] = 'text';
|
||||
} else {
|
||||
$length = intval($c['oct_length']);
|
||||
}
|
||||
} else {
|
||||
$length = $this->length($c['type']);
|
||||
}
|
||||
$fields[$c['name']] = array(
|
||||
'type' => $this->column($c['type']),
|
||||
'null' => ($c['null'] == 'NO' ? false : true),
|
||||
'default' => preg_replace(
|
||||
"/^'(.*)'$/",
|
||||
"$1",
|
||||
preg_replace('/::.*/', '', $c['default'])
|
||||
),
|
||||
'length' => $length
|
||||
);
|
||||
if ($c['name'] == $model->primaryKey) {
|
||||
$fields[$c['name']]['key'] = 'primary';
|
||||
if ($fields[$c['name']]['type'] !== 'string') {
|
||||
$fields[$c['name']]['length'] = 11;
|
||||
}
|
||||
}
|
||||
if (
|
||||
$fields[$c['name']]['default'] == 'NULL' ||
|
||||
preg_match('/nextval\([\'"]?([\w.]+)/', $c['default'], $seq)
|
||||
) {
|
||||
$fields[$c['name']]['default'] = null;
|
||||
if (!empty($seq) && isset($seq[1])) {
|
||||
$this->_sequenceMap[$table][$c['name']] = $seq[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->__cacheDescription($table, $fields);
|
||||
}
|
||||
if (isset($model->sequence)) {
|
||||
$this->_sequenceMap[$table][$model->primaryKey] = $model->sequence;
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted and escaped string of $data for use in an SQL statement.
|
||||
*
|
||||
* @param string $data String to be prepared for use in an SQL statement
|
||||
* @param string $column The column into which this data will be inserted
|
||||
* @param boolean $read Value to be used in READ or WRITE context
|
||||
* @return string Quoted and escaped
|
||||
* @todo Add logic that formats/escapes data based on column type
|
||||
*/
|
||||
function value($data, $column = null, $read = true) {
|
||||
|
||||
$parent = parent::value($data, $column);
|
||||
if ($parent != null) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
if ($data === null || (is_array($data) && empty($data))) {
|
||||
return 'NULL';
|
||||
}
|
||||
if (empty($column)) {
|
||||
$column = $this->introspectType($data);
|
||||
}
|
||||
|
||||
switch($column) {
|
||||
case 'binary':
|
||||
$data = pg_escape_bytea($data);
|
||||
break;
|
||||
case 'boolean':
|
||||
if ($data === true || $data === 't' || $data === 'true') {
|
||||
return 'TRUE';
|
||||
} elseif ($data === false || $data === 'f' || $data === 'false') {
|
||||
return 'FALSE';
|
||||
}
|
||||
return (!empty($data) ? 'TRUE' : 'FALSE');
|
||||
break;
|
||||
case 'float':
|
||||
if (is_float($data)) {
|
||||
$data = sprintf('%F', $data);
|
||||
}
|
||||
case 'inet':
|
||||
case 'integer':
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
case 'time':
|
||||
if ($data === '') {
|
||||
return $read ? 'NULL' : 'DEFAULT';
|
||||
}
|
||||
default:
|
||||
$data = pg_escape_string($data);
|
||||
break;
|
||||
}
|
||||
return "'" . $data . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message from previous database operation.
|
||||
*
|
||||
* @return string Error message
|
||||
*/
|
||||
function lastError() {
|
||||
$error = pg_last_error($this->connection);
|
||||
return ($error) ? $error : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of affected rows in previous database operation. If no previous operation exists, this returns false.
|
||||
*
|
||||
* @return integer Number of affected rows
|
||||
*/
|
||||
function lastAffected() {
|
||||
return ($this->_result) ? pg_affected_rows($this->_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of rows in previous resultset. If no previous resultset exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of rows in resultset
|
||||
*/
|
||||
function lastNumRows() {
|
||||
return ($this->_result) ? pg_num_rows($this->_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @param string $source Name of the database table
|
||||
* @param string $field Name of the ID database field. Defaults to "id"
|
||||
* @return integer
|
||||
*/
|
||||
function lastInsertId($source, $field = 'id') {
|
||||
$seq = $this->getSequence($source, $field);
|
||||
$data = $this->fetchRow("SELECT currval('{$seq}') as max");
|
||||
return $data[0]['max'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the associated sequence for the given table/field
|
||||
*
|
||||
* @param mixed $table Either a full table name (with prefix) as a string, or a model object
|
||||
* @param string $field Name of the ID database field. Defaults to "id"
|
||||
* @return string The associated sequence name from the sequence map, defaults to "{$table}_{$field}_seq"
|
||||
*/
|
||||
function getSequence($table, $field = 'id') {
|
||||
if (is_object($table)) {
|
||||
$table = $this->fullTableName($table, false);
|
||||
}
|
||||
if (isset($this->_sequenceMap[$table]) && isset($this->_sequenceMap[$table][$field])) {
|
||||
return $this->_sequenceMap[$table][$field];
|
||||
} else {
|
||||
return "{$table}_{$field}_seq";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all the records in a table and drops all associated auto-increment sequences
|
||||
*
|
||||
* @param mixed $table A string or model class representing the table to be truncated
|
||||
* @param integer $reset If -1, sequences are dropped, if 0 (default), sequences are reset,
|
||||
* and if 1, sequences are not modified
|
||||
* @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
|
||||
* @access public
|
||||
*/
|
||||
function truncate($table, $reset = 0) {
|
||||
if (parent::truncate($table)) {
|
||||
$table = $this->fullTableName($table, false);
|
||||
if (isset($this->_sequenceMap[$table]) && $reset !== 1) {
|
||||
foreach ($this->_sequenceMap[$table] as $field => $sequence) {
|
||||
if ($reset === 0) {
|
||||
$this->execute("ALTER SEQUENCE \"{$sequence}\" RESTART WITH 1");
|
||||
} elseif ($reset === -1) {
|
||||
$this->execute("DROP SEQUENCE IF EXISTS \"{$sequence}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares field names to be quoted by parent
|
||||
*
|
||||
* @param string $data
|
||||
* @return string SQL field
|
||||
*/
|
||||
function name($data) {
|
||||
if (is_string($data)) {
|
||||
$data = str_replace('"__"', '__', $data);
|
||||
}
|
||||
return parent::name($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the fields list of an SQL query.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string $alias Alias tablename
|
||||
* @param mixed $fields
|
||||
* @return array
|
||||
*/
|
||||
function fields(&$model, $alias = null, $fields = array(), $quote = true) {
|
||||
if (empty($alias)) {
|
||||
$alias = $model->alias;
|
||||
}
|
||||
$fields = parent::fields($model, $alias, $fields, false);
|
||||
|
||||
if (!$quote) {
|
||||
return $fields;
|
||||
}
|
||||
$count = count($fields);
|
||||
|
||||
if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) {
|
||||
$result = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) {
|
||||
if (substr($fields[$i], -1) == '*') {
|
||||
if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
|
||||
$build = explode('.', $fields[$i]);
|
||||
$AssociatedModel = $model->{$build[0]};
|
||||
} else {
|
||||
$AssociatedModel = $model;
|
||||
}
|
||||
|
||||
$_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
|
||||
$result = array_merge($result, $_fields);
|
||||
continue;
|
||||
}
|
||||
|
||||
$prepend = '';
|
||||
if (strpos($fields[$i], 'DISTINCT') !== false) {
|
||||
$prepend = 'DISTINCT ';
|
||||
$fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
|
||||
}
|
||||
|
||||
if (strrpos($fields[$i], '.') === false) {
|
||||
$fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]);
|
||||
} else {
|
||||
$build = explode('.', $fields[$i]);
|
||||
$fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]);
|
||||
}
|
||||
} else {
|
||||
$fields[$i] = preg_replace_callback('/\(([\s\.\w]+)\)/', array(&$this, '__quoteFunctionField'), $fields[$i]);
|
||||
}
|
||||
$result[] = $fields[$i];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auxiliary function to quote matched `(Model.fields)` from a preg_replace_callback call
|
||||
*
|
||||
* @param string matched string
|
||||
* @return string quoted strig
|
||||
* @access private
|
||||
*/
|
||||
function __quoteFunctionField($match) {
|
||||
$prepend = '';
|
||||
if (strpos($match[1], 'DISTINCT') !== false) {
|
||||
$prepend = 'DISTINCT ';
|
||||
$match[1] = trim(str_replace('DISTINCT', '', $match[1]));
|
||||
}
|
||||
if (strpos($match[1], '.') === false) {
|
||||
$match[1] = $this->name($match[1]);
|
||||
} else {
|
||||
$parts = explode('.', $match[1]);
|
||||
if (!Set::numeric($parts)) {
|
||||
$match[1] = $this->name($match[1]);
|
||||
}
|
||||
}
|
||||
return '(' . $prepend .$match[1] . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the indexes in given datasource name.
|
||||
*
|
||||
* @param string $model Name of model to inspect
|
||||
* @return array Fields in table. Keys are column and unique
|
||||
*/
|
||||
function index($model) {
|
||||
$index = array();
|
||||
$table = $this->fullTableName($model, false);
|
||||
if ($table) {
|
||||
$indexes = $this->query("SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, i.indisvalid, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) as statement, c2.reltablespace
|
||||
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
|
||||
WHERE c.oid = (
|
||||
SELECT c.oid
|
||||
FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname ~ '^(" . $table . ")$'
|
||||
AND pg_catalog.pg_table_is_visible(c.oid)
|
||||
AND n.nspname ~ '^(" . $this->config['schema'] . ")$'
|
||||
)
|
||||
AND c.oid = i.indrelid AND i.indexrelid = c2.oid
|
||||
ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname", false);
|
||||
foreach ($indexes as $i => $info) {
|
||||
$key = array_pop($info);
|
||||
if ($key['indisprimary']) {
|
||||
$key['relname'] = 'PRIMARY';
|
||||
}
|
||||
$col = array();
|
||||
preg_match('/\(([^\)]+)\)/', $key['statement'], $indexColumns);
|
||||
$parsedColumn = $indexColumns[1];
|
||||
if (strpos($indexColumns[1], ',') !== false) {
|
||||
$parsedColumn = explode(', ', $indexColumns[1]);
|
||||
}
|
||||
$index[$key['relname']]['unique'] = $key['indisunique'];
|
||||
$index[$key['relname']]['column'] = $parsedColumn;
|
||||
}
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the Schema of a table.
|
||||
*
|
||||
* @param array $compare Results of CakeSchema::compare()
|
||||
* @param string $table name of the table
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function alterSchema($compare, $table = null) {
|
||||
if (!is_array($compare)) {
|
||||
return false;
|
||||
}
|
||||
$out = '';
|
||||
$colList = array();
|
||||
foreach ($compare as $curTable => $types) {
|
||||
$indexes = $colList = array();
|
||||
if (!$table || $table == $curTable) {
|
||||
$out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
|
||||
foreach ($types as $type => $column) {
|
||||
if (isset($column['indexes'])) {
|
||||
$indexes[$type] = $column['indexes'];
|
||||
unset($column['indexes']);
|
||||
}
|
||||
switch ($type) {
|
||||
case 'add':
|
||||
foreach ($column as $field => $col) {
|
||||
$col['name'] = $field;
|
||||
$alter = 'ADD COLUMN '.$this->buildColumn($col);
|
||||
if (isset($col['after'])) {
|
||||
$alter .= ' AFTER '. $this->name($col['after']);
|
||||
}
|
||||
$colList[] = $alter;
|
||||
}
|
||||
break;
|
||||
case 'drop':
|
||||
foreach ($column as $field => $col) {
|
||||
$col['name'] = $field;
|
||||
$colList[] = 'DROP COLUMN '.$this->name($field);
|
||||
}
|
||||
break;
|
||||
case 'change':
|
||||
foreach ($column as $field => $col) {
|
||||
if (!isset($col['name'])) {
|
||||
$col['name'] = $field;
|
||||
}
|
||||
$fieldName = $this->name($field);
|
||||
|
||||
$default = isset($col['default']) ? $col['default'] : null;
|
||||
$nullable = isset($col['null']) ? $col['null'] : null;
|
||||
unset($col['default'], $col['null']);
|
||||
$colList[] = 'ALTER COLUMN '. $fieldName .' TYPE ' . str_replace($fieldName, '', $this->buildColumn($col));
|
||||
|
||||
if (isset($nullable)) {
|
||||
$nullable = ($nullable) ? 'DROP NOT NULL' : 'SET NOT NULL';
|
||||
$colList[] = 'ALTER COLUMN '. $fieldName .' ' . $nullable;
|
||||
}
|
||||
|
||||
if (isset($default)) {
|
||||
$colList[] = 'ALTER COLUMN '. $fieldName .' SET DEFAULT ' . $this->value($default, $col['type']);
|
||||
} else {
|
||||
$colList[] = 'ALTER COLUMN '. $fieldName .' DROP DEFAULT';
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($indexes['drop']['PRIMARY'])) {
|
||||
$colList[] = 'DROP CONSTRAINT ' . $curTable . '_pkey';
|
||||
}
|
||||
if (isset($indexes['add']['PRIMARY'])) {
|
||||
$cols = $indexes['add']['PRIMARY']['column'];
|
||||
if (is_array($cols)) {
|
||||
$cols = implode(', ', $cols);
|
||||
}
|
||||
$colList[] = 'ADD PRIMARY KEY (' . $cols . ')';
|
||||
}
|
||||
|
||||
if (!empty($colList)) {
|
||||
$out .= "\t" . implode(",\n\t", $colList) . ";\n\n";
|
||||
} else {
|
||||
$out = '';
|
||||
}
|
||||
$out .= implode(";\n\t", $this->_alterIndexes($curTable, $indexes));
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate PostgreSQL index alteration statements for a table.
|
||||
*
|
||||
* @param string $table Table to alter indexes for
|
||||
* @param array $new Indexes to add and drop
|
||||
* @return array Index alteration statements
|
||||
*/
|
||||
function _alterIndexes($table, $indexes) {
|
||||
$alter = array();
|
||||
if (isset($indexes['drop'])) {
|
||||
foreach($indexes['drop'] as $name => $value) {
|
||||
$out = 'DROP ';
|
||||
if ($name == 'PRIMARY') {
|
||||
continue;
|
||||
} else {
|
||||
$out .= 'INDEX ' . $name;
|
||||
}
|
||||
$alter[] = $out;
|
||||
}
|
||||
}
|
||||
if (isset($indexes['add'])) {
|
||||
foreach ($indexes['add'] as $name => $value) {
|
||||
$out = 'CREATE ';
|
||||
if ($name == 'PRIMARY') {
|
||||
continue;
|
||||
} else {
|
||||
if (!empty($value['unique'])) {
|
||||
$out .= 'UNIQUE ';
|
||||
}
|
||||
$out .= 'INDEX ';
|
||||
}
|
||||
if (is_array($value['column'])) {
|
||||
$out .= $name . ' ON ' . $table . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
|
||||
} else {
|
||||
$out .= $name . ' ON ' . $table . ' (' . $this->name($value['column']) . ')';
|
||||
}
|
||||
$alter[] = $out;
|
||||
}
|
||||
}
|
||||
return $alter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a limit statement in the correct format for the particular database.
|
||||
*
|
||||
* @param integer $limit Limit of results returned
|
||||
* @param integer $offset Offset from which to start results
|
||||
* @return string SQL limit/offset statement
|
||||
*/
|
||||
function limit($limit, $offset = null) {
|
||||
if ($limit) {
|
||||
$rt = '';
|
||||
if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
|
||||
$rt = ' LIMIT';
|
||||
}
|
||||
|
||||
$rt .= ' ' . $limit;
|
||||
if ($offset) {
|
||||
$rt .= ' OFFSET ' . $offset;
|
||||
}
|
||||
|
||||
return $rt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts database-layer column types to basic types
|
||||
*
|
||||
* @param string $real Real database-layer column type (i.e. "varchar(255)")
|
||||
* @return string Abstract column type (i.e. "string")
|
||||
*/
|
||||
function column($real) {
|
||||
if (is_array($real)) {
|
||||
$col = $real['name'];
|
||||
if (isset($real['limit'])) {
|
||||
$col .= '(' . $real['limit'] . ')';
|
||||
}
|
||||
return $col;
|
||||
}
|
||||
|
||||
$col = str_replace(')', '', $real);
|
||||
$limit = null;
|
||||
|
||||
if (strpos($col, '(') !== false) {
|
||||
list($col, $limit) = explode('(', $col);
|
||||
}
|
||||
|
||||
$floats = array(
|
||||
'float', 'float4', 'float8', 'double', 'double precision', 'decimal', 'real', 'numeric'
|
||||
);
|
||||
|
||||
switch (true) {
|
||||
case (in_array($col, array('date', 'time', 'inet', 'boolean'))):
|
||||
return $col;
|
||||
case (strpos($col, 'timestamp') !== false):
|
||||
return 'datetime';
|
||||
case (strpos($col, 'time') === 0):
|
||||
return 'time';
|
||||
case (strpos($col, 'int') !== false && $col != 'interval'):
|
||||
return 'integer';
|
||||
case (strpos($col, 'char') !== false || $col == 'uuid'):
|
||||
return 'string';
|
||||
case (strpos($col, 'text') !== false):
|
||||
return 'text';
|
||||
case (strpos($col, 'bytea') !== false):
|
||||
return 'binary';
|
||||
case (in_array($col, $floats)):
|
||||
return 'float';
|
||||
default:
|
||||
return 'text';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of a database-native column description, or null if no length
|
||||
*
|
||||
* @param string $real Real database-layer column type (i.e. "varchar(255)")
|
||||
* @return int An integer representing the length of the column
|
||||
*/
|
||||
function length($real) {
|
||||
$col = str_replace(array(')', 'unsigned'), '', $real);
|
||||
$limit = null;
|
||||
|
||||
if (strpos($col, '(') !== false) {
|
||||
list($col, $limit) = explode('(', $col);
|
||||
}
|
||||
if ($col == 'uuid') {
|
||||
return 36;
|
||||
}
|
||||
if ($limit != null) {
|
||||
return intval($limit);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param unknown_type $results
|
||||
*/
|
||||
function resultSet(&$results) {
|
||||
$this->results =& $results;
|
||||
$this->map = array();
|
||||
$num_fields = pg_num_fields($results);
|
||||
$index = 0;
|
||||
$j = 0;
|
||||
|
||||
while ($j < $num_fields) {
|
||||
$columnName = pg_field_name($results, $j);
|
||||
|
||||
if (strpos($columnName, '__')) {
|
||||
$parts = explode('__', $columnName);
|
||||
$this->map[$index++] = array($parts[0], $parts[1]);
|
||||
} else {
|
||||
$this->map[$index++] = array(0, $columnName);
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next row from the current result set
|
||||
*
|
||||
* @return unknown
|
||||
*/
|
||||
function fetchResult() {
|
||||
if ($row = pg_fetch_row($this->results)) {
|
||||
$resultRow = array();
|
||||
|
||||
foreach ($row as $index => $field) {
|
||||
list($table, $column) = $this->map[$index];
|
||||
$type = pg_field_type($this->results, $index);
|
||||
|
||||
switch ($type) {
|
||||
case 'bool':
|
||||
$resultRow[$table][$column] = $this->boolean($row[$index], false);
|
||||
break;
|
||||
case 'binary':
|
||||
case 'bytea':
|
||||
$resultRow[$table][$column] = pg_unescape_bytea($row[$index]);
|
||||
break;
|
||||
default:
|
||||
$resultRow[$table][$column] = $row[$index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $resultRow;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates between PHP boolean values and PostgreSQL boolean values
|
||||
*
|
||||
* @param mixed $data Value to be translated
|
||||
* @param boolean $quote True to quote value, false otherwise
|
||||
* @return mixed Converted boolean value
|
||||
*/
|
||||
function boolean($data, $quote = true) {
|
||||
switch (true) {
|
||||
case ($data === true || $data === false):
|
||||
return $data;
|
||||
case ($data === 't' || $data === 'f'):
|
||||
return ($data === 't');
|
||||
case ($data === 'true' || $data === 'false'):
|
||||
return ($data === 'true');
|
||||
case ($data === 'TRUE' || $data === 'FALSE'):
|
||||
return ($data === 'TRUE');
|
||||
default:
|
||||
return (bool)$data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database encoding
|
||||
*
|
||||
* @param mixed $enc Database encoding
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function setEncoding($enc) {
|
||||
return pg_set_client_encoding($this->connection, $enc) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database encoding
|
||||
*
|
||||
* @return string The database encoding
|
||||
*/
|
||||
function getEncoding() {
|
||||
return pg_client_encoding($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Postgres-native column schema string
|
||||
*
|
||||
* @param array $column An array structured like the following:
|
||||
* array('name'=>'value', 'type'=>'value'[, options]),
|
||||
* where options can be 'default', 'length', or 'key'.
|
||||
* @return string
|
||||
*/
|
||||
function buildColumn($column) {
|
||||
$col = $this->columns[$column['type']];
|
||||
if (!isset($col['length']) && !isset($col['limit'])) {
|
||||
unset($column['length']);
|
||||
}
|
||||
$out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column));
|
||||
$out = str_replace('integer serial', 'serial', $out);
|
||||
if (strpos($out, 'timestamp DEFAULT')) {
|
||||
if (isset($column['null']) && $column['null']) {
|
||||
$out = str_replace('DEFAULT NULL', '', $out);
|
||||
} else {
|
||||
$out = str_replace('DEFAULT NOT NULL', '', $out);
|
||||
}
|
||||
}
|
||||
if (strpos($out, 'DEFAULT DEFAULT')) {
|
||||
if (isset($column['null']) && $column['null']) {
|
||||
$out = str_replace('DEFAULT DEFAULT', 'DEFAULT NULL', $out);
|
||||
} elseif (in_array($column['type'], array('integer', 'float'))) {
|
||||
$out = str_replace('DEFAULT DEFAULT', 'DEFAULT 0', $out);
|
||||
} elseif ($column['type'] == 'boolean') {
|
||||
$out = str_replace('DEFAULT DEFAULT', 'DEFAULT FALSE', $out);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format indexes for create table
|
||||
*
|
||||
* @param array $indexes
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
function buildIndex($indexes, $table = null) {
|
||||
$join = array();
|
||||
if (!is_array($indexes)) {
|
||||
return array();
|
||||
}
|
||||
foreach ($indexes as $name => $value) {
|
||||
if ($name == 'PRIMARY') {
|
||||
$out = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
|
||||
} else {
|
||||
$out = 'CREATE ';
|
||||
if (!empty($value['unique'])) {
|
||||
$out .= 'UNIQUE ';
|
||||
}
|
||||
if (is_array($value['column'])) {
|
||||
$value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
|
||||
} else {
|
||||
$value['column'] = $this->name($value['column']);
|
||||
}
|
||||
$out .= "INDEX {$name} ON {$table}({$value['column']});";
|
||||
}
|
||||
$join[] = $out;
|
||||
}
|
||||
return $join;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides DboSource::renderStatement to handle schema generation with Postgres-style indexes
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
function renderStatement($type, $data) {
|
||||
switch (strtolower($type)) {
|
||||
case 'schema':
|
||||
extract($data);
|
||||
|
||||
foreach ($indexes as $i => $index) {
|
||||
if (preg_match('/PRIMARY KEY/', $index)) {
|
||||
unset($indexes[$i]);
|
||||
$columns[] = $index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$join = array('columns' => ",\n\t", 'indexes' => "\n");
|
||||
|
||||
foreach (array('columns', 'indexes') as $var) {
|
||||
if (is_array(${$var})) {
|
||||
${$var} = implode($join[$var], array_filter(${$var}));
|
||||
}
|
||||
}
|
||||
return "CREATE TABLE {$table} (\n\t{$columns}\n);\n{$indexes}";
|
||||
break;
|
||||
default:
|
||||
return parent::renderStatement($type, $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
623
web-cake/html/cake/libs/model/datasources/dbo/dbo_sqlite.php
Normal file
623
web-cake/html/cake/libs/model/datasources/dbo/dbo_sqlite.php
Normal file
@@ -0,0 +1,623 @@
|
||||
<?php
|
||||
/**
|
||||
* SQLite layer for DBO
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
* @since CakePHP(tm) v 0.9.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* DBO implementation for the SQLite DBMS.
|
||||
*
|
||||
* Long description for class
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model.datasources.dbo
|
||||
*/
|
||||
class DboSqlite extends DboSource {
|
||||
|
||||
/**
|
||||
* Datasource Description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $description = "SQLite DBO Driver";
|
||||
|
||||
/**
|
||||
* Opening quote for quoted identifiers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $startQuote = '"';
|
||||
|
||||
/**
|
||||
* Closing quote for quoted identifiers
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $endQuote = '"';
|
||||
|
||||
/**
|
||||
* Keeps the transaction statistics of CREATE/UPDATE/DELETE queries
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_queryStats = array();
|
||||
|
||||
/**
|
||||
* Base configuration settings for SQLite driver
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_baseConfig = array(
|
||||
'persistent' => true,
|
||||
'database' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Index of basic SQL commands
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_commands = array(
|
||||
'begin' => 'BEGIN TRANSACTION',
|
||||
'commit' => 'COMMIT TRANSACTION',
|
||||
'rollback' => 'ROLLBACK TRANSACTION'
|
||||
);
|
||||
|
||||
/**
|
||||
* SQLite column definition
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $columns = array(
|
||||
'primary_key' => array('name' => 'integer primary key'),
|
||||
'string' => array('name' => 'varchar', 'limit' => '255'),
|
||||
'text' => array('name' => 'text'),
|
||||
'integer' => array('name' => 'integer', 'limit' => 11, 'formatter' => 'intval'),
|
||||
'float' => array('name' => 'float', 'formatter' => 'floatval'),
|
||||
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
|
||||
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
|
||||
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
|
||||
'binary' => array('name' => 'blob'),
|
||||
'boolean' => array('name' => 'boolean')
|
||||
);
|
||||
|
||||
/**
|
||||
* List of engine specific additional field parameters used on table creating
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $fieldParameters = array(
|
||||
'collate' => array(
|
||||
'value' => 'COLLATE',
|
||||
'quote' => false,
|
||||
'join' => ' ',
|
||||
'column' => 'Collate',
|
||||
'position' => 'afterDefault',
|
||||
'options' => array(
|
||||
'BINARY', 'NOCASE', 'RTRIM'
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Connects to the database using config['database'] as a filename.
|
||||
*
|
||||
* @param array $config Configuration array for connecting
|
||||
* @return mixed
|
||||
*/
|
||||
function connect() {
|
||||
$config = $this->config;
|
||||
|
||||
if (!$config['persistent']) {
|
||||
$this->connection = sqlite_open($config['database']);
|
||||
} else {
|
||||
$this->connection = sqlite_popen($config['database']);
|
||||
}
|
||||
$this->connected = is_resource($this->connection);
|
||||
|
||||
if ($this->connected) {
|
||||
$this->_execute('PRAGMA count_changes = 1;');
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that SQLite is enabled/installed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function enabled() {
|
||||
return extension_loaded('sqlite');
|
||||
}
|
||||
/**
|
||||
* Disconnects from database.
|
||||
*
|
||||
* @return boolean True if the database could be disconnected, else false
|
||||
*/
|
||||
function disconnect() {
|
||||
@sqlite_close($this->connection);
|
||||
$this->connected = false;
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given SQL statement.
|
||||
*
|
||||
* @param string $sql SQL statement
|
||||
* @return resource Result resource identifier
|
||||
*/
|
||||
function _execute($sql) {
|
||||
$result = sqlite_query($this->connection, $sql);
|
||||
|
||||
if (preg_match('/^(INSERT|UPDATE|DELETE)/', $sql)) {
|
||||
$this->resultSet($result);
|
||||
list($this->_queryStats) = $this->fetchResult();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides DboSource::execute() to correctly handle query statistics
|
||||
*
|
||||
* @param string $sql
|
||||
* @return unknown
|
||||
*/
|
||||
function execute($sql) {
|
||||
$result = parent::execute($sql);
|
||||
$this->_queryStats = array();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
|
||||
*
|
||||
* @return array Array of tablenames in the database
|
||||
*/
|
||||
function listSources() {
|
||||
$cache = parent::listSources();
|
||||
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
$result = $this->fetchAll("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;", false);
|
||||
|
||||
if (empty($result)) {
|
||||
return array();
|
||||
} else {
|
||||
$tables = array();
|
||||
foreach ($result as $table) {
|
||||
$tables[] = $table[0]['name'];
|
||||
}
|
||||
parent::listSources($tables);
|
||||
return $tables;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the fields in given table name.
|
||||
*
|
||||
* @param string $tableName Name of database table to inspect
|
||||
* @return array Fields in table. Keys are name and type
|
||||
*/
|
||||
function describe(&$model) {
|
||||
$cache = parent::describe($model);
|
||||
if ($cache != null) {
|
||||
return $cache;
|
||||
}
|
||||
$fields = array();
|
||||
$result = $this->fetchAll('PRAGMA table_info(' . $this->fullTableName($model) . ')');
|
||||
|
||||
foreach ($result as $column) {
|
||||
$fields[$column[0]['name']] = array(
|
||||
'type' => $this->column($column[0]['type']),
|
||||
'null' => !$column[0]['notnull'],
|
||||
'default' => $column[0]['dflt_value'],
|
||||
'length' => $this->length($column[0]['type'])
|
||||
);
|
||||
if ($column[0]['pk'] == 1) {
|
||||
$colLength = $this->length($column[0]['type']);
|
||||
$fields[$column[0]['name']] = array(
|
||||
'type' => $fields[$column[0]['name']]['type'],
|
||||
'null' => false,
|
||||
'default' => $column[0]['dflt_value'],
|
||||
'key' => $this->index['PRI'],
|
||||
'length'=> ($colLength != null) ? $colLength : 11
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->__cacheDescription($model->tablePrefix . $model->table, $fields);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted and escaped string of $data for use in an SQL statement.
|
||||
*
|
||||
* @param string $data String to be prepared for use in an SQL statement
|
||||
* @return string Quoted and escaped
|
||||
*/
|
||||
function value($data, $column = null, $safe = false) {
|
||||
$parent = parent::value($data, $column, $safe);
|
||||
|
||||
if ($parent != null) {
|
||||
return $parent;
|
||||
}
|
||||
if ($data === null) {
|
||||
return 'NULL';
|
||||
}
|
||||
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
|
||||
return "''";
|
||||
}
|
||||
switch ($column) {
|
||||
case 'boolean':
|
||||
$data = $this->boolean((bool)$data);
|
||||
break;
|
||||
case 'integer':
|
||||
case 'float':
|
||||
if ($data === '') {
|
||||
return 'NULL';
|
||||
}
|
||||
default:
|
||||
$data = sqlite_escape_string($data);
|
||||
break;
|
||||
}
|
||||
return "'" . $data . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and executes an SQL UPDATE statement for given model, fields, and values.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $fields
|
||||
* @param array $values
|
||||
* @param mixed $conditions
|
||||
* @return array
|
||||
*/
|
||||
function update(&$model, $fields = array(), $values = null, $conditions = null) {
|
||||
if (empty($values) && !empty($fields)) {
|
||||
foreach ($fields as $field => $value) {
|
||||
if (strpos($field, $model->alias . '.') !== false) {
|
||||
unset($fields[$field]);
|
||||
$field = str_replace($model->alias . '.', "", $field);
|
||||
$field = str_replace($model->alias . '.', "", $field);
|
||||
$fields[$field] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$result = parent::update($model, $fields, $values, $conditions);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all the records in a table and resets the count of the auto-incrementing
|
||||
* primary key, where applicable.
|
||||
*
|
||||
* @param mixed $table A string or model class representing the table to be truncated
|
||||
* @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
|
||||
* @access public
|
||||
*/
|
||||
function truncate($table) {
|
||||
return $this->execute('DELETE From ' . $this->fullTableName($table));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message from previous database operation.
|
||||
*
|
||||
* @return string Error message
|
||||
*/
|
||||
function lastError() {
|
||||
$error = sqlite_last_error($this->connection);
|
||||
if ($error) {
|
||||
return $error.': '.sqlite_error_string($error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of affected rows in previous database operation. If no previous operation exists, this returns false.
|
||||
*
|
||||
* @return integer Number of affected rows
|
||||
*/
|
||||
function lastAffected() {
|
||||
if (!empty($this->_queryStats)) {
|
||||
foreach (array('rows inserted', 'rows updated', 'rows deleted') as $key) {
|
||||
if (array_key_exists($key, $this->_queryStats)) {
|
||||
return $this->_queryStats[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of rows in previous resultset. If no previous resultset exists,
|
||||
* this returns false.
|
||||
*
|
||||
* @return integer Number of rows in resultset
|
||||
*/
|
||||
function lastNumRows() {
|
||||
if ($this->hasResult()) {
|
||||
sqlite_num_rows($this->_result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function lastInsertId() {
|
||||
return sqlite_last_insert_rowid($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts database-layer column types to basic types
|
||||
*
|
||||
* @param string $real Real database-layer column type (i.e. "varchar(255)")
|
||||
* @return string Abstract column type (i.e. "string")
|
||||
*/
|
||||
function column($real) {
|
||||
if (is_array($real)) {
|
||||
$col = $real['name'];
|
||||
if (isset($real['limit'])) {
|
||||
$col .= '('.$real['limit'].')';
|
||||
}
|
||||
return $col;
|
||||
}
|
||||
|
||||
$col = strtolower(str_replace(')', '', $real));
|
||||
$limit = null;
|
||||
if (strpos($col, '(') !== false) {
|
||||
list($col, $limit) = explode('(', $col);
|
||||
}
|
||||
|
||||
if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) {
|
||||
return $col;
|
||||
}
|
||||
if (strpos($col, 'varchar') !== false) {
|
||||
return 'string';
|
||||
}
|
||||
if (in_array($col, array('blob', 'clob'))) {
|
||||
return 'binary';
|
||||
}
|
||||
if (strpos($col, 'numeric') !== false) {
|
||||
return 'float';
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param unknown_type $results
|
||||
*/
|
||||
function resultSet(&$results) {
|
||||
$this->results =& $results;
|
||||
$this->map = array();
|
||||
$fieldCount = sqlite_num_fields($results);
|
||||
$index = $j = 0;
|
||||
|
||||
while ($j < $fieldCount) {
|
||||
$columnName = str_replace('"', '', sqlite_field_name($results, $j));
|
||||
|
||||
if (strpos($columnName, '.')) {
|
||||
$parts = explode('.', $columnName);
|
||||
$this->map[$index++] = array($parts[0], $parts[1]);
|
||||
} else {
|
||||
$this->map[$index++] = array(0, $columnName);
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next row from the current result set
|
||||
*
|
||||
* @return unknown
|
||||
*/
|
||||
function fetchResult() {
|
||||
if ($row = sqlite_fetch_array($this->results, SQLITE_ASSOC)) {
|
||||
$resultRow = array();
|
||||
$i = 0;
|
||||
|
||||
foreach ($row as $index => $field) {
|
||||
if (strpos($index, '.')) {
|
||||
list($table, $column) = explode('.', str_replace('"', '', $index));
|
||||
$resultRow[$table][$column] = $row[$index];
|
||||
} else {
|
||||
$resultRow[0][str_replace('"', '', $index)] = $row[$index];
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $resultRow;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a limit statement in the correct format for the particular database.
|
||||
*
|
||||
* @param integer $limit Limit of results returned
|
||||
* @param integer $offset Offset from which to start results
|
||||
* @return string SQL limit/offset statement
|
||||
*/
|
||||
function limit($limit, $offset = null) {
|
||||
if ($limit) {
|
||||
$rt = '';
|
||||
if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
|
||||
$rt = ' LIMIT';
|
||||
}
|
||||
$rt .= ' ' . $limit;
|
||||
if ($offset) {
|
||||
$rt .= ' OFFSET ' . $offset;
|
||||
}
|
||||
return $rt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a database-native column schema string
|
||||
*
|
||||
* @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
|
||||
* where options can be 'default', 'length', or 'key'.
|
||||
* @return string
|
||||
*/
|
||||
function buildColumn($column) {
|
||||
$name = $type = null;
|
||||
$column = array_merge(array('null' => true), $column);
|
||||
extract($column);
|
||||
|
||||
if (empty($name) || empty($type)) {
|
||||
trigger_error(__('Column name or type not defined in schema', true), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($this->columns[$type])) {
|
||||
trigger_error(sprintf(__('Column type %s does not exist', true), $type), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
$real = $this->columns[$type];
|
||||
$out = $this->name($name) . ' ' . $real['name'];
|
||||
if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
|
||||
return $this->name($name) . ' ' . $this->columns['primary_key']['name'];
|
||||
}
|
||||
return parent::buildColumn($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database encoding
|
||||
*
|
||||
* @param string $enc Database encoding
|
||||
*/
|
||||
function setEncoding($enc) {
|
||||
if (!in_array($enc, array("UTF-8", "UTF-16", "UTF-16le", "UTF-16be"))) {
|
||||
return false;
|
||||
}
|
||||
return $this->_execute("PRAGMA encoding = \"{$enc}\"") !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database encoding
|
||||
*
|
||||
* @return string The database encoding
|
||||
*/
|
||||
function getEncoding() {
|
||||
return $this->fetchRow('PRAGMA encoding');
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes redundant primary key indexes, as they are handled in the column def of the key.
|
||||
*
|
||||
* @param array $indexes
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
function buildIndex($indexes, $table = null) {
|
||||
$join = array();
|
||||
|
||||
foreach ($indexes as $name => $value) {
|
||||
|
||||
if ($name == 'PRIMARY') {
|
||||
continue;
|
||||
}
|
||||
$out = 'CREATE ';
|
||||
|
||||
if (!empty($value['unique'])) {
|
||||
$out .= 'UNIQUE ';
|
||||
}
|
||||
if (is_array($value['column'])) {
|
||||
$value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
|
||||
} else {
|
||||
$value['column'] = $this->name($value['column']);
|
||||
}
|
||||
$out .= "INDEX {$name} ON {$table}({$value['column']});";
|
||||
$join[] = $out;
|
||||
}
|
||||
return $join;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides DboSource::index to handle SQLite indexe introspection
|
||||
* Returns an array of the indexes in given table name.
|
||||
*
|
||||
* @param string $model Name of model to inspect
|
||||
* @return array Fields in table. Keys are column and unique
|
||||
*/
|
||||
function index(&$model) {
|
||||
$index = array();
|
||||
$table = $this->fullTableName($model);
|
||||
if ($table) {
|
||||
$indexes = $this->query('PRAGMA index_list(' . $table . ')');
|
||||
$tableInfo = $this->query('PRAGMA table_info(' . $table . ')');
|
||||
foreach ($indexes as $i => $info) {
|
||||
$key = array_pop($info);
|
||||
$keyInfo = $this->query('PRAGMA index_info("' . $key['name'] . '")');
|
||||
foreach ($keyInfo as $keyCol) {
|
||||
if (!isset($index[$key['name']])) {
|
||||
$col = array();
|
||||
if (preg_match('/autoindex/', $key['name'])) {
|
||||
$key['name'] = 'PRIMARY';
|
||||
}
|
||||
$index[$key['name']]['column'] = $keyCol[0]['name'];
|
||||
$index[$key['name']]['unique'] = intval($key['unique'] == 1);
|
||||
} else {
|
||||
if (!is_array($index[$key['name']]['column'])) {
|
||||
$col[] = $index[$key['name']]['column'];
|
||||
}
|
||||
$col[] = $keyCol[0]['name'];
|
||||
$index[$key['name']]['column'] = $col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides DboSource::renderStatement to handle schema generation with SQLite-style indexes
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
function renderStatement($type, $data) {
|
||||
switch (strtolower($type)) {
|
||||
case 'schema':
|
||||
extract($data);
|
||||
|
||||
foreach (array('columns', 'indexes') as $var) {
|
||||
if (is_array(${$var})) {
|
||||
${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
|
||||
}
|
||||
}
|
||||
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
|
||||
break;
|
||||
default:
|
||||
return parent::renderStatement($type, $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
2925
web-cake/html/cake/libs/model/datasources/dbo_source.php
Executable file
2925
web-cake/html/cake/libs/model/datasources/dbo_source.php
Executable file
File diff suppressed because it is too large
Load Diff
332
web-cake/html/cake/libs/model/db_acl.php
Normal file
332
web-cake/html/cake/libs/model/db_acl.php
Normal file
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
/**
|
||||
* This is core configuration file.
|
||||
*
|
||||
* Use it to configure core behaviour ofCake.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load Model and AppModel
|
||||
*/
|
||||
App::import('Model', 'App');
|
||||
|
||||
/**
|
||||
* ACL Node
|
||||
*
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class AclNode extends AppModel {
|
||||
|
||||
/**
|
||||
* Explicitly disable in-memory query caching for ACL models
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $cacheQueries = false;
|
||||
|
||||
/**
|
||||
* ACL models use the Tree behavior
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $actsAs = array('Tree' => 'nested');
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct() {
|
||||
$config = Configure::read('Acl.database');
|
||||
if (isset($config)) {
|
||||
$this->useDbConfig = $config;
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Aro/Aco node for this model
|
||||
*
|
||||
* @param mixed $ref Array with 'model' and 'foreign_key', model object, or string value
|
||||
* @return array Node found in database
|
||||
* @access public
|
||||
*/
|
||||
function node($ref = null) {
|
||||
$db =& ConnectionManager::getDataSource($this->useDbConfig);
|
||||
$type = $this->alias;
|
||||
$result = null;
|
||||
|
||||
if (!empty($this->useTable)) {
|
||||
$table = $this->useTable;
|
||||
} else {
|
||||
$table = Inflector::pluralize(Inflector::underscore($type));
|
||||
}
|
||||
|
||||
if (empty($ref)) {
|
||||
return null;
|
||||
} elseif (is_string($ref)) {
|
||||
$path = explode('/', $ref);
|
||||
$start = $path[0];
|
||||
unset($path[0]);
|
||||
|
||||
$queryData = array(
|
||||
'conditions' => array(
|
||||
$db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft"),
|
||||
$db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght")),
|
||||
'fields' => array('id', 'parent_id', 'model', 'foreign_key', 'alias'),
|
||||
'joins' => array(array(
|
||||
'table' => $db->fullTableName($this),
|
||||
'alias' => "{$type}0",
|
||||
'type' => 'LEFT',
|
||||
'conditions' => array("{$type}0.alias" => $start)
|
||||
)),
|
||||
'order' => $db->name("{$type}.lft") . ' DESC'
|
||||
);
|
||||
|
||||
foreach ($path as $i => $alias) {
|
||||
$j = $i - 1;
|
||||
|
||||
$queryData['joins'][] = array(
|
||||
'table' => $db->fullTableName($this),
|
||||
'alias' => "{$type}{$i}",
|
||||
'type' => 'LEFT',
|
||||
'conditions' => array(
|
||||
$db->name("{$type}{$i}.lft") . ' > ' . $db->name("{$type}{$j}.lft"),
|
||||
$db->name("{$type}{$i}.rght") . ' < ' . $db->name("{$type}{$j}.rght"),
|
||||
$db->name("{$type}{$i}.alias") . ' = ' . $db->value($alias, 'string'),
|
||||
$db->name("{$type}{$j}.id") . ' = ' . $db->name("{$type}{$i}.parent_id")
|
||||
)
|
||||
);
|
||||
|
||||
$queryData['conditions'] = array('or' => array(
|
||||
$db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft") . ' AND ' . $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght"),
|
||||
$db->name("{$type}.lft") . ' <= ' . $db->name("{$type}{$i}.lft") . ' AND ' . $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}{$i}.rght"))
|
||||
);
|
||||
}
|
||||
$result = $db->read($this, $queryData, -1);
|
||||
$path = array_values($path);
|
||||
|
||||
if (
|
||||
!isset($result[0][$type]) ||
|
||||
(!empty($path) && $result[0][$type]['alias'] != $path[count($path) - 1]) ||
|
||||
(empty($path) && $result[0][$type]['alias'] != $start)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} elseif (is_object($ref) && is_a($ref, 'Model')) {
|
||||
$ref = array('model' => $ref->alias, 'foreign_key' => $ref->id);
|
||||
} elseif (is_array($ref) && !(isset($ref['model']) && isset($ref['foreign_key']))) {
|
||||
$name = key($ref);
|
||||
|
||||
if (PHP5) {
|
||||
$model = ClassRegistry::init(array('class' => $name, 'alias' => $name));
|
||||
} else {
|
||||
$model =& ClassRegistry::init(array('class' => $name, 'alias' => $name));
|
||||
}
|
||||
|
||||
if (empty($model)) {
|
||||
trigger_error(sprintf(__("Model class '%s' not found in AclNode::node() when trying to bind %s object", true), $type, $this->alias), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
$tmpRef = null;
|
||||
if (method_exists($model, 'bindNode')) {
|
||||
$tmpRef = $model->bindNode($ref);
|
||||
}
|
||||
if (empty($tmpRef)) {
|
||||
$ref = array('model' => $name, 'foreign_key' => $ref[$name][$model->primaryKey]);
|
||||
} else {
|
||||
if (is_string($tmpRef)) {
|
||||
return $this->node($tmpRef);
|
||||
}
|
||||
$ref = $tmpRef;
|
||||
}
|
||||
}
|
||||
if (is_array($ref)) {
|
||||
if (is_array(current($ref)) && is_string(key($ref))) {
|
||||
$name = key($ref);
|
||||
$ref = current($ref);
|
||||
}
|
||||
foreach ($ref as $key => $val) {
|
||||
if (strpos($key, $type) !== 0 && strpos($key, '.') === false) {
|
||||
unset($ref[$key]);
|
||||
$ref["{$type}0.{$key}"] = $val;
|
||||
}
|
||||
}
|
||||
$queryData = array(
|
||||
'conditions' => $ref,
|
||||
'fields' => array('id', 'parent_id', 'model', 'foreign_key', 'alias'),
|
||||
'joins' => array(array(
|
||||
'table' => $db->fullTableName($this),
|
||||
'alias' => "{$type}0",
|
||||
'type' => 'LEFT',
|
||||
'conditions' => array(
|
||||
$db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft"),
|
||||
$db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght")
|
||||
)
|
||||
)),
|
||||
'order' => $db->name("{$type}.lft") . ' DESC'
|
||||
);
|
||||
$result = $db->read($this, $queryData, -1);
|
||||
|
||||
if (!$result) {
|
||||
trigger_error(sprintf(__("AclNode::node() - Couldn't find %s node identified by \"%s\"", true), $type, print_r($ref, true)), E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Control Object
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class Aco extends AclNode {
|
||||
|
||||
/**
|
||||
* Model name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'Aco';
|
||||
|
||||
/**
|
||||
* Binds to ARO nodes through permissions settings
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $hasAndBelongsToMany = array('Aro' => array('with' => 'Permission'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for Access Control Object
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class AcoAction extends AppModel {
|
||||
|
||||
/**
|
||||
* Model name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'AcoAction';
|
||||
|
||||
/**
|
||||
* ACO Actions belong to ACOs
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $belongsTo = array('Aco');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Request Object
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class Aro extends AclNode {
|
||||
|
||||
/**
|
||||
* Model name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'Aro';
|
||||
|
||||
/**
|
||||
* AROs are linked to ACOs by means of Permission
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $hasAndBelongsToMany = array('Aco' => array('with' => 'Permission'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Permissions linking AROs with ACOs
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class Permission extends AppModel {
|
||||
|
||||
/**
|
||||
* Model name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $name = 'Permission';
|
||||
|
||||
/**
|
||||
* Explicitly disable in-memory query caching
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $cacheQueries = false;
|
||||
|
||||
/**
|
||||
* Override default table name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $useTable = 'aros_acos';
|
||||
|
||||
/**
|
||||
* Permissions link AROs with ACOs
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $belongsTo = array('Aro', 'Aco');
|
||||
|
||||
/**
|
||||
* No behaviors for this model
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $actsAs = null;
|
||||
|
||||
/**
|
||||
* Constructor, used to tell this model to use the
|
||||
* database configured for ACL
|
||||
*/
|
||||
function __construct() {
|
||||
$config = Configure::read('Acl.database');
|
||||
if (!empty($config)) {
|
||||
$this->useDbConfig = $config;
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
3074
web-cake/html/cake/libs/model/model.php
Normal file
3074
web-cake/html/cake/libs/model/model.php
Normal file
File diff suppressed because it is too large
Load Diff
533
web-cake/html/cake/libs/model/model_behavior.php
Normal file
533
web-cake/html/cake/libs/model/model_behavior.php
Normal file
@@ -0,0 +1,533 @@
|
||||
<?php
|
||||
/**
|
||||
* Model behaviors base class.
|
||||
*
|
||||
* Adds methods and automagic functionality to Cake Models.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
* @since CakePHP(tm) v 1.2.0.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model behavior base class.
|
||||
*
|
||||
* Defines the Behavior interface, and contains common model interaction functionality.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class ModelBehavior extends Object {
|
||||
|
||||
/**
|
||||
* Contains configuration settings for use with individual model objects. This
|
||||
* is used because if multiple models use this Behavior, each will use the same
|
||||
* object instance. Individual model settings should be stored as an
|
||||
* associative array, keyed off of the model name.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
* @see Model::$alias
|
||||
*/
|
||||
var $settings = array();
|
||||
|
||||
/**
|
||||
* Allows the mapping of preg-compatible regular expressions to public or
|
||||
* private methods in this class, where the array key is a /-delimited regular
|
||||
* expression, and the value is a class method. Similar to the functionality of
|
||||
* the findBy* / findAllBy* magic methods.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $mapMethods = array();
|
||||
|
||||
/**
|
||||
* Setup this behavior with the specified configuration settings.
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param array $config Configuration settings for $model
|
||||
* @access public
|
||||
*/
|
||||
function setup(&$model, $config = array()) { }
|
||||
|
||||
/**
|
||||
* Clean up any initialization this behavior has done on a model. Called when a behavior is dynamically
|
||||
* detached from a model using Model::detach().
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @access public
|
||||
* @see BehaviorCollection::detach()
|
||||
*/
|
||||
function cleanup(&$model) {
|
||||
if (isset($this->settings[$model->alias])) {
|
||||
unset($this->settings[$model->alias]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Before find callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param array $queryData Data used to execute this query, i.e. conditions, order, etc.
|
||||
* @return mixed False if the operation should abort. An array will replace the value of $query.
|
||||
* @access public
|
||||
*/
|
||||
function beforeFind(&$model, $query) { }
|
||||
|
||||
/**
|
||||
* After find callback. Can be used to modify any results returned by find and findAll.
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param mixed $results The results of the find operation
|
||||
* @param boolean $primary Whether this model is being queried directly (vs. being queried as an association)
|
||||
* @return mixed An array value will replace the value of $results - any other value will be ignored.
|
||||
* @access public
|
||||
*/
|
||||
function afterFind(&$model, $results, $primary) { }
|
||||
|
||||
/**
|
||||
* Before validate callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @return mixed False if the operation should abort. Any other result will continue.
|
||||
* @access public
|
||||
*/
|
||||
function beforeValidate(&$model) { }
|
||||
|
||||
/**
|
||||
* Before save callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @return mixed False if the operation should abort. Any other result will continue.
|
||||
* @access public
|
||||
*/
|
||||
function beforeSave(&$model) { }
|
||||
|
||||
/**
|
||||
* After save callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param boolean $created True if this save created a new record
|
||||
* @access public
|
||||
*/
|
||||
function afterSave(&$model, $created) { }
|
||||
|
||||
/**
|
||||
* Before delete callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param boolean $cascade If true records that depend on this record will also be deleted
|
||||
* @return mixed False if the operation should abort. Any other result will continue.
|
||||
* @access public
|
||||
*/
|
||||
function beforeDelete(&$model, $cascade = true) { }
|
||||
|
||||
/**
|
||||
* After delete callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @access public
|
||||
*/
|
||||
function afterDelete(&$model) { }
|
||||
|
||||
/**
|
||||
* DataSource error callback
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param string $error Error generated in DataSource
|
||||
* @access public
|
||||
*/
|
||||
function onError(&$model, $error) { }
|
||||
|
||||
/**
|
||||
* Overrides Object::dispatchMethod to account for PHP4's broken reference support
|
||||
*
|
||||
* @see Object::dispatchMethod
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
function dispatchMethod(&$model, $method, $params = array()) {
|
||||
if (empty($params)) {
|
||||
return $this->{$method}($model);
|
||||
}
|
||||
$params = array_values($params);
|
||||
|
||||
switch (count($params)) {
|
||||
case 1:
|
||||
return $this->{$method}($model, $params[0]);
|
||||
case 2:
|
||||
return $this->{$method}($model, $params[0], $params[1]);
|
||||
case 3:
|
||||
return $this->{$method}($model, $params[0], $params[1], $params[2]);
|
||||
case 4:
|
||||
return $this->{$method}($model, $params[0], $params[1], $params[2], $params[3]);
|
||||
case 5:
|
||||
return $this->{$method}($model, $params[0], $params[1], $params[2], $params[3], $params[4]);
|
||||
default:
|
||||
$params = array_merge(array(&$model), $params);
|
||||
return call_user_func_array(array(&$this, $method), $params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If $model's whitelist property is non-empty, $field will be added to it.
|
||||
* Note: this method should *only* be used in beforeValidate or beforeSave to ensure
|
||||
* that it only modifies the whitelist for the current save operation. Also make sure
|
||||
* you explicitly set the value of the field which you are allowing.
|
||||
*
|
||||
* @param object $model Model using this behavior
|
||||
* @param string $field Field to be added to $model's whitelist
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
function _addToWhitelist(&$model, $field) {
|
||||
if (is_array($field)) {
|
||||
foreach ($field as $f) {
|
||||
$this->_addToWhitelist($model, $f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!empty($model->whitelist) && !in_array($field, $model->whitelist)) {
|
||||
$model->whitelist[] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Model behavior collection class.
|
||||
*
|
||||
* Defines the Behavior interface, and contains common model interaction functionality.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.model
|
||||
*/
|
||||
class BehaviorCollection extends Object {
|
||||
|
||||
/**
|
||||
* Stores a reference to the attached name
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $modelName = null;
|
||||
|
||||
/**
|
||||
* Lists the currently-attached behavior objects
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_attached = array();
|
||||
|
||||
/**
|
||||
* Lists the currently-attached behavior objects which are disabled
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_disabled = array();
|
||||
|
||||
/**
|
||||
* Keeps a list of all methods of attached behaviors
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $__methods = array();
|
||||
|
||||
/**
|
||||
* Keeps a list of all methods which have been mapped with regular expressions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $__mappedMethods = array();
|
||||
|
||||
/**
|
||||
* Attaches a model object and loads a list of behaviors
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function init($modelName, $behaviors = array()) {
|
||||
$this->modelName = $modelName;
|
||||
|
||||
if (!empty($behaviors)) {
|
||||
foreach (Set::normalize($behaviors) as $behavior => $config) {
|
||||
$this->attach($behavior, $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a behavior to a model
|
||||
*
|
||||
* @param string $behavior CamelCased name of the behavior to load
|
||||
* @param array $config Behavior configuration parameters
|
||||
* @return boolean True on success, false on failure
|
||||
* @access public
|
||||
*/
|
||||
function attach($behavior, $config = array()) {
|
||||
list($plugin, $name) = pluginSplit($behavior);
|
||||
$class = $name . 'Behavior';
|
||||
|
||||
if (!App::import('Behavior', $behavior)) {
|
||||
$this->cakeError('missingBehaviorFile', array(array(
|
||||
'behavior' => $behavior,
|
||||
'file' => Inflector::underscore($behavior) . '.php',
|
||||
'code' => 500,
|
||||
'base' => '/'
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
$this->cakeError('missingBehaviorClass', array(array(
|
||||
'behavior' => $class,
|
||||
'file' => Inflector::underscore($class) . '.php',
|
||||
'code' => 500,
|
||||
'base' => '/'
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->{$name})) {
|
||||
if (ClassRegistry::isKeySet($class)) {
|
||||
if (PHP5) {
|
||||
$this->{$name} = ClassRegistry::getObject($class);
|
||||
} else {
|
||||
$this->{$name} =& ClassRegistry::getObject($class);
|
||||
}
|
||||
} else {
|
||||
if (PHP5) {
|
||||
$this->{$name} = new $class;
|
||||
} else {
|
||||
$this->{$name} =& new $class;
|
||||
}
|
||||
ClassRegistry::addObject($class, $this->{$name});
|
||||
if (!empty($plugin)) {
|
||||
ClassRegistry::addObject($plugin.'.'.$class, $this->{$name});
|
||||
}
|
||||
}
|
||||
} elseif (isset($this->{$name}->settings) && isset($this->{$name}->settings[$this->modelName])) {
|
||||
if ($config !== null && $config !== false) {
|
||||
$config = array_merge($this->{$name}->settings[$this->modelName], $config);
|
||||
} else {
|
||||
$config = array();
|
||||
}
|
||||
}
|
||||
if (empty($config)) {
|
||||
$config = array();
|
||||
}
|
||||
$this->{$name}->setup(ClassRegistry::getObject($this->modelName), $config);
|
||||
|
||||
foreach ($this->{$name}->mapMethods as $method => $alias) {
|
||||
$this->__mappedMethods[$method] = array($alias, $name);
|
||||
}
|
||||
$methods = get_class_methods($this->{$name});
|
||||
$parentMethods = array_flip(get_class_methods('ModelBehavior'));
|
||||
$callbacks = array(
|
||||
'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave',
|
||||
'beforeDelete', 'afterDelete', 'afterError'
|
||||
);
|
||||
|
||||
foreach ($methods as $m) {
|
||||
if (!isset($parentMethods[$m])) {
|
||||
$methodAllowed = (
|
||||
$m[0] != '_' && !array_key_exists($m, $this->__methods) &&
|
||||
!in_array($m, $callbacks)
|
||||
);
|
||||
if ($methodAllowed) {
|
||||
$this->__methods[$m] = array($m, $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($name, $this->_attached)) {
|
||||
$this->_attached[] = $name;
|
||||
}
|
||||
if (in_array($name, $this->_disabled) && !(isset($config['enabled']) && $config['enabled'] === false)) {
|
||||
$this->enable($name);
|
||||
} elseif (isset($config['enabled']) && $config['enabled'] === false) {
|
||||
$this->disable($name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a behavior from a model
|
||||
*
|
||||
* @param string $name CamelCased name of the behavior to unload
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function detach($name) {
|
||||
list($plugin, $name) = pluginSplit($name);
|
||||
if (isset($this->{$name})) {
|
||||
$this->{$name}->cleanup(ClassRegistry::getObject($this->modelName));
|
||||
unset($this->{$name});
|
||||
}
|
||||
foreach ($this->__methods as $m => $callback) {
|
||||
if (is_array($callback) && $callback[1] == $name) {
|
||||
unset($this->__methods[$m]);
|
||||
}
|
||||
}
|
||||
$this->_attached = array_values(array_diff($this->_attached, (array)$name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables callbacks on a behavior or array of behaviors
|
||||
*
|
||||
* @param mixed $name CamelCased name of the behavior(s) to enable (string or array)
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function enable($name) {
|
||||
$this->_disabled = array_diff($this->_disabled, (array)$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables callbacks on a behavior or array of behaviors. Public behavior methods are still
|
||||
* callable as normal.
|
||||
*
|
||||
* @param mixed $name CamelCased name of the behavior(s) to disable (string or array)
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function disable($name) {
|
||||
foreach ((array)$name as $behavior) {
|
||||
if (in_array($behavior, $this->_attached) && !in_array($behavior, $this->_disabled)) {
|
||||
$this->_disabled[] = $behavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of currently-enabled behaviors, or, the current status of a single behavior
|
||||
*
|
||||
* @param string $name Optional. The name of the behavior to check the status of. If omitted,
|
||||
* returns an array of currently-enabled behaviors
|
||||
* @return mixed If $name is specified, returns the boolean status of the corresponding behavior.
|
||||
* Otherwise, returns an array of all enabled behaviors.
|
||||
* @access public
|
||||
*/
|
||||
function enabled($name = null) {
|
||||
if (!empty($name)) {
|
||||
return (in_array($name, $this->_attached) && !in_array($name, $this->_disabled));
|
||||
}
|
||||
return array_diff($this->_attached, $this->_disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a behavior method
|
||||
*
|
||||
* @return array All methods for all behaviors attached to this object
|
||||
* @access public
|
||||
*/
|
||||
function dispatchMethod(&$model, $method, $params = array(), $strict = false) {
|
||||
$methods = array_keys($this->__methods);
|
||||
foreach ($methods as $key => $value) {
|
||||
$methods[$key] = strtolower($value);
|
||||
}
|
||||
$method = strtolower($method);
|
||||
$check = array_flip($methods);
|
||||
$found = isset($check[$method]);
|
||||
$call = null;
|
||||
|
||||
if ($strict && !$found) {
|
||||
trigger_error(sprintf(__("BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior", true), $method), E_USER_WARNING);
|
||||
return null;
|
||||
} elseif ($found) {
|
||||
$methods = array_combine($methods, array_values($this->__methods));
|
||||
$call = $methods[$method];
|
||||
} else {
|
||||
$count = count($this->__mappedMethods);
|
||||
$mapped = array_keys($this->__mappedMethods);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (preg_match($mapped[$i] . 'i', $method)) {
|
||||
$call = $this->__mappedMethods[$mapped[$i]];
|
||||
array_unshift($params, $method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($call)) {
|
||||
return $this->{$call[1]}->dispatchMethod($model, $call[0], $params);
|
||||
}
|
||||
return array('unhandled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a behavior callback on all attached behavior objects
|
||||
*
|
||||
* @param model $model
|
||||
* @param string $callback
|
||||
* @param array $params
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function trigger(&$model, $callback, $params = array(), $options = array()) {
|
||||
if (empty($this->_attached)) {
|
||||
return true;
|
||||
}
|
||||
$options = array_merge(array('break' => false, 'breakOn' => array(null, false), 'modParams' => false), $options);
|
||||
$count = count($this->_attached);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$name = $this->_attached[$i];
|
||||
if (in_array($name, $this->_disabled)) {
|
||||
continue;
|
||||
}
|
||||
$result = $this->{$name}->dispatchMethod($model, $callback, $params);
|
||||
|
||||
if ($options['break'] && ($result === $options['breakOn'] || (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true)))) {
|
||||
return $result;
|
||||
} elseif ($options['modParams'] && is_array($result)) {
|
||||
$params[0] = $result;
|
||||
}
|
||||
}
|
||||
if ($options['modParams'] && isset($params[0])) {
|
||||
return $params[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method list for attached behaviors, i.e. all public, non-callback methods
|
||||
*
|
||||
* @return array All public methods for all behaviors attached to this collection
|
||||
* @access public
|
||||
*/
|
||||
function methods() {
|
||||
return $this->__methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of attached behaviors, or, whether the given behavior is attached
|
||||
*
|
||||
* @param string $name Optional. The name of the behavior to check the status of. If omitted,
|
||||
* returns an array of currently-attached behaviors
|
||||
* @return mixed If $name is specified, returns the boolean status of the corresponding behavior.
|
||||
* Otherwise, returns an array of all attached behaviors.
|
||||
* @access public
|
||||
*/
|
||||
function attached($name = null) {
|
||||
if (!empty($name)) {
|
||||
return (in_array($name, $this->_attached));
|
||||
}
|
||||
return $this->_attached;
|
||||
}
|
||||
}
|
||||
1172
web-cake/html/cake/libs/multibyte.php
Normal file
1172
web-cake/html/cake/libs/multibyte.php
Normal file
File diff suppressed because it is too large
Load Diff
298
web-cake/html/cake/libs/object.php
Normal file
298
web-cake/html/cake/libs/object.php
Normal file
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
/**
|
||||
* Object class, allowing __construct and __destruct in PHP4.
|
||||
*
|
||||
* Also includes methods for logging and the special method RequestAction,
|
||||
* to call other Controllers' Actions from anywhere.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object class, allowing __construct and __destruct in PHP4.
|
||||
*
|
||||
* Also includes methods for logging and the special method RequestAction,
|
||||
* to call other Controllers' Actions from anywhere.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Object {
|
||||
|
||||
/**
|
||||
* A hack to support __construct() on PHP 4
|
||||
* Hint: descendant classes have no PHP4 class_name() constructors,
|
||||
* so this constructor gets called first and calls the top-layer __construct()
|
||||
* which (if present) should call parent::__construct()
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
function Object() {
|
||||
$args = func_get_args();
|
||||
if (method_exists($this, '__destruct')) {
|
||||
register_shutdown_function (array(&$this, '__destruct'));
|
||||
}
|
||||
call_user_func_array(array(&$this, '__construct'), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor, overridden in descendant classes.
|
||||
*/
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Object-to-string conversion.
|
||||
* Each class can override this method as necessary.
|
||||
*
|
||||
* @return string The name of this class
|
||||
* @access public
|
||||
*/
|
||||
function toString() {
|
||||
$class = get_class($this);
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a controller's method from any location. Can be used to connect controllers together
|
||||
* or tie plugins into a main application. requestAction can be used to return rendered views
|
||||
* or fetch the return value from controller actions.
|
||||
*
|
||||
* @param mixed $url String or array-based url.
|
||||
* @param array $extra if array includes the key "return" it sets the AutoRender to true.
|
||||
* @return mixed Boolean true or false on success/failure, or contents
|
||||
* of rendered action if 'return' is set in $extra.
|
||||
* @access public
|
||||
*/
|
||||
function requestAction($url, $extra = array()) {
|
||||
if (empty($url)) {
|
||||
return false;
|
||||
}
|
||||
if (!class_exists('dispatcher')) {
|
||||
require CAKE . 'dispatcher.php';
|
||||
}
|
||||
if (in_array('return', $extra, true)) {
|
||||
$extra = array_merge($extra, array('return' => 0, 'autoRender' => 1));
|
||||
}
|
||||
if (is_array($url) && !isset($extra['url'])) {
|
||||
$extra['url'] = array();
|
||||
}
|
||||
$params = array_merge(array('autoRender' => 0, 'return' => 1, 'bare' => 1, 'requested' => 1), $extra);
|
||||
$dispatcher = new Dispatcher;
|
||||
return $dispatcher->dispatch($url, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a method on this object with the given parameters. Provides an OO wrapper
|
||||
* for `call_user_func_array`
|
||||
*
|
||||
* @param string $method Name of the method to call
|
||||
* @param array $params Parameter list to use when calling $method
|
||||
* @return mixed Returns the result of the method call
|
||||
* @access public
|
||||
*/
|
||||
function dispatchMethod($method, $params = array()) {
|
||||
switch (count($params)) {
|
||||
case 0:
|
||||
return $this->{$method}();
|
||||
case 1:
|
||||
return $this->{$method}($params[0]);
|
||||
case 2:
|
||||
return $this->{$method}($params[0], $params[1]);
|
||||
case 3:
|
||||
return $this->{$method}($params[0], $params[1], $params[2]);
|
||||
case 4:
|
||||
return $this->{$method}($params[0], $params[1], $params[2], $params[3]);
|
||||
case 5:
|
||||
return $this->{$method}($params[0], $params[1], $params[2], $params[3], $params[4]);
|
||||
default:
|
||||
return call_user_func_array(array(&$this, $method), $params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop execution of the current script. Wraps exit() making
|
||||
* testing easier.
|
||||
*
|
||||
* @param $status see http://php.net/exit for values
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function _stop($status = 0) {
|
||||
exit($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convience method to write a message to CakeLog. See CakeLog::write()
|
||||
* for more information on writing to logs.
|
||||
*
|
||||
* @param string $msg Log message
|
||||
* @param integer $type Error type constant. Defined in app/config/core.php.
|
||||
* @return boolean Success of log write
|
||||
* @access public
|
||||
*/
|
||||
function log($msg, $type = LOG_ERROR) {
|
||||
if (!class_exists('CakeLog')) {
|
||||
require LIBS . 'cake_log.php';
|
||||
}
|
||||
if (!is_string($msg)) {
|
||||
$msg = print_r($msg, true);
|
||||
}
|
||||
return CakeLog::write($type, $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting of multiple properties of the object in a single line of code. Will only set
|
||||
* properties that are part of a class declaration.
|
||||
*
|
||||
* @param array $properties An associative array containing properties and corresponding values.
|
||||
* @return void
|
||||
* @access protected
|
||||
*/
|
||||
function _set($properties = array()) {
|
||||
if (is_array($properties) && !empty($properties)) {
|
||||
$vars = get_object_vars($this);
|
||||
foreach ($properties as $key => $val) {
|
||||
if (array_key_exists($key, $vars)) {
|
||||
$this->{$key} = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to report user friendly errors.
|
||||
* If there is a file app/error.php or app/app_error.php this file will be loaded
|
||||
* error.php is the AppError class it should extend ErrorHandler class.
|
||||
*
|
||||
* @param string $method Method to be called in the error class (AppError or ErrorHandler classes)
|
||||
* @param array $messages Message that is to be displayed by the error class
|
||||
* @return error message
|
||||
* @access public
|
||||
*/
|
||||
function cakeError($method, $messages = array()) {
|
||||
if (!class_exists('ErrorHandler')) {
|
||||
App::import('Core', 'Error');
|
||||
|
||||
if (file_exists(APP . 'error.php')) {
|
||||
include_once (APP . 'error.php');
|
||||
} elseif (file_exists(APP . 'app_error.php')) {
|
||||
include_once (APP . 'app_error.php');
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('AppError')) {
|
||||
$error = new AppError($method, $messages);
|
||||
} else {
|
||||
$error = new ErrorHandler($method, $messages);
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for a persistent class file, if found file is opened and true returned
|
||||
* If file is not found a file is created and false returned
|
||||
* If used in other locations of the model you should choose a unique name for the persistent file
|
||||
* There are many uses for this method, see manual for examples
|
||||
*
|
||||
* @param string $name name of the class to persist
|
||||
* @param string $object the object to persist
|
||||
* @return boolean Success
|
||||
* @access protected
|
||||
* @todo add examples to manual
|
||||
*/
|
||||
function _persist($name, $return = null, &$object, $type = null) {
|
||||
$file = CACHE . 'persistent' . DS . strtolower($name) . '.php';
|
||||
if ($return === null) {
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$this->_savePersistent($name, $object);
|
||||
return false;
|
||||
} else {
|
||||
$this->__openPersistent($name, $type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* You should choose a unique name for the persistent file
|
||||
*
|
||||
* There are many uses for this method, see manual for examples
|
||||
*
|
||||
* @param string $name name used for object to cache
|
||||
* @param object $object the object to persist
|
||||
* @return boolean true on save, throws error if file can not be created
|
||||
* @access protected
|
||||
*/
|
||||
function _savePersistent($name, &$object) {
|
||||
$file = 'persistent' . DS . strtolower($name) . '.php';
|
||||
$objectArray = array(&$object);
|
||||
$data = str_replace('\\', '\\\\', serialize($objectArray));
|
||||
$data = '<?php $' . $name . ' = \'' . str_replace('\'', '\\\'', $data) . '\' ?>';
|
||||
$duration = '+999 days';
|
||||
if (Configure::read() >= 1) {
|
||||
$duration = '+10 seconds';
|
||||
}
|
||||
cache($file, $data, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the persistent class file for reading
|
||||
* Used by Object::_persist()
|
||||
*
|
||||
* @param string $name Name of persisted class
|
||||
* @param string $type Type of persistance (e.g: registry)
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __openPersistent($name, $type = null) {
|
||||
$file = CACHE . 'persistent' . DS . strtolower($name) . '.php';
|
||||
include($file);
|
||||
|
||||
switch ($type) {
|
||||
case 'registry':
|
||||
$vars = unserialize(${$name});
|
||||
foreach ($vars['0'] as $key => $value) {
|
||||
if (strpos($key, '_behavior') !== false) {
|
||||
App::import('Behavior', Inflector::classify(substr($key, 0, -9)));
|
||||
} else {
|
||||
App::import('Model', Inflector::camelize($key));
|
||||
}
|
||||
unset ($value);
|
||||
}
|
||||
unset($vars);
|
||||
$vars = unserialize(${$name});
|
||||
foreach ($vars['0'] as $key => $value) {
|
||||
ClassRegistry::addObject($key, $value);
|
||||
unset ($value);
|
||||
}
|
||||
unset($vars);
|
||||
break;
|
||||
default:
|
||||
$vars = unserialize(${$name});
|
||||
$this->{$name} = $vars['0'];
|
||||
unset($vars);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
web-cake/html/cake/libs/overloadable.php
Normal file
36
web-cake/html/cake/libs/overloadable.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Overload abstraction interface. Merges differences between PHP4 and 5.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overloadable class selector
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load the interface class based on the version of PHP.
|
||||
*
|
||||
*/
|
||||
if (!PHP5) {
|
||||
require(LIBS . 'overloadable_php4.php');
|
||||
} else {
|
||||
require(LIBS . 'overloadable_php5.php');
|
||||
}
|
||||
165
web-cake/html/cake/libs/overloadable_php4.php
Normal file
165
web-cake/html/cake/libs/overloadable_php4.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/**
|
||||
* Overload abstraction interface. Merges differences between PHP4 and 5.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overloadable class selector
|
||||
*
|
||||
* Load the interface class based on the version of PHP.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Overloadable extends Object {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __construct() {
|
||||
$this->overload();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload implementation.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function overload() {
|
||||
if (function_exists('overload')) {
|
||||
if (func_num_args() > 0) {
|
||||
foreach (func_get_args() as $class) {
|
||||
if (is_object($class)) {
|
||||
overload(get_class($class));
|
||||
} elseif (is_string($class)) {
|
||||
overload($class);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overload(get_class($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method handler.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param array $params Parameters to send to method
|
||||
* @param mixed $return Where to store return value from method
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __call($method, $params, &$return) {
|
||||
if (!method_exists($this, 'call__')) {
|
||||
trigger_error(sprintf(__('Magic method handler call__ not defined in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
$return = $this->call__($method, $params);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Overloadable::overload('Overloadable');
|
||||
|
||||
/**
|
||||
* Overloadable2 class selector
|
||||
*
|
||||
* Load the interface class based on the version of PHP.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Overloadable2 extends Object {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function __construct() {
|
||||
$this->overload();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload implementation.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function overload() {
|
||||
if (function_exists('overload')) {
|
||||
if (func_num_args() > 0) {
|
||||
foreach (func_get_args() as $class) {
|
||||
if (is_object($class)) {
|
||||
overload(get_class($class));
|
||||
} elseif (is_string($class)) {
|
||||
overload($class);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overload(get_class($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method handler.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param array $params Parameters to send to method
|
||||
* @param mixed $return Where to store return value from method
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __call($method, $params, &$return) {
|
||||
if (!method_exists($this, 'call__')) {
|
||||
trigger_error(sprintf(__('Magic method handler call__ not defined in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
$return = $this->call__($method, $params);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter.
|
||||
*
|
||||
* @param mixed $name What to get
|
||||
* @param mixed $value Where to store returned value
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __get($name, &$value) {
|
||||
$value = $this->get__($name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter.
|
||||
*
|
||||
* @param mixed $name What to set
|
||||
* @param mixed $value Value to set
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __set($name, $value) {
|
||||
$this->set__($name, $value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Overloadable::overload('Overloadable2');
|
||||
108
web-cake/html/cake/libs/overloadable_php5.php
Normal file
108
web-cake/html/cake/libs/overloadable_php5.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* Overload abstraction interface. Merges differences between PHP4 and 5.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overloadable class selector
|
||||
*
|
||||
* Load the interface class based on the version of PHP.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Overloadable extends Object {
|
||||
|
||||
/**
|
||||
* Overload implementation. No need for implementation in PHP5.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function overload() { }
|
||||
|
||||
/**
|
||||
* Magic method handler.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param array $params Parameters to send to method
|
||||
* @return mixed Return value from method
|
||||
* @access private
|
||||
*/
|
||||
function __call($method, $params) {
|
||||
if (!method_exists($this, 'call__')) {
|
||||
trigger_error(sprintf(__('Magic method handler call__ not defined in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
return $this->call__($method, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloadable2 class selector
|
||||
*
|
||||
* Load the interface class based on the version of PHP.
|
||||
*
|
||||
* @package cake
|
||||
*/
|
||||
class Overloadable2 extends Object {
|
||||
|
||||
/**
|
||||
* Overload implementation. No need for implementation in PHP5.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function overload() { }
|
||||
|
||||
/**
|
||||
* Magic method handler.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param array $params Parameters to send to method
|
||||
* @return mixed Return value from method
|
||||
* @access private
|
||||
*/
|
||||
function __call($method, $params) {
|
||||
if (!method_exists($this, 'call__')) {
|
||||
trigger_error(sprintf(__('Magic method handler call__ not defined in %s', true), get_class($this)), E_USER_ERROR);
|
||||
}
|
||||
return $this->call__($method, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter.
|
||||
*
|
||||
* @param mixed $name What to get
|
||||
* @param mixed $value Where to store returned value
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __get($name) {
|
||||
return $this->get__($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter.
|
||||
*
|
||||
* @param mixed $name What to set
|
||||
* @param mixed $value Value to set
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
*/
|
||||
function __set($name, $value) {
|
||||
return $this->set__($name, $value);
|
||||
}
|
||||
}
|
||||
1645
web-cake/html/cake/libs/router.php
Normal file
1645
web-cake/html/cake/libs/router.php
Normal file
File diff suppressed because it is too large
Load Diff
348
web-cake/html/cake/libs/sanitize.php
Normal file
348
web-cake/html/cake/libs/sanitize.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/**
|
||||
* Washes strings from unwanted noise.
|
||||
*
|
||||
* Helpful methods to make unsafe strings usable.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data Sanitization.
|
||||
*
|
||||
* Removal of alpahnumeric characters, SQL-safe slash-added strings, HTML-friendly strings,
|
||||
* and all of the above on arrays.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Sanitize {
|
||||
|
||||
/**
|
||||
* Removes any non-alphanumeric characters.
|
||||
*
|
||||
* @param string $string String to sanitize
|
||||
* @param array $allowed An array of additional characters that are not to be removed.
|
||||
* @return string Sanitized string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function paranoid($string, $allowed = array()) {
|
||||
$allow = null;
|
||||
if (!empty($allowed)) {
|
||||
foreach ($allowed as $value) {
|
||||
$allow .= "\\$value";
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($string)) {
|
||||
$cleaned = array();
|
||||
foreach ($string as $key => $clean) {
|
||||
$cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $clean);
|
||||
}
|
||||
} else {
|
||||
$cleaned = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $string);
|
||||
}
|
||||
return $cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a string SQL-safe.
|
||||
*
|
||||
* @param string $string String to sanitize
|
||||
* @param string $connection Database connection being used
|
||||
* @return string SQL safe string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function escape($string, $connection = 'default') {
|
||||
$db =& ConnectionManager::getDataSource($connection);
|
||||
if (is_numeric($string) || $string === null || is_bool($string)) {
|
||||
return $string;
|
||||
}
|
||||
$string = substr($db->value($string), 1);
|
||||
$string = substr($string, 0, -1);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given string safe for display as HTML. Renders entities.
|
||||
*
|
||||
* strip_tags() does not validating HTML syntax or structure, so it might strip whole passages
|
||||
* with broken HTML.
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - remove (boolean) if true strips all HTML tags before encoding
|
||||
* - charset (string) the charset used to encode the string
|
||||
* - quotes (int) see http://php.net/manual/en/function.htmlentities.php
|
||||
*
|
||||
* @param string $string String from where to strip tags
|
||||
* @param array $options Array of options to use.
|
||||
* @return string Sanitized string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function html($string, $options = array()) {
|
||||
static $defaultCharset = false;
|
||||
if ($defaultCharset === false) {
|
||||
$defaultCharset = Configure::read('App.encoding');
|
||||
if ($defaultCharset === null) {
|
||||
$defaultCharset = 'UTF-8';
|
||||
}
|
||||
}
|
||||
$default = array(
|
||||
'remove' => false,
|
||||
'charset' => $defaultCharset,
|
||||
'quotes' => ENT_QUOTES
|
||||
);
|
||||
|
||||
$options = array_merge($default, $options);
|
||||
|
||||
if ($options['remove']) {
|
||||
$string = strip_tags($string);
|
||||
}
|
||||
|
||||
return htmlentities($string, $options['quotes'], $options['charset']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips extra whitespace from output
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @return string whitespace sanitized string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function stripWhitespace($str) {
|
||||
$r = preg_replace('/[\n\r\t]+/', '', $str);
|
||||
return preg_replace('/\s{2,}/', ' ', $r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips image tags from output
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @return string Sting with images stripped.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function stripImages($str) {
|
||||
$str = preg_replace('/(<a[^>]*>)(<img[^>]+alt=")([^"]*)("[^>]*>)(<\/a>)/i', '$1$3$5<br />', $str);
|
||||
$str = preg_replace('/(<img[^>]+alt=")([^"]*)("[^>]*>)/i', '$2<br />', $str);
|
||||
$str = preg_replace('/<img[^>]*>/i', '', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips scripts and stylesheets from output
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @return string String with <script>, <style>, <link> elements removed.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function stripScripts($str) {
|
||||
return preg_replace('/(<link[^>]+rel="[^"]*stylesheet"[^>]*>|<img[^>]*>|style="[^"]*")|<script[^>]*>.*?<\/script>|<style[^>]*>.*?<\/style>|<!--.*?-->/is', '', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips extra whitespace, images, scripts and stylesheets from output
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @return string sanitized string
|
||||
* @access public
|
||||
*/
|
||||
function stripAll($str) {
|
||||
$str = Sanitize::stripWhitespace($str);
|
||||
$str = Sanitize::stripImages($str);
|
||||
$str = Sanitize::stripScripts($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the specified tags from output. First parameter is string from
|
||||
* where to remove tags. All subsequent parameters are tags.
|
||||
*
|
||||
* Ex.`$clean = Sanitize::stripTags($dirty, 'b', 'p', 'div');`
|
||||
*
|
||||
* Will remove all `<b>`, `<p>`, and `<div>` tags from the $dirty string.
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @param string $tag Tag to remove (add more parameters as needed)
|
||||
* @return string sanitized String
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function stripTags() {
|
||||
$params = params(func_get_args());
|
||||
$str = $params[0];
|
||||
|
||||
for ($i = 1, $count = count($params); $i < $count; $i++) {
|
||||
$str = preg_replace('/<' . $params[$i] . '\b[^>]*>/i', '', $str);
|
||||
$str = preg_replace('/<\/' . $params[$i] . '[^>]*>/i', '', $str);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes given array or value for safe input. Use the options to specify
|
||||
* the connection to use, and what filters should be applied (with a boolean
|
||||
* value). Valid filters:
|
||||
*
|
||||
* - odd_spaces - removes any non space whitespace characters
|
||||
* - encode - Encode any html entities. Encode must be true for the `remove_html` to work.
|
||||
* - dollar - Escape `$` with `\$`
|
||||
* - carriage - Remove `\r`
|
||||
* - unicode -
|
||||
* - escape - Should the string be SQL escaped.
|
||||
* - backslash -
|
||||
* - remove_html - Strip HTML with strip_tags. `encode` must be true for this option to work.
|
||||
*
|
||||
* @param mixed $data Data to sanitize
|
||||
* @param mixed $options If string, DB connection being used, otherwise set of options
|
||||
* @return mixed Sanitized data
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function clean($data, $options = array()) {
|
||||
if (empty($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (is_string($options)) {
|
||||
$options = array('connection' => $options);
|
||||
} else if (!is_array($options)) {
|
||||
$options = array();
|
||||
}
|
||||
|
||||
$options = array_merge(array(
|
||||
'connection' => 'default',
|
||||
'odd_spaces' => true,
|
||||
'remove_html' => false,
|
||||
'encode' => true,
|
||||
'dollar' => true,
|
||||
'carriage' => true,
|
||||
'unicode' => true,
|
||||
'escape' => true,
|
||||
'backslash' => true
|
||||
), $options);
|
||||
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $val) {
|
||||
$data[$key] = Sanitize::clean($val, $options);
|
||||
}
|
||||
return $data;
|
||||
} else {
|
||||
if ($options['odd_spaces']) {
|
||||
$data = str_replace(chr(0xCA), '', str_replace(' ', ' ', $data));
|
||||
}
|
||||
if ($options['encode']) {
|
||||
$data = Sanitize::html($data, array('remove' => $options['remove_html']));
|
||||
}
|
||||
if ($options['dollar']) {
|
||||
$data = str_replace("\\\$", "$", $data);
|
||||
}
|
||||
if ($options['carriage']) {
|
||||
$data = str_replace("\r", "", $data);
|
||||
}
|
||||
|
||||
$data = str_replace("'", "'", str_replace("!", "!", $data));
|
||||
|
||||
if ($options['unicode']) {
|
||||
$data = preg_replace("/&#([0-9]+);/s", "&#\\1;", $data);
|
||||
}
|
||||
if ($options['escape']) {
|
||||
$data = Sanitize::escape($data, $options['connection']);
|
||||
}
|
||||
if ($options['backslash']) {
|
||||
$data = preg_replace("/\\\(?!&#|\?#)/", "\\", $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats column data from definition in DBO's $columns array
|
||||
*
|
||||
* @param Model $model The model containing the data to be formatted
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function formatColumns(&$model) {
|
||||
foreach ($model->data as $name => $values) {
|
||||
if ($name == $model->alias) {
|
||||
$curModel =& $model;
|
||||
} elseif (isset($model->{$name}) && is_object($model->{$name}) && is_subclass_of($model->{$name}, 'Model')) {
|
||||
$curModel =& $model->{$name};
|
||||
} else {
|
||||
$curModel = null;
|
||||
}
|
||||
|
||||
if ($curModel != null) {
|
||||
foreach ($values as $column => $data) {
|
||||
$colType = $curModel->getColumnType($column);
|
||||
|
||||
if ($colType != null) {
|
||||
$db =& ConnectionManager::getDataSource($curModel->useDbConfig);
|
||||
$colData = $db->columns[$colType];
|
||||
|
||||
if (isset($colData['limit']) && strlen(strval($data)) > $colData['limit']) {
|
||||
$data = substr(strval($data), 0, $colData['limit']);
|
||||
}
|
||||
|
||||
if (isset($colData['formatter']) || isset($colData['format'])) {
|
||||
|
||||
switch (strtolower($colData['formatter'])) {
|
||||
case 'date':
|
||||
$data = date($colData['format'], strtotime($data));
|
||||
break;
|
||||
case 'sprintf':
|
||||
$data = sprintf($colData['format'], $data);
|
||||
break;
|
||||
case 'intval':
|
||||
$data = intval($data);
|
||||
break;
|
||||
case 'floatval':
|
||||
$data = floatval($data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$model->data[$name][$column]=$data;
|
||||
/*
|
||||
switch ($colType) {
|
||||
case 'integer':
|
||||
case 'int':
|
||||
return $data;
|
||||
break;
|
||||
case 'string':
|
||||
case 'text':
|
||||
case 'binary':
|
||||
case 'date':
|
||||
case 'time':
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
case 'date':
|
||||
return "'" . $data . "'";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
191
web-cake/html/cake/libs/security.php
Normal file
191
web-cake/html/cake/libs/security.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* Core Security
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v .0.10.0.1233
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Security Library contains utility methods related to security
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Security extends Object {
|
||||
|
||||
/**
|
||||
* Default hash method
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $hashType = null;
|
||||
|
||||
/**
|
||||
* Singleton implementation to get object instance.
|
||||
*
|
||||
* @return object
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &getInstance() {
|
||||
static $instance = array();
|
||||
if (!$instance) {
|
||||
$instance[0] =& new Security;
|
||||
}
|
||||
return $instance[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get allowed minutes of inactivity based on security level.
|
||||
*
|
||||
* @return integer Allowed inactivity in minutes
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function inactiveMins() {
|
||||
switch (Configure::read('Security.level')) {
|
||||
case 'high':
|
||||
return 10;
|
||||
break;
|
||||
case 'medium':
|
||||
return 100;
|
||||
break;
|
||||
case 'low':
|
||||
default:
|
||||
return 300;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate authorization hash.
|
||||
*
|
||||
* @return string Hash
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function generateAuthKey() {
|
||||
if (!class_exists('String')) {
|
||||
App::import('Core', 'String');
|
||||
}
|
||||
return Security::hash(String::uuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate authorization hash.
|
||||
*
|
||||
* @param string $authKey Authorization hash
|
||||
* @return boolean Success
|
||||
* @access public
|
||||
* @static
|
||||
* @todo Complete implementation
|
||||
*/
|
||||
function validateAuthKey($authKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hash from string using given method.
|
||||
* Fallback on next available method.
|
||||
*
|
||||
* @param string $string String to hash
|
||||
* @param string $type Method to use (sha1/sha256/md5)
|
||||
* @param boolean $salt If true, automatically appends the application's salt
|
||||
* value to $string (Security.salt)
|
||||
* @return string Hash
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function hash($string, $type = null, $salt = false) {
|
||||
$_this =& Security::getInstance();
|
||||
|
||||
if ($salt) {
|
||||
if (is_string($salt)) {
|
||||
$string = $salt . $string;
|
||||
} else {
|
||||
$string = Configure::read('Security.salt') . $string;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($type)) {
|
||||
$type = $_this->hashType;
|
||||
}
|
||||
$type = strtolower($type);
|
||||
|
||||
if ($type == 'sha1' || $type == null) {
|
||||
if (function_exists('sha1')) {
|
||||
$return = sha1($string);
|
||||
return $return;
|
||||
}
|
||||
$type = 'sha256';
|
||||
}
|
||||
|
||||
if ($type == 'sha256' && function_exists('mhash')) {
|
||||
return bin2hex(mhash(MHASH_SHA256, $string));
|
||||
}
|
||||
|
||||
if (function_exists('hash')) {
|
||||
return hash($type, $string);
|
||||
}
|
||||
return md5($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default hash method for the Security object. This affects all objects using
|
||||
* Security::hash().
|
||||
*
|
||||
* @param string $hash Method to use (sha1/sha256/md5)
|
||||
* @access public
|
||||
* @return void
|
||||
* @static
|
||||
* @see Security::hash()
|
||||
*/
|
||||
function setHash($hash) {
|
||||
$_this =& Security::getInstance();
|
||||
$_this->hashType = $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts/Decrypts a text using the given key.
|
||||
*
|
||||
* @param string $text Encrypted string to decrypt, normal string to encrypt
|
||||
* @param string $key Key to use
|
||||
* @return string Encrypted/Decrypted string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function cipher($text, $key) {
|
||||
if (empty($key)) {
|
||||
trigger_error(__('You cannot use an empty key for Security::cipher()', true), E_USER_WARNING);
|
||||
return '';
|
||||
}
|
||||
|
||||
srand(Configure::read('Security.cipherSeed'));
|
||||
$out = '';
|
||||
$keyLength = strlen($key);
|
||||
for ($i = 0, $textLength = strlen($text); $i < $textLength; $i++) {
|
||||
$j = ord(substr($key, $i % $keyLength, 1));
|
||||
while ($j--) {
|
||||
rand(0, 255);
|
||||
}
|
||||
$mask = rand(0, 255);
|
||||
$out .= chr(ord(substr($text, $i, 1)) ^ $mask);
|
||||
}
|
||||
srand();
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
1152
web-cake/html/cake/libs/set.php
Normal file
1152
web-cake/html/cake/libs/set.php
Normal file
File diff suppressed because it is too large
Load Diff
329
web-cake/html/cake/libs/string.php
Normal file
329
web-cake/html/cake/libs/string.php
Normal file
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
/**
|
||||
* String handling methods.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP(tm) v 1.2.0.5551
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* String handling methods.
|
||||
*
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class String {
|
||||
|
||||
/**
|
||||
* Generate a random UUID
|
||||
*
|
||||
* @see http://www.ietf.org/rfc/rfc4122.txt
|
||||
* @return RFC 4122 UUID
|
||||
* @static
|
||||
*/
|
||||
function uuid() {
|
||||
$node = env('SERVER_ADDR');
|
||||
$pid = null;
|
||||
|
||||
if (strpos($node, ':') !== false) {
|
||||
if (substr_count($node, '::')) {
|
||||
$node = str_replace(
|
||||
'::', str_repeat(':0000', 8 - substr_count($node, ':')) . ':', $node
|
||||
);
|
||||
}
|
||||
$node = explode(':', $node) ;
|
||||
$ipv6 = '' ;
|
||||
|
||||
foreach ($node as $id) {
|
||||
$ipv6 .= str_pad(base_convert($id, 16, 2), 16, 0, STR_PAD_LEFT);
|
||||
}
|
||||
$node = base_convert($ipv6, 2, 10);
|
||||
|
||||
if (strlen($node) < 38) {
|
||||
$node = null;
|
||||
} else {
|
||||
$node = crc32($node);
|
||||
}
|
||||
} elseif (empty($node)) {
|
||||
$host = env('HOSTNAME');
|
||||
|
||||
if (empty($host)) {
|
||||
$host = env('HOST');
|
||||
}
|
||||
|
||||
if (!empty($host)) {
|
||||
$ip = gethostbyname($host);
|
||||
|
||||
if ($ip === $host) {
|
||||
$node = crc32($host);
|
||||
} else {
|
||||
$node = ip2long($ip);
|
||||
}
|
||||
}
|
||||
} elseif ($node !== '127.0.0.1') {
|
||||
$node = ip2long($node);
|
||||
} else {
|
||||
$node = null;
|
||||
}
|
||||
|
||||
if (empty($node)) {
|
||||
$node = crc32(Configure::read('Security.salt'));
|
||||
}
|
||||
|
||||
if (function_exists('zend_thread_id')) {
|
||||
$pid = zend_thread_id();
|
||||
} else {
|
||||
$pid = getmypid();
|
||||
}
|
||||
|
||||
if (!$pid || $pid > 65535) {
|
||||
$pid = mt_rand(0, 0xfff) | 0x4000;
|
||||
}
|
||||
|
||||
list($timeMid, $timeLow) = explode(' ', microtime());
|
||||
$uuid = sprintf(
|
||||
"%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff,
|
||||
mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node
|
||||
);
|
||||
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a string using $separator, ignoring any instance of $separator that appears between
|
||||
* $leftBound and $rightBound
|
||||
*
|
||||
* @param string $data The data to tokenize
|
||||
* @param string $separator The token to split the data on.
|
||||
* @param string $leftBound The left boundary to ignore separators in.
|
||||
* @param string $rightBound The right boundary to ignore separators in.
|
||||
* @return array Array of tokens in $data.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function tokenize($data, $separator = ',', $leftBound = '(', $rightBound = ')') {
|
||||
if (empty($data) || is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$depth = 0;
|
||||
$offset = 0;
|
||||
$buffer = '';
|
||||
$results = array();
|
||||
$length = strlen($data);
|
||||
$open = false;
|
||||
|
||||
while ($offset <= $length) {
|
||||
$tmpOffset = -1;
|
||||
$offsets = array(
|
||||
strpos($data, $separator, $offset),
|
||||
strpos($data, $leftBound, $offset),
|
||||
strpos($data, $rightBound, $offset)
|
||||
);
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) {
|
||||
$tmpOffset = $offsets[$i];
|
||||
}
|
||||
}
|
||||
if ($tmpOffset !== -1) {
|
||||
$buffer .= substr($data, $offset, ($tmpOffset - $offset));
|
||||
if ($data{$tmpOffset} == $separator && $depth == 0) {
|
||||
$results[] = $buffer;
|
||||
$buffer = '';
|
||||
} else {
|
||||
$buffer .= $data{$tmpOffset};
|
||||
}
|
||||
if ($leftBound != $rightBound) {
|
||||
if ($data{$tmpOffset} == $leftBound) {
|
||||
$depth++;
|
||||
}
|
||||
if ($data{$tmpOffset} == $rightBound) {
|
||||
$depth--;
|
||||
}
|
||||
} else {
|
||||
if ($data{$tmpOffset} == $leftBound) {
|
||||
if (!$open) {
|
||||
$depth++;
|
||||
$open = true;
|
||||
} else {
|
||||
$depth--;
|
||||
$open = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$offset = ++$tmpOffset;
|
||||
} else {
|
||||
$results[] = $buffer . substr($data, $offset);
|
||||
$offset = $length + 1;
|
||||
}
|
||||
}
|
||||
if (empty($results) && !empty($buffer)) {
|
||||
$results[] = $buffer;
|
||||
}
|
||||
|
||||
if (!empty($results)) {
|
||||
$data = array_map('trim', $results);
|
||||
} else {
|
||||
$data = array();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces variable placeholders inside a $str with any given $data. Each key in the $data array
|
||||
* corresponds to a variable placeholder name in $str.
|
||||
* Example: `String::insert(':name is :age years old.', array('name' => 'Bob', '65'));`
|
||||
* Returns: Bob is 65 years old.
|
||||
*
|
||||
* Available $options are:
|
||||
*
|
||||
* - before: The character or string in front of the name of the variable placeholder (Defaults to `:`)
|
||||
* - after: The character or string after the name of the variable placeholder (Defaults to null)
|
||||
* - escape: The character or string used to escape the before character / string (Defaults to `\`)
|
||||
* - format: A regex to use for matching variable placeholders. Default is: `/(?<!\\)\:%s/`
|
||||
* (Overwrites before, after, breaks escape / clean)
|
||||
* - clean: A boolean or array with instructions for String::cleanInsert
|
||||
*
|
||||
* @param string $str A string containing variable placeholders
|
||||
* @param string $data A key => val array where each key stands for a placeholder variable name
|
||||
* to be replaced with val
|
||||
* @param string $options An array of options, see description above
|
||||
* @return string
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function insert($str, $data, $options = array()) {
|
||||
$defaults = array(
|
||||
'before' => ':', 'after' => null, 'escape' => '\\', 'format' => null, 'clean' => false
|
||||
);
|
||||
$options += $defaults;
|
||||
$format = $options['format'];
|
||||
$data = (array)$data;
|
||||
if (empty($data)) {
|
||||
return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
|
||||
}
|
||||
|
||||
if (!isset($format)) {
|
||||
$format = sprintf(
|
||||
'/(?<!%s)%s%%s%s/',
|
||||
preg_quote($options['escape'], '/'),
|
||||
str_replace('%', '%%', preg_quote($options['before'], '/')),
|
||||
str_replace('%', '%%', preg_quote($options['after'], '/'))
|
||||
);
|
||||
}
|
||||
|
||||
if (strpos($str, '?') !== false && is_numeric(key($data))) {
|
||||
$offset = 0;
|
||||
while (($pos = strpos($str, '?', $offset)) !== false) {
|
||||
$val = array_shift($data);
|
||||
$offset = $pos + strlen($val);
|
||||
$str = substr_replace($str, $val, $pos, 1);
|
||||
}
|
||||
return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
|
||||
} else {
|
||||
asort($data);
|
||||
|
||||
$hashKeys = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$hashKeys[] = crc32($key);
|
||||
}
|
||||
|
||||
$tempData = array_combine(array_keys($data), array_values($hashKeys));
|
||||
krsort($tempData);
|
||||
foreach ($tempData as $key => $hashVal) {
|
||||
$key = sprintf($format, preg_quote($key, '/'));
|
||||
$str = preg_replace($key, $hashVal, $str);
|
||||
}
|
||||
$dataReplacements = array_combine($hashKeys, array_values($data));
|
||||
foreach ($dataReplacements as $tmpHash => $tmpValue) {
|
||||
$tmpValue = (is_array($tmpValue)) ? '' : $tmpValue;
|
||||
$str = str_replace($tmpHash, $tmpValue, $str);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options['format']) && isset($options['before'])) {
|
||||
$str = str_replace($options['escape'].$options['before'], $options['before'], $str);
|
||||
}
|
||||
return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up a String::insert() formated string with given $options depending on the 'clean' key in
|
||||
* $options. The default method used is text but html is also available. The goal of this function
|
||||
* is to replace all whitespace and uneeded markup around placeholders that did not get replaced
|
||||
* by String::insert().
|
||||
*
|
||||
* @param string $str
|
||||
* @param string $options
|
||||
* @return string
|
||||
* @access public
|
||||
* @static
|
||||
* @see String::insert()
|
||||
*/
|
||||
function cleanInsert($str, $options) {
|
||||
$clean = $options['clean'];
|
||||
if (!$clean) {
|
||||
return $str;
|
||||
}
|
||||
if ($clean === true) {
|
||||
$clean = array('method' => 'text');
|
||||
}
|
||||
if (!is_array($clean)) {
|
||||
$clean = array('method' => $options['clean']);
|
||||
}
|
||||
switch ($clean['method']) {
|
||||
case 'html':
|
||||
$clean = array_merge(array(
|
||||
'word' => '[\w,.]+',
|
||||
'andText' => true,
|
||||
'replacement' => '',
|
||||
), $clean);
|
||||
$kleenex = sprintf(
|
||||
'/[\s]*[a-z]+=(")(%s%s%s[\s]*)+\\1/i',
|
||||
preg_quote($options['before'], '/'),
|
||||
$clean['word'],
|
||||
preg_quote($options['after'], '/')
|
||||
);
|
||||
$str = preg_replace($kleenex, $clean['replacement'], $str);
|
||||
if ($clean['andText']) {
|
||||
$options['clean'] = array('method' => 'text');
|
||||
$str = String::cleanInsert($str, $options);
|
||||
}
|
||||
break;
|
||||
case 'text':
|
||||
$clean = array_merge(array(
|
||||
'word' => '[\w,.]+',
|
||||
'gap' => '[\s]*(?:(?:and|or)[\s]*)?',
|
||||
'replacement' => '',
|
||||
), $clean);
|
||||
|
||||
$kleenex = sprintf(
|
||||
'/(%s%s%s%s|%s%s%s%s)/',
|
||||
preg_quote($options['before'], '/'),
|
||||
$clean['word'],
|
||||
preg_quote($options['after'], '/'),
|
||||
$clean['gap'],
|
||||
$clean['gap'],
|
||||
preg_quote($options['before'], '/'),
|
||||
$clean['word'],
|
||||
preg_quote($options['after'], '/')
|
||||
);
|
||||
$str = preg_replace($kleenex, $clean['replacement'], $str);
|
||||
break;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
1060
web-cake/html/cake/libs/validation.php
Normal file
1060
web-cake/html/cake/libs/validation.php
Normal file
File diff suppressed because it is too large
Load Diff
26
web-cake/html/cake/libs/view/elements/email/html/default.ctp
Normal file
26
web-cake/html/cake/libs/view/elements/email/html/default.ctp
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.elements.email.html
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
$content = explode("\n", $content);
|
||||
|
||||
foreach ($content as $line):
|
||||
echo '<p> ' . $line . '</p>';
|
||||
endforeach;
|
||||
?>
|
||||
20
web-cake/html/cake/libs/view/elements/email/text/default.ctp
Normal file
20
web-cake/html/cake/libs/view/elements/email/text/default.ctp
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.elements.email.text
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<?php echo $content; ?>
|
||||
61
web-cake/html/cake/libs/view/elements/sql_dump.ctp
Normal file
61
web-cake/html/cake/libs/view/elements/sql_dump.ctp
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* SQL Dump element. Dumps out SQL log information
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.elements
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
if (!class_exists('ConnectionManager') || Configure::read('debug') < 2) {
|
||||
return false;
|
||||
}
|
||||
$noLogs = !isset($logs);
|
||||
if ($noLogs):
|
||||
$sources = ConnectionManager::sourceList();
|
||||
|
||||
$logs = array();
|
||||
foreach ($sources as $source):
|
||||
$db =& ConnectionManager::getDataSource($source);
|
||||
if (!$db->isInterfaceSupported('getLog')):
|
||||
continue;
|
||||
endif;
|
||||
$logs[$source] = $db->getLog();
|
||||
endforeach;
|
||||
endif;
|
||||
|
||||
if ($noLogs || isset($_forced_from_dbo_)):
|
||||
foreach ($logs as $source => $logInfo):
|
||||
$text = $logInfo['count'] > 1 ? 'queries' : 'query';
|
||||
printf(
|
||||
'<table class="cake-sql-log" id="cakeSqlLog_%s" summary="Cake SQL Log" cellspacing="0" border = "0">',
|
||||
preg_replace('/[^A-Za-z0-9_]/', '_', uniqid(time(), true))
|
||||
);
|
||||
printf('<caption>(%s) %s %s took %s ms</caption>', $source, $logInfo['count'], $text, $logInfo['time']);
|
||||
?>
|
||||
<thead>
|
||||
<tr><th>Nr</th><th>Query</th><th>Error</th><th>Affected</th><th>Num. rows</th><th>Took (ms)</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($logInfo['log'] as $k => $i) :
|
||||
echo "<tr><td>" . ($k + 1) . "</td><td>" . h($i['query']) . "</td><td>{$i['error']}</td><td style = \"text-align: right\">{$i['affected']}</td><td style = \"text-align: right\">{$i['numRows']}</td><td style = \"text-align: right\">{$i['took']}</td></tr>\n";
|
||||
endforeach;
|
||||
?>
|
||||
</tbody></table>
|
||||
<?php
|
||||
endforeach;
|
||||
else:
|
||||
echo '<p>Encountered unexpected $logs cannot generate SQL log</p>';
|
||||
endif;
|
||||
?>
|
||||
24
web-cake/html/cake/libs/view/errors/error404.ctp
Normal file
24
web-cake/html/cake/libs/view/errors/error404.ctp
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php echo $name; ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The requested address %s was not found on this server.', true), "<strong>'{$message}'</strong>"); ?>
|
||||
</p>
|
||||
24
web-cake/html/cake/libs/view/errors/error500.ctp
Normal file
24
web-cake/html/cake/libs/view/errors/error500.ctp
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php echo $name; ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('An Internal Error Has Occurred.', true), "<strong>'{$message}'</strong>"); ?>
|
||||
</p>
|
||||
46
web-cake/html/cake/libs/view/errors/missing_action.ctp
Normal file
46
web-cake/html/cake/libs/view/errors/missing_action.ctp
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php printf(__('Missing Method in %s', true), $controller); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The action %1$s is not defined in controller %2$s', true), '<em>' . $action . '</em>', '<em>' . $controller . '</em>'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create %1$s%2$s in file: %3$s.', true), '<em>' . $controller . '::</em>', '<em>' . $action . '()</em>', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $controller;?> extends AppController {
|
||||
|
||||
var $name = '<?php echo $controllerName;?>';
|
||||
|
||||
<strong>
|
||||
function <?php echo $action;?>() {
|
||||
|
||||
}
|
||||
</strong>
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_action.ctp'); ?>
|
||||
</p>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Behavior Class'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The behavior class <em>%s</em> can not be found or does not exist.', true), $behaviorClass); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class below in file: %s', true), APP_DIR . DS . 'models' . DS . 'behaviors' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $behaviorClass;?> extends ModelBehavior {
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_behavior_class.ctp'); ?>
|
||||
</p>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Behavior File'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The Behavior file %s can not be found or does not exist.', true), APP_DIR . DS . 'models' . DS . 'behaviors' . DS . $file); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class below in file: %s', true), APP_DIR . DS . 'models' . DS . 'behaviors' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $behaviorClass;?> extends ModelBehavior {
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_behavior_file.ctp'); ?>
|
||||
</p>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Component Class'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Component class %1$s in %2$s was not found.', true), '<em>' . $component . 'Component</em>', '<em>' . $controller . 'Controller</em>'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class %s in file: %s', true), '<em>' . $component . 'Component</em>', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $component;?>Component extends Object {<br />
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_component_class.ctp'); ?>
|
||||
</p>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Component File'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php __('The component file was not found.'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class %s in file: %s', true), '<em>' . $component . 'Component</em>', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $component;?>Component extends Object {<br />
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_component_file.ctp'); ?>
|
||||
</p>
|
||||
32
web-cake/html/cake/libs/view/errors/missing_connection.ctp
Normal file
32
web-cake/html/cake/libs/view/errors/missing_connection.ctp
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Database Connection'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('%s requires a database connection', true), $model); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Confirm you have created the file : %s.', true), APP_DIR . DS . 'config' . DS . 'database.php'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s.', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . basename(__FILE__)); ?>
|
||||
</p>
|
||||
40
web-cake/html/cake/libs/view/errors/missing_controller.ctp
Normal file
40
web-cake/html/cake/libs/view/errors/missing_controller.ctp
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Controller'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('%s could not be found.', true), '<em>' . $controller . '</em>'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class %s below in file: %s', true), '<em>' . $controller . '</em>', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $controller;?> extends AppController {
|
||||
|
||||
var $name = '<?php echo $controllerName;?>';
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_controller.ctp'); ?>
|
||||
</p>
|
||||
39
web-cake/html/cake/libs/view/errors/missing_helper_class.ctp
Normal file
39
web-cake/html/cake/libs/view/errors/missing_helper_class.ctp
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Helper Class'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The helper class <em>%s</em> can not be found or does not exist.', true), $helperClass); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class below in file: %s', true), APP_DIR . DS . 'views' . DS . 'helpers' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $helperClass;?> extends AppHelper {
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_helper_class.ctp'); ?>
|
||||
</p>
|
||||
39
web-cake/html/cake/libs/view/errors/missing_helper_file.ctp
Normal file
39
web-cake/html/cake/libs/view/errors/missing_helper_file.ctp
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Helper File'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The helper file %s can not be found or does not exist.', true), APP_DIR . DS . 'views' . DS . 'helpers' . DS . $file); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class below in file: %s', true), APP_DIR . DS . 'views' . DS . 'helpers' . DS . $file); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $helperClass;?> extends AppHelper {
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_helper_file.ctp'); ?>
|
||||
</p>
|
||||
32
web-cake/html/cake/libs/view/errors/missing_layout.ctp
Normal file
32
web-cake/html/cake/libs/view/errors/missing_layout.ctp
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Layout'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The layout file %s can not be found or does not exist.', true), '<em>' . $file . '</em>'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Confirm you have created the file: %s', true), '<em>' . $file . '</em>'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_layout.ctp'); ?>
|
||||
</p>
|
||||
41
web-cake/html/cake/libs/view/errors/missing_model.ctp
Normal file
41
web-cake/html/cake/libs/view/errors/missing_model.ctp
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Model'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('<em>%s</em> could not be found.', true), $model); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Create the class %s in file: %s', true), '<em>' . $model . '</em>', APP_DIR . DS . 'models' . DS . Inflector::underscore($model) . '.php'); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
class <?php echo $model;?> extends AppModel {
|
||||
|
||||
var $name = '<?php echo $model;?>';
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_model.ctp'); ?>
|
||||
</p>
|
||||
32
web-cake/html/cake/libs/view/errors/missing_scaffolddb.ctp
Normal file
32
web-cake/html/cake/libs/view/errors/missing_scaffolddb.ctp
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Database Connection'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php __('Scaffold requires a database connection'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Confirm you have created the file: %s', true), APP_DIR . DS . 'config' . DS . 'database.php'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_scaffolddb.ctp'); ?>
|
||||
</p>
|
||||
28
web-cake/html/cake/libs/view/errors/missing_table.ctp
Normal file
28
web-cake/html/cake/libs/view/errors/missing_table.ctp
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing Database Table'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Database table %1$s for model %2$s was not found.', true), '<em>' . $table . '</em>', '<em>' . $model . '</em>'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_table.ctp'); ?>
|
||||
</p>
|
||||
32
web-cake/html/cake/libs/view/errors/missing_view.ctp
Normal file
32
web-cake/html/cake/libs/view/errors/missing_view.ctp
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Missing View'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('The view for %1$s%2$s was not found.', true), '<em>' . $controller . 'Controller::</em>', '<em>' . $action . '()</em>'); ?>
|
||||
</p>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('Confirm you have created the file: %s', true), $file); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'missing_view.ctp'); ?>
|
||||
</p>
|
||||
28
web-cake/html/cake/libs/view/errors/private_action.ctp
Normal file
28
web-cake/html/cake/libs/view/errors/private_action.ctp
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php printf(__('Private Method in %s', true), $controller); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php printf(__('%s%s cannot be accessed directly.', true), '<em>' . $controller . '::</em>', '<em>' . $action . '()</em>'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'private_action.ctp'); ?>
|
||||
</p>
|
||||
35
web-cake/html/cake/libs/view/errors/scaffold_error.ctp
Normal file
35
web-cake/html/cake/libs/view/errors/scaffold_error.ctp
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.templates.errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
?>
|
||||
<h2><?php __('Scaffold Error'); ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php __('Error'); ?>: </strong>
|
||||
<?php __('Method _scaffoldError in was not found in the controller'); ?>
|
||||
</p>
|
||||
<p class="notice">
|
||||
<strong><?php __('Notice'); ?>: </strong>
|
||||
<?php printf(__('If you want to customize this error message, create %s', true), APP_DIR . DS . 'views' . DS . 'errors' . DS . 'scaffold_error.ctp'); ?>
|
||||
</p>
|
||||
<pre>
|
||||
<?php
|
||||
function _scaffoldError() {<br />
|
||||
|
||||
}
|
||||
?>
|
||||
</pre>
|
||||
912
web-cake/html/cake/libs/view/helper.php
Normal file
912
web-cake/html/cake/libs/view/helper.php
Normal file
@@ -0,0 +1,912 @@
|
||||
<?php
|
||||
/**
|
||||
* Backend for helpers.
|
||||
*
|
||||
* Internal methods for the Helpers.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libs
|
||||
*/
|
||||
App::import('Core', 'Overloadable');
|
||||
|
||||
/**
|
||||
* Abstract base class for all other Helpers in CakePHP.
|
||||
* Provides common methods and features.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view
|
||||
*/
|
||||
class Helper extends Overloadable {
|
||||
|
||||
/**
|
||||
* List of helpers used by this helper
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $helpers = null;
|
||||
|
||||
/**
|
||||
* Base URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $base = null;
|
||||
|
||||
/**
|
||||
* Webroot path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $webroot = null;
|
||||
|
||||
/**
|
||||
* The current theme name if any.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $theme = null;
|
||||
|
||||
/**
|
||||
* URL to current action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $here = null;
|
||||
|
||||
/**
|
||||
* Parameter array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $params = array();
|
||||
|
||||
/**
|
||||
* Current action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $action = null;
|
||||
|
||||
/**
|
||||
* Plugin path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $plugin = null;
|
||||
|
||||
/**
|
||||
* POST data for models
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $data = null;
|
||||
|
||||
/**
|
||||
* List of named arguments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $namedArgs = null;
|
||||
|
||||
/**
|
||||
* URL argument separator character
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $argSeparator = null;
|
||||
|
||||
/**
|
||||
* Contains model validation errors of form post-backs
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
var $validationErrors = null;
|
||||
|
||||
/**
|
||||
* Holds tag templates.
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
var $tags = array();
|
||||
|
||||
/**
|
||||
* Holds the content to be cleaned.
|
||||
*
|
||||
* @access private
|
||||
* @var mixed
|
||||
*/
|
||||
var $__tainted = null;
|
||||
|
||||
/**
|
||||
* Holds the cleaned content.
|
||||
*
|
||||
* @access private
|
||||
* @var mixed
|
||||
*/
|
||||
var $__cleaned = null;
|
||||
|
||||
/**
|
||||
* Default overload methods
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
function get__($name) {}
|
||||
function set__($name, $value) {}
|
||||
function call__($method, $params) {
|
||||
trigger_error(sprintf(__('Method %1$s::%2$s does not exist', true), get_class($this), $method), E_USER_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses tag templates into $this->tags.
|
||||
*
|
||||
* @param $name file name inside app/config to load.
|
||||
* @return array merged tags from config/$name.php
|
||||
* @access public
|
||||
*/
|
||||
function loadConfig($name = 'tags') {
|
||||
if (file_exists(CONFIGS . $name .'.php')) {
|
||||
require(CONFIGS . $name .'.php');
|
||||
if (isset($tags)) {
|
||||
$this->tags = array_merge($this->tags, $tags);
|
||||
}
|
||||
}
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds URL for specified action.
|
||||
*
|
||||
* Returns a URL pointing at the provided parameters.
|
||||
*
|
||||
* @param mixed $url Either a relative string url like `/products/view/23` or
|
||||
* an array of url parameters. Using an array for urls will allow you to leverage
|
||||
* the reverse routing features of CakePHP.
|
||||
* @param boolean $full If true, the full base URL will be prepended to the result
|
||||
* @return string Full translated URL with base path.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1448/url
|
||||
*/
|
||||
function url($url = null, $full = false) {
|
||||
return h(Router::url($url, $full));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file exists when theme is used, if no file is found default location is returned
|
||||
*
|
||||
* @param string $file The file to create a webroot path to.
|
||||
* @return string Web accessible path to file.
|
||||
* @access public
|
||||
*/
|
||||
function webroot($file) {
|
||||
$asset = explode('?', $file);
|
||||
$asset[1] = isset($asset[1]) ? '?' . $asset[1] : null;
|
||||
$webPath = "{$this->webroot}" . $asset[0];
|
||||
$file = $asset[0];
|
||||
|
||||
if (!empty($this->theme)) {
|
||||
$file = trim($file, '/');
|
||||
$theme = $this->theme . '/';
|
||||
|
||||
if (DS === '\\') {
|
||||
$file = str_replace('/', '\\', $file);
|
||||
}
|
||||
|
||||
if (file_exists(Configure::read('App.www_root') . 'theme' . DS . $this->theme . DS . $file)) {
|
||||
$webPath = "{$this->webroot}theme/" . $theme . $asset[0];
|
||||
} else {
|
||||
$viewPaths = App::path('views');
|
||||
|
||||
foreach ($viewPaths as $viewPath) {
|
||||
$path = $viewPath . 'themed'. DS . $this->theme . DS . 'webroot' . DS . $file;
|
||||
|
||||
if (file_exists($path)) {
|
||||
$webPath = "{$this->webroot}theme/" . $theme . $asset[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strpos($webPath, '//') !== false) {
|
||||
return str_replace('//', '/', $webPath . $asset[1]);
|
||||
}
|
||||
return $webPath . $asset[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a timestamp to a file based resource based on the value of `Asset.timestamp` in
|
||||
* Configure. If Asset.timestamp is true and debug > 0, or Asset.timestamp == 'force'
|
||||
* a timestamp will be added.
|
||||
*
|
||||
* @param string $path The file path to timestamp, the path must be inside WWW_ROOT
|
||||
* @return string Path with a timestamp added, or not.
|
||||
* @access public
|
||||
*/
|
||||
function assetTimestamp($path) {
|
||||
$timestampEnabled = (
|
||||
(Configure::read('Asset.timestamp') === true && Configure::read() > 0) ||
|
||||
Configure::read('Asset.timestamp') === 'force'
|
||||
);
|
||||
if (strpos($path, '?') === false && $timestampEnabled) {
|
||||
$filepath = preg_replace('/^' . preg_quote($this->webroot, '/') . '/', '', $path);
|
||||
$webrootPath = WWW_ROOT . str_replace('/', DS, $filepath);
|
||||
if (file_exists($webrootPath)) {
|
||||
return $path . '?' . @filemtime($webrootPath);
|
||||
}
|
||||
$segments = explode('/', ltrim($filepath, '/'));
|
||||
if ($segments[0] === 'theme') {
|
||||
$theme = $segments[1];
|
||||
unset($segments[0], $segments[1]);
|
||||
$themePath = App::themePath($theme) . 'webroot' . DS . implode(DS, $segments);
|
||||
return $path . '?' . @filemtime($themePath);
|
||||
} else {
|
||||
$plugin = $segments[0];
|
||||
unset($segments[0]);
|
||||
$pluginPath = App::pluginPath($plugin) . 'webroot' . DS . implode(DS, $segments);
|
||||
return $path . '?' . @filemtime($pluginPath);
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to remove harmful tags from content. Removes a number of well known XSS attacks
|
||||
* from content. However, is not guaranteed to remove all possiblities. Escaping
|
||||
* content is the best way to prevent all possible attacks.
|
||||
*
|
||||
* @param mixed $output Either an array of strings to clean or a single string to clean.
|
||||
* @return cleaned content for output
|
||||
* @access public
|
||||
*/
|
||||
function clean($output) {
|
||||
$this->__reset();
|
||||
if (empty($output)) {
|
||||
return null;
|
||||
}
|
||||
if (is_array($output)) {
|
||||
foreach ($output as $key => $value) {
|
||||
$return[$key] = $this->clean($value);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
$this->__tainted = $output;
|
||||
$this->__clean();
|
||||
return $this->__cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a space-delimited string with items of the $options array. If a
|
||||
* key of $options array happens to be one of:
|
||||
*
|
||||
* - 'compact'
|
||||
* - 'checked'
|
||||
* - 'declare'
|
||||
* - 'readonly'
|
||||
* - 'disabled'
|
||||
* - 'selected'
|
||||
* - 'defer'
|
||||
* - 'ismap'
|
||||
* - 'nohref'
|
||||
* - 'noshade'
|
||||
* - 'nowrap'
|
||||
* - 'multiple'
|
||||
* - 'noresize'
|
||||
*
|
||||
* And its value is one of:
|
||||
*
|
||||
* - '1' (string)
|
||||
* - 1 (integer)
|
||||
* - true (boolean)
|
||||
* - 'true' (string)
|
||||
*
|
||||
* Then the value will be reset to be identical with key's name.
|
||||
* If the value is not one of these 3, the parameter is not output.
|
||||
*
|
||||
* 'escape' is a special option in that it controls the conversion of
|
||||
* attributes to their html-entity encoded equivalents. Set to false to disable html-encoding.
|
||||
*
|
||||
* If value for any option key is set to `null` or `false`, that option will be excluded from output.
|
||||
*
|
||||
* @param array $options Array of options.
|
||||
* @param array $exclude Array of options to be excluded, the options here will not be part of the return.
|
||||
* @param string $insertBefore String to be inserted before options.
|
||||
* @param string $insertAfter String to be inserted after options.
|
||||
* @return string Composed attributes.
|
||||
* @access public
|
||||
*/
|
||||
function _parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) {
|
||||
if (is_array($options)) {
|
||||
$options = array_merge(array('escape' => true), $options);
|
||||
|
||||
if (!is_array($exclude)) {
|
||||
$exclude = array();
|
||||
}
|
||||
$keys = array_diff(array_keys($options), array_merge($exclude, array('escape')));
|
||||
$values = array_intersect_key(array_values($options), $keys);
|
||||
$escape = $options['escape'];
|
||||
$attributes = array();
|
||||
|
||||
foreach ($keys as $index => $key) {
|
||||
if ($values[$index] !== false && $values[$index] !== null) {
|
||||
$attributes[] = $this->__formatAttribute($key, $values[$index], $escape);
|
||||
}
|
||||
}
|
||||
$out = implode(' ', $attributes);
|
||||
} else {
|
||||
$out = $options;
|
||||
}
|
||||
return $out ? $insertBefore . $out . $insertAfter : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an individual attribute, and returns the string value of the composed attribute.
|
||||
* Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
|
||||
*
|
||||
* @param string $key The name of the attribute to create
|
||||
* @param string $value The value of the attribute to create.
|
||||
* @return string The composed attribute.
|
||||
* @access private
|
||||
*/
|
||||
function __formatAttribute($key, $value, $escape = true) {
|
||||
$attribute = '';
|
||||
$attributeFormat = '%s="%s"';
|
||||
$minimizedAttributes = array('compact', 'checked', 'declare', 'readonly', 'disabled',
|
||||
'selected', 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize');
|
||||
if (is_array($value)) {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
if (in_array($key, $minimizedAttributes)) {
|
||||
if ($value === 1 || $value === true || $value === 'true' || $value === '1' || $value == $key) {
|
||||
$attribute = sprintf($attributeFormat, $key, $key);
|
||||
}
|
||||
} else {
|
||||
$attribute = sprintf($attributeFormat, $key, ($escape ? h($value) : $value));
|
||||
}
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this helper's model and field properties to the dot-separated value-pair in $entity.
|
||||
*
|
||||
* @param mixed $entity A field name, like "ModelName.fieldName" or "ModelName.ID.fieldName"
|
||||
* @param boolean $setScope Sets the view scope to the model specified in $tagValue
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function setEntity($entity, $setScope = false) {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
|
||||
if ($setScope) {
|
||||
$view->modelScope = false;
|
||||
} elseif (!empty($view->entityPath) && $view->entityPath == $entity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity === null) {
|
||||
$view->model = null;
|
||||
$view->association = null;
|
||||
$view->modelId = null;
|
||||
$view->modelScope = false;
|
||||
$view->entityPath = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$view->entityPath = $entity;
|
||||
$model = $view->model;
|
||||
$sameScope = $hasField = false;
|
||||
$parts = array_values(Set::filter(explode('.', $entity), true));
|
||||
|
||||
if (empty($parts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$count = count($parts);
|
||||
if ($count === 1) {
|
||||
$sameScope = true;
|
||||
} else {
|
||||
if (is_numeric($parts[0])) {
|
||||
$sameScope = true;
|
||||
}
|
||||
$reverse = array_reverse($parts);
|
||||
$field = array_shift($reverse);
|
||||
while(!empty($reverse)) {
|
||||
$subject = array_shift($reverse);
|
||||
if (is_numeric($subject)) {
|
||||
continue;
|
||||
}
|
||||
if (ClassRegistry::isKeySet($subject)) {
|
||||
$model = $subject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ClassRegistry::isKeySet($model)) {
|
||||
$ModelObj =& ClassRegistry::getObject($model);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (
|
||||
is_a($ModelObj, 'Model') &&
|
||||
($ModelObj->hasField($parts[$i]) ||
|
||||
array_key_exists($parts[$i], $ModelObj->validate))
|
||||
) {
|
||||
$hasField = $i;
|
||||
if ($hasField === 0 || ($hasField === 1 && is_numeric($parts[0]))) {
|
||||
$sameScope = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($sameScope === true && in_array($parts[0], array_keys($ModelObj->hasAndBelongsToMany))) {
|
||||
$sameScope = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$view->association && $parts[0] == $view->field && $view->field != $view->model) {
|
||||
array_unshift($parts, $model);
|
||||
$hasField = true;
|
||||
}
|
||||
$view->field = $view->modelId = $view->fieldSuffix = $view->association = null;
|
||||
|
||||
switch (count($parts)) {
|
||||
case 1:
|
||||
if ($view->modelScope === false) {
|
||||
$view->model = $parts[0];
|
||||
} else {
|
||||
$view->field = $parts[0];
|
||||
if ($sameScope === false) {
|
||||
$view->association = $parts[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ($view->modelScope === false) {
|
||||
list($view->model, $view->field) = $parts;
|
||||
} elseif ($sameScope === true && $hasField === 0) {
|
||||
list($view->field, $view->fieldSuffix) = $parts;
|
||||
} elseif ($sameScope === true && $hasField === 1) {
|
||||
list($view->modelId, $view->field) = $parts;
|
||||
} else {
|
||||
list($view->association, $view->field) = $parts;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ($sameScope === true && $hasField === 1) {
|
||||
list($view->modelId, $view->field, $view->fieldSuffix) = $parts;
|
||||
} elseif ($hasField === 2) {
|
||||
list($view->association, $view->modelId, $view->field) = $parts;
|
||||
} else {
|
||||
list($view->association, $view->field, $view->fieldSuffix) = $parts;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if ($parts[0] === $view->model) {
|
||||
list($view->model, $view->modelId, $view->field, $view->fieldSuffix) = $parts;
|
||||
} else {
|
||||
list($view->association, $view->modelId, $view->field, $view->fieldSuffix) = $parts;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$reverse = array_reverse($parts);
|
||||
|
||||
if ($hasField) {
|
||||
$view->field = $field;
|
||||
if (!is_numeric($reverse[1]) && $reverse[1] != $model) {
|
||||
$view->field = $reverse[1];
|
||||
$view->fieldSuffix = $field;
|
||||
}
|
||||
}
|
||||
if (is_numeric($parts[0])) {
|
||||
$view->modelId = $parts[0];
|
||||
} elseif ($view->model == $parts[0] && is_numeric($parts[1])) {
|
||||
$view->modelId = $parts[1];
|
||||
}
|
||||
$view->association = $model;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($view->model) || empty($view->model)) {
|
||||
$view->model = $view->association;
|
||||
$view->association = null;
|
||||
} elseif ($view->model === $view->association) {
|
||||
$view->association = null;
|
||||
}
|
||||
|
||||
if ($setScope) {
|
||||
$view->modelScope = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently-used model of the rendering context.
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function model() {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
if (!empty($view->association)) {
|
||||
return $view->association;
|
||||
} else {
|
||||
return $view->model;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the currently-used model of the rendering context.
|
||||
*
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function modelID() {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
return $view->modelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently-used model field of the rendering context.
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function field() {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
return $view->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if given FORM field has no errors. Otherwise it returns the constant set in
|
||||
* the array Model->validationErrors.
|
||||
*
|
||||
* @param string $model Model name as a string
|
||||
* @param string $field Fieldname as a string
|
||||
* @param integer $modelID Unique index identifying this record within the form
|
||||
* @return boolean True on errors.
|
||||
*/
|
||||
function tagIsInvalid($model = null, $field = null, $modelID = null) {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$errors = $this->validationErrors;
|
||||
$entity = $view->entity();
|
||||
if (!empty($entity)) {
|
||||
return Set::extract($errors, join('.', $entity));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a DOM ID for the selected element, if one is not set.
|
||||
* Uses the current View::entity() settings to generate a CamelCased id attribute.
|
||||
*
|
||||
* @param mixed $options Either an array of html attributes to add $id into, or a string
|
||||
* with a view entity path to get a domId for.
|
||||
* @param string $id The name of the 'id' attribute.
|
||||
* @return mixed If $options was an array, an array will be returned with $id set. If a string
|
||||
* was supplied, a string will be returned.
|
||||
* @todo Refactor this method to not have as many input/output options.
|
||||
*/
|
||||
function domId($options = null, $id = 'id') {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
|
||||
if (is_array($options) && array_key_exists($id, $options) && $options[$id] === null) {
|
||||
unset($options[$id]);
|
||||
return $options;
|
||||
} elseif (!is_array($options) && $options !== null) {
|
||||
$this->setEntity($options);
|
||||
return $this->domId();
|
||||
}
|
||||
|
||||
$entity = $view->entity();
|
||||
$model = array_shift($entity);
|
||||
$dom = $model . join('', array_map(array('Inflector', 'camelize'), $entity));
|
||||
|
||||
if (is_array($options) && !array_key_exists($id, $options)) {
|
||||
$options[$id] = $dom;
|
||||
} elseif ($options === null) {
|
||||
return $dom;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input field name for the current tag. Creates input name attributes
|
||||
* using CakePHP's data[Model][field] formatting.
|
||||
*
|
||||
* @param mixed $options If an array, should be an array of attributes that $key needs to be added to.
|
||||
* If a string or null, will be used as the View entity.
|
||||
* @param string $field
|
||||
* @param string $key The name of the attribute to be set, defaults to 'name'
|
||||
* @return mixed If an array was given for $options, an array with $key set will be returned.
|
||||
* If a string was supplied a string will be returned.
|
||||
* @access protected
|
||||
* @todo Refactor this method to not have as many input/output options.
|
||||
*/
|
||||
function _name($options = array(), $field = null, $key = 'name') {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
if ($options === null) {
|
||||
$options = array();
|
||||
} elseif (is_string($options)) {
|
||||
$field = $options;
|
||||
$options = 0;
|
||||
}
|
||||
|
||||
if (!empty($field)) {
|
||||
$this->setEntity($field);
|
||||
}
|
||||
|
||||
if (is_array($options) && array_key_exists($key, $options)) {
|
||||
return $options;
|
||||
}
|
||||
|
||||
switch ($field) {
|
||||
case '_method':
|
||||
$name = $field;
|
||||
break;
|
||||
default:
|
||||
$name = 'data[' . implode('][', $view->entity()) . ']';
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_array($options)) {
|
||||
$options[$key] = $name;
|
||||
return $options;
|
||||
} else {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data for the current tag
|
||||
*
|
||||
* @param mixed $options If an array, should be an array of attributes that $key needs to be added to.
|
||||
* If a string or null, will be used as the View entity.
|
||||
* @param string $field
|
||||
* @param string $key The name of the attribute to be set, defaults to 'value'
|
||||
* @return mixed If an array was given for $options, an array with $key set will be returned.
|
||||
* If a string was supplied a string will be returned.
|
||||
* @access public
|
||||
* @todo Refactor this method to not have as many input/output options.
|
||||
*/
|
||||
function value($options = array(), $field = null, $key = 'value') {
|
||||
if ($options === null) {
|
||||
$options = array();
|
||||
} elseif (is_string($options)) {
|
||||
$field = $options;
|
||||
$options = 0;
|
||||
}
|
||||
|
||||
if (is_array($options) && isset($options[$key])) {
|
||||
return $options;
|
||||
}
|
||||
|
||||
if (!empty($field)) {
|
||||
$this->setEntity($field);
|
||||
}
|
||||
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$result = null;
|
||||
|
||||
$entity = $view->entity();
|
||||
if (!empty($this->data) && !empty($entity)) {
|
||||
$result = Set::extract($this->data, join('.', $entity));
|
||||
}
|
||||
|
||||
$habtmKey = $this->field();
|
||||
if (empty($result) && isset($this->data[$habtmKey][$habtmKey])) {
|
||||
$result = $this->data[$habtmKey][$habtmKey];
|
||||
} elseif (empty($result) && isset($this->data[$habtmKey]) && is_array($this->data[$habtmKey])) {
|
||||
if (ClassRegistry::isKeySet($habtmKey)) {
|
||||
$model =& ClassRegistry::getObject($habtmKey);
|
||||
$result = $this->__selectedArray($this->data[$habtmKey], $model->primaryKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($result)) {
|
||||
if (array_key_exists($view->fieldSuffix, $result)) {
|
||||
$result = $result[$view->fieldSuffix];
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($options)) {
|
||||
if ($result === null && isset($options['default'])) {
|
||||
$result = $options['default'];
|
||||
}
|
||||
unset($options['default']);
|
||||
}
|
||||
|
||||
if (is_array($options)) {
|
||||
$options[$key] = $result;
|
||||
return $options;
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaults for an input tag. Will set the
|
||||
* name, value, and id attributes for an array of html attributes. Will also
|
||||
* add a 'form-error' class if the field contains validation errors.
|
||||
*
|
||||
* @param string $field The field name to initialize.
|
||||
* @param array $options Array of options to use while initializing an input field.
|
||||
* @return array Array options for the form input.
|
||||
* @access protected
|
||||
*/
|
||||
function _initInputField($field, $options = array()) {
|
||||
if ($field !== null) {
|
||||
$this->setEntity($field);
|
||||
}
|
||||
$options = (array)$options;
|
||||
$options = $this->_name($options);
|
||||
$options = $this->value($options);
|
||||
$options = $this->domId($options);
|
||||
if ($this->tagIsInvalid()) {
|
||||
$options = $this->addClass($options, 'form-error');
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given class to the element options
|
||||
*
|
||||
* @param array $options Array options/attributes to add a class to
|
||||
* @param string $class The classname being added.
|
||||
* @param string $key the key to use for class.
|
||||
* @return array Array of options with $key set.
|
||||
* @access public
|
||||
*/
|
||||
function addClass($options = array(), $class = null, $key = 'class') {
|
||||
if (isset($options[$key]) && trim($options[$key]) != '') {
|
||||
$options[$key] .= ' ' . $class;
|
||||
} else {
|
||||
$options[$key] = $class;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string generated by a helper method
|
||||
*
|
||||
* This method can be overridden in subclasses to do generalized output post-processing
|
||||
*
|
||||
* @param string $str String to be output.
|
||||
* @return string
|
||||
* @deprecated This method will be removed in future versions.
|
||||
*/
|
||||
function output($str) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before render callback. beforeRender is called before the view file is rendered.
|
||||
*
|
||||
* Overridden in subclasses.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function beforeRender() {
|
||||
}
|
||||
|
||||
/**
|
||||
* After render callback. afterRender is called after the view file is rendered
|
||||
* but before the layout has been rendered.
|
||||
*
|
||||
* Overridden in subclasses.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterRender() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Before layout callback. beforeLayout is called before the layout is rendered.
|
||||
*
|
||||
* Overridden in subclasses.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function beforeLayout() {
|
||||
}
|
||||
|
||||
/**
|
||||
* After layout callback. afterLayout is called after the layout has rendered.
|
||||
*
|
||||
* Overridden in subclasses.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function afterLayout() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a recordset from a hasAndBelongsToMany association to a list of selected
|
||||
* options for a multiple select element
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param string $key
|
||||
* @return array
|
||||
* @access private
|
||||
*/
|
||||
function __selectedArray($data, $key = 'id') {
|
||||
if (!is_array($data)) {
|
||||
$model = $data;
|
||||
if (!empty($this->data[$model][$model])) {
|
||||
return $this->data[$model][$model];
|
||||
}
|
||||
if (!empty($this->data[$model])) {
|
||||
$data = $this->data[$model];
|
||||
}
|
||||
}
|
||||
$array = array();
|
||||
if (!empty($data)) {
|
||||
foreach ($data as $var) {
|
||||
$array[$var[$key]] = $var[$key];
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the vars used by Helper::clean() to null
|
||||
*
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __reset() {
|
||||
$this->__tainted = null;
|
||||
$this->__cleaned = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes harmful content from output
|
||||
*
|
||||
* @return void
|
||||
* @access private
|
||||
*/
|
||||
function __clean() {
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$this->__cleaned = stripslashes($this->__tainted);
|
||||
} else {
|
||||
$this->__cleaned = $this->__tainted;
|
||||
}
|
||||
|
||||
$this->__cleaned = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $this->__cleaned);
|
||||
$this->__cleaned = html_entity_decode($this->__cleaned, ENT_COMPAT, "UTF-8");
|
||||
$this->__cleaned = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=*([\'\"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#iUu','$1=$2nomozbinding...', $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*expression[\x00-\x20]*\([^>]*>#iU', "$1>", $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*behaviour[\x00-\x20]*\([^>]*>#iU', "$1>", $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*>#iUu', "$1>", $this->__cleaned);
|
||||
$this->__cleaned = preg_replace('#</*\w+:\w[^>]*>#i', "", $this->__cleaned);
|
||||
do {
|
||||
$oldstring = $this->__cleaned;
|
||||
$this->__cleaned = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $this->__cleaned);
|
||||
} while ($oldstring != $this->__cleaned);
|
||||
$this->__cleaned = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $this->__cleaned);
|
||||
}
|
||||
}
|
||||
1036
web-cake/html/cake/libs/view/helpers/ajax.php
Normal file
1036
web-cake/html/cake/libs/view/helpers/ajax.php
Normal file
File diff suppressed because it is too large
Load Diff
36
web-cake/html/cake/libs/view/helpers/app_helper.php
Normal file
36
web-cake/html/cake/libs/view/helpers/app_helper.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Application level View Helper
|
||||
*
|
||||
* This file is application-wide helper file. You can put all
|
||||
* application-wide helper-related methods here.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('View', 'Helper', false);
|
||||
|
||||
/**
|
||||
* This is a placeholder class.
|
||||
* Create the same file in app/app_helper.php
|
||||
*
|
||||
* Add your application-wide methods in the class below, your helpers
|
||||
* will inherit them.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake
|
||||
*/
|
||||
class AppHelper extends Helper {
|
||||
}
|
||||
261
web-cake/html/cake/libs/view/helpers/cache.php
Normal file
261
web-cake/html/cake/libs/view/helpers/cache.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
/**
|
||||
* CacheHelper helps create full page view caching.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.0.0.2277
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* CacheHelper helps create full page view caching.
|
||||
*
|
||||
* When using CacheHelper you don't call any of its methods, they are all automatically
|
||||
* called by View, and use the $cacheAction settings set in the controller.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1376/Cache
|
||||
*/
|
||||
class CacheHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Array of strings replaced in cached views.
|
||||
* The strings are found between <cake:nocache><cake:nocache> in views
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__replace = array();
|
||||
|
||||
/**
|
||||
* Array of string that are replace with there var replace above.
|
||||
* The strings are any content inside <cake:nocache><cake:nocache> and includes the tags in views
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__match = array();
|
||||
|
||||
/**
|
||||
* cache action time
|
||||
*
|
||||
* @var object
|
||||
* @access public
|
||||
*/
|
||||
var $cacheAction;
|
||||
|
||||
/**
|
||||
* Main method used to cache a view
|
||||
*
|
||||
* @param string $file File to cache
|
||||
* @param string $out output to cache
|
||||
* @param boolean $cache Whether or not a cache file should be written.
|
||||
* @return string view ouput
|
||||
*/
|
||||
function cache($file, $out, $cache = false) {
|
||||
$cacheTime = 0;
|
||||
$useCallbacks = false;
|
||||
if (is_array($this->cacheAction)) {
|
||||
$keys = array_keys($this->cacheAction);
|
||||
$index = null;
|
||||
|
||||
foreach ($keys as $action) {
|
||||
if ($action == $this->params['action']) {
|
||||
$index = $action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($index) && $this->action == 'index') {
|
||||
$index = 'index';
|
||||
}
|
||||
|
||||
$options = $this->cacheAction;
|
||||
if (isset($this->cacheAction[$index])) {
|
||||
if (is_array($this->cacheAction[$index])) {
|
||||
$options = array_merge(array('duration' => 0, 'callbacks' => false), $this->cacheAction[$index]);
|
||||
} else {
|
||||
$cacheTime = $this->cacheAction[$index];
|
||||
}
|
||||
}
|
||||
if (isset($options['duration'])) {
|
||||
$cacheTime = $options['duration'];
|
||||
}
|
||||
if (isset($options['callbacks'])) {
|
||||
$useCallbacks = $options['callbacks'];
|
||||
}
|
||||
} else {
|
||||
$cacheTime = $this->cacheAction;
|
||||
}
|
||||
|
||||
if ($cacheTime != '' && $cacheTime > 0) {
|
||||
$this->__parseFile($file, $out);
|
||||
if ($cache === true) {
|
||||
$cached = $this->__parseOutput($out);
|
||||
$this->__writeFile($cached, $cacheTime, $useCallbacks);
|
||||
}
|
||||
return $out;
|
||||
} else {
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse file searching for no cache tags
|
||||
*
|
||||
* @param string $file The filename that needs to be parsed.
|
||||
* @param string $cache The cached content
|
||||
* @access private
|
||||
*/
|
||||
function __parseFile($file, $cache) {
|
||||
if (is_file($file)) {
|
||||
$file = file_get_contents($file);
|
||||
} elseif ($file = fileExistsInPath($file)) {
|
||||
$file = file_get_contents($file);
|
||||
}
|
||||
preg_match_all('/(<cake:nocache>(?<=<cake:nocache>)[\\s\\S]*?(?=<\/cake:nocache>)<\/cake:nocache>)/i', $cache, $outputResult, PREG_PATTERN_ORDER);
|
||||
preg_match_all('/(?<=<cake:nocache>)([\\s\\S]*?)(?=<\/cake:nocache>)/i', $file, $fileResult, PREG_PATTERN_ORDER);
|
||||
$fileResult = $fileResult[0];
|
||||
$outputResult = $outputResult[0];
|
||||
|
||||
if (!empty($this->__replace)) {
|
||||
foreach ($outputResult as $i => $element) {
|
||||
$index = array_search($element, $this->__match);
|
||||
if ($index !== false) {
|
||||
unset($outputResult[$i]);
|
||||
}
|
||||
}
|
||||
$outputResult = array_values($outputResult);
|
||||
}
|
||||
|
||||
if (!empty($fileResult)) {
|
||||
$i = 0;
|
||||
foreach ($fileResult as $cacheBlock) {
|
||||
if (isset($outputResult[$i])) {
|
||||
$this->__replace[] = $cacheBlock;
|
||||
$this->__match[] = $outputResult[$i];
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the output and replace cache tags
|
||||
*
|
||||
* @param string $cache Output to replace content in.
|
||||
* @return string with all replacements made to <cake:nocache><cake:nocache>
|
||||
* @access private
|
||||
*/
|
||||
function __parseOutput($cache) {
|
||||
$count = 0;
|
||||
if (!empty($this->__match)) {
|
||||
foreach ($this->__match as $found) {
|
||||
$original = $cache;
|
||||
$length = strlen($found);
|
||||
$position = 0;
|
||||
|
||||
for ($i = 1; $i <= 1; $i++) {
|
||||
$position = strpos($cache, $found, $position);
|
||||
|
||||
if ($position !== false) {
|
||||
$cache = substr($original, 0, $position);
|
||||
$cache .= $this->__replace[$count];
|
||||
$cache .= substr($original, $position + $length);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a cached version of the file
|
||||
*
|
||||
* @param string $content view content to write to a cache file.
|
||||
* @param sting $timestamp Duration to set for cache file.
|
||||
* @return boolean success of caching view.
|
||||
* @access private
|
||||
*/
|
||||
function __writeFile($content, $timestamp, $useCallbacks = false) {
|
||||
$now = time();
|
||||
|
||||
if (is_numeric($timestamp)) {
|
||||
$cacheTime = $now + $timestamp;
|
||||
} else {
|
||||
$cacheTime = strtotime($timestamp, $now);
|
||||
}
|
||||
$path = $this->here;
|
||||
if ($this->here == '/') {
|
||||
$path = 'home';
|
||||
}
|
||||
$cache = strtolower(Inflector::slug($path));
|
||||
|
||||
if (empty($cache)) {
|
||||
return;
|
||||
}
|
||||
$cache = $cache . '.php';
|
||||
$file = '<!--cachetime:' . $cacheTime . '--><?php';
|
||||
|
||||
if (empty($this->plugin)) {
|
||||
$file .= '
|
||||
App::import(\'Controller\', \'' . $this->controllerName. '\');
|
||||
';
|
||||
} else {
|
||||
$file .= '
|
||||
App::import(\'Controller\', \'' . $this->plugin . '.' . $this->controllerName. '\');
|
||||
';
|
||||
}
|
||||
|
||||
$file .= '$controller =& new ' . $this->controllerName . 'Controller();
|
||||
$controller->plugin = $this->plugin = \''.$this->plugin.'\';
|
||||
$controller->helpers = $this->helpers = unserialize(\'' . serialize($this->helpers) . '\');
|
||||
$controller->base = $this->base = \'' . $this->base . '\';
|
||||
$controller->layout = $this->layout = \'' . $this->layout. '\';
|
||||
$controller->webroot = $this->webroot = \'' . $this->webroot . '\';
|
||||
$controller->here = $this->here = \'' . $this->here . '\';
|
||||
$controller->params = $this->params = unserialize(stripslashes(\'' . addslashes(serialize($this->params)) . '\'));
|
||||
$controller->action = $this->action = unserialize(\'' . serialize($this->action) . '\');
|
||||
$controller->data = $this->data = unserialize(stripslashes(\'' . addslashes(serialize($this->data)) . '\'));
|
||||
$controller->theme = $this->theme = \'' . $this->theme . '\';
|
||||
Router::setRequestInfo(array($this->params, array(\'base\' => $this->base, \'webroot\' => $this->webroot)));';
|
||||
|
||||
if ($useCallbacks == true) {
|
||||
$file .= '
|
||||
$controller->constructClasses();
|
||||
$controller->Component->initialize($controller);
|
||||
$controller->beforeFilter();
|
||||
$controller->Component->startup($controller);';
|
||||
}
|
||||
|
||||
$file .= '
|
||||
$loadedHelpers = array();
|
||||
$loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);
|
||||
foreach (array_keys($loadedHelpers) as $helper) {
|
||||
$camelBackedHelper = Inflector::variable($helper);
|
||||
${$camelBackedHelper} =& $loadedHelpers[$helper];
|
||||
$this->loaded[$camelBackedHelper] =& ${$camelBackedHelper};
|
||||
$this->{$helper} =& $loadedHelpers[$helper];
|
||||
}
|
||||
?>';
|
||||
$content = preg_replace("/(<\\?xml)/", "<?php echo '$1';?>",$content);
|
||||
$file .= $content;
|
||||
return cache('views' . DS . $cache, $file, $timestamp);
|
||||
}
|
||||
}
|
||||
2197
web-cake/html/cake/libs/view/helpers/form.php
Normal file
2197
web-cake/html/cake/libs/view/helpers/form.php
Normal file
File diff suppressed because it is too large
Load Diff
835
web-cake/html/cake/libs/view/helpers/html.php
Normal file
835
web-cake/html/cake/libs/view/helpers/html.php
Normal file
@@ -0,0 +1,835 @@
|
||||
<?php
|
||||
/**
|
||||
* Html Helper class file.
|
||||
*
|
||||
* Simplifies the construction of HTML elements.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 0.9.1
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
/**
|
||||
* Html Helper class for easy use of HTML widgets.
|
||||
*
|
||||
* HtmlHelper encloses all methods needed while working with HTML pages.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1434/HTML
|
||||
*/
|
||||
class HtmlHelper extends AppHelper {
|
||||
/**
|
||||
* html tags used by this helper.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $tags = array(
|
||||
'meta' => '<meta%s/>',
|
||||
'metalink' => '<link href="%s"%s/>',
|
||||
'link' => '<a href="%s"%s>%s</a>',
|
||||
'mailto' => '<a href="mailto:%s" %s>%s</a>',
|
||||
'form' => '<form %s>',
|
||||
'formend' => '</form>',
|
||||
'input' => '<input name="%s" %s/>',
|
||||
'textarea' => '<textarea name="%s" %s>%s</textarea>',
|
||||
'hidden' => '<input type="hidden" name="%s" %s/>',
|
||||
'checkbox' => '<input type="checkbox" name="%s" %s/>',
|
||||
'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
|
||||
'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
|
||||
'selectstart' => '<select name="%s"%s>',
|
||||
'selectmultiplestart' => '<select name="%s[]"%s>',
|
||||
'selectempty' => '<option value=""%s> </option>',
|
||||
'selectoption' => '<option value="%s"%s>%s</option>',
|
||||
'selectend' => '</select>',
|
||||
'optiongroup' => '<optgroup label="%s"%s>',
|
||||
'optiongroupend' => '</optgroup>',
|
||||
'checkboxmultiplestart' => '',
|
||||
'checkboxmultipleend' => '',
|
||||
'password' => '<input type="password" name="%s" %s/>',
|
||||
'file' => '<input type="file" name="%s" %s/>',
|
||||
'file_no_model' => '<input type="file" name="%s" %s/>',
|
||||
'submit' => '<input %s/>',
|
||||
'submitimage' => '<input type="image" src="%s" %s/>',
|
||||
'button' => '<button type="%s"%s>%s</button>',
|
||||
'image' => '<img src="%s" %s/>',
|
||||
'tableheader' => '<th%s>%s</th>',
|
||||
'tableheaderrow' => '<tr%s>%s</tr>',
|
||||
'tablecell' => '<td%s>%s</td>',
|
||||
'tablerow' => '<tr%s>%s</tr>',
|
||||
'block' => '<div%s>%s</div>',
|
||||
'blockstart' => '<div%s>',
|
||||
'blockend' => '</div>',
|
||||
'tag' => '<%s%s>%s</%s>',
|
||||
'tagstart' => '<%s%s>',
|
||||
'tagend' => '</%s>',
|
||||
'para' => '<p%s>%s</p>',
|
||||
'parastart' => '<p%s>',
|
||||
'label' => '<label for="%s"%s>%s</label>',
|
||||
'fieldset' => '<fieldset%s>%s</fieldset>',
|
||||
'fieldsetstart' => '<fieldset><legend>%s</legend>',
|
||||
'fieldsetend' => '</fieldset>',
|
||||
'legend' => '<legend>%s</legend>',
|
||||
'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
|
||||
'style' => '<style type="text/css"%s>%s</style>',
|
||||
'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
|
||||
'ul' => '<ul%s>%s</ul>',
|
||||
'ol' => '<ol%s>%s</ol>',
|
||||
'li' => '<li%s>%s</li>',
|
||||
'error' => '<div%s>%s</div>',
|
||||
'javascriptblock' => '<script type="text/javascript"%s>%s</script>',
|
||||
'javascriptstart' => '<script type="text/javascript">',
|
||||
'javascriptlink' => '<script type="text/javascript" src="%s"%s></script>',
|
||||
'javascriptend' => '</script>'
|
||||
);
|
||||
|
||||
/**
|
||||
* Breadcrumbs.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_crumbs = array();
|
||||
|
||||
/**
|
||||
* Names of script files that have been included once
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__includedScripts = array();
|
||||
/**
|
||||
* Options for the currently opened script block buffer if any.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_scriptBlockOptions = array();
|
||||
/**
|
||||
* Document type definitions
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $__docTypes = array(
|
||||
'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
|
||||
'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
|
||||
'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
|
||||
'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
||||
'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
|
||||
'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
|
||||
'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds a link to the breadcrumbs array.
|
||||
*
|
||||
* @param string $name Text for link
|
||||
* @param string $link URL for link (if empty it won't be a link)
|
||||
* @param mixed $options Link attributes e.g. array('id'=>'selected')
|
||||
* @return void
|
||||
* @see HtmlHelper::link() for details on $options that can be used.
|
||||
* @access public
|
||||
*/
|
||||
function addCrumb($name, $link = null, $options = null) {
|
||||
$this->_crumbs[] = array($name, $link, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a doctype string.
|
||||
*
|
||||
* Possible doctypes:
|
||||
*
|
||||
* - html4-strict: HTML4 Strict.
|
||||
* - html4-trans: HTML4 Transitional.
|
||||
* - html4-frame: HTML4 Frameset.
|
||||
* - xhtml-strict: XHTML1 Strict.
|
||||
* - xhtml-trans: XHTML1 Transitional.
|
||||
* - xhtml-frame: XHTML1 Frameset.
|
||||
* - xhtml11: XHTML1.1.
|
||||
*
|
||||
* @param string $type Doctype to use.
|
||||
* @return string Doctype string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1439/docType
|
||||
*/
|
||||
function docType($type = 'xhtml-strict') {
|
||||
if (isset($this->__docTypes[$type])) {
|
||||
return $this->__docTypes[$type];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a link to an external resource and handles basic meta tags
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `inline` Whether or not the link element should be output inline, or in scripts_for_layout.
|
||||
*
|
||||
* @param string $type The title of the external resource
|
||||
* @param mixed $url The address of the external resource or string for content attribute
|
||||
* @param array $options Other attributes for the generated tag. If the type attribute is html,
|
||||
* rss, atom, or icon, the mime-type is returned.
|
||||
* @return string A completed `<link />` element.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1438/meta
|
||||
*/
|
||||
function meta($type, $url = null, $options = array()) {
|
||||
$inline = isset($options['inline']) ? $options['inline'] : true;
|
||||
unset($options['inline']);
|
||||
|
||||
if (!is_array($type)) {
|
||||
$types = array(
|
||||
'rss' => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
|
||||
'atom' => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
|
||||
'icon' => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
|
||||
'keywords' => array('name' => 'keywords', 'content' => $url),
|
||||
'description' => array('name' => 'description', 'content' => $url),
|
||||
);
|
||||
|
||||
if ($type === 'icon' && $url === null) {
|
||||
$types['icon']['link'] = $this->webroot('favicon.ico');
|
||||
}
|
||||
|
||||
if (isset($types[$type])) {
|
||||
$type = $types[$type];
|
||||
} elseif (!isset($options['type']) && $url !== null) {
|
||||
if (is_array($url) && isset($url['ext'])) {
|
||||
$type = $types[$url['ext']];
|
||||
} else {
|
||||
$type = $types['rss'];
|
||||
}
|
||||
} elseif (isset($options['type']) && isset($types[$options['type']])) {
|
||||
$type = $types[$options['type']];
|
||||
unset($options['type']);
|
||||
} else {
|
||||
$type = array();
|
||||
}
|
||||
} elseif ($url !== null) {
|
||||
$inline = $url;
|
||||
}
|
||||
$options = array_merge($type, $options);
|
||||
$out = null;
|
||||
|
||||
if (isset($options['link'])) {
|
||||
if (isset($options['rel']) && $options['rel'] === 'icon') {
|
||||
$out = sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
|
||||
$options['rel'] = 'shortcut icon';
|
||||
} else {
|
||||
$options['link'] = $this->url($options['link'], true);
|
||||
}
|
||||
$out .= sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
|
||||
} else {
|
||||
$out = sprintf($this->tags['meta'], $this->_parseAttributes($options, array('type'), ' ', ' '));
|
||||
}
|
||||
|
||||
if ($inline) {
|
||||
return $out;
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript($out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a charset META-tag.
|
||||
*
|
||||
* @param string $charset The character set to be used in the meta tag. If empty,
|
||||
* The App.encoding value will be used. Example: "utf-8".
|
||||
* @return string A meta tag containing the specified character set.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1436/charset
|
||||
*/
|
||||
function charset($charset = null) {
|
||||
if (empty($charset)) {
|
||||
$charset = strtolower(Configure::read('App.encoding'));
|
||||
}
|
||||
return sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML link.
|
||||
*
|
||||
* If $url starts with "http://" this is treated as an external link. Else,
|
||||
* it is treated as a path to controller/action and parsed with the
|
||||
* HtmlHelper::url() method.
|
||||
*
|
||||
* If the $url is empty, $title is used instead.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `escape` Set to false to disable escaping of title and attributes.
|
||||
*
|
||||
* @param string $title The content to be wrapped by <a> tags.
|
||||
* @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
|
||||
* @param array $options Array of HTML attributes.
|
||||
* @param string $confirmMessage JavaScript confirmation message.
|
||||
* @return string An `<a />` element.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1442/link
|
||||
*/
|
||||
function link($title, $url = null, $options = array(), $confirmMessage = false) {
|
||||
$escapeTitle = true;
|
||||
if ($url !== null) {
|
||||
$url = $this->url($url);
|
||||
} else {
|
||||
$url = $this->url($title);
|
||||
$title = $url;
|
||||
$escapeTitle = false;
|
||||
}
|
||||
|
||||
if (isset($options['escape'])) {
|
||||
$escapeTitle = $options['escape'];
|
||||
}
|
||||
|
||||
if ($escapeTitle === true) {
|
||||
$title = h($title);
|
||||
} elseif (is_string($escapeTitle)) {
|
||||
$title = htmlentities($title, ENT_QUOTES, $escapeTitle);
|
||||
}
|
||||
|
||||
if (!empty($options['confirm'])) {
|
||||
$confirmMessage = $options['confirm'];
|
||||
unset($options['confirm']);
|
||||
}
|
||||
if ($confirmMessage) {
|
||||
$confirmMessage = str_replace("'", "\'", $confirmMessage);
|
||||
$confirmMessage = str_replace('"', '\"', $confirmMessage);
|
||||
$options['onclick'] = "return confirm('{$confirmMessage}');";
|
||||
} elseif (isset($options['default']) && $options['default'] == false) {
|
||||
if (isset($options['onclick'])) {
|
||||
$options['onclick'] .= ' event.returnValue = false; return false;';
|
||||
} else {
|
||||
$options['onclick'] = 'event.returnValue = false; return false;';
|
||||
}
|
||||
unset($options['default']);
|
||||
}
|
||||
return sprintf($this->tags['link'], $url, $this->_parseAttributes($options), $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a link element for CSS stylesheets.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `inline` If set to false, the generated tag appears in the head tag of the layout. Defaults to true
|
||||
*
|
||||
* @param mixed $path The name of a CSS style sheet or an array containing names of
|
||||
* CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
|
||||
* of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
|
||||
* @param string $rel Rel attribute. Defaults to "stylesheet". If equal to 'import' the stylesheet will be imported.
|
||||
* @param array $options Array of HTML attributes.
|
||||
* @return string CSS <link /> or <style /> tag, depending on the type of link.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1437/css
|
||||
*/
|
||||
function css($path, $rel = null, $options = array()) {
|
||||
$options += array('inline' => true);
|
||||
if (is_array($path)) {
|
||||
$out = '';
|
||||
foreach ($path as $i) {
|
||||
$out .= "\n\t" . $this->css($i, $rel, $options);
|
||||
}
|
||||
if ($options['inline']) {
|
||||
return $out . "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($path, '://') !== false) {
|
||||
$url = $path;
|
||||
} else {
|
||||
if ($path[0] !== '/') {
|
||||
$path = CSS_URL . $path;
|
||||
}
|
||||
|
||||
if (strpos($path, '?') === false) {
|
||||
if (substr($path, -4) !== '.css') {
|
||||
$path .= '.css';
|
||||
}
|
||||
}
|
||||
$url = $this->assetTimestamp($this->webroot($path));
|
||||
|
||||
if (Configure::read('Asset.filter.css')) {
|
||||
$pos = strpos($url, CSS_URL);
|
||||
if ($pos !== false) {
|
||||
$url = substr($url, 0, $pos) . 'ccss/' . substr($url, $pos + strlen(CSS_URL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rel == 'import') {
|
||||
$out = sprintf($this->tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');');
|
||||
} else {
|
||||
if ($rel == null) {
|
||||
$rel = 'stylesheet';
|
||||
}
|
||||
$out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($options, array('inline'), '', ' '));
|
||||
}
|
||||
|
||||
if ($options['inline']) {
|
||||
return $out;
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript($out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one or many `<script>` tags depending on the number of scripts given.
|
||||
*
|
||||
* If the filename is prefixed with "/", the path will be relative to the base path of your
|
||||
* application. Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
|
||||
*
|
||||
* Can include one or many Javascript files.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `inline` - Whether script should be output inline or into scripts_for_layout.
|
||||
* - `once` - Whether or not the script should be checked for uniqueness. If true scripts will only be
|
||||
* included once, use false to allow the same script to be included more than once per request.
|
||||
*
|
||||
* @param mixed $url String or array of javascript files to include
|
||||
* @param mixed $options Array of options, and html attributes see above. If boolean sets $options['inline'] = value
|
||||
* @return mixed String of `<script />` tags or null if $inline is false or if $once is true and the file has been
|
||||
* included before.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1589/script
|
||||
*/
|
||||
function script($url, $options = array()) {
|
||||
if (is_bool($options)) {
|
||||
list($inline, $options) = array($options, array());
|
||||
$options['inline'] = $inline;
|
||||
}
|
||||
$options = array_merge(array('inline' => true, 'once' => true), $options);
|
||||
if (is_array($url)) {
|
||||
$out = '';
|
||||
foreach ($url as $i) {
|
||||
$out .= "\n\t" . $this->script($i, $options);
|
||||
}
|
||||
if ($options['inline']) {
|
||||
return $out . "\n";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if ($options['once'] && isset($this->__includedScripts[$url])) {
|
||||
return null;
|
||||
}
|
||||
$this->__includedScripts[$url] = true;
|
||||
|
||||
if (strpos($url, '://') === false) {
|
||||
if ($url[0] !== '/') {
|
||||
$url = JS_URL . $url;
|
||||
}
|
||||
if (strpos($url, '?') === false && substr($url, -3) !== '.js') {
|
||||
$url .= '.js';
|
||||
}
|
||||
$url = $this->assetTimestamp($this->webroot($url));
|
||||
|
||||
if (Configure::read('Asset.filter.js')) {
|
||||
$url = str_replace(JS_URL, 'cjs/', $url);
|
||||
}
|
||||
}
|
||||
$attributes = $this->_parseAttributes($options, array('inline', 'once'), ' ');
|
||||
$out = sprintf($this->tags['javascriptlink'], $url, $attributes);
|
||||
|
||||
if ($options['inline']) {
|
||||
return $out;
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript($out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap $script in a script tag.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `safe` (boolean) Whether or not the $script should be wrapped in <![CDATA[ ]]>
|
||||
* - `inline` (boolean) Whether or not the $script should be added to $scripts_for_layout or output inline
|
||||
*
|
||||
* @param string $script The script to wrap
|
||||
* @param array $options The options to use.
|
||||
* @return mixed string or null depending on the value of `$options['inline']`
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1604/scriptBlock
|
||||
*/
|
||||
function scriptBlock($script, $options = array()) {
|
||||
$options += array('safe' => true, 'inline' => true);
|
||||
if ($options['safe']) {
|
||||
$script = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
|
||||
}
|
||||
$inline = $options['inline'];
|
||||
unset($options['inline'], $options['safe']);
|
||||
$attributes = $this->_parseAttributes($options, ' ', ' ');
|
||||
if ($inline) {
|
||||
return sprintf($this->tags['javascriptblock'], $attributes, $script);
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript(sprintf($this->tags['javascriptblock'], $attributes, $script));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a script block that captures output until HtmlHelper::scriptEnd()
|
||||
* is called. This capturing block will capture all output between the methods
|
||||
* and create a scriptBlock from it.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `safe` Whether the code block should contain a CDATA
|
||||
* - `inline` Should the generated script tag be output inline or in `$scripts_for_layout`
|
||||
*
|
||||
* @param array $options Options for the code block.
|
||||
* @return void
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1605/scriptStart
|
||||
*/
|
||||
function scriptStart($options = array()) {
|
||||
$options += array('safe' => true, 'inline' => true);
|
||||
$this->_scriptBlockOptions = $options;
|
||||
ob_start();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* End a Buffered section of Javascript capturing.
|
||||
* Generates a script tag inline or in `$scripts_for_layout` depending on the settings
|
||||
* used when the scriptBlock was started
|
||||
*
|
||||
* @return mixed depending on the settings of scriptStart() either a script tag or null
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1606/scriptEnd
|
||||
*/
|
||||
function scriptEnd() {
|
||||
$buffer = ob_get_clean();
|
||||
$options = $this->_scriptBlockOptions;
|
||||
$this->_scriptBlockOptions = array();
|
||||
return $this->scriptBlock($buffer, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds CSS style data from an array of CSS properties
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* {{{
|
||||
* echo $html->style(array('margin' => '10px', 'padding' => '10px'), true);
|
||||
*
|
||||
* // creates
|
||||
* 'margin:10px;padding:10px;'
|
||||
* }}}
|
||||
*
|
||||
* @param array $data Style data array, keys will be used as property names, values as property values.
|
||||
* @param boolean $oneline Whether or not the style block should be displayed on one line.
|
||||
* @return string CSS styling data
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1440/style
|
||||
*/
|
||||
function style($data, $oneline = true) {
|
||||
if (!is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
$out = array();
|
||||
foreach ($data as $key=> $value) {
|
||||
$out[] = $key.':'.$value.';';
|
||||
}
|
||||
if ($oneline) {
|
||||
return join(' ', $out);
|
||||
}
|
||||
return implode("\n", $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the breadcrumb trail as a sequence of »-separated links.
|
||||
*
|
||||
* @param string $separator Text to separate crumbs.
|
||||
* @param string $startText This will be the first crumb, if false it defaults to first crumb in array
|
||||
* @return string Composed bread crumbs
|
||||
* @access public
|
||||
*/
|
||||
function getCrumbs($separator = '»', $startText = false) {
|
||||
if (!empty($this->_crumbs)) {
|
||||
$out = array();
|
||||
if ($startText) {
|
||||
$out[] = $this->link($startText, '/');
|
||||
}
|
||||
|
||||
foreach ($this->_crumbs as $crumb) {
|
||||
if (!empty($crumb[1])) {
|
||||
$out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
|
||||
} else {
|
||||
$out[] = $crumb[0];
|
||||
}
|
||||
}
|
||||
return join($separator, $out);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a formatted IMG element. If `$options['url']` is provided, an image link will be
|
||||
* generated with the link pointed at `$options['url']`. This method will set an empty
|
||||
* alt attribute if one is not supplied.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Create a regular image:
|
||||
*
|
||||
* `echo $html->image('cake_icon.png', array('alt' => 'CakePHP'));`
|
||||
*
|
||||
* Create an image link:
|
||||
*
|
||||
* `echo $html->image('cake_icon.png', array('alt' => 'CakePHP', 'url' => 'http://cakephp.org'));`
|
||||
*
|
||||
* @param string $path Path to the image file, relative to the app/webroot/img/ directory.
|
||||
* @param array $options Array of HTML attributes.
|
||||
* @return string completed img tag
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1441/image
|
||||
*/
|
||||
function image($path, $options = array()) {
|
||||
if (is_array($path)) {
|
||||
$path = $this->url($path);
|
||||
} elseif (strpos($path, '://') === false) {
|
||||
if ($path[0] !== '/') {
|
||||
$path = IMAGES_URL . $path;
|
||||
}
|
||||
$path = $this->assetTimestamp($this->webroot($path));
|
||||
}
|
||||
|
||||
if (!isset($options['alt'])) {
|
||||
$options['alt'] = '';
|
||||
}
|
||||
|
||||
$url = false;
|
||||
if (!empty($options['url'])) {
|
||||
$url = $options['url'];
|
||||
unset($options['url']);
|
||||
}
|
||||
|
||||
$image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
|
||||
|
||||
if ($url) {
|
||||
return sprintf($this->tags['link'], $this->url($url), null, $image);
|
||||
}
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a row of formatted and named TABLE headers.
|
||||
*
|
||||
* @param array $names Array of tablenames.
|
||||
* @param array $trOptions HTML options for TR elements.
|
||||
* @param array $thOptions HTML options for TH elements.
|
||||
* @return string Completed table headers
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1446/tableHeaders
|
||||
*/
|
||||
function tableHeaders($names, $trOptions = null, $thOptions = null) {
|
||||
$out = array();
|
||||
foreach ($names as $arg) {
|
||||
$out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
|
||||
}
|
||||
return sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string of table rows (TR's with TD's in them).
|
||||
*
|
||||
* @param array $data Array of table data
|
||||
* @param array $oddTrOptions HTML options for odd TR elements if true useCount is used
|
||||
* @param array $evenTrOptions HTML options for even TR elements
|
||||
* @param bool $useCount adds class "column-$i"
|
||||
* @param bool $continueOddEven If false, will use a non-static $count variable,
|
||||
* so that the odd/even count is reset to zero just for that call.
|
||||
* @return string Formatted HTML
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1447/tableCells
|
||||
*/
|
||||
function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
|
||||
if (empty($data[0]) || !is_array($data[0])) {
|
||||
$data = array($data);
|
||||
}
|
||||
|
||||
if ($oddTrOptions === true) {
|
||||
$useCount = true;
|
||||
$oddTrOptions = null;
|
||||
}
|
||||
|
||||
if ($evenTrOptions === false) {
|
||||
$continueOddEven = false;
|
||||
$evenTrOptions = null;
|
||||
}
|
||||
|
||||
if ($continueOddEven) {
|
||||
static $count = 0;
|
||||
} else {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
foreach ($data as $line) {
|
||||
$count++;
|
||||
$cellsOut = array();
|
||||
$i = 0;
|
||||
foreach ($line as $cell) {
|
||||
$cellOptions = array();
|
||||
|
||||
if (is_array($cell)) {
|
||||
$cellOptions = $cell[1];
|
||||
$cell = $cell[0];
|
||||
} elseif ($useCount) {
|
||||
$cellOptions['class'] = 'column-' . ++$i;
|
||||
}
|
||||
$cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
|
||||
}
|
||||
$options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
|
||||
$out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut));
|
||||
}
|
||||
return implode("\n", $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted block tag, i.e DIV, SPAN, P.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `escape` Whether or not the contents should be html_entity escaped.
|
||||
*
|
||||
* @param string $name Tag name.
|
||||
* @param string $text String content that will appear inside the div element.
|
||||
* If null, only a start tag will be printed
|
||||
* @param array $options Additional HTML attributes of the DIV tag, see above.
|
||||
* @return string The formatted tag element
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1443/tag
|
||||
*/
|
||||
function tag($name, $text = null, $options = array()) {
|
||||
if (is_array($options) && isset($options['escape']) && $options['escape']) {
|
||||
$text = h($text);
|
||||
unset($options['escape']);
|
||||
}
|
||||
if (!is_array($options)) {
|
||||
$options = array('class' => $options);
|
||||
}
|
||||
if ($text === null) {
|
||||
$tag = 'tagstart';
|
||||
} else {
|
||||
$tag = 'tag';
|
||||
}
|
||||
return sprintf($this->tags[$tag], $name, $this->_parseAttributes($options, null, ' ', ''), $text, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted DIV tag for HTML FORMs.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `escape` Whether or not the contents should be html_entity escaped.
|
||||
*
|
||||
* @param string $class CSS class name of the div element.
|
||||
* @param string $text String content that will appear inside the div element.
|
||||
* If null, only a start tag will be printed
|
||||
* @param array $options Additional HTML attributes of the DIV tag
|
||||
* @return string The formatted DIV element
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1444/div
|
||||
*/
|
||||
function div($class = null, $text = null, $options = array()) {
|
||||
if (!empty($class)) {
|
||||
$options['class'] = $class;
|
||||
}
|
||||
return $this->tag('div', $text, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted P tag.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `escape` Whether or not the contents should be html_entity escaped.
|
||||
*
|
||||
* @param string $class CSS class name of the p element.
|
||||
* @param string $text String content that will appear inside the p element.
|
||||
* @param array $options Additional HTML attributes of the P tag
|
||||
* @return string The formatted P element
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1445/para
|
||||
*/
|
||||
function para($class, $text, $options = array()) {
|
||||
if (isset($options['escape'])) {
|
||||
$text = h($text);
|
||||
}
|
||||
if ($class != null && !empty($class)) {
|
||||
$options['class'] = $class;
|
||||
}
|
||||
if ($text === null) {
|
||||
$tag = 'parastart';
|
||||
} else {
|
||||
$tag = 'para';
|
||||
}
|
||||
return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a nested list (UL/OL) out of an associative array.
|
||||
*
|
||||
* @param array $list Set of elements to list
|
||||
* @param array $options Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag
|
||||
* @param array $itemOptions Additional HTML attributes of the list item (LI) tag
|
||||
* @param string $tag Type of list tag to use (ol/ul)
|
||||
* @return string The nested list
|
||||
* @access public
|
||||
*/
|
||||
function nestedList($list, $options = array(), $itemOptions = array(), $tag = 'ul') {
|
||||
if (is_string($options)) {
|
||||
$tag = $options;
|
||||
$options = array();
|
||||
}
|
||||
$items = $this->__nestedListItem($list, $options, $itemOptions, $tag);
|
||||
return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to build a nested list (UL/OL) out of an associative array.
|
||||
*
|
||||
* @param array $list Set of elements to list
|
||||
* @param array $options Additional HTML attributes of the list (ol/ul) tag
|
||||
* @param array $itemOptions Additional HTML attributes of the list item (LI) tag
|
||||
* @param string $tag Type of list tag to use (ol/ul)
|
||||
* @return string The nested list element
|
||||
* @access private
|
||||
* @see HtmlHelper::nestedList()
|
||||
*/
|
||||
function __nestedListItem($items, $options, $itemOptions, $tag) {
|
||||
$out = '';
|
||||
|
||||
$index = 1;
|
||||
foreach ($items as $key => $item) {
|
||||
if (is_array($item)) {
|
||||
$item = $key . $this->nestedList($item, $options, $itemOptions, $tag);
|
||||
}
|
||||
if (isset($itemOptions['even']) && $index % 2 == 0) {
|
||||
$itemOptions['class'] = $itemOptions['even'];
|
||||
} else if (isset($itemOptions['odd']) && $index % 2 != 0) {
|
||||
$itemOptions['class'] = $itemOptions['odd'];
|
||||
}
|
||||
$out .= sprintf($this->tags['li'], $this->_parseAttributes($itemOptions, array('even', 'odd'), ' ', ''), $item);
|
||||
$index++;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
721
web-cake/html/cake/libs/view/helpers/javascript.php
Normal file
721
web-cake/html/cake/libs/view/helpers/javascript.php
Normal file
@@ -0,0 +1,721 @@
|
||||
<?php
|
||||
/**
|
||||
* Javascript Helper class file.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Javascript Helper class for easy use of JavaScript.
|
||||
*
|
||||
* JavascriptHelper encloses all methods needed while working with JavaScript.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1450/Javascript
|
||||
*/
|
||||
class JavascriptHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Determines whether native JSON extension is used for encoding. Set by object constructor.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $useNative = false;
|
||||
|
||||
/**
|
||||
* If true, automatically writes events to the end of a script or to an external JavaScript file
|
||||
* at the end of page execution
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $enabled = true;
|
||||
|
||||
/**
|
||||
* Indicates whether <script /> blocks should be written 'safely,' i.e. wrapped in CDATA blocks
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
var $safe = false;
|
||||
|
||||
/**
|
||||
* HTML tags used by this helper.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $tags = array(
|
||||
'javascriptstart' => '<script type="text/javascript">',
|
||||
'javascriptend' => '</script>',
|
||||
'javascriptblock' => '<script type="text/javascript">%s</script>',
|
||||
'javascriptlink' => '<script type="text/javascript" src="%s"></script>'
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds options passed to codeBlock(), saved for when block is dumped to output
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
* @see JavascriptHelper::codeBlock()
|
||||
*/
|
||||
var $_blockOptions = array();
|
||||
|
||||
/**
|
||||
* Caches events written by event() for output at the end of page execution
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
* @see JavascriptHelper::event()
|
||||
*/
|
||||
var $_cachedEvents = array();
|
||||
|
||||
/**
|
||||
* Indicates whether generated events should be cached for later output (can be written at the
|
||||
* end of the page, in the <head />, or to an external file).
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
* @see JavascriptHelper::event()
|
||||
* @see JavascriptHelper::writeEvents()
|
||||
*/
|
||||
var $_cacheEvents = false;
|
||||
|
||||
/**
|
||||
* Indicates whether cached events should be written to an external file
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
* @see JavascriptHelper::event()
|
||||
* @see JavascriptHelper::writeEvents()
|
||||
*/
|
||||
var $_cacheToFile = false;
|
||||
|
||||
/**
|
||||
* Indicates whether *all* generated JavaScript should be cached for later output
|
||||
*
|
||||
* @var boolean
|
||||
* @access protected
|
||||
* @see JavascriptHelper::codeBlock()
|
||||
* @see JavascriptHelper::blockEnd()
|
||||
*/
|
||||
var $_cacheAll = false;
|
||||
|
||||
/**
|
||||
* Contains event rules attached with CSS selectors. Used with the event:Selectors JavaScript
|
||||
* library.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
* @see JavascriptHelper::event()
|
||||
* @link http://alternateidea.com/event-selectors/
|
||||
*/
|
||||
var $_rules = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $__scriptBuffer = null;
|
||||
|
||||
/**
|
||||
* Constructor. Checks for presence of native PHP JSON extension to use for object encoding
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function __construct($options = array()) {
|
||||
if (!empty($options)) {
|
||||
foreach ($options as $key => $val) {
|
||||
if (is_numeric($key)) {
|
||||
$key = $val;
|
||||
$val = true;
|
||||
}
|
||||
switch ($key) {
|
||||
case 'cache':
|
||||
|
||||
break;
|
||||
case 'safe':
|
||||
$this->safe = $val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->useNative = function_exists('json_encode');
|
||||
return parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JavaScript script tag.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - allowCache: boolean, designates whether this block is cacheable using the
|
||||
* current cache settings.
|
||||
* - safe: boolean, whether this block should be wrapped in CDATA tags. Defaults
|
||||
* to helper's object configuration.
|
||||
* - inline: whether the block should be printed inline, or written
|
||||
* to cached for later output (i.e. $scripts_for_layout).
|
||||
*
|
||||
* @param string $script The JavaScript to be wrapped in SCRIPT tags.
|
||||
* @param array $options Set of options:
|
||||
* @return string The full SCRIPT element, with the JavaScript inside it, or null,
|
||||
* if 'inline' is set to false.
|
||||
*/
|
||||
function codeBlock($script = null, $options = array()) {
|
||||
if (!empty($options) && !is_array($options)) {
|
||||
$options = array('allowCache' => $options);
|
||||
} elseif (empty($options)) {
|
||||
$options = array();
|
||||
}
|
||||
$defaultOptions = array('allowCache' => true, 'safe' => true, 'inline' => true);
|
||||
$options = array_merge($defaultOptions, $options);
|
||||
|
||||
if (empty($script)) {
|
||||
$this->__scriptBuffer = @ob_get_contents();
|
||||
$this->_blockOptions = $options;
|
||||
$this->inBlock = true;
|
||||
@ob_end_clean();
|
||||
ob_start();
|
||||
return null;
|
||||
}
|
||||
if ($this->_cacheEvents && $this->_cacheAll && $options['allowCache']) {
|
||||
$this->_cachedEvents[] = $script;
|
||||
return null;
|
||||
}
|
||||
if ($options['safe'] || $this->safe) {
|
||||
$script = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
|
||||
}
|
||||
if ($options['inline']) {
|
||||
return sprintf($this->tags['javascriptblock'], $script);
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript(sprintf($this->tags['javascriptblock'], $script));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a block of cached JavaScript code
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function blockEnd() {
|
||||
if (!isset($this->inBlock) || !$this->inBlock) {
|
||||
return;
|
||||
}
|
||||
$script = @ob_get_contents();
|
||||
@ob_end_clean();
|
||||
ob_start();
|
||||
echo $this->__scriptBuffer;
|
||||
$this->__scriptBuffer = null;
|
||||
$options = $this->_blockOptions;
|
||||
$this->_blockOptions = array();
|
||||
$this->inBlock = false;
|
||||
|
||||
if (empty($script)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->codeBlock($script, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JavaScript include tag (SCRIPT element). If the filename is prefixed with "/",
|
||||
* the path will be relative to the base path of your application. Otherwise, the path will
|
||||
* be relative to your JavaScript path, usually webroot/js.
|
||||
*
|
||||
* @param mixed $url String URL to JavaScript file, or an array of URLs.
|
||||
* @param boolean $inline If true, the <script /> tag will be printed inline,
|
||||
* otherwise it will be printed in the <head />, using $scripts_for_layout
|
||||
* @see JS_URL
|
||||
* @return string
|
||||
*/
|
||||
function link($url, $inline = true) {
|
||||
if (is_array($url)) {
|
||||
$out = '';
|
||||
foreach ($url as $i) {
|
||||
$out .= "\n\t" . $this->link($i, $inline);
|
||||
}
|
||||
if ($inline) {
|
||||
return $out . "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($url, '://') === false) {
|
||||
if ($url[0] !== '/') {
|
||||
$url = JS_URL . $url;
|
||||
}
|
||||
if (strpos($url, '?') === false) {
|
||||
if (substr($url, -3) !== '.js') {
|
||||
$url .= '.js';
|
||||
}
|
||||
}
|
||||
$url = $this->assetTimestamp($this->webroot($url));
|
||||
|
||||
if (Configure::read('Asset.filter.js')) {
|
||||
$pos = strpos($url, JS_URL);
|
||||
if ($pos !== false) {
|
||||
$url = substr($url, 0, $pos) . 'cjs/' . substr($url, $pos + strlen(JS_URL));
|
||||
}
|
||||
}
|
||||
}
|
||||
$out = sprintf($this->tags['javascriptlink'], $url);
|
||||
|
||||
if ($inline) {
|
||||
return $out;
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript($out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape carriage returns and single and double quotes for JavaScript segments.
|
||||
*
|
||||
* @param string $script string that might have javascript elements
|
||||
* @return string escaped string
|
||||
*/
|
||||
function escapeScript($script) {
|
||||
$script = str_replace(array("\r\n", "\n", "\r"), '\n', $script);
|
||||
$script = str_replace(array('"', "'"), array('\"', "\\'"), $script);
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string to be JavaScript friendly.
|
||||
*
|
||||
* List of escaped ellements:
|
||||
* + "\r\n" => '\n'
|
||||
* + "\r" => '\n'
|
||||
* + "\n" => '\n'
|
||||
* + '"' => '\"'
|
||||
* + "'" => "\\'"
|
||||
*
|
||||
* @param string $script String that needs to get escaped.
|
||||
* @return string Escaped string.
|
||||
*/
|
||||
function escapeString($string) {
|
||||
App::import('Core', 'Multibyte');
|
||||
$escape = array("\r\n" => "\n", "\r" => "\n");
|
||||
$string = str_replace(array_keys($escape), array_values($escape), $string);
|
||||
return $this->_utf8ToHex($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string into JSON. Converts and escapes necessary characters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function _utf8ToHex($string) {
|
||||
$length = strlen($string);
|
||||
$return = '';
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$ord = ord($string{$i});
|
||||
switch (true) {
|
||||
case $ord == 0x08:
|
||||
$return .= '\b';
|
||||
break;
|
||||
case $ord == 0x09:
|
||||
$return .= '\t';
|
||||
break;
|
||||
case $ord == 0x0A:
|
||||
$return .= '\n';
|
||||
break;
|
||||
case $ord == 0x0C:
|
||||
$return .= '\f';
|
||||
break;
|
||||
case $ord == 0x0D:
|
||||
$return .= '\r';
|
||||
break;
|
||||
case $ord == 0x22:
|
||||
case $ord == 0x2F:
|
||||
case $ord == 0x5C:
|
||||
case $ord == 0x27:
|
||||
$return .= '\\' . $string{$i};
|
||||
break;
|
||||
case (($ord >= 0x20) && ($ord <= 0x7F)):
|
||||
$return .= $string{$i};
|
||||
break;
|
||||
case (($ord & 0xE0) == 0xC0):
|
||||
if ($i + 1 >= $length) {
|
||||
$i += 1;
|
||||
$return .= '?';
|
||||
break;
|
||||
}
|
||||
$charbits = $string{$i} . $string{$i + 1};
|
||||
$char = Multibyte::utf8($charbits);
|
||||
$return .= sprintf('\u%04s', dechex($char[0]));
|
||||
$i += 1;
|
||||
break;
|
||||
case (($ord & 0xF0) == 0xE0):
|
||||
if ($i + 2 >= $length) {
|
||||
$i += 2;
|
||||
$return .= '?';
|
||||
break;
|
||||
}
|
||||
$charbits = $string{$i} . $string{$i + 1} . $string{$i + 2};
|
||||
$char = Multibyte::utf8($charbits);
|
||||
$return .= sprintf('\u%04s', dechex($char[0]));
|
||||
$i += 2;
|
||||
break;
|
||||
case (($ord & 0xF8) == 0xF0):
|
||||
if ($i + 3 >= $length) {
|
||||
$i += 3;
|
||||
$return .= '?';
|
||||
break;
|
||||
}
|
||||
$charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3};
|
||||
$char = Multibyte::utf8($charbits);
|
||||
$return .= sprintf('\u%04s', dechex($char[0]));
|
||||
$i += 3;
|
||||
break;
|
||||
case (($ord & 0xFC) == 0xF8):
|
||||
if ($i + 4 >= $length) {
|
||||
$i += 4;
|
||||
$return .= '?';
|
||||
break;
|
||||
}
|
||||
$charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3} . $string{$i + 4};
|
||||
$char = Multibyte::utf8($charbits);
|
||||
$return .= sprintf('\u%04s', dechex($char[0]));
|
||||
$i += 4;
|
||||
break;
|
||||
case (($ord & 0xFE) == 0xFC):
|
||||
if ($i + 5 >= $length) {
|
||||
$i += 5;
|
||||
$return .= '?';
|
||||
break;
|
||||
}
|
||||
$charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3} . $string{$i + 4} . $string{$i + 5};
|
||||
$char = Multibyte::utf8($charbits);
|
||||
$return .= sprintf('\u%04s', dechex($char[0]));
|
||||
$i += 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach an event to an element. Used with the Prototype library.
|
||||
*
|
||||
* @param string $object Object to be observed
|
||||
* @param string $event event to observe
|
||||
* @param string $observer function to call
|
||||
* @param array $options Set options: useCapture, allowCache, safe
|
||||
* @return boolean true on success
|
||||
*/
|
||||
function event($object, $event, $observer = null, $options = array()) {
|
||||
if (!empty($options) && !is_array($options)) {
|
||||
$options = array('useCapture' => $options);
|
||||
} else if (empty($options)) {
|
||||
$options = array();
|
||||
}
|
||||
|
||||
$defaultOptions = array('useCapture' => false);
|
||||
$options = array_merge($defaultOptions, $options);
|
||||
|
||||
if ($options['useCapture'] == true) {
|
||||
$options['useCapture'] = 'true';
|
||||
} else {
|
||||
$options['useCapture'] = 'false';
|
||||
}
|
||||
$isObject = (
|
||||
strpos($object, 'window') !== false || strpos($object, 'document') !== false ||
|
||||
strpos($object, '$(') !== false || strpos($object, '"') !== false ||
|
||||
strpos($object, '\'') !== false
|
||||
);
|
||||
|
||||
if ($isObject) {
|
||||
$b = "Event.observe({$object}, '{$event}', function(event) { {$observer} }, ";
|
||||
$b .= "{$options['useCapture']});";
|
||||
} elseif ($object[0] == '\'') {
|
||||
$b = "Event.observe(" . substr($object, 1) . ", '{$event}', function(event) { ";
|
||||
$b .= "{$observer} }, {$options['useCapture']});";
|
||||
} else {
|
||||
$chars = array('#', ' ', ', ', '.', ':');
|
||||
$found = false;
|
||||
foreach ($chars as $char) {
|
||||
if (strpos($object, $char) !== false) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
$this->_rules[$object] = $event;
|
||||
} else {
|
||||
$b = "Event.observe(\$('{$object}'), '{$event}', function(event) { ";
|
||||
$b .= "{$observer} }, {$options['useCapture']});";
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($b) && !empty($b)) {
|
||||
if ($this->_cacheEvents === true) {
|
||||
$this->_cachedEvents[] = $b;
|
||||
return;
|
||||
} else {
|
||||
return $this->codeBlock($b, array_diff_key($options, $defaultOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache JavaScript events created with event()
|
||||
*
|
||||
* @param boolean $file If true, code will be written to a file
|
||||
* @param boolean $all If true, all code written with JavascriptHelper will be sent to a file
|
||||
* @return null
|
||||
*/
|
||||
function cacheEvents($file = false, $all = false) {
|
||||
$this->_cacheEvents = true;
|
||||
$this->_cacheToFile = $file;
|
||||
$this->_cacheAll = $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets (and clears) the current JavaScript event cache
|
||||
*
|
||||
* @param boolean $clear
|
||||
* @return string
|
||||
*/
|
||||
function getCache($clear = true) {
|
||||
$out = '';
|
||||
$rules = array();
|
||||
|
||||
if (!empty($this->_rules)) {
|
||||
foreach ($this->_rules as $sel => $event) {
|
||||
$rules[] = "\t'{$sel}': function(element, event) {\n\t\t{$event}\n\t}";
|
||||
}
|
||||
}
|
||||
$data = implode("\n", $this->_cachedEvents);
|
||||
|
||||
if (!empty($rules)) {
|
||||
$data .= "\nvar Rules = {\n" . implode(",\n\n", $rules) . "\n}";
|
||||
$data .= "\nEventSelectors.start(Rules);\n";
|
||||
}
|
||||
if ($clear) {
|
||||
$this->_rules = array();
|
||||
$this->_cacheEvents = false;
|
||||
$this->_cachedEvents = array();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write cached JavaScript events
|
||||
*
|
||||
* @param boolean $inline If true, returns JavaScript event code. Otherwise it is added to the
|
||||
* output of $scripts_for_layout in the layout.
|
||||
* @param array $options Set options for codeBlock
|
||||
* @return string
|
||||
*/
|
||||
function writeEvents($inline = true, $options = array()) {
|
||||
$out = '';
|
||||
$rules = array();
|
||||
|
||||
if (!$this->_cacheEvents) {
|
||||
return;
|
||||
}
|
||||
$data = $this->getCache();
|
||||
|
||||
if (empty($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_cacheToFile) {
|
||||
$filename = md5($data);
|
||||
if (!file_exists(JS . $filename . '.js')) {
|
||||
cache(str_replace(WWW_ROOT, '', JS) . $filename . '.js', $data, '+999 days', 'public');
|
||||
}
|
||||
$out = $this->link($filename);
|
||||
} else {
|
||||
$out = $this->codeBlock("\n" . $data . "\n", $options);
|
||||
}
|
||||
|
||||
if ($inline) {
|
||||
return $out;
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$view->addScript($out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes the Prototype Javascript library (and anything else) inside a single script tag.
|
||||
*
|
||||
* Note: The recommended approach is to copy the contents of
|
||||
* javascripts into your application's
|
||||
* public/javascripts/ directory, and use @see javascriptIncludeTag() to
|
||||
* create remote script links.
|
||||
*
|
||||
* @param string $script Script file to include
|
||||
* @param array $options Set options for codeBlock
|
||||
* @return string script with all javascript in/javascripts folder
|
||||
*/
|
||||
function includeScript($script = "", $options = array()) {
|
||||
if ($script == "") {
|
||||
$files = scandir(JS);
|
||||
$javascript = '';
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (substr($file, -3) == '.js') {
|
||||
$javascript .= file_get_contents(JS . "{$file}") . "\n\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$javascript = file_get_contents(JS . "$script.js") . "\n\n";
|
||||
}
|
||||
return $this->codeBlock("\n\n" . $javascript, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a JavaScript object in JavaScript Object Notation (JSON)
|
||||
* from an array
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - block - Wraps the return value in a script tag if true. Default is false
|
||||
* - prefix - Prepends the string to the returned data. Default is ''
|
||||
* - postfix - Appends the string to the returned data. Default is ''
|
||||
* - stringKeys - A list of array keys to be treated as a string.
|
||||
* - quoteKeys - If false treats $stringKeys as a list of keys **not** to be quoted. Default is true.
|
||||
* - q - The type of quote to use. Default is '"'. This option only affects the keys, not the values.
|
||||
*
|
||||
* @param array $data Data to be converted
|
||||
* @param array $options Set of options: block, prefix, postfix, stringKeys, quoteKeys, q
|
||||
* @return string A JSON code block
|
||||
*/
|
||||
function object($data = array(), $options = array()) {
|
||||
if (!empty($options) && !is_array($options)) {
|
||||
$options = array('block' => $options);
|
||||
} else if (empty($options)) {
|
||||
$options = array();
|
||||
}
|
||||
|
||||
$defaultOptions = array(
|
||||
'block' => false, 'prefix' => '', 'postfix' => '',
|
||||
'stringKeys' => array(), 'quoteKeys' => true, 'q' => '"'
|
||||
);
|
||||
$options = array_merge($defaultOptions, $options, array_filter(compact(array_keys($defaultOptions))));
|
||||
|
||||
if (is_object($data)) {
|
||||
$data = get_object_vars($data);
|
||||
}
|
||||
|
||||
$out = $keys = array();
|
||||
$numeric = true;
|
||||
|
||||
if ($this->useNative) {
|
||||
$rt = json_encode($data);
|
||||
} else {
|
||||
if (is_null($data)) {
|
||||
return 'null';
|
||||
}
|
||||
if (is_bool($data)) {
|
||||
return $data ? 'true' : 'false';
|
||||
}
|
||||
|
||||
if (is_array($data)) {
|
||||
$keys = array_keys($data);
|
||||
}
|
||||
|
||||
if (!empty($keys)) {
|
||||
$numeric = (array_values($keys) === array_keys(array_values($keys)));
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$val = $this->object(
|
||||
$val,
|
||||
array_merge($options, array('block' => false, 'prefix' => '', 'postfix' => ''))
|
||||
);
|
||||
} else {
|
||||
$quoteStrings = (
|
||||
!count($options['stringKeys']) ||
|
||||
($options['quoteKeys'] && in_array($key, $options['stringKeys'], true)) ||
|
||||
(!$options['quoteKeys'] && !in_array($key, $options['stringKeys'], true))
|
||||
);
|
||||
$val = $this->value($val, $quoteStrings);
|
||||
}
|
||||
if (!$numeric) {
|
||||
$val = $options['q'] . $this->value($key, false) . $options['q'] . ':' . $val;
|
||||
}
|
||||
$out[] = $val;
|
||||
}
|
||||
|
||||
if (!$numeric) {
|
||||
$rt = '{' . implode(',', $out) . '}';
|
||||
} else {
|
||||
$rt = '[' . implode(',', $out) . ']';
|
||||
}
|
||||
}
|
||||
$rt = $options['prefix'] . $rt . $options['postfix'];
|
||||
|
||||
if ($options['block']) {
|
||||
$rt = $this->codeBlock($rt, array_diff_key($options, $defaultOptions));
|
||||
}
|
||||
|
||||
return $rt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a PHP-native variable of any type to a JSON-equivalent representation
|
||||
*
|
||||
* @param mixed $val A PHP variable to be converted to JSON
|
||||
* @param boolean $quoteStrings If false, leaves string values unquoted
|
||||
* @return string a JavaScript-safe/JSON representation of $val
|
||||
*/
|
||||
function value($val, $quoteStrings = true) {
|
||||
switch (true) {
|
||||
case (is_array($val) || is_object($val)):
|
||||
$val = $this->object($val);
|
||||
break;
|
||||
case ($val === null):
|
||||
$val = 'null';
|
||||
break;
|
||||
case (is_bool($val)):
|
||||
$val = !empty($val) ? 'true' : 'false';
|
||||
break;
|
||||
case (is_int($val)):
|
||||
$val = $val;
|
||||
break;
|
||||
case (is_float($val)):
|
||||
$val = sprintf("%.11f", $val);
|
||||
break;
|
||||
default:
|
||||
$val = $this->escapeString($val);
|
||||
if ($quoteStrings) {
|
||||
$val = '"' . $val . '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* AfterRender callback. Writes any cached events to the view, or to a temp file.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
function afterRender() {
|
||||
if (!$this->enabled) {
|
||||
return;
|
||||
}
|
||||
echo $this->writeEvents(true);
|
||||
}
|
||||
}
|
||||
363
web-cake/html/cake/libs/view/helpers/jquery_engine.php
Normal file
363
web-cake/html/cake/libs/view/helpers/jquery_engine.php
Normal file
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/**
|
||||
* jQuery Engine Helper for JsHelper
|
||||
*
|
||||
* Provides jQuery specific Javascript for JsHelper.
|
||||
*
|
||||
* Implements the JsHelper interface for jQuery. All $options arrays
|
||||
* support all options found in the JsHelper, as well as those in the jQuery
|
||||
* documentation.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
|
||||
* @link http://cakephp.org CakePHP Project
|
||||
* @package cake
|
||||
* @subpackage cake.view.helpers
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Helper', 'Js');
|
||||
|
||||
class JqueryEngineHelper extends JsBaseEngineHelper {
|
||||
/**
|
||||
* Option mappings for jQuery
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_optionMap = array(
|
||||
'request' => array(
|
||||
'type' => 'dataType',
|
||||
'before' => 'beforeSend',
|
||||
'method' => 'type',
|
||||
),
|
||||
'sortable' => array(
|
||||
'complete' => 'stop',
|
||||
),
|
||||
'drag' => array(
|
||||
'snapGrid' => 'grid',
|
||||
'container' => 'containment',
|
||||
),
|
||||
'drop' => array(
|
||||
'leave' => 'out',
|
||||
'hover' => 'over'
|
||||
),
|
||||
'slider' => array(
|
||||
'complete' => 'stop',
|
||||
'direction' => 'orientation'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Callback arguments lists
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_callbackArguments = array(
|
||||
'slider' => array(
|
||||
'start' => 'event, ui',
|
||||
'slide' => 'event, ui',
|
||||
'change' => 'event, ui',
|
||||
'stop' => 'event, ui'
|
||||
),
|
||||
'sortable' => array(
|
||||
'start' => 'event, ui',
|
||||
'sort' => 'event, ui',
|
||||
'change' => 'event, ui',
|
||||
'beforeStop' => 'event, ui',
|
||||
'stop' => 'event, ui',
|
||||
'update' => 'event, ui',
|
||||
'receive' => 'event, ui',
|
||||
'remove' => 'event, ui',
|
||||
'over' => 'event, ui',
|
||||
'out' => 'event, ui',
|
||||
'activate' => 'event, ui',
|
||||
'deactivate' => 'event, ui'
|
||||
),
|
||||
'drag' => array(
|
||||
'start' => 'event, ui',
|
||||
'drag' => 'event, ui',
|
||||
'stop' => 'event, ui',
|
||||
),
|
||||
'drop' => array(
|
||||
'activate' => 'event, ui',
|
||||
'deactivate' => 'event, ui',
|
||||
'over' => 'event, ui',
|
||||
'out' => 'event, ui',
|
||||
'drop' => 'event, ui'
|
||||
),
|
||||
'request' => array(
|
||||
'beforeSend' => 'XMLHttpRequest',
|
||||
'error' => 'XMLHttpRequest, textStatus, errorThrown',
|
||||
'success' => 'data, textStatus',
|
||||
'complete' => 'XMLHttpRequest, textStatus',
|
||||
'xhr' => ''
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* The variable name of the jQuery Object, useful
|
||||
* when jQuery is put into noConflict() mode.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $jQueryObject = '$';
|
||||
|
||||
/**
|
||||
* Helper function to wrap repetitive simple method templating.
|
||||
*
|
||||
* @param string $method The method name being generated.
|
||||
* @param string $template The method template
|
||||
* @param string $selection the selection to apply
|
||||
* @param string $options Array of options for method
|
||||
* @param string $callbacks Array of callback / special options.
|
||||
* @return string Composed method string
|
||||
* @access public
|
||||
*/
|
||||
function _methodTemplate($method, $template, $options, $extraSafeKeys = array()) {
|
||||
$options = $this->_mapOptions($method, $options);
|
||||
$options = $this->_prepareCallbacks($method, $options);
|
||||
$callbacks = array_keys($this->_callbackArguments[$method]);
|
||||
if (!empty($extraSafeKeys)) {
|
||||
$callbacks = array_merge($callbacks, $extraSafeKeys);
|
||||
}
|
||||
$options = $this->_parseOptions($options, $callbacks);
|
||||
return sprintf($template, $this->selection, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create javascript selector for a CSS rule
|
||||
*
|
||||
* @param string $selector The selector that is targeted
|
||||
* @return object instance of $this. Allows chained methods.
|
||||
* @access public
|
||||
*/
|
||||
function get($selector) {
|
||||
if ($selector == 'window' || $selector == 'document') {
|
||||
$this->selection = $this->jQueryObject . '(' . $selector .')';
|
||||
} else {
|
||||
$this->selection = $this->jQueryObject . '("' . $selector . '")';
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event to the script cache. Operates on the currently selected elements.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - 'wrap' - Whether you want the callback wrapped in an anonymous function. (defaults true)
|
||||
* - 'stop' - Whether you want the event to stopped. (defaults true)
|
||||
*
|
||||
* @param string $type Type of event to bind to the current dom id
|
||||
* @param string $callback The Javascript function you wish to trigger or the function literal
|
||||
* @param array $options Options for the event.
|
||||
* @return string completed event handler
|
||||
* @access public
|
||||
*/
|
||||
function event($type, $callback, $options = array()) {
|
||||
$defaults = array('wrap' => true, 'stop' => true);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$function = 'function (event) {%s}';
|
||||
if ($options['wrap'] && $options['stop']) {
|
||||
$callback .= "\nreturn false;";
|
||||
}
|
||||
if ($options['wrap']) {
|
||||
$callback = sprintf($function, $callback);
|
||||
}
|
||||
return sprintf('%s.bind("%s", %s);', $this->selection, $type, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a domReady event. For jQuery. This method does not
|
||||
* bind a 'traditional event' as `$(document).bind('ready', fn)`
|
||||
* Works in an entirely different fashion than `$(document).ready()`
|
||||
* The first will not run the function when eval()'d as part of a response
|
||||
* The second will. Because of the way that ajax pagination is done
|
||||
* `$().ready()` is used.
|
||||
*
|
||||
* @param string $functionBody The code to run on domReady
|
||||
* @return string completed domReady method
|
||||
* @access public
|
||||
*/
|
||||
function domReady($functionBody) {
|
||||
return $this->jQueryObject . '(document).ready(function () {' . $functionBody . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an iteration over the current selection result.
|
||||
*
|
||||
* @param string $method The method you want to apply to the selection
|
||||
* @param string $callback The function body you wish to apply during the iteration.
|
||||
* @return string completed iteration
|
||||
* @access public
|
||||
*/
|
||||
function each($callback) {
|
||||
return $this->selection . '.each(function () {' . $callback . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an Effect.
|
||||
*
|
||||
* @param string $name The name of the effect to trigger.
|
||||
* @param array $options Array of options for the effect.
|
||||
* @return string completed string with effect.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::effect()
|
||||
*/
|
||||
function effect($name, $options = array()) {
|
||||
$speed = null;
|
||||
if (isset($options['speed']) && in_array($options['speed'], array('fast', 'slow'))) {
|
||||
$speed = $this->value($options['speed']);
|
||||
}
|
||||
$effect = '';
|
||||
switch ($name) {
|
||||
case 'slideIn':
|
||||
case 'slideOut':
|
||||
$name = ($name == 'slideIn') ? 'slideDown' : 'slideUp';
|
||||
case 'hide':
|
||||
case 'show':
|
||||
case 'fadeIn':
|
||||
case 'fadeOut':
|
||||
case 'slideDown':
|
||||
case 'slideUp':
|
||||
$effect = ".$name($speed);";
|
||||
break;
|
||||
}
|
||||
return $this->selection . $effect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an $.ajax() call.
|
||||
*
|
||||
* If the 'update' key is set, success callback will be overridden.
|
||||
*
|
||||
* @param mixed $url
|
||||
* @param array $options See JsHelper::request() for options.
|
||||
* @return string The completed ajax call.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::request() for options list.
|
||||
*/
|
||||
function request($url, $options = array()) {
|
||||
$url = $this->url($url);
|
||||
$options = $this->_mapOptions('request', $options);
|
||||
if (isset($options['data']) && is_array($options['data'])) {
|
||||
$options['data'] = $this->_toQuerystring($options['data']);
|
||||
}
|
||||
$options['url'] = $url;
|
||||
if (isset($options['update'])) {
|
||||
$wrapCallbacks = isset($options['wrapCallbacks']) ? $options['wrapCallbacks'] : true;
|
||||
$success = '';
|
||||
if(isset($options['success']) AND !empty($options['success'])) {
|
||||
$success .= $options['success'];
|
||||
}
|
||||
$success .= $this->jQueryObject . '("' . $options['update'] . '").html(data);';
|
||||
if (!$wrapCallbacks) {
|
||||
$success = 'function (data, textStatus) {' . $success . '}';
|
||||
}
|
||||
$options['dataType'] = 'html';
|
||||
$options['success'] = $success;
|
||||
unset($options['update']);
|
||||
}
|
||||
$callbacks = array('success', 'error', 'beforeSend', 'complete');
|
||||
if (isset($options['dataExpression'])) {
|
||||
$callbacks[] = 'data';
|
||||
unset($options['dataExpression']);
|
||||
}
|
||||
$options = $this->_prepareCallbacks('request', $options);
|
||||
$options = $this->_parseOptions($options, $callbacks);
|
||||
return $this->jQueryObject . '.ajax({' . $options .'});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sortable element.
|
||||
*
|
||||
* Requires both Ui.Core and Ui.Sortables to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the sortable.
|
||||
* @return string Completed sortable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::sortable() for options list.
|
||||
*/
|
||||
function sortable($options = array()) {
|
||||
$template = '%s.sortable({%s});';
|
||||
return $this->_methodTemplate('sortable', $template, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Draggable element
|
||||
*
|
||||
* Requires both Ui.Core and Ui.Draggable to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the draggable element.
|
||||
* @return string Completed Draggable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::drag() for options list.
|
||||
*/
|
||||
function drag($options = array()) {
|
||||
$template = '%s.draggable({%s});';
|
||||
return $this->_methodTemplate('drag', $template, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Droppable element
|
||||
*
|
||||
* Requires both Ui.Core and Ui.Droppable to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the droppable element.
|
||||
* @return string Completed Droppable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::drop() for options list.
|
||||
*/
|
||||
function drop($options = array()) {
|
||||
$template = '%s.droppable({%s});';
|
||||
return $this->_methodTemplate('drop', $template, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Slider element
|
||||
*
|
||||
* Requires both Ui.Core and Ui.Slider to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the droppable element.
|
||||
* @return string Completed Slider script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::slider() for options list.
|
||||
*/
|
||||
function slider($options = array()) {
|
||||
$callbacks = array('start', 'change', 'slide', 'stop');
|
||||
$template = '%s.slider({%s});';
|
||||
return $this->_methodTemplate('slider', $template, $options, $callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a form attached to $selector. If the current selection is not an input or
|
||||
* form, errors will be created in the Javascript.
|
||||
*
|
||||
* @param array $options Options for the serialization
|
||||
* @return string completed form serialization script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::serializeForm() for option list.
|
||||
*/
|
||||
function serializeForm($options = array()) {
|
||||
$options = array_merge(array('isForm' => false, 'inline' => false), $options);
|
||||
$selector = $this->selection;
|
||||
if (!$options['isForm']) {
|
||||
$selector = $this->selection . '.closest("form")';
|
||||
}
|
||||
$method = '.serialize()';
|
||||
if (!$options['inline']) {
|
||||
$method .= ';';
|
||||
}
|
||||
return $selector . $method;
|
||||
}
|
||||
}
|
||||
1128
web-cake/html/cake/libs/view/helpers/js.php
Normal file
1128
web-cake/html/cake/libs/view/helpers/js.php
Normal file
File diff suppressed because it is too large
Load Diff
374
web-cake/html/cake/libs/view/helpers/mootools_engine.php
Normal file
374
web-cake/html/cake/libs/view/helpers/mootools_engine.php
Normal file
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
/**
|
||||
* MooTools Engine Helper for JsHelper
|
||||
*
|
||||
* Provides MooTools specific Javascript for JsHelper.
|
||||
* Assumes that you have the following MooTools packages
|
||||
*
|
||||
* - Remote, Remote.HTML, Remote.JSON
|
||||
* - Fx, Fx.Tween, Fx.Morph
|
||||
* - Selectors, DomReady,
|
||||
* - Drag, Drag.Move
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Helper', 'Js');
|
||||
|
||||
class MootoolsEngineHelper extends JsBaseEngineHelper {
|
||||
/**
|
||||
* Option mappings for MooTools
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_optionMap = array(
|
||||
'request' => array(
|
||||
'complete' => 'onComplete',
|
||||
'success' => 'onSuccess',
|
||||
'before' => 'onRequest',
|
||||
'error' => 'onFailure'
|
||||
),
|
||||
'sortable' => array(
|
||||
'distance' => 'snap',
|
||||
'containment' => 'constrain',
|
||||
'sort' => 'onSort',
|
||||
'complete' => 'onComplete',
|
||||
'start' => 'onStart',
|
||||
),
|
||||
'drag' => array(
|
||||
'snapGrid' => 'snap',
|
||||
'start' => 'onStart',
|
||||
'drag' => 'onDrag',
|
||||
'stop' => 'onComplete',
|
||||
),
|
||||
'drop' => array(
|
||||
'drop' => 'onDrop',
|
||||
'hover' => 'onEnter',
|
||||
'leave' => 'onLeave',
|
||||
),
|
||||
'slider' => array(
|
||||
'complete' => 'onComplete',
|
||||
'change' => 'onChange',
|
||||
'direction' => 'mode',
|
||||
'step' => 'steps'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Contains a list of callback names -> default arguments.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_callbackArguments = array(
|
||||
'slider' => array(
|
||||
'onTick' => 'position',
|
||||
'onChange' => 'step',
|
||||
'onComplete' => 'event'
|
||||
),
|
||||
'request' => array(
|
||||
'onRequest' => '',
|
||||
'onComplete' => '',
|
||||
'onCancel' => '',
|
||||
'onSuccess' => 'responseText, responseXML',
|
||||
'onFailure' => 'xhr',
|
||||
'onException' => 'headerName, value',
|
||||
),
|
||||
'drag' => array(
|
||||
'onBeforeStart' => 'element',
|
||||
'onStart' => 'element',
|
||||
'onSnap' => 'element',
|
||||
'onDrag' => 'element, event',
|
||||
'onComplete' => 'element, event',
|
||||
'onCancel' => 'element',
|
||||
),
|
||||
'drop' => array(
|
||||
'onBeforeStart' => 'element',
|
||||
'onStart' => 'element',
|
||||
'onSnap' => 'element',
|
||||
'onDrag' => 'element, event',
|
||||
'onComplete' => 'element, event',
|
||||
'onCancel' => 'element',
|
||||
'onDrop' => 'element, droppable, event',
|
||||
'onLeave' => 'element, droppable',
|
||||
'onEnter' => 'element, droppable',
|
||||
),
|
||||
'sortable' => array(
|
||||
'onStart' => 'element, clone',
|
||||
'onSort' => 'element, clone',
|
||||
'onComplete' => 'element',
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Create javascript selector for a CSS rule
|
||||
*
|
||||
* @param string $selector The selector that is targeted
|
||||
* @return object instance of $this. Allows chained methods.
|
||||
*/
|
||||
function get($selector) {
|
||||
$this->_multipleSelection = false;
|
||||
if ($selector == 'window' || $selector == 'document') {
|
||||
$this->selection = "$(" . $selector .")";
|
||||
return $this;
|
||||
}
|
||||
if (preg_match('/^#[^\s.]+$/', $selector)) {
|
||||
$this->selection = '$("' . substr($selector, 1) . '")';
|
||||
return $this;
|
||||
}
|
||||
$this->_multipleSelection = true;
|
||||
$this->selection = '$$("' . $selector . '")';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event to the script cache. Operates on the currently selected elements.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - 'wrap' - Whether you want the callback wrapped in an anonymous function. (defaults true)
|
||||
* - 'stop' - Whether you want the event to stopped. (defaults true)
|
||||
*
|
||||
* @param string $type Type of event to bind to the current dom id
|
||||
* @param string $callback The Javascript function you wish to trigger or the function literal
|
||||
* @param array $options Options for the event.
|
||||
* @return string completed event handler
|
||||
*/
|
||||
function event($type, $callback, $options = array()) {
|
||||
$defaults = array('wrap' => true, 'stop' => true);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$function = 'function (event) {%s}';
|
||||
if ($options['wrap'] && $options['stop']) {
|
||||
$callback = "event.stop();\n" . $callback;
|
||||
}
|
||||
if ($options['wrap']) {
|
||||
$callback = sprintf($function, $callback);
|
||||
}
|
||||
$out = $this->selection . ".addEvent(\"{$type}\", $callback);";
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a domReady event. This is a special event in many libraries
|
||||
*
|
||||
* @param string $functionBody The code to run on domReady
|
||||
* @return string completed domReady method
|
||||
*/
|
||||
function domReady($functionBody) {
|
||||
$this->selection = 'window';
|
||||
return $this->event('domready', $functionBody, array('stop' => false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an iteration over the current selection result.
|
||||
*
|
||||
* @param string $method The method you want to apply to the selection
|
||||
* @param string $callback The function body you wish to apply during the iteration.
|
||||
* @return string completed iteration
|
||||
*/
|
||||
function each($callback) {
|
||||
return $this->selection . '.each(function (item, index) {' . $callback . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an Effect.
|
||||
*
|
||||
* @param string $name The name of the effect to trigger.
|
||||
* @param array $options Array of options for the effect.
|
||||
* @return string completed string with effect.
|
||||
* @see JsBaseEngineHelper::effect()
|
||||
*/
|
||||
function effect($name, $options = array()) {
|
||||
$speed = null;
|
||||
if (isset($options['speed']) && in_array($options['speed'], array('fast', 'slow'))) {
|
||||
if ($options['speed'] == 'fast') {
|
||||
$speed = '"short"';
|
||||
} elseif ($options['speed'] == 'slow') {
|
||||
$speed = '"long"';
|
||||
}
|
||||
}
|
||||
$effect = '';
|
||||
switch ($name) {
|
||||
case 'hide':
|
||||
$effect = 'setStyle("display", "none")';
|
||||
break;
|
||||
case 'show':
|
||||
$effect = 'setStyle("display", "")';
|
||||
break;
|
||||
case 'fadeIn':
|
||||
case 'fadeOut':
|
||||
case 'slideIn':
|
||||
case 'slideOut':
|
||||
list($effectName, $direction) = preg_split('/([A-Z][a-z]+)/', $name, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$direction = strtolower($direction);
|
||||
if ($speed) {
|
||||
$effect .= "set(\"$effectName\", {duration:$speed}).";
|
||||
}
|
||||
$effect .= "$effectName(\"$direction\")";
|
||||
break;
|
||||
}
|
||||
return $this->selection . '.' . $effect . ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an new Request.
|
||||
*
|
||||
* Requires `Request`. If you wish to use 'update' key you must have ```Request.HTML```
|
||||
* if you wish to do Json requests you will need ```JSON``` and ```Request.JSON```.
|
||||
*
|
||||
* @param mixed $url
|
||||
* @param array $options
|
||||
* @return string The completed ajax call.
|
||||
*/
|
||||
function request($url, $options = array()) {
|
||||
$url = $this->url($url);
|
||||
$options = $this->_mapOptions('request', $options);
|
||||
$type = $data = null;
|
||||
if (isset($options['type']) || isset($options['update'])) {
|
||||
if (isset($options['type']) && strtolower($options['type']) == 'json') {
|
||||
$type = '.JSON';
|
||||
}
|
||||
if (isset($options['update'])) {
|
||||
$options['update'] = str_replace('#', '', $options['update']);
|
||||
$type = '.HTML';
|
||||
}
|
||||
unset($options['type']);
|
||||
}
|
||||
if (!empty($options['data'])) {
|
||||
$data = $options['data'];
|
||||
unset($options['data']);
|
||||
}
|
||||
$options['url'] = $url;
|
||||
$options = $this->_prepareCallbacks('request', $options);
|
||||
if (isset($options['dataExpression'])) {
|
||||
$callbacks[] = 'data';
|
||||
unset($options['dataExpression']);
|
||||
} elseif (!empty($data)) {
|
||||
$data = $this->object($data);
|
||||
}
|
||||
$options = $this->_parseOptions($options, array_keys($this->_callbackArguments['request']));
|
||||
return "var jsRequest = new Request$type({{$options}}).send($data);";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sortable element.
|
||||
*
|
||||
* Requires the `Sortables` plugin from MootoolsMore
|
||||
*
|
||||
* @param array $options Array of options for the sortable.
|
||||
* @return string Completed sortable script.
|
||||
* @see JsBaseEngineHelper::sortable() for options list.
|
||||
*/
|
||||
function sortable($options = array()) {
|
||||
$options = $this->_processOptions('sortable', $options);
|
||||
return 'var jsSortable = new Sortables(' . $this->selection . ', {' . $options . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Draggable element.
|
||||
*
|
||||
* Requires the `Drag` plugin from MootoolsMore
|
||||
*
|
||||
* @param array $options Array of options for the draggable.
|
||||
* @return string Completed draggable script.
|
||||
* @see JsHelper::drag() for options list.
|
||||
*/
|
||||
function drag($options = array()) {
|
||||
$options = $this->_processOptions('drag', $options);
|
||||
return $this->selection . '.makeDraggable({' . $options . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Droppable element.
|
||||
*
|
||||
* Requires the `Drag` and `Drag.Move` plugins from MootoolsMore
|
||||
*
|
||||
* Droppables in Mootools function differently from other libraries. Droppables
|
||||
* are implemented as an extension of Drag. So in addtion to making a get() selection for
|
||||
* the droppable element. You must also provide a selector rule to the draggable element. Furthermore,
|
||||
* Mootools droppables inherit all options from Drag.
|
||||
*
|
||||
* @param array $options Array of options for the droppable.
|
||||
* @return string Completed droppable script.
|
||||
* @see JsBaseEngineHelper::drop() for options list.
|
||||
*/
|
||||
function drop($options = array()) {
|
||||
if (empty($options['drag'])) {
|
||||
trigger_error(
|
||||
__('MootoolsEngine::drop() requires a "drag" option to properly function', true), E_USER_WARNING
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$options['droppables'] = $this->selection;
|
||||
|
||||
$this->get($options['drag']);
|
||||
unset($options['drag']);
|
||||
|
||||
$options = $this->_mapOptions('drag', $this->_mapOptions('drop', $options));
|
||||
$options = $this->_prepareCallbacks('drop', $options);
|
||||
$safe = array_merge(array_keys($this->_callbackArguments['drop']), array('droppables'));
|
||||
$optionString = $this->_parseOptions($options, $safe);
|
||||
$out = $this->selection . '.makeDraggable({' . $optionString . '});';
|
||||
$this->selection = $options['droppables'];
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a slider control
|
||||
*
|
||||
* Requires `Slider` from MootoolsMore
|
||||
*
|
||||
* @param array $options Array of options for the slider.
|
||||
* @return string Completed slider script.
|
||||
* @see JsBaseEngineHelper::slider() for options list.
|
||||
*/
|
||||
function slider($options = array()) {
|
||||
$slider = $this->selection;
|
||||
$this->get($options['handle']);
|
||||
unset($options['handle']);
|
||||
|
||||
if (isset($options['min']) && isset($options['max'])) {
|
||||
$options['range'] = array($options['min'], $options['max']);
|
||||
unset($options['min'], $options['max']);
|
||||
}
|
||||
$optionString = $this->_processOptions('slider', $options);
|
||||
if (!empty($optionString)) {
|
||||
$optionString = ', {' . $optionString . '}';
|
||||
}
|
||||
$out = 'var jsSlider = new Slider(' . $slider . ', ' . $this->selection . $optionString . ');';
|
||||
$this->selection = $slider;
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the form attached to $selector.
|
||||
*
|
||||
* @param array $options Array of options.
|
||||
* @return string Completed serializeForm() snippet
|
||||
* @see JsBaseEngineHelper::serializeForm()
|
||||
*/
|
||||
function serializeForm($options = array()) {
|
||||
$options = array_merge(array('isForm' => false, 'inline' => false), $options);
|
||||
$selection = $this->selection;
|
||||
if (!$options['isForm']) {
|
||||
$selection = '$(' . $this->selection . '.form)';
|
||||
}
|
||||
$method = '.toQueryString()';
|
||||
if (!$options['inline']) {
|
||||
$method .= ';';
|
||||
}
|
||||
return $selection . $method;
|
||||
}
|
||||
}
|
||||
257
web-cake/html/cake/libs/view/helpers/number.php
Normal file
257
web-cake/html/cake/libs/view/helpers/number.php
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
/**
|
||||
* Number Helper.
|
||||
*
|
||||
* Methods to make numbers more readable.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Number helper library.
|
||||
*
|
||||
* Methods to make numbers more readable.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1452/Number
|
||||
*/
|
||||
class NumberHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Currencies supported by the helper. You can add additional currency formats
|
||||
* with NumberHelper::addFormat
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_currencies = array(
|
||||
'USD' => array(
|
||||
'before' => '$', 'after' => 'c', 'zero' => 0, 'places' => 2, 'thousands' => ',',
|
||||
'decimals' => '.', 'negative' => '()', 'escape' => true
|
||||
),
|
||||
'GBP' => array(
|
||||
'before'=>'£', 'after' => 'p', 'zero' => 0, 'places' => 2, 'thousands' => ',',
|
||||
'decimals' => '.', 'negative' => '()','escape' => false
|
||||
),
|
||||
'EUR' => array(
|
||||
'before'=>'€', 'after' => false, 'zero' => 0, 'places' => 2, 'thousands' => '.',
|
||||
'decimals' => ',', 'negative' => '()', 'escape' => false
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Default options for currency formats
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_currencyDefaults = array(
|
||||
'before'=>'', 'after' => '', 'zero' => '0', 'places' => 2, 'thousands' => ',',
|
||||
'decimals' => '.','negative' => '()', 'escape' => true
|
||||
);
|
||||
|
||||
/**
|
||||
* Formats a number with a level of precision.
|
||||
*
|
||||
* @param float $number A floating point number.
|
||||
* @param integer $precision The precision of the returned number.
|
||||
* @return float Formatted float.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1454/precision
|
||||
*/
|
||||
function precision($number, $precision = 3) {
|
||||
return sprintf("%01.{$precision}f", $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted-for-humans file size.
|
||||
*
|
||||
* @param integer $length Size in bytes
|
||||
* @return string Human readable size
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1456/toReadableSize
|
||||
*/
|
||||
function toReadableSize($size) {
|
||||
switch (true) {
|
||||
case $size < 1024:
|
||||
return sprintf(__n('%d Byte', '%d Bytes', $size, true), $size);
|
||||
case round($size / 1024) < 1024:
|
||||
return sprintf(__('%d KB', true), $this->precision($size / 1024, 0));
|
||||
case round($size / 1024 / 1024, 2) < 1024:
|
||||
return sprintf(__('%.2f MB', true), $this->precision($size / 1024 / 1024, 2));
|
||||
case round($size / 1024 / 1024 / 1024, 2) < 1024:
|
||||
return sprintf(__('%.2f GB', true), $this->precision($size / 1024 / 1024 / 1024, 2));
|
||||
default:
|
||||
return sprintf(__('%.2f TB', true), $this->precision($size / 1024 / 1024 / 1024 / 1024, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number into a percentage string.
|
||||
*
|
||||
* @param float $number A floating point number
|
||||
* @param integer $precision The precision of the returned number
|
||||
* @return string Percentage string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1455/toPercentage
|
||||
*/
|
||||
function toPercentage($number, $precision = 2) {
|
||||
return $this->precision($number, $precision) . '%';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number into a currency format.
|
||||
*
|
||||
* @param float $number A floating point number
|
||||
* @param integer $options if int then places, if string then before, if (,.-) then use it
|
||||
* or array with places and before keys
|
||||
* @return string formatted number
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1457/format
|
||||
*/
|
||||
function format($number, $options = false) {
|
||||
$places = 0;
|
||||
if (is_int($options)) {
|
||||
$places = $options;
|
||||
}
|
||||
|
||||
$separators = array(',', '.', '-', ':');
|
||||
|
||||
$before = $after = null;
|
||||
if (is_string($options) && !in_array($options, $separators)) {
|
||||
$before = $options;
|
||||
}
|
||||
$thousands = ',';
|
||||
if (!is_array($options) && in_array($options, $separators)) {
|
||||
$thousands = $options;
|
||||
}
|
||||
$decimals = '.';
|
||||
if (!is_array($options) && in_array($options, $separators)) {
|
||||
$decimals = $options;
|
||||
}
|
||||
|
||||
$escape = true;
|
||||
if (is_array($options)) {
|
||||
$options = array_merge(array('before'=>'$', 'places' => 2, 'thousands' => ',', 'decimals' => '.'), $options);
|
||||
extract($options);
|
||||
}
|
||||
|
||||
$out = $before . number_format($number, $places, $decimals, $thousands) . $after;
|
||||
|
||||
if ($escape) {
|
||||
return h($out);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number into a currency format.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `before` - The currency symbol to place before whole numbers ie. '$'
|
||||
* - `after` - The currency symbol to place after decimal numbers ie. 'c'. Set to boolean false to
|
||||
* use no decimal symbol. eg. 0.35 => $0.35.
|
||||
* - `zero` - The text to use for zero values, can be a string or a number. ie. 0, 'Free!'
|
||||
* - `places` - Number of decimal places to use. ie. 2
|
||||
* - `thousands` - Thousands separator ie. ','
|
||||
* - `decimals` - Decimal separator symbol ie. '.'
|
||||
* - `negative` - Symbol for negative numbers. If equal to '()', the number will be wrapped with ( and )
|
||||
* - `escape` - Should the output be htmlentity escaped? Defaults to true
|
||||
*
|
||||
* @param float $number
|
||||
* @param string $currency Shortcut to default options. Valid values are 'USD', 'EUR', 'GBP', otherwise
|
||||
* set at least 'before' and 'after' options.
|
||||
* @param array $options
|
||||
* @return string Number formatted as a currency.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1453/currency
|
||||
*/
|
||||
function currency($number, $currency = 'USD', $options = array()) {
|
||||
$default = $this->_currencyDefaults;
|
||||
|
||||
if (isset($this->_currencies[$currency])) {
|
||||
$default = $this->_currencies[$currency];
|
||||
} elseif (is_string($currency)) {
|
||||
$options['before'] = $currency;
|
||||
}
|
||||
|
||||
$options = array_merge($default, $options);
|
||||
|
||||
$result = null;
|
||||
|
||||
if ($number == 0 ) {
|
||||
if ($options['zero'] !== 0 ) {
|
||||
return $options['zero'];
|
||||
}
|
||||
$options['after'] = null;
|
||||
} elseif ($number < 1 && $number > -1 ) {
|
||||
if ($options['after'] !== false) {
|
||||
$multiply = intval('1' . str_pad('', $options['places'], '0'));
|
||||
$number = $number * $multiply;
|
||||
$options['before'] = null;
|
||||
$options['places'] = null;
|
||||
}
|
||||
} elseif (empty($options['before'])) {
|
||||
$options['before'] = null;
|
||||
} else {
|
||||
$options['after'] = null;
|
||||
}
|
||||
|
||||
$abs = abs($number);
|
||||
$result = $this->format($abs, $options);
|
||||
|
||||
if ($number < 0 ) {
|
||||
if ($options['negative'] == '()') {
|
||||
$result = '(' . $result .')';
|
||||
} else {
|
||||
$result = $options['negative'] . $result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a currency format to the Number helper. Makes reusing
|
||||
* currency formats easier.
|
||||
*
|
||||
* {{{ $number->addFormat('NOK', array('before' => 'Kr. ')); }}}
|
||||
*
|
||||
* You can now use `NOK` as a shortform when formatting currency amounts.
|
||||
*
|
||||
* {{{ $number->currency($value, 'NOK'); }}}
|
||||
*
|
||||
* Added formats are merged with the following defaults.
|
||||
*
|
||||
* {{{
|
||||
* array(
|
||||
* 'before' => '$', 'after' => 'c', 'zero' => 0, 'places' => 2, 'thousands' => ',',
|
||||
* 'decimals' => '.', 'negative' => '()', 'escape' => true
|
||||
* )
|
||||
* }}}
|
||||
*
|
||||
* @param string $formatName The format name to be used in the future.
|
||||
* @param array $options The array of options for this format.
|
||||
* @return void
|
||||
* @see NumberHelper::currency()
|
||||
* @access public
|
||||
*/
|
||||
function addFormat($formatName, $options) {
|
||||
$this->_currencies[$formatName] = $options + $this->_currencyDefaults;
|
||||
}
|
||||
|
||||
}
|
||||
813
web-cake/html/cake/libs/view/helpers/paginator.php
Normal file
813
web-cake/html/cake/libs/view/helpers/paginator.php
Normal file
@@ -0,0 +1,813 @@
|
||||
<?php
|
||||
/**
|
||||
* Pagination Helper class file.
|
||||
*
|
||||
* Generates pagination links
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.2.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pagination Helper class for easy generation of pagination links.
|
||||
*
|
||||
* PaginationHelper encloses all methods needed when working with pagination.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1458/Paginator
|
||||
*/
|
||||
class PaginatorHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Helper dependencies
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $helpers = array('Html');
|
||||
|
||||
/**
|
||||
* Holds the default model for paged recordsets
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $__defaultModel = null;
|
||||
|
||||
/**
|
||||
* The class used for 'Ajax' pagination links.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_ajaxHelperClass = 'Js';
|
||||
|
||||
/**
|
||||
* Holds the default options for pagination links
|
||||
*
|
||||
* The values that may be specified are:
|
||||
*
|
||||
* - `$options['format']` Format of the counter. Supported formats are 'range' and 'pages'
|
||||
* and custom (default). In the default mode the supplied string is parsed and constants are replaced
|
||||
* by their actual values.
|
||||
* Constants: %page%, %pages%, %current%, %count%, %start%, %end% .
|
||||
* - `$options['separator']` The separator of the actual page and number of pages (default: ' of ').
|
||||
* - `$options['url']` Url of the action. See Router::url()
|
||||
* - `$options['url']['sort']` the key that the recordset is sorted.
|
||||
* - `$options['url']['direction']` Direction of the sorting (default: 'asc').
|
||||
* - `$options['url']['page']` Page # to display.
|
||||
* - `$options['model']` The name of the model.
|
||||
* - `$options['escape']` Defines if the title field for the link should be escaped (default: true).
|
||||
* - `$options['update']` DOM id of the element updated with the results of the AJAX call.
|
||||
* If this key isn't specified Paginator will use plain HTML links.
|
||||
* - `$options['indicator']` DOM id of the element that will be shown when doing AJAX requests. **Only supported by
|
||||
* AjaxHelper**
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $options = array();
|
||||
|
||||
/**
|
||||
* Constructor for the helper. Sets up the helper that is used for creating 'AJAX' links.
|
||||
*
|
||||
* Use `var $helpers = array('Paginator' => array('ajax' => 'CustomHelper'));` to set a custom Helper
|
||||
* or choose a non JsHelper Helper. If you want to use a specific library with JsHelper declare JsHelper and its
|
||||
* adapter before including PaginatorHelper in your helpers array.
|
||||
*
|
||||
* The chosen custom helper must implement a `link()` method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct($config = array()) {
|
||||
$ajaxProvider = isset($config['ajax']) ? $config['ajax'] : 'Js';
|
||||
$this->helpers[] = $ajaxProvider;
|
||||
$this->_ajaxHelperClass = $ajaxProvider;
|
||||
|
||||
App::import('Helper', $ajaxProvider);
|
||||
$classname = $ajaxProvider . 'Helper';
|
||||
if (!is_callable(array($classname, 'link'))) {
|
||||
trigger_error(sprintf(__('%s does not implement a link() method, it is incompatible with PaginatorHelper', true), $classname), E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Before render callback. Overridden to merge passed args with url options.
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function beforeRender() {
|
||||
$this->options['url'] = array_merge($this->params['pass'], $this->params['named']);
|
||||
|
||||
parent::beforeRender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current paging parameters from the resultset for the given model
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @return array The array of paging parameters for the paginated resultset.
|
||||
* @access public
|
||||
*/
|
||||
function params($model = null) {
|
||||
if (empty($model)) {
|
||||
$model = $this->defaultModel();
|
||||
}
|
||||
if (!isset($this->params['paging']) || empty($this->params['paging'][$model])) {
|
||||
return null;
|
||||
}
|
||||
return $this->params['paging'][$model];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default options for all pagination links
|
||||
*
|
||||
* @param mixed $options Default options for pagination links. If a string is supplied - it
|
||||
* is used as the DOM id element to update. See PaginatorHelper::$options for list of keys.
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
function options($options = array()) {
|
||||
if (is_string($options)) {
|
||||
$options = array('update' => $options);
|
||||
}
|
||||
|
||||
if (!empty($options['paging'])) {
|
||||
if (!isset($this->params['paging'])) {
|
||||
$this->params['paging'] = array();
|
||||
}
|
||||
$this->params['paging'] = array_merge($this->params['paging'], $options['paging']);
|
||||
unset($options['paging']);
|
||||
}
|
||||
$model = $this->defaultModel();
|
||||
|
||||
if (!empty($options[$model])) {
|
||||
if (!isset($this->params['paging'][$model])) {
|
||||
$this->params['paging'][$model] = array();
|
||||
}
|
||||
$this->params['paging'][$model] = array_merge(
|
||||
$this->params['paging'][$model], $options[$model]
|
||||
);
|
||||
unset($options[$model]);
|
||||
}
|
||||
$this->options = array_filter(array_merge($this->options, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current page of the recordset for the given model
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @return string The current page number of the recordset.
|
||||
* @access public
|
||||
*/
|
||||
function current($model = null) {
|
||||
$params = $this->params($model);
|
||||
|
||||
if (isset($params['page'])) {
|
||||
return $params['page'];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current key by which the recordset is sorted
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @param mixed $options Options for pagination links. See #options for list of keys.
|
||||
* @return string The name of the key by which the recordset is being sorted, or
|
||||
* null if the results are not currently sorted.
|
||||
* @access public
|
||||
*/
|
||||
function sortKey($model = null, $options = array()) {
|
||||
if (empty($options)) {
|
||||
$params = $this->params($model);
|
||||
$options = array_merge($params['defaults'], $params['options']);
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && !empty($options['sort'])) {
|
||||
return $options['sort'];
|
||||
} elseif (isset($options['order']) && is_array($options['order'])) {
|
||||
return key($options['order']);
|
||||
} elseif (isset($options['order']) && is_string($options['order'])) {
|
||||
return $options['order'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current direction the recordset is sorted
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @param mixed $options Options for pagination links. See #options for list of keys.
|
||||
* @return string The direction by which the recordset is being sorted, or
|
||||
* null if the results are not currently sorted.
|
||||
* @access public
|
||||
*/
|
||||
function sortDir($model = null, $options = array()) {
|
||||
$dir = null;
|
||||
|
||||
if (empty($options)) {
|
||||
$params = $this->params($model);
|
||||
$options = array_merge($params['defaults'], $params['options']);
|
||||
}
|
||||
|
||||
if (isset($options['direction'])) {
|
||||
$dir = strtolower($options['direction']);
|
||||
} elseif (isset($options['order']) && is_array($options['order'])) {
|
||||
$dir = strtolower(current($options['order']));
|
||||
}
|
||||
|
||||
if ($dir == 'desc') {
|
||||
return 'desc';
|
||||
}
|
||||
return 'asc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a "previous" link for a set of paged records
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
|
||||
* - `escape` Whether you want the contents html entity encoded, defaults to true
|
||||
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
|
||||
*
|
||||
* @param string $title Title for the link. Defaults to '<< Previous'.
|
||||
* @param mixed $options Options for pagination link. See #options for list of keys.
|
||||
* @param string $disabledTitle Title when the link is disabled.
|
||||
* @param mixed $disabledOptions Options for the disabled pagination link. See #options for list of keys.
|
||||
* @return string A "previous" link or $disabledTitle text if the link is disabled.
|
||||
* @access public
|
||||
*/
|
||||
function prev($title = '<< Previous', $options = array(), $disabledTitle = null, $disabledOptions = array()) {
|
||||
return $this->__pagingLink('Prev', $title, $options, $disabledTitle, $disabledOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a "next" link for a set of paged records
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
|
||||
* - `escape` Whether you want the contents html entity encoded, defaults to true
|
||||
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
|
||||
*
|
||||
* @param string $title Title for the link. Defaults to 'Next >>'.
|
||||
* @param mixed $options Options for pagination link. See above for list of keys.
|
||||
* @param string $disabledTitle Title when the link is disabled.
|
||||
* @param mixed $disabledOptions Options for the disabled pagination link. See above for list of keys.
|
||||
* @return string A "next" link or or $disabledTitle text if the link is disabled.
|
||||
* @access public
|
||||
*/
|
||||
function next($title = 'Next >>', $options = array(), $disabledTitle = null, $disabledOptions = array()) {
|
||||
return $this->__pagingLink('Next', $title, $options, $disabledTitle, $disabledOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a sorting link. Sets named parameters for the sort and direction. Handles
|
||||
* direction switching automatically.
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `escape` Whether you want the contents html entity encoded, defaults to true
|
||||
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
|
||||
*
|
||||
* @param string $title Title for the link.
|
||||
* @param string $key The name of the key that the recordset should be sorted. If $key is null
|
||||
* $title will be used for the key, and a title will be generated by inflection.
|
||||
* @param array $options Options for sorting link. See above for list of keys.
|
||||
* @return string A link sorting default by 'asc'. If the resultset is sorted 'asc' by the specified
|
||||
* key the returned link will sort by 'desc'.
|
||||
* @access public
|
||||
*/
|
||||
function sort($title, $key = null, $options = array()) {
|
||||
$options = array_merge(array('url' => array(), 'model' => null), $options);
|
||||
$url = $options['url'];
|
||||
unset($options['url']);
|
||||
|
||||
if (empty($key)) {
|
||||
$key = $title;
|
||||
$title = __(Inflector::humanize(preg_replace('/_id$/', '', $title)), true);
|
||||
}
|
||||
$dir = isset($options['direction']) ? $options['direction'] : 'asc';
|
||||
unset($options['direction']);
|
||||
|
||||
$sortKey = $this->sortKey($options['model']);
|
||||
$defaultModel = $this->defaultModel();
|
||||
$isSorted = (
|
||||
$sortKey === $key ||
|
||||
$sortKey === $defaultModel . '.' . $key ||
|
||||
$key === $defaultModel . '.' . $sortKey
|
||||
);
|
||||
|
||||
if ($isSorted) {
|
||||
$dir = $this->sortDir($options['model']) === 'asc' ? 'desc' : 'asc';
|
||||
$class = $dir === 'asc' ? 'desc' : 'asc';
|
||||
if (!empty($options['class'])) {
|
||||
$options['class'] .= ' ' . $class;
|
||||
} else {
|
||||
$options['class'] = $class;
|
||||
}
|
||||
}
|
||||
if (is_array($title) && array_key_exists($dir, $title)) {
|
||||
$title = $title[$dir];
|
||||
}
|
||||
|
||||
$url = array_merge(array('sort' => $key, 'direction' => $dir), $url, array('order' => null));
|
||||
return $this->link($title, $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a plain or Ajax link with pagination parameters
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `update` The Id of the DOM element you wish to update. Creates Ajax enabled links
|
||||
* with the AjaxHelper.
|
||||
* - `escape` Whether you want the contents html entity encoded, defaults to true
|
||||
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
|
||||
*
|
||||
* @param string $title Title for the link.
|
||||
* @param mixed $url Url for the action. See Router::url()
|
||||
* @param array $options Options for the link. See #options for list of keys.
|
||||
* @return string A link with pagination parameters.
|
||||
* @access public
|
||||
*/
|
||||
function link($title, $url = array(), $options = array()) {
|
||||
$options = array_merge(array('model' => null, 'escape' => true), $options);
|
||||
$model = $options['model'];
|
||||
unset($options['model']);
|
||||
|
||||
if (!empty($this->options)) {
|
||||
$options = array_merge($this->options, $options);
|
||||
}
|
||||
if (isset($options['url'])) {
|
||||
$url = array_merge((array)$options['url'], (array)$url);
|
||||
unset($options['url']);
|
||||
}
|
||||
$url = $this->url($url, true, $model);
|
||||
|
||||
$obj = isset($options['update']) ? $this->_ajaxHelperClass : 'Html';
|
||||
$url = array_merge(array('page' => $this->current($model)), $url);
|
||||
$url = array_merge(Set::filter($url, true), array_intersect_key($url, array('plugin' => true)));
|
||||
return $this->{$obj}->link($title, $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges passed URL options with current pagination state to generate a pagination URL.
|
||||
*
|
||||
* @param array $options Pagination/URL options array
|
||||
* @param boolean $asArray Return the url as an array, or a URI string
|
||||
* @param string $model Which model to paginate on
|
||||
* @return mixed By default, returns a full pagination URL string for use in non-standard contexts (i.e. JavaScript)
|
||||
* @access public
|
||||
*/
|
||||
function url($options = array(), $asArray = false, $model = null) {
|
||||
$paging = $this->params($model);
|
||||
$url = array_merge(array_filter(Set::diff(array_merge(
|
||||
$paging['defaults'], $paging['options']), $paging['defaults'])), $options
|
||||
);
|
||||
|
||||
if (isset($url['order'])) {
|
||||
$sort = $direction = null;
|
||||
if (is_array($url['order'])) {
|
||||
list($sort, $direction) = array($this->sortKey($model, $url), current($url['order']));
|
||||
}
|
||||
unset($url['order']);
|
||||
$url = array_merge($url, compact('sort', 'direction'));
|
||||
}
|
||||
|
||||
if ($asArray) {
|
||||
return $url;
|
||||
}
|
||||
return parent::url($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected method for generating prev/next links
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
function __pagingLink($which, $title = null, $options = array(), $disabledTitle = null, $disabledOptions = array()) {
|
||||
$check = 'has' . $which;
|
||||
$_defaults = array(
|
||||
'url' => array(), 'step' => 1, 'escape' => true,
|
||||
'model' => null, 'tag' => 'span', 'class' => strtolower($which)
|
||||
);
|
||||
$options = array_merge($_defaults, (array)$options);
|
||||
$paging = $this->params($options['model']);
|
||||
if (empty($disabledOptions)) {
|
||||
$disabledOptions = $options;
|
||||
}
|
||||
|
||||
if (!$this->{$check}($options['model']) && (!empty($disabledTitle) || !empty($disabledOptions))) {
|
||||
if (!empty($disabledTitle) && $disabledTitle !== true) {
|
||||
$title = $disabledTitle;
|
||||
}
|
||||
$options = array_merge($_defaults, (array)$disabledOptions);
|
||||
} elseif (!$this->{$check}($options['model'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (array_keys($_defaults) as $key) {
|
||||
${$key} = $options[$key];
|
||||
unset($options[$key]);
|
||||
}
|
||||
$url = array_merge(array('page' => $paging['page'] + ($which == 'Prev' ? $step * -1 : $step)), $url);
|
||||
|
||||
if ($this->{$check}($model)) {
|
||||
return $this->Html->tag($tag, $this->link($title, $url, array_merge($options, compact('escape', 'class'))));
|
||||
} else {
|
||||
return $this->Html->tag($tag, $title, array_merge($options, compact('escape', 'class')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given result set is not at the first page
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @return boolean True if the result set is not at the first page.
|
||||
* @access public
|
||||
*/
|
||||
function hasPrev($model = null) {
|
||||
return $this->__hasPage($model, 'prev');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given result set is not at the last page
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @return boolean True if the result set is not at the last page.
|
||||
* @access public
|
||||
*/
|
||||
function hasNext($model = null) {
|
||||
return $this->__hasPage($model, 'next');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given result set has the page number given by $page
|
||||
*
|
||||
* @param string $model Optional model name. Uses the default if none is specified.
|
||||
* @param int $page The page number - if not set defaults to 1.
|
||||
* @return boolean True if the given result set has the specified page number.
|
||||
* @access public
|
||||
*/
|
||||
function hasPage($model = null, $page = 1) {
|
||||
if (is_numeric($model)) {
|
||||
$page = $model;
|
||||
$model = null;
|
||||
}
|
||||
$paging = $this->params($model);
|
||||
return $page <= $paging['pageCount'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does $model have $page in its range?
|
||||
*
|
||||
* @param string $model Model name to get parameters for.
|
||||
* @param integer $page Page number you are checking.
|
||||
* @return boolean Whether model has $page
|
||||
* @access protected
|
||||
*/
|
||||
function __hasPage($model, $page) {
|
||||
$params = $this->params($model);
|
||||
if (!empty($params)) {
|
||||
if ($params["{$page}Page"] == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default model of the paged sets
|
||||
*
|
||||
* @return string Model name or null if the pagination isn't initialized.
|
||||
* @access public
|
||||
*/
|
||||
function defaultModel() {
|
||||
if ($this->__defaultModel != null) {
|
||||
return $this->__defaultModel;
|
||||
}
|
||||
if (empty($this->params['paging'])) {
|
||||
return null;
|
||||
}
|
||||
list($this->__defaultModel) = array_keys($this->params['paging']);
|
||||
return $this->__defaultModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a counter string for the paged result set
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `model` The model to use, defaults to PaginatorHelper::defaultModel();
|
||||
* - `format` The format string you want to use, defaults to 'pages' Which generates output like '1 of 5'
|
||||
* set to 'range' to generate output like '1 - 3 of 13'. Can also be set to a custom string, containing
|
||||
* the following placeholders `%page%`, `%pages%`, `%current%`, `%count%`, `%start%`, `%end%` and any
|
||||
* custom content you would like.
|
||||
* - `separator` The separator string to use, default to ' of '
|
||||
*
|
||||
* @param mixed $options Options for the counter string. See #options for list of keys.
|
||||
* @return string Counter string.
|
||||
* @access public
|
||||
*/
|
||||
function counter($options = array()) {
|
||||
if (is_string($options)) {
|
||||
$options = array('format' => $options);
|
||||
}
|
||||
|
||||
$options = array_merge(
|
||||
array(
|
||||
'model' => $this->defaultModel(),
|
||||
'format' => 'pages',
|
||||
'separator' => __(' of ', true)
|
||||
),
|
||||
$options);
|
||||
|
||||
$paging = $this->params($options['model']);
|
||||
if ($paging['pageCount'] == 0) {
|
||||
$paging['pageCount'] = 1;
|
||||
}
|
||||
$start = 0;
|
||||
if ($paging['count'] >= 1) {
|
||||
$start = (($paging['page'] - 1) * $paging['options']['limit']) + 1;
|
||||
}
|
||||
$end = $start + $paging['options']['limit'] - 1;
|
||||
if ($paging['count'] < $end) {
|
||||
$end = $paging['count'];
|
||||
}
|
||||
|
||||
switch ($options['format']) {
|
||||
case 'range':
|
||||
if (!is_array($options['separator'])) {
|
||||
$options['separator'] = array(' - ', $options['separator']);
|
||||
}
|
||||
$out = $start . $options['separator'][0] . $end . $options['separator'][1];
|
||||
$out .= $paging['count'];
|
||||
break;
|
||||
case 'pages':
|
||||
$out = $paging['page'] . $options['separator'] . $paging['pageCount'];
|
||||
break;
|
||||
default:
|
||||
$map = array(
|
||||
'%page%' => $paging['page'],
|
||||
'%pages%' => $paging['pageCount'],
|
||||
'%current%' => $paging['current'],
|
||||
'%count%' => $paging['count'],
|
||||
'%start%' => $start,
|
||||
'%end%' => $end
|
||||
);
|
||||
$out = str_replace(array_keys($map), array_values($map), $options['format']);
|
||||
|
||||
$newKeys = array(
|
||||
'{:page}', '{:pages}', '{:current}', '{:count}', '{:start}', '{:end}'
|
||||
);
|
||||
$out = str_replace($newKeys, array_values($map), $out);
|
||||
break;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of numbers for the paged result set
|
||||
* uses a modulus to decide how many numbers to show on each side of the current page (default: 8)
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `before` Content to be inserted before the numbers
|
||||
* - `after` Content to be inserted after the numbers
|
||||
* - `model` Model to create numbers for, defaults to PaginatorHelper::defaultModel()
|
||||
* - `modulus` how many numbers to include on either side of the current page, defaults to 8.
|
||||
* - `separator` Separator content defaults to ' | '
|
||||
* - `tag` The tag to wrap links in, defaults to 'span'
|
||||
* - `first` Whether you want first links generated, set to an integer to define the number of 'first'
|
||||
* links to generate
|
||||
* - `last` Whether you want last links generated, set to an integer to define the number of 'last'
|
||||
* links to generate
|
||||
*
|
||||
* @param mixed $options Options for the numbers, (before, after, model, modulus, separator)
|
||||
* @return string numbers string.
|
||||
* @access public
|
||||
*/
|
||||
function numbers($options = array()) {
|
||||
if ($options === true) {
|
||||
$options = array(
|
||||
'before' => ' | ', 'after' => ' | ', 'first' => 'first', 'last' => 'last'
|
||||
);
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'tag' => 'span', 'before' => null, 'after' => null, 'model' => $this->defaultModel(),
|
||||
'modulus' => '8', 'separator' => ' | ', 'first' => null, 'last' => null,
|
||||
);
|
||||
$options += $defaults;
|
||||
|
||||
$params = (array)$this->params($options['model']) + array('page'=> 1);
|
||||
unset($options['model']);
|
||||
|
||||
if ($params['pageCount'] <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extract($options);
|
||||
unset($options['tag'], $options['before'], $options['after'], $options['model'],
|
||||
$options['modulus'], $options['separator'], $options['first'], $options['last']);
|
||||
|
||||
$out = '';
|
||||
|
||||
if ($modulus && $params['pageCount'] > $modulus) {
|
||||
$half = intval($modulus / 2);
|
||||
$end = $params['page'] + $half;
|
||||
|
||||
if ($end > $params['pageCount']) {
|
||||
$end = $params['pageCount'];
|
||||
}
|
||||
$start = $params['page'] - ($modulus - ($end - $params['page']));
|
||||
if ($start <= 1) {
|
||||
$start = 1;
|
||||
$end = $params['page'] + ($modulus - $params['page']) + 1;
|
||||
}
|
||||
|
||||
if ($first && $start > 1) {
|
||||
$offset = ($start <= (int)$first) ? $start - 1 : $first;
|
||||
if ($offset < $start - 1) {
|
||||
$out .= $this->first($offset, array('tag' => $tag, 'separator' => $separator));
|
||||
} else {
|
||||
$out .= $this->first($offset, array('tag' => $tag, 'after' => $separator, 'separator' => $separator));
|
||||
}
|
||||
}
|
||||
|
||||
$out .= $before;
|
||||
|
||||
for ($i = $start; $i < $params['page']; $i++) {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options))
|
||||
. $separator;
|
||||
}
|
||||
|
||||
$out .= $this->Html->tag($tag, $params['page'], array('class' => 'current'));
|
||||
if ($i != $params['pageCount']) {
|
||||
$out .= $separator;
|
||||
}
|
||||
|
||||
$start = $params['page'] + 1;
|
||||
for ($i = $start; $i < $end; $i++) {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options))
|
||||
. $separator;
|
||||
}
|
||||
|
||||
if ($end != $params['page']) {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $end), $options));
|
||||
}
|
||||
|
||||
$out .= $after;
|
||||
|
||||
if ($last && $end < $params['pageCount']) {
|
||||
$offset = ($params['pageCount'] < $end + (int)$last) ? $params['pageCount'] - $end : $last;
|
||||
if ($offset <= $last && $params['pageCount'] - $end > $offset) {
|
||||
$out .= $this->last($offset, array('tag' => $tag, 'separator' => $separator));
|
||||
} else {
|
||||
$out .= $this->last($offset, array('tag' => $tag, 'before' => $separator, 'separator' => $separator));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$out .= $before;
|
||||
|
||||
for ($i = 1; $i <= $params['pageCount']; $i++) {
|
||||
if ($i == $params['page']) {
|
||||
$out .= $this->Html->tag($tag, $i, array('class' => 'current'));
|
||||
} else {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options));
|
||||
}
|
||||
if ($i != $params['pageCount']) {
|
||||
$out .= $separator;
|
||||
}
|
||||
}
|
||||
|
||||
$out .= $after;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a first or set of numbers for the first pages
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
|
||||
* - `before` Content to insert before the link/tag
|
||||
* - `model` The model to use defaults to PaginatorHelper::defaultModel()
|
||||
* - `separator` Content between the generated links, defaults to ' | '
|
||||
*
|
||||
* @param mixed $first if string use as label for the link, if numeric print page numbers
|
||||
* @param mixed $options
|
||||
* @return string numbers string.
|
||||
* @access public
|
||||
*/
|
||||
function first($first = '<< first', $options = array()) {
|
||||
$options = array_merge(
|
||||
array(
|
||||
'tag' => 'span',
|
||||
'after'=> null,
|
||||
'model' => $this->defaultModel(),
|
||||
'separator' => ' | ',
|
||||
),
|
||||
(array)$options);
|
||||
|
||||
$params = array_merge(array('page'=> 1), (array)$this->params($options['model']));
|
||||
unset($options['model']);
|
||||
|
||||
if ($params['pageCount'] <= 1) {
|
||||
return false;
|
||||
}
|
||||
extract($options);
|
||||
unset($options['tag'], $options['after'], $options['model'], $options['separator']);
|
||||
|
||||
$out = '';
|
||||
|
||||
if (is_int($first) && $params['page'] > $first) {
|
||||
if ($after === null) {
|
||||
$after = '...';
|
||||
}
|
||||
for ($i = 1; $i <= $first; $i++) {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options));
|
||||
if ($i != $first) {
|
||||
$out .= $separator;
|
||||
}
|
||||
}
|
||||
$out .= $after;
|
||||
} elseif ($params['page'] > 1) {
|
||||
$out = $this->Html->tag($tag, $this->link($first, array('page' => 1), $options))
|
||||
. $after;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a last or set of numbers for the last pages
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
|
||||
* - `before` Content to insert before the link/tag
|
||||
* - `model` The model to use defaults to PaginatorHelper::defaultModel()
|
||||
* - `separator` Content between the generated links, defaults to ' | '
|
||||
*
|
||||
* @param mixed $last if string use as label for the link, if numeric print page numbers
|
||||
* @param mixed $options Array of options
|
||||
* @return string numbers string.
|
||||
* @access public
|
||||
*/
|
||||
function last($last = 'last >>', $options = array()) {
|
||||
$options = array_merge(
|
||||
array(
|
||||
'tag' => 'span',
|
||||
'before'=> null,
|
||||
'model' => $this->defaultModel(),
|
||||
'separator' => ' | ',
|
||||
),
|
||||
(array)$options);
|
||||
|
||||
$params = array_merge(array('page'=> 1), (array)$this->params($options['model']));
|
||||
unset($options['model']);
|
||||
|
||||
if ($params['pageCount'] <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extract($options);
|
||||
unset($options['tag'], $options['before'], $options['model'], $options['separator']);
|
||||
|
||||
$out = '';
|
||||
$lower = $params['pageCount'] - $last + 1;
|
||||
|
||||
if (is_int($last) && $params['page'] < $lower) {
|
||||
if ($before === null) {
|
||||
$before = '...';
|
||||
}
|
||||
for ($i = $lower; $i <= $params['pageCount']; $i++) {
|
||||
$out .= $this->Html->tag($tag, $this->link($i, array('page' => $i), $options));
|
||||
if ($i != $params['pageCount']) {
|
||||
$out .= $separator;
|
||||
}
|
||||
}
|
||||
$out = $before . $out;
|
||||
} elseif ($params['page'] < $params['pageCount']) {
|
||||
$out = $before . $this->Html->tag(
|
||||
$tag, $this->link($last, array('page' => $params['pageCount']), $options
|
||||
));
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
365
web-cake/html/cake/libs/view/helpers/prototype_engine.php
Normal file
365
web-cake/html/cake/libs/view/helpers/prototype_engine.php
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
/**
|
||||
* Prototype Engine Helper for JsHelper
|
||||
*
|
||||
* Provides Prototype specific Javascript for JsHelper. Requires at least
|
||||
* Prototype 1.6
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Helper', 'Js');
|
||||
|
||||
class PrototypeEngineHelper extends JsBaseEngineHelper {
|
||||
/**
|
||||
* Is the current selection a multiple selection? or is it just a single element.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $_multiple = false;
|
||||
|
||||
/**
|
||||
* Option mappings for Prototype
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_optionMap = array(
|
||||
'request' => array(
|
||||
'async' => 'asynchronous',
|
||||
'data' => 'parameters',
|
||||
'before' => 'onCreate',
|
||||
'success' => 'onSuccess',
|
||||
'complete' => 'onComplete',
|
||||
'error' => 'onFailure'
|
||||
),
|
||||
'sortable' => array(
|
||||
'start' => 'onStart',
|
||||
'sort' => 'onChange',
|
||||
'complete' => 'onUpdate',
|
||||
'distance' => 'snap',
|
||||
),
|
||||
'drag' => array(
|
||||
'snapGrid' => 'snap',
|
||||
'container' => 'constraint',
|
||||
'stop' => 'onEnd',
|
||||
'start' => 'onStart',
|
||||
'drag' => 'onDrag',
|
||||
),
|
||||
'drop' => array(
|
||||
'hover' => 'onHover',
|
||||
'drop' => 'onDrop',
|
||||
'hoverClass' => 'hoverclass',
|
||||
),
|
||||
'slider' => array(
|
||||
'direction' => 'axis',
|
||||
'change' => 'onSlide',
|
||||
'complete' => 'onChange',
|
||||
'value' => 'sliderValue',
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Contains a list of callback names -> default arguments.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_callbackArguments = array(
|
||||
'slider' => array(
|
||||
'onSlide' => 'value',
|
||||
'onChange' => 'value',
|
||||
),
|
||||
'drag' => array(
|
||||
'onStart' => 'event',
|
||||
'onDrag' => 'event',
|
||||
'change' => 'draggable',
|
||||
'onEnd' => 'event',
|
||||
),
|
||||
'drop' => array(
|
||||
'onHover' => 'draggable, droppable, event',
|
||||
'onDrop' => 'draggable, droppable, event',
|
||||
),
|
||||
'request' => array(
|
||||
'onCreate' => 'transport',
|
||||
'onComplete' => 'transport',
|
||||
'onFailure' => 'response, jsonHeader',
|
||||
'onRequest' => 'transport',
|
||||
'onSuccess' => 'response, jsonHeader'
|
||||
),
|
||||
'sortable' => array(
|
||||
'onStart' => 'element',
|
||||
'onChange' => 'element',
|
||||
'onUpdate' => 'element',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Create javascript selector for a CSS rule
|
||||
*
|
||||
* @param string $selector The selector that is targeted
|
||||
* @return object instance of $this. Allows chained methods.
|
||||
*/
|
||||
function get($selector) {
|
||||
$this->_multiple = false;
|
||||
if ($selector == 'window' || $selector == 'document') {
|
||||
$this->selection = "$(" . $selector .")";
|
||||
return $this;
|
||||
}
|
||||
if (preg_match('/^#[^\s.]+$/', $selector)) {
|
||||
$this->selection = '$("' . substr($selector, 1) . '")';
|
||||
return $this;
|
||||
}
|
||||
$this->_multiple = true;
|
||||
$this->selection = '$$("' . $selector . '")';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event to the script cache. Operates on the currently selected elements.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `wrap` - Whether you want the callback wrapped in an anonymous function. (defaults true)
|
||||
* - `stop` - Whether you want the event to stopped. (defaults true)
|
||||
*
|
||||
* @param string $type Type of event to bind to the current 946 id
|
||||
* @param string $callback The Javascript function you wish to trigger or the function literal
|
||||
* @param array $options Options for the event.
|
||||
* @return string completed event handler
|
||||
*/
|
||||
function event($type, $callback, $options = array()) {
|
||||
$defaults = array('wrap' => true, 'stop' => true);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$function = 'function (event) {%s}';
|
||||
if ($options['wrap'] && $options['stop']) {
|
||||
$callback = "event.stop();\n" . $callback;
|
||||
}
|
||||
if ($options['wrap']) {
|
||||
$callback = sprintf($function, $callback);
|
||||
}
|
||||
$out = $this->selection . ".observe(\"{$type}\", $callback);";
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a domReady event. This is a special event in many libraries
|
||||
*
|
||||
* @param string $functionBody The code to run on domReady
|
||||
* @return string completed domReady method
|
||||
* @access public
|
||||
*/
|
||||
function domReady($functionBody) {
|
||||
$this->selection = 'document';
|
||||
return $this->event('dom:loaded', $functionBody, array('stop' => false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an iteration over the current selection result.
|
||||
*
|
||||
* @param string $method The method you want to apply to the selection
|
||||
* @param string $callback The function body you wish to apply during the iteration.
|
||||
* @return string completed iteration
|
||||
* @access public
|
||||
*/
|
||||
function each($callback) {
|
||||
return $this->selection . '.each(function (item, index) {' . $callback . '});';
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an Effect.
|
||||
*
|
||||
* ### Note: Effects require Scriptaculous to be loaded.
|
||||
*
|
||||
* @param string $name The name of the effect to trigger.
|
||||
* @param array $options Array of options for the effect.
|
||||
* @return string completed string with effect.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::effect()
|
||||
*/
|
||||
function effect($name, $options = array()) {
|
||||
$effect = '';
|
||||
$optionString = null;
|
||||
if (isset($options['speed'])) {
|
||||
if ($options['speed'] == 'fast') {
|
||||
$options['duration'] = 0.5;
|
||||
} elseif ($options['speed'] == 'slow') {
|
||||
$options['duration'] = 2;
|
||||
} else {
|
||||
$options['duration'] = 1;
|
||||
}
|
||||
unset($options['speed']);
|
||||
}
|
||||
if (!empty($options)) {
|
||||
$optionString = ', {' . $this->_parseOptions($options) . '}';
|
||||
}
|
||||
switch ($name) {
|
||||
case 'hide':
|
||||
case 'show':
|
||||
$effect = $this->selection . '.' . $name . '();';
|
||||
break;
|
||||
case 'slideIn':
|
||||
case 'slideOut':
|
||||
$name = ($name == 'slideIn') ? 'slideDown' : 'slideUp';
|
||||
$effect = 'Effect.' . $name . '(' . $this->selection . $optionString . ');';
|
||||
break;
|
||||
case 'fadeIn':
|
||||
case 'fadeOut':
|
||||
$name = ($name == 'fadeIn') ? 'appear' : 'fade';
|
||||
$effect = $this->selection . '.' . $name .'(' . substr($optionString, 2) . ');';
|
||||
break;
|
||||
}
|
||||
return $effect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Ajax or Ajax.Updater call.
|
||||
*
|
||||
* @param mixed $url
|
||||
* @param array $options
|
||||
* @return string The completed ajax call.
|
||||
* @access public
|
||||
*/
|
||||
function request($url, $options = array()) {
|
||||
$url = '"'. $this->url($url) . '"';
|
||||
$options = $this->_mapOptions('request', $options);
|
||||
$type = '.Request';
|
||||
$data = null;
|
||||
if (isset($options['type']) && strtolower($options['type']) == 'json') {
|
||||
unset($options['type']);
|
||||
}
|
||||
if (isset($options['update'])) {
|
||||
$url = '"' . str_replace('#', '', $options['update']) . '", ' . $url;
|
||||
$type = '.Updater';
|
||||
unset($options['update'], $options['type']);
|
||||
}
|
||||
$safe = array_keys($this->_callbackArguments['request']);
|
||||
$options = $this->_prepareCallbacks('request', $options, $safe);
|
||||
if (isset($options['dataExpression'])) {
|
||||
$safe[] = 'parameters';
|
||||
unset($options['dataExpression']);
|
||||
}
|
||||
$options = $this->_parseOptions($options, $safe);
|
||||
if (!empty($options)) {
|
||||
$options = ', {' . $options . '}';
|
||||
}
|
||||
return "var jsRequest = new Ajax$type($url$options);";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sortable element.
|
||||
*
|
||||
* #### Note: Requires scriptaculous to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the sortable.
|
||||
* @return string Completed sortable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::sortable() for options list.
|
||||
*/
|
||||
function sortable($options = array()) {
|
||||
$options = $this->_processOptions('sortable', $options);
|
||||
if (!empty($options)) {
|
||||
$options = ', {' . $options . '}';
|
||||
}
|
||||
return 'var jsSortable = Sortable.create(' . $this->selection . $options . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Draggable element.
|
||||
*
|
||||
* #### Note: Requires scriptaculous to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the draggable.
|
||||
* @return string Completed draggable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::draggable() for options list.
|
||||
*/
|
||||
function drag($options = array()) {
|
||||
$options = $this->_processOptions('drag', $options);
|
||||
if (!empty($options)) {
|
||||
$options = ', {' . $options . '}';
|
||||
}
|
||||
if ($this->_multiple) {
|
||||
return $this->each('new Draggable(item' . $options . ');');
|
||||
}
|
||||
return 'var jsDrag = new Draggable(' . $this->selection . $options . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Droppable element.
|
||||
*
|
||||
* #### Note: Requires scriptaculous to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the droppable.
|
||||
* @return string Completed droppable script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::droppable() for options list.
|
||||
*/
|
||||
function drop($options = array()) {
|
||||
$options = $this->_processOptions('drop', $options);
|
||||
if (!empty($options)) {
|
||||
$options = ', {' . $options . '}';
|
||||
}
|
||||
return 'Droppables.add(' . $this->selection . $options . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a slider control widget.
|
||||
*
|
||||
* ### Note: Requires scriptaculous to be loaded.
|
||||
*
|
||||
* @param array $options Array of options for the slider.
|
||||
* @return string Completed slider script.
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::slider() for options list.
|
||||
*/
|
||||
function slider($options = array()) {
|
||||
$slider = $this->selection;
|
||||
$this->get($options['handle']);
|
||||
unset($options['handle']);
|
||||
|
||||
if (isset($options['min']) && isset($options['max'])) {
|
||||
$options['range'] = array($options['min'], $options['max']);
|
||||
unset($options['min'], $options['max']);
|
||||
}
|
||||
$optionString = $this->_processOptions('slider', $options);
|
||||
if (!empty($optionString)) {
|
||||
$optionString = ', {' . $optionString . '}';
|
||||
}
|
||||
$out = 'var jsSlider = new Control.Slider(' . $this->selection . ', ' . $slider . $optionString . ');';
|
||||
$this->selection = $slider;
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the form attached to $selector.
|
||||
*
|
||||
* @param array $options Array of options.
|
||||
* @return string Completed serializeForm() snippet
|
||||
* @access public
|
||||
* @see JsBaseEngineHelper::serializeForm()
|
||||
*/
|
||||
function serializeForm($options = array()) {
|
||||
$options = array_merge(array('isForm' => false, 'inline' => false), $options);
|
||||
$selection = $this->selection;
|
||||
if (!$options['isForm']) {
|
||||
$selection = '$(' . $this->selection . '.form)';
|
||||
}
|
||||
$method = '.serialize()';
|
||||
if (!$options['inline']) {
|
||||
$method .= ';';
|
||||
}
|
||||
return $selection . $method;
|
||||
}
|
||||
}
|
||||
292
web-cake/html/cake/libs/view/helpers/rss.php
Normal file
292
web-cake/html/cake/libs/view/helpers/rss.php
Normal file
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/**
|
||||
* RSS Helper class file.
|
||||
*
|
||||
* Simplifies the output of RSS feeds.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Helper', 'Xml');
|
||||
|
||||
/**
|
||||
* XML Helper class for easy output of XML structures.
|
||||
*
|
||||
* XmlHelper encloses all methods needed while working with XML documents.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1460/RSS
|
||||
*/
|
||||
class RssHelper extends XmlHelper {
|
||||
|
||||
/**
|
||||
* Helpers used by RSS Helper
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $helpers = array('Time');
|
||||
|
||||
/**
|
||||
* Base URL
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $base = null;
|
||||
|
||||
/**
|
||||
* URL to current action.
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $here = null;
|
||||
|
||||
/**
|
||||
* Parameter array.
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
var $params = array();
|
||||
|
||||
/**
|
||||
* Current action.
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $action = null;
|
||||
|
||||
/**
|
||||
* POSTed model data
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
var $data = null;
|
||||
|
||||
/**
|
||||
* Name of the current model
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $model = null;
|
||||
|
||||
/**
|
||||
* Name of the current field
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $field = null;
|
||||
|
||||
/**
|
||||
* Default spec version of generated RSS
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $version = '2.0';
|
||||
|
||||
/**
|
||||
* Returns an RSS document wrapped in `<rss />` tags
|
||||
*
|
||||
* @param array $attrib `<rss />` tag attributes
|
||||
* @return string An RSS document
|
||||
* @access public
|
||||
*/
|
||||
function document($attrib = array(), $content = null) {
|
||||
if ($content === null) {
|
||||
$content = $attrib;
|
||||
$attrib = array();
|
||||
}
|
||||
if (!isset($attrib['version']) || empty($attrib['version'])) {
|
||||
$attrib['version'] = $this->version;
|
||||
}
|
||||
|
||||
return $this->elem('rss', $attrib, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an RSS `<channel />` element
|
||||
*
|
||||
* @param array $attrib `<channel />` tag attributes
|
||||
* @param mixed $elements Named array elements which are converted to tags
|
||||
* @param mixed $content Content (`<item />`'s belonging to this channel
|
||||
* @return string An RSS `<channel />`
|
||||
* @access public
|
||||
*/
|
||||
function channel($attrib = array(), $elements = array(), $content = null) {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
|
||||
if (!isset($elements['title']) && !empty($view->pageTitle)) {
|
||||
$elements['title'] = $view->pageTitle;
|
||||
}
|
||||
if (!isset($elements['link'])) {
|
||||
$elements['link'] = '/';
|
||||
}
|
||||
if (!isset($elements['description'])) {
|
||||
$elements['description'] = '';
|
||||
}
|
||||
$elements['link'] = $this->url($elements['link'], true);
|
||||
|
||||
$elems = '';
|
||||
foreach ($elements as $elem => $data) {
|
||||
$attributes = array();
|
||||
if (is_array($data)) {
|
||||
if (strtolower($elem) == 'cloud') {
|
||||
$attributes = $data;
|
||||
$data = array();
|
||||
} elseif (isset($data['attrib']) && is_array($data['attrib'])) {
|
||||
$attributes = $data['attrib'];
|
||||
unset($data['attrib']);
|
||||
} else {
|
||||
$innerElements = '';
|
||||
foreach ($data as $subElement => $value) {
|
||||
$innerElements .= $this->elem($subElement, array(), $value);
|
||||
}
|
||||
$data = $innerElements;
|
||||
}
|
||||
}
|
||||
$elems .= $this->elem($elem, $attributes, $data);
|
||||
}
|
||||
return $this->elem('channel', $attrib, $elems . $content, !($content === null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of data using an optional callback, and maps it to a set
|
||||
* of `<item />` tags
|
||||
*
|
||||
* @param array $items The list of items to be mapped
|
||||
* @param mixed $callback A string function name, or array containing an object
|
||||
* and a string method name
|
||||
* @return string A set of RSS `<item />` elements
|
||||
* @access public
|
||||
*/
|
||||
function items($items, $callback = null) {
|
||||
if ($callback != null) {
|
||||
$items = array_map($callback, $items);
|
||||
}
|
||||
|
||||
$out = '';
|
||||
$c = count($items);
|
||||
|
||||
for ($i = 0; $i < $c; $i++) {
|
||||
$out .= $this->item(array(), $items[$i]);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array into an `<item />` element and its contents
|
||||
*
|
||||
* @param array $attrib The attributes of the `<item />` element
|
||||
* @param array $elements The list of elements contained in this `<item />`
|
||||
* @return string An RSS `<item />` element
|
||||
* @access public
|
||||
*/
|
||||
function item($att = array(), $elements = array()) {
|
||||
$content = null;
|
||||
|
||||
if (isset($elements['link']) && !isset($elements['guid'])) {
|
||||
$elements['guid'] = $elements['link'];
|
||||
}
|
||||
|
||||
foreach ($elements as $key => $val) {
|
||||
$attrib = array();
|
||||
|
||||
$escape = true;
|
||||
if (is_array($val) && isset($val['convertEntities'])) {
|
||||
$escape = $val['convertEntities'];
|
||||
unset($val['convertEntities']);
|
||||
}
|
||||
|
||||
switch ($key) {
|
||||
case 'pubDate' :
|
||||
$val = $this->time($val);
|
||||
break;
|
||||
case 'category' :
|
||||
if (is_array($val) && !empty($val[0])) {
|
||||
foreach ($val as $category) {
|
||||
$attrib = array();
|
||||
if (isset($category['domain'])) {
|
||||
$attrib['domain'] = $category['domain'];
|
||||
unset($category['domain']);
|
||||
}
|
||||
$categories[] = $this->elem($key, $attrib, $category);
|
||||
}
|
||||
$elements[$key] = implode('', $categories);
|
||||
continue 2;
|
||||
} else if (is_array($val) && isset($val['domain'])) {
|
||||
$attrib['domain'] = $val['domain'];
|
||||
}
|
||||
break;
|
||||
case 'link':
|
||||
case 'guid':
|
||||
case 'comments':
|
||||
if (is_array($val) && isset($val['url'])) {
|
||||
$attrib = $val;
|
||||
unset($attrib['url']);
|
||||
$val = $val['url'];
|
||||
}
|
||||
$val = $this->url($val, true);
|
||||
break;
|
||||
case 'source':
|
||||
if (is_array($val) && isset($val['url'])) {
|
||||
$attrib['url'] = $this->url($val['url'], true);
|
||||
$val = $val['title'];
|
||||
} elseif (is_array($val)) {
|
||||
$attrib['url'] = $this->url($val[0], true);
|
||||
$val = $val[1];
|
||||
}
|
||||
break;
|
||||
case 'enclosure':
|
||||
if (is_string($val['url']) && is_file(WWW_ROOT . $val['url']) && file_exists(WWW_ROOT . $val['url'])) {
|
||||
if (!isset($val['length']) && strpos($val['url'], '://') === false) {
|
||||
$val['length'] = sprintf("%u", filesize(WWW_ROOT . $val['url']));
|
||||
}
|
||||
if (!isset($val['type']) && function_exists('mime_content_type')) {
|
||||
$val['type'] = mime_content_type(WWW_ROOT . $val['url']);
|
||||
}
|
||||
}
|
||||
$val['url'] = $this->url($val['url'], true);
|
||||
$attrib = $val;
|
||||
$val = null;
|
||||
break;
|
||||
}
|
||||
if (!is_null($val) && $escape) {
|
||||
$val = h($val);
|
||||
}
|
||||
$elements[$key] = $this->elem($key, $attrib, $val);
|
||||
}
|
||||
if (!empty($elements)) {
|
||||
$content = implode('', $elements);
|
||||
}
|
||||
return $this->elem('item', $att, $content, !($content === null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a time in any format to an RSS time
|
||||
*
|
||||
* @param mixed $time
|
||||
* @return string An RSS-formatted timestamp
|
||||
* @see TimeHelper::toRSS
|
||||
*/
|
||||
function time($time) {
|
||||
return $this->Time->toRSS($time);
|
||||
}
|
||||
}
|
||||
201
web-cake/html/cake/libs/view/helpers/session.php
Normal file
201
web-cake/html/cake/libs/view/helpers/session.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/**
|
||||
* Session Helper provides access to the Session in the Views.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.1.7.3328
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
if (!class_exists('cakesession')) {
|
||||
require LIBS . 'cake_session.php';
|
||||
}
|
||||
/**
|
||||
* Session Helper.
|
||||
*
|
||||
* Session reading from the view.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1465/Session
|
||||
*/
|
||||
class SessionHelper extends CakeSession {
|
||||
|
||||
/**
|
||||
* List of helpers used by this helper
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $helpers = array();
|
||||
|
||||
/**
|
||||
* Used to determine if methods implementation is used, or bypassed
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
var $__active = true;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $base
|
||||
*/
|
||||
function __construct($base = null) {
|
||||
if (Configure::read('Session.start') === true) {
|
||||
parent::__construct($base, false);
|
||||
$this->start();
|
||||
$this->__active = true;
|
||||
} else {
|
||||
$this->__active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn sessions on if 'Session.start' is set to false in core.php
|
||||
*
|
||||
* @param string $base
|
||||
* @access public
|
||||
*/
|
||||
function activate($base = null) {
|
||||
$this->__active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read a session values set in a controller for a key or return values for all keys.
|
||||
*
|
||||
* In your view: `$session->read('Controller.sessKey');`
|
||||
* Calling the method without a param will return all session vars
|
||||
*
|
||||
* @param string $name the name of the session key you want to read
|
||||
* @return values from the session vars
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1466/Methods
|
||||
*/
|
||||
function read($name = null) {
|
||||
if ($this->__active === true && $this->__start()) {
|
||||
return parent::read($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check is a session key has been set
|
||||
*
|
||||
* In your view: `$session->check('Controller.sessKey');`
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1466/Methods
|
||||
*/
|
||||
function check($name) {
|
||||
if ($this->__active === true && $this->__start()) {
|
||||
return parent::check($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last error encountered in a session
|
||||
*
|
||||
* In your view: `$session->error();`
|
||||
*
|
||||
* @return string last error
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1466/Methods
|
||||
*/
|
||||
function error() {
|
||||
if ($this->__active === true && $this->__start()) {
|
||||
return parent::error();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to render the message set in Controller::Session::setFlash()
|
||||
*
|
||||
* In your view: $session->flash('somekey');
|
||||
* Will default to flash if no param is passed
|
||||
*
|
||||
* @param string $key The [Message.]key you are rendering in the view.
|
||||
* @return boolean|string Will return the value if $key is set, or false if not set.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1466/Methods
|
||||
* @link http://book.cakephp.org/view/1467/flash
|
||||
*/
|
||||
function flash($key = 'flash') {
|
||||
$out = false;
|
||||
|
||||
if ($this->__active === true && $this->__start()) {
|
||||
if (parent::check('Message.' . $key)) {
|
||||
$flash = parent::read('Message.' . $key);
|
||||
|
||||
if ($flash['element'] == 'default') {
|
||||
if (!empty($flash['params']['class'])) {
|
||||
$class = $flash['params']['class'];
|
||||
} else {
|
||||
$class = 'message';
|
||||
}
|
||||
$out = '<div id="' . $key . 'Message" class="' . $class . '">' . $flash['message'] . '</div>';
|
||||
} elseif ($flash['element'] == '' || $flash['element'] == null) {
|
||||
$out = $flash['message'];
|
||||
} else {
|
||||
$view =& ClassRegistry::getObject('view');
|
||||
$tmpVars = $flash['params'];
|
||||
$tmpVars['message'] = $flash['message'];
|
||||
$out = $view->element($flash['element'], $tmpVars);
|
||||
}
|
||||
parent::delete('Message.' . $key);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check is a session is valid in a view
|
||||
*
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function valid() {
|
||||
if ($this->__active === true && $this->__start()) {
|
||||
return parent::valid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override CakeSession::write().
|
||||
* This method should not be used in a view
|
||||
*
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function write() {
|
||||
trigger_error(__('You can not write to a Session from the view', true), E_USER_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if Session has been started
|
||||
* and attempt to start it if not
|
||||
*
|
||||
* @return boolean true if Session is already started, false if
|
||||
* Session could not be started
|
||||
* @access private
|
||||
*/
|
||||
function __start() {
|
||||
if (!$this->started()) {
|
||||
return $this->start();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
336
web-cake/html/cake/libs/view/helpers/text.php
Normal file
336
web-cake/html/cake/libs/view/helpers/text.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
/**
|
||||
* Text Helper
|
||||
*
|
||||
* Text manipulations: Highlight, excerpt, truncate, strip of links, convert email addresses to mailto: links...
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Included libraries.
|
||||
*
|
||||
*/
|
||||
if (!class_exists('HtmlHelper')) {
|
||||
App::import('Helper', 'Html');
|
||||
}
|
||||
if (!class_exists('Multibyte')) {
|
||||
App::import('Core', 'Multibyte');
|
||||
}
|
||||
|
||||
/**
|
||||
* Text helper library.
|
||||
*
|
||||
* Text manipulations: Highlight, excerpt, truncate, strip of links, convert email addresses to mailto: links...
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1469/Text
|
||||
*/
|
||||
class TextHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Highlights a given phrase in a text. You can specify any expression in highlighter that
|
||||
* may include the \1 expression to include the $phrase found.
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `format` The piece of html with that the phrase will be highlighted
|
||||
* - `html` If true, will ignore any HTML tags, ensuring that only the correct text is highlighted
|
||||
*
|
||||
* @param string $text Text to search the phrase in
|
||||
* @param string $phrase The phrase that will be searched
|
||||
* @param array $options An array of html attributes and options.
|
||||
* @return string The highlighted text
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#highlight-1622
|
||||
*/
|
||||
function highlight($text, $phrase, $options = array()) {
|
||||
if (empty($phrase)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$default = array(
|
||||
'format' => '<span class="highlight">\1</span>',
|
||||
'html' => false
|
||||
);
|
||||
$options = array_merge($default, $options);
|
||||
extract($options);
|
||||
|
||||
if (is_array($phrase)) {
|
||||
$replace = array();
|
||||
$with = array();
|
||||
|
||||
foreach ($phrase as $key => $segment) {
|
||||
$segment = "($segment)";
|
||||
if ($html) {
|
||||
$segment = "(?![^<]+>)$segment(?![^<]+>)";
|
||||
}
|
||||
|
||||
$with[] = (is_array($format)) ? $format[$key] : $format;
|
||||
$replace[] = "|$segment|iu";
|
||||
}
|
||||
|
||||
return preg_replace($replace, $with, $text);
|
||||
} else {
|
||||
$phrase = "($phrase)";
|
||||
if ($html) {
|
||||
$phrase = "(?![^<]+>)$phrase(?![^<]+>)";
|
||||
}
|
||||
|
||||
return preg_replace("|$phrase|iu", $format, $text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips given text of all links (<a href=....)
|
||||
*
|
||||
* @param string $text Text
|
||||
* @return string The text without links
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#stripLinks-1623
|
||||
*/
|
||||
function stripLinks($text) {
|
||||
return preg_replace('|<a\s+[^>]+>|im', '', preg_replace('|<\/a>|im', '', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds links (<a href=....) to a given text, by finding text that begins with
|
||||
* strings like http:// and ftp://.
|
||||
*
|
||||
* @param string $text Text to add links to
|
||||
* @param array $options Array of HTML options.
|
||||
* @return string The text with links
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#autoLinkUrls-1619
|
||||
*/
|
||||
function autoLinkUrls($text, $htmlOptions = array()) {
|
||||
$options = var_export($htmlOptions, true);
|
||||
$text = preg_replace_callback('#(?<!href="|">)((?:https?|ftp|nntp)://[^\s<>()]+)#i', create_function('$matches',
|
||||
'$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], $matches[0],' . $options . ');'), $text);
|
||||
|
||||
return preg_replace_callback('#(?<!href="|">)(?<!http://|https://|ftp://|nntp://)(www\.[^\n\%\ <]+[^<\n\%\,\.\ <])(?<!\))#i',
|
||||
create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "http://" . $matches[0],' . $options . ');'), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds email links (<a href="mailto:....) to a given text.
|
||||
*
|
||||
* @param string $text Text
|
||||
* @param array $options Array of HTML options.
|
||||
* @return string The text with links
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#autoLinkEmails-1618
|
||||
*/
|
||||
function autoLinkEmails($text, $options = array()) {
|
||||
$linkOptions = 'array(';
|
||||
foreach ($options as $option => $value) {
|
||||
$value = var_export($value, true);
|
||||
$linkOptions .= "'$option' => $value, ";
|
||||
}
|
||||
$linkOptions .= ')';
|
||||
|
||||
return preg_replace_callback('#([_A-Za-z0-9+-]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#',
|
||||
create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "mailto:" . $matches[0],' . $linkOptions . ');'), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all links and email adresses to HTML links.
|
||||
*
|
||||
* @param string $text Text
|
||||
* @param array $options Array of HTML options.
|
||||
* @return string The text with links
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#autoLink-1620
|
||||
*/
|
||||
function autoLink($text, $options = array()) {
|
||||
return $this->autoLinkEmails($this->autoLinkUrls($text, $options), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates text.
|
||||
*
|
||||
* Cuts a string to the length of $length and replaces the last characters
|
||||
* with the ending if the text is longer than length.
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `ending` Will be used as Ending and appended to the trimmed string
|
||||
* - `exact` If false, $text will not be cut mid-word
|
||||
* - `html` If true, HTML tags would be handled correctly
|
||||
*
|
||||
* @param string $text String to truncate.
|
||||
* @param integer $length Length of returned string, including ellipsis.
|
||||
* @param array $options An array of html attributes and options.
|
||||
* @return string Trimmed string.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#truncate-1625
|
||||
*/
|
||||
function truncate($text, $length = 100, $options = array()) {
|
||||
$default = array(
|
||||
'ending' => '...', 'exact' => true, 'html' => false
|
||||
);
|
||||
$options = array_merge($default, $options);
|
||||
extract($options);
|
||||
|
||||
if ($html) {
|
||||
if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
|
||||
return $text;
|
||||
}
|
||||
$totalLength = mb_strlen(strip_tags($ending));
|
||||
$openTags = array();
|
||||
$truncate = '';
|
||||
|
||||
preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER);
|
||||
foreach ($tags as $tag) {
|
||||
if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
|
||||
if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
|
||||
array_unshift($openTags, $tag[2]);
|
||||
} else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
|
||||
$pos = array_search($closeTag[1], $openTags);
|
||||
if ($pos !== false) {
|
||||
array_splice($openTags, $pos, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
$truncate .= $tag[1];
|
||||
|
||||
$contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
|
||||
if ($contentLength + $totalLength > $length) {
|
||||
$left = $length - $totalLength;
|
||||
$entitiesLength = 0;
|
||||
if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) {
|
||||
foreach ($entities[0] as $entity) {
|
||||
if ($entity[1] + 1 - $entitiesLength <= $left) {
|
||||
$left--;
|
||||
$entitiesLength += mb_strlen($entity[0]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength);
|
||||
break;
|
||||
} else {
|
||||
$truncate .= $tag[3];
|
||||
$totalLength += $contentLength;
|
||||
}
|
||||
if ($totalLength >= $length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mb_strlen($text) <= $length) {
|
||||
return $text;
|
||||
} else {
|
||||
$truncate = mb_substr($text, 0, $length - mb_strlen($ending));
|
||||
}
|
||||
}
|
||||
if (!$exact) {
|
||||
$spacepos = mb_strrpos($truncate, ' ');
|
||||
if (isset($spacepos)) {
|
||||
if ($html) {
|
||||
$bits = mb_substr($truncate, $spacepos);
|
||||
preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
|
||||
if (!empty($droppedTags)) {
|
||||
foreach ($droppedTags as $closingTag) {
|
||||
if (!in_array($closingTag[1], $openTags)) {
|
||||
array_unshift($openTags, $closingTag[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$truncate = mb_substr($truncate, 0, $spacepos);
|
||||
}
|
||||
}
|
||||
$truncate .= $ending;
|
||||
|
||||
if ($html) {
|
||||
foreach ($openTags as $tag) {
|
||||
$truncate .= '</'.$tag.'>';
|
||||
}
|
||||
}
|
||||
|
||||
return $truncate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts an excerpt from the text surrounding the phrase with a number of characters on each side
|
||||
* determined by radius.
|
||||
*
|
||||
* @param string $text String to search the phrase in
|
||||
* @param string $phrase Phrase that will be searched for
|
||||
* @param integer $radius The amount of characters that will be returned on each side of the founded phrase
|
||||
* @param string $ending Ending that will be appended
|
||||
* @return string Modified string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#excerpt-1621
|
||||
*/
|
||||
function excerpt($text, $phrase, $radius = 100, $ending = '...') {
|
||||
if (empty($text) or empty($phrase)) {
|
||||
return $this->truncate($text, $radius * 2, array('ending' => $ending));
|
||||
}
|
||||
|
||||
$phraseLen = mb_strlen($phrase);
|
||||
if ($radius < $phraseLen) {
|
||||
$radius = $phraseLen;
|
||||
}
|
||||
|
||||
$pos = mb_strpos(mb_strtolower($text), mb_strtolower($phrase));
|
||||
|
||||
$startPos = 0;
|
||||
if ($pos > $radius) {
|
||||
$startPos = $pos - $radius;
|
||||
}
|
||||
|
||||
$textLen = mb_strlen($text);
|
||||
|
||||
$endPos = $pos + $phraseLen + $radius;
|
||||
if ($endPos >= $textLen) {
|
||||
$endPos = $textLen;
|
||||
}
|
||||
|
||||
$excerpt = mb_substr($text, $startPos, $endPos - $startPos);
|
||||
if ($startPos != 0) {
|
||||
$excerpt = substr_replace($excerpt, $ending, 0, $phraseLen);
|
||||
}
|
||||
|
||||
if ($endPos != $textLen) {
|
||||
$excerpt = substr_replace($excerpt, $ending, -$phraseLen);
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comma separated list where the last two items are joined with 'and', forming natural English
|
||||
*
|
||||
* @param array $list The list to be joined
|
||||
* @param string $and The word used to join the last and second last items together with. Defaults to 'and'
|
||||
* @param string $separator The separator used to join all othe other items together. Defaults to ', '
|
||||
* @return string The glued together string.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1469/Text#toList-1624
|
||||
*/
|
||||
function toList($list, $and = 'and', $separator = ', ') {
|
||||
if (count($list) > 1) {
|
||||
return implode($separator, array_slice($list, null, -1)) . ' ' . $and . ' ' . array_pop($list);
|
||||
} else {
|
||||
return array_pop($list);
|
||||
}
|
||||
}
|
||||
}
|
||||
735
web-cake/html/cake/libs/view/helpers/time.php
Normal file
735
web-cake/html/cake/libs/view/helpers/time.php
Normal file
@@ -0,0 +1,735 @@
|
||||
<?php
|
||||
/**
|
||||
* Time Helper class file.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Helper class for easy use of time data.
|
||||
*
|
||||
* Manipulation of time data.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1470/Time
|
||||
*/
|
||||
class TimeHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Converts a string representing the format for the function strftime and returns a
|
||||
* windows safe and i18n aware format.
|
||||
*
|
||||
* @param string $format Format with specifiers for strftime function.
|
||||
* Accepts the special specifier %S which mimics th modifier S for date()
|
||||
* @param string UNIX timestamp
|
||||
* @return string windows safe and date() function compatible format for strftime
|
||||
* @access public
|
||||
*/
|
||||
function convertSpecifiers($format, $time = null) {
|
||||
if (!$time) {
|
||||
$time = time();
|
||||
}
|
||||
$this->__time = $time;
|
||||
return preg_replace_callback('/\%(\w+)/', array($this, '__translateSpecifier'), $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auxiliary function to translate a matched specifier element from a regular expresion into
|
||||
* a windows safe and i18n aware specifier
|
||||
*
|
||||
* @param array $specifier match from regular expression
|
||||
* @return string converted element
|
||||
* @access private
|
||||
*/
|
||||
function __translateSpecifier($specifier) {
|
||||
switch ($specifier[1]) {
|
||||
case 'a':
|
||||
$abday = __c('abday', 5, true);
|
||||
if (is_array($abday)) {
|
||||
return $abday[date('w', $this->__time)];
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
$day = __c('day',5,true);
|
||||
if (is_array($day)) {
|
||||
return $day[date('w', $this->__time)];
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
$format = __c('d_t_fmt',5,true);
|
||||
if ($format != 'd_t_fmt') {
|
||||
return $this->convertSpecifiers($format, $this->__time);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
return sprintf("%02d", date('Y', $this->__time) / 100);
|
||||
case 'D':
|
||||
return '%m/%d/%y';
|
||||
case 'eS' :
|
||||
return date('jS', $this->__time);
|
||||
case 'b':
|
||||
case 'h':
|
||||
$months = __c('abmon', 5, true);
|
||||
if (is_array($months)) {
|
||||
return $months[date('n', $this->__time) -1];
|
||||
}
|
||||
return '%b';
|
||||
case 'B':
|
||||
$months = __c('mon',5,true);
|
||||
if (is_array($months)) {
|
||||
return $months[date('n', $this->__time) -1];
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
return "\n";
|
||||
case 'p':
|
||||
case 'P':
|
||||
$default = array('am' => 0, 'pm' => 1);
|
||||
$meridiem = $default[date('a',$this->__time)];
|
||||
$format = __c('am_pm', 5, true);
|
||||
if (is_array($format)) {
|
||||
$meridiem = $format[$meridiem];
|
||||
return ($specifier[1] == 'P') ? strtolower($meridiem) : strtoupper($meridiem);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
$complete = __c('t_fmt_ampm', 5, true);
|
||||
if ($complete != 't_fmt_ampm') {
|
||||
return str_replace('%p',$this->__translateSpecifier(array('%p', 'p')),$complete);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
return date('H:i', $this->__time);
|
||||
case 't':
|
||||
return "\t";
|
||||
case 'T':
|
||||
return '%H:%M:%S';
|
||||
case 'u':
|
||||
return ($weekDay = date('w', $this->__time)) ? $weekDay : 7;
|
||||
case 'x':
|
||||
$format = __c('d_fmt', 5, true);
|
||||
if ($format != 'd_fmt') {
|
||||
return $this->convertSpecifiers($format, $this->__time);
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
$format = __c('t_fmt',5,true);
|
||||
if ($format != 't_fmt') {
|
||||
return $this->convertSpecifiers($format, $this->__time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $specifier[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts given time (in server's time zone) to user's local time, given his/her offset from GMT.
|
||||
*
|
||||
* @param string $serverTime UNIX timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string UNIX timestamp
|
||||
* @access public
|
||||
*/
|
||||
function convert($serverTime, $userOffset) {
|
||||
$serverOffset = $this->serverOffset();
|
||||
$gmtTime = $serverTime - $serverOffset;
|
||||
$userTime = $gmtTime + $userOffset * (60*60);
|
||||
return $userTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server's offset from GMT in seconds.
|
||||
*
|
||||
* @return int Offset
|
||||
* @access public
|
||||
*/
|
||||
function serverOffset() {
|
||||
return date('Z', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UNIX timestamp, given either a UNIX timestamp or a valid strtotime() date string.
|
||||
*
|
||||
* @param string $dateString Datetime string
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Parsed timestamp
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function fromString($dateString, $userOffset = null) {
|
||||
if (empty($dateString)) {
|
||||
return false;
|
||||
}
|
||||
if (is_integer($dateString) || is_numeric($dateString)) {
|
||||
$date = intval($dateString);
|
||||
} else {
|
||||
$date = strtotime($dateString);
|
||||
}
|
||||
if ($userOffset !== null) {
|
||||
return $this->convert($date, $userOffset);
|
||||
}
|
||||
if ($date === -1) {
|
||||
return false;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nicely formatted date string for given Datetime string.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Formatted date string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function nice($dateString = null, $userOffset = null) {
|
||||
if ($dateString != null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
} else {
|
||||
$date = time();
|
||||
}
|
||||
$format = $this->convertSpecifiers('%a, %b %eS %Y, %H:%M', $date);
|
||||
return strftime($format, $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted descriptive date string for given datetime string.
|
||||
*
|
||||
* If the given date is today, the returned string could be "Today, 16:54".
|
||||
* If the given date was yesterday, the returned string could be "Yesterday, 16:54".
|
||||
* If $dateString's year is the current year, the returned string does not
|
||||
* include mention of the year.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Described, relative date string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function niceShort($dateString = null, $userOffset = null) {
|
||||
$date = $dateString ? $this->fromString($dateString, $userOffset) : time();
|
||||
|
||||
$y = $this->isThisYear($date) ? '' : ' %Y';
|
||||
|
||||
if ($this->isToday($date)) {
|
||||
$ret = sprintf(__('Today, %s',true), strftime("%H:%M", $date));
|
||||
} elseif ($this->wasYesterday($date)) {
|
||||
$ret = sprintf(__('Yesterday, %s',true), strftime("%H:%M", $date));
|
||||
} else {
|
||||
$format = $this->convertSpecifiers("%b %eS{$y}, %H:%M", $date);
|
||||
$ret = strftime($format, $date);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial SQL string to search for all records between two dates.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param string $end Datetime string or Unix timestamp
|
||||
* @param string $fieldName Name of database field to compare with
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Partial SQL string.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function daysAsSql($begin, $end, $fieldName, $userOffset = null) {
|
||||
$begin = $this->fromString($begin, $userOffset);
|
||||
$end = $this->fromString($end, $userOffset);
|
||||
$begin = date('Y-m-d', $begin) . ' 00:00:00';
|
||||
$end = date('Y-m-d', $end) . ' 23:59:59';
|
||||
|
||||
return "($fieldName >= '$begin') AND ($fieldName <= '$end')";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial SQL string to search for all records between two times
|
||||
* occurring on the same day.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param string $fieldName Name of database field to compare with
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Partial SQL string.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function dayAsSql($dateString, $fieldName, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return $this->daysAsSql($dateString, $dateString, $fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string is today.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return boolean True if datetime string is today
|
||||
* @access public
|
||||
*/
|
||||
function isToday($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('Y-m-d', $date) == date('Y-m-d', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string is within this week
|
||||
* @param string $dateString
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return boolean True if datetime string is within current week
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*/
|
||||
function isThisWeek($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('W Y', $date) == date('W Y', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string is within this month
|
||||
* @param string $dateString
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return boolean True if datetime string is within current month
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*/
|
||||
function isThisMonth($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString);
|
||||
return date('m Y',$date) == date('m Y', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string is within current year.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @return boolean True if datetime string is within current year
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*/
|
||||
function isThisYear($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('Y', $date) == date('Y', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string was yesterday.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return boolean True if datetime string was yesterday
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*
|
||||
*/
|
||||
function wasYesterday($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('Y-m-d', $date) == date('Y-m-d', strtotime('yesterday'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given datetime string is tomorrow.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return boolean True if datetime string was yesterday
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*/
|
||||
function isTomorrow($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('Y-m-d', $date) == date('Y-m-d', strtotime('tomorrow'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quarter
|
||||
*
|
||||
* @param string $dateString
|
||||
* @param boolean $range if true returns a range in Y-m-d format
|
||||
* @return boolean True if datetime string is within current week
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function toQuarter($dateString, $range = false) {
|
||||
$time = $this->fromString($dateString);
|
||||
$date = ceil(date('m', $time) / 3);
|
||||
|
||||
if ($range === true) {
|
||||
$range = 'Y-m-d';
|
||||
}
|
||||
|
||||
if ($range !== false) {
|
||||
$year = date('Y', $time);
|
||||
|
||||
switch ($date) {
|
||||
case 1:
|
||||
$date = array($year.'-01-01', $year.'-03-31');
|
||||
break;
|
||||
case 2:
|
||||
$date = array($year.'-04-01', $year.'-06-30');
|
||||
break;
|
||||
case 3:
|
||||
$date = array($year.'-07-01', $year.'-09-30');
|
||||
break;
|
||||
case 4:
|
||||
$date = array($year.'-10-01', $year.'-12-31');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UNIX timestamp from a textual datetime description. Wrapper for PHP function strtotime().
|
||||
*
|
||||
* @param string $dateString Datetime string to be represented as a Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return integer Unix timestamp
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function toUnix($dateString, $userOffset = null) {
|
||||
return $this->fromString($dateString, $userOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date formatted for Atom RSS feeds.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Formatted date string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function toAtom($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date('Y-m-d\TH:i:s\Z', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats date for RSS feeds
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Formatted date string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function toRSS($dateString, $userOffset = null) {
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
return date("r", $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either a relative date or a formatted date depending
|
||||
* on the difference between the current time and given datetime.
|
||||
* $datetime should be in a <i>strtotime</i> - parsable format, like MySQL's datetime datatype.
|
||||
*
|
||||
* ### Options:
|
||||
*
|
||||
* - `format` => a fall back format if the relative time is longer than the duration specified by end
|
||||
* - `end` => The end of relative time telling
|
||||
* - `userOffset` => Users offset from GMT (in hours)
|
||||
*
|
||||
* Relative dates look something like this:
|
||||
* 3 weeks, 4 days ago
|
||||
* 15 seconds ago
|
||||
*
|
||||
* Default date formatting is d/m/yy e.g: on 18/2/09
|
||||
*
|
||||
* The returned string includes 'ago' or 'on' and assumes you'll properly add a word
|
||||
* like 'Posted ' before the function output.
|
||||
*
|
||||
* @param string $dateString Datetime string or Unix timestamp
|
||||
* @param array $options Default format if timestamp is used in $dateString
|
||||
* @return string Relative time string.
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function timeAgoInWords($dateTime, $options = array()) {
|
||||
$userOffset = null;
|
||||
if (is_array($options) && isset($options['userOffset'])) {
|
||||
$userOffset = $options['userOffset'];
|
||||
}
|
||||
$now = time();
|
||||
if (!is_null($userOffset)) {
|
||||
$now = $this->convert(time(), $userOffset);
|
||||
}
|
||||
$inSeconds = $this->fromString($dateTime, $userOffset);
|
||||
$backwards = ($inSeconds > $now);
|
||||
|
||||
$format = 'j/n/y';
|
||||
$end = '+1 month';
|
||||
|
||||
if (is_array($options)) {
|
||||
if (isset($options['format'])) {
|
||||
$format = $options['format'];
|
||||
unset($options['format']);
|
||||
}
|
||||
if (isset($options['end'])) {
|
||||
$end = $options['end'];
|
||||
unset($options['end']);
|
||||
}
|
||||
} else {
|
||||
$format = $options;
|
||||
}
|
||||
|
||||
if ($backwards) {
|
||||
$futureTime = $inSeconds;
|
||||
$pastTime = $now;
|
||||
} else {
|
||||
$futureTime = $now;
|
||||
$pastTime = $inSeconds;
|
||||
}
|
||||
$diff = $futureTime - $pastTime;
|
||||
|
||||
// If more than a week, then take into account the length of months
|
||||
if ($diff >= 604800) {
|
||||
$current = array();
|
||||
$date = array();
|
||||
|
||||
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime));
|
||||
|
||||
list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime));
|
||||
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
|
||||
|
||||
if ($future['Y'] == $past['Y'] && $future['m'] == $past['m']) {
|
||||
$months = 0;
|
||||
$years = 0;
|
||||
} else {
|
||||
if ($future['Y'] == $past['Y']) {
|
||||
$months = $future['m'] - $past['m'];
|
||||
} else {
|
||||
$years = $future['Y'] - $past['Y'];
|
||||
$months = $future['m'] + ((12 * $years) - $past['m']);
|
||||
|
||||
if ($months >= 12) {
|
||||
$years = floor($months / 12);
|
||||
$months = $months - ($years * 12);
|
||||
}
|
||||
|
||||
if ($future['m'] < $past['m'] && $future['Y'] - $past['Y'] == 1) {
|
||||
$years --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($future['d'] >= $past['d']) {
|
||||
$days = $future['d'] - $past['d'];
|
||||
} else {
|
||||
$daysInPastMonth = date('t', $pastTime);
|
||||
$daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));
|
||||
|
||||
if (!$backwards) {
|
||||
$days = ($daysInPastMonth - $past['d']) + $future['d'];
|
||||
} else {
|
||||
$days = ($daysInFutureMonth - $past['d']) + $future['d'];
|
||||
}
|
||||
|
||||
if ($future['m'] != $past['m']) {
|
||||
$months --;
|
||||
}
|
||||
}
|
||||
|
||||
if ($months == 0 && $years >= 1 && $diff < ($years * 31536000)) {
|
||||
$months = 11;
|
||||
$years --;
|
||||
}
|
||||
|
||||
if ($months >= 12) {
|
||||
$years = $years + 1;
|
||||
$months = $months - 12;
|
||||
}
|
||||
|
||||
if ($days >= 7) {
|
||||
$weeks = floor($days / 7);
|
||||
$days = $days - ($weeks * 7);
|
||||
}
|
||||
} else {
|
||||
$years = $months = $weeks = 0;
|
||||
$days = floor($diff / 86400);
|
||||
|
||||
$diff = $diff - ($days * 86400);
|
||||
|
||||
$hours = floor($diff / 3600);
|
||||
$diff = $diff - ($hours * 3600);
|
||||
|
||||
$minutes = floor($diff / 60);
|
||||
$diff = $diff - ($minutes * 60);
|
||||
$seconds = $diff;
|
||||
}
|
||||
$relativeDate = '';
|
||||
$diff = $futureTime - $pastTime;
|
||||
|
||||
if ($diff > abs($now - $this->fromString($end))) {
|
||||
$relativeDate = sprintf(__('on %s',true), date($format, $inSeconds));
|
||||
} else {
|
||||
if ($years > 0) {
|
||||
// years and months and days
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $years . ' ' . __n('year', 'years', $years, true);
|
||||
$relativeDate .= $months > 0 ? ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months, true) : '';
|
||||
$relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true) : '';
|
||||
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
|
||||
} elseif (abs($months) > 0) {
|
||||
// months, weeks and days
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months, true);
|
||||
$relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true) : '';
|
||||
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
|
||||
} elseif (abs($weeks) > 0) {
|
||||
// weeks and days
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true);
|
||||
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
|
||||
} elseif (abs($days) > 0) {
|
||||
// days and hours
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true);
|
||||
$relativeDate .= $hours > 0 ? ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours, true) : '';
|
||||
} elseif (abs($hours) > 0) {
|
||||
// hours and minutes
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours, true);
|
||||
$relativeDate .= $minutes > 0 ? ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes, true) : '';
|
||||
} elseif (abs($minutes) > 0) {
|
||||
// minutes only
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes, true);
|
||||
} else {
|
||||
// seconds only
|
||||
$relativeDate .= ($relativeDate ? ', ' : '') . $seconds . ' ' . __n('second', 'seconds', $seconds, true);
|
||||
}
|
||||
|
||||
if (!$backwards) {
|
||||
$relativeDate = sprintf(__('%s ago', true), $relativeDate);
|
||||
}
|
||||
}
|
||||
return $relativeDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for timeAgoInWords
|
||||
*
|
||||
* @param mixed $dateTime Datetime string (strtotime-compatible) or Unix timestamp
|
||||
* @param mixed $options Default format string, if timestamp is used in $dateTime, or an array of options to be passed
|
||||
* on to timeAgoInWords().
|
||||
* @return string Relative time string.
|
||||
* @see TimeHelper::timeAgoInWords
|
||||
* @access public
|
||||
* @deprecated This method alias will be removed in future versions.
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function relativeTime($dateTime, $options = array()) {
|
||||
return $this->timeAgoInWords($dateTime, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if specified datetime was within the interval specified, else false.
|
||||
*
|
||||
* @param mixed $timeInterval the numeric value with space then time type.
|
||||
* Example of valid types: 6 hours, 2 days, 1 minute.
|
||||
* @param mixed $dateString the datestring or unix timestamp to compare
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return bool
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1472/Testing-Time
|
||||
*/
|
||||
function wasWithinLast($timeInterval, $dateString, $userOffset = null) {
|
||||
$tmp = str_replace(' ', '', $timeInterval);
|
||||
if (is_numeric($tmp)) {
|
||||
$timeInterval = $tmp . ' ' . __('days', true);
|
||||
}
|
||||
|
||||
$date = $this->fromString($dateString, $userOffset);
|
||||
$interval = $this->fromString('-'.$timeInterval);
|
||||
|
||||
if ($date >= $interval && $date <= time()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns gmt, given either a UNIX timestamp or a valid strtotime() date string.
|
||||
*
|
||||
* @param string $dateString Datetime string
|
||||
* @return string Formatted date string
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1471/Formatting
|
||||
*/
|
||||
function gmt($string = null) {
|
||||
if ($string != null) {
|
||||
$string = $this->fromString($string);
|
||||
} else {
|
||||
$string = time();
|
||||
}
|
||||
$string = $this->fromString($string);
|
||||
$hour = intval(date("G", $string));
|
||||
$minute = intval(date("i", $string));
|
||||
$second = intval(date("s", $string));
|
||||
$month = intval(date("n", $string));
|
||||
$day = intval(date("j", $string));
|
||||
$year = intval(date("Y", $string));
|
||||
|
||||
return gmmktime($hour, $minute, $second, $month, $day, $year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string.
|
||||
* This function also accepts a time string and a format string as first and second parameters.
|
||||
* In that case this function behaves as a wrapper for TimeHelper::i18nFormat()
|
||||
*
|
||||
* @param string $format date format string (or a DateTime string)
|
||||
* @param string $dateString Datetime string (or a date format string)
|
||||
* @param boolean $invalid flag to ignore results of fromString == false
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Formatted date string
|
||||
* @access public
|
||||
*/
|
||||
function format($format, $date = null, $invalid = false, $userOffset = null) {
|
||||
$time = $this->fromString($date, $userOffset);
|
||||
$_time = $this->fromString($format, $userOffset);
|
||||
|
||||
if (is_numeric($_time) && $time === false) {
|
||||
$format = $date;
|
||||
return $this->i18nFormat($_time, $format, $invalid, $userOffset);
|
||||
}
|
||||
if ($time === false && $invalid !== false) {
|
||||
return $invalid;
|
||||
}
|
||||
return date($format, $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string.
|
||||
* It take in account the default date format for the current language if a LC_TIME file is used.
|
||||
*
|
||||
* @param string $dateString Datetime string
|
||||
* @param string $format strftime format string.
|
||||
* @param boolean $invalid flag to ignore results of fromString == false
|
||||
* @param int $userOffset User's offset from GMT (in hours)
|
||||
* @return string Formatted and translated date string @access public
|
||||
* @access public
|
||||
*/
|
||||
function i18nFormat($date, $format = null, $invalid = false, $userOffset = null) {
|
||||
$date = $this->fromString($date, $userOffset);
|
||||
if ($date === false && $invalid !== false) {
|
||||
return $invalid;
|
||||
}
|
||||
if (empty($format)) {
|
||||
$format = '%x';
|
||||
}
|
||||
$format = $this->convertSpecifiers($format, $date);
|
||||
return strftime($format, $date);
|
||||
}
|
||||
}
|
||||
174
web-cake/html/cake/libs/view/helpers/xml.php
Normal file
174
web-cake/html/cake/libs/view/helpers/xml.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* XML Helper class file.
|
||||
*
|
||||
* Simplifies the output of XML documents.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
App::import('Core', array('Xml', 'Set'));
|
||||
|
||||
/**
|
||||
* XML Helper class for easy output of XML structures.
|
||||
*
|
||||
* XmlHelper encloses all methods needed while working with XML documents.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs.view.helpers
|
||||
* @link http://book.cakephp.org/view/1473/XML
|
||||
*/
|
||||
class XmlHelper extends AppHelper {
|
||||
|
||||
/**
|
||||
* Default document encoding
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
var $encoding = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
$this->Xml =& new Xml();
|
||||
$this->Xml->options(array('verifyNs' => false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML document header
|
||||
*
|
||||
* @param array $attrib Header tag attributes
|
||||
* @return string XML header
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1476/header
|
||||
*/
|
||||
function header($attrib = array()) {
|
||||
if (Configure::read('App.encoding') !== null) {
|
||||
$this->encoding = Configure::read('App.encoding');
|
||||
}
|
||||
|
||||
if (is_array($attrib)) {
|
||||
$attrib = array_merge(array('encoding' => $this->encoding), $attrib);
|
||||
}
|
||||
if (is_string($attrib) && strpos($attrib, 'xml') !== 0) {
|
||||
$attrib = 'xml ' . $attrib;
|
||||
}
|
||||
|
||||
return $this->Xml->header($attrib);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a namespace to any documents generated
|
||||
*
|
||||
* @param string $name The namespace name
|
||||
* @param string $url The namespace URI; can be empty if in the default namespace map
|
||||
* @return boolean False if no URL is specified, and the namespace does not exist
|
||||
* default namespace map, otherwise true
|
||||
* @deprecated
|
||||
* @see Xml::addNs()
|
||||
*/
|
||||
function addNs($name, $url = null) {
|
||||
return $this->Xml->addNamespace($name, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a namespace added in addNs()
|
||||
*
|
||||
* @param string $name The namespace name or URI
|
||||
* @deprecated
|
||||
* @see Xml::removeNs()
|
||||
* @access public
|
||||
*/
|
||||
function removeNs($name) {
|
||||
return $this->Xml->removeGlobalNamespace($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an XML element
|
||||
*
|
||||
* @param string $name The name of the XML element
|
||||
* @param array $attrib The attributes of the XML element
|
||||
* @param mixed $content XML element content
|
||||
* @param boolean $endTag Whether the end tag of the element should be printed
|
||||
* @return string XML
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1475/elem
|
||||
*/
|
||||
function elem($name, $attrib = array(), $content = null, $endTag = true) {
|
||||
$namespace = null;
|
||||
if (isset($attrib['namespace'])) {
|
||||
$namespace = $attrib['namespace'];
|
||||
unset($attrib['namespace']);
|
||||
}
|
||||
$cdata = false;
|
||||
if (is_array($content) && isset($content['cdata'])) {
|
||||
$cdata = true;
|
||||
unset($content['cdata']);
|
||||
}
|
||||
if (is_array($content) && array_key_exists('value', $content)) {
|
||||
$content = $content['value'];
|
||||
}
|
||||
$children = array();
|
||||
if (is_array($content)) {
|
||||
$children = $content;
|
||||
$content = null;
|
||||
}
|
||||
|
||||
$elem =& $this->Xml->createElement($name, $content, $attrib, $namespace);
|
||||
foreach ($children as $child) {
|
||||
$elem->createElement($child);
|
||||
}
|
||||
$out = $elem->toString(array('cdata' => $cdata, 'leaveOpen' => !$endTag));
|
||||
|
||||
if (!$endTag) {
|
||||
$this->Xml =& $elem;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create closing tag for current element
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function closeElem() {
|
||||
$name = $this->Xml->name();
|
||||
if ($parent =& $this->Xml->parent()) {
|
||||
$this->Xml =& $parent;
|
||||
}
|
||||
return '</' . $name . '>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a model resultset into XML
|
||||
*
|
||||
* @param mixed $data The content to be converted to XML
|
||||
* @param array $options The data formatting options. For a list of valid options, see
|
||||
* Xml::__construct().
|
||||
* @return string A copy of $data in XML format
|
||||
* @see Xml::__construct()
|
||||
* @access public
|
||||
* @link http://book.cakephp.org/view/1474/serialize
|
||||
*/
|
||||
function serialize($data, $options = array()) {
|
||||
$options += array('attributes' => false, 'format' => 'attributes');
|
||||
$data =& new Xml($data, $options);
|
||||
return $data->toString($options + array('header' => false));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user