diff options
| author | Charles <sircharlesaze@gmail.com> | 2020-01-09 10:55:03 +0100 |
|---|---|---|
| committer | Charles <sircharlesaze@gmail.com> | 2020-01-09 13:09:38 +0100 |
| commit | 04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa (patch) | |
| tree | 5c691241355c943a3c68ddb06b8cf8c60aa11319 /srcs/phpmyadmin/libraries/classes/Navigation/Nodes | |
| parent | 7e0d85db834d6351ed85d01e5126ac31dc510b86 (diff) | |
| download | ft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.tar.gz ft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.tar.bz2 ft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.zip | |
phpmyadmin working
Diffstat (limited to 'srcs/phpmyadmin/libraries/classes/Navigation/Nodes')
21 files changed, 2860 insertions, 0 deletions
diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/Node.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/Node.php new file mode 100644 index 0000000..3d68f65 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/Node.php @@ -0,0 +1,842 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree in the left frame + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Relation; +use PhpMyAdmin\Util; + +/** + * The Node is the building block for the collapsible navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class Node +{ + /** + * @var int Defines a possible node type + */ + public const CONTAINER = 0; + /** + * @var int Defines a possible node type + */ + public const OBJECT = 1; + /** + * @var string A non-unique identifier for the node + * This may be trimmed when grouping nodes + */ + public $name = ""; + /** + * @var string A non-unique identifier for the node + * This will never change after being assigned + */ + public $realName = ""; + /** + * @var int May be one of CONTAINER or OBJECT + */ + public $type = Node::OBJECT; + /** + * @var bool Whether this object has been created while grouping nodes + * Only relevant if the node is of type CONTAINER + */ + public $isGroup; + /** + * @var bool Whether to add a "display: none;" CSS + * rule to the node when rendering it + */ + public $visible = false; + /** + * @var Node A reference to the parent object of + * this node, NULL for the root node. + */ + public $parent; + /** + * @var Node[] An array of Node objects that are + * direct children of this node + */ + public $children = []; + /** + * @var Mixed A string used to group nodes, or an array of strings + * Only relevant if the node is of type CONTAINER + */ + public $separator = ''; + /** + * @var int How many time to recursively apply the grouping function + * Only relevant if the node is of type CONTAINER + */ + public $separatorDepth = 1; + /** + * @var string|array An IMG tag, used when rendering the node, an array for NodeTabl + */ + public $icon; + /** + * @var array An array of A tags, used when rendering the node + * The indexes in the array may be 'icon' and 'text' + */ + public $links; + /** + * @var string HTML title + */ + public $title; + /** + * @var string Extra CSS classes for the node + */ + public $classes = ''; + /** + * @var bool Whether this node is a link for creating new objects + */ + public $isNew = false; + /** + * @var int The position for the pagination of + * the branch at the second level of the tree + */ + public $pos2 = 0; + /** + * @var int The position for the pagination of + * the branch at the third level of the tree + */ + public $pos3 = 0; + + /** + * @var Relation + */ + protected $relation; + + /** + * @var string $displayName display name for the navigation tree + */ + public $displayName; + + /** + * Initialises the class by setting the mandatory variables + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + if (strlen((string) $name)) { + $this->name = $name; + $this->realName = $name; + } + if ($type === Node::CONTAINER) { + $this->type = Node::CONTAINER; + } + $this->isGroup = (bool) $isGroup; + $this->relation = new Relation($GLOBALS['dbi']); + } + + /** + * Adds a child node to this node + * + * @param Node $child A child node + * + * @return void + */ + public function addChild($child) + { + $this->children[] = $child; + $child->parent = $this; + } + + /** + * Returns a child node given it's name + * + * @param string $name The name of requested child + * @param bool $realName Whether to use the "realName" + * instead of "name" in comparisons + * + * @return false|Node The requested child node or false, + * if the requested node cannot be found + */ + public function getChild($name, $realName = false) + { + if ($realName) { + foreach ($this->children as $child) { + if ($child->realName == $name) { + return $child; + } + } + } else { + foreach ($this->children as $child) { + if ($child->name == $name) { + return $child; + } + } + } + + return false; + } + + /** + * Removes a child node from this node + * + * @param string $name The name of child to be removed + * + * @return void + */ + public function removeChild($name) + { + foreach ($this->children as $key => $child) { + if ($child->name == $name) { + unset($this->children[$key]); + break; + } + } + } + + /** + * Retrieves the parents for a node + * + * @param bool $self Whether to include the Node itself in the results + * @param bool $containers Whether to include nodes of type CONTAINER + * @param bool $groups Whether to include nodes which have $group == true + * + * @return array An array of parent Nodes + */ + public function parents($self = false, $containers = false, $groups = false) + { + $parents = []; + if ($self + && ($this->type != Node::CONTAINER || $containers) + && (! $this->isGroup || $groups) + ) { + $parents[] = $this; + } + $parent = $this->parent; + while ($parent !== null) { + if (($parent->type != Node::CONTAINER || $containers) + && (! $parent->isGroup || $groups) + ) { + $parents[] = $parent; + } + $parent = $parent->parent; + } + + return $parents; + } + + /** + * Returns the actual parent of a node. If used twice on an index or columns + * node, it will return the table and database nodes. The names of the returned + * nodes can be used in SQL queries, etc... + * + * @return Node|false + */ + public function realParent() + { + $retval = $this->parents(); + if (count($retval) <= 0) { + return false; + } + + return $retval[0]; + } + + /** + * This function checks if the node has children nodes associated with it + * + * @param bool $countEmptyContainers Whether to count empty child + * containers as valid children + * + * @return bool Whether the node has child nodes + */ + public function hasChildren($countEmptyContainers = true) + { + $retval = false; + if ($countEmptyContainers) { + if (count($this->children)) { + $retval = true; + } + } else { + foreach ($this->children as $child) { + if ($child->type == Node::OBJECT || $child->hasChildren(false)) { + $retval = true; + break; + } + } + } + + return $retval; + } + + /** + * Returns true if the node has some siblings (other nodes on the same tree + * level, in the same branch), false otherwise. + * The only exception is for nodes on + * the third level of the tree (columns and indexes), for which the function + * always returns true. This is because we want to render the containers + * for these nodes + * + * @return bool + */ + public function hasSiblings() + { + $retval = false; + $paths = $this->getPaths(); + if (count($paths['aPath_clean']) > 3) { + return true; + } + + foreach ($this->parent->children as $child) { + if ($child !== $this + && ($child->type == Node::OBJECT || $child->hasChildren(false)) + ) { + $retval = true; + break; + } + } + + return $retval; + } + + /** + * Returns the number of child nodes that a node has associated with it + * + * @return int The number of children nodes + */ + public function numChildren() + { + $retval = 0; + foreach ($this->children as $child) { + if ($child->type == Node::OBJECT) { + $retval++; + } else { + $retval += $child->numChildren(); + } + } + + return $retval; + } + + /** + * Returns the actual path and the virtual paths for a node + * both as clean arrays and base64 encoded strings + * + * @return array + */ + public function getPaths() + { + $aPath = []; + $aPathClean = []; + foreach ($this->parents(true, true, false) as $parent) { + $aPath[] = base64_encode($parent->realName); + $aPathClean[] = $parent->realName; + } + $aPath = implode('.', array_reverse($aPath)); + $aPathClean = array_reverse($aPathClean); + + $vPath = []; + $vPathClean = []; + foreach ($this->parents(true, true, true) as $parent) { + $vPath[] = base64_encode((string) $parent->name); + $vPathClean[] = $parent->name; + } + $vPath = implode('.', array_reverse($vPath)); + $vPathClean = array_reverse($vPathClean); + + return [ + 'aPath' => $aPath, + 'aPath_clean' => $aPathClean, + 'vPath' => $vPath, + 'vPath_clean' => $vPathClean, + ]; + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $maxItems = $GLOBALS['cfg']['FirstLevelNavigationItems']; + if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] + || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] + ) { + if (isset($GLOBALS['cfg']['Server']['DisableIS']) + && ! $GLOBALS['cfg']['Server']['DisableIS'] + ) { + $query = "SELECT `SCHEMA_NAME` "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); + $query .= "ORDER BY `SCHEMA_NAME` "; + $query .= "LIMIT $pos, $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + + return $retval; + } + + if ($GLOBALS['dbs_to_test'] === false) { + $retval = []; + $query = "SHOW DATABASES "; + $query .= $this->getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + return $retval; + } + + $count = 0; + if (! $GLOBALS['dbi']->dataSeek($handle, $pos)) { + return $retval; + } + + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } else { + break; + } + } + + return $retval; + } + + $retval = []; + $count = 0; + foreach ($this->getDatabasesToSearch($searchClause) as $db) { + $query = "SHOW DATABASES LIKE '" . $db . "'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + continue; + } + + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($this->isHideDb($arr[0])) { + continue; + } + if (in_array($arr[0], $retval)) { + continue; + } + + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } + sort($retval); + + return $retval; + } + + $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; + if (isset($GLOBALS['cfg']['Server']['DisableIS']) + && ! $GLOBALS['cfg']['Server']['DisableIS'] + ) { + $query = "SELECT `SCHEMA_NAME` "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, "; + $query .= "("; + $query .= "SELECT DB_first_level "; + $query .= "FROM ( "; + $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; + $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "', 1) "; + $query .= "DB_first_level "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); + $query .= ") t "; + $query .= "ORDER BY DB_first_level ASC "; + $query .= "LIMIT $pos, $maxItems"; + $query .= ") t2 "; + $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); + $query .= "AND 1 = LOCATE(CONCAT(DB_first_level, "; + $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "'), "; + $query .= "CONCAT(SCHEMA_NAME, "; + $query .= "'" . $GLOBALS['dbi']->escapeString($dbSeparator) . "')) "; + $query .= "ORDER BY SCHEMA_NAME ASC"; + $retval = $GLOBALS['dbi']->fetchResult($query); + + return $retval; + } + + if ($GLOBALS['dbs_to_test'] === false) { + $query = "SHOW DATABASES "; + $query .= $this->getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + $prefixes = []; + if ($handle !== false) { + $prefixMap = []; + $total = $pos + $maxItems; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + $prefix = strstr($arr[0], $dbSeparator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + if (count($prefixMap) == $total) { + break; + } + } + $prefixes = array_slice(array_keys($prefixMap), (int) $pos); + } + + $query = "SHOW DATABASES "; + $query .= $this->getWhereClause('Database', $searchClause); + $query .= "AND ("; + $subClauses = []; + foreach ($prefixes as $prefix) { + $subClauses[] = " LOCATE('" + . $GLOBALS['dbi']->escapeString((string) $prefix) . $dbSeparator + . "', " + . "CONCAT(`Database`, '" . $dbSeparator . "')) = 1 "; + } + $query .= implode("OR", $subClauses) . ")"; + $retval = $GLOBALS['dbi']->fetchResult($query); + + return $retval; + } + + $retval = []; + $prefixMap = []; + $total = $pos + $maxItems; + foreach ($this->getDatabasesToSearch($searchClause) as $db) { + $query = "SHOW DATABASES LIKE '" . $db . "'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + continue; + } + + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($this->isHideDb($arr[0])) { + continue; + } + $prefix = strstr($arr[0], $dbSeparator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + if (count($prefixMap) == $total) { + break 2; + } + } + } + $prefixes = array_slice(array_keys($prefixMap), $pos); + + foreach ($this->getDatabasesToSearch($searchClause) as $db) { + $query = "SHOW DATABASES LIKE '" . $db . "'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + continue; + } + + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($this->isHideDb($arr[0])) { + continue; + } + if (in_array($arr[0], $retval)) { + continue; + } + + foreach ($prefixes as $prefix) { + $startsWith = strpos( + $arr[0] . $dbSeparator, + $prefix . $dbSeparator + ) === 0; + if ($startsWith) { + $retval[] = $arr[0]; + break; + } + } + } + } + sort($retval); + + return $retval; + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param string $searchClause A string used to filter the results of the query + * + * @return int + */ + public function getPresence($type = '', $searchClause = '') + { + if (! $GLOBALS['cfg']['NavigationTreeEnableGrouping'] + || ! $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] + ) { + if (isset($GLOBALS['cfg']['Server']['DisableIS']) + && ! $GLOBALS['cfg']['Server']['DisableIS'] + ) { + $query = "SELECT COUNT(*) "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + + return $retval; + } + + if ($GLOBALS['dbs_to_test'] === false) { + $query = "SHOW DATABASES "; + $query .= $this->getWhereClause('Database', $searchClause); + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + + return $retval; + } + + $retval = 0; + foreach ($this->getDatabasesToSearch($searchClause) as $db) { + $query = "SHOW DATABASES LIKE '" . $db . "'"; + $retval += $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + + return $retval; + } + + $dbSeparator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = "SELECT COUNT(*) "; + $query .= "FROM ( "; + $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; + $query .= "'$dbSeparator', 1) "; + $query .= "DB_first_level "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->getWhereClause('SCHEMA_NAME', $searchClause); + $query .= ") t "; + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + + return $retval; + } + + if ($GLOBALS['dbs_to_test'] !== false) { + $prefixMap = []; + foreach ($this->getDatabasesToSearch($searchClause) as $db) { + $query = "SHOW DATABASES LIKE '" . $db . "'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + continue; + } + + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($this->isHideDb($arr[0])) { + continue; + } + $prefix = strstr($arr[0], $dbSeparator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + } + } + $retval = count($prefixMap); + + return $retval; + } + + $prefixMap = []; + $query = "SHOW DATABASES "; + $query .= $this->getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + $prefix = strstr($arr[0], $dbSeparator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + } + } + $retval = count($prefixMap); + + return $retval; + } + + /** + * Detemines whether a given database should be hidden according to 'hide_db' + * + * @param string $db database name + * + * @return boolean whether to hide + */ + private function isHideDb($db) + { + return ! empty($GLOBALS['cfg']['Server']['hide_db']) + && preg_match('/' . $GLOBALS['cfg']['Server']['hide_db'] . '/', $db); + } + + /** + * Get the list of databases for 'SHOW DATABASES LIKE' queries. + * If a search clause is set it gets the highest priority while only_db gets + * the next priority. In case both are empty list of databases determined by + * GRANTs are used + * + * @param string $searchClause search clause + * + * @return array array of databases + */ + private function getDatabasesToSearch($searchClause) + { + $databases = []; + if (! empty($searchClause)) { + $databases = [ + "%" . $GLOBALS['dbi']->escapeString($searchClause) . "%", + ]; + } elseif (! empty($GLOBALS['cfg']['Server']['only_db'])) { + $databases = $GLOBALS['cfg']['Server']['only_db']; + } elseif (! empty($GLOBALS['dbs_to_test'])) { + $databases = $GLOBALS['dbs_to_test']; + } + sort($databases); + + return $databases; + } + + /** + * Returns the WHERE clause depending on the $searchClause parameter + * and the hide_db directive + * + * @param string $columnName Column name of the column having database names + * @param string $searchClause A string used to filter the results of the query + * + * @return string + */ + private function getWhereClause($columnName, $searchClause = '') + { + $whereClause = "WHERE TRUE "; + if (! empty($searchClause)) { + $whereClause .= "AND " . Util::backquote($columnName) + . " LIKE '%"; + $whereClause .= $GLOBALS['dbi']->escapeString($searchClause); + $whereClause .= "%' "; + } + + if (! empty($GLOBALS['cfg']['Server']['hide_db'])) { + $whereClause .= "AND " . Util::backquote($columnName) + . " NOT REGEXP '" + . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['hide_db']) + . "' "; + } + + if (! empty($GLOBALS['cfg']['Server']['only_db'])) { + if (is_string($GLOBALS['cfg']['Server']['only_db'])) { + $GLOBALS['cfg']['Server']['only_db'] = [ + $GLOBALS['cfg']['Server']['only_db'], + ]; + } + $whereClause .= "AND ("; + $subClauses = []; + foreach ($GLOBALS['cfg']['Server']['only_db'] as $eachOnlyDb) { + $subClauses[] = " " . Util::backquote($columnName) + . " LIKE '" + . $GLOBALS['dbi']->escapeString($eachOnlyDb) . "' "; + } + $whereClause .= implode("OR", $subClauses) . ") "; + } + + return $whereClause; + } + + /** + * Returns HTML for control buttons displayed infront of a node + * + * @return String HTML for control buttons + */ + public function getHtmlForControlButtons() + { + return ''; + } + + /** + * Returns CSS classes for a node + * + * @param boolean $match Whether the node matched loaded tree + * + * @return String with html classes. + */ + public function getCssClasses($match) + { + if (! $GLOBALS['cfg']['NavigationTreeEnableExpansion'] + ) { + return ''; + } + + $result = ['expander']; + + if ($this->isGroup || $match) { + $result[] = 'loaded'; + } + if ($this->type == Node::CONTAINER) { + $result[] = 'container'; + } + + return implode(' ', $result); + } + + /** + * Returns icon for the node + * + * @param boolean $match Whether the node matched loaded tree + * + * @return String with image name + */ + public function getIcon($match) + { + if (! $GLOBALS['cfg']['NavigationTreeEnableExpansion'] + ) { + return ''; + } elseif ($match) { + $this->visible = true; + + return Util::getImage('b_minus'); + } + + return Util::getImage('b_plus', __('Expand/Collapse')); + } + + /** + * Gets the count of hidden elements for each database + * + * @return array|null array containing the count of hidden elements for each database + */ + public function getNavigationHidingData() + { + $cfgRelation = $this->relation->getRelationsParam(); + if ($cfgRelation['navwork']) { + $navTable = Util::backquote($cfgRelation['db']) + . "." . Util::backquote( + $cfgRelation['navigationhiding'] + ); + $sqlQuery = "SELECT `db_name`, COUNT(*) AS `count` FROM " . $navTable + . " WHERE `username`='" + . $GLOBALS['dbi']->escapeString( + $GLOBALS['cfg']['Server']['user'] + ) . "'" + . " GROUP BY `db_name`"; + $counts = $GLOBALS['dbi']->fetchResult( + $sqlQuery, + 'db_name', + 'count', + DatabaseInterface::CONNECT_CONTROL + ); + + return $counts; + } + + return null; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php new file mode 100644 index 0000000..9c9e605 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumn.php @@ -0,0 +1,116 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a columns node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeColumn extends Node +{ + /** + * Initialises the class + * + * @param array $item array to identify the column node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($item, $type = Node::OBJECT, $isGroup = false) + { + $this->displayName = $this->getDisplayName($item); + + parent::__construct($item['name'], $type, $isGroup); + $this->icon = Util::getImage($this->getColumnIcon($item['key']), __('Column')); + $this->links = [ + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&field=%1$s' + . '&change_column=1', + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&field=%1$s' + . '&change_column=1', + 'title' => __('Structure'), + ]; + } + + /** + * Get customized Icon for columns in navigation tree + * + * @param string $key The key type - (primary, foreign etc.) + * + * @return string Icon name for required key. + */ + private function getColumnIcon($key) + { + switch ($key) { + case 'PRI': + $retval = 'b_primary'; + break; + case 'UNI': + $retval = 'bd_primary'; + break; + default: + $retval = 'pause'; + break; + } + return $retval; + } + + /** + * Get displayable name for navigation tree (key_type, data_type, default) + * + * @param array $item Item is array containing required info + * + * @return string Display name for navigation tree + */ + private function getDisplayName($item) + { + $retval = $item['name']; + $flag = 0; + foreach ($item as $key => $value) { + if (! empty($value) && $key != 'name') { + $flag == 0 ? $retval .= ' (' : $retval .= ', '; + $flag = 1; + $retval .= $this->getTruncateValue($key, $value); + } + } + $retval .= ')'; + return $retval; + } + + /** + * Get truncated value for display in node column view + * + * @param string $key key to identify default,datatype etc + * @param string $value value corresponding to key + * + * @return string truncated value + */ + public function getTruncateValue($key, $value) + { + $retval = ''; + + switch ($key) { + case 'default': + strlen($value) > 6 ? + $retval .= substr($value, 0, 6) . '...' : + $retval = $value; + break; + default: + $retval = $value; + break; + } + + return $retval; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php new file mode 100644 index 0000000..22cba58 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeColumnContainer.php @@ -0,0 +1,55 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for column nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeColumnContainer extends Node +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Columns'), Node::CONTAINER); + $this->icon = Util::getImage('pause', __('Columns')); + $this->links = [ + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + ]; + $this->realName = 'columns'; + + $newLabel = _pgettext('Create new column', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_column_add', $newLabel); + $new->links = [ + 'text' => 'tbl_addfield.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s' + . '&field_where=last&after_field=', + 'icon' => 'tbl_addfield.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s' + . '&field_where=last&after_field=', + ]; + $new->classes = 'new_column italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php new file mode 100644 index 0000000..33c93fb --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabase.php @@ -0,0 +1,717 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Relation; +use PhpMyAdmin\Url; +use PhpMyAdmin\Util; + +/** + * Represents a database node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeDatabase extends Node +{ + /** + * The number of hidden items in this database + * + * @var int + */ + protected $hiddenCount = 0; + + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage( + 's_db', + __('Database operations') + ); + + $scriptName = Util::getScriptNameForOption( + $GLOBALS['cfg']['DefaultTabDatabase'], + 'database' + ); + $this->links = [ + 'text' => $scriptName + . '?server=' . $GLOBALS['server'] + . '&db=%1$s', + 'icon' => 'db_operations.php?server=' . $GLOBALS['server'] + . '&db=%1$s&', + 'title' => __('Structure'), + ]; + $this->classes = 'database'; + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase + * and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + public function getPresence($type = '', $searchClause = '', $singleItem = false) + { + $retval = 0; + switch ($type) { + case 'tables': + $retval = $this->getTableCount($searchClause, $singleItem); + break; + case 'views': + $retval = $this->getViewCount($searchClause, $singleItem); + break; + case 'procedures': + $retval = $this->getProcedureCount($searchClause, $singleItem); + break; + case 'functions': + $retval = $this->getFunctionCount($searchClause, $singleItem); + break; + case 'events': + $retval = $this->getEventCount($searchClause, $singleItem); + break; + default: + break; + } + + return $retval; + } + + /** + * Returns the number of tables or views present inside this database + * + * @param string $which tables|views + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getTableOrViewCount($which, $searchClause, $singleItem) + { + $db = $this->realName; + if ($which == 'tables') { + $condition = 'IN'; + } else { + $condition = 'NOT IN'; + } + + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + $query .= "AND `TABLE_TYPE`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'TABLE_NAME' + ); + } + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= Util::backquote($db); + $query .= " WHERE `Table_type`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'Tables_in_' . $db + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + + return $retval; + } + + /** + * Returns the number of tables present inside this database + * + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getTableCount($searchClause, $singleItem) + { + return $this->getTableOrViewCount( + 'tables', + $searchClause, + $singleItem + ); + } + + /** + * Returns the number of views present inside this database + * + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getViewCount($searchClause, $singleItem) + { + return $this->getTableOrViewCount( + 'views', + $searchClause, + $singleItem + ); + } + + /** + * Returns the number of procedures present inside this database + * + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getProcedureCount($searchClause, $singleItem) + { + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA` " + . Util::getCollateForIS() . "='$db'"; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'ROUTINE_NAME' + ); + } + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SHOW PROCEDURE STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + + return $retval; + } + + /** + * Returns the number of functions present inside this database + * + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getFunctionCount($searchClause, $singleItem) + { + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA` " + . Util::getCollateForIS() . "='$db' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'ROUTINE_NAME' + ); + } + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SHOW FUNCTION STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + + return $retval; + } + + /** + * Returns the number of events present inside this database + * + * @param string $searchClause A string used to filter the results of + * the query + * @param boolean $singleItem Whether to get presence of a single known + * item or false in none + * + * @return int + */ + private function getEventCount($searchClause, $singleItem) + { + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA` " + . Util::getCollateForIS() . "='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'EVENT_NAME' + ); + } + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $db = Util::backquote($db); + $query = "SHOW EVENTS FROM $db "; + if (! empty($searchClause)) { + $query .= "WHERE " . $this->getWhereClauseForSearch( + $searchClause, + $singleItem, + 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + + return $retval; + } + + /** + * Returns the WHERE clause for searching inside a database + * + * @param string $searchClause A string used to filter the results of the query + * @param boolean $singleItem Whether to get presence of a single known item + * @param string $columnName Name of the column in the result set to match + * + * @return string WHERE clause for searching + */ + private function getWhereClauseForSearch( + $searchClause, + $singleItem, + $columnName + ) { + $query = ''; + if ($singleItem) { + $query .= Util::backquote($columnName) . " = "; + $query .= "'" . $GLOBALS['dbi']->escapeString($searchClause) . "'"; + } else { + $query .= Util::backquote($columnName) . " LIKE "; + $query .= "'%" . $GLOBALS['dbi']->escapeString($searchClause) + . "%'"; + } + + return $query; + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase + * and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $retval = []; + switch ($type) { + case 'tables': + $retval = $this->getTables($pos, $searchClause); + break; + case 'views': + $retval = $this->getViews($pos, $searchClause); + break; + case 'procedures': + $retval = $this->getProcedures($pos, $searchClause); + break; + case 'functions': + $retval = $this->getFunctions($pos, $searchClause); + break; + case 'events': + $retval = $this->getEvents($pos, $searchClause); + break; + default: + break; + } + + // Remove hidden items so that they are not displayed in navigation tree + $cfgRelation = $this->relation->getRelationsParam(); + if ($cfgRelation['navwork']) { + $hiddenItems = $this->getHiddenItems(substr($type, 0, -1)); + foreach ($retval as $key => $item) { + if (in_array($item, $hiddenItems)) { + unset($retval[$key]); + } + } + } + + return $retval; + } + + /** + * Return list of hidden items of given type + * + * @param string $type The type of items we are looking for + * ('table', 'function', 'group', etc.) + * + * @return array Array containing hidden items of given type + */ + public function getHiddenItems($type) + { + $db = $this->realName; + $cfgRelation = $this->relation->getRelationsParam(); + if (! $cfgRelation['navwork']) { + return []; + } + $navTable = Util::backquote($cfgRelation['db']) + . "." . Util::backquote($cfgRelation['navigationhiding']); + $sqlQuery = "SELECT `item_name` FROM " . $navTable + . " WHERE `username`='" . $cfgRelation['user'] . "'" + . " AND `item_type`='" . $type + . "' AND `db_name`='" . $GLOBALS['dbi']->escapeString($db) + . "'"; + $result = $this->relation->queryAsControlUser($sqlQuery, false); + $hiddenItems = []; + if ($result) { + while ($row = $GLOBALS['dbi']->fetchArray($result)) { + $hiddenItems[] = $row[0]; + } + } + $GLOBALS['dbi']->freeResult($result); + + return $hiddenItems; + } + + /** + * Returns the list of tables or views inside this database + * + * @param string $which tables|views + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getTablesOrViews($which, $pos, $searchClause) + { + if ($which == 'tables') { + $condition = 'IN'; + } else { + $condition = 'NOT IN'; + } + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = []; + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; + $query .= "AND `TABLE_TYPE`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= $GLOBALS['dbi']->escapeString($searchClause); + $query .= "%'"; + } + $query .= "ORDER BY `TABLE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $query = " SHOW FULL TABLES FROM "; + $query .= Util::backquote($db); + $query .= " WHERE `Table_type`" . $condition . "('BASE TABLE', 'SYSTEM VERSIONED') "; + if (! empty($searchClause)) { + $query .= "AND " . Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . $GLOBALS['dbi']->escapeString( + $searchClause + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } else { + break; + } + } + } + } + } + + return $retval; + } + + /** + * Returns the list of tables inside this database + * + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getTables($pos, $searchClause) + { + return $this->getTablesOrViews('tables', $pos, $searchClause); + } + + /** + * Returns the list of views inside this database + * + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getViews($pos, $searchClause) + { + return $this->getTablesOrViews('views', $pos, $searchClause); + } + + /** + * Returns the list of procedures or functions inside this database + * + * @param string $routineType PROCEDURE|FUNCTION + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getRoutines($routineType, $pos, $searchClause) + { + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = []; + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA` " + . Util::getCollateForIS() . "='$escdDb'"; + $query .= "AND `ROUTINE_TYPE`='" . $routineType . "' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= $GLOBALS['dbi']->escapeString($searchClause); + $query .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $escdDb = $GLOBALS['dbi']->escapeString($db); + $query = "SHOW " . $routineType . " STATUS WHERE `Db`='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= $GLOBALS['dbi']->escapeString($searchClause); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } else { + break; + } + } + } + } + } + + return $retval; + } + + /** + * Returns the list of procedures inside this database + * + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getProcedures($pos, $searchClause) + { + return $this->getRoutines('PROCEDURE', $pos, $searchClause); + } + + /** + * Returns the list of functions inside this database + * + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getFunctions($pos, $searchClause) + { + return $this->getRoutines('FUNCTION', $pos, $searchClause); + } + + /** + * Returns the list of events inside this database + * + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + private function getEvents($pos, $searchClause) + { + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = []; + $db = $this->realName; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = $GLOBALS['dbi']->escapeString($db); + $query = "SELECT `EVENT_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA` " + . Util::getCollateForIS() . "='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `EVENT_NAME` LIKE '%"; + $query .= $GLOBALS['dbi']->escapeString($searchClause); + $query .= "%'"; + } + $query .= "ORDER BY `EVENT_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $escdDb = Util::backquote($db); + $query = "SHOW EVENTS FROM $escdDb "; + if (! empty($searchClause)) { + $query .= "WHERE `Name` LIKE '%"; + $query .= $GLOBALS['dbi']->escapeString($searchClause); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } else { + break; + } + } + } + } + } + + return $retval; + } + + /** + * Returns HTML for control buttons displayed infront of a node + * + * @return String HTML for control buttons + */ + public function getHtmlForControlButtons() + { + $ret = ''; + $cfgRelation = $this->relation->getRelationsParam(); + if ($cfgRelation['navwork']) { + if ($this->hiddenCount > 0) { + $params = [ + 'showUnhideDialog' => true, + 'dbName' => $this->realName, + ]; + $ret = '<span class="dbItemControls">' + . '<a href="navigation.php" data-post="' + . Url::getCommon($params, '') . '"' + . ' class="showUnhide ajax">' + . Util::getImage( + 'show', + __('Show hidden items') + ) + . '</a></span>'; + } + } + + return $ret; + } + + /** + * Sets the number of hidden items in this database + * + * @param int $count hidden item count + * + * @return void + */ + public function setHiddenCount($count) + { + $this->hiddenCount = $count; + } + + /** + * Returns the number of hidden items in this database + * + * @return int hidden item count + */ + public function getHiddenCount() + { + return $this->hiddenCount; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php new file mode 100644 index 0000000..0005915 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChild.php @@ -0,0 +1,62 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Relation; +use PhpMyAdmin\Url; +use PhpMyAdmin\Util; + +/** + * Represents a node that is a child of a database node + * This may either be a concrete child such as table or a container + * such as table container + * + * @package PhpMyAdmin-Navigation + */ +abstract class NodeDatabaseChild extends Node +{ + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + abstract protected function getItemType(); + + /** + * Returns HTML for control buttons displayed infront of a node + * + * @return String HTML for control buttons + */ + public function getHtmlForControlButtons() + { + $ret = ''; + $cfgRelation = $this->relation->getRelationsParam(); + if ($cfgRelation['navwork']) { + $db = $this->realParent()->realName; + $item = $this->realName; + + $params = [ + 'hideNavItem' => true, + 'itemType' => $this->getItemType(), + 'itemName' => $item, + 'dbName' => $db, + ]; + + $ret = '<span class="navItemControls">' + . '<a href="navigation.php" data-post="' + . Url::getCommon($params, '') . '"' + . ' class="hideNavItem ajax">' + . Util::getImage('hide', __('Hide')) + . '</a></span>'; + } + + return $ret; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php new file mode 100644 index 0000000..7c182c6 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseChildContainer.php @@ -0,0 +1,43 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Represents container node that carries children of a database + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +/** + * Represents container node that carries children of a database + * + * @package PhpMyAdmin-Navigation + */ +abstract class NodeDatabaseChildContainer extends NodeDatabaseChild +{ + /** + * Initialises the class by setting the common variables + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + */ + public function __construct($name, $type = Node::OBJECT) + { + parent::__construct($name, $type); + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $this->separator = $GLOBALS['cfg']['NavigationTreeTableSeparator']; + $this->separatorDepth = (int) $GLOBALS['cfg']['NavigationTreeTableLevel']; + } + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'group'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php new file mode 100644 index 0000000..9b5746f --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php @@ -0,0 +1,52 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\CheckUserPrivileges; +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for database nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeDatabaseContainer extends Node +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + */ + public function __construct($name) + { + $checkUserPrivileges = new CheckUserPrivileges($GLOBALS['dbi']); + $checkUserPrivileges->getPrivileges(); + + parent::__construct($name, Node::CONTAINER); + + if ($GLOBALS['is_create_db_priv'] + && $GLOBALS['cfg']['ShowCreateDb'] !== false + ) { + $new = NodeFactory::getInstance( + 'Node', + _pgettext('Create new database', 'New') + ); + $new->isNew = true; + $new->icon = Util::getImage('b_newdb', ''); + $new->links = [ + 'text' => 'server_databases.php?server=' . $GLOBALS['server'], + 'icon' => 'server_databases.php?server=' . $GLOBALS['server'], + ]; + $new->classes = 'new_database italics'; + $this->addChild($new); + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php new file mode 100644 index 0000000..91aa5ce --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEvent.php @@ -0,0 +1,51 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a event node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeEvent extends NodeDatabaseChild +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_events'); + $this->links = [ + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&edit_item=1', + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&export_item=1', + ]; + $this->classes = 'event'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'event'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php new file mode 100644 index 0000000..86c2937 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeEventContainer.php @@ -0,0 +1,52 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for events nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeEventContainer extends NodeDatabaseChildContainer +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Events'), Node::CONTAINER); + $this->icon = Util::getImage('b_events', ''); + $this->links = [ + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%1$s', + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%1$s', + ]; + $this->realName = 'events'; + + $new = NodeFactory::getInstance( + 'Node', + _pgettext('Create new event', 'New') + ); + $new->isNew = true; + $new->icon = Util::getImage('b_event_add', ''); + $new->links = [ + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1', + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1', + ]; + $new->classes = 'new_event italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php new file mode 100644 index 0000000..ffd2afe --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunction.php @@ -0,0 +1,53 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a function node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeFunction extends NodeDatabaseChild +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_routines', __('Function')); + $this->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' + . '&edit_item=1', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' + . '&execute_dialog=1', + ]; + $this->classes = 'function'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'function'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php new file mode 100644 index 0000000..52715a3 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeFunctionContainer.php @@ -0,0 +1,53 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for functions nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeFunctionContainer extends NodeDatabaseChildContainer +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Functions'), Node::CONTAINER); + $this->icon = Util::getImage('b_routines', __('Functions')); + $this->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&type=FUNCTION', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&type=FUNCTION', + ]; + $this->realName = 'functions'; + + $newLabel = _pgettext('Create new function', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_routine_add', $newLabel); + $new->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1&item_type=FUNCTION', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1&item_type=FUNCTION', + ]; + $new->classes = 'new_function italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php new file mode 100644 index 0000000..c464114 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndex.php @@ -0,0 +1,41 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a index node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeIndex extends Node +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_index', __('Index')); + $this->links = [ + 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&index=%1$s', + 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&index=%1$s', + ]; + $this->classes = 'index'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php new file mode 100644 index 0000000..9be90d3 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeIndexContainer.php @@ -0,0 +1,55 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for index nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeIndexContainer extends Node +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Indexes'), Node::CONTAINER); + $this->icon = Util::getImage('b_index', __('Indexes')); + $this->links = [ + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + ]; + $this->realName = 'indexes'; + + $newLabel = _pgettext('Create new index', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_index_add', $newLabel); + $new->links = [ + 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&create_index=1&added_fields=2' + . '&db=%3$s&table=%2$s', + 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&create_index=1&added_fields=2' + . '&db=%3$s&table=%2$s', + ]; + $new->classes = 'new_index italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php new file mode 100644 index 0000000..fbced93 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedure.php @@ -0,0 +1,53 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a procedure node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeProcedure extends NodeDatabaseChild +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_routines', __('Procedure')); + $this->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' + . '&edit_item=1', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' + . '&execute_dialog=1', + ]; + $this->classes = 'procedure'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'procedure'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php new file mode 100644 index 0000000..1978ede --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeProcedureContainer.php @@ -0,0 +1,53 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for procedure nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeProcedureContainer extends NodeDatabaseChildContainer +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Procedures'), Node::CONTAINER); + $this->icon = Util::getImage('b_routines', __('Procedures')); + $this->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&type=PROCEDURE', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&type=PROCEDURE', + ]; + $this->realName = 'procedures'; + + $newLabel = _pgettext('Create new procedure', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_routine_add', $newLabel); + $new->links = [ + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&add_item=1', + ]; + $new->classes = 'new_procedure italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php new file mode 100644 index 0000000..89965eb --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTable.php @@ -0,0 +1,310 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a columns node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeTable extends NodeDatabaseChild +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = []; + $this->addIcon( + Util::getScriptNameForOption( + $GLOBALS['cfg']['NavigationTreeDefaultTabTable'], + 'table' + ) + ); + $this->addIcon( + Util::getScriptNameForOption( + $GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], + 'table' + ) + ); + $title = Util::getTitleForTarget( + $GLOBALS['cfg']['DefaultTabTable'] + ); + $this->title = $title; + + $scriptName = Util::getScriptNameForOption( + $GLOBALS['cfg']['DefaultTabTable'], + 'table' + ); + $this->links = [ + 'text' => $scriptName + . '?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&pos=0', + 'icon' => [ + Util::getScriptNameForOption( + $GLOBALS['cfg']['NavigationTreeDefaultTabTable'], + 'table' + ) + . '?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + Util::getScriptNameForOption( + $GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], + 'table' + ) + . '?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + ], + 'title' => $this->title, + ]; + $this->classes = 'table'; + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase + * and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('columns' or 'indexes') + * @param string $searchClause A string used to filter the results of the query + * + * @return int + */ + public function getPresence($type = '', $searchClause = '') + { + $retval = 0; + $db = $this->realParent()->realName; + $table = $this->realName; + switch ($type) { + case 'columns': + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db'"; + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $db = Util::backquote($db); + $table = Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $retval = (int) $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + break; + case 'indexes': + $db = Util::backquote($db); + $table = Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $retval = (int) $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + break; + case 'triggers': + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA` " + . Util::getCollateForIS() . "='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE` " + . Util::getCollateForIS() . "='$table'"; + $retval = (int) $GLOBALS['dbi']->fetchValue($query); + } else { + $db = Util::backquote($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $retval = (int) $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + break; + default: + break; + } + + return $retval; + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase + * and PhpMyAdmin\Navigation\Nodes\NodeTable classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = []; + $db = $this->realParent()->realName; + $table = $this->realName; + switch ($type) { + case 'columns': + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SELECT `COLUMN_NAME` AS `name` "; + $query .= ",`COLUMN_KEY` AS `key` "; + $query .= ",`DATA_TYPE` AS `type` "; + $query .= ",`COLUMN_DEFAULT` AS `default` "; + $query .= ",IF (`IS_NULLABLE` = 'NO', '', 'nullable') AS `nullable` "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db' "; + $query .= "ORDER BY `COLUMN_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + } + + $db = Util::backquote($db); + $table = Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + break; + } + + $count = 0; + if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr['Field']; + $count++; + } else { + break; + } + } + } + break; + case 'indexes': + $db = Util::backquote($db); + $table = Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + break; + } + + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if (in_array($arr['Key_name'], $retval)) { + continue; + } + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Key_name']; + $count++; + } + $pos--; + } + break; + case 'triggers': + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = $GLOBALS['dbi']->escapeString($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SELECT `TRIGGER_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA` " + . Util::getCollateForIS() . "='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE` " + . Util::getCollateForIS() . "='$table' "; + $query .= "ORDER BY `TRIGGER_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + } + + $db = Util::backquote($db); + $table = $GLOBALS['dbi']->escapeString($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle === false) { + break; + } + + $count = 0; + if ($GLOBALS['dbi']->dataSeek($handle, $pos)) { + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($count < $maxItems) { + $retval[] = $arr['Trigger']; + $count++; + } else { + break; + } + } + } + break; + default: + break; + } + + return $retval; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'table'; + } + + /** + * Add an icon to navigation tree + * + * @param string $page Page name to redirect + * + * @return void + */ + private function addIcon($page) + { + if (empty($page)) { + return; + } + + switch ($page) { + case 'tbl_structure.php': + $this->icon[] = Util::getImage('b_props', __('Structure')); + break; + case 'tbl_select.php': + $this->icon[] = Util::getImage('b_search', __('Search')); + break; + case 'tbl_change.php': + $this->icon[] = Util::getImage('b_insrow', __('Insert')); + break; + case 'tbl_sql.php': + $this->icon[] = Util::getImage('b_sql', __('SQL')); + break; + case 'sql.php': + $this->icon[] = Util::getImage('b_browse', __('Browse')); + break; + } + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php new file mode 100644 index 0000000..ec93203 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTableContainer.php @@ -0,0 +1,54 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for table nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeTableContainer extends NodeDatabaseChildContainer +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Tables'), Node::CONTAINER); + $this->icon = Util::getImage('b_browse', __('Tables')); + $this->links = [ + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=table', + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=table', + ]; + $this->realName = 'tables'; + $this->classes = 'tableContainer subContainer'; + + $newLabel = _pgettext('Create new table', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_table_add', $newLabel); + $new->links = [ + 'text' => 'tbl_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s', + 'icon' => 'tbl_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s', + ]; + $new->classes = 'new_table italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php new file mode 100644 index 0000000..8ec4612 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTrigger.php @@ -0,0 +1,41 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a trigger node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeTrigger extends Node +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_triggers'); + $this->links = [ + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&item_name=%1$s&edit_item=1', + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&item_name=%1$s&export_item=1', + ]; + $this->classes = 'trigger'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php new file mode 100644 index 0000000..a5aa3b7 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeTriggerContainer.php @@ -0,0 +1,52 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for trigger nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeTriggerContainer extends Node +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Triggers'), Node::CONTAINER); + $this->icon = Util::getImage('b_triggers'); + $this->links = [ + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + ]; + $this->realName = 'triggers'; + + $new = NodeFactory::getInstance( + 'Node', + _pgettext('Create new trigger', 'New') + ); + $new->isNew = true; + $new->icon = Util::getImage('b_trigger_add', ''); + $new->links = [ + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&add_item=1', + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&add_item=1', + ]; + $new->classes = 'new_trigger italics'; + $this->addChild($new); + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php new file mode 100644 index 0000000..1ded149 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeView.php @@ -0,0 +1,51 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Util; + +/** + * Represents a view node in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeView extends NodeDatabaseChild +{ + /** + * Initialises the class + * + * @param string $name An identifier for the new node + * @param int $type Type of node, may be one of CONTAINER or OBJECT + * @param bool $isGroup Whether this object has been created + * while grouping nodes + */ + public function __construct($name, $type = Node::OBJECT, $isGroup = false) + { + parent::__construct($name, $type, $isGroup); + $this->icon = Util::getImage('b_props', __('View')); + $this->links = [ + 'text' => 'sql.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s&pos=0', + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s', + ]; + $this->classes = 'view'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'view'; + } +} diff --git a/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php new file mode 100644 index 0000000..f202904 --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Navigation/Nodes/NodeViewContainer.php @@ -0,0 +1,54 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Navigation\Nodes; + +use PhpMyAdmin\Navigation\NodeFactory; +use PhpMyAdmin\Util; + +/** + * Represents a container for view nodes in the navigation tree + * + * @package PhpMyAdmin-Navigation + */ +class NodeViewContainer extends NodeDatabaseChildContainer +{ + /** + * Initialises the class + */ + public function __construct() + { + parent::__construct(__('Views'), Node::CONTAINER); + $this->icon = Util::getImage('b_views', __('Views')); + $this->links = [ + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=view', + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=view', + ]; + $this->classes = 'viewContainer subContainer'; + $this->realName = 'views'; + + $newLabel = _pgettext('Create new view', 'New'); + $new = NodeFactory::getInstance( + 'Node', + $newLabel + ); + $new->isNew = true; + $new->icon = Util::getImage('b_view_add', $newLabel); + $new->links = [ + 'text' => 'view_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s', + 'icon' => 'view_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s', + ]; + $new->classes = 'new_view italics'; + $this->addChild($new); + } +} |
