AAAAPK /?\h)џ џ table.phpnu W+A _tbl = $table;
$this->_tbl_key = $key;
$this->_db = &$db;
// Initialise the table properties.
if ($fields = $this->getFields())
{
foreach ($fields as $name => $v)
{
// Add the field if it is not already present.
if (!property_exists($this, $name))
{
$this->$name = null;
}
}
}
// If we are tracking assets, make sure an access field exists and initially set the default.
if (property_exists($this, 'asset_id'))
{
$this->_trackAssets = true;
}
// If the access property exists, set the default.
if (property_exists($this, 'access'))
{
$this->access = (int) JFactory::getConfig()->get('access');
}
}
/**
* Get the columns from database table.
*
* @return mixed An array of the field names, or false if an error occurs.
*
* @since 11.1
*/
public function getFields()
{
static $cache = null;
if ($cache === null)
{
// Lookup the fields for this table only once.
$name = $this->_tbl;
$fields = $this->_db->getTableColumns($name, false);
if (empty($fields))
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_COLUMNS_NOT_FOUND'));
$this->setError($e);
return false;
}
$cache = $fields;
}
return $cache;
}
/**
* Static method to get an instance of a JTable class if it can be found in
* the table include paths. To add include paths for searching for JTable
* classes @see JTable::addIncludePath().
*
* @param string $type The type (name) of the JTable class to get an instance of.
* @param string $prefix An optional prefix for the table class name.
* @param array $config An optional array of configuration values for the JTable object.
*
* @return mixed A JTable object if found or boolean false if one could not be found.
*
* @link http://docs.joomla.org/JTable/getInstance
* @since 11.1
*/
public static function getInstance($type, $prefix = 'JTable', $config = array())
{
// Sanitize and prepare the table class name.
$type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type);
$tableClass = $prefix . ucfirst($type);
// Only try to load the class if it doesn't already exist.
if (!class_exists($tableClass))
{
// Search for the class file in the JTable include paths.
jimport('joomla.filesystem.path');
$paths = JTable::addIncludePath();
$pathIndex = 0;
while (!class_exists($tableClass) && $pathIndex < count($paths))
{
if ($tryThis = JPath::find($paths[$pathIndex++], strtolower($type) . '.php'))
{
// Import the class file.
include_once $tryThis;
}
}
if (!class_exists($tableClass))
{
// If we were unable to find the class file in the JTable include paths, raise a warning and return false.
JError::raiseWarning(0, JText::sprintf('JLIB_DATABASE_ERROR_NOT_SUPPORTED_FILE_NOT_FOUND', $type));
return false;
}
}
// If a database object was passed in the configuration array use it, otherwise get the global one from JFactory.
$db = isset($config['dbo']) ? $config['dbo'] : JFactory::getDbo();
// Instantiate a new table class and return it.
return new $tableClass($db);
}
/**
* Add a filesystem path where JTable should search for table class files.
* You may either pass a string or an array of paths.
*
* @param mixed $path A filesystem path or array of filesystem paths to add.
*
* @return array An array of filesystem paths to find JTable classes in.
*
* @link http://docs.joomla.org/JTable/addIncludePath
* @since 11.1
*/
public static function addIncludePath($path = null)
{
// Declare the internal paths as a static variable.
static $_paths;
// If the internal paths have not been initialised, do so with the base table path.
if (!isset($_paths))
{
$_paths = array(dirname(__FILE__) . '/table');
}
// Convert the passed path(s) to add to an array.
settype($path, 'array');
// If we have new paths to add, do so.
if (!empty($path) && !in_array($path, $_paths))
{
// Check and add each individual new path.
foreach ($path as $dir)
{
// Sanitize path.
$dir = trim($dir);
// Add to the front of the list so that custom paths are searched first.
array_unshift($_paths, $dir);
}
}
return $_paths;
}
/**
* Method to compute the default name of the asset.
* The default name is in the form table_name.id
* where id is the value of the primary key of the table.
*
* @return string
*
* @since 11.1
*/
protected function _getAssetName()
{
$k = $this->_tbl_key;
return $this->_tbl . '.' . (int) $this->$k;
}
/**
* Method to return the title to use for the asset table. In
* tracking the assets a title is kept for each asset so that there is some
* context available in a unified access manager. Usually this would just
* return $this->title or $this->name or whatever is being used for the
* primary name of the row. If this method is not overridden, the asset name is used.
*
* @return string The string to use as the title in the asset table.
*
* @link http://docs.joomla.org/JTable/getAssetTitle
* @since 11.1
*/
protected function _getAssetTitle()
{
return $this->_getAssetName();
}
/**
* Method to get the parent asset under which to register this one.
* By default, all assets are registered to the ROOT node with ID,
* which will default to 1 if none exists.
* The extended class can define a table and id to lookup. If the
* asset does not exist it will be created.
*
* @param JTable $table A JTable object for the asset parent.
* @param integer $id Id to look up
*
* @return integer
*
* @since 11.1
*/
protected function _getAssetParentId($table = null, $id = null)
{
// For simple cases, parent to the asset root.
$assets = self::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo()));
$rootId = $assets->getRootId();
if (!empty($rootId))
{
return $rootId;
}
return 1;
}
/**
* Method to get the database table name for the class.
*
* @return string The name of the database table being modeled.
*
* @since 11.1
*
* @link http://docs.joomla.org/JTable/getTableName
*/
public function getTableName()
{
return $this->_tbl;
}
/**
* Method to get the primary key field name for the table.
*
* @return string The name of the primary key for the table.
*
* @link http://docs.joomla.org/JTable/getKeyName
* @since 11.1
*/
public function getKeyName()
{
return $this->_tbl_key;
}
/**
* Method to get the JDatabase connector object.
*
* @return JDatabase The internal database connector object.
*
* @link http://docs.joomla.org/JTable/getDBO
* @since 11.1
*/
public function getDbo()
{
return $this->_db;
}
/**
* Method to set the JDatabase connector object.
*
* @param object &$db A JDatabase connector object to be used by the table object.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/setDBO
* @since 11.1
*/
public function setDBO(&$db)
{
// Make sure the new database object is a JDatabase.
if (!($db instanceof JDatabase))
{
return false;
}
$this->_db = &$db;
return true;
}
/**
* Method to set rules for the record.
*
* @param mixed $input A JAccessRules object, JSON string, or array.
*
* @return void
*
* @since 11.1
*/
public function setRules($input)
{
if ($input instanceof JAccessRules)
{
$this->_rules = $input;
}
else
{
$this->_rules = new JAccessRules($input);
}
}
/**
* Method to get the rules for the record.
*
* @return JAccessRules object
*
* @since 11.1
*/
public function getRules()
{
return $this->_rules;
}
/**
* Method to reset class properties to the defaults set in the class
* definition. It will ignore the primary key as well as any private class
* properties.
*
* @return void
*
* @link http://docs.joomla.org/JTable/reset
* @since 11.1
*/
public function reset()
{
// Get the default values for the class from the table.
foreach ($this->getFields() as $k => $v)
{
// If the property is not the primary key or private, reset it.
if ($k != $this->_tbl_key && (strpos($k, '_') !== 0))
{
$this->$k = $v->Default;
}
}
}
/**
* Method to bind an associative array or object to the JTable instance.This
* method only binds properties that are publicly accessible and optionally
* takes an array of properties to ignore when binding.
*
* @param mixed $src An associative array or object to bind to the JTable instance.
* @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/bind
* @since 11.1
*/
public function bind($src, $ignore = array())
{
// If the source value is not an array or object return false.
if (!is_object($src) && !is_array($src))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_BIND_FAILED_INVALID_SOURCE_ARGUMENT', get_class($this)));
$this->setError($e);
return false;
}
// If the source value is an object, get its accessible properties.
if (is_object($src))
{
$src = get_object_vars($src);
}
// If the ignore value is a string, explode it over spaces.
if (!is_array($ignore))
{
$ignore = explode(' ', $ignore);
}
// Bind the source value, excluding the ignored fields.
foreach ($this->getProperties() as $k => $v)
{
// Only process fields not in the ignore array.
if (!in_array($k, $ignore))
{
if (isset($src[$k]))
{
$this->$k = $src[$k];
}
}
}
return true;
}
/**
* Method to load a row from the database by primary key and bind the fields
* to the JTable instance properties.
*
* @param mixed $keys An optional primary key value to load the row by, or an array of fields to match. If not
* set the instance property value is used.
* @param boolean $reset True to reset the default values before loading the new row.
*
* @return boolean True if successful. False if row not found or on error (internal error state set in that case).
*
* @link http://docs.joomla.org/JTable/load
* @since 11.1
*/
public function load($keys = null, $reset = true)
{
if (empty($keys))
{
// If empty, use the value of the current key
$keyName = $this->_tbl_key;
$keyValue = $this->$keyName;
// If empty primary key there's is no need to load anything
if (empty($keyValue))
{
return true;
}
$keys = array($keyName => $keyValue);
}
elseif (!is_array($keys))
{
// Load by primary key.
$keys = array($this->_tbl_key => $keys);
}
if ($reset)
{
$this->reset();
}
// Initialise the query.
$query = $this->_db->getQuery(true);
$query->select('*');
$query->from($this->_tbl);
$fields = array_keys($this->getProperties());
foreach ($keys as $field => $value)
{
// Check that $field is in the table.
if (!in_array($field, $fields))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CLASS_IS_MISSING_FIELD', get_class($this), $field));
$this->setError($e);
return false;
}
// Add the search tuple to the query.
$query->where($this->_db->quoteName($field) . ' = ' . $this->_db->quote($value));
}
$this->_db->setQuery($query);
try
{
$row = $this->_db->loadAssoc();
}
catch (RuntimeException $e)
{
$je = new JException($e->getMessage());
$this->setError($je);
return false;
}
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy && $this->_db->getErrorNum())
{
$e = new JException($this->_db->getErrorMsg());
$this->setError($e);
return false;
}
// Check that we have a result.
if (empty($row))
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_EMPTY_ROW_RETURNED'));
$this->setError($e);
return false;
}
// Bind the object with the row and return.
return $this->bind($row);
}
/**
* Method to perform sanity checks on the JTable instance properties to ensure
* they are safe to store in the database. Child classes should override this
* method to make sure the data they are storing in the database is safe and
* as expected before storage.
*
* @return boolean True if the instance is sane and able to be stored in the database.
*
* @link http://docs.joomla.org/JTable/check
* @since 11.1
*/
public function check()
{
return true;
}
/**
* Method to store a row in the database from the JTable instance properties.
* If a primary key value is set the row with that primary key value will be
* updated with the instance property values. If no primary key value is set
* a new row will be inserted into the database with the properties from the
* JTable instance.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/store
* @since 11.1
*/
public function store($updateNulls = false)
{
// Initialise variables.
$k = $this->_tbl_key;
if (!empty($this->asset_id))
{
$currentAssetId = $this->asset_id;
}
// The asset id field is managed privately by this class.
if ($this->_trackAssets)
{
unset($this->asset_id);
}
// If a primary key exists update the object, otherwise insert it.
if ($this->$k)
{
$stored = $this->_db->updateObject($this->_tbl, $this, $this->_tbl_key, $updateNulls);
}
else
{
$stored = $this->_db->insertObject($this->_tbl, $this, $this->_tbl_key);
}
// If the store failed return false.
if (!$stored)
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// If the table is not set to track assets return true.
if (!$this->_trackAssets)
{
return true;
}
if ($this->_locked)
{
$this->_unlock();
}
//
// Asset Tracking
//
$parentId = $this->_getAssetParentId();
$name = $this->_getAssetName();
$title = $this->_getAssetTitle();
$asset = JTable::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo()));
$asset->loadByName($name);
// Re-inject the asset id.
$this->asset_id = $asset->id;
// Check for an error.
if ($error = $asset->getError())
{
$this->setError($error);
return false;
}
// Specify how a new or moved node asset is inserted into the tree.
if (empty($this->asset_id) || $asset->parent_id != $parentId)
{
$asset->setLocation($parentId, 'last-child');
}
// Prepare the asset to be stored.
$asset->parent_id = $parentId;
$asset->name = $name;
$asset->title = $title;
if ($this->_rules instanceof JAccessRules)
{
$asset->rules = (string) $this->_rules;
}
if (!$asset->check() || !$asset->store($updateNulls))
{
$this->setError($asset->getError());
return false;
}
// Create an asset_id or heal one that is corrupted.
if (empty($this->asset_id) || ($currentAssetId != $this->asset_id && !empty($this->asset_id)))
{
// Update the asset_id field in this table.
$this->asset_id = (int) $asset->id;
$query = $this->_db->getQuery(true);
$query->update($this->_db->quoteName($this->_tbl));
$query->set('asset_id = ' . (int) $this->asset_id);
$query->where($this->_db->quoteName($k) . ' = ' . (int) $this->$k);
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED_UPDATE_ASSET_ID', $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
}
return true;
}
/**
* Method to provide a shortcut to binding, checking and storing a JTable
* instance to the database table. The method will check a row in once the
* data has been stored and if an ordering filter is present will attempt to
* reorder the table rows based on the filter. The ordering filter is an instance
* property name. The rows that will be reordered are those whose value matches
* the JTable instance for the property specified.
*
* @param mixed $src An associative array or object to bind to the JTable instance.
* @param string $orderingFilter Filter for the order updating
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/save
* @since 11.1
*/
public function save($src, $orderingFilter = '', $ignore = '')
{
// Attempt to bind the source to the instance.
if (!$this->bind($src, $ignore))
{
return false;
}
// Run any sanity checks on the instance and verify that it is ready for storage.
if (!$this->check())
{
return false;
}
// Attempt to store the properties to the database table.
if (!$this->store())
{
return false;
}
// Attempt to check the row in, just in case it was checked out.
if (!$this->checkin())
{
return false;
}
// If an ordering filter is set, attempt reorder the rows in the table based on the filter and value.
if ($orderingFilter)
{
$filterValue = $this->$orderingFilter;
$this->reorder($orderingFilter ? $this->_db->quoteName($orderingFilter) . ' = ' . $this->_db->Quote($filterValue) : '');
}
// Set the error to empty and return true.
$this->setError('');
return true;
}
/**
* Method to delete a row from the database table by primary key value.
*
* @param mixed $pk An optional primary key value to delete. If not set the instance property value is used.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/delete
* @since 11.1
*/
public function delete($pk = null)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk === null)
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_NULL_PRIMARY_KEY'));
$this->setError($e);
return false;
}
// If tracking assets, remove the asset first.
if ($this->_trackAssets)
{
// Get and the asset name.
$this->$k = $pk;
$name = $this->_getAssetName();
$asset = JTable::getInstance('Asset');
if ($asset->loadByName($name))
{
if (!$asset->delete())
{
$this->setError($asset->getError());
return false;
}
}
else
{
$this->setError($asset->getError());
return false;
}
}
// Delete the row by primary key.
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_tbl);
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($pk));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_DELETE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
return true;
}
/**
* Method to check a row out if the necessary properties/fields exist. To
* prevent race conditions while editing rows in a database, a row can be
* checked out if the fields 'checked_out' and 'checked_out_time' are available.
* While a row is checked out, any attempt to store the row by a user other
* than the one who checked the row out should be held until the row is checked
* in again.
*
* @param integer $userId The Id of the user checking out the row.
* @param mixed $pk An optional primary key value to check out. If not set
* the instance property value is used.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/checkOut
* @since 11.1
*/
public function checkOut($userId, $pk = null)
{
// If there is no checked_out or checked_out_time field, just return true.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
return true;
}
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk === null)
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_NULL_PRIMARY_KEY'));
$this->setError($e);
return false;
}
// Get the current time in MySQL format.
$time = JFactory::getDate()->toSql();
// Check the row out by primary key.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set($this->_db->quoteName('checked_out') . ' = ' . (int) $userId);
$query->set($this->_db->quoteName('checked_out_time') . ' = ' . $this->_db->quote($time));
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($pk));
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CHECKOUT_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Set table values in the object.
$this->checked_out = (int) $userId;
$this->checked_out_time = $time;
return true;
}
/**
* Method to check a row in if the necessary properties/fields exist. Checking
* a row in will allow other users the ability to edit the row.
*
* @param mixed $pk An optional primary key value to check out. If not set the instance property value is used.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/checkIn
* @since 11.1
*/
public function checkIn($pk = null)
{
// If there is no checked_out or checked_out_time field, just return true.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
return true;
}
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk === null)
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_NULL_PRIMARY_KEY'));
$this->setError($e);
return false;
}
// Check the row in by primary key.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set($this->_db->quoteName('checked_out') . ' = 0');
$query->set($this->_db->quoteName('checked_out_time') . ' = ' . $this->_db->quote($this->_db->getNullDate()));
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($pk));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CHECKIN_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Set table values in the object.
$this->checked_out = 0;
$this->checked_out_time = '';
return true;
}
/**
* Method to increment the hits for a row if the necessary property/field exists.
*
* @param mixed $pk An optional primary key value to increment. If not set the instance property value is used.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/hit
* @since 11.1
*/
public function hit($pk = null)
{
// If there is no hits field, just return true.
if (!property_exists($this, 'hits'))
{
return true;
}
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk === null)
{
return false;
}
// Check the row in by primary key.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set($this->_db->quoteName('hits') . ' = (' . $this->_db->quoteName('hits') . ' + 1)');
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($pk));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_HIT_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Set table values in the object.
$this->hits++;
return true;
}
/**
* Method to determine if a row is checked out and therefore uneditable by
* a user. If the row is checked out by the same user, then it is considered
* not checked out -- as the user can still edit it.
*
* @param integer $with The userid to preform the match with, if an item is checked
* out by this user the function will return false.
* @param integer $against The userid to perform the match against when the function
* is used as a static function.
*
* @return boolean True if checked out.
*
* @link http://docs.joomla.org/JTable/isCheckedOut
* @since 11.1
* @todo This either needs to be static or not.
*/
public function isCheckedOut($with = 0, $against = null)
{
// Handle the non-static case.
if (isset($this) && ($this instanceof JTable) && is_null($against))
{
$against = $this->get('checked_out');
}
// The item is not checked out or is checked out by the same user.
if (!$against || ($against == $with))
{
return false;
}
$db = JFactory::getDBO();
$db->setQuery('SELECT COUNT(userid)' . ' FROM ' . $db->quoteName('#__session') . ' WHERE ' . $db->quoteName('userid') . ' = ' . (int) $against);
$checkedOut = (boolean) $db->loadResult();
// If a session exists for the user then it is checked out.
return $checkedOut;
}
/**
* Method to get the next ordering value for a group of rows defined by an SQL WHERE clause.
* This is useful for placing a new item last in a group of items in the table.
*
* @param string $where WHERE clause to use for selecting the MAX(ordering) for the table.
*
* @return mixed Boolean false an failure or the next ordering value as an integer.
*
* @link http://docs.joomla.org/JTable/getNextOrder
* @since 11.1
*/
public function getNextOrder($where = '')
{
// If there is no ordering field set an error and return false.
if (!property_exists($this, 'ordering'))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CLASS_DOES_NOT_SUPPORT_ORDERING', get_class($this)));
$this->setError($e);
return false;
}
// Get the largest ordering value for a given where clause.
$query = $this->_db->getQuery(true);
$query->select('MAX(ordering)');
$query->from($this->_tbl);
if ($where)
{
$query->where($where);
}
$this->_db->setQuery($query);
$max = (int) $this->_db->loadResult();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GET_NEXT_ORDER_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Return the largest ordering value + 1.
return ($max + 1);
}
/**
* Method to compact the ordering values of rows in a group of rows
* defined by an SQL WHERE clause.
*
* @param string $where WHERE clause to use for limiting the selection of rows to compact the ordering values.
*
* @return mixed Boolean true on success.
*
* @link http://docs.joomla.org/JTable/reorder
* @since 11.1
*/
public function reorder($where = '')
{
// If there is no ordering field set an error and return false.
if (!property_exists($this, 'ordering'))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CLASS_DOES_NOT_SUPPORT_ORDERING', get_class($this)));
$this->setError($e);
return false;
}
// Initialise variables.
$k = $this->_tbl_key;
// Get the primary keys and ordering values for the selection.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', ordering');
$query->from($this->_tbl);
$query->where('ordering >= 0');
$query->order('ordering');
// Setup the extra where and ordering clause data.
if ($where)
{
$query->where($where);
}
$this->_db->setQuery($query);
$rows = $this->_db->loadObjectList();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_REORDER_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Compact the ordering values.
foreach ($rows as $i => $row)
{
// Make sure the ordering is a positive integer.
if ($row->ordering >= 0)
{
// Only update rows that are necessary.
if ($row->ordering != $i + 1)
{
// Update the row ordering field.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('ordering = ' . ($i + 1));
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($row->$k));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(
JText::sprintf('JLIB_DATABASE_ERROR_REORDER_UPDATE_ROW_FAILED', get_class($this), $i, $this->_db->getErrorMsg())
);
$this->setError($e);
return false;
}
}
}
}
return true;
}
/**
* Method to move a row in the ordering sequence of a group of rows defined by an SQL WHERE clause.
* Negative numbers move the row up in the sequence and positive numbers move it down.
*
* @param integer $delta The direction and magnitude to move the row in the ordering sequence.
* @param string $where WHERE clause to use for limiting the selection of rows to compact the
* ordering values.
*
* @return mixed Boolean true on success.
*
* @link http://docs.joomla.org/JTable/move
* @since 11.1
*/
public function move($delta, $where = '')
{
// If there is no ordering field set an error and return false.
if (!property_exists($this, 'ordering'))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CLASS_DOES_NOT_SUPPORT_ORDERING', get_class($this)));
$this->setError($e);
return false;
}
// If the change is none, do nothing.
if (empty($delta))
{
return true;
}
// Initialise variables.
$k = $this->_tbl_key;
$row = null;
$query = $this->_db->getQuery(true);
// Select the primary key and ordering values from the table.
$query->select($this->_tbl_key . ', ordering');
$query->from($this->_tbl);
// If the movement delta is negative move the row up.
if ($delta < 0)
{
$query->where('ordering < ' . (int) $this->ordering);
$query->order('ordering DESC');
}
// If the movement delta is positive move the row down.
elseif ($delta > 0)
{
$query->where('ordering > ' . (int) $this->ordering);
$query->order('ordering ASC');
}
// Add the custom WHERE clause if set.
if ($where)
{
$query->where($where);
}
// Select the first row with the criteria.
$this->_db->setQuery($query, 0, 1);
$row = $this->_db->loadObject();
// If a row is found, move the item.
if (!empty($row))
{
// Update the ordering field for this instance to the row's ordering value.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('ordering = ' . (int) $row->ordering);
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($this->$k));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_MOVE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Update the ordering field for the row to this instance's ordering value.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('ordering = ' . (int) $this->ordering);
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($row->$k));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_MOVE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Update the instance value.
$this->ordering = $row->ordering;
}
else
{
// Update the ordering field for this instance.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('ordering = ' . (int) $this->ordering);
$query->where($this->_tbl_key . ' = ' . $this->_db->quote($this->$k));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_MOVE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
}
return true;
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* @param mixed $pks An optional array of primary key values to update. If not set the instance property value is used.
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* @param integer $userId The user id of the user performing the operation.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/publish
* @since 11.1
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
// Initialise variables.
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
$this->setError($e);
return false;
}
}
// Update the publishing state for rows with the given primary keys.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('published = ' . (int) $state);
// Determine if there is checkin support for the table.
if (property_exists($this, 'checked_out') || property_exists($this, 'checked_out_time'))
{
$query->where('(checked_out = 0 OR checked_out = ' . (int) $userId . ')');
$checkin = true;
}
else
{
$checkin = false;
}
// Build the WHERE clause for the primary keys.
$query->where($k . ' = ' . implode(' OR ' . $k . ' = ', $pks));
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_PUBLISH_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin && (count($pks) == $this->_db->getAffectedRows()))
{
// Checkin the rows.
foreach ($pks as $pk)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->published = $state;
}
$this->setError('');
return true;
}
/**
* Generic check for whether dependencies exist for this object in the database schema
*
* Can be overloaded/supplemented by the child class
*
* @param mixed $pk An optional primary key value check the row for. If not
* set the instance property value is used.
* @param array $joins An optional array to compiles standard joins formatted like:
* [label => 'Label', name => 'table name' , idfield => 'field', joinfield => 'field']
*
* @return boolean True on success.
*
* @deprecated 12.1
* @link http://docs.joomla.org/JTable/canDelete
* @since 11.1
*/
public function canDelete($pk = null, $joins = null)
{
// Deprecation warning.
JLog::add('JTable::canDelete() is deprecated.', JLog::WARNING, 'deprecated');
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk === null)
{
return false;
}
if (is_array($joins))
{
// Get a query object.
$query = $this->_db->getQuery(true);
// Setup the basic query.
$query->select($this->_db->quoteName($this->_tbl_key));
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName($this->_tbl_key) . ' = ' . $this->_db->quote($this->$k));
$query->group($this->_db->quoteName($this->_tbl_key));
// For each join add the select and join clauses to the query object.
foreach ($joins as $table)
{
$query->select('COUNT(DISTINCT ' . $table['idfield'] . ') AS ' . $table['idfield']);
$query->join('LEFT', $table['name'] . ' ON ' . $table['joinfield'] . ' = ' . $k);
}
// Get the row object from the query.
$this->_db->setQuery((string) $query, 0, 1);
$row = $this->_db->loadObject();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
$msg = array();
$i = 0;
foreach ($joins as $table)
{
$k = $table['idfield'] . $i;
if ($row->$k)
{
$msg[] = JText::_($table['label']);
}
$i++;
}
if (count($msg))
{
$this->setError("noDeleteRecord" . ": " . implode(', ', $msg));
return false;
}
else
{
return true;
}
}
return true;
}
/**
* Method to export the JTable instance properties to an XML string.
*
* @param boolean $mapKeysToText True to map foreign keys to text values.
*
* @return string XML string representation of the instance.
*
* @deprecated 12.1
* @link http://docs.joomla.org/JTable/toXML
* @since 11.1
*/
public function toXML($mapKeysToText = false)
{
// Deprecation warning.
JLog::add('JTable::toXML() is deprecated.', JLog::WARNING, 'deprecated');
// Initialise variables.
$xml = array();
$map = $mapKeysToText ? ' mapkeystotext="true"' : '';
// Open root node.
$xml[] = '';
// Get the publicly accessible instance properties.
foreach (get_object_vars($this) as $k => $v)
{
// If the value is null or non-scalar, or the field is internal ignore it.
if (!is_scalar($v) || ($v === null) || ($k[0] == '_'))
{
continue;
}
$xml[] = ' <' . $k . '>' . $k . '>';
}
// Close root node.
$xml[] = '';
// Return the XML array imploded over new lines.
return implode("\n", $xml);
}
/**
* Method to lock the database table for writing.
*
* @return boolean True on success.
*
* @since 11.1
* @throws JDatabaseException
*/
protected function _lock()
{
$this->_db->lockTable($this->_tbl);
$this->_locked = true;
return true;
}
/**
* Method to unlock the database table for writing.
*
* @return boolean True on success.
*
* @since 11.1
*/
protected function _unlock()
{
$this->_db->unlockTables();
$this->_locked = false;
return true;
}
}
PK /?\]=|
exception.phpnu W+A
Order allow,deny
Deny from all
PK /?\z- table/module.phpnu W+A access = (int) JFactory::getConfig()->get('access');
}
/**
* Overloaded check function.
*
* @return boolean True if the instance is sane and able to be stored in the database.
*
* @see JTable::check
* @since 11.1
*/
public function check()
{
// check for valid name
if (trim($this->title) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_MODULE'));
return false;
}
// Check the publish down date is not earlier than publish up.
if (intval($this->publish_down) > 0 && $this->publish_down < $this->publish_up)
{
$this->setError(JText::_('JGLOBAL_START_PUBLISH_AFTER_FINISH'));
return false;
}
return true;
}
/**
* Overloaded bind function.
*
* @param array $array Named array.
* @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
return parent::bind($array, $ignore);
}
}
PK /?\u table/menu.phpnu W+A access = (int) JFactory::getConfig()->get('access');
}
/**
* Overloaded bind function
*
* @param array $array Named array
* @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
// Verify that the default home menu is not unset
if ($this->home == '1' && $this->language == '*' && ($array['home'] == '0'))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_CANNOT_UNSET_DEFAULT_DEFAULT'));
return false;
}
//Verify that the default home menu set to "all" languages" is not unset
if ($this->home == '1' && $this->language == '*' && ($array['language'] != '*'))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_CANNOT_UNSET_DEFAULT'));
return false;
}
// Verify that the default home menu is not unpublished
if ($this->home == '1' && $this->language == '*' && $array['published'] != '1')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_UNPUBLISH_DEFAULT_HOME'));
return false;
}
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
return parent::bind($array, $ignore);
}
/**
* Overloaded check function
*
* @return boolean True on success
*
* @see JTable::check
* @since 11.1
*/
public function check()
{
// If the alias field is empty, set it to the title.
$this->alias = trim($this->alias);
if ((empty($this->alias)) && ($this->type != 'alias' && $this->type != 'url'))
{
$this->alias = $this->title;
}
// Make the alias URL safe.
$this->alias = JApplication::stringURLSafe($this->alias);
if (trim(str_replace('-', '', $this->alias)) == '')
{
$this->alias = JFactory::getDate()->format('Y-m-d-H-i-s');
}
// Cast the home property to an int for checking.
$this->home = (int) $this->home;
// Verify that a first level menu item alias is not 'component'.
if ($this->parent_id == 1 && $this->alias == 'component')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_ROOT_ALIAS_COMPONENT'));
return false;
}
// Verify that a first level menu item alias is not the name of a folder.
jimport('joomla.filesystem.folders');
if ($this->parent_id == 1 && in_array($this->alias, JFolder::folders(JPATH_ROOT)))
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_MENU_ROOT_ALIAS_FOLDER', $this->alias, $this->alias));
return false;
}
// Verify that the home item a component.
if ($this->home && $this->type != 'component')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_HOME_NOT_COMPONENT'));
return false;
}
return true;
}
/**
* Overloaded store function
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return mixed False on failure, positive integer on success.
*
* @see JTable::store
* @since 11.1
*/
public function store($updateNulls = false)
{
$db = JFactory::getDBO();
// Verify that the alias is unique
$table = JTable::getInstance('Menu', 'JTable');
if ($table->load(array('alias' => $this->alias, 'parent_id' => $this->parent_id, 'client_id' => $this->client_id, 'language' => $this->language))
&& ($table->id != $this->id || $this->id == 0))
{
if ($this->menutype == $table->menutype)
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS'));
}
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS_ROOT'));
}
return false;
}
// Verify that the home page for this language is unique
if ($this->home == '1')
{
$table = JTable::getInstance('Menu', 'JTable');
if ($table->load(array('home' => '1', 'language' => $this->language)))
{
if ($table->checked_out && $table->checked_out != $this->checked_out)
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_DEFAULT_CHECKIN_USER_MISMATCH'));
return false;
}
$table->home = 0;
$table->checked_out = 0;
$table->checked_out_time = $db->getNullDate();
$table->store();
}
// Verify that the home page for this menu is unique.
if ($table->load(array('home' => '1', 'menutype' => $this->menutype)) && ($table->id != $this->id || $this->id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENU_HOME_NOT_UNIQUE_IN_MENU'));
return false;
}
}
if (!parent::store($updateNulls))
{
return false;
}
// Get the new path in case the node was moved
$pathNodes = $this->getPath();
$segments = array();
foreach ($pathNodes as $node)
{
// Don't include root in path
if ($node->alias != 'root')
{
$segments[] = $node->alias;
}
}
$newPath = trim(implode('/', $segments), ' /\\');
// Use new path for partial rebuild of table
// Rebuild will return positive integer on success, false on failure
return ($this->rebuild($this->{$this->_tbl_key}, $this->lft, $this->level, $newPath) > 0);
}
}
PK /?\:Be e table/usergroup.phpnu W+A title)) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_USERGROUP_TITLE'));
return false;
}
// Check for a duplicate parent_id, title.
// There is a unique index on the (parent_id, title) field in the table.
$db = $this->_db;
$query = $db->getQuery(true)
->select('COUNT(title)')
->from($this->_tbl)
->where('title = ' . $db->quote(trim($this->title)))
->where('parent_id = ' . (int) $this->parent_id)
->where('id <> ' . (int) $this->id);
$db->setQuery($query);
if ($db->loadResult() > 0)
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_USERGROUP_TITLE_EXISTS'));
return false;
}
return true;
}
/**
* Method to recursively rebuild the nested set tree.
*
* @param integer $parent_id The root of the tree to rebuild.
* @param integer $left The left id to start with in building the tree.
*
* @return boolean True on success
*
* @since 11.1
*/
public function rebuild($parent_id = 0, $left = 0)
{
// get the database object
$db = &$this->_db;
// get all children of this node
$db->setQuery('SELECT id FROM ' . $this->_tbl . ' WHERE parent_id=' . (int) $parent_id . ' ORDER BY parent_id, title');
$children = $db->loadColumn();
// the right value of this node is the left value + 1
$right = $left + 1;
// execute this function recursively over all children
for ($i = 0, $n = count($children); $i < $n; $i++)
{
// $right is the current right value, which is incremented on recursion return
$right = $this->rebuild($children[$i], $right);
// if there is an update failure, return false to break out of the recursion
if ($right === false)
{
return false;
}
}
// we've got the left value, and now that we've processed
// the children of this node we also know the right value
$db->setQuery('UPDATE ' . $this->_tbl . ' SET lft=' . (int) $left . ', rgt=' . (int) $right . ' WHERE id=' . (int) $parent_id);
// if there is an update failure, return false to break out of the recursion
if (!$db->execute())
{
return false;
}
// return the right value of this node + 1
return $right + 1;
}
/**
* Inserts a new row if id is zero or updates an existing row in the database table
*
* @param boolean $updateNulls If false, null object variables are not updated
*
* @return boolean True if successful, false otherwise and an internal error message is set
*
* @since 11.1
*/
public function store($updateNulls = false)
{
if ($result = parent::store($updateNulls))
{
// Rebuild the nested set tree.
$this->rebuild();
}
return $result;
}
/**
* Delete this object and its dependencies
*
* @param integer $oid The primary key of the user group to delete.
*
* @return mixed Boolean or Exception.
*
* @since 11.1
*/
public function delete($oid = null)
{
if ($oid)
{
$this->load($oid);
}
if ($this->id == 0)
{
return new JException(JText::_('JGLOBAL_CATEGORY_NOT_FOUND'));
}
if ($this->parent_id == 0)
{
return new JException(JText::_('JLIB_DATABASE_ERROR_DELETE_ROOT_CATEGORIES'));
}
if ($this->lft == 0 or $this->rgt == 0)
{
return new JException(JText::_('JLIB_DATABASE_ERROR_DELETE_CATEGORY'));
}
$db = $this->_db;
// Select the category ID and it's children
$query = $db->getQuery(true);
$query->select($db->quoteName('c') . '.' . $db->quoteName('id'));
$query->from($db->quoteName($this->_tbl) . 'AS c');
$query->where($db->quoteName('c') . '.' . $db->quoteName('lft') . ' >= ' . (int) $this->lft);
$query->where($db->quoteName('c') . '.' . $db->quoteName('rgt') . ' <= ' . (int) $this->rgt);
$db->setQuery($query);
$ids = $db->loadColumn();
if (empty($ids))
{
return new JException(JText::_('JLIB_DATABASE_ERROR_DELETE_CATEGORY'));
}
// Delete the category dependencies
// @todo Remove all related threads, posts and subscriptions
// Delete the category and its children
$query->clear();
$query->delete();
$query->from($db->quoteName($this->_tbl));
$query->where($db->quoteName('id') . ' IN (' . implode(',', $ids) . ')');
$db->setQuery($query);
if (!$db->execute())
{
$this->setError($db->getErrorMsg());
return false;
}
// Delete the usergroup in view levels
$replace = array();
foreach ($ids as $id)
{
$replace[] = ',' . $db->quote("[$id,") . ',' . $db->quote("[") . ')';
$replace[] = ',' . $db->quote(",$id,") . ',' . $db->quote(",") . ')';
$replace[] = ',' . $db->quote(",$id]") . ',' . $db->quote("]") . ')';
$replace[] = ',' . $db->quote("[$id]") . ',' . $db->quote("[]") . ')';
}
$query->clear();
//sqlsrv change. Alternative for regexp
$query->select('id, rules');
$query->from('#__viewlevels');
$db->setQuery($query);
$rules = $db->loadObjectList();
$match_ids = array();
foreach ($rules as $rule)
{
foreach ($ids as $id)
{
if (strstr($rule->rules, '[' . $id) || strstr($rule->rules, ',' . $id) || strstr($rule->rules, $id . ']'))
{
$match_ids[] = $rule->id;
}
}
}
if (!empty($match_ids))
{
$query = $db->getQuery(true);
$query->set('rules=' . str_repeat('replace(', 4 * count($ids)) . 'rules' . implode('', $replace));
$query->update('#__viewlevels');
$query->where('id IN (' . implode(',', $match_ids) . ')');
$db->setQuery($query);
if (!$db->execute())
{
$this->setError($db->getErrorMsg());
return false;
}
}
// Delete the user to usergroup mappings for the group(s) from the database.
$query->clear();
$query->delete();
$query->from($db->quoteName('#__user_usergroup_map'));
$query->where($db->quoteName('group_id') . ' IN (' . implode(',', $ids) . ')');
$db->setQuery($query);
$db->execute();
// Check for a database error.
if ($db->getErrorNum())
{
$this->setError($db->getErrorMsg());
return false;
}
return true;
}
}
PK /?\={Sgi i table/extension.phpnu W+A name) == '' || trim($this->element) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_EXTENSION'));
return false;
}
return true;
}
/**
* Overloaded bind function
*
* @param array $array Named array
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
if (isset($array['control']) && is_array($array['control']))
{
$registry = new JRegistry;
$registry->loadArray($array['control']);
$array['control'] = (string) $registry;
}
return parent::bind($array, $ignore);
}
/**
* Method to create and execute a SELECT WHERE query.
*
* @param array $options Array of options
*
* @return JDatabase The database query result
*
* @since 11.1
*/
public function find($options = array())
{
// Get the JDatabaseQuery object
$query = $this->_db->getQuery(true);
foreach ($options as $col => $val)
{
$query->where($col . ' = ' . $this->_db->quote($val));
}
$query->select($this->_db->quoteName('extension_id'));
$query->from($this->_db->quoteName('#__extensions'));
$this->_db->setQuery($query);
return $this->_db->loadResult();
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* @param mixed $pks An optional array of primary key values to update. If not
* set the instance property value is used.
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* @param integer $userId The user id of the user performing the operation.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
// Initialise variables.
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
return false;
}
}
// Build the WHERE clause for the primary keys.
$where = $k . '=' . implode(' OR ' . $k . '=', $pks);
// Determine if there is checkin support for the table.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
$checkin = '';
}
else
{
$checkin = ' AND (checked_out = 0 OR checked_out = ' . (int) $userId . ')';
}
// Get the JDatabaseQuery object
$query = $this->_db->getQuery(true);
// Update the publishing state for rows with the given primary keys.
$query->update($this->_db->quoteName($this->_tbl));
$query->set($this->_db->quoteName('enabled') . ' = ' . (int) $state);
$query->where('(' . $where . ')' . $checkin);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin && (count($pks) == $this->_db->getAffectedRows()))
{
// Checkin the rows.
foreach ($pks as $pk)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->enabled = $state;
}
$this->setError('');
return true;
}
}
PK /?\݆Š table/asset.phpnu W+A _db->getQuery(true);
// Get the asset id for the asset.
$query->select($this->_db->quoteName('id'));
$query->from($this->_db->quoteName('#__assets'));
$query->where($this->_db->quoteName('name') . ' = ' . $this->_db->quote($name));
$this->_db->setQuery($query);
$assetId = (int) $this->_db->loadResult();
if (empty($assetId))
{
return false;
}
// Check for a database error.
if ($error = $this->_db->getErrorMsg())
{
$this->setError($error);
return false;
}
return $this->load($assetId);
}
/**
* Asset that the nested set data is valid.
*
* @return boolean True if the instance is sane and able to be stored in the database.
*
* @link http://docs.joomla.org/JTable/check
* @since 11.1
*/
public function check()
{
$this->parent_id = (int) $this->parent_id;
// JTableNested does not allow parent_id = 0, override this.
if ($this->parent_id > 0)
{
// Get the JDatabaseQuery object
$query = $this->_db->getQuery(true);
$query->select('COUNT(id)');
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName('id') . ' = ' . $this->parent_id);
$this->_db->setQuery($query);
if ($this->_db->loadResult())
{
return true;
}
else
{
if ($error = $this->_db->getErrorMsg())
{
$this->setError($error);
}
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_INVALID_PARENT_ID'));
}
return false;
}
}
return true;
}
}
PK /?\ӵ table/session.phpnu W+A guest = 1;
$this->username = '';
}
/**
* Insert a session
*
* @param string $sessionId The session id
* @param integer $clientId The id of the client application
*
* @return boolean True on success
*
* @since 11.1
*/
public function insert($sessionId, $clientId)
{
$this->session_id = $sessionId;
$this->client_id = $clientId;
$this->time = time();
$ret = $this->_db->insertObject($this->_tbl, $this, 'session_id');
if (!$ret)
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', strtolower(get_class($this)), $this->_db->stderr()));
return false;
}
else
{
return true;
}
}
/**
* Updates the session
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function update($updateNulls = false)
{
$this->time = time();
$ret = $this->_db->updateObject($this->_tbl, $this, 'session_id', $updateNulls);
if (!$ret)
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', strtolower(get_class($this)), $this->_db->stderr()));
return false;
}
else
{
return true;
}
}
/**
* Destroys the pre-existing session
*
* @param integer $userId Identifier of the user for this session.
* @param array $clientIds Array of client ids for which session(s) will be destroyed
*
* @return boolean True on success.
*
* @since 11.1
*/
public function destroy($userId, $clientIds = array())
{
$clientIds = implode(',', $clientIds);
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName('userid') . ' = ' . $this->_db->quote($userId));
$query->where($this->_db->quoteName('client_id') . ' IN (' . $clientIds . ')');
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$this->setError($this->_db->stderr());
return false;
}
return true;
}
/**
* Purge old sessions
*
* @param integer $maxLifetime Session age in seconds
*
* @return mixed Resource on success, null on fail
*
* @since 11.1
*/
public function purge($maxLifetime = 1440)
{
$past = time() - $maxLifetime;
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName('time') . ' < ' . (int) $past);
$this->_db->setQuery($query);
return $this->_db->execute();
}
/**
* Find out if a user has a one or more active sessions
*
* @param integer $userid The identifier of the user
*
* @return boolean True if a session for this user exists
*
* @since 11.1
*/
public function exists($userid)
{
$query = $this->_db->getQuery(true);
$query->select('COUNT(userid)');
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName('userid') . ' = ' . $this->_db->quote($userid));
$this->_db->setQuery($query);
if (!$result = $this->_db->loadResult())
{
$this->setError($this->_db->stderr());
return false;
}
return (boolean) $result;
}
/**
* Overloaded delete method
*
* We must override it because of the non-integer primary key
*
* @param integer $oid The object id (optional).
*
* @return mixed True if successful otherwise an error message
*
* @since 11.1
*/
public function delete($oid = null)
{
//if (!$this->canDelete($msg))
//{
// return $msg;
//}
$k = $this->_tbl_key;
if ($oid)
{
$this->$k = $oid;
}
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName($this->_tbl_key) . ' = ' . $this->_db->quote($this->$k));
$this->_db->setQuery($query);
if ($this->_db->execute())
{
return true;
}
else
{
$this->setError($this->_db->getErrorMsg());
return false;
}
}
}
PK /?\V table/index.htmlnu W+A
PK /?\8 table/viewlevel.phpnu W+A title)) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_VIEWLEVEL'));
return false;
}
return true;
}
}
PK /?\9 table/update.phpnu W+A name) == '' || trim($this->element) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_EXTENSION'));
return false;
}
return true;
}
/**
* Overloaded bind function
*
* @param array $array Named array
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
if (isset($array['control']) && is_array($array['control']))
{
$registry = new JRegistry;
$registry->loadArray($array['control']);
$array['control'] = (string) $registry;
}
return parent::bind($array, $ignore);
}
/**
* Method to create and execute a SELECT WHERE query.
*
* @param array $options Array of options
*
* @return JDatabase Results of query
*
* @since 11.1
*/
public function find($options = array())
{
$where = array();
foreach ($options as $col => $val)
{
$where[] = $col . ' = ' . $this->_db->Quote($val);
}
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName($this->_tbl_key));
$query->from($this->_db->quoteName($this->_tbl));
$query->where(implode(' AND ', $where));
$this->_db->setQuery($query);
return $this->_db->loadResult();
}
}
PK /?\\' ' table/content.phpnu W+A _tbl_key;
return 'com_content.article.' . (int) $this->$k;
}
/**
* Method to return the title to use for the asset table.
*
* @return string
*
* @since 11.1
*/
protected function _getAssetTitle()
{
return $this->title;
}
/**
* Method to get the parent asset id for the record
*
* @param JTable $table A JTable object (optional) for the asset parent
* @param integer $id The id (optional) of the content.
*
* @return integer
*
* @since 11.1
*/
protected function _getAssetParentId($table = null, $id = null)
{
// Initialise variables.
$assetId = null;
// This is a article under a category.
if ($this->catid)
{
// Build the query to get the asset id for the parent category.
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('asset_id'));
$query->from($this->_db->quoteName('#__categories'));
$query->where($this->_db->quoteName('id') . ' = ' . (int) $this->catid);
// Get the asset id from the database.
$this->_db->setQuery($query);
if ($result = $this->_db->loadResult())
{
$assetId = (int) $result;
}
}
// Return the asset id.
if ($assetId)
{
return $assetId;
}
else
{
return parent::_getAssetParentId($table, $id);
}
}
/**
* Overloaded bind function
*
* @param array $array Named array
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error string
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
// Search for the {readmore} tag and split the text up accordingly.
if (isset($array['articletext']))
{
$pattern = '#
#i';
$tagPos = preg_match($pattern, $array['articletext']);
if ($tagPos == 0)
{
$this->introtext = $array['articletext'];
$this->fulltext = '';
}
else
{
list ($this->introtext, $this->fulltext) = preg_split($pattern, $array['articletext'], 2);
}
}
if (isset($array['attribs']) && is_array($array['attribs']))
{
$registry = new JRegistry;
$registry->loadArray($array['attribs']);
$array['attribs'] = (string) $registry;
}
if (isset($array['metadata']) && is_array($array['metadata']))
{
$registry = new JRegistry;
$registry->loadArray($array['metadata']);
$array['metadata'] = (string) $registry;
}
// Bind the rules.
if (isset($array['rules']) && is_array($array['rules']))
{
$rules = new JAccessRules($array['rules']);
$this->setRules($rules);
}
return parent::bind($array, $ignore);
}
/**
* Overloaded check function
*
* @return boolean True on success, false on failure
*
* @see JTable::check
* @since 11.1
*/
public function check()
{
if (trim($this->title) == '')
{
$this->setError(JText::_('COM_CONTENT_WARNING_PROVIDE_VALID_NAME'));
return false;
}
if (trim($this->alias) == '')
{
$this->alias = $this->title;
}
$this->alias = JApplication::stringURLSafe($this->alias);
if (trim(str_replace('-', '', $this->alias)) == '')
{
$this->alias = JFactory::getDate()->format('Y-m-d-H-i-s');
}
if (trim(str_replace(' ', '', $this->fulltext)) == '')
{
$this->fulltext = '';
}
if (trim($this->introtext) == '' && trim($this->fulltext) == '')
{
$this->setError(JText::_('JGLOBAL_ARTICLE_MUST_HAVE_TEXT'));
return false;
}
// Check the publish down date is not earlier than publish up.
if ($this->publish_down > $this->_db->getNullDate() && $this->publish_down < $this->publish_up)
{
$this->setError(JText::_('JGLOBAL_START_PUBLISH_AFTER_FINISH'));
return false;
}
// Clean up keywords -- eliminate extra spaces between phrases
// and cr (\r) and lf (\n) characters from string
if (!empty($this->metakey))
{
// Only process if not empty
$bad_characters = array("\n", "\r", "\"", "<", ">"); // array of characters to remove
$after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); // remove bad characters
$keys = explode(',', $after_clean); // create array using commas as delimiter
$clean_keys = array();
foreach ($keys as $key)
{
if (trim($key))
{
// Ignore blank keywords
$clean_keys[] = trim($key);
}
}
$this->metakey = implode(", ", $clean_keys); // put array back together delimited by ", "
}
return true;
}
/**
* Overrides JTable::store to set modified data and user id.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function store($updateNulls = false)
{
$date = JFactory::getDate();
$user = JFactory::getUser();
if ($this->id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else
{
// New article. An article created and created_by field can be set by the user,
// so we don't touch either of these if they are set.
if (!intval($this->created))
{
$this->created = $date->toSql();
}
if (empty($this->created_by))
{
$this->created_by = $user->get('id');
}
}
// Verify that the alias is unique
$table = JTable::getInstance('Content', 'JTable');
if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS'));
return false;
}
return parent::store($updateNulls);
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* @param mixed $pks An optional array of primary key values to update. If not set the instance property value is used.
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* @param integer $userId The user id of the user performing the operation.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
// Initialise variables.
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
return false;
}
}
// Build the WHERE clause for the primary keys.
$where = $k . '=' . implode(' OR ' . $k . '=', $pks);
// Determine if there is checkin support for the table.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
$checkin = '';
}
else
{
$checkin = ' AND (checked_out = 0 OR checked_out = ' . (int) $userId . ')';
}
// Get the JDatabaseQuery object
$query = $this->_db->getQuery(true);
// Update the publishing state for rows with the given primary keys.
$query->update($this->_db->quoteName($this->_tbl));
$query->set($this->_db->quoteName('state') . ' = ' . (int) $state);
$query->where('(' . $where . ')' . $checkin);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin && (count($pks) == $this->_db->getAffectedRows()))
{
// Checkin the rows.
foreach ($pks as $pk)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->state = $state;
}
$this->setError('');
return true;
}
/**
* Converts record to XML
*
* @param boolean $mapKeysToText Map foreign keys to text values
*
* @return string Record in XML format
*
* @since 11.1
* @deprecated 12.1
* @codeCoverageIgnore
*/
public function toXML($mapKeysToText = false)
{
// Deprecation warning.
JLog::add('JTableContent::toXML() is deprecated.', JLog::WARNING, 'deprecated');
if ($mapKeysToText)
{
// Get the JDatabaseQuery object
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('name'));
$query->from($this->_db->quoteName('#__categories'));
$query->where($this->_db->quoteName('id') . ' = ' . (int) $this->catid);
$this->_db->setQuery($query);
$this->catid = $this->_db->loadResult();
$query->clear();
$query->select($this->_db->quoteName('name'));
$query->from($this->_db->quoteName('#__users'));
$query->where($this->_db->quoteName('id') . ' = ' . (int) $this->created_by);
$this->_db->setQuery($query);
$this->created_by = $this->_db->loadResult();
}
return parent::toXML($mapKeysToText);
}
}
PK /?\z
_ _ table/category.phpnu W+A access = (int) JFactory::getConfig()->get('access');
}
/**
* Method to compute the default name of the asset.
* The default name is in the form table_name.id
* where id is the value of the primary key of the table.
*
* @return string
*
* @since 11.1
*/
protected function _getAssetName()
{
$k = $this->_tbl_key;
return $this->extension . '.category.' . (int) $this->$k;
}
/**
* Method to return the title to use for the asset table.
*
* @return string
*
* @since 11.1
*/
protected function _getAssetTitle()
{
return $this->title;
}
/**
* Get the parent asset id for the record
*
* @param JTable $table A JTable object for the asset parent.
* @param integer $id The id for the asset
*
* @return integer The id of the asset's parent
*
* @since 11.1
*/
protected function _getAssetParentId($table = null, $id = null)
{
// Initialise variables.
$assetId = null;
// This is a category under a category.
if ($this->parent_id > 1)
{
// Build the query to get the asset id for the parent category.
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('asset_id'));
$query->from($this->_db->quoteName('#__categories'));
$query->where($this->_db->quoteName('id') . ' = ' . $this->parent_id);
// Get the asset id from the database.
$this->_db->setQuery($query);
if ($result = $this->_db->loadResult())
{
$assetId = (int) $result;
}
}
// This is a category that needs to parent with the extension.
elseif ($assetId === null)
{
// Build the query to get the asset id for the parent category.
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('id'));
$query->from($this->_db->quoteName('#__assets'));
$query->where($this->_db->quoteName('name') . ' = ' . $this->_db->quote($this->extension));
// Get the asset id from the database.
$this->_db->setQuery($query);
if ($result = $this->_db->loadResult())
{
$assetId = (int) $result;
}
}
// Return the asset id.
if ($assetId)
{
return $assetId;
}
else
{
return parent::_getAssetParentId($table, $id);
}
}
/**
* Override check function
*
* @return boolean
*
* @see JTable::check
* @since 11.1
*/
public function check()
{
// Check for a title.
if (trim($this->title) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_CATEGORY'));
return false;
}
$this->alias = trim($this->alias);
if (empty($this->alias))
{
$this->alias = $this->title;
}
$this->alias = JApplication::stringURLSafe($this->alias);
if (trim(str_replace('-', '', $this->alias)) == '')
{
$this->alias = JFactory::getDate()->format('Y-m-d-H-i-s');
}
return true;
}
/**
* Overloaded bind function.
*
* @param array $array named array
* @param string $ignore An optional array or space separated list of properties
* to ignore while binding.
*
* @return mixed Null if operation was satisfactory, otherwise returns an error
*
* @see JTable::bind
* @since 11.1
*/
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
if (isset($array['metadata']) && is_array($array['metadata']))
{
$registry = new JRegistry;
$registry->loadArray($array['metadata']);
$array['metadata'] = (string) $registry;
}
// Bind the rules.
if (isset($array['rules']) && is_array($array['rules']))
{
$rules = new JAccessRules($array['rules']);
$this->setRules($rules);
}
return parent::bind($array, $ignore);
}
/**
* Overridden JTable::store to set created/modified and user id.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function store($updateNulls = false)
{
$date = JFactory::getDate();
$user = JFactory::getUser();
if ($this->id)
{
// Existing category
$this->modified_time = $date->toSql();
$this->modified_user_id = $user->get('id');
}
else
{
// New category
$this->created_time = $date->toSql();
$this->created_user_id = $user->get('id');
}
// Verify that the alias is unique
$table = JTable::getInstance('Category', 'JTable', array('dbo' => $this->getDbo()));
if ($table->load(array('alias' => $this->alias, 'parent_id' => $this->parent_id, 'extension' => $this->extension))
&& ($table->id != $this->id || $this->id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS'));
return false;
}
return parent::store($updateNulls);
}
}
PK /?\1f^I2 I2 table/user.phpnu W+A group ids
*
* @var array
* @since 11.1
*/
public $groups;
/**
* Constructor
*
* @param JDatabase &$db A database connector object.
*
* @since 11.1
*/
public function __construct(&$db)
{
parent::__construct('#__users', 'id', $db);
// Initialise.
$this->id = 0;
$this->sendEmail = 0;
}
/**
* Method to load a user, user groups, and any other necessary data
* from the database so that it can be bound to the user object.
*
* @param integer $userId An optional user id.
* @param boolean $reset False if row not found or on error
* (internal error state set in that case).
*
* @return boolean True on success, false on failure.
*
* @since 11.1
*/
public function load($userId = null, $reset = true)
{
// Get the id to load.
if ($userId !== null)
{
$this->id = $userId;
}
else
{
$userId = $this->id;
}
// Check for a valid id to load.
if ($userId === null)
{
return false;
}
// Reset the table.
$this->reset();
// Load the user data.
$query = $this->_db->getQuery(true);
$query->select('*');
$query->from($this->_db->quoteName('#__users'));
$query->where($this->_db->quoteName('id') . ' = ' . (int) $userId);
$this->_db->setQuery($query);
$data = (array) $this->_db->loadAssoc();
// Check for an error message.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
if (!count($data))
{
return false;
}
// Bind the data to the table.
$return = $this->bind($data);
if ($return !== false)
{
// Load the user groups.
$query->clear();
$query->select($this->_db->quoteName('g') . '.' . $this->_db->quoteName('id'));
$query->select($this->_db->quoteName('g') . '.' . $this->_db->quoteName('title'));
$query->from($this->_db->quoteName('#__usergroups') . ' AS g');
$query->join('INNER', $this->_db->quoteName('#__user_usergroup_map') . ' AS m ON m.group_id = g.id');
$query->where($this->_db->quoteName('m.user_id') . ' = ' . (int) $userId);
$this->_db->setQuery($query);
// Add the groups to the user data.
$this->groups = $this->_db->loadAssocList('id', 'id');
// Check for an error message.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
}
return $return;
}
/**
* Method to bind the user, user groups, and any other necessary data.
*
* @param array $array The data to bind.
* @param mixed $ignore An array or space separated list of fields to ignore.
*
* @return boolean True on success, false on failure.
*
* @since 11.1
*/
public function bind($array, $ignore = '')
{
if (key_exists('params', $array) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
// Attempt to bind the data.
$return = parent::bind($array, $ignore);
// Load the real group data based on the bound ids.
if ($return && !empty($this->groups))
{
// Set the group ids.
JArrayHelper::toInteger($this->groups);
// Get the titles for the user groups.
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('id'));
$query->select($this->_db->quoteName('title'));
$query->from($this->_db->quoteName('#__usergroups'));
$query->where($this->_db->quoteName('id') . ' = ' . implode(' OR ' . $this->_db->quoteName('id') . ' = ', $this->groups));
$this->_db->setQuery($query);
// Set the titles for the user groups.
$this->groups = $this->_db->loadAssocList('id', 'id');
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
}
return $return;
}
/**
* Validation and filtering
*
* @return boolean True if satisfactory
*
* @since 11.1
*/
public function check()
{
// Validate user information
if (trim($this->name) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_PLEASE_ENTER_YOUR_NAME'));
return false;
}
if (trim($this->username) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_PLEASE_ENTER_A_USER_NAME'));
return false;
}
if (preg_match('#[<>"\'%;()&\\\\]|\\.\\./#', $this->username) || strlen(utf8_decode($this->username)) < 2
|| trim($this->username) != $this->username)
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_VALID_AZ09', 2));
return false;
}
if ((trim($this->email) == "") || !JMailHelper::isEmailAddress($this->email))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_VALID_MAIL'));
return false;
}
// Set the registration timestamp
if ($this->registerDate == null || $this->registerDate == $this->_db->getNullDate())
{
$this->registerDate = JFactory::getDate()->toSql();
}
// check for existing username
$query = $this->_db->getQuery(true);
$query->select($this->_db->quoteName('id'));
$query->from($this->_db->quoteName('#__users'));
$query->where($this->_db->quoteName('username') . ' = ' . $this->_db->quote($this->username));
$query->where($this->_db->quoteName('id') . ' != ' . (int) $this->id);
$this->_db->setQuery($query);
$xid = intval($this->_db->loadResult());
if ($xid && $xid != intval($this->id))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_USERNAME_INUSE'));
return false;
}
// check for existing email
$query->clear();
$query->select($this->_db->quoteName('id'));
$query->from($this->_db->quoteName('#__users'));
$query->where($this->_db->quoteName('email') . ' = ' . $this->_db->quote($this->email));
$query->where($this->_db->quoteName('id') . ' != ' . (int) $this->id);
$this->_db->setQuery($query);
$xid = intval($this->_db->loadResult());
if ($xid && $xid != intval($this->id))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_EMAIL_INUSE'));
return false;
}
// check for root_user != username
$config = JFactory::getConfig();
$rootUser = $config->get('root_user');
if (!is_numeric($rootUser))
{
$query->clear();
$query->select($this->_db->quoteName('id'));
$query->from($this->_db->quoteName('#__users'));
$query->where($this->_db->quoteName('username') . ' = ' . $this->_db->quote($rootUser));
$this->_db->setQuery($query);
$xid = intval($this->_db->loadResult());
if ($rootUser == $this->username && (!$xid || $xid && $xid != intval($this->id))
|| $xid && $xid == intval($this->id) && $rootUser != $this->username)
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_USERNAME_CANNOT_CHANGE'));
return false;
}
}
return true;
}
/**
* Method to store a row in the database from the JTable instance properties.
* If a primary key value is set the row with that primary key value will be
* updated with the instance property values. If no primary key value is set
* a new row will be inserted into the database with the properties from the
* JTable instance.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/store
* @since 11.1
*/
public function store($updateNulls = false)
{
// Get the table key and key value.
$k = $this->_tbl_key;
$key = $this->$k;
// TODO: This is a dumb way to handle the groups.
// Store groups locally so as to not update directly.
$groups = $this->groups;
unset($this->groups);
// Insert or update the object based on presence of a key value.
if ($key)
{
// Already have a table key, update the row.
$return = $this->_db->updateObject($this->_tbl, $this, $this->_tbl_key, $updateNulls);
}
else
{
// Don't have a table key, insert the row.
$return = $this->_db->insertObject($this->_tbl, $this, $this->_tbl_key);
}
// Handle error if it exists.
if (!$return)
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', strtolower(get_class($this)), $this->_db->getErrorMsg()));
return false;
}
// Reset groups to the local object.
$this->groups = $groups;
unset($groups);
// Store the group data if the user data was saved.
if ($return && is_array($this->groups) && count($this->groups))
{
// Delete the old user group maps.
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_db->quoteName('#__user_usergroup_map'));
$query->where($this->_db->quoteName('user_id') . ' = ' . (int) $this->id);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// Set the new user group maps.
$query->clear();
$query->insert($this->_db->quoteName('#__user_usergroup_map'));
$query->columns(array($this->_db->quoteName('user_id'), $this->_db->quoteName('group_id')));
$query->values($this->id . ', ' . implode('), (' . $this->id . ', ', $this->groups));
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
}
return true;
}
/**
* Method to delete a user, user groups, and any other necessary data from the database.
*
* @param integer $userId An optional user id.
*
* @return boolean True on success, false on failure.
*
* @since 11.1
*/
public function delete($userId = null)
{
// Set the primary key to delete.
$k = $this->_tbl_key;
if ($userId)
{
$this->$k = intval($userId);
}
// Delete the user.
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_db->quoteName($this->_tbl));
$query->where($this->_db->quoteName($this->_tbl_key) . ' = ' . (int) $this->$k);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// Delete the user group maps.
$query->clear();
$query->delete();
$query->from($this->_db->quoteName('#__user_usergroup_map'));
$query->where($this->_db->quoteName('user_id') . ' = ' . (int) $this->$k);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
/*
* Clean Up Related Data.
*/
$query->clear();
$query->delete();
$query->from($this->_db->quoteName('#__messages_cfg'));
$query->where($this->_db->quoteName('user_id') . ' = ' . (int) $this->$k);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
$query->clear();
$query->delete();
$query->from($this->_db->quoteName('#__messages'));
$query->where($this->_db->quoteName('user_id_to') . ' = ' . (int) $this->$k);
$this->_db->setQuery($query);
$this->_db->execute();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
return true;
}
/**
* Updates last visit time of user
*
* @param integer $timeStamp The timestamp, defaults to 'now'.
* @param integer $userId The user id (optional).
*
* @return boolean False if an error occurs
*
* @since 11.1
*/
public function setLastVisit($timeStamp = null, $userId = null)
{
// Check for User ID
if (is_null($userId))
{
if (isset($this))
{
$userId = $this->id;
}
else
{
// do not translate
jexit(JText::_('JLIB_DATABASE_ERROR_SETLASTVISIT'));
}
}
// If no timestamp value is passed to function, than current time is used.
$date = JFactory::getDate($timeStamp);
// Update the database row for the user.
$db = $this->_db;
$query = $db->getQuery(true);
$query->update($db->quoteName($this->_tbl));
$query->set($db->quoteName('lastvisitDate') . '=' . $db->quote($date->toSql()));
$query->where($db->quoteName('id') . '=' . (int) $userId);
$db->setQuery($query);
$db->execute();
// Check for a database error.
if ($db->getErrorNum())
{
$this->setError($db->getErrorMsg());
return false;
}
return true;
}
}
PK /?\) ) table/menutype.phpnu W+A menutype = JApplication::stringURLSafe($this->menutype);
if (empty($this->menutype))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_MENUTYPE_EMPTY'));
return false;
}
// Sanitise data.
if (trim($this->title) == '')
{
$this->title = $this->menutype;
}
// Check for unique menutype.
$query = $this->_db->getQuery(true);
$query->select('COUNT(id)');
$query->from($this->_db->quoteName('#__menu_types'));
$query->where($this->_db->quoteName('menutype') . ' = ' . $this->_db->quote($this->menutype));
$query->where($this->_db->quoteName('id') . ' <> ' . (int) $this->id);
$this->_db->setQuery($query);
if ($this->_db->loadResult())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_MENUTYPE_EXISTS', $this->menutype));
return false;
}
return true;
}
/**
* Method to store a row in the database from the JTable instance properties.
* If a primary key value is set the row with that primary key value will be
* updated with the instance property values. If no primary key value is set
* a new row will be inserted into the database with the properties from the
* JTable instance.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/store
* @since 11.1
*/
public function store($updateNulls = false)
{
if ($this->id)
{
// Get the user id
$userId = JFactory::getUser()->id;
// Get the old value of the table
$table = JTable::getInstance('Menutype', 'JTable');
$table->load($this->id);
// Verify that no items are checked out
$query = $this->_db->getQuery(true);
$query->select('id');
$query->from('#__menu');
$query->where('menutype=' . $this->_db->quote($table->menutype));
$query->where('checked_out !=' . (int) $userId);
$query->where('checked_out !=0');
$this->_db->setQuery($query);
if ($this->_db->loadRowList())
{
$this->setError(
JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), JText::_('JLIB_DATABASE_ERROR_MENUTYPE_CHECKOUT'))
);
return false;
}
// Verify that no module for this menu are checked out
$query = $this->_db->getQuery(true);
$query->select('id');
$query->from('#__modules');
$query->where('module=' . $this->_db->quote('mod_menu'));
$query->where('params LIKE ' . $this->_db->quote('%"menutype":' . json_encode($table->menutype) . '%'));
$query->where('checked_out !=' . (int) $userId);
$query->where('checked_out !=0');
$this->_db->setQuery($query);
if ($this->_db->loadRowList())
{
$this->setError(
JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), JText::_('JLIB_DATABASE_ERROR_MENUTYPE_CHECKOUT'))
);
return false;
}
// Update the menu items
$query = $this->_db->getQuery(true);
$query->update('#__menu');
$query->set('menutype=' . $this->_db->quote($this->menutype));
$query->where('menutype=' . $this->_db->quote($table->menutype));
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), $this->_db->getErrorMsg()));
return false;
}
// Update the module items
$query = $this->_db->getQuery(true);
$query->update('#__modules');
$query->set(
'params=REPLACE(params,' . $this->_db->quote('"menutype":' . json_encode($table->menutype)) . ',' .
$this->_db->quote('"menutype":' . json_encode($this->menutype)) . ')'
);
$query->where('module=' . $this->_db->quote('mod_menu'));
$query->where('params LIKE ' . $this->_db->quote('%"menutype":' . json_encode($table->menutype) . '%'));
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), $this->_db->getErrorMsg()));
return false;
}
}
return parent::store($updateNulls);
}
/**
* Method to delete a row from the database table by primary key value.
*
* @param mixed $pk An optional primary key value to delete. If not set the instance property value is used.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTable/delete
* @since 11.1
*/
public function delete($pk = null)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// If no primary key is given, return false.
if ($pk !== null)
{
// Get the user id
$userId = JFactory::getUser()->id;
// Get the old value of the table
$table = JTable::getInstance('Menutype', 'JTable');
$table->load($pk);
// Verify that no items are checked out
$query = $this->_db->getQuery(true);
$query->select('id');
$query->from('#__menu');
$query->where('menutype=' . $this->_db->quote($table->menutype));
$query->where('client_id=0');
$query->where('(checked_out NOT IN (0,' . (int) $userId . ') OR home=1 AND language=' . $this->_db->quote('*') . ')');
$this->_db->setQuery($query);
if ($this->_db->loadRowList())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_DELETE_FAILED', get_class($this), JText::_('JLIB_DATABASE_ERROR_MENUTYPE')));
return false;
}
// Verify that no module for this menu are checked out
$query = $this->_db->getQuery(true);
$query->select('id');
$query->from('#__modules');
$query->where('module=' . $this->_db->quote('mod_menu'));
$query->where('params LIKE ' . $this->_db->quote('%"menutype":' . json_encode($table->menutype) . '%'));
$query->where('checked_out !=' . (int) $userId);
$query->where('checked_out !=0');
$this->_db->setQuery($query);
if ($this->_db->loadRowList())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_DELETE_FAILED', get_class($this), JText::_('JLIB_DATABASE_ERROR_MENUTYPE')));
return false;
}
// Delete the menu items
$query = $this->_db->getQuery(true);
$query->delete();
$query->from('#__menu');
$query->where('menutype=' . $this->_db->quote($table->menutype));
$query->where('client_id=0');
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_DELETE_FAILED', get_class($this), $this->_db->getErrorMsg()));
return false;
}
// Update the module items
$query = $this->_db->getQuery(true);
$query->delete();
$query->from('#__modules');
$query->where('module=' . $this->_db->quote('mod_menu'));
$query->where('params LIKE ' . $this->_db->quote('%"menutype":' . json_encode($table->menutype) . '%'));
$this->_db->setQuery($query);
if (!$this->_db->execute())
{
$this->setError(JText::sprintf('JLIB_DATABASE_ERROR_DELETE_FAILED', get_class($this), $this->_db->getErrorMsg()));
return false;
}
}
return parent::delete($pk);
}
}
PK /?\) table/.htaccessnu W+A
Order allow,deny
Deny from all
PK /?\z6 6 table/language.phpnu W+A title) == '')
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_LANGUAGE_NO_TITLE'));
return false;
}
return true;
}
/**
* Overrides JTable::store to check unique fields.
*
* @param boolean $updateNulls True to update fields even if they are null.
*
* @return boolean True on success.
*
* @since 11.4
*/
public function store($updateNulls = false)
{
// Verify that the sef field is unique
$table = JTable::getInstance('Language', 'JTable');
if ($table->load(array('sef' => $this->sef)) && ($table->lang_id != $this->lang_id || $this->lang_id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_LANGUAGE_UNIQUE_SEF'));
return false;
}
// Verify that the image field is unique
if ($table->load(array('image' => $this->image)) && ($table->lang_id != $this->lang_id || $this->lang_id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_LANGUAGE_UNIQUE_IMAGE'));
return false;
}
// Verify that the language code is unique
if ($table->load(array('lang_code' => $this->lang_code)) && ($table->lang_id != $this->lang_id || $this->lang_id == 0))
{
$this->setError(JText::_('JLIB_DATABASE_ERROR_LANGUAGE_UNIQUE_LANG_CODE'));
return false;
}
return parent::store($updateNulls);
}
}
PK /?\V
index.htmlnu W+A
PK /?\F& database.phpnu W+A getMessage()));
}
else
{
throw new JDatabaseException(JText::sprintf('JLIB_DATABASE_ERROR_CONNECT_DATABASE', $e->getMessage()));
}
}
// Set the new connector to the global instances based on signature.
self::$instances[$signature] = $instance;
}
return self::$instances[$signature];
}
/**
* Splits a string of multiple queries into an array of individual queries.
*
* @param string $sql 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
*/
public static function splitSql($sql)
{
$start = 0;
$open = false;
$char = '';
$end = strlen($sql);
$queries = array();
for ($i = 0; $i < $end; $i++)
{
$current = substr($sql, $i, 1);
if (($current == '"' || $current == '\''))
{
$n = 2;
while (substr($sql, $i - $n + 1, 1) == '\\' && $n < $i)
{
$n++;
}
if ($n % 2 == 0)
{
if ($open)
{
if ($current == $char)
{
$open = false;
$char = '';
}
}
else
{
$open = true;
$char = $current;
}
}
}
if (($current == ';' && !$open) || $i == $end - 1)
{
$queries[] = substr($sql, $start, ($i - $start + 1));
$start = $i + 1;
}
}
return $queries;
}
/**
* Magic method to provide method alias support for quote() and quoteName().
*
* @param string $method The called method.
* @param array $args The array of arguments passed to the method.
*
* @return string The aliased method's return value or null.
*
* @since 11.1
*/
public function __call($method, $args)
{
if (empty($args))
{
return;
}
switch ($method)
{
case 'q':
return $this->quote($args[0], isset($args[1]) ? $args[1] : true);
break;
case 'nq':
case 'qn':
return $this->quoteName($args[0], isset($args[1]) ? $args[1] : null);
break;
}
}
/**
* Constructor.
*
* @param array $options List of options used to configure the connection
*
* @since 11.1
*/
protected function __construct($options)
{
// Initialise object variables.
$this->_database = (isset($options['database'])) ? $options['database'] : '';
$this->tablePrefix = (isset($options['prefix'])) ? $options['prefix'] : 'jos_';
$this->count = 0;
$this->errorNum = 0;
$this->log = array();
$this->quoted = array();
$this->hasQuoted = false;
// Set charactersets (needed for MySQL 4.1.2+).
$this->setUTF();
}
/**
* Adds a field or array of field names to the list that are to be quoted.
*
* @param mixed $quoted Field name or array of names.
*
* @return void
*
* @deprecated 12.1
* @since 11.1
*/
public function addQuoted($quoted)
{
// Deprecation warning.
JLog::add('JDatabase::addQuoted() is deprecated.', JLog::WARNING, 'deprecated');
if (is_string($quoted))
{
$this->quoted[] = $quoted;
}
else
{
$this->quoted = array_merge($this->quoted, (array) $quoted);
}
$this->hasQuoted = true;
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
abstract public function connected();
/**
* Drops a table from the database.
*
* @param string $table The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public abstract function dropTable($table, $ifExists = true);
/**
* 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 11.1
*/
abstract public function escape($text, $extra = false);
/**
* 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 11.1
*/
abstract protected function fetchArray($cursor = null);
/**
* 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 11.1
*/
abstract protected function fetchAssoc($cursor = null);
/**
* 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 11.1
*/
abstract protected function fetchObject($cursor = null, $class = 'stdClass');
/**
* 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 11.1
*/
abstract protected function freeResult($cursor = null);
/**
* Get the number of affected rows for the previous executed SQL statement.
*
* @return integer The number of affected rows.
*
* @since 11.1
*/
abstract public function getAffectedRows();
/**
* 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 11.1
*/
abstract public function getCollation();
/**
* Method that provides access to the underlying database connection. Useful for when you need to call a
* proprietary method such as postgresql's lo_* methods.
*
* @return resource The underlying database connection resource.
*
* @since 11.1
*/
public function getConnection()
{
return $this->connection;
}
/**
* Get the total number of SQL statements executed by the database driver.
*
* @return integer
*
* @since 11.1
*/
public function getCount()
{
return $this->count;
}
/**
* Gets the name of the database used by this conneciton.
*
* @return string
*
* @since 11.4
*/
protected function getDatabase()
{
return $this->_database;
}
/**
* Returns a PHP date() function compliant date format for the database driver.
*
* @return string The format string.
*
* @since 11.1
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
/**
* Get the row limit for the current SQL statement.
*
* @return integer The affected row limit for the current SQL statement.
*
* @since 2.5.17 (CMS Only)
* @deprecated 3.0 Required for SQLSRV support for 2.5 only
*/
public function getLimit()
{
return $this->limit;
}
/**
* Get the database driver SQL statement log.
*
* @return array SQL statements executed by the database driver.
*
* @since 11.1
*/
public function getLog()
{
return $this->log;
}
/**
* Get the minimum supported database version.
*
* @return string The minimum version number for the database driver.
*
* @since 12.1
*/
public function getMinimum()
{
return $this->dbMinimum;
}
/**
* Get the null or zero representation of a timestamp for the database driver.
*
* @return string Null or zero representation of a timestamp.
*
* @since 11.1
*/
public function getNullDate()
{
return $this->nullDate;
}
/**
* 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 11.1
*/
abstract public function getNumRows($cursor = null);
/**
* Get the row offset for the current SQL statement.
*
* @return integer The affected row offset to apply for the current SQL statement.
*
* @since 2.5.17 (CMS Only)
* @deprecated 3.0 Required for SQLSRV support for 2.5 only
*/
public function getOffset()
{
return $this->offset;
}
/**
* Get the common table prefix for the database driver.
*
* @return string The common database table prefix.
*
* @since 11.1
*/
public function getPrefix()
{
return $this->tablePrefix;
}
/**
* Get the current query object or a new JDatabaseQuery object.
*
* @param boolean $new False to return the current query object, True to return a new JDatabaseQuery object.
*
* @return JDatabaseQuery The current query object or a new object extending the JDatabaseQuery class.
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function getQuery($new = false);
/**
* Retrieves field information about the given tables.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True (default) to only return field types.
*
* @return array An array of fields by table.
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function getTableColumns($table, $typeOnly = true);
/**
* 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 11.1
* @throws JDatabaseException
*/
abstract public function getTableCreate($tables);
/**
* Retrieves field information about the given tables.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array An array of keys for the table(s).
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function getTableKeys($tables);
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function getTableList();
/**
* Determine whether or not the database engine supports UTF-8 character encoding.
*
* @return boolean True if the database engine supports UTF-8 character encoding.
*
* @since 11.1
*/
public function getUTFSupport()
{
return $this->utf;
}
/**
* Get the version of the database connector
*
* @return string The database connector version.
*
* @since 11.1
*/
abstract public function getVersion();
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
*
* @deprecated 12.1
*/
abstract public function hasUTF();
/**
* 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 11.1
*/
abstract public function insertid();
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert into.
* @param object &$object A reference to an object whose public properties match the table fields.
* @param string $key The name of the primary key. If provided the object property is updated.
*
* @return boolean True on success.
*
* @since 11.1
* @throws JDatabaseException
*/
public function insertObject($table, &$object, $key = null)
{
// Initialise variables.
$fields = array();
$values = array();
// Create the base insert statement.
$statement = 'INSERT INTO ' . $this->quoteName($table) . ' (%s) VALUES (%s)';
// Iterate over the object variables to build the query fields and values.
foreach (get_object_vars($object) as $k => $v)
{
// Only process non-null scalars.
if (is_array($v) or is_object($v) or $v === null)
{
continue;
}
// Ignore any internal fields.
if ($k[0] == '_')
{
continue;
}
// Prepare and sanitize the fields and values for the database query.
$fields[] = $this->quoteName($k);
$values[] = $this->quote($v);
}
// Set the query and execute the insert.
$this->setQuery(sprintf($statement, implode(',', $fields), implode(',', $values)));
if (!$this->execute())
{
return false;
}
// Update the primary key if it exists.
$id = $this->insertid();
if ($key && $id)
{
$object->$key = $id;
}
return true;
}
/**
* Method to check whether the installed database version is supported by the database driver
*
* @return boolean True if the database version is supported
*
* @since 12.1
*/
public function isMinimumVersion()
{
return version_compare($this->getVersion(), $this->dbMinimum) >= 0;
}
/**
* Method to get the first row of the result set from the database query as an associative array
* of ['field_name' => 'row_value'].
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadAssoc()
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an associative array.
if ($array = $this->fetchAssoc($cursor))
{
$ret = $array;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query where each row is an associative array
* of ['field_name' => 'row_value']. The array of rows can optionally be keyed by a field name, but defaults to
* a sequential numeric array.
*
* NOTE: Chosing to key the result array by a non-unique field name can result in unwanted
* behavior and should be avoided.
*
* @param string $key The name of a field on which to key the result array.
* @param string $column An optional column name. Instead of the whole row, only this column value will be in
* the result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadAssocList($key = null, $column = null)
{
// Initialise variables.
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get all of the rows from the result set.
while ($row = $this->fetchAssoc($cursor))
{
$value = ($column) ? (isset($row[$column]) ? $row[$column] : $row) : $row;
if ($key)
{
$array[$row[$key]] = $value;
}
else
{
$array[] = $value;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get an array of values from the $offset field in each row of the result set from
* the database query.
*
* @param integer $offset The row offset to use to build the result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadColumn($offset = 0)
{
// Initialise variables.
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get all of the rows from the result set as arrays.
while ($row = $this->fetchArray($cursor))
{
$array[] = $row[$offset];
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get the next row in the result set from the database query as an object.
*
* @param string $class The class name to use for the returned row object.
*
* @return mixed The result of the query as an array, false if there are no more rows.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadNextObject($class = 'stdClass')
{
static $cursor;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return $this->errorNum ? null : false;
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchObject($cursor, $class))
{
return $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
$cursor = null;
return false;
}
/**
* Method to get the next row in the result set from the database query as an array.
*
* @return mixed The result of the query as an array, false if there are no more rows.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadNextRow()
{
static $cursor;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return $this->errorNum ? null : false;
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchArray($cursor))
{
return $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
$cursor = null;
return false;
}
/**
* Method to get the first row of the result set from the database query as an object.
*
* @param string $class The class name to use for the returned row object.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadObject($class = 'stdClass')
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an object of type $class.
if ($object = $this->fetchObject($cursor, $class))
{
$ret = $object;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query where each row is an object. The array
* of objects can optionally be keyed by a field name, but defaults to a sequential numeric array.
*
* NOTE: Choosing to key the result array by a non-unique field name can result in unwanted
* behavior and should be avoided.
*
* @param string $key The name of a field on which to key the result array.
* @param string $class The class name to use for the returned row objects.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadObjectList($key = '', $class = 'stdClass')
{
// Initialise variables.
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get all of the rows from the result set as objects of type $class.
while ($row = $this->fetchObject($cursor, $class))
{
if ($key)
{
$array[$row->$key] = $row;
}
else
{
$array[] = $row;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get the first field of the first row of the result set from the database query.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadResult()
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an array.
if ($row = $this->fetchArray($cursor))
{
$ret = $row[0];
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get the first row of the result set from the database query as an array. Columns are indexed
* numerically so the first column in the result set would be accessible via $row[0], etc.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadRow()
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an array.
if ($row = $this->fetchArray($cursor))
{
$ret = $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query where each row is an array. The array
* of objects can optionally be keyed by a field offset, but defaults to a sequential numeric array.
*
* NOTE: Choosing to key the result array by a non-unique field can result in unwanted
* behavior and should be avoided.
*
* @param string $key The name of a field on which to key the result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadRowList($key = null)
{
// Initialise variables.
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get all of the rows from the result set as arrays.
while ($row = $this->fetchArray($cursor))
{
if ($key !== null)
{
$array[$row[$key]] = $row;
}
else
{
$array[] = $row;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to unlock.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public abstract function lockTable($tableName);
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 11.1
* @throws JDatabaseException
*/
public function query()
{
return $this->execute();
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 12.1
* @throws JDatabaseException
*/
abstract public function execute();
/**
* Method to quote and optionally escape a string to database requirements for insertion into the database.
*
* @param string $text The string to quote.
* @param boolean $escape True (default) to escape the string, false to leave it unchanged.
*
* @return string The quoted input string.
*
* @since 11.1
*/
public function quote($text, $escape = true)
{
return '\'' . ($escape ? $this->escape($text) : $text) . '\'';
}
/**
* Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
* risks and reserved word conflicts.
*
* @param mixed $name The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
* Each type supports dot-notation name.
* @param mixed $as The AS query part associated to $name. It can be string or array, in latter case it has to be
* same length of $name; if is null there will not be any AS part for string or array element.
*
* @return mixed The quote wrapped name, same type of $name.
*
* @since 11.1
*/
public function quoteName($name, $as = null)
{
if (is_string($name))
{
$quotedName = $this->quoteNameStr(explode('.', $name));
$quotedAs = '';
if (!is_null($as))
{
settype($as, 'array');
$quotedAs .= ' AS ' . $this->quoteNameStr($as);
}
return $quotedName . $quotedAs;
}
else
{
$fin = array();
if (is_null($as))
{
foreach ($name as $str)
{
$fin[] = $this->quoteName($str);
}
}
elseif (is_array($name) && (count($name) == count($as)))
{
for ($i = 0; $i < count($name); $i++)
{
$fin[] = $this->quoteName($name[$i], $as[$i]);
}
}
return $fin;
}
}
/**
* Quote strings coming from quoteName call.
*
* @param array $strArr Array of strings coming from quoteName dot-explosion.
*
* @return string Dot-imploded string of quoted parts.
*
* @since 11.3
*/
protected function quoteNameStr($strArr)
{
$parts = array();
$q = $this->nameQuote;
foreach ($strArr as $part)
{
if (is_null($part))
{
continue;
}
if (strlen($q) == 1)
{
$parts[] = $q . $part . $q;
}
else
{
$parts[] = $q{0} . $part . $q{1};
}
}
return implode('.', $parts);
}
/**
* This function replaces a string identifier $prefix with the string held is the
* tablePrefix class variable.
*
* @param string $sql The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 11.1
*/
public function replacePrefix($sql, $prefix = '#__')
{
// Initialize variables.
$escaped = false;
$startPos = 0;
$quoteChar = '';
$literal = '';
$sql = trim($sql);
$n = strlen($sql);
while ($startPos < $n)
{
$ip = strpos($sql, $prefix, $startPos);
if ($ip === false)
{
break;
}
$j = strpos($sql, "'", $startPos);
$k = strpos($sql, '"', $startPos);
if (($k !== false) && (($k < $j) || ($j === false)))
{
$quoteChar = '"';
$j = $k;
}
else
{
$quoteChar = "'";
}
if ($j === false)
{
$j = $n;
}
$literal .= str_replace($prefix, $this->tablePrefix, substr($sql, $startPos, $j - $startPos));
$startPos = $j;
$j = $startPos + 1;
if ($j >= $n)
{
break;
}
// quote comes first, find end of quote
while (true)
{
$k = strpos($sql, $quoteChar, $j);
$escaped = false;
if ($k === false)
{
break;
}
$l = $k - 1;
while ($l >= 0 && $sql{$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($sql, $startPos, $k - $startPos + 1);
$startPos = $k + 1;
}
if ($startPos < $n)
{
$literal .= substr($sql, $startPos, $n - $startPos);
}
return $literal;
}
/**
* 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 Table prefix
* @param string $prefix For the table - used to rename constraints in non-mysql databases
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public abstract function renameTable($oldTable, $newTable, $backup = null, $prefix = null);
/**
* 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 11.1
* @throws JDatabaseException
*/
abstract public function select($database);
/**
* Sets the database debugging state for the driver.
*
* @param boolean $level True to enable debugging.
*
* @return boolean The old debugging level.
*
* @since 11.1
*/
public function setDebug($level)
{
$previous = $this->debug;
$this->debug = (bool) $level;
return $previous;
}
/**
* Sets the SQL statement string for later execution.
*
* @param mixed $query The SQL statement to set either as a JDatabaseQuery object or a string.
* @param integer $offset The affected row offset to set.
* @param integer $limit The maximum affected rows to set.
*
* @return JDatabase This object to support method chaining.
*
* @since 11.1
*/
public function setQuery($query, $offset = 0, $limit = 0)
{
$this->sql = $query;
$this->limit = (int) max(0, $limit);
$this->offset = (int) max(0, $offset);
return $this;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
abstract public function setUTF();
/**
* Method to commit a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function transactionCommit();
/**
* Method to roll back a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function transactionRollback();
/**
* Method to initialize a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
abstract public function transactionStart();
/**
* Method to truncate a table.
*
* @param string $table The table to truncate
*
* @return void
*
* @since 11.3
* @throws JDatabaseException
*/
public function truncateTable($table)
{
$this->setQuery('TRUNCATE TABLE ' . $this->quoteName($table));
$this->execute();
}
/**
* Updates a row in a table based on an object's properties.
*
* @param string $table The name of the database table to update.
* @param object &$object A reference to an object whose public properties match the table fields.
* @param string $key The name of the primary key.
* @param boolean $nulls True to update null fields or false to ignore them.
*
* @return boolean True on success.
*
* @since 11.1
* @throws JDatabaseException
*/
public function updateObject($table, &$object, $key, $nulls = false)
{
// Initialise variables.
$fields = array();
$where = '';
// Create the base update statement.
$statement = 'UPDATE ' . $this->quoteName($table) . ' SET %s WHERE %s';
// Iterate over the object variables to build the query fields/value pairs.
foreach (get_object_vars($object) as $k => $v)
{
// Only process scalars that are not internal fields.
if (is_array($v) or is_object($v) or $k[0] == '_')
{
continue;
}
// Set the primary key to the WHERE clause instead of a field to update.
if ($k == $key)
{
$where = $this->quoteName($k) . '=' . $this->quote($v);
continue;
}
// Prepare and sanitize the fields and values for the database query.
if ($v === null)
{
// If the value is null and we want to update nulls then set it.
if ($nulls)
{
$val = 'NULL';
}
// If the value is null and we do not want to update nulls then ignore this field.
else
{
continue;
}
}
// The field is not null so we prep it for update.
else
{
$val = $this->quote($v);
}
// Add the field to be updated.
$fields[] = $this->quoteName($k) . '=' . $val;
}
// We don't have any fields to update.
if (empty($fields))
{
return true;
}
// Set the query and execute the update.
$this->setQuery(sprintf($statement, implode(",", $fields), $where));
return $this->execute();
}
/**
* Unlocks tables in the database.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public abstract function unlockTables();
//
// Deprecated methods.
//
/**
* Sets the debug level on or off
*
* @param integer $level 0 to disable debugging and 1 to enable it.
*
* @return void
*
* @deprecated 12.1
* @since 11.1
*/
public function debug($level)
{
// Deprecation warning.
JLog::add('JDatabase::debug() is deprecated, use JDatabase::setDebug() instead.', JLog::NOTICE, 'deprecated');
$this->setDebug(($level == 0) ? false : true);
}
/**
* Diagnostic method to return explain information for a query.
*
* @return string The explain output.
*
* @deprecated 12.1
* @since 11.1
*/
abstract public function explain();
/**
* 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 12.1
* @since 11.1
*/
public function getErrorMsg($escaped = false)
{
// Deprecation warning.
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 12.1
*/
public function getErrorNum()
{
// Deprecation warning.
JLog::add('JDatabase::getErrorNum() is deprecated, use exception handling instead.', JLog::WARNING, 'deprecated');
return $this->errorNum;
}
/**
* 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 11.1
* @deprecated 12.1
*/
public function getEscaped($text, $extra = false)
{
// Deprecation warning.
JLog::add('JDatabase::getEscaped() is deprecated. Use JDatabase::escape().', JLog::WARNING, 'deprecated');
return $this->escape($text, $extra);
}
/**
* Retrieves field information about the given tables.
*
* @param mixed $tables A table name or a list of table names.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields by table.
*
* @since 11.1
* @throws JDatabaseException
* @deprecated 12.1
*/
public function getTableFields($tables, $typeOnly = true)
{
// Deprecation warning.
JLog::add('JDatabase::getTableFields() is deprecated. Use JDatabase::getTableColumns().', JLog::WARNING, 'deprecated');
$results = array();
settype($tables, 'array');
foreach ($tables as $table)
{
$results[$table] = $this->getTableColumns($table, $typeOnly);
}
return $results;
}
/**
* Get the total number of SQL statements executed by the database driver.
*
* @return integer
*
* @since 11.1
* @deprecated 12.1
*/
public function getTicker()
{
// Deprecation warning.
JLog::add('JDatabase::getTicker() is deprecated, use JDatabase::getCount() instead.', JLog::NOTICE, 'deprecated');
return $this->count;
}
/**
* Checks if field name needs to be quoted.
*
* @param string $field The field name to be checked.
*
* @return bool
*
* @deprecated 12.1
* @since 11.1
*/
public function isQuoted($field)
{
// Deprecation warning.
JLog::add('JDatabase::isQuoted() is deprecated.', JLog::WARNING, 'deprecated');
if ($this->hasQuoted)
{
return in_array($field, $this->quoted);
}
else
{
return true;
}
}
/**
* Method to get an array of values from the $offset field in each row of the result set from
* the database query.
*
* @param integer $offset The row offset to use to build the result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
* @deprecated 12.1
*/
public function loadResultArray($offset = 0)
{
// Deprecation warning.
JLog::add('JDatabase::loadResultArray() is deprecated. Use JDatabase::loadColumn().', JLog::WARNING, 'deprecated');
return $this->loadColumn($offset);
}
/**
* Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
* risks and reserved word conflicts.
*
* @param string $name The identifier name to wrap in quotes.
*
* @return string The quote wrapped name.
*
* @since 11.1
* @deprecated 12.1
*/
public function nameQuote($name)
{
// Deprecation warning.
JLog::add('JDatabase::nameQuote() is deprecated. Use JDatabase::quoteName().', JLog::WARNING, 'deprecated');
return $this->quoteName($name);
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @deprecated 12.1
* @since 11.1
*/
abstract public function queryBatch($abortOnError = true, $transactionSafe = false);
/**
* 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.
*
* @deprecated 12.1
* @since 11.1
*/
public function stderr($showSQL = false)
{
// Deprecation warning.
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 ? "
SQL = $this->sql
" : '');
}
else
{
return JText::_('JLIB_DATABASE_FUNCTION_NOERROR');
}
}
}
PK /?\6 tablenested.phpnu W+A _debug = intval($level);
}
/**
* Method to get an array of nodes from a given node to its root.
*
* @param integer $pk Primary key of the node for which to get the path.
* @param boolean $diagnostic Only select diagnostic data for the nested sets.
*
* @return mixed Boolean false on failure or array of node objects on success.
*
* @link http://docs.joomla.org/JTableNested/getPath
* @since 11.1
*/
public function getPath($pk = null, $diagnostic = false)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Get the path from the node to the root.
$query = $this->_db->getQuery(true);
$select = ($diagnostic) ? 'p.' . $k . ', p.parent_id, p.level, p.lft, p.rgt' : 'p.*';
$query->select($select);
$query->from($this->_tbl . ' AS n, ' . $this->_tbl . ' AS p');
$query->where('n.lft BETWEEN p.lft AND p.rgt');
$query->where('n.' . $k . ' = ' . (int) $pk);
$query->order('p.lft');
$this->_db->setQuery($query);
$path = $this->_db->loadObjectList();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GET_PATH_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
return $path;
}
/**
* Method to get a node and all its child nodes.
*
* @param integer $pk Primary key of the node for which to get the tree.
* @param boolean $diagnostic Only select diagnostic data for the nested sets.
*
* @return mixed Boolean false on failure or array of node objects on success.
*
* @link http://docs.joomla.org/JTableNested/getTree
* @since 11.1
*/
public function getTree($pk = null, $diagnostic = false)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Get the node and children as a tree.
$query = $this->_db->getQuery(true);
$select = ($diagnostic) ? 'n.' . $k . ', n.parent_id, n.level, n.lft, n.rgt' : 'n.*';
$query->select($select);
$query->from($this->_tbl . ' AS n, ' . $this->_tbl . ' AS p');
$query->where('n.lft BETWEEN p.lft AND p.rgt');
$query->where('p.' . $k . ' = ' . (int) $pk);
$query->order('n.lft');
$this->_db->setQuery($query);
$tree = $this->_db->loadObjectList();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GET_TREE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
return $tree;
}
/**
* Method to determine if a node is a leaf node in the tree (has no children).
*
* @param integer $pk Primary key of the node to check.
*
* @return boolean True if a leaf node.
*
* @link http://docs.joomla.org/JTableNested/isLeaf
* @since 11.1
*/
public function isLeaf($pk = null)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Get the node by primary key.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
return false;
}
// The node is a leaf node.
return (($node->rgt - $node->lft) == 1);
}
/**
* Method to set the location of a node in the tree object. This method does not
* save the new location to the database, but will set it in the object so
* that when the node is stored it will be stored in the new location.
*
* @param integer $referenceId The primary key of the node to reference new location by.
* @param string $position Location type string. ['before', 'after', 'first-child', 'last-child']
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/setLocation
* @since 11.1
*/
public function setLocation($referenceId, $position = 'after')
{
// Make sure the location is valid.
if (($position != 'before') && ($position != 'after') && ($position != 'first-child') && ($position != 'last-child'))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_INVALID_LOCATION', get_class($this)));
$this->setError($e);
return false;
}
// Set the location properties.
$this->_location = $position;
$this->_location_id = $referenceId;
return true;
}
/**
* Method to move a row in the ordering sequence of a group of rows defined by an SQL WHERE clause.
* Negative numbers move the row up in the sequence and positive numbers move it down.
*
* @param integer $delta The direction and magnitude to move the row in the ordering sequence.
* @param string $where WHERE clause to use for limiting the selection of rows to compact the
* ordering values.
*
* @return mixed Boolean true on success.
*
* @link http://docs.joomla.org/JTable/move
* @since 11.1
*/
public function move($delta, $where = '')
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = $this->$k;
$query = $this->_db->getQuery(true);
$query->select($k);
$query->from($this->_tbl);
$query->where('parent_id = ' . $this->parent_id);
if ($where)
{
$query->where($where);
}
$position = 'after';
if ($delta > 0)
{
$query->where('rgt > ' . $this->rgt);
$query->order('rgt ASC');
$position = 'after';
}
else
{
$query->where('lft < ' . $this->lft);
$query->order('lft DESC');
$position = 'before';
}
$this->_db->setQuery($query);
$referenceId = $this->_db->loadResult();
if ($referenceId)
{
return $this->moveByReference($referenceId, $position, $pk);
}
else
{
return false;
}
}
/**
* Method to move a node and its children to a new location in the tree.
*
* @param integer $referenceId The primary key of the node to reference new location by.
* @param string $position Location type string. ['before', 'after', 'first-child', 'last-child']
* @param integer $pk The primary key of the node to move.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/moveByReference
* @since 11.1
*/
public function moveByReference($referenceId, $position = 'after', $pk = null)
{
if ($this->_debug)
{
echo "\nMoving ReferenceId:$referenceId, Position:$position, PK:$pk";
}
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Get the node by id.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
return false;
}
// Get the ids of child nodes.
$query = $this->_db->getQuery(true);
$query->select($k);
$query->from($this->_tbl);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
$children = $this->_db->loadColumn();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_MOVE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
if ($this->_debug)
{
$this->_logtable(false);
}
// Cannot move the node to be a child of itself.
if (in_array($referenceId, $children))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_INVALID_NODE_RECURSION', get_class($this)));
$this->setError($e);
return false;
}
// Lock the table for writing.
if (!$this->_lock())
{
return false;
}
/*
* Move the sub-tree out of the nested sets by negating its left and right values.
*/
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft * (-1), rgt = rgt * (-1)');
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
/*
* Close the hole in the tree that was opened by removing the sub-tree from the nested sets.
*/
// Compress the left values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - ' . (int) $node->width);
$query->where('lft > ' . (int) $node->rgt);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
// Compress the right values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = rgt - ' . (int) $node->width);
$query->where('rgt > ' . (int) $node->rgt);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
// We are moving the tree relative to a reference node.
if ($referenceId)
{
// Get the reference node by primary key.
if (!$reference = $this->_getNode($referenceId))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Get the reposition data for shifting the tree and re-inserting the node.
if (!$repositionData = $this->_getTreeRepositionData($reference, $node->width, $position))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
}
// We are moving the tree to be the last child of the root node
else
{
// Get the last root node as the reference node.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', parent_id, level, lft, rgt');
$query->from($this->_tbl);
$query->where('parent_id = 0');
$query->order('lft DESC');
$this->_db->setQuery($query, 0, 1);
$reference = $this->_db->loadObject();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_MOVE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
if ($this->_debug)
{
$this->_logtable(false);
}
// Get the reposition data for re-inserting the node after the found root.
if (!$repositionData = $this->_getTreeRepositionData($reference, $node->width, 'last-child'))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
}
/*
* Create space in the nested sets at the new location for the moved sub-tree.
*/
// Shift left values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft + ' . (int) $node->width);
$query->where($repositionData->left_where);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
// Shift right values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = rgt + ' . (int) $node->width);
$query->where($repositionData->right_where);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
/*
* Calculate the offset between where the node used to be in the tree and
* where it needs to be in the tree for left ids (also works for right ids).
*/
$offset = $repositionData->new_lft - $node->lft;
$levelOffset = $repositionData->new_level - $node->level;
// Move the nodes back into position in the tree using the calculated offsets.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = ' . (int) $offset . ' - rgt');
$query->set('lft = ' . (int) $offset . ' - lft');
$query->set('level = level + ' . (int) $levelOffset);
$query->where('lft < 0');
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
// Set the correct parent id for the moved node if required.
if ($node->parent_id != $repositionData->new_parent_id)
{
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
// Update the title and alias fields if they exist for the table.
if (property_exists($this, 'title') && $this->title !== null)
{
$query->set('title = ' . $this->_db->Quote($this->title));
}
if (property_exists($this, 'alias') && $this->alias !== null)
{
$query->set('alias = ' . $this->_db->Quote($this->alias));
}
$query->set('parent_id = ' . (int) $repositionData->new_parent_id);
$query->where($this->_tbl_key . ' = ' . (int) $node->$k);
$this->_db->setQuery($query);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_MOVE_FAILED');
}
// Unlock the table for writing.
$this->_unlock();
// Set the object values.
$this->parent_id = $repositionData->new_parent_id;
$this->level = $repositionData->new_level;
$this->lft = $repositionData->new_lft;
$this->rgt = $repositionData->new_rgt;
return true;
}
/**
* Method to delete a node and, optionally, its child nodes from the table.
*
* @param integer $pk The primary key of the node to delete.
* @param boolean $children True to delete child nodes, false to move them up a level.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/delete
* @since 11.1
*/
public function delete($pk = null, $children = true)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Lock the table for writing.
if (!$this->_lock())
{
// Error message set in lock method.
return false;
}
// If tracking assets, remove the asset first.
if ($this->_trackAssets)
{
$name = $this->_getAssetName();
$asset = JTable::getInstance('Asset');
// Lock the table for writing.
if (!$asset->_lock())
{
// Error message set in lock method.
return false;
}
if ($asset->loadByName($name))
{
// Delete the node in assets table.
if (!$asset->delete(null, $children))
{
$this->setError($asset->getError());
$asset->_unlock();
return false;
}
$asset->_unlock();
}
else
{
$this->setError($asset->getError());
$asset->_unlock();
return false;
}
}
// Get the node by id.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Should we delete all children along with the node?
if ($children)
{
// Delete the node and all of its children.
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_tbl);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Compress the left values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - ' . (int) $node->width);
$query->where('lft > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Compress the right values.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = rgt - ' . (int) $node->width);
$query->where('rgt > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
}
// Leave the children and move them up a level.
else
{
// Delete the node.
$query = $this->_db->getQuery(true);
$query->delete();
$query->from($this->_tbl);
$query->where('lft = ' . (int) $node->lft);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all node's children up a level.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - 1');
$query->set('rgt = rgt - 1');
$query->set('level = level - 1');
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Adjust all the parent values for direct children of the deleted node.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('parent_id = ' . (int) $node->parent_id);
$query->where('parent_id = ' . (int) $node->$k);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all of the left values that are right of the node.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - 2');
$query->where('lft > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
// Shift all of the right values that are right of the node.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = rgt - 2');
$query->where('rgt > ' . (int) $node->rgt);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_DELETE_FAILED');
}
// Unlock the table for writing.
$this->_unlock();
return true;
}
/**
* Asset that the nested set data is valid.
*
* @return boolean True if the instance is sane and able to be stored in the database.
*
* @link http://docs.joomla.org/JTable/check
* @since 11.1
*/
public function check()
{
$this->parent_id = (int) $this->parent_id;
if ($this->parent_id > 0)
{
$query = $this->_db->getQuery(true);
$query->select('COUNT(' . $this->_tbl_key . ')');
$query->from($this->_tbl);
$query->where($this->_tbl_key . ' = ' . $this->parent_id);
$this->_db->setQuery($query);
if ($this->_db->loadResult())
{
return true;
}
else
{
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CHECK_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
}
else
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_INVALID_PARENT_ID', get_class($this)));
$this->setError($e);
}
}
}
else
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_INVALID_PARENT_ID', get_class($this)));
$this->setError($e);
}
return false;
}
/**
* Method to store a node in the database table.
*
* @param boolean $updateNulls True to update null values as well.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/store
* @since 11.1
*/
public function store($updateNulls = false)
{
// Initialise variables.
$k = $this->_tbl_key;
if ($this->_debug)
{
echo "\n" . get_class($this) . "::store\n";
$this->_logtable(true, false);
}
/*
* If the primary key is empty, then we assume we are inserting a new node into the
* tree. From this point we would need to determine where in the tree to insert it.
*/
if (empty($this->$k))
{
/*
* We are inserting a node somewhere in the tree with a known reference
* node. We have to make room for the new node and set the left and right
* values before we insert the row.
*/
if ($this->_location_id >= 0)
{
// Lock the table for writing.
if (!$this->_lock())
{
// Error message set in lock method.
return false;
}
// We are inserting a node relative to the last root node.
if ($this->_location_id == 0)
{
// Get the last root node as the reference node.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', parent_id, level, lft, rgt');
$query->from($this->_tbl);
$query->where('parent_id = 0');
$query->order('lft DESC');
$this->_db->setQuery($query, 0, 1);
$reference = $this->_db->loadObject();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
if ($this->_debug)
{
$this->_logtable(false);
}
}
// We have a real node set as a location reference.
else
{
// Get the reference node by primary key.
if (!$reference = $this->_getNode($this->_location_id))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
}
// Get the reposition data for shifting the tree and re-inserting the node.
if (!($repositionData = $this->_getTreeRepositionData($reference, 2, $this->_location)))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Create space in the tree at the new location for the new node in left ids.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft + 2');
$query->where($repositionData->left_where);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_STORE_FAILED');
// Create space in the tree at the new location for the new node in right ids.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('rgt = rgt + 2');
$query->where($repositionData->right_where);
$this->_runQuery($query, 'JLIB_DATABASE_ERROR_STORE_FAILED');
// Set the object values.
$this->parent_id = $repositionData->new_parent_id;
$this->level = $repositionData->new_level;
$this->lft = $repositionData->new_lft;
$this->rgt = $repositionData->new_rgt;
}
else
{
// Negative parent ids are invalid
$e = new JException(JText::_('JLIB_DATABASE_ERROR_INVALID_PARENT_ID'));
$this->setError($e);
return false;
}
}
/*
* If we have a given primary key then we assume we are simply updating this
* node in the tree. We should assess whether or not we are moving the node
* or just updating its data fields.
*/
else
{
// If the location has been set, move the node to its new location.
if ($this->_location_id > 0)
{
if (!$this->moveByReference($this->_location_id, $this->_location, $this->$k))
{
// Error message set in move method.
return false;
}
}
// Lock the table for writing.
if (!$this->_lock())
{
// Error message set in lock method.
return false;
}
}
// Store the row to the database.
if (!parent::store($updateNulls))
{
$this->_unlock();
return false;
}
if ($this->_debug)
{
$this->_logtable();
}
// Unlock the table for writing.
$this->_unlock();
return true;
}
/**
* Method to set the publishing state for a node or list of nodes in the database
* table. The method respects rows checked out by other users and will attempt
* to checkin rows that it can after adjustments are made. The method will not
* allow you to set a publishing state higher than any ancestor node and will
* not allow you to set a publishing state on a node with a checked out child.
*
* @param mixed $pks An optional array of primary key values to update. If not
* set the instance property value is used.
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* @param integer $userId The user id of the user performing the operation.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/publish
* @since 11.1
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
// Initialise variables.
$k = $this->_tbl_key;
// Sanitize input.
JArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If $state > 1, then we allow state changes even if an ancestor has lower state
// (for example, can change a child state to Archived (2) if an ancestor is Published (1)
$compareState = ($state > 1) ? 1 : $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = explode(',', $this->$k);
}
// Nothing to set publishing state on, return false.
else
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED', get_class($this)));
$this->setError($e);
return false;
}
}
// Determine if there is checkout support for the table.
$checkoutSupport = (property_exists($this, 'checked_out') || property_exists($this, 'checked_out_time'));
// Iterate over the primary keys to execute the publish action if possible.
foreach ($pks as $pk)
{
// Get the node by primary key.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
return false;
}
// If the table has checkout support, verify no children are checked out.
if ($checkoutSupport)
{
// Ensure that children are not checked out.
$query = $this->_db->getQuery(true);
$query->select('COUNT(' . $k . ')');
$query->from($this->_tbl);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$query->where('(checked_out <> 0 AND checked_out <> ' . (int) $userId . ')');
$this->_db->setQuery($query);
// Check for checked out children.
if ($this->_db->loadResult())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_CHILD_ROWS_CHECKED_OUT', get_class($this)));
$this->setError($e);
return false;
}
}
// If any parent nodes have lower published state values, we cannot continue.
if ($node->parent_id)
{
// Get any ancestor nodes that have a lower publishing state.
$query = $this->_db->getQuery(true)->select('n.' . $k)->from($this->_db->quoteName($this->_tbl) . ' AS n')
->where('n.lft < ' . (int) $node->lft)->where('n.rgt > ' . (int) $node->rgt)->where('n.parent_id > 0')
->where('n.published < ' . (int) $compareState);
// Just fetch one row (one is one too many).
$this->_db->setQuery($query, 0, 1);
$rows = $this->_db->loadColumn();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_PUBLISH_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
if (!empty($rows))
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_ANCESTOR_NODES_LOWER_STATE'));
$this->setError($e);
return false;
}
}
// Update and cascade the publishing state.
$query = $this->_db->getQuery(true)->update($this->_db->quoteName($this->_tbl))->set('published = ' . (int) $state)
->where('(lft > ' . (int) $node->lft . ' AND rgt < ' . (int) $node->rgt . ')' . ' OR ' . $k . ' = ' . (int) $pk);
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_PUBLISH_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// If checkout support exists for the object, check the row in.
if ($checkoutSupport)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->published = $state;
}
$this->setError('');
return true;
}
/**
* Method to move a node one position to the left in the same level.
*
* @param integer $pk Primary key of the node to move.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/orderUp
* @since 11.1
*/
public function orderUp($pk)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Lock the table for writing.
if (!$this->_lock())
{
// Error message set in lock method.
return false;
}
// Get the node by primary key.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Get the left sibling node.
if (!$sibling = $this->_getNode($node->lft - 1, 'right'))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Get the primary keys of child nodes.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key);
$query->from($this->_tbl);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
$children = $this->_db->loadColumn();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERUP_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Shift left and right values for the node and it's children.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - ' . (int) $sibling->width);
$query->set('rgt = rgt - ' . (int) $sibling->width);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERUP_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Shift left and right values for the sibling and it's children.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft + ' . (int) $node->width);
$query->set('rgt = rgt + ' . (int) $node->width);
$query->where('lft BETWEEN ' . (int) $sibling->lft . ' AND ' . (int) $sibling->rgt);
$query->where($this->_tbl_key . ' NOT IN (' . implode(',', $children) . ')');
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERUP_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Unlock the table for writing.
$this->_unlock();
return true;
}
/**
* Method to move a node one position to the right in the same level.
*
* @param integer $pk Primary key of the node to move.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/orderDown
* @since 11.1
*/
public function orderDown($pk)
{
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Lock the table for writing.
if (!$this->_lock())
{
// Error message set in lock method.
return false;
}
// Get the node by primary key.
if (!$node = $this->_getNode($pk))
{
// Error message set in getNode method.
$this->_unlock();
return false;
}
// Get the right sibling node.
if (!$sibling = $this->_getNode($node->rgt + 1, 'left'))
{
// Error message set in getNode method.
$query->unlock($this->_db);
$this->_locked = false;
return false;
}
// Get the primary keys of child nodes.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key);
$query->from($this->_tbl);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
$children = $this->_db->loadColumn();
// Check for a database error.
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERDOWN_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Shift left and right values for the node and it's children.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft + ' . (int) $sibling->width);
$query->set('rgt = rgt + ' . (int) $sibling->width);
$query->where('lft BETWEEN ' . (int) $node->lft . ' AND ' . (int) $node->rgt);
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERDOWN_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Shift left and right values for the sibling and it's children.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = lft - ' . (int) $node->width);
$query->set('rgt = rgt - ' . (int) $node->width);
$query->where('lft BETWEEN ' . (int) $sibling->lft . ' AND ' . (int) $sibling->rgt);
$query->where($this->_tbl_key . ' NOT IN (' . implode(',', $children) . ')');
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_ORDERDOWN_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
// Unlock the table for writing.
$this->_unlock();
return true;
}
/**
* Gets the ID of the root item in the tree
*
* @return mixed The ID of the root row, or false and the internal error is set.
*
* @since 11.1
*/
public function getRootId()
{
// Get the root item.
$k = $this->_tbl_key;
// Test for a unique record with parent_id = 0
$query = $this->_db->getQuery(true);
$query->select($k);
$query->from($this->_tbl);
$query->where('parent_id = 0');
$this->_db->setQuery($query);
$result = $this->_db->loadColumn();
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GETROOTID_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
if (count($result) == 1)
{
$parentId = $result[0];
}
else
{
// Test for a unique record with lft = 0
$query = $this->_db->getQuery(true);
$query->select($k);
$query->from($this->_tbl);
$query->where('lft = 0');
$this->_db->setQuery($query);
$result = $this->_db->loadColumn();
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GETROOTID_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
if (count($result) == 1)
{
$parentId = $result[0];
}
elseif (property_exists($this, 'alias'))
{
// Test for a unique record alias = root
$query = $this->_db->getQuery(true);
$query->select($k);
$query->from($this->_tbl);
$query->where('alias = ' . $this->_db->quote('root'));
$this->_db->setQuery($query);
$result = $this->_db->loadColumn();
if ($this->_db->getErrorNum())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GETROOTID_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
if (count($result) == 1)
{
$parentId = $result[0];
}
else
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_ROOT_NODE_NOT_FOUND'));
$this->setError($e);
return false;
}
}
else
{
$e = new JException(JText::_('JLIB_DATABASE_ERROR_ROOT_NODE_NOT_FOUND'));
$this->setError($e);
return false;
}
}
return $parentId;
}
/**
* Method to recursively rebuild the whole nested set tree.
*
* @param integer $parentId The root of the tree to rebuild.
* @param integer $leftId The left id to start with in building the tree.
* @param integer $level The level to assign to the current nodes.
* @param string $path The path to the current nodes.
*
* @return integer 1 + value of root rgt on success, false on failure
*
* @link http://docs.joomla.org/JTableNested/rebuild
* @since 11.1
*/
public function rebuild($parentId = null, $leftId = 0, $level = 0, $path = '')
{
// If no parent is provided, try to find it.
if ($parentId === null)
{
// Get the root item.
$parentId = $this->getRootId();
if ($parentId === false)
{
return false;
}
}
// Build the structure of the recursive query.
if (!isset($this->_cache['rebuild.sql']))
{
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', alias');
$query->from($this->_tbl);
$query->where('parent_id = %d');
// If the table has an ordering field, use that for ordering.
if (property_exists($this, 'ordering'))
{
$query->order('parent_id, ordering, lft');
}
else
{
$query->order('parent_id, lft');
}
$this->_cache['rebuild.sql'] = (string) $query;
}
// Make a shortcut to database object.
// Assemble the query to find all children of this node.
$this->_db->setQuery(sprintf($this->_cache['rebuild.sql'], (int) $parentId));
$children = $this->_db->loadObjectList();
// The right value of this node is the left value + 1
$rightId = $leftId + 1;
// execute this function recursively over all children
foreach ($children as $node)
{
// $rightId is the current right value, which is incremented on recursion return.
// Increment the level for the children.
// Add this item's alias to the path (but avoid a leading /)
$rightId = $this->rebuild($node->{$this->_tbl_key}, $rightId, $level + 1, $path . (empty($path) ? '' : '/') . $node->alias);
// If there is an update failure, return false to break out of the recursion.
if ($rightId === false)
{
return false;
}
}
// We've got the left value, and now that we've processed
// the children of this node we also know the right value.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('lft = ' . (int) $leftId);
$query->set('rgt = ' . (int) $rightId);
$query->set('level = ' . (int) $level);
$query->set('path = ' . $this->_db->quote($path));
$query->where($this->_tbl_key . ' = ' . (int) $parentId);
$this->_db->setQuery($query);
// If there is an update failure, return false to break out of the recursion.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_REBUILD_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Return the right value of this node + 1.
return $rightId + 1;
}
/**
* Method to rebuild the node's path field from the alias values of the
* nodes from the current node to the root node of the tree.
*
* @param integer $pk Primary key of the node for which to get the path.
*
* @return boolean True on success.
*
* @link http://docs.joomla.org/JTableNested/rebuildPath
* @since 11.1
*/
public function rebuildPath($pk = null)
{
// If there is no alias or path field, just return true.
if (!property_exists($this, 'alias') || !property_exists($this, 'path'))
{
return true;
}
// Initialise variables.
$k = $this->_tbl_key;
$pk = (is_null($pk)) ? $this->$k : $pk;
// Get the aliases for the path from the node to the root node.
$query = $this->_db->getQuery(true);
$query->select('p.alias');
$query->from($this->_tbl . ' AS n, ' . $this->_tbl . ' AS p');
$query->where('n.lft BETWEEN p.lft AND p.rgt');
$query->where('n.' . $this->_tbl_key . ' = ' . (int) $pk);
$query->order('p.lft');
$this->_db->setQuery($query);
$segments = $this->_db->loadColumn();
// Make sure to remove the root path if it exists in the list.
if ($segments[0] == 'root')
{
array_shift($segments);
}
// Build the path.
$path = trim(implode('/', $segments), ' /\\');
// Update the path field for the node.
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->set('path = ' . $this->_db->quote($path));
$query->where($this->_tbl_key . ' = ' . (int) $pk);
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_REBUILDPATH_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Update the current record's path to the new one:
$this->path = $path;
return true;
}
/**
* Method to update order of table rows
*
* @param array $idArray id numbers of rows to be reordered.
* @param array $lft_array lft values of rows to be reordered.
*
* @return integer 1 + value of root rgt on success, false on failure.
*
* @since 11.1
*/
public function saveorder($idArray = null, $lft_array = null)
{
// Validate arguments
if (is_array($idArray) && is_array($lft_array) && count($idArray) == count($lft_array))
{
for ($i = 0, $count = count($idArray); $i < $count; $i++)
{
// Do an update to change the lft values in the table for each id
$query = $this->_db->getQuery(true);
$query->update($this->_tbl);
$query->where($this->_tbl_key . ' = ' . (int) $idArray[$i]);
$query->set('lft = ' . (int) $lft_array[$i]);
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_REORDER_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
if ($this->_debug)
{
$this->_logtable();
}
}
return $this->rebuild();
}
else
{
return false;
}
}
/**
* Method to get nested set properties for a node in the tree.
*
* @param integer $id Value to look up the node by.
* @param string $key Key to look up the node by.
*
* @return mixed Boolean false on failure or node object on success.
*
* @since 11.1
*/
protected function _getNode($id, $key = null)
{
// Determine which key to get the node base on.
switch ($key)
{
case 'parent':
$k = 'parent_id';
break;
case 'left':
$k = 'lft';
break;
case 'right':
$k = 'rgt';
break;
default:
$k = $this->_tbl_key;
break;
}
// Get the node data.
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', parent_id, level, lft, rgt');
$query->from($this->_tbl);
$query->where($k . ' = ' . (int) $id);
$this->_db->setQuery($query, 0, 1);
$row = $this->_db->loadObject();
// Check for a database error or no $row returned
if ((!$row) || ($this->_db->getErrorNum()))
{
$e = new JException(JText::sprintf('JLIB_DATABASE_ERROR_GETNODE_FAILED', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
return false;
}
// Do some simple calculations.
$row->numChildren = (int) ($row->rgt - $row->lft - 1) / 2;
$row->width = (int) $row->rgt - $row->lft + 1;
return $row;
}
/**
* Method to get various data necessary to make room in the tree at a location
* for a node and its children. The returned data object includes conditions
* for SQL WHERE clauses for updating left and right id values to make room for
* the node as well as the new left and right ids for the node.
*
* @param object $referenceNode A node object with at least a 'lft' and 'rgt' with
* which to make room in the tree around for a new node.
* @param integer $nodeWidth The width of the node for which to make room in the tree.
* @param string $position The position relative to the reference node where the room
* should be made.
*
* @return mixed Boolean false on failure or data object on success.
*
* @since 11.1
*/
protected function _getTreeRepositionData($referenceNode, $nodeWidth, $position = 'before')
{
// Make sure the reference an object with a left and right id.
if (!is_object($referenceNode) && isset($referenceNode->lft) && isset($referenceNode->rgt))
{
return false;
}
// A valid node cannot have a width less than 2.
if ($nodeWidth < 2)
{
return false;
}
// Initialise variables.
$k = $this->_tbl_key;
$data = new stdClass;
// Run the calculations and build the data object by reference position.
switch ($position)
{
case 'first-child':
$data->left_where = 'lft > ' . $referenceNode->lft;
$data->right_where = 'rgt >= ' . $referenceNode->lft;
$data->new_lft = $referenceNode->lft + 1;
$data->new_rgt = $referenceNode->lft + $nodeWidth;
$data->new_parent_id = $referenceNode->$k;
$data->new_level = $referenceNode->level + 1;
break;
case 'last-child':
$data->left_where = 'lft > ' . ($referenceNode->rgt);
$data->right_where = 'rgt >= ' . ($referenceNode->rgt);
$data->new_lft = $referenceNode->rgt;
$data->new_rgt = $referenceNode->rgt + $nodeWidth - 1;
$data->new_parent_id = $referenceNode->$k;
$data->new_level = $referenceNode->level + 1;
break;
case 'before':
$data->left_where = 'lft >= ' . $referenceNode->lft;
$data->right_where = 'rgt >= ' . $referenceNode->lft;
$data->new_lft = $referenceNode->lft;
$data->new_rgt = $referenceNode->lft + $nodeWidth - 1;
$data->new_parent_id = $referenceNode->parent_id;
$data->new_level = $referenceNode->level;
break;
default:
case 'after':
$data->left_where = 'lft > ' . $referenceNode->rgt;
$data->right_where = 'rgt > ' . $referenceNode->rgt;
$data->new_lft = $referenceNode->rgt + 1;
$data->new_rgt = $referenceNode->rgt + $nodeWidth;
$data->new_parent_id = $referenceNode->parent_id;
$data->new_level = $referenceNode->level;
break;
}
if ($this->_debug)
{
echo "\nRepositioning Data for $position" . "\n-----------------------------------" . "\nLeft Where: $data->left_where"
. "\nRight Where: $data->right_where" . "\nNew Lft: $data->new_lft" . "\nNew Rgt: $data->new_rgt"
. "\nNew Parent ID: $data->new_parent_id" . "\nNew Level: $data->new_level" . "\n";
}
return $data;
}
/**
* Method to create a log table in the buffer optionally showing the query and/or data.
*
* @param boolean $showData True to show data
* @param boolean $showQuery True to show query
*
* @return void
*
* @since 11.1
*/
protected function _logtable($showData = true, $showQuery = true)
{
$sep = "\n" . str_pad('', 40, '-');
$buffer = '';
if ($showQuery)
{
$buffer .= "\n" . $this->_db->getQuery() . $sep;
}
if ($showData)
{
$query = $this->_db->getQuery(true);
$query->select($this->_tbl_key . ', parent_id, lft, rgt, level');
$query->from($this->_tbl);
$query->order($this->_tbl_key);
$this->_db->setQuery($query);
$rows = $this->_db->loadRowList();
$buffer .= sprintf("\n| %4s | %4s | %4s | %4s |", $this->_tbl_key, 'par', 'lft', 'rgt');
$buffer .= $sep;
foreach ($rows as $row)
{
$buffer .= sprintf("\n| %4s | %4s | %4s | %4s |", $row[0], $row[1], $row[2], $row[3]);
}
$buffer .= $sep;
}
echo $buffer;
}
/**
* Method to run an update query and check for a database error
*
* @param string $query The query.
* @param string $errorMessage Unused.
*
* @return boolean False on exception
*
* @since 11.1
*/
protected function _runQuery($query, $errorMessage)
{
$this->_db->setQuery($query);
// Check for a database error.
if (!$this->_db->execute())
{
$e = new JException(JText::sprintf('$errorMessage', get_class($this), $this->_db->getErrorMsg()));
$this->setError($e);
$this->_unlock();
return false;
}
if ($this->_debug)
{
$this->_logtable();
}
}
}
PK /?\D database/mysqliexporter.phpnu W+A db instanceof JDatabaseMySqli))
{
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 JDatabaseMySQLi $db The database connector.
*
* @return JDatabaseExporterMySQLi Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQLi $db)
{
$this->db = $db;
return $this;
}
}
PK /?\+= database/sqlazurequery.phpnu W+A $options['database'],
'uid' => $options['user'],
'pwd' => $options['password'],
'CharacterSet' => 'UTF-8',
'ReturnDatesAsStrings' => true);
// Make sure the SQLSRV extension for PHP is installed and enabled.
if (!function_exists('sqlsrv_connect'))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_SQLSRV');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_SQLSRV'));
}
}
// Attempt to connect to the server.
if (!($this->connection = @ sqlsrv_connect($options['host'], $config)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_SQLSRV');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_SQLSRV'));
}
}
// Make sure that DB warnings are not returned as errors.
sqlsrv_configure('WarningsReturnAsErrors', 0);
// Finalize initialisation
parent::__construct($options);
// If auto-select is enabled select the given database.
if ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_resource($this->connection))
{
sqlsrv_close($this->connection);
}
}
/**
* Get table constraints
*
* @param string $tableName The name of the database table.
*
* @return array Any constraints available for the table.
*
* @since 11.1
*/
protected function getTableConstraints($tableName)
{
$query = $this->getQuery(true);
$this->setQuery(
'SELECT CONSTRAINT_NAME FROM' . ' INFORMATION_SCHEMA.TABLE_CONSTRAINTS' . ' WHERE TABLE_NAME = ' . $query->quote($tableName)
);
return $this->loadColumn();
}
/**
* Rename constraints.
*
* @param array $constraints Array(strings) of table constraints
* @param string $prefix A string
* @param string $backup A string
*
* @return void
*
* @since 11.1
*/
protected function renameConstraints($constraints = array(), $prefix = null, $backup = null)
{
foreach ($constraints as $constraint)
{
$this->setQuery('sp_rename ' . $constraint . ',' . str_replace($prefix, $backup, $constraint));
$this->execute();
}
}
/**
* Method to escape a string for usage in an SQL statement.
*
* The escaping for MSSQL isn't handled in the driver though that would be nice. Because of this we need
* to handle the escaping ourselves.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 11.1
*/
public function escape($text, $extra = false)
{
$result = addslashes($text);
$result = str_replace("\'", "''", $result);
$result = str_replace('\"', '"', $result);
$result = str_replace('\\\/', '/', $result);
$result = str_replace('\\\\', '\\', $result);
if ($extra)
{
// We need the below str_replace since the search in sql server doesn't recognize _ character.
$result = str_replace('_', '[_]', $result);
}
return $result;
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
// TODO: Run a blank query here
return true;
}
/**
* 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 JDatabaseSQLSrv Returns this object to support chaining.
*
* @since 11.1
* @throws JDatabaseException
*/
public function dropTable($tableName, $ifExists = true)
{
$query = $this->getQuery(true);
if ($ifExists)
{
$this->setQuery(
'IF EXISTS(SELECT TABLE_NAME FROM' . ' INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ' . $query->quote($tableName) . ') DROP TABLE ' . $tableName
);
}
else
{
$this->setQuery('DROP TABLE ' . $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 11.1
*/
public function getAffectedRows()
{
return sqlsrv_rows_affected($this->cursor);
}
/**
* 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 11.1
*/
public function getCollation()
{
// TODO: Not fake this
return 'MSSQL UTF-8 (UCS2)';
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterSQLAzure An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterSQLAzure'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterSQLAzure;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterSQLAzure An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterSQLAzure'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterSQLAzure;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return sqlsrv_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQuerySQLSrv'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQuerySQLSrv($this);
}
else
{
return $this->sql;
}
}
/**
* Retrieves field information about the given tables.
*
* @param mixed $table A table name
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableColumns($table, $typeOnly = true)
{
// Initialise variables.
$result = array();
$table_temp = $this->replacePrefix((string) $table);
// Set the query to get the table fields statement.
$this->setQuery(
'SELECT column_name as Field, data_type as Type, is_nullable as \'Null\', column_default as \'Default\'' .
' FROM information_schema.columns' . ' WHERE table_name = ' . $this->quote($table_temp)
);
$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;
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* This is unsupported by MSSQL.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableCreate($tables)
{
return '';
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function getTableKeys($table)
{
// TODO To implement.
return array();
}
/**
* Method to quote and optionally escape a string to database requirements for insertion into the database.
*
* @param string $text The string to quote.
* @param boolean $escape True to escape the string, false to leave it unchanged.
*
* @return string The quoted input string.
*
* @since 11.1
*/
public function quote($text, $escape = true)
{
return 'N' . '\'' . ($escape ? $this->escape($text) : $text) . '\'';
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableList()
{
// Set the query to get the tables statement.
$this->setQuery('SELECT name FROM ' . $this->getDatabase() . '.sys.Tables WHERE type = \'U\';');
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 11.1
*/
public function getVersion()
{
$version = sqlsrv_server_info($this->connection);
return $version['SQLServerVersion'];
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
*/
public function hasUTF()
{
return true;
}
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert into.
* @param object &$object A reference to an object whose public properties match the table fields.
* @param string $key The name of the primary key. If provided the object property is updated.
*
* @return boolean True on success.
*
* @since 11.1
* @throws JDatabaseException
*/
public function insertObject($table, &$object, $key = null)
{
$fields = array();
$values = array();
$statement = 'INSERT INTO ' . $this->quoteName($table) . ' (%s) VALUES (%s)';
foreach (get_object_vars($object) as $k => $v)
{
if (is_array($v) or is_object($v))
{
continue;
}
if (!$this->checkFieldExists($table, $k))
{
continue;
}
if ($k[0] == '_')
{
// internal field
continue;
}
if ($k == $key && $key == 0)
{
continue;
}
$fields[] = $this->quoteName($k);
$values[] = $this->Quote($v);
}
// Set the query and execute the insert.
$this->setQuery(sprintf($statement, implode(',', $fields), implode(',', $values)));
if (!$this->execute())
{
return false;
}
$id = $this->insertid();
if ($key && $id)
{
$object->$key = $id;
}
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
// TODO: SELECT IDENTITY
$this->setQuery('SELECT @@IDENTITY');
return (int) $this->loadResult();
}
/**
* Method to get the first field of the first row of the result set from the database query.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadResult()
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an array.
if ($row = sqlsrv_fetch_array($cursor, SQLSRV_FETCH_NUMERIC))
{
$ret = $row[0];
}
// Free up system resources and return.
$this->freeResult($cursor);
//For SQLServer - we need to strip slashes
$ret = stripslashes($ret);
return $ret;
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_resource($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseDriverSQLAzure::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) && ($this->limit > 0 || $this->offset > 0))
{
$sql = $this->limit($sql, $this->limit, $this->offset);
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// sqlsrv_num_rows requires a static or keyset cursor.
if (strncmp(ltrim(strtoupper($sql)), 'SELECT', strlen('SELECT')) == 0)
{
$array = array('Scrollable' => SQLSRV_CURSOR_KEYSET);
}
else
{
$array = array();
}
// Execute the query.
$this->cursor = sqlsrv_query($this->connection, $sql, array(), $array);
// If an error occurred handle it.
if (!$this->cursor)
{
// Populate the errors.
$errors = sqlsrv_errors();
$this->errorNum = $errors[0]['SQLSTATE'];
$this->errorMsg = $errors[0]['message'] . 'SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseDriverSQLAzure::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
return $this->cursor;
}
/**
* This function replaces a string identifier $prefix with the string held is the
* tablePrefix class variable.
*
* @param string $sql The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 11.1
*/
public function replacePrefix($sql, $prefix = '#__')
{
$tablePrefix = 'jos_';
// Initialize variables.
$escaped = false;
$startPos = 0;
$quoteChar = '';
$literal = '';
$sql = trim($sql);
$n = strlen($sql);
while ($startPos < $n)
{
$ip = strpos($sql, $prefix, $startPos);
if ($ip === false)
{
break;
}
$j = strpos($sql, "N'", $startPos);
$k = strpos($sql, '"', $startPos);
if (($k !== false) && (($k < $j) || ($j === false)))
{
$quoteChar = '"';
$j = $k;
}
else
{
$quoteChar = "'";
}
if ($j === false)
{
$j = $n;
}
$literal .= str_replace($prefix, $this->tablePrefix, substr($sql, $startPos, $j - $startPos));
$startPos = $j;
$j = $startPos + 1;
if ($j >= $n)
{
break;
}
// quote comes first, find end of quote
while (true)
{
$k = strpos($sql, $quoteChar, $j);
$escaped = false;
if ($k === false)
{
break;
}
$l = $k - 1;
while ($l >= 0 && $sql{$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($sql, $startPos, $k - $startPos + 1);
$startPos = $k + 1;
}
if ($startPos < $n)
{
$literal .= substr($sql, $startPos, $n - $startPos);
}
return $literal;
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!sqlsrv_query($this->connection, 'USE ' . $database, null, array('scrollable' => SQLSRV_CURSOR_STATIC)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
// TODO: Remove this?
}
/**
* Method to commit a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionCommit()
{
$this->setQuery('COMMIT TRANSACTION');
$this->execute();
}
/**
* Method to roll back a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionRollback()
{
$this->setQuery('ROLLBACK TRANSACTION');
$this->execute();
}
/**
* Method to initialize a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionStart()
{
$this->setQuery('START TRANSACTION');
$this->execute();
}
/**
* 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 11.1
*/
protected function fetchArray($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor, SQLSRV_FETCH_NUMERIC);
}
/**
* 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 11.1
*/
protected function fetchAssoc($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor, SQLSRV_FETCH_ASSOC);
}
/**
* 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 11.1
*/
protected function fetchObject($cursor = null, $class = 'stdClass')
{
return sqlsrv_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 11.1
*/
protected function freeResult($cursor = null)
{
sqlsrv_free_stmt($cursor ? $cursor : $this->cursor);
}
/**
* Diagnostic method to return explain information for a query.
*
* @return string The explain output.
*
* @deprecated 12.1
* @see http://msdn.microsoft.com/en-us/library/aa259203%28SQL.80%29.aspx
* @since 11.1
*/
public function explain()
{
// Deprecation warning.
JLog::add('JDatabase::explain() is deprecated.', JLog::WARNING, 'deprecated');
// Backup the current query so we can reset it later.
$backup = $this->sql;
// SET SHOWPLAN_ALL ON - will make sqlsrv to show some explain of query instead of run it
$this->setQuery('SET SHOWPLAN_ALL ON');
$this->execute();
// Execute the query and get the result set cursor.
$this->setQuery($backup);
if (!($cursor = $this->execute()))
{
return null;
}
// Build the HTML table.
$first = true;
$buffer = '';
$buffer .= '| ' . $this->getQuery() . ' |
';
while ($row = $this->fetchAssoc($cursor))
{
if ($first)
{
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $k . ' | ';
}
$buffer .= '
';
$first = false;
}
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $v . ' | ';
}
$buffer .= '
';
}
$buffer .= '
';
// Free up system resources and return.
$this->freeResult($cursor);
// Remove the explain status.
$this->setQuery('SET SHOWPLAN_ALL OFF');
$this->execute();
// Restore the original query to its state before we ran the explain.
$this->sql = $backup;
return $buffer;
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @since 11.1
* @deprecated 12.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabase::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$this->_sql = 'BEGIN TRANSACTION;' . $this->sql . '; COMMIT TRANSACTION;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = sqlsrv_query($this->connection, $query, null, array('scrollable' => SQLSRV_CURSOR_STATIC));
if ($this->_debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$errors = sqlsrv_errors();
$this->errorNum = $errors[0]['sqlstate'];
$this->errorMsg = $errors[0]['message'];
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
/**
* Method to check and see if a field exists in a table.
*
* @param string $table The table in which to verify the field.
* @param string $field The field to verify.
*
* @return boolean True if the field exists in the table.
*
* @since 11.1
*/
protected function checkFieldExists($table, $field)
{
$table = $this->replacePrefix((string) $table);
$sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS" . " WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" .
" ORDER BY ORDINAL_POSITION";
$this->setQuery($sql);
if ($this->loadResult())
{
return true;
}
else
{
return false;
}
}
/**
* Method to wrap an SQL statement to provide a LIMIT and OFFSET behavior for scrolling through a result set.
*
* @param string $sql The SQL statement to process.
* @param integer $limit The maximum affected rows to set.
* @param integer $offset The affected row offset to set.
*
* @return string The processed SQL statement.
*
* @since 11.1
*/
protected function limit($sql, $limit, $offset)
{
if ($limit == 0 && $offset == 0)
{
return $sql;
}
$start = $offset + 1;
$end = $offset + $limit;
$orderBy = stristr($sql, 'ORDER BY');
if (is_null($orderBy) || empty($orderBy))
{
$orderBy = 'ORDER BY (select 0)';
}
$sql = str_ireplace($orderBy, '', $sql);
$rowNumberText = ', ROW_NUMBER() OVER (' . $orderBy . ') AS RowNumber FROM ';
$sql = preg_replace('/\sFROM\s/i', $rowNumberText, $sql, 1);
$sql = 'SELECT * FROM (' . $sql . ') _myResults WHERE RowNumber BETWEEN ' . $start . ' AND ' . $end;
return $sql;
}
/**
* 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 Table prefix
* @param string $prefix For the table - used to rename constraints in non-mysql databases
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
{
$constraints = array();
if (!is_null($prefix) && !is_null($backup))
{
$constraints = $this->getTableConstraints($oldTable);
}
if (!empty($constraints))
{
$this->renameConstraints($constraints, $prefix, $backup);
}
$this->setQuery("sp_rename '" . $oldTable . "', '" . $newTable . "'");
return $this->execute();
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to lock.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function lockTable($tableName)
{
return $this;
}
/**
* Unlocks tables in the database.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function unlockTables()
{
return $this;
}
}
PK /?\d= = database/mysqlimporter.phpnu W+A options = new JObject;
$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 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 JDatabaseMySql))
{
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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySQL($keys);
return $sql;
}
/**
* 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)
{
// Initialise variables.
$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 '';
// echo '
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 '
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 '
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 '
Collation: '.
// ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '.
// (string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation;
// echo '
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 '
Same = '.($same ? 'true' : 'false');
// echo '
';
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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
. $this->getColumnSQL($field);
return $sql;
}
/**
* 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)
{
// Initialise variables.
// 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'];
$sql = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$sql .= ' NOT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault);
}
}
else
{
if ($fDefault === null)
{
$sql .= ' DEFAULT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' DEFAULT ' . $this->db->quote($fDefault);
}
}
if ($fExtra)
{
$sql .= ' ' . strtoupper($fExtra);
}
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
*
* @return string
*
* @since 11.1
*/
protected function getDropPrimaryKeySQL($table)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY';
return $sql;
}
/**
* 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'];
}
}
$sql = $prefix . 'KEY ' . ($kName != 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')';
return $sql;
}
/**
* 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()
{
// Initialise variables.
$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((string) $query);
if (!$this->db->execute())
{
$this->addLog('Fail: ' . $this->db->getQuery());
throw new Exception($this->db->getErrorMsg());
}
else
{
$this->addLog('Pass: ' . $this->db->getQuery());
}
}
}
}
else
{
// This is a new table.
$sql = $this->xmlToCreate($table);
$this->db->setQuery((string) $sql);
if (!$this->db->execute())
{
$this->addLog('Fail: ' . $this->db->getQuery());
throw new Exception($this->db->getErrorMsg());
}
else
{
$this->addLog('Pass: ' . $this->db->getQuery());
}
}
}
}
/**
* Sets the database connector to use for exporting structure and/or data from MySQL.
*
* @param JDatabaseMySQL $db The database connector.
*
* @return JDatabaseImporterMySQL Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQL $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->set('with-structure', (boolean) $setting);
return $this;
}
}
PK /?\pQ pQ database/mysql.phpnu W+A errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQL'));
}
}
// Attempt to connect to the server.
if (!($this->connection = @ mysql_connect($options['host'], $options['user'], $options['password'], true)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL'));
}
}
// Finalize initialisation
parent::__construct($options);
// 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 ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_resource($this->connection))
{
mysql_close($this->connection);
}
}
/**
* 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 11.1
*/
public function escape($text, $extra = false)
{
$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 11.1
*/
public static function test()
{
return (function_exists('mysql_connect'));
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
if (is_resource($this->connection))
{
return mysql_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 JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.1
* @throws JDatabaseException
*/
public function dropTable($tableName, $ifExists = true)
{
$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 11.1
*/
public function getAffectedRows()
{
return mysql_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 11.1
* @throws JDatabaseException
*/
public function getCollation()
{
$this->setQuery('SHOW FULL COLUMNS FROM #__users');
$array = $this->loadAssocList();
return $array['2']['Collation'];
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterMySQL An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterMySQL;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterMySQL An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterMySQL;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return mysql_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQueryMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQueryMySQL($this);
}
else
{
return $this->sql;
}
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function getTableCreate($tables)
{
// Initialise variables.
$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 11.1
* @throws JDatabaseException
*/
public function getTableColumns($table, $typeOnly = true)
{
$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 11.1
* @throws JDatabaseException
*/
public function getTableKeys($table)
{
// 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 11.1
* @throws JDatabaseException
*/
public function getTableList()
{
// 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 11.1
*/
public function getVersion()
{
return mysql_get_server_info($this->connection);
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
* @deprecated 12.1
*/
public function hasUTF()
{
JLog::add('JDatabaseMySQL::hasUTF() is deprecated.', JLog::WARNING, 'deprecated');
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
return mysql_insert_id($this->connection);
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
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 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_resource($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQL::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if ($this->limit > 0 || $this->offset > 0)
{
$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// Execute the query.
$this->cursor = mysql_query($sql, $this->connection);
// If an error occurred handle it.
if (!$this->cursor)
{
$this->errorNum = (int) mysql_errno($this->connection);
$this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQL::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($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 JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!mysql_select_db($database, $this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
return mysql_set_charset('utf8', $this->connection);
}
/**
* Method to commit a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionCommit()
{
$this->setQuery('COMMIT');
$this->execute();
}
/**
* Method to roll back a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionRollback()
{
$this->setQuery('ROLLBACK');
$this->execute();
}
/**
* Method to initialize a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionStart()
{
$this->setQuery('START TRANSACTION');
$this->execute();
}
/**
* 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 11.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 11.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 11.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 11.1
*/
protected function freeResult($cursor = null)
{
mysql_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Diagnostic method to return explain information for a query.
*
* @return string The explain output.
*
* @since 11.1
* @deprecated 12.1
*/
public function explain()
{
// Deprecation warning.
JLog::add('JDatabaseMySQL::explain() is deprecated.', JLog::WARNING, 'deprecated');
// Backup the current query so we can reset it later.
$backup = $this->sql;
// Prepend the current query with EXPLAIN so we get the diagnostic data.
$this->sql = 'EXPLAIN ' . $this->sql;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Build the HTML table.
$first = true;
$buffer = '';
$buffer .= '| ' . $this->getQuery() . ' |
';
while ($row = $this->fetchAssoc($cursor))
{
if ($first)
{
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $k . ' | ';
}
$buffer .= '
';
$first = false;
}
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $v . ' | ';
}
$buffer .= '
';
}
$buffer .= '
';
// Restore the original query to its state before we ran the explain.
$this->sql = $backup;
// Free up system resources and return.
$this->freeResult($cursor);
return $buffer;
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @deprecated 12.1
* @since 11.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabaseMySQL::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$sql = 'START TRANSACTION;' . rtrim($sql, "; \t\r\n\0") . '; COMMIT;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = mysql_query($query, $this->connection);
if ($this->debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$this->errorNum .= mysql_errno($this->connection) . ' ';
$this->errorMsg .= mysql_error($this->connection) . " SQL=$query
";
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function unlockTables()
{
$this->setQuery('UNLOCK TABLES')->execute();
return $this;
}
}
PK /?\3 database/sqlazure.phpnu W+A sql;
}
}
}
PK /?\m{ database/mysqlquery.phpnu W+A quote($separator);
foreach ($values as $value)
{
$concat_string .= ', ' . $value;
}
return $concat_string . ')';
}
else
{
return 'CONCAT(' . implode(',', $values) . ')';
}
}
}
PK /?\ database/mysqliimporter.phpnu W+A db instanceof JDatabaseMySqli))
{
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 JDatabaseMySQLi $db The database connector.
*
* @return JDatabaseImporterMySQLi Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQLi $db)
{
$this->db = $db;
return $this;
}
}
PK /?\Oi^ ^ database/mysqlexporter.phpnu W+A options = new JObject;
$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();
$buffer = '';
// Get the format.
switch ($this->asFormat)
{
case 'xml':
default:
$buffer = $this->buildXml();
break;
}
return $buffer;
}
/**
* 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[] = '';
$buffer[] = '';
$buffer[] = ' ';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' ';
$buffer[] = '';
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);
$keys = $this->db->getTableKeys($table);
$buffer[] = ' ';
foreach ($fields as $field)
{
$buffer[] = ' Default) ? ' Default="' . $field->Default . '"' : '') . ' Extra="' . $field->Extra . '"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' ';
}
$buffer[] = ' ';
}
return $buffer;
}
/**
* 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 JDatabaseMySQL))
{
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 JDatabaseMySQL $db The database connector.
*
* @return JDatabaseExporterMySQL Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQL $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->set('with-structure', (boolean) $setting);
return $this;
}
}
PK /?\6 6 database/mysqli.phpnu W+A errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI'));
}
}
$this->connection = @mysqli_connect(
$options['host'], $options['user'], $options['password'], null, $options['port'], $options['socket']
);
// Attempt to connect to the server.
if (!$this->connection)
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL'));
}
}
// Finalize initialisation
JDatabase::__construct($options);
// 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 ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_callable(array($this->connection, 'close')))
{
mysqli_close($this->connection);
}
}
/**
* 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 11.1
*/
public function escape($text, $extra = false)
{
$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 11.1
*/
public static function test()
{
return (function_exists('mysqli_connect'));
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
if (is_object($this->connection))
{
return mysqli_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 11.1
*/
public function getAffectedRows()
{
return mysqli_affected_rows($this->connection);
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterMySQLi An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterMySQLi;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterMySQLi An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterMySQLi;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return mysqli_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQueryMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQueryMySQLi($this);
}
else
{
return $this->sql;
}
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 11.1
*/
public function getVersion()
{
return mysqli_get_server_info($this->connection);
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
* @deprecated 12.1
*/
public function hasUTF()
{
JLog::add('JDatabaseMySQLi::hasUTF() is deprecated.', JLog::WARNING, 'deprecated');
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
return mysqli_insert_id($this->connection);
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_object($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if ($this->limit > 0 || $this->offset > 0)
{
$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// Execute the query.
$this->cursor = mysqli_query($this->connection, $sql);
// If an error occurred handle it.
if (!$this->cursor)
{
$this->errorNum = (int) mysqli_errno($this->connection);
$this->errorMsg = (string) mysqli_error($this->connection) . ' SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!mysqli_select_db($this->connection, $database))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
mysqli_set_charset($this->connection, 'utf8');
}
/**
* 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 11.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 11.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 11.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 11.1
*/
protected function freeResult($cursor = null)
{
mysqli_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @deprecated 12.1
* @since 11.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabaseMySQLi::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$sql = 'START TRANSACTION;' . rtrim($sql, "; \t\r\n\0") . '; COMMIT;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = mysqli_query($this->connection, $query);
if ($this->debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$this->errorNum .= mysqli_errno($this->connection) . ' ';
$this->errorMsg .= mysqli_error($this->connection) . " SQL=$query
";
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
}
PK /?\a5 database/mysqliquery.phpnu W+A type)
{
case 'select':
$query .= (string) $this->select;
$query .= (string) $this->from;
// Get the limit and offset values from JDatabase
$limit = $this->db->getLimit();
$offset = $this->db->getOffset();
if ($limit > 0 || $offset > 0)
{
if ($this->order)
{
$query .= (string) $this->order;
}
$query = $this->processLimit($query, $limit, $offset);
}
if ($this->join)
{
// special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
break;
case 'insert':
$query .= (string) $this->insert;
// Set method
if ($this->set)
{
$query .= (string) $this->set;
}
// Columns-Values method
elseif ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$elements = $this->insert->getElements();
$tableName = array_shift($elements);
$query .= 'VALUES ';
$query .= (string) $this->values;
if ($this->autoIncrementField)
{
$query = 'SET IDENTITY_INSERT ' . $tableName . ' ON;' . $query . 'SET IDENTITY_INSERT ' . $tableName . ' OFF;';
}
if ($this->where)
{
$query .= (string) $this->where;
}
}
break;
default:
$query = parent::__toString();
break;
}
return $query;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* @param string $value The value to cast as a char.
*
* @return string Returns the cast value.
*
* @since 11.1
*/
public function castAsChar($value)
{
return 'CAST(' . $value . ' as NVARCHAR(10))';
}
/**
* Gets the function to determine the length of a character string.
*
* @param string $field A value.
*
* @return string The required char length call.
*
* @since 11.1
*/
public function charLength($field)
{
return 'DATALENGTH(' . $field . ') IS NOT NULL';
}
/**
* Concatenates an array of column names or values.
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 11.1
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return '(' . implode('+' . $this->quote($separator) . '+', $values) . ')';
}
else
{
return '(' . implode('+', $values) . ')';
}
}
/**
* Gets the current date and time.
*
* @return string
*
* @since 11.1
*/
public function currentTimestamp()
{
return 'GETDATE()';
}
/**
* Get the length of a string in bytes.
*
* @param string $value The string to measure.
*
* @return integer
*
* @since 11.1
*/
public function length($value)
{
return 'LEN(' . $value . ')';
}
/**
* Method to modify a query already in string format with the needed
* additions to make the query limited to a particular number of
* results, or start at a particular offset.
*
* @param string $query The query in string format
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return string
*
* @since 12.1
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit == 0 && $offset == 0)
{
return $query;
}
$start = $offset + 1;
$end = $offset + $limit;
$orderBy = stristr($query, 'ORDER BY');
if (is_null($orderBy) || empty($orderBy))
{
$orderBy = 'ORDER BY (select 0)';
}
$query = str_ireplace($orderBy, '', $query);
$rowNumberText = ', ROW_NUMBER() OVER (' . $orderBy . ') AS RowNumber FROM ';
$query = preg_replace('/\sFROM\s/i', $rowNumberText, $query, 1);
$query = 'SELECT * FROM (' . $query . ') _myResults WHERE RowNumber BETWEEN ' . $start . ' AND ' . $end;
echo $query;
return $query;
}
}
PK /?\) database/.htaccessnu W+A
Order allow,deny
Deny from all
PK /?\V database/index.htmlnu W+A
PK /?\BBn Bn query.phpnu W+A elements = array();
$this->name = $name;
$this->glue = $glue;
$this->append($elements);
}
/**
* Magic function to convert the query element to a string.
*
* @return string
*
* @since 11.1
*/
public function __toString()
{
if (substr($this->name, -2) == '()')
{
return PHP_EOL . substr($this->name, 0, -2) . '(' . implode($this->glue, $this->elements) . ')';
}
else
{
return PHP_EOL . $this->name . ' ' . implode($this->glue, $this->elements);
}
}
/**
* Appends element parts to the internal list.
*
* @param mixed $elements String or array.
*
* @return void
*
* @since 11.1
*/
public function append($elements)
{
if (is_array($elements))
{
$this->elements = array_merge($this->elements, $elements);
}
else
{
$this->elements = array_merge($this->elements, array($elements));
}
}
/**
* Gets the elements of this element.
*
* @return string
*
* @since 11.1
*/
public function getElements()
{
return $this->elements;
}
/**
* Method to provide deep copy support to nested objects and arrays
* when cloning.
*
* @return void
*
* @since 11.3
*/
public function __clone()
{
foreach ($this as $k => $v)
{
if (is_object($v) || is_array($v))
{
$this->{$k} = unserialize(serialize($v));
}
}
}
}
/**
* Query Building Class.
*
* @package Joomla.Platform
* @subpackage Database
* @since 11.1
*/
abstract class JDatabaseQuery
{
/**
* @var JDatabase The database connection resource.
* @since 11.1
*/
protected $db = null;
/**
* @var string The query type.
* @since 11.1
*/
protected $type = '';
/**
* @var JDatabaseQueryElement The query element for a generic query (type = null).
* @since 11.1
*/
protected $element = null;
/**
* @var JDatabaseQueryElement The select element.
* @since 11.1
*/
protected $select = null;
/**
* @var JDatabaseQueryElement The delete element.
* @since 11.1
*/
protected $delete = null;
/**
* @var JDatabaseQueryElement The update element.
* @since 11.1
*/
protected $update = null;
/**
* @var JDatabaseQueryElement The insert element.
* @since 11.1
*/
protected $insert = null;
/**
* @var JDatabaseQueryElement The from element.
* @since 11.1
*/
protected $from = null;
/**
* @var JDatabaseQueryElement The join element.
* @since 11.1
*/
protected $join = null;
/**
* @var JDatabaseQueryElement The set element.
* @since 11.1
*/
protected $set = null;
/**
* @var JDatabaseQueryElement The where element.
* @since 11.1
*/
protected $where = null;
/**
* @var JDatabaseQueryElement The group by element.
* @since 11.1
*/
protected $group = null;
/**
* @var JDatabaseQueryElement The having element.
* @since 11.1
*/
protected $having = null;
/**
* @var JDatabaseQueryElement The column list for an INSERT statement.
* @since 11.1
*/
protected $columns = null;
/**
* @var JDatabaseQueryElement The values list for an INSERT statement.
* @since 11.1
*/
protected $values = null;
/**
* @var JDatabaseQueryElement The order element.
* @since 11.1
*/
protected $order = null;
/**
* @var JDatabaseQueryElement The union element.
* @since 12.1
*/
protected $union = null;
/**
* @var object The auto increment insert field element.
* @since 11.1
*/
protected $autoIncrementField = null;
/**
* Magic method to provide method alias support for quote() and quoteName().
*
* @param string $method The called method.
* @param array $args The array of arguments passed to the method.
*
* @return string The aliased method's return value or null.
*
* @since 11.1
*/
public function __call($method, $args)
{
if (empty($args))
{
return;
}
switch ($method)
{
case 'q':
return $this->quote($args[0], isset($args[1]) ? $args[1] : true);
break;
case 'qn':
return $this->quoteName($args[0]);
break;
case 'e':
return $this->escape($args[0], isset($args[1]) ? $args[1] : false);
break;
}
}
/**
* Class constructor.
*
* @param JDatabase $db The database connector resource.
*
* @since 11.1
*/
public function __construct(JDatabase $db = null)
{
$this->db = $db;
}
/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 11.1
*/
public function __toString()
{
$query = '';
switch ($this->type)
{
case 'element':
$query .= (string) $this->element;
break;
case 'select':
$query .= (string) $this->select;
$query .= (string) $this->from;
if ($this->join)
{
// special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
case 'union':
$query .= (string) $this->union;
break;
case 'delete':
$query .= (string) $this->delete;
$query .= (string) $this->from;
if ($this->join)
{
// special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
break;
case 'update':
$query .= (string) $this->update;
if ($this->join)
{
// special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
$query .= (string) $this->set;
if ($this->where)
{
$query .= (string) $this->where;
}
break;
case 'insert':
$query .= (string) $this->insert;
// Set method
if ($this->set)
{
$query .= (string) $this->set;
}
// Columns-Values method
elseif ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$query .= ' VALUES ';
$query .= (string) $this->values;
}
break;
}
return $query;
}
/**
* Magic function to get protected variable value
*
* @param string $name The name of the variable.
*
* @return mixed
*
* @since 11.1
*/
public function __get($name)
{
return isset($this->$name) ? $this->$name : null;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* Usage:
* $query->select($query->castAsChar('a'));
*
* @param string $value The value to cast as a char.
*
* @return string Returns the cast value.
*
* @since 11.1
*/
public function castAsChar($value)
{
return $value;
}
/**
* Gets the number of characters in a string.
*
* Note, use 'length' to find the number of bytes in a string.
*
* Usage:
* $query->select($query->charLength('a'));
*
* @param string $field A value.
*
* @return string The required char length call.
*
* @since 11.1
*/
public function charLength($field)
{
return 'CHAR_LENGTH(' . $field . ')';
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear, or nothing to clear the whole query.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function clear($clause = null)
{
switch ($clause)
{
case 'select':
$this->select = null;
$this->type = null;
break;
case 'delete':
$this->delete = null;
$this->type = null;
break;
case 'update':
$this->update = null;
$this->type = null;
break;
case 'insert':
$this->insert = null;
$this->type = null;
$this->autoIncrementField = null;
break;
case 'from':
$this->from = null;
break;
case 'join':
$this->join = null;
break;
case 'set':
$this->set = null;
break;
case 'where':
$this->where = null;
break;
case 'group':
$this->group = null;
break;
case 'having':
$this->having = null;
break;
case 'order':
$this->order = null;
break;
case 'columns':
$this->columns = null;
break;
case 'values':
$this->values = null;
break;
default:
$this->type = null;
$this->select = null;
$this->delete = null;
$this->update = null;
$this->insert = null;
$this->from = null;
$this->join = null;
$this->set = null;
$this->where = null;
$this->group = null;
$this->having = null;
$this->order = null;
$this->columns = null;
$this->values = null;
$this->autoIncrementField = null;
break;
}
return $this;
}
/**
* Adds a column, or array of column names that would be used for an INSERT INTO statement.
*
* @param mixed $columns A column name, or array of column names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function columns($columns)
{
if (is_null($this->columns))
{
$this->columns = new JDatabaseQueryElement('()', $columns);
}
else
{
$this->columns->append($columns);
}
return $this;
}
/**
* Concatenates an array of column names or values.
*
* Usage:
* $query->select($query->concatenate(array('a', 'b')));
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 11.1
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return 'CONCATENATE(' . implode(' || ' . $this->quote($separator) . ' || ', $values) . ')';
}
else
{
return 'CONCATENATE(' . implode(' || ', $values) . ')';
}
}
/**
* Gets the current date and time.
*
* Usage:
* $query->where('published_up < '.$query->currentTimestamp());
*
* @return string
*
* @since 11.1
*/
public function currentTimestamp()
{
return 'CURRENT_TIMESTAMP()';
}
/**
* Returns a PHP date() function compliant date format for the database driver.
*
* This method is provided for use where the query object is passed to a function for modification.
* If you have direct access to the database object, it is recommended you use the getDateFormat method directly.
*
* @return string The format string.
*
* @since 11.1
*/
public function dateFormat()
{
if (!($this->db instanceof JDatabase))
{
throw new JDatabaseException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->getDateFormat();
}
/**
* Creates a formatted dump of the query for debugging purposes.
*
* Usage:
* echo $query->dump();
*
* @return string
*
* @since 11.3
*/
public function dump()
{
return '' . str_replace('#__', $this->db->getPrefix(), $this) . '';
}
/**
* Add a table name to the DELETE clause of the query.
*
* Note that you must not mix insert, update, delete and select method calls when building a query.
*
* Usage:
* $query->delete('#__a')->where('id = 1');
*
* @param string $table The name of the table to delete from.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function delete($table = null)
{
$this->type = 'delete';
$this->delete = new JDatabaseQueryElement('DELETE', null);
if (!empty($table))
{
$this->from($table);
}
return $this;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* This method is provided for use where the query object is passed to a function for modification.
* If you have direct access to the database object, it is recommended you use the escape method directly.
*
* Note that 'e' is an alias for this method as it is in JDatabase.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 11.1
* @throws DatabaseError if the internal db property is not a valid object.
*/
public function escape($text, $extra = false)
{
if (!($this->db instanceof JDatabase))
{
throw new JDatabaseException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->escape($text, $extra);
}
/**
* Add a table to the FROM clause of the query.
*
* Note that while an array of tables can be provided, it is recommended you use explicit joins.
*
* Usage:
* $query->select('*')->from('#__a');
*
* @param mixed $tables A string or array of table names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function from($tables)
{
if (is_null($this->from))
{
$this->from = new JDatabaseQueryElement('FROM', $tables);
}
else
{
$this->from->append($tables);
}
return $this;
}
/**
* Add a grouping column to the GROUP clause of the query.
*
* Usage:
* $query->group('id');
*
* @param mixed $columns A string or array of ordering columns.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function group($columns)
{
if (is_null($this->group))
{
$this->group = new JDatabaseQueryElement('GROUP BY', $columns);
}
else
{
$this->group->append($columns);
}
return $this;
}
/**
* A conditions to the HAVING clause of the query.
*
* Usage:
* $query->group('id')->having('COUNT(id) > 5');
*
* @param mixed $conditions A string or array of columns.
* @param string $glue The glue by which to join the conditions. Defaults to AND.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function having($conditions, $glue = 'AND')
{
if (is_null($this->having))
{
$glue = strtoupper($glue);
$this->having = new JDatabaseQueryElement('HAVING', $conditions, " $glue ");
}
else
{
$this->having->append($conditions);
}
return $this;
}
/**
* Add an INNER JOIN clause to the query.
*
* Usage:
* $query->innerJoin('b ON b.id = a.id')->innerJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function innerJoin($condition)
{
$this->join('INNER', $condition);
return $this;
}
/**
* Add a table name to the INSERT clause of the query.
*
* Note that you must not mix insert, update, delete and select method calls when building a query.
*
* Usage:
* $query->insert('#__a')->set('id = 1');
* $query->insert('#__a)->columns('id, title')->values('1,2')->values->('3,4');
* $query->insert('#__a)->columns('id, title')->values(array('1,2', '3,4'));
*
* @param mixed $table The name of the table to insert data into.
* @param boolean $incrementField The name of the field to auto increment.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function insert($table, $incrementField=false)
{
$this->type = 'insert';
$this->insert = new JDatabaseQueryElement('INSERT INTO', $table);
$this->autoIncrementField = $incrementField;
return $this;
}
/**
* Add a JOIN clause to the query.
*
* Usage:
* $query->join('INNER', 'b ON b.id = a.id);
*
* @param string $type The type of join. This string is prepended to the JOIN keyword.
* @param string $conditions A string or array of conditions.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function join($type, $conditions)
{
if (is_null($this->join))
{
$this->join = array();
}
$this->join[] = new JDatabaseQueryElement(strtoupper($type) . ' JOIN', $conditions);
return $this;
}
/**
* Add a LEFT JOIN clause to the query.
*
* Usage:
* $query->leftJoin('b ON b.id = a.id')->leftJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function leftJoin($condition)
{
$this->join('LEFT', $condition);
return $this;
}
/**
* Get the length of a string in bytes.
*
* Note, use 'charLength' to find the number of characters in a string.
*
* Usage:
* query->where($query->length('a').' > 3');
*
* @param string $value The string to measure.
*
* @return int
*
* @since 11.1
*/
public function length($value)
{
return 'LENGTH(' . $value . ')';
}
/**
* Get the null or zero representation of a timestamp for the database driver.
*
* This method is provided for use where the query object is passed to a function for modification.
* If you have direct access to the database object, it is recommended you use the nullDate method directly.
*
* Usage:
* $query->where('modified_date <> '.$query->nullDate());
*
* @param boolean $quoted Optionally wraps the null date in database quotes (true by default).
*
* @return string Null or zero representation of a timestamp.
*
* @since 11.1
*/
public function nullDate($quoted = true)
{
if (!($this->db instanceof JDatabase))
{
throw new JDatabaseException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
$result = $this->db->getNullDate($quoted);
if ($quoted)
{
return $this->db->quote($result);
}
return $result;
}
/**
* Add a ordering column to the ORDER clause of the query.
*
* Usage:
* $query->order('foo')->order('bar');
* $query->order(array('foo','bar'));
*
* @param mixed $columns A string or array of ordering columns.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function order($columns)
{
if (is_null($this->order))
{
$this->order = new JDatabaseQueryElement('ORDER BY', $columns);
}
else
{
$this->order->append($columns);
}
return $this;
}
/**
* Add an OUTER JOIN clause to the query.
*
* Usage:
* $query->outerJoin('b ON b.id = a.id')->outerJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function outerJoin($condition)
{
$this->join('OUTER', $condition);
return $this;
}
/**
* Method to quote and optionally escape a string to database requirements for insertion into the database.
*
* This method is provided for use where the query object is passed to a function for modification.
* If you have direct access to the database object, it is recommended you use the quote method directly.
*
* Note that 'q' is an alias for this method as it is in JDatabase.
*
* Usage:
* $query->quote('fulltext');
* $query->q('fulltext');
*
* @param string $text The string to quote.
* @param boolean $escape True to escape the string, false to leave it unchanged.
*
* @return string The quoted input string.
*
* @since 11.1
* @throws DatabaseError if the internal db property is not a valid object.
*/
public function quote($text, $escape = true)
{
if (!($this->db instanceof JDatabase))
{
throw new JDatabaseException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->quote(($escape ? $this->db->escape($text) : $text));
}
/**
* Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
* risks and reserved word conflicts.
*
* This method is provided for use where the query object is passed to a function for modification.
* If you have direct access to the database object, it is recommended you use the quoteName method directly.
*
* Note that 'qn' is an alias for this method as it is in JDatabase.
*
* Usage:
* $query->quoteName('#__a');
* $query->qn('#__a');
*
* @param string $name The identifier name to wrap in quotes.
*
* @return string The quote wrapped name.
*
* @since 11.1
* @throws DatabaseError if the internal db property is not a valid object.
*/
public function quoteName($name)
{
if (!($this->db instanceof JDatabase))
{
throw new JDatabaseException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->quoteName($name);
}
/**
* Add a RIGHT JOIN clause to the query.
*
* Usage:
* $query->rightJoin('b ON b.id = a.id')->rightJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function rightJoin($condition)
{
$this->join('RIGHT', $condition);
return $this;
}
/**
* Add a single column, or array of columns to the SELECT clause of the query.
*
* Note that you must not mix insert, update, delete and select method calls when building a query.
* The select method can, however, be called multiple times in the same query.
*
* Usage:
* $query->select('a.*')->select('b.id');
* $query->select(array('a.*', 'b.id'));
*
* @param mixed $columns A string or an array of field names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function select($columns)
{
$this->type = 'select';
if (is_null($this->select))
{
$this->select = new JDatabaseQueryElement('SELECT', $columns);
}
else
{
$this->select->append($columns);
}
return $this;
}
/**
* Add a single condition string, or an array of strings to the SET clause of the query.
*
* Usage:
* $query->set('a = 1')->set('b = 2');
* $query->set(array('a = 1', 'b = 2');
*
* @param mixed $conditions A string or array of string conditions.
* @param string $glue The glue by which to join the condition strings. Defaults to ,.
* Note that the glue is set on first use and cannot be changed.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function set($conditions, $glue = ',')
{
if (is_null($this->set))
{
$glue = strtoupper($glue);
$this->set = new JDatabaseQueryElement('SET', $conditions, "\n\t$glue ");
}
else
{
$this->set->append($conditions);
}
return $this;
}
/**
* Add a table name to the UPDATE clause of the query.
*
* Note that you must not mix insert, update, delete and select method calls when building a query.
*
* Usage:
* $query->update('#__foo')->set(...);
*
* @param string $table A table to update.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function update($table)
{
$this->type = 'update';
$this->update = new JDatabaseQueryElement('UPDATE', $table);
return $this;
}
/**
* Adds a tuple, or array of tuples that would be used as values for an INSERT INTO statement.
*
* Usage:
* $query->values('1,2,3')->values('4,5,6');
* $query->values(array('1,2,3', '4,5,6'));
*
* @param string $values A single tuple, or array of tuples.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function values($values)
{
if (is_null($this->values))
{
$this->values = new JDatabaseQueryElement('()', $values, '),(');
}
else
{
$this->values->append($values);
}
return $this;
}
/**
* Add a single condition, or an array of conditions to the WHERE clause of the query.
*
* Usage:
* $query->where('a = 1')->where('b = 2');
* $query->where(array('a = 1', 'b = 2'));
*
* @param mixed $conditions A string or array of where conditions.
* @param string $glue The glue by which to join the conditions. Defaults to AND.
* Note that the glue is set on first use and cannot be changed.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 11.1
*/
public function where($conditions, $glue = 'AND')
{
if (is_null($this->where))
{
$glue = strtoupper($glue);
$this->where = new JDatabaseQueryElement('WHERE', $conditions, " $glue ");
}
else
{
$this->where->append($conditions);
}
return $this;
}
/**
* Method to provide deep copy support to nested objects and
* arrays when cloning.
*
* @return void
*
* @since 11.3
*/
public function __clone()
{
foreach ($this as $k => $v)
{
if ($k === 'db')
{
continue;
}
if (is_object($v) || is_array($v))
{
$this->$k = unserialize(serialize($v));
}
}
}
/**
* Add a query to UNION with the current query.
* Multiple unions each require separate statements and create an array of unions.
*
* Usage:
* $query->union('SELECT name FROM #__foo')
* $query->union('SELECT name FROM #__foo','distinct')
* $query->union(array('SELECT name FROM #__foo','SELECT name FROM #__bar'))
*
* @param mixed $query The JDatabaseQuery object or string to union.
* @param boolean $distinct True to only return distinct rows from the union.
* @param string $glue The glue by which to join the conditions.
*
* @return mixed The JDatabaseQuery object on success or boolean false on failure.
*
* @since 12.1
*/
public function union($query, $distinct = false, $glue = '')
{
// Clear any ORDER BY clause in UNION query
// See http://dev.mysql.com/doc/refman/5.0/en/union.html
if (!is_null($this->order))
{
$this->clear('order');
}
// Set up the DISTINCT flag, the name with parentheses, and the glue.
if ($distinct)
{
$name = 'UNION DISTINCT ()';
$glue = ')' . PHP_EOL . 'UNION DISTINCT (';
}
else
{
$glue = ')' . PHP_EOL . 'UNION (';
$name = 'UNION ()';
}
// Get the JDatabaseQueryElement if it does not exist
if (is_null($this->union))
{
$this->union = new JDatabaseQueryElement($name, $query, "$glue");
}
// Otherwise append the second UNION.
else
{
$glue = '';
$this->union->append($query);
}
return $this;
}
/**
* Add a query to UNION DISTINCT with the current query. Simply a proxy to Union with the Distinct clause.
*
* Usage:
* $query->unionDistinct('SELECT name FROM #__foo')
*
* @param mixed $query The JDatabaseQuery object or string to union.
* @param string $glue The glue by which to join the conditions.
*
* @return mixed The JDatabaseQuery object on success or boolean false on failure.
*
* @since 12.1
*/
public function unionDistinct($query, $glue = '')
{
$distinct = true;
// Apply the distinct flag to the union.
return $this->union($query, $distinct, $glue);
}
}
PK ?\D mysqliexporter.phpnu W+A db instanceof JDatabaseMySqli))
{
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 JDatabaseMySQLi $db The database connector.
*
* @return JDatabaseExporterMySQLi Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQLi $db)
{
$this->db = $db;
return $this;
}
}
PK ?\+= sqlazurequery.phpnu W+A $options['database'],
'uid' => $options['user'],
'pwd' => $options['password'],
'CharacterSet' => 'UTF-8',
'ReturnDatesAsStrings' => true);
// Make sure the SQLSRV extension for PHP is installed and enabled.
if (!function_exists('sqlsrv_connect'))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_SQLSRV');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_SQLSRV'));
}
}
// Attempt to connect to the server.
if (!($this->connection = @ sqlsrv_connect($options['host'], $config)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_SQLSRV');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_SQLSRV'));
}
}
// Make sure that DB warnings are not returned as errors.
sqlsrv_configure('WarningsReturnAsErrors', 0);
// Finalize initialisation
parent::__construct($options);
// If auto-select is enabled select the given database.
if ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_resource($this->connection))
{
sqlsrv_close($this->connection);
}
}
/**
* Get table constraints
*
* @param string $tableName The name of the database table.
*
* @return array Any constraints available for the table.
*
* @since 11.1
*/
protected function getTableConstraints($tableName)
{
$query = $this->getQuery(true);
$this->setQuery(
'SELECT CONSTRAINT_NAME FROM' . ' INFORMATION_SCHEMA.TABLE_CONSTRAINTS' . ' WHERE TABLE_NAME = ' . $query->quote($tableName)
);
return $this->loadColumn();
}
/**
* Rename constraints.
*
* @param array $constraints Array(strings) of table constraints
* @param string $prefix A string
* @param string $backup A string
*
* @return void
*
* @since 11.1
*/
protected function renameConstraints($constraints = array(), $prefix = null, $backup = null)
{
foreach ($constraints as $constraint)
{
$this->setQuery('sp_rename ' . $constraint . ',' . str_replace($prefix, $backup, $constraint));
$this->execute();
}
}
/**
* Method to escape a string for usage in an SQL statement.
*
* The escaping for MSSQL isn't handled in the driver though that would be nice. Because of this we need
* to handle the escaping ourselves.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 11.1
*/
public function escape($text, $extra = false)
{
$result = addslashes($text);
$result = str_replace("\'", "''", $result);
$result = str_replace('\"', '"', $result);
$result = str_replace('\\\/', '/', $result);
$result = str_replace('\\\\', '\\', $result);
if ($extra)
{
// We need the below str_replace since the search in sql server doesn't recognize _ character.
$result = str_replace('_', '[_]', $result);
}
return $result;
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
// TODO: Run a blank query here
return true;
}
/**
* 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 JDatabaseSQLSrv Returns this object to support chaining.
*
* @since 11.1
* @throws JDatabaseException
*/
public function dropTable($tableName, $ifExists = true)
{
$query = $this->getQuery(true);
if ($ifExists)
{
$this->setQuery(
'IF EXISTS(SELECT TABLE_NAME FROM' . ' INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ' . $query->quote($tableName) . ') DROP TABLE ' . $tableName
);
}
else
{
$this->setQuery('DROP TABLE ' . $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 11.1
*/
public function getAffectedRows()
{
return sqlsrv_rows_affected($this->cursor);
}
/**
* 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 11.1
*/
public function getCollation()
{
// TODO: Not fake this
return 'MSSQL UTF-8 (UCS2)';
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterSQLAzure An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterSQLAzure'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterSQLAzure;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterSQLAzure An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterSQLAzure'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterSQLAzure;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return sqlsrv_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQuerySQLSrv'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQuerySQLSrv($this);
}
else
{
return $this->sql;
}
}
/**
* Retrieves field information about the given tables.
*
* @param mixed $table A table name
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableColumns($table, $typeOnly = true)
{
// Initialise variables.
$result = array();
$table_temp = $this->replacePrefix((string) $table);
// Set the query to get the table fields statement.
$this->setQuery(
'SELECT column_name as Field, data_type as Type, is_nullable as \'Null\', column_default as \'Default\'' .
' FROM information_schema.columns' . ' WHERE table_name = ' . $this->quote($table_temp)
);
$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;
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* This is unsupported by MSSQL.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableCreate($tables)
{
return '';
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function getTableKeys($table)
{
// TODO To implement.
return array();
}
/**
* Method to quote and optionally escape a string to database requirements for insertion into the database.
*
* @param string $text The string to quote.
* @param boolean $escape True to escape the string, false to leave it unchanged.
*
* @return string The quoted input string.
*
* @since 11.1
*/
public function quote($text, $escape = true)
{
return 'N' . '\'' . ($escape ? $this->escape($text) : $text) . '\'';
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getTableList()
{
// Set the query to get the tables statement.
$this->setQuery('SELECT name FROM ' . $this->getDatabase() . '.sys.Tables WHERE type = \'U\';');
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 11.1
*/
public function getVersion()
{
$version = sqlsrv_server_info($this->connection);
return $version['SQLServerVersion'];
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
*/
public function hasUTF()
{
return true;
}
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert into.
* @param object &$object A reference to an object whose public properties match the table fields.
* @param string $key The name of the primary key. If provided the object property is updated.
*
* @return boolean True on success.
*
* @since 11.1
* @throws JDatabaseException
*/
public function insertObject($table, &$object, $key = null)
{
$fields = array();
$values = array();
$statement = 'INSERT INTO ' . $this->quoteName($table) . ' (%s) VALUES (%s)';
foreach (get_object_vars($object) as $k => $v)
{
if (is_array($v) or is_object($v))
{
continue;
}
if (!$this->checkFieldExists($table, $k))
{
continue;
}
if ($k[0] == '_')
{
// internal field
continue;
}
if ($k == $key && $key == 0)
{
continue;
}
$fields[] = $this->quoteName($k);
$values[] = $this->Quote($v);
}
// Set the query and execute the insert.
$this->setQuery(sprintf($statement, implode(',', $fields), implode(',', $values)));
if (!$this->execute())
{
return false;
}
$id = $this->insertid();
if ($key && $id)
{
$object->$key = $id;
}
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
// TODO: SELECT IDENTITY
$this->setQuery('SELECT @@IDENTITY');
return (int) $this->loadResult();
}
/**
* Method to get the first field of the first row of the result set from the database query.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws JDatabaseException
*/
public function loadResult()
{
// Initialise variables.
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Get the first row from the result set as an array.
if ($row = sqlsrv_fetch_array($cursor, SQLSRV_FETCH_NUMERIC))
{
$ret = $row[0];
}
// Free up system resources and return.
$this->freeResult($cursor);
//For SQLServer - we need to strip slashes
$ret = stripslashes($ret);
return $ret;
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_resource($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseDriverSQLAzure::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) && ($this->limit > 0 || $this->offset > 0))
{
$sql = $this->limit($sql, $this->limit, $this->offset);
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// sqlsrv_num_rows requires a static or keyset cursor.
if (strncmp(ltrim(strtoupper($sql)), 'SELECT', strlen('SELECT')) == 0)
{
$array = array('Scrollable' => SQLSRV_CURSOR_KEYSET);
}
else
{
$array = array();
}
// Execute the query.
$this->cursor = sqlsrv_query($this->connection, $sql, array(), $array);
// If an error occurred handle it.
if (!$this->cursor)
{
// Populate the errors.
$errors = sqlsrv_errors();
$this->errorNum = $errors[0]['SQLSTATE'];
$this->errorMsg = $errors[0]['message'] . 'SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseDriverSQLAzure::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
return $this->cursor;
}
/**
* This function replaces a string identifier $prefix with the string held is the
* tablePrefix class variable.
*
* @param string $sql The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 11.1
*/
public function replacePrefix($sql, $prefix = '#__')
{
$tablePrefix = 'jos_';
// Initialize variables.
$escaped = false;
$startPos = 0;
$quoteChar = '';
$literal = '';
$sql = trim($sql);
$n = strlen($sql);
while ($startPos < $n)
{
$ip = strpos($sql, $prefix, $startPos);
if ($ip === false)
{
break;
}
$j = strpos($sql, "N'", $startPos);
$k = strpos($sql, '"', $startPos);
if (($k !== false) && (($k < $j) || ($j === false)))
{
$quoteChar = '"';
$j = $k;
}
else
{
$quoteChar = "'";
}
if ($j === false)
{
$j = $n;
}
$literal .= str_replace($prefix, $this->tablePrefix, substr($sql, $startPos, $j - $startPos));
$startPos = $j;
$j = $startPos + 1;
if ($j >= $n)
{
break;
}
// quote comes first, find end of quote
while (true)
{
$k = strpos($sql, $quoteChar, $j);
$escaped = false;
if ($k === false)
{
break;
}
$l = $k - 1;
while ($l >= 0 && $sql{$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($sql, $startPos, $k - $startPos + 1);
$startPos = $k + 1;
}
if ($startPos < $n)
{
$literal .= substr($sql, $startPos, $n - $startPos);
}
return $literal;
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!sqlsrv_query($this->connection, 'USE ' . $database, null, array('scrollable' => SQLSRV_CURSOR_STATIC)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
// TODO: Remove this?
}
/**
* Method to commit a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionCommit()
{
$this->setQuery('COMMIT TRANSACTION');
$this->execute();
}
/**
* Method to roll back a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionRollback()
{
$this->setQuery('ROLLBACK TRANSACTION');
$this->execute();
}
/**
* Method to initialize a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionStart()
{
$this->setQuery('START TRANSACTION');
$this->execute();
}
/**
* 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 11.1
*/
protected function fetchArray($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor, SQLSRV_FETCH_NUMERIC);
}
/**
* 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 11.1
*/
protected function fetchAssoc($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor, SQLSRV_FETCH_ASSOC);
}
/**
* 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 11.1
*/
protected function fetchObject($cursor = null, $class = 'stdClass')
{
return sqlsrv_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 11.1
*/
protected function freeResult($cursor = null)
{
sqlsrv_free_stmt($cursor ? $cursor : $this->cursor);
}
/**
* Diagnostic method to return explain information for a query.
*
* @return string The explain output.
*
* @deprecated 12.1
* @see http://msdn.microsoft.com/en-us/library/aa259203%28SQL.80%29.aspx
* @since 11.1
*/
public function explain()
{
// Deprecation warning.
JLog::add('JDatabase::explain() is deprecated.', JLog::WARNING, 'deprecated');
// Backup the current query so we can reset it later.
$backup = $this->sql;
// SET SHOWPLAN_ALL ON - will make sqlsrv to show some explain of query instead of run it
$this->setQuery('SET SHOWPLAN_ALL ON');
$this->execute();
// Execute the query and get the result set cursor.
$this->setQuery($backup);
if (!($cursor = $this->execute()))
{
return null;
}
// Build the HTML table.
$first = true;
$buffer = '';
$buffer .= '| ' . $this->getQuery() . ' |
';
while ($row = $this->fetchAssoc($cursor))
{
if ($first)
{
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $k . ' | ';
}
$buffer .= '
';
$first = false;
}
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $v . ' | ';
}
$buffer .= '
';
}
$buffer .= '
';
// Free up system resources and return.
$this->freeResult($cursor);
// Remove the explain status.
$this->setQuery('SET SHOWPLAN_ALL OFF');
$this->execute();
// Restore the original query to its state before we ran the explain.
$this->sql = $backup;
return $buffer;
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @since 11.1
* @deprecated 12.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabase::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$this->_sql = 'BEGIN TRANSACTION;' . $this->sql . '; COMMIT TRANSACTION;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = sqlsrv_query($this->connection, $query, null, array('scrollable' => SQLSRV_CURSOR_STATIC));
if ($this->_debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$errors = sqlsrv_errors();
$this->errorNum = $errors[0]['sqlstate'];
$this->errorMsg = $errors[0]['message'];
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
/**
* Method to check and see if a field exists in a table.
*
* @param string $table The table in which to verify the field.
* @param string $field The field to verify.
*
* @return boolean True if the field exists in the table.
*
* @since 11.1
*/
protected function checkFieldExists($table, $field)
{
$table = $this->replacePrefix((string) $table);
$sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS" . " WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" .
" ORDER BY ORDINAL_POSITION";
$this->setQuery($sql);
if ($this->loadResult())
{
return true;
}
else
{
return false;
}
}
/**
* Method to wrap an SQL statement to provide a LIMIT and OFFSET behavior for scrolling through a result set.
*
* @param string $sql The SQL statement to process.
* @param integer $limit The maximum affected rows to set.
* @param integer $offset The affected row offset to set.
*
* @return string The processed SQL statement.
*
* @since 11.1
*/
protected function limit($sql, $limit, $offset)
{
if ($limit == 0 && $offset == 0)
{
return $sql;
}
$start = $offset + 1;
$end = $offset + $limit;
$orderBy = stristr($sql, 'ORDER BY');
if (is_null($orderBy) || empty($orderBy))
{
$orderBy = 'ORDER BY (select 0)';
}
$sql = str_ireplace($orderBy, '', $sql);
$rowNumberText = ', ROW_NUMBER() OVER (' . $orderBy . ') AS RowNumber FROM ';
$sql = preg_replace('/\sFROM\s/i', $rowNumberText, $sql, 1);
$sql = 'SELECT * FROM (' . $sql . ') _myResults WHERE RowNumber BETWEEN ' . $start . ' AND ' . $end;
return $sql;
}
/**
* 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 Table prefix
* @param string $prefix For the table - used to rename constraints in non-mysql databases
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
{
$constraints = array();
if (!is_null($prefix) && !is_null($backup))
{
$constraints = $this->getTableConstraints($oldTable);
}
if (!empty($constraints))
{
$this->renameConstraints($constraints, $prefix, $backup);
}
$this->setQuery("sp_rename '" . $oldTable . "', '" . $newTable . "'");
return $this->execute();
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to lock.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function lockTable($tableName)
{
return $this;
}
/**
* Unlocks tables in the database.
*
* @return JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function unlockTables()
{
return $this;
}
}
PK ?\d= = mysqlimporter.phpnu W+A options = new JObject;
$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 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 JDatabaseMySql))
{
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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySQL($keys);
return $sql;
}
/**
* 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)
{
// Initialise variables.
$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 '';
// echo '
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 '
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 '
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 '
Collation: '.
// ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '.
// (string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation;
// echo '
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 '
Same = '.($same ? 'true' : 'false');
// echo '
';
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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
. $this->getColumnSQL($field);
return $sql;
}
/**
* 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)
{
// Initialise variables.
// 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'];
$sql = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$sql .= ' NOT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault);
}
}
else
{
if ($fDefault === null)
{
$sql .= ' DEFAULT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' DEFAULT ' . $this->db->quote($fDefault);
}
}
if ($fExtra)
{
$sql .= ' ' . strtoupper($fExtra);
}
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
return $sql;
}
/**
* 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)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
*
* @return string
*
* @since 11.1
*/
protected function getDropPrimaryKeySQL($table)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY';
return $sql;
}
/**
* 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'];
}
}
$sql = $prefix . 'KEY ' . ($kName != 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')';
return $sql;
}
/**
* 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()
{
// Initialise variables.
$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((string) $query);
if (!$this->db->execute())
{
$this->addLog('Fail: ' . $this->db->getQuery());
throw new Exception($this->db->getErrorMsg());
}
else
{
$this->addLog('Pass: ' . $this->db->getQuery());
}
}
}
}
else
{
// This is a new table.
$sql = $this->xmlToCreate($table);
$this->db->setQuery((string) $sql);
if (!$this->db->execute())
{
$this->addLog('Fail: ' . $this->db->getQuery());
throw new Exception($this->db->getErrorMsg());
}
else
{
$this->addLog('Pass: ' . $this->db->getQuery());
}
}
}
}
/**
* Sets the database connector to use for exporting structure and/or data from MySQL.
*
* @param JDatabaseMySQL $db The database connector.
*
* @return JDatabaseImporterMySQL Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQL $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->set('with-structure', (boolean) $setting);
return $this;
}
}
PK ?\pQ pQ mysql.phpnu W+A errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQL'));
}
}
// Attempt to connect to the server.
if (!($this->connection = @ mysql_connect($options['host'], $options['user'], $options['password'], true)))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL'));
}
}
// Finalize initialisation
parent::__construct($options);
// 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 ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_resource($this->connection))
{
mysql_close($this->connection);
}
}
/**
* 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 11.1
*/
public function escape($text, $extra = false)
{
$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 11.1
*/
public static function test()
{
return (function_exists('mysql_connect'));
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
if (is_resource($this->connection))
{
return mysql_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 JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.1
* @throws JDatabaseException
*/
public function dropTable($tableName, $ifExists = true)
{
$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 11.1
*/
public function getAffectedRows()
{
return mysql_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 11.1
* @throws JDatabaseException
*/
public function getCollation()
{
$this->setQuery('SHOW FULL COLUMNS FROM #__users');
$array = $this->loadAssocList();
return $array['2']['Collation'];
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterMySQL An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterMySQL;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterMySQL An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterMySQL;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return mysql_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQueryMySQL'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQueryMySQL($this);
}
else
{
return $this->sql;
}
}
/**
* 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 11.1
* @throws JDatabaseException
*/
public function getTableCreate($tables)
{
// Initialise variables.
$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 11.1
* @throws JDatabaseException
*/
public function getTableColumns($table, $typeOnly = true)
{
$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 11.1
* @throws JDatabaseException
*/
public function getTableKeys($table)
{
// 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 11.1
* @throws JDatabaseException
*/
public function getTableList()
{
// 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 11.1
*/
public function getVersion()
{
return mysql_get_server_info($this->connection);
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
* @deprecated 12.1
*/
public function hasUTF()
{
JLog::add('JDatabaseMySQL::hasUTF() is deprecated.', JLog::WARNING, 'deprecated');
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
return mysql_insert_id($this->connection);
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
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 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_resource($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQL::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if ($this->limit > 0 || $this->offset > 0)
{
$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// Execute the query.
$this->cursor = mysql_query($sql, $this->connection);
// If an error occurred handle it.
if (!$this->cursor)
{
$this->errorNum = (int) mysql_errno($this->connection);
$this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQL::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($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 JDatabase Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!mysql_select_db($database, $this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
return mysql_set_charset('utf8', $this->connection);
}
/**
* Method to commit a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionCommit()
{
$this->setQuery('COMMIT');
$this->execute();
}
/**
* Method to roll back a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionRollback()
{
$this->setQuery('ROLLBACK');
$this->execute();
}
/**
* Method to initialize a transaction.
*
* @return void
*
* @since 11.1
* @throws JDatabaseException
*/
public function transactionStart()
{
$this->setQuery('START TRANSACTION');
$this->execute();
}
/**
* 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 11.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 11.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 11.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 11.1
*/
protected function freeResult($cursor = null)
{
mysql_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Diagnostic method to return explain information for a query.
*
* @return string The explain output.
*
* @since 11.1
* @deprecated 12.1
*/
public function explain()
{
// Deprecation warning.
JLog::add('JDatabaseMySQL::explain() is deprecated.', JLog::WARNING, 'deprecated');
// Backup the current query so we can reset it later.
$backup = $this->sql;
// Prepend the current query with EXPLAIN so we get the diagnostic data.
$this->sql = 'EXPLAIN ' . $this->sql;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return null;
}
// Build the HTML table.
$first = true;
$buffer = '';
$buffer .= '| ' . $this->getQuery() . ' |
';
while ($row = $this->fetchAssoc($cursor))
{
if ($first)
{
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $k . ' | ';
}
$buffer .= '
';
$first = false;
}
$buffer .= '';
foreach ($row as $k => $v)
{
$buffer .= '| ' . $v . ' | ';
}
$buffer .= '
';
}
$buffer .= '
';
// Restore the original query to its state before we ran the explain.
$this->sql = $backup;
// Free up system resources and return.
$this->freeResult($cursor);
return $buffer;
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @deprecated 12.1
* @since 11.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabaseMySQL::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$sql = 'START TRANSACTION;' . rtrim($sql, "; \t\r\n\0") . '; COMMIT;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = mysql_query($query, $this->connection);
if ($this->debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$this->errorNum .= mysql_errno($this->connection) . ' ';
$this->errorMsg .= mysql_error($this->connection) . " SQL=$query
";
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseMySQL Returns this object to support chaining.
*
* @since 11.4
* @throws JDatabaseException
*/
public function unlockTables()
{
$this->setQuery('UNLOCK TABLES')->execute();
return $this;
}
}
PK ?\3 sqlazure.phpnu W+A sql;
}
}
}
PK ?\m{ mysqlquery.phpnu W+A quote($separator);
foreach ($values as $value)
{
$concat_string .= ', ' . $value;
}
return $concat_string . ')';
}
else
{
return 'CONCAT(' . implode(',', $values) . ')';
}
}
}
PK ?\ mysqliimporter.phpnu W+A db instanceof JDatabaseMySqli))
{
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 JDatabaseMySQLi $db The database connector.
*
* @return JDatabaseImporterMySQLi Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQLi $db)
{
$this->db = $db;
return $this;
}
}
PK ?\Oi^ ^ mysqlexporter.phpnu W+A options = new JObject;
$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();
$buffer = '';
// Get the format.
switch ($this->asFormat)
{
case 'xml':
default:
$buffer = $this->buildXml();
break;
}
return $buffer;
}
/**
* 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[] = '';
$buffer[] = '';
$buffer[] = ' ';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' ';
$buffer[] = '';
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);
$keys = $this->db->getTableKeys($table);
$buffer[] = ' ';
foreach ($fields as $field)
{
$buffer[] = ' Default) ? ' Default="' . $field->Default . '"' : '') . ' Extra="' . $field->Extra . '"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' ';
}
$buffer[] = ' ';
}
return $buffer;
}
/**
* 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 JDatabaseMySQL))
{
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 JDatabaseMySQL $db The database connector.
*
* @return JDatabaseExporterMySQL Method supports chaining.
*
* @since 11.1
*/
public function setDbo(JDatabaseMySQL $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->set('with-structure', (boolean) $setting);
return $this;
}
}
PK ?\6 6
mysqli.phpnu W+A errorNum = 1;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI'));
}
}
$this->connection = @mysqli_connect(
$options['host'], $options['user'], $options['password'], null, $options['port'], $options['socket']
);
// Attempt to connect to the server.
if (!$this->connection)
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 2;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL');
return;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL'));
}
}
// Finalize initialisation
JDatabase::__construct($options);
// 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 ($options['select'] && !empty($options['database']))
{
$this->select($options['database']);
}
}
/**
* Destructor.
*
* @since 11.1
*/
public function __destruct()
{
if (is_callable(array($this->connection, 'close')))
{
mysqli_close($this->connection);
}
}
/**
* 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 11.1
*/
public function escape($text, $extra = false)
{
$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 11.1
*/
public static function test()
{
return (function_exists('mysqli_connect'));
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 11.1
*/
public function connected()
{
if (is_object($this->connection))
{
return mysqli_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 11.1
*/
public function getAffectedRows()
{
return mysqli_affected_rows($this->connection);
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporterMySQLi An exporter object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getExporter()
{
// Make sure we have an exporter class for this driver.
if (!class_exists('JDatabaseExporterMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
}
$o = new JDatabaseExporterMySQLi;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporterMySQLi An importer object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getImporter()
{
// Make sure we have an importer class for this driver.
if (!class_exists('JDatabaseImporterMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
}
$o = new JDatabaseImporterMySQLi;
$o->setDbo($this);
return $o;
}
/**
* 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 11.1
*/
public function getNumRows($cursor = null)
{
return mysqli_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to return a new JDatabaseQuery object.
*
* @return mixed The current value of the internal SQL variable or a new JDatabaseQuery object.
*
* @since 11.1
* @throws JDatabaseException
*/
public function getQuery($new = false)
{
if ($new)
{
// Make sure we have a query class for this driver.
if (!class_exists('JDatabaseQueryMySQLi'))
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
}
return new JDatabaseQueryMySQLi($this);
}
else
{
return $this->sql;
}
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 11.1
*/
public function getVersion()
{
return mysqli_get_server_info($this->connection);
}
/**
* Determines if the database engine supports UTF-8 character encoding.
*
* @return boolean True if supported.
*
* @since 11.1
* @deprecated 12.1
*/
public function hasUTF()
{
JLog::add('JDatabaseMySQLi::hasUTF() is deprecated.', JLog::WARNING, 'deprecated');
return true;
}
/**
* 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 11.1
*/
public function insertid()
{
return mysqli_insert_id($this->connection);
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on failure.
*
* @since 11.1
* @throws JDatabaseException
*/
public function execute()
{
if (!is_object($this->connection))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
throw new JDatabaseException($this->errorMsg, $this->errorNum);
}
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->replacePrefix((string) $this->sql);
if ($this->limit > 0 || $this->offset > 0)
{
$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
}
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Increment the query counter and add the query to the object queue.
$this->count++;
$this->log[] = $sql;
JLog::add($sql, JLog::DEBUG, 'databasequery');
}
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// Execute the query.
$this->cursor = mysqli_query($this->connection, $sql);
// If an error occurred handle it.
if (!$this->cursor)
{
$this->errorNum = (int) mysqli_errno($this->connection);
$this->errorMsg = (string) mysqli_error($this->connection) . ' SQL=' . $sql;
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
if ($this->debug)
{
JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
}
return false;
}
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
throw new JDatabaseException($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 11.1
* @throws JDatabaseException
*/
public function select($database)
{
if (!$database)
{
return false;
}
if (!mysqli_select_db($this->connection, $database))
{
// Legacy error handling switch based on the JError::$legacy switch.
// @deprecated 12.1
if (JError::$legacy)
{
$this->errorNum = 3;
$this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
return false;
}
else
{
throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
}
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function setUTF()
{
mysqli_set_charset($this->connection, 'utf8');
}
/**
* 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 11.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 11.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 11.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 11.1
*/
protected function freeResult($cursor = null)
{
mysqli_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Execute a query batch.
*
* @param boolean $abortOnError Abort on error.
* @param boolean $transactionSafe Transaction safe queries.
*
* @return mixed A database resource if successful, false if not.
*
* @deprecated 12.1
* @since 11.1
*/
public function queryBatch($abortOnError = true, $transactionSafe = false)
{
// Deprecation warning.
JLog::add('JDatabaseMySQLi::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');
$sql = $this->replacePrefix((string) $this->sql);
$this->errorNum = 0;
$this->errorMsg = '';
// If the batch is meant to be transaction safe then we need to wrap it in a transaction.
if ($transactionSafe)
{
$sql = 'START TRANSACTION;' . rtrim($sql, "; \t\r\n\0") . '; COMMIT;';
}
$queries = $this->splitSql($sql);
$error = 0;
foreach ($queries as $query)
{
$query = trim($query);
if ($query != '')
{
$this->cursor = mysqli_query($this->connection, $query);
if ($this->debug)
{
$this->count++;
$this->log[] = $query;
}
if (!$this->cursor)
{
$error = 1;
$this->errorNum .= mysqli_errno($this->connection) . ' ';
$this->errorMsg .= mysqli_error($this->connection) . " SQL=$query
";
if ($abortOnError)
{
return $this->cursor;
}
}
}
}
return $error ? false : true;
}
}
PK ?\a5 mysqliquery.phpnu W+A type)
{
case 'select':
$query .= (string) $this->select;
$query .= (string) $this->from;
// Get the limit and offset values from JDatabase
$limit = $this->db->getLimit();
$offset = $this->db->getOffset();
if ($limit > 0 || $offset > 0)
{
if ($this->order)
{
$query .= (string) $this->order;
}
$query = $this->processLimit($query, $limit, $offset);
}
if ($this->join)
{
// special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
break;
case 'insert':
$query .= (string) $this->insert;
// Set method
if ($this->set)
{
$query .= (string) $this->set;
}
// Columns-Values method
elseif ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$elements = $this->insert->getElements();
$tableName = array_shift($elements);
$query .= 'VALUES ';
$query .= (string) $this->values;
if ($this->autoIncrementField)
{
$query = 'SET IDENTITY_INSERT ' . $tableName . ' ON;' . $query . 'SET IDENTITY_INSERT ' . $tableName . ' OFF;';
}
if ($this->where)
{
$query .= (string) $this->where;
}
}
break;
default:
$query = parent::__toString();
break;
}
return $query;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* @param string $value The value to cast as a char.
*
* @return string Returns the cast value.
*
* @since 11.1
*/
public function castAsChar($value)
{
return 'CAST(' . $value . ' as NVARCHAR(10))';
}
/**
* Gets the function to determine the length of a character string.
*
* @param string $field A value.
*
* @return string The required char length call.
*
* @since 11.1
*/
public function charLength($field)
{
return 'DATALENGTH(' . $field . ') IS NOT NULL';
}
/**
* Concatenates an array of column names or values.
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 11.1
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return '(' . implode('+' . $this->quote($separator) . '+', $values) . ')';
}
else
{
return '(' . implode('+', $values) . ')';
}
}
/**
* Gets the current date and time.
*
* @return string
*
* @since 11.1
*/
public function currentTimestamp()
{
return 'GETDATE()';
}
/**
* Get the length of a string in bytes.
*
* @param string $value The string to measure.
*
* @return integer
*
* @since 11.1
*/
public function length($value)
{
return 'LEN(' . $value . ')';
}
/**
* Method to modify a query already in string format with the needed
* additions to make the query limited to a particular number of
* results, or start at a particular offset.
*
* @param string $query The query in string format
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return string
*
* @since 12.1
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit == 0 && $offset == 0)
{
return $query;
}
$start = $offset + 1;
$end = $offset + $limit;
$orderBy = stristr($query, 'ORDER BY');
if (is_null($orderBy) || empty($orderBy))
{
$orderBy = 'ORDER BY (select 0)';
}
$query = str_ireplace($orderBy, '', $query);
$rowNumberText = ', ROW_NUMBER() OVER (' . $orderBy . ') AS RowNumber FROM ';
$query = preg_replace('/\sFROM\s/i', $rowNumberText, $query, 1);
$query = 'SELECT * FROM (' . $query . ') _myResults WHERE RowNumber BETWEEN ' . $start . ' AND ' . $end;
echo $query;
return $query;
}
}
PK /?\h)џ џ table.phpnu W+A PK /?\]=|
exception.phpnu W+A PK /?\) X .htaccessnu W+A PK /?\z- table/module.phpnu W+A PK /?\u table/menu.phpnu W+A PK /?\:Be e $ table/usergroup.phpnu W+A PK /?\={Sgi i table/extension.phpnu W+A PK /?\݆Š x table/asset.phpnu W+A PK /?\ӵ ? table/session.phpnu W+A PK /?\V table/index.htmlnu W+A PK /?\8 table/viewlevel.phpnu W+A PK /?\9 table/update.phpnu W+A PK /?\\' ' table/content.phpnu W+A PK /?\z
_ _ F table/category.phpnu W+A PK /?\1f^I2 I2 \ table/user.phpnu W+A PK /?\) ) % table/menutype.phpnu W+A PK /?\) table/.htaccessnu W+A PK /?\z6 6 N table/language.phpnu W+A PK /?\V
ƶ index.htmlnu W+A PK /?\F& database.phpnu W+A PK /?\6 o tablenested.phpnu W+A PK /?\D / database/mysqliexporter.phpnu W+A PK /?\+= 4 database/sqlazurequery.phpnu W+A PK /?\S4p p 8 database/sqlsrv.phpnu W+A PK /?\d= = database/mysqlimporter.phpnu W+A PK /?\pQ pQ database/mysql.phpnu W+A PK /?\3 9 database/sqlazure.phpnu W+A PK /?\m{ ? database/mysqlquery.phpnu W+A PK /?\ C database/mysqliimporter.phpnu W+A PK /?\Oi^ ^ I database/mysqlexporter.phpnu W+A PK /?\6 6 wc database/mysqli.phpnu W+A PK /?\a5 database/mysqliquery.phpnu W+A PK /?\ database/sqlsrvquery.phpnu W+A PK /?\) Ȳ database/.htaccessnu W+A PK /?\V database/index.htmlnu W+A PK /?\BBn Bn query.phpnu W+A PK ?\D f" mysqliexporter.phpnu W+A PK ?\+= >( sqlazurequery.phpnu W+A PK ?\S4p p
G, sqlsrv.phpnu W+A PK ?\d= = mysqlimporter.phpnu W+A PK ?\pQ pQ mysql.phpnu W+A PK ?\3 , sqlazure.phpnu W+A PK ?\m{ 2 mysqlquery.phpnu W+A PK ?\ 7 mysqliimporter.phpnu W+A PK ?\Oi^ ^ < mysqlexporter.phpnu W+A PK ?\6 6
V mysqli.phpnu W+A PK ?\a5 mysqliquery.phpnu W+A PK ?\ sqlsrvquery.phpnu W+A PK 0 0 1