mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-09-08 04:22:40 +00:00
Moving some spare clases to the corresponding packages
This commit is contained in:
parent
c542ac20c9
commit
b19b25a788
9 changed files with 0 additions and 0 deletions
458
lib/Cake/Controller/Scaffold.php
Normal file
458
lib/Cake/Controller/Scaffold.php
Normal file
|
@ -0,0 +1,458 @@
|
|||
<?php
|
||||
/**
|
||||
* Scaffold.
|
||||
*
|
||||
* Automatic forms and actions generation for rapid web application development.
|
||||
*
|
||||
* PHP 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)
|
||||
*/
|
||||
App::uses('Scaffold', 'View');
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* Controller object
|
||||
*
|
||||
* @var Controller
|
||||
*/
|
||||
public $controller = null;
|
||||
|
||||
/**
|
||||
* Name of the controller to scaffold
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = null;
|
||||
|
||||
/**
|
||||
* Name of current model this view context is attached to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $model = null;
|
||||
|
||||
/**
|
||||
* Path to View.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $viewPath;
|
||||
|
||||
/**
|
||||
* Name of layout to use with this View.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $layout = 'default';
|
||||
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
* @var CakeRequest
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* valid session.
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
protected $_validSession = null;
|
||||
|
||||
/**
|
||||
* List of variables to collect from the associated controller
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
private $__passedVars = array(
|
||||
'layout', 'name', 'viewPath', 'request'
|
||||
);
|
||||
|
||||
/**
|
||||
* Title HTML element for current scaffolded view
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $scaffoldTitle = null;
|
||||
|
||||
/**
|
||||
* Construct and set up given controller with given parameters.
|
||||
*
|
||||
* @param Controller $controller Controller to scaffold
|
||||
* @param CakeRequest $request Request parameters.
|
||||
*/
|
||||
function __construct(Controller $controller, CakeRequest $request) {
|
||||
$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})) {
|
||||
throw new MissingModelException($this->modelClass);
|
||||
}
|
||||
|
||||
$this->ScaffoldModel = $this->controller->{$this->modelClass};
|
||||
$this->scaffoldTitle = Inflector::humanize($this->viewPath);
|
||||
$this->scaffoldActions = $controller->scaffold;
|
||||
$title_for_layout = __('Scaffold :: ') . Inflector::humanize($request->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($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a scaffold method passing it through the Controller::afterFilter()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _output() {
|
||||
$this->controller->afterFilter();
|
||||
$this->controller->getResponse()->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view action of scaffolded model.
|
||||
*
|
||||
* @param CakeRequest $request Request Object for scaffolding
|
||||
* @return mixed A rendered view of a row from Models database table
|
||||
*/
|
||||
protected function _scaffoldView(CakeRequest $request) {
|
||||
if ($this->controller->_beforeScaffold('view')) {
|
||||
|
||||
$message = __(sprintf("No id set for %s::view()", Inflector::humanize($this->modelKey)));
|
||||
if (isset($request->params['pass'][0])) {
|
||||
$this->ScaffoldModel->id = $request->params['pass'][0];
|
||||
} else {
|
||||
return $this->_sendMessage($message);
|
||||
}
|
||||
$this->ScaffoldModel->recursive = 1;
|
||||
$this->controller->request->data = $this->controller->data = $this->ScaffoldModel->read();
|
||||
$this->controller->set(
|
||||
Inflector::variable($this->controller->modelClass), $this->request->data
|
||||
);
|
||||
$this->controller->render($this->request['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
|
||||
*/
|
||||
protected 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->request['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
|
||||
*/
|
||||
protected 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 CakeRequest $request Request Object 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
|
||||
*/
|
||||
protected function _scaffoldSave(CakeRequest $request, $action = 'edit') {
|
||||
$formAction = 'edit';
|
||||
$success = __('updated');
|
||||
if ($action === 'add') {
|
||||
$formAction = 'add';
|
||||
$success = __('saved');
|
||||
}
|
||||
|
||||
if ($this->controller->_beforeScaffold($action)) {
|
||||
if ($action == 'edit') {
|
||||
if (isset($request->params['pass'][0])) {
|
||||
$this->ScaffoldModel->id = $request['pass'][0];
|
||||
}
|
||||
|
||||
if (!$this->ScaffoldModel->exists()) {
|
||||
$message = __(sprintf("Invalid id for %s::edit()", Inflector::humanize($this->modelKey)));
|
||||
return $this->_sendMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($request->data)) {
|
||||
if ($action == 'create') {
|
||||
$this->ScaffoldModel->create();
|
||||
}
|
||||
|
||||
if ($this->ScaffoldModel->save($request->data)) {
|
||||
if ($this->controller->_afterScaffoldSave($action)) {
|
||||
$message = __(
|
||||
sprintf('The %1$s has been %2$s', Inflector::humanize($this->modelKey), $success)
|
||||
);
|
||||
return $this->_sendMessage($message);
|
||||
} else {
|
||||
return $this->controller->_afterScaffoldSaveError($action);
|
||||
}
|
||||
} else {
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash(__('Please correct errors below.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($request->data)) {
|
||||
if ($this->ScaffoldModel->id) {
|
||||
$this->controller->data = $request->data = $this->ScaffoldModel->read();
|
||||
} else {
|
||||
$this->controller->data = $request->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
|
||||
*/
|
||||
protected function _scaffoldDelete(CakeRequest $request) {
|
||||
if ($this->controller->_beforeScaffold('delete')) {
|
||||
$message = __(
|
||||
sprintf("No id set for %s::delete()", Inflector::humanize($this->modelKey))
|
||||
);
|
||||
if (isset($request->params['pass'][0])) {
|
||||
$id = $request->params['pass'][0];
|
||||
} else {
|
||||
return $this->_sendMessage($message);
|
||||
}
|
||||
|
||||
if ($this->ScaffoldModel->delete($id)) {
|
||||
$message = __(
|
||||
sprintf('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id)
|
||||
);
|
||||
return $this->_sendMessage($message);
|
||||
} else {
|
||||
$message = __(sprintf(
|
||||
'There was an error deleting the %1$s with id: %2$d',
|
||||
Inflector::humanize($this->modelClass), $id
|
||||
));
|
||||
return $this->_sendMessage($message);
|
||||
}
|
||||
} elseif ($this->controller->_scaffoldError('delete') === false) {
|
||||
return $this->_scaffoldError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the user. Either uses Sessions or flash messages depending
|
||||
* on the availability of a session
|
||||
*
|
||||
* @param string $message Message to display
|
||||
* @return void
|
||||
*/
|
||||
protected function _sendMessage($message) {
|
||||
if ($this->_validSession) {
|
||||
$this->controller->Session->setFlash($message);
|
||||
$this->controller->redirect($this->redirect);
|
||||
} else {
|
||||
$this->controller->flash($message, $this->redirect);
|
||||
$this->_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a scaffold error
|
||||
*
|
||||
* @return mixed A rendered view showing the error
|
||||
*/
|
||||
protected 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:
|
||||
* `public $scaffold;` is placed in the controller's class definition.
|
||||
*
|
||||
* @param CakeRequest $request Request object for scaffolding
|
||||
* @return mixed A rendered view of scaffold action, or showing the error
|
||||
*/
|
||||
protected function _scaffold(CakeRequest $request) {
|
||||
$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($request->params['action'], $this->scaffoldActions)) {
|
||||
if (!empty($prefixes)) {
|
||||
$request->params['action'] = str_replace($scaffoldPrefix . '_', '', $request->params['action']);
|
||||
}
|
||||
switch ($request->params['action']) {
|
||||
case 'index':
|
||||
case 'list':
|
||||
$this->_scaffoldIndex($request);
|
||||
break;
|
||||
case 'view':
|
||||
$this->_scaffoldView($request);
|
||||
break;
|
||||
case 'add':
|
||||
case 'create':
|
||||
$this->_scaffoldSave($request, 'add');
|
||||
break;
|
||||
case 'edit':
|
||||
case 'update':
|
||||
$this->_scaffoldSave($request, 'edit');
|
||||
break;
|
||||
case 'delete':
|
||||
$this->_scaffoldDelete($request);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
throw new MissingActionException(array(
|
||||
'controller' => $this->controller->name,
|
||||
'action' => $request->action
|
||||
));
|
||||
}
|
||||
} else {
|
||||
throw new MissingDatabaseException(array('connection' => $this->ScaffoldModel->useDbConfig));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns associations for controllers models.
|
||||
*
|
||||
* @return array Associations for model
|
||||
*/
|
||||
protected 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;
|
||||
}
|
||||
}
|
291
lib/Cake/Network/CakeSocket.php
Normal file
291
lib/Cake/Network/CakeSocket.php
Normal file
|
@ -0,0 +1,291 @@
|
|||
<?php
|
||||
/**
|
||||
* Cake Socket connection class.
|
||||
*
|
||||
* PHP 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::uses('Validation', 'Core');
|
||||
|
||||
/**
|
||||
* Cake network socket connection class.
|
||||
*
|
||||
* Core base class for network communication.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class CakeSocket {
|
||||
|
||||
/**
|
||||
* Object description
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $description = 'Remote DataSource Network Socket Interface';
|
||||
|
||||
/**
|
||||
* Base configuration settings for the socket connection
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected $_baseConfig = array(
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'protocol' => 'tcp',
|
||||
'port' => 80,
|
||||
'timeout' => 30
|
||||
);
|
||||
|
||||
/**
|
||||
* Configuration settings for the socket connection
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
public $config = array();
|
||||
|
||||
/**
|
||||
* Reference to socket connection resource
|
||||
*
|
||||
* @var resource
|
||||
* @access public
|
||||
*/
|
||||
public $connection = null;
|
||||
|
||||
/**
|
||||
* This boolean contains the current state of the CakeSocket class
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
public $connected = false;
|
||||
|
||||
/**
|
||||
* This variable contains an array with the last error number (num) and string (str)
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
public $lastError = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config Socket configuration, which will be merged with the base configuration
|
||||
* @see CakeSocket::$_baseConfig
|
||||
*/
|
||||
function __construct($config = array()) {
|
||||
$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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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'));
|
||||
return false;
|
||||
}
|
||||
return $buffer;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort socket operation.
|
||||
*
|
||||
* @return boolean Success
|
||||
*/
|
||||
public function abort() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the socket from the current connection.
|
||||
*
|
||||
* @return boolean Success
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
1063
lib/Cake/Network/HttpSocket.php
Normal file
1063
lib/Cake/Network/HttpSocket.php
Normal file
File diff suppressed because it is too large
Load diff
513
lib/Cake/Utility/File.php
Normal file
513
lib/Cake/Utility/File.php
Normal file
|
@ -0,0 +1,513 @@
|
|||
<?php
|
||||
/**
|
||||
* Convenience class for reading, writing and appending to files.
|
||||
*
|
||||
* PHP 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('Folder')) {
|
||||
require LIBS . 'folder.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience class for reading, writing and appending to files.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class File {
|
||||
|
||||
/**
|
||||
* Folder object of the File
|
||||
*
|
||||
* @var Folder
|
||||
* @access public
|
||||
*/
|
||||
public $Folder = null;
|
||||
|
||||
/**
|
||||
* Filename
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $name = null;
|
||||
|
||||
/**
|
||||
* file info
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $info = array();
|
||||
|
||||
/**
|
||||
* Holds the file handler resource if the file is opened
|
||||
*
|
||||
* @var resource
|
||||
* @access public
|
||||
*/
|
||||
public $handle = null;
|
||||
|
||||
/**
|
||||
* enable locking for file reading and writing
|
||||
*
|
||||
* @var boolean
|
||||
* @access public
|
||||
*/
|
||||
public $lock = null;
|
||||
|
||||
/**
|
||||
* path property
|
||||
*
|
||||
* Current file's absolute path
|
||||
*
|
||||
* @var mixed null
|
||||
* @access public
|
||||
*/
|
||||
public $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) {
|
||||
$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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function close() {
|
||||
if (!is_resource($this->handle)) {
|
||||
return true;
|
||||
}
|
||||
return fclose($this->handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the File.
|
||||
*
|
||||
* @return boolean Success
|
||||
*/
|
||||
public function delete() {
|
||||
clearstatcache();
|
||||
if ($this->exists()) {
|
||||
return unlink($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File info.
|
||||
*
|
||||
* @return string The File extension
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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()}
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function writable() {
|
||||
return is_writable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is executable.
|
||||
*
|
||||
* @return boolean true if its executable, false otherwise
|
||||
*/
|
||||
public function executable() {
|
||||
return is_executable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the File is readable.
|
||||
*
|
||||
* @return boolean true if file is readable, false otherwise
|
||||
*/
|
||||
public function readable() {
|
||||
return is_readable($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File's owner.
|
||||
*
|
||||
* @return integer the Fileowner
|
||||
*/
|
||||
public function owner() {
|
||||
if ($this->exists()) {
|
||||
return fileowner($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File's group.
|
||||
*
|
||||
* @return integer the Filegroup
|
||||
*/
|
||||
public function group() {
|
||||
if ($this->exists()) {
|
||||
return filegroup($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last access time.
|
||||
*
|
||||
* @return integer timestamp Timestamp of last access time
|
||||
*/
|
||||
public function lastAccess() {
|
||||
if ($this->exists()) {
|
||||
return fileatime($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last modified time.
|
||||
*
|
||||
* @return integer timestamp Timestamp of last modification
|
||||
*/
|
||||
public function lastChange() {
|
||||
if ($this->exists()) {
|
||||
return filemtime($this->path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current folder.
|
||||
*
|
||||
* @return Folder Current folder
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function copy($dest, $overwrite = true) {
|
||||
if (!$this->exists() || is_file($dest) && !$overwrite) {
|
||||
return false;
|
||||
}
|
||||
return copy($this->path, $dest);
|
||||
}
|
||||
}
|
294
lib/Cake/Utility/MagicDb.php
Normal file
294
lib/Cake/Utility/MagicDb.php
Normal file
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
/**
|
||||
* MagicDb parser and file analyzer
|
||||
*
|
||||
* PHP 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
|
||||
*/
|
||||
public $db = array();
|
||||
|
||||
/**
|
||||
* Reads a MagicDb from various formats
|
||||
*
|
||||
* @public $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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public $resource = null;
|
||||
|
||||
/**
|
||||
* undocumented variable
|
||||
*
|
||||
* @var unknown
|
||||
* @access public
|
||||
*/
|
||||
public $offset = 0;
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $file
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($file) {
|
||||
if (file_exists($file)) {
|
||||
$this->resource = new File($file);
|
||||
} else {
|
||||
$this->resource = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* undocumented function
|
||||
*
|
||||
* @param unknown $magic
|
||||
* @return void
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
331
lib/Cake/Utility/Sanitize.php
Normal file
331
lib/Cake/Utility/Sanitize.php
Normal file
|
@ -0,0 +1,331 @@
|
|||
<?php
|
||||
/**
|
||||
* Washes strings from unwanted noise.
|
||||
*
|
||||
* Helpful methods to make unsafe strings usable.
|
||||
*
|
||||
* PHP 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
* - double (boolean) doube encode html entities
|
||||
*
|
||||
* @param string $string String from where to strip tags
|
||||
* @param array $options Array of options to use.
|
||||
* @return string Sanitized string
|
||||
*/
|
||||
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,
|
||||
'double' => true
|
||||
);
|
||||
|
||||
$options = array_merge($default, $options);
|
||||
|
||||
if ($options['remove']) {
|
||||
$string = strip_tags($string);
|
||||
}
|
||||
|
||||
return htmlentities($string, $options['quotes'], $options['charset'], $options['double']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips extra whitespace from output
|
||||
*
|
||||
* @param string $str String to sanitize
|
||||
* @return string whitespace sanitized string
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static function stripTags() {
|
||||
$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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
159
lib/Cake/Utility/Security.php
Normal file
159
lib/Cake/Utility/Security.php
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* Core Security
|
||||
*
|
||||
* PHP 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)
|
||||
*/
|
||||
|
||||
App::uses('String', 'Core');
|
||||
|
||||
/**
|
||||
* Security Library contains utility methods related to security
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Security {
|
||||
|
||||
/**
|
||||
* Default hash method
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $hashType = null;
|
||||
|
||||
/**
|
||||
* Get allowed minutes of inactivity based on security level.
|
||||
*
|
||||
* @return integer Allowed inactivity in minutes
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static function generateAuthKey() {
|
||||
return Security::hash(String::uuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate authorization hash.
|
||||
*
|
||||
* @param string $authKey Authorization hash
|
||||
* @return boolean Success
|
||||
* @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
|
||||
*/
|
||||
public static function hash($string, $type = null, $salt = false) {
|
||||
if ($salt) {
|
||||
if (is_string($salt)) {
|
||||
$string = $salt . $string;
|
||||
} else {
|
||||
$string = Configure::read('Security.salt') . $string;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($type)) {
|
||||
$type = self::$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)
|
||||
* @return void
|
||||
* @see Security::hash()
|
||||
*/
|
||||
public static function setHash($hash) {
|
||||
self::$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
|
||||
*/
|
||||
public static function cipher($text, $key) {
|
||||
if (empty($key)) {
|
||||
trigger_error(__('You cannot use an empty key for Security::cipher()'), 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;
|
||||
}
|
||||
}
|
836
lib/Cake/Utility/Validation.php
Normal file
836
lib/Cake/Utility/Validation.php
Normal file
|
@ -0,0 +1,836 @@
|
|||
<?php
|
||||
/**
|
||||
* Validation Class. Used for validation of model data
|
||||
*
|
||||
* PHP Version 5.x
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2009, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2009, 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.3830
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
App::uses('Multibyte', 'I18n');
|
||||
|
||||
/**
|
||||
* Offers different validation methods.
|
||||
*
|
||||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
* @since CakePHP v 1.2.0.3830
|
||||
*/
|
||||
class Validation {
|
||||
|
||||
/**
|
||||
* Some complex patterns needed in multiple places
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $__pattern = array(
|
||||
'hostname' => '(?:[a-z0-9][-a-z0-9]*\.)*(?:[a-z0-9][-a-z0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,4}|museum|travel)'
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds an array of errors messages set in this class.
|
||||
* These are used for debugging purposes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $errors = array();
|
||||
|
||||
/**
|
||||
* Checks that a string contains something other than whitespace
|
||||
*
|
||||
* Returns true if string contains something other than whitespace
|
||||
*
|
||||
* $check can be passed as an array:
|
||||
* array('check' => 'valueToCheck');
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function notEmpty($check) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (empty($check) && $check != '0') {
|
||||
return false;
|
||||
}
|
||||
return self::_check($check, '/[^\s]+/m');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string contains only integer or letters
|
||||
*
|
||||
* Returns true if string contains only integer or letters
|
||||
*
|
||||
* $check can be passed as an array:
|
||||
* array('check' => 'valueToCheck');
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function alphaNumeric($check) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (empty($check) && $check != '0') {
|
||||
return false;
|
||||
}
|
||||
return self::_check($check, '/^[\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]+$/mu');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string length is within s specified range.
|
||||
* Spaces are included in the character count.
|
||||
* Returns true is string matches value min, max, or between min and max,
|
||||
*
|
||||
* @param string $check Value to check for length
|
||||
* @param integer $min Minimum value in range (inclusive)
|
||||
* @param integer $max Maximum value in range (inclusive)
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function between($check, $min, $max) {
|
||||
$length = mb_strlen($check);
|
||||
return ($length >= $min && $length <= $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if field is left blank -OR- only whitespace characters are present in it's value
|
||||
* Whitespace characters include Space, Tab, Carriage Return, Newline
|
||||
*
|
||||
* $check can be passed as an array:
|
||||
* array('check' => 'valueToCheck');
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function blank($check) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
return !self::_check($check, '/[^\\s]/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation of credit card numbers.
|
||||
* Returns true if $check is in the proper credit card format.
|
||||
*
|
||||
* @param mixed $check credit card number to validate
|
||||
* @param mixed $type 'all' may be passed as a sting, defaults to fast which checks format of most major credit cards
|
||||
* if an array is used only the values of the array are checked.
|
||||
* Example: array('amex', 'bankcard', 'maestro')
|
||||
* @param boolean $deep set to true this will check the Luhn algorithm of the credit card.
|
||||
* @param string $regex A custom regex can also be passed, this will be used instead of the defined regex values
|
||||
* @return boolean Success
|
||||
* @see Validation::luhn()
|
||||
*/
|
||||
public static function cc($check, $type = 'fast', $deep = false, $regex = null) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
$check = str_replace(array('-', ' '), '', $check);
|
||||
if (mb_strlen($check) < 13) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_null($regex)) {
|
||||
if (self::_check($check, $regex)) {
|
||||
return self::luhn($check, $deep);
|
||||
}
|
||||
}
|
||||
$cards = array(
|
||||
'all' => array(
|
||||
'amex' => '/^3[4|7]\\d{13}$/',
|
||||
'bankcard' => '/^56(10\\d\\d|022[1-5])\\d{10}$/',
|
||||
'diners' => '/^(?:3(0[0-5]|[68]\\d)\\d{11})|(?:5[1-5]\\d{14})$/',
|
||||
'disc' => '/^(?:6011|650\\d)\\d{12}$/',
|
||||
'electron' => '/^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$/',
|
||||
'enroute' => '/^2(?:014|149)\\d{11}$/',
|
||||
'jcb' => '/^(3\\d{4}|2100|1800)\\d{11}$/',
|
||||
'maestro' => '/^(?:5020|6\\d{3})\\d{12}$/',
|
||||
'mc' => '/^5[1-5]\\d{14}$/',
|
||||
'solo' => '/^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$/',
|
||||
'switch' => '/^(?:49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})\\d{10}(\\d{2,3})?)|(?:564182\\d{10}(\\d{2,3})?)|(6(3(33[0-4][0-9])|759[0-9]{2})\\d{10}(\\d{2,3})?)$/',
|
||||
'visa' => '/^4\\d{12}(\\d{3})?$/',
|
||||
'voyager' => '/^8699[0-9]{11}$/'),
|
||||
'fast' => '/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/');
|
||||
|
||||
if (is_array($type)) {
|
||||
foreach ($type as $value) {
|
||||
$regex = $cards['all'][strtolower($value)];
|
||||
|
||||
if (self::_check($check, $regex)) {
|
||||
return self::luhn($check, $deep);
|
||||
}
|
||||
}
|
||||
} elseif ($type == 'all') {
|
||||
foreach ($cards['all'] as $value) {
|
||||
$regex = $value;
|
||||
|
||||
if (self::_check($check, $regex)) {
|
||||
return self::luhn($check, $deep);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$regex = $cards['fast'];
|
||||
|
||||
if (self::_check($check, $regex)) {
|
||||
return self::luhn($check, $deep);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to compare 2 numeric values.
|
||||
*
|
||||
* @param mixed $check1 if string is passed for a string must also be passed for $check2
|
||||
* used as an array it must be passed as array('check1' => value, 'operator' => 'value', 'check2' -> value)
|
||||
* @param string $operator Can be either a word or operand
|
||||
* is greater >, is less <, greater or equal >=
|
||||
* less or equal <=, is less <, equal to ==, not equal !=
|
||||
* @param integer $check2 only needed if $check1 is a string
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function comparison($check1, $operator = null, $check2 = null) {
|
||||
if (is_array($check1)) {
|
||||
extract($check1, EXTR_OVERWRITE);
|
||||
}
|
||||
$operator = str_replace(array(' ', "\t", "\n", "\r", "\0", "\x0B"), '', strtolower($operator));
|
||||
|
||||
switch ($operator) {
|
||||
case 'isgreater':
|
||||
case '>':
|
||||
if ($check1 > $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'isless':
|
||||
case '<':
|
||||
if ($check1 < $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'greaterorequal':
|
||||
case '>=':
|
||||
if ($check1 >= $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'lessorequal':
|
||||
case '<=':
|
||||
if ($check1 <= $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'equalto':
|
||||
case '==':
|
||||
if ($check1 == $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'notequal':
|
||||
case '!=':
|
||||
if ($check1 != $check2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
self::$errors[] = __('You must define the $operator parameter for Validation::comparison()', true);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when a custom regular expression is needed.
|
||||
*
|
||||
* @param mixed $check When used as a string, $regex must also be a valid regular expression.
|
||||
* As and array: array('check' => value, 'regex' => 'valid regular expression')
|
||||
* @param string $regex If $check is passed as a string, $regex must also be set to valid regular expression
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function custom($check, $regex = null) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
if ($regex === null) {
|
||||
self::$errors[] = __('You must define a regular expression for Validation::custom()', true);
|
||||
return false;
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date validation, determines if the string passed is a valid date.
|
||||
* keys that expect full month, day and year will validate leap years
|
||||
*
|
||||
* @param string $check a valid date string
|
||||
* @param mixed $format Use a string or an array of the keys below. Arrays should be passed as array('dmy', 'mdy', etc)
|
||||
* Keys: dmy 27-12-2006 or 27-12-06 separators can be a space, period, dash, forward slash
|
||||
* mdy 12-27-2006 or 12-27-06 separators can be a space, period, dash, forward slash
|
||||
* ymd 2006-12-27 or 06-12-27 separators can be a space, period, dash, forward slash
|
||||
* dMy 27 December 2006 or 27 Dec 2006
|
||||
* Mdy December 27, 2006 or Dec 27, 2006 comma is optional
|
||||
* My December 2006 or Dec 2006
|
||||
* my 12/2006 separators can be a space, period, dash, forward slash
|
||||
* @param string $regex If a custom regular expression is used this is the only validation that will occur.
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function date($check, $format = 'ymd', $regex = null) {
|
||||
if (!is_null($regex)) {
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
$regex['dmy'] = '%^(?:(?:31(\\/|-|\\.|\\x20)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.|\\x20)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.|\\x20)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.|\\x20)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
|
||||
$regex['mdy'] = '%^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.|\\x20)31)\\1|(?:(?:0?[13-9]|1[0-2])(\\/|-|\\.|\\x20)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2(\\/|-|\\.|\\x20)29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.|\\x20)(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
|
||||
$regex['ymd'] = '%^(?:(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.|\\x20)(?:0?2\\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.|\\x20)(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]))))$%';
|
||||
$regex['dMy'] = '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ (((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))|(0?[1-9])|1\\d|2[0-8])\\ (Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ((1[6-9]|[2-9]\\d)\\d{2})$/';
|
||||
$regex['Mdy'] = '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sept|Nov|Dec)(ember)?)\\ (0?[1-9]|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ ((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))))\\,?\\ ((1[6-9]|[2-9]\\d)\\d{2}))$/';
|
||||
$regex['My'] = '%^(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)[ /]((1[6-9]|[2-9]\\d)\\d{2})$%';
|
||||
$regex['my'] = '%^(((0[123456789]|10|11|12)([- /.])(([1][9][0-9][0-9])|([2][0-9][0-9][0-9]))))$%';
|
||||
|
||||
$format = (is_array($format)) ? array_values($format) : array($format);
|
||||
foreach ($format as $key) {
|
||||
$regex = $regex[$key];
|
||||
|
||||
if (self::_check($check, $regex) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time validation, determines if the string passed is a valid time.
|
||||
* Validates time as 24hr (HH:MM) or am/pm ([H]H:MM[a|p]m)
|
||||
* Does not allow/validate seconds.
|
||||
*
|
||||
* @param string $check a valid time string
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function time($check) {
|
||||
return self::_check($check, '%^((0?[1-9]|1[012])(:[0-5]\d){0,2}([AP]M|[ap]m))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$%');
|
||||
}
|
||||
|
||||
/**
|
||||
* Boolean validation, determines if value passed is a boolean integer or true/false.
|
||||
*
|
||||
* @param string $check a valid boolean
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function boolean($check) {
|
||||
$booleanList = array(0, 1, '0', '1', true, false);
|
||||
return in_array($check, $booleanList, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a value is a valid decimal. If $places is null, the $check is allowed to be a scientific float
|
||||
* If no decimal point is found a false will be returned. Both the sign and exponent are optional.
|
||||
*
|
||||
* @param integer $check The value the test for decimal
|
||||
* @param integer $places if set $check value must have exactly $places after the decimal point
|
||||
* @param string $regex If a custom regular expression is used this is the only validation that will occur.
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function decimal($check, $places = null, $regex = null) {
|
||||
if (is_null($regex)) {
|
||||
if (is_null($places)) {
|
||||
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]+(?:[eE][-+]?[0-9]+)?$/';
|
||||
} else {
|
||||
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]{'.$places.'}$/';
|
||||
}
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates for an email address.
|
||||
*
|
||||
* Only uses getmxrr() checking for deep validation if PHP 5.3.0+ is used, or
|
||||
* any PHP version on a non-windows distribution
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param boolean $deep Perform a deeper validation (if true), by also checking availability of host
|
||||
* @param string $regex Regex to use (if none it will use built in regex)
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function email($check, $deep = false, $regex = null) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (is_null($regex)) {
|
||||
$regex = '/^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@' . self::$__pattern['hostname'] . '$/i';
|
||||
}
|
||||
$return = self::_check($check, $regex);
|
||||
if ($deep === false || $deep === null) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
if ($return === true && preg_match('/@(' . self::$__pattern['hostname'] . ')$/i', $check, $regs)) {
|
||||
if (function_exists('getmxrr') && getmxrr($regs[1], $mxhosts)) {
|
||||
return true;
|
||||
}
|
||||
if (function_exists('checkdnsrr') && checkdnsrr($regs[1], 'MX')) {
|
||||
return true;
|
||||
}
|
||||
return is_array(gethostbynamel($regs[1]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that value is exactly $comparedTo.
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @param mixed $comparedTo Value to compare
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function equalTo($check, $comparedTo) {
|
||||
return ($check === $comparedTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that value has a valid file extension.
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @param array $extensions file extenstions to allow
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function extension($check, $extensions = array('gif', 'jpeg', 'png', 'jpg')) {
|
||||
if (is_array($check)) {
|
||||
return self::extension(array_shift($check), $extensions);
|
||||
}
|
||||
$extension = strtolower(array_pop(explode('.', $check)));
|
||||
foreach ($extensions as $value) {
|
||||
if ($extension == strtolower($value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation of an IP address.
|
||||
*
|
||||
* @param string $check The string to test.
|
||||
* @param string $ipVersion The IP Protocol version to validate against
|
||||
* @return boolean Success
|
||||
*/
|
||||
public function ip($check, $type = 'both') {
|
||||
$type = strtolower($type);
|
||||
$flags = array();
|
||||
if ($type === 'ipv4' || $type === 'both') {
|
||||
$flags[] = FILTER_FLAG_IPV4;
|
||||
}
|
||||
if ($type === 'ipv6' || $type === 'both') {
|
||||
$flags[] = FILTER_FLAG_IPV6;
|
||||
}
|
||||
return (boolean)filter_var($check, FILTER_VALIDATE_IP, array('flags' => $flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the length of a string is greater or equal to a minimal length.
|
||||
*
|
||||
* @param string $check The string to test
|
||||
* @param integer $min The minimal string length
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function minLength($check, $min) {
|
||||
return mb_strlen($check) >= $min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the length of a string is smaller or equal to a maximal length..
|
||||
*
|
||||
* @param string $check The string to test
|
||||
* @param integer $max The maximal string length
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function maxLength($check, $max) {
|
||||
return mb_strlen($check) <= $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a value is a monetary amount.
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param string $symbolPosition Where symbol is located (left/right)
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function money($check, $symbolPosition = 'left') {
|
||||
$money = '(?!0,?\d)(?:\d{1,3}(?:([, .])\d{3})?(?:\1\d{3})*|(?:\d+))((?!\1)[,.]\d{2})?';
|
||||
if ($symbolPosition == 'right') {
|
||||
$regex = '/^' . $money . '(?<!\x{00a2})\p{Sc}?$/u';
|
||||
} else {
|
||||
$regex = '/^(?!\x{00a2})\p{Sc}?' . $money . '$/u';
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a multiple select.
|
||||
*
|
||||
* Valid Options
|
||||
*
|
||||
* - in => provide a list of choices that selections must be made from
|
||||
* - max => maximun number of non-zero choices that can be made
|
||||
* - min => minimum number of non-zero choices that can be made
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @param mixed $options Options for the check.
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function multiple($check, $options = array()) {
|
||||
$defaults = array('in' => null, 'max' => null, 'min' => null);
|
||||
$options = array_merge($defaults, $options);
|
||||
$check = array_filter((array)$check);
|
||||
if (empty($check)) {
|
||||
return false;
|
||||
}
|
||||
if ($options['max'] && count($check) > $options['max']) {
|
||||
return false;
|
||||
}
|
||||
if ($options['min'] && count($check) < $options['min']) {
|
||||
return false;
|
||||
}
|
||||
if ($options['in'] && is_array($options['in'])) {
|
||||
foreach ($check as $val) {
|
||||
if (!in_array($val, $options['in'])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is numeric.
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @return boolean Succcess
|
||||
*/
|
||||
public static function numeric($check) {
|
||||
return is_numeric($check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a value is a valid phone number.
|
||||
*
|
||||
* @param mixed $check Value to check (string or array)
|
||||
* @param string $regex Regular expression to use
|
||||
* @param string $country Country code (defaults to 'all')
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function phone($check, $regex = null, $country = 'all') {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (is_null($regex)) {
|
||||
switch ($country) {
|
||||
case 'us':
|
||||
case 'all':
|
||||
case 'can':
|
||||
// includes all NANPA members. see http://en.wikipedia.org/wiki/North_American_Numbering_Plan#List_of_NANPA_countries_and_territories
|
||||
$regex = '/^(?:\+?1)?[-. ]?\\(?[2-9][0-8][0-9]\\)?[-. ]?[2-9][0-9]{2}[-. ]?[0-9]{4}$/';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty($regex)) {
|
||||
return self::_pass('phone', $check, $country);
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a given value is a valid postal code.
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @param string $regex Regular expression to use
|
||||
* @param string $country Country to use for formatting
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function postal($check, $regex = null, $country = 'us') {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (is_null($regex)) {
|
||||
switch ($country) {
|
||||
case 'uk':
|
||||
$regex = '/\\A\\b[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}\\b\\z/i';
|
||||
break;
|
||||
case 'ca':
|
||||
$regex = '/\\A\\b[ABCEGHJKLMNPRSTVXY][0-9][A-Z] [0-9][A-Z][0-9]\\b\\z/i';
|
||||
break;
|
||||
case 'it':
|
||||
case 'de':
|
||||
$regex = '/^[0-9]{5}$/i';
|
||||
break;
|
||||
case 'be':
|
||||
$regex = '/^[1-9]{1}[0-9]{3}$/i';
|
||||
break;
|
||||
case 'us':
|
||||
$regex = '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty($regex)) {
|
||||
return self::_pass('postal', $check, $country);
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a number is in specified range.
|
||||
* if $lower and $upper are not set, will return true if
|
||||
* $check is a legal finite on this platform
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param integer $lower Lower limit
|
||||
* @param integer $upper Upper limit
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function range($check, $lower = null, $upper = null) {
|
||||
if (!is_numeric($check)) {
|
||||
return false;
|
||||
}
|
||||
if (isset($lower) && isset($upper)) {
|
||||
return ($check > $lower && $check < $upper);
|
||||
}
|
||||
return is_finite($check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a value is a valid Social Security Number.
|
||||
*
|
||||
* @param mixed $check Value to check
|
||||
* @param string $regex Regular expression to use
|
||||
* @param string $country Country
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function ssn($check, $regex = null, $country = null) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
|
||||
if (is_null($regex)) {
|
||||
switch ($country) {
|
||||
case 'dk':
|
||||
$regex = '/\\A\\b[0-9]{6}-[0-9]{4}\\b\\z/i';
|
||||
break;
|
||||
case 'nl':
|
||||
$regex = '/\\A\\b[0-9]{9}\\b\\z/i';
|
||||
break;
|
||||
case 'us':
|
||||
$regex = '/\\A\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b\\z/i';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty($regex)) {
|
||||
return self::_pass('ssn', $check, $country);
|
||||
}
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt
|
||||
*
|
||||
* The regex checks for the following component parts:
|
||||
*
|
||||
* - a valid, optional, scheme
|
||||
* - a valid ip address OR
|
||||
* a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt
|
||||
* with an optional port number
|
||||
* - an optional valid path
|
||||
* - an optional query string (get parameters)
|
||||
* - an optional fragment (anchor tag)
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param boolean $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher)
|
||||
* @param string $ipVersion The IP Protocol version to validate against
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function url($check, $strict = false) {
|
||||
self::__populateIp();
|
||||
$validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~') . '\/0-9a-z]|(%[0-9a-f]{2}))';
|
||||
$regex = '/^(?:(?:https?|ftps?|file|news|gopher):\/\/)' . (!empty($strict) ? '' : '?') .
|
||||
'(?:' . self::$__pattern['IPv4'] . '|' . self::$__pattern['hostname'] . ')(?::[1-9][0-9]{0,3})?' .
|
||||
'(?:\/?|\/' . $validChars . '*)?' .
|
||||
'(?:\?' . $validChars . '*)?' .
|
||||
'(?:#' . $validChars . '*)?$/i';
|
||||
return self::_check($check, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is in a given list.
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param array $list List to check against
|
||||
* @return boolean Succcess
|
||||
*/
|
||||
public static function inList($check, $list) {
|
||||
return in_array($check, $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an user-defined validation.
|
||||
*
|
||||
* @param mixed $check value that will be validated in user-defined methods.
|
||||
* @param object $object class that holds validation method
|
||||
* @param string $method class method name for validation to run
|
||||
* @param array $args arguments to send to method
|
||||
* @return mixed user-defined class class method returns
|
||||
*/
|
||||
public static function userDefined($check, $object, $method, $args = null) {
|
||||
return call_user_func_array(array($object, $method), array($check, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to pass unhandled Validation locales to a class starting with $classPrefix
|
||||
* and ending with Validation. For example $classPrefix = 'nl', the class would be
|
||||
* `NlValidation`.
|
||||
*
|
||||
* @param string $method The method to call on the other class.
|
||||
* @param mixed $check The value to check or an array of parameters for the method to be called.
|
||||
* @param string $classPrefix The prefix for the class to do the validation.
|
||||
* @return mixed Return of Passed method, false on failure
|
||||
*/
|
||||
protected static function _pass($method, $check, $classPrefix) {
|
||||
$className = ucwords($classPrefix) . 'Validation';
|
||||
if (!class_exists($className)) {
|
||||
trigger_error(sprintf(__('Could not find %s class, unable to complete validation.', true), $className), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
if (!method_exists($className, $method)) {
|
||||
trigger_error(sprintf(__('Method %s does not exist on %s unable to complete validation.', true), $method, $className), E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$check = (array)$check;
|
||||
return call_user_func_array(array($className, $method), $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a regular expression match.
|
||||
*
|
||||
* @param mixed $check Value to check against the $regex expression
|
||||
* @param string $regex Regular expression
|
||||
* @return boolean Success of match
|
||||
*/
|
||||
protected static function _check($check, $regex) {
|
||||
if (preg_match($regex, $check)) {
|
||||
self::$errors[] = false;
|
||||
return true;
|
||||
} else {
|
||||
self::$errors[] = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the values to use when value sent to validation method is
|
||||
* an array.
|
||||
*
|
||||
* @param array $params Parameters sent to validation method
|
||||
* @return void
|
||||
*/
|
||||
protected static function _defaults($params) {
|
||||
self::__reset();
|
||||
$defaults = array(
|
||||
'check' => null,
|
||||
'regex' => null,
|
||||
'country' => null,
|
||||
'deep' => false,
|
||||
'type' => null
|
||||
);
|
||||
$params = array_merge($defaults, $params);
|
||||
if ($params['country'] !== null) {
|
||||
$params['country'] = mb_strtolower($params['country']);
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Luhn algorithm
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Luhn_algorithm
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function luhn($check, $deep = false) {
|
||||
if (is_array($check)) {
|
||||
extract(self::_defaults($check));
|
||||
}
|
||||
if ($deep !== true) {
|
||||
return true;
|
||||
}
|
||||
if ($check == 0) {
|
||||
return false;
|
||||
}
|
||||
$sum = 0;
|
||||
$length = strlen($check);
|
||||
|
||||
for ($position = 1 - ($length % 2); $position < $length; $position += 2) {
|
||||
$sum += $check[$position];
|
||||
}
|
||||
|
||||
for ($position = ($length % 2); $position < $length; $position += 2) {
|
||||
$number = $check[$position] * 2;
|
||||
$sum += ($number < 10) ? $number : $number - 9;
|
||||
}
|
||||
|
||||
return ($sum % 10 == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily populate the IP address patterns used for validations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function __populateIp() {
|
||||
if (!isset(self::$__pattern['IPv6'])) {
|
||||
$pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
|
||||
$pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
|
||||
$pattern .= '|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})';
|
||||
$pattern .= '(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)';
|
||||
$pattern .= '{4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
|
||||
$pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}';
|
||||
$pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
|
||||
$pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
|
||||
$pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
|
||||
$pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
|
||||
$pattern .= '{0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)';
|
||||
$pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
|
||||
$pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
|
||||
$pattern .= '{1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?';
|
||||
|
||||
self::$__pattern['IPv6'] = $pattern;
|
||||
}
|
||||
if (!isset(self::$__pattern['IPv4'])) {
|
||||
$pattern = '(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])';
|
||||
self::$__pattern['IPv4'] = $pattern;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset internal variables for another validation run.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function __reset() {
|
||||
self::$errors = array();
|
||||
}
|
||||
}
|
333
lib/Cake/Utility/Xml.php
Normal file
333
lib/Cake/Utility/Xml.php
Normal file
|
@ -0,0 +1,333 @@
|
|||
<?php
|
||||
/**
|
||||
* XML handling for Cake.
|
||||
*
|
||||
* The methods in these classes enable the datasources that use XML to work.
|
||||
*
|
||||
* PHP 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 v .0.10.3.1400
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
class Xml {
|
||||
|
||||
/**
|
||||
* Initialize SimpleXMLElement or DOMDocument from a given XML string, file path, URL or array.
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Building XML from a string:
|
||||
*
|
||||
* `$xml = Xml::build('<example>text</example>');`
|
||||
*
|
||||
* Building XML from string (output DOMDocument):
|
||||
*
|
||||
* `$xml = Xml::build('<example>text</example>', array('return' => 'domdocument'));`
|
||||
*
|
||||
* Building XML from a file path:
|
||||
*
|
||||
* `$xml = Xml::build('/path/to/an/xml/file.xml');`
|
||||
*
|
||||
* Building from a remote URL:
|
||||
*
|
||||
* `$xml = Xml::build('http://example.com/example.xml');`
|
||||
*
|
||||
* Building from an array:
|
||||
*
|
||||
* {{{
|
||||
* $value = array(
|
||||
* 'tags' => array(
|
||||
* 'tag' => array(
|
||||
* array(
|
||||
* 'id' => '1',
|
||||
* 'name' => 'defect'
|
||||
* ),
|
||||
* array(
|
||||
* 'id' => '2',
|
||||
* 'name' => 'enhancement'
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
* $xml = Xml::build($value);
|
||||
* }}}
|
||||
*
|
||||
* When building XML from an array ensure that there is only one top level element.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument.
|
||||
* - If using array as input, you can pass `options` from Xml::fromArray.
|
||||
*
|
||||
* @param mixed $input XML string, a path to a file, an URL or an array
|
||||
* @param array $options The options to use
|
||||
* @return object SimpleXMLElement or DOMDocument
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function build($input, $options = array()) {
|
||||
if (!is_array($options)) {
|
||||
$options = array('return' => (string)$options);
|
||||
}
|
||||
$defaults = array(
|
||||
'return' => 'simplexml'
|
||||
);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if (is_array($input) || is_object($input)) {
|
||||
return self::fromArray((array)$input, $options);
|
||||
} elseif (strpos($input, '<') !== false) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML($input);
|
||||
return $dom;
|
||||
} elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA, true);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($input);
|
||||
return $dom;
|
||||
} elseif (!is_string($input)) {
|
||||
throw new Exception(__('Invalid input.'));
|
||||
}
|
||||
throw new Exception(__('XML cannot be read.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an array into a SimpleXMLElement
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `format` If create childs ('tags') or attributes ('attribute').
|
||||
* - `version` Version of XML document. Default is 1.0.
|
||||
* - `encoding` Encoding of XML document. If null remove from XML header. Default is the some of application.
|
||||
* - `return` If return object of SimpleXMLElement ('simplexml') or DOMDocument ('domdocument'). Default is SimpleXMLElement.
|
||||
*
|
||||
* Using the following data:
|
||||
*
|
||||
* {{{
|
||||
* $value = array(
|
||||
* 'root' => array(
|
||||
* 'tag' => array(
|
||||
* 'id' => 1,
|
||||
* 'value' => 'defect',
|
||||
* '@' => 'description'
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* Calling `Xml::fromArray($value, 'tags');` Will generate:
|
||||
*
|
||||
* `<root><tag><id>1</id><value>defect</value>description</tag></root>`
|
||||
*
|
||||
* And calling `Xml::fromArray($value, 'attribute');` Will generate:
|
||||
*
|
||||
* `<root><tag id="1" value="defect">description</tag></root>`
|
||||
*
|
||||
* @param array $input Array with data
|
||||
* @param array $options The options to use
|
||||
* @return object SimpleXMLElement or DOMDocument
|
||||
*/
|
||||
public static function fromArray($input, $options = array()) {
|
||||
if (!is_array($input) || count($input) !== 1) {
|
||||
throw new Exception(__('Invalid input.'));
|
||||
}
|
||||
$key = key($input);
|
||||
if (is_integer($key)) {
|
||||
throw new Exception(__('The key of input must be alphanumeric'));
|
||||
}
|
||||
|
||||
if (!is_array($options)) {
|
||||
$options = array('format' => (string)$options);
|
||||
}
|
||||
$defaults = array(
|
||||
'format' => 'tags',
|
||||
'version' => '1.0',
|
||||
'encoding' => Configure::read('App.encoding'),
|
||||
'return' => 'simplexml'
|
||||
);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$dom = new DOMDocument($options['version'], $options['encoding']);
|
||||
self::_fromArray($dom, $dom, $input, $options['format']);
|
||||
|
||||
$options['return'] = strtolower($options['return']);
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($dom->saveXML());
|
||||
}
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive method to create childs from array
|
||||
*
|
||||
* @param object $dom Handler to DOMDocument
|
||||
* @param object $node Handler to DOMElement (child)
|
||||
* @param array $data Array of data to append to the $node.
|
||||
* @param string $format Either 'attribute' or 'tags'. This determines where nested keys go.
|
||||
* @return void
|
||||
*/
|
||||
protected function _fromArray(&$dom, &$node, &$data, $format) {
|
||||
if (empty($data) || !is_array($data)) {
|
||||
return;
|
||||
}
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_string($key)) {
|
||||
if (!is_array($value)) {
|
||||
if (is_bool($value)) {
|
||||
$value = (int)$value;
|
||||
} elseif ($value === null) {
|
||||
$value = '';
|
||||
}
|
||||
$isNamespace = strpos($key, 'xmlns:');
|
||||
$nsUri = null;
|
||||
if ($isNamespace !== false) {
|
||||
$node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value);
|
||||
continue;
|
||||
}
|
||||
if ($key[0] !== '@' && $format === 'tags') {
|
||||
$child = $dom->createElement($key, $value);
|
||||
$node->appendChild($child);
|
||||
} else {
|
||||
if ($key[0] === '@') {
|
||||
$key = substr($key, 1);
|
||||
}
|
||||
$attribute = $dom->createAttribute($key);
|
||||
$attribute->appendChild($dom->createTextNode($value));
|
||||
$node->appendChild($attribute);
|
||||
}
|
||||
} else {
|
||||
if ($key[0] === '@') {
|
||||
throw new Exception(__('Invalid array'));
|
||||
}
|
||||
if (array_keys($value) === range(0, count($value) - 1)) { // List
|
||||
foreach ($value as $item) {
|
||||
$data = compact('dom', 'node', 'key', 'format');
|
||||
$data['value'] = $item;
|
||||
self::__createChild($data);
|
||||
}
|
||||
} else { // Struct
|
||||
self::__createChild(compact('dom', 'node', 'key', 'value', 'format'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Exception(__('Invalid array'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to _fromArray(). It will create childs of arrays
|
||||
*
|
||||
* @param array $data Array with informations to create childs
|
||||
* @return void
|
||||
*/
|
||||
private function __createChild($data) {
|
||||
extract($data);
|
||||
$childNS = $childValue = null;
|
||||
if (is_array($value)) {
|
||||
if (isset($value['@'])) {
|
||||
$childValue = (string)$value['@'];
|
||||
unset($value['@']);
|
||||
}
|
||||
if (isset($value['xmlns:'])) {
|
||||
$childNS = $value['xmlns:'];
|
||||
unset($value['xmlns:']);
|
||||
}
|
||||
} elseif (!empty($value) || $value === 0) {
|
||||
$childValue = (string)$value;
|
||||
}
|
||||
|
||||
if ($childValue) {
|
||||
$child = $dom->createElement($key, $childValue);
|
||||
} else {
|
||||
$child = $dom->createElement($key);
|
||||
}
|
||||
if ($childNS) {
|
||||
$child->setAttribute('xmlns', $childNS);
|
||||
}
|
||||
|
||||
self::_fromArray($dom, $child, $value, $format);
|
||||
$node->appendChild($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this XML structure as a array.
|
||||
*
|
||||
* @param object $obj SimpleXMLElement, DOMDocument or DOMNode instance
|
||||
* @return array Array representation of the XML structure.
|
||||
*/
|
||||
public static function toArray($obj) {
|
||||
if ($obj instanceof DOMNode) {
|
||||
$obj = simplexml_import_dom($obj);
|
||||
}
|
||||
if (!($obj instanceof SimpleXMLElement)) {
|
||||
throw new Exception(__('The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.'));
|
||||
}
|
||||
$result = array();
|
||||
$namespaces = array_merge(array('' => ''), $obj->getNamespaces(true));
|
||||
self::_toArray($obj, $result, '', array_keys($namespaces));
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive method to toArray
|
||||
*
|
||||
* @param object $xml SimpleXMLElement object
|
||||
* @param array $parentData Parent array with data
|
||||
* @param string $ns Namespace of current child
|
||||
* @param array $namespaces List of namespaces in XML
|
||||
* @return void
|
||||
*/
|
||||
protected static function _toArray($xml, &$parentData, $ns, $namespaces) {
|
||||
$data = array();
|
||||
|
||||
foreach ($namespaces as $namespace) {
|
||||
foreach ($xml->attributes($namespace, true) as $key => $value) {
|
||||
if (!empty($namespace)) {
|
||||
$key = $namespace . ':' . $key;
|
||||
}
|
||||
$data['@' . $key] = (string)$value;
|
||||
}
|
||||
|
||||
foreach ($xml->children($namespace, true) as $child) {
|
||||
self::_toArray($child, $data, $namespace, $namespaces);
|
||||
}
|
||||
}
|
||||
|
||||
$asString = trim((string)$xml);
|
||||
if (empty($data)) {
|
||||
$data = $asString;
|
||||
} elseif (!empty($asString)) {
|
||||
$data['@'] = $asString;
|
||||
}
|
||||
|
||||
if (!empty($ns)) {
|
||||
$ns .= ':';
|
||||
}
|
||||
$name = $ns . $xml->getName();
|
||||
if (isset($parentData[$name])) {
|
||||
if (!is_array($parentData[$name]) || !isset($parentData[$name][0])) {
|
||||
$parentData[$name] = array($parentData[$name]);
|
||||
}
|
||||
$parentData[$name][] = $data;
|
||||
} else {
|
||||
$parentData[$name] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue