Node.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Functionality for the navigation tree in the left frame
  5. *
  6. * @package PhpMyAdmin-Navigation
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * The Node is the building block for the collapsible navigation tree
  13. *
  14. * @package PhpMyAdmin-Navigation
  15. */
  16. class Node
  17. {
  18. /**
  19. * @var int Defines a possible node type
  20. */
  21. const CONTAINER = 0;
  22. /**
  23. * @var int Defines a possible node type
  24. */
  25. const OBJECT = 1;
  26. /**
  27. * @var string A non-unique identifier for the node
  28. * This may be trimmed when grouping nodes
  29. */
  30. public $name = "";
  31. /**
  32. * @var string A non-unique identifier for the node
  33. * This will never change after being assigned
  34. */
  35. public $real_name = "";
  36. /**
  37. * @var int May be one of CONTAINER or OBJECT
  38. */
  39. public $type = Node::OBJECT;
  40. /**
  41. * @var bool Whether this object has been created while grouping nodes
  42. * Only relevant if the node is of type CONTAINER
  43. */
  44. public $is_group;
  45. /**
  46. * @var bool Whether to add a "display: none;" CSS
  47. * rule to the node when rendering it
  48. */
  49. public $visible = false;
  50. /**
  51. * @var Node A reference to the parent object of
  52. * this node, NULL for the root node.
  53. */
  54. public $parent;
  55. /**
  56. * @var array An array of Node objects that are
  57. * direct children of this node
  58. */
  59. public $children = array();
  60. /**
  61. * @var Mixed A string used to group nodes, or an array of strings
  62. * Only relevant if the node is of type CONTAINER
  63. */
  64. public $separator = '';
  65. /**
  66. * @var int How many time to recursively apply the grouping function
  67. * Only relevant if the node is of type CONTAINER
  68. */
  69. public $separator_depth = 1;
  70. /**
  71. * @var string An IMG tag, used when rendering the node
  72. */
  73. public $icon;
  74. /**
  75. * @var Array An array of A tags, used when rendering the node
  76. * The indexes in the array may be 'icon' and 'text'
  77. */
  78. public $links;
  79. /**
  80. * @var string Extra CSS classes for the node
  81. */
  82. public $classes = '';
  83. /**
  84. * @var string Whether this node is a link for creating new objects
  85. */
  86. public $isNew = false;
  87. /**
  88. * @var int The position for the pagination of
  89. * the branch at the second level of the tree
  90. */
  91. public $pos2 = 0;
  92. /**
  93. * @var int The position for the pagination of
  94. * the branch at the third level of the tree
  95. */
  96. public $pos3 = 0;
  97. /**
  98. * Initialises the class by setting the mandatory variables
  99. *
  100. * @param string $name An identifier for the new node
  101. * @param int $type Type of node, may be one of CONTAINER or OBJECT
  102. * @param bool $is_group Whether this object has been created
  103. * while grouping nodes
  104. *
  105. * @return Node
  106. */
  107. public function __construct($name, $type = Node::OBJECT, $is_group = false)
  108. {
  109. if (! empty($name)) {
  110. $this->name = $name;
  111. $this->real_name = $name;
  112. }
  113. if ($type === Node::CONTAINER) {
  114. $this->type = Node::CONTAINER;
  115. }
  116. $this->is_group = (bool)$is_group;
  117. }
  118. /**
  119. * Adds a child node to this node
  120. *
  121. * @param Node $child A child node
  122. *
  123. * @return nothing
  124. */
  125. public function addChild($child)
  126. {
  127. $this->children[] = $child;
  128. $child->parent = $this;
  129. }
  130. /**
  131. * Returns a child node given it's name
  132. *
  133. * @param string $name The name of requested child
  134. * @param bool $real_name Whether to use the "real_name"
  135. * instead of "name" in comparisons
  136. *
  137. * @return false|Node The requested child node or false,
  138. * if the requested node cannot be found
  139. */
  140. public function getChild($name, $real_name = false)
  141. {
  142. if ($real_name) {
  143. foreach ($this->children as $child) {
  144. if ($child->real_name == $name) {
  145. return $child;
  146. }
  147. }
  148. } else {
  149. foreach ($this->children as $child) {
  150. if ($child->name == $name) {
  151. return $child;
  152. }
  153. }
  154. }
  155. return false;
  156. }
  157. /**
  158. * Removes a child node from this node
  159. *
  160. * @param string $name The name of child to be removed
  161. *
  162. * @return nothing
  163. */
  164. public function removeChild($name)
  165. {
  166. foreach ($this->children as $key => $child) {
  167. if ($child->name == $name) {
  168. unset($this->children[$key]);
  169. break;
  170. }
  171. }
  172. }
  173. /**
  174. * Retreives the parents for a node
  175. *
  176. * @param bool $self Whether to include the Node itself in the results
  177. * @param bool $containers Whether to include nodes of type CONTAINER
  178. * @param bool $groups Whether to include nodes which have $group == true
  179. *
  180. * @return array An array of parent Nodes
  181. */
  182. public function parents($self = false, $containers = false, $groups = false)
  183. {
  184. $parents = array();
  185. if ($self
  186. && ($this->type != Node::CONTAINER || $containers)
  187. && ($this->is_group != true || $groups)
  188. ) {
  189. $parents[] = $this;
  190. $self = false;
  191. }
  192. $parent = $this->parent;
  193. while (isset($parent)) {
  194. if ( ($parent->type != Node::CONTAINER || $containers)
  195. && ($parent->is_group != true || $groups)
  196. ) {
  197. $parents[] = $parent;
  198. }
  199. $parent = $parent->parent;
  200. }
  201. return $parents;
  202. }
  203. /**
  204. * Returns the actual parent of a node. If used twice on an index or columns
  205. * node, it will return the table and database nodes. The names of the returned
  206. * nodes can be used in SQL queries, etc...
  207. *
  208. * @return Node
  209. */
  210. public function realParent()
  211. {
  212. $retval = $this->parents();
  213. if (count($retval) > 0) {
  214. return $retval[0];
  215. } else {
  216. return false;
  217. }
  218. }
  219. /**
  220. * This function checks if the node has children nodes associated with it
  221. *
  222. * @param bool $count_empty_containers Whether to count empty child
  223. * containers as valid children
  224. *
  225. * @return bool Whether the node has child nodes
  226. */
  227. public function hasChildren($count_empty_containers = true)
  228. {
  229. $retval = false;
  230. if ($count_empty_containers) {
  231. if (count($this->children)) {
  232. $retval = true;
  233. }
  234. } else {
  235. foreach ($this->children as $child) {
  236. if ($child->type == Node::OBJECT || $child->hasChildren(false)) {
  237. $retval = true;
  238. break;
  239. }
  240. }
  241. }
  242. return $retval;
  243. }
  244. /**
  245. * Returns true the node has some siblings (other nodes on the same tree level,
  246. * in the same branch), false otherwise. The only exception is for nodes on
  247. * the third level of the tree (columns and indexes), for which the function
  248. * always returns true. This is because we want to render the containers
  249. * for these nodes
  250. *
  251. * @return bool
  252. */
  253. public function hasSiblings()
  254. {
  255. $retval = false;
  256. $paths = $this->getPaths();
  257. if (count($paths['aPath_clean']) > 3) {
  258. $retval = true;
  259. } else {
  260. foreach ($this->parent->children as $child) {
  261. if ($child !== $this
  262. && ($child->type == Node::OBJECT || $child->hasChildren(false))
  263. ) {
  264. $retval = true;
  265. break;
  266. }
  267. }
  268. }
  269. return $retval;
  270. }
  271. /**
  272. * Returns the number of child nodes that a node has associated with it
  273. *
  274. * @return int The number of children nodes
  275. */
  276. public function numChildren()
  277. {
  278. $retval = 0;
  279. foreach ($this->children as $child) {
  280. if ($child->type == Node::OBJECT) {
  281. $retval++;
  282. } else {
  283. $retval += $child->numChildren();
  284. }
  285. }
  286. return $retval;
  287. }
  288. /**
  289. * Returns the actual path and the virtual paths for a node
  290. * both as clean arrays and base64 encoded strings
  291. *
  292. * @return array
  293. */
  294. public function getPaths()
  295. {
  296. $aPath = array();
  297. $aPath_clean = array();
  298. foreach ($this->parents(true, true, false) as $parent) {
  299. $aPath[] = base64_encode($parent->real_name);
  300. $aPath_clean[] = $parent->real_name;
  301. }
  302. $aPath = implode('.', array_reverse($aPath));
  303. $aPath_clean = array_reverse($aPath_clean);
  304. $vPath = array();
  305. $vPath_clean = array();
  306. foreach ($this->parents(true, true, true) as $parent) {
  307. $vPath[] = base64_encode($parent->name);
  308. $vPath_clean[] = $parent->name;
  309. }
  310. $vPath = implode('.', array_reverse($vPath));
  311. $vPath_clean = array_reverse($vPath_clean);
  312. return array(
  313. 'aPath' => $aPath,
  314. 'aPath_clean' => $aPath_clean,
  315. 'vPath' => $vPath,
  316. 'vPath_clean' => $vPath_clean
  317. );
  318. }
  319. /**
  320. * Returns the names of children of type $type present inside this container
  321. * This method is overridden by the Node_Database and Node_Table classes
  322. *
  323. * @param string $type The type of item we are looking for
  324. * ('tables', 'views', etc)
  325. * @param int $pos The offset of the list within the results
  326. * @param string $searchClause A string used to filter the results of the query
  327. *
  328. * @return array
  329. */
  330. public function getData($type, $pos, $searchClause = '')
  331. {
  332. // @todo obey the DisableIS directive
  333. $query = "SELECT `SCHEMA_NAME` ";
  334. $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` ";
  335. $query .= $this->_getWhereClause($searchClause);
  336. $query .= "ORDER BY `SCHEMA_NAME` ASC ";
  337. $query .= "LIMIT $pos, {$GLOBALS['cfg']['MaxNavigationItems']}";
  338. return PMA_DBI_fetch_result($query);
  339. }
  340. /**
  341. * Returns the number of children of type $type present inside this container
  342. * This method is overridden by the Node_Database and Node_Table classes
  343. *
  344. * @param string $type The type of item we are looking for
  345. * ('tables', 'views', etc)
  346. * @param string $searchClause A string used to filter the results of the query
  347. *
  348. * @return int
  349. */
  350. public function getPresence($type = '', $searchClause = '')
  351. {
  352. if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) {
  353. $query = "SELECT COUNT(*) ";
  354. $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` ";
  355. $query .= $this->_getWhereClause($searchClause);
  356. $retval = (int)PMA_DBI_fetch_value($query);
  357. } else {
  358. $query = "SHOW DATABASES ";
  359. if (! empty($searchClause)) {
  360. $query .= "LIKE '%";
  361. $query .= PMA_Util::sqlAddSlashes(
  362. $searchClause, true
  363. );
  364. $query .= "%' ";
  365. }
  366. $retval = PMA_DBI_num_rows(PMA_DBI_try_query($query));
  367. }
  368. return $retval;
  369. }
  370. /**
  371. * Returns the WHERE clause depending on the $searchClause parameter
  372. * and the hide_db directive
  373. *
  374. * @param string $searchClause A string used to filter the results of the query
  375. *
  376. * @return string
  377. */
  378. private function _getWhereClause($searchClause = '')
  379. {
  380. $whereClause = "WHERE TRUE ";
  381. if (! empty($searchClause)) {
  382. $whereClause .= "AND `SCHEMA_NAME` LIKE '%";
  383. $whereClause .= PMA_Util::sqlAddSlashes(
  384. $searchClause, true
  385. );
  386. $whereClause .= "%' ";
  387. }
  388. if (! empty($GLOBALS['cfg']['Server']['hide_db'])) {
  389. $whereClause .= "AND `SCHEMA_NAME` NOT REGEXP '"
  390. . $GLOBALS['cfg']['Server']['hide_db'] . "' ";
  391. }
  392. if (! empty($GLOBALS['cfg']['Server']['only_db'])) {
  393. if (is_string($GLOBALS['cfg']['Server']['only_db'])) {
  394. $GLOBALS['cfg']['Server']['only_db'] = array(
  395. $GLOBALS['cfg']['Server']['only_db']
  396. );
  397. }
  398. $whereClause .= "AND (";
  399. $subClauses = array();
  400. foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) {
  401. $subClauses[] = " `SCHEMA_NAME` LIKE '"
  402. . $each_only_db . "' ";
  403. }
  404. $whereClause .= implode("OR", $subClauses) . ")";
  405. }
  406. return $whereClause;
  407. }
  408. }
  409. ?>