Translated using Weblate (Czech)
[phpmyadmin.git] / libraries / classes / CentralColumns.php
blob7379cee48496163f7c5ba3ccff57d8e1d9cda205
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Functions for displaying user preferences pages
6 * @package PhpMyAdmin
7 */
8 namespace PhpMyAdmin;
10 use PhpMyAdmin\Charsets;
11 use PhpMyAdmin\DatabaseInterface;
12 use PhpMyAdmin\Message;
13 use PhpMyAdmin\Relation;
14 use PhpMyAdmin\Template;
15 use PhpMyAdmin\Url;
16 use PhpMyAdmin\Util;
18 /**
19 * PhpMyAdmin\CentralColumns class
21 * @package PhpMyAdmin
23 class CentralColumns
25 /**
26 * DatabaseInterface instance
28 * @var DatabaseInterface
30 private $dbi;
32 /**
33 * Current user
35 * @var string
37 private $user;
39 /**
40 * Number of rows displayed when browsing a result set
42 * @var int
44 private $maxRows;
46 /**
47 * Which editor should be used for CHAR/VARCHAR fields
49 * @var string
51 private $charEditing;
53 /**
54 * Disable use of INFORMATION_SCHEMA
56 * @var boolean
58 private $disableIs;
60 /**
61 * @var Relation
63 private $relation;
65 /**
66 * Constructor
68 * @param DatabaseInterface $dbi DatabaseInterface instance
70 public function __construct(DatabaseInterface $dbi)
72 $this->dbi = $dbi;
74 $this->user = $GLOBALS['cfg']['Server']['user'];
75 $this->maxRows = (int) $GLOBALS['cfg']['MaxRows'];
76 $this->charEditing = $GLOBALS['cfg']['CharEditing'];
77 $this->disableIs = (bool) $GLOBALS['cfg']['Server']['DisableIS'];
79 $this->relation = new Relation();
82 /**
83 * Defines the central_columns parameters for the current user
85 * @return array the central_columns parameters for the current user
86 * @access public
88 public function getParams()
90 static $cfgCentralColumns = null;
92 if (null !== $cfgCentralColumns) {
93 return $cfgCentralColumns;
96 $cfgRelation = $this->relation->getRelationsParam();
98 if ($cfgRelation['centralcolumnswork']) {
99 $cfgCentralColumns = array(
100 'user' => $this->user,
101 'db' => $cfgRelation['db'],
102 'table' => $cfgRelation['central_columns'],
104 } else {
105 $cfgCentralColumns = false;
108 return $cfgCentralColumns;
112 * get $num columns of given database from central columns list
113 * starting at offset $from
115 * @param string $db selected database
116 * @param int $from starting offset of first result
117 * @param int $num maximum number of results to return
119 * @return array list of $num columns present in central columns list
120 * starting at offset $from for the given database
122 public function getColumnsList($db, $from = 0, $num = 25)
124 $cfgCentralColumns = $this->getParams();
125 if (empty($cfgCentralColumns)) {
126 return array();
128 $pmadb = $cfgCentralColumns['db'];
129 $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL);
130 $central_list_table = $cfgCentralColumns['table'];
131 //get current values of $db from central column list
132 if ($num == 0) {
133 $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' '
134 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';';
135 } else {
136 $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' '
137 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' '
138 . 'LIMIT ' . $from . ', ' . $num . ';';
140 $has_list = (array) $this->dbi->fetchResult(
141 $query, null, null, DatabaseInterface::CONNECT_CONTROL
143 $this->handleColumnExtra($has_list);
144 return $has_list;
148 * Get the number of columns present in central list for given db
150 * @param string $db current database
152 * @return int number of columns in central list of columns for $db
154 public function getCount($db)
156 $cfgCentralColumns = $this->getParams();
157 if (empty($cfgCentralColumns)) {
158 return 0;
160 $pmadb = $cfgCentralColumns['db'];
161 $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL);
162 $central_list_table = $cfgCentralColumns['table'];
163 $query = 'SELECT count(db_name) FROM ' .
164 Util::backquote($central_list_table) . ' '
165 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';';
166 $res = $this->dbi->fetchResult(
167 $query, null, null, DatabaseInterface::CONNECT_CONTROL
169 if (isset($res[0])) {
170 return $res[0];
173 return 0;
177 * return the existing columns in central list among the given list of columns
179 * @param string $db the selected database
180 * @param string $cols comma separated list of given columns
181 * @param boolean $allFields set if need all the fields of existing columns,
182 * otherwise only column_name is returned
184 * @return array list of columns in central columns among given set of columns
186 private function findExistingColNames(
187 $db,
188 $cols,
189 $allFields = false
191 $cfgCentralColumns = $this->getParams();
192 if (empty($cfgCentralColumns)) {
193 return array();
195 $pmadb = $cfgCentralColumns['db'];
196 $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL);
197 $central_list_table = $cfgCentralColumns['table'];
198 if ($allFields) {
199 $query = 'SELECT * FROM ' . Util::backquote($central_list_table) . ' '
200 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' AND col_name IN (' . $cols . ');';
201 $has_list = (array) $this->dbi->fetchResult(
202 $query, null, null, DatabaseInterface::CONNECT_CONTROL
204 $this->handleColumnExtra($has_list);
205 } else {
206 $query = 'SELECT col_name FROM '
207 . Util::backquote($central_list_table) . ' '
208 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' AND col_name IN (' . $cols . ');';
209 $has_list = (array) $this->dbi->fetchResult(
210 $query, null, null, DatabaseInterface::CONNECT_CONTROL
214 return $has_list;
218 * return error message to be displayed if central columns
219 * configuration storage is not completely configured
221 * @return Message
223 private function configErrorMessage()
225 return Message::error(
227 'The configuration storage is not ready for the central list'
228 . ' of columns feature.'
234 * build the insert query for central columns list given PMA storage
235 * db, central_columns table, column name and corresponding definition to be added
237 * @param string $column column to add into central list
238 * @param array $def list of attributes of the column being added
239 * @param string $db PMA configuration storage database name
240 * @param string $central_list_table central columns configuration storage table name
242 * @return string query string to insert the given column
243 * with definition into central list
245 private function getInsertQuery(
246 $column,
247 array $def,
248 $db,
249 $central_list_table
251 $type = "";
252 $length = 0;
253 $attribute = "";
254 if (isset($def['Type'])) {
255 $extracted_columnspec = Util::extractColumnSpec($def['Type']);
256 $attribute = trim($extracted_columnspec[ 'attribute']);
257 $type = $extracted_columnspec['type'];
258 $length = $extracted_columnspec['spec_in_brackets'];
260 if (isset($def['Attribute'])) {
261 $attribute = $def['Attribute'];
263 $collation = isset($def['Collation'])?$def['Collation']:"";
264 $isNull = ($def['Null'] == "NO")?0:1;
265 $extra = isset($def['Extra'])?$def['Extra']:"";
266 $default = isset($def['Default'])?$def['Default']:"";
267 $insQuery = 'INSERT INTO '
268 . Util::backquote($central_list_table) . ' '
269 . 'VALUES ( \'' . $this->dbi->escapeString($db) . '\' ,'
270 . '\'' . $this->dbi->escapeString($column) . '\',\''
271 . $this->dbi->escapeString($type) . '\','
272 . '\'' . $this->dbi->escapeString($length) . '\',\''
273 . $this->dbi->escapeString($collation) . '\','
274 . '\'' . $this->dbi->escapeString($isNull) . '\','
275 . '\'' . implode(',', array($extra, $attribute))
276 . '\',\'' . $this->dbi->escapeString($default) . '\');';
277 return $insQuery;
281 * If $isTable is true then unique columns from given tables as $field_select
282 * are added to central list otherwise the $field_select is considered as
283 * list of columns and these columns are added to central list if not already added
285 * @param array $field_select if $isTable is true selected tables list
286 * otherwise selected columns list
287 * @param bool $isTable if passed array is of tables or columns
288 * @param string $table if $isTable is false, then table name to
289 * which columns belong
291 * @return true|PhpMyAdmin\Message
293 public function syncUniqueColumns(
294 array $field_select,
295 $isTable = true,
296 $table = null
298 $cfgCentralColumns = $this->getParams();
299 if (empty($cfgCentralColumns)) {
300 return $this->configErrorMessage();
302 $db = $_POST['db'];
303 $pmadb = $cfgCentralColumns['db'];
304 $central_list_table = $cfgCentralColumns['table'];
305 $this->dbi->selectDb($db);
306 $existingCols = array();
307 $cols = "";
308 $insQuery = array();
309 $fields = array();
310 $message = true;
311 if ($isTable) {
312 foreach ($field_select as $table) {
313 $fields[$table] = (array) $this->dbi->getColumns(
314 $db, $table, null, true
316 foreach ($fields[$table] as $field => $def) {
317 $cols .= "'" . $this->dbi->escapeString($field) . "',";
321 $has_list = $this->findExistingColNames($db, trim($cols, ','));
322 foreach ($field_select as $table) {
323 foreach ($fields[$table] as $field => $def) {
324 if (!in_array($field, $has_list)) {
325 $has_list[] = $field;
326 $insQuery[] = $this->getInsertQuery(
327 $field, $def, $db, $central_list_table
329 } else {
330 $existingCols[] = "'" . $field . "'";
334 } else {
335 if ($table === null) {
336 $table = $_POST['table'];
338 foreach ($field_select as $column) {
339 $cols .= "'" . $this->dbi->escapeString($column) . "',";
341 $has_list = $this->findExistingColNames($db, trim($cols, ','));
342 foreach ($field_select as $column) {
343 if (!in_array($column, $has_list)) {
344 $has_list[] = $column;
345 $field = (array) $this->dbi->getColumns(
346 $db, $table, $column,
347 true
349 $insQuery[] = $this->getInsertQuery(
350 $column, $field, $db, $central_list_table
352 } else {
353 $existingCols[] = "'" . $column . "'";
357 if (! empty($existingCols)) {
358 $existingCols = implode(",", array_unique($existingCols));
359 $message = Message::notice(
360 sprintf(
362 'Could not add %1$s as they already exist in central list!'
363 ), htmlspecialchars($existingCols)
366 $message->addMessage(
367 Message::notice(
368 "Please remove them first "
369 . "from central list if you want to update above columns"
373 $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL);
374 if (! empty($insQuery)) {
375 foreach ($insQuery as $query) {
376 if (!$this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) {
377 $message = Message::error(__('Could not add columns!'));
378 $message->addMessage(
379 Message::rawError(
380 $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL)
383 break;
387 return $message;
391 * if $isTable is true it removes all columns of given tables as $field_select from
392 * central columns list otherwise $field_select is columns list and it removes
393 * given columns if present in central list
395 * @param array $field_select if $isTable selected list of tables otherwise
396 * selected list of columns to remove from central list
397 * @param bool $isTable if passed array is of tables or columns
399 * @return true|PhpMyAdmin\Message
401 public function deleteColumnsFromList(
402 array $field_select,
403 $isTable = true
405 $cfgCentralColumns = $this->getParams();
406 if (empty($cfgCentralColumns)) {
407 return $this->configErrorMessage();
409 $db = $_POST['db'];
410 $pmadb = $cfgCentralColumns['db'];
411 $central_list_table = $cfgCentralColumns['table'];
412 $this->dbi->selectDb($db);
413 $message = true;
414 $colNotExist = array();
415 $fields = array();
416 if ($isTable) {
417 $cols = '';
418 foreach ($field_select as $table) {
419 $fields[$table] = (array) $this->dbi->getColumnNames(
420 $db, $table
422 foreach ($fields[$table] as $col_select) {
423 $cols .= '\'' . $this->dbi->escapeString($col_select) . '\',';
426 $cols = trim($cols, ',');
427 $has_list = $this->findExistingColNames($db, $cols);
428 foreach ($field_select as $table) {
429 foreach ($fields[$table] as $column) {
430 if (!in_array($column, $has_list)) {
431 $colNotExist[] = "'" . $column . "'";
436 } else {
437 $cols = '';
438 foreach ($field_select as $col_select) {
439 $cols .= '\'' . $this->dbi->escapeString($col_select) . '\',';
441 $cols = trim($cols, ',');
442 $has_list = $this->findExistingColNames($db, $cols);
443 foreach ($field_select as $column) {
444 if (!in_array($column, $has_list)) {
445 $colNotExist[] = "'" . $column . "'";
449 if (!empty($colNotExist)) {
450 $colNotExist = implode(",", array_unique($colNotExist));
451 $message = Message::notice(
452 sprintf(
454 'Couldn\'t remove Column(s) %1$s '
455 . 'as they don\'t exist in central columns list!'
456 ), htmlspecialchars($colNotExist)
460 $this->dbi->selectDb($pmadb, DatabaseInterface::CONNECT_CONTROL);
462 $query = 'DELETE FROM ' . Util::backquote($central_list_table) . ' '
463 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' AND col_name IN (' . $cols . ');';
465 if (!$this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) {
466 $message = Message::error(__('Could not remove columns!'));
467 $message->addHtml('<br />' . htmlspecialchars($cols) . '<br />');
468 $message->addMessage(
469 Message::rawError(
470 $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL)
474 return $message;
478 * Make the columns of given tables consistent with central list of columns.
479 * Updates only those columns which are not being referenced.
481 * @param string $db current database
482 * @param array $selected_tables list of selected tables.
484 * @return true|PhpMyAdmin\Message
486 public function makeConsistentWithList(
487 $db,
488 array $selected_tables
490 $message = true;
491 foreach ($selected_tables as $table) {
492 $query = 'ALTER TABLE ' . Util::backquote($table);
493 $has_list = $this->getFromTable($db, $table, true);
494 $this->dbi->selectDb($db);
495 foreach ($has_list as $column) {
496 $column_status = $this->relation->checkChildForeignReferences(
497 $db, $table, $column['col_name']
499 //column definition can only be changed if
500 //it is not referenced by another column
501 if ($column_status['isEditable']) {
502 $query .= ' MODIFY ' . Util::backquote($column['col_name']) . ' '
503 . $this->dbi->escapeString($column['col_type']);
504 if ($column['col_length']) {
505 $query .= '(' . $column['col_length'] . ')';
508 $query .= ' ' . $column['col_attribute'];
509 if ($column['col_isNull']) {
510 $query .= ' NULL';
511 } else {
512 $query .= ' NOT NULL';
515 $query .= ' ' . $column['col_extra'];
516 if ($column['col_default']) {
517 if ($column['col_default'] != 'CURRENT_TIMESTAMP'
518 || $column['col_default'] != 'current_timestamp()') {
519 $query .= ' DEFAULT \'' . $this->dbi->escapeString(
520 $column['col_default']
521 ) . '\'';
522 } else {
523 $query .= ' DEFAULT ' . $this->dbi->escapeString(
524 $column['col_default']
528 $query .= ',';
531 $query = trim($query, " ,") . ";";
532 if (!$this->dbi->tryQuery($query)) {
533 if ($message === true) {
534 $message = Message::error(
535 $this->dbi->getError()
537 } else {
538 $message->addText(
539 $this->dbi->getError(),
540 '<br />'
545 return $message;
549 * return the columns present in central list of columns for a given
550 * table of a given database
552 * @param string $db given database
553 * @param string $table given table
554 * @param boolean $allFields set if need all the fields of existing columns,
555 * otherwise only column_name is returned
557 * @return array columns present in central list from given table of given db.
559 public function getFromTable(
560 $db,
561 $table,
562 $allFields = false
564 $cfgCentralColumns = $this->getParams();
565 if (empty($cfgCentralColumns)) {
566 return array();
568 $this->dbi->selectDb($db);
569 $fields = (array) $this->dbi->getColumnNames(
570 $db, $table
572 $cols = '';
573 foreach ($fields as $col_select) {
574 $cols .= '\'' . $this->dbi->escapeString($col_select) . '\',';
576 $cols = trim($cols, ',');
577 $has_list = $this->findExistingColNames($db, $cols, $allFields);
578 if (! empty($has_list)) {
579 return (array)$has_list;
582 return array();
586 * update a column in central columns list if a edit is requested
588 * @param string $db current database
589 * @param string $orig_col_name original column name before edit
590 * @param string $col_name new column name
591 * @param string $col_type new column type
592 * @param string $col_attribute new column attribute
593 * @param string $col_length new column length
594 * @param int $col_isNull value 1 if new column isNull is true, 0 otherwise
595 * @param string $collation new column collation
596 * @param string $col_extra new column extra property
597 * @param string $col_default new column default value
599 * @return true|PhpMyAdmin\Message
601 public function updateOneColumn(
602 $db,
603 $orig_col_name,
604 $col_name,
605 $col_type,
606 $col_attribute,
607 $col_length,
608 $col_isNull,
609 $collation,
610 $col_extra,
611 $col_default
613 $cfgCentralColumns = $this->getParams();
614 if (empty($cfgCentralColumns)) {
615 return $this->configErrorMessage();
617 $centralTable = $cfgCentralColumns['table'];
618 $this->dbi->selectDb($cfgCentralColumns['db'], DatabaseInterface::CONNECT_CONTROL);
619 if ($orig_col_name == "") {
620 $def = array();
621 $def['Type'] = $col_type;
622 if ($col_length) {
623 $def['Type'] .= '(' . $col_length . ')';
625 $def['Collation'] = $collation;
626 $def['Null'] = $col_isNull?__('YES'):__('NO');
627 $def['Extra'] = $col_extra;
628 $def['Attribute'] = $col_attribute;
629 $def['Default'] = $col_default;
630 $query = $this->getInsertQuery($col_name, $def, $db, $centralTable);
631 } else {
632 $query = 'UPDATE ' . Util::backquote($centralTable)
633 . ' SET col_type = \'' . $this->dbi->escapeString($col_type) . '\''
634 . ', col_name = \'' . $this->dbi->escapeString($col_name) . '\''
635 . ', col_length = \'' . $this->dbi->escapeString($col_length) . '\''
636 . ', col_isNull = ' . $col_isNull
637 . ', col_collation = \'' . $this->dbi->escapeString($collation) . '\''
638 . ', col_extra = \''
639 . implode(',', array($col_extra, $col_attribute)) . '\''
640 . ', col_default = \'' . $this->dbi->escapeString($col_default) . '\''
641 . ' WHERE db_name = \'' . $this->dbi->escapeString($db) . '\' '
642 . 'AND col_name = \'' . $this->dbi->escapeString($orig_col_name)
643 . '\'';
645 if (!$this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL)) {
646 return Message::error(
647 $this->dbi->getError(DatabaseInterface::CONNECT_CONTROL)
650 return true;
654 * Update Multiple column in central columns list if a chnage is requested
656 * @return true|PhpMyAdmin\Message
658 public function updateMultipleColumn()
660 $db = $_POST['db'];
661 $col_name = $_POST['field_name'];
662 $orig_col_name = $_POST['orig_col_name'];
663 $col_default = $_POST['field_default_type'];
664 $col_length = $_POST['field_length'];
665 $col_attribute = $_POST['field_attribute'];
666 $col_type = $_POST['field_type'];
667 $collation = $_POST['field_collation'];
668 $col_isNull = array();
669 $col_extra = array();
670 $num_central_fields = count($orig_col_name);
671 for ($i = 0; $i < $num_central_fields ; $i++) {
672 $col_isNull[$i] = isset($_POST['field_null'][$i]) ? 1 : 0;
673 $col_extra[$i] = isset($_POST['col_extra'][$i])
674 ? $_POST['col_extra'][$i] : '';
676 if ($col_default[$i] == 'NONE') {
677 $col_default[$i] = "";
678 } elseif ($col_default[$i] == 'USER_DEFINED') {
679 $col_default[$i] = $_POST['field_default_value'][$i];
682 $message = $this->updateOneColumn(
683 $db, $orig_col_name[$i], $col_name[$i], $col_type[$i],
684 $col_attribute[$i], $col_length[$i], $col_isNull[$i], $collation[$i],
685 $col_extra[$i], $col_default[$i]
687 if (!is_bool($message)) {
688 return $message;
691 return true;
695 * get the html for table navigation in Central columns page
697 * @param int $total_rows total number of rows in complete result set
698 * @param int $pos offset of first result with complete result set
699 * @param string $db current database
701 * @return string html for table navigation in Central columns page
703 public function getHtmlForTableNavigation($total_rows, $pos, $db)
705 $pageNow = ($pos / $this->maxRows) + 1;
706 $nbTotalPage = ceil($total_rows / $this->maxRows);
707 $page_selector = ($nbTotalPage > 1)?(Util::pageselector(
708 'pos', $this->maxRows, $pageNow, $nbTotalPage
709 )):'';
710 return Template::get('database/central_columns/table_navigation')->render(array(
711 "pos" => $pos,
712 "max_rows" => $this->maxRows,
713 "db" => $db,
714 "total_rows" => $total_rows,
715 "nb_total_page" => $nbTotalPage,
716 "page_selector" => $page_selector,
721 * function generate and return the table header for central columns page
723 * @param string $class styling class of 'th' elements
724 * @param string $title title of the 'th' elements
725 * @param integer $actionCount number of actions
727 * @return string html for table header in central columns view/edit page
729 public function getTableHeader($class = '', $title = '', $actionCount = 0)
731 $action = '';
732 if ($actionCount > 0) {
733 $action .= '<th class="column_action" colspan="' . $actionCount . '">'
734 . __('Action') . '</th>';
736 $tableheader = '<thead>';
737 $tableheader .= '<tr>'
738 . '<th class="' . $class . '"></th>'
739 . '<th class="hide"></th>'
740 . $action
741 . '<th class="' . $class . '" title="' . $title . '" data-column="name">'
742 . __('Name') . '<div class="sorticon"></div></th>'
743 . '<th class="' . $class . '" title="' . $title . '" data-column="type">'
744 . __('Type') . '<div class="sorticon"></div></th>'
745 . '<th class="' . $class . '" title="' . $title . '" data-column="length">'
746 . __('Length/Values') . '<div class="sorticon"></div></th>'
747 . '<th class="' . $class . '" title="' . $title . '" data-column="default">'
748 . __('Default') . '<div class="sorticon"></div></th>'
749 . '<th class="' . $class . '" title="' . $title . '" data-column="collation"'
750 . '>' . __('Collation') . '<div class="sorticon"></div></th>'
751 . '<th class="' . $class . '" title="' . $title
752 . '" data-column="attribute">'
753 . __('Attribute') . '<div class="sorticon"></div></th>'
754 . '<th class="' . $class . '" title="' . $title . '" data-column="isnull">'
755 . __('Null') . '<div class="sorticon"></div></th>'
756 . '<th class="' . $class . '" title="' . $title . '" data-column="extra">'
757 . __('A_I') . '<div class="sorticon"></div></th>'
758 . '</tr>';
759 $tableheader .= '</thead>';
760 return $tableheader;
764 * Function generate and return the table header for
765 * multiple edit central columns page
767 * @param array $headers headers list
769 * @return string html for table header in central columns multi edit page
771 private function getEditTableHeader(array $headers)
773 return Template::get(
774 'database/central_columns/edit_table_header'
775 )->render([
776 'headers' => $headers,
781 * build the dropdown select html for tables of given database
783 * @param string $db current database
785 * @return string html dropdown for selecting table
787 private function getHtmlForTableDropdown($db)
789 $this->dbi->selectDb($db);
790 $tables = $this->dbi->getTables($db);
791 $selectHtml = '<select name="table-select" id="table-select">'
792 . '<option value="" disabled="disabled" selected="selected">'
793 . __('Select a table') . '</option>';
794 foreach ($tables as $table) {
795 $selectHtml .= '<option value="' . htmlspecialchars($table) . '">'
796 . htmlspecialchars($table) . '</option>';
798 $selectHtml .= '</select>';
799 return $selectHtml;
803 * build dropdown select html to select column in selected table,
804 * include only columns which are not already in central list
806 * @param string $db current database to which selected table belongs
807 * @param string $selected_tbl selected table
809 * @return string html to select column
811 public function getHtmlForColumnDropdown($db, $selected_tbl)
813 $existing_cols = $this->getFromTable($db, $selected_tbl);
814 $this->dbi->selectDb($db);
815 $columns = (array) $this->dbi->getColumnNames(
816 $db, $selected_tbl
818 $selectColHtml = "";
819 foreach ($columns as $column) {
820 if (!in_array($column, $existing_cols)) {
821 $selectColHtml .= '<option value="' . htmlspecialchars($column) . '">'
822 . htmlspecialchars($column)
823 . '</option>';
826 return $selectColHtml;
830 * HTML to display the form that let user to add a column on Central columns page
832 * @param int $total_rows total number of rows in complete result set
833 * @param int $pos offset of first result with complete result set
834 * @param string $db current database
836 * @return string html to add a column in the central list
838 public function getHtmlForAddColumn(
839 $total_rows,
840 $pos,
843 $icon = Util::getIcon(
844 'centralColumns_add',
845 __('Add column')
847 $table_drop_down = $this->getHtmlForTableDropdown($db);
848 return Template::get('database/central_columns/add_column')->render(array(
849 'icon' => $icon,
850 'pos' => $pos,
851 'db' => $db,
852 'total_rows' => $total_rows,
853 'table_drop_down' => $table_drop_down,
858 * build html for a row in central columns table
860 * @param array $row array contains complete information of a particular row of central list table
861 * @param int $row_num position the row in the table
862 * @param string $db current database
864 * @return string html of a particular row in the central columns table.
866 public function getHtmlForTableRow(array $row, $row_num, $db)
868 $tableHtml = '<tr data-rownum="' . $row_num . '" id="f_' . $row_num . '">'
869 . Url::getHiddenInputs(
872 . '<input type="hidden" name="edit_save" value="save">'
873 . '<td class="nowrap">'
874 . '<input type="checkbox" class="checkall" name="selected_fld[]" '
875 . 'value="' . htmlspecialchars($row['col_name']) . '" '
876 . 'id="checkbox_row_' . $row_num . '"/>'
877 . '</td>'
878 . '<td id="edit_' . $row_num . '" class="edit center">'
879 . '<a href="#">' . Util::getIcon('b_edit', __('Edit')) . '</a></td>'
880 . '<td class="del_row" data-rownum = "' . $row_num . '">'
881 . '<a hrf="#">' . Util::getIcon('b_drop', __('Delete')) . '</a>'
882 . '<input type="submit" data-rownum = "' . $row_num . '"'
883 . ' class="edit_cancel_form" value="Cancel"></td>'
884 . '<td id="save_' . $row_num . '" class="hide">'
885 . '<input type="submit" data-rownum = "' . $row_num . '"'
886 . ' class="edit_save_form" value="Save"></td>';
888 $tableHtml .=
889 '<td name="col_name" class="nowrap">'
890 . '<span>' . htmlspecialchars($row['col_name']) . '</span>'
891 . '<input name="orig_col_name" type="hidden" '
892 . 'value="' . htmlspecialchars($row['col_name']) . '">'
893 . Template::get('columns_definitions/column_name')->render(array(
894 'column_number' => $row_num,
895 'ci' => 0,
896 'ci_offset' => 0,
897 'column_meta' => array(
898 'Field'=>$row['col_name']
900 'cfg_relation' => array(
901 'centralcolumnswork' => false
903 'max_rows' => $this->maxRows,
905 . '</td>';
906 $tableHtml .=
907 '<td name = "col_type" class="nowrap"><span>'
908 . htmlspecialchars($row['col_type']) . '</span>'
909 . Template::get('columns_definitions/column_type')
910 ->render(
911 array(
912 'column_number' => $row_num,
913 'ci' => 1,
914 'ci_offset' => 0,
915 'type_upper' => mb_strtoupper($row['col_type']),
916 'column_meta' => array()
919 . '</td>';
920 $tableHtml .=
921 '<td class="nowrap" name="col_length">'
922 . '<span>' . ($row['col_length']?htmlspecialchars($row['col_length']):"")
923 . '</span>'
924 . Template::get('columns_definitions/column_length')->render(
925 array(
926 'column_number' => $row_num,
927 'ci' => 2,
928 'ci_offset' => 0,
929 'length_values_input_size' => 8,
930 'length_to_display' => $row['col_length']
933 . '</td>';
935 $meta = array();
936 if (!isset($row['col_default']) || $row['col_default'] == '') {
937 $meta['DefaultType'] = 'NONE';
938 } else {
939 if ($row['col_default'] == 'CURRENT_TIMESTAMP'
940 || $row['col_default'] == 'current_timestamp()'
942 $meta['DefaultType'] = 'CURRENT_TIMESTAMP';
943 } elseif ($row['col_default'] == 'NULL') {
944 $meta['DefaultType'] = $row['col_default'];
945 } else {
946 $meta['DefaultType'] = 'USER_DEFINED';
947 $meta['DefaultValue'] = $row['col_default'];
950 $tableHtml .=
951 '<td class="nowrap" name="col_default"><span>' . (isset($row['col_default'])
952 ? htmlspecialchars($row['col_default']) : 'None')
953 . '</span>'
954 . Template::get('columns_definitions/column_default')
955 ->render(
956 array(
957 'column_number' => $row_num,
958 'ci' => 3,
959 'ci_offset' => 0,
960 'type_upper' => mb_strtoupper($row['col_type']),
961 'column_meta' => $meta,
962 'char_editing' => $this->charEditing,
965 . '</td>';
967 $tableHtml .=
968 '<td name="collation" class="nowrap">'
969 . '<span>' . htmlspecialchars($row['col_collation']) . '</span>'
970 . Charsets::getCollationDropdownBox(
971 $this->dbi,
972 $this->disableIs,
973 'field_collation[' . $row_num . ']',
974 'field_' . $row_num . '_4', $row['col_collation'], false
976 . '</td>';
977 $tableHtml .=
978 '<td class="nowrap" name="col_attribute">'
979 . '<span>' .
980 ($row['col_attribute']
981 ? htmlspecialchars($row['col_attribute']) : "" )
982 . '</span>'
983 . Template::get('columns_definitions/column_attribute')
984 ->render(
985 array(
986 'column_number' => $row_num,
987 'ci' => 5,
988 'ci_offset' => 0,
989 'extracted_columnspec' => array(),
990 'column_meta' => $row['col_attribute'],
991 'submit_attribute' => false,
992 'attribute_types' => $this->dbi->types->getAttributes(),
995 . '</td>';
996 $tableHtml .=
997 '<td class="nowrap" name="col_isNull">'
998 . '<span>' . ($row['col_isNull'] ? __('Yes') : __('No'))
999 . '</span>'
1000 . Template::get('columns_definitions/column_null')
1001 ->render(
1002 array(
1003 'column_number' => $row_num,
1004 'ci' => 6,
1005 'ci_offset' => 0,
1006 'column_meta' => array(
1007 'Null' => $row['col_isNull']
1011 . '</td>';
1013 $tableHtml .=
1014 '<td class="nowrap" name="col_extra"><span>'
1015 . htmlspecialchars($row['col_extra']) . '</span>'
1016 . Template::get('columns_definitions/column_extra')->render(
1017 array(
1018 'column_number' => $row_num,
1019 'ci' => 7,
1020 'ci_offset' => 0,
1021 'column_meta' => array('Extra'=>$row['col_extra'])
1024 . '</td>';
1026 $tableHtml .= '</tr>';
1028 return $tableHtml;
1032 * build html for editing a row in central columns table
1034 * @param array $row array contains complete information of a
1035 * particular row of central list table
1036 * @param int $row_num position the row in the table
1038 * @return string html of a particular row in the central columns table.
1040 private function getHtmlForEditTableRow(array $row, $row_num)
1042 $tableHtml = '<tr>'
1043 . '<input name="orig_col_name[' . $row_num . ']" type="hidden" '
1044 . 'value="' . htmlspecialchars($row['col_name']) . '">'
1045 . '<td name="col_name" class="nowrap">'
1046 . Template::get('columns_definitions/column_name')->render(array(
1047 'column_number' => $row_num,
1048 'ci' => 0,
1049 'ci_offset' => 0,
1050 'column_meta' => array(
1051 'Field' => $row['col_name']
1053 'cfg_relation' => array(
1054 'centralcolumnswork' => false
1056 'max_rows' => $this->maxRows,
1058 . '</td>';
1059 $tableHtml .=
1060 '<td name = "col_type" class="nowrap">'
1061 . Template::get('columns_definitions/column_type')
1062 ->render(
1063 array(
1064 'column_number' => $row_num,
1065 'ci' => 1,
1066 'ci_offset' => 0,
1067 'type_upper' => mb_strtoupper($row['col_type']),
1068 'column_meta' => array()
1071 . '</td>';
1072 $tableHtml .=
1073 '<td class="nowrap" name="col_length">'
1074 . Template::get('columns_definitions/column_length')->render(
1075 array(
1076 'column_number' => $row_num,
1077 'ci' => 2,
1078 'ci_offset' => 0,
1079 'length_values_input_size' => 8,
1080 'length_to_display' => $row['col_length']
1083 . '</td>';
1084 $meta = array();
1085 if (!isset($row['col_default']) || $row['col_default'] == '') {
1086 $meta['DefaultType'] = 'NONE';
1087 } else {
1088 if ($row['col_default'] == 'CURRENT_TIMESTAMP'
1089 || $row['col_default'] == 'current_timestamp()'
1091 $meta['DefaultType'] = 'CURRENT_TIMESTAMP';
1092 } elseif ($row['col_default'] == 'NULL') {
1093 $meta['DefaultType'] = $row['col_default'];
1094 } else {
1095 $meta['DefaultType'] = 'USER_DEFINED';
1096 $meta['DefaultValue'] = $row['col_default'];
1099 $tableHtml .=
1100 '<td class="nowrap" name="col_default">'
1101 . Template::get('columns_definitions/column_default')
1102 ->render(
1103 array(
1104 'column_number' => $row_num,
1105 'ci' => 3,
1106 'ci_offset' => 0,
1107 'type_upper' => mb_strtoupper($row['col_default']),
1108 'column_meta' => $meta,
1109 'char_editing' => $this->charEditing,
1112 . '</td>';
1113 $tableHtml .=
1114 '<td name="collation" class="nowrap">'
1115 . Charsets::getCollationDropdownBox(
1116 $this->dbi,
1117 $this->disableIs,
1118 'field_collation[' . $row_num . ']',
1119 'field_' . $row_num . '_4', $row['col_collation'], false
1121 . '</td>';
1122 $tableHtml .=
1123 '<td class="nowrap" name="col_attribute">'
1124 . Template::get('columns_definitions/column_attribute')
1125 ->render(
1126 array(
1127 'column_number' => $row_num,
1128 'ci' => 5,
1129 'ci_offset' => 0,
1130 'extracted_columnspec' => array(
1131 'attribute' => $row['col_attribute']
1133 'column_meta' => array(),
1134 'submit_attribute' => false,
1135 'attribute_types' => $this->dbi->types->getAttributes(),
1138 . '</td>';
1139 $tableHtml .=
1140 '<td class="nowrap" name="col_isNull">'
1141 . Template::get('columns_definitions/column_null')
1142 ->render(
1143 array(
1144 'column_number' => $row_num,
1145 'ci' => 6,
1146 'ci_offset' => 0,
1147 'column_meta' => array(
1148 'Null' => $row['col_isNull']
1152 . '</td>';
1154 $tableHtml .=
1155 '<td class="nowrap" name="col_extra">'
1156 . Template::get('columns_definitions/column_extra')->render(
1157 array(
1158 'column_number' => $row_num,
1159 'ci' => 7,
1160 'ci_offset' => 0,
1161 'column_meta' => array('Extra' => $row['col_extra'])
1164 . '</td>';
1165 $tableHtml .= '</tr>';
1166 return $tableHtml;
1170 * get the list of columns in given database excluding
1171 * the columns present in current table
1173 * @param string $db selected database
1174 * @param string $table current table name
1176 * @return string encoded list of columns present in central list for the given
1177 * database
1179 public function getListRaw($db, $table)
1181 $cfgCentralColumns = $this->getParams();
1182 if (empty($cfgCentralColumns)) {
1183 return json_encode(array());
1185 $centralTable = $cfgCentralColumns['table'];
1186 if (empty($table) || $table == '') {
1187 $query = 'SELECT * FROM ' . Util::backquote($centralTable) . ' '
1188 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\';';
1189 } else {
1190 $this->dbi->selectDb($db);
1191 $columns = (array) $this->dbi->getColumnNames(
1192 $db, $table
1194 $cols = '';
1195 foreach ($columns as $col_select) {
1196 $cols .= '\'' . $this->dbi->escapeString($col_select) . '\',';
1198 $cols = trim($cols, ',');
1199 $query = 'SELECT * FROM ' . Util::backquote($centralTable) . ' '
1200 . 'WHERE db_name = \'' . $this->dbi->escapeString($db) . '\'';
1201 if ($cols) {
1202 $query .= ' AND col_name NOT IN (' . $cols . ')';
1204 $query .= ';';
1206 $this->dbi->selectDb($cfgCentralColumns['db'], DatabaseInterface::CONNECT_CONTROL);
1207 $columns_list = (array)$this->dbi->fetchResult(
1208 $query, null, null, DatabaseInterface::CONNECT_CONTROL
1210 $this->handleColumnExtra($columns_list);
1211 return json_encode($columns_list);
1215 * Get HTML for "check all" check box with "with selected" dropdown
1217 * @param string $pmaThemeImage pma theme image url
1218 * @param string $text_dir url for text directory
1220 * @return string $html_output
1222 public function getTableFooter($pmaThemeImage, $text_dir)
1224 $html_output = Template::get('select_all')
1225 ->render(
1226 array(
1227 'pma_theme_image' => $pmaThemeImage,
1228 'text_dir' => $text_dir,
1229 'form_name' => 'tableslistcontainer',
1232 $html_output .= Util::getButtonOrImage(
1233 'edit_central_columns', 'mult_submit change_central_columns',
1234 __('Edit'), 'b_edit', 'edit central columns'
1236 $html_output .= Util::getButtonOrImage(
1237 'delete_central_columns', 'mult_submit',
1238 __('Delete'), 'b_drop',
1239 'remove_from_central_columns'
1241 return $html_output;
1245 * function generate and return the table footer for
1246 * multiple edit central columns page
1248 * @return string html for table footer in central columns multi edit page
1250 private function getEditTableFooter()
1252 $html_output = '<fieldset class="tblFooters">'
1253 . '<input type="submit" '
1254 . 'name="save_multi_central_column_edit" value="' . __('Save') . '" />'
1255 . '</fieldset>';
1256 return $html_output;
1260 * Column `col_extra` is used to store both extra and attributes for a column.
1261 * This method separates them.
1263 * @param array &$columns_list columns list
1265 * @return void
1267 private function handleColumnExtra(array &$columns_list)
1269 foreach ($columns_list as &$row) {
1270 $vals = explode(',', $row['col_extra']);
1272 if (in_array('BINARY', $vals)) {
1273 $row['col_attribute'] = 'BINARY';
1274 } elseif (in_array('UNSIGNED', $vals)) {
1275 $row['col_attribute'] = 'UNSIGNED';
1276 } elseif (in_array('UNSIGNED ZEROFILL', $vals)) {
1277 $row['col_attribute'] = 'UNSIGNED ZEROFILL';
1278 } elseif (in_array('on update CURRENT_TIMESTAMP', $vals)) {
1279 $row['col_attribute'] = 'on update CURRENT_TIMESTAMP';
1280 } else {
1281 $row['col_attribute'] = '';
1284 if (in_array('auto_increment', $vals)) {
1285 $row['col_extra'] = 'auto_increment';
1286 } else {
1287 $row['col_extra'] = '';
1293 * build html for adding a new user defined column to central list
1295 * @param string $db current database
1296 * @param integer $total_rows number of rows in central columns
1298 * @return string html of the form to let user add a new user defined column to the
1299 * list
1301 public function getHtmlForAddNewColumn($db, $total_rows)
1303 $addNewColumn = '<div id="add_col_div" class="topmargin"><a href="#">'
1304 . '<span>+</span> ' . __('Add new column') . '</a>'
1305 . '<form id="add_new" class="new_central_col '
1306 . ($total_rows != 0 ? 'hide"' : '"')
1307 . 'method="post" action="db_central_columns.php">'
1308 . Url::getHiddenInputs(
1311 . '<input type="hidden" name="add_new_column" value="add_new_column">'
1312 . '<div class="responsivetable">'
1313 . '<table>';
1314 $addNewColumn .= $this->getTableHeader();
1315 $addNewColumn .= '<tr>'
1316 . '<td></td>'
1317 . '<td name="col_name" class="nowrap">'
1318 . Template::get('columns_definitions/column_name')->render(array(
1319 'column_number' => 0,
1320 'ci' => 0,
1321 'ci_offset' => 0,
1322 'column_meta' => array(),
1323 'cfg_relation' => array(
1324 'centralcolumnswork' => false
1326 'max_rows' => $this->maxRows,
1328 . '</td>'
1329 . '<td name = "col_type" class="nowrap">'
1330 . Template::get('columns_definitions/column_type')
1331 ->render(
1332 array(
1333 'column_number' => 0,
1334 'ci' => 1,
1335 'ci_offset' => 0,
1336 'type_upper' => '',
1337 'column_meta' => array()
1340 . '</td>'
1341 . '<td class="nowrap" name="col_length">'
1342 . Template::get('columns_definitions/column_length')->render(
1343 array(
1344 'column_number' => 0,
1345 'ci' => 2,
1346 'ci_offset' => 0,
1347 'length_values_input_size' => 8,
1348 'length_to_display' => ''
1351 . '</td>'
1352 . '<td class="nowrap" name="col_default">'
1353 . Template::get('columns_definitions/column_default')
1354 ->render(
1355 array(
1356 'column_number' => 0,
1357 'ci' => 3,
1358 'ci_offset' => 0,
1359 'type_upper' => '',
1360 'column_meta' => array(),
1361 'char_editing' => $this->charEditing,
1364 . '</td>'
1365 . '<td name="collation" class="nowrap">'
1366 . Charsets::getCollationDropdownBox(
1367 $this->dbi,
1368 $this->disableIs,
1369 'field_collation[0]',
1370 'field_0_4', null, false
1372 . '</td>'
1373 . '<td class="nowrap" name="col_attribute">'
1374 . Template::get('columns_definitions/column_attribute')
1375 ->render(
1376 array(
1377 'column_number' => 0,
1378 'ci' => 5,
1379 'ci_offset' => 0,
1380 'extracted_columnspec' => array(),
1381 'column_meta' => array(),
1382 'submit_attribute' => false,
1383 'attribute_types' => $this->dbi->types->getAttributes(),
1386 . '</td>'
1387 . '<td class="nowrap" name="col_isNull">'
1388 . Template::get('columns_definitions/column_null')
1389 ->render(
1390 array(
1391 'column_number' => 0,
1392 'ci' => 6,
1393 'ci_offset' => 0,
1394 'column_meta' => array()
1397 . '</td>'
1398 . '<td class="nowrap" name="col_extra">'
1399 . Template::get('columns_definitions/column_extra')->render(
1400 array(
1401 'column_number' => 0,
1402 'ci' => 7,
1403 'ci_offset' => 0,
1404 'column_meta' => array()
1407 . '</td>'
1408 . ' <td>'
1409 . '<input id="add_column_save" type="submit" '
1410 . ' value="Save"/></td>'
1411 . '</tr>';
1412 $addNewColumn .= '</table></div></form></div>';
1413 return $addNewColumn;
1417 * Get HTML for editing page central columns
1419 * @param array $selected_fld Array containing the selected fields
1420 * @param string $selected_db String containing the name of database
1422 * @return string HTML for complete editing page for central columns
1424 public function getHtmlForEditingPage(array $selected_fld, $selected_db)
1426 $html = '<form id="multi_edit_central_columns">';
1427 $header_cells = array(
1428 __('Name'), __('Type'), __('Length/Values'), __('Default'),
1429 __('Collation'), __('Attributes'), __('Null'), __('A_I')
1431 $html .= $this->getEditTableHeader($header_cells);
1432 $selected_fld_safe = array();
1433 foreach ($selected_fld as $key) {
1434 $selected_fld_safe[] = $this->dbi->escapeString($key);
1436 $columns_list = implode("','", $selected_fld_safe);
1437 $columns_list = "'" . $columns_list . "'";
1438 $list_detail_cols = $this->findExistingColNames($selected_db, $columns_list, true);
1439 $row_num = 0;
1440 foreach ($list_detail_cols as $row) {
1441 $tableHtmlRow = $this->getHtmlForEditTableRow(
1442 $row,
1443 $row_num
1445 $html .= $tableHtmlRow;
1446 $row_num++;
1448 $html .= '</table>';
1449 $html .= $this->getEditTableFooter();
1450 $html .= '</form>';
1451 return $html;