You've already forked joomla_test
first commit
This commit is contained in:
570
libraries/joomla/access/access.php
Normal file
570
libraries/joomla/access/access.php
Normal file
@ -0,0 +1,570 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.utilities.arrayhelper');
|
||||
|
||||
/**
|
||||
* Class that handles all access authorisation routines.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
* @since 11.1
|
||||
*/
|
||||
class JAccess
|
||||
{
|
||||
/**
|
||||
* Array of view levels
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $viewLevels = array();
|
||||
|
||||
/**
|
||||
* Array of rules for the asset
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $assetRules = array();
|
||||
|
||||
/**
|
||||
* Array of user groups.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $userGroups = array();
|
||||
|
||||
/**
|
||||
* Array of user group paths.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $userGroupPaths = array();
|
||||
|
||||
/**
|
||||
* Array of cached groups by user.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $groupsByUser = array();
|
||||
|
||||
/**
|
||||
* Method for clearing static caches.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public static function clearStatics()
|
||||
{
|
||||
self::$viewLevels = array();
|
||||
self::$assetRules = array();
|
||||
self::$userGroups = array();
|
||||
self::$userGroupPaths = array();
|
||||
self::$groupsByUser = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if a user is authorised to perform an action, optionally on an asset.
|
||||
*
|
||||
* @param integer $userId Id of the user for which to check authorisation.
|
||||
* @param string $action The name of the action to authorise.
|
||||
* @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
|
||||
*
|
||||
* @return boolean True if authorised.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function check($userId, $action, $asset = null)
|
||||
{
|
||||
// Sanitise inputs.
|
||||
$userId = (int) $userId;
|
||||
|
||||
$action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
|
||||
$asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
|
||||
|
||||
// Default to the root asset node.
|
||||
if (empty($asset))
|
||||
{
|
||||
$db = JFactory::getDbo();
|
||||
$assets = JTable::getInstance('Asset', 'JTable', array('dbo' => $db));
|
||||
$rootId = $assets->getRootId();
|
||||
$asset = $rootId;
|
||||
}
|
||||
|
||||
// Get the rules for the asset recursively to root if not already retrieved.
|
||||
if (empty(self::$assetRules[$asset]))
|
||||
{
|
||||
self::$assetRules[$asset] = self::getAssetRules($asset, true);
|
||||
}
|
||||
|
||||
// Get all groups against which the user is mapped.
|
||||
$identities = self::getGroupsByUser($userId);
|
||||
array_unshift($identities, $userId * -1);
|
||||
|
||||
return self::$assetRules[$asset]->allow($action, $identities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if a group is authorised to perform an action, optionally on an asset.
|
||||
*
|
||||
* @param integer $groupId The path to the group for which to check authorisation.
|
||||
* @param string $action The name of the action to authorise.
|
||||
* @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
|
||||
*
|
||||
* @return boolean True if authorised.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function checkGroup($groupId, $action, $asset = null)
|
||||
{
|
||||
// Sanitize inputs.
|
||||
$groupId = (int) $groupId;
|
||||
$action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
|
||||
$asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
|
||||
|
||||
// Get group path for group
|
||||
$groupPath = self::getGroupPath($groupId);
|
||||
|
||||
// Default to the root asset node.
|
||||
if (empty($asset))
|
||||
{
|
||||
// TODO: $rootId doesn't seem to be used!
|
||||
$db = JFactory::getDbo();
|
||||
$assets = JTable::getInstance('Asset', 'JTable', array('dbo' => $db));
|
||||
$rootId = $assets->getRootId();
|
||||
}
|
||||
|
||||
// Get the rules for the asset recursively to root if not already retrieved.
|
||||
if (empty(self::$assetRules[$asset]))
|
||||
{
|
||||
self::$assetRules[$asset] = self::getAssetRules($asset, true);
|
||||
}
|
||||
|
||||
return self::$assetRules[$asset]->allow($action, $groupPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent groups that a leaf group belongs to in its branch back to the root of the tree
|
||||
* (including the leaf group id).
|
||||
*
|
||||
* @param mixed $groupId An integer or array of integers representing the identities to check.
|
||||
*
|
||||
* @return mixed True if allowed, false for an explicit deny, null for an implicit deny.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static function getGroupPath($groupId)
|
||||
{
|
||||
// Preload all groups
|
||||
if (empty(self::$userGroups))
|
||||
{
|
||||
$db = JFactory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select('parent.id, parent.lft, parent.rgt')
|
||||
->from('#__usergroups AS parent')
|
||||
->order('parent.lft');
|
||||
$db->setQuery($query);
|
||||
self::$userGroups = $db->loadObjectList('id');
|
||||
}
|
||||
|
||||
// Make sure groupId is valid
|
||||
if (!array_key_exists($groupId, self::$userGroups))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
// Get parent groups and leaf group
|
||||
if (!isset(self::$userGroupPaths[$groupId]))
|
||||
{
|
||||
self::$userGroupPaths[$groupId] = array();
|
||||
|
||||
foreach (self::$userGroups as $group)
|
||||
{
|
||||
if ($group->lft <= self::$userGroups[$groupId]->lft && $group->rgt >= self::$userGroups[$groupId]->rgt)
|
||||
{
|
||||
self::$userGroupPaths[$groupId][] = $group->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$userGroupPaths[$groupId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the JAccessRules object for an asset. The returned object can optionally hold
|
||||
* only the rules explicitly set for the asset or the summation of all inherited rules from
|
||||
* parent assets and explicit rules.
|
||||
*
|
||||
* @param mixed $asset Integer asset id or the name of the asset as a string.
|
||||
* @param boolean $recursive True to return the rules object with inherited rules.
|
||||
*
|
||||
* @return JAccessRules JAccessRules object for the asset.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getAssetRules($asset, $recursive = false)
|
||||
{
|
||||
// Get the database connection object.
|
||||
$db = JFactory::getDbo();
|
||||
|
||||
// Build the database query to get the rules for the asset.
|
||||
$query = $db->getQuery(true)
|
||||
->select($recursive ? 'b.rules' : 'a.rules')
|
||||
->from('#__assets AS a');
|
||||
|
||||
// SQLsrv change
|
||||
$query->group($recursive ? 'b.id, b.rules, b.lft' : 'a.id, a.rules, a.lft');
|
||||
|
||||
// If the asset identifier is numeric assume it is a primary key, else lookup by name.
|
||||
if (is_numeric($asset))
|
||||
{
|
||||
$query->where('(a.id = ' . (int) $asset . ')');
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->where('(a.name = ' . $db->quote($asset) . ')');
|
||||
}
|
||||
|
||||
// If we want the rules cascading up to the global asset node we need a self-join.
|
||||
if ($recursive)
|
||||
{
|
||||
$query->join('LEFT', '#__assets AS b ON b.lft <= a.lft AND b.rgt >= a.rgt')
|
||||
->order('b.lft');
|
||||
}
|
||||
|
||||
// Execute the query and load the rules from the result.
|
||||
$db->setQuery($query);
|
||||
$result = $db->loadColumn();
|
||||
|
||||
// Get the root even if the asset is not found and in recursive mode
|
||||
if (empty($result))
|
||||
{
|
||||
$db = JFactory::getDbo();
|
||||
$assets = JTable::getInstance('Asset', 'JTable', array('dbo' => $db));
|
||||
$rootId = $assets->getRootId();
|
||||
$query->clear()
|
||||
->select('rules')
|
||||
->from('#__assets')
|
||||
->where('id = ' . $db->quote($rootId));
|
||||
$db->setQuery($query);
|
||||
$result = $db->loadResult();
|
||||
$result = array($result);
|
||||
}
|
||||
// Instantiate and return the JAccessRules object for the asset rules.
|
||||
$rules = new JAccessRules;
|
||||
$rules->mergeCollection($result);
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of user groups mapped to a user. The returned list can optionally hold
|
||||
* only the groups explicitly mapped to the user or all groups both explicitly mapped and inherited
|
||||
* by the user.
|
||||
*
|
||||
* @param integer $userId Id of the user for which to get the list of groups.
|
||||
* @param boolean $recursive True to include inherited user groups.
|
||||
*
|
||||
* @return array List of user group ids to which the user is mapped.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getGroupsByUser($userId, $recursive = true)
|
||||
{
|
||||
// Creates a simple unique string for each parameter combination:
|
||||
$storeId = $userId . ':' . (int) $recursive;
|
||||
|
||||
if (!isset(self::$groupsByUser[$storeId]))
|
||||
{
|
||||
// TODO: Uncouple this from JComponentHelper and allow for a configuration setting or value injection.
|
||||
if (class_exists('JComponentHelper'))
|
||||
{
|
||||
$guestUsergroup = JComponentHelper::getParams('com_users')->get('guest_usergroup', 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$guestUsergroup = 1;
|
||||
}
|
||||
|
||||
// Guest user (if only the actually assigned group is requested)
|
||||
if (empty($userId) && !$recursive)
|
||||
{
|
||||
$result = array($guestUsergroup);
|
||||
}
|
||||
// Registered user and guest if all groups are requested
|
||||
else
|
||||
{
|
||||
$db = JFactory::getDbo();
|
||||
|
||||
// Build the database query to get the rules for the asset.
|
||||
$query = $db->getQuery(true)
|
||||
->select($recursive ? 'b.id' : 'a.id');
|
||||
|
||||
if (empty($userId))
|
||||
{
|
||||
$query->from('#__usergroups AS a')
|
||||
->where('a.id = ' . (int) $guestUsergroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->from('#__user_usergroup_map AS map')
|
||||
->where('map.user_id = ' . (int) $userId)
|
||||
->join('LEFT', '#__usergroups AS a ON a.id = map.group_id');
|
||||
}
|
||||
|
||||
// If we want the rules cascading up to the global asset node we need a self-join.
|
||||
if ($recursive)
|
||||
{
|
||||
$query->join('LEFT', '#__usergroups AS b ON b.lft <= a.lft AND b.rgt >= a.rgt');
|
||||
}
|
||||
|
||||
// Execute the query and load the rules from the result.
|
||||
$db->setQuery($query);
|
||||
$result = $db->loadColumn();
|
||||
|
||||
// Clean up any NULL or duplicate values, just in case
|
||||
JArrayHelper::toInteger($result);
|
||||
|
||||
if (empty($result))
|
||||
{
|
||||
$result = array('1');
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = array_unique($result);
|
||||
}
|
||||
}
|
||||
|
||||
self::$groupsByUser[$storeId] = $result;
|
||||
}
|
||||
|
||||
return self::$groupsByUser[$storeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of user Ids contained in a Group
|
||||
*
|
||||
* @param integer $groupId The group Id
|
||||
* @param boolean $recursive Recursively include all child groups (optional)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 11.1
|
||||
* @todo This method should move somewhere else
|
||||
*/
|
||||
public static function getUsersByGroup($groupId, $recursive = false)
|
||||
{
|
||||
// Get a database object.
|
||||
$db = JFactory::getDbo();
|
||||
|
||||
$test = $recursive ? '>=' : '=';
|
||||
|
||||
// First find the users contained in the group
|
||||
$query = $db->getQuery(true)
|
||||
->select('DISTINCT(user_id)')
|
||||
->from('#__usergroups as ug1')
|
||||
->join('INNER', '#__usergroups AS ug2 ON ug2.lft' . $test . 'ug1.lft AND ug1.rgt' . $test . 'ug2.rgt')
|
||||
->join('INNER', '#__user_usergroup_map AS m ON ug2.id=m.group_id')
|
||||
->where('ug1.id=' . $db->quote($groupId));
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
$result = $db->loadColumn();
|
||||
|
||||
// Clean up any NULL values, just in case
|
||||
JArrayHelper::toInteger($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of view levels for which the user is authorised.
|
||||
*
|
||||
* @param integer $userId Id of the user for which to get the list of authorised view levels.
|
||||
*
|
||||
* @return array List of view levels for which the user is authorised.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getAuthorisedViewLevels($userId)
|
||||
{
|
||||
// Get all groups that the user is mapped to recursively.
|
||||
$groups = self::getGroupsByUser($userId);
|
||||
|
||||
// Only load the view levels once.
|
||||
if (empty(self::$viewLevels))
|
||||
{
|
||||
// Get a database object.
|
||||
$db = JFactory::getDbo();
|
||||
|
||||
// Build the base query.
|
||||
$query = $db->getQuery(true)
|
||||
->select('id, rules')
|
||||
->from($db->quoteName('#__viewlevels'));
|
||||
|
||||
// Set the query for execution.
|
||||
$db->setQuery($query);
|
||||
|
||||
// Build the view levels array.
|
||||
foreach ($db->loadAssocList() as $level)
|
||||
{
|
||||
self::$viewLevels[$level['id']] = (array) json_decode($level['rules']);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the authorised array.
|
||||
$authorised = array(1);
|
||||
|
||||
// Find the authorised levels.
|
||||
foreach (self::$viewLevels as $level => $rule)
|
||||
{
|
||||
foreach ($rule as $id)
|
||||
{
|
||||
if (($id < 0) && (($id * -1) == $userId))
|
||||
{
|
||||
$authorised[] = $level;
|
||||
break;
|
||||
}
|
||||
// Check to see if the group is mapped to the level.
|
||||
elseif (($id >= 0) && in_array($id, $groups))
|
||||
{
|
||||
$authorised[] = $level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $authorised;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of actions for which permissions can be set given a component and section.
|
||||
*
|
||||
* @param string $component The component from which to retrieve the actions.
|
||||
* @param string $section The name of the section within the component from which to retrieve the actions.
|
||||
*
|
||||
* @return array List of actions available for the given component and section.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 12.3 (Platform) & 4.0 (CMS) Use JAccess::getActionsFromFile or JAccess::getActionsFromData instead.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function getActions($component, $section = 'component')
|
||||
{
|
||||
JLog::add(__METHOD__ . ' is deprecated. Use JAccess::getActionsFromFile or JAccess::getActionsFromData instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
$actions = self::getActionsFromFile(
|
||||
JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml',
|
||||
"/access/section[@name='" . $section . "']/"
|
||||
);
|
||||
|
||||
if (empty($actions))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of actions from a file for which permissions can be set.
|
||||
*
|
||||
* @param string $file The path to the XML file.
|
||||
* @param string $xpath An optional xpath to search for the fields.
|
||||
*
|
||||
* @return boolean|array False if case of error or the list of actions available.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function getActionsFromFile($file, $xpath = "/access/section[@name='component']/")
|
||||
{
|
||||
if (!is_file($file) || !is_readable($file))
|
||||
{
|
||||
// If unable to find the file return false.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else return the actions from the xml.
|
||||
$xml = simplexml_load_file($file);
|
||||
|
||||
return self::getActionsFromData($xml, $xpath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a list of actions from a string or from an xml for which permissions can be set.
|
||||
*
|
||||
* @param string|SimpleXMLElement $data The XML string or an XML element.
|
||||
* @param string $xpath An optional xpath to search for the fields.
|
||||
*
|
||||
* @return boolean|array False if case of error or the list of actions available.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function getActionsFromData($data, $xpath = "/access/section[@name='component']/")
|
||||
{
|
||||
// If the data to load isn't already an XML element or string return false.
|
||||
if ((!($data instanceof SimpleXMLElement)) && (!is_string($data)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to load the XML if a string.
|
||||
if (is_string($data))
|
||||
{
|
||||
try
|
||||
{
|
||||
$data = new SimpleXMLElement($data);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the XML loaded correctly.
|
||||
if (!$data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the actions array
|
||||
$actions = array();
|
||||
|
||||
// Get the elements from the xpath
|
||||
$elements = $data->xpath($xpath . 'action[@name][@title][@description]');
|
||||
|
||||
// If there some elements, analyse them
|
||||
if (!empty($elements))
|
||||
{
|
||||
foreach ($elements as $action)
|
||||
{
|
||||
// Add the action to the actions array
|
||||
$actions[] = (object) array(
|
||||
'name' => (string) $action['name'],
|
||||
'title' => (string) $action['title'],
|
||||
'description' => (string) $action['description']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally return the actions array
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/access/index.html
Normal file
1
libraries/joomla/access/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
176
libraries/joomla/access/rule.php
Normal file
176
libraries/joomla/access/rule.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JAccessRule class.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
* @since 11.4
|
||||
*/
|
||||
class JAccessRule
|
||||
{
|
||||
/**
|
||||
* A named array
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The input array must be in the form: array(-42 => true, 3 => true, 4 => false)
|
||||
* or an equivalent JSON encoded string.
|
||||
*
|
||||
* @param mixed $identities A JSON format string (probably from the database) or a named array.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($identities)
|
||||
{
|
||||
// Convert string input to an array.
|
||||
if (is_string($identities))
|
||||
{
|
||||
$identities = json_decode($identities, true);
|
||||
}
|
||||
|
||||
$this->mergeIdentities($identities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for the action.
|
||||
*
|
||||
* @return array A named array
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the identities
|
||||
*
|
||||
* @param mixed $identities An integer or array of integers representing the identities to check.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function mergeIdentities($identities)
|
||||
{
|
||||
if ($identities instanceof JAccessRule)
|
||||
{
|
||||
$identities = $identities->getData();
|
||||
}
|
||||
|
||||
if (is_array($identities))
|
||||
{
|
||||
foreach ($identities as $identity => $allow)
|
||||
{
|
||||
$this->mergeIdentity($identity, $allow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the values for an identity.
|
||||
*
|
||||
* @param integer $identity The identity.
|
||||
* @param boolean $allow The value for the identity (true == allow, false == deny).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function mergeIdentity($identity, $allow)
|
||||
{
|
||||
$identity = (int) $identity;
|
||||
$allow = (int) ((boolean) $allow);
|
||||
|
||||
// Check that the identity exists.
|
||||
if (isset($this->data[$identity]))
|
||||
{
|
||||
// Explicit deny always wins a merge.
|
||||
if ($this->data[$identity] !== 0)
|
||||
{
|
||||
$this->data[$identity] = $allow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->data[$identity] = $allow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that this action can be performed by an identity.
|
||||
*
|
||||
* The identity is an integer where +ve represents a user group,
|
||||
* and -ve represents a user.
|
||||
*
|
||||
* @param mixed $identities An integer or array of integers representing the identities to check.
|
||||
*
|
||||
* @return mixed True if allowed, false for an explicit deny, null for an implicit deny.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function allow($identities)
|
||||
{
|
||||
// Implicit deny by default.
|
||||
$result = null;
|
||||
|
||||
// Check that the inputs are valid.
|
||||
if (!empty($identities))
|
||||
{
|
||||
if (!is_array($identities))
|
||||
{
|
||||
$identities = array($identities);
|
||||
}
|
||||
|
||||
foreach ($identities as $identity)
|
||||
{
|
||||
// Technically the identity just needs to be unique.
|
||||
$identity = (int) $identity;
|
||||
|
||||
// Check if the identity is known.
|
||||
if (isset($this->data[$identity]))
|
||||
{
|
||||
$result = (boolean) $this->data[$identity];
|
||||
|
||||
// An explicit deny wins.
|
||||
if ($result === false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this object into a JSON encoded string.
|
||||
*
|
||||
* @return string JSON encoded string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return json_encode($this->data);
|
||||
}
|
||||
}
|
||||
220
libraries/joomla/access/rules.php
Normal file
220
libraries/joomla/access/rules.php
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JAccessRules class.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Access
|
||||
* @since 11.4
|
||||
*/
|
||||
class JAccessRules
|
||||
{
|
||||
/**
|
||||
* A named array.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The input array must be in the form: array('action' => array(-42 => true, 3 => true, 4 => false))
|
||||
* or an equivalent JSON encoded string, or an object where properties are arrays.
|
||||
*
|
||||
* @param mixed $input A JSON format string (probably from the database) or a nested array.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($input = '')
|
||||
{
|
||||
// Convert in input to an array.
|
||||
if (is_string($input))
|
||||
{
|
||||
$input = json_decode($input, true);
|
||||
}
|
||||
elseif (is_object($input))
|
||||
{
|
||||
$input = (array) $input;
|
||||
}
|
||||
|
||||
if (is_array($input))
|
||||
{
|
||||
// Top level keys represent the actions.
|
||||
foreach ($input as $action => $identities)
|
||||
{
|
||||
$this->mergeAction($action, $identities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for the action.
|
||||
*
|
||||
* @return array A named array of JAccessRule objects.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to merge a collection of JAccessRules.
|
||||
*
|
||||
* @param mixed $input JAccessRule or array of JAccessRules
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function mergeCollection($input)
|
||||
{
|
||||
// Check if the input is an array.
|
||||
if (is_array($input))
|
||||
{
|
||||
foreach ($input as $actions)
|
||||
{
|
||||
$this->merge($actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to merge actions with this object.
|
||||
*
|
||||
* @param mixed $actions JAccessRule object, an array of actions or a JSON string array of actions.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function merge($actions)
|
||||
{
|
||||
if (is_string($actions))
|
||||
{
|
||||
$actions = json_decode($actions, true);
|
||||
}
|
||||
|
||||
if (is_array($actions))
|
||||
{
|
||||
foreach ($actions as $action => $identities)
|
||||
{
|
||||
$this->mergeAction($action, $identities);
|
||||
}
|
||||
}
|
||||
elseif ($actions instanceof JAccessRules)
|
||||
{
|
||||
$data = $actions->getData();
|
||||
|
||||
foreach ($data as $name => $identities)
|
||||
{
|
||||
$this->mergeAction($name, $identities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges an array of identities for an action.
|
||||
*
|
||||
* @param string $action The name of the action.
|
||||
* @param array $identities An array of identities
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function mergeAction($action, $identities)
|
||||
{
|
||||
if (isset($this->data[$action]))
|
||||
{
|
||||
// If exists, merge the action.
|
||||
$this->data[$action]->mergeIdentities($identities);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If new, add the action.
|
||||
$this->data[$action] = new JAccessRule($identities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that an action can be performed by an identity.
|
||||
*
|
||||
* The identity is an integer where +ve represents a user group,
|
||||
* and -ve represents a user.
|
||||
*
|
||||
* @param string $action The name of the action.
|
||||
* @param mixed $identity An integer representing the identity, or an array of identities
|
||||
*
|
||||
* @return mixed Object or null if there is no information about the action.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function allow($action, $identity)
|
||||
{
|
||||
// Check we have information about this action.
|
||||
if (isset($this->data[$action]))
|
||||
{
|
||||
return $this->data[$action]->allow($identity);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the allowed actions for an identity.
|
||||
*
|
||||
* @param mixed $identity An integer representing the identity or an array of identities
|
||||
*
|
||||
* @return JObject Allowed actions for the identity or identities
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAllowed($identity)
|
||||
{
|
||||
// Sweep for the allowed actions.
|
||||
$allowed = new JObject;
|
||||
|
||||
foreach ($this->data as $name => &$action)
|
||||
{
|
||||
if ($action->allow($identity))
|
||||
{
|
||||
$allowed->set($name, true);
|
||||
}
|
||||
}
|
||||
return $allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to convert the object to JSON string representation.
|
||||
*
|
||||
* @return string JSON representation of the actions array
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$temp = array();
|
||||
|
||||
foreach ($this->data as $name => $rule)
|
||||
{
|
||||
// Convert the action to JSON, then back into an array otherwise
|
||||
// re-encoding will quote the JSON for the identities in the action.
|
||||
$temp[$name] = json_decode((string) $rule);
|
||||
}
|
||||
|
||||
return json_encode($temp);
|
||||
}
|
||||
}
|
||||
151
libraries/joomla/application/base.php
Normal file
151
libraries/joomla/application/base.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Base Application Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JApplicationBase
|
||||
{
|
||||
/**
|
||||
* The application dispatcher object.
|
||||
*
|
||||
* @var JEventDispatcher
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* The application identity object.
|
||||
*
|
||||
* @var JUser
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $identity;
|
||||
|
||||
/**
|
||||
* The application input object.
|
||||
*
|
||||
* @var JInput
|
||||
* @since 12.1
|
||||
*/
|
||||
public $input = null;
|
||||
|
||||
/**
|
||||
* Method to close the application.
|
||||
*
|
||||
* @param integer $code The exit code (optional; default is 0).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 12.1
|
||||
*/
|
||||
public function close($code = 0)
|
||||
{
|
||||
exit($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application identity.
|
||||
*
|
||||
* @return mixed A JUser object or null.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
return $this->identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler to a particular event group.
|
||||
*
|
||||
* @param string $event The event name.
|
||||
* @param callable $handler The handler, a function or an instance of a event object.
|
||||
*
|
||||
* @return JApplicationBase The application to allow chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function registerEvent($event, $handler)
|
||||
{
|
||||
if ($this->dispatcher instanceof JEventDispatcher)
|
||||
{
|
||||
$this->dispatcher->register($event, $handler);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls all handlers associated with an event group.
|
||||
*
|
||||
* @param string $event The event name.
|
||||
* @param array $args An array of arguments (optional).
|
||||
*
|
||||
* @return array An array of results from each function call, or null if no dispatcher is defined.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function triggerEvent($event, array $args = null)
|
||||
{
|
||||
if ($this->dispatcher instanceof JEventDispatcher)
|
||||
{
|
||||
return $this->dispatcher->trigger($event, $args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the application to load a custom or default dispatcher.
|
||||
*
|
||||
* The logic and options for creating this object are adequately generic for default cases
|
||||
* but for many applications it will make sense to override this method and create event
|
||||
* dispatchers, if required, based on more specific needs.
|
||||
*
|
||||
* @param JEventDispatcher $dispatcher An optional dispatcher object. If omitted, the factory dispatcher is created.
|
||||
*
|
||||
* @return JApplicationBase This method is chainable.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function loadDispatcher(JEventDispatcher $dispatcher = null)
|
||||
{
|
||||
$this->dispatcher = ($dispatcher === null) ? JEventDispatcher::getInstance() : $dispatcher;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the application to load a custom or default identity.
|
||||
*
|
||||
* The logic and options for creating this object are adequately generic for default cases
|
||||
* but for many applications it will make sense to override this method and create an identity,
|
||||
* if required, based on more specific needs.
|
||||
*
|
||||
* @param JUser $identity An optional identity object. If omitted, the factory user is created.
|
||||
*
|
||||
* @return JApplicationBase This method is chainable.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function loadIdentity(JUser $identity = null)
|
||||
{
|
||||
$this->identity = ($identity === null) ? JFactory::getUser() : $identity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
294
libraries/joomla/application/cli.php
Normal file
294
libraries/joomla/application/cli.php
Normal file
@ -0,0 +1,294 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Base class for a Joomla! command line application.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 11.4
|
||||
*/
|
||||
class JApplicationCli extends JApplicationBase
|
||||
{
|
||||
/**
|
||||
* @var JRegistry The application configuration object.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var JApplicationCli The application instance.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param mixed $input An optional argument to provide dependency injection for the application's
|
||||
* input object. If the argument is a JInputCli object that object will become
|
||||
* the application's input object, otherwise a default input object is created.
|
||||
* @param mixed $config An optional argument to provide dependency injection for the application's
|
||||
* config object. If the argument is a JRegistry object that object will become
|
||||
* the application's config object, otherwise a default config object is created.
|
||||
* @param mixed $dispatcher An optional argument to provide dependency injection for the application's
|
||||
* event dispatcher. If the argument is a JEventDispatcher object that object will become
|
||||
* the application's event dispatcher, if it is null then the default event dispatcher
|
||||
* will be created based on the application's loadDispatcher() method.
|
||||
*
|
||||
* @see loadDispatcher()
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct(JInputCli $input = null, JRegistry $config = null, JEventDispatcher $dispatcher = null)
|
||||
{
|
||||
// Close the application if we are not executed from the command line.
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!defined('STDOUT') || !defined('STDIN') || !isset($_SERVER['argv']))
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// If a input object is given use it.
|
||||
if ($input instanceof JInput)
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
// Create the input based on the application logic.
|
||||
else
|
||||
{
|
||||
if (class_exists('JInput'))
|
||||
{
|
||||
$this->input = new JInputCLI;
|
||||
}
|
||||
}
|
||||
|
||||
// If a config object is given use it.
|
||||
if ($config instanceof JRegistry)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
// Instantiate a new configuration object.
|
||||
else
|
||||
{
|
||||
$this->config = new JRegistry;
|
||||
}
|
||||
|
||||
$this->loadDispatcher($dispatcher);
|
||||
|
||||
// Load the configuration object.
|
||||
$this->loadConfiguration($this->fetchConfigurationData());
|
||||
|
||||
// Set the execution datetime and timestamp;
|
||||
$this->set('execution.datetime', gmdate('Y-m-d H:i:s'));
|
||||
$this->set('execution.timestamp', time());
|
||||
|
||||
// Set the current directory.
|
||||
$this->set('cwd', getcwd());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a property of the object or the default value if the property is not set.
|
||||
*
|
||||
* @param string $key The name of the property.
|
||||
* @param mixed $default The default value (optional) if none is set.
|
||||
*
|
||||
* @return mixed The value of the configuration.
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
return $this->config->get($key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the global JApplicationCli object, only creating it if it doesn't already exist.
|
||||
*
|
||||
* This method must be invoked as: $cli = JApplicationCli::getInstance();
|
||||
*
|
||||
* @param string $name The name (optional) of the JApplicationCli class to instantiate.
|
||||
*
|
||||
* @return JApplicationCli
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getInstance($name = null)
|
||||
{
|
||||
// Only create the object if it doesn't exist.
|
||||
if (empty(self::$instance))
|
||||
{
|
||||
if (class_exists($name) && (is_subclass_of($name, 'JApplicationCli')))
|
||||
{
|
||||
self::$instance = new $name;
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$instance = new JApplicationCli;
|
||||
}
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the application.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
// Trigger the onBeforeExecute event.
|
||||
$this->triggerEvent('onBeforeExecute');
|
||||
|
||||
// Perform application routines.
|
||||
$this->doExecute();
|
||||
|
||||
// Trigger the onAfterExecute event.
|
||||
$this->triggerEvent('onAfterExecute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an object or array into the application configuration object.
|
||||
*
|
||||
* @param mixed $data Either an array or object to be loaded into the configuration object.
|
||||
*
|
||||
* @return JApplicationCli Instance of $this to allow chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function loadConfiguration($data)
|
||||
{
|
||||
// Load the data into the configuration object.
|
||||
if (is_array($data))
|
||||
{
|
||||
$this->config->loadArray($data);
|
||||
}
|
||||
elseif (is_object($data))
|
||||
{
|
||||
$this->config->loadObject($data);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string to standard output.
|
||||
*
|
||||
* @param string $text The text to display.
|
||||
* @param boolean $nl True (default) to append a new line at the end of the output string.
|
||||
*
|
||||
* @return JApplicationCli Instance of $this to allow chaining.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.1
|
||||
*/
|
||||
public function out($text = '', $nl = true)
|
||||
{
|
||||
fwrite(STDOUT, $text . ($nl ? "\n" : null));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from standard input.
|
||||
*
|
||||
* @return string The input string from standard input.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.1
|
||||
*/
|
||||
public function in()
|
||||
{
|
||||
return rtrim(fread(STDIN, 8192), "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a property of the object, creating it if it does not already exist.
|
||||
*
|
||||
* @param string $key The name of the property.
|
||||
* @param mixed $value The value of the property to set (optional).
|
||||
*
|
||||
* @return mixed Previous value of the property
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public function set($key, $value = null)
|
||||
{
|
||||
$previous = $this->config->get($key);
|
||||
$this->config->set($key, $value);
|
||||
|
||||
return $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to load a PHP configuration class file based on convention and return the instantiated data object. You
|
||||
* will extend this method in child classes to provide configuration data from whatever data source is relevant
|
||||
* for your specific application.
|
||||
*
|
||||
* @param string $file The path and filename of the configuration file. If not provided, configuration.php
|
||||
* in JPATH_BASE will be used.
|
||||
* @param string $class The class name to instantiate.
|
||||
*
|
||||
* @return mixed Either an array or object to be loaded into the configuration object.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function fetchConfigurationData($file = '', $class = 'JConfig')
|
||||
{
|
||||
// Instantiate variables.
|
||||
$config = array();
|
||||
|
||||
if (empty($file) && defined('JPATH_BASE'))
|
||||
{
|
||||
$file = JPATH_BASE . '/configuration.php';
|
||||
|
||||
// Applications can choose not to have any configuration data
|
||||
// by not implementing this method and not having a config file.
|
||||
if (!file_exists($file))
|
||||
{
|
||||
$file = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($file))
|
||||
{
|
||||
JLoader::register($class, $file);
|
||||
|
||||
if (class_exists($class))
|
||||
{
|
||||
$config = new $class;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Configuration class does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to run the application routines. Most likely you will want to instantiate a controller
|
||||
* and execute it, or perform some sort of task directly.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.3
|
||||
*/
|
||||
protected function doExecute()
|
||||
{
|
||||
// Your application routines go here.
|
||||
}
|
||||
}
|
||||
915
libraries/joomla/application/daemon.php
Normal file
915
libraries/joomla/application/daemon.php
Normal file
@ -0,0 +1,915 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.filesystem.folder');
|
||||
|
||||
/**
|
||||
* Class to turn JCli applications into daemons. It requires CLI and PCNTL support built into PHP.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @see http://www.php.net/manual/en/book.pcntl.php
|
||||
* @see http://php.net/manual/en/features.commandline.php
|
||||
* @since 11.1
|
||||
*/
|
||||
class JApplicationDaemon extends JApplicationCli
|
||||
{
|
||||
/**
|
||||
* @var array The available POSIX signals to be caught by default.
|
||||
* @see http://php.net/manual/pcntl.constants.php
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $signals = array(
|
||||
'SIGHUP',
|
||||
'SIGINT',
|
||||
'SIGQUIT',
|
||||
'SIGILL',
|
||||
'SIGTRAP',
|
||||
'SIGABRT',
|
||||
'SIGIOT',
|
||||
'SIGBUS',
|
||||
'SIGFPE',
|
||||
'SIGUSR1',
|
||||
'SIGSEGV',
|
||||
'SIGUSR2',
|
||||
'SIGPIPE',
|
||||
'SIGALRM',
|
||||
'SIGTERM',
|
||||
'SIGSTKFLT',
|
||||
'SIGCLD',
|
||||
'SIGCHLD',
|
||||
'SIGCONT',
|
||||
'SIGTSTP',
|
||||
'SIGTTIN',
|
||||
'SIGTTOU',
|
||||
'SIGURG',
|
||||
'SIGXCPU',
|
||||
'SIGXFSZ',
|
||||
'SIGVTALRM',
|
||||
'SIGPROF',
|
||||
'SIGWINCH',
|
||||
'SIGPOLL',
|
||||
'SIGIO',
|
||||
'SIGPWR',
|
||||
'SIGSYS',
|
||||
'SIGBABY',
|
||||
'SIG_BLOCK',
|
||||
'SIG_UNBLOCK',
|
||||
'SIG_SETMASK'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var boolean True if the daemon is in the process of exiting.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $exiting = false;
|
||||
|
||||
/**
|
||||
* @var integer The parent process id.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $parentId = 0;
|
||||
|
||||
/**
|
||||
* @var integer The process id of the daemon.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $processId = 0;
|
||||
|
||||
/**
|
||||
* @var boolean True if the daemon is currently running.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $running = false;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param mixed $input An optional argument to provide dependency injection for the application's
|
||||
* input object. If the argument is a JInputCli object that object will become
|
||||
* the application's input object, otherwise a default input object is created.
|
||||
* @param mixed $config An optional argument to provide dependency injection for the application's
|
||||
* config object. If the argument is a JRegistry object that object will become
|
||||
* the application's config object, otherwise a default config object is created.
|
||||
* @param mixed $dispatcher An optional argument to provide dependency injection for the application's
|
||||
* event dispatcher. If the argument is a JEventDispatcher object that object will become
|
||||
* the application's event dispatcher, if it is null then the default event dispatcher
|
||||
* will be created based on the application's loadDispatcher() method.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct(JInputCli $input = null, JRegistry $config = null, JEventDispatcher $dispatcher = null)
|
||||
{
|
||||
// Verify that the process control extension for PHP is available.
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!defined('SIGHUP'))
|
||||
{
|
||||
JLog::add('The PCNTL extension for PHP is not available.', JLog::ERROR);
|
||||
throw new RuntimeException('The PCNTL extension for PHP is not available.');
|
||||
}
|
||||
|
||||
// Verify that POSIX support for PHP is available.
|
||||
if (!function_exists('posix_getpid'))
|
||||
{
|
||||
JLog::add('The POSIX extension for PHP is not available.', JLog::ERROR);
|
||||
throw new RuntimeException('The POSIX extension for PHP is not available.');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// Call the parent constructor.
|
||||
parent::__construct($input, $config, $dispatcher);
|
||||
|
||||
// Set some system limits.
|
||||
@set_time_limit($this->config->get('max_execution_time', 0));
|
||||
|
||||
if ($this->config->get('max_memory_limit') !== null)
|
||||
{
|
||||
ini_set('memory_limit', $this->config->get('max_memory_limit', '256M'));
|
||||
}
|
||||
|
||||
// Flush content immediately.
|
||||
ob_implicit_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle POSIX signals.
|
||||
*
|
||||
* @param integer $signal The received POSIX signal.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
* @see pcntl_signal()
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function signal($signal)
|
||||
{
|
||||
// Log all signals sent to the daemon.
|
||||
JLog::add('Received signal: ' . $signal, JLog::DEBUG);
|
||||
|
||||
// Let's make sure we have an application instance.
|
||||
if (!is_subclass_of(static::$instance, 'JApplicationDaemon'))
|
||||
{
|
||||
JLog::add('Cannot find the application instance.', JLog::EMERGENCY);
|
||||
throw new RuntimeException('Cannot find the application instance.');
|
||||
}
|
||||
|
||||
// Fire the onReceiveSignal event.
|
||||
static::$instance->triggerEvent('onReceiveSignal', array($signal));
|
||||
|
||||
switch ($signal)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
// Handle shutdown tasks
|
||||
if (static::$instance->running && static::$instance->isActive())
|
||||
{
|
||||
static::$instance->shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$instance->close();
|
||||
}
|
||||
break;
|
||||
case SIGHUP:
|
||||
// Handle restart tasks
|
||||
if (static::$instance->running && static::$instance->isActive())
|
||||
{
|
||||
static::$instance->shutdown(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$instance->close();
|
||||
}
|
||||
break;
|
||||
case SIGCHLD:
|
||||
// A child process has died
|
||||
while (static::$instance->pcntlWait($signal, WNOHANG || WUNTRACED) > 0)
|
||||
{
|
||||
usleep(1000);
|
||||
}
|
||||
break;
|
||||
case SIGCLD:
|
||||
while (static::$instance->pcntlWait($signal, WNOHANG) > 0)
|
||||
{
|
||||
$signal = static::$instance->pcntlChildExitStatus($signal);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the daemon is active. This does not assume that $this daemon is active, but
|
||||
* only if an instance of the application is active as a daemon.
|
||||
*
|
||||
* @return boolean True if daemon is active.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function isActive()
|
||||
{
|
||||
// Get the process id file location for the application.
|
||||
$pidFile = $this->config->get('application_pid_file');
|
||||
|
||||
// If the process id file doesn't exist then the daemon is obviously not running.
|
||||
if (!is_file($pidFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the contents of the process id file as an integer.
|
||||
$fp = fopen($pidFile, 'r');
|
||||
$pid = fread($fp, filesize($pidFile));
|
||||
$pid = (int) $pid;
|
||||
fclose($fp);
|
||||
|
||||
// Check to make sure that the process id exists as a positive integer.
|
||||
if (!$pid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to make sure the process is active by pinging it and ensure it responds.
|
||||
if (!posix_kill($pid, 0))
|
||||
{
|
||||
// No response so remove the process id file and log the situation.
|
||||
@ unlink($pidFile);
|
||||
JLog::add('The process found based on PID file was unresponsive.', JLog::WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an object or array into the application configuration object.
|
||||
*
|
||||
* @param mixed $data Either an array or object to be loaded into the configuration object.
|
||||
*
|
||||
* @return JCli Instance of $this to allow chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function loadConfiguration($data)
|
||||
{
|
||||
// Execute the parent load method.
|
||||
parent::loadConfiguration($data);
|
||||
|
||||
/*
|
||||
* Setup some application metadata options. This is useful if we ever want to write out startup scripts
|
||||
* or just have some sort of information available to share about things.
|
||||
*/
|
||||
|
||||
// The application author name. This string is used in generating startup scripts and has
|
||||
// a maximum of 50 characters.
|
||||
$tmp = (string) $this->config->get('author_name', 'Joomla Platform');
|
||||
$this->config->set('author_name', (strlen($tmp) > 50) ? substr($tmp, 0, 50) : $tmp);
|
||||
|
||||
// The application author email. This string is used in generating startup scripts.
|
||||
$tmp = (string) $this->config->get('author_email', 'admin@joomla.org');
|
||||
$this->config->set('author_email', filter_var($tmp, FILTER_VALIDATE_EMAIL));
|
||||
|
||||
// The application name. This string is used in generating startup scripts.
|
||||
$tmp = (string) $this->config->get('application_name', 'JApplicationDaemon');
|
||||
$this->config->set('application_name', (string) preg_replace('/[^A-Z0-9_-]/i', '', $tmp));
|
||||
|
||||
// The application description. This string is used in generating startup scripts.
|
||||
$tmp = (string) $this->config->get('application_description', 'A generic Joomla Platform application.');
|
||||
$this->config->set('application_description', filter_var($tmp, FILTER_SANITIZE_STRING));
|
||||
|
||||
/*
|
||||
* Setup the application path options. This defines the default executable name, executable directory,
|
||||
* and also the path to the daemon process id file.
|
||||
*/
|
||||
|
||||
// The application executable daemon. This string is used in generating startup scripts.
|
||||
$tmp = (string) $this->config->get('application_executable', basename($this->input->executable));
|
||||
$this->config->set('application_executable', $tmp);
|
||||
|
||||
// The home directory of the daemon.
|
||||
$tmp = (string) $this->config->get('application_directory', dirname($this->input->executable));
|
||||
$this->config->set('application_directory', $tmp);
|
||||
|
||||
// The pid file location. This defaults to a path inside the /tmp directory.
|
||||
$name = $this->config->get('application_name');
|
||||
$tmp = (string) $this->config->get('application_pid_file', strtolower('/tmp/' . $name . '/' . $name . '.pid'));
|
||||
$this->config->set('application_pid_file', $tmp);
|
||||
|
||||
/*
|
||||
* Setup the application identity options. It is important to remember if the default of 0 is set for
|
||||
* either UID or GID then changing that setting will not be attempted as there is no real way to "change"
|
||||
* the identity of a process from some user to root.
|
||||
*/
|
||||
|
||||
// The user id under which to run the daemon.
|
||||
$tmp = (int) $this->config->get('application_uid', 0);
|
||||
$options = array('options' => array('min_range' => 0, 'max_range' => 65000));
|
||||
$this->config->set('application_uid', filter_var($tmp, FILTER_VALIDATE_INT, $options));
|
||||
|
||||
// The group id under which to run the daemon.
|
||||
$tmp = (int) $this->config->get('application_gid', 0);
|
||||
$options = array('options' => array('min_range' => 0, 'max_range' => 65000));
|
||||
$this->config->set('application_gid', filter_var($tmp, FILTER_VALIDATE_INT, $options));
|
||||
|
||||
// Option to kill the daemon if it cannot switch to the chosen identity.
|
||||
$tmp = (bool) $this->config->get('application_require_identity', 1);
|
||||
$this->config->set('application_require_identity', $tmp);
|
||||
|
||||
/*
|
||||
* Setup the application runtime options. By default our execution time limit is infinite obviously
|
||||
* because a daemon should be constantly running unless told otherwise. The default limit for memory
|
||||
* usage is 128M, which admittedly is a little high, but remember it is a "limit" and PHP's memory
|
||||
* management leaves a bit to be desired :-)
|
||||
*/
|
||||
|
||||
// The maximum execution time of the application in seconds. Zero is infinite.
|
||||
$tmp = $this->config->get('max_execution_time');
|
||||
|
||||
if ($tmp !== null)
|
||||
{
|
||||
$this->config->set('max_execution_time', (int) $tmp);
|
||||
}
|
||||
|
||||
// The maximum amount of memory the application can use.
|
||||
$tmp = $this->config->get('max_memory_limit', '256M');
|
||||
|
||||
if ($tmp !== null)
|
||||
{
|
||||
$this->config->set('max_memory_limit', (string) $tmp);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the daemon.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
// Trigger the onBeforeExecute event.
|
||||
$this->triggerEvent('onBeforeExecute');
|
||||
|
||||
// Enable basic garbage collection.
|
||||
gc_enable();
|
||||
|
||||
JLog::add('Starting ' . $this->name, JLog::INFO);
|
||||
|
||||
// Set off the process for becoming a daemon.
|
||||
if ($this->daemonize())
|
||||
{
|
||||
// Declare ticks to start signal monitoring. When you declare ticks, PCNTL will monitor
|
||||
// incoming signals after each tick and call the relevant signal handler automatically.
|
||||
declare (ticks = 1);
|
||||
|
||||
// Start the main execution loop.
|
||||
while (true)
|
||||
{
|
||||
// Perform basic garbage collection.
|
||||
$this->gc();
|
||||
|
||||
// Don't completely overload the CPU.
|
||||
usleep(1000);
|
||||
|
||||
// Execute the main application logic.
|
||||
$this->doExecute();
|
||||
}
|
||||
}
|
||||
// We were not able to daemonize the application so log the failure and die gracefully.
|
||||
else
|
||||
{
|
||||
JLog::add('Starting ' . $this->name . ' failed', JLog::INFO);
|
||||
}
|
||||
|
||||
// Trigger the onAfterExecute event.
|
||||
$this->triggerEvent('onAfterExecute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart daemon process.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.1
|
||||
*/
|
||||
public function restart()
|
||||
{
|
||||
JLog::add('Stopping ' . $this->name, JLog::INFO);
|
||||
$this->shutdown(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop daemon process.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.1
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
JLog::add('Stopping ' . $this->name, JLog::INFO);
|
||||
$this->shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to change the identity of the daemon process and resources.
|
||||
*
|
||||
* @return boolean True if identity successfully changed
|
||||
*
|
||||
* @since 11.1
|
||||
* @see posix_setuid()
|
||||
*/
|
||||
protected function changeIdentity()
|
||||
{
|
||||
// Get the group and user ids to set for the daemon.
|
||||
$uid = (int) $this->config->get('application_uid', 0);
|
||||
$gid = (int) $this->config->get('application_gid', 0);
|
||||
|
||||
// Get the application process id file path.
|
||||
$file = $this->config->get('application_pid_file');
|
||||
|
||||
// Change the user id for the process id file if necessary.
|
||||
if ($uid && (fileowner($file) != $uid) && (!@ chown($file, $uid)))
|
||||
{
|
||||
JLog::add('Unable to change user ownership of the process id file.', JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the group id for the process id file if necessary.
|
||||
if ($gid && (filegroup($file) != $gid) && (!@ chgrp($file, $gid)))
|
||||
{
|
||||
JLog::add('Unable to change group ownership of the process id file.', JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the correct home directory for the process.
|
||||
if ($uid && ($info = posix_getpwuid($uid)) && is_dir($info['dir']))
|
||||
{
|
||||
system('export HOME="' . $info['dir'] . '"');
|
||||
}
|
||||
|
||||
// Change the user id for the process necessary.
|
||||
if ($uid && (posix_getuid($file) != $uid) && (!@ posix_setuid($uid)))
|
||||
{
|
||||
JLog::add('Unable to change user ownership of the proccess.', JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the group id for the process necessary.
|
||||
if ($gid && (posix_getgid($file) != $gid) && (!@ posix_setgid($gid)))
|
||||
{
|
||||
JLog::add('Unable to change group ownership of the proccess.', JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the user and group information based on uid and gid.
|
||||
$user = posix_getpwuid($uid);
|
||||
$group = posix_getgrgid($gid);
|
||||
|
||||
JLog::add('Changed daemon identity to ' . $user['name'] . ':' . $group['name'], JLog::INFO);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to put the application into the background.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function daemonize()
|
||||
{
|
||||
// Is there already an active daemon running?
|
||||
if ($this->isActive())
|
||||
{
|
||||
JLog::add($this->name . ' daemon is still running. Exiting the application.', JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset Process Information
|
||||
$this->safeMode = !!@ ini_get('safe_mode');
|
||||
$this->processId = 0;
|
||||
$this->running = false;
|
||||
|
||||
// Detach process!
|
||||
try
|
||||
{
|
||||
// Check if we should run in the foreground.
|
||||
if (!$this->input->get('f'))
|
||||
{
|
||||
// Detach from the terminal.
|
||||
$this->detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup running values.
|
||||
$this->exiting = false;
|
||||
$this->running = true;
|
||||
|
||||
// Set the process id.
|
||||
$this->processId = (int) posix_getpid();
|
||||
$this->parentId = $this->processId;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
JLog::add('Unable to fork.', JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the process id is valid.
|
||||
if ($this->processId < 1)
|
||||
{
|
||||
JLog::add('The process id is invalid; the fork failed.', JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear the umask.
|
||||
@ umask(0);
|
||||
|
||||
// Write out the process id file for concurrency management.
|
||||
if (!$this->writeProcessIdFile())
|
||||
{
|
||||
JLog::add('Unable to write the pid file at: ' . $this->config->get('application_pid_file'), JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to change the identity of user running the process.
|
||||
if (!$this->changeIdentity())
|
||||
{
|
||||
|
||||
// If the identity change was required then we need to return false.
|
||||
if ($this->config->get('application_require_identity'))
|
||||
{
|
||||
JLog::add('Unable to change process owner.', JLog::CRITICAL);
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
JLog::add('Unable to change process owner.', JLog::WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the signal handlers for the daemon.
|
||||
if (!$this->setupSignalHandlers())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the current working directory to the application working directory.
|
||||
@ chdir($this->config->get('application_directory'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is truly where the magic happens. This is where we fork the process and kill the parent
|
||||
* process, which is essentially what turns the application into a daemon.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function detach()
|
||||
{
|
||||
JLog::add('Detaching the ' . $this->name . ' daemon.', JLog::DEBUG);
|
||||
|
||||
// Attempt to fork the process.
|
||||
$pid = $this->fork();
|
||||
|
||||
// If the pid is positive then we successfully forked, and can close this application.
|
||||
if ($pid)
|
||||
{
|
||||
// Add the log entry for debugging purposes and exit gracefully.
|
||||
JLog::add('Ending ' . $this->name . ' parent process', JLog::DEBUG);
|
||||
$this->close();
|
||||
}
|
||||
// We are in the forked child process.
|
||||
else
|
||||
{
|
||||
// Setup some protected values.
|
||||
$this->exiting = false;
|
||||
$this->running = true;
|
||||
|
||||
// Set the parent to self.
|
||||
$this->parentId = $this->processId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fork the process.
|
||||
*
|
||||
* @return integer The child process id to the parent process, zero to the child process.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function fork()
|
||||
{
|
||||
// Attempt to fork the process.
|
||||
$pid = $this->pcntlFork();
|
||||
|
||||
// If the fork failed, throw an exception.
|
||||
if ($pid === -1)
|
||||
{
|
||||
throw new RuntimeException('The process could not be forked.');
|
||||
}
|
||||
// Update the process id for the child.
|
||||
elseif ($pid === 0)
|
||||
{
|
||||
$this->processId = (int) posix_getpid();
|
||||
}
|
||||
// Log the fork in the parent.
|
||||
else
|
||||
{
|
||||
// Log the fork.
|
||||
JLog::add('Process forked ' . $pid, JLog::DEBUG);
|
||||
}
|
||||
|
||||
// Trigger the onFork event.
|
||||
$this->postFork();
|
||||
|
||||
return $pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform basic garbage collection and memory management in the sense of clearing the
|
||||
* stat cache. We will probably call this method pretty regularly in our main loop.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function gc()
|
||||
{
|
||||
// Perform generic garbage collection.
|
||||
gc_collect_cycles();
|
||||
|
||||
// Clear the stat cache so it doesn't blow up memory.
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to attach the JApplicationDaemon signal handler to the known signals. Applications
|
||||
* can override these handlers by using the pcntl_signal() function and attaching a different
|
||||
* callback method.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 11.1
|
||||
* @see pcntl_signal()
|
||||
*/
|
||||
protected function setupSignalHandlers()
|
||||
{
|
||||
// We add the error suppression for the loop because on some platforms some constants are not defined.
|
||||
foreach (self::$signals as $signal)
|
||||
{
|
||||
// Ignore signals that are not defined.
|
||||
if (!defined($signal) || !is_int(constant($signal)) || (constant($signal) === 0))
|
||||
{
|
||||
// Define the signal to avoid notices.
|
||||
JLog::add('Signal "' . $signal . '" not defined. Defining it as null.', JLog::DEBUG);
|
||||
define($signal, null);
|
||||
|
||||
// Don't listen for signal.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attach the signal handler for the signal.
|
||||
if (!$this->pcntlSignal(constant($signal), array('JApplicationDaemon', 'signal')))
|
||||
{
|
||||
JLog::add(sprintf('Unable to reroute signal handler: %s', $signal), JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to shut down the daemon and optionally restart it.
|
||||
*
|
||||
* @param boolean $restart True to restart the daemon on exit.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function shutdown($restart = false)
|
||||
{
|
||||
// If we are already exiting, chill.
|
||||
if ($this->exiting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If not, now we are.
|
||||
else
|
||||
{
|
||||
$this->exiting = true;
|
||||
}
|
||||
|
||||
// If we aren't already daemonized then just kill the application.
|
||||
if (!$this->running && !$this->isActive())
|
||||
{
|
||||
JLog::add('Process was not daemonized yet, just halting current process', JLog::INFO);
|
||||
$this->close();
|
||||
}
|
||||
|
||||
// Only read the pid for the parent file.
|
||||
if ($this->parentId == $this->processId)
|
||||
{
|
||||
// Read the contents of the process id file as an integer.
|
||||
$fp = fopen($this->config->get('application_pid_file'), 'r');
|
||||
$pid = fread($fp, filesize($this->config->get('application_pid_file')));
|
||||
$pid = (int) $pid;
|
||||
fclose($fp);
|
||||
|
||||
// Remove the process id file.
|
||||
@ unlink($this->config->get('application_pid_file'));
|
||||
|
||||
// If we are supposed to restart the daemon we need to execute the same command.
|
||||
if ($restart)
|
||||
{
|
||||
$this->close(exec(implode(' ', $GLOBALS['argv']) . ' > /dev/null &'));
|
||||
}
|
||||
// If we are not supposed to restart the daemon let's just kill -9.
|
||||
else
|
||||
{
|
||||
passthru('kill -9 ' . $pid);
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to write the process id file out to disk.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function writeProcessIdFile()
|
||||
{
|
||||
// Verify the process id is valid.
|
||||
if ($this->processId < 1)
|
||||
{
|
||||
JLog::add('The process id is invalid.', JLog::EMERGENCY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the application process id file path.
|
||||
$file = $this->config->get('application_pid_file');
|
||||
|
||||
if (empty($file))
|
||||
{
|
||||
JLog::add('The process id file path is empty.', JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure that the folder where we are writing the process id file exists.
|
||||
$folder = dirname($file);
|
||||
|
||||
if (!is_dir($folder) && !JFolder::create($folder))
|
||||
{
|
||||
JLog::add('Unable to create directory: ' . $folder, JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the process id file out to disk.
|
||||
if (!file_put_contents($file, $this->processId))
|
||||
{
|
||||
JLog::add('Unable to write proccess id file: ' . $file, JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the permissions for the proccess id file are accurate.
|
||||
if (!chmod($file, 0644))
|
||||
{
|
||||
JLog::add('Unable to adjust permissions for the proccess id file: ' . $file, JLog::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle post-fork triggering of the onFork event.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function postFork()
|
||||
{
|
||||
// Trigger the onFork event.
|
||||
$this->triggerEvent('onFork');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the exit code of a terminated child process.
|
||||
*
|
||||
* @param integer $status The status parameter is the status parameter supplied to a successful call to pcntl_waitpid().
|
||||
*
|
||||
* @return integer The child process exit code.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @see pcntl_wexitstatus()
|
||||
* @since 11.3
|
||||
*/
|
||||
protected function pcntlChildExitStatus($status)
|
||||
{
|
||||
return pcntl_wexitstatus($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the exit code of a terminated child process.
|
||||
*
|
||||
* @return integer On success, the PID of the child process is returned in the parent's thread
|
||||
* of execution, and a 0 is returned in the child's thread of execution. On
|
||||
* failure, a -1 will be returned in the parent's context, no child process
|
||||
* will be created, and a PHP error is raised.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @see pcntl_fork()
|
||||
* @since 11.3
|
||||
*/
|
||||
protected function pcntlFork()
|
||||
{
|
||||
return pcntl_fork();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to install a signal handler.
|
||||
*
|
||||
* @param integer $signal The signal number.
|
||||
* @param callable $handler The signal handler which may be the name of a user created function,
|
||||
* or method, or either of the two global constants SIG_IGN or SIG_DFL.
|
||||
* @param boolean $restart Specifies whether system call restarting should be used when this
|
||||
* signal arrives.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @see pcntl_signal()
|
||||
* @since 11.3
|
||||
*/
|
||||
protected function pcntlSignal($signal , $handler, $restart = true)
|
||||
{
|
||||
return pcntl_signal($signal, $handler, $restart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to wait on or return the status of a forked child.
|
||||
*
|
||||
* @param integer &$status Status information.
|
||||
* @param integer $options If wait3 is available on your system (mostly BSD-style systems),
|
||||
* you can provide the optional options parameter.
|
||||
*
|
||||
* @return integer The process ID of the child which exited, -1 on error or zero if WNOHANG
|
||||
* was provided as an option (on wait3-available systems) and no child was available.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @see pcntl_wait()
|
||||
* @since 11.3
|
||||
*/
|
||||
protected function pcntlWait(&$status, $options = 0)
|
||||
{
|
||||
return pcntl_wait($status, $options);
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/application/index.html
Normal file
1
libraries/joomla/application/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
107
libraries/joomla/application/route.php
Normal file
107
libraries/joomla/application/route.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Route handling class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 11.1
|
||||
*/
|
||||
class JRoute
|
||||
{
|
||||
/**
|
||||
* The route object so we don't have to keep fetching it.
|
||||
*
|
||||
* @var JRouter
|
||||
* @since 12.2
|
||||
*/
|
||||
private static $_router = null;
|
||||
|
||||
/**
|
||||
* Translates an internal Joomla URL to a humanly readible URL.
|
||||
*
|
||||
* @param string $url Absolute or Relative URI to Joomla resource.
|
||||
* @param boolean $xhtml Replace & by & for XML compilance.
|
||||
* @param integer $ssl Secure state for the resolved URI.
|
||||
* 1: Make URI secure using global secure site URI.
|
||||
* 2: Make URI unsecure using the global unsecure site URI.
|
||||
*
|
||||
* @return The translated humanly readible URL.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function _($url, $xhtml = true, $ssl = null)
|
||||
{
|
||||
if (!self::$_router)
|
||||
{
|
||||
// Get the router.
|
||||
self::$_router = JFactory::getApplication()->getRouter();
|
||||
|
||||
// Make sure that we have our router
|
||||
if (!self::$_router)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ((strpos($url, '&') !== 0) && (strpos($url, 'index.php') !== 0))
|
||||
{
|
||||
return $url;
|
||||
}
|
||||
|
||||
// Build route.
|
||||
$uri = self::$_router->build($url);
|
||||
$url = $uri->toString(array('path', 'query', 'fragment'));
|
||||
|
||||
// Replace spaces.
|
||||
$url = preg_replace('/\s/u', '%20', $url);
|
||||
|
||||
/*
|
||||
* Get the secure/unsecure URLs.
|
||||
*
|
||||
* If the first 5 characters of the BASE are 'https', then we are on an ssl connection over
|
||||
* https and need to set our secure URL to the current request URL, if not, and the scheme is
|
||||
* 'http', then we need to do a quick string manipulation to switch schemes.
|
||||
*/
|
||||
if ((int) $ssl)
|
||||
{
|
||||
$uri = JUri::getInstance();
|
||||
|
||||
// Get additional parts.
|
||||
static $prefix;
|
||||
|
||||
if (!$prefix)
|
||||
{
|
||||
$prefix = $uri->toString(array('host', 'port'));
|
||||
}
|
||||
|
||||
// Determine which scheme we want.
|
||||
$scheme = ((int) $ssl === 1) ? 'https' : 'http';
|
||||
|
||||
// Make sure our URL path begins with a slash.
|
||||
if (!preg_match('#^/#', $url))
|
||||
{
|
||||
$url = '/' . $url;
|
||||
}
|
||||
|
||||
// Build the URL.
|
||||
$url = $scheme . '://' . $prefix . $url;
|
||||
}
|
||||
|
||||
if ($xhtml)
|
||||
{
|
||||
$url = htmlspecialchars($url);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
521
libraries/joomla/application/router.php
Normal file
521
libraries/joomla/application/router.php
Normal file
@ -0,0 +1,521 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Set the available masks for the routing mode
|
||||
*/
|
||||
const JROUTER_MODE_RAW = 0;
|
||||
const JROUTER_MODE_SEF = 1;
|
||||
|
||||
/**
|
||||
* Class to create and parse routes
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 11.1
|
||||
*/
|
||||
class JRouter
|
||||
{
|
||||
/**
|
||||
* The rewrite mode
|
||||
*
|
||||
* @var integer
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $mode = null;
|
||||
|
||||
/**
|
||||
* The rewrite mode
|
||||
*
|
||||
* @var integer
|
||||
* @since 11.1
|
||||
* @deprecated use $mode declare as private
|
||||
*/
|
||||
protected $_mode = null;
|
||||
|
||||
/**
|
||||
* An array of variables
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $vars = array();
|
||||
|
||||
/**
|
||||
* An array of variables
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
* @deprecated use $vars declare as private
|
||||
*/
|
||||
protected $_vars = array();
|
||||
|
||||
/**
|
||||
* An array of rules
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $rules = array(
|
||||
'build' => array(),
|
||||
'parse' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* An array of rules
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
* @deprecated use $rules declare as private
|
||||
*/
|
||||
protected $_rules = array(
|
||||
'build' => array(),
|
||||
'parse' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array JRouter instances container.
|
||||
* @since 11.3
|
||||
*/
|
||||
protected static $instances = array();
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $options Array of options
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
if (array_key_exists('mode', $options))
|
||||
{
|
||||
$this->_mode = $options['mode'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_mode = JROUTER_MODE_RAW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global JRouter object, only creating it if it
|
||||
* doesn't already exist.
|
||||
*
|
||||
* @param string $client The name of the client
|
||||
* @param array $options An associative array of options
|
||||
*
|
||||
* @return JRouter A JRouter object.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getInstance($client, $options = array())
|
||||
{
|
||||
if (empty(self::$instances[$client]))
|
||||
{
|
||||
// Create a JRouter object
|
||||
$classname = 'JRouter' . ucfirst($client);
|
||||
|
||||
if (!class_exists($classname))
|
||||
{
|
||||
JLog::add('Non-autoloadable JRouter subclasses are deprecated.', JLog::WARNING, 'deprecated');
|
||||
|
||||
// Load the router object
|
||||
$info = JApplicationHelper::getClientInfo($client, true);
|
||||
|
||||
if (is_object($info))
|
||||
{
|
||||
$path = $info->path . '/includes/router.php';
|
||||
|
||||
if (file_exists($path))
|
||||
{
|
||||
include_once $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists($classname))
|
||||
{
|
||||
self::$instances[$client] = new $classname($options);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(JText::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD', $client), 500);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$instances[$client];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert a route to an internal URI
|
||||
*
|
||||
* @param JUri $uri The uri.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function parse($uri)
|
||||
{
|
||||
// Process the parsed variables based on custom defined rules
|
||||
$vars = $this->_processParseRules($uri);
|
||||
|
||||
// Parse RAW URL
|
||||
if ($this->_mode == JROUTER_MODE_RAW)
|
||||
{
|
||||
$vars += $this->_parseRawRoute($uri);
|
||||
}
|
||||
|
||||
// Parse SEF URL
|
||||
if ($this->_mode == JROUTER_MODE_SEF)
|
||||
{
|
||||
$vars += $this->_parseSefRoute($uri);
|
||||
}
|
||||
|
||||
return array_merge($this->getVars(), $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert an internal URI to a route
|
||||
*
|
||||
* @param string $url The internal URL
|
||||
*
|
||||
* @return string The absolute search engine friendly URL
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function build($url)
|
||||
{
|
||||
// Create the URI object
|
||||
$uri = $this->_createURI($url);
|
||||
|
||||
// Process the uri information based on custom defined rules
|
||||
$this->_processBuildRules($uri);
|
||||
|
||||
// Build RAW URL
|
||||
if ($this->_mode == JROUTER_MODE_RAW)
|
||||
{
|
||||
$this->_buildRawRoute($uri);
|
||||
}
|
||||
|
||||
// Build SEF URL : mysite/route/index.php?var=x
|
||||
if ($this->_mode == JROUTER_MODE_SEF)
|
||||
{
|
||||
$this->_buildSefRoute($uri);
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the router mode
|
||||
*
|
||||
* @return integer
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getMode()
|
||||
{
|
||||
return $this->_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the router mode
|
||||
*
|
||||
* @param integer $mode The routing mode.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setMode($mode)
|
||||
{
|
||||
$this->_mode = $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a router variable, creating it if it doesn't exist
|
||||
*
|
||||
* @param string $key The name of the variable
|
||||
* @param mixed $value The value of the variable
|
||||
* @param boolean $create If True, the variable will be created if it doesn't exist yet
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setVar($key, $value, $create = true)
|
||||
{
|
||||
if ($create || array_key_exists($key, $this->_vars))
|
||||
{
|
||||
$this->_vars[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the router variable array
|
||||
*
|
||||
* @param array $vars An associative array with variables
|
||||
* @param boolean $merge If True, the array will be merged instead of overwritten
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setVars($vars = array(), $merge = true)
|
||||
{
|
||||
if ($merge)
|
||||
{
|
||||
$this->_vars = array_merge($this->_vars, $vars);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_vars = $vars;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a router variable
|
||||
*
|
||||
* @param string $key The name of the variable
|
||||
*
|
||||
* @return mixed Value of the variable
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getVar($key)
|
||||
{
|
||||
$result = null;
|
||||
|
||||
if (isset($this->_vars[$key]))
|
||||
{
|
||||
$result = $this->_vars[$key];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the router variable array
|
||||
*
|
||||
* @return array An associative array of router variables
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getVars()
|
||||
{
|
||||
return $this->_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a build rule
|
||||
*
|
||||
* @param callback $callback The function to be called
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1.
|
||||
*/
|
||||
public function attachBuildRule($callback)
|
||||
{
|
||||
$this->_rules['build'][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a parse rule
|
||||
*
|
||||
* @param callback $callback The function to be called.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function attachParseRule($callback)
|
||||
{
|
||||
$this->_rules['parse'][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert a raw route to an internal URI
|
||||
*
|
||||
* @param JUri $uri The raw route
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _parseRawRoute($uri)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert a sef route to an internal URI
|
||||
*
|
||||
* @param JUri $uri The sef URI
|
||||
*
|
||||
* @return string Internal URI
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _parseSefRoute($uri)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to build a raw route
|
||||
*
|
||||
* @param JUri $uri The internal URL
|
||||
*
|
||||
* @return string Raw Route
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _buildRawRoute($uri)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to build a sef route
|
||||
*
|
||||
* @param JUri $uri The uri
|
||||
*
|
||||
* @return string The SEF route
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _buildSefRoute($uri)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the parsed router variables based on custom defined rules
|
||||
*
|
||||
* @param JUri $uri The URI to parse
|
||||
*
|
||||
* @return array The array of processed URI variables
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _processParseRules($uri)
|
||||
{
|
||||
$vars = array();
|
||||
|
||||
foreach ($this->_rules['parse'] as $rule)
|
||||
{
|
||||
$vars += call_user_func_array($rule, array(&$this, &$uri));
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the build uri query data based on custom defined rules
|
||||
*
|
||||
* @param JUri $uri The URI
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _processBuildRules($uri)
|
||||
{
|
||||
foreach ($this->_rules['build'] as $rule)
|
||||
{
|
||||
call_user_func_array($rule, array(&$this, &$uri));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a uri based on a full or partial url string
|
||||
*
|
||||
* @param string $url The URI
|
||||
*
|
||||
* @return JUri
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _createURI($url)
|
||||
{
|
||||
// Create full URL if we are only appending variables to it
|
||||
if (substr($url, 0, 1) == '&')
|
||||
{
|
||||
$vars = array();
|
||||
|
||||
if (strpos($url, '&') !== false)
|
||||
{
|
||||
$url = str_replace('&', '&', $url);
|
||||
}
|
||||
|
||||
parse_str($url, $vars);
|
||||
|
||||
$vars = array_merge($this->getVars(), $vars);
|
||||
|
||||
foreach ($vars as $key => $var)
|
||||
{
|
||||
if ($var == "")
|
||||
{
|
||||
unset($vars[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$url = 'index.php?' . JUri::buildQuery($vars);
|
||||
}
|
||||
|
||||
// Decompose link into url component parts
|
||||
return new JUri($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode route segments
|
||||
*
|
||||
* @param array $segments An array of route segments
|
||||
*
|
||||
* @return array Array of encoded route segments
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _encodeSegments($segments)
|
||||
{
|
||||
$total = count($segments);
|
||||
|
||||
for ($i = 0; $i < $total; $i++)
|
||||
{
|
||||
$segments[$i] = str_replace(':', '-', $segments[$i]);
|
||||
}
|
||||
|
||||
return $segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode route segments
|
||||
*
|
||||
* @param array $segments An array of route segments
|
||||
*
|
||||
* @return array Array of decoded route segments
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _decodeSegments($segments)
|
||||
{
|
||||
$total = count($segments);
|
||||
|
||||
for ($i = 0; $i < $total; $i++)
|
||||
{
|
||||
$segments[$i] = preg_replace('/-/', ':', $segments[$i], 1);
|
||||
}
|
||||
|
||||
return $segments;
|
||||
}
|
||||
}
|
||||
1184
libraries/joomla/application/web.php
Normal file
1184
libraries/joomla/application/web.php
Normal file
File diff suppressed because it is too large
Load Diff
516
libraries/joomla/application/web/client.php
Normal file
516
libraries/joomla/application/web/client.php
Normal file
@ -0,0 +1,516 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Class to model a Web Client.
|
||||
*
|
||||
* @property-read integer $platform The detected platform on which the web client runs.
|
||||
* @property-read boolean $mobile True if the web client is a mobile device.
|
||||
* @property-read integer $engine The detected rendering engine used by the web client.
|
||||
* @property-read integer $browser The detected browser used by the web client.
|
||||
* @property-read string $browserVersion The detected browser version used by the web client.
|
||||
* @property-read array $languages The priority order detected accepted languages for the client.
|
||||
* @property-read array $encodings The priority order detected accepted encodings for the client.
|
||||
* @property-read string $userAgent The web client's user agent string.
|
||||
* @property-read string $acceptEncoding The web client's accepted encoding string.
|
||||
* @property-read string $acceptLanguage The web client's accepted languages string.
|
||||
* @property-read array $detection An array of flags determining whether or not a detection routine has been run.
|
||||
* @property-read boolean $robot True if the web client is a robot
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 12.1
|
||||
*/
|
||||
class JApplicationWebClient
|
||||
{
|
||||
const WINDOWS = 1;
|
||||
const WINDOWS_PHONE = 2;
|
||||
const WINDOWS_CE = 3;
|
||||
const IPHONE = 4;
|
||||
const IPAD = 5;
|
||||
const IPOD = 6;
|
||||
const MAC = 7;
|
||||
const BLACKBERRY = 8;
|
||||
const ANDROID = 9;
|
||||
const LINUX = 10;
|
||||
const TRIDENT = 11;
|
||||
const WEBKIT = 12;
|
||||
const GECKO = 13;
|
||||
const PRESTO = 14;
|
||||
const KHTML = 15;
|
||||
const AMAYA = 16;
|
||||
const IE = 17;
|
||||
const FIREFOX = 18;
|
||||
const CHROME = 19;
|
||||
const SAFARI = 20;
|
||||
const OPERA = 21;
|
||||
const ANDROIDTABLET = 22;
|
||||
|
||||
/**
|
||||
* @var integer The detected platform on which the web client runs.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $platform;
|
||||
|
||||
/**
|
||||
* @var boolean True if the web client is a mobile device.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $mobile = false;
|
||||
|
||||
/**
|
||||
* @var integer The detected rendering engine used by the web client.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $engine;
|
||||
|
||||
/**
|
||||
* @var integer The detected browser used by the web client.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $browser;
|
||||
|
||||
/**
|
||||
* @var string The detected browser version used by the web client.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $browserVersion;
|
||||
|
||||
/**
|
||||
* @var array The priority order detected accepted languages for the client.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $languages = array();
|
||||
|
||||
/**
|
||||
* @var array The priority order detected accepted encodings for the client.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $encodings = array();
|
||||
|
||||
/**
|
||||
* @var string The web client's user agent string.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $userAgent;
|
||||
|
||||
/**
|
||||
* @var string The web client's accepted encoding string.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $acceptEncoding;
|
||||
|
||||
/**
|
||||
* @var string The web client's accepted languages string.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $acceptLanguage;
|
||||
|
||||
/**
|
||||
* @var boolean True if the web client is a robot.
|
||||
* @since 12.3
|
||||
*/
|
||||
protected $robot = false;
|
||||
|
||||
/**
|
||||
* @var array An array of flags determining whether or not a detection routine has been run.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $detection = array();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $userAgent The optional user-agent string to parse.
|
||||
* @param string $acceptEncoding The optional client accept encoding string to parse.
|
||||
* @param string $acceptLanguage The optional client accept language string to parse.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($userAgent = null, $acceptEncoding = null, $acceptLanguage = null)
|
||||
{
|
||||
// If no explicit user agent string was given attempt to use the implicit one from server environment.
|
||||
if (empty($userAgent) && isset($_SERVER['HTTP_USER_AGENT']))
|
||||
{
|
||||
$this->userAgent = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->userAgent = $userAgent;
|
||||
}
|
||||
|
||||
// If no explicit acceptable encoding string was given attempt to use the implicit one from server environment.
|
||||
if (empty($acceptEncoding) && isset($_SERVER['HTTP_ACCEPT_ENCODING']))
|
||||
{
|
||||
$this->acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->acceptEncoding = $acceptEncoding;
|
||||
}
|
||||
|
||||
// If no explicit acceptable languages string was given attempt to use the implicit one from server environment.
|
||||
if (empty($acceptLanguage) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
|
||||
{
|
||||
$this->acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->acceptLanguage = $acceptLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to get an object property's value by name.
|
||||
*
|
||||
* @param string $name Name of the property for which to return a value.
|
||||
*
|
||||
* @return mixed The requested value if it exists.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
switch ($name)
|
||||
{
|
||||
case 'mobile':
|
||||
case 'platform':
|
||||
if (empty($this->detection['platform']))
|
||||
{
|
||||
$this->detectPlatform($this->userAgent);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'engine':
|
||||
if (empty($this->detection['engine']))
|
||||
{
|
||||
$this->detectEngine($this->userAgent);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'browser':
|
||||
case 'browserVersion':
|
||||
if (empty($this->detection['browser']))
|
||||
{
|
||||
$this->detectBrowser($this->userAgent);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'languages':
|
||||
if (empty($this->detection['acceptLanguage']))
|
||||
{
|
||||
$this->detectLanguage($this->acceptLanguage);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'encodings':
|
||||
if (empty($this->detection['acceptEncoding']))
|
||||
{
|
||||
$this->detectEncoding($this->acceptEncoding);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'robot':
|
||||
if (empty($this->detection['robot']))
|
||||
{
|
||||
$this->detectRobot($this->userAgent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the property if it exists.
|
||||
if (isset($this->$name))
|
||||
{
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the client browser and version in a user agent string.
|
||||
*
|
||||
* @param string $userAgent The user-agent string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function detectBrowser($userAgent)
|
||||
{
|
||||
// Attempt to detect the browser type. Obviously we are only worried about major browsers.
|
||||
if ((stripos($userAgent, 'MSIE') !== false) && (stripos($userAgent, 'Opera') === false))
|
||||
{
|
||||
$this->browser = self::IE;
|
||||
$patternBrowser = 'MSIE';
|
||||
}
|
||||
elseif ((stripos($userAgent, 'Firefox') !== false) && (stripos($userAgent, 'like Firefox') === false))
|
||||
{
|
||||
$this->browser = self::FIREFOX;
|
||||
$patternBrowser = 'Firefox';
|
||||
}
|
||||
elseif (stripos($userAgent, 'Chrome') !== false)
|
||||
{
|
||||
$this->browser = self::CHROME;
|
||||
$patternBrowser = 'Chrome';
|
||||
}
|
||||
elseif (stripos($userAgent, 'Safari') !== false)
|
||||
{
|
||||
$this->browser = self::SAFARI;
|
||||
$patternBrowser = 'Safari';
|
||||
}
|
||||
elseif (stripos($userAgent, 'Opera') !== false)
|
||||
{
|
||||
$this->browser = self::OPERA;
|
||||
$patternBrowser = 'Opera';
|
||||
}
|
||||
|
||||
// If we detected a known browser let's attempt to determine the version.
|
||||
if ($this->browser)
|
||||
{
|
||||
// Build the REGEX pattern to match the browser version string within the user agent string.
|
||||
$pattern = '#(?<browser>Version|' . $patternBrowser . ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
|
||||
|
||||
// Attempt to find version strings in the user agent string.
|
||||
$matches = array();
|
||||
|
||||
if (preg_match_all($pattern, $userAgent, $matches))
|
||||
{
|
||||
// Do we have both a Version and browser match?
|
||||
if (count($matches['browser']) == 2)
|
||||
{
|
||||
// See whether Version or browser came first, and use the number accordingly.
|
||||
if (strripos($userAgent, 'Version') < strripos($userAgent, $patternBrowser))
|
||||
{
|
||||
$this->browserVersion = $matches['version'][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->browserVersion = $matches['version'][1];
|
||||
}
|
||||
}
|
||||
elseif (count($matches['browser']) > 2)
|
||||
{
|
||||
$key = array_search('Version', $matches['browser']);
|
||||
|
||||
if ($key)
|
||||
{
|
||||
$this->browserVersion = $matches['version'][$key];
|
||||
}
|
||||
}
|
||||
// We only have a Version or a browser so use what we have.
|
||||
else
|
||||
{
|
||||
$this->browserVersion = $matches['version'][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this detection routine as run.
|
||||
$this->detection['browser'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to detect the accepted response encoding by the client.
|
||||
*
|
||||
* @param string $acceptEncoding The client accept encoding string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function detectEncoding($acceptEncoding)
|
||||
{
|
||||
// Parse the accepted encodings.
|
||||
$this->encodings = array_map('trim', (array) explode(',', $acceptEncoding));
|
||||
|
||||
// Mark this detection routine as run.
|
||||
$this->detection['acceptEncoding'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the client rendering engine in a user agent string.
|
||||
*
|
||||
* @param string $userAgent The user-agent string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function detectEngine($userAgent)
|
||||
{
|
||||
// Attempt to detect the client engine -- starting with the most popular ... for now.
|
||||
if (stripos($userAgent, 'MSIE') !== false || stripos($userAgent, 'Trident') !== false)
|
||||
{
|
||||
$this->engine = self::TRIDENT;
|
||||
}
|
||||
// Evidently blackberry uses WebKit and doesn't necessarily report it. Bad RIM.
|
||||
elseif (stripos($userAgent, 'AppleWebKit') !== false || stripos($userAgent, 'blackberry') !== false)
|
||||
{
|
||||
$this->engine = self::WEBKIT;
|
||||
}
|
||||
// We have to check for like Gecko because some other browsers spoof Gecko.
|
||||
elseif (stripos($userAgent, 'Gecko') !== false && stripos($userAgent, 'like Gecko') === false)
|
||||
{
|
||||
$this->engine = self::GECKO;
|
||||
}
|
||||
// Sometimes Opera browsers don't say Presto.
|
||||
elseif (stripos($userAgent, 'Opera') !== false || stripos($userAgent, 'Presto') !== false)
|
||||
{
|
||||
$this->engine = self::PRESTO;
|
||||
}
|
||||
// *sigh*
|
||||
elseif (stripos($userAgent, 'KHTML') !== false)
|
||||
{
|
||||
$this->engine = self::KHTML;
|
||||
}
|
||||
// Lesser known engine but it finishes off the major list from Wikipedia :-)
|
||||
elseif (stripos($userAgent, 'Amaya') !== false)
|
||||
{
|
||||
$this->engine = self::AMAYA;
|
||||
}
|
||||
|
||||
// Mark this detection routine as run.
|
||||
$this->detection['engine'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to detect the accepted languages by the client.
|
||||
*
|
||||
* @param mixed $acceptLanguage The client accept language string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function detectLanguage($acceptLanguage)
|
||||
{
|
||||
// Parse the accepted encodings.
|
||||
$this->languages = array_map('trim', (array) explode(',', $acceptLanguage));
|
||||
|
||||
// Mark this detection routine as run.
|
||||
$this->detection['acceptLanguage'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the client platform in a user agent string.
|
||||
*
|
||||
* @param string $userAgent The user-agent string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function detectPlatform($userAgent)
|
||||
{
|
||||
// Attempt to detect the client platform.
|
||||
if (stripos($userAgent, 'Windows') !== false)
|
||||
{
|
||||
$this->platform = self::WINDOWS;
|
||||
|
||||
// Let's look at the specific mobile options in the Windows space.
|
||||
if (stripos($userAgent, 'Windows Phone') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::WINDOWS_PHONE;
|
||||
}
|
||||
elseif (stripos($userAgent, 'Windows CE') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::WINDOWS_CE;
|
||||
}
|
||||
}
|
||||
// Interestingly 'iPhone' is present in all iOS devices so far including iPad and iPods.
|
||||
elseif (stripos($userAgent, 'iPhone') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::IPHONE;
|
||||
|
||||
// Let's look at the specific mobile options in the iOS space.
|
||||
if (stripos($userAgent, 'iPad') !== false)
|
||||
{
|
||||
$this->platform = self::IPAD;
|
||||
}
|
||||
elseif (stripos($userAgent, 'iPod') !== false)
|
||||
{
|
||||
$this->platform = self::IPOD;
|
||||
}
|
||||
}
|
||||
// In case where iPhone is not mentioed in iPad user agent string
|
||||
elseif (stripos($userAgent, 'iPad') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::IPAD;
|
||||
}
|
||||
// In case where iPhone is not mentioed in iPod user agent string
|
||||
elseif (stripos($userAgent, 'iPod') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::IPOD;
|
||||
}
|
||||
// This has to come after the iPhone check because mac strings are also present in iOS devices.
|
||||
elseif (preg_match('/macintosh|mac os x/i', $userAgent))
|
||||
{
|
||||
$this->platform = self::MAC;
|
||||
}
|
||||
elseif (stripos($userAgent, 'Blackberry') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::BLACKBERRY;
|
||||
}
|
||||
elseif (stripos($userAgent, 'Android') !== false)
|
||||
{
|
||||
$this->mobile = true;
|
||||
$this->platform = self::ANDROID;
|
||||
/**
|
||||
* Attempt to distinguish between Android phones and tablets
|
||||
* There is no totally foolproof method but certain rules almost always hold
|
||||
* Android 3.x is only used for tablets
|
||||
* Some devices and browsers encourage users to change their UA string to include Tablet.
|
||||
* Google encourages manufacturers to exclude the string Mobile from tablet device UA strings.
|
||||
* In some modes Kindle Android devices include the string Mobile but they include the string Silk.
|
||||
*/
|
||||
if (stripos($userAgent, 'Android 3') !== false || stripos($userAgent, 'Tablet') !== false
|
||||
|| stripos($userAgent, 'Mobile') === false || stripos($userAgent, 'Silk') !== false )
|
||||
{
|
||||
$this->platform = self::ANDROIDTABLET;
|
||||
}
|
||||
}
|
||||
elseif (stripos($userAgent, 'Linux') !== false)
|
||||
{
|
||||
$this->platform = self::LINUX;
|
||||
}
|
||||
|
||||
// Mark this detection routine as run.
|
||||
$this->detection['platform'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the browser is a robot or not.
|
||||
*
|
||||
* @param string $userAgent The user-agent string to parse.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
protected function detectRobot($userAgent)
|
||||
{
|
||||
if (preg_match('/http|bot|robot|spider|crawler|curl|^$/i', $userAgent))
|
||||
{
|
||||
$this->robot = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->robot = false;
|
||||
}
|
||||
|
||||
$this->detection['robot'] = true;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/application/web/index.html
Normal file
1
libraries/joomla/application/web/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
153
libraries/joomla/application/web/router.php
Normal file
153
libraries/joomla/application/web/router.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Class to define an abstract Web application router.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 12.2
|
||||
*/
|
||||
abstract class JApplicationWebRouter
|
||||
{
|
||||
/**
|
||||
* @var JApplicationWeb The web application on whose behalf we are routing the request.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @var string The default page controller name for an empty route.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $default;
|
||||
|
||||
/**
|
||||
* @var string Controller class name prefix for creating controller objects by name.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $controllerPrefix;
|
||||
|
||||
/**
|
||||
* @var JInput An input object from which to derive the route.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param JApplicationWeb $app The web application on whose behalf we are routing the request.
|
||||
* @param JInput $input An optional input object from which to derive the route. If none
|
||||
* is given than the input from the application object will be used.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function __construct(JApplicationWeb $app, JInput $input = null)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->input = ($input === null) ? $this->app->input : $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and execute the appropriate controller based on a given route.
|
||||
*
|
||||
* @param string $route The route string for which to find and execute a controller.
|
||||
*
|
||||
* @return mixed The return value of the controller executed
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function execute($route)
|
||||
{
|
||||
// Get the controller name based on the route patterns and requested route.
|
||||
$name = $this->parseRoute($route);
|
||||
|
||||
// Get the controller object by name.
|
||||
$controller = $this->fetchController($name);
|
||||
|
||||
// Execute the controller.
|
||||
return $controller->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the controller name prefix.
|
||||
*
|
||||
* @param string $prefix Controller class name prefix for creating controller objects by name.
|
||||
*
|
||||
* @return JApplicationWebRouter This object for method chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function setControllerPrefix($prefix)
|
||||
{
|
||||
$this->controllerPrefix = (string) $prefix;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default controller name.
|
||||
*
|
||||
* @param string $name The default page controller name for an empty route.
|
||||
*
|
||||
* @return JApplicationWebRouter This object for method chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function setDefaultController($name)
|
||||
{
|
||||
$this->default = (string) $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given route and return the name of a controller mapped to the given route.
|
||||
*
|
||||
* @param string $route The route string for which to find and execute a controller.
|
||||
*
|
||||
* @return string The controller name for the given route excluding prefix.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
abstract protected function parseRoute($route);
|
||||
|
||||
/**
|
||||
* Get a JController object for a given name.
|
||||
*
|
||||
* @param string $name The controller name (excluding prefix) for which to fetch and instance.
|
||||
*
|
||||
* @return JController
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function fetchController($name)
|
||||
{
|
||||
// Derive the controller class name.
|
||||
$class = $this->controllerPrefix . ucfirst($name);
|
||||
|
||||
// If the controller class does not exist panic.
|
||||
if (!class_exists($class) || !is_subclass_of($class, 'JController'))
|
||||
{
|
||||
throw new RuntimeException(sprintf('Unable to locate controller `%s`.', $class), 404);
|
||||
}
|
||||
|
||||
// Instantiate the controller.
|
||||
$controller = new $class($this->input, $this->app);
|
||||
|
||||
return $controller;
|
||||
}
|
||||
}
|
||||
177
libraries/joomla/application/web/router/base.php
Normal file
177
libraries/joomla/application/web/router/base.php
Normal file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Basic Web application router class for the Joomla Platform.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 12.2
|
||||
*/
|
||||
class JApplicationWebRouterBase extends JApplicationWebRouter
|
||||
{
|
||||
/**
|
||||
* @var array An array of rules, each rule being an associative array('regex'=> $regex, 'vars' => $vars, 'controller' => $controller)
|
||||
* for routing the request.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $maps = array();
|
||||
|
||||
/**
|
||||
* Add a route map to the router. If the pattern already exists it will be overwritten.
|
||||
*
|
||||
* @param string $pattern The route pattern to use for matching.
|
||||
* @param string $controller The controller name to map to the given pattern.
|
||||
*
|
||||
* @return JApplicationWebRouter This object for method chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function addMap($pattern, $controller)
|
||||
{
|
||||
// Sanitize and explode the pattern.
|
||||
$pattern = explode('/', trim(parse_url((string) $pattern, PHP_URL_PATH), ' /'));
|
||||
|
||||
// Prepare the route variables
|
||||
$vars = array();
|
||||
|
||||
// Initialize regular expression
|
||||
$regex = array();
|
||||
|
||||
// Loop on each segment
|
||||
foreach ($pattern as $segment)
|
||||
{
|
||||
// Match a splat with no variable.
|
||||
if ($segment == '*')
|
||||
{
|
||||
$regex[] = '.*';
|
||||
}
|
||||
// Match a splat and capture the data to a named variable.
|
||||
elseif ($segment[0] == '*')
|
||||
{
|
||||
$vars[] = substr($segment, 1);
|
||||
$regex[] = '(.*)';
|
||||
}
|
||||
// Match an escaped splat segment.
|
||||
elseif ($segment[0] == '\\' && $segment[1] == '*')
|
||||
{
|
||||
$regex[] = '\*' . preg_quote(substr($segment, 2));
|
||||
}
|
||||
// Match an unnamed variable without capture.
|
||||
elseif ($segment == ':')
|
||||
{
|
||||
$regex[] = '[^/]*';
|
||||
}
|
||||
// Match a named variable and capture the data.
|
||||
elseif ($segment[0] == ':')
|
||||
{
|
||||
$vars[] = substr($segment, 1);
|
||||
$regex[] = '([^/]*)';
|
||||
}
|
||||
// Match a segment with an escaped variable character prefix.
|
||||
elseif ($segment[0] == '\\' && $segment[1] == ':')
|
||||
{
|
||||
$regex[] = preg_quote(substr($segment, 1));
|
||||
}
|
||||
// Match the standard segment.
|
||||
else
|
||||
{
|
||||
$regex[] = preg_quote($segment);
|
||||
}
|
||||
}
|
||||
|
||||
$this->maps[] = array(
|
||||
'regex' => chr(1) . '^' . implode('/', $regex) . '$' . chr(1),
|
||||
'vars' => $vars,
|
||||
'controller' => (string) $controller
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a route map to the router. If the pattern already exists it will be overwritten.
|
||||
*
|
||||
* @param array $maps A list of route maps to add to the router as $pattern => $controller.
|
||||
*
|
||||
* @return JApplicationWebRouter This object for method chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function addMaps($maps)
|
||||
{
|
||||
foreach ($maps as $pattern => $controller)
|
||||
{
|
||||
$this->addMap($pattern, $controller);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given route and return the name of a controller mapped to the given route.
|
||||
*
|
||||
* @param string $route The route string for which to find and execute a controller.
|
||||
*
|
||||
* @return string The controller name for the given route excluding prefix.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function parseRoute($route)
|
||||
{
|
||||
$controller = false;
|
||||
|
||||
// Trim the query string off.
|
||||
$route = preg_replace('/([^?]*).*/u', '\1', $route);
|
||||
|
||||
// Sanitize and explode the route.
|
||||
$route = trim(parse_url($route, PHP_URL_PATH), ' /');
|
||||
|
||||
// If the route is empty then simply return the default route. No parsing necessary.
|
||||
if ($route == '')
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
// Iterate through all of the known route maps looking for a match.
|
||||
foreach ($this->maps as $rule)
|
||||
{
|
||||
if (preg_match($rule['regex'], $route, $matches))
|
||||
{
|
||||
// If we have gotten this far then we have a positive match.
|
||||
$controller = $rule['controller'];
|
||||
|
||||
// Time to set the input variables.
|
||||
// We are only going to set them if they don't already exist to avoid overwriting things.
|
||||
foreach ($rule['vars'] as $i => $var)
|
||||
{
|
||||
$this->input->def($var, $matches[$i + 1]);
|
||||
|
||||
// Don't forget to do an explicit set on the GET superglobal.
|
||||
$this->input->get->def($var, $matches[$i + 1]);
|
||||
}
|
||||
|
||||
$this->input->def('_rawRoute', $route);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We were unable to find a route match for the request. Panic.
|
||||
if (!$controller)
|
||||
{
|
||||
throw new InvalidArgumentException(sprintf('Unable to handle request for route `%s`.', $route), 404);
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/application/web/router/index.html
Normal file
1
libraries/joomla/application/web/router/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
142
libraries/joomla/application/web/router/rest.php
Normal file
142
libraries/joomla/application/web/router/rest.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* RESTful Web application router class for the Joomla Platform.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Application
|
||||
* @since 12.2
|
||||
*/
|
||||
class JApplicationWebRouterRest extends JApplicationWebRouterBase
|
||||
{
|
||||
/**
|
||||
* @var boolean A boolean allowing to pass _method as parameter in POST requests
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $methodInPostRequest = false;
|
||||
|
||||
/**
|
||||
* @var array An array of HTTP Method => controller suffix pairs for routing the request.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $suffixMap = array(
|
||||
'GET' => 'Get',
|
||||
'POST' => 'Create',
|
||||
'PUT' => 'Update',
|
||||
'PATCH' => 'Update',
|
||||
'DELETE' => 'Delete',
|
||||
'HEAD' => 'Head',
|
||||
'OPTIONS' => 'Options'
|
||||
);
|
||||
|
||||
/**
|
||||
* Find and execute the appropriate controller based on a given route.
|
||||
*
|
||||
* @param string $route The route string for which to find and execute a controller.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function execute($route)
|
||||
{
|
||||
// Get the controller name based on the route patterns and requested route.
|
||||
$name = $this->parseRoute($route);
|
||||
|
||||
// Append the HTTP method based suffix.
|
||||
$name .= $this->fetchControllerSuffix();
|
||||
|
||||
// Get the controller object by name.
|
||||
$controller = $this->fetchController($name);
|
||||
|
||||
// Execute the controller.
|
||||
$controller->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a controller class suffix for a given HTTP method.
|
||||
*
|
||||
* @param string $method The HTTP method for which to set the class suffix.
|
||||
* @param string $suffix The class suffix to use when fetching the controller name for a given request.
|
||||
*
|
||||
* @return JApplicationWebRouter This object for method chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function setHttpMethodSuffix($method, $suffix)
|
||||
{
|
||||
$this->suffixMap[strtoupper((string) $method)] = (string) $suffix;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to allow or not method in POST request
|
||||
*
|
||||
* @param boolean $value A boolean to allow or not method in POST request
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function setMethodInPostRequest($value)
|
||||
{
|
||||
$this->methodInPostRequest = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property to allow or not method in POST request
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function isMethodInPostRequest()
|
||||
{
|
||||
return $this->methodInPostRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the controller class suffix string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function fetchControllerSuffix()
|
||||
{
|
||||
// Validate that we have a map to handle the given HTTP method.
|
||||
if (!isset($this->suffixMap[$this->input->getMethod()]))
|
||||
{
|
||||
throw new RuntimeException(sprintf('Unable to support the HTTP method `%s`.', $this->input->getMethod()), 404);
|
||||
}
|
||||
|
||||
// Check if request method is POST
|
||||
if ( $this->methodInPostRequest == true && strcmp(strtoupper($this->input->server->getMethod()), 'POST') === 0)
|
||||
{
|
||||
// Get the method from input
|
||||
$postMethod = $this->input->get->getWord('_method');
|
||||
|
||||
// Validate that we have a map to handle the given HTTP method from input
|
||||
if ($postMethod && isset($this->suffixMap[strtoupper($postMethod)]))
|
||||
{
|
||||
return ucfirst($this->suffixMap[strtoupper($postMethod)]);
|
||||
}
|
||||
}
|
||||
|
||||
return ucfirst($this->suffixMap[$this->input->getMethod()]);
|
||||
}
|
||||
}
|
||||
198
libraries/joomla/archive/archive.php
Normal file
198
libraries/joomla/archive/archive.php
Normal file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.filesystem.file');
|
||||
jimport('joomla.filesystem.folder');
|
||||
|
||||
/**
|
||||
* An Archive handling class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 11.1
|
||||
*/
|
||||
class JArchive
|
||||
{
|
||||
/**
|
||||
* @var array The array of instantiated archive adapters.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected static $adapters = array();
|
||||
|
||||
/**
|
||||
* Extract an archive file to a directory.
|
||||
*
|
||||
* @param string $archivename The name of the archive file
|
||||
* @param string $extractdir Directory to unpack into
|
||||
*
|
||||
* @return boolean True for success
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function extract($archivename, $extractdir)
|
||||
{
|
||||
$untar = false;
|
||||
$result = false;
|
||||
$ext = JFile::getExt(strtolower($archivename));
|
||||
|
||||
// Check if a tar is embedded...gzip/bzip2 can just be plain files!
|
||||
if (JFile::getExt(JFile::stripExt(strtolower($archivename))) == 'tar')
|
||||
{
|
||||
$untar = true;
|
||||
}
|
||||
|
||||
switch ($ext)
|
||||
{
|
||||
case 'zip':
|
||||
$adapter = self::getAdapter('zip');
|
||||
|
||||
if ($adapter)
|
||||
{
|
||||
$result = $adapter->extract($archivename, $extractdir);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tar':
|
||||
$adapter = self::getAdapter('tar');
|
||||
|
||||
if ($adapter)
|
||||
{
|
||||
$result = $adapter->extract($archivename, $extractdir);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tgz':
|
||||
// This format is a tarball gzip'd
|
||||
$untar = true;
|
||||
|
||||
case 'gz':
|
||||
case 'gzip':
|
||||
// This may just be an individual file (e.g. sql script)
|
||||
$adapter = self::getAdapter('gzip');
|
||||
|
||||
if ($adapter)
|
||||
{
|
||||
$config = JFactory::getConfig();
|
||||
$tmpfname = $config->get('tmp_path') . '/' . uniqid('gzip');
|
||||
$gzresult = $adapter->extract($archivename, $tmpfname);
|
||||
|
||||
if ($gzresult instanceof Exception)
|
||||
{
|
||||
@unlink($tmpfname);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($untar)
|
||||
{
|
||||
// Try to untar the file
|
||||
$tadapter = self::getAdapter('tar');
|
||||
|
||||
if ($tadapter)
|
||||
{
|
||||
$result = $tadapter->extract($tmpfname, $extractdir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = JPath::clean($extractdir);
|
||||
JFolder::create($path);
|
||||
$result = JFile::copy($tmpfname, $path . '/' . JFile::stripExt(basename(strtolower($archivename))), null, 1);
|
||||
}
|
||||
|
||||
@unlink($tmpfname);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tbz2':
|
||||
// This format is a tarball bzip2'd
|
||||
$untar = true;
|
||||
|
||||
case 'bz2':
|
||||
case 'bzip2':
|
||||
// This may just be an individual file (e.g. sql script)
|
||||
$adapter = self::getAdapter('bzip2');
|
||||
|
||||
if ($adapter)
|
||||
{
|
||||
$config = JFactory::getConfig();
|
||||
$tmpfname = $config->get('tmp_path') . '/' . uniqid('bzip2');
|
||||
$bzresult = $adapter->extract($archivename, $tmpfname);
|
||||
|
||||
if ($bzresult instanceof Exception)
|
||||
{
|
||||
@unlink($tmpfname);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($untar)
|
||||
{
|
||||
// Try to untar the file
|
||||
$tadapter = self::getAdapter('tar');
|
||||
|
||||
if ($tadapter)
|
||||
{
|
||||
$result = $tadapter->extract($tmpfname, $extractdir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = JPath::clean($extractdir);
|
||||
JFolder::create($path);
|
||||
$result = JFile::copy($tmpfname, $path . '/' . JFile::stripExt(basename(strtolower($archivename))), null, 1);
|
||||
}
|
||||
|
||||
@unlink($tmpfname);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unknown Archive Type');
|
||||
}
|
||||
|
||||
if (!$result || $result instanceof Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file compression adapter.
|
||||
*
|
||||
* @param string $type The type of adapter (bzip2|gzip|tar|zip).
|
||||
*
|
||||
* @return JArchiveExtractable Adapter for the requested type
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public static function getAdapter($type)
|
||||
{
|
||||
if (!isset(self::$adapters[$type]))
|
||||
{
|
||||
// Try to load the adapter object
|
||||
$class = 'JArchive' . ucfirst($type);
|
||||
|
||||
if (!class_exists($class))
|
||||
{
|
||||
throw new UnexpectedValueException('Unable to load archive', 500);
|
||||
}
|
||||
|
||||
self::$adapters[$type] = new $class;
|
||||
}
|
||||
|
||||
return self::$adapters[$type];
|
||||
}
|
||||
}
|
||||
181
libraries/joomla/archive/bzip2.php
Normal file
181
libraries/joomla/archive/bzip2.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.filesystem.stream');
|
||||
|
||||
/**
|
||||
* Bzip2 format adapter for the JArchive class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 11.1
|
||||
*/
|
||||
class JArchiveBzip2 implements JArchiveExtractable
|
||||
{
|
||||
/**
|
||||
* Bzip2 file data buffer
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_data = null;
|
||||
|
||||
/**
|
||||
* Extract a Bzip2 compressed file to a given path
|
||||
*
|
||||
* @param string $archive Path to Bzip2 archive to extract
|
||||
* @param string $destination Path to extract archive to
|
||||
* @param array $options Extraction options [unused]
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function extract($archive, $destination, array $options = array ())
|
||||
{
|
||||
$this->_data = null;
|
||||
|
||||
if (!extension_loaded('bz2'))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'The bz2 extension is not available.');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('The bz2 extension is not available.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options['use_streams']) || $options['use_streams'] == false)
|
||||
{
|
||||
// Old style: read the whole file and then parse it
|
||||
$this->_data = file_get_contents($archive);
|
||||
|
||||
if (!$this->_data)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive');
|
||||
}
|
||||
}
|
||||
|
||||
$buffer = bzdecompress($this->_data);
|
||||
unset($this->_data);
|
||||
|
||||
if (empty($buffer))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to decompress data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to decompress data');
|
||||
}
|
||||
}
|
||||
|
||||
if (JFile::write($destination, $buffer) === false)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write archive');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// New style! streams!
|
||||
$input = JFactory::getStream();
|
||||
|
||||
// Use bzip
|
||||
$input->set('processingmethod', 'bz');
|
||||
|
||||
if (!$input->open($archive))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive (bz2)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive (bz2)');
|
||||
}
|
||||
}
|
||||
|
||||
$output = JFactory::getStream();
|
||||
|
||||
if (!$output->open($destination, 'w'))
|
||||
{
|
||||
$input->close();
|
||||
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write archive (bz2)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write archive (bz2)');
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
$this->_data = $input->read($input->get('chunksize', 8196));
|
||||
|
||||
if ($this->_data)
|
||||
{
|
||||
if (!$output->write($this->_data))
|
||||
{
|
||||
$input->close();
|
||||
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write archive (bz2)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write archive (bz2)');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while ($this->_data);
|
||||
|
||||
$output->close();
|
||||
$input->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this adapter can unpack files on this computer.
|
||||
*
|
||||
* @return boolean True if supported
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return extension_loaded('bz2');
|
||||
}
|
||||
}
|
||||
42
libraries/joomla/archive/extractable.php
Normal file
42
libraries/joomla/archive/extractable.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Archieve class interface
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 12.1
|
||||
*/
|
||||
interface JArchiveExtractable
|
||||
{
|
||||
/**
|
||||
* Extract a compressed file to a given path
|
||||
*
|
||||
* @param string $archive Path to archive to extract
|
||||
* @param string $destination Path to extract archive to
|
||||
* @param array $options Extraction options [may be unused]
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function extract($archive, $destination, array $options = array());
|
||||
|
||||
/**
|
||||
* Tests whether this adapter can unpack files on this computer.
|
||||
*
|
||||
* @return boolean True if supported
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported();
|
||||
}
|
||||
247
libraries/joomla/archive/gzip.php
Normal file
247
libraries/joomla/archive/gzip.php
Normal file
@ -0,0 +1,247 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Gzip format adapter for the JArchive class
|
||||
*
|
||||
* This class is inspired from and draws heavily in code and concept from the Compress package of
|
||||
* The Horde Project <http://www.horde.org>
|
||||
*
|
||||
* @contributor Michael Slusarz <slusarz@horde.org>
|
||||
* @contributor Michael Cochrane <mike@graftonhall.co.nz>
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 11.1
|
||||
*/
|
||||
class JArchiveGzip implements JArchiveExtractable
|
||||
{
|
||||
/**
|
||||
* Gzip file flags.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_flags = array('FTEXT' => 0x01, 'FHCRC' => 0x02, 'FEXTRA' => 0x04, 'FNAME' => 0x08, 'FCOMMENT' => 0x10);
|
||||
|
||||
/**
|
||||
* Gzip file data buffer
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_data = null;
|
||||
|
||||
/**
|
||||
* Extract a Gzip compressed file to a given path
|
||||
*
|
||||
* @param string $archive Path to ZIP archive to extract
|
||||
* @param string $destination Path to extract archive to
|
||||
* @param array $options Extraction options [unused]
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function extract($archive, $destination, array $options = array ())
|
||||
{
|
||||
$this->_data = null;
|
||||
|
||||
if (!extension_loaded('zlib'))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'The zlib extension is not available.');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('The zlib extension is not available.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($options['use_streams']) || $options['use_streams'] == false)
|
||||
{
|
||||
$this->_data = file_get_contents($archive);
|
||||
|
||||
if (!$this->_data)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive');
|
||||
}
|
||||
}
|
||||
|
||||
$position = $this->_getFilePosition();
|
||||
$buffer = gzinflate(substr($this->_data, $position, strlen($this->_data) - $position));
|
||||
|
||||
if (empty($buffer))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to decompress data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to decompress data');
|
||||
}
|
||||
}
|
||||
|
||||
if (JFile::write($destination, $buffer) === false)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write archive');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// New style! streams!
|
||||
$input = JFactory::getStream();
|
||||
|
||||
// Use gz
|
||||
$input->set('processingmethod', 'gz');
|
||||
|
||||
if (!$input->open($archive))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive (gz)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive (gz)');
|
||||
}
|
||||
}
|
||||
|
||||
$output = JFactory::getStream();
|
||||
|
||||
if (!$output->open($destination, 'w'))
|
||||
{
|
||||
$input->close();
|
||||
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write archive (gz)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write archive (gz)');
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
$this->_data = $input->read($input->get('chunksize', 8196));
|
||||
|
||||
if ($this->_data)
|
||||
{
|
||||
if (!$output->write($this->_data))
|
||||
{
|
||||
$input->close();
|
||||
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write file (gz)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write file (gz)');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while ($this->_data);
|
||||
|
||||
$output->close();
|
||||
$input->close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this adapter can unpack files on this computer.
|
||||
*
|
||||
* @return boolean True if supported
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return extension_loaded('zlib');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file data offset for archive
|
||||
*
|
||||
* @return integer Data position marker for archive
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function _getFilePosition()
|
||||
{
|
||||
// Gzipped file... unpack it first
|
||||
$position = 0;
|
||||
$info = @ unpack('CCM/CFLG/VTime/CXFL/COS', substr($this->_data, $position + 2));
|
||||
|
||||
if (!$info)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to decompress data.');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to decompress data.');
|
||||
}
|
||||
}
|
||||
|
||||
$position += 10;
|
||||
|
||||
if ($info['FLG'] & $this->_flags['FEXTRA'])
|
||||
{
|
||||
$XLEN = unpack('vLength', substr($this->_data, $position + 0, 2));
|
||||
$XLEN = $XLEN['Length'];
|
||||
$position += $XLEN + 2;
|
||||
}
|
||||
|
||||
if ($info['FLG'] & $this->_flags['FNAME'])
|
||||
{
|
||||
$filenamePos = strpos($this->_data, "\x0", $position);
|
||||
$position = $filenamePos + 1;
|
||||
}
|
||||
|
||||
if ($info['FLG'] & $this->_flags['FCOMMENT'])
|
||||
{
|
||||
$commentPos = strpos($this->_data, "\x0", $position);
|
||||
$position = $commentPos + 1;
|
||||
}
|
||||
|
||||
if ($info['FLG'] & $this->_flags['FHCRC'])
|
||||
{
|
||||
$hcrc = unpack('vCRC', substr($this->_data, $position + 0, 2));
|
||||
$hcrc = $hcrc['CRC'];
|
||||
$position += 2;
|
||||
}
|
||||
|
||||
return $position;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/archive/index.html
Normal file
1
libraries/joomla/archive/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
221
libraries/joomla/archive/tar.php
Normal file
221
libraries/joomla/archive/tar.php
Normal file
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.filesystem.folder');
|
||||
|
||||
/**
|
||||
* Tar format adapter for the JArchive class
|
||||
*
|
||||
* This class is inspired from and draws heavily in code and concept from the Compress package of
|
||||
* The Horde Project <http://www.horde.org>
|
||||
*
|
||||
* @contributor Michael Slusarz <slusarz@horde.org>
|
||||
* @contributor Michael Cochrane <mike@graftonhall.co.nz>
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 11.1
|
||||
*/
|
||||
class JArchiveTar implements JArchiveExtractable
|
||||
{
|
||||
/**
|
||||
* Tar file types.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_types = array(
|
||||
0x0 => 'Unix file',
|
||||
0x30 => 'File',
|
||||
0x31 => 'Link',
|
||||
0x32 => 'Symbolic link',
|
||||
0x33 => 'Character special file',
|
||||
0x34 => 'Block special file',
|
||||
0x35 => 'Directory',
|
||||
0x36 => 'FIFO special file',
|
||||
0x37 => 'Contiguous file');
|
||||
|
||||
/**
|
||||
* Tar file data buffer
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_data = null;
|
||||
|
||||
/**
|
||||
* Tar file metadata array
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_metadata = null;
|
||||
|
||||
/**
|
||||
* Extract a ZIP compressed file to a given path
|
||||
*
|
||||
* @param string $archive Path to ZIP archive to extract
|
||||
* @param string $destination Path to extract archive into
|
||||
* @param array $options Extraction options [unused]
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @since 11.1
|
||||
*/
|
||||
public function extract($archive, $destination, array $options = array())
|
||||
{
|
||||
$this->_data = null;
|
||||
$this->_metadata = null;
|
||||
|
||||
$this->_data = file_get_contents($archive);
|
||||
|
||||
if (!$this->_data)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive');
|
||||
}
|
||||
}
|
||||
|
||||
$this->_getTarInfo($this->_data);
|
||||
|
||||
for ($i = 0, $n = count($this->_metadata); $i < $n; $i++)
|
||||
{
|
||||
$type = strtolower($this->_metadata[$i]['type']);
|
||||
|
||||
if ($type == 'file' || $type == 'unix file')
|
||||
{
|
||||
$buffer = $this->_metadata[$i]['data'];
|
||||
$path = JPath::clean($destination . '/' . $this->_metadata[$i]['name']);
|
||||
|
||||
// Make sure the destination folder exists
|
||||
if (!JFolder::create(dirname($path)))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to create destination');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to create destination');
|
||||
}
|
||||
}
|
||||
if (JFile::write($path, $buffer) === false)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write entry');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write entry');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this adapter can unpack files on this computer.
|
||||
*
|
||||
* @return boolean True if supported
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of files/data from a Tar archive buffer.
|
||||
*
|
||||
* @param string &$data The Tar archive buffer.
|
||||
*
|
||||
* @return array Archive metadata array
|
||||
* <pre>
|
||||
* KEY: Position in the array
|
||||
* VALUES: 'attr' -- File attributes
|
||||
* 'data' -- Raw file contents
|
||||
* 'date' -- File modification time
|
||||
* 'name' -- Filename
|
||||
* 'size' -- Original file size
|
||||
* 'type' -- File type
|
||||
* </pre>
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _getTarInfo(& $data)
|
||||
{
|
||||
$position = 0;
|
||||
$return_array = array();
|
||||
|
||||
while ($position < strlen($data))
|
||||
{
|
||||
$info = @unpack(
|
||||
"a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/Ctypeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor",
|
||||
substr($data, $position)
|
||||
);
|
||||
|
||||
if (!$info)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to decompress data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to decompress data');
|
||||
}
|
||||
}
|
||||
|
||||
$position += 512;
|
||||
$contents = substr($data, $position, octdec($info['size']));
|
||||
$position += ceil(octdec($info['size']) / 512) * 512;
|
||||
|
||||
if ($info['filename'])
|
||||
{
|
||||
$file = array(
|
||||
'attr' => null,
|
||||
'data' => null,
|
||||
'date' => octdec($info['mtime']),
|
||||
'name' => trim($info['filename']),
|
||||
'size' => octdec($info['size']),
|
||||
'type' => isset($this->_types[$info['typeflag']]) ? $this->_types[$info['typeflag']] : null);
|
||||
|
||||
if (($info['typeflag'] == 0) || ($info['typeflag'] == 0x30) || ($info['typeflag'] == 0x35))
|
||||
{
|
||||
/* File or folder. */
|
||||
$file['data'] = $contents;
|
||||
|
||||
$mode = hexdec(substr($info['mode'], 4, 3));
|
||||
$file['attr'] = (($info['typeflag'] == 0x35) ? 'd' : '-') . (($mode & 0x400) ? 'r' : '-') . (($mode & 0x200) ? 'w' : '-') .
|
||||
(($mode & 0x100) ? 'x' : '-') . (($mode & 0x040) ? 'r' : '-') . (($mode & 0x020) ? 'w' : '-') . (($mode & 0x010) ? 'x' : '-') .
|
||||
(($mode & 0x004) ? 'r' : '-') . (($mode & 0x002) ? 'w' : '-') . (($mode & 0x001) ? 'x' : '-');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some other type. */
|
||||
}
|
||||
$return_array[] = $file;
|
||||
}
|
||||
}
|
||||
$this->_metadata = $return_array;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
717
libraries/joomla/archive/zip.php
Normal file
717
libraries/joomla/archive/zip.php
Normal file
@ -0,0 +1,717 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
jimport('joomla.filesystem.folder');
|
||||
|
||||
/**
|
||||
* ZIP format adapter for the JArchive class
|
||||
*
|
||||
* The ZIP compression code is partially based on code from:
|
||||
* Eric Mueller <eric@themepark.com>
|
||||
* http://www.zend.com/codex.php?id=535&single=1
|
||||
*
|
||||
* Deins125 <webmaster@atlant.ru>
|
||||
* http://www.zend.com/codex.php?id=470&single=1
|
||||
*
|
||||
* The ZIP compression date code is partially based on code from
|
||||
* Peter Listiak <mlady@users.sourceforge.net>
|
||||
*
|
||||
* This class is inspired from and draws heavily in code and concept from the Compress package of
|
||||
* The Horde Project <http://www.horde.org>
|
||||
*
|
||||
* @contributor Chuck Hagenbuch <chuck@horde.org>
|
||||
* @contributor Michael Slusarz <slusarz@horde.org>
|
||||
* @contributor Michael Cochrane <mike@graftonhall.co.nz>
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Archive
|
||||
* @since 11.1
|
||||
*/
|
||||
class JArchiveZip implements JArchiveExtractable
|
||||
{
|
||||
/**
|
||||
* ZIP compression methods.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_methods = array(0x0 => 'None', 0x1 => 'Shrunk', 0x2 => 'Super Fast', 0x3 => 'Fast', 0x4 => 'Normal', 0x5 => 'Maximum', 0x6 => 'Imploded',
|
||||
0x8 => 'Deflated');
|
||||
|
||||
/**
|
||||
* Beginning of central directory record.
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_ctrlDirHeader = "\x50\x4b\x01\x02";
|
||||
|
||||
/**
|
||||
* End of central directory record.
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_ctrlDirEnd = "\x50\x4b\x05\x06\x00\x00\x00\x00";
|
||||
|
||||
/**
|
||||
* Beginning of file contents.
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_fileHeader = "\x50\x4b\x03\x04";
|
||||
|
||||
/**
|
||||
* ZIP file data buffer
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_data = null;
|
||||
|
||||
/**
|
||||
* ZIP file metadata array
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
private $_metadata = null;
|
||||
|
||||
/**
|
||||
* Create a ZIP compressed file from an array of file data.
|
||||
*
|
||||
* @param string $archive Path to save archive.
|
||||
* @param array $files Array of files to add to archive.
|
||||
*
|
||||
* @return boolean True if successful.
|
||||
*
|
||||
* @since 11.1
|
||||
*
|
||||
* @todo Finish Implementation
|
||||
*/
|
||||
public function create($archive, $files)
|
||||
{
|
||||
$contents = array();
|
||||
$ctrldir = array();
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$this->_addToZIPFile($file, $contents, $ctrldir);
|
||||
}
|
||||
|
||||
return $this->_createZIPFile($contents, $ctrldir, $archive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a ZIP compressed file to a given path
|
||||
*
|
||||
* @param string $archive Path to ZIP archive to extract
|
||||
* @param string $destination Path to extract archive into
|
||||
* @param array $options Extraction options [unused]
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function extract($archive, $destination, array $options = array())
|
||||
{
|
||||
if (!is_file($archive))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Archive does not exist');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Archive does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->hasNativeSupport())
|
||||
{
|
||||
return $this->extractNative($archive, $destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->extractCustom($archive, $destination);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this adapter can unpack files on this computer.
|
||||
*
|
||||
* @return boolean True if supported
|
||||
*
|
||||
* @since 11.3
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return (self::hasNativeSupport() || extension_loaded('zlib'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if the server has native zip support for faster handling
|
||||
*
|
||||
* @return boolean True if php has native ZIP support
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function hasNativeSupport()
|
||||
{
|
||||
return (function_exists('zip_open') && function_exists('zip_read'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the data is a valid ZIP file.
|
||||
*
|
||||
* @param string &$data ZIP archive data buffer.
|
||||
*
|
||||
* @return boolean True if valid, false if invalid.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function checkZipData(&$data)
|
||||
{
|
||||
if (strpos($data, $this->_fileHeader) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a ZIP compressed file to a given path using a php based algorithm that only requires zlib support
|
||||
*
|
||||
* @param string $archive Path to ZIP archive to extract.
|
||||
* @param string $destination Path to extract archive into.
|
||||
*
|
||||
* @return mixed True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function extractCustom($archive, $destination)
|
||||
{
|
||||
$this->_data = null;
|
||||
$this->_metadata = null;
|
||||
|
||||
if (!extension_loaded('zlib'))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Zlib not supported');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Zlib not supported');
|
||||
}
|
||||
}
|
||||
|
||||
$this->_data = file_get_contents($archive);
|
||||
|
||||
if (!$this->_data)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read archive (zip)');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read archive (zip)');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_readZipInfo($this->_data))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Get ZIP Information failed');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Get ZIP Information failed');
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0, $n = count($this->_metadata); $i < $n; $i++)
|
||||
{
|
||||
$lastPathCharacter = substr($this->_metadata[$i]['name'], -1, 1);
|
||||
|
||||
if ($lastPathCharacter !== '/' && $lastPathCharacter !== '\\')
|
||||
{
|
||||
$buffer = $this->_getFileData($i);
|
||||
$path = JPath::clean($destination . '/' . $this->_metadata[$i]['name']);
|
||||
|
||||
// Make sure the destination folder exists
|
||||
if (!JFolder::create(dirname($path)))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to create destination');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to create destination');
|
||||
}
|
||||
}
|
||||
|
||||
if (JFile::write($path, $buffer) === false)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write entry');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write entry');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a ZIP compressed file to a given path using native php api calls for speed
|
||||
*
|
||||
* @param string $archive Path to ZIP archive to extract
|
||||
* @param string $destination Path to extract archive into
|
||||
*
|
||||
* @return boolean True on success
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function extractNative($archive, $destination)
|
||||
{
|
||||
$zip = zip_open($archive);
|
||||
|
||||
if (is_resource($zip))
|
||||
{
|
||||
// Make sure the destination folder exists
|
||||
if (!JFolder::create($destination))
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to create destination');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to create destination');
|
||||
}
|
||||
}
|
||||
|
||||
// Read files in the archive
|
||||
while ($file = @zip_read($zip))
|
||||
{
|
||||
if (zip_entry_open($zip, $file, "r"))
|
||||
{
|
||||
if (substr(zip_entry_name($file), strlen(zip_entry_name($file)) - 1) != "/")
|
||||
{
|
||||
$buffer = zip_entry_read($file, zip_entry_filesize($file));
|
||||
|
||||
if (JFile::write($destination . '/' . zip_entry_name($file), $buffer) === false)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to write entry');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to write entry');
|
||||
}
|
||||
}
|
||||
|
||||
zip_entry_close($file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to read entry');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to read entry');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@zip_close($zip);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Unable to open archive');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to open archive');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of files/data from a ZIP archive buffer.
|
||||
*
|
||||
* <pre>
|
||||
* KEY: Position in zipfile
|
||||
* VALUES: 'attr' -- File attributes
|
||||
* 'crc' -- CRC checksum
|
||||
* 'csize' -- Compressed file size
|
||||
* 'date' -- File modification time
|
||||
* 'name' -- Filename
|
||||
* 'method'-- Compression method
|
||||
* 'size' -- Original file size
|
||||
* 'type' -- File type
|
||||
* </pre>
|
||||
*
|
||||
* @param string &$data The ZIP archive buffer.
|
||||
*
|
||||
* @return boolean True on success
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function _readZipInfo(&$data)
|
||||
{
|
||||
$entries = array();
|
||||
|
||||
// Find the last central directory header entry
|
||||
$fhLast = strpos($data, $this->_ctrlDirEnd);
|
||||
|
||||
do
|
||||
{
|
||||
$last = $fhLast;
|
||||
}
|
||||
while (($fhLast = strpos($data, $this->_ctrlDirEnd, $fhLast + 1)) !== false);
|
||||
|
||||
// Find the central directory offset
|
||||
$offset = 0;
|
||||
|
||||
if ($last)
|
||||
{
|
||||
$endOfCentralDirectory = unpack(
|
||||
'vNumberOfDisk/vNoOfDiskWithStartOfCentralDirectory/vNoOfCentralDirectoryEntriesOnDisk/' .
|
||||
'vTotalCentralDirectoryEntries/VSizeOfCentralDirectory/VCentralDirectoryOffset/vCommentLength',
|
||||
substr($data, $last + 4)
|
||||
);
|
||||
$offset = $endOfCentralDirectory['CentralDirectoryOffset'];
|
||||
}
|
||||
|
||||
// Get details from central directory structure.
|
||||
$fhStart = strpos($data, $this->_ctrlDirHeader, $offset);
|
||||
$dataLength = strlen($data);
|
||||
|
||||
do
|
||||
{
|
||||
if ($dataLength < $fhStart + 31)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Invalid Zip Data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Invalid Zip Data');
|
||||
}
|
||||
}
|
||||
|
||||
$info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength', substr($data, $fhStart + 10, 20));
|
||||
$name = substr($data, $fhStart + 46, $info['Length']);
|
||||
|
||||
$entries[$name] = array(
|
||||
'attr' => null,
|
||||
'crc' => sprintf("%08s", dechex($info['CRC32'])),
|
||||
'csize' => $info['Compressed'],
|
||||
'date' => null,
|
||||
'_dataStart' => null,
|
||||
'name' => $name,
|
||||
'method' => $this->_methods[$info['Method']],
|
||||
'_method' => $info['Method'],
|
||||
'size' => $info['Uncompressed'],
|
||||
'type' => null
|
||||
);
|
||||
|
||||
$entries[$name]['date'] = mktime(
|
||||
(($info['Time'] >> 11) & 0x1f),
|
||||
(($info['Time'] >> 5) & 0x3f),
|
||||
(($info['Time'] << 1) & 0x3e),
|
||||
(($info['Time'] >> 21) & 0x07),
|
||||
(($info['Time'] >> 16) & 0x1f),
|
||||
((($info['Time'] >> 25) & 0x7f) + 1980)
|
||||
);
|
||||
|
||||
if ($dataLength < $fhStart + 43)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Invalid ZIP data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Invalid ZIP data');
|
||||
}
|
||||
}
|
||||
|
||||
$info = unpack('vInternal/VExternal/VOffset', substr($data, $fhStart + 36, 10));
|
||||
|
||||
$entries[$name]['type'] = ($info['Internal'] & 0x01) ? 'text' : 'binary';
|
||||
$entries[$name]['attr'] = (($info['External'] & 0x10) ? 'D' : '-') . (($info['External'] & 0x20) ? 'A' : '-')
|
||||
. (($info['External'] & 0x03) ? 'S' : '-') . (($info['External'] & 0x02) ? 'H' : '-') . (($info['External'] & 0x01) ? 'R' : '-');
|
||||
$entries[$name]['offset'] = $info['Offset'];
|
||||
|
||||
// Get details from local file header since we have the offset
|
||||
$lfhStart = strpos($data, $this->_fileHeader, $entries[$name]['offset']);
|
||||
|
||||
if ($dataLength < $lfhStart + 34)
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
return JError::raiseWarning(100, 'Invalid Zip Data');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Invalid Zip Data');
|
||||
}
|
||||
}
|
||||
|
||||
$info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength/vExtraLength', substr($data, $lfhStart + 8, 25));
|
||||
$name = substr($data, $lfhStart + 30, $info['Length']);
|
||||
$entries[$name]['_dataStart'] = $lfhStart + 30 + $info['Length'] + $info['ExtraLength'];
|
||||
|
||||
// Bump the max execution time because not using the built in php zip libs makes this process slow.
|
||||
@set_time_limit(ini_get('max_execution_time'));
|
||||
}
|
||||
while ((($fhStart = strpos($data, $this->_ctrlDirHeader, $fhStart + 46)) !== false));
|
||||
|
||||
$this->_metadata = array_values($entries);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file data for a file by offsest in the ZIP archive
|
||||
*
|
||||
* @param integer $key The position of the file in the archive.
|
||||
*
|
||||
* @return string Uncompressed file data buffer.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
private function _getFileData($key)
|
||||
{
|
||||
if ($this->_metadata[$key]['_method'] == 0x8)
|
||||
{
|
||||
return gzinflate(substr($this->_data, $this->_metadata[$key]['_dataStart'], $this->_metadata[$key]['csize']));
|
||||
}
|
||||
elseif ($this->_metadata[$key]['_method'] == 0x0)
|
||||
{
|
||||
/* Files that aren't compressed. */
|
||||
return substr($this->_data, $this->_metadata[$key]['_dataStart'], $this->_metadata[$key]['csize']);
|
||||
}
|
||||
elseif ($this->_metadata[$key]['_method'] == 0x12)
|
||||
{
|
||||
// If bz2 extension is loaded use it
|
||||
if (extension_loaded('bz2'))
|
||||
{
|
||||
return bzdecompress(substr($this->_data, $this->_metadata[$key]['_dataStart'], $this->_metadata[$key]['csize']));
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a UNIX timestamp to a 4-byte DOS date and time format
|
||||
* (date in high 2-bytes, time in low 2-bytes allowing magnitude
|
||||
* comparison).
|
||||
*
|
||||
* @param int $unixtime The current UNIX timestamp.
|
||||
*
|
||||
* @return int The current date in a 4-byte DOS format.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _unix2DOSTime($unixtime = null)
|
||||
{
|
||||
$timearray = (is_null($unixtime)) ? getdate() : getdate($unixtime);
|
||||
|
||||
if ($timearray['year'] < 1980)
|
||||
{
|
||||
$timearray['year'] = 1980;
|
||||
$timearray['mon'] = 1;
|
||||
$timearray['mday'] = 1;
|
||||
$timearray['hours'] = 0;
|
||||
$timearray['minutes'] = 0;
|
||||
$timearray['seconds'] = 0;
|
||||
}
|
||||
|
||||
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) |
|
||||
($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "file" to the ZIP archive.
|
||||
*
|
||||
* @param array &$file File data array to add
|
||||
* @param array &$contents An array of existing zipped files.
|
||||
* @param array &$ctrldir An array of central directory information.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*
|
||||
* @todo Review and finish implementation
|
||||
*/
|
||||
private function _addToZIPFile(array &$file, array &$contents, array &$ctrldir)
|
||||
{
|
||||
$data = &$file['data'];
|
||||
$name = str_replace('\\', '/', $file['name']);
|
||||
|
||||
/* See if time/date information has been provided. */
|
||||
$ftime = null;
|
||||
|
||||
if (isset($file['time']))
|
||||
{
|
||||
$ftime = $file['time'];
|
||||
}
|
||||
|
||||
// Get the hex time.
|
||||
$dtime = dechex($this->_unix2DosTime($ftime));
|
||||
$hexdtime = chr(hexdec($dtime[6] . $dtime[7])) . chr(hexdec($dtime[4] . $dtime[5])) . chr(hexdec($dtime[2] . $dtime[3]))
|
||||
. chr(hexdec($dtime[0] . $dtime[1]));
|
||||
|
||||
/* Begin creating the ZIP data. */
|
||||
$fr = $this->_fileHeader;
|
||||
/* Version needed to extract. */
|
||||
$fr .= "\x14\x00";
|
||||
/* General purpose bit flag. */
|
||||
$fr .= "\x00\x00";
|
||||
/* Compression method. */
|
||||
$fr .= "\x08\x00";
|
||||
/* Last modification time/date. */
|
||||
$fr .= $hexdtime;
|
||||
|
||||
/* "Local file header" segment. */
|
||||
$unc_len = strlen($data);
|
||||
$crc = crc32($data);
|
||||
$zdata = gzcompress($data);
|
||||
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
|
||||
$c_len = strlen($zdata);
|
||||
|
||||
/* CRC 32 information. */
|
||||
$fr .= pack('V', $crc);
|
||||
/* Compressed filesize. */
|
||||
$fr .= pack('V', $c_len);
|
||||
/* Uncompressed filesize. */
|
||||
$fr .= pack('V', $unc_len);
|
||||
/* Length of filename. */
|
||||
$fr .= pack('v', strlen($name));
|
||||
/* Extra field length. */
|
||||
$fr .= pack('v', 0);
|
||||
/* File name. */
|
||||
$fr .= $name;
|
||||
|
||||
/* "File data" segment. */
|
||||
$fr .= $zdata;
|
||||
|
||||
/* Add this entry to array. */
|
||||
$old_offset = strlen(implode('', $contents));
|
||||
$contents[] = &$fr;
|
||||
|
||||
/* Add to central directory record. */
|
||||
$cdrec = $this->_ctrlDirHeader;
|
||||
/* Version made by. */
|
||||
$cdrec .= "\x00\x00";
|
||||
/* Version needed to extract */
|
||||
$cdrec .= "\x14\x00";
|
||||
/* General purpose bit flag */
|
||||
$cdrec .= "\x00\x00";
|
||||
/* Compression method */
|
||||
$cdrec .= "\x08\x00";
|
||||
/* Last mod time/date. */
|
||||
$cdrec .= $hexdtime;
|
||||
/* CRC 32 information. */
|
||||
$cdrec .= pack('V', $crc);
|
||||
/* Compressed filesize. */
|
||||
$cdrec .= pack('V', $c_len);
|
||||
/* Uncompressed filesize. */
|
||||
$cdrec .= pack('V', $unc_len);
|
||||
/* Length of filename. */
|
||||
$cdrec .= pack('v', strlen($name));
|
||||
/* Extra field length. */
|
||||
$cdrec .= pack('v', 0);
|
||||
/* File comment length. */
|
||||
$cdrec .= pack('v', 0);
|
||||
/* Disk number start. */
|
||||
$cdrec .= pack('v', 0);
|
||||
/* Internal file attributes. */
|
||||
$cdrec .= pack('v', 0);
|
||||
/* External file attributes -'archive' bit set. */
|
||||
$cdrec .= pack('V', 32);
|
||||
/* Relative offset of local header. */
|
||||
$cdrec .= pack('V', $old_offset);
|
||||
/* File name. */
|
||||
$cdrec .= $name;
|
||||
/* Optional extra field, file comment goes here. */
|
||||
|
||||
/* Save to central directory array. */
|
||||
$ctrldir[] = &$cdrec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the ZIP file.
|
||||
*
|
||||
* Official ZIP file format: http://www.pkware.com/appnote.txt
|
||||
*
|
||||
* @param array &$contents An array of existing zipped files.
|
||||
* @param array &$ctrlDir An array of central directory information.
|
||||
* @param string $path The path to store the archive.
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
*
|
||||
* @todo Review and finish implementation
|
||||
*/
|
||||
private function _createZIPFile(array &$contents, array &$ctrlDir, $path)
|
||||
{
|
||||
$data = implode('', $contents);
|
||||
$dir = implode('', $ctrlDir);
|
||||
|
||||
$buffer = $data . $dir . $this->_ctrlDirEnd . /* Total # of entries "on this disk". */
|
||||
pack('v', count($ctrlDir)) . /* Total # of entries overall. */
|
||||
pack('v', count($ctrlDir)) . /* Size of central directory. */
|
||||
pack('V', strlen($dir)) . /* Offset to start of central dir. */
|
||||
pack('V', strlen($data)) . /* ZIP file comment length. */
|
||||
"\x00\x00";
|
||||
|
||||
if (JFile::write($path, $buffer) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
libraries/joomla/base/adapter.php
Normal file
196
libraries/joomla/base/adapter.php
Normal file
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Base
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Adapter Class
|
||||
* Retains common adapter pattern functions
|
||||
* Class harvested from joomla.installer.installer
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Base
|
||||
* @since 11.1
|
||||
*/
|
||||
class JAdapter extends JObject
|
||||
{
|
||||
/**
|
||||
* Associative array of adapters
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_adapters = array();
|
||||
|
||||
/**
|
||||
* Adapter Folder
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_adapterfolder = 'adapters';
|
||||
|
||||
/**
|
||||
* @var string Adapter Class Prefix
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_classprefix = 'J';
|
||||
|
||||
/**
|
||||
* Base Path for the adapter instance
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_basepath = null;
|
||||
|
||||
/**
|
||||
* Database Connector Object
|
||||
*
|
||||
* @var JDatabaseDriver
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_db;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $basepath Base Path of the adapters
|
||||
* @param string $classprefix Class prefix of adapters
|
||||
* @param string $adapterfolder Name of folder to append to base path
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($basepath, $classprefix = null, $adapterfolder = null)
|
||||
{
|
||||
$this->_basepath = $basepath;
|
||||
$this->_classprefix = $classprefix ? $classprefix : 'J';
|
||||
$this->_adapterfolder = $adapterfolder ? $adapterfolder : 'adapters';
|
||||
|
||||
$this->_db = JFactory::getDbo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database connector object
|
||||
*
|
||||
* @return JDatabaseDriver Database connector object
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getDBO()
|
||||
{
|
||||
return $this->_db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an adapter by name
|
||||
*
|
||||
* @param string $name Adapter name
|
||||
* @param object &$adapter Adapter object
|
||||
* @param array $options Adapter options
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setAdapter($name, &$adapter = null, $options = array())
|
||||
{
|
||||
if (!is_object($adapter))
|
||||
{
|
||||
$fullpath = $this->_basepath . '/' . $this->_adapterfolder . '/' . strtolower($name) . '.php';
|
||||
|
||||
if (!file_exists($fullpath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to load the adapter object
|
||||
require_once $fullpath;
|
||||
|
||||
$class = $this->_classprefix . ucfirst($name);
|
||||
|
||||
if (!class_exists($class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$adapter = new $class($this, $this->_db, $options);
|
||||
}
|
||||
|
||||
$this->_adapters[$name] = &$adapter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an adapter.
|
||||
*
|
||||
* @param string $name Name of adapter to return
|
||||
* @param array $options Adapter options
|
||||
*
|
||||
* @return object Adapter of type 'name' or false
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAdapter($name, $options = array())
|
||||
{
|
||||
if (!array_key_exists($name, $this->_adapters))
|
||||
{
|
||||
if (!$this->setAdapter($name, $options))
|
||||
{
|
||||
$false = false;
|
||||
|
||||
return $false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_adapters[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all adapters.
|
||||
*
|
||||
* @param array $options Adapter options
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function loadAllAdapters($options = array())
|
||||
{
|
||||
$files = new DirectoryIterator($this->_basepath . '/' . $this->_adapterfolder);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$fileName = $file->getFilename();
|
||||
|
||||
// Only load for php files.
|
||||
// Note: DirectoryIterator::getExtension only available PHP >= 5.3.6
|
||||
if (!$file->isFile() || substr($fileName, strrpos($fileName, '.') + 1) != 'php')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to load the adapter object
|
||||
require_once $this->_basepath . '/' . $this->_adapterfolder . '/' . $fileName;
|
||||
|
||||
// Derive the class name from the filename.
|
||||
$name = str_ireplace('.php', '', ucfirst(trim($fileName)));
|
||||
$class = $this->_classprefix . ucfirst($name);
|
||||
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// Skip to next one
|
||||
continue;
|
||||
}
|
||||
|
||||
$adapter = new $class($this, $this->_db, $options);
|
||||
$this->_adapters[$name] = clone $adapter;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
libraries/joomla/base/adapterinstance.php
Normal file
69
libraries/joomla/base/adapterinstance.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Base
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Adapter Instance Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Base
|
||||
* @since 11.1
|
||||
*/
|
||||
class JAdapterInstance extends JObject
|
||||
{
|
||||
/**
|
||||
* Parent
|
||||
*
|
||||
* @var JAdapter
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $parent = null;
|
||||
|
||||
/**
|
||||
* Database
|
||||
*
|
||||
* @var JDatabaseDriver
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $db = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param JAdapter $parent Parent object
|
||||
* @param JDatabaseDriver $db Database object
|
||||
* @param array $options Configuration Options
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct(JAdapter $parent, JDatabaseDriver $db, array $options = array())
|
||||
{
|
||||
// Set the properties from the options array that is passed in
|
||||
$this->setProperties($options);
|
||||
|
||||
// Set the parent and db in case $options for some reason overrides it.
|
||||
$this->parent = $parent;
|
||||
|
||||
// Pull in the global dbo in case something happened to it.
|
||||
$this->db = $db ?: JFactory::getDbo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the parent object
|
||||
*
|
||||
* @return JAdapter parent
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/base/index.html
Normal file
1
libraries/joomla/base/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
726
libraries/joomla/cache/cache.php
vendored
Normal file
726
libraries/joomla/cache/cache.php
vendored
Normal file
@ -0,0 +1,726 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla! Cache base object
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCache
|
||||
{
|
||||
/**
|
||||
* @var object Storage handler
|
||||
* @since 11.1
|
||||
*/
|
||||
public static $_handler = array();
|
||||
|
||||
/**
|
||||
* @var array Options
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options options
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
$conf = JFactory::getConfig();
|
||||
|
||||
$this->_options = array(
|
||||
'cachebase' => $conf->get('cache_path', JPATH_CACHE),
|
||||
'lifetime' => (int) $conf->get('cachetime'),
|
||||
'language' => $conf->get('language', 'en-GB'),
|
||||
'storage' => $conf->get('cache_handler', ''),
|
||||
'defaultgroup' => 'default',
|
||||
'locking' => true,
|
||||
'locktime' => 15,
|
||||
'checkTime' => true,
|
||||
'caching' => ($conf->get('caching') >= 1) ? true : false);
|
||||
|
||||
// Overwrite default options with given options
|
||||
foreach ($options as $option => $value)
|
||||
{
|
||||
if (isset($options[$option]) && $options[$option] !== '')
|
||||
{
|
||||
$this->_options[$option] = $options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->_options['storage']))
|
||||
{
|
||||
$this->_options['caching'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a cache adapter object, always creating it
|
||||
*
|
||||
* @param string $type The cache object type to instantiate
|
||||
* @param array $options The array of options
|
||||
*
|
||||
* @return JCache A JCache object
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getInstance($type = 'output', $options = array())
|
||||
{
|
||||
return JCacheController::getInstance($type, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the storage handlers
|
||||
*
|
||||
* @return array An array of available storage handlers
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getStores()
|
||||
{
|
||||
$handlers = array();
|
||||
|
||||
// Get an iterator and loop trough the driver classes.
|
||||
$iterator = new DirectoryIterator(__DIR__ . '/storage');
|
||||
|
||||
foreach ($iterator as $file)
|
||||
{
|
||||
$fileName = $file->getFilename();
|
||||
|
||||
// Only load for php files.
|
||||
// Note: DirectoryIterator::getExtension only available PHP >= 5.3.6
|
||||
if (!$file->isFile()
|
||||
|| substr($fileName, strrpos($fileName, '.') + 1) != 'php'
|
||||
|| $fileName == 'helper.php')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive the class name from the type.
|
||||
$class = str_ireplace('.php', '', 'JCacheStorage' . ucfirst(trim($fileName)));
|
||||
|
||||
// If the class doesn't exist we have nothing left to do but look at the next type. We did our best.
|
||||
if (!class_exists($class))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sweet! Our class exists, so now we just need to know if it passes its test method.
|
||||
if ($class::isSupported())
|
||||
{
|
||||
// Connector names should not have file extensions.
|
||||
$handlers[] = str_ireplace('.php', '', $fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set caching enabled state
|
||||
*
|
||||
* @param boolean $enabled True to enable caching
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setCaching($enabled)
|
||||
{
|
||||
$this->_options['caching'] = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get caching state
|
||||
*
|
||||
* @return boolean Caching state
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getCaching()
|
||||
{
|
||||
return $this->_options['caching'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache lifetime
|
||||
*
|
||||
* @param integer $lt Cache lifetime
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setLifeTime($lt)
|
||||
{
|
||||
$this->_options['lifetime'] = $lt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return mixed boolean False on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group = null)
|
||||
{
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Get the storage
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception) && $this->_options['caching'])
|
||||
{
|
||||
return $handler->get($id, $group, $this->_options['checkTime']);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all cached data
|
||||
*
|
||||
* @return mixed Boolean false on failure or an object with a list of cache groups and data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
// Get the storage
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception) && $this->_options['caching'])
|
||||
{
|
||||
return $handler->getAll();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the cached data by id and group
|
||||
*
|
||||
* @param mixed $data The data to store
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True if cache stored
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($data, $id, $group = null)
|
||||
{
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Get the storage and store the cached data
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception) && $this->_options['caching'])
|
||||
{
|
||||
$handler->_lifetime = $this->_options['lifetime'];
|
||||
return $handler->store($id, $group, $data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group = null)
|
||||
{
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Get the storage
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception))
|
||||
{
|
||||
return $handler->remove($id, $group);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group = null, $mode = 'group')
|
||||
{
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Get the storage handler
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception))
|
||||
{
|
||||
return $handler->clean($group, $mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collect expired cache data
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
// Get the storage handler
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception))
|
||||
{
|
||||
return $handler->gc();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lock flag on cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $locktime The default locktime for locking the cache.
|
||||
*
|
||||
* @return object Properties are lock and locklooped
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function lock($id, $group = null, $locktime = null)
|
||||
{
|
||||
$returning = new stdClass;
|
||||
$returning->locklooped = false;
|
||||
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Get the default locktime
|
||||
$locktime = ($locktime) ? $locktime : $this->_options['locktime'];
|
||||
|
||||
// Allow storage handlers to perform locking on their own
|
||||
// NOTE drivers with lock need also unlock or unlocking will fail because of false $id
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception) && $this->_options['locking'] == true && $this->_options['caching'] == true)
|
||||
{
|
||||
$locked = $handler->lock($id, $group, $locktime);
|
||||
if ($locked !== false)
|
||||
{
|
||||
return $locked;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
$curentlifetime = $this->_options['lifetime'];
|
||||
|
||||
// Set lifetime to locktime for storing in children
|
||||
$this->_options['lifetime'] = $locktime;
|
||||
|
||||
$looptime = $locktime * 10;
|
||||
$id2 = $id . '_lock';
|
||||
|
||||
if ($this->_options['locking'] == true && $this->_options['caching'] == true)
|
||||
{
|
||||
$data_lock = $this->get($id2, $group);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$data_lock = false;
|
||||
$returning->locked = false;
|
||||
}
|
||||
|
||||
if ($data_lock !== false)
|
||||
{
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released.
|
||||
// That implies that data get from other thread has finished
|
||||
while ($data_lock !== false)
|
||||
{
|
||||
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
$returning->locked = false;
|
||||
$returning->locklooped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = $this->get($id2, $group);
|
||||
$lock_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_options['locking'] == true && $this->_options['caching'] == true)
|
||||
{
|
||||
$returning->locked = $this->store(1, $id2, $group);
|
||||
}
|
||||
|
||||
// Revert lifetime to previous one
|
||||
$this->_options['lifetime'] = $curentlifetime;
|
||||
|
||||
return $returning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset lock flag on cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
$unlock = false;
|
||||
|
||||
// Get the default group
|
||||
$group = ($group) ? $group : $this->_options['defaultgroup'];
|
||||
|
||||
// Allow handlers to perform unlocking on their own
|
||||
$handler = $this->_getStorage();
|
||||
if (!($handler instanceof Exception) && $this->_options['caching'])
|
||||
{
|
||||
$unlocked = $handler->unlock($id, $group);
|
||||
if ($unlocked !== false)
|
||||
{
|
||||
return $unlocked;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if ($this->_options['caching'])
|
||||
{
|
||||
$unlock = $this->remove($id . '_lock', $group);
|
||||
}
|
||||
|
||||
return $unlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache storage handler
|
||||
*
|
||||
* @return JCacheStorage A JCacheStorage object
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function &_getStorage()
|
||||
{
|
||||
$hash = md5(serialize($this->_options));
|
||||
|
||||
if (isset(self::$_handler[$hash]))
|
||||
{
|
||||
return self::$_handler[$hash];
|
||||
}
|
||||
|
||||
self::$_handler[$hash] = JCacheStorage::getInstance($this->_options['storage'], $this->_options);
|
||||
return self::$_handler[$hash];
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform workarounds on retrieved cached data
|
||||
*
|
||||
* @param string $data Cached data
|
||||
* @param array $options Array of options
|
||||
*
|
||||
* @return string Body of cached data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getWorkarounds($data, $options = array())
|
||||
{
|
||||
$app = JFactory::getApplication();
|
||||
$document = JFactory::getDocument();
|
||||
$body = null;
|
||||
|
||||
// Get the document head out of the cache.
|
||||
if (isset($options['mergehead']) && $options['mergehead'] == 1 && isset($data['head']) && !empty($data['head']))
|
||||
{
|
||||
$document->mergeHeadData($data['head']);
|
||||
}
|
||||
elseif (isset($data['head']) && method_exists($document, 'setHeadData'))
|
||||
{
|
||||
$document->setHeadData($data['head']);
|
||||
}
|
||||
|
||||
// If the pathway buffer is set in the cache data, get it.
|
||||
if (isset($data['pathway']) && is_array($data['pathway']))
|
||||
{
|
||||
// Push the pathway data into the pathway object.
|
||||
$pathway = $app->getPathWay();
|
||||
$pathway->setPathway($data['pathway']);
|
||||
}
|
||||
|
||||
// @todo check if the following is needed, seems like it should be in page cache
|
||||
// If a module buffer is set in the cache data, get it.
|
||||
if (isset($data['module']) && is_array($data['module']))
|
||||
{
|
||||
// Iterate through the module positions and push them into the document buffer.
|
||||
foreach ($data['module'] as $name => $contents)
|
||||
{
|
||||
$document->setBuffer($contents, 'module', $name);
|
||||
}
|
||||
}
|
||||
|
||||
// Set cached headers.
|
||||
if (isset($data['headers']) && $data['headers'])
|
||||
{
|
||||
foreach($data['headers'] as $header)
|
||||
{
|
||||
JResponse::setHeader($header['name'], $header['value']);
|
||||
}
|
||||
}
|
||||
|
||||
// The following code searches for a token in the cached page and replaces it with the
|
||||
// proper token.
|
||||
if (isset($data['body']))
|
||||
{
|
||||
$token = JSession::getFormToken();
|
||||
$search = '#<input type="hidden" name="[0-9a-f]{32}" value="1" />#';
|
||||
$replacement = '<input type="hidden" name="' . $token . '" value="1" />';
|
||||
|
||||
$data['body'] = preg_replace($search, $replacement, $data['body']);
|
||||
$body = $data['body'];
|
||||
}
|
||||
|
||||
// Get the document body out of the cache.
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create workarounded data to be cached
|
||||
*
|
||||
* @param string $data Cached data
|
||||
* @param array $options Array of options
|
||||
*
|
||||
* @return string Data to be cached
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function setWorkarounds($data, $options = array())
|
||||
{
|
||||
$loptions = array(
|
||||
'nopathway' => 0,
|
||||
'nohead' => 0,
|
||||
'nomodules' => 0,
|
||||
'modulemode' => 0,
|
||||
);
|
||||
|
||||
if (isset($options['nopathway']))
|
||||
{
|
||||
$loptions['nopathway'] = $options['nopathway'];
|
||||
}
|
||||
|
||||
if (isset($options['nohead']))
|
||||
{
|
||||
$loptions['nohead'] = $options['nohead'];
|
||||
}
|
||||
|
||||
if (isset($options['nomodules']))
|
||||
{
|
||||
$loptions['nomodules'] = $options['nomodules'];
|
||||
}
|
||||
|
||||
if (isset($options['modulemode']))
|
||||
{
|
||||
$loptions['modulemode'] = $options['modulemode'];
|
||||
}
|
||||
|
||||
$app = JFactory::getApplication();
|
||||
$document = JFactory::getDocument();
|
||||
|
||||
if ($loptions['nomodules'] != 1)
|
||||
{
|
||||
// Get the modules buffer before component execution.
|
||||
$buffer1 = $document->getBuffer();
|
||||
if (!is_array($buffer1))
|
||||
{
|
||||
$buffer1 = array();
|
||||
}
|
||||
|
||||
// Make sure the module buffer is an array.
|
||||
if (!isset($buffer1['module']) || !is_array($buffer1['module']))
|
||||
{
|
||||
$buffer1['module'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
// View body data
|
||||
$cached['body'] = $data;
|
||||
|
||||
// Document head data
|
||||
if ($loptions['nohead'] != 1 && method_exists($document, 'getHeadData'))
|
||||
{
|
||||
|
||||
if ($loptions['modulemode'] == 1)
|
||||
{
|
||||
$headnow = $document->getHeadData();
|
||||
$unset = array('title', 'description', 'link', 'links', 'metaTags');
|
||||
|
||||
foreach ($unset as $un)
|
||||
{
|
||||
unset($headnow[$un]);
|
||||
unset($options['headerbefore'][$un]);
|
||||
}
|
||||
|
||||
$cached['head'] = array();
|
||||
|
||||
// Only store what this module has added
|
||||
foreach ($headnow as $now => $value)
|
||||
{
|
||||
if (isset($options['headerbefore'][$now]))
|
||||
{
|
||||
// We have to serialize the content of the arrays because the may contain other arrays which is a notice in PHP 5.4 and newer
|
||||
$nowvalue = array_map('serialize', $headnow[$now]);
|
||||
$beforevalue = array_map('serialize', $options['headerbefore'][$now]);
|
||||
$newvalue = array_diff_assoc($nowvalue, $beforevalue);
|
||||
$newvalue = array_map('unserialize', $newvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$newvalue = $headnow[$now];
|
||||
}
|
||||
|
||||
if (!empty($newvalue))
|
||||
{
|
||||
$cached['head'][$now] = $newvalue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$cached['head'] = $document->getHeadData();
|
||||
}
|
||||
}
|
||||
|
||||
// Pathway data
|
||||
if ($app->isSite() && $loptions['nopathway'] != 1)
|
||||
{
|
||||
$pathway = $app->getPathWay();
|
||||
$cached['pathway'] = isset($data['pathway']) ? $data['pathway'] : $pathway->getPathway();
|
||||
}
|
||||
|
||||
if ($loptions['nomodules'] != 1)
|
||||
{
|
||||
// @todo Check if the following is needed, seems like it should be in page cache
|
||||
// Get the module buffer after component execution.
|
||||
$buffer2 = $document->getBuffer();
|
||||
if (!is_array($buffer2))
|
||||
{
|
||||
$buffer2 = array();
|
||||
}
|
||||
|
||||
// Make sure the module buffer is an array.
|
||||
if (!isset($buffer2['module']) || !is_array($buffer2['module']))
|
||||
{
|
||||
$buffer2['module'] = array();
|
||||
}
|
||||
|
||||
// Compare the second module buffer against the first buffer.
|
||||
$cached['module'] = array_diff_assoc($buffer2['module'], $buffer1['module']);
|
||||
}
|
||||
|
||||
// Headers data
|
||||
if (isset($options['headers']) && $options['headers'])
|
||||
{
|
||||
$cached['headers'] = JResponse::getHeaders();
|
||||
}
|
||||
|
||||
return $cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create safe id for cached data from url parameters set by plugins and framework
|
||||
*
|
||||
* @return string md5 encoded cacheid
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function makeId()
|
||||
{
|
||||
$app = JFactory::getApplication();
|
||||
|
||||
// Get url parameters set by plugins
|
||||
if (!empty($app->registeredurlparams))
|
||||
{
|
||||
$registeredurlparams = $app->registeredurlparams;
|
||||
}
|
||||
|
||||
// Platform defaults
|
||||
$registeredurlparams->format = 'WORD';
|
||||
$registeredurlparams->option = 'WORD';
|
||||
$registeredurlparams->view = 'WORD';
|
||||
$registeredurlparams->layout = 'WORD';
|
||||
$registeredurlparams->tpl = 'CMD';
|
||||
$registeredurlparams->id = 'INT';
|
||||
|
||||
$safeuriaddon = new stdClass;
|
||||
|
||||
foreach ($registeredurlparams as $key => $value)
|
||||
{
|
||||
$safeuriaddon->$key = $app->input->get($key, null, $value);
|
||||
}
|
||||
|
||||
return md5(serialize($safeuriaddon));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a directory where JCache should search for handlers. You may
|
||||
* either pass a string or an array of directories.
|
||||
*
|
||||
* @param string $path A path to search.
|
||||
*
|
||||
* @return array An array with directory elements
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function addIncludePath($path = '')
|
||||
{
|
||||
static $paths;
|
||||
|
||||
if (!isset($paths))
|
||||
{
|
||||
$paths = array();
|
||||
}
|
||||
if (!empty($path) && !in_array($path, $paths))
|
||||
{
|
||||
jimport('joomla.filesystem.path');
|
||||
array_unshift($paths, JPath::clean($path));
|
||||
}
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
235
libraries/joomla/cache/controller.php
vendored
Normal file
235
libraries/joomla/cache/controller.php
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Public cache handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheController
|
||||
{
|
||||
/**
|
||||
* @var JCache
|
||||
* @since 11.1
|
||||
*/
|
||||
public $cache;
|
||||
|
||||
/**
|
||||
* @var array Array of options
|
||||
* @since 11.1
|
||||
*/
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Array of options
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
$this->cache = new JCache($options);
|
||||
$this->options = & $this->cache->_options;
|
||||
|
||||
// Overwrite default options with given options
|
||||
foreach ($options as $option => $value)
|
||||
{
|
||||
if (isset($options[$option]))
|
||||
{
|
||||
$this->options[$option] = $options[$option];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to proxy JCacheControllerMethods
|
||||
*
|
||||
* @param string $name Name of the function
|
||||
* @param array $arguments Array of arguments for the function
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
$nazaj = call_user_func_array(array($this->cache, $name), $arguments);
|
||||
return $nazaj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a cache adapter object, always creating it
|
||||
*
|
||||
* @param string $type The cache object type to instantiate; default is output.
|
||||
* @param array $options Array of options
|
||||
*
|
||||
* @return JCache A JCache object
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getInstance($type = 'output', $options = array())
|
||||
{
|
||||
self::addIncludePath(JPATH_PLATFORM . '/joomla/cache/controller');
|
||||
|
||||
$type = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $type));
|
||||
|
||||
$class = 'JCacheController' . ucfirst($type);
|
||||
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// Search for the class file in the JCache include paths.
|
||||
jimport('joomla.filesystem.path');
|
||||
|
||||
if ($path = JPath::find(self::addIncludePath(), strtolower($type) . '.php'))
|
||||
{
|
||||
include_once $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException('Unable to load Cache Controller: ' . $type, 500);
|
||||
}
|
||||
}
|
||||
|
||||
return new $class($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set caching enabled state
|
||||
*
|
||||
* @param boolean $enabled True to enable caching
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setCaching($enabled)
|
||||
{
|
||||
$this->cache->setCaching($enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache lifetime
|
||||
*
|
||||
* @param integer $lt Cache lifetime
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setLifeTime($lt)
|
||||
{
|
||||
$this->cache->setLifeTime($lt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a directory where JCache should search for controllers. You may
|
||||
* either pass a string or an array of directories.
|
||||
*
|
||||
* @param string $path A path to search.
|
||||
*
|
||||
* @return array An array with directory elements
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function addIncludePath($path = '')
|
||||
{
|
||||
static $paths;
|
||||
|
||||
if (!isset($paths))
|
||||
{
|
||||
$paths = array();
|
||||
}
|
||||
if (!empty($path) && !in_array($path, $paths))
|
||||
{
|
||||
jimport('joomla.filesystem.path');
|
||||
array_unshift($paths, JPath::clean($path));
|
||||
}
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stored cached data by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return mixed False on no result, cached object otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group = null)
|
||||
{
|
||||
$data = $this->cache->get($id, $group);
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$locktest = new stdClass;
|
||||
$locktest->locked = null;
|
||||
$locktest->locklooped = null;
|
||||
$locktest = $this->cache->lock($id, $group);
|
||||
if ($locktest->locked == true && $locktest->locklooped == true)
|
||||
{
|
||||
$data = $this->cache->get($id, $group);
|
||||
}
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
}
|
||||
|
||||
// Check again because we might get it from second attempt
|
||||
if ($data !== false)
|
||||
{
|
||||
// Trim to fix unserialize errors
|
||||
$data = unserialize(trim($data));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data to cache by id and group
|
||||
*
|
||||
* @param mixed $data The data to store
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $wrkarounds True to use wrkarounds
|
||||
*
|
||||
* @return boolean True if cache stored
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($data, $id, $group = null, $wrkarounds = true)
|
||||
{
|
||||
$locktest = new stdClass;
|
||||
$locktest->locked = null;
|
||||
$locktest->locklooped = null;
|
||||
|
||||
$locktest = $this->cache->lock($id, $group);
|
||||
|
||||
if ($locktest->locked == false && $locktest->locklooped == true)
|
||||
{
|
||||
$locktest = $this->cache->lock($id, $group);
|
||||
}
|
||||
|
||||
$sucess = $this->cache->store(serialize($data), $id, $group);
|
||||
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
|
||||
return $sucess;
|
||||
}
|
||||
}
|
||||
205
libraries/joomla/cache/controller/callback.php
vendored
Normal file
205
libraries/joomla/cache/controller/callback.php
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla! Cache callback type object
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheControllerCallback extends JCacheController
|
||||
{
|
||||
/**
|
||||
* Executes a cacheable callback if not found in cache else returns cached output and result
|
||||
*
|
||||
* Since arguments to this function are read with func_get_args you can pass any number of
|
||||
* arguments to this method
|
||||
* as long as the first argument passed is the callback definition.
|
||||
*
|
||||
* The callback definition can be in several forms:
|
||||
* - Standard PHP Callback array see <http://php.net/callback> [recommended]
|
||||
* - Function name as a string eg. 'foo' for function foo()
|
||||
* - Static method name as a string eg. 'MyClass::myMethod' for method myMethod() of class MyClass
|
||||
*
|
||||
* @return mixed Result of the callback
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function call()
|
||||
{
|
||||
// Get callback and arguments
|
||||
$args = func_get_args();
|
||||
$callback = array_shift($args);
|
||||
|
||||
return $this->get($callback, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a cacheable callback if not found in cache else returns cached output and result
|
||||
*
|
||||
* @param mixed $callback Callback or string shorthand for a callback
|
||||
* @param array $args Callback arguments
|
||||
* @param string $id Cache id
|
||||
* @param boolean $wrkarounds True to use wrkarounds
|
||||
* @param array $woptions Workaround options
|
||||
*
|
||||
* @return mixed Result of the callback
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($callback, $args = array(), $id = false, $wrkarounds = false, $woptions = array())
|
||||
{
|
||||
|
||||
// Normalize callback
|
||||
if (is_array($callback))
|
||||
{
|
||||
// We have a standard php callback array -- do nothing
|
||||
}
|
||||
elseif (strstr($callback, '::'))
|
||||
{
|
||||
// This is shorthand for a static method callback classname::methodname
|
||||
list ($class, $method) = explode('::', $callback);
|
||||
$callback = array(trim($class), trim($method));
|
||||
}
|
||||
elseif (strstr($callback, '->'))
|
||||
{
|
||||
/*
|
||||
* This is a really not so smart way of doing this... we provide this for backward compatability but this
|
||||
* WILL! disappear in a future version. If you are using this syntax change your code to use the standard
|
||||
* PHP callback array syntax: <http://php.net/callback>
|
||||
*
|
||||
* We have to use some silly global notation to pull it off and this is very unreliable
|
||||
*/
|
||||
list ($object_123456789, $method) = explode('->', $callback);
|
||||
global $$object_123456789;
|
||||
$callback = array($$object_123456789, $method);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have just a standard function -- do nothing
|
||||
}
|
||||
|
||||
if (!$id)
|
||||
{
|
||||
// Generate an ID
|
||||
$id = $this->_makeId($callback, $args);
|
||||
}
|
||||
|
||||
$data = $this->cache->get($id);
|
||||
|
||||
$locktest = new stdClass;
|
||||
$locktest->locked = null;
|
||||
$locktest->locklooped = null;
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$locktest = $this->cache->lock($id);
|
||||
if ($locktest->locked == true && $locktest->locklooped == true)
|
||||
{
|
||||
$data = $this->cache->get($id);
|
||||
}
|
||||
}
|
||||
|
||||
$coptions = array();
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
|
||||
$cached = unserialize(trim($data));
|
||||
$coptions['mergehead'] = isset($woptions['mergehead']) ? $woptions['mergehead'] : 0;
|
||||
$output = ($wrkarounds == false) ? $cached['output'] : JCache::getWorkarounds($cached['output'], $coptions);
|
||||
$result = $cached['result'];
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!is_array($args))
|
||||
{
|
||||
$Args = !empty($args) ? array(&$args) : array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$Args = &$args;
|
||||
}
|
||||
|
||||
if ($locktest->locked == false)
|
||||
{
|
||||
$locktest = $this->cache->lock($id);
|
||||
}
|
||||
|
||||
if (isset($woptions['modulemode']) && $woptions['modulemode'] == 1)
|
||||
{
|
||||
$document = JFactory::getDocument();
|
||||
$coptions['modulemode'] = 1;
|
||||
$coptions['headerbefore'] = $document->getHeadData();
|
||||
}
|
||||
else
|
||||
{
|
||||
$coptions['modulemode'] = 0;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
|
||||
$result = call_user_func_array($callback, $Args);
|
||||
$output = ob_get_contents();
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
$cached = array();
|
||||
|
||||
$coptions['nopathway'] = isset($woptions['nopathway']) ? $woptions['nopathway'] : 1;
|
||||
$coptions['nohead'] = isset($woptions['nohead']) ? $woptions['nohead'] : 1;
|
||||
$coptions['nomodules'] = isset($woptions['nomodules']) ? $woptions['nomodules'] : 1;
|
||||
|
||||
$cached['output'] = ($wrkarounds == false) ? $output : JCache::setWorkarounds($output, $coptions);
|
||||
$cached['result'] = $result;
|
||||
|
||||
// Store the cache data
|
||||
$this->cache->store(serialize($cached), $id);
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id);
|
||||
}
|
||||
}
|
||||
|
||||
echo $output;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a callback cache id
|
||||
*
|
||||
* @param callback $callback Callback to cache
|
||||
* @param array $args Arguments to the callback method to cache
|
||||
*
|
||||
* @return string MD5 Hash : function cache id
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _makeId($callback, $args)
|
||||
{
|
||||
if (is_array($callback) && is_object($callback[0]))
|
||||
{
|
||||
$vars = get_object_vars($callback[0]);
|
||||
$vars[] = strtolower(get_class($callback[0]));
|
||||
$callback[0] = $vars;
|
||||
}
|
||||
|
||||
return md5(serialize(array($callback, $args)));
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/cache/controller/index.html
vendored
Normal file
1
libraries/joomla/cache/controller/index.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
122
libraries/joomla/cache/controller/output.php
vendored
Normal file
122
libraries/joomla/cache/controller/output.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Cache output type object
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheControllerOutput extends JCacheController
|
||||
{
|
||||
/**
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_id;
|
||||
|
||||
/**
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_group;
|
||||
|
||||
/**
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_locktest = null;
|
||||
|
||||
/**
|
||||
* Start the cache
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True if the cache is hit (false else)
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function start($id, $group = null)
|
||||
{
|
||||
// If we have data in cache use that.
|
||||
$data = $this->cache->get($id, $group);
|
||||
|
||||
$this->_locktest = new stdClass;
|
||||
$this->_locktest->locked = null;
|
||||
$this->_locktest->locklooped = null;
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$this->_locktest = $this->cache->lock($id, $group);
|
||||
if ($this->_locktest->locked == true && $this->_locktest->locklooped == true)
|
||||
{
|
||||
$data = $this->cache->get($id, $group);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
$data = unserialize(trim($data));
|
||||
echo $data;
|
||||
if ($this->_locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing in cache... let's start the output buffer and start collecting data for next time.
|
||||
if ($this->_locktest->locked == false)
|
||||
{
|
||||
$this->_locktest = $this->cache->lock($id, $group);
|
||||
}
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
|
||||
// Set id and group placeholders
|
||||
$this->_id = $id;
|
||||
$this->_group = $group;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the cache buffer and store the cached data
|
||||
*
|
||||
* @return boolean True if cache stored
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
// Get data from output buffer and echo it
|
||||
$data = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo $data;
|
||||
|
||||
// Get id and group and reset them placeholders
|
||||
$id = $this->_id;
|
||||
$group = $this->_group;
|
||||
$this->_id = null;
|
||||
$this->_group = null;
|
||||
|
||||
// Get the storage handler and store the cached data
|
||||
$ret = $this->cache->store(serialize($data), $id, $group);
|
||||
|
||||
if ($this->_locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
211
libraries/joomla/cache/controller/page.php
vendored
Normal file
211
libraries/joomla/cache/controller/page.php
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla! Cache page type object
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheControllerPage extends JCacheController
|
||||
{
|
||||
/**
|
||||
* @var integer ID property for the cache page object.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_id;
|
||||
|
||||
/**
|
||||
* @var string Cache group
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_group;
|
||||
|
||||
/**
|
||||
* @var object Cache lock test
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_locktest = null;
|
||||
|
||||
/**
|
||||
* Get the cached page data
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True if the cache is hit (false else)
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id = false, $group = 'page')
|
||||
{
|
||||
// If an id is not given, generate it from the request
|
||||
if ($id == false)
|
||||
{
|
||||
$id = $this->_makeId();
|
||||
}
|
||||
|
||||
// If the etag matches the page id ... set a no change header and exit : utilize browser cache
|
||||
if (!headers_sent() && isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||
{
|
||||
$etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
|
||||
if ($etag == $id)
|
||||
{
|
||||
$browserCache = isset($this->options['browsercache']) ? $this->options['browsercache'] : false;
|
||||
if ($browserCache)
|
||||
{
|
||||
$this->_noChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We got a cache hit... set the etag header and echo the page data
|
||||
$data = $this->cache->get($id, $group);
|
||||
|
||||
$this->_locktest = new stdClass;
|
||||
$this->_locktest->locked = null;
|
||||
$this->_locktest->locklooped = null;
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$this->_locktest = $this->cache->lock($id, $group);
|
||||
if ($this->_locktest->locked == true && $this->_locktest->locklooped == true)
|
||||
{
|
||||
$data = $this->cache->get($id, $group);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
$data = unserialize(trim($data));
|
||||
|
||||
$data = JCache::getWorkarounds($data);
|
||||
|
||||
$this->_setEtag($id);
|
||||
if ($this->_locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Set id and group placeholders
|
||||
$this->_id = $id;
|
||||
$this->_group = $group;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the cache buffer and store the cached data
|
||||
*
|
||||
* @param mixed $data The data to store
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $wrkarounds True to use wrkarounds
|
||||
*
|
||||
* @return boolean True if cache stored
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($data, $id, $group = null, $wrkarounds = true)
|
||||
{
|
||||
// Get page data from JResponse
|
||||
if (empty($data))
|
||||
{
|
||||
$data = JResponse::getBody();
|
||||
}
|
||||
|
||||
// Get id and group and reset the placeholders
|
||||
if (empty($id))
|
||||
{
|
||||
$id = $this->_id;
|
||||
}
|
||||
if (empty($group))
|
||||
{
|
||||
$group = $this->_group;
|
||||
}
|
||||
|
||||
// Only attempt to store if page data exists
|
||||
if ($data)
|
||||
{
|
||||
if ($wrkarounds) {
|
||||
$data = JCache::setWorkarounds($data, array(
|
||||
'nopathway' => 1,
|
||||
'nohead' => 1,
|
||||
'nomodules' => 1,
|
||||
'headers' => true
|
||||
));
|
||||
}
|
||||
|
||||
if ($this->_locktest->locked == false)
|
||||
{
|
||||
$this->_locktest = $this->cache->lock($id, $group);
|
||||
}
|
||||
|
||||
$sucess = $this->cache->store(serialize($data), $id, $group);
|
||||
|
||||
if ($this->_locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id, $group);
|
||||
}
|
||||
|
||||
return $sucess;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a page cache id
|
||||
*
|
||||
* @return string MD5 Hash : page cache id
|
||||
*
|
||||
* @since 11.1
|
||||
* @todo Discuss whether this should be coupled to a data hash or a request
|
||||
* hash ... perhaps hashed with a serialized request
|
||||
*/
|
||||
protected function _makeId()
|
||||
{
|
||||
return JCache::makeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no change in page data so send an
|
||||
* unmodified header and die gracefully
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _noChange()
|
||||
{
|
||||
$app = JFactory::getApplication();
|
||||
|
||||
// Send not modified header and exit gracefully
|
||||
header('HTTP/1.x 304 Not Modified', true);
|
||||
$app->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ETag header in the response
|
||||
*
|
||||
* @param string $etag The entity tag (etag) to set
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _setEtag($etag)
|
||||
{
|
||||
JResponse::setHeader('ETag', $etag, true);
|
||||
}
|
||||
}
|
||||
135
libraries/joomla/cache/controller/view.php
vendored
Normal file
135
libraries/joomla/cache/controller/view.php
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla! Cache view type object
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheControllerView extends JCacheController
|
||||
{
|
||||
/**
|
||||
* Get the cached view data
|
||||
*
|
||||
* @param object &$view The view object to cache output for
|
||||
* @param string $method The method name of the view method to cache output for
|
||||
* @param string $id The cache data id
|
||||
* @param boolean $wrkarounds True to enable workarounds.
|
||||
*
|
||||
* @return boolean True if the cache is hit (false else)
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get( $view, $method = 'display' , $id = false, $wrkarounds = true )
|
||||
{
|
||||
// If an id is not given generate it from the request
|
||||
if ($id == false)
|
||||
{
|
||||
$id = $this->_makeId($view, $method);
|
||||
}
|
||||
|
||||
$data = $this->cache->get($id);
|
||||
|
||||
$locktest = new stdClass;
|
||||
$locktest->locked = null;
|
||||
$locktest->locklooped = null;
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$locktest = $this->cache->lock($id, null);
|
||||
|
||||
// If the loop is completed and returned true it means the lock has been set.
|
||||
// If looped is true try to get the cached data again; it could exist now.
|
||||
if ($locktest->locked == true && $locktest->locklooped == true)
|
||||
{
|
||||
$data = $this->cache->get($id);
|
||||
}
|
||||
|
||||
// False means that locking is either turned off or maxtime has been exceeded.
|
||||
// Execute the view.
|
||||
}
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
$data = unserialize(trim($data));
|
||||
|
||||
if ($wrkarounds === true)
|
||||
{
|
||||
echo JCache::getWorkarounds($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No workarounds, so all data is stored in one piece
|
||||
echo (isset($data)) ? $data : null;
|
||||
}
|
||||
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* No hit so we have to execute the view
|
||||
*/
|
||||
if (method_exists($view, $method))
|
||||
{
|
||||
// If previous lock failed try again
|
||||
if ($locktest->locked == false)
|
||||
{
|
||||
$locktest = $this->cache->lock($id);
|
||||
}
|
||||
|
||||
// Capture and echo output
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
$view->$method();
|
||||
$data = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo $data;
|
||||
|
||||
/*
|
||||
* For a view we have a special case. We need to cache not only the output from the view, but the state
|
||||
* of the document head after the view has been rendered. This will allow us to properly cache any attached
|
||||
* scripts or stylesheets or links or any other modifications that the view has made to the document object
|
||||
*/
|
||||
$cached = $wrkarounds == true ? JCache::setWorkarounds($data) : $data;
|
||||
|
||||
// Store the cache data
|
||||
$this->cache->store(serialize($cached), $id);
|
||||
|
||||
if ($locktest->locked == true)
|
||||
{
|
||||
$this->cache->unlock($id);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a view cache id.
|
||||
*
|
||||
* @param object &$view The view object to cache output for
|
||||
* @param string $method The method name to cache for the view object
|
||||
*
|
||||
* @return string MD5 Hash : view cache id
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _makeId(&$view, $method)
|
||||
{
|
||||
return md5(serialize(array(JCache::makeId(), get_class($view), $method)));
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/cache/index.html
vendored
Normal file
1
libraries/joomla/cache/index.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
346
libraries/joomla/cache/storage.php
vendored
Normal file
346
libraries/joomla/cache/storage.php
vendored
Normal file
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Abstract cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorage
|
||||
{
|
||||
/**
|
||||
* @var string Rawname
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $rawname;
|
||||
|
||||
/**
|
||||
* @var datetime Now
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_now;
|
||||
|
||||
/**
|
||||
* @var integer Cache lifetime
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_lifetime;
|
||||
|
||||
/**
|
||||
* @var boolean Locking
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_locking;
|
||||
|
||||
/**
|
||||
* @var string Language
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_language;
|
||||
|
||||
/**
|
||||
* @var string Application name.
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_application;
|
||||
|
||||
/**
|
||||
* @var string Hash
|
||||
* @since 11.1
|
||||
*/
|
||||
public $_hash;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
$config = JFactory::getConfig();
|
||||
$this->_hash = md5($config->get('secret'));
|
||||
$this->_application = (isset($options['application'])) ? $options['application'] : null;
|
||||
$this->_language = (isset($options['language'])) ? $options['language'] : 'en-GB';
|
||||
$this->_locking = (isset($options['locking'])) ? $options['locking'] : true;
|
||||
$this->_lifetime = (isset($options['lifetime'])) ? $options['lifetime'] * 60 : $config->get('cachetime') * 60;
|
||||
$this->_now = (isset($options['now'])) ? $options['now'] : time();
|
||||
|
||||
// Set time threshold value. If the lifetime is not set, default to 60 (0 is BAD)
|
||||
// _threshold is now available ONLY as a legacy (it's deprecated). It's no longer used in the core.
|
||||
if (empty($this->_lifetime))
|
||||
{
|
||||
$this->_threshold = $this->_now - 60;
|
||||
$this->_lifetime = 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_threshold = $this->_now - $this->_lifetime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cache storage handler object, only creating it
|
||||
* if it doesn't already exist.
|
||||
*
|
||||
* @param string $handler The cache storage handler to instantiate
|
||||
* @param array $options Array of handler options
|
||||
*
|
||||
* @return JCacheStorage A JCacheStorage instance
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws UnexpectedValueException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getInstance($handler = null, $options = array())
|
||||
{
|
||||
static $now = null;
|
||||
|
||||
self::addIncludePath(JPATH_PLATFORM . '/joomla/cache/storage');
|
||||
|
||||
if (!isset($handler))
|
||||
{
|
||||
$conf = JFactory::getConfig();
|
||||
$handler = $conf->get('cache_handler');
|
||||
if (empty($handler))
|
||||
{
|
||||
throw new UnexpectedValueException('Cache Storage Handler not set.');
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($now))
|
||||
{
|
||||
$now = time();
|
||||
}
|
||||
|
||||
$options['now'] = $now;
|
||||
|
||||
// We can't cache this since options may change...
|
||||
$handler = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $handler));
|
||||
|
||||
$class = 'JCacheStorage' . ucfirst($handler);
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// Search for the class file in the JCacheStorage include paths.
|
||||
jimport('joomla.filesystem.path');
|
||||
if ($path = JPath::find(self::addIncludePath(), strtolower($handler) . '.php'))
|
||||
{
|
||||
include_once $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(sprintf('Unable to load Cache Storage: %s', $handler));
|
||||
}
|
||||
}
|
||||
|
||||
return new $class($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data object
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data object
|
||||
*
|
||||
* @since 11.1
|
||||
* @todo Review this method. The docblock doesn't fit what it actually does.
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
if (!class_exists('JCacheStorageHelper', false))
|
||||
{
|
||||
include_once JPATH_PLATFORM . '/joomla/cache/storage/helper.php';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to cache by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collect expired cache data
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the storage handler is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 12.1.
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the storage handler is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 12.3 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public static function test()
|
||||
{
|
||||
JLog::add('JCacheStorage::test() is deprecated. Use JCacheStorage::isSupported() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return static::isSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param integer $locktime Cached item max lock time
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function lock($id, $group, $locktime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cache_id string from an id/group pair
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return string The cache_id string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _getCacheId($id, $group)
|
||||
{
|
||||
$name = md5($this->_application . '-' . $id . '-' . $this->_language);
|
||||
$this->rawname = $this->_hash . '-' . $name;
|
||||
return $this->_hash . '-cache-' . $group . '-' . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a directory where JCacheStorage should search for handlers. You may
|
||||
* either pass a string or an array of directories.
|
||||
*
|
||||
* @param string $path A path to search.
|
||||
*
|
||||
* @return array An array with directory elements
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function addIncludePath($path = '')
|
||||
{
|
||||
static $paths;
|
||||
|
||||
if (!isset($paths))
|
||||
{
|
||||
$paths = array();
|
||||
}
|
||||
|
||||
if (!empty($path) && !in_array($path, $paths))
|
||||
{
|
||||
jimport('joomla.filesystem.path');
|
||||
array_unshift($paths, JPath::clean($path));
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
248
libraries/joomla/cache/storage/apc.php
vendored
Normal file
248
libraries/joomla/cache/storage/apc.php
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* APC cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @see http://php.net/manual/en/book.apc.php
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageApc extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* Get cached data from APC by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean False on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
return apc_fetch($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$allinfo = apc_cache_info('user');
|
||||
$keys = $allinfo['cache_list'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
|
||||
$name = $key['info'];
|
||||
$namearr = explode('-', $name);
|
||||
|
||||
if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache')
|
||||
{
|
||||
$group = $namearr[2];
|
||||
|
||||
if (!isset($data[$group]))
|
||||
{
|
||||
$item = new JCacheStorageHelper($group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $data[$group];
|
||||
}
|
||||
|
||||
$item->updateSize($key['mem_size'] / 1024);
|
||||
|
||||
$data[$group] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to APC by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
return apc_store($cache_id, $data, $this->_lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
return apc_delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
$allinfo = apc_cache_info('user');
|
||||
$keys = $allinfo['cache_list'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
|
||||
if (strpos($key['info'], $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group')
|
||||
{
|
||||
apc_delete($key['info']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force garbage collect expired cache data as items are removed only on fetch!
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
$allinfo = apc_cache_info('user');
|
||||
$keys = $allinfo['cache_list'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (strpos($key['info'], $secret . '-cache-'))
|
||||
{
|
||||
apc_fetch($key['info']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return extension_loaded('apc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cached item - override parent as this is more efficient
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param integer $locktime Cached item max lock time
|
||||
*
|
||||
* @return object Properties are lock and locklooped
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function lock($id, $group, $locktime)
|
||||
{
|
||||
$returning = new stdClass;
|
||||
$returning->locklooped = false;
|
||||
|
||||
$looptime = $locktime * 10;
|
||||
|
||||
$cache_id = $this->_getCacheId($id, $group) . '_lock';
|
||||
|
||||
$data_lock = apc_add($cache_id, 1, $locktime);
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released.
|
||||
// That implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
$returning->locked = false;
|
||||
$returning->locklooped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = apc_add($cache_id, 1, $locktime);
|
||||
$lock_counter++;
|
||||
}
|
||||
|
||||
}
|
||||
$returning->locked = $data_lock;
|
||||
|
||||
return $returning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cached item - override parent for cacheid compatibility with lock
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group) . '_lock';
|
||||
|
||||
$unlock = apc_delete($cache_id);
|
||||
return $unlock;
|
||||
}
|
||||
}
|
||||
336
libraries/joomla/cache/storage/cachelite.php
vendored
Normal file
336
libraries/joomla/cache/storage/cachelite.php
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Cache lite storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @see http://pear.php.net/package/Cache_Lite/
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageCachelite extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* @var object
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $CacheLiteInstance = null;
|
||||
|
||||
/**
|
||||
* @var
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_root;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
|
||||
$this->_root = $options['cachebase'];
|
||||
|
||||
$cloptions = array(
|
||||
'cacheDir' => $this->_root . '/',
|
||||
'lifeTime' => $this->_lifetime,
|
||||
'fileLocking' => $this->_locking,
|
||||
'automaticCleaningFactor' => isset($options['autoclean']) ? $options['autoclean'] : 200,
|
||||
'fileNameProtection' => false,
|
||||
'hashedDirectoryLevel' => 0,
|
||||
'caching' => $options['caching']);
|
||||
|
||||
if (self::$CacheLiteInstance === null)
|
||||
{
|
||||
$this->initCache($cloptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the appropriate CacheLite object.
|
||||
* Only initializes the engine if it does not already exist.
|
||||
* Note this is a protected method
|
||||
*
|
||||
* @param array $cloptions optional parameters
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function initCache($cloptions)
|
||||
{
|
||||
require_once 'Cache/Lite.php';
|
||||
|
||||
self::$CacheLiteInstance = new Cache_Lite($cloptions);
|
||||
|
||||
return self::$CacheLiteInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data from a file by id and group
|
||||
*
|
||||
* @param string $id The cache data id.
|
||||
* @param string $group The cache data group.
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold.
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
self::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/');
|
||||
$this->_getCacheId($id, $group);
|
||||
$data = self::$CacheLiteInstance->get($this->rawname, $group);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$path = $this->_root;
|
||||
$folders = new DirectoryIterator($path);
|
||||
$data = array();
|
||||
|
||||
foreach ($folders as $folder)
|
||||
{
|
||||
if (!$folder->isDir() || $folder->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$foldername = $folder->getFilename();
|
||||
|
||||
$files = new DirectoryIterator($path . '/' . $foldername);
|
||||
$item = new JCacheStorageHelper($foldername);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
if (!$file->isFile())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $file->getFilename();
|
||||
|
||||
$item->updateSize(filesize($path . '/' . $foldername . '/' . $filename) / 1024);
|
||||
}
|
||||
|
||||
$data[$foldername] = $item;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to a file by id and group
|
||||
*
|
||||
* @param string $id The cache data id.
|
||||
* @param string $group The cache data group.
|
||||
* @param string $data The data to store in cache.
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$dir = $this->_root . '/' . $group;
|
||||
|
||||
// If the folder doesn't exist try to create it
|
||||
if (!is_dir($dir))
|
||||
{
|
||||
// Make sure the index file is there
|
||||
$indexFile = $dir . '/index.html';
|
||||
@mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE html><title></title>');
|
||||
}
|
||||
|
||||
// Make sure the folder exists
|
||||
if (!is_dir($dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/');
|
||||
$this->_getCacheId($id, $group);
|
||||
$success = self::$CacheLiteInstance->save($data, $this->rawname, $group);
|
||||
|
||||
if ($success == true)
|
||||
{
|
||||
return $success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data file by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
self::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/');
|
||||
$this->_getCacheId($id, $group);
|
||||
$success = self::$CacheLiteInstance->remove($this->rawname, $group);
|
||||
|
||||
if ($success == true)
|
||||
{
|
||||
return $success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group.
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup].
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
jimport('joomla.filesystem.folder');
|
||||
|
||||
switch ($mode)
|
||||
{
|
||||
case 'notgroup':
|
||||
$clmode = 'notingroup';
|
||||
$success = self::$CacheLiteInstance->clean($group, $clmode);
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
if (is_dir($this->_root . '/' . $group))
|
||||
{
|
||||
$clmode = $group;
|
||||
self::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/');
|
||||
$success = self::$CacheLiteInstance->clean($group, $clmode);
|
||||
JFolder::delete($this->_root . '/' . $group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_dir($this->_root . '/' . $group))
|
||||
{
|
||||
$clmode = $group;
|
||||
self::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/');
|
||||
$success = self::$CacheLiteInstance->clean($group, $clmode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($success == true)
|
||||
{
|
||||
return $success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collect expired cache data
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
$result = true;
|
||||
self::$CacheLiteInstance->setOption('automaticCleaningFactor', 1);
|
||||
self::$CacheLiteInstance->setOption('hashedDirectoryLevel', 1);
|
||||
$success1 = self::$CacheLiteInstance->_cleanDir($this->_root . '/', false, 'old');
|
||||
|
||||
if (!($dh = opendir($this->_root . '/')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while ($file = readdir($dh))
|
||||
{
|
||||
if (($file != '.') && ($file != '..') && ($file != '.svn'))
|
||||
{
|
||||
$file2 = $this->_root . '/' . $file;
|
||||
|
||||
if (is_dir($file2))
|
||||
{
|
||||
$result = ($result && (self::$CacheLiteInstance->_cleanDir($file2 . '/', false, 'old')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$success = ($success1 && $result);
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
@include_once 'Cache/Lite.php';
|
||||
|
||||
if (class_exists('Cache_Lite'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
689
libraries/joomla/cache/storage/file.php
vendored
Normal file
689
libraries/joomla/cache/storage/file.php
vendored
Normal file
@ -0,0 +1,689 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* File cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageFile extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_root;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
$this->_root = $options['cachebase'];
|
||||
}
|
||||
|
||||
// NOTE: raw php calls are up to 100 times faster than JFile or JFolder
|
||||
|
||||
/**
|
||||
* Get cached data from a file by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$data = false;
|
||||
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
|
||||
if ($checkTime == false || ($checkTime == true && $this->_checkExpire($id, $group) === true))
|
||||
{
|
||||
if (file_exists($path))
|
||||
{
|
||||
$data = file_get_contents($path);
|
||||
if ($data)
|
||||
{
|
||||
// Remove the initial die() statement
|
||||
$data = str_replace('<?php die("Access Denied"); ?>#x#', '', $data);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array The cached data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$path = $this->_root;
|
||||
$folders = $this->_folders($path);
|
||||
$data = array();
|
||||
|
||||
foreach ($folders as $folder)
|
||||
{
|
||||
$files = $this->_filesInFolder($path . '/' . $folder);
|
||||
$item = new JCacheStorageHelper($folder);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$item->updateSize(filesize($path . '/' . $folder . '/' . $file) / 1024);
|
||||
}
|
||||
$data[$folder] = $item;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to a file by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$written = false;
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
$die = '<?php die("Access Denied"); ?>#x#';
|
||||
|
||||
// Prepend a die string
|
||||
$data = $die . $data;
|
||||
|
||||
$_fileopen = @fopen($path, "wb");
|
||||
|
||||
if ($_fileopen)
|
||||
{
|
||||
$len = strlen($data);
|
||||
@fwrite($_fileopen, $data, $len);
|
||||
$written = true;
|
||||
}
|
||||
|
||||
// Data integrity check
|
||||
if ($written && ($data == file_get_contents($path)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data file by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
if (!@unlink($path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
$return = true;
|
||||
$folder = $group;
|
||||
|
||||
if (trim($folder) == '')
|
||||
{
|
||||
$mode = 'notgroup';
|
||||
}
|
||||
|
||||
switch ($mode)
|
||||
{
|
||||
case 'notgroup':
|
||||
$folders = $this->_folders($this->_root);
|
||||
for ($i = 0, $n = count($folders); $i < $n; $i++)
|
||||
{
|
||||
if ($folders[$i] != $folder)
|
||||
{
|
||||
$return |= $this->_deleteFolder($this->_root . '/' . $folders[$i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'group':
|
||||
default:
|
||||
if (is_dir($this->_root . '/' . $folder))
|
||||
{
|
||||
$return = $this->_deleteFolder($this->_root . '/' . $folder);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collect expired cache data
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
$result = true;
|
||||
|
||||
// Files older than lifeTime get deleted from cache
|
||||
$files = $this->_filesInFolder($this->_root, '', true, true, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html'));
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$time = @filemtime($file);
|
||||
if (($time + $this->_lifetime) < $this->_now || empty($time))
|
||||
{
|
||||
$result |= @unlink($file);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
$conf = JFactory::getConfig();
|
||||
return is_writable($conf->get('cache_path', JPATH_CACHE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param integer $locktime Cached item max lock time
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function lock($id, $group, $locktime)
|
||||
{
|
||||
$returning = new stdClass;
|
||||
$returning->locklooped = false;
|
||||
|
||||
$looptime = $locktime * 10;
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
|
||||
$_fileopen = @fopen($path, "r+b");
|
||||
|
||||
if ($_fileopen)
|
||||
{
|
||||
$data_lock = @flock($_fileopen, LOCK_EX);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data_lock = false;
|
||||
}
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released.
|
||||
// That implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
$returning->locked = false;
|
||||
$returning->locklooped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = @flock($_fileopen, LOCK_EX);
|
||||
$lock_counter++;
|
||||
}
|
||||
|
||||
}
|
||||
$returning->locked = $data_lock;
|
||||
|
||||
return $returning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cached item
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
|
||||
$_fileopen = @fopen($path, "r+b");
|
||||
|
||||
if ($_fileopen)
|
||||
{
|
||||
$ret = @flock($_fileopen, LOCK_UN);
|
||||
@fclose($_fileopen);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to make sure cache is still valid, if not, delete it.
|
||||
*
|
||||
* @param string $id Cache key to expire.
|
||||
* @param string $group The cache data group.
|
||||
*
|
||||
* @return boolean False if not valid
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _checkExpire($id, $group)
|
||||
{
|
||||
$path = $this->_getFilePath($id, $group);
|
||||
|
||||
// Check prune period
|
||||
if (file_exists($path))
|
||||
{
|
||||
$time = @filemtime($path);
|
||||
if (($time + $this->_lifetime) < $this->_now || empty($time))
|
||||
{
|
||||
@unlink($path);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cache file path from an id/group pair
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return string The cache file path
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _getFilePath($id, $group)
|
||||
{
|
||||
$name = $this->_getCacheId($id, $group);
|
||||
$dir = $this->_root . '/' . $group;
|
||||
|
||||
// If the folder doesn't exist try to create it
|
||||
if (!is_dir($dir))
|
||||
{
|
||||
|
||||
// Make sure the index file is there
|
||||
$indexFile = $dir . '/index.html';
|
||||
@ mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE html><title></title>');
|
||||
}
|
||||
|
||||
// Make sure the folder exists
|
||||
if (!is_dir($dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $dir . '/' . $name . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly delete a folder of files
|
||||
*
|
||||
* @param string $path The path to the folder to delete.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _deleteFolder($path)
|
||||
{
|
||||
// Sanity check
|
||||
if (!$path || !is_dir($path) || empty($this->_root))
|
||||
{
|
||||
// Bad programmer! Bad Bad programmer!
|
||||
JLog::add('JCacheStorageFile::_deleteFolder ' . JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'), JLog::WARNING, 'jerror');
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $this->_cleanPath($path);
|
||||
|
||||
// Check to make sure path is inside cache folder, we do not want to delete Joomla root!
|
||||
$pos = strpos($path, $this->_cleanPath($this->_root));
|
||||
|
||||
if ($pos === false || $pos > 0)
|
||||
{
|
||||
JLog::add('JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove all the files in folder if they exist; disable all filtering
|
||||
$files = $this->_filesInFolder($path, '.', false, true, array(), array());
|
||||
|
||||
if (!empty($files) && !is_array($files))
|
||||
{
|
||||
if (@unlink($files) !== true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (!empty($files) && is_array($files))
|
||||
{
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$file = $this->_cleanPath($file);
|
||||
|
||||
// In case of restricted permissions we zap it one way or the other
|
||||
// as long as the owner is either the webserver or the ftp
|
||||
if (@unlink($file))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
$filename = basename($file);
|
||||
JLog::add('JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', $filename), JLog::WARNING, 'jerror');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove sub-folders of folder; disable all filtering
|
||||
$folders = $this->_folders($path, '.', false, true, array(), array());
|
||||
|
||||
foreach ($folders as $folder)
|
||||
{
|
||||
if (is_link($folder))
|
||||
{
|
||||
// Don't descend into linked directories, just delete the link.
|
||||
if (@unlink($folder) !== true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif ($this->_deleteFolder($folder) !== true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// In case of restricted permissions we zap it one way or the other
|
||||
// as long as the owner is either the webserver or the ftp
|
||||
if (@rmdir($path))
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
JLog::add('JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path), JLog::WARNING, 'jerror');
|
||||
$ret = false;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to strip additional / or \ in a path name
|
||||
*
|
||||
* @param string $path The path to clean
|
||||
* @param string $ds Directory separator (optional)
|
||||
*
|
||||
* @return string The cleaned path
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _cleanPath($path, $ds = DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$path = trim($path);
|
||||
|
||||
if (empty($path))
|
||||
{
|
||||
$path = $this->_root;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove double slashes and backslahses and convert all slashes and backslashes to DIRECTORY_SEPARATOR
|
||||
$path = preg_replace('#[/\\\\]+#', $ds, $path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to quickly read the files in a folder.
|
||||
*
|
||||
* @param string $path The path of the folder to read.
|
||||
* @param string $filter A filter for file names.
|
||||
* @param mixed $recurse True to recursively search into sub-folders, or an
|
||||
* integer to specify the maximum depth.
|
||||
* @param boolean $fullpath True to return the full path to the file.
|
||||
* @param array $exclude Array with names of files which should not be shown in
|
||||
* the result.
|
||||
* @param array $excludefilter Array of folder names to exclude
|
||||
*
|
||||
* @return array Files in the given folder.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _filesInFolder($path, $filter = '.', $recurse = false, $fullpath = false
|
||||
, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'), $excludefilter = array('^\..*', '.*~'))
|
||||
{
|
||||
$arr = array();
|
||||
|
||||
// Check to make sure the path valid and clean
|
||||
$path = $this->_cleanPath($path);
|
||||
|
||||
// Is the path a folder?
|
||||
if (!is_dir($path))
|
||||
{
|
||||
JLog::add('JCacheStorageFile::_filesInFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the source directory.
|
||||
if (!($handle = @opendir($path)))
|
||||
{
|
||||
return $arr;
|
||||
}
|
||||
|
||||
if (count($excludefilter))
|
||||
{
|
||||
$excludefilter = '/(' . implode('|', $excludefilter) . ')/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$excludefilter = '';
|
||||
}
|
||||
while (($file = readdir($handle)) !== false)
|
||||
{
|
||||
if (($file != '.') && ($file != '..') && (!in_array($file, $exclude)) && (!$excludefilter || !preg_match($excludefilter, $file)))
|
||||
{
|
||||
$dir = $path . '/' . $file;
|
||||
$isDir = is_dir($dir);
|
||||
if ($isDir)
|
||||
{
|
||||
if ($recurse)
|
||||
{
|
||||
if (is_int($recurse))
|
||||
{
|
||||
$arr2 = $this->_filesInFolder($dir, $filter, $recurse - 1, $fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
$arr2 = $this->_filesInFolder($dir, $filter, $recurse, $fullpath);
|
||||
}
|
||||
|
||||
$arr = array_merge($arr, $arr2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match("/$filter/", $file))
|
||||
{
|
||||
if ($fullpath)
|
||||
{
|
||||
$arr[] = $path . '/' . $file;
|
||||
}
|
||||
else
|
||||
{
|
||||
$arr[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to read the folders in a folder.
|
||||
*
|
||||
* @param string $path The path of the folder to read.
|
||||
* @param string $filter A filter for folder names.
|
||||
* @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth.
|
||||
* @param boolean $fullpath True to return the full path to the folders.
|
||||
* @param array $exclude Array with names of folders which should not be shown in the result.
|
||||
* @param array $excludefilter Array with regular expressions matching folders which should not be shown in the result.
|
||||
*
|
||||
* @return array Folders in the given folder.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function _folders($path, $filter = '.', $recurse = false, $fullpath = false
|
||||
, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'), $excludefilter = array('^\..*'))
|
||||
{
|
||||
$arr = array();
|
||||
|
||||
// Check to make sure the path valid and clean
|
||||
$path = $this->_cleanPath($path);
|
||||
|
||||
// Is the path a folder?
|
||||
if (!is_dir($path))
|
||||
{
|
||||
JLog::add('JCacheStorageFile::_folders' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the source directory
|
||||
if (!($handle = @opendir($path)))
|
||||
{
|
||||
return $arr;
|
||||
}
|
||||
|
||||
if (count($excludefilter))
|
||||
{
|
||||
$excludefilter_string = '/(' . implode('|', $excludefilter) . ')/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$excludefilter_string = '';
|
||||
}
|
||||
while (($file = readdir($handle)) !== false)
|
||||
{
|
||||
if (($file != '.') && ($file != '..')
|
||||
&& (!in_array($file, $exclude))
|
||||
&& (empty($excludefilter_string) || !preg_match($excludefilter_string, $file)))
|
||||
{
|
||||
$dir = $path . '/' . $file;
|
||||
$isDir = is_dir($dir);
|
||||
if ($isDir)
|
||||
{
|
||||
// Removes filtered directories
|
||||
if (preg_match("/$filter/", $file))
|
||||
{
|
||||
if ($fullpath)
|
||||
{
|
||||
$arr[] = $dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
$arr[] = $file;
|
||||
}
|
||||
}
|
||||
if ($recurse)
|
||||
{
|
||||
if (is_int($recurse))
|
||||
{
|
||||
$arr2 = $this->_folders($dir, $filter, $recurse - 1, $fullpath, $exclude, $excludefilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
$arr2 = $this->_folders($dir, $filter, $recurse, $fullpath, $exclude, $excludefilter);
|
||||
}
|
||||
|
||||
$arr = array_merge($arr, $arr2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
71
libraries/joomla/cache/storage/helper.php
vendored
Normal file
71
libraries/joomla/cache/storage/helper.php
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Cache storage helper functions.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageHelper
|
||||
{
|
||||
/**
|
||||
* Cache data group
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
public $group = '';
|
||||
|
||||
/**
|
||||
* Cached item size
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
public $size = 0;
|
||||
|
||||
/**
|
||||
* Counter
|
||||
*
|
||||
* @var integer
|
||||
* @since 11.1
|
||||
*/
|
||||
public $count = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase cache items count.
|
||||
*
|
||||
* @param string $size Cached item size
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function updateSize($size)
|
||||
{
|
||||
$this->size = number_format($this->size + $size, 2);
|
||||
$this->count++;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/cache/storage/index.html
vendored
Normal file
1
libraries/joomla/cache/storage/index.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
485
libraries/joomla/cache/storage/memcache.php
vendored
Normal file
485
libraries/joomla/cache/storage/memcache.php
vendored
Normal file
@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Memcache cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @see http://php.net/manual/en/book.memcache.php
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageMemcache extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* @var Memcache
|
||||
* @since 11.1
|
||||
*/
|
||||
protected static $_db = null;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_persistent = false;
|
||||
|
||||
/**
|
||||
* @var
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $_compress = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
if (self::$_db === null)
|
||||
{
|
||||
$this->getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return memcache connection object
|
||||
*
|
||||
* @return object memcache connection object
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function getConnection()
|
||||
{
|
||||
if ((extension_loaded('memcache') && class_exists('Memcache')) != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = JFactory::getConfig();
|
||||
$this->_persistent = $config->get('memcache_persist', true);
|
||||
$this->_compress = $config->get('memcache_compress', false) == false ? 0 : MEMCACHE_COMPRESSED;
|
||||
|
||||
/*
|
||||
* This will be an array of loveliness
|
||||
* @todo: multiple servers
|
||||
* $servers = (isset($params['servers'])) ? $params['servers'] : array();
|
||||
*/
|
||||
$server = array();
|
||||
$server['host'] = $config->get('memcache_server_host', 'localhost');
|
||||
$server['port'] = $config->get('memcache_server_port', 11211);
|
||||
|
||||
// Create the memcache connection
|
||||
self::$_db = new Memcache;
|
||||
self::$_db->addServer($server['host'], $server['port'], $this->_persistent);
|
||||
|
||||
$memcachetest = @self::$_db->connect($server['host'], $server['port']);
|
||||
if ($memcachetest == false)
|
||||
{
|
||||
throw new RuntimeException('Could not connect to memcache server', 404);
|
||||
}
|
||||
|
||||
// Memcahed has no list keys, we do our own accounting, initialise key index
|
||||
if (self::$_db->get($this->_hash . '-index') === false)
|
||||
{
|
||||
$empty = array();
|
||||
self::$_db->set($this->_hash . '-index', $empty, $this->_compress, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data from memcache by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
$back = self::$_db->get($cache_id);
|
||||
return $back;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$keys = self::$_db->get($this->_hash . '-index');
|
||||
$secret = $this->_hash;
|
||||
|
||||
$data = array();
|
||||
|
||||
if (!empty($keys))
|
||||
{
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (empty($key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$namearr = explode('-', $key->name);
|
||||
|
||||
if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache')
|
||||
{
|
||||
|
||||
$group = $namearr[2];
|
||||
|
||||
if (!isset($data[$group]))
|
||||
{
|
||||
$item = new JCacheStorageHelper($group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $data[$group];
|
||||
}
|
||||
|
||||
$item->updateSize($key->size / 1024);
|
||||
|
||||
$data[$group] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to memcache by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$tmparr = new stdClass;
|
||||
$tmparr->name = $cache_id;
|
||||
$tmparr->size = strlen($data);
|
||||
|
||||
$config = JFactory::getConfig();
|
||||
$lifetime = (int) $config->get('cachetime', 15);
|
||||
if ($this->_lifetime == $lifetime)
|
||||
{
|
||||
$this->_lifetime = $lifetime * 60;
|
||||
}
|
||||
|
||||
$index[] = $tmparr;
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
// Prevent double writes, write only if it doesn't exist else replace
|
||||
if (!self::$_db->replace($cache_id, $data, $this->_compress, $this->_lifetime))
|
||||
{
|
||||
self::$_db->set($cache_id, $data, $this->_compress, $this->_lifetime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
if ($value->name == $cache_id)
|
||||
{
|
||||
unset($index[$key]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
return self::$_db->delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$secret = $this->_hash;
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
|
||||
if (strpos($value->name, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group')
|
||||
{
|
||||
self::$_db->delete($value->name, 0);
|
||||
unset($index[$key]);
|
||||
}
|
||||
}
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0, 0);
|
||||
$this->unlockindex();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
if ((extension_loaded('memcache') && class_exists('Memcache')) != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = JFactory::getConfig();
|
||||
$host = $config->get('memcache_server_host', 'localhost');
|
||||
$port = $config->get('memcache_server_port', 11211);
|
||||
|
||||
$memcache = new Memcache;
|
||||
$memcachetest = @$memcache->connect($host, $port);
|
||||
|
||||
if (!$memcachetest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cached item - override parent as this is more efficient
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param integer $locktime Cached item max lock time
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function lock($id, $group, $locktime)
|
||||
{
|
||||
$returning = new stdClass;
|
||||
$returning->locklooped = false;
|
||||
|
||||
$looptime = $locktime * 10;
|
||||
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$tmparr = new stdClass;
|
||||
$tmparr->name = $cache_id;
|
||||
$tmparr->size = 1;
|
||||
$index[] = $tmparr;
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
$data_lock = self::$_db->add($cache_id . '_lock', 1, false, $locktime);
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released.
|
||||
// That implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
$returning->locked = false;
|
||||
$returning->locklooped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = self::$_db->add($cache_id . '_lock', 1, false, $locktime);
|
||||
$lock_counter++;
|
||||
}
|
||||
|
||||
}
|
||||
$returning->locked = $data_lock;
|
||||
|
||||
return $returning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cached item - override parent for cacheid compatibility with lock
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group) . '_lock';
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
if ($value->name == $cache_id)
|
||||
{
|
||||
unset($index[$key]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
return self::$_db->delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cache index
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function lockindex()
|
||||
{
|
||||
$looptime = 300;
|
||||
$data_lock = self::$_db->add($this->_hash . '-index_lock', 1, false, 30);
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released. that implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = self::$_db->add($this->_hash . '-index_lock', 1, false, 30);
|
||||
$lock_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cache index
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function unlockindex()
|
||||
{
|
||||
return self::$_db->delete($this->_hash . '-index_lock');
|
||||
}
|
||||
}
|
||||
489
libraries/joomla/cache/storage/memcached.php
vendored
Normal file
489
libraries/joomla/cache/storage/memcached.php
vendored
Normal file
@ -0,0 +1,489 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Memcached cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @see http://php.net/manual/en/book.memcached.php
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCacheStorageMemcached extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* @var Memcached
|
||||
* @since 12.1
|
||||
*/
|
||||
protected static $_db = null;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $_persistent = false;
|
||||
|
||||
/**
|
||||
* @var
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $_compress = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
if (self::$_db === null)
|
||||
{
|
||||
$this->getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return memcached connection object
|
||||
*
|
||||
* @return object memcached connection object
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function getConnection()
|
||||
{
|
||||
if ((extension_loaded('memcached') && class_exists('Memcached')) != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = JFactory::getConfig();
|
||||
$this->_persistent = $config->get('memcache_persist', true);
|
||||
$this->_compress = $config->get('memcache_compress', false) == false ? 0 : Memcached::OPT_COMPRESSION;
|
||||
|
||||
/*
|
||||
* This will be an array of loveliness
|
||||
* @todo: multiple servers
|
||||
* $servers = (isset($params['servers'])) ? $params['servers'] : array();
|
||||
*/
|
||||
$server = array();
|
||||
$server['host'] = $config->get('memcache_server_host', 'localhost');
|
||||
$server['port'] = $config->get('memcache_server_port', 11211);
|
||||
|
||||
// Create the memcache connection
|
||||
if ($this->_persistent)
|
||||
{
|
||||
$session = JFactory::getSession();
|
||||
self::$_db = new Memcached($session->getId());
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$_db = new Memcached;
|
||||
}
|
||||
$memcachedtest = self::$_db->addServer($server['host'], $server['port']);
|
||||
|
||||
if ($memcachedtest == false)
|
||||
{
|
||||
throw new RuntimeException('Could not connect to memcached server', 404);
|
||||
}
|
||||
|
||||
self::$_db->setOption(Memcached::OPT_COMPRESSION, $this->_compress);
|
||||
|
||||
// Memcached has no list keys, we do our own accounting, initialise key index
|
||||
if (self::$_db->get($this->_hash . '-index') === false)
|
||||
{
|
||||
$empty = array();
|
||||
self::$_db->set($this->_hash . '-index', $empty, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data from memcached by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
$back = self::$_db->get($cache_id);
|
||||
return $back;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array data
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$keys = self::$_db->get($this->_hash . '-index');
|
||||
$secret = $this->_hash;
|
||||
|
||||
$data = array();
|
||||
|
||||
if (!empty($keys) && is_array($keys))
|
||||
{
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (empty($key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$namearr = explode('-', $key->name);
|
||||
|
||||
if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache')
|
||||
{
|
||||
|
||||
$group = $namearr[2];
|
||||
|
||||
if (!isset($data[$group]))
|
||||
{
|
||||
$item = new JCacheStorageHelper($group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $data[$group];
|
||||
}
|
||||
|
||||
$item->updateSize($key->size / 1024);
|
||||
|
||||
$data[$group] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to memcached by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$tmparr = new stdClass;
|
||||
$tmparr->name = $cache_id;
|
||||
$tmparr->size = strlen($data);
|
||||
$index[] = $tmparr;
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
// Prevent double writes, write only if it doesn't exist else replace
|
||||
if (!self::$_db->replace($cache_id, $data, $this->_lifetime))
|
||||
{
|
||||
self::$_db->set($cache_id, $data, $this->_lifetime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
if ($value->name == $cache_id)
|
||||
{
|
||||
unset($index[$key]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
return self::$_db->delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$secret = $this->_hash;
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
|
||||
if (strpos($value->name, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group')
|
||||
{
|
||||
self::$_db->delete($value->name, 0);
|
||||
unset($index[$key]);
|
||||
}
|
||||
}
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0);
|
||||
$this->unlockindex();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
if ((extension_loaded('memcached') && class_exists('Memcached')) != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = JFactory::getConfig();
|
||||
$host = $config->get('memcache_server_host', 'localhost');
|
||||
$port = $config->get('memcache_server_port', 11211);
|
||||
|
||||
$memcached = new Memcached;
|
||||
$memcachedtest = @$memcached->addServer($host, $port);
|
||||
|
||||
if (!$memcachedtest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cached item - override parent as this is more efficient
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param integer $locktime Cached item max lock time
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function lock($id, $group, $locktime)
|
||||
{
|
||||
$returning = new stdClass;
|
||||
$returning->locklooped = false;
|
||||
|
||||
$looptime = $locktime * 10;
|
||||
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
$tmparr = new stdClass;
|
||||
$tmparr->name = $cache_id;
|
||||
$tmparr->size = 1;
|
||||
|
||||
$index[] = $tmparr;
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0);
|
||||
|
||||
$this->unlockindex();
|
||||
|
||||
$data_lock = self::$_db->add($cache_id . '_lock', 1, $locktime);
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released.
|
||||
// That implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
$returning->locked = false;
|
||||
$returning->locklooped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = self::$_db->add($cache_id . '_lock', 1, $locktime);
|
||||
$lock_counter++;
|
||||
}
|
||||
|
||||
}
|
||||
$returning->locked = $data_lock;
|
||||
|
||||
return $returning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cached item - override parent for cacheid compatibility with lock
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function unlock($id, $group = null)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group) . '_lock';
|
||||
|
||||
if (!$this->lockindex())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = self::$_db->get($this->_hash . '-index');
|
||||
if ($index === false)
|
||||
{
|
||||
$index = array();
|
||||
}
|
||||
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
if ($value->name == $cache_id)
|
||||
{
|
||||
unset($index[$key]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
self::$_db->replace($this->_hash . '-index', $index, 0);
|
||||
$this->unlockindex();
|
||||
|
||||
return self::$_db->delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock cache index
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function lockindex()
|
||||
{
|
||||
$looptime = 300;
|
||||
$data_lock = self::$_db->add($this->_hash . '-index_lock', 1, 30);
|
||||
|
||||
if ($data_lock === false)
|
||||
{
|
||||
|
||||
$lock_counter = 0;
|
||||
|
||||
// Loop until you find that the lock has been released. that implies that data get from other thread has finished
|
||||
while ($data_lock === false)
|
||||
{
|
||||
if ($lock_counter > $looptime)
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
$data_lock = self::$_db->add($this->_hash . '-index_lock', 1, 30);
|
||||
$lock_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock cache index
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function unlockindex()
|
||||
{
|
||||
return self::$_db->delete($this->_hash . '-index_lock');
|
||||
}
|
||||
}
|
||||
194
libraries/joomla/cache/storage/wincache.php
vendored
Normal file
194
libraries/joomla/cache/storage/wincache.php
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* WINCACHE cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @see http://php.net/manual/en/book.wincache.php
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageWincache extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Optional parameters.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data from WINCACHE by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
$cache_content = wincache_ucache_get($cache_id);
|
||||
return $cache_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* @return array data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$allinfo = wincache_ucache_info();
|
||||
$keys = $allinfo['cache_entries'];
|
||||
$secret = $this->_hash;
|
||||
$data = array();
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
$name = $key['key_name'];
|
||||
$namearr = explode('-', $name);
|
||||
if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache')
|
||||
{
|
||||
$group = $namearr[2];
|
||||
if (!isset($data[$group]))
|
||||
{
|
||||
$item = new JCacheStorageHelper($group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $data[$group];
|
||||
}
|
||||
if (isset($key['value_size']))
|
||||
{
|
||||
$item->updateSize($key['value_size'] / 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dummy, WINCACHE version is too low.
|
||||
$item->updateSize(1);
|
||||
}
|
||||
$data[$group] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data to WINCACHE by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
return wincache_ucache_set($cache_id, $data, $this->_lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
return wincache_ucache_delete($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
$allinfo = wincache_ucache_info();
|
||||
$keys = $allinfo['cache_entries'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (strpos($key['key_name'], $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group')
|
||||
{
|
||||
wincache_ucache_delete($key['key_name']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force garbage collect expired cache data as items are removed only on get/add/delete/info etc
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
$allinfo = wincache_ucache_info();
|
||||
$keys = $allinfo['cache_entries'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (strpos($key['key_name'], $secret . '-cache-'))
|
||||
{
|
||||
wincache_ucache_get($key['key_name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
$test = extension_loaded('wincache') && function_exists('wincache_ucache_get') && !strcmp(ini_get('wincache.ucenabled'), '1');
|
||||
return $test;
|
||||
}
|
||||
}
|
||||
209
libraries/joomla/cache/storage/xcache.php
vendored
Normal file
209
libraries/joomla/cache/storage/xcache.php
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* XCache cache storage handler
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Cache
|
||||
* @link http://xcache.lighttpd.net/
|
||||
* @since 11.1
|
||||
*/
|
||||
class JCacheStorageXcache extends JCacheStorage
|
||||
{
|
||||
/**
|
||||
* Get cached data by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param boolean $checkTime True to verify cache time expiration threshold
|
||||
*
|
||||
* @return mixed Boolean false on failure or a cached data string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function get($id, $group, $checkTime = true)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
$cache_content = xcache_get($cache_id);
|
||||
|
||||
if ($cache_content === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $cache_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached data
|
||||
*
|
||||
* This requires the php.ini setting xcache.admin.enable_auth = Off.
|
||||
*
|
||||
* @return array data
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
parent::getAll();
|
||||
|
||||
$allinfo = xcache_list(XC_TYPE_VAR, 0);
|
||||
$keys = $allinfo['cache_list'];
|
||||
$secret = $this->_hash;
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
|
||||
$namearr = explode('-', $key['name']);
|
||||
|
||||
if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache')
|
||||
{
|
||||
$group = $namearr[2];
|
||||
|
||||
if (!isset($data[$group]))
|
||||
{
|
||||
$item = new JCacheStorageHelper($group);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $data[$group];
|
||||
}
|
||||
|
||||
$item->updateSize($key['size'] / 1024);
|
||||
|
||||
$data[$group] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the data by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
* @param string $data The data to store in cache
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function store($id, $group, $data)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
$store = xcache_set($cache_id, $data, $this->_lifetime);
|
||||
return $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached data entry by id and group
|
||||
*
|
||||
* @param string $id The cache data id
|
||||
* @param string $group The cache data group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function remove($id, $group)
|
||||
{
|
||||
$cache_id = $this->_getCacheId($id, $group);
|
||||
|
||||
if (!xcache_isset($cache_id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return xcache_unset($cache_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cache for a group given a mode.
|
||||
*
|
||||
* This requires the php.ini setting xcache.admin.enable_auth = Off.
|
||||
*
|
||||
* @param string $group The cache data group
|
||||
* @param string $mode The mode for cleaning cache [group|notgroup]
|
||||
* group mode : cleans all cache in the group
|
||||
* notgroup mode : cleans all cache not in the group
|
||||
*
|
||||
* @return boolean True on success, false otherwise
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function clean($group, $mode = null)
|
||||
{
|
||||
$allinfo = xcache_list(XC_TYPE_VAR, 0);
|
||||
$keys = $allinfo['cache_list'];
|
||||
|
||||
$secret = $this->_hash;
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if (strpos($key['name'], $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group')
|
||||
{
|
||||
xcache_unset($key['name']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collect expired cache data
|
||||
*
|
||||
* This is a dummy, since xcache has built in garbage collector, turn it
|
||||
* on in php.ini by changing default xcache.gc_interval setting from
|
||||
* 0 to 3600 (=1 hour)
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function gc()
|
||||
{
|
||||
/*
|
||||
$now = time();
|
||||
|
||||
$cachecount = xcache_count(XC_TYPE_VAR);
|
||||
|
||||
for ($i = 0; $i < $cachecount; $i ++) {
|
||||
|
||||
$allinfo = xcache_list(XC_TYPE_VAR, $i);
|
||||
$keys = $allinfo ['cache_list'];
|
||||
|
||||
foreach($keys as $key) {
|
||||
|
||||
if (strstr($key['name'], $this->_hash)) {
|
||||
if (($key['ctime'] + $this->_lifetime ) < $this->_now) xcache_unset($key['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the cache storage is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return (extension_loaded('xcache'));
|
||||
}
|
||||
}
|
||||
1788
libraries/joomla/client/ftp.php
Normal file
1788
libraries/joomla/client/ftp.php
Normal file
File diff suppressed because it is too large
Load Diff
240
libraries/joomla/client/helper.php
Normal file
240
libraries/joomla/client/helper.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Client
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Client helper class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Client
|
||||
* @since 11.1
|
||||
*/
|
||||
class JClientHelper
|
||||
{
|
||||
/**
|
||||
* Method to return the array of client layer configuration options
|
||||
*
|
||||
* @param string $client Client name, currently only 'ftp' is supported
|
||||
* @param boolean $force Forces re-creation of the login credentials. Set this to
|
||||
* true if login credentials in the session storage have changed
|
||||
*
|
||||
* @return array Client layer configuration options, consisting of at least
|
||||
* these fields: enabled, host, port, user, pass, root
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function getCredentials($client, $force = false)
|
||||
{
|
||||
static $credentials = array();
|
||||
|
||||
$client = strtolower($client);
|
||||
|
||||
if (!isset($credentials[$client]) || $force)
|
||||
{
|
||||
$config = JFactory::getConfig();
|
||||
|
||||
// Fetch the client layer configuration options for the specific client
|
||||
switch ($client)
|
||||
{
|
||||
case 'ftp':
|
||||
$options = array(
|
||||
'enabled' => $config->get('ftp_enable'),
|
||||
'host' => $config->get('ftp_host'),
|
||||
'port' => $config->get('ftp_port'),
|
||||
'user' => $config->get('ftp_user'),
|
||||
'pass' => $config->get('ftp_pass'),
|
||||
'root' => $config->get('ftp_root'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$options = array('enabled' => false, 'host' => '', 'port' => '', 'user' => '', 'pass' => '', 'root' => '');
|
||||
break;
|
||||
}
|
||||
|
||||
// If user and pass are not set in global config lets see if they are in the session
|
||||
if ($options['enabled'] == true && ($options['user'] == '' || $options['pass'] == ''))
|
||||
{
|
||||
$session = JFactory::getSession();
|
||||
$options['user'] = $session->get($client . '.user', null, 'JClientHelper');
|
||||
$options['pass'] = $session->get($client . '.pass', null, 'JClientHelper');
|
||||
}
|
||||
|
||||
// If user or pass are missing, disable this client
|
||||
if ($options['user'] == '' || $options['pass'] == '')
|
||||
{
|
||||
$options['enabled'] = false;
|
||||
}
|
||||
|
||||
// Save the credentials for later use
|
||||
$credentials[$client] = $options;
|
||||
}
|
||||
|
||||
return $credentials[$client];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set client login credentials
|
||||
*
|
||||
* @param string $client Client name, currently only 'ftp' is supported
|
||||
* @param string $user Username
|
||||
* @param string $pass Password
|
||||
*
|
||||
* @return boolean True if the given login credentials have been set and are valid
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function setCredentials($client, $user, $pass)
|
||||
{
|
||||
$return = false;
|
||||
$client = strtolower($client);
|
||||
|
||||
// Test if the given credentials are valid
|
||||
switch ($client)
|
||||
{
|
||||
case 'ftp':
|
||||
$config = JFactory::getConfig();
|
||||
$options = array('enabled' => $config->get('ftp_enable'), 'host' => $config->get('ftp_host'), 'port' => $config->get('ftp_port'));
|
||||
|
||||
if ($options['enabled'])
|
||||
{
|
||||
$ftp = JClientFtp::getInstance($options['host'], $options['port']);
|
||||
|
||||
// Test the connection and try to log in
|
||||
if ($ftp->isConnected())
|
||||
{
|
||||
if ($ftp->login($user, $pass))
|
||||
{
|
||||
$return = true;
|
||||
}
|
||||
$ftp->quit();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ($return)
|
||||
{
|
||||
// Save valid credentials to the session
|
||||
$session = JFactory::getSession();
|
||||
$session->set($client . '.user', $user, 'JClientHelper');
|
||||
$session->set($client . '.pass', $pass, 'JClientHelper');
|
||||
|
||||
// Force re-creation of the data saved within JClientHelper::getCredentials()
|
||||
self::getCredentials($client, true);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if client login credentials are present
|
||||
*
|
||||
* @param string $client Client name, currently only 'ftp' is supported
|
||||
*
|
||||
* @return boolean True if login credentials are available
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public static function hasCredentials($client)
|
||||
{
|
||||
$return = false;
|
||||
$client = strtolower($client);
|
||||
|
||||
// Get (unmodified) credentials for this client
|
||||
switch ($client)
|
||||
{
|
||||
case 'ftp':
|
||||
$config = JFactory::getConfig();
|
||||
$options = array('enabled' => $config->get('ftp_enable'), 'user' => $config->get('ftp_user'), 'pass' => $config->get('ftp_pass'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$options = array('enabled' => false, 'user' => '', 'pass' => '');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($options['enabled'] == false)
|
||||
{
|
||||
// The client is disabled in global config, so let's pretend we are OK
|
||||
$return = true;
|
||||
}
|
||||
elseif ($options['user'] != '' && $options['pass'] != '')
|
||||
{
|
||||
// Login credentials are available in global config
|
||||
$return = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if login credentials are available in the session
|
||||
$session = JFactory::getSession();
|
||||
$user = $session->get($client . '.user', null, 'JClientHelper');
|
||||
$pass = $session->get($client . '.pass', null, 'JClientHelper');
|
||||
|
||||
if ($user != '' && $pass != '')
|
||||
{
|
||||
$return = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether input fields for client settings need to be shown
|
||||
*
|
||||
* If valid credentials were passed along with the request, they are saved to the session.
|
||||
* This functions returns an exception if invalid credentials have been given or if the
|
||||
* connection to the server failed for some other reason.
|
||||
*
|
||||
* @param string $client The name of the client.
|
||||
*
|
||||
* @return mixed True, if FTP settings; JError if using legacy tree.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws InvalidArgumentException if credentials invalid
|
||||
*/
|
||||
public static function setCredentialsFromRequest($client)
|
||||
{
|
||||
// Determine whether FTP credentials have been passed along with the current request
|
||||
$input = JFactory::getApplication()->input;
|
||||
$user = $input->post->getString('username', null);
|
||||
$pass = $input->post->getString('password', null);
|
||||
|
||||
if ($user != '' && $pass != '')
|
||||
{
|
||||
// Add credentials to the session
|
||||
if (self::setCredentials($client, $user, $pass))
|
||||
{
|
||||
$return = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (class_exists('JError'))
|
||||
{
|
||||
$return = JError::raiseWarning('SOME_ERROR_CODE', JText::_('JLIB_CLIENT_ERROR_HELPER_SETCREDENTIALSFROMREQUEST_FAILED'));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid user credentials');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just determine if the FTP input fields need to be shown
|
||||
$return = !self::hasCredentials('ftp');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/client/index.html
Normal file
1
libraries/joomla/client/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
683
libraries/joomla/client/ldap.php
Normal file
683
libraries/joomla/client/ldap.php
Normal file
@ -0,0 +1,683 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Client
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* LDAP client class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Client
|
||||
* @since 12.1
|
||||
*/
|
||||
class JClientLdap
|
||||
{
|
||||
/**
|
||||
* @var string Hostname of LDAP server
|
||||
* @since 12.1
|
||||
*/
|
||||
public $host = null;
|
||||
|
||||
/**
|
||||
* @var bool Authorization Method to use
|
||||
* @since 12.1
|
||||
*/
|
||||
public $auth_method = null;
|
||||
|
||||
/**
|
||||
* @var int Port of LDAP server
|
||||
* @since 12.1
|
||||
*/
|
||||
public $port = null;
|
||||
|
||||
/**
|
||||
* @var string Base DN (e.g. o=MyDir)
|
||||
* @since 12.1
|
||||
*/
|
||||
public $base_dn = null;
|
||||
|
||||
/**
|
||||
* @var string User DN (e.g. cn=Users,o=MyDir)
|
||||
* @since 12.1
|
||||
*/
|
||||
public $users_dn = null;
|
||||
|
||||
/**
|
||||
* @var string Search String
|
||||
* @since 12.1
|
||||
*/
|
||||
public $search_string = null;
|
||||
|
||||
/**
|
||||
* @var boolean Use LDAP Version 3
|
||||
* @since 12.1
|
||||
*/
|
||||
public $use_ldapV3 = null;
|
||||
|
||||
/**
|
||||
* @var boolean No referrals (server transfers)
|
||||
* @since 11.1
|
||||
*/
|
||||
public $no_referrals = null;
|
||||
|
||||
/**
|
||||
* @var boolean Negotiate TLS (encrypted communications)
|
||||
* @since 12.1
|
||||
*/
|
||||
public $negotiate_tls = null;
|
||||
|
||||
/**
|
||||
* @var string Username to connect to server
|
||||
* @since 12.1
|
||||
*/
|
||||
public $username = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string Password to connect to server
|
||||
* @since 12.1
|
||||
*/
|
||||
public $password = null;
|
||||
|
||||
/**
|
||||
* @var mixed LDAP Resource Identifier
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_resource = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string Current DN
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_dn = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $configObj An object of configuration variables
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($configObj = null)
|
||||
{
|
||||
if (is_object($configObj))
|
||||
{
|
||||
$vars = get_class_vars(get_class($this));
|
||||
|
||||
foreach (array_keys($vars) as $var)
|
||||
{
|
||||
if (substr($var, 0, 1) != '_')
|
||||
{
|
||||
$param = $configObj->get($var);
|
||||
|
||||
if ($param)
|
||||
{
|
||||
$this->$var = $param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to server
|
||||
*
|
||||
* @return boolean True if successful
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->host == '')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_resource = @ ldap_connect($this->host, $this->port);
|
||||
|
||||
if ($this->_resource)
|
||||
{
|
||||
if ($this->use_ldapV3)
|
||||
{
|
||||
if (!@ldap_set_option($this->_resource, LDAP_OPT_PROTOCOL_VERSION, 3))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!@ldap_set_option($this->_resource, LDAP_OPT_REFERRALS, (int) $this->no_referrals))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->negotiate_tls)
|
||||
{
|
||||
if (!@ldap_start_tls($this->_resource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@ ldap_close($this->_resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DN with some template replacements
|
||||
*
|
||||
* @param string $username The username
|
||||
* @param string $nosub ...
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setDN($username, $nosub = 0)
|
||||
{
|
||||
if ($this->users_dn == '' || $nosub)
|
||||
{
|
||||
$this->_dn = $username;
|
||||
}
|
||||
elseif (strlen($username))
|
||||
{
|
||||
$this->_dn = str_replace('[username]', $username, $this->users_dn);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_dn = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DN
|
||||
*
|
||||
* @return string The current dn
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getDN()
|
||||
{
|
||||
return $this->_dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymously binds to LDAP directory
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function anonymous_bind()
|
||||
{
|
||||
$bindResult = @ldap_bind($this->_resource);
|
||||
|
||||
return $bindResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds to the LDAP directory
|
||||
*
|
||||
* @param string $username The username
|
||||
* @param string $password The password
|
||||
* @param string $nosub ...
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function bind($username = null, $password = null, $nosub = 0)
|
||||
{
|
||||
if (is_null($username))
|
||||
{
|
||||
$username = $this->username;
|
||||
}
|
||||
|
||||
if (is_null($password))
|
||||
{
|
||||
$password = $this->password;
|
||||
}
|
||||
|
||||
$this->setDN($username, $nosub);
|
||||
$bindResult = @ldap_bind($this->_resource, $this->getDN(), $password);
|
||||
|
||||
return $bindResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an LDAP search using comma separated search strings
|
||||
*
|
||||
* @param string $search search string of search values
|
||||
*
|
||||
* @return array Search results
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function simple_search($search)
|
||||
{
|
||||
$results = explode(';', $search);
|
||||
|
||||
foreach ($results as $key => $result)
|
||||
{
|
||||
$results[$key] = '(' . $result . ')';
|
||||
}
|
||||
|
||||
return $this->search($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an LDAP search
|
||||
*
|
||||
* @param array $filters Search Filters (array of strings)
|
||||
* @param string $dnoverride DN Override
|
||||
* @param array $attributes An array of attributes to return (if empty, all fields are returned).
|
||||
*
|
||||
* @return array Multidimensional array of results
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function search(array $filters, $dnoverride = null, array $attributes = array())
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if ($dnoverride)
|
||||
{
|
||||
$dn = $dnoverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dn = $this->base_dn;
|
||||
}
|
||||
|
||||
$resource = $this->_resource;
|
||||
|
||||
foreach ($filters as $search_filter)
|
||||
{
|
||||
$search_result = @ldap_search($resource, $dn, $search_filter, $attributes);
|
||||
|
||||
if ($search_result && ($count = @ldap_count_entries($resource, $search_result)) > 0)
|
||||
{
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
$result[$i] = array();
|
||||
|
||||
if (!$i)
|
||||
{
|
||||
$firstentry = @ldap_first_entry($resource, $search_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
$firstentry = @ldap_next_entry($resource, $firstentry);
|
||||
}
|
||||
|
||||
// Load user-specified attributes
|
||||
$result_array = @ldap_get_attributes($resource, $firstentry);
|
||||
|
||||
// LDAP returns an array of arrays, fit this into attributes result array
|
||||
foreach ($result_array as $ki => $ai)
|
||||
{
|
||||
if (is_array($ai))
|
||||
{
|
||||
$subcount = $ai['count'];
|
||||
$result[$i][$ki] = array();
|
||||
|
||||
for ($k = 0; $k < $subcount; $k++)
|
||||
{
|
||||
$result[$i][$ki][$k] = $ai[$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result[$i]['dn'] = @ldap_get_dn($resource, $firstentry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an entry and return a true or false result
|
||||
*
|
||||
* @param string $dn The DN which contains the attribute you want to replace
|
||||
* @param string $attribute The attribute values you want to replace
|
||||
*
|
||||
* @return mixed result of comparison (true, false, -1 on error)
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function replace($dn, $attribute)
|
||||
{
|
||||
return @ldap_mod_replace($this->_resource, $dn, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies an entry and return a true or false result
|
||||
*
|
||||
* @param string $dn The DN which contains the attribute you want to modify
|
||||
* @param string $attribute The attribute values you want to modify
|
||||
*
|
||||
* @return mixed result of comparison (true, false, -1 on error)
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function modify($dn, $attribute)
|
||||
{
|
||||
return @ldap_modify($this->_resource, $dn, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes attribute value from given dn and return a true or false result
|
||||
*
|
||||
* @param string $dn The DN which contains the attribute you want to remove
|
||||
* @param string $attribute The attribute values you want to remove
|
||||
*
|
||||
* @return mixed result of comparison (true, false, -1 on error)
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function remove($dn, $attribute)
|
||||
{
|
||||
$resource = $this->_resource;
|
||||
|
||||
return @ldap_mod_del($resource, $dn, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare an entry and return a true or false result
|
||||
*
|
||||
* @param string $dn The DN which contains the attribute you want to compare
|
||||
* @param string $attribute The attribute whose value you want to compare
|
||||
* @param string $value The value you want to check against the LDAP attribute
|
||||
*
|
||||
* @return mixed result of comparison (true, false, -1 on error)
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function compare($dn, $attribute, $value)
|
||||
{
|
||||
return @ldap_compare($this->_resource, $dn, $attribute, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all or specified attributes of given dn
|
||||
*
|
||||
* @param string $dn The DN of the object you want to read
|
||||
*
|
||||
* @return mixed array of attributes or -1 on error
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function read($dn)
|
||||
{
|
||||
$base = substr($dn, strpos($dn, ',') + 1);
|
||||
$cn = substr($dn, 0, strpos($dn, ','));
|
||||
$result = @ldap_read($this->_resource, $base, $cn);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
return @ldap_get_entries($this->_resource, $result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given DN from the tree
|
||||
*
|
||||
* @param string $dn The DN of the object you want to delete
|
||||
*
|
||||
* @return boolean Result of operation
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function delete($dn)
|
||||
{
|
||||
return @ldap_delete($this->_resource, $dn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DN
|
||||
*
|
||||
* @param string $dn The DN where you want to put the object
|
||||
* @param array $entries An array of arrays describing the object to add
|
||||
*
|
||||
* @return boolean Result of operation
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function create($dn, array $entries)
|
||||
{
|
||||
return @ldap_add($this->_resource, $dn, $entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attribute to the given DN
|
||||
* Note: DN has to exist already
|
||||
*
|
||||
* @param string $dn The DN of the entry to add the attribute
|
||||
* @param array $entry An array of arrays with attributes to add
|
||||
*
|
||||
* @return boolean Result of operation
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function add($dn, array $entry)
|
||||
{
|
||||
return @ldap_mod_add($this->_resource, $dn, $entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename the entry
|
||||
*
|
||||
* @param string $dn The DN of the entry at the moment
|
||||
* @param string $newdn The DN of the entry should be (only cn=newvalue)
|
||||
* @param string $newparent The full DN of the parent (null by default)
|
||||
* @param boolean $deleteolddn Delete the old values (default)
|
||||
*
|
||||
* @return boolean Result of operation
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function rename($dn, $newdn, $newparent, $deleteolddn)
|
||||
{
|
||||
return @ldap_rename($this->_resource, $dn, $newdn, $newparent, $deleteolddn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message
|
||||
*
|
||||
* @return string error message
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getErrorMsg()
|
||||
{
|
||||
return @ldap_error($this->_resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a dot notation IP address to net address (e.g. for Netware, etc)
|
||||
*
|
||||
* @param string $ip IP Address (e.g. xxx.xxx.xxx.xxx)
|
||||
*
|
||||
* @return string Net address
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function ipToNetAddress($ip)
|
||||
{
|
||||
$parts = explode('.', $ip);
|
||||
$address = '1#';
|
||||
|
||||
foreach ($parts as $int)
|
||||
{
|
||||
$tmp = dechex($int);
|
||||
|
||||
if (strlen($tmp) != 2)
|
||||
{
|
||||
$tmp = '0' . $tmp;
|
||||
}
|
||||
|
||||
$address .= '\\' . $tmp;
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract readable network address from the LDAP encoded networkAddress attribute.
|
||||
*
|
||||
* Please keep this document block and author attribution in place.
|
||||
*
|
||||
* Novell Docs, see: http://developer.novell.com/ndk/doc/ndslib/schm_enu/data/sdk5624.html#sdk5624
|
||||
* for Address types: http://developer.novell.com/ndk/doc/ndslib/index.html?page=/ndk/doc/ndslib/schm_enu/data/sdk4170.html
|
||||
* LDAP Format, String:
|
||||
* taggedData = uint32String "#" octetstring
|
||||
* byte 0 = uint32String = Address Type: 0= IPX Address; 1 = IP Address
|
||||
* byte 1 = char = "#" - separator
|
||||
* byte 2+ = octetstring - the ordinal value of the address
|
||||
* Note: with eDirectory 8.6.2, the IP address (type 1) returns
|
||||
* correctly, however, an IPX address does not seem to. eDir 8.7 may correct this.
|
||||
* Enhancement made by Merijn van de Schoot:
|
||||
* If addresstype is 8 (UDP) or 9 (TCP) do some additional parsing like still returning the IP address
|
||||
*
|
||||
* @param string $networkaddress The network address
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @author Jay Burrell, Systems & Networks, Mississippi State University
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function LDAPNetAddr($networkaddress)
|
||||
{
|
||||
$addr = "";
|
||||
$addrtype = (int) substr($networkaddress, 0, 1);
|
||||
|
||||
// Throw away bytes 0 and 1 which should be the addrtype and the "#" separator
|
||||
$networkaddress = substr($networkaddress, 2);
|
||||
|
||||
if (($addrtype == 8) || ($addrtype = 9))
|
||||
{
|
||||
// TODO 1.6: If UDP or TCP, (TODO fill addrport and) strip portnumber information from address
|
||||
$networkaddress = substr($networkaddress, (strlen($networkaddress) - 4));
|
||||
}
|
||||
|
||||
$addrtypes = array(
|
||||
'IPX',
|
||||
'IP',
|
||||
'SDLC',
|
||||
'Token Ring',
|
||||
'OSI',
|
||||
'AppleTalk',
|
||||
'NetBEUI',
|
||||
'Socket',
|
||||
'UDP',
|
||||
'TCP',
|
||||
'UDP6',
|
||||
'TCP6',
|
||||
'Reserved (12)',
|
||||
'URL',
|
||||
'Count');
|
||||
$len = strlen($networkaddress);
|
||||
|
||||
if ($len > 0)
|
||||
{
|
||||
for ($i = 0; $i < $len; $i++)
|
||||
{
|
||||
$byte = substr($networkaddress, $i, 1);
|
||||
$addr .= ord($byte);
|
||||
|
||||
if (($addrtype == 1) || ($addrtype == 8) || ($addrtype = 9))
|
||||
{
|
||||
// Dot separate IP addresses...
|
||||
$addr .= ".";
|
||||
}
|
||||
}
|
||||
if (($addrtype == 1) || ($addrtype == 8) || ($addrtype = 9))
|
||||
{
|
||||
// Strip last period from end of $addr
|
||||
$addr = substr($addr, 0, strlen($addr) - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$addr .= JText::_('JLIB_CLIENT_ERROR_LDAP_ADDRESS_NOT_AVAILABLE');
|
||||
}
|
||||
return array('protocol' => $addrtypes[$addrtype], 'address' => $addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a LDAP compatible password
|
||||
*
|
||||
* @param string $password Clear text password to encrypt
|
||||
* @param string $type Type of password hash, either md5 or SHA
|
||||
*
|
||||
* @return string Encrypted password
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function generatePassword($password, $type = 'md5')
|
||||
{
|
||||
switch (strtolower($type))
|
||||
{
|
||||
case 'sha':
|
||||
$userpassword = '{SHA}' . base64_encode(pack('H*', sha1($password)));
|
||||
break;
|
||||
case 'md5':
|
||||
default:
|
||||
$userpassword = '{MD5}' . base64_encode(pack('H*', md5($password)));
|
||||
break;
|
||||
}
|
||||
|
||||
return $userpassword;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated class placeholder. You should use JClientLdap instead.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Client
|
||||
* @since 11.1
|
||||
* @deprecated 12.3 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
class JLDAP extends JClientLdap
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $configObj An object of configuration variables
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct($configObj = null)
|
||||
{
|
||||
JLog::add('JLDAP is deprecated. Use JClientLdap instead.', JLog::WARNING, 'deprecated');
|
||||
parent::__construct($configObj);
|
||||
}
|
||||
}
|
||||
137
libraries/joomla/controller/base.php
Normal file
137
libraries/joomla/controller/base.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Controller
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Base Controller Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Controller
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JControllerBase implements JController
|
||||
{
|
||||
/**
|
||||
* The application object.
|
||||
*
|
||||
* @var JApplicationBase
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* The input object.
|
||||
*
|
||||
* @var JInput
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* Instantiate the controller.
|
||||
*
|
||||
* @param JInput $input The input object.
|
||||
* @param JApplicationBase $app The application object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct(JInput $input = null, JApplicationBase $app = null)
|
||||
{
|
||||
// Setup dependencies.
|
||||
$this->app = isset($app) ? $app : $this->loadApplication();
|
||||
$this->input = isset($input) ? $input : $this->loadInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application object.
|
||||
*
|
||||
* @return JApplicationBase The application object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input object.
|
||||
*
|
||||
* @return JInput The input object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the controller.
|
||||
*
|
||||
* @return string The serialized controller.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize the controller.
|
||||
*
|
||||
* @param string $input The serialized controller.
|
||||
*
|
||||
* @return JController Supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws UnexpectedValueException if input is not the right class.
|
||||
*/
|
||||
public function unserialize($input)
|
||||
{
|
||||
// Setup dependencies.
|
||||
$this->app = $this->loadApplication();
|
||||
|
||||
// Unserialize the input.
|
||||
$this->input = unserialize($input);
|
||||
|
||||
if (!($this->input instanceof JInput))
|
||||
{
|
||||
throw new UnexpectedValueException(sprintf('%s::unserialize would not accept a `%s`.', get_class($this), gettype($this->input)));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the application object.
|
||||
*
|
||||
* @return JApplicationBase The application object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function loadApplication()
|
||||
{
|
||||
return JFactory::getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the input object.
|
||||
*
|
||||
* @return JInput The input object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function loadInput()
|
||||
{
|
||||
return $this->app->input;
|
||||
}
|
||||
}
|
||||
51
libraries/joomla/controller/controller.php
Normal file
51
libraries/joomla/controller/controller.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Controller
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Controller Interface
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Controller
|
||||
* @since 12.1
|
||||
*/
|
||||
interface JController extends Serializable
|
||||
{
|
||||
/**
|
||||
* Execute the controller.
|
||||
*
|
||||
* @return boolean True if controller finished execution, false if the controller did not
|
||||
* finish execution. A controller might return false if some precondition for
|
||||
* the controller to run has not been satisfied.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws LogicException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function execute();
|
||||
|
||||
/**
|
||||
* Get the application object.
|
||||
*
|
||||
* @return JApplicationBase The application object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getApplication();
|
||||
|
||||
/**
|
||||
* Get the input object.
|
||||
*
|
||||
* @return JInput The input object.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getInput();
|
||||
}
|
||||
1
libraries/joomla/controller/index.html
Normal file
1
libraries/joomla/controller/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
55
libraries/joomla/crypt/cipher.php
Normal file
55
libraries/joomla/crypt/cipher.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher interface.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
interface JCryptCipher
|
||||
{
|
||||
/**
|
||||
* Method to decrypt a data string.
|
||||
*
|
||||
* @param string $data The encrypted string to decrypt.
|
||||
* @param JCryptKey $key The key[/pair] object to use for decryption.
|
||||
*
|
||||
* @return string The decrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function decrypt($data, JCryptKey $key);
|
||||
|
||||
/**
|
||||
* Method to encrypt a data string.
|
||||
*
|
||||
* @param string $data The data string to encrypt.
|
||||
* @param JCryptKey $key The key[/pair] object to use for encryption.
|
||||
*
|
||||
* @return string The encrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function encrypt($data, JCryptKey $key);
|
||||
|
||||
/**
|
||||
* Method to generate a new encryption key[/pair] object.
|
||||
*
|
||||
* @param array $options Key generation options.
|
||||
*
|
||||
* @return JCryptKey
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function generateKey(array $options = array());
|
||||
}
|
||||
40
libraries/joomla/crypt/cipher/3des.php
Normal file
40
libraries/joomla/crypt/cipher/3des.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher for Triple DES encryption, decryption and key generation.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCryptCipher3DES extends JCryptCipherMcrypt
|
||||
{
|
||||
/**
|
||||
* @var integer The mcrypt cipher constant.
|
||||
* @see http://www.php.net/manual/en/mcrypt.ciphers.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $type = MCRYPT_3DES;
|
||||
|
||||
/**
|
||||
* @var integer The mcrypt block cipher mode.
|
||||
* @see http://www.php.net/manual/en/mcrypt.constants.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $mode = MCRYPT_MODE_CBC;
|
||||
|
||||
/**
|
||||
* @var string The JCrypt key type for validation.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $keyType = '3des';
|
||||
}
|
||||
40
libraries/joomla/crypt/cipher/blowfish.php
Normal file
40
libraries/joomla/crypt/cipher/blowfish.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher for Blowfish encryption, decryption and key generation.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCryptCipherBlowfish extends JCryptCipherMcrypt
|
||||
{
|
||||
/**
|
||||
* @var integer The mcrypt cipher constant.
|
||||
* @see http://www.php.net/manual/en/mcrypt.ciphers.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $type = MCRYPT_BLOWFISH;
|
||||
|
||||
/**
|
||||
* @var integer The mcrypt block cipher mode.
|
||||
* @see http://www.php.net/manual/en/mcrypt.constants.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $mode = MCRYPT_MODE_CBC;
|
||||
|
||||
/**
|
||||
* @var string The JCrypt key type for validation.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $keyType = 'blowfish';
|
||||
}
|
||||
1
libraries/joomla/crypt/cipher/index.html
Normal file
1
libraries/joomla/crypt/cipher/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
175
libraries/joomla/crypt/cipher/mcrypt.php
Normal file
175
libraries/joomla/crypt/cipher/mcrypt.php
Normal file
@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher for mcrypt algorithm encryption, decryption and key generation.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JCryptCipherMcrypt implements JCryptCipher
|
||||
{
|
||||
/**
|
||||
* @var integer The mcrypt cipher constant.
|
||||
* @see http://www.php.net/manual/en/mcrypt.ciphers.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var integer The mcrypt block cipher mode.
|
||||
* @see http://www.php.net/manual/en/mcrypt.constants.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $mode;
|
||||
|
||||
/**
|
||||
* @var string The JCrypt key type for validation.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $keyType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!is_callable('mcrypt_encrypt'))
|
||||
{
|
||||
throw new RuntimeException('The mcrypt extension is not available.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to decrypt a data string.
|
||||
*
|
||||
* @param string $data The encrypted string to decrypt.
|
||||
* @param JCryptKey $key The key object to use for decryption.
|
||||
*
|
||||
* @return string The decrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function decrypt($data, JCryptKey $key)
|
||||
{
|
||||
// Validate key.
|
||||
if ($key->type != $this->keyType)
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected ' . $this->keyType . '.');
|
||||
}
|
||||
|
||||
// Decrypt the data.
|
||||
$decrypted = trim(mcrypt_decrypt($this->type, $key->private, $data, $this->mode, $key->public));
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to encrypt a data string.
|
||||
*
|
||||
* @param string $data The data string to encrypt.
|
||||
* @param JCryptKey $key The key object to use for encryption.
|
||||
*
|
||||
* @return string The encrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function encrypt($data, JCryptKey $key)
|
||||
{
|
||||
// Validate key.
|
||||
if ($key->type != $this->keyType)
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected ' . $this->keyType . '.');
|
||||
}
|
||||
|
||||
// Encrypt the data.
|
||||
$encrypted = mcrypt_encrypt($this->type, $key->private, $data, $this->mode, $key->public);
|
||||
|
||||
return $encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate a new encryption key object.
|
||||
*
|
||||
* @param array $options Key generation options.
|
||||
*
|
||||
* @return JCryptKey
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function generateKey(array $options = array())
|
||||
{
|
||||
// Create the new encryption key object.
|
||||
$key = new JCryptKey($this->keyType);
|
||||
|
||||
// Generate an initialisation vector based on the algorithm.
|
||||
$key->public = mcrypt_create_iv(mcrypt_get_iv_size($this->type, $this->mode));
|
||||
|
||||
// Get the salt and password setup.
|
||||
$salt = (isset($options['salt'])) ? $options['salt'] : substr(pack("h*", md5(mt_rand())), 0, 16);
|
||||
$password = (isset($options['password'])) ? $options['password'] : 'J00ml4R0ck$!';
|
||||
|
||||
// Generate the derived key.
|
||||
$key->private = $this->pbkdf2($password, $salt, mcrypt_get_key_size($this->type, $this->mode));
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* PBKDF2 Implementation for deriving keys.
|
||||
*
|
||||
* @param string $p Password
|
||||
* @param string $s Salt
|
||||
* @param integer $kl Key length
|
||||
* @param integer $c Iteration count
|
||||
* @param string $a Hash algorithm
|
||||
*
|
||||
* @return string The derived key.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/PBKDF2
|
||||
* @see http://www.ietf.org/rfc/rfc2898.txt
|
||||
* @since 12.1
|
||||
*/
|
||||
public function pbkdf2($p, $s, $kl, $c = 10000, $a = 'sha256')
|
||||
{
|
||||
// Hash length.
|
||||
$hl = strlen(hash($a, null, true));
|
||||
|
||||
// Key blocks to compute.
|
||||
$kb = ceil($kl / $hl);
|
||||
|
||||
// Derived key.
|
||||
$dk = '';
|
||||
|
||||
// Create the key.
|
||||
for ($block = 1; $block <= $kb; $block++)
|
||||
{
|
||||
// Initial hash for this block.
|
||||
$ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
|
||||
|
||||
// Perform block iterations.
|
||||
for ($i = 1; $i < $c; $i++)
|
||||
{
|
||||
$ib ^= ($b = hash_hmac($a, $b, $p, true));
|
||||
}
|
||||
|
||||
// Append the iterated block.
|
||||
$dk .= $ib;
|
||||
}
|
||||
|
||||
// Return derived key of correct length.
|
||||
return substr($dk, 0, $kl);
|
||||
}
|
||||
}
|
||||
40
libraries/joomla/crypt/cipher/rijndael256.php
Normal file
40
libraries/joomla/crypt/cipher/rijndael256.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher for Rijndael 256 encryption, decryption and key generation.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCryptCipherRijndael256 extends JCryptCipherMcrypt
|
||||
{
|
||||
/**
|
||||
* @var integer The mcrypt cipher constant.
|
||||
* @see http://www.php.net/manual/en/mcrypt.ciphers.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $type = MCRYPT_RIJNDAEL_256;
|
||||
|
||||
/**
|
||||
* @var integer The mcrypt block cipher mode.
|
||||
* @see http://www.php.net/manual/en/mcrypt.constants.php
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $mode = MCRYPT_MODE_CBC;
|
||||
|
||||
/**
|
||||
* @var string The JCrypt key type for validation.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $keyType = 'rijndael256';
|
||||
}
|
||||
284
libraries/joomla/crypt/cipher/simple.php
Normal file
284
libraries/joomla/crypt/cipher/simple.php
Normal file
@ -0,0 +1,284 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt cipher for Simple encryption, decryption and key generation.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCryptCipherSimple implements JCryptCipher
|
||||
{
|
||||
/**
|
||||
* Method to decrypt a data string.
|
||||
*
|
||||
* @param string $data The encrypted string to decrypt.
|
||||
* @param JCryptKey $key The key[/pair] object to use for decryption.
|
||||
*
|
||||
* @return string The decrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function decrypt($data, JCryptKey $key)
|
||||
{
|
||||
// Validate key.
|
||||
if ($key->type != 'simple')
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected simple.');
|
||||
}
|
||||
|
||||
$decrypted = '';
|
||||
$tmp = $key->public;
|
||||
|
||||
// Convert the HEX input into an array of integers and get the number of characters.
|
||||
$chars = $this->_hexToIntArray($data);
|
||||
$charCount = count($chars);
|
||||
|
||||
// Repeat the key as many times as necessary to ensure that the key is at least as long as the input.
|
||||
for ($i = 0; $i < $charCount; $i = strlen($tmp))
|
||||
{
|
||||
$tmp = $tmp . $tmp;
|
||||
}
|
||||
|
||||
// Get the XOR values between the ASCII values of the input and key characters for all input offsets.
|
||||
for ($i = 0; $i < $charCount; $i++)
|
||||
{
|
||||
$decrypted .= chr($chars[$i] ^ ord($tmp[$i]));
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to encrypt a data string.
|
||||
*
|
||||
* @param string $data The data string to encrypt.
|
||||
* @param JCryptKey $key The key[/pair] object to use for encryption.
|
||||
*
|
||||
* @return string The encrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function encrypt($data, JCryptKey $key)
|
||||
{
|
||||
// Validate key.
|
||||
if ($key->type != 'simple')
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected simple.');
|
||||
}
|
||||
|
||||
$encrypted = '';
|
||||
$tmp = $key->private;
|
||||
|
||||
// Split up the input into a character array and get the number of characters.
|
||||
$chars = preg_split('//', $data, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$charCount = count($chars);
|
||||
|
||||
// Repeat the key as many times as necessary to ensure that the key is at least as long as the input.
|
||||
for ($i = 0; $i < $charCount; $i = strlen($tmp))
|
||||
{
|
||||
$tmp = $tmp . $tmp;
|
||||
}
|
||||
|
||||
// Get the XOR values between the ASCII values of the input and key characters for all input offsets.
|
||||
for ($i = 0; $i < $charCount; $i++)
|
||||
{
|
||||
$encrypted .= $this->_intToHex(ord($tmp[$i]) ^ ord($chars[$i]));
|
||||
}
|
||||
|
||||
return $encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate a new encryption key[/pair] object.
|
||||
*
|
||||
* @param array $options Key generation options.
|
||||
*
|
||||
* @return JCryptKey
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function generateKey(array $options = array())
|
||||
{
|
||||
// Create the new encryption key[/pair] object.
|
||||
$key = new JCryptKey('simple');
|
||||
|
||||
// Just a random key of a given length.
|
||||
$key->private = $this->_getRandomKey();
|
||||
$key->public = $key->private;
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate a random key of a given length.
|
||||
*
|
||||
* @param integer $length The length of the key to generate.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
private function _getRandomKey($length = 256)
|
||||
{
|
||||
$key = '';
|
||||
$salt = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$saltLength = strlen($salt);
|
||||
|
||||
// Build the random key.
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$key .= $salt[mt_rand(0, $saltLength - 1)];
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex to an integer
|
||||
*
|
||||
* @param string $s The hex string to convert.
|
||||
* @param integer $i The offset?
|
||||
*
|
||||
* @return integer
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
private function _hexToInt($s, $i)
|
||||
{
|
||||
$j = (int) $i * 2;
|
||||
$k = 0;
|
||||
$s1 = (string) $s;
|
||||
|
||||
// Get the character at position $j.
|
||||
$c = substr($s1, $j, 1);
|
||||
|
||||
// Get the character at position $j + 1.
|
||||
$c1 = substr($s1, $j + 1, 1);
|
||||
|
||||
switch ($c)
|
||||
{
|
||||
case 'A':
|
||||
$k += 160;
|
||||
break;
|
||||
case 'B':
|
||||
$k += 176;
|
||||
break;
|
||||
case 'C':
|
||||
$k += 192;
|
||||
break;
|
||||
case 'D':
|
||||
$k += 208;
|
||||
break;
|
||||
case 'E':
|
||||
$k += 224;
|
||||
break;
|
||||
case 'F':
|
||||
$k += 240;
|
||||
break;
|
||||
case ' ':
|
||||
$k += 0;
|
||||
break;
|
||||
default:
|
||||
(int) $k = $k + (16 * (int) $c);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($c1)
|
||||
{
|
||||
case 'A':
|
||||
$k += 10;
|
||||
break;
|
||||
case 'B':
|
||||
$k += 11;
|
||||
break;
|
||||
case 'C':
|
||||
$k += 12;
|
||||
break;
|
||||
case 'D':
|
||||
$k += 13;
|
||||
break;
|
||||
case 'E':
|
||||
$k += 14;
|
||||
break;
|
||||
case 'F':
|
||||
$k += 15;
|
||||
break;
|
||||
case ' ':
|
||||
$k += 0;
|
||||
break;
|
||||
default:
|
||||
$k += (int) $c1;
|
||||
break;
|
||||
}
|
||||
|
||||
return $k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex to an array of integers
|
||||
*
|
||||
* @param string $hex The hex string to convert to an integer array.
|
||||
*
|
||||
* @return array An array of integers.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
private function _hexToIntArray($hex)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
$j = (int) strlen($hex) / 2;
|
||||
|
||||
for ($i = 0; $i < $j; $i++)
|
||||
{
|
||||
$array[$i] = (int) $this->_hexToInt($hex, $i);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an integer to a hexadecimal string.
|
||||
*
|
||||
* @param integer $i An integer value to convert to a hex string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
private function _intToHex($i)
|
||||
{
|
||||
// Sanitize the input.
|
||||
$i = (int) $i;
|
||||
|
||||
// Get the first character of the hexadecimal string if there is one.
|
||||
$j = (int) ($i / 16);
|
||||
|
||||
if ($j === 0)
|
||||
{
|
||||
$s = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$s = strtoupper(dechex($j));
|
||||
}
|
||||
|
||||
// Get the second character of the hexadecimal string.
|
||||
$k = $i - $j * 16;
|
||||
$s = $s . strtoupper(dechex($k));
|
||||
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
252
libraries/joomla/crypt/crypt.php
Normal file
252
libraries/joomla/crypt/crypt.php
Normal file
@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JCrypt is a Joomla Platform class for handling basic encryption/decryption of data.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCrypt
|
||||
{
|
||||
/**
|
||||
* @var JCryptCipher The encryption cipher object.
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_cipher;
|
||||
|
||||
/**
|
||||
* @var JCryptKey The encryption key[/pair)].
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_key;
|
||||
|
||||
/**
|
||||
* Object Constructor takes an optional key to be used for encryption/decryption. If no key is given then the
|
||||
* secret word from the configuration object is used.
|
||||
*
|
||||
* @param JCryptCipher $cipher The encryption cipher object.
|
||||
* @param JCryptKey $key The encryption key[/pair)].
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct(JCryptCipher $cipher = null, JCryptKey $key = null)
|
||||
{
|
||||
// Set the encryption key[/pair)].
|
||||
$this->_key = $key;
|
||||
|
||||
// Set the encryption cipher.
|
||||
$this->_cipher = isset($cipher) ? $cipher : new JCryptCipherSimple;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to decrypt a data string.
|
||||
*
|
||||
* @param string $data The encrypted string to decrypt.
|
||||
*
|
||||
* @return string The decrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function decrypt($data)
|
||||
{
|
||||
return $this->_cipher->decrypt($data, $this->_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to encrypt a data string.
|
||||
*
|
||||
* @param string $data The data string to encrypt.
|
||||
*
|
||||
* @return string The encrypted data string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function encrypt($data)
|
||||
{
|
||||
return $this->_cipher->encrypt($data, $this->_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate a new encryption key[/pair] object.
|
||||
*
|
||||
* @param array $options Key generation options.
|
||||
*
|
||||
* @return JCryptKey
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function generateKey(array $options = array())
|
||||
{
|
||||
return $this->_cipher->generateKey($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the encryption key[/pair] object.
|
||||
*
|
||||
* @param JCryptKey $key The key object to set.
|
||||
*
|
||||
* @return JCrypt
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setKey(JCryptKey $key)
|
||||
{
|
||||
$this->_key = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random bytes.
|
||||
*
|
||||
* @param integer $length Length of the random data to generate
|
||||
*
|
||||
* @return string Random binary data
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function genRandomBytes($length = 16)
|
||||
{
|
||||
$sslStr = '';
|
||||
|
||||
/*
|
||||
* if a secure randomness generator exists and we don't
|
||||
* have a buggy PHP version use it.
|
||||
*/
|
||||
if (function_exists('openssl_random_pseudo_bytes')
|
||||
&& (version_compare(PHP_VERSION, '5.3.4') >= 0 || IS_WIN))
|
||||
{
|
||||
$sslStr = openssl_random_pseudo_bytes($length, $strong);
|
||||
|
||||
if ($strong)
|
||||
{
|
||||
return $sslStr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect any entropy available in the system along with a number
|
||||
* of time measurements of operating system randomness.
|
||||
*/
|
||||
$bitsPerRound = 2;
|
||||
$maxTimeMicro = 400;
|
||||
$shaHashLength = 20;
|
||||
$randomStr = '';
|
||||
$total = $length;
|
||||
|
||||
// Check if we can use /dev/urandom.
|
||||
$urandom = false;
|
||||
$handle = null;
|
||||
|
||||
// This is PHP 5.3.3 and up
|
||||
if (function_exists('stream_set_read_buffer') && @is_readable('/dev/urandom'))
|
||||
{
|
||||
$handle = @fopen('/dev/urandom', 'rb');
|
||||
|
||||
if ($handle)
|
||||
{
|
||||
$urandom = true;
|
||||
}
|
||||
}
|
||||
|
||||
while ($length > strlen($randomStr))
|
||||
{
|
||||
$bytes = ($total > $shaHashLength)? $shaHashLength : $total;
|
||||
$total -= $bytes;
|
||||
|
||||
/*
|
||||
* Collect any entropy available from the PHP system and filesystem.
|
||||
* If we have ssl data that isn't strong, we use it once.
|
||||
*/
|
||||
$entropy = rand() . uniqid(mt_rand(), true) . $sslStr;
|
||||
$entropy .= implode('', @fstat(fopen(__FILE__, 'r')));
|
||||
$entropy .= memory_get_usage();
|
||||
$sslStr = '';
|
||||
|
||||
if ($urandom)
|
||||
{
|
||||
stream_set_read_buffer($handle, 0);
|
||||
$entropy .= @fread($handle, $bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* There is no external source of entropy so we repeat calls
|
||||
* to mt_rand until we are assured there's real randomness in
|
||||
* the result.
|
||||
*
|
||||
* Measure the time that the operations will take on average.
|
||||
*/
|
||||
$samples = 3;
|
||||
$duration = 0;
|
||||
|
||||
for ($pass = 0; $pass < $samples; ++$pass)
|
||||
{
|
||||
$microStart = microtime(true) * 1000000;
|
||||
$hash = sha1(mt_rand(), true);
|
||||
|
||||
for ($count = 0; $count < 50; ++$count)
|
||||
{
|
||||
$hash = sha1($hash, true);
|
||||
}
|
||||
|
||||
$microEnd = microtime(true) * 1000000;
|
||||
$entropy .= $microStart . $microEnd;
|
||||
|
||||
if ($microStart >= $microEnd)
|
||||
{
|
||||
$microEnd += 1000000;
|
||||
}
|
||||
|
||||
$duration += $microEnd - $microStart;
|
||||
}
|
||||
|
||||
$duration = $duration / $samples;
|
||||
|
||||
/*
|
||||
* Based on the average time, determine the total rounds so that
|
||||
* the total running time is bounded to a reasonable number.
|
||||
*/
|
||||
$rounds = (int) (($maxTimeMicro / $duration) * 50);
|
||||
|
||||
/*
|
||||
* Take additional measurements. On average we can expect
|
||||
* at least $bitsPerRound bits of entropy from each measurement.
|
||||
*/
|
||||
$iter = $bytes * (int) ceil(8 / $bitsPerRound);
|
||||
|
||||
for ($pass = 0; $pass < $iter; ++$pass)
|
||||
{
|
||||
$microStart = microtime(true);
|
||||
$hash = sha1(mt_rand(), true);
|
||||
|
||||
for ($count = 0; $count < $rounds; ++$count)
|
||||
{
|
||||
$hash = sha1($hash, true);
|
||||
}
|
||||
|
||||
$entropy .= $microStart . microtime(true);
|
||||
}
|
||||
}
|
||||
|
||||
$randomStr .= sha1($entropy, true);
|
||||
}
|
||||
|
||||
if ($urandom)
|
||||
{
|
||||
@fclose($handle);
|
||||
}
|
||||
|
||||
return substr($randomStr, 0, $length);
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/crypt/index.html
Normal file
1
libraries/joomla/crypt/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
80
libraries/joomla/crypt/key.php
Normal file
80
libraries/joomla/crypt/key.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Encryption key object for the Joomla Platform.
|
||||
*
|
||||
* @property-read string $type The key type.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.1
|
||||
*/
|
||||
class JCryptKey
|
||||
{
|
||||
/**
|
||||
* @var string The private key.
|
||||
* @since 12.1
|
||||
*/
|
||||
public $private;
|
||||
|
||||
/**
|
||||
* @var string The public key.
|
||||
* @since 12.1
|
||||
*/
|
||||
public $public;
|
||||
|
||||
/**
|
||||
* @var string The key type.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $type The key type.
|
||||
* @param string $private The private key.
|
||||
* @param string $public The public key.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($type, $private = null, $public = null)
|
||||
{
|
||||
// Set the key type.
|
||||
$this->type = (string) $type;
|
||||
|
||||
// Set the optional public/private key strings.
|
||||
$this->private = isset($private) ? (string) $private : null;
|
||||
$this->public = isset($public) ? (string) $public : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to return some protected property values.
|
||||
*
|
||||
* @param string $name The name of the property to return.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == 'type')
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Cannot access property ' . __CLASS__ . '::' . $name, E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
libraries/joomla/crypt/password.php
Normal file
72
libraries/joomla/crypt/password.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Password Hashing Interface
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.2
|
||||
*/
|
||||
interface JCryptPassword
|
||||
{
|
||||
const BLOWFISH = '$2y$';
|
||||
|
||||
const JOOMLA = 'Joomla';
|
||||
|
||||
const PBKDF = '$pbkdf$';
|
||||
|
||||
const MD5 = '$1$';
|
||||
|
||||
/**
|
||||
* Creates a password hash
|
||||
*
|
||||
* @param string $password The password to hash.
|
||||
* @param string $type The type of hash. This determines the prefix of the hashing function.
|
||||
*
|
||||
* @return string The hashed password.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function create($password, $type = null);
|
||||
|
||||
/**
|
||||
* Verifies a password hash
|
||||
*
|
||||
* @param string $password The password to verify.
|
||||
* @param string $hash The password hash to check.
|
||||
*
|
||||
* @return boolean True if the password is valid, false otherwise.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function verify($password, $hash);
|
||||
|
||||
/**
|
||||
* Sets a default prefix
|
||||
*
|
||||
* @param string $type The prefix to set as default
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function setDefaultType($type);
|
||||
|
||||
/**
|
||||
* Gets the default type
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function getDefaultType();
|
||||
}
|
||||
1
libraries/joomla/crypt/password/index.html
Normal file
1
libraries/joomla/crypt/password/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
190
libraries/joomla/crypt/password/simple.php
Normal file
190
libraries/joomla/crypt/password/simple.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Password Crypter
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Crypt
|
||||
* @since 12.2
|
||||
*/
|
||||
class JCryptPasswordSimple implements JCryptPassword
|
||||
{
|
||||
/**
|
||||
* @var integer The cost parameter for hashing algorithms.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $cost = 10;
|
||||
|
||||
/**
|
||||
* @var string The default hash type
|
||||
* @since 12.3
|
||||
*/
|
||||
protected $defaultType = '$2y$';
|
||||
|
||||
/**
|
||||
* Creates a password hash
|
||||
*
|
||||
* @param string $password The password to hash.
|
||||
* @param string $type The hash type.
|
||||
*
|
||||
* @return string The hashed password.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function create($password, $type = null)
|
||||
{
|
||||
if (empty($type))
|
||||
{
|
||||
$type = $this->defaultType;
|
||||
}
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case '$2a$':
|
||||
case JCryptPassword::BLOWFISH:
|
||||
if (version_compare(PHP_VERSION, '5.3.7') >= 0)
|
||||
{
|
||||
$type = '$2y$';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = '$2a$';
|
||||
}
|
||||
|
||||
$salt = $type . str_pad($this->cost, 2, '0', STR_PAD_LEFT) . '$' . $this->getSalt(22);
|
||||
|
||||
return crypt($password, $salt);
|
||||
|
||||
case JCryptPassword::MD5:
|
||||
$salt = $this->getSalt(12);
|
||||
|
||||
$salt = '$1$' . $salt;
|
||||
|
||||
return crypt($password, $salt);
|
||||
|
||||
case JCryptPassword::JOOMLA:
|
||||
$salt = $this->getSalt(32);
|
||||
|
||||
return md5($password . $salt) . ':' . $salt;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Hash type %s is not supported', $type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost parameter for the generated hash for algorithms that use a cost factor.
|
||||
*
|
||||
* @param integer $cost The new cost value.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function setCost($cost)
|
||||
{
|
||||
$this->cost = $cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a salt of specified length. The salt consists of characters in the set [./0-9A-Za-z].
|
||||
*
|
||||
* @param integer $length The number of characters to return.
|
||||
*
|
||||
* @return string The string of random characters.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
protected function getSalt($length)
|
||||
{
|
||||
$bytes = ceil($length * 6 / 8);
|
||||
|
||||
$randomData = str_replace('+', '.', base64_encode(JCrypt::genRandomBytes($bytes)));
|
||||
|
||||
return substr($randomData, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a password hash
|
||||
*
|
||||
* @param string $password The password to verify.
|
||||
* @param string $hash The password hash to check.
|
||||
*
|
||||
* @return boolean True if the password is valid, false otherwise.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function verify($password, $hash)
|
||||
{
|
||||
// Check if the hash is a blowfish hash.
|
||||
if (substr($hash, 0, 4) == '$2a$' || substr($hash, 0, 4) == '$2y$')
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.3.7') >= 0)
|
||||
{
|
||||
$type = '$2y$';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = '$2a$';
|
||||
}
|
||||
|
||||
$hash = $type . substr($hash, 4);
|
||||
|
||||
return (crypt($password, $hash) === $hash);
|
||||
}
|
||||
|
||||
// Check if the hash is an MD5 hash.
|
||||
if (substr($hash, 0, 3) == '$1$')
|
||||
{
|
||||
return (crypt($password, $hash) === $hash);
|
||||
}
|
||||
|
||||
// Check if the hash is a Joomla hash.
|
||||
if (preg_match('#[a-z0-9]{32}:[A-Za-z0-9]{32}#', $hash) === 1)
|
||||
{
|
||||
return md5($password . substr($hash, 33)) == substr($hash, 0, 32);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default type
|
||||
*
|
||||
* @param string $type The value to set as default.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function setDefaultType($type)
|
||||
{
|
||||
if (!empty($type))
|
||||
{
|
||||
$this->defaultType = $type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default type
|
||||
*
|
||||
* @return string $type The default type
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function getDefaultType()
|
||||
{
|
||||
return $this->defaultType;
|
||||
}
|
||||
}
|
||||
332
libraries/joomla/data/data.php
Normal file
332
libraries/joomla/data/data.php
Normal file
@ -0,0 +1,332 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JData is a class that is used to store data but allowing you to access the data
|
||||
* by mimicking the way PHP handles class properties.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
* @since 12.3
|
||||
*/
|
||||
class JData implements JDataDumpable, IteratorAggregate, JsonSerializable, Countable
|
||||
{
|
||||
/**
|
||||
* The data properties.
|
||||
*
|
||||
* @var array
|
||||
* @since 12.3
|
||||
*/
|
||||
private $_properties = array();
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param mixed $properties Either an associative array or another object
|
||||
* by which to set the initial properties of the new object.
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($properties = array())
|
||||
{
|
||||
// Check the properties input.
|
||||
if (!empty($properties))
|
||||
{
|
||||
// Bind the properties.
|
||||
$this->bind($properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic get method is used to get a data property.
|
||||
*
|
||||
* This method is a public proxy for the protected getProperty method.
|
||||
*
|
||||
* Note: Magic __get does not allow recursive calls. This can be tricky because the error generated by recursing into
|
||||
* __get is "Undefined property: {CLASS}::{PROPERTY}" which is misleading. This is relevant for this class because
|
||||
* requesting a non-visible property can trigger a call to a sub-function. If that references the property directly in
|
||||
* the object, it will cause a recursion into __get.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
*
|
||||
* @return mixed The value of the data property, or null if the data property does not exist.
|
||||
*
|
||||
* @see JData::getProperty()
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
return $this->getProperty($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic isset method is used to check the state of an object property.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
*
|
||||
* @return boolean True if set, otherwise false is returned.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __isset($property)
|
||||
{
|
||||
return isset($this->_properties[$property]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic set method is used to set a data property.
|
||||
*
|
||||
* This is a public proxy for the protected setProperty method.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
* @param mixed $value The value to give the data property.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see JData::setProperty()
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __set($property, $value)
|
||||
{
|
||||
$this->setProperty($property, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic unset method is used to unset a data property.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __unset($property)
|
||||
{
|
||||
unset($this->_properties[$property]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds an array or object to this object.
|
||||
*
|
||||
* @param mixed $properties An associative array of properties or an object.
|
||||
* @param boolean $updateNulls True to bind null values, false to ignore null values.
|
||||
*
|
||||
* @return JData Returns itself to allow chaining.
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function bind($properties, $updateNulls = true)
|
||||
{
|
||||
// Check the properties data type.
|
||||
if (!is_array($properties) && !is_object($properties))
|
||||
{
|
||||
throw new InvalidArgumentException(sprintf('%s(%s)', __METHOD__, gettype($properties)));
|
||||
}
|
||||
|
||||
// Check if the object is traversable.
|
||||
if ($properties instanceof Traversable)
|
||||
{
|
||||
// Convert iterator to array.
|
||||
$properties = iterator_to_array($properties);
|
||||
}
|
||||
// Check if the object needs to be converted to an array.
|
||||
elseif (is_object($properties))
|
||||
{
|
||||
// Convert properties to an array.
|
||||
$properties = (array) $properties;
|
||||
}
|
||||
|
||||
// Bind the properties.
|
||||
foreach ($properties as $property => $value)
|
||||
{
|
||||
// Check if the value is null and should be bound.
|
||||
if ($value === null && !$updateNulls)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the property.
|
||||
$this->setProperty($property, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the data properties into a stdClass object, recursively if appropriate.
|
||||
*
|
||||
* @param integer $depth The maximum depth of recursion (default = 3).
|
||||
* For example, a depth of 0 will return a stdClass with all the properties in native
|
||||
* form. A depth of 1 will recurse into the first level of properties only.
|
||||
* @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
|
||||
*
|
||||
* @return stdClass The data properties as a simple PHP stdClass object.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function dump($depth = 3, SplObjectStorage $dumped = null)
|
||||
{
|
||||
// Check if we should initialise the recursion tracker.
|
||||
if ($dumped === null)
|
||||
{
|
||||
$dumped = new SplObjectStorage;
|
||||
}
|
||||
|
||||
// Add this object to the dumped stack.
|
||||
$dumped->attach($this);
|
||||
|
||||
// Setup a container.
|
||||
$dump = new stdClass;
|
||||
|
||||
// Dump all object properties.
|
||||
foreach (array_keys($this->_properties) as $property)
|
||||
{
|
||||
// Get the property.
|
||||
$dump->$property = $this->dumpProperty($property, $depth, $dumped);
|
||||
}
|
||||
|
||||
return $dump;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this object represented as an ArrayIterator.
|
||||
*
|
||||
* This allows the data properties to be access via a foreach statement.
|
||||
*
|
||||
* @return ArrayIterator This object represented as an ArrayIterator.
|
||||
*
|
||||
* @see IteratorAggregate::getIterator()
|
||||
* @since 12.3
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->dump(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data properties in a form that can be serialised to JSON format.
|
||||
*
|
||||
* @return string An object that can be serialised by json_encode().
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->dump();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a data property.
|
||||
*
|
||||
* If recursion is set, this method will dump any object implementing JDumpable (like JData and JDataSet); it will
|
||||
* convert a JDate object to a string; and it will convert a JRegistry to an object.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
* @param integer $depth The current depth of recursion (a value of 0 will ignore recursion).
|
||||
* @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
|
||||
*
|
||||
* @return mixed The value of the dumped property.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
protected function dumpProperty($property, $depth, SplObjectStorage $dumped)
|
||||
{
|
||||
$value = $this->getProperty($property);
|
||||
|
||||
if ($depth > 0)
|
||||
{
|
||||
// Check if the object is also an dumpable object.
|
||||
if ($value instanceof JDataDumpable)
|
||||
{
|
||||
// Do not dump the property if it has already been dumped.
|
||||
if (!$dumped->contains($value))
|
||||
{
|
||||
$value = $value->dump($depth - 1, $dumped);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the object is a date.
|
||||
if ($value instanceof JDate)
|
||||
{
|
||||
$value = (string) $value;
|
||||
}
|
||||
// Check if the object is a registry.
|
||||
elseif ($value instanceof JRegistry)
|
||||
{
|
||||
$value = $value->toObject();
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data property.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
*
|
||||
* @return mixed The value of the data property.
|
||||
*
|
||||
* @see JData::__get()
|
||||
* @since 12.3
|
||||
*/
|
||||
protected function getProperty($property)
|
||||
{
|
||||
// Get the raw value.
|
||||
$value = array_key_exists($property, $this->_properties) ? $this->_properties[$property] : null;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a data property.
|
||||
*
|
||||
* If the name of the property starts with a null byte, this method will return null.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
* @param mixed $value The value to give the data property.
|
||||
*
|
||||
* @return mixed The value of the data property.
|
||||
*
|
||||
* @see JData::__set()
|
||||
* @since 12.3
|
||||
*/
|
||||
protected function setProperty($property, $value)
|
||||
{
|
||||
/*
|
||||
* Check if the property starts with a null byte. If so, discard it because a later attempt to try to access it
|
||||
* can cause a fatal error. See http://us3.php.net/manual/en/language.types.array.php#language.types.array.casting
|
||||
*/
|
||||
if (strpos($property, "\0") === 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the value.
|
||||
$this->_properties[$property] = $value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of data properties.
|
||||
*
|
||||
* @return integer The number of data properties.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->_properties);
|
||||
}
|
||||
}
|
||||
34
libraries/joomla/data/dumpable.php
Normal file
34
libraries/joomla/data/dumpable.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* An interface to define if an object is dumpable.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
* @since 12.3
|
||||
*/
|
||||
interface JDataDumpable
|
||||
{
|
||||
/**
|
||||
* Dumps the object properties into a stdClass object, recursively if appropriate.
|
||||
*
|
||||
* @param integer $depth The maximum depth of recursion.
|
||||
* For example, a depth of 0 will return a stdClass with all the properties in native
|
||||
* form. A depth of 1 will recurse into the first level of properties only.
|
||||
* @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
|
||||
*
|
||||
* @return stdClass The data properties as a simple PHP stdClass object.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function dump($depth = 3, SplObjectStorage $dumped = null);
|
||||
}
|
||||
1
libraries/joomla/data/index.html
Normal file
1
libraries/joomla/data/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
518
libraries/joomla/data/set.php
Normal file
518
libraries/joomla/data/set.php
Normal file
@ -0,0 +1,518 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* JDataSet is a collection class that allows the developer to operate on a set of JData objects as if they were in a
|
||||
* typical PHP array.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Data
|
||||
* @since 12.3
|
||||
*/
|
||||
class JDataSet implements JDataDumpable, ArrayAccess, Countable, Iterator
|
||||
{
|
||||
/**
|
||||
* The current position of the iterator.
|
||||
*
|
||||
* @var integer
|
||||
* @since 12.3
|
||||
*/
|
||||
private $_current = false;
|
||||
|
||||
/**
|
||||
* The iterator objects.
|
||||
*
|
||||
* @var array
|
||||
* @since 12.3
|
||||
*/
|
||||
private $_objects = array();
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param array $objects An array of JData objects to bind to the data set.
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws InvalidArgumentException if an object is not an instance of JData.
|
||||
*/
|
||||
public function __construct(array $objects = array())
|
||||
{
|
||||
// Set the objects.
|
||||
$this->_initialise($objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic call method is used to call object methods using the iterator.
|
||||
*
|
||||
* Example: $array = $objectList->foo('bar');
|
||||
*
|
||||
* The object list will iterate over its objects and see if each object has a callable 'foo' method.
|
||||
* If so, it will pass the argument list and assemble any return values. If an object does not have
|
||||
* a callable method no return value is recorded.
|
||||
* The keys of the objects and the result array are maintained.
|
||||
*
|
||||
* @param string $method The name of the method called.
|
||||
* @param array $arguments The arguments of the method called.
|
||||
*
|
||||
* @return array An array of values returned by the methods called on the objects in the data set.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __call($method, $arguments = array())
|
||||
{
|
||||
$return = array();
|
||||
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $key => $object)
|
||||
{
|
||||
// Create the object callback.
|
||||
$callback = array($object, $method);
|
||||
|
||||
// Check if the callback is callable.
|
||||
if (is_callable($callback))
|
||||
{
|
||||
// Call the method for the object.
|
||||
$return[$key] = call_user_func_array($callback, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic get method is used to get a list of properties from the objects in the data set.
|
||||
*
|
||||
* Example: $array = $dataSet->foo;
|
||||
*
|
||||
* This will return a column of the values of the 'foo' property in all the objects
|
||||
* (or values determined by custom property setters in the individual JData's).
|
||||
* The result array will contain an entry for each object in the list (compared to __call which may not).
|
||||
* The keys of the objects and the result array are maintained.
|
||||
*
|
||||
* @param string $property The name of the data property.
|
||||
*
|
||||
* @return array An associative array of the values.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
$return = array();
|
||||
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $key => $object)
|
||||
{
|
||||
// Get the property.
|
||||
$return[$key] = $object->$property;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic isset method is used to check the state of an object property using the iterator.
|
||||
*
|
||||
* Example: $array = isset($objectList->foo);
|
||||
*
|
||||
* @param string $property The name of the property.
|
||||
*
|
||||
* @return boolean True if the property is set in any of the objects in the data set.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __isset($property)
|
||||
{
|
||||
$return = array();
|
||||
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $object)
|
||||
{
|
||||
// Check the property.
|
||||
$return[] = isset($object->$property);
|
||||
}
|
||||
|
||||
return in_array(true, $return, true) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic set method is used to set an object property using the iterator.
|
||||
*
|
||||
* Example: $objectList->foo = 'bar';
|
||||
*
|
||||
* This will set the 'foo' property to 'bar' in all of the objects
|
||||
* (or a value determined by custom property setters in the JData).
|
||||
*
|
||||
* @param string $property The name of the property.
|
||||
* @param mixed $value The value to give the data property.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __set($property, $value)
|
||||
{
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $object)
|
||||
{
|
||||
// Set the property.
|
||||
$object->$property = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The magic unset method is used to unset an object property using the iterator.
|
||||
*
|
||||
* Example: unset($objectList->foo);
|
||||
*
|
||||
* This will unset all of the 'foo' properties in the list of JData's.
|
||||
*
|
||||
* @param string $property The name of the property.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function __unset($property)
|
||||
{
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $object)
|
||||
{
|
||||
unset($object->$property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of data objects in the set.
|
||||
*
|
||||
* @return integer The number of objects.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->_objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the objects in the data set.
|
||||
*
|
||||
* @return JDataSet Returns itself to allow chaining.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->_objects = array();
|
||||
$this->rewind();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current data object in the set.
|
||||
*
|
||||
* @return JData The current object, or false if the array is empty or the pointer is beyond the end of the elements.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return is_scalar($this->_current) ? $this->_objects[$this->_current] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the data object in the set, recursively if appropriate.
|
||||
*
|
||||
* @param integer $depth The maximum depth of recursion (default = 3).
|
||||
* For example, a depth of 0 will return a stdClass with all the properties in native
|
||||
* form. A depth of 1 will recurse into the first level of properties only.
|
||||
* @param SplObjectStorage $dumped An array of already serialized objects that is used to avoid infinite loops.
|
||||
*
|
||||
* @return array An associative array of the date objects in the set, dumped as a simple PHP stdClass object.
|
||||
*
|
||||
* @see JData::dump()
|
||||
* @since 12.3
|
||||
*/
|
||||
public function dump($depth = 3, SplObjectStorage $dumped = null)
|
||||
{
|
||||
// Check if we should initialise the recursion tracker.
|
||||
if ($dumped === null)
|
||||
{
|
||||
$dumped = new SplObjectStorage;
|
||||
}
|
||||
|
||||
// Add this object to the dumped stack.
|
||||
$dumped->attach($this);
|
||||
|
||||
$objects = array();
|
||||
|
||||
// Make sure that we have not reached our maximum depth.
|
||||
if ($depth > 0)
|
||||
{
|
||||
// Handle JSON serialization recursively.
|
||||
foreach ($this->_objects as $key => $object)
|
||||
{
|
||||
$objects[$key] = $object->dump($depth, $dumped);
|
||||
}
|
||||
}
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data set in a form that can be serialised to JSON format.
|
||||
*
|
||||
* Note that this method will not return an associative array, otherwise it would be encoded into an object.
|
||||
* JSON decoders do not consistently maintain the order of associative keys, whereas they do maintain the order of arrays.
|
||||
*
|
||||
* @param mixed $serialized An array of objects that have already been serialized that is used to infinite loops
|
||||
* (null on first call).
|
||||
*
|
||||
* @return array An array that can be serialised by json_encode().
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function jsonSerialize($serialized = null)
|
||||
{
|
||||
// Check if we should initialise the recursion tracker.
|
||||
if ($serialized === null)
|
||||
{
|
||||
$serialized = array();
|
||||
}
|
||||
|
||||
// Add this object to the serialized stack.
|
||||
$serialized[] = spl_object_hash($this);
|
||||
$return = array();
|
||||
|
||||
// Iterate through the objects.
|
||||
foreach ($this->_objects as $object)
|
||||
{
|
||||
// Call the method for the object.
|
||||
$return[] = $object->jsonSerialize($serialized);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key of the current object in the iterator.
|
||||
*
|
||||
* @return scalar The object key on success; null on failure.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of keys for all the objects in the iterator (emulates array_keys).
|
||||
*
|
||||
* @return array The array of keys
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function keys()
|
||||
{
|
||||
return array_keys($this->_objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the iterator to the next object in the iterator.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
// Get the object offsets.
|
||||
$keys = $this->keys();
|
||||
|
||||
// Check if _current has been set to false but offsetUnset.
|
||||
if ($this->_current === false && isset($keys[0]))
|
||||
{
|
||||
// This is a special case where offsetUnset was used in a foreach loop and the first element was unset.
|
||||
$this->_current = $keys[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the current key.
|
||||
$position = array_search($this->_current, $keys);
|
||||
|
||||
// Check if there is an object after the current object.
|
||||
if ($position !== false && isset($keys[$position + 1]))
|
||||
{
|
||||
// Get the next id.
|
||||
$this->_current = $keys[$position + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// That was the last object or the internal properties have become corrupted.
|
||||
$this->_current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an offset exists in the iterator.
|
||||
*
|
||||
* @param mixed $offset The object offset.
|
||||
*
|
||||
* @return boolean True if the object exists, false otherwise.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->_objects[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an offset in the iterator.
|
||||
*
|
||||
* @param mixed $offset The object offset.
|
||||
*
|
||||
* @return JData The object if it exists, null otherwise.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->_objects[$offset]) ? $this->_objects[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an offset in the iterator.
|
||||
*
|
||||
* @param mixed $offset The object offset.
|
||||
* @param JData $object The object object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws InvalidArgumentException if an object is not an instance of JData.
|
||||
*/
|
||||
public function offsetSet($offset, $object)
|
||||
{
|
||||
// Check if the object is a JData object.
|
||||
if (!($object instanceof JData))
|
||||
{
|
||||
throw new InvalidArgumentException(sprintf('%s("%s", *%s*)', __METHOD__, $offset, gettype($object)));
|
||||
}
|
||||
|
||||
// Set the offset.
|
||||
$this->_objects[$offset] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets an offset in the iterator.
|
||||
*
|
||||
* @param mixed $offset The object offset.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (!$this->offsetExists($offset))
|
||||
{
|
||||
// Do nothing if the offset does not exist.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for special handling of unsetting the current position.
|
||||
if ($offset == $this->_current)
|
||||
{
|
||||
// Get the current position.
|
||||
$keys = $this->keys();
|
||||
$position = array_search($this->_current, $keys);
|
||||
|
||||
// Check if there is an object before the current object.
|
||||
if ($position > 0)
|
||||
{
|
||||
// Move the current position back one.
|
||||
$this->_current = $keys[$position - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are at the start of the keys AND let's assume we are in a foreach loop and `next` is going to be called.
|
||||
$this->_current = false;
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->_objects[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the iterator to the first object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
// Set the current position to the first object.
|
||||
if (empty($this->_objects))
|
||||
{
|
||||
$this->_current = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$keys = $this->keys();
|
||||
$this->_current = array_shift($keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the iterator.
|
||||
*
|
||||
* @return boolean True if valid, false otherwise.
|
||||
*
|
||||
* @since 12.3
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
// Check the current position.
|
||||
if (!is_scalar($this->_current) || !isset($this->_objects[$this->_current]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the list with an array of objects.
|
||||
*
|
||||
* @param array $input An array of objects.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws InvalidArgumentException if an object is not an instance of JData.
|
||||
*/
|
||||
private function _initialise(array $input = array())
|
||||
{
|
||||
foreach ($input as $key => $object)
|
||||
{
|
||||
if (!is_null($object))
|
||||
{
|
||||
$this->offsetSet($key, $object);
|
||||
}
|
||||
}
|
||||
|
||||
$this->rewind();
|
||||
}
|
||||
}
|
||||
174
libraries/joomla/database/database.php
Normal file
174
libraries/joomla/database/database.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Database connector class.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 11.1
|
||||
* @deprecated 13.3 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
abstract class JDatabase
|
||||
{
|
||||
/**
|
||||
* Execute the SQL statement.
|
||||
*
|
||||
* @return mixed A database cursor resource on success, boolean false on failure.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws RuntimeException
|
||||
* @deprecated 13.1 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
JLog::add('JDatabase::query() is deprecated, use JDatabaseDriver::execute() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of available database connectors. The list will only be populated with connectors that both
|
||||
* the class exists and the static test method returns true. This gives us the ability to have a multitude
|
||||
* of connector classes that are self-aware as to whether or not they are able to be used on a given system.
|
||||
*
|
||||
* @return array An array of available database connectors.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 13.1 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public static function getConnectors()
|
||||
{
|
||||
JLog::add('JDatabase::getConnectors() is deprecated, use JDatabaseDriver::getConnectors() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return JDatabaseDriver::getConnectors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error message from the database connection.
|
||||
*
|
||||
* @param boolean $escaped True to escape the message string for use in JavaScript.
|
||||
*
|
||||
* @return string The error message for the most recent query.
|
||||
*
|
||||
* @deprecated 13.3 (Platform) & 4.0 (CMS)
|
||||
* @since 11.1
|
||||
*/
|
||||
public function getErrorMsg($escaped = false)
|
||||
{
|
||||
JLog::add('JDatabase::getErrorMsg() is deprecated, use exception handling instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
if ($escaped)
|
||||
{
|
||||
return addslashes($this->errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->errorMsg;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error number from the database connection.
|
||||
*
|
||||
* @return integer The error number for the most recent query.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 13.3 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public function getErrorNum()
|
||||
{
|
||||
JLog::add('JDatabase::getErrorNum() is deprecated, use exception handling instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return $this->errorNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return a JDatabaseDriver instance based on the given options. There are three global options and then
|
||||
* the rest are specific to the database driver. The 'driver' option defines which JDatabaseDriver class is
|
||||
* used for the connection -- the default is 'mysqli'. The 'database' option determines which database is to
|
||||
* be used for the connection. The 'select' option determines whether the connector should automatically select
|
||||
* the chosen database.
|
||||
*
|
||||
* Instances are unique to the given options and new objects are only created when a unique options array is
|
||||
* passed into the method. This ensures that we don't end up with unnecessary database connection resources.
|
||||
*
|
||||
* @param array $options Parameters to be passed to the database driver.
|
||||
*
|
||||
* @return JDatabaseDriver A database object.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 13.1 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public static function getInstance($options = array())
|
||||
{
|
||||
JLog::add('JDatabase::getInstance() is deprecated, use JDatabaseDriver::getInstance() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return JDatabaseDriver::getInstance($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a string of multiple queries into an array of individual queries.
|
||||
*
|
||||
* @param string $query Input SQL string with which to split into individual queries.
|
||||
*
|
||||
* @return array The queries from the input string separated into an array.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 13.1 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public static function splitSql($query)
|
||||
{
|
||||
JLog::add('JDatabase::splitSql() is deprecated, use JDatabaseDriver::splitSql() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return JDatabaseDriver::splitSql($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the most recent error message for the database connector.
|
||||
*
|
||||
* @param boolean $showSQL True to display the SQL statement sent to the database as well as the error.
|
||||
*
|
||||
* @return string The error message for the most recent query.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 13.3 (Platform) & 4.0 (CMS)
|
||||
*/
|
||||
public function stderr($showSQL = false)
|
||||
{
|
||||
JLog::add('JDatabase::stderr() is deprecated.', JLog::WARNING, 'deprecated');
|
||||
|
||||
if ($this->errorNum != 0)
|
||||
{
|
||||
return JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $this->errorNum, $this->errorMsg)
|
||||
. ($showSQL ? "<br />SQL = <pre>$this->sql</pre>" : '');
|
||||
}
|
||||
else
|
||||
{
|
||||
return JText::_('JLIB_DATABASE_FUNCTION_NOERROR');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the connector is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 11.1
|
||||
* @deprecated 12.3 (Platform) & 4.0 (CMS) - Use JDatabaseDriver::isSupported() instead.
|
||||
*/
|
||||
public static function test()
|
||||
{
|
||||
JLog::add('JDatabase::test() is deprecated. Use JDatabaseDriver::isSupported() instead.', JLog::WARNING, 'deprecated');
|
||||
|
||||
return static::isSupported();
|
||||
}
|
||||
}
|
||||
1871
libraries/joomla/database/driver.php
Normal file
1871
libraries/joomla/database/driver.php
Normal file
File diff suppressed because it is too large
Load Diff
1
libraries/joomla/database/driver/index.html
Normal file
1
libraries/joomla/database/driver/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
463
libraries/joomla/database/driver/mysql.php
Normal file
463
libraries/joomla/database/driver/mysql.php
Normal file
@ -0,0 +1,463 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQL database driver
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://dev.mysql.com/doc/
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseDriverMysql extends JDatabaseDriverMysqli
|
||||
{
|
||||
/**
|
||||
* The name of the database driver.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
public $name = 'mysql';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options Array of database options with keys: host, user, password, database, select.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
// Get some basic values from the options.
|
||||
$options['host'] = (isset($options['host'])) ? $options['host'] : 'localhost';
|
||||
$options['user'] = (isset($options['user'])) ? $options['user'] : 'root';
|
||||
$options['password'] = (isset($options['password'])) ? $options['password'] : '';
|
||||
$options['database'] = (isset($options['database'])) ? $options['database'] : '';
|
||||
$options['select'] = (isset($options['select'])) ? (bool) $options['select'] : true;
|
||||
|
||||
// Finalize initialisation.
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the database if needed.
|
||||
*
|
||||
* @return void Returns void if the database connected successfully.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->connection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the MySQL extension for PHP is installed and enabled.
|
||||
if (!function_exists('mysql_connect'))
|
||||
{
|
||||
throw new RuntimeException('Could not connect to MySQL.');
|
||||
}
|
||||
|
||||
// Attempt to connect to the server.
|
||||
if (!($this->connection = @ mysql_connect($this->options['host'], $this->options['user'], $this->options['password'], true)))
|
||||
{
|
||||
throw new RuntimeException('Could not connect to MySQL.');
|
||||
}
|
||||
|
||||
// Set sql_mode to non_strict mode
|
||||
mysql_query("SET @@SESSION.sql_mode = '';", $this->connection);
|
||||
|
||||
// If auto-select is enabled select the given database.
|
||||
if ($this->options['select'] && !empty($this->options['database']))
|
||||
{
|
||||
$this->select($this->options['database']);
|
||||
}
|
||||
|
||||
// Set charactersets (needed for MySQL 4.1.2+).
|
||||
$this->setUTF();
|
||||
|
||||
// Turn MySQL profiling ON in debug mode:
|
||||
if ($this->debug && $this->hasProfiling())
|
||||
{
|
||||
mysql_query("SET profiling = 1;", $this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
// Close the connection.
|
||||
if (is_resource($this->connection))
|
||||
{
|
||||
foreach ($this->disconnectHandlers as $h)
|
||||
{
|
||||
call_user_func_array($h, array( &$this));
|
||||
}
|
||||
|
||||
mysql_close($this->connection);
|
||||
}
|
||||
|
||||
$this->connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to escape a string for usage in an SQL statement.
|
||||
*
|
||||
* @param string $text The string to be escaped.
|
||||
* @param boolean $extra Optional parameter to provide extra escaping.
|
||||
*
|
||||
* @return string The escaped string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function escape($text, $extra = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$result = mysql_real_escape_string($text, $this->getConnection());
|
||||
|
||||
if ($extra)
|
||||
{
|
||||
$result = addcslashes($result, '%_');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the MySQL connector is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return (function_exists('mysql_connect'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the connection to the server is active.
|
||||
*
|
||||
* @return boolean True if connected to the database engine.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
if (is_resource($this->connection))
|
||||
{
|
||||
return @mysql_ping($this->connection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected rows for the previous executed SQL statement.
|
||||
*
|
||||
* @return integer The number of affected rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getAffectedRows()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysql_affected_rows($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of returned rows for the previous executed SQL statement.
|
||||
*
|
||||
* @param resource $cursor An optional database cursor resource to extract the row count from.
|
||||
*
|
||||
* @return integer The number of returned rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getNumRows($cursor = null)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysql_num_rows($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database connector.
|
||||
*
|
||||
* @return string The database connector version.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysql_get_server_info($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the auto-incremented value from the last INSERT statement.
|
||||
*
|
||||
* @return integer The value of the auto-increment field from the last inserted row.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function insertid()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysql_insert_id($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the SQL statement.
|
||||
*
|
||||
* @return mixed A database cursor resource on success, boolean false on failure.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!is_resource($this->connection))
|
||||
{
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
|
||||
// Take a local copy so that we don't modify the original query and cause issues later
|
||||
$query = $this->replacePrefix((string) $this->sql);
|
||||
|
||||
if ($this->limit > 0 || $this->offset > 0)
|
||||
{
|
||||
$query .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
|
||||
}
|
||||
|
||||
// Increment the query counter.
|
||||
$this->count++;
|
||||
|
||||
// Reset the error values.
|
||||
$this->errorNum = 0;
|
||||
$this->errorMsg = '';
|
||||
|
||||
// If debugging is enabled then let's log the query.
|
||||
if ($this->debug)
|
||||
{
|
||||
// Add the query to the object queue.
|
||||
$this->log[] = $query;
|
||||
|
||||
JLog::add($query, JLog::DEBUG, 'databasequery');
|
||||
|
||||
$this->timings[] = microtime(true);
|
||||
}
|
||||
|
||||
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
|
||||
$this->cursor = @mysql_query($query, $this->connection);
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
$this->timings[] = microtime(true);
|
||||
|
||||
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
|
||||
{
|
||||
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->callStacks[] = debug_backtrace();
|
||||
}
|
||||
}
|
||||
|
||||
// If an error occurred handle it.
|
||||
if (!$this->cursor)
|
||||
{
|
||||
// Check if the server was disconnected.
|
||||
if (!$this->connected())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to reconnect.
|
||||
$this->connection = null;
|
||||
$this->connect();
|
||||
}
|
||||
// If connect fails, ignore that exception and throw the normal exception.
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
// Get the error number and message.
|
||||
$this->errorNum = (int) mysql_errno($this->connection);
|
||||
$this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $query;
|
||||
|
||||
// Throw the normal query exception.
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
|
||||
// Since we were able to reconnect, run the query again.
|
||||
return $this->execute();
|
||||
}
|
||||
// The server was not disconnected.
|
||||
else
|
||||
{
|
||||
// Get the error number and message.
|
||||
$this->errorNum = (int) mysql_errno($this->connection);
|
||||
$this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $query;
|
||||
|
||||
// Throw the normal query exception.
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database for use.
|
||||
*
|
||||
* @param string $database The name of the database to select for use.
|
||||
*
|
||||
* @return boolean True if the database was successfully selected.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function select($database)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mysql_select_db($database, $this->connection))
|
||||
{
|
||||
throw new RuntimeException('Could not connect to database');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use UTF-8 character encoding.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setUTF()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysql_set_charset('utf8', $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an array.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchArray($cursor = null)
|
||||
{
|
||||
return mysql_fetch_row($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an associative array.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchAssoc($cursor = null)
|
||||
{
|
||||
return mysql_fetch_assoc($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
* @param string $class The class name to use for the returned row object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchObject($cursor = null, $class = 'stdClass')
|
||||
{
|
||||
return mysql_fetch_object($cursor ? $cursor : $this->cursor, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function freeResult($cursor = null)
|
||||
{
|
||||
mysql_free_result($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to check if profiling is available
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.1.3
|
||||
*/
|
||||
private function hasProfiling()
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = mysql_query("SHOW VARIABLES LIKE 'have_profiling'", $this->connection);
|
||||
$row = mysql_fetch_assoc($res);
|
||||
|
||||
return isset($row);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
834
libraries/joomla/database/driver/mysqli.php
Normal file
834
libraries/joomla/database/driver/mysqli.php
Normal file
@ -0,0 +1,834 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQLi database driver
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://php.net/manual/en/book.mysqli.php
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseDriverMysqli extends JDatabaseDriver
|
||||
{
|
||||
/**
|
||||
* The name of the database driver.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
public $name = 'mysqli';
|
||||
|
||||
/**
|
||||
* The character(s) used to quote SQL statement names such as table names or field names,
|
||||
* etc. The child classes should define this as necessary. If a single character string the
|
||||
* same character is used for both sides of the quoted name, else the first character will be
|
||||
* used for the opening quote and the second for the closing quote.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $nameQuote = '`';
|
||||
|
||||
/**
|
||||
* The null or zero representation of a timestamp for the database driver. This should be
|
||||
* defined in child classes to hold the appropriate value for the engine.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.2
|
||||
*/
|
||||
protected $nullDate = '0000-00-00 00:00:00';
|
||||
|
||||
/**
|
||||
* @var string The minimum supported database version.
|
||||
* @since 12.2
|
||||
*/
|
||||
protected static $dbMinimum = '5.0.4';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options List of options used to configure the connection
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
// Get some basic values from the options.
|
||||
$options['host'] = (isset($options['host'])) ? $options['host'] : 'localhost';
|
||||
$options['user'] = (isset($options['user'])) ? $options['user'] : 'root';
|
||||
$options['password'] = (isset($options['password'])) ? $options['password'] : '';
|
||||
$options['database'] = (isset($options['database'])) ? $options['database'] : '';
|
||||
$options['select'] = (isset($options['select'])) ? (bool) $options['select'] : true;
|
||||
$options['port'] = null;
|
||||
$options['socket'] = null;
|
||||
|
||||
// Finalize initialisation.
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the database if needed.
|
||||
*
|
||||
* @return void Returns void if the database connected successfully.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->connection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike mysql_connect(), mysqli_connect() takes the port and socket as separate arguments. Therefore, we
|
||||
* have to extract them from the host string.
|
||||
*/
|
||||
$tmp = substr(strstr($this->options['host'], ':'), 1);
|
||||
if (!empty($tmp))
|
||||
{
|
||||
// Get the port number or socket name
|
||||
if (is_numeric($tmp))
|
||||
{
|
||||
$this->options['port'] = $tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->options['socket'] = $tmp;
|
||||
}
|
||||
|
||||
// Extract the host name only
|
||||
$this->options['host'] = substr($this->options['host'], 0, strlen($this->options['host']) - (strlen($tmp) + 1));
|
||||
|
||||
// This will take care of the following notation: ":3306"
|
||||
if ($this->options['host'] == '')
|
||||
{
|
||||
$this->options['host'] = 'localhost';
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the MySQLi extension for PHP is installed and enabled.
|
||||
if (!function_exists('mysqli_connect'))
|
||||
{
|
||||
throw new RuntimeException('The MySQL adapter mysqli is not available');
|
||||
}
|
||||
|
||||
$this->connection = @mysqli_connect(
|
||||
$this->options['host'], $this->options['user'], $this->options['password'], null, $this->options['port'], $this->options['socket']
|
||||
);
|
||||
|
||||
// Attempt to connect to the server.
|
||||
if (!$this->connection)
|
||||
{
|
||||
throw new RuntimeException('Could not connect to MySQL.');
|
||||
}
|
||||
|
||||
// Set sql_mode to non_strict mode
|
||||
mysqli_query($this->connection, "SET @@SESSION.sql_mode = '';");
|
||||
|
||||
// If auto-select is enabled select the given database.
|
||||
if ($this->options['select'] && !empty($this->options['database']))
|
||||
{
|
||||
$this->select($this->options['database']);
|
||||
}
|
||||
|
||||
// Set charactersets (needed for MySQL 4.1.2+).
|
||||
$this->setUTF();
|
||||
|
||||
// Turn MySQL profiling ON in debug mode:
|
||||
if ($this->debug && $this->hasProfiling())
|
||||
{
|
||||
mysqli_query($this->connection, "SET profiling_history_size = 100;");
|
||||
mysqli_query($this->connection, "SET profiling = 1;");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
// Close the connection.
|
||||
if ($this->connection)
|
||||
{
|
||||
foreach ($this->disconnectHandlers as $h)
|
||||
{
|
||||
call_user_func_array($h, array( &$this));
|
||||
}
|
||||
|
||||
mysqli_close($this->connection);
|
||||
}
|
||||
|
||||
$this->connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to escape a string for usage in an SQL statement.
|
||||
*
|
||||
* @param string $text The string to be escaped.
|
||||
* @param boolean $extra Optional parameter to provide extra escaping.
|
||||
*
|
||||
* @return string The escaped string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function escape($text, $extra = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$result = mysqli_real_escape_string($this->getConnection(), $text);
|
||||
|
||||
if ($extra)
|
||||
{
|
||||
$result = addcslashes($result, '%_');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the MySQL connector is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return (function_exists('mysqli_connect'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the connection to the server is active.
|
||||
*
|
||||
* @return boolean True if connected to the database engine.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
if (is_object($this->connection))
|
||||
{
|
||||
return mysqli_ping($this->connection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a table from the database.
|
||||
*
|
||||
* @param string $tableName The name of the database table to drop.
|
||||
* @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
|
||||
*
|
||||
* @return JDatabaseDriverMysqli Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function dropTable($tableName, $ifExists = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $query->quoteName($tableName));
|
||||
|
||||
$this->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected rows for the previous executed SQL statement.
|
||||
*
|
||||
* @return integer The number of affected rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getAffectedRows()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysqli_affected_rows($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the database collation in use by sampling a text field of a table in the database.
|
||||
*
|
||||
* @return mixed The collation in use by the database (string) or boolean false if not supported.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getCollation()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$tables = $this->getTableList();
|
||||
|
||||
$this->setQuery('SHOW FULL COLUMNS FROM ' . $tables[0]);
|
||||
$array = $this->loadAssocList();
|
||||
|
||||
foreach ($array as $field)
|
||||
{
|
||||
if (!is_null($field['Collation']))
|
||||
{
|
||||
return $field['Collation'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of returned rows for the previous executed SQL statement.
|
||||
*
|
||||
* @param resource $cursor An optional database cursor resource to extract the row count from.
|
||||
*
|
||||
* @return integer The number of returned rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getNumRows($cursor = null)
|
||||
{
|
||||
return mysqli_num_rows($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the table CREATE statement that creates the given tables.
|
||||
*
|
||||
* @param mixed $tables A table name or a list of table names.
|
||||
*
|
||||
* @return array A list of the create SQL for the tables.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableCreate($tables)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$result = array();
|
||||
|
||||
// Sanitize input to an array and iterate over the list.
|
||||
settype($tables, 'array');
|
||||
foreach ($tables as $table)
|
||||
{
|
||||
// Set the query to get the table CREATE statement.
|
||||
$this->setQuery('SHOW CREATE table ' . $this->quoteName($this->escape($table)));
|
||||
$row = $this->loadRow();
|
||||
|
||||
// Populate the result array based on the create statements.
|
||||
$result[$table] = $row[1];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves field information about a given table.
|
||||
*
|
||||
* @param string $table The name of the database table.
|
||||
* @param boolean $typeOnly True to only return field types.
|
||||
*
|
||||
* @return array An array of fields for the database table.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableColumns($table, $typeOnly = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$result = array();
|
||||
|
||||
// Set the query to get the table fields statement.
|
||||
$this->setQuery('SHOW FULL COLUMNS FROM ' . $this->quoteName($this->escape($table)));
|
||||
$fields = $this->loadObjectList();
|
||||
|
||||
// If we only want the type as the value add just that to the list.
|
||||
if ($typeOnly)
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$result[$field->Field] = preg_replace("/[(0-9)]/", '', $field->Type);
|
||||
}
|
||||
}
|
||||
// If we want the whole field data object add that to the list.
|
||||
else
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$result[$field->Field] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of keys for a table.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return array An array of the column specification for the table.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableKeys($table)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
// Get the details columns information.
|
||||
$this->setQuery('SHOW KEYS FROM ' . $this->quoteName($table));
|
||||
$keys = $this->loadObjectList();
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get an array of all tables in the database.
|
||||
*
|
||||
* @return array An array of all the tables in the database.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableList()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
// Set the query to get the tables statement.
|
||||
$this->setQuery('SHOW TABLES');
|
||||
$tables = $this->loadColumn();
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database connector.
|
||||
*
|
||||
* @return string The database connector version.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysqli_get_server_info($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the auto-incremented value from the last INSERT statement.
|
||||
*
|
||||
* @return mixed The value of the auto-increment field from the last inserted row.
|
||||
* If the value is greater than maximal int value, it will return a string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function insertid()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return mysqli_insert_id($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a table in the database.
|
||||
*
|
||||
* @param string $table The name of the table to unlock.
|
||||
*
|
||||
* @return JDatabaseDriverMysqli Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function lockTable($table)
|
||||
{
|
||||
$this->setQuery('LOCK TABLES ' . $this->quoteName($table) . ' WRITE')->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the SQL statement.
|
||||
*
|
||||
* @return mixed A database cursor resource on success, boolean false on failure.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!is_object($this->connection))
|
||||
{
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
|
||||
// Take a local copy so that we don't modify the original query and cause issues later
|
||||
$query = $this->replacePrefix((string) $this->sql);
|
||||
if ($this->limit > 0 || $this->offset > 0)
|
||||
{
|
||||
$query .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
|
||||
}
|
||||
|
||||
// Increment the query counter.
|
||||
$this->count++;
|
||||
|
||||
// Reset the error values.
|
||||
$this->errorNum = 0;
|
||||
$this->errorMsg = '';
|
||||
$memoryBefore = null;
|
||||
|
||||
// If debugging is enabled then let's log the query.
|
||||
if ($this->debug)
|
||||
{
|
||||
// Add the query to the object queue.
|
||||
$this->log[] = $query;
|
||||
|
||||
JLog::add($query, JLog::DEBUG, 'databasequery');
|
||||
|
||||
$this->timings[] = microtime(true);
|
||||
|
||||
if (is_object($this->cursor))
|
||||
{
|
||||
$this->freeResult();
|
||||
}
|
||||
$memoryBefore = memory_get_usage();
|
||||
}
|
||||
|
||||
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
|
||||
$this->cursor = @mysqli_query($this->connection, $query);
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
$this->timings[] = microtime(true);
|
||||
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
|
||||
{
|
||||
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->callStacks[] = debug_backtrace();
|
||||
}
|
||||
$this->callStacks[count($this->callStacks) - 1][0]['memory'] = array($memoryBefore, memory_get_usage(), is_object($this->cursor) ? $this->getNumRows() : null);
|
||||
}
|
||||
|
||||
// If an error occurred handle it.
|
||||
if (!$this->cursor)
|
||||
{
|
||||
$this->errorNum = (int) mysqli_errno($this->connection);
|
||||
$this->errorMsg = (string) mysqli_error($this->connection) . ' SQL=' . $query;
|
||||
|
||||
// Check if the server was disconnected.
|
||||
if (!$this->connected())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to reconnect.
|
||||
$this->connection = null;
|
||||
$this->connect();
|
||||
}
|
||||
// If connect fails, ignore that exception and throw the normal exception.
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
|
||||
// Since we were able to reconnect, run the query again.
|
||||
return $this->execute();
|
||||
}
|
||||
// The server was not disconnected.
|
||||
else
|
||||
{
|
||||
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
|
||||
throw new RuntimeException($this->errorMsg, $this->errorNum);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a table in the database.
|
||||
*
|
||||
* @param string $oldTable The name of the table to be renamed
|
||||
* @param string $newTable The new name for the table.
|
||||
* @param string $backup Not used by MySQL.
|
||||
* @param string $prefix Not used by MySQL.
|
||||
*
|
||||
* @return JDatabaseDriverMysqli Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
|
||||
{
|
||||
$this->setQuery('RENAME TABLE ' . $oldTable . ' TO ' . $newTable)->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database for use.
|
||||
*
|
||||
* @param string $database The name of the database to select for use.
|
||||
*
|
||||
* @return boolean True if the database was successfully selected.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function select($database)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mysqli_select_db($this->connection, $database))
|
||||
{
|
||||
throw new RuntimeException('Could not connect to database.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use UTF-8 character encoding.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setUTF()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return $this->connection->set_charset('utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to commit a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, commit to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionCommit($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
if ($this->setQuery('COMMIT')->execute())
|
||||
{
|
||||
$this->transactionDepth = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to roll back a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, rollback to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionRollback($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
if ($this->setQuery('ROLLBACK')->execute())
|
||||
{
|
||||
$this->transactionDepth = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$savepoint = 'SP_' . ($this->transactionDepth - 1);
|
||||
$this->setQuery('ROLLBACK TO SAVEPOINT ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to initialize a transaction.
|
||||
*
|
||||
* @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.2
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionStart($asSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$asSavepoint || !$this->transactionDepth)
|
||||
{
|
||||
if ($this->setQuery('START TRANSACTION')->execute())
|
||||
{
|
||||
$this->transactionDepth = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$savepoint = 'SP_' . $this->transactionDepth;
|
||||
$this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an array.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchArray($cursor = null)
|
||||
{
|
||||
return mysqli_fetch_row($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an associative array.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchAssoc($cursor = null)
|
||||
{
|
||||
return mysqli_fetch_assoc($cursor ? $cursor : $this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
* @param string $class The class name to use for the returned row object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchObject($cursor = null, $class = 'stdClass')
|
||||
{
|
||||
return mysqli_fetch_object($cursor ? $cursor : $this->cursor, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @param mixed $cursor The optional result set cursor from which to fetch the row.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function freeResult($cursor = null)
|
||||
{
|
||||
mysqli_free_result($cursor ? $cursor : $this->cursor);
|
||||
if ((! $cursor) || ($cursor === $this->cursor))
|
||||
{
|
||||
$this->cursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks tables in the database.
|
||||
*
|
||||
* @return JDatabaseDriverMysqli Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function unlockTables()
|
||||
{
|
||||
$this->setQuery('UNLOCK TABLES')->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to check if profiling is available
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.1.3
|
||||
*/
|
||||
private function hasProfiling()
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = mysqli_query($this->connection, "SHOW VARIABLES LIKE 'have_profiling'");
|
||||
$row = mysqli_fetch_assoc($res);
|
||||
|
||||
return isset($row);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
680
libraries/joomla/database/driver/oracle.php
Normal file
680
libraries/joomla/database/driver/oracle.php
Normal file
@ -0,0 +1,680 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Oracle database driver
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://php.net/pdo
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseDriverOracle extends JDatabaseDriverPdo
|
||||
{
|
||||
/**
|
||||
* The name of the database driver.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
public $name = 'oracle';
|
||||
|
||||
/**
|
||||
* The character(s) used to quote SQL statement names such as table names or field names,
|
||||
* etc. The child classes should define this as necessary. If a single character string the
|
||||
* same character is used for both sides of the quoted name, else the first character will be
|
||||
* used for the opening quote and the second for the closing quote.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $nameQuote = '"';
|
||||
|
||||
/**
|
||||
* Returns the current dateformat
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $dateformat;
|
||||
|
||||
/**
|
||||
* Returns the current character set
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $charset;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options List of options used to configure the connection
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
$options['driver'] = 'oci';
|
||||
$options['charset'] = (isset($options['charset'])) ? $options['charset'] : 'AL32UTF8';
|
||||
$options['dateformat'] = (isset($options['dateformat'])) ? $options['dateformat'] : 'RRRR-MM-DD HH24:MI:SS';
|
||||
|
||||
$this->charset = $options['charset'];
|
||||
$this->dateformat = $options['dateformat'];
|
||||
|
||||
// Finalize initialisation
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->freeResult();
|
||||
unset($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the database if needed.
|
||||
*
|
||||
* @return void Returns void if the database connected successfully.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->connection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parent::connect();
|
||||
|
||||
if (isset($this->options['schema']))
|
||||
{
|
||||
$this->setQuery('ALTER SESSION SET CURRENT_SCHEMA = ' . $this->quoteName($this->options['schema']))->execute();
|
||||
}
|
||||
|
||||
$this->setDateFormat($this->dateformat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
// Close the connection.
|
||||
$this->freeResult();
|
||||
unset($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a table from the database.
|
||||
*
|
||||
* Note: The IF EXISTS flag is unused in the Oracle driver.
|
||||
*
|
||||
* @param string $tableName The name of the database table to drop.
|
||||
* @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
|
||||
*
|
||||
* @return JDatabaseDriverOracle Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function dropTable($tableName, $ifExists = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$query = $this->getQuery(true)
|
||||
->setQuery('DROP TABLE :tableName');
|
||||
$query->bind(':tableName', $tableName);
|
||||
|
||||
$this->setQuery($query);
|
||||
|
||||
$this->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the database collation in use by sampling a text field of a table in the database.
|
||||
*
|
||||
* @return mixed The collation in use by the database or boolean false if not supported.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getCollation()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query to run and verify the database is operational.
|
||||
*
|
||||
* @return string The query to check the health of the DB.
|
||||
*
|
||||
* @since 12.2
|
||||
*/
|
||||
public function getConnectedQuery()
|
||||
{
|
||||
return 'SELECT 1 FROM dual';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current date format
|
||||
* This method should be useful in the case that
|
||||
* somebody actually wants to use a different
|
||||
* date format and needs to check what the current
|
||||
* one is to see if it needs to be changed.
|
||||
*
|
||||
* @return string The current date format
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getDateFormat()
|
||||
{
|
||||
return $this->dateformat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the table CREATE statement that creates the given tables.
|
||||
*
|
||||
* Note: You must have the correct privileges before this method
|
||||
* will return usable results!
|
||||
*
|
||||
* @param mixed $tables A table name or a list of table names.
|
||||
*
|
||||
* @return array A list of the create SQL for the tables.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableCreate($tables)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$result = array();
|
||||
$query = $this->getQuery(true)
|
||||
->select('dbms_metadata.get_ddl(:type, :tableName)')
|
||||
->from('dual')
|
||||
->bind(':type', 'TABLE');
|
||||
|
||||
// Sanitize input to an array and iterate over the list.
|
||||
settype($tables, 'array');
|
||||
foreach ($tables as $table)
|
||||
{
|
||||
$query->bind(':tableName', $table);
|
||||
$this->setQuery($query);
|
||||
$statement = (string) $this->loadResult();
|
||||
$result[$table] = $statement;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves field information about a given table.
|
||||
*
|
||||
* @param string $table The name of the database table.
|
||||
* @param boolean $typeOnly True to only return field types.
|
||||
*
|
||||
* @return array An array of fields for the database table.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableColumns($table, $typeOnly = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$columns = array();
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
|
||||
|
||||
$table = strtoupper($table);
|
||||
|
||||
$query->select('*');
|
||||
$query->from('ALL_TAB_COLUMNS');
|
||||
$query->where('table_name = :tableName');
|
||||
|
||||
$prefixedTable = str_replace('#__', strtoupper($this->tablePrefix), $table);
|
||||
$query->bind(':tableName', $prefixedTable);
|
||||
$this->setQuery($query);
|
||||
$fields = $this->loadObjectList();
|
||||
|
||||
if ($typeOnly)
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$columns[$field->COLUMN_NAME] = $field->DATA_TYPE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$columns[$field->COLUMN_NAME] = $field;
|
||||
$columns[$field->COLUMN_NAME]->Default = null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of keys for a table.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return array An array of the column specification for the table.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableKeys($table)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
|
||||
|
||||
$table = strtoupper($table);
|
||||
$query->select('*')
|
||||
->from('ALL_CONSTRAINTS')
|
||||
->where('table_name = :tableName')
|
||||
->bind(':tableName', $table);
|
||||
|
||||
$this->setQuery($query);
|
||||
$keys = $this->loadObjectList();
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get an array of all tables in the database (schema).
|
||||
*
|
||||
* @param string $databaseName The database (schema) name
|
||||
* @param boolean $includeDatabaseName Whether to include the schema name in the results
|
||||
*
|
||||
* @return array An array of all the tables in the database.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableList($databaseName = null, $includeDatabaseName = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
if ($includeDatabaseName)
|
||||
{
|
||||
$query->select('owner, table_name');
|
||||
}
|
||||
else
|
||||
{
|
||||
$query->select('table_name');
|
||||
}
|
||||
|
||||
$query->from('all_tables');
|
||||
if ($databaseName)
|
||||
{
|
||||
$query->where('owner = :database')
|
||||
->bind(':database', $databaseName);
|
||||
}
|
||||
|
||||
$query->order('table_name');
|
||||
|
||||
$this->setQuery($query);
|
||||
|
||||
if ($includeDatabaseName)
|
||||
{
|
||||
$tables = $this->loadAssocList();
|
||||
}
|
||||
else
|
||||
{
|
||||
$tables = $this->loadColumn();
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database connector.
|
||||
*
|
||||
* @return string The database connector version.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$this->setQuery("select value from nls_database_parameters where parameter = 'NLS_RDBMS_VERSION'");
|
||||
|
||||
return $this->loadResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database for use.
|
||||
*
|
||||
* @param string $database The name of the database to select for use.
|
||||
*
|
||||
* @return boolean True if the database was successfully selected.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function select($database)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Oracle Date Format for the session
|
||||
* Default date format for Oracle is = DD-MON-RR
|
||||
* The default date format for this driver is:
|
||||
* 'RRRR-MM-DD HH24:MI:SS' since it is the format
|
||||
* that matches the MySQL one used within most Joomla
|
||||
* tables.
|
||||
*
|
||||
* @param string $dateFormat Oracle Date Format String
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setDateFormat($dateFormat = 'DD-MON-RR')
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$this->setQuery("ALTER SESSION SET NLS_DATE_FORMAT = '$dateFormat'");
|
||||
|
||||
if (!$this->execute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setQuery("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = '$dateFormat'");
|
||||
if (!$this->execute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->dateformat = $dateFormat;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use UTF-8 character encoding.
|
||||
*
|
||||
* Returns false automatically for the Oracle driver since
|
||||
* you can only set the character set when the connection
|
||||
* is created.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setUTF()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a table in the database.
|
||||
*
|
||||
* @param string $table The name of the table to unlock.
|
||||
*
|
||||
* @return JDatabaseDriverOracle Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function lockTable($table)
|
||||
{
|
||||
$this->setQuery('LOCK TABLE ' . $this->quoteName($table) . ' IN EXCLUSIVE MODE')->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a table in the database.
|
||||
*
|
||||
* @param string $oldTable The name of the table to be renamed
|
||||
* @param string $newTable The new name for the table.
|
||||
* @param string $backup Not used by Oracle.
|
||||
* @param string $prefix Not used by Oracle.
|
||||
*
|
||||
* @return JDatabaseDriverOracle Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
|
||||
{
|
||||
$this->setQuery('RENAME ' . $oldTable . ' TO ' . $newTable)->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks tables in the database.
|
||||
*
|
||||
* @return JDatabaseDriverOracle Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function unlockTables()
|
||||
{
|
||||
$this->setQuery('COMMIT')->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the PDO ODBC connector is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return class_exists('PDO') && in_array('oci', PDO::getAvailableDrivers());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function replaces a string identifier <var>$prefix</var> with the string held is the
|
||||
* <var>tablePrefix</var> class variable.
|
||||
*
|
||||
* @param string $query The SQL statement to prepare.
|
||||
* @param string $prefix The common table prefix.
|
||||
*
|
||||
* @return string The processed SQL statement.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function replacePrefix($query, $prefix = '#__')
|
||||
{
|
||||
$startPos = 0;
|
||||
$quoteChar = "'";
|
||||
$literal = '';
|
||||
|
||||
$query = trim($query);
|
||||
$n = strlen($query);
|
||||
|
||||
while ($startPos < $n)
|
||||
{
|
||||
$ip = strpos($query, $prefix, $startPos);
|
||||
if ($ip === false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
$j = strpos($query, "'", $startPos);
|
||||
|
||||
if ($j === false)
|
||||
{
|
||||
$j = $n;
|
||||
}
|
||||
|
||||
$literal .= str_replace($prefix, $this->tablePrefix, substr($query, $startPos, $j - $startPos));
|
||||
$startPos = $j;
|
||||
|
||||
$j = $startPos + 1;
|
||||
|
||||
if ($j >= $n)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Quote comes first, find end of quote
|
||||
while (true)
|
||||
{
|
||||
$k = strpos($query, $quoteChar, $j);
|
||||
$escaped = false;
|
||||
if ($k === false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$l = $k - 1;
|
||||
while ($l >= 0 && $query{$l} == '\\')
|
||||
{
|
||||
$l--;
|
||||
$escaped = !$escaped;
|
||||
}
|
||||
if ($escaped)
|
||||
{
|
||||
$j = $k + 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($k === false)
|
||||
{
|
||||
// Error in the query - no end quote; ignore it
|
||||
break;
|
||||
}
|
||||
$literal .= substr($query, $startPos, $k - $startPos + 1);
|
||||
$startPos = $k + 1;
|
||||
}
|
||||
if ($startPos < $n)
|
||||
{
|
||||
$literal .= substr($query, $startPos, $n - $startPos);
|
||||
}
|
||||
|
||||
return $literal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to commit a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, commit to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionCommit($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
parent::transactionCommit($toSavepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to roll back a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, rollback to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionRollback($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
parent::transactionRollback($toSavepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
$savepoint = 'SP_' . ($this->transactionDepth - 1);
|
||||
$this->setQuery('ROLLBACK TO SAVEPOINT ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to initialize a transaction.
|
||||
*
|
||||
* @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionStart($asSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$asSavepoint || !$this->transactionDepth)
|
||||
{
|
||||
return parent::transactionStart($asSavepoint);
|
||||
}
|
||||
|
||||
$savepoint = 'SP_' . $this->transactionDepth;
|
||||
$this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
1017
libraries/joomla/database/driver/pdo.php
Normal file
1017
libraries/joomla/database/driver/pdo.php
Normal file
File diff suppressed because it is too large
Load Diff
1401
libraries/joomla/database/driver/postgresql.php
Normal file
1401
libraries/joomla/database/driver/postgresql.php
Normal file
File diff suppressed because it is too large
Load Diff
29
libraries/joomla/database/driver/sqlazure.php
Normal file
29
libraries/joomla/database/driver/sqlazure.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* SQL Server database driver
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://msdn.microsoft.com/en-us/library/ee336279.aspx
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseDriverSqlazure extends JDatabaseDriverSqlsrv
|
||||
{
|
||||
/**
|
||||
* The name of the database driver.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
public $name = 'sqlzure';
|
||||
}
|
||||
464
libraries/joomla/database/driver/sqlite.php
Normal file
464
libraries/joomla/database/driver/sqlite.php
Normal file
@ -0,0 +1,464 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* SQLite database driver
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://php.net/pdo
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseDriverSqlite extends JDatabaseDriverPdo
|
||||
{
|
||||
/**
|
||||
* The name of the database driver.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
public $name = 'sqlite';
|
||||
|
||||
/**
|
||||
* The character(s) used to quote SQL statement names such as table names or field names,
|
||||
* etc. The child classes should define this as necessary. If a single character string the
|
||||
* same character is used for both sides of the quoted name, else the first character will be
|
||||
* used for the opening quote and the second for the closing quote.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $nameQuote = '`';
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->freeResult();
|
||||
unset($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->freeResult();
|
||||
unset($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a table from the database.
|
||||
*
|
||||
* @param string $tableName The name of the database table to drop.
|
||||
* @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
|
||||
*
|
||||
* @return JDatabaseDriverSqlite Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function dropTable($tableName, $ifExists = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $query->quoteName($tableName));
|
||||
|
||||
$this->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to escape a string for usage in an SQLite statement.
|
||||
*
|
||||
* Note: Using query objects with bound variables is
|
||||
* preferable to the below.
|
||||
*
|
||||
* @param string $text The string to be escaped.
|
||||
* @param boolean $extra Unused optional parameter to provide extra escaping.
|
||||
*
|
||||
* @return string The escaped string.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function escape($text, $extra = false)
|
||||
{
|
||||
if (is_int($text) || is_float($text))
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
|
||||
return SQLite3::escapeString($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the database collation in use by sampling a text field of a table in the database.
|
||||
*
|
||||
* @return mixed The collation in use by the database or boolean false if not supported.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getCollation()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the table CREATE statement that creates the given tables.
|
||||
*
|
||||
* Note: Doesn't appear to have support in SQLite
|
||||
*
|
||||
* @param mixed $tables A table name or a list of table names.
|
||||
*
|
||||
* @return array A list of the create SQL for the tables.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableCreate($tables)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
// Sanitize input to an array and iterate over the list.
|
||||
settype($tables, 'array');
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves field information about a given table.
|
||||
*
|
||||
* @param string $table The name of the database table.
|
||||
* @param boolean $typeOnly True to only return field types.
|
||||
*
|
||||
* @return array An array of fields for the database table.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableColumns($table, $typeOnly = true)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$columns = array();
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
|
||||
|
||||
$table = strtoupper($table);
|
||||
|
||||
$query->setQuery('pragma table_info(' . $table . ')');
|
||||
|
||||
$this->setQuery($query);
|
||||
$fields = $this->loadObjectList();
|
||||
|
||||
if ($typeOnly)
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$columns[$field->NAME] = $field->TYPE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
// Do some dirty translation to MySQL output.
|
||||
// TODO: Come up with and implement a standard across databases.
|
||||
$columns[$field->NAME] = (object) array(
|
||||
'Field' => $field->NAME,
|
||||
'Type' => $field->TYPE,
|
||||
'Null' => ($field->NOTNULL == '1' ? 'NO' : 'YES'),
|
||||
'Default' => $field->DFLT_VALUE,
|
||||
'Key' => ($field->PK == '1' ? 'PRI' : '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of keys for a table.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return array An array of the column specification for the table.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableKeys($table)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$keys = array();
|
||||
$query = $this->getQuery(true);
|
||||
|
||||
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
|
||||
|
||||
$table = strtoupper($table);
|
||||
$query->setQuery('pragma table_info( ' . $table . ')');
|
||||
|
||||
// $query->bind(':tableName', $table);
|
||||
|
||||
$this->setQuery($query);
|
||||
$rows = $this->loadObjectList();
|
||||
|
||||
foreach ($rows as $column)
|
||||
{
|
||||
if ($column->PK == 1)
|
||||
{
|
||||
$keys[$column->NAME] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get an array of all tables in the database (schema).
|
||||
*
|
||||
* @return array An array of all the tables in the database.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getTableList()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$type = 'table';
|
||||
|
||||
$query->$this->getQuery(true)
|
||||
->select('name')
|
||||
->from('sqlite_master')
|
||||
->where('type = :type')
|
||||
->bind(':type', $type)
|
||||
->order('name');
|
||||
|
||||
$this->setQuery($query);
|
||||
|
||||
$tables = $this->loadColumn();
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database connector.
|
||||
*
|
||||
* @return string The database connector version.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
$this->setQuery("SELECT sqlite_version()");
|
||||
|
||||
return $this->loadResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database for use.
|
||||
*
|
||||
* @param string $database The name of the database to select for use.
|
||||
*
|
||||
* @return boolean True if the database was successfully selected.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function select($database)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use UTF-8 character encoding.
|
||||
*
|
||||
* Returns false automatically for the Oracle driver since
|
||||
* you can only set the character set when the connection
|
||||
* is created.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setUTF()
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a table in the database.
|
||||
*
|
||||
* @param string $table The name of the table to unlock.
|
||||
*
|
||||
* @return JDatabaseDriverSqlite Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function lockTable($table)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a table in the database.
|
||||
*
|
||||
* @param string $oldTable The name of the table to be renamed
|
||||
* @param string $newTable The new name for the table.
|
||||
* @param string $backup Not used by Sqlite.
|
||||
* @param string $prefix Not used by Sqlite.
|
||||
*
|
||||
* @return JDatabaseDriverSqlite Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
|
||||
{
|
||||
$this->setQuery('ALTER TABLE ' . $oldTable . ' RENAME TO ' . $newTable)->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks tables in the database.
|
||||
*
|
||||
* @return JDatabaseDriverSqlite Returns this object to support chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function unlockTables()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the PDO ODBC connector is available.
|
||||
*
|
||||
* @return boolean True on success, false otherwise.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return class_exists('PDO') && in_array('sqlite', PDO::getAvailableDrivers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to commit a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, commit to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionCommit($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
parent::transactionCommit($toSavepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to roll back a transaction.
|
||||
*
|
||||
* @param boolean $toSavepoint If true, rollback to the last savepoint.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionRollback($toSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$toSavepoint || $this->transactionDepth <= 1)
|
||||
{
|
||||
parent::transactionRollback($toSavepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
$savepoint = 'SP_' . ($this->transactionDepth - 1);
|
||||
$this->setQuery('ROLLBACK TO ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to initialize a transaction.
|
||||
*
|
||||
* @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.3
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function transactionStart($asSavepoint = false)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if (!$asSavepoint || !$this->transactionDepth)
|
||||
{
|
||||
parent::transactionStart($asSavepoint);
|
||||
}
|
||||
|
||||
$savepoint = 'SP_' . $this->transactionDepth;
|
||||
$this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));
|
||||
|
||||
if ($this->execute())
|
||||
{
|
||||
$this->transactionDepth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
1080
libraries/joomla/database/driver/sqlsrv.php
Normal file
1080
libraries/joomla/database/driver/sqlsrv.php
Normal file
File diff suppressed because it is too large
Load Diff
22
libraries/joomla/database/exporter.php
Normal file
22
libraries/joomla/database/exporter.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Database Exporter Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JDatabaseExporter
|
||||
{
|
||||
|
||||
}
|
||||
1
libraries/joomla/database/exporter/index.html
Normal file
1
libraries/joomla/database/exporter/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
62
libraries/joomla/database/exporter/mysql.php
Normal file
62
libraries/joomla/database/exporter/mysql.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQL export driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 11.1
|
||||
*/
|
||||
class JDatabaseExporterMysql extends JDatabaseExporterMysqli
|
||||
{
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseExporterMySQL Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverMysql))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from MySQL.
|
||||
*
|
||||
* @param JDatabaseDriverMysql $db The database connector.
|
||||
*
|
||||
* @return JDatabaseExporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverMysql $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
287
libraries/joomla/database/exporter/mysqli.php
Normal file
287
libraries/joomla/database/exporter/mysqli.php
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQLi export driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 11.1
|
||||
*/
|
||||
class JDatabaseExporterMysqli extends JDatabaseExporter
|
||||
{
|
||||
/**
|
||||
* An array of cached data.
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* The database connector to use for exporting structure and/or data.
|
||||
*
|
||||
* @var JDatabaseDriverMysql
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $db = null;
|
||||
|
||||
/**
|
||||
* An array input sources (table names).
|
||||
*
|
||||
* @var array
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $from = array();
|
||||
|
||||
/**
|
||||
* The type of output format (xml).
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $asFormat = 'xml';
|
||||
|
||||
/**
|
||||
* An array of options for the exporter.
|
||||
*
|
||||
* @var object
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $options = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets up the default options for the exporter.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->options = new stdClass;
|
||||
|
||||
$this->cache = array('columns' => array(), 'keys' => array());
|
||||
|
||||
// Set up the class defaults:
|
||||
|
||||
// Export with only structure
|
||||
$this->withStructure();
|
||||
|
||||
// Export as xml.
|
||||
$this->asXml();
|
||||
|
||||
// Default destination is a string using $output = (string) $exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic function to exports the data to a string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
// Check everything is ok to run first.
|
||||
$this->check();
|
||||
|
||||
return $this->buildXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output option for the exporter to XML format.
|
||||
*
|
||||
* @return JDatabaseExporterMySQL Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function asXml()
|
||||
{
|
||||
$this->asFormat = 'xml';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the XML data for the tables to export.
|
||||
*
|
||||
* @return string An XML string
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error occurs.
|
||||
*/
|
||||
protected function buildXml()
|
||||
{
|
||||
$buffer = array();
|
||||
|
||||
$buffer[] = '<?xml version="1.0"?>';
|
||||
$buffer[] = '<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
|
||||
$buffer[] = ' <database name="">';
|
||||
|
||||
$buffer = array_merge($buffer, $this->buildXmlStructure());
|
||||
|
||||
$buffer[] = ' </database>';
|
||||
$buffer[] = '</mysqldump>';
|
||||
|
||||
return implode("\n", $buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the XML structure to export.
|
||||
*
|
||||
* @return array An array of XML lines (strings).
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error occurs.
|
||||
*/
|
||||
protected function buildXmlStructure()
|
||||
{
|
||||
$buffer = array();
|
||||
|
||||
foreach ($this->from as $table)
|
||||
{
|
||||
// Replace the magic prefix if found.
|
||||
$table = $this->getGenericTableName($table);
|
||||
|
||||
// Get the details columns information.
|
||||
$fields = $this->db->getTableColumns($table, false);
|
||||
$keys = $this->db->getTableKeys($table);
|
||||
|
||||
$buffer[] = ' <table_structure name="' . $table . '">';
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$buffer[] = ' <field Field="' . $field->Field . '"' . ' Type="' . $field->Type . '"' . ' Null="' . $field->Null . '"' . ' Key="' .
|
||||
$field->Key . '"' . (isset($field->Default) ? ' Default="' . $field->Default . '"' : '') . ' Extra="' . $field->Extra . '"' .
|
||||
' />';
|
||||
}
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
$buffer[] = ' <key Table="' . $table . '"' . ' Non_unique="' . $key->Non_unique . '"' . ' Key_name="' . $key->Key_name . '"' .
|
||||
' Seq_in_index="' . $key->Seq_in_index . '"' . ' Column_name="' . $key->Column_name . '"' . ' Collation="' . $key->Collation . '"' .
|
||||
' Null="' . $key->Null . '"' . ' Index_type="' . $key->Index_type . '"' . ' Comment="' . htmlspecialchars($key->Comment) . '"' .
|
||||
' />';
|
||||
}
|
||||
|
||||
$buffer[] = ' </table_structure>';
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseExporterMysqli Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverMysqli))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic name of the table, converting the database prefix to the wildcard string.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return string The name of the table with the database prefix replaced with #__.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getGenericTableName($table)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
// Replace the magic prefix if found.
|
||||
$table = preg_replace("|^$prefix|", '#__', $table);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a list of table names to export.
|
||||
*
|
||||
* @param mixed $from The name of a single table, or an array of the table names to export.
|
||||
*
|
||||
* @return JDatabaseExporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if input is not a string or array.
|
||||
*/
|
||||
public function from($from)
|
||||
{
|
||||
if (is_string($from))
|
||||
{
|
||||
$this->from = array($from);
|
||||
}
|
||||
elseif (is_array($from))
|
||||
{
|
||||
$this->from = $from;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_INPUT_REQUIRES_STRING_OR_ARRAY');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from MySQL.
|
||||
*
|
||||
* @param JDatabaseDriverMysqli $db The database connector.
|
||||
*
|
||||
* @return JDatabaseExporterMysqli Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverMysqli $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an internal option to export the structure of the input table(s).
|
||||
*
|
||||
* @param boolean $setting True to export the structure, false to not.
|
||||
*
|
||||
* @return JDatabaseExporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function withStructure($setting = true)
|
||||
{
|
||||
$this->options->withStructure = (boolean) $setting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
302
libraries/joomla/database/exporter/postgresql.php
Normal file
302
libraries/joomla/database/exporter/postgresql.php
Normal file
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* PostgreSQL export driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseExporterPostgresql extends JDatabaseExporter
|
||||
{
|
||||
/**
|
||||
* An array of cached data.
|
||||
*
|
||||
* @var array
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* The database connector to use for exporting structure and/or data.
|
||||
*
|
||||
* @var JDatabaseDriverPostgresql
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $db = null;
|
||||
|
||||
/**
|
||||
* An array input sources (table names).
|
||||
*
|
||||
* @var array
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $from = array();
|
||||
|
||||
/**
|
||||
* The type of output format (xml).
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $asFormat = 'xml';
|
||||
|
||||
/**
|
||||
* An array of options for the exporter.
|
||||
*
|
||||
* @var object
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $options = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets up the default options for the exporter.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->options = new stdClass;
|
||||
|
||||
$this->cache = array('columns' => array(), 'keys' => array());
|
||||
|
||||
// Set up the class defaults:
|
||||
|
||||
// Export with only structure
|
||||
$this->withStructure();
|
||||
|
||||
// Export as xml.
|
||||
$this->asXml();
|
||||
|
||||
// Default destination is a string using $output = (string) $exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic function to exports the data to a string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
// Check everything is ok to run first.
|
||||
$this->check();
|
||||
|
||||
return $this->buildXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output option for the exporter to XML format.
|
||||
*
|
||||
* @return JDatabaseExporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function asXml()
|
||||
{
|
||||
$this->asFormat = 'xml';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the XML data for the tables to export.
|
||||
*
|
||||
* @return string An XML string
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception if an error occurs.
|
||||
*/
|
||||
protected function buildXml()
|
||||
{
|
||||
$buffer = array();
|
||||
|
||||
$buffer[] = '<?xml version="1.0"?>';
|
||||
$buffer[] = '<postgresqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
|
||||
$buffer[] = ' <database name="">';
|
||||
|
||||
$buffer = array_merge($buffer, $this->buildXmlStructure());
|
||||
|
||||
$buffer[] = ' </database>';
|
||||
$buffer[] = '</postgresqldump>';
|
||||
|
||||
return implode("\n", $buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the XML structure to export.
|
||||
*
|
||||
* @return array An array of XML lines (strings).
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception if an error occurs.
|
||||
*/
|
||||
protected function buildXmlStructure()
|
||||
{
|
||||
$buffer = array();
|
||||
|
||||
foreach ($this->from as $table)
|
||||
{
|
||||
// Replace the magic prefix if found.
|
||||
$table = $this->getGenericTableName($table);
|
||||
|
||||
// Get the details columns information.
|
||||
$fields = $this->db->getTableColumns($table, false);
|
||||
$keys = $this->db->getTableKeys($table);
|
||||
$sequences = $this->db->getTableSequences($table);
|
||||
|
||||
$buffer[] = ' <table_structure name="' . $table . '">';
|
||||
|
||||
foreach ($sequences as $sequence)
|
||||
{
|
||||
if (version_compare($this->db->getVersion(), '9.1.0') < 0)
|
||||
{
|
||||
$sequence->start_value = null;
|
||||
}
|
||||
|
||||
$buffer[] = ' <sequence Name="' . $sequence->sequence . '"' . ' Schema="' . $sequence->schema . '"' .
|
||||
' Table="' . $sequence->table . '"' . ' Column="' . $sequence->column . '"' . ' Type="' . $sequence->data_type . '"' .
|
||||
' Start_Value="' . $sequence->start_value . '"' . ' Min_Value="' . $sequence->minimum_value . '"' .
|
||||
' Max_Value="' . $sequence->maximum_value . '"' . ' Increment="' . $sequence->increment . '"' .
|
||||
' Cycle_option="' . $sequence->cycle_option . '"' .
|
||||
' />';
|
||||
}
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$buffer[] = ' <field Field="' . $field->column_name . '"' . ' Type="' . $field->type . '"' . ' Null="' . $field->null . '"' .
|
||||
(isset($field->default) ? ' Default="' . $field->default . '"' : '') . ' Comments="' . $field->comments . '"' .
|
||||
' />';
|
||||
}
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
$buffer[] = ' <key Index="' . $key->idxName . '"' . ' is_primary="' . $key->isPrimary . '"' . ' is_unique="' . $key->isUnique . '"' .
|
||||
' Query="' . $key->Query . '" />';
|
||||
}
|
||||
|
||||
$buffer[] = ' </table_structure>';
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseExporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverPostgresql))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic name of the table, converting the database prefix to the wildcard string.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return string The name of the table with the database prefix replaced with #__.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getGenericTableName($table)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
// Replace the magic prefix if found.
|
||||
$table = preg_replace("|^$prefix|", '#__', $table);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a list of table names to export.
|
||||
*
|
||||
* @param mixed $from The name of a single table, or an array of the table names to export.
|
||||
*
|
||||
* @return JDatabaseExporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception if input is not a string or array.
|
||||
*/
|
||||
public function from($from)
|
||||
{
|
||||
if (is_string($from))
|
||||
{
|
||||
$this->from = array($from);
|
||||
}
|
||||
elseif (is_array($from))
|
||||
{
|
||||
$this->from = $from;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_INPUT_REQUIRES_STRING_OR_ARRAY');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from PostgreSQL.
|
||||
*
|
||||
* @param JDatabaseDriverPostgresql $db The database connector.
|
||||
*
|
||||
* @return JDatabaseExporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverPostgresql $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an internal option to export the structure of the input table(s).
|
||||
*
|
||||
* @param boolean $setting True to export the structure, false to not.
|
||||
*
|
||||
* @return JDatabaseExporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function withStructure($setting = true)
|
||||
{
|
||||
$this->options->withStructure = (boolean) $setting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
192
libraries/joomla/database/factory.php
Normal file
192
libraries/joomla/database/factory.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Database Factory class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseFactory
|
||||
{
|
||||
/**
|
||||
* Contains the current JDatabaseFactory instance
|
||||
*
|
||||
* @var JDatabaseFactory
|
||||
* @since 12.1
|
||||
*/
|
||||
private static $_instance = null;
|
||||
|
||||
/**
|
||||
* Method to return a JDatabaseDriver instance based on the given options. There are three global options and then
|
||||
* the rest are specific to the database driver. The 'database' option determines which database is to
|
||||
* be used for the connection. The 'select' option determines whether the connector should automatically select
|
||||
* the chosen database.
|
||||
*
|
||||
* Instances are unique to the given options and new objects are only created when a unique options array is
|
||||
* passed into the method. This ensures that we don't end up with unnecessary database connection resources.
|
||||
*
|
||||
* @param string $name Name of the database driver you'd like to instantiate
|
||||
* @param array $options Parameters to be passed to the database driver.
|
||||
*
|
||||
* @return JDatabaseDriver A database driver object.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getDriver($name = 'mysqli', $options = array())
|
||||
{
|
||||
// Sanitize the database connector options.
|
||||
$options['driver'] = preg_replace('/[^A-Z0-9_\.-]/i', '', $name);
|
||||
$options['database'] = (isset($options['database'])) ? $options['database'] : null;
|
||||
$options['select'] = (isset($options['select'])) ? $options['select'] : true;
|
||||
|
||||
// Derive the class name from the driver.
|
||||
$class = 'JDatabaseDriver' . ucfirst(strtolower($options['driver']));
|
||||
|
||||
// If the class still doesn't exist we have nothing left to do but throw an exception. We did our best.
|
||||
if (!class_exists($class))
|
||||
{
|
||||
throw new RuntimeException(sprintf('Unable to load Database Driver: %s', $options['driver']));
|
||||
}
|
||||
|
||||
// Create our new JDatabaseDriver connector based on the options given.
|
||||
try
|
||||
{
|
||||
$instance = new $class($options);
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
throw new RuntimeException(sprintf('Unable to connect to the Database: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an exporter class object.
|
||||
*
|
||||
* @param string $name Name of the driver you want an exporter for.
|
||||
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
|
||||
*
|
||||
* @return JDatabaseExporter An exporter object.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getExporter($name, JDatabaseDriver $db = null)
|
||||
{
|
||||
// Derive the class name from the driver.
|
||||
$class = 'JDatabaseExporter' . ucfirst(strtolower($name));
|
||||
|
||||
// Make sure we have an exporter class for this driver.
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// If it doesn't exist we are at an impasse so throw an exception.
|
||||
throw new RuntimeException('Database Exporter not found.');
|
||||
}
|
||||
|
||||
$o = new $class;
|
||||
|
||||
if ($db instanceof JDatabaseDriver)
|
||||
{
|
||||
$o->setDbo($db);
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an importer class object.
|
||||
*
|
||||
* @param string $name Name of the driver you want an importer for.
|
||||
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
|
||||
*
|
||||
* @return JDatabaseImporter An importer object.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getImporter($name, JDatabaseDriver $db = null)
|
||||
{
|
||||
// Derive the class name from the driver.
|
||||
$class = 'JDatabaseImporter' . ucfirst(strtolower($name));
|
||||
|
||||
// Make sure we have an importer class for this driver.
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// If it doesn't exist we are at an impasse so throw an exception.
|
||||
throw new RuntimeException('Database importer not found.');
|
||||
}
|
||||
|
||||
$o = new $class;
|
||||
|
||||
if ($db instanceof JDatabaseDriver)
|
||||
{
|
||||
$o->setDbo($db);
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of the factory object.
|
||||
*
|
||||
* @return JDatabaseFactory
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
return self::$_instance ? self::$_instance : new JDatabaseFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current query object or a new JDatabaseQuery object.
|
||||
*
|
||||
* @param string $name Name of the driver you want an query object for.
|
||||
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
|
||||
*
|
||||
* @return JDatabaseQuery The current query object or a new object extending the JDatabaseQuery class.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getQuery($name, JDatabaseDriver $db = null)
|
||||
{
|
||||
// Derive the class name from the driver.
|
||||
$class = 'JDatabaseQuery' . ucfirst(strtolower($name));
|
||||
|
||||
// Make sure we have a query class for this driver.
|
||||
if (!class_exists($class))
|
||||
{
|
||||
// If it doesn't exist we are at an impasse so throw an exception.
|
||||
throw new RuntimeException('Database Query class not found');
|
||||
}
|
||||
|
||||
return new $class($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of a factory object to return on subsequent calls of getInstance.
|
||||
*
|
||||
* @param JDatabaseFactory $instance A JDatabaseFactory object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public static function setInstance(JDatabaseFactory $instance = null)
|
||||
{
|
||||
self::$_instance = $instance;
|
||||
}
|
||||
}
|
||||
22
libraries/joomla/database/importer.php
Normal file
22
libraries/joomla/database/importer.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Database Importer Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JDatabaseImporter
|
||||
{
|
||||
|
||||
}
|
||||
1
libraries/joomla/database/importer/index.html
Normal file
1
libraries/joomla/database/importer/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
61
libraries/joomla/database/importer/mysql.php
Normal file
61
libraries/joomla/database/importer/mysql.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQL import driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 11.1
|
||||
*/
|
||||
class JDatabaseImporterMysql extends JDatabaseImporterMysqli
|
||||
{
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseImporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverMysql))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from MySQL.
|
||||
*
|
||||
* @param JDatabaseDriverMysql $db The database connector.
|
||||
*
|
||||
* @return JDatabaseImporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverMysql $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
646
libraries/joomla/database/importer/mysqli.php
Normal file
646
libraries/joomla/database/importer/mysqli.php
Normal file
@ -0,0 +1,646 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQLi import driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 11.1
|
||||
*/
|
||||
class JDatabaseImporterMysqli extends JDatabaseImporter
|
||||
{
|
||||
/**
|
||||
* @var array An array of cached data.
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* The database connector to use for exporting structure and/or data.
|
||||
*
|
||||
* @var JDatabaseDriverMysql
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $db = null;
|
||||
|
||||
/**
|
||||
* The input source.
|
||||
*
|
||||
* @var mixed
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $from = array();
|
||||
|
||||
/**
|
||||
* The type of input format (XML).
|
||||
*
|
||||
* @var string
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $asFormat = 'xml';
|
||||
|
||||
/**
|
||||
* An array of options for the exporter.
|
||||
*
|
||||
* @var object
|
||||
* @since 11.1
|
||||
*/
|
||||
protected $options = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets up the default options for the exporter.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->options = new stdClass;
|
||||
|
||||
$this->cache = array('columns' => array(), 'keys' => array());
|
||||
|
||||
// Set up the class defaults:
|
||||
|
||||
// Import with only structure
|
||||
$this->withStructure();
|
||||
|
||||
// Export as XML.
|
||||
$this->asXml();
|
||||
|
||||
// Default destination is a string using $output = (string) $exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output option for the exporter to XML format.
|
||||
*
|
||||
* @return JDatabaseImporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function asXml()
|
||||
{
|
||||
$this->asFormat = 'xml';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseImporterMysqli Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverMysqli))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the data source to import.
|
||||
*
|
||||
* @param mixed $from The data source to import.
|
||||
*
|
||||
* @return JDatabaseImporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function from($from)
|
||||
{
|
||||
$this->from = $from;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to add a column.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param SimpleXMLElement $field The XML field definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getAddColumnSQL($table, SimpleXMLElement $field)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to add a key.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param array $keys An array of the fields pertaining to this key.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getAddKeySQL($table, $keys)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySQL($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alters for table if there is a difference.
|
||||
*
|
||||
* @param SimpleXMLElement $structure The XML structure pf the table.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getAlterTableSQL(SimpleXMLElement $structure)
|
||||
{
|
||||
$table = $this->getRealTableName($structure['name']);
|
||||
$oldFields = $this->db->getTableColumns($table);
|
||||
$oldKeys = $this->db->getTableKeys($table);
|
||||
$alters = array();
|
||||
|
||||
// Get the fields and keys from the XML that we are aiming for.
|
||||
$newFields = $structure->xpath('field');
|
||||
$newKeys = $structure->xpath('key');
|
||||
|
||||
// Loop through each field in the new structure.
|
||||
foreach ($newFields as $field)
|
||||
{
|
||||
$fName = (string) $field['Field'];
|
||||
|
||||
if (isset($oldFields[$fName]))
|
||||
{
|
||||
// The field exists, check it's the same.
|
||||
$column = $oldFields[$fName];
|
||||
|
||||
// Test whether there is a change.
|
||||
$change = ((string) $field['Type'] != $column->Type) || ((string) $field['Null'] != $column->Null)
|
||||
|| ((string) $field['Default'] != $column->Default) || ((string) $field['Extra'] != $column->Extra);
|
||||
|
||||
if ($change)
|
||||
{
|
||||
$alters[] = $this->getChangeColumnSQL($table, $field);
|
||||
}
|
||||
|
||||
// Unset this field so that what we have left are fields that need to be removed.
|
||||
unset($oldFields[$fName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The field is new.
|
||||
$alters[] = $this->getAddColumnSQL($table, $field);
|
||||
}
|
||||
}
|
||||
|
||||
// Any columns left are orphans
|
||||
foreach ($oldFields as $name => $column)
|
||||
{
|
||||
// Delete the column.
|
||||
$alters[] = $this->getDropColumnSQL($table, $name);
|
||||
}
|
||||
|
||||
// Get the lookups for the old and new keys.
|
||||
$oldLookup = $this->getKeyLookup($oldKeys);
|
||||
$newLookup = $this->getKeyLookup($newKeys);
|
||||
|
||||
// Loop through each key in the new structure.
|
||||
foreach ($newLookup as $name => $keys)
|
||||
{
|
||||
// Check if there are keys on this field in the existing table.
|
||||
if (isset($oldLookup[$name]))
|
||||
{
|
||||
$same = true;
|
||||
$newCount = count($newLookup[$name]);
|
||||
$oldCount = count($oldLookup[$name]);
|
||||
|
||||
// There is a key on this field in the old and new tables. Are they the same?
|
||||
if ($newCount == $oldCount)
|
||||
{
|
||||
// Need to loop through each key and do a fine grained check.
|
||||
for ($i = 0; $i < $newCount; $i++)
|
||||
{
|
||||
$same = (((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique)
|
||||
&& ((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name)
|
||||
&& ((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index)
|
||||
&& ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation)
|
||||
&& ((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type));
|
||||
|
||||
/*
|
||||
Debug.
|
||||
echo '<pre>';
|
||||
echo '<br />Non_unique: '.
|
||||
((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique ? 'Pass' : 'Fail').' '.
|
||||
(string) $newLookup[$name][$i]['Non_unique'].' vs '.$oldLookup[$name][$i]->Non_unique;
|
||||
echo '<br />Column_name: '.
|
||||
((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name ? 'Pass' : 'Fail').' '.
|
||||
(string) $newLookup[$name][$i]['Column_name'].' vs '.$oldLookup[$name][$i]->Column_name;
|
||||
echo '<br />Seq_in_index: '.
|
||||
((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index ? 'Pass' : 'Fail').' '.
|
||||
(string) $newLookup[$name][$i]['Seq_in_index'].' vs '.$oldLookup[$name][$i]->Seq_in_index;
|
||||
echo '<br />Collation: '.
|
||||
((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '.
|
||||
(string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation;
|
||||
echo '<br />Index_type: '.
|
||||
((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type ? 'Pass' : 'Fail').' '.
|
||||
(string) $newLookup[$name][$i]['Index_type'].' vs '.$oldLookup[$name][$i]->Index_type;
|
||||
echo '<br />Same = '.($same ? 'true' : 'false');
|
||||
echo '</pre>';
|
||||
*/
|
||||
|
||||
if (!$same)
|
||||
{
|
||||
// Break out of the loop. No need to check further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count is different, just drop and add.
|
||||
$same = false;
|
||||
}
|
||||
|
||||
if (!$same)
|
||||
{
|
||||
$alters[] = $this->getDropKeySQL($table, $name);
|
||||
$alters[] = $this->getAddKeySQL($table, $keys);
|
||||
}
|
||||
|
||||
// Unset this field so that what we have left are fields that need to be removed.
|
||||
unset($oldLookup[$name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a new key.
|
||||
$alters[] = $this->getAddKeySQL($table, $keys);
|
||||
}
|
||||
}
|
||||
|
||||
// Any keys left are orphans.
|
||||
foreach ($oldLookup as $name => $keys)
|
||||
{
|
||||
if (strtoupper($name) == 'PRIMARY')
|
||||
{
|
||||
$alters[] = $this->getDropPrimaryKeySQL($table);
|
||||
}
|
||||
else
|
||||
{
|
||||
$alters[] = $this->getDropKeySQL($table, $name);
|
||||
}
|
||||
}
|
||||
|
||||
return $alters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the syntax to alter a column.
|
||||
*
|
||||
* @param string $table The name of the database table to alter.
|
||||
* @param SimpleXMLElement $field The XML definition for the field.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getChangeColumnSQL($table, SimpleXMLElement $field)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
|
||||
. $this->getColumnSQL($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for a single column that would be included in a table create or alter statement.
|
||||
*
|
||||
* @param SimpleXMLElement $field The XML field definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getColumnSQL(SimpleXMLElement $field)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$blobs = array('text', 'smalltext', 'mediumtext', 'largetext');
|
||||
|
||||
$fName = (string) $field['Field'];
|
||||
$fType = (string) $field['Type'];
|
||||
$fNull = (string) $field['Null'];
|
||||
$fDefault = isset($field['Default']) ? (string) $field['Default'] : null;
|
||||
$fExtra = (string) $field['Extra'];
|
||||
|
||||
$query = $this->db->quoteName($fName) . ' ' . $fType;
|
||||
|
||||
if ($fNull == 'NO')
|
||||
{
|
||||
if (in_array($fType, $blobs) || $fDefault === null)
|
||||
{
|
||||
$query .= ' NOT NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO Don't quote numeric values.
|
||||
$query .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($fDefault === null)
|
||||
{
|
||||
$query .= ' DEFAULT NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO Don't quote numeric values.
|
||||
$query .= ' DEFAULT ' . $this->db->quote($fDefault);
|
||||
}
|
||||
}
|
||||
|
||||
if ($fExtra)
|
||||
{
|
||||
$query .= ' ' . strtoupper($fExtra);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a column.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param string $name The name of the field to drop.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getDropColumnSQL($table, $name)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a key.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param string $name The name of the key to drop.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getDropKeySQL($table, $name)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a key.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getDropPrimaryKeySQL($table)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of keys for a table.
|
||||
*
|
||||
* @param array $keys An array of objects that comprise the keys for the table.
|
||||
*
|
||||
* @return array The lookup array. array({key name} => array(object, ...))
|
||||
*
|
||||
* @since 11.1
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getKeyLookup($keys)
|
||||
{
|
||||
// First pass, create a lookup of the keys.
|
||||
$lookup = array();
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if ($key instanceof SimpleXMLElement)
|
||||
{
|
||||
$kName = (string) $key['Key_name'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$kName = $key->Key_name;
|
||||
}
|
||||
|
||||
if (empty($lookup[$kName]))
|
||||
{
|
||||
$lookup[$kName] = array();
|
||||
}
|
||||
|
||||
$lookup[$kName][] = $key;
|
||||
}
|
||||
|
||||
return $lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for a key.
|
||||
*
|
||||
* @param array $columns An array of SimpleXMLElement objects comprising the key.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getKeySQL($columns)
|
||||
{
|
||||
// TODO Error checking on array and element types.
|
||||
|
||||
$kNonUnique = (string) $columns[0]['Non_unique'];
|
||||
$kName = (string) $columns[0]['Key_name'];
|
||||
$kColumn = (string) $columns[0]['Column_name'];
|
||||
|
||||
$prefix = '';
|
||||
|
||||
if ($kName == 'PRIMARY')
|
||||
{
|
||||
$prefix = 'PRIMARY ';
|
||||
}
|
||||
elseif ($kNonUnique == 0)
|
||||
{
|
||||
$prefix = 'UNIQUE ';
|
||||
}
|
||||
|
||||
$nColumns = count($columns);
|
||||
$kColumns = array();
|
||||
|
||||
if ($nColumns == 1)
|
||||
{
|
||||
$kColumns[] = $this->db->quoteName($kColumn);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($columns as $column)
|
||||
{
|
||||
$kColumns[] = (string) $column['Column_name'];
|
||||
}
|
||||
}
|
||||
|
||||
$query = $prefix . 'KEY ' . ($kName != 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')';
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real name of the table, converting the prefix wildcard string if present.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return string The real name of the table.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
protected function getRealTableName($table)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
// Replace the magic prefix if found.
|
||||
$table = preg_replace('|^#__|', $prefix, $table);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the incoming structure definition with the existing structure.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @note Currently only supports XML format.
|
||||
* @since 11.1
|
||||
* @throws Exception on error.
|
||||
* @todo If it's not XML convert to XML first.
|
||||
*/
|
||||
protected function mergeStructure()
|
||||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
$tables = $this->db->getTableList();
|
||||
|
||||
if ($this->from instanceof SimpleXMLElement)
|
||||
{
|
||||
$xml = $this->from;
|
||||
}
|
||||
else
|
||||
{
|
||||
$xml = new SimpleXMLElement($this->from);
|
||||
}
|
||||
|
||||
// Get all the table definitions.
|
||||
$xmlTables = $xml->xpath('database/table_structure');
|
||||
|
||||
foreach ($xmlTables as $table)
|
||||
{
|
||||
// Convert the magic prefix into the real table name.
|
||||
$tableName = (string) $table['name'];
|
||||
$tableName = preg_replace('|^#__|', $prefix, $tableName);
|
||||
|
||||
if (in_array($tableName, $tables))
|
||||
{
|
||||
// The table already exists. Now check if there is any difference.
|
||||
if ($queries = $this->getAlterTableSQL($xml->database->table_structure))
|
||||
{
|
||||
// Run the queries to upgrade the data structure.
|
||||
foreach ($queries as $query)
|
||||
{
|
||||
$this->db->setQuery($query);
|
||||
|
||||
try
|
||||
{
|
||||
$this->db->execute();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
$this->addLog('Fail: ' . $this->db->getQuery());
|
||||
throw $e;
|
||||
}
|
||||
$this->addLog('Pass: ' . $this->db->getQuery());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a new table.
|
||||
$query = $this->xmlToCreate($table);
|
||||
|
||||
$this->db->setQuery($query);
|
||||
|
||||
try
|
||||
{
|
||||
$this->db->execute();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
$this->addLog('Fail: ' . $this->db->getQuery());
|
||||
throw $e;
|
||||
}
|
||||
$this->addLog('Pass: ' . $this->db->getQuery());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from MySQL.
|
||||
*
|
||||
* @param JDatabaseDriverMysqli $db The database connector.
|
||||
*
|
||||
* @return JDatabaseImporterMysqli Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverMysqli $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an internal option to merge the structure based on the input data.
|
||||
*
|
||||
* @param boolean $setting True to export the structure, false to not.
|
||||
*
|
||||
* @return JDatabaseImporterMysql Method supports chaining.
|
||||
*
|
||||
* @since 11.1
|
||||
*/
|
||||
public function withStructure($setting = true)
|
||||
{
|
||||
$this->options->withStructure = (boolean) $setting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
780
libraries/joomla/database/importer/postgresql.php
Normal file
780
libraries/joomla/database/importer/postgresql.php
Normal file
@ -0,0 +1,780 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* PostgreSQL import driver.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseImporterPostgresql extends JDatabaseImporter
|
||||
{
|
||||
/**
|
||||
* @var array An array of cached data.
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* The database connector to use for exporting structure and/or data.
|
||||
*
|
||||
* @var JDatabaseDriverPostgresql
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $db = null;
|
||||
|
||||
/**
|
||||
* The input source.
|
||||
*
|
||||
* @var mixed
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $from = array();
|
||||
|
||||
/**
|
||||
* The type of input format (XML).
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $asFormat = 'xml';
|
||||
|
||||
/**
|
||||
* An array of options for the exporter.
|
||||
*
|
||||
* @var object
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $options = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets up the default options for the exporter.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->options = new stdClass;
|
||||
|
||||
$this->cache = array('columns' => array(), 'keys' => array());
|
||||
|
||||
// Set up the class defaults:
|
||||
|
||||
// Import with only structure
|
||||
$this->withStructure();
|
||||
|
||||
// Export as XML.
|
||||
$this->asXml();
|
||||
|
||||
// Default destination is a string using $output = (string) $exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output option for the exporter to XML format.
|
||||
*
|
||||
* @return JDatabaseImporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function asXml()
|
||||
{
|
||||
$this->asFormat = 'xml';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all data and options are in order prior to exporting.
|
||||
*
|
||||
* @return JDatabaseImporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception if an error is encountered.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Check if the db connector has been set.
|
||||
if (!($this->db instanceof JDatabaseDriverPostgresql))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
|
||||
}
|
||||
|
||||
// Check if the tables have been specified.
|
||||
if (empty($this->from))
|
||||
{
|
||||
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the data source to import.
|
||||
*
|
||||
* @param mixed $from The data source to import.
|
||||
*
|
||||
* @return JDatabaseImporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function from($from)
|
||||
{
|
||||
$this->from = $from;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to add a column.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param SimpleXMLElement $field The XML field definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getAddColumnSQL($table, SimpleXMLElement $field)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to add an index.
|
||||
*
|
||||
* @param SimpleXMLElement $field The XML index definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getAddIndexSQL(SimpleXMLElement $field)
|
||||
{
|
||||
return (string) $field['Query'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alters for table if there is a difference.
|
||||
*
|
||||
* @param SimpleXMLElement $structure The XML structure of the table.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getAlterTableSQL(SimpleXMLElement $structure)
|
||||
{
|
||||
$table = $this->getRealTableName($structure['name']);
|
||||
$oldFields = $this->db->getTableColumns($table);
|
||||
$oldKeys = $this->db->getTableKeys($table);
|
||||
$oldSequence = $this->db->getTableSequences($table);
|
||||
$alters = array();
|
||||
|
||||
// Get the fields and keys from the XML that we are aiming for.
|
||||
$newFields = $structure->xpath('field');
|
||||
$newKeys = $structure->xpath('key');
|
||||
$newSequence = $structure->xpath('sequence');
|
||||
|
||||
/* Sequence section */
|
||||
$oldSeq = $this->getSeqLookup($oldSequence);
|
||||
$newSequenceLook = $this->getSeqLookup($newSequence);
|
||||
|
||||
foreach ($newSequenceLook as $kSeqName => $vSeq)
|
||||
{
|
||||
if (isset($oldSeq[$kSeqName]))
|
||||
{
|
||||
// The field exists, check it's the same.
|
||||
$column = $oldSeq[$kSeqName][0];
|
||||
|
||||
/* For older database version that doesn't support these fields use default values */
|
||||
if (version_compare($this->db->getVersion(), '9.1.0') < 0)
|
||||
{
|
||||
$column->Min_Value = '1';
|
||||
$column->Max_Value = '9223372036854775807';
|
||||
$column->Increment = '1';
|
||||
$column->Cycle_option = 'NO';
|
||||
$column->Start_Value = '1';
|
||||
}
|
||||
|
||||
// Test whether there is a change.
|
||||
$change = ((string) $vSeq[0]['Type'] != $column->Type) || ((string) $vSeq[0]['Start_Value'] != $column->Start_Value)
|
||||
|| ((string) $vSeq[0]['Min_Value'] != $column->Min_Value) || ((string) $vSeq[0]['Max_Value'] != $column->Max_Value)
|
||||
|| ((string) $vSeq[0]['Increment'] != $column->Increment) || ((string) $vSeq[0]['Cycle_option'] != $column->Cycle_option)
|
||||
|| ((string) $vSeq[0]['Table'] != $column->Table) || ((string) $vSeq[0]['Column'] != $column->Column)
|
||||
|| ((string) $vSeq[0]['Schema'] != $column->Schema) || ((string) $vSeq[0]['Name'] != $column->Name);
|
||||
|
||||
if ($change)
|
||||
{
|
||||
$alters[] = $this->getChangeSequenceSQL($kSeqName, $vSeq);
|
||||
}
|
||||
|
||||
// Unset this field so that what we have left are fields that need to be removed.
|
||||
unset($oldSeq[$kSeqName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The sequence is new
|
||||
$alters[] = $this->getAddSequenceSQL($newSequenceLook[$kSeqName][0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Any sequences left are orphans
|
||||
foreach ($oldSeq as $name => $column)
|
||||
{
|
||||
// Delete the sequence.
|
||||
$alters[] = $this->getDropSequenceSQL($name);
|
||||
}
|
||||
|
||||
/* Field section */
|
||||
// Loop through each field in the new structure.
|
||||
foreach ($newFields as $field)
|
||||
{
|
||||
$fName = (string) $field['Field'];
|
||||
|
||||
if (isset($oldFields[$fName]))
|
||||
{
|
||||
// The field exists, check it's the same.
|
||||
$column = $oldFields[$fName];
|
||||
|
||||
// Test whether there is a change.
|
||||
$change = ((string) $field['Type'] != $column->Type) || ((string) $field['Null'] != $column->Null)
|
||||
|| ((string) $field['Default'] != $column->Default);
|
||||
|
||||
if ($change)
|
||||
{
|
||||
$alters[] = $this->getChangeColumnSQL($table, $field);
|
||||
}
|
||||
|
||||
// Unset this field so that what we have left are fields that need to be removed.
|
||||
unset($oldFields[$fName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The field is new.
|
||||
$alters[] = $this->getAddColumnSQL($table, $field);
|
||||
}
|
||||
}
|
||||
|
||||
// Any columns left are orphans
|
||||
foreach ($oldFields as $name => $column)
|
||||
{
|
||||
// Delete the column.
|
||||
$alters[] = $this->getDropColumnSQL($table, $name);
|
||||
}
|
||||
|
||||
/* Index section */
|
||||
// Get the lookups for the old and new keys
|
||||
$oldLookup = $this->getIdxLookup($oldKeys);
|
||||
$newLookup = $this->getIdxLookup($newKeys);
|
||||
|
||||
// Loop through each key in the new structure.
|
||||
foreach ($newLookup as $name => $keys)
|
||||
{
|
||||
// Check if there are keys on this field in the existing table.
|
||||
if (isset($oldLookup[$name]))
|
||||
{
|
||||
$same = true;
|
||||
$newCount = count($newLookup[$name]);
|
||||
$oldCount = count($oldLookup[$name]);
|
||||
|
||||
// There is a key on this field in the old and new tables. Are they the same?
|
||||
if ($newCount == $oldCount)
|
||||
{
|
||||
for ($i = 0; $i < $newCount; $i++)
|
||||
{
|
||||
// Check only query field -> different query means different index
|
||||
$same = ((string) $newLookup[$name][$i]['Query'] == $oldLookup[$name][$i]->Query);
|
||||
|
||||
if (!$same)
|
||||
{
|
||||
// Break out of the loop. No need to check further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count is different, just drop and add.
|
||||
$same = false;
|
||||
}
|
||||
|
||||
if (!$same)
|
||||
{
|
||||
$alters[] = $this->getDropIndexSQL($name);
|
||||
$alters[] = (string) $newLookup[$name][0]['Query'];
|
||||
}
|
||||
|
||||
// Unset this field so that what we have left are fields that need to be removed.
|
||||
unset($oldLookup[$name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a new key.
|
||||
$alters[] = (string) $newLookup[$name][0]['Query'];
|
||||
}
|
||||
}
|
||||
|
||||
// Any keys left are orphans.
|
||||
foreach ($oldLookup as $name => $keys)
|
||||
{
|
||||
if ($oldLookup[$name][0]->is_primary == 'TRUE')
|
||||
{
|
||||
$alters[] = $this->getDropPrimaryKeySQL($table, $oldLookup[$name][0]->Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
$alters[] = $this->getDropIndexSQL($name);
|
||||
}
|
||||
}
|
||||
|
||||
return $alters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a sequence.
|
||||
*
|
||||
* @param string $name The name of the sequence to drop.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getDropSequenceSQL($name)
|
||||
{
|
||||
return 'DROP SEQUENCE ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the syntax to add a sequence.
|
||||
*
|
||||
* @param SimpleXMLElement $field The XML definition for the sequence.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getAddSequenceSQL($field)
|
||||
{
|
||||
/* For older database version that doesn't support these fields use default values */
|
||||
if (version_compare($this->db->getVersion(), '9.1.0') < 0)
|
||||
{
|
||||
$field['Min_Value'] = '1';
|
||||
$field['Max_Value'] = '9223372036854775807';
|
||||
$field['Increment'] = '1';
|
||||
$field['Cycle_option'] = 'NO';
|
||||
$field['Start_Value'] = '1';
|
||||
}
|
||||
|
||||
return 'CREATE SEQUENCE ' . (string) $field['Name'] .
|
||||
' INCREMENT BY ' . (string) $field['Increment'] . ' MINVALUE ' . $field['Min_Value'] .
|
||||
' MAXVALUE ' . (string) $field['Max_Value'] . ' START ' . (string) $field['Start_Value'] .
|
||||
(((string) $field['Cycle_option'] == 'NO') ? ' NO' : '') . ' CYCLE' .
|
||||
' OWNED BY ' . $this->db->quoteName((string) $field['Schema'] . '.' . (string) $field['Table'] . '.' . (string) $field['Column']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the syntax to alter a sequence.
|
||||
*
|
||||
* @param SimpleXMLElement $field The XML definition for the sequence.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getChangeSequenceSQL($field)
|
||||
{
|
||||
/* For older database version that doesn't support these fields use default values */
|
||||
if (version_compare($this->db->getVersion(), '9.1.0') < 0)
|
||||
{
|
||||
$field['Min_Value'] = '1';
|
||||
$field['Max_Value'] = '9223372036854775807';
|
||||
$field['Increment'] = '1';
|
||||
$field['Cycle_option'] = 'NO';
|
||||
$field['Start_Value'] = '1';
|
||||
}
|
||||
|
||||
return 'ALTER SEQUENCE ' . (string) $field['Name'] .
|
||||
' INCREMENT BY ' . (string) $field['Increment'] . ' MINVALUE ' . (string) $field['Min_Value'] .
|
||||
' MAXVALUE ' . (string) $field['Max_Value'] . ' START ' . (string) $field['Start_Value'] .
|
||||
' OWNED BY ' . $this->db->quoteName((string) $field['Schema'] . '.' . (string) $field['Table'] . '.' . (string) $field['Column']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the syntax to alter a column.
|
||||
*
|
||||
* @param string $table The name of the database table to alter.
|
||||
* @param SimpleXMLElement $field The XML definition for the field.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getChangeColumnSQL($table, SimpleXMLElement $field)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ALTER COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
|
||||
. $this->getAlterColumnSQL($table, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for a single column that would be included in a table create statement.
|
||||
*
|
||||
* @param string $table The name of the database table to alter.
|
||||
* @param SimpleXMLElement $field The XML field definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getAlterColumnSQL($table, $field)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$blobs = array('text', 'smalltext', 'mediumtext', 'largetext');
|
||||
|
||||
$fName = (string) $field['Field'];
|
||||
$fType = (string) $field['Type'];
|
||||
$fNull = (string) $field['Null'];
|
||||
$fDefault = (isset($field['Default']) && $field['Default'] != 'NULL' ) ?
|
||||
preg_match('/^[0-9]$/', $field['Default']) ? $field['Default'] : $this->db->quote((string) $field['Default'])
|
||||
: null;
|
||||
|
||||
$query = ' TYPE ' . $fType;
|
||||
|
||||
if ($fNull == 'NO')
|
||||
{
|
||||
if (in_array($fType, $blobs) || $fDefault === null)
|
||||
{
|
||||
$query .= ",\nALTER COLUMN " . $this->db->quoteName($fName) . ' SET NOT NULL' .
|
||||
",\nALTER COLUMN " . $this->db->quoteName($fName) . ' DROP DEFAULT';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query .= ",\nALTER COLUMN " . $this->db->quoteName($fName) . ' SET NOT NULL' .
|
||||
",\nALTER COLUMN " . $this->db->quoteName($fName) . ' SET DEFAULT ' . $fDefault;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($fDefault !== null)
|
||||
{
|
||||
$query .= ",\nALTER COLUMN " . $this->db->quoteName($fName) . ' DROP NOT NULL' .
|
||||
",\nALTER COLUMN " . $this->db->quoteName($fName) . ' SET DEFAULT ' . $fDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/* sequence was created in other function, here is associated a default value but not yet owner */
|
||||
if (strpos($fDefault, 'nextval') !== false)
|
||||
{
|
||||
$query .= ";\nALTER SEQUENCE " . $this->db->quoteName($table . '_' . $fName . '_seq') . ' OWNED BY ' . $this->db->quoteName($table . '.' . $fName);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for a single column that would be included in a table create statement.
|
||||
*
|
||||
* @param SimpleXMLElement $field The XML field definition.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getColumnSQL(SimpleXMLElement $field)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$blobs = array('text', 'smalltext', 'mediumtext', 'largetext');
|
||||
|
||||
$fName = (string) $field['Field'];
|
||||
$fType = (string) $field['Type'];
|
||||
$fNull = (string) $field['Null'];
|
||||
$fDefault = (isset($field['Default']) && $field['Default'] != 'NULL' ) ?
|
||||
preg_match('/^[0-9]$/', $field['Default']) ? $field['Default'] : $this->db->quote((string) $field['Default'])
|
||||
: null;
|
||||
|
||||
/* nextval() as default value means that type field is serial */
|
||||
if (strpos($fDefault, 'nextval') !== false)
|
||||
{
|
||||
$query = $this->db->quoteName($fName) . ' SERIAL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = $this->db->quoteName($fName) . ' ' . $fType;
|
||||
|
||||
if ($fNull == 'NO')
|
||||
{
|
||||
if (in_array($fType, $blobs) || $fDefault === null)
|
||||
{
|
||||
$query .= ' NOT NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query .= ' NOT NULL DEFAULT ' . $fDefault;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($fDefault !== null)
|
||||
{
|
||||
$query .= ' DEFAULT ' . $fDefault;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a column.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param string $name The name of the field to drop.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getDropColumnSQL($table, $name)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop an index.
|
||||
*
|
||||
* @param string $name The name of the key to drop.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getDropIndexSQL($name)
|
||||
{
|
||||
return 'DROP INDEX ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax to drop a key.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @param string $name The constraint name.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getDropPrimaryKeySQL($table, $name)
|
||||
{
|
||||
return 'ALTER TABLE ONLY ' . $this->db->quoteName($table) . ' DROP CONSTRAINT ' . $this->db->quoteName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of keys for a table.
|
||||
*
|
||||
* @param array $keys An array of objects that comprise the keys for the table.
|
||||
*
|
||||
* @return array The lookup array. array({key name} => array(object, ...))
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getIdxLookup($keys)
|
||||
{
|
||||
// First pass, create a lookup of the keys.
|
||||
$lookup = array();
|
||||
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
if ($key instanceof SimpleXMLElement)
|
||||
{
|
||||
$kName = (string) $key['Index'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$kName = $key->Index;
|
||||
}
|
||||
if (empty($lookup[$kName]))
|
||||
{
|
||||
$lookup[$kName] = array();
|
||||
}
|
||||
$lookup[$kName][] = $key;
|
||||
}
|
||||
|
||||
return $lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details list of sequences for a table.
|
||||
*
|
||||
* @param array $sequences An array of objects that comprise the sequences for the table.
|
||||
*
|
||||
* @return array The lookup array. array({key name} => array(object, ...))
|
||||
*
|
||||
* @since 12.1
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getSeqLookup($sequences)
|
||||
{
|
||||
// First pass, create a lookup of the keys.
|
||||
$lookup = array();
|
||||
|
||||
foreach ($sequences as $seq)
|
||||
{
|
||||
if ($seq instanceof SimpleXMLElement)
|
||||
{
|
||||
$sName = (string) $seq['Name'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sName = $seq->Name;
|
||||
}
|
||||
if (empty($lookup[$sName]))
|
||||
{
|
||||
$lookup[$sName] = array();
|
||||
}
|
||||
$lookup[$sName][] = $seq;
|
||||
}
|
||||
|
||||
return $lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real name of the table, converting the prefix wildcard string if present.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
*
|
||||
* @return string The real name of the table.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function getRealTableName($table)
|
||||
{
|
||||
// TODO Incorporate into parent class and use $this.
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
// Replace the magic prefix if found.
|
||||
$table = preg_replace('|^#__|', $prefix, $table);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the incoming structure definition with the existing structure.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @note Currently only supports XML format.
|
||||
* @since 12.1
|
||||
* @throws Exception on error.
|
||||
* @todo If it's not XML convert to XML first.
|
||||
*/
|
||||
protected function mergeStructure()
|
||||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
$tables = $this->db->getTableList();
|
||||
|
||||
if ($this->from instanceof SimpleXMLElement)
|
||||
{
|
||||
$xml = $this->from;
|
||||
}
|
||||
else
|
||||
{
|
||||
$xml = new SimpleXMLElement($this->from);
|
||||
}
|
||||
|
||||
// Get all the table definitions.
|
||||
$xmlTables = $xml->xpath('database/table_structure');
|
||||
|
||||
foreach ($xmlTables as $table)
|
||||
{
|
||||
// Convert the magic prefix into the real table name.
|
||||
$tableName = (string) $table['name'];
|
||||
$tableName = preg_replace('|^#__|', $prefix, $tableName);
|
||||
|
||||
if (in_array($tableName, $tables))
|
||||
{
|
||||
// The table already exists. Now check if there is any difference.
|
||||
if ($queries = $this->getAlterTableSQL($xml->database->table_structure))
|
||||
{
|
||||
// Run the queries to upgrade the data structure.
|
||||
foreach ($queries as $query)
|
||||
{
|
||||
$this->db->setQuery($query);
|
||||
|
||||
try
|
||||
{
|
||||
$this->db->execute();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
$this->addLog('Fail: ' . $this->db->getQuery());
|
||||
throw $e;
|
||||
}
|
||||
$this->addLog('Pass: ' . $this->db->getQuery());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a new table.
|
||||
$query = $this->xmlToCreate($table);
|
||||
|
||||
$this->db->setQuery($query);
|
||||
|
||||
try
|
||||
{
|
||||
$this->db->execute();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
$this->addLog('Fail: ' . $this->db->getQuery());
|
||||
throw $e;
|
||||
}
|
||||
$this->addLog('Pass: ' . $this->db->getQuery());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database connector to use for exporting structure and/or data from PostgreSQL.
|
||||
*
|
||||
* @param JDatabaseDriverPostgresql $db The database connector.
|
||||
*
|
||||
* @return JDatabaseImporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function setDbo(JDatabaseDriverPostgresql $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an internal option to merge the structure based on the input data.
|
||||
*
|
||||
* @param boolean $setting True to export the structure, false to not.
|
||||
*
|
||||
* @return JDatabaseImporterPostgresql Method supports chaining.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function withStructure($setting = true)
|
||||
{
|
||||
$this->options->withStructure = (boolean) $setting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
1
libraries/joomla/database/index.html
Normal file
1
libraries/joomla/database/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
205
libraries/joomla/database/iterator.php
Normal file
205
libraries/joomla/database/iterator.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Joomla Platform Database Driver Class
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract class JDatabaseIterator implements Countable, Iterator
|
||||
{
|
||||
/**
|
||||
* The database cursor.
|
||||
*
|
||||
* @var mixed
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $cursor;
|
||||
|
||||
/**
|
||||
* The class of object to create.
|
||||
*
|
||||
* @var string
|
||||
* @since 12.1
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* The name of the column to use for the key of the database record.
|
||||
*
|
||||
* @var mixed
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_column;
|
||||
|
||||
/**
|
||||
* The current database record.
|
||||
*
|
||||
* @var mixed
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_current;
|
||||
|
||||
/**
|
||||
* A numeric or string key for the current database record.
|
||||
*
|
||||
* @var scalar
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_key;
|
||||
|
||||
/**
|
||||
* The number of fetched records.
|
||||
*
|
||||
* @var integer
|
||||
* @since 12.1
|
||||
*/
|
||||
private $_fetched = 0;
|
||||
|
||||
/**
|
||||
* Database iterator constructor.
|
||||
*
|
||||
* @param mixed $cursor The database cursor.
|
||||
* @param string $column An option column to use as the iterator key.
|
||||
* @param string $class The class of object that is returned.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($cursor, $column = null, $class = 'stdClass')
|
||||
{
|
||||
if (!class_exists($class))
|
||||
{
|
||||
throw new InvalidArgumentException(sprintf('new %s(*%s*, cursor)', get_class($this), gettype($class)));
|
||||
}
|
||||
|
||||
$this->cursor = $cursor;
|
||||
$this->class = $class;
|
||||
$this->_column = $column;
|
||||
$this->_fetched = 0;
|
||||
$this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Database iterator destructor.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->cursor)
|
||||
{
|
||||
$this->freeResult($this->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The current element in the iterator.
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @see Iterator::current()
|
||||
* @since 12.1
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key of the current element in the iterator.
|
||||
*
|
||||
* @return scalar
|
||||
*
|
||||
* @see Iterator::key()
|
||||
* @since 12.1
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves forward to the next result from the SQL query.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see Iterator::next()
|
||||
* @since 12.1
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
// Set the default key as being the number of fetched object
|
||||
$this->_key = $this->_fetched;
|
||||
|
||||
// Try to get an object
|
||||
$this->_current = $this->fetchObject();
|
||||
|
||||
// If an object has been found
|
||||
if ($this->_current)
|
||||
{
|
||||
// Set the key as being the indexed column (if it exists)
|
||||
if (isset($this->_current->{$this->_column}))
|
||||
{
|
||||
$this->_key = $this->_current->{$this->_column};
|
||||
}
|
||||
|
||||
// Update the number of fetched object
|
||||
$this->_fetched++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the iterator.
|
||||
*
|
||||
* This iterator cannot be rewound.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see Iterator::rewind()
|
||||
* @since 12.1
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current position of the iterator is valid.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see Iterator::valid()
|
||||
* @since 12.1
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return (boolean) $this->_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract protected function fetchObject();
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
abstract protected function freeResult();
|
||||
}
|
||||
21
libraries/joomla/database/iterator/azure.php
Normal file
21
libraries/joomla/database/iterator/azure.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* SQL azure database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorAzure extends JDatabaseIteratorSqlsrv
|
||||
{
|
||||
}
|
||||
1
libraries/joomla/database/iterator/index.html
Normal file
1
libraries/joomla/database/iterator/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
58
libraries/joomla/database/iterator/mysql.php
Normal file
58
libraries/joomla/database/iterator/mysql.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQL database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @see http://dev.mysql.com/doc/
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorMysql extends JDatabaseIterator
|
||||
{
|
||||
/**
|
||||
* Get the number of rows in the result set for the executed SQL given by the cursor.
|
||||
*
|
||||
* @return integer The number of rows in the result set.
|
||||
*
|
||||
* @since 12.1
|
||||
* @see Countable::count()
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return mysql_num_rows($this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchObject()
|
||||
{
|
||||
return mysql_fetch_object($this->cursor, $this->class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function freeResult()
|
||||
{
|
||||
mysql_free_result($this->cursor);
|
||||
}
|
||||
}
|
||||
57
libraries/joomla/database/iterator/mysqli.php
Normal file
57
libraries/joomla/database/iterator/mysqli.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* MySQLi database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorMysqli extends JDatabaseIterator
|
||||
{
|
||||
/**
|
||||
* Get the number of rows in the result set for the executed SQL given by the cursor.
|
||||
*
|
||||
* @return integer The number of rows in the result set.
|
||||
*
|
||||
* @since 12.1
|
||||
* @see Countable::count()
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return mysqli_num_rows($this->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchObject()
|
||||
{
|
||||
return mysqli_fetch_object($this->cursor, $this->class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function freeResult()
|
||||
{
|
||||
mysqli_free_result($this->cursor);
|
||||
}
|
||||
}
|
||||
21
libraries/joomla/database/iterator/oracle.php
Normal file
21
libraries/joomla/database/iterator/oracle.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* Oracle database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorOracle extends JDatabaseIteratorPdo
|
||||
{
|
||||
}
|
||||
74
libraries/joomla/database/iterator/pdo.php
Normal file
74
libraries/joomla/database/iterator/pdo.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* PDO database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorPdo extends JDatabaseIterator
|
||||
{
|
||||
/**
|
||||
* Get the number of rows in the result set for the executed SQL given by the cursor.
|
||||
*
|
||||
* @return integer The number of rows in the result set.
|
||||
*
|
||||
* @since 12.1
|
||||
* @see Countable::count()
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
|
||||
{
|
||||
return $this->cursor->rowCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch a row from the result set cursor as an object.
|
||||
*
|
||||
* @return mixed Either the next row from the result set or false if there are no more rows.
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function fetchObject()
|
||||
{
|
||||
if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
|
||||
{
|
||||
return $this->cursor->fetchObject($this->class);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to free up the memory used for the result set.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 12.1
|
||||
*/
|
||||
protected function freeResult()
|
||||
{
|
||||
if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
|
||||
{
|
||||
$this->cursor->closeCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
libraries/joomla/database/iterator/sqlite.php
Normal file
21
libraries/joomla/database/iterator/sqlite.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
/**
|
||||
* SQLite database iterator.
|
||||
*
|
||||
* @package Joomla.Platform
|
||||
* @subpackage Database
|
||||
* @since 12.1
|
||||
*/
|
||||
class JDatabaseIteratorSqlite extends JDatabaseIteratorPdo
|
||||
{
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user