PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/phpMyAdmin/libraries/relation.lib.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 1138 lines | 702 code | 146 blank | 290 comment | 190 complexity | 240e044e4e813791d6947c11ea60da86 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.0, JSON, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Set of functions used with the relation and pdf feature
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * Executes a query as controluser if possible, otherwise as normal user
  13. *
  14. * @param string $sql the query to execute
  15. * @param boolean $show_error whether to display SQL error messages or not
  16. * @param int $options query options
  17. *
  18. * @return integer the result set, or false if no result set
  19. *
  20. * @access public
  21. *
  22. */
  23. function PMA_query_as_controluser($sql, $show_error = true, $options = 0)
  24. {
  25. // Avoid caching of the number of rows affected; for example, this function
  26. // is called for tracking purposes but we want to display the correct number
  27. // of rows affected by the original query, not by the query generated for
  28. // tracking.
  29. $cache_affected_rows = false;
  30. if ($show_error) {
  31. $result = PMA_DBI_query($sql, $GLOBALS['controllink'], $options, $cache_affected_rows);
  32. } else {
  33. $result = @PMA_DBI_try_query($sql, $GLOBALS['controllink'], $options, $cache_affected_rows);
  34. } // end if... else...
  35. if ($result) {
  36. return $result;
  37. } else {
  38. return false;
  39. }
  40. } // end of the "PMA_query_as_controluser()" function
  41. /**
  42. * @param bool $verbose whether to print diagnostic info
  43. *
  44. * @return array $cfgRelation
  45. */
  46. function PMA_getRelationsParam($verbose = false)
  47. {
  48. if (empty($_SESSION['relation'][$GLOBALS['server']])) {
  49. $_SESSION['relation'][$GLOBALS['server']] = PMA__getRelationsParam();
  50. }
  51. // just for BC but needs to be before PMA_printRelationsParamDiagnostic()
  52. // which uses it
  53. $GLOBALS['cfgRelation'] = $_SESSION['relation'][$GLOBALS['server']];
  54. if ($verbose) {
  55. PMA_printRelationsParamDiagnostic($_SESSION['relation'][$GLOBALS['server']]);
  56. }
  57. return $_SESSION['relation'][$GLOBALS['server']];
  58. }
  59. /**
  60. * prints out diagnostic info for pma relation feature
  61. *
  62. * @param array $cfgRelation
  63. *
  64. * @return nothing
  65. */
  66. function PMA_printRelationsParamDiagnostic($cfgRelation)
  67. {
  68. $messages['error'] = '<font color="red"><strong>' . __('not OK')
  69. . '</strong></font> [ <a href="Documentation.html#%s" target="documentation">'
  70. . __('Documentation') . '</a> ]';
  71. $messages['ok'] = '<font color="green"><strong>' . __('OK') . '</strong></font>';
  72. $messages['enabled'] = '<font color="green">' . __('Enabled') . '</font>';
  73. $messages['disabled'] = '<font color="red">' . __('Disabled') . '</font>';
  74. if (false === $GLOBALS['cfg']['Server']['pmadb']) {
  75. echo 'PMA Database ... '
  76. . sprintf($messages['error'], 'pmadb')
  77. . '<br />' . "\n"
  78. . __('General relation features')
  79. . ' <font color="green">' . __('Disabled')
  80. . '</font>' . "\n";
  81. return;
  82. }
  83. echo '<table>' . "\n";
  84. PMA_printDiagMessageForParameter('pmadb', $GLOBALS['cfg']['Server']['pmadb'], $messages, 'pmadb');
  85. PMA_printDiagMessageForParameter('relation', isset($cfgRelation['relation']), $messages, 'relation');
  86. PMA_printDiagMessageForFeature(__('General relation features'), 'relwork', $messages);
  87. PMA_printDiagMessageForParameter('table_info', isset($cfgRelation['table_info']), $messages, 'table_info');
  88. PMA_printDiagMessageForFeature(__('Display Features'), 'displaywork', $messages);
  89. PMA_printDiagMessageForParameter('table_coords', isset($cfgRelation['table_coords']), $messages, 'table_coords');
  90. PMA_printDiagMessageForParameter('pdf_pages', isset($cfgRelation['pdf_pages']), $messages, 'table_coords');
  91. PMA_printDiagMessageForFeature(__('Creation of PDFs'), 'pdfwork', $messages);
  92. PMA_printDiagMessageForParameter('column_info', isset($cfgRelation['column_info']), $messages, 'col_com');
  93. PMA_printDiagMessageForFeature(__('Displaying Column Comments'), 'commwork', $messages, false);
  94. PMA_printDiagMessageForFeature(__('Browser transformation'), 'mimework', $messages);
  95. if ($cfgRelation['commwork'] && ! $cfgRelation['mimework']) {
  96. echo '<tr><td colspan=2 align="left">' . __('Please see the documentation on how to update your column_comments table') . '</td></tr>' . "\n";
  97. }
  98. PMA_printDiagMessageForParameter('bookmarktable', isset($cfgRelation['bookmark']), $messages, 'bookmark');
  99. PMA_printDiagMessageForFeature(__('Bookmarked SQL query'), 'bookmarkwork', $messages);
  100. PMA_printDiagMessageForParameter('history', isset($cfgRelation['history']), $messages, 'history');
  101. PMA_printDiagMessageForFeature(__('SQL history'), 'historywork', $messages);
  102. PMA_printDiagMessageForParameter('designer_coords', isset($cfgRelation['designer_coords']), $messages, 'designer_coords');
  103. PMA_printDiagMessageForFeature(__('Designer'), 'designerwork', $messages);
  104. PMA_printDiagMessageForParameter('recent', isset($cfgRelation['recent']), $messages, 'recent');
  105. PMA_printDiagMessageForFeature(__('Persistent recently used tables'), 'recentwork', $messages);
  106. PMA_printDiagMessageForParameter('table_uiprefs', isset($cfgRelation['table_uiprefs']), $messages, 'table_uiprefs');
  107. PMA_printDiagMessageForFeature(__('Persistent tables\' UI preferences'), 'uiprefswork', $messages);
  108. PMA_printDiagMessageForParameter('tracking', isset($cfgRelation['tracking']), $messages, 'tracking');
  109. PMA_printDiagMessageForFeature(__('Tracking'), 'trackingwork', $messages);
  110. PMA_printDiagMessageForParameter('userconfig', isset($cfgRelation['userconfig']), $messages, 'userconfig');
  111. PMA_printDiagMessageForFeature(__('User preferences'), 'userconfigwork', $messages);
  112. echo '</table>' . "\n";
  113. echo '<p>' . __('Quick steps to setup advanced features:') . '</p>';
  114. echo '<ul>';
  115. echo '<li>' . __('Create the needed tables with the <code>examples/create_tables.sql</code>.') . ' ' . PMA_showDocu('linked-tables') . '</li>';
  116. echo '<li>' . __('Create a pma user and give access to these tables.') . ' ' . PMA_showDocu('pmausr') . '</li>';
  117. echo '<li>' . __('Enable advanced features in configuration file (<code>config.inc.php</code>), for example by starting from <code>config.sample.inc.php</code>.') . ' ' . PMA_showDocu('quick_install') . '</li>';
  118. echo '<li>' . __('Re-login to phpMyAdmin to load the updated configuration file.') . '</li>';
  119. echo '</ul>';
  120. }
  121. /**
  122. * prints out one diagnostic message for a feature
  123. *
  124. * @param string $feature_name feature name in a message string
  125. * @param string $relation_parameter the $GLOBALS['cfgRelation'] parameter to check
  126. * @param array $messages utility messages
  127. * @param boolean $skip_line whether to skip a line after the message
  128. *
  129. * @return nothing
  130. */
  131. function PMA_printDiagMessageForFeature($feature_name, $relation_parameter, $messages, $skip_line=true)
  132. {
  133. echo ' <tr><td colspan=2 align="right">' . $feature_name . ': '
  134. . ($GLOBALS['cfgRelation'][$relation_parameter] ? $messages['enabled'] : $messages['disabled'])
  135. . '</td></tr>' . "\n";
  136. if ($skip_line) {
  137. echo ' <tr><td>&nbsp;</td></tr>' . "\n";
  138. }
  139. }
  140. /**
  141. * prints out one diagnostic message for a configuration parameter
  142. *
  143. * @param string $parameter config parameter name to display
  144. * @param boolean $relation_parameter_set whether this parameter is set
  145. * @param array $messages utility messages
  146. * @param string $doc_anchor anchor in Documentation.html
  147. *
  148. * @return nothing
  149. */
  150. function PMA_printDiagMessageForParameter($parameter, $relation_parameter_set, $messages, $doc_anchor)
  151. {
  152. echo ' <tr><th align="left">';
  153. echo '$cfg[\'Servers\'][$i][\'' . $parameter . '\'] ... </th><td align="right">';
  154. echo ($relation_parameter_set ? $messages['ok'] : sprintf($messages['error'], $doc_anchor)) . '</td></tr>' . "\n";
  155. }
  156. /**
  157. * Defines the relation parameters for the current user
  158. * just a copy of the functions used for relations ;-)
  159. * but added some stuff to check what will work
  160. *
  161. * @access protected
  162. * @return array the relation parameters for the current user
  163. */
  164. function PMA__getRelationsParam()
  165. {
  166. $cfgRelation = array();
  167. $cfgRelation['relwork'] = false;
  168. $cfgRelation['displaywork'] = false;
  169. $cfgRelation['bookmarkwork']= false;
  170. $cfgRelation['pdfwork'] = false;
  171. $cfgRelation['commwork'] = false;
  172. $cfgRelation['mimework'] = false;
  173. $cfgRelation['historywork'] = false;
  174. $cfgRelation['recentwork'] = false;
  175. $cfgRelation['uiprefswork'] = false;
  176. $cfgRelation['trackingwork'] = false;
  177. $cfgRelation['designerwork'] = false;
  178. $cfgRelation['userconfigwork'] = false;
  179. $cfgRelation['allworks'] = false;
  180. $cfgRelation['user'] = null;
  181. $cfgRelation['db'] = null;
  182. if ($GLOBALS['server'] == 0 || empty($GLOBALS['cfg']['Server']['pmadb'])
  183. || ! PMA_DBI_select_db($GLOBALS['cfg']['Server']['pmadb'], $GLOBALS['controllink'])
  184. ) {
  185. // No server selected -> no bookmark table
  186. // we return the array with the falses in it,
  187. // to avoid some 'Unitialized string offset' errors later
  188. $GLOBALS['cfg']['Server']['pmadb'] = false;
  189. return $cfgRelation;
  190. }
  191. $cfgRelation['user'] = $GLOBALS['cfg']['Server']['user'];
  192. $cfgRelation['db'] = $GLOBALS['cfg']['Server']['pmadb'];
  193. // Now I just check if all tables that i need are present so I can for
  194. // example enable relations but not pdf...
  195. // I was thinking of checking if they have all required columns but I
  196. // fear it might be too slow
  197. $tab_query = 'SHOW TABLES FROM ' . PMA_backquote($GLOBALS['cfg']['Server']['pmadb']);
  198. $tab_rs = PMA_query_as_controluser($tab_query, false, PMA_DBI_QUERY_STORE);
  199. if (! $tab_rs) {
  200. // query failed ... ?
  201. //$GLOBALS['cfg']['Server']['pmadb'] = false;
  202. return $cfgRelation;
  203. }
  204. while ($curr_table = @PMA_DBI_fetch_row($tab_rs)) {
  205. if ($curr_table[0] == $GLOBALS['cfg']['Server']['bookmarktable']) {
  206. $cfgRelation['bookmark'] = $curr_table[0];
  207. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['relation']) {
  208. $cfgRelation['relation'] = $curr_table[0];
  209. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_info']) {
  210. $cfgRelation['table_info'] = $curr_table[0];
  211. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_coords']) {
  212. $cfgRelation['table_coords'] = $curr_table[0];
  213. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['designer_coords']) {
  214. $cfgRelation['designer_coords'] = $curr_table[0];
  215. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['column_info']) {
  216. $cfgRelation['column_info'] = $curr_table[0];
  217. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['pdf_pages']) {
  218. $cfgRelation['pdf_pages'] = $curr_table[0];
  219. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['history']) {
  220. $cfgRelation['history'] = $curr_table[0];
  221. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['recent']) {
  222. $cfgRelation['recent'] = $curr_table[0];
  223. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_uiprefs']) {
  224. $cfgRelation['table_uiprefs'] = $curr_table[0];
  225. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['tracking']) {
  226. $cfgRelation['tracking'] = $curr_table[0];
  227. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['userconfig']) {
  228. $cfgRelation['userconfig'] = $curr_table[0];
  229. }
  230. } // end while
  231. PMA_DBI_free_result($tab_rs);
  232. if (isset($cfgRelation['relation'])) {
  233. $cfgRelation['relwork'] = true;
  234. if (isset($cfgRelation['table_info'])) {
  235. $cfgRelation['displaywork'] = true;
  236. }
  237. }
  238. if (isset($cfgRelation['table_coords']) && isset($cfgRelation['pdf_pages'])) {
  239. $cfgRelation['pdfwork'] = true;
  240. }
  241. if (isset($cfgRelation['column_info'])) {
  242. $cfgRelation['commwork'] = true;
  243. if ($GLOBALS['cfg']['Server']['verbose_check']) {
  244. $mime_query = PMA_DBI_get_columns_sql($cfgRelation['db'], $cfgRelation['column_info']);
  245. $mime_rs = PMA_query_as_controluser($mime_query, false);
  246. $mime_field_mimetype = false;
  247. $mime_field_transformation = false;
  248. $mime_field_transformation_options = false;
  249. while ($curr_mime_field = @PMA_DBI_fetch_row($mime_rs)) {
  250. if ($curr_mime_field[0] == 'mimetype') {
  251. $mime_field_mimetype = true;
  252. } elseif ($curr_mime_field[0] == 'transformation') {
  253. $mime_field_transformation = true;
  254. } elseif ($curr_mime_field[0] == 'transformation_options') {
  255. $mime_field_transformation_options = true;
  256. }
  257. }
  258. PMA_DBI_free_result($mime_rs);
  259. if ($mime_field_mimetype
  260. && $mime_field_transformation
  261. && $mime_field_transformation_options
  262. ) {
  263. $cfgRelation['mimework'] = true;
  264. }
  265. } else {
  266. $cfgRelation['mimework'] = true;
  267. }
  268. }
  269. if (isset($cfgRelation['history'])) {
  270. $cfgRelation['historywork'] = true;
  271. }
  272. if (isset($cfgRelation['recent'])) {
  273. $cfgRelation['recentwork'] = true;
  274. }
  275. if (isset($cfgRelation['table_uiprefs'])) {
  276. $cfgRelation['uiprefswork'] = true;
  277. }
  278. if (isset($cfgRelation['tracking'])) {
  279. $cfgRelation['trackingwork'] = true;
  280. }
  281. if (isset($cfgRelation['userconfig'])) {
  282. $cfgRelation['userconfigwork'] = true;
  283. }
  284. // we do not absolutely need that the internal relations or the PDF
  285. // schema feature be activated
  286. if (isset($cfgRelation['designer_coords'])) {
  287. $cfgRelation['designerwork'] = true;
  288. }
  289. if (isset($cfgRelation['bookmark'])) {
  290. $cfgRelation['bookmarkwork'] = true;
  291. }
  292. if ($cfgRelation['relwork'] && $cfgRelation['displaywork']
  293. && $cfgRelation['pdfwork'] && $cfgRelation['commwork']
  294. && $cfgRelation['mimework'] && $cfgRelation['historywork']
  295. && $cfgRelation['recentwork'] && $cfgRelation['uiprefswork']
  296. && $cfgRelation['trackingwork'] && $cfgRelation['userconfigwork']
  297. && $cfgRelation['bookmarkwork'] && $cfgRelation['designerwork']
  298. ) {
  299. $cfgRelation['allworks'] = true;
  300. }
  301. return $cfgRelation;
  302. } // end of the 'PMA_getRelationsParam()' function
  303. /**
  304. * Gets all Relations to foreign tables for a given table or
  305. * optionally a given column in a table
  306. *
  307. * @param string $db the name of the db to check for
  308. * @param string $table the name of the table to check for
  309. * @param string $column the name of the column to check for
  310. * @param string $source the source for foreign key information
  311. *
  312. * @return array db,table,column
  313. *
  314. * @access public
  315. */
  316. function PMA_getForeigners($db, $table, $column = '', $source = 'both')
  317. {
  318. $cfgRelation = PMA_getRelationsParam();
  319. $foreign = array();
  320. if ($cfgRelation['relwork'] && ($source == 'both' || $source == 'internal')) {
  321. $rel_query = '
  322. SELECT `master_field`,
  323. `foreign_db`,
  324. `foreign_table`,
  325. `foreign_field`
  326. FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['relation']) . '
  327. WHERE `master_db` = \'' . PMA_sqlAddSlashes($db) . '\'
  328. AND `master_table` = \'' . PMA_sqlAddSlashes($table) . '\' ';
  329. if (strlen($column)) {
  330. $rel_query .= ' AND `master_field` = \'' . PMA_sqlAddSlashes($column) . '\'';
  331. }
  332. $foreign = PMA_DBI_fetch_result($rel_query, 'master_field', null, $GLOBALS['controllink']);
  333. }
  334. if (($source == 'both' || $source == 'foreign') && strlen($table)) {
  335. $show_create_table_query = 'SHOW CREATE TABLE '
  336. . PMA_backquote($db) . '.' . PMA_backquote($table);
  337. $show_create_table = PMA_DBI_fetch_value($show_create_table_query, 0, 1);
  338. $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table));
  339. foreach ($analyzed_sql[0]['foreign_keys'] as $one_key) {
  340. // The analyzer may return more than one column name in the
  341. // index list or the ref_index_list; if this happens,
  342. // the current logic just discards the whole index; having
  343. // more than one index field is currently unsupported (see FAQ 3.6)
  344. if (count($one_key['index_list']) == 1) {
  345. foreach ($one_key['index_list'] as $i => $field) {
  346. // If a foreign key is defined in the 'internal' source (pmadb)
  347. // and as a native foreign key, we won't get it twice
  348. // if $source='both' because we use $field as key
  349. // The parser looks for a CONSTRAINT clause just before
  350. // the FOREIGN KEY clause. It finds it (as output from
  351. // SHOW CREATE TABLE) in MySQL 4.0.13, but not in older
  352. // versions like 3.23.58.
  353. // In those cases, the FOREIGN KEY parsing will put numbers
  354. // like -1, 0, 1... instead of the constraint number.
  355. if (isset($one_key['constraint'])) {
  356. $foreign[$field]['constraint'] = $one_key['constraint'];
  357. }
  358. if (isset($one_key['ref_db_name'])) {
  359. $foreign[$field]['foreign_db'] = $one_key['ref_db_name'];
  360. } else {
  361. $foreign[$field]['foreign_db'] = $db;
  362. }
  363. $foreign[$field]['foreign_table'] = $one_key['ref_table_name'];
  364. $foreign[$field]['foreign_field'] = $one_key['ref_index_list'][$i];
  365. if (isset($one_key['on_delete'])) {
  366. $foreign[$field]['on_delete'] = $one_key['on_delete'];
  367. }
  368. if (isset($one_key['on_update'])) {
  369. $foreign[$field]['on_update'] = $one_key['on_update'];
  370. }
  371. }
  372. }
  373. }
  374. }
  375. /**
  376. * Emulating relations for some information_schema and data_dictionary tables
  377. */
  378. $is_information_schema = strtolower($db) == 'information_schema';
  379. $is_data_dictionary = PMA_DRIZZLE && strtolower($db) == 'data_dictionary';
  380. if (($is_information_schema || $is_data_dictionary) && ($source == 'internal' || $source == 'both')) {
  381. if ($is_information_schema) {
  382. $relations_key = 'information_schema_relations';
  383. include_once './libraries/information_schema_relations.lib.php';
  384. } else {
  385. $relations_key = 'data_dictionary_relations';
  386. include_once './libraries/data_dictionary_relations.lib.php';
  387. }
  388. if (isset($GLOBALS[$relations_key][$table])) {
  389. foreach ($GLOBALS[$relations_key][$table] as $field => $relations) {
  390. if ((! strlen($column) || $column == $field)
  391. && (! isset($foreign[$field]) || ! strlen($foreign[$field]))
  392. ) {
  393. $foreign[$field] = $relations;
  394. }
  395. }
  396. }
  397. }
  398. return $foreign;
  399. } // end of the 'PMA_getForeigners()' function
  400. /**
  401. * Gets the display field of a table
  402. *
  403. * @param string $db the name of the db to check for
  404. * @param string $table the name of the table to check for
  405. *
  406. * @return string field name
  407. *
  408. * @access public
  409. */
  410. function PMA_getDisplayField($db, $table)
  411. {
  412. $cfgRelation = PMA_getRelationsParam();
  413. /**
  414. * Try to fetch the display field from DB.
  415. */
  416. if ($cfgRelation['displaywork']) {
  417. $disp_query = '
  418. SELECT `display_field`
  419. FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['table_info']) . '
  420. WHERE `db_name` = \'' . PMA_sqlAddSlashes($db) . '\'
  421. AND `table_name` = \'' . PMA_sqlAddSlashes($table) . '\'';
  422. $row = PMA_DBI_fetch_single_row($disp_query, 'ASSOC', $GLOBALS['controllink']);
  423. if (isset($row['display_field'])) {
  424. return $row['display_field'];
  425. }
  426. }
  427. /**
  428. * Emulating the display field for some information_schema tables.
  429. */
  430. if ($db == 'information_schema') {
  431. switch ($table) {
  432. case 'CHARACTER_SETS':
  433. return 'DESCRIPTION';
  434. case 'TABLES':
  435. return 'TABLE_COMMENT';
  436. }
  437. }
  438. /**
  439. * No Luck...
  440. */
  441. return false;
  442. } // end of the 'PMA_getDisplayField()' function
  443. /**
  444. * Gets the comments for all rows of a table or the db itself
  445. *
  446. * @param string $db the name of the db to check for
  447. * @param string $table the name of the table to check for
  448. *
  449. * @return array [field_name] = comment
  450. *
  451. * @access public
  452. */
  453. function PMA_getComments($db, $table = '')
  454. {
  455. $comments = array();
  456. if ($table != '') {
  457. // MySQL native column comments
  458. $fields = PMA_DBI_get_columns($db, $table, null, true);
  459. if ($fields) {
  460. foreach ($fields as $field) {
  461. if (! empty($field['Comment'])) {
  462. $comments[$field['Field']] = $field['Comment'];
  463. }
  464. }
  465. }
  466. } else {
  467. $comments[] = PMA_getDbComment($db);
  468. }
  469. return $comments;
  470. } // end of the 'PMA_getComments()' function
  471. /**
  472. * Gets the comment for a db
  473. *
  474. * @param string $db the name of the db to check for
  475. *
  476. * @return string comment
  477. *
  478. * @access public
  479. */
  480. function PMA_getDbComment($db)
  481. {
  482. $cfgRelation = PMA_getRelationsParam();
  483. $comment = '';
  484. if ($cfgRelation['commwork']) {
  485. // pmadb internal db comment
  486. $com_qry = "
  487. SELECT `comment`
  488. FROM " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . "
  489. WHERE db_name = '" . PMA_sqlAddSlashes($db) . "'
  490. AND table_name = ''
  491. AND column_name = '(db_comment)'";
  492. $com_rs = PMA_query_as_controluser($com_qry, true, PMA_DBI_QUERY_STORE);
  493. if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) {
  494. $row = PMA_DBI_fetch_assoc($com_rs);
  495. $comment = $row['comment'];
  496. }
  497. PMA_DBI_free_result($com_rs);
  498. }
  499. return $comment;
  500. } // end of the 'PMA_getDbComment()' function
  501. /**
  502. * Gets the comment for a db
  503. *
  504. * @access public
  505. *
  506. * @return string comment
  507. */
  508. function PMA_getDbComments()
  509. {
  510. $cfgRelation = PMA_getRelationsParam();
  511. $comments = array();
  512. if ($cfgRelation['commwork']) {
  513. // pmadb internal db comment
  514. $com_qry = "
  515. SELECT `db_name`, `comment`
  516. FROM " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . "
  517. WHERE `column_name` = '(db_comment)'";
  518. $com_rs = PMA_query_as_controluser($com_qry, true, PMA_DBI_QUERY_STORE);
  519. if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) {
  520. while ($row = PMA_DBI_fetch_assoc($com_rs)) {
  521. $comments[$row['db_name']] = $row['comment'];
  522. }
  523. }
  524. PMA_DBI_free_result($com_rs);
  525. }
  526. return $comments;
  527. } // end of the 'PMA_getDbComments()' function
  528. /**
  529. * Set a database comment to a certain value.
  530. *
  531. * @param string $db the name of the db
  532. * @param string $comment the value of the column
  533. *
  534. * @return boolean true, if comment-query was made.
  535. *
  536. * @access public
  537. */
  538. function PMA_setDbComment($db, $comment = '')
  539. {
  540. $cfgRelation = PMA_getRelationsParam();
  541. if (! $cfgRelation['commwork']) {
  542. return false;
  543. }
  544. if (strlen($comment)) {
  545. $upd_query = "
  546. INSERT INTO
  547. " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . "
  548. (`db_name`, `table_name`, `column_name`, `comment`)
  549. VALUES (
  550. '" . PMA_sqlAddSlashes($db) . "',
  551. '',
  552. '(db_comment)',
  553. '" . PMA_sqlAddSlashes($comment) . "')
  554. ON DUPLICATE KEY UPDATE
  555. `comment` = '" . PMA_sqlAddSlashes($comment) . "'";
  556. } else {
  557. $upd_query = '
  558. DELETE FROM
  559. ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['column_info']) . '
  560. WHERE `db_name` = \'' . PMA_sqlAddSlashes($db) . '\'
  561. AND `table_name` = \'\'
  562. AND `column_name` = \'(db_comment)\'';
  563. }
  564. if (isset($upd_query)) {
  565. return PMA_query_as_controluser($upd_query);
  566. }
  567. return false;
  568. } // end of 'PMA_setDbComment()' function
  569. /**
  570. * Set a SQL history entry
  571. *
  572. * @param string $db the name of the db
  573. * @param string $table the name of the table
  574. * @param string $username the username
  575. * @param string $sqlquery the sql query
  576. *
  577. * @return nothing
  578. *
  579. * @access public
  580. */
  581. function PMA_setHistory($db, $table, $username, $sqlquery)
  582. {
  583. if (strlen($sqlquery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) {
  584. return;
  585. }
  586. $cfgRelation = PMA_getRelationsParam();
  587. if (! isset($_SESSION['sql_history'])) {
  588. $_SESSION['sql_history'] = array();
  589. }
  590. $key = md5($sqlquery . $db . $table);
  591. if (isset($_SESSION['sql_history'][$key])) {
  592. unset($_SESSION['sql_history'][$key]);
  593. }
  594. $_SESSION['sql_history'][$key] = array(
  595. 'db' => $db,
  596. 'table' => $table,
  597. 'sqlquery' => $sqlquery,
  598. );
  599. if (count($_SESSION['sql_history']) > $GLOBALS['cfg']['QueryHistoryMax']) {
  600. // history should not exceed a maximum count
  601. array_shift($_SESSION['sql_history']);
  602. }
  603. if (! $cfgRelation['historywork'] || ! $GLOBALS['cfg']['QueryHistoryDB']) {
  604. return;
  605. }
  606. PMA_query_as_controluser(
  607. 'INSERT INTO
  608. ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . '
  609. (`username`,
  610. `db`,
  611. `table`,
  612. `timevalue`,
  613. `sqlquery`)
  614. VALUES
  615. (\'' . PMA_sqlAddSlashes($username) . '\',
  616. \'' . PMA_sqlAddSlashes($db) . '\',
  617. \'' . PMA_sqlAddSlashes($table) . '\',
  618. NOW(),
  619. \'' . PMA_sqlAddSlashes($sqlquery) . '\')'
  620. );
  621. } // end of 'PMA_setHistory()' function
  622. /**
  623. * Gets a SQL history entry
  624. *
  625. * @param string $username the username
  626. *
  627. * @return array list of history items
  628. *
  629. * @access public
  630. */
  631. function PMA_getHistory($username)
  632. {
  633. $cfgRelation = PMA_getRelationsParam();
  634. if (! $cfgRelation['historywork']) {
  635. return false;
  636. }
  637. $hist_query = '
  638. SELECT `db`,
  639. `table`,
  640. `sqlquery`
  641. FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . '
  642. WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\'
  643. ORDER BY `id` DESC';
  644. return PMA_DBI_fetch_result($hist_query, null, null, $GLOBALS['controllink']);
  645. } // end of 'PMA_getHistory()' function
  646. /**
  647. * purges SQL history
  648. *
  649. * deletes entries that exceeds $cfg['QueryHistoryMax'], oldest first, for the
  650. * given user
  651. *
  652. * @param string $username the username
  653. *
  654. * @return nothing
  655. *
  656. * @access public
  657. */
  658. function PMA_purgeHistory($username)
  659. {
  660. $cfgRelation = PMA_getRelationsParam();
  661. if (! $GLOBALS['cfg']['QueryHistoryDB'] || ! $cfgRelation['historywork']) {
  662. return;
  663. }
  664. if (! $cfgRelation['historywork']) {
  665. return;
  666. }
  667. $search_query = '
  668. SELECT `timevalue`
  669. FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . '
  670. WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\'
  671. ORDER BY `timevalue` DESC
  672. LIMIT ' . $GLOBALS['cfg']['QueryHistoryMax'] . ', 1';
  673. if ($max_time = PMA_DBI_fetch_value($search_query, 0, 0, $GLOBALS['controllink'])) {
  674. PMA_query_as_controluser(
  675. 'DELETE FROM
  676. ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . '
  677. WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\'
  678. AND `timevalue` <= \'' . $max_time . '\''
  679. );
  680. }
  681. } // end of 'PMA_purgeHistory()' function
  682. /**
  683. * Prepares the dropdown for one mode
  684. *
  685. * @param array $foreign the keys and values for foreigns
  686. * @param string $data the current data of the dropdown
  687. * @param string $mode the needed mode
  688. *
  689. * @return array the <option value=""><option>s
  690. *
  691. * @access protected
  692. */
  693. function PMA__foreignDropdownBuild($foreign, $data, $mode)
  694. {
  695. $reloptions = array();
  696. // id-only is a special mode used when no foreign display column
  697. // is available
  698. if ($mode == 'id-content' || $mode == 'id-only') {
  699. // sort for id-content
  700. if ($GLOBALS['cfg']['NaturalOrder']) {
  701. uksort($foreign, 'strnatcasecmp');
  702. } else {
  703. ksort($foreign);
  704. }
  705. } elseif ($mode == 'content-id') {
  706. // sort for content-id
  707. if ($GLOBALS['cfg']['NaturalOrder']) {
  708. natcasesort($foreign);
  709. } else {
  710. asort($foreign);
  711. }
  712. }
  713. foreach ($foreign as $key => $value) {
  714. if (PMA_strlen($value) <= $GLOBALS['cfg']['LimitChars']) {
  715. $vtitle = '';
  716. $value = htmlspecialchars($value);
  717. } else {
  718. $vtitle = htmlspecialchars($value);
  719. $value = htmlspecialchars(substr($value, 0, $GLOBALS['cfg']['LimitChars']) . '...');
  720. }
  721. $reloption = '<option value="' . htmlspecialchars($key) . '"';
  722. if ($vtitle != '') {
  723. $reloption .= ' title="' . $vtitle . '"';
  724. }
  725. if ((string) $key == (string) $data) {
  726. $reloption .= ' selected="selected"';
  727. }
  728. if ($mode == 'content-id') {
  729. $reloptions[] = $reloption . '>' . $value . '&nbsp;-&nbsp;' . htmlspecialchars($key) . '</option>';
  730. } elseif ($mode == 'id-content') {
  731. $reloptions[] = $reloption . '>' . htmlspecialchars($key) . '&nbsp;-&nbsp;' . $value . '</option>';
  732. } elseif ($mode == 'id-only') {
  733. $reloptions[] = $reloption . '>' . htmlspecialchars($key) . '</option>';
  734. }
  735. } // end foreach
  736. return $reloptions;
  737. } // end of 'PMA__foreignDropdownBuild' function
  738. /**
  739. * Outputs dropdown with values of foreign fields
  740. *
  741. * @param array $disp_row array of the displayed row
  742. * @param string $foreign_field the foreign field
  743. * @param string $foreign_display the foreign field to display
  744. * @param string $data the current data of the dropdown (field in row)
  745. * @param int $max maximum number of items in the dropdown
  746. *
  747. * @return string the <option value=""><option>s
  748. *
  749. * @access public
  750. */
  751. function PMA_foreignDropdown($disp_row, $foreign_field, $foreign_display, $data,
  752. $max = null)
  753. {
  754. if (null === $max) {
  755. $max = $GLOBALS['cfg']['ForeignKeyMaxLimit'];
  756. }
  757. $foreign = array();
  758. // collect the data
  759. foreach ($disp_row as $relrow) {
  760. $key = $relrow[$foreign_field];
  761. // if the display field has been defined for this foreign table
  762. if ($foreign_display) {
  763. $value = $relrow[$foreign_display];
  764. } else {
  765. $value = '';
  766. } // end if ($foreign_display)
  767. $foreign[$key] = $value;
  768. } // end foreach
  769. // put the dropdown sections in correct order
  770. $top = array();
  771. $bottom = array();
  772. if ($foreign_display) {
  773. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'], 'array')) {
  774. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'][0])) {
  775. $top = PMA__foreignDropdownBuild(
  776. $foreign,
  777. $data,
  778. $GLOBALS['cfg']['ForeignKeyDropdownOrder'][0]
  779. );
  780. }
  781. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'][1])) {
  782. $bottom = PMA__foreignDropdownBuild(
  783. $foreign,
  784. $data,
  785. $GLOBALS['cfg']['ForeignKeyDropdownOrder'][1]
  786. );
  787. }
  788. } else {
  789. $top = PMA__foreignDropdownBuild($foreign, $data, 'id-content');
  790. $bottom = PMA__foreignDropdownBuild($foreign, $data, 'content-id');
  791. }
  792. } else {
  793. $top = PMA__foreignDropdownBuild($foreign, $data, 'id-only');
  794. }
  795. // beginning of dropdown
  796. $ret = '<option value="">&nbsp;</option>';
  797. $top_count = count($top);
  798. if ($max == -1 || $top_count < $max) {
  799. $ret .= implode('', $top);
  800. if ($foreign_display && $top_count > 0) {
  801. // this empty option is to visually mark the beginning of the
  802. // second series of values (bottom)
  803. $ret .= '<option value="">&nbsp;</option>';
  804. }
  805. }
  806. if ($foreign_display) {
  807. $ret .= implode('', $bottom);
  808. }
  809. return $ret;
  810. } // end of 'PMA_foreignDropdown()' function
  811. /**
  812. * Gets foreign keys in preparation for a drop-down selector
  813. *
  814. * @param array $foreigners array of the foreign keys
  815. * @param string $field the foreign field name
  816. * @param bool $override_total whether to override the total
  817. * @param string $foreign_filter a possible filter
  818. * @param string $foreign_limit a possible LIMIT clause
  819. *
  820. * @return array data about the foreign keys
  821. *
  822. * @access public
  823. */
  824. function PMA_getForeignData($foreigners, $field, $override_total, $foreign_filter, $foreign_limit)
  825. {
  826. // we always show the foreign field in the drop-down; if a display
  827. // field is defined, we show it besides the foreign field
  828. $foreign_link = false;
  829. if ($foreigners && isset($foreigners[$field])) {
  830. $foreigner = $foreigners[$field];
  831. $foreign_db = $foreigner['foreign_db'];
  832. $foreign_table = $foreigner['foreign_table'];
  833. $foreign_field = $foreigner['foreign_field'];
  834. // Count number of rows in the foreign table. Currently we do
  835. // not use a drop-down if more than 200 rows in the foreign table,
  836. // for speed reasons and because we need a better interface for this.
  837. //
  838. // We could also do the SELECT anyway, with a LIMIT, and ensure that
  839. // the current value of the field is one of the choices.
  840. $the_total = PMA_Table::countRecords($foreign_db, $foreign_table);
  841. if ($override_total == true || $the_total < $GLOBALS['cfg']['ForeignKeyMaxLimit']) {
  842. // foreign_display can be false if no display field defined:
  843. $foreign_display = PMA_getDisplayField($foreign_db, $foreign_table);
  844. $f_query_main = 'SELECT ' . PMA_backquote($foreign_field)
  845. . (($foreign_display == false) ? '' : ', ' . PMA_backquote($foreign_display));
  846. $f_query_from = ' FROM ' . PMA_backquote($foreign_db) . '.' . PMA_backquote($foreign_table);
  847. $f_query_filter = empty($foreign_filter) ? '' : ' WHERE ' . PMA_backquote($foreign_field)
  848. . ' LIKE "%' . PMA_sqlAddSlashes($foreign_filter, true) . '%"'
  849. . (($foreign_display == false) ? '' : ' OR ' . PMA_backquote($foreign_display)
  850. . ' LIKE "%' . PMA_sqlAddSlashes($foreign_filter, true) . '%"'
  851. );
  852. $f_query_order = ($foreign_display == false) ? '' :' ORDER BY ' . PMA_backquote($foreign_table) . '.' . PMA_backquote($foreign_display);
  853. $f_query_limit = isset($foreign_limit) ? $foreign_limit : '';
  854. if (!empty($foreign_filter)) {
  855. $res = PMA_DBI_query('SELECT COUNT(*)' . $f_query_from . $f_query_filter);
  856. if ($res) {
  857. $the_total = PMA_DBI_fetch_value($res);
  858. @PMA_DBI_free_result($res);
  859. } else {
  860. $the_total = 0;
  861. }
  862. }
  863. $disp = PMA_DBI_query($f_query_main . $f_query_from . $f_query_filter . $f_query_order . $f_query_limit);
  864. if ($disp && PMA_DBI_num_rows($disp) > 0) {
  865. // If a resultset has been created, pre-cache it in the $disp_row array
  866. // This helps us from not needing to use mysql_data_seek by accessing a pre-cached
  867. // PHP array. Usually those resultsets are not that big, so a performance hit should
  868. // not be expected.
  869. $disp_row = array();
  870. while ($single_disp_row = @PMA_DBI_fetch_assoc($disp)) {
  871. $disp_row[] = $single_disp_row;
  872. }
  873. @PMA_DBI_free_result($disp);
  874. }
  875. } else {
  876. $disp_row = null;
  877. $foreign_link = true;
  878. }
  879. } // end if $foreigners
  880. $foreignData['foreign_link'] = $foreign_link;
  881. $foreignData['the_total'] = isset($the_total) ? $the_total : null;
  882. $foreignData['foreign_display'] = isset($foreign_display) ? $foreign_display : null;
  883. $foreignData['disp_row'] = isset($disp_row) ? $disp_row : null;
  884. $foreignData['foreign_field'] = isset($foreign_field) ? $foreign_field : null;
  885. return $foreignData;
  886. } // end of 'PMA_getForeignData()' function
  887. /**
  888. * Finds all related tables
  889. *
  890. * @param string $from whether to go from master to foreign or vice versa
  891. *
  892. * @return boolean always true
  893. *
  894. * @global array $tab_left the list of tables that we still couldn't connect
  895. * @global array $tab_know the list of allready connected tables
  896. * @global string $fromclause
  897. *
  898. * @access private
  899. */
  900. function PMA_getRelatives($from)
  901. {
  902. global $tab_left, $tab_know, $fromclause;
  903. if ($from == 'master') {
  904. $to = 'foreign';
  905. } else {
  906. $to = 'master';
  907. }
  908. $in_know = '(\'' . implode('\', \'', $tab_know) . '\')';
  909. $in_left = '(\'' . implode('\', \'', $tab_left) . '\')';
  910. $rel_query = 'SELECT *'
  911. . ' FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db'])
  912. . '.' . PMA_backquote($GLOBALS['cfgRelation']['relation'])
  913. . ' WHERE ' . $from . '_db = \'' . PMA_sqlAddSlashes($GLOBALS['db']) . '\''
  914. . ' AND ' . $to . '_db = \'' . PMA_sqlAddSlashes($GLOBALS['db']) . '\''
  915. . ' AND ' . $from . '_table IN ' . $in_know
  916. . ' AND ' . $to . '_table IN ' . $in_left;
  917. $relations = @PMA_DBI_query($rel_query, $GLOBALS['controllink']);
  918. while ($row = PMA_DBI_fetch_assoc($relations)) {
  919. $found_table = $row[$to . '_table'];
  920. if (isset($tab_left[$found_table])) {
  921. $fromclause
  922. .= "\n" . ' LEFT JOIN '
  923. . PMA_backquote($GLOBALS['db']) . '.' . PMA_backquote($row[$to . '_table']) . ' ON '
  924. . PMA_backquote($row[$from . '_table']) . '.'
  925. . PMA_backquote($row[$from . '_field']) . ' = '
  926. . PMA_backquote($row[$to . '_table']) . '.'
  927. . PMA_backquote($row[$to . '_field']) . ' ';
  928. $tab_know[$found_table] = $found_table;
  929. unset($tab_left[$found_table]);
  930. }
  931. } // end while
  932. return true;
  933. } // end of the "PMA_getRelatives()" function
  934. /**
  935. * Rename a field in relation tables
  936. *
  937. * usually called after a field in a table was renamed in tbl_alter.php
  938. *
  939. * @param string $db databse name
  940. * @param string $table table name
  941. * @param string $field old field name
  942. * @param string $new_name new field name
  943. *
  944. * @return nothing
  945. */
  946. function PMA_REL_renameField($db, $table, $field, $new_name)
  947. {
  948. $cfgRelation = PMA_getRelationsParam();
  949. if ($cfgRelation['displaywork']) {
  950. $table_query = 'UPDATE ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['table_info'])
  951. . ' SET display_field = \'' . PMA_sqlAddSlashes($new_name) . '\''
  952. . ' WHERE db_name = \'' . PMA_sqlAddSlashes($db) . '\''
  953. . ' AND table_name = \'' . PMA_sqlAddSlashes($table) . '\''
  954. . ' AND display_field = \'' . PMA_sqlAddSlashes($field) . '\'';
  955. PMA_query_as_controluser($table_query);
  956. }
  957. if ($cfgRelation['relwork']) {
  958. $table_query = 'UPDATE ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['relation'])
  959. . ' SET master_field = \'' . PMA_sqlAddSlashes($new_name) . '\''
  960. . ' WHERE master_db = \'' . PMA_sqlAddSlashes($db) . '\''
  961. . ' AND master_table = \'' . PMA_sqlAddSlashes($table) . '\''
  962. . ' AND master_field = \'' . PMA_sqlAddSlashes($field) . '\'';
  963. PMA_query_as_controluser($table_query);
  964. $table_query = 'UPDATE ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['relation'])
  965. . ' SET foreign_field = \'' . PMA_sqlAddSlashes($new_name) . '\''
  966. . ' WHERE foreign_db = \'' . PMA_sqlAddSlashes($db) . '\''
  967. . ' AND foreign_table = \'' . PMA_sqlAddSlashes($table) . '\''
  968. . ' AND foreign_field = \'' . PMA_sqlAddSlashes($field) . '\'';
  969. PMA_query_as_controluser($table_query);
  970. } // end if relwork
  971. }
  972. /**
  973. * Create a PDF page
  974. *
  975. * @param string $newpage name of the new PDF page
  976. * @param array $cfgRelation
  977. * @param string $db database name
  978. *
  979. * @return string $pdf_page_number
  980. */
  981. function PMA_REL_create_page($newpage, $cfgRelation, $db)
  982. {
  983. if (! isset($newpage) || $newpage == '') {
  984. $newpage = __('no description');
  985. }
  986. $ins_query = 'INSERT INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['pdf_pages'])
  987. . ' (db_name, page_descr)'
  988. . ' VALUES (\'' . PMA_sqlAddSlashes($db) . '\', \'' . PMA_sqlAddSlashes($newpage) . '\')';
  989. PMA_query_as_controluser($ins_query, false);
  990. return PMA_DBI_insert_id(isset($GLOBALS['controllink']) ? $GLOBALS['controllink'] : '');
  991. }
  992. ?>