AAAAPK/?\h)џџ table.phpnuW+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 . '>'; } // 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.phpnuW+A Order allow,deny Deny from all PK/?\z-table/module.phpnuW+Aaccess = (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/?\utable/menu.phpnuW+Aaccess = (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/?\:Beetable/usergroup.phpnuW+Atitle)) == '') { $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/?\={Sgiitable/extension.phpnuW+Aname) == '' || 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.phpnuW+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.phpnuW+Aguest = 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/?\Vtable/index.htmlnuW+A PK/?\8table/viewlevel.phpnuW+Atitle)) == '') { $this->setError(JText::_('JLIB_DATABASE_ERROR_VIEWLEVEL')); return false; } return true; } } PK/?\9 table/update.phpnuW+Aname) == '' || 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.phpnuW+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.phpnuW+Aaccess = (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^I2I2table/user.phpnuW+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.phpnuW+Amenutype = 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/.htaccessnuW+A Order allow,deny Deny from all PK/?\z66table/language.phpnuW+Atitle) == '') { $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.htmlnuW+A PK/?\F& database.phpnuW+AgetMessage())); } 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/?\6tablenested.phpnuW+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/?\Ddatabase/mysqliexporter.phpnuW+Adb 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.phpnuW+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 .= ''; while ($row = $this->fetchAssoc($cursor)) { if ($first) { $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; $first = false; } $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; } $buffer .= '
' . $this->getQuery() . '
' . $k . '
' . $v . '
'; // 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.phpnuW+Aoptions = 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/?\׺pQpQdatabase/mysql.phpnuW+AerrorNum = 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 .= ''; while ($row = $this->fetchAssoc($cursor)) { if ($first) { $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; $first = false; } $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; } $buffer .= '
' . $this->getQuery() . '
' . $k . '
' . $v . '
'; // 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/?\3database/sqlazure.phpnuW+Asql; } } } PK/?\m{database/mysqlquery.phpnuW+Aquote($separator); foreach ($values as $value) { $concat_string .= ', ' . $value; } return $concat_string . ')'; } else { return 'CONCAT(' . implode(',', $values) . ')'; } } } PK/?\ database/mysqliimporter.phpnuW+Adb 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.phpnuW+Aoptions = 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/?\66database/mysqli.phpnuW+AerrorNum = 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/?\a5database/mysqliquery.phpnuW+Atype) { 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/.htaccessnuW+A Order allow,deny Deny from all PK/?\Vdatabase/index.htmlnuW+A PK/?\ BBnBn query.phpnuW+Aelements = 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?\Dmysqliexporter.phpnuW+Adb 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.phpnuW+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 .= ''; while ($row = $this->fetchAssoc($cursor)) { if ($first) { $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; $first = false; } $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; } $buffer .= '
' . $this->getQuery() . '
' . $k . '
' . $v . '
'; // 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.phpnuW+Aoptions = 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?\׺pQpQ mysql.phpnuW+AerrorNum = 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 .= ''; while ($row = $this->fetchAssoc($cursor)) { if ($first) { $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; $first = false; } $buffer .= ''; foreach ($row as $k => $v) { $buffer .= ''; } $buffer .= ''; } $buffer .= '
' . $this->getQuery() . '
' . $k . '
' . $v . '
'; // 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.phpnuW+Asql; } } } PK?\m{mysqlquery.phpnuW+Aquote($separator); foreach ($values as $value) { $concat_string .= ', ' . $value; } return $concat_string . ')'; } else { return 'CONCAT(' . implode(',', $values) . ')'; } } } PK?\ mysqliimporter.phpnuW+Adb 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.phpnuW+Aoptions = 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?\66 mysqli.phpnuW+AerrorNum = 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?\a5mysqliquery.phpnuW+Atype) { 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.phpnuW+APK/?\]=|  exception.phpnuW+APK/?\) X.htaccessnuW+APK/?\z-table/module.phpnuW+APK/?\utable/menu.phpnuW+APK/?\:Bee$table/usergroup.phpnuW+APK/?\={Sgiitable/extension.phpnuW+APK/?\݆Š xtable/asset.phpnuW+APK/?\ӵ?table/session.phpnuW+APK/?\Vtable/index.htmlnuW+APK/?\8table/viewlevel.phpnuW+APK/?\9  table/update.phpnuW+APK/?\\''table/content.phpnuW+APK/?\z __Ftable/category.phpnuW+APK/?\1f^I2I2\table/user.phpnuW+APK/?\))%table/menutype.phpnuW+APK/?\)table/.htaccessnuW+APK/?\z66Ntable/language.phpnuW+APK/?\V ƶindex.htmlnuW+APK/?\F& database.phpnuW+APK/?\6otablenested.phpnuW+APK/?\D/database/mysqliexporter.phpnuW+APK/?\+=4database/sqlazurequery.phpnuW+APK/?\S4pp8database/sqlsrv.phpnuW+APK/?\d==database/mysqlimporter.phpnuW+APK/?\׺pQpQdatabase/mysql.phpnuW+APK/?\39database/sqlazure.phpnuW+APK/?\m{?database/mysqlquery.phpnuW+APK/?\ Cdatabase/mysqliimporter.phpnuW+APK/?\Oi^^Idatabase/mysqlexporter.phpnuW+APK/?\66wcdatabase/mysqli.phpnuW+APK/?\a5database/mysqliquery.phpnuW+APK/?\database/sqlsrvquery.phpnuW+APK/?\)Ȳdatabase/.htaccessnuW+APK/?\Vdatabase/index.htmlnuW+APK/?\ BBnBn query.phpnuW+APK?\Df"mysqliexporter.phpnuW+APK?\+=>(sqlazurequery.phpnuW+APK?\S4pp G,sqlsrv.phpnuW+APK?\d==mysqlimporter.phpnuW+APK?\׺pQpQ mysql.phpnuW+APK?\3 ,sqlazure.phpnuW+APK?\m{2mysqlquery.phpnuW+APK?\ 7mysqliimporter.phpnuW+APK?\Oi^^<mysqlexporter.phpnuW+APK?\66 Vmysqli.phpnuW+APK?\a5mysqliquery.phpnuW+APK?\sqlsrvquery.phpnuW+APK001