added japanese language
[openemr.git] / phpmyadmin / libraries / DisplayResults.class.php
blobb495104f777596856c4fba802e4c4385d7931486
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Hold the PMA_DisplayResults class
6 * @package PhpMyAdmin
7 */
8 if (! defined('PHPMYADMIN')) {
9 exit;
12 /**
13 * Handle all the functionalities related to displaying results
14 * of sql queries, stored procedure, browsing sql processes or
15 * displaying binary log.
17 * @package PhpMyAdmin
19 class PMA_DisplayResults
22 // Define constants
23 const NO_EDIT_OR_DELETE = 'nn';
24 const UPDATE_ROW = 'ur';
25 const DELETE_ROW = 'dr';
26 const KILL_PROCESS = 'kp';
28 const POSITION_LEFT = 'left';
29 const POSITION_RIGHT = 'right';
30 const POSITION_BOTH = 'both';
31 const POSITION_NONE = 'none';
33 const PLACE_TOP_DIRECTION_DROPDOWN = 'top_direction_dropdown';
34 const PLACE_BOTTOM_DIRECTION_DROPDOWN = 'bottom_direction_dropdown';
36 const DISP_DIR_HORIZONTAL = 'horizontal';
37 const DISP_DIR_HORIZONTAL_FLIPPED = 'horizontalflipped';
38 const DISP_DIR_VERTICAL = 'vertical';
40 const DISPLAY_FULL_TEXT = 'F';
41 const DISPLAY_PARTIAL_TEXT = 'P';
43 const HEADER_FLIP_TYPE_AUTO = 'auto';
44 const HEADER_FLIP_TYPE_CSS = 'css';
45 const HEADER_FLIP_TYPE_FAKE = 'fake';
47 const DATE_FIELD = 'date';
48 const DATETIME_FIELD = 'datetime';
49 const TIMESTAMP_FIELD = 'timestamp';
50 const TIME_FIELD = 'time';
51 const STRING_FIELD = 'string';
52 const GEOMETRY_FIELD = 'geometry';
53 const BLOB_FIELD = 'BLOB';
54 const BINARY_FIELD = 'BINARY';
56 const RELATIONAL_KEY = 'K';
57 const RELATIONAL_DISPLAY_COLUMN = 'D';
59 const GEOMETRY_DISP_GEOM = 'GEOM';
60 const GEOMETRY_DISP_WKT = 'WKT';
61 const GEOMETRY_DISP_WKB = 'WKB';
63 const SMART_SORT_ORDER = 'SMART';
64 const ASCENDING_SORT_DIR = 'ASC';
65 const DESCENDING_SORT_DIR = 'DESC';
67 const TABLE_TYPE_INNO_DB = 'InnoDB';
68 const ALL_ROWS = 'all';
69 const QUERY_TYPE_SELECT = 'SELECT';
71 const ROUTINE_PROCEDURE = 'procedure';
72 const ROUTINE_FUNCTION = 'function';
74 const ACTION_LINK_CONTENT_ICONS = 'icons';
75 const ACTION_LINK_CONTENT_TEXT = 'text';
78 // Declare global fields
80 /** array with properties of the class */
81 private $_property_array = array(
83 /** string Database name */
84 'db' => null,
86 /** string Table name */
87 'table' => null,
89 /** string the URL to go back in case of errors */
90 'goto' => null,
92 /** string the SQL query */
93 'sql_query' => null,
95 /**
96 * integer the total number of rows returned by the SQL query without any
97 * appended "LIMIT" clause programmatically
99 'unlim_num_rows' => null,
101 /** array meta information about fields */
102 'fields_meta' => null,
104 /** boolean */
105 'is_count' => null,
107 /** integer */
108 'is_export' => null,
110 /** boolean */
111 'is_func' => null,
113 /** integer */
114 'is_analyse' => null,
116 /** integer the total number of rows returned by the SQL query */
117 'num_rows' => null,
119 /** integer the total number of fields returned by the SQL query */
120 'fields_cnt' => null,
122 /** double time taken for execute the SQL query */
123 'querytime' => null,
125 /** string path for theme images directory */
126 'pma_theme_image' => null,
128 /** string */
129 'text_dir' => null,
131 /** boolean */
132 'is_maint' => null,
134 /** boolean */
135 'is_explain' => null,
137 /** boolean */
138 'is_show' => null,
140 /** array table definitions */
141 'showtable' => null,
143 /** string */
144 'printview' => null,
146 /** string URL query */
147 'url_query' => null,
149 /** array column names to highlight */
150 'highlight_columns' => null,
152 /** array informations used with vertical display mode */
153 'vertical_display' => null,
155 /** array mime types information of fields */
156 'mime_map' => null,
158 /** boolean */
159 'editable' => null
163 * This variable contains the column transformation information
164 * for some of the system databases.
165 * One element of this array represent all relevant columns in all tables in
166 * one specific database
168 public $transformation_info;
172 * Get any property of this class
174 * @param string $property name of the property
176 * @return mixed|void if property exist, value of the relevant property
178 public function __get($property)
180 if (array_key_exists($property, $this->_property_array)) {
181 return $this->_property_array[$property];
187 * Set values for any property of this class
189 * @param string $property name of the property
190 * @param mixed $value value to set
192 * @return void
194 public function __set($property, $value)
196 if (array_key_exists($property, $this->_property_array)) {
197 $this->_property_array[$property] = $value;
203 * Constructor for PMA_DisplayResults class
205 * @param string $db the database name
206 * @param string $table the table name
207 * @param string $goto the URL to go back in case of errors
208 * @param string $sql_query the SQL query
210 * @access public
212 public function __construct($db, $table, $goto, $sql_query)
214 $this->_setDefaultTransformations();
216 $this->__set('db', $db);
217 $this->__set('table', $table);
218 $this->__set('goto', $goto);
219 $this->__set('sql_query', $sql_query);
223 * Sets default transformations for some columns
225 * @return void
227 private function _setDefaultTransformations()
229 $sql_highlighting_data = array(
230 'libraries/plugins/transformations/Text_Plain_Formatted.class.php',
231 'Text_Plain_Formatted',
232 'Text_Plain'
234 $this->transformation_info = array(
235 'information_schema' => array(
236 'events' => array(
237 'event_definition' => $sql_highlighting_data
239 'processlist' => array(
240 'info' => $sql_highlighting_data
242 'routines' => array(
243 'routine_definition' => $sql_highlighting_data
245 'triggers' => array(
246 'action_statement' => $sql_highlighting_data
248 'views' => array(
249 'view_definition' => $sql_highlighting_data
254 $cfgRelation = PMA_getRelationsParam();
255 if ($cfgRelation['db']) {
256 $this->transformation_info[$cfgRelation['db']] = array();
257 $relDb = &$this->transformation_info[$cfgRelation['db']];
258 if (! empty($cfgRelation['history'])) {
259 $relDb[$cfgRelation['history']] = array(
260 'sqlquery' => $sql_highlighting_data
263 if (! empty($cfgRelation['bookmark'])) {
264 $relDb[$cfgRelation['bookmark']] = array(
265 'query' => $sql_highlighting_data
268 if (! empty($cfgRelation['tracking'])) {
269 $relDb[$cfgRelation['tracking']] = array(
270 'schema_sql' => $sql_highlighting_data,
271 'data_sql' => $sql_highlighting_data
278 * Set properties which were not initialized at the constructor
280 * @param integer $unlim_num_rows the total number of rows returned by
281 * the SQL query without any appended
282 * "LIMIT" clause programmatically
283 * @param array $fields_meta meta information about fields
284 * @param boolean $is_count statement is SELECT COUNT
285 * @param integer $is_export statement contains INTO OUTFILE
286 * @param boolean $is_func statement contains a function like SUM()
287 * @param integer $is_analyse statement contains PROCEDURE ANALYSE
288 * @param integer $num_rows total no. of rows returned by SQL query
289 * @param integer $fields_cnt total no.of fields returned by SQL query
290 * @param double $querytime time taken for execute the SQL query
291 * @param string $pmaThemeImage path for theme images directory
292 * @param string $text_dir text direction
293 * @param boolean $is_maint statement contains a maintenance command
294 * @param boolean $is_explain statement contains EXPLAIN
295 * @param boolean $is_show statement contains SHOW
296 * @param array $showtable table definitions
297 * @param string $printview print view was requested
298 * @param string $url_query URL query
299 * @param boolean $editable whether the results set is editable
301 * @return void
303 * @see sql.php
305 public function setProperties(
306 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
307 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
308 $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
309 $editable
312 $this->__set('unlim_num_rows', $unlim_num_rows);
313 $this->__set('fields_meta', $fields_meta);
314 $this->__set('is_count', $is_count);
315 $this->__set('is_export', $is_export);
316 $this->__set('is_func', $is_func);
317 $this->__set('is_analyse', $is_analyse);
318 $this->__set('num_rows', $num_rows);
319 $this->__set('fields_cnt', $fields_cnt);
320 $this->__set('querytime', $querytime);
321 $this->__set('pma_theme_image', $pmaThemeImage);
322 $this->__set('text_dir', $text_dir);
323 $this->__set('is_maint', $is_maint);
324 $this->__set('is_explain', $is_explain);
325 $this->__set('is_show', $is_show);
326 $this->__set('showtable', $showtable);
327 $this->__set('printview', $printview);
328 $this->__set('url_query', $url_query);
329 $this->__set('editable', $editable);
331 } // end of the 'setProperties()' function
335 * Defines the display mode to use for the results of a SQL query
337 * It uses a synthetic string that contains all the required informations.
338 * In this string:
339 * - the first two characters stand for the action to do while
340 * clicking on the "edit" link (e.g. 'ur' for update a row, 'nn' for no
341 * edit link...);
342 * - the next two characters stand for the action to do while
343 * clicking on the "delete" link (e.g. 'kp' for kill a process, 'nn' for
344 * no delete link...);
345 * - the next characters are boolean values (1/0) and respectively stand
346 * for sorting links, navigation bar, "insert a new row" link, the
347 * bookmark feature, the expand/collapse text/blob fields button and
348 * the "display printable view" option.
349 * Of course '0'/'1' means the feature won't/will be enabled.
351 * @param string &$the_disp_mode the synthetic value for display_mode (see a few
352 * lines above for explanations)
353 * @param integer &$the_total the total number of rows returned by the SQL
354 * query without any programmatically appended
355 * LIMIT clause
356 * (just a copy of $unlim_num_rows if it exists,
357 * elsecomputed inside this function)
359 * @return array an array with explicit indexes for all the display
360 * elements
362 * @access private
364 * @see getTable()
366 private function _setDisplayMode(&$the_disp_mode, &$the_total)
369 // Following variables are needed for use in isset/empty or
370 // use with array indexes or safe use in foreach
371 $db = $this->__get('db');
372 $table = $this->__get('table');
373 $unlim_num_rows = $this->__get('unlim_num_rows');
374 $fields_meta = $this->__get('fields_meta');
375 $printview = $this->__get('printview');
377 // 1. Initializes the $do_display array
378 $do_display = array();
379 $do_display['edit_lnk'] = $the_disp_mode[0] . $the_disp_mode[1];
380 $do_display['del_lnk'] = $the_disp_mode[2] . $the_disp_mode[3];
381 $do_display['sort_lnk'] = (string) $the_disp_mode[4];
382 $do_display['nav_bar'] = (string) $the_disp_mode[5];
383 $do_display['ins_row'] = (string) $the_disp_mode[6];
384 $do_display['bkm_form'] = (string) $the_disp_mode[7];
385 $do_display['text_btn'] = (string) $the_disp_mode[8];
386 $do_display['pview_lnk'] = (string) $the_disp_mode[9];
388 // 2. Display mode is not "false for all elements" -> updates the
389 // display mode
390 if ($the_disp_mode != 'nnnn000000') {
392 if (isset($printview) && ($printview == '1')) {
393 // 2.0 Print view -> set all elements to false!
394 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
395 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
396 $do_display['sort_lnk'] = (string) '0';
397 $do_display['nav_bar'] = (string) '0';
398 $do_display['ins_row'] = (string) '0';
399 $do_display['bkm_form'] = (string) '0';
400 $do_display['text_btn'] = (string) '0';
401 $do_display['pview_lnk'] = (string) '0';
403 } elseif ($this->__get('is_count') || $this->__get('is_analyse')
404 || $this->__get('is_maint') || $this->__get('is_explain')
406 // 2.1 Statement is a "SELECT COUNT", a
407 // "CHECK/ANALYZE/REPAIR/OPTIMIZE", an "EXPLAIN" one or
408 // contains a "PROC ANALYSE" part
409 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
410 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
411 $do_display['sort_lnk'] = (string) '0';
412 $do_display['nav_bar'] = (string) '0';
413 $do_display['ins_row'] = (string) '0';
414 $do_display['bkm_form'] = (string) '1';
416 if ($this->__get('is_maint')) {
417 $do_display['text_btn'] = (string) '1';
418 } else {
419 $do_display['text_btn'] = (string) '0';
421 $do_display['pview_lnk'] = (string) '1';
423 } elseif ($this->__get('is_show')) {
424 // 2.2 Statement is a "SHOW..."
426 * 2.2.1
427 * @todo defines edit/delete links depending on show statement
429 preg_match(
430 '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
431 . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
432 . ')@i',
433 $this->__get('sql_query'), $which
435 if (isset($which[1])
436 && (strpos(' ' . strtoupper($which[1]), 'PROCESSLIST') > 0)
438 // no edit link
439 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
440 // "kill process" type edit link
441 $do_display['del_lnk'] = self::KILL_PROCESS;
442 } else {
443 // Default case -> no links
444 // no edit link
445 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
446 // no delete link
447 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
449 // 2.2.2 Other settings
450 $do_display['sort_lnk'] = (string) '0';
451 $do_display['nav_bar'] = (string) '0';
452 $do_display['ins_row'] = (string) '0';
453 $do_display['bkm_form'] = (string) '1';
454 $do_display['text_btn'] = (string) '1';
455 $do_display['pview_lnk'] = (string) '1';
457 } else {
458 // 2.3 Other statements (ie "SELECT" ones) -> updates
459 // $do_display['edit_lnk'], $do_display['del_lnk'] and
460 // $do_display['text_btn'] (keeps other default values)
461 $prev_table = $fields_meta[0]->table;
462 $do_display['text_btn'] = (string) '1';
464 for ($i = 0; $i < $this->__get('fields_cnt'); $i++) {
466 $is_link = ($do_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
467 || ($do_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
468 || ($do_display['sort_lnk'] != '0')
469 || ($do_display['ins_row'] != '0');
471 // 2.3.2 Displays edit/delete/sort/insert links?
472 if ($is_link
473 && (($fields_meta[$i]->table == '')
474 || ($fields_meta[$i]->table != $prev_table))
476 // don't display links
477 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
478 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
480 * @todo May be problematic with same field names
481 * in two joined table.
483 // $do_display['sort_lnk'] = (string) '0';
484 $do_display['ins_row'] = (string) '0';
485 if ($do_display['text_btn'] == '1') {
486 break;
488 } // end if (2.3.2)
490 // 2.3.3 Always display print view link
491 $do_display['pview_lnk'] = (string) '1';
492 $prev_table = $fields_meta[$i]->table;
494 } // end for
495 } // end if..elseif...else (2.1 -> 2.3)
496 } // end if (2)
498 // 3. Gets the total number of rows if it is unknown
499 if (isset($unlim_num_rows) && $unlim_num_rows != '') {
500 $the_total = $unlim_num_rows;
501 } elseif ((($do_display['nav_bar'] == '1')
502 || ($do_display['sort_lnk'] == '1'))
503 && (strlen($db) && !empty($table))
505 $the_total = PMA_Table::countRecords($db, $table);
508 // 4. If navigation bar or sorting fields names URLs should be
509 // displayed but there is only one row, change these settings to
510 // false
511 if ($do_display['nav_bar'] == '1' || $do_display['sort_lnk'] == '1') {
513 // - Do not display sort links if less than 2 rows.
514 // - For a VIEW we (probably) did not count the number of rows
515 // so don't test this number here, it would remove the possibility
516 // of sorting VIEW results.
517 if (isset($unlim_num_rows)
518 && ($unlim_num_rows < 2)
519 && ! PMA_Table::isView($db, $table)
521 // force display of navbar for vertical/horizontal display-choice.
522 // $do_display['nav_bar'] = (string) '0';
523 $do_display['sort_lnk'] = (string) '0';
525 } // end if (3)
527 // 5. Updates the synthetic var
528 $the_disp_mode = join('', $do_display);
530 return $do_display;
532 } // end of the 'setDisplayMode()' function
536 * Return true if we are executing a query in the form of
537 * "SELECT * FROM <a table> ..."
539 * @param array $analyzed_sql the analyzed query
541 * @return boolean
543 * @access private
545 * @see _getTableHeaders(), _getColumnParams()
547 private function _isSelect($analyzed_sql)
549 if (!isset($analyzed_sql[0]['select_expr'])) {
550 $analyzed_sql[0]['select_expr'] = 0;
553 return ! ($this->__get('is_count') || $this->__get('is_export')
554 || $this->__get('is_func') || $this->__get('is_analyse'))
555 && (count($analyzed_sql[0]['select_expr']) == 0)
556 && isset($analyzed_sql[0]['queryflags']['select_from'])
557 && (count($analyzed_sql[0]['table_ref']) == 1);
562 * Get a navigation button
564 * @param string $caption iconic caption for button
565 * @param string $title text for button
566 * @param integer $pos position for next query
567 * @param string $html_sql_query query ready for display
568 * @param string $onsubmit optional onsubmit clause
569 * @param string $input_for_real_end optional hidden field for special treatment
570 * @param string $onclick optional onclick clause
572 * @return string html content
574 * @access private
576 * @see _getMoveBackwardButtonsForTableNavigation(),
577 * _getMoveForwardButtonsForTableNavigation()
579 private function _getTableNavigationButton(
580 $caption, $title, $pos, $html_sql_query, $onsubmit = '',
581 $input_for_real_end = '', $onclick = ''
584 $caption_output = '';
585 if (PMA_Util::showIcons('TableNavigationLinksMode')) {
586 $caption_output .= $caption;
589 if (PMA_Util::showText('TableNavigationLinksMode')) {
590 $caption_output .= '&nbsp;' . $title;
592 $title_output = ' title="' . $title . '"';
594 return '<td>'
595 . '<form action="sql.php" method="post" ' . $onsubmit . '>'
596 . PMA_URL_getHiddenInputs(
597 $this->__get('db'), $this->__get('table')
599 . '<input type="hidden" name="sql_query" value="'
600 . $html_sql_query . '" />'
601 . '<input type="hidden" name="pos" value="' . $pos . '" />'
602 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
603 . '" />'
604 . $input_for_real_end
605 . '<input type="submit" name="navig"'
606 . ' class="ajax" '
607 . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
608 . '</form>'
609 . '</td>';
611 } // end function _getTableNavigationButton()
615 * Get a navigation bar to browse among the results of a SQL query
617 * @param integer $pos_next the offset for the "next" page
618 * @param integer $pos_prev the offset for the "previous" page
619 * @param string $id_for_direction_dropdown the id for the direction dropdown
620 * @param boolean $is_innodb whether its InnoDB or not
622 * @return string html content
624 * @access private
626 * @see _getTable()
628 private function _getTableNavigation(
629 $pos_next, $pos_prev, $id_for_direction_dropdown, $is_innodb
632 $table_navigation_html = '';
633 $showtable = $this->__get('showtable'); // To use in isset
635 // here, using htmlentities() would cause problems if the query
636 // contains accented characters
637 $html_sql_query = htmlspecialchars($this->__get('sql_query'));
640 * @todo move this to a central place
641 * @todo for other future table types
643 $is_innodb = (isset($showtable['Type'])
644 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
646 // Navigation bar
647 $table_navigation_html .= '<table class="navigation nospacing nopadding">'
648 . '<tr>'
649 . '<td class="navigation_separator"></td>';
651 // Move to the beginning or to the previous page
652 if ($_SESSION['tmpval']['pos']
653 && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
656 $table_navigation_html
657 .= $this->_getMoveBackwardButtonsForTableNavigation(
658 $html_sql_query, $pos_prev
661 } // end move back
663 $nbTotalPage = 1;
664 //page redirection
665 // (unless we are showing all records)
666 if ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) { //if1
668 $pageNow = @floor(
669 $_SESSION['tmpval']['pos']
670 / $_SESSION['tmpval']['max_rows']
671 ) + 1;
673 $nbTotalPage = @ceil(
674 $this->__get('unlim_num_rows')
675 / $_SESSION['tmpval']['max_rows']
678 if ($nbTotalPage > 1) { //if2
680 $table_navigation_html .= '<td>';
681 $_url_params = array(
682 'db' => $this->__get('db'),
683 'table' => $this->__get('table'),
684 'sql_query' => $this->__get('sql_query'),
685 'goto' => $this->__get('goto'),
688 //<form> to keep the form alignment of button < and <<
689 // and also to know what to execute when the selector changes
690 $table_navigation_html .= '<form action="sql.php'
691 . PMA_URL_getCommon($_url_params)
692 . '" method="post">';
694 $table_navigation_html .= PMA_Util::pageselector(
695 'pos',
696 $_SESSION['tmpval']['max_rows'],
697 $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
700 $table_navigation_html .= '</form>'
701 . '</td>';
702 } //_if2
703 } //_if1
705 // Display the "Show all" button if allowed
706 if (($this->__get('num_rows') < $this->__get('unlim_num_rows'))
707 && ($GLOBALS['cfg']['ShowAll']
708 || ($this->__get('unlim_num_rows') <= 500))
711 $table_navigation_html .= $this->_getShowAllButtonForTableNavigation(
712 $html_sql_query
715 } // end show all
717 // Move to the next page or to the last one
718 $endpos = $_SESSION['tmpval']['pos']
719 + $_SESSION['tmpval']['max_rows'];
721 if (($endpos < $this->__get('unlim_num_rows'))
722 && ($this->__get('num_rows') >= $_SESSION['tmpval']['max_rows'])
723 && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
726 $table_navigation_html
727 .= $this->_getMoveForwardButtonsForTableNavigation(
728 $html_sql_query, $pos_next, $is_innodb
731 } // end move toward
733 // show separator if pagination happen
734 if ($nbTotalPage > 1) {
735 $table_navigation_html
736 .= '<td><div class="navigation_separator">|</div></td>';
739 $table_navigation_html .= '<td>'
740 . '<div class="save_edited hide">'
741 . '<input type="submit" value="' . __('Save edited data') . '" />'
742 . '<div class="navigation_separator">|</div>'
743 . '</div>'
744 . '</td>'
745 . '<td>'
746 . '<div class="restore_column hide">'
747 . '<input type="submit" value="' . __('Restore column order') . '" />'
748 . '<div class="navigation_separator">|</div>'
749 . '</div>'
750 . '</td>';
752 // if displaying a VIEW, $unlim_num_rows could be zero because
753 // of $cfg['MaxExactCountViews']; in this case, avoid passing
754 // the 5th parameter to checkFormElementInRange()
755 // (this means we can't validate the upper limit
756 $table_navigation_html .= '<td class="navigation_goto">';
758 $table_navigation_html .= '<form action="sql.php" method="post" '
759 . 'onsubmit="return '
760 . '(checkFormElementInRange('
761 . 'this, '
762 . '\'session_max_rows\', '
763 . '\''
764 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
765 . '\', '
766 . '1)'
767 . ' &amp;&amp; '
768 . 'checkFormElementInRange('
769 . 'this, '
770 . '\'pos\', '
771 . '\''
772 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
773 . '\', '
774 . '0'
775 . (($this->__get('unlim_num_rows') > 0)
776 ? ', ' . ($this->__get('unlim_num_rows') - 1)
777 : ''
779 . ')'
780 . ')'
781 . '">';
783 $table_navigation_html .= PMA_URL_getHiddenInputs(
784 $this->__get('db'), $this->__get('table')
787 $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
788 $html_sql_query, $id_for_direction_dropdown
791 $table_navigation_html .= '</form>'
792 . '</td>'
793 . '<td class="navigation_separator"></td>'
794 . '<td>'
795 . '<span>' . __('Filter rows') . ':</span>'
796 . '<input type="text" class="filter_rows" placeholder="'
797 . __('Search this table') . '">'
798 . '</td>'
799 . '<td class="navigation_separator"></td>'
800 . '</tr>'
801 . '</table>';
803 return $table_navigation_html;
805 } // end of the '_getTableNavigation()' function
809 * Prepare move backward buttons - previous and first
811 * @param string $html_sql_query the sql encoded by html special characters
812 * @param integer $pos_prev the offset for the "previous" page
814 * @return string html content
816 * @access private
818 * @see _getTableNavigation()
820 private function _getMoveBackwardButtonsForTableNavigation(
821 $html_sql_query, $pos_prev
823 return $this->_getTableNavigationButton(
824 '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query
826 . $this->_getTableNavigationButton(
827 '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
828 $html_sql_query
830 } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
834 * Prepare Show All button for table navigation
836 * @param string $html_sql_query the sql encoded by html special characters
838 * @return string html content
840 * @access private
842 * @see _getTableNavigation()
844 private function _getShowAllButtonForTableNavigation($html_sql_query)
846 return "\n"
847 . '<td>'
848 . '<form action="sql.php" method="post">'
849 . PMA_URL_getHiddenInputs(
850 $this->__get('db'), $this->__get('table')
852 . '<input type="hidden" name="sql_query" value="'
853 . $html_sql_query . '" />'
854 . '<input type="hidden" name="pos" value="0" />'
855 . '<input type="hidden" name="session_max_rows" value="all" />'
856 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
857 . '" />'
858 . '<input type="submit" name="navig" value="' . __('Show all') . '" />'
859 . '</form>'
860 . '</td>';
861 } // end of the '_getShowAllButtonForTableNavigation()' function
865 * Prepare move forward buttons - next and last
867 * @param string $html_sql_query the sql encoded by htmlspecialchars()
868 * @param integer $pos_next the offset for the "next" page
869 * @param boolean $is_innodb whether it's InnoDB or not
871 * @return string $buttons_html html content
873 * @access private
875 * @see _getTableNavigation()
877 private function _getMoveForwardButtonsForTableNavigation(
878 $html_sql_query, $pos_next, $is_innodb
881 // display the Next button
882 $buttons_html = $this->_getTableNavigationButton(
883 '&gt;',
884 _pgettext('Next page', 'Next'),
885 $pos_next,
886 $html_sql_query
889 // prepare some options for the End button
890 if ($is_innodb
891 && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
893 $input_for_real_end = '<input id="real_end_input" type="hidden" '
894 . 'name="find_real_end" value="1" />';
895 // no backquote around this message
896 $onclick = '';
897 } else {
898 $input_for_real_end = $onclick = '';
901 $maxRows = $_SESSION['tmpval']['max_rows'];
902 $onsubmit = 'onsubmit="return '
903 . ($_SESSION['tmpval']['pos']
904 + $maxRows
905 < $this->__get('unlim_num_rows')
906 && $this->__get('num_rows') >= $maxRows)
907 ? 'true'
908 : 'false' . '"';
910 // display the End button
911 $buttons_html .= $this->_getTableNavigationButton(
912 '&gt;&gt;',
913 _pgettext('Last page', 'End'),
914 @((ceil(
915 $this->__get('unlim_num_rows')
916 / $_SESSION['tmpval']['max_rows']
917 )- 1) * $maxRows),
918 $html_sql_query, $onsubmit, $input_for_real_end, $onclick
921 return $buttons_html;
923 } // end of the '_getMoveForwardButtonsForTableNavigation()' function
927 * Prepare fields for table navigation
928 * Number of rows
930 * @param string $html_sql_query the sql encoded by htmlspecialchars()
931 * @param string $id_for_direction_dropdown the id for the direction dropdown
933 * @return string $additional_fields_html html content
935 * @access private
937 * @see _getTableNavigation()
939 private function _getAdditionalFieldsForTableNavigation(
940 $html_sql_query, $id_for_direction_dropdown
943 $additional_fields_html = '';
945 $additional_fields_html .= '<input type="hidden" name="sql_query" '
946 . 'value="' . $html_sql_query . '" />'
947 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
948 . '" />'
949 . '<input type="hidden" name="pos" size="3" value="'
950 // Do not change the position when changing the number of rows
951 . $_SESSION['tmpval']['pos'] . '" />';
953 $numberOfRowsChoices = array(
954 '25' => 25,
955 '50' => 50,
956 '100' => 100,
957 '250' => 250,
958 '500' => 500
960 $additional_fields_html .= __('Number of rows:') . ' ';
961 $additional_fields_html .= PMA_Util::getDropdown(
962 'session_max_rows', $numberOfRowsChoices,
963 $_SESSION['tmpval']['max_rows'], '', 'autosubmit'
966 if ($GLOBALS['cfg']['ShowDisplayDirection']) {
967 // Display mode (horizontal/vertical)
968 $additional_fields_html .= __('Mode:') . ' ' . "\n";
969 $choices = array(
970 'horizontal' => __('horizontal'),
971 'horizontalflipped' => __('horizontal (rotated headers)'),
972 'vertical' => __('vertical')
975 $additional_fields_html .= PMA_Util::getDropdown(
976 'disp_direction', $choices,
977 $_SESSION['tmpval']['disp_direction'],
978 $id_for_direction_dropdown, 'autosubmit'
980 unset($choices);
983 return $additional_fields_html;
985 } // end of the '_getAdditionalFieldsForTableNavigation()' function
989 * Get the headers of the results table
991 * @param array &$is_display which elements to display
992 * @param array|string $analyzed_sql the analyzed query
993 * @param array $sort_expression sort expression
994 * @param array $sort_expression_nodirection sort expression
995 * without direction
996 * @param array $sort_direction sort direction
997 * @param boolean $is_limited_display with limited operations
998 * or not
1000 * @return string html content
1002 * @access private
1004 * @see getTable()
1006 private function _getTableHeaders(
1007 &$is_display, $analyzed_sql = '',
1008 $sort_expression = '', $sort_expression_nodirection = '',
1009 $sort_direction = '', $is_limited_display = false
1012 $table_headers_html = '';
1013 // Following variable are needed for use in isset/empty or
1014 // use with array indexes/safe use in foreach
1015 $fields_meta = $this->__get('fields_meta');
1016 $highlight_columns = $this->__get('highlight_columns');
1017 $printview = $this->__get('printview');
1018 $vertical_display = $this->__get('vertical_display');
1020 // required to generate sort links that will remember whether the
1021 // "Show all" button has been clicked
1022 $sql_md5 = md5($this->__get('sql_query'));
1023 $session_max_rows = $is_limited_display
1025 : $_SESSION['tmpval']['query'][$sql_md5]['max_rows'];
1027 $direction = isset($_SESSION['tmpval']['disp_direction'])
1028 ? $_SESSION['tmpval']['disp_direction']
1029 : '';
1031 if ($analyzed_sql == '') {
1032 $analyzed_sql = array();
1035 $directionCondition = ($direction == self::DISP_DIR_HORIZONTAL)
1036 || ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED);
1038 // can the result be sorted?
1039 if ($is_display['sort_lnk'] == '1') {
1041 list($unsorted_sql_query, $drop_down_html)
1042 = $this->_getUnsortedSqlAndSortByKeyDropDown(
1043 $analyzed_sql, $sort_expression
1046 $table_headers_html .= $drop_down_html;
1050 // Output data needed for grid editing
1051 $table_headers_html .= '<input id="save_cells_at_once" type="hidden" value="'
1052 . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
1053 . '<div class="common_hidden_inputs">'
1054 . PMA_URL_getHiddenInputs(
1055 $this->__get('db'), $this->__get('table')
1057 . '</div>';
1059 // Output data needed for column reordering and show/hide column
1060 if ($this->_isSelect($analyzed_sql)) {
1061 $table_headers_html .= $this->_getDataForResettingColumnOrder();
1064 $vertical_display['emptypre'] = 0;
1065 $vertical_display['emptyafter'] = 0;
1066 $vertical_display['textbtn'] = '';
1067 $full_or_partial_text_link = null;
1069 $this->__set('vertical_display', $vertical_display);
1071 // Display options (if we are not in print view)
1072 if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
1074 $table_headers_html .= $this->_getOptionsBlock();
1076 // prepare full/partial text button or link
1077 $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
1080 // Start of form for multi-rows edit/delete/export
1081 $table_headers_html .= $this->_getFormForMultiRowOperations(
1082 $is_display['del_lnk']
1085 // 1. Set $colspan or $rowspan and generate html with full/partial
1086 // text button or link
1087 list($colspan, $rowspan, $button_html)
1088 = $this->_getFieldVisibilityParams(
1089 $directionCondition, $is_display, $full_or_partial_text_link
1092 $table_headers_html .= $button_html;
1094 // 2. Displays the fields' name
1095 // 2.0 If sorting links should be used, checks if the query is a "JOIN"
1096 // statement (see 2.1.3)
1098 // 2.0.1 Prepare Display column comments if enabled
1099 // ($GLOBALS['cfg']['ShowBrowseComments']).
1100 // Do not show comments, if using horizontalflipped mode,
1101 // because of space usage
1102 $comments_map = $this->_getTableCommentsArray($direction, $analyzed_sql);
1104 if ($GLOBALS['cfgRelation']['commwork']
1105 && $GLOBALS['cfgRelation']['mimework']
1106 && $GLOBALS['cfg']['BrowseMIME']
1107 && ! $_SESSION['tmpval']['hide_transformation']
1109 include_once './libraries/transformations.lib.php';
1110 $this->__set(
1111 'mime_map',
1112 PMA_getMIME($this->__get('db'), $this->__get('table'))
1116 // See if we have to highlight any header fields of a WHERE query.
1117 // Uses SQL-Parser results.
1118 $this->_setHighlightedColumnGlobalField($analyzed_sql);
1120 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
1122 for ($j = 0; $j < $this->__get('fields_cnt'); $j++) {
1124 // assign $i with appropriate column order
1125 $i = $col_order ? $col_order[$j] : $j;
1127 // See if this column should get highlight because it's used in the
1128 // where-query.
1129 $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
1130 || isset(
1131 $highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)])
1133 ? true
1134 : false;
1136 // 2.0 Prepare comment-HTML-wrappers for each row, if defined/enabled.
1137 $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
1139 $vertical_display = $this->__get('vertical_display');
1141 if (($is_display['sort_lnk'] == '1') && ! $is_limited_display) {
1143 list($order_link, $sorted_header_html)
1144 = $this->_getOrderLinkAndSortedHeaderHtml(
1145 $fields_meta[$i], $sort_expression,
1146 $sort_expression_nodirection, $i, $unsorted_sql_query,
1147 $session_max_rows, $direction, $comments,
1148 $sort_direction, $directionCondition, $col_visib,
1149 $col_visib[$j]
1152 $table_headers_html .= $sorted_header_html;
1154 $vertical_display['desc'][] = ' <th '
1155 . 'class="draggable'
1156 . ($condition_field ? ' condition' : '')
1157 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1158 . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
1159 } else {
1160 // 2.2 Results can't be sorted
1162 if ($directionCondition) {
1163 $table_headers_html
1164 .= $this->_getDraggableClassForNonSortableColumns(
1165 $col_visib, $col_visib[$j], $condition_field,
1166 $direction, $fields_meta[$i], $comments
1170 $vertical_display['desc'][] = ' <th '
1171 . 'class="draggable'
1172 . ($condition_field ? ' condition"' : '')
1173 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1174 . '">' . "\n" . ' '
1175 . htmlspecialchars($fields_meta[$i]->name)
1176 . "\n" . $comments . ' </th>';
1177 } // end else (2.2)
1179 $this->__set('vertical_display', $vertical_display);
1181 } // end for
1183 // Display column at rightside - checkboxes or empty column
1184 if (! $printview) {
1185 $table_headers_html .= $this->_getColumnAtRightSide(
1186 $is_display, $directionCondition, $full_or_partial_text_link,
1187 $colspan, $rowspan
1191 if ($directionCondition) {
1192 $table_headers_html .= '</tr>'
1193 . '</thead>';
1196 return $table_headers_html;
1198 } // end of the '_getTableHeaders()' function
1202 * Prepare unsorted sql query and sort by key drop down
1204 * @param array $analyzed_sql the analyzed query
1205 * @param string $sort_expression sort expression
1207 * @return array two element array - $unsorted_sql_query, $drop_down_html
1209 * @access private
1211 * @see _getTableHeaders()
1213 private function _getUnsortedSqlAndSortByKeyDropDown(
1214 $analyzed_sql, $sort_expression
1217 $drop_down_html = '';
1219 // Just as fallback
1220 $unsorted_sql_query = $this->__get('sql_query');
1221 if (isset($analyzed_sql[0]['unsorted_query'])) {
1222 $unsorted_sql_query = $analyzed_sql[0]['unsorted_query'];
1224 // Handles the case of multiple clicks on a column's header
1225 // which would add many spaces before "ORDER BY" in the
1226 // generated query.
1227 $unsorted_sql_query = trim($unsorted_sql_query);
1229 // sorting by indexes, only if it makes sense (only one table ref)
1230 if (isset($analyzed_sql)
1231 && isset($analyzed_sql[0])
1232 && isset($analyzed_sql[0]['querytype'])
1233 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
1234 && isset($analyzed_sql[0]['table_ref'])
1235 && (count($analyzed_sql[0]['table_ref']) == 1)
1237 // grab indexes data:
1238 $indexes = PMA_Index::getFromTable(
1239 $this->__get('table'),
1240 $this->__get('db')
1243 // do we have any index?
1244 if ($indexes) {
1245 $drop_down_html = $this->_getSortByKeyDropDown(
1246 $indexes, $sort_expression,
1247 $unsorted_sql_query
1252 return array($unsorted_sql_query, $drop_down_html);
1254 } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function
1258 * Prepare sort by key dropdown - html code segment
1260 * @param array $indexes the indexes of the table for sort criteria
1261 * @param string $sort_expression the sort expression
1262 * @param string $unsorted_sql_query the unsorted sql query
1264 * @return string $drop_down_html html content
1266 * @access private
1268 * @see _getTableHeaders()
1270 private function _getSortByKeyDropDown(
1271 $indexes, $sort_expression, $unsorted_sql_query
1274 $drop_down_html = '';
1276 $drop_down_html .= '<form action="sql.php" method="post">' . "\n"
1277 . PMA_URL_getHiddenInputs(
1278 $this->__get('db'), $this->__get('table')
1280 . __('Sort by key')
1281 . ': <select name="sql_query" class="autosubmit">' . "\n";
1283 $used_index = false;
1284 $local_order = (isset($sort_expression) ? $sort_expression : '');
1286 foreach ($indexes as $index) {
1288 $asc_sort = '`'
1289 . implode('` ASC, `', array_keys($index->getColumns()))
1290 . '` ASC';
1292 $desc_sort = '`'
1293 . implode('` DESC, `', array_keys($index->getColumns()))
1294 . '` DESC';
1296 $used_index = $used_index
1297 || ($local_order == $asc_sort)
1298 || ($local_order == $desc_sort);
1300 if (preg_match(
1301 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|'
1302 . 'FOR UPDATE|LOCK IN SHARE MODE))@is',
1303 $unsorted_sql_query, $my_reg
1304 )) {
1305 $unsorted_sql_query_first_part = $my_reg[1];
1306 $unsorted_sql_query_second_part = $my_reg[2];
1307 } else {
1308 $unsorted_sql_query_first_part = $unsorted_sql_query;
1309 $unsorted_sql_query_second_part = '';
1312 $drop_down_html .= '<option value="'
1313 . htmlspecialchars(
1314 $unsorted_sql_query_first_part . "\n"
1315 . ' ORDER BY ' . $asc_sort
1316 . $unsorted_sql_query_second_part
1318 . '"' . ($local_order == $asc_sort
1319 ? ' selected="selected"'
1320 : '')
1321 . '>' . htmlspecialchars($index->getName()) . ' ('
1322 . __('Ascending') . ')</option>';
1324 $drop_down_html .= '<option value="'
1325 . htmlspecialchars(
1326 $unsorted_sql_query_first_part . "\n"
1327 . ' ORDER BY ' . $desc_sort
1328 . $unsorted_sql_query_second_part
1330 . '"' . ($local_order == $desc_sort
1331 ? ' selected="selected"'
1332 : '')
1333 . '>' . htmlspecialchars($index->getName()) . ' ('
1334 . __('Descending') . ')</option>';
1337 $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query)
1338 . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None')
1339 . '</option>'
1340 . '</select>' . "\n"
1341 . '</form>' . "\n";
1343 return $drop_down_html;
1345 } // end of the '_getSortByKeyDropDown()' function
1349 * Set column span, row span and prepare html with full/partial
1350 * text button or link
1352 * @param boolean $directionCondition display direction horizontal or
1353 * horizontalflipped
1354 * @param array &$is_display which elements to display
1355 * @param string $full_or_partial_text_link full/partial link or text button
1357 * @return array 3 element array - $colspan, $rowspan, $button_html
1359 * @access private
1361 * @see _getTableHeaders()
1363 private function _getFieldVisibilityParams(
1364 $directionCondition, &$is_display, $full_or_partial_text_link
1367 $button_html = '';
1368 $colspan = $rowspan = null;
1369 $vertical_display = $this->__get('vertical_display');
1371 // 1. Displays the full/partial text button (part 1)...
1372 if ($directionCondition) {
1374 $button_html .= '<thead><tr>' . "\n";
1376 $colspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1377 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1378 ? ' colspan="4"'
1379 : '';
1381 } else {
1382 $rowspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1383 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1384 ? ' rowspan="4"'
1385 : '';
1388 // ... before the result table
1389 if ((($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
1390 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
1391 && ($is_display['text_btn'] == '1')
1394 $vertical_display['emptypre']
1395 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1396 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1398 if ($directionCondition) {
1400 $button_html .= '<th colspan="' . $this->__get('fields_cnt') . '">'
1401 . '</th>'
1402 . '</tr>'
1403 . '<tr>';
1405 // end horizontal/horizontalflipped mode
1406 } else {
1408 $span = $this->__get('num_rows') + 1 + floor(
1409 $this->__get('num_rows')
1410 / $_SESSION['tmpval']['repeat_cells']
1412 $button_html .= '<tr><th colspan="' . $span . '"></th></tr>';
1414 } // end vertical mode
1416 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1417 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1418 && ($is_display['text_btn'] == '1')
1420 // ... at the left column of the result table header if possible
1421 // and required
1423 $vertical_display['emptypre']
1424 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1425 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1427 if ($directionCondition) {
1429 $button_html .= '<th ' . $colspan . '>'
1430 . $full_or_partial_text_link . '</th>';
1431 // end horizontal/horizontalflipped mode
1433 } else {
1435 $vertical_display['textbtn']
1436 = ' <th ' . $rowspan . ' class="vmiddle">' . "\n"
1437 . ' ' . "\n"
1438 . ' </th>' . "\n";
1439 } // end vertical mode
1441 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1442 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1443 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1444 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1446 // ... elseif no button, displays empty(ies) col(s) if required
1448 $vertical_display['emptypre']
1449 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1450 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1452 if ($directionCondition) {
1454 $button_html .= '<td ' . $colspan . '></td>';
1456 // end horizontal/horizontalfipped mode
1457 } else {
1458 $vertical_display['textbtn'] = ' <td' . $rowspan .
1459 '></td>' . "\n";
1460 } // end vertical mode
1462 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
1463 && ($directionCondition)
1465 // ... elseif display an empty column if the actions links are
1466 // disabled to match the rest of the table
1467 $button_html .= '<th></th>';
1470 $this->__set('vertical_display', $vertical_display);
1472 return array($colspan, $rowspan, $button_html);
1474 } // end of the '_getFieldVisibilityParams()' function
1478 * Get table comments as array
1480 * @param boolean $direction display direction, horizontal
1481 * or horizontalflipped
1482 * @param array $analyzed_sql the analyzed query
1484 * @return array $comments_map table comments when condition true
1485 * null when condition falls
1487 * @access private
1489 * @see _getTableHeaders()
1491 private function _getTableCommentsArray($direction, $analyzed_sql)
1494 $comments_map = null;
1496 if ($GLOBALS['cfg']['ShowBrowseComments']
1497 && ($direction != self::DISP_DIR_HORIZONTAL_FLIPPED)
1499 $comments_map = array();
1500 if (isset($analyzed_sql[0])
1501 && is_array($analyzed_sql[0])
1502 && isset($analyzed_sql[0]['table_ref'])
1504 foreach ($analyzed_sql[0]['table_ref'] as $tbl) {
1505 $tb = $tbl['table_true_name'];
1506 $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb);
1507 unset($tb);
1512 return $comments_map;
1514 } // end of the '_getTableCommentsArray()' function
1518 * Set global array for store highlighted header fields
1520 * @param array $analyzed_sql the analyzed query
1522 * @return void
1524 * @access private
1526 * @see _getTableHeaders()
1528 private function _setHighlightedColumnGlobalField($analyzed_sql)
1531 $highlight_columns = array();
1532 if (isset($analyzed_sql) && isset($analyzed_sql[0])
1533 && isset($analyzed_sql[0]['where_clause_identifiers'])
1534 && is_array($analyzed_sql[0]['where_clause_identifiers'])
1536 foreach ($analyzed_sql[0]['where_clause_identifiers'] as $wci) {
1537 $highlight_columns[$wci] = 'true';
1541 $this->__set('highlight_columns', $highlight_columns);
1543 } // end of the '_setHighlightedColumnGlobalField()' function
1547 * Prepare data for column restoring and show/hide
1549 * @return string $data_html html content
1551 * @access private
1553 * @see _getTableHeaders()
1555 private function _getDataForResettingColumnOrder()
1558 $data_html = '';
1560 // generate the column order, if it is set
1561 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
1562 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
1564 if ($col_order) {
1565 $data_html .= '<input id="col_order" type="hidden" value="'
1566 . implode(',', $col_order) . '" />';
1569 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
1571 if ($col_visib) {
1572 $data_html .= '<input id="col_visib" type="hidden" value="'
1573 . implode(',', $col_visib) . '" />';
1576 // generate table create time
1577 if (! PMA_Table::isView($this->__get('db'), $this->__get('table'))) {
1578 $data_html .= '<input id="table_create_time" type="hidden" value="'
1579 . PMA_Table::sGetStatusInfo(
1580 $this->__get('db'), $this->__get('table'), 'Create_time'
1581 ) . '" />';
1584 return $data_html;
1586 } // end of the '_getDataForResettingColumnOrder()' function
1590 * Prepare option fields block
1592 * @return string $options_html html content
1594 * @access private
1596 * @see _getTableHeaders()
1598 private function _getOptionsBlock()
1601 $options_html = '';
1603 $options_html .= '<form method="post" action="sql.php" '
1604 . 'name="displayOptionsForm" '
1605 . 'id="displayOptionsForm"';
1607 $options_html .= ' class="ajax" ';
1609 $options_html .= '>';
1610 $url_params = array(
1611 'db' => $this->__get('db'),
1612 'table' => $this->__get('table'),
1613 'sql_query' => $this->__get('sql_query'),
1614 'goto' => $this->__get('goto'),
1615 'display_options_form' => 1
1618 $options_html .= PMA_URL_getHiddenInputs($url_params)
1619 . '<br />'
1620 . PMA_Util::getDivForSliderEffect(
1621 'displayoptions', __('Options')
1623 . '<fieldset>';
1625 $options_html .= '<div class="formelement">';
1626 $choices = array(
1627 'P' => __('Partial texts'),
1628 'F' => __('Full texts')
1631 // pftext means "partial or full texts" (done to reduce line lengths)
1632 $options_html .= PMA_Util::getRadioFields(
1633 'pftext', $choices,
1634 $_SESSION['tmpval']['pftext']
1636 . '</div>';
1638 if ($GLOBALS['cfgRelation']['relwork']
1639 && $GLOBALS['cfgRelation']['displaywork']
1641 $options_html .= '<div class="formelement">';
1642 $choices = array(
1643 'K' => __('Relational key'),
1644 'D' => __('Relational display column')
1647 $options_html .= PMA_Util::getRadioFields(
1648 'relational_display', $choices,
1649 $_SESSION['tmpval']['relational_display']
1651 . '</div>';
1654 $options_html .= '<div class="formelement">'
1655 . PMA_Util::getCheckbox(
1656 'display_binary', __('Show binary contents'),
1657 ! empty($_SESSION['tmpval']['display_binary']), false
1659 . '<br />'
1660 . PMA_Util::getCheckbox(
1661 'display_blob', __('Show BLOB contents'),
1662 ! empty($_SESSION['tmpval']['display_blob']), false
1664 . '<br />'
1665 . PMA_Util::getCheckbox(
1666 'display_binary_as_hex', __('Show binary contents as HEX'),
1667 ! empty($_SESSION['tmpval']['display_binary_as_hex']), false
1669 . '</div>';
1671 // I would have preferred to name this "display_transformation".
1672 // This is the only way I found to be able to keep this setting sticky
1673 // per SQL query, and at the same time have a default that displays
1674 // the transformations.
1675 $options_html .= '<div class="formelement">'
1676 . PMA_Util::getCheckbox(
1677 'hide_transformation', __('Hide browser transformation'),
1678 ! empty($_SESSION['tmpval']['hide_transformation']), false
1680 . '</div>';
1682 if (! PMA_DRIZZLE) {
1683 $options_html .= '<div class="formelement">';
1684 $choices = array(
1685 'GEOM' => __('Geometry'),
1686 'WKT' => __('Well Known Text'),
1687 'WKB' => __('Well Known Binary')
1690 $options_html .= PMA_Util::getRadioFields(
1691 'geoOption', $choices,
1692 $_SESSION['tmpval']['geoOption']
1694 . '</div>';
1697 $options_html .= '<div class="clearfloat"></div>'
1698 . '</fieldset>';
1700 $options_html .= '<fieldset class="tblFooters">'
1701 . '<input type="submit" value="' . __('Go') . '" />'
1702 . '</fieldset>'
1703 . '</div>'
1704 . '</form>';
1706 return $options_html;
1708 } // end of the '_getOptionsBlock()' function
1712 * Get full/partial text button or link
1714 * @return string html content
1716 * @access private
1718 * @see _getTableHeaders()
1720 private function _getFullOrPartialTextButtonOrLink()
1723 $url_params_full_text = array(
1724 'db' => $this->__get('db'),
1725 'table' => $this->__get('table'),
1726 'sql_query' => $this->__get('sql_query'),
1727 'goto' => $this->__get('goto'),
1728 'full_text_button' => 1
1731 if ($_SESSION['tmpval']['pftext'] == self::DISPLAY_FULL_TEXT) {
1732 // currently in fulltext mode so show the opposite link
1733 $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png';
1734 $tmp_txt = __('Partial texts');
1735 $url_params_full_text['pftext'] = self::DISPLAY_PARTIAL_TEXT;
1736 } else {
1737 $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png';
1738 $tmp_txt = __('Full texts');
1739 $url_params_full_text['pftext'] = self::DISPLAY_FULL_TEXT;
1742 $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
1743 . $tmp_txt . '" title="' . $tmp_txt . '" />';
1744 $tmp_url = 'sql.php' . PMA_URL_getCommon($url_params_full_text);
1746 return PMA_Util::linkOrButton(
1747 $tmp_url, $tmp_image, array(), false
1750 } // end of the '_getFullOrPartialTextButtonOrLink()' function
1754 * Prepare html form for multi row operations
1756 * @param string $del_lnk the delete link of current row
1758 * @return string $form_html html content
1760 * @access private
1762 * @see _getTableHeaders()
1764 private function _getFormForMultiRowOperations($del_lnk)
1767 $form_html = '';
1769 if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) {
1771 $form_html .= '<form method="post" action="tbl_row_action.php" '
1772 . 'name="resultsForm" id="resultsForm"';
1774 $form_html .= ' class="ajax" ';
1776 $form_html .= '>'
1777 . PMA_URL_getHiddenInputs(
1778 $this->__get('db'), $this->__get('table'), 1
1780 . '<input type="hidden" name="goto" value="sql.php" />';
1783 $form_html .= '<table id="table_results" class="data';
1784 $form_html .= ' ajax';
1785 $form_html .= '">';
1787 return $form_html;
1789 } // end of the '_getFormForMultiRowOperations()' function
1793 * Get comment for row
1795 * @param array $comments_map comments array
1796 * @param array $fields_meta set of field properties
1798 * @return string $comment html content
1800 * @access private
1802 * @see _getTableHeaders()
1804 private function _getCommentForRow($comments_map, $fields_meta)
1806 $comments = '';
1807 if (isset($comments_map)
1808 && isset($comments_map[$fields_meta->table])
1809 && isset($comments_map[$fields_meta->table][$fields_meta->name])
1811 $comments = '<span class="tblcomment">'
1812 . htmlspecialchars(
1813 $comments_map[$fields_meta->table][$fields_meta->name]
1815 . '</span>';
1817 return $comments;
1818 } // end of the '_getCommentForRow()' function
1822 * Prepare parameters and html for sorted table header fields
1824 * @param array $fields_meta set of field properties
1825 * @param array $sort_expression sort expression
1826 * @param array $sort_expression_nodirection sort expression without direction
1827 * @param integer $column_index the index of the column
1828 * @param string $unsorted_sql_query the unsorted sql query
1829 * @param integer $session_max_rows maximum rows resulted by sql
1830 * @param string $direction the display direction
1831 * @param string $comments comment for row
1832 * @param array $sort_direction sort direction
1833 * @param boolean $directionCondition display direction horizontal
1834 * or horizontalflipped
1835 * @param boolean $col_visib column is visible(false)
1836 * array column isn't visible(string array)
1837 * @param string $col_visib_j element of $col_visib array
1839 * @return array 2 element array - $order_link, $sorted_header_html
1841 * @access private
1843 * @see _getTableHeaders()
1845 private function _getOrderLinkAndSortedHeaderHtml(
1846 $fields_meta, $sort_expression, $sort_expression_nodirection,
1847 $column_index, $unsorted_sql_query, $session_max_rows, $direction,
1848 $comments, $sort_direction, $directionCondition, $col_visib, $col_visib_j
1851 $sorted_header_html = '';
1853 // Checks if the table name is required; it's the case
1854 // for a query with a "JOIN" statement and if the column
1855 // isn't aliased, or in queries like
1856 // SELECT `1`.`master_field` , `2`.`master_field`
1857 // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2`
1859 $sort_tbl = (isset($fields_meta->table)
1860 && strlen($fields_meta->table))
1861 ? PMA_Util::backquote(
1862 $fields_meta->table
1863 ) . '.'
1864 : '';
1866 $name_to_use_in_sort = $fields_meta->name;
1868 // Generates the orderby clause part of the query which is part
1869 // of URL
1870 list($sort_order, $order_img) = $this->_makeUrl(
1871 $sort_expression, $sort_expression_nodirection, $sort_tbl,
1872 $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
1875 if (preg_match(
1876 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|'
1877 . 'LOCK IN SHARE MODE))@is',
1878 $unsorted_sql_query, $regs3
1879 )) {
1880 $sorted_sql_query = $regs3[1] . $sort_order . $regs3[2];
1881 } else {
1882 $sorted_sql_query = $unsorted_sql_query . $sort_order;
1885 $_url_params = array(
1886 'db' => $this->__get('db'),
1887 'table' => $this->__get('table'),
1888 'sql_query' => $sorted_sql_query,
1889 'session_max_rows' => $session_max_rows
1891 $order_url = 'sql.php' . PMA_URL_getCommon($_url_params);
1893 // Displays the sorting URL
1894 // enable sort order swapping for image
1895 $order_link = $this->_getSortOrderLink(
1896 $order_img, $column_index, $direction,
1897 $fields_meta, $order_url
1900 $sorted_header_html .= $this->_getDraggableClassForSortableColumns(
1901 $col_visib, $col_visib_j, $direction,
1902 $fields_meta, $order_link, $comments
1905 return array($order_link, $sorted_header_html);
1907 } // end of the '_getOrderLinkAndSortedHeaderHtml()' function
1910 * Prepare parameters and html for sorted table header fields
1912 * @param array $sort_expression sort expression
1913 * @param array $sort_expression_nodirection sort expression without direction
1914 * @param string $sort_tbl The name of the table to which
1915 * the current column belongs to
1916 * @param string $name_to_use_in_sort The current column under
1917 * consideration
1918 * @param array $sort_direction sort direction
1919 * @param array $fields_meta set of field properties
1920 * @param integer $column_index The index number to current column
1922 * @return array 2 element array - $order_link, $sorted_header_html
1924 * @access private
1926 * @see _getOrderLinkAndSortedHeaderHtml()
1928 private function _makeUrl(
1929 $sort_expression, $sort_expression_nodirection, $sort_tbl,
1930 $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
1932 $sort_order = "";
1933 // Check if the current column is in the order by clause
1934 $is_in_sort = $this->_isInSorted(
1935 $sort_expression, $sort_expression_nodirection,
1936 $sort_tbl, $name_to_use_in_sort
1938 $current_name = $name_to_use_in_sort;
1939 if ($sort_expression_nodirection[0] == '' || !$is_in_sort) {
1940 $special_index = $sort_expression_nodirection[0] == ''
1942 : count($sort_expression_nodirection);
1943 $sort_expression_nodirection[$special_index]
1944 = PMA_Util::backquote(
1945 $current_name
1947 $sort_direction[$special_index] = (preg_match(
1948 '@time|date@i',
1949 $fields_meta->type
1950 )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
1953 $sort_expression_nodirection = array_filter($sort_expression_nodirection);
1954 foreach ($sort_expression_nodirection as $index=>$expression) {
1955 // check if this is the first clause,
1956 // if it is then we have to add "order by"
1957 $is_first_clause = ($index == 0);
1958 $name_to_use_in_sort = $expression;
1959 $sort_tbl_new = $sort_tbl;
1960 // Test to detect if the column name is a standard name
1961 // Standard name has the table name prefixed to the column name
1962 $is_standard_name = false;
1963 if (strpos($name_to_use_in_sort, '.') !== false) {
1964 $matches = explode('.', $name_to_use_in_sort);
1965 // Matches[0] has the table name
1966 // Matches[1] has the column name
1967 $name_to_use_in_sort = $matches[1];
1968 $sort_tbl_new = $matches[0];
1969 $is_standard_name = true;
1973 // $name_to_use_in_sort might contain a space due to
1974 // formatting of function expressions like "COUNT(name )"
1975 // so we remove the space in this situation
1976 $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort);
1977 $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort);
1979 // If this the first column name in the order by clause add
1980 // order by clause to the column name
1981 $query_head = $is_first_clause ? "\nORDER BY " : "";
1982 $tbl = $is_standard_name ? $sort_tbl_new : $sort_tbl;
1983 // Again a check to see if the given column is a aggregate column
1984 if (strpos($name_to_use_in_sort, '(') !== false) {
1985 $sort_order .= $query_head . $name_to_use_in_sort . ' ' ;
1986 } else {
1987 $sort_order .= $query_head . $sort_tbl_new . "."
1988 . PMA_Util::backquote(
1989 $name_to_use_in_sort
1990 ) . ' ' ;
1993 // For a special case where the code generates two dots between
1994 // column name and table name.
1995 $sort_order = preg_replace("/\.\./", ".", $sort_order);
1996 // Incase the current column name is in the order by clause
1997 // We need to generate the arrow button and related html
1998 if ($current_name == $name_to_use_in_sort && $is_in_sort) {
1999 list($sort_order, $order_img) = $this->_getSortingUrlParams(
2000 $sort_direction, $sort_order, $column_index, $index
2002 } else {
2003 $sort_order .= strtoupper($sort_direction[$index]);
2005 // Separate columns by a comma
2006 $sort_order .= ", ";
2007 unset($name_to_use_in_sort);
2009 // remove the comma from the last column name in the newly
2010 // constructed clause
2011 $sort_order = substr($sort_order, 0, strlen($sort_order)-2);
2012 if (empty($order_img)) {
2013 $order_img = '';
2015 return array($sort_order, $order_img);
2019 * Check whether the column is sorted
2021 * @param array $sort_expression sort expression
2022 * @param array $sort_expression_nodirection sort expression without direction
2023 * @param string $sort_tbl the table name
2024 * @param string $name_to_use_in_sort the sorting column name
2026 * @return boolean $is_in_sort the column sorted or not
2028 * @access private
2030 * @see _getTableHeaders()
2032 private function _isInSorted(
2033 $sort_expression, $sort_expression_nodirection, $sort_tbl,
2034 $name_to_use_in_sort
2037 $index_in_expression = 0;
2039 foreach ($sort_expression_nodirection as $index => $clause) {
2040 if (strpos($clause, '.') !== false) {
2041 $fragments = explode('.', $clause);
2042 $clause2 = $fragments[0] . "." . str_replace('`', '', $fragments[1]);
2043 } else {
2044 $clause2 = $sort_tbl . str_replace('`', '', $clause);
2046 if ($clause2 === $sort_tbl . $name_to_use_in_sort) {
2047 $index_in_expression = $index;
2048 break;
2051 if (empty($sort_expression[$index_in_expression])) {
2052 $is_in_sort = false;
2053 } else {
2054 // Field name may be preceded by a space, or any number
2055 // of characters followed by a dot (tablename.fieldname)
2056 // so do a direct comparison for the sort expression;
2057 // this avoids problems with queries like
2058 // "SELECT id, count(id)..." and clicking to sort
2059 // on id or on count(id).
2060 // Another query to test this:
2061 // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p
2062 // (and try clicking on each column's header twice)
2063 if (! empty($sort_tbl)
2064 && strpos($sort_expression_nodirection[$index_in_expression], $sort_tbl) === false
2065 && strpos($sort_expression_nodirection[$index_in_expression], '(') === false
2067 $new_sort_expression_nodirection = $sort_tbl
2068 . $sort_expression_nodirection[$index_in_expression];
2069 } else {
2070 $new_sort_expression_nodirection
2071 = $sort_expression_nodirection[$index_in_expression];
2074 //Back quotes are removed in next comparison, so remove them from value
2075 //to compare.
2076 $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort);
2078 $is_in_sort = false;
2079 $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort;
2081 if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection)
2082 || $sort_name == str_replace('`', '', $sort_expression_nodirection[$index_in_expression])
2084 $is_in_sort = true;
2088 return $is_in_sort;
2090 } // end of the '_isInSorted()' function
2094 * Get sort url paramaeters - sort order and order image
2096 * @param array $sort_direction the sort direction
2097 * @param string $sort_order the sorting order
2098 * @param integer $column_index the index of the column
2099 * @param integer $index the index of sort direction array.
2101 * @return array 2 element array - $sort_order, $order_img
2103 * @access private
2105 * @see _makeUrl()
2107 private function _getSortingUrlParams(
2108 $sort_direction, $sort_order, $column_index, $index
2111 $index2 = $index + 1;
2112 if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) {
2114 $sort_number = "<small>" . $index2 . "</small>";
2115 $sort_order .= ' ASC';
2116 $order_img = ' ' . PMA_Util::getImage(
2117 's_desc.png', __('Descending'),
2118 array('class' => "soimg$column_index", 'title' => '')
2121 $order_img .= ' ' . PMA_Util::getImage(
2122 's_asc.png', __('Ascending'),
2123 array('class' => "soimg$column_index hide", 'title' => '')
2124 ) . $sort_number;
2126 } else {
2128 $sort_number = "<small>" . $index2 . "</small>";
2129 $sort_order .= ' DESC';
2130 $order_img = ' ' . PMA_Util::getImage(
2131 's_asc.png', __('Ascending'),
2132 array('class' => "soimg$column_index", 'title' => '')
2135 $order_img .= ' ' . PMA_Util::getImage(
2136 's_desc.png', __('Descending'),
2137 array('class' => "soimg$column_index hide", 'title' => '')
2138 ) . $sort_number;
2142 return array($sort_order, $order_img);
2144 } // end of the '_getSortingUrlParams()' function
2148 * Get sort order link
2150 * @param string $order_img the sort order image
2151 * @param integer $col_index the index of the column
2152 * @param string $direction the display direction
2153 * @param array $fields_meta set of field properties
2154 * @param string $order_url the url for sort
2156 * @return string the sort order link
2158 * @access private
2160 * @see _getTableHeaders()
2162 private function _getSortOrderLink(
2163 $order_img, $col_index, $direction, $fields_meta, $order_url
2166 $order_link_params = array();
2167 if (isset($order_img) && ($order_img != '')) {
2168 if (strstr($order_img, 'asc')) {
2169 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2170 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2171 } elseif (strstr($order_img, 'desc')) {
2172 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2173 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2177 if ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_AUTO) {
2179 $GLOBALS['cfg']['HeaderFlipType']
2180 = (PMA_USR_BROWSER_AGENT == 'IE')
2181 ? self::HEADER_FLIP_TYPE_CSS
2182 : self::HEADER_FLIP_TYPE_FAKE;
2185 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED
2186 && $GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS
2188 $order_link_params['style'] = 'direction: ltr; writing-mode: tb-rl;';
2191 $order_link_content = (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2192 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE))
2193 ? PMA_Util::flipstring(
2194 htmlspecialchars($fields_meta->name),
2195 "<br />\n"
2197 : htmlspecialchars($fields_meta->name);
2199 return PMA_Util::linkOrButton(
2200 $order_url, $order_link_content . $order_img,
2201 $order_link_params, false, true
2204 } // end of the '_getSortOrderLink()' function
2208 * Prepare columns to draggable effect for sortable columns
2210 * @param boolean $col_visib the column is visible (false)
2211 * array the column is not visible (string array)
2212 * @param string $col_visib_j element of $col_visib array
2213 * @param string $direction the display direction
2214 * @param array $fields_meta set of field properties
2215 * @param string $order_link the order link
2216 * @param string $comments the comment for the column
2218 * @return string $draggable_html html content
2220 * @access private
2222 * @see _getTableHeaders()
2224 private function _getDraggableClassForSortableColumns(
2225 $col_visib, $col_visib_j, $direction, $fields_meta,
2226 $order_link, $comments
2229 $draggable_html = '<th';
2230 $th_class = array();
2231 $th_class[] = 'draggable';
2233 if ($col_visib && !$col_visib_j) {
2234 $th_class[] = 'hide';
2237 $th_class[] = 'column_heading';
2238 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
2239 $th_class[] = 'pointer';
2242 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
2243 $th_class[] = 'marker';
2246 $draggable_html .= ' class="' . implode(' ', $th_class);
2248 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2249 $draggable_html .= ' vbottom';
2252 $draggable_html .= '" data-column="' . htmlspecialchars($fields_meta->name)
2253 . '">' . $order_link . $comments . '</th>';
2255 return $draggable_html;
2257 } // end of the '_getDraggableClassForSortableColumns()' function
2261 * Prepare columns to draggable effect for non sortable columns
2263 * @param boolean $col_visib the column is visible (false)
2264 * array the column is not visible (string array)
2265 * @param string $col_visib_j element of $col_visib array
2266 * @param boolean $condition_field whether to add CSS class condition
2267 * @param string $direction the display direction
2268 * @param array $fields_meta set of field properties
2269 * @param string $comments the comment for the column
2271 * @return string $draggable_html html content
2273 * @access private
2275 * @see _getTableHeaders()
2277 private function _getDraggableClassForNonSortableColumns(
2278 $col_visib, $col_visib_j, $condition_field,
2279 $direction, $fields_meta, $comments
2282 $draggable_html = '<th';
2283 $th_class = array();
2284 $th_class[] = 'draggable';
2286 if ($col_visib && !$col_visib_j) {
2287 $th_class[] = 'hide';
2290 if ($condition_field) {
2291 $th_class[] = 'condition';
2294 $draggable_html .= ' class="' . implode(' ', $th_class);
2295 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2296 $draggable_html .= ' vbottom';
2299 $draggable_html .= '"';
2300 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2301 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS)
2303 $draggable_html .= ' style="direction: ltr; writing-mode: tb-rl;"';
2306 $draggable_html .= ' data-column="'
2307 . htmlspecialchars($fields_meta->name) . '">';
2309 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2310 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE)
2313 $draggable_html .= PMA_Util::flipstring(
2314 htmlspecialchars($fields_meta->name), '<br />'
2317 } else {
2318 $draggable_html .= htmlspecialchars($fields_meta->name);
2321 $draggable_html .= "\n" . $comments . '</th>';
2323 return $draggable_html;
2325 } // end of the '_getDraggableClassForNonSortableColumns()' function
2329 * Prepare column to show at right side - check boxes or empty column
2331 * @param array &$is_display which elements to display
2332 * @param boolean $directionCondition display direction horizontal
2333 * or horizontalflipped
2334 * @param string $full_or_partial_text_link full/partial link or text button
2335 * @param string $colspan column span of table header
2336 * @param string $rowspan row span of table header
2338 * @return string html content
2340 * @access private
2342 * @see _getTableHeaders()
2344 private function _getColumnAtRightSide(
2345 &$is_display, $directionCondition, $full_or_partial_text_link,
2346 $colspan, $rowspan
2349 $right_column_html = '';
2350 $vertical_display = $this->__get('vertical_display');
2352 // Displays the needed checkboxes at the right
2353 // column of the result table header if possible and required...
2354 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2355 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2356 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2357 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
2358 && ($is_display['text_btn'] == '1')
2361 $vertical_display['emptyafter']
2362 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2363 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2365 if ($directionCondition) {
2366 $right_column_html .= "\n"
2367 . '<th ' . $colspan . '>' . $full_or_partial_text_link
2368 . '</th>';
2370 // end horizontal/horizontalflipped mode
2371 } else {
2372 $vertical_display['textbtn'] = ' <th ' . $rowspan
2373 . ' class="vmiddle">' . "\n"
2374 . ' ' . "\n"
2375 . ' </th>' . "\n";
2376 } // end vertical mode
2377 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2378 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2379 && (($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
2380 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
2381 && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent'])
2383 // ... elseif no button, displays empty columns if required
2384 // (unless coming from Browse mode print view)
2386 $vertical_display['emptyafter']
2387 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2388 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2390 if ($directionCondition) {
2391 $right_column_html .= "\n"
2392 . '<td ' . $colspan . '></td>';
2394 // end horizontal/horizontalflipped mode
2395 } else {
2396 $vertical_display['textbtn'] = ' <td' . $rowspan
2397 . '></td>' . "\n";
2398 } // end vertical mode
2401 $this->__set('vertical_display', $vertical_display);
2403 return $right_column_html;
2405 } // end of the '_getColumnAtRightSide()' function
2409 * Prepares the display for a value
2411 * @param string $class class of table cell
2412 * @param bool $condition_field whether to add CSS class condition
2413 * @param string $value value to display
2415 * @return string the td
2417 * @access private
2419 * @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(),
2420 * _getDataCellForNonNumericAndNonBlobColumns()
2422 private function _buildValueDisplay($class, $condition_field, $value)
2424 return '<td class="left ' . $class . ($condition_field ? ' condition' : '')
2425 . '">' . $value . '</td>';
2426 } // end of the '_buildValueDisplay()' function
2430 * Prepares the display for a null value
2432 * @param string $class class of table cell
2433 * @param bool $condition_field whether to add CSS class condition
2434 * @param object $meta the meta-information about this field
2435 * @param string $align cell allignment
2437 * @return string the td
2439 * @access private
2441 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2442 * _getDataCellForGeometryColumns(),
2443 * _getDataCellForNonNumericAndNonBlobColumns()
2445 private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
2447 // the null class is needed for grid editing
2448 return '<td ' . $align . ' data-decimals="' . $meta->decimals
2449 . '" data-type="' . $meta->type . '" class="'
2450 . $this->_addClass(
2451 $class, $condition_field, $meta, ''
2453 . ' null"><i>NULL</i></td>';
2454 } // end of the '_buildNullDisplay()' function
2458 * Prepares the display for an empty value
2460 * @param string $class class of table cell
2461 * @param bool $condition_field whether to add CSS class condition
2462 * @param object $meta the meta-information about this field
2463 * @param string $align cell allignment
2465 * @return string the td
2467 * @access private
2469 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2470 * _getDataCellForGeometryColumns(),
2471 * _getDataCellForNonNumericAndNonBlobColumns()
2473 private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
2475 return '<td ' . $align . ' class="'
2476 . $this->_addClass(
2477 $class, $condition_field, $meta, ' nowrap'
2479 . '"></td>';
2480 } // end of the '_buildEmptyDisplay()' function
2484 * Adds the relevant classes.
2486 * @param string $class class of table cell
2487 * @param bool $condition_field whether to add CSS class condition
2488 * @param object $meta the meta-information about the field
2489 * @param string $nowrap avoid wrapping
2490 * @param bool $is_field_truncated is field truncated (display ...)
2491 * @param string $transformation_plugin transformation plugin.
2492 * Can also be the default function:
2493 * PMA_mimeDefaultFunction
2494 * @param string $default_function default transformation function
2496 * @return string the list of classes
2498 * @access private
2500 * @see _buildNullDisplay(), _getRowData()
2502 private function _addClass(
2503 $class, $condition_field, $meta, $nowrap, $is_field_truncated = false,
2504 $transformation_plugin = '', $default_function = ''
2507 // Define classes to be added to this data field based on the type of data
2508 $enum_class = '';
2509 if (strpos($meta->flags, 'enum') !== false) {
2510 $enum_class = ' enum';
2513 $set_class = '';
2514 if (strpos($meta->flags, 'set') !== false) {
2515 $set_class = ' set';
2518 $bit_class = '';
2519 if (strpos($meta->type, 'bit') !== false) {
2520 $bit_class = ' bit';
2523 $mime_type_class = '';
2524 if (isset($meta->mimetype)) {
2525 $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype);
2528 return $class . ($condition_field ? ' condition' : '') . $nowrap
2529 . ' ' . ($is_field_truncated ? ' truncated' : '')
2530 . ($transformation_plugin != $default_function ? ' transformed' : '')
2531 . $enum_class . $set_class . $bit_class . $mime_type_class;
2533 } // end of the '_addClass()' function
2537 * Prepare the body of the results table
2539 * @param integer &$dt_result the link id associated to the query
2540 * which results have to be displayed
2541 * @param array &$is_display which elements to display
2542 * @param array $map the list of relations
2543 * @param array $analyzed_sql the analyzed query
2544 * @param boolean $is_limited_display with limited operations or not
2546 * @return string $table_body_html html content
2548 * @global array $row current row data
2550 * @access private
2552 * @see getTable()
2554 private function _getTableBody(
2555 &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false
2558 global $row; // mostly because of browser transformations,
2559 // to make the row-data accessible in a plugin
2561 $table_body_html = '';
2563 // query without conditions to shorten URLs when needed, 200 is just
2564 // guess, it should depend on remaining URL length
2565 $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql);
2567 $vertical_display = $this->__get('vertical_display');
2569 if (! is_array($map)) {
2570 $map = array();
2573 $row_no = 0;
2574 $vertical_display['edit'] = array();
2575 $vertical_display['copy'] = array();
2576 $vertical_display['delete'] = array();
2577 $vertical_display['data'] = array();
2578 $vertical_display['row_delete'] = array();
2579 $this->__set('vertical_display', $vertical_display);
2581 // name of the class added to all grid editable elements;
2582 // if we don't have all the columns of a unique key in the result set,
2583 // do not permit grid editing
2584 if ($is_limited_display || ! $this->__get('editable')) {
2585 $grid_edit_class = '';
2586 } else {
2587 switch ($GLOBALS['cfg']['GridEditing']) {
2588 case 'double-click':
2589 // trying to reduce generated HTML by using shorter
2590 // classes like click1 and click2
2591 $grid_edit_class = 'grid_edit click2';
2592 break;
2593 case 'click':
2594 $grid_edit_class = 'grid_edit click1';
2595 break;
2596 case 'disabled':
2597 $grid_edit_class = '';
2598 break;
2602 // prepare to get the column order, if available
2603 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
2605 // Correction University of Virginia 19991216 in the while below
2606 // Previous code assumed that all tables have keys, specifically that
2607 // the phpMyAdmin GUI should support row delete/edit only for such
2608 // tables.
2609 // Although always using keys is arguably the prescribed way of
2610 // defining a relational table, it is not required. This will in
2611 // particular be violated by the novice.
2612 // We want to encourage phpMyAdmin usage by such novices. So the code
2613 // below has been changed to conditionally work as before when the
2614 // table being displayed has one or more keys; but to display
2615 // delete/edit options correctly for tables without keys.
2617 $odd_row = true;
2618 $directionCondition
2619 = ($_SESSION['tmpval']['disp_direction']
2620 == self::DISP_DIR_HORIZONTAL)
2621 || ($_SESSION['tmpval']['disp_direction']
2622 == self::DISP_DIR_HORIZONTAL_FLIPPED);
2624 while ($row = $GLOBALS['dbi']->fetchRow($dt_result)) {
2626 // "vertical display" mode stuff
2627 $table_body_html .= $this->_getVerticalDisplaySupportSegments(
2628 $vertical_display, $row_no, $directionCondition
2631 $alternating_color_class = ($odd_row ? 'odd' : 'even');
2632 $odd_row = ! $odd_row;
2634 if ($directionCondition) {
2635 // pointer code part
2636 $table_body_html .= '<tr class="' . $alternating_color_class . '">';
2639 // 1. Prepares the row
2640 // 1.1 Results from a "SELECT" statement -> builds the
2641 // WHERE clause to use in links (a unique key if possible)
2643 * @todo $where_clause could be empty, for example a table
2644 * with only one field and it's a BLOB; in this case,
2645 * avoid to display the delete and edit links
2647 list($where_clause, $clause_is_unique, $condition_array)
2648 = PMA_Util::getUniqueCondition(
2649 $dt_result,
2650 $this->__get('fields_cnt'),
2651 $this->__get('fields_meta'),
2652 $row
2654 $where_clause_html = urlencode($where_clause);
2656 // In print view these variable needs toinitialized
2657 $del_url = $del_query = $del_str = $edit_anchor_class
2658 = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
2660 // 1.2 Defines the URLs for the modify/delete link(s)
2662 if (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2663 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
2665 // We need to copy the value
2666 // or else the == 'both' check will always return true
2668 if ($GLOBALS['cfg']['ActionLinksMode'] === self::POSITION_BOTH) {
2669 $iconic_spacer = '<div class="nowrap">';
2670 } else {
2671 $iconic_spacer = '';
2674 // 1.2.1 Modify link(s) - update row case
2675 if ($is_display['edit_lnk'] == self::UPDATE_ROW) {
2677 list($edit_url, $copy_url, $edit_str, $copy_str,
2678 $edit_anchor_class)
2679 = $this->_getModifiedLinks(
2680 $where_clause,
2681 $clause_is_unique, $url_sql_query
2684 } // end if (1.2.1)
2686 // 1.2.2 Delete/Kill link(s)
2687 if (($is_display['del_lnk'] == self::DELETE_ROW)
2688 || ($is_display['del_lnk'] == self::KILL_PROCESS)
2691 list($del_query, $del_url, $del_str, $js_conf)
2692 = $this->_getDeleteAndKillLinks(
2693 $where_clause, $clause_is_unique,
2694 $url_sql_query, $is_display['del_lnk'],
2695 $row
2698 } // end if (1.2.2)
2700 // 1.3 Displays the links at left if required
2701 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2702 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2703 && $directionCondition
2706 $table_body_html .= $this->_getPlacedLinks(
2707 self::POSITION_LEFT, $del_url, $is_display, $row_no,
2708 $where_clause, $where_clause_html, $condition_array,
2709 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2710 $edit_str, $copy_str, $del_str, $js_conf
2713 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
2714 && $directionCondition
2717 $table_body_html .= $this->_getPlacedLinks(
2718 self::POSITION_NONE, $del_url, $is_display, $row_no,
2719 $where_clause, $where_clause_html, $condition_array,
2720 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2721 $edit_str, $copy_str, $del_str, $js_conf
2724 } // end if (1.3)
2725 } // end if (1)
2727 // 2. Displays the rows' values
2728 $table_body_html .= $this->_getRowValues(
2729 $dt_result, $row, $row_no, $col_order, $map,
2730 $grid_edit_class, $col_visib, $where_clause,
2731 $url_sql_query, $analyzed_sql, $directionCondition
2734 // 3. Displays the modify/delete links on the right if required
2735 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2736 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2737 && $directionCondition
2740 $table_body_html .= $this->_getPlacedLinks(
2741 self::POSITION_RIGHT, $del_url, $is_display, $row_no,
2742 $where_clause, $where_clause_html, $condition_array,
2743 $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class,
2744 $edit_str, $copy_str, $del_str, $js_conf
2747 } // end if (3)
2749 if ($directionCondition) {
2750 $table_body_html .= '</tr>';
2751 } // end if
2753 // 4. Gather links of del_urls and edit_urls in an array for later
2754 // output
2755 $this->_gatherLinksForLaterOutputs(
2756 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
2757 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url,
2758 $edit_str, $copy_url, $copy_str, $alternating_color_class,
2759 $condition_array
2762 $table_body_html .= $directionCondition ? "\n" : '';
2763 $row_no++;
2765 } // end while
2767 return $table_body_html;
2769 } // end of the '_getTableBody()' function
2773 * Get the values for one data row
2775 * @param integer &$dt_result the link id associated to the query
2776 * which results have to be displayed
2777 * @param array $row current row data
2778 * @param integer $row_no the index of current row
2779 * @param array $col_order the column order
2780 * false when a property not found
2781 * @param array $map the list of relations
2782 * @param string $grid_edit_class the class for all editable columns
2783 * @param boolean $col_visib column is visible(false)
2784 * array column isn't visible(string array)
2785 * @param string $where_clause where clause
2786 * @param string $url_sql_query the analyzed sql query
2787 * @param array $analyzed_sql the analyzed query
2788 * @param boolean $directionCondition the directional condition
2790 * @return string $row_values_html html content
2792 * @access private
2794 * @see _getTableBody()
2796 private function _getRowValues(
2797 &$dt_result, $row, $row_no, $col_order, $map,
2798 $grid_edit_class, $col_visib, $where_clause,
2799 $url_sql_query, $analyzed_sql, $directionCondition
2802 $row_values_html = '';
2804 // Following variable are needed for use in isset/empty or
2805 // use with array indexes/safe use in foreach
2806 $sql_query = $this->__get('sql_query');
2807 $fields_meta = $this->__get('fields_meta');
2808 $highlight_columns = $this->__get('highlight_columns');
2809 $mime_map = $this->__get('mime_map');
2811 $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order);
2813 for ($currentColumn = 0;
2814 $currentColumn < $this->__get('fields_cnt');
2815 ++$currentColumn) {
2817 // assign $i with appropriate column order
2818 $i = $col_order ? $col_order[$currentColumn] : $currentColumn;
2820 $meta = $fields_meta[$i];
2821 $not_null_class = $meta->not_null ? 'not_null' : '';
2822 $relation_class = isset($map[$meta->name]) ? 'relation' : '';
2823 $hide_class = ($col_visib && ! $col_visib[$currentColumn]
2824 // hide per <td> only if the display dir is not vertical
2825 && ($_SESSION['tmpval']['disp_direction']
2826 != self::DISP_DIR_VERTICAL))
2827 ? 'hide'
2828 : '';
2830 // handle datetime-related class, for grid editing
2831 $field_type_class
2832 = $this->_getClassForDateTimeRelatedFields($meta->type);
2834 $is_field_truncated = false;
2835 // combine all the classes applicable to this column's value
2836 $class = $this->_getClassesForColumn(
2837 $grid_edit_class, $not_null_class, $relation_class,
2838 $hide_class, $field_type_class, $row_no
2841 // See if this column should get highlight because it's used in the
2842 // where-query.
2843 $condition_field = (isset($highlight_columns)
2844 && (isset($highlight_columns[$meta->name])
2845 || isset($highlight_columns[PMA_Util::backquote($meta->name)])))
2846 ? true
2847 : false;
2849 // Wrap MIME-transformations. [MIME]
2850 $default_function = '_mimeDefaultFunction'; // default_function
2851 $transformation_plugin = $default_function;
2852 $transform_options = array();
2854 if ($GLOBALS['cfgRelation']['mimework']
2855 && $GLOBALS['cfg']['BrowseMIME']
2858 if (isset($mime_map[$meta->name]['mimetype'])
2859 && isset($mime_map[$meta->name]['transformation'])
2860 && !empty($mime_map[$meta->name]['transformation'])
2863 $file = $mime_map[$meta->name]['transformation'];
2864 $include_file = 'libraries/plugins/transformations/' . $file;
2866 if (file_exists($include_file)) {
2868 include_once $include_file;
2869 $class_name = str_replace('.class.php', '', $file);
2870 // todo add $plugin_manager
2871 $plugin_manager = null;
2872 $transformation_plugin = new $class_name(
2873 $plugin_manager
2876 $transform_options = PMA_Transformation_getOptions(
2877 isset($mime_map[$meta->name]
2878 ['transformation_options']
2880 ? $mime_map[$meta->name]
2881 ['transformation_options']
2882 : ''
2885 $meta->mimetype = str_replace(
2886 '_', '/',
2887 $mime_map[$meta->name]['mimetype']
2890 } // end if file_exists
2891 } // end if transformation is set
2892 } // end if mime/transformation works.
2894 $_url_params = array(
2895 'db' => $this->__get('db'),
2896 'table' => $this->__get('table'),
2897 'where_clause' => $where_clause,
2898 'transform_key' => $meta->name,
2901 if (! empty($sql_query)) {
2902 $_url_params['sql_query'] = $url_sql_query;
2905 $transform_options['wrapper_link']
2906 = PMA_URL_getCommon($_url_params);
2908 $vertical_display = $this->__get('vertical_display');
2910 // Check whether the field needs to display with syntax highlighting
2912 if (! empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)])
2913 && (trim($row[$i]) != '')
2915 $row[$i] = PMA_Util::formatSql($row[$i]);
2916 include_once $this->transformation_info
2917 [strtolower($this->__get('db'))]
2918 [strtolower($this->__get('table'))]
2919 [strtolower($meta->name)][0];
2920 $transformation_plugin = new $this->transformation_info
2921 [strtolower($this->__get('db'))]
2922 [strtolower($this->__get('table'))]
2923 [strtolower($meta->name)][1](null);
2925 $transform_options = PMA_Transformation_getOptions(
2926 isset($mime_map[$meta->name]['transformation_options'])
2927 ? $mime_map[$meta->name]['transformation_options']
2928 : ''
2931 $meta->mimetype = str_replace(
2932 '_', '/',
2933 $this->transformation_info[strtolower($this->__get('db'))]
2934 [strtolower($this->__get('table'))]
2935 [strtolower($meta->name)][2]
2940 // Check for the predefined fields need to show as link in schemas
2941 include_once 'libraries/special_schema_links.lib.php';
2943 if (isset($GLOBALS['special_schema_links'])
2944 && (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)]))
2947 $linking_url = $this->_getSpecialLinkUrl(
2948 $row[$i], $row_info, strtolower($meta->name)
2950 include_once
2951 "libraries/plugins/transformations/Text_Plain_Link.class.php";
2952 $transformation_plugin = new Text_Plain_Link(null);
2954 $transform_options = array(
2955 0 => $linking_url,
2956 2 => true
2959 $meta->mimetype = str_replace(
2960 '_', '/',
2961 'Text/Plain'
2966 if ($meta->numeric == 1) {
2967 // n u m e r i c
2969 $vertical_display['data'][$row_no][$i]
2970 = $this->_getDataCellForNumericColumns(
2971 $row[$i], $class, $condition_field, $meta, $map,
2972 $is_field_truncated, $analyzed_sql,
2973 $transformation_plugin, $default_function,
2974 $transform_options
2977 } elseif (stristr($meta->type, self::BLOB_FIELD)) {
2978 // b l o b
2980 // PMA_mysql_fetch_fields returns BLOB in place of
2981 // TEXT fields type so we have to ensure it's really a BLOB
2982 $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $i);
2984 $vertical_display['data'][$row_no][$i]
2985 = $this->_getDataCellForBlobColumns(
2986 $row[$i], $class, $meta, $_url_params, $field_flags,
2987 $transformation_plugin, $default_function,
2988 $transform_options, $condition_field, $is_field_truncated
2991 } elseif ($meta->type == self::GEOMETRY_FIELD) {
2992 // g e o m e t r y
2994 // Remove 'grid_edit' from $class as we do not allow to
2995 // inline-edit geometry data.
2996 $class = str_replace('grid_edit', '', $class);
2998 $vertical_display['data'][$row_no][$i]
2999 = $this->_getDataCellForGeometryColumns(
3000 $row[$i], $class, $meta, $map, $_url_params,
3001 $condition_field, $transformation_plugin,
3002 $default_function, $transform_options,
3003 $is_field_truncated, $analyzed_sql
3006 } else {
3007 // n o t n u m e r i c a n d n o t B L O B
3009 $vertical_display['data'][$row_no][$i]
3010 = $this->_getDataCellForNonNumericAndNonBlobColumns(
3011 $row[$i], $class, $meta, $map, $_url_params,
3012 $condition_field, $transformation_plugin,
3013 $default_function, $transform_options,
3014 $is_field_truncated, $analyzed_sql, $dt_result, $i
3019 // output stored cell
3020 if ($directionCondition) {
3021 $row_values_html
3022 .= $vertical_display['data'][$row_no][$i];
3025 if (isset($vertical_display['rowdata'][$i][$row_no])) {
3026 $vertical_display['rowdata'][$i][$row_no]
3027 .= $vertical_display['data'][$row_no][$i];
3028 } else {
3029 $vertical_display['rowdata'][$i][$row_no]
3030 = $vertical_display['data'][$row_no][$i];
3033 $this->__set('vertical_display', $vertical_display);
3035 } // end for
3037 return $row_values_html;
3039 } // end of the '_getRowValues()' function
3043 * Gather delete/edit url links for further outputs
3045 * @param integer $row_no the index of current row
3046 * @param array $is_display which elements to display
3047 * @param string $where_clause where clause
3048 * @param string $where_clause_html the html encoded where clause
3049 * @param string $js_conf text for the JS confirmation
3050 * @param string $del_url the url for delete row
3051 * @param string $del_query the query for delete row
3052 * @param string $del_str the label for delete row
3053 * @param string $edit_anchor_class the class for html element for edit
3054 * @param string $edit_url the url for edit row
3055 * @param string $edit_str the label for edit row
3056 * @param string $copy_url the url for copy row
3057 * @param string $copy_str the label for copy row
3058 * @param string $alternating_color_class class for display two colors in rows
3059 * @param array $condition_array array of keys
3060 * (primary,unique,condition)
3062 * @return void
3064 * @access private
3066 * @see _getTableBody()
3068 private function _gatherLinksForLaterOutputs(
3069 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
3070 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, $edit_str,
3071 $copy_url, $copy_str, $alternating_color_class, $condition_array
3074 $vertical_display = $this->__get('vertical_display');
3076 if (! isset($vertical_display['edit'][$row_no])) {
3077 $vertical_display['edit'][$row_no] = '';
3078 $vertical_display['copy'][$row_no] = '';
3079 $vertical_display['delete'][$row_no] = '';
3080 $vertical_display['row_delete'][$row_no] = '';
3083 $vertical_class = ' row_' . $row_no;
3084 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
3085 $vertical_class .= ' vpointer';
3088 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
3089 $vertical_class .= ' vmarker';
3092 if (!empty($del_url)
3093 && ($is_display['del_lnk'] != self::KILL_PROCESS)
3096 $vertical_display['row_delete'][$row_no]
3097 .= $this->_getCheckboxForMultiRowSubmissions(
3098 $del_url, $is_display, $row_no, $where_clause_html,
3099 $condition_array, $del_query, '[%_PMA_CHECKBOX_DIR_%]',
3100 $alternating_color_class . $vertical_class
3103 } else {
3104 unset($vertical_display['row_delete'][$row_no]);
3107 if (isset($edit_url)) {
3109 $vertical_display['edit'][$row_no] .= $this->_getEditLink(
3110 $edit_url,
3111 $alternating_color_class . ' ' . $edit_anchor_class
3112 . $vertical_class, $edit_str,
3113 $where_clause,
3114 $where_clause_html
3117 } else {
3118 unset($vertical_display['edit'][$row_no]);
3121 if (isset($copy_url)) {
3123 $vertical_display['copy'][$row_no] .= $this->_getCopyLink(
3124 $copy_url, $copy_str, $where_clause, $where_clause_html,
3125 $alternating_color_class . $vertical_class
3128 } else {
3129 unset($vertical_display['copy'][$row_no]);
3132 if (isset($del_url)) {
3134 if (! isset($js_conf)) {
3135 $js_conf = '';
3138 $vertical_display['delete'][$row_no]
3139 .= $this->_getDeleteLink(
3140 $del_url, $del_str, $js_conf,
3141 $alternating_color_class . $vertical_class
3144 } else {
3145 unset($vertical_display['delete'][$row_no]);
3148 $this->__set('vertical_display', $vertical_display);
3150 } // end of the '_gatherLinksForLaterOutputs()' function
3154 * Get link for display special schema links
3156 * @param string $column_value column value
3157 * @param array $row_info information about row
3158 * @param string $field_name column name
3160 * @return string generated link
3162 private function _getSpecialLinkUrl($column_value, $row_info, $field_name)
3165 $linking_url_params = array();
3166 $link_relations = $GLOBALS['special_schema_links']
3167 [strtolower($this->__get('db'))]
3168 [strtolower($this->__get('table'))]
3169 [$field_name];
3171 if (! is_array($link_relations['link_param'])) {
3172 $linking_url_params[$link_relations['link_param']] = $column_value;
3173 } else {
3174 // Consider only the case of creating link for column field
3175 // sql query that needs to be passed as url param
3176 $sql = 'SELECT `' . $column_value . '` FROM `'
3177 . $row_info[$link_relations['link_param'][1]] . '`.`'
3178 . $row_info[$link_relations['link_param'][2]] . '`';
3179 $linking_url_params[$link_relations['link_param'][0]] = $sql;
3183 if (! empty($link_relations['link_dependancy_params'])) {
3185 foreach ($link_relations['link_dependancy_params'] as $new_param) {
3187 // If param_info is an array, set the key and value
3188 // from that array
3189 if (is_array($new_param['param_info'])) {
3190 $linking_url_params[$new_param['param_info'][0]]
3191 = $new_param['param_info'][1];
3192 } else {
3194 $linking_url_params[$new_param['param_info']]
3195 = $row_info[strtolower($new_param['column_name'])];
3197 // Special case 1 - when executing routines, according
3198 // to the type of the routine, url param changes
3199 if (!empty($row_info['routine_type'])) {
3200 $lowerRoutineType = strtolower($row_info['routine_type']);
3201 if ($lowerRoutineType == self::ROUTINE_PROCEDURE
3202 || $lowerRoutineType == self::ROUTINE_FUNCTION
3204 $linking_url_params['edit_item'] = 1;
3213 return $link_relations['default_page']
3214 . PMA_URL_getCommon($linking_url_params);
3220 * Prepare row information for display special links
3222 * @param array $row current row data
3223 * @param array $col_order the column order
3225 * @return array $row_info associative array with column nama -> value
3227 private function _getRowInfoForSpecialLinks($row, $col_order)
3230 $row_info = array();
3231 $fields_meta = $this->__get('fields_meta');
3233 for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) {
3234 $m = $col_order ? $col_order[$n] : $n;
3235 $row_info[strtolower($fields_meta[$m]->name)] = $row[$m];
3238 return $row_info;
3244 * Get url sql query without conditions to shorten URLs
3246 * @param array $analyzed_sql analyzed query
3248 * @return string $url_sql analyzed sql query
3250 * @access private
3252 * @see _getTableBody()
3254 private function _getUrlSqlQuery($analyzed_sql)
3257 if (isset($analyzed_sql)
3258 && isset($analyzed_sql[0])
3259 && isset($analyzed_sql[0]['querytype'])
3260 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
3261 && (strlen($this->__get('sql_query')) > 200)
3264 $url_sql_query = 'SELECT ';
3265 if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
3266 $url_sql_query .= ' DISTINCT ';
3269 $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
3270 if (!empty($analyzed_sql[0]['from_clause'])) {
3271 $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
3274 return $url_sql_query;
3277 return $this->__get('sql_query');
3279 } // end of the '_getUrlSqlQuery()' function
3283 * Get column order and column visibility
3285 * @param array $analyzed_sql the analyzed query
3287 * @return array 2 element array - $col_order, $col_visib
3289 * @access private
3291 * @see _getTableBody()
3293 private function _getColumnParams($analyzed_sql)
3295 if ($this->_isSelect($analyzed_sql)) {
3296 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
3297 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
3298 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
3299 } else {
3300 $col_order = false;
3301 $col_visib = false;
3304 return array($col_order, $col_visib);
3305 } // end of the '_getColumnParams()' function
3309 * Prepare vertical display mode necessay HTML stuff
3311 * @param array $vertical_display informations used with vertical
3312 * display mode
3313 * @param integer $row_no the index of current row
3314 * @param boolean $directionCondition the directional condition
3316 * @return string $vertical_disp_html html content
3318 * @access private
3320 * @see _getTableBody()
3322 private function _getVerticalDisplaySupportSegments(
3323 $vertical_display, $row_no, $directionCondition
3326 $support_html = '';
3328 if ((($row_no != 0) && ($_SESSION['tmpval']['repeat_cells'] != 0))
3329 && !($row_no % $_SESSION['tmpval']['repeat_cells'])
3330 && $directionCondition
3333 $support_html .= '<tr>' . "\n";
3335 if ($vertical_display['emptypre'] > 0) {
3337 $support_html .= ' <th colspan="'
3338 . $vertical_display['emptypre'] . '">'
3339 . "\n" . ' &nbsp;</th>' . "\n";
3341 } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
3342 $support_html .= ' <th></th>' . "\n";
3345 foreach ($vertical_display['desc'] as $val) {
3346 $support_html .= $val;
3349 if ($vertical_display['emptyafter'] > 0) {
3350 $support_html
3351 .= ' <th colspan="' . $vertical_display['emptyafter']
3352 . '">'
3353 . "\n" . ' &nbsp;</th>' . "\n";
3355 $support_html .= '</tr>' . "\n";
3356 } // end if
3358 return $support_html;
3360 } // end of the '_getVerticalDisplaySupportSegments()' function
3364 * Get modified links
3366 * @param string $where_clause the where clause of the sql
3367 * @param boolean $clause_is_unique the unique condition of clause
3368 * @param string $url_sql_query the analyzed sql query
3370 * @return array 5 element array - $edit_url, $copy_url,
3371 * $edit_str, $copy_str, $edit_anchor_class
3373 * @access private
3375 * @see _getTableBody()
3377 private function _getModifiedLinks(
3378 $where_clause, $clause_is_unique, $url_sql_query
3381 $_url_params = array(
3382 'db' => $this->__get('db'),
3383 'table' => $this->__get('table'),
3384 'where_clause' => $where_clause,
3385 'clause_is_unique' => $clause_is_unique,
3386 'sql_query' => $url_sql_query,
3387 'goto' => 'sql.php',
3390 $edit_url = 'tbl_change.php'
3391 . PMA_URL_getCommon(
3392 $_url_params + array('default_action' => 'update')
3395 $copy_url = 'tbl_change.php'
3396 . PMA_URL_getCommon(
3397 $_url_params + array('default_action' => 'insert')
3400 $edit_str = $this->_getActionLinkContent(
3401 'b_edit.png', __('Edit')
3403 $copy_str = $this->_getActionLinkContent(
3404 'b_insrow.png', __('Copy')
3407 // Class definitions required for grid editing jQuery scripts
3408 $edit_anchor_class = "edit_row_anchor";
3409 if ( $clause_is_unique == 0) {
3410 $edit_anchor_class .= ' nonunique';
3413 return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
3415 } // end of the '_getModifiedLinks()' function
3419 * Get delete and kill links
3421 * @param string $where_clause the where clause of the sql
3422 * @param boolean $clause_is_unique the unique condition of clause
3423 * @param string $url_sql_query the analyzed sql query
3424 * @param string $del_lnk the delete link of current row
3425 * @param array $row the current row
3427 * @return array 4 element array - $del_query,
3428 * $del_url, $del_str, $js_conf
3430 * @access private
3432 * @see _getTableBody()
3434 private function _getDeleteAndKillLinks(
3435 $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row
3438 $goto = $this->__get('goto');
3440 if ($del_lnk == self::DELETE_ROW) { // delete row case
3442 $_url_params = array(
3443 'db' => $this->__get('db'),
3444 'table' => $this->__get('table'),
3445 'sql_query' => $url_sql_query,
3446 'message_to_show' => __('The row has been deleted.'),
3447 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto),
3450 $lnk_goto = 'sql.php' . PMA_URL_getCommon($_url_params, 'text');
3452 $del_query = 'DELETE FROM '
3453 . PMA_Util::backquote($this->__get('db')) . '.'
3454 . PMA_Util::backquote($this->__get('table'))
3455 . ' WHERE ' . $where_clause .
3456 ($clause_is_unique ? '' : ' LIMIT 1');
3458 $_url_params = array(
3459 'db' => $this->__get('db'),
3460 'table' => $this->__get('table'),
3461 'sql_query' => $del_query,
3462 'message_to_show' => __('The row has been deleted.'),
3463 'goto' => $lnk_goto,
3465 $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
3467 $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('db')) . '.'
3468 . PMA_jsFormat($this->__get('table'))
3469 . ' WHERE ' . PMA_jsFormat($where_clause, false)
3470 . ($clause_is_unique ? '' : ' LIMIT 1');
3472 $del_str = $this->_getActionLinkContent('b_drop.png', __('Delete'));
3474 } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case
3476 $_url_params = array(
3477 'db' => $this->__get('db'),
3478 'table' => $this->__get('table'),
3479 'sql_query' => $url_sql_query,
3480 'goto' => 'index.php',
3483 $lnk_goto = 'sql.php'
3484 . PMA_URL_getCommon(
3485 $_url_params, 'text'
3488 $_url_params = array(
3489 'db' => 'mysql',
3490 'sql_query' => 'KILL ' . $row[0],
3491 'goto' => $lnk_goto,
3494 $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
3495 $del_query = 'KILL ' . $row[0];
3496 $js_conf = 'KILL ' . $row[0];
3497 $del_str = PMA_Util::getIcon(
3498 'b_drop.png', __('Kill')
3502 return array($del_query, $del_url, $del_str, $js_conf);
3504 } // end of the '_getDeleteAndKillLinks()' function
3508 * Get content inside the table row action links (Edit/Copy/Delete)
3510 * @param string $icon The name of the file to get
3511 * @param string $display_text The text displaying after the image icon
3513 * @return string
3515 * @access private
3517 * @see _getModifiedLinks(), _getDeleteAndKillLinks()
3519 private function _getActionLinkContent($icon, $display_text)
3522 $linkContent = '';
3524 if (isset($GLOBALS['cfg']['RowActionType'])
3525 && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_ICONS
3528 $linkContent .= '<span class="nowrap">'
3529 . PMA_Util::getImage(
3530 $icon, $display_text
3532 . '</span>';
3534 } else if (isset($GLOBALS['cfg']['RowActionType'])
3535 && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_TEXT
3538 $linkContent .= '<span class="nowrap">' . $display_text . '</span>';
3540 } else {
3542 $linkContent .= PMA_Util::getIcon(
3543 $icon, $display_text
3548 return $linkContent;
3554 * Prepare placed links
3556 * @param string $dir the direction of links should place
3557 * @param string $del_url the url for delete row
3558 * @param array $is_display which elements to display
3559 * @param integer $row_no the index of current row
3560 * @param string $where_clause the where clause of the sql
3561 * @param string $where_clause_html the html encoded where clause
3562 * @param array $condition_array array of keys (primary, unique, condition)
3563 * @param string $del_query the query for delete row
3564 * @param string $dir_letter the letter denoted the direction
3565 * @param string $edit_url the url for edit row
3566 * @param string $copy_url the url for copy row
3567 * @param string $edit_anchor_class the class for html element for edit
3568 * @param string $edit_str the label for edit row
3569 * @param string $copy_str the label for copy row
3570 * @param string $del_str the label for delete row
3571 * @param string $js_conf text for the JS confirmation
3573 * @return string html content
3575 * @access private
3577 * @see _getTableBody()
3579 private function _getPlacedLinks(
3580 $dir, $del_url, $is_display, $row_no, $where_clause, $where_clause_html,
3581 $condition_array, $del_query, $dir_letter, $edit_url, $copy_url,
3582 $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
3585 if (! isset($js_conf)) {
3586 $js_conf = '';
3589 return $this->_getCheckboxAndLinks(
3590 $dir, $del_url, $is_display,
3591 $row_no, $where_clause, $where_clause_html, $condition_array,
3592 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
3593 $edit_str, $copy_str, $del_str, $js_conf
3596 } // end of the '_getPlacedLinks()' function
3600 * Get the combined classes for a column
3602 * @param string $grid_edit_class the class for all editable columns
3603 * @param string $not_null_class the class for not null columns
3604 * @param string $relation_class the class for relations in a column
3605 * @param string $hide_class the class for visibility of a column
3606 * @param string $field_type_class the class related to type of the field
3607 * @param integer $row_no the row index
3609 * @return string $class the combined classes
3611 * @access private
3613 * @see _getTableBody()
3615 private function _getClassesForColumn(
3616 $grid_edit_class, $not_null_class, $relation_class,
3617 $hide_class, $field_type_class, $row_no
3620 $printview = $this->__get('printview');
3622 $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' '
3623 . $relation_class . ' ' . $hide_class . ' ' . $field_type_class;
3625 $disp_direction = $_SESSION['tmpval']['disp_direction'];
3626 if (($disp_direction == self::DISP_DIR_VERTICAL)
3627 && (! isset($printview) || ($printview != '1'))
3629 // the row number corresponds to a data row, not HTML table row
3630 $class .= ' row_' . $row_no;
3631 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
3632 $class .= ' vpointer';
3635 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
3636 $class .= ' vmarker';
3640 return $class;
3642 } // end of the '_getClassesForColumn()' function
3646 * Get class for datetime related fields
3648 * @param string $type the type of the column field
3650 * @return string $field_type_class the class for the column
3652 * @access private
3654 * @see _getTableBody()
3656 private function _getClassForDateTimeRelatedFields($type)
3658 if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD)
3659 || ($type == self::DATETIME_FIELD)
3661 $field_type_class = 'datetimefield';
3662 } elseif ($type == self::DATE_FIELD) {
3663 $field_type_class = 'datefield';
3664 } elseif ($type == self::TIME_FIELD) {
3665 $field_type_class = 'timefield';
3666 } else {
3667 $field_type_class = '';
3669 return $field_type_class;
3670 } // end of the '_getClassForDateTimeRelatedFields()' function
3674 * Prepare data cell for numeric type fields
3676 * @param string $column the relevant column in data row
3677 * @param string $class the html class for column
3678 * @param boolean $condition_field the column should highlighted
3679 * or not
3680 * @param object $meta the meta-information about this
3681 * field
3682 * @param array $map the list of relations
3683 * @param boolean $is_field_truncated the condition for blob data
3684 * replacements
3685 * @param array $analyzed_sql the analyzed query
3686 * @param string $transformation_plugin the name of transformation plugin
3687 * @param string $default_function the default transformation function
3688 * @param array $transform_options the transformation parameters
3690 * @return string $cell the prepared cell, html content
3692 * @access private
3694 * @see _getTableBody()
3696 private function _getDataCellForNumericColumns(
3697 $column, $class, $condition_field, $meta, $map, $is_field_truncated,
3698 $analyzed_sql, $transformation_plugin, $default_function,
3699 $transform_options
3702 if (! isset($column) || is_null($column)) {
3704 $cell = $this->_buildNullDisplay(
3705 'right ' . $class, $condition_field, $meta, ''
3708 } elseif ($column != '') {
3710 $nowrap = ' nowrap';
3711 $where_comparison = ' = ' . $column;
3713 $cell = $this->_getRowData(
3714 'right ' . $class, $condition_field,
3715 $analyzed_sql, $meta, $map, $column,
3716 $transformation_plugin, $default_function, $nowrap,
3717 $where_comparison, $transform_options,
3718 $is_field_truncated
3720 } else {
3722 $cell = $this->_buildEmptyDisplay(
3723 'right ' . $class, $condition_field, $meta, ''
3727 return $cell;
3729 } // end of the '_getDataCellForNumericColumns()' function
3733 * Get data cell for blob type fields
3735 * @param string $column the relevant column in data row
3736 * @param string $class the html class for column
3737 * @param object $meta the meta-information about this
3738 * field
3739 * @param array $_url_params the parameters for generate url
3740 * @param string $field_flags field flags for column(blob,
3741 * primary etc)
3742 * @param string $transformation_plugin the name of transformation function
3743 * @param string $default_function the default transformation function
3744 * @param array $transform_options the transformation parameters
3745 * @param boolean $condition_field the column should highlighted
3746 * or not
3747 * @param boolean $is_field_truncated the condition for blob data
3748 * replacements
3750 * @return string $cell the prepared cell, html content
3752 * @access private
3754 * @see _getTableBody()
3756 private function _getDataCellForBlobColumns(
3757 $column, $class, $meta, $_url_params, $field_flags, $transformation_plugin,
3758 $default_function, $transform_options, $condition_field, $is_field_truncated
3761 if (stristr($field_flags, self::BINARY_FIELD)) {
3763 // remove 'grid_edit' from $class as we can't edit binary data.
3764 $class = str_replace('grid_edit', '', $class);
3766 if (! isset($column) || is_null($column)) {
3768 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3770 } else {
3772 $blobtext = $this->_handleNonPrintableContents(
3773 self::BLOB_FIELD, (isset($column) ? $column : ''),
3774 $transformation_plugin, $transform_options,
3775 $default_function, $meta, $_url_params
3778 $cell = $this->_buildValueDisplay(
3779 $class, $condition_field, $blobtext
3781 unset($blobtext);
3783 } else {
3784 // not binary:
3786 if (! isset($column) || is_null($column)) {
3788 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3790 } elseif ($column != '') {
3792 // if a transform function for blob is set, none of these
3793 // replacements will be made
3794 $limitChars = $GLOBALS['cfg']['LimitChars'];
3795 if (($GLOBALS['PMA_String']->strlen($column) > $limitChars)
3796 && ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
3797 && empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower(strtolower($meta->name))])
3799 $column = $GLOBALS['PMA_String']->substr(
3800 $column, 0, $GLOBALS['cfg']['LimitChars']
3801 ) . '...';
3802 $is_field_truncated = true;
3805 // displays all space characters, 4 space
3806 // characters for tabulations and <cr>/<lf>
3807 $column = ($default_function != $transformation_plugin)
3808 ? $transformation_plugin->applyTransformation(
3809 $column,
3810 $transform_options,
3811 $meta
3813 : $this->$default_function($column, array(), $meta);
3815 if ($is_field_truncated) {
3816 $class .= ' truncated';
3819 $cell = $this->_buildValueDisplay($class, $condition_field, $column);
3821 } else {
3822 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3826 return $cell;
3828 } // end of the '_getDataCellForBlobColumns()' function
3832 * Get data cell for geometry type fields
3834 * @param string $column the relevant column in data row
3835 * @param string $class the html class for column
3836 * @param object $meta the meta-information about this field
3837 * @param array $map the list of relations
3838 * @param array $_url_params the parameters for generate url
3839 * @param boolean $condition_field the column should highlighted or not
3840 * @param string $transformation_plugin the name of transformation function
3841 * @param string $default_function the default transformation function
3842 * @param array $transform_options the transformation parameters
3843 * @param boolean $is_field_truncated the condition for blob data replacements
3844 * @param array $analyzed_sql the analyzed query
3846 * @return string $cell the prepared data cell, html content
3848 * @access private
3850 * @see _getTableBody()
3852 private function _getDataCellForGeometryColumns(
3853 $column, $class, $meta, $map, $_url_params, $condition_field,
3854 $transformation_plugin, $default_function, $transform_options,
3855 $is_field_truncated, $analyzed_sql
3858 $pftext = $_SESSION['tmpval']['pftext'];
3859 $limitChars = $GLOBALS['cfg']['LimitChars'];
3861 if (! isset($column) || is_null($column)) {
3863 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3865 } elseif ($column != '') {
3867 // Display as [GEOMETRY - (size)]
3868 if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) {
3870 $geometry_text = $this->_handleNonPrintableContents(
3871 strtoupper(self::GEOMETRY_FIELD),
3872 (isset($column) ? $column : ''), $transformation_plugin,
3873 $transform_options, $default_function, $meta
3876 $cell = $this->_buildValueDisplay(
3877 $class, $condition_field, $geometry_text
3880 } elseif ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_WKT) {
3881 // Prepare in Well Known Text(WKT) format.
3883 $where_comparison = ' = ' . $column;
3885 // Convert to WKT format
3886 $wktval = PMA_Util::asWKT($column);
3888 if (($GLOBALS['PMA_String']->strlen($wktval) > $limitChars)
3889 && ($pftext == self::DISPLAY_PARTIAL_TEXT)
3891 $wktval = $GLOBALS['PMA_String']->substr(
3892 $wktval, 0, $limitChars
3893 ) . '...';
3894 $is_field_truncated = true;
3897 $cell = $this->_getRowData(
3898 $class, $condition_field, $analyzed_sql, $meta, $map,
3899 $wktval, $transformation_plugin, $default_function, '',
3900 $where_comparison, $transform_options,
3901 $is_field_truncated
3904 } else {
3905 // Prepare in Well Known Binary (WKB) format.
3907 if ($_SESSION['tmpval']['display_binary']) {
3909 $where_comparison = ' = ' . $column;
3911 $wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8);
3913 if (($GLOBALS['PMA_String']->strlen($wkbval) > $limitChars)
3914 && ($pftext == self::DISPLAY_PARTIAL_TEXT)
3916 $wkbval = $GLOBALS['PMA_String']->substr(
3917 $wkbval, 0, $GLOBALS['cfg']['LimitChars']
3918 ) . '...';
3919 $is_field_truncated = true;
3922 $cell = $this->_getRowData(
3923 $class, $condition_field,
3924 $analyzed_sql, $meta, $map, $wkbval,
3925 $transformation_plugin, $default_function, '',
3926 $where_comparison, $transform_options,
3927 $is_field_truncated
3930 } else {
3931 $wkbval = $this->_handleNonPrintableContents(
3932 self::BINARY_FIELD, $column, $transformation_plugin,
3933 $transform_options, $default_function, $meta,
3934 $_url_params
3937 $cell = $this->_buildValueDisplay(
3938 $class, $condition_field, $wkbval
3942 } else {
3943 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3946 return $cell;
3948 } // end of the '_getDataCellForGeometryColumns()' function
3952 * Get data cell for non numeric and non blob type fields
3954 * @param string $column the relevant column in data row
3955 * @param string $class the html class for column
3956 * @param object $meta the meta-information about the field
3957 * @param array $map the list of relations
3958 * @param array $_url_params the parameters for generate url
3959 * @param boolean $condition_field the column should highlighted
3960 * or not
3961 * @param string $transformation_plugin the name of transformation function
3962 * @param string $default_function the default transformation function
3963 * @param array $transform_options the transformation parameters
3964 * @param boolean $is_field_truncated the condition for blob data
3965 * replacements
3966 * @param array $analyzed_sql the analyzed query
3967 * @param integer &$dt_result the link id associated to the query
3968 * which results have to be displayed
3969 * @param integer $col_index the column index
3971 * @return string $cell the prepared data cell, html content
3973 * @access private
3975 * @see _getTableBody()
3977 private function _getDataCellForNonNumericAndNonBlobColumns(
3978 $column, $class, $meta, $map, $_url_params, $condition_field,
3979 $transformation_plugin, $default_function, $transform_options,
3980 $is_field_truncated, $analyzed_sql, &$dt_result, $col_index
3983 $limitChars = $GLOBALS['cfg']['LimitChars'];
3984 $is_analyse = $this->__get('is_analyse');
3985 $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index);
3986 if (stristr($field_flags, self::BINARY_FIELD)
3987 && ($GLOBALS['cfg']['ProtectBinary'] == 'all'
3988 || $GLOBALS['cfg']['ProtectBinary'] == 'noblob')
3990 $class = str_replace('grid_edit', '', $class);
3993 if (! isset($column) || is_null($column)) {
3995 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3997 } elseif ($column != '') {
3999 // Cut all fields to $GLOBALS['cfg']['LimitChars']
4000 // (unless it's a link-type transformation)
4001 if ($GLOBALS['PMA_String']->strlen($column) > $limitChars
4002 && ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
4003 && ! (gettype($transformation_plugin) == "object"
4004 && strpos($transformation_plugin->getName(), 'Link') !== false)
4006 $column = $GLOBALS['PMA_String']->substr(
4007 $column, 0, $GLOBALS['cfg']['LimitChars']
4008 ) . '...';
4009 $is_field_truncated = true;
4012 $formatted = false;
4013 if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
4015 $column = PMA_Util::printableBitValue(
4016 $column, $meta->length
4019 // some results of PROCEDURE ANALYSE() are reported as
4020 // being BINARY but they are quite readable,
4021 // so don't treat them as BINARY
4022 } elseif (stristr($field_flags, self::BINARY_FIELD)
4023 && ($meta->type == self::STRING_FIELD)
4024 && !(isset($is_analyse) && $is_analyse)
4027 if ($_SESSION['tmpval']['display_binary']) {
4029 // user asked to see the real contents of BINARY
4030 // fields
4031 $column = $this->_displayBinaryAsPrintable($column, 'binary');
4033 } else {
4034 // we show the BINARY message and field's size
4035 // (or maybe use a transformation)
4036 $column = $this->_handleNonPrintableContents(
4037 self::BINARY_FIELD, $column, $transformation_plugin,
4038 $transform_options, $default_function,
4039 $meta, $_url_params
4041 $formatted = true;
4043 } elseif (((substr($meta->type, 0, 9) == self::TIMESTAMP_FIELD)
4044 || ($meta->type == self::DATETIME_FIELD)
4045 || ($meta->type == self::TIME_FIELD)
4046 || ($meta->type == self::TIME_FIELD))
4047 && (strpos($column, ".") === true)
4049 $column = PMA_Util::addMicroseconds($column);
4052 if ($formatted) {
4054 $cell = $this->_buildValueDisplay(
4055 $class, $condition_field, $column
4058 } else {
4060 // transform functions may enable no-wrapping:
4061 $function_nowrap = 'applyTransformationNoWrap';
4063 $bool_nowrap = (($default_function != $transformation_plugin)
4064 && function_exists($transformation_plugin->$function_nowrap()))
4065 ? $transformation_plugin->$function_nowrap($transform_options)
4066 : false;
4068 // do not wrap if date field type
4069 $nowrap = (preg_match('@DATE|TIME@i', $meta->type)
4070 || $bool_nowrap) ? ' nowrap' : '';
4072 $where_comparison = ' = \''
4073 . PMA_Util::sqlAddSlashes($column)
4074 . '\'';
4076 $cell = $this->_getRowData(
4077 $class, $condition_field,
4078 $analyzed_sql, $meta, $map, $column,
4079 $transformation_plugin, $default_function, $nowrap,
4080 $where_comparison, $transform_options,
4081 $is_field_truncated
4085 } else {
4086 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
4089 return $cell;
4091 } // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function
4095 * Get the resulted table with the vertical direction mode.
4097 * @param array $analyzed_sql the analyzed query
4098 * @param array $is_display display mode
4100 * @return string html content
4102 * @access private
4104 * @see _getTable()
4106 private function _getVerticalTable($analyzed_sql, $is_display)
4109 $vertical_table_html = '';
4110 $vertical_display = $this->__get('vertical_display');
4112 // Prepares "multi row delete" link at top if required
4113 if (($GLOBALS['cfg']['RowActionLinks'] != self::POSITION_RIGHT)
4114 && is_array($vertical_display['row_delete'])
4115 && ((count($vertical_display['row_delete']) > 0)
4116 || !empty($vertical_display['textbtn']))
4119 $vertical_table_html .= '<tr>' . "\n";
4120 if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
4121 // if we are not showing the RowActionLinks, then we need to show
4122 // the Multi-Row-Action checkboxes
4123 $vertical_table_html .= '<th></th>' . "\n";
4126 $vertical_table_html .= $vertical_display['textbtn']
4127 . $this->_getCheckBoxesForMultipleRowOperations('_left', $is_display)
4128 . '</tr>' . "\n";
4129 } // end if
4131 // Prepares "edit" link at top if required
4132 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4133 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4134 && is_array($vertical_display['edit'])
4135 && ((count($vertical_display['edit']) > 0)
4136 || !empty($vertical_display['textbtn']))
4138 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4139 'edit'
4141 } // end if
4143 // Prepares "copy" link at top if required
4144 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4145 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4146 && is_array($vertical_display['copy'])
4147 && ((count($vertical_display['copy']) > 0)
4148 || !empty($vertical_display['textbtn']))
4150 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4151 'copy'
4153 } // end if
4155 // Prepares "delete" link at top if required
4156 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4157 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4158 && is_array($vertical_display['delete'])
4159 && ((count($vertical_display['delete']) > 0)
4160 || !empty($vertical_display['textbtn']))
4162 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4163 'delete'
4165 } // end if
4167 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
4169 // Prepares data
4170 foreach ($vertical_display['desc'] as $j => $val) {
4172 // assign appropriate key with current column order
4173 $key = $col_order ? $col_order[$j] : $j;
4175 $vertical_table_html .= '<tr'
4176 . (($col_visib && !$col_visib[$j]) ? ' class="hide"' : '')
4177 . '>' . "\n"
4178 . $val;
4180 $cell_displayed = 0;
4181 foreach ($vertical_display['rowdata'][$key] as $subval) {
4183 if (($cell_displayed != 0)
4184 && ($_SESSION['tmpval']['repeat_cells'] != 0)
4185 && ! ($cell_displayed % $_SESSION['tmpval']['repeat_cells'])
4187 $vertical_table_html .= $val;
4190 $vertical_table_html .= $subval;
4191 $cell_displayed++;
4193 } // end while
4195 $vertical_table_html .= '</tr>' . "\n";
4196 } // end while
4198 // Prepares "multi row delete" link at bottom if required
4199 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4200 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4201 && is_array($vertical_display['row_delete'])
4202 && ((count($vertical_display['row_delete']) > 0)
4203 || !empty($vertical_display['textbtn']))
4206 $vertical_table_html .= '<tr>' . "\n"
4207 . $vertical_display['textbtn']
4208 . $this->_getCheckBoxesForMultipleRowOperations(
4209 '_right', $is_display
4211 . '</tr>' . "\n";
4212 } // end if
4214 // Prepares "edit" link at bottom if required
4215 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4216 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4217 && is_array($vertical_display['edit'])
4218 && ((count($vertical_display['edit']) > 0)
4219 || !empty($vertical_display['textbtn']))
4221 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4222 'edit'
4224 } // end if
4226 // Prepares "copy" link at bottom if required
4227 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4228 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4229 && is_array($vertical_display['copy'])
4230 && ((count($vertical_display['copy']) > 0)
4231 || !empty($vertical_display['textbtn']))
4233 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4234 'copy'
4236 } // end if
4238 // Prepares "delete" link at bottom if required
4239 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4240 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4241 && is_array($vertical_display['delete'])
4242 && ((count($vertical_display['delete']) > 0)
4243 || !empty($vertical_display['textbtn']))
4245 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4246 'delete'
4250 return $vertical_table_html;
4252 } // end of the '_getVerticalTable' function
4256 * Prepare edit, copy and delete links for verticle table
4258 * @param string $operation edit/copy/delete
4260 * @return string $links_html html content
4262 * @access private
4264 * @see _getVerticalTable()
4266 private function _getOperationLinksForVerticleTable($operation)
4269 $link_html = '<tr>' . "\n";
4270 $vertical_display = $this->__get('vertical_display');
4272 if (! is_array($vertical_display['row_delete'])) {
4274 if (($operation == 'edit') || ($operation == 'copy')) {
4275 $link_html .= $vertical_display['textbtn'];
4277 } elseif ($operation == 'delete') {
4279 if (! is_array($vertical_display['edit'])) {
4280 $link_html .= $vertical_display['textbtn'];
4285 foreach ($vertical_display[$operation] as $val) {
4286 $link_html .= $val;
4287 } // end while
4289 $link_html .= '</tr>' . "\n";
4291 return $link_html;
4293 } // end of the '_getOperationLinksForVerticleTable' function
4297 * Get checkboxes for multiple row data operations
4299 * @param string $dir _left / _right
4300 * @param array $is_display display mode
4302 * @return String $checkBoxes_html html content
4304 * @access private
4306 * @see _getVerticalTable()
4308 private function _getCheckBoxesForMultipleRowOperations($dir, $is_display)
4311 $checkBoxes_html = '';
4312 $cell_displayed = 0;
4313 $vertical_display = $this->__get('vertical_display');
4315 foreach ($vertical_display['row_delete'] as $val) {
4317 if (($cell_displayed != 0)
4318 && ($_SESSION['tmpval']['repeat_cells'] != 0)
4319 && !($cell_displayed % $_SESSION['tmpval']['repeat_cells'])
4322 $checkBoxes_html .= '<th'
4323 . (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
4324 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
4325 ? ' rowspan="4"'
4326 : ''
4327 . '></th>' . "\n";
4331 $checkBoxes_html .= str_replace('[%_PMA_CHECKBOX_DIR_%]', $dir, $val);
4332 $cell_displayed++;
4333 } // end while
4335 return $checkBoxes_html;
4337 } // end of the '_getCheckBoxesForMultipleRowOperations' function
4341 * Checks the posted options for viewing query resutls
4342 * and sets appropriate values in the session.
4344 * @todo make maximum remembered queries configurable
4345 * @todo move/split into SQL class!?
4346 * @todo currently this is called twice unnecessary
4347 * @todo ignore LIMIT and ORDER in query!?
4349 * @return void
4351 * @access public
4353 * @see sql.php file
4355 public function setConfigParamsForDisplayTable()
4358 $sql_md5 = md5($this->__get('sql_query'));
4359 $query = array();
4360 if (isset($_SESSION['tmpval']['query'][$sql_md5])) {
4361 $query = $_SESSION['tmpval']['query'][$sql_md5];
4364 $query['sql'] = $this->__get('sql_query');
4366 $valid_disp_dir = PMA_isValid(
4367 $_REQUEST['disp_direction'],
4368 array(self::DISP_DIR_HORIZONTAL, self::DISP_DIR_VERTICAL,
4369 self::DISP_DIR_HORIZONTAL_FLIPPED
4373 if ($valid_disp_dir) {
4374 $query['disp_direction'] = $_REQUEST['disp_direction'];
4375 unset($_REQUEST['disp_direction']);
4376 } elseif (empty($query['disp_direction'])) {
4377 $query['disp_direction'] = $GLOBALS['cfg']['DefaultDisplay'];
4380 if (empty($query['repeat_cells'])) {
4381 $query['repeat_cells'] = $GLOBALS['cfg']['RepeatCells'];
4384 // as this is a form value, the type is always string so we cannot
4385 // use PMA_isValid($_REQUEST['session_max_rows'], 'integer')
4386 if (PMA_isValid($_REQUEST['session_max_rows'], 'numeric')) {
4387 $query['max_rows'] = (int)$_REQUEST['session_max_rows'];
4388 unset($_REQUEST['session_max_rows']);
4389 } elseif ($_REQUEST['session_max_rows'] == self::ALL_ROWS) {
4390 $query['max_rows'] = self::ALL_ROWS;
4391 unset($_REQUEST['session_max_rows']);
4392 } elseif (empty($query['max_rows'])) {
4393 $query['max_rows'] = $GLOBALS['cfg']['MaxRows'];
4396 if (PMA_isValid($_REQUEST['pos'], 'numeric')) {
4397 $query['pos'] = $_REQUEST['pos'];
4398 unset($_REQUEST['pos']);
4399 } elseif (empty($query['pos'])) {
4400 $query['pos'] = 0;
4403 if (PMA_isValid(
4404 $_REQUEST['pftext'],
4405 array(
4406 self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT
4410 $query['pftext'] = $_REQUEST['pftext'];
4411 unset($_REQUEST['pftext']);
4412 } elseif (empty($query['pftext'])) {
4413 $query['pftext'] = self::DISPLAY_PARTIAL_TEXT;
4416 if (PMA_isValid(
4417 $_REQUEST['relational_display'],
4418 array(
4419 self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN
4423 $query['relational_display'] = $_REQUEST['relational_display'];
4424 unset($_REQUEST['relational_display']);
4425 } elseif (empty($query['relational_display'])) {
4426 $query['relational_display'] = self::RELATIONAL_KEY;
4429 if (PMA_isValid(
4430 $_REQUEST['geoOption'],
4431 array(
4432 self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB,
4433 self::GEOMETRY_DISP_GEOM
4437 $query['geoOption'] = $_REQUEST['geoOption'];
4438 unset($_REQUEST['geoOption']);
4439 } elseif (empty($query['geoOption'])) {
4440 $query['geoOption'] = self::GEOMETRY_DISP_GEOM;
4443 if (isset($_REQUEST['display_binary'])) {
4444 $query['display_binary'] = true;
4445 unset($_REQUEST['display_binary']);
4446 } elseif (isset($_REQUEST['display_options_form'])) {
4447 // we know that the checkbox was unchecked
4448 unset($query['display_binary']);
4449 } elseif (isset($_REQUEST['full_text_button'])) {
4450 // do nothing to keep the value that is there in the session
4451 } else {
4452 // selected by default because some operations like OPTIMIZE TABLE
4453 // and all queries involving functions return "binary" contents,
4454 // according to low-level field flags
4455 $query['display_binary'] = true;
4458 if (isset($_REQUEST['display_binary_as_hex'])) {
4459 $query['display_binary_as_hex'] = true;
4460 unset($_REQUEST['display_binary_as_hex']);
4461 } elseif (isset($_REQUEST['display_options_form'])) {
4462 // we know that the checkbox was unchecked
4463 unset($query['display_binary_as_hex']);
4464 } elseif (isset($_REQUEST['full_text_button'])) {
4465 // do nothing to keep the value that is there in the session
4466 } else {
4467 // display_binary_as_hex config option
4468 if (isset($GLOBALS['cfg']['DisplayBinaryAsHex'])
4469 && ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true)
4471 $query['display_binary_as_hex'] = true;
4475 if (isset($_REQUEST['display_blob'])) {
4476 $query['display_blob'] = true;
4477 unset($_REQUEST['display_blob']);
4478 } elseif (isset($_REQUEST['display_options_form'])) {
4479 // we know that the checkbox was unchecked
4480 unset($query['display_blob']);
4483 if (isset($_REQUEST['hide_transformation'])) {
4484 $query['hide_transformation'] = true;
4485 unset($_REQUEST['hide_transformation']);
4486 } elseif (isset($_REQUEST['display_options_form'])) {
4487 // we know that the checkbox was unchecked
4488 unset($query['hide_transformation']);
4491 // move current query to the last position, to be removed last
4492 // so only least executed query will be removed if maximum remembered
4493 // queries limit is reached
4494 unset($_SESSION['tmpval']['query'][$sql_md5]);
4495 $_SESSION['tmpval']['query'][$sql_md5] = $query;
4497 // do not exceed a maximum number of queries to remember
4498 if (count($_SESSION['tmpval']['query']) > 10) {
4499 array_shift($_SESSION['tmpval']['query']);
4500 //echo 'deleting one element ...';
4503 // populate query configuration
4504 $_SESSION['tmpval']['pftext']
4505 = $query['pftext'];
4506 $_SESSION['tmpval']['relational_display']
4507 = $query['relational_display'];
4508 $_SESSION['tmpval']['geoOption']
4509 = $query['geoOption'];
4510 $_SESSION['tmpval']['display_binary'] = isset(
4511 $query['display_binary']
4513 $_SESSION['tmpval']['display_binary_as_hex'] = isset(
4514 $query['display_binary_as_hex']
4516 $_SESSION['tmpval']['display_blob'] = isset(
4517 $query['display_blob']
4519 $_SESSION['tmpval']['hide_transformation'] = isset(
4520 $query['hide_transformation']
4522 $_SESSION['tmpval']['pos']
4523 = $query['pos'];
4524 $_SESSION['tmpval']['max_rows']
4525 = $query['max_rows'];
4526 $_SESSION['tmpval']['repeat_cells']
4527 = $query['repeat_cells'];
4528 $_SESSION['tmpval']['disp_direction']
4529 = $query['disp_direction'];
4535 * Prepare a table of results returned by a SQL query.
4536 * This function is called by the "sql.php" script.
4538 * @param integer &$dt_result the link id associated to the query
4539 * which results have to be displayed
4540 * @param array &$the_disp_mode the display mode
4541 * @param array $analyzed_sql the analyzed query
4542 * @param boolean $is_limited_display With limited operations or not
4544 * @return string $table_html Generated HTML content for resulted table
4546 * @access public
4548 * @see sql.php file
4550 public function getTable(
4551 &$dt_result, &$the_disp_mode, $analyzed_sql,
4552 $is_limited_display = false
4555 $table_html = '';
4556 // Following variable are needed for use in isset/empty or
4557 // use with array indexes/safe use in foreach
4558 $fields_meta = $this->__get('fields_meta');
4559 $showtable = $this->__get('showtable');
4560 $printview = $this->__get('printview');
4562 // why was this called here? (already called from sql.php)
4563 //$this->setConfigParamsForDisplayTable();
4566 * @todo move this to a central place
4567 * @todo for other future table types
4569 $is_innodb = (isset($showtable['Type'])
4570 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
4572 if ($is_innodb
4573 && ! isset($analyzed_sql[0]['queryflags']['union'])
4574 && ! isset($analyzed_sql[0]['table_ref'][1]['table_name'])
4575 && (empty($analyzed_sql[0]['where_clause'])
4576 || ($analyzed_sql[0]['where_clause'] == '1 '))
4578 // "j u s t b r o w s i n g"
4579 $pre_count = '~';
4580 $after_count = PMA_Util::showHint(
4581 PMA_sanitize(
4582 __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc].')
4585 } else {
4586 $pre_count = '';
4587 $after_count = '';
4590 // 1. ----- Prepares the work -----
4592 // 1.1 Gets the informations about which functionalities should be
4593 // displayed
4594 $total = '';
4595 $is_display = $this->_setDisplayMode($the_disp_mode, $total);
4597 // 1.2 Defines offsets for the next and previous pages
4598 if ($is_display['nav_bar'] == '1') {
4599 list($pos_next, $pos_prev) = $this->_getOffsets();
4600 } // end if
4601 if (!isset($analyzed_sql[0]['order_by_clause'])) {
4602 $analyzed_sql[0]['order_by_clause'] = "";
4605 // 1.3 Find the sort expression
4606 // we need $sort_expression and $sort_expression_nodirection
4607 // even if there are many table references
4608 list(
4609 $sort_expression, $sort_expression_nodirection,
4610 $sort_direction
4611 ) = $this->_getSortParams($analyzed_sql[0]['order_by_clause']);
4613 $number_of_columns = count($sort_expression_nodirection);
4614 // 1.4 Prepares display of first and last value of the sorted column
4615 $sorted_column_message = '';
4616 for ( $i = 0; $i < $number_of_columns; $i++ ) {
4617 $sorted_column_message .= $this->_getSortedColumnMessage(
4618 $dt_result, $sort_expression_nodirection[$i]
4622 // 2. ----- Prepare to display the top of the page -----
4624 // 2.1 Prepares a messages with position informations
4625 if (($is_display['nav_bar'] == '1') && isset($pos_next)) {
4627 $message = $this->_setMessageInformation(
4628 $sorted_column_message, $analyzed_sql[0]['limit_clause'],
4629 $total, $pos_next, $pre_count, $after_count
4632 $table_html .= PMA_Util::getMessage(
4633 $message, $this->__get('sql_query'), 'success'
4636 } elseif (! isset($printview) || ($printview != '1')) {
4638 $table_html .= PMA_Util::getMessage(
4639 __('Your SQL query has been executed successfully.'),
4640 $this->__get('sql_query'), 'success'
4644 // 2.3 Prepare the navigation bars
4645 if (! strlen($this->__get('table'))) {
4647 if (isset($analyzed_sql[0]['query_type'])
4648 && ($analyzed_sql[0]['query_type'] == self::QUERY_TYPE_SELECT)
4650 // table does not always contain a real table name,
4651 // for example in MySQL 5.0.x, the query SHOW STATUS
4652 // returns STATUS as a table name
4653 $this->__set('table', $fields_meta[0]->table);
4654 } else {
4655 $this->__set('table', '');
4660 if (($is_display['nav_bar'] == '1')
4661 && empty($analyzed_sql[0]['limit_clause'])
4664 $table_html .= $this->_getPlacedTableNavigations(
4665 $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN,
4666 "\n", $is_innodb
4669 } elseif (! isset($printview) || ($printview != '1')) {
4670 $table_html .= "\n" . '<br /><br />' . "\n";
4673 // 2b ----- Get field references from Database -----
4674 // (see the 'relation' configuration variable)
4676 // initialize map
4677 $map = array();
4679 // find tables
4680 $target=array();
4681 if (isset($analyzed_sql[0]['table_ref'])
4682 && is_array($analyzed_sql[0]['table_ref'])
4685 foreach ($analyzed_sql[0]['table_ref']
4686 as $table_ref_position => $table_ref) {
4687 $target[] = $analyzed_sql[0]['table_ref']
4688 [$table_ref_position]['table_true_name'];
4693 if (strlen($this->__get('table'))) {
4694 // This method set the values for $map array
4695 $this->_setParamForLinkForeignKeyRelatedTables($map);
4696 } // end if
4697 // end 2b
4699 // 3. ----- Prepare the results table -----
4700 $table_html .= $this->_getTableHeaders(
4701 $is_display, $analyzed_sql, $sort_expression,
4702 $sort_expression_nodirection, $sort_direction, $is_limited_display
4704 . '<tbody>' . "\n";
4706 $table_html .= $this->_getTableBody(
4707 $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display
4710 // vertical output case
4711 if ($_SESSION['tmpval']['disp_direction'] == self::DISP_DIR_VERTICAL) {
4712 $table_html .= $this->_getVerticalTable($analyzed_sql, $is_display);
4713 } // end if
4715 $this->__set('vertical_display', null);
4717 $table_html .= '</tbody>' . "\n"
4718 . '</table>';
4720 // 4. ----- Prepares the link for multi-fields edit and delete
4722 if ($is_display['del_lnk'] == self::DELETE_ROW
4723 && $is_display['del_lnk'] != self::KILL_PROCESS
4726 $table_html .= $this->_getMultiRowOperationLinks(
4727 $dt_result, $analyzed_sql, $is_display['del_lnk']
4732 // 5. ----- Get the navigation bar at the bottom if required -----
4733 if (($is_display['nav_bar'] == '1')
4734 && empty($analyzed_sql[0]['limit_clause'])
4736 $table_html .= $this->_getPlacedTableNavigations(
4737 $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN,
4738 '<br />' . "\n", $is_innodb
4740 } elseif (! isset($printview) || ($printview != '1')) {
4741 $table_html .= "\n" . '<br /><br />' . "\n";
4745 // 6. ----- Prepare "Query results operations"
4746 if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) {
4747 $table_html .= $this->_getResultsOperations(
4748 $the_disp_mode, $analyzed_sql
4752 return $table_html;
4754 } // end of the 'getTable()' function
4758 * Get offsets for next page and previous page
4760 * @return array array with two elements - $pos_next, $pos_prev
4762 * @access private
4764 * @see getTable()
4766 private function _getOffsets()
4769 if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
4770 $pos_next = 0;
4771 $pos_prev = 0;
4772 } else {
4774 $pos_next = $_SESSION['tmpval']['pos']
4775 + $_SESSION['tmpval']['max_rows'];
4777 $pos_prev = $_SESSION['tmpval']['pos']
4778 - $_SESSION['tmpval']['max_rows'];
4780 if ($pos_prev < 0) {
4781 $pos_prev = 0;
4785 return array($pos_next, $pos_prev);
4787 } // end of the '_getOffsets()' function
4791 * Get sort parameters
4793 * @param string $order_by_clause the order by clause of the sql query
4795 * @return array 3 element array: $sort_expression,
4796 * $sort_expression_nodirection, $sort_direction
4798 * @access private
4800 * @see getTable()
4802 private function _getSortParams($order_by_clause)
4805 $sort_expression = array();
4806 $sort_expression_nodirection = array();
4807 $sort_direction = array();
4808 if (! empty($order_by_clause)) {
4809 // Each order by clause is assumed to be delimited by a comma
4810 // A typical order by clause would be order by column1 asc, column2 desc
4811 // The following line counts the number of columns in order by clause
4812 $matches = explode(',', $order_by_clause);
4813 // Iterate over each column in order by clause
4814 foreach ($matches as $index=>$order_by_clause2) {
4816 $sort_expression[$index] = trim(
4817 str_replace(' ', ' ', $order_by_clause2)
4820 * Get rid of ASC|DESC
4822 preg_match(
4823 '@(.*)([[:space:]]*(ASC|DESC))@si',
4824 $sort_expression[$index], $matches
4827 $sort_expression_nodirection[$index] = isset($matches[1])
4828 ? trim($matches[1])
4829 : $sort_expression[$index];
4830 $sort_direction[$index]
4831 = isset($matches[2]) ? trim($matches[2]) : '';
4833 } else {
4834 $sort_expression[0] = $sort_expression_nodirection[0]
4835 = $sort_direction[0] = '';
4838 return array($sort_expression, $sort_expression_nodirection,
4839 $sort_direction
4842 } // end of the '_getSortParams()' function
4846 * Prepare sorted column message
4848 * @param integer &$dt_result the link id associated to the
4849 * query which results have to
4850 * be displayed
4851 * @param string $sort_expression_nodirection sort expression without direction
4853 * @return string html content
4854 * null if not found sorted column
4856 * @access private
4858 * @see getTable()
4860 private function _getSortedColumnMessage(
4861 &$dt_result, $sort_expression_nodirection
4864 $fields_meta = $this->__get('fields_meta'); // To use array indexes
4866 if (! empty($sort_expression_nodirection)) {
4868 if (strpos($sort_expression_nodirection, '.') === false) {
4869 $sort_table = $this->__get('table');
4870 $sort_column = $sort_expression_nodirection;
4871 } else {
4872 list($sort_table, $sort_column)
4873 = explode('.', $sort_expression_nodirection);
4876 $sort_table = PMA_Util::unQuote($sort_table);
4877 $sort_column = PMA_Util::unQuote($sort_column);
4879 // find the sorted column index in row result
4880 // (this might be a multi-table query)
4881 $sorted_column_index = false;
4883 foreach ($fields_meta as $key => $meta) {
4884 if (($meta->table == $sort_table) && ($meta->name == $sort_column)) {
4885 $sorted_column_index = $key;
4886 break;
4890 if ($sorted_column_index !== false) {
4892 // fetch first row of the result set
4893 $row = $GLOBALS['dbi']->fetchRow($dt_result);
4895 // initializing default arguments
4896 $default_function = '_mimeDefaultFunction';
4897 $transformation_plugin = $default_function;
4898 $transform_options = array();
4900 // check for non printable sorted row data
4901 $meta = $fields_meta[$sorted_column_index];
4903 if (stristr($meta->type, self::BLOB_FIELD)
4904 || ($meta->type == self::GEOMETRY_FIELD)
4907 $column_for_first_row = $this->_handleNonPrintableContents(
4908 $meta->type, $row[$sorted_column_index],
4909 $transformation_plugin, $transform_options,
4910 $default_function, $meta
4913 } else {
4914 $column_for_first_row = $row[$sorted_column_index];
4917 $column_for_first_row = strtoupper(
4918 substr($column_for_first_row, 0, $GLOBALS['cfg']['LimitChars'])
4921 // fetch last row of the result set
4922 $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
4923 $row = $GLOBALS['dbi']->fetchRow($dt_result);
4925 // check for non printable sorted row data
4926 $meta = $fields_meta[$sorted_column_index];
4927 if (stristr($meta->type, self::BLOB_FIELD)
4928 || ($meta->type == self::GEOMETRY_FIELD)
4931 $column_for_last_row = $this->_handleNonPrintableContents(
4932 $meta->type, $row[$sorted_column_index],
4933 $transformation_plugin, $transform_options,
4934 $default_function, $meta
4937 } else {
4938 $column_for_last_row = $row[$sorted_column_index];
4941 $column_for_last_row = strtoupper(
4942 substr($column_for_last_row, 0, $GLOBALS['cfg']['LimitChars'])
4945 // reset to first row for the loop in _getTableBody()
4946 $GLOBALS['dbi']->dataSeek($dt_result, 0);
4948 // we could also use here $sort_expression_nodirection
4949 return ' [' . htmlspecialchars($sort_column)
4950 . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - '
4951 . htmlspecialchars($column_for_last_row) . '</strong>]';
4955 return null;
4957 } // end of the '_getSortedColumnMessage()' function
4961 * Set the content that needs to be shown in message
4963 * @param string $sorted_column_message the message for sorted column
4964 * @param string $limit_clause the limit clause of analyzed query
4965 * @param integer $total the total number of rows returned by
4966 * the SQL query without any
4967 * programmatically appended LIMIT clause
4968 * @param integer $pos_next the offset for next page
4969 * @param string $pre_count the string renders before row count
4970 * @param string $after_count the string renders after row count
4972 * @return PMA_Message $message an object of PMA_Message
4974 * @access private
4976 * @see getTable()
4978 private function _setMessageInformation(
4979 $sorted_column_message, $limit_clause, $total,
4980 $pos_next, $pre_count, $after_count
4983 $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset()
4985 if (! empty($limit_clause)) {
4987 $limit_data
4988 = PMA_Util::analyzeLimitClause($limit_clause);
4989 $first_shown_rec = $limit_data['start'];
4991 if ($limit_data['length'] < $total) {
4992 $last_shown_rec = $limit_data['start'] + $limit_data['length'] - 1;
4993 } else {
4994 $last_shown_rec = $limit_data['start'] + $total - 1;
4997 } elseif (($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS)
4998 || ($pos_next > $total)
5001 $first_shown_rec = $_SESSION['tmpval']['pos'];
5002 $last_shown_rec = $total - 1;
5004 } else {
5006 $first_shown_rec = $_SESSION['tmpval']['pos'];
5007 $last_shown_rec = $pos_next - 1;
5011 if (PMA_Table::isView($this->__get('db'), $this->__get('table'))
5012 && ($total == $GLOBALS['cfg']['MaxExactCountViews'])
5015 $message = PMA_Message::notice(
5017 'This view has at least this number of rows. '
5018 . 'Please refer to %sdocumentation%s.'
5022 $message->addParam('[doc@cfg_MaxExactCount]');
5023 $message->addParam('[/doc]');
5024 $message_view_warning = PMA_Util::showHint($message);
5026 } else {
5027 $message_view_warning = false;
5030 $message = PMA_Message::success(__('Showing rows %1s - %2s'));
5031 $message->addParam($first_shown_rec);
5033 if ($message_view_warning) {
5034 $message->addParam('... ' . $message_view_warning, false);
5035 } else {
5036 $message->addParam($last_shown_rec);
5039 $message->addMessage('(');
5041 if (!$message_view_warning) {
5043 if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) {
5044 $message_total = PMA_Message::notice(
5045 $pre_count . __('%1$d total, %2$d in query')
5047 $message_total->addParam($total);
5048 $message_total->addParam($unlim_num_rows);
5049 } else {
5050 $message_total = PMA_Message::notice($pre_count . __('%d total'));
5051 $message_total->addParam($total);
5054 if (!empty($after_count)) {
5055 $message_total->addMessage($after_count);
5057 $message->addMessage($message_total, '');
5059 $message->addMessage(', ', '');
5062 $message_qt = PMA_Message::notice(__('Query took %01.4f seconds.') . ')');
5063 $message_qt->addParam($this->__get('querytime'));
5065 $message->addMessage($message_qt, '');
5066 if (! is_null($sorted_column_message)) {
5067 $message->addMessage($sorted_column_message, '');
5070 return $message;
5072 } // end of the '_setMessageInformation()' function
5076 * Set the value of $map array for linking foreign key related tables
5078 * @param array &$map the list of relations
5080 * @return void
5082 * @access private
5084 * @see getTable()
5086 private function _setParamForLinkForeignKeyRelatedTables(&$map)
5089 // To be able to later display a link to the related table,
5090 // we verify both types of relations: either those that are
5091 // native foreign keys or those defined in the phpMyAdmin
5092 // configuration storage. If no PMA storage, we won't be able
5093 // to use the "column to display" notion (for example show
5094 // the name related to a numeric id).
5095 $exist_rel = PMA_getForeigners(
5096 $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH
5099 if ($exist_rel) {
5101 foreach ($exist_rel as $master_field => $rel) {
5103 $display_field = PMA_getDisplayField(
5104 $rel['foreign_db'], $rel['foreign_table']
5107 $map[$master_field] = array(
5108 $rel['foreign_table'],
5109 $rel['foreign_field'],
5110 $display_field,
5111 $rel['foreign_db']
5113 } // end while
5114 } // end if
5116 } // end of the '_setParamForLinkForeignKeyRelatedTables()' function
5120 * Prepare multi field edit/delete links
5122 * @param integer &$dt_result the link id associated to the query
5123 * which results have to be displayed
5124 * @param array $analyzed_sql the analyzed query
5125 * @param string $del_link the display element - 'del_link'
5127 * @return string $links_html html content
5129 * @access private
5131 * @see getTable()
5133 private function _getMultiRowOperationLinks(
5134 &$dt_result, $analyzed_sql, $del_link
5137 $links_html = '';
5138 $url_query = $this->__get('url_query');
5139 $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill');
5141 if ($_SESSION['tmpval']['disp_direction'] != self::DISP_DIR_VERTICAL) {
5143 $links_html .= '<img class="selectallarrow" width="38" height="22"'
5144 . ' src="' . $this->__get('pma_theme_image') . 'arrow_'
5145 . $this->__get('text_dir') . '.png' . '"'
5146 . ' alt="' . __('With selected:') . '" />';
5149 $links_html .= '<input type="checkbox" id="resultsForm_checkall" '
5150 . 'class="checkall_box" title="' . __('Check All') . '" /> '
5151 . '<label for="resultsForm_checkall">' . __('Check All') . '</label> '
5152 . '<i style="margin-left: 2em">' . __('With selected:') . '</i>' . "\n";
5154 $links_html .= PMA_Util::getButtonOrImage(
5155 'submit_mult', 'mult_submit', 'submit_mult_change',
5156 __('Change'), 'b_edit.png', 'edit'
5159 $links_html .= PMA_Util::getButtonOrImage(
5160 'submit_mult', 'mult_submit', 'submit_mult_delete',
5161 $delete_text, 'b_drop.png', 'delete'
5164 if (isset($analyzed_sql[0])
5165 && $analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT
5167 $links_html .= PMA_Util::getButtonOrImage(
5168 'submit_mult', 'mult_submit', 'submit_mult_export',
5169 __('Export'), 'b_tblexport.png', 'export'
5173 $links_html .= "\n";
5175 $links_html .= '<input type="hidden" name="sql_query"'
5176 . ' value="' . htmlspecialchars($this->__get('sql_query')) . '" />'
5177 . "\n";
5179 if (! empty($url_query)) {
5180 $links_html .= '<input type="hidden" name="url_query"'
5181 . ' value="' . $url_query . '" />' . "\n";
5184 // fetch last row of the result set
5185 $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
5186 $row = $GLOBALS['dbi']->fetchRow($dt_result);
5188 // $clause_is_unique is needed by getTable() to generate the proper param
5189 // in the multi-edit and multi-delete form
5190 list($where_clause, $clause_is_unique, $condition_array)
5191 = PMA_Util::getUniqueCondition(
5192 $dt_result,
5193 $this->__get('fields_cnt'),
5194 $this->__get('fields_meta'),
5195 $row
5197 unset($where_clause, $condition_array);
5199 // reset to first row for the loop in _getTableBody()
5200 $GLOBALS['dbi']->dataSeek($dt_result, 0);
5202 $links_html .= '<input type="hidden" name="clause_is_unique"'
5203 . ' value="' . $clause_is_unique . '" />' . "\n";
5205 $links_html .= '</form>' . "\n";
5207 return $links_html;
5209 } // end of the '_getMultiRowOperationLinks()' function
5213 * Prepare table navigation bar at the top or bottom
5215 * @param integer $pos_next the offset for the "next" page
5216 * @param integer $pos_prev the offset for the "previous" page
5217 * @param string $place the place to show navigation
5218 * @param string $empty_line empty line depend on the $place
5219 * @param boolean $is_innodb whether its InnoDB or not
5221 * @return string html content of navigation bar
5223 * @access private
5225 * @see _getTable()
5227 private function _getPlacedTableNavigations(
5228 $pos_next, $pos_prev, $place, $empty_line, $is_innodb
5231 $navigation_html = '';
5233 if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) {
5234 $navigation_html .= '<br />' . "\n";
5237 $navigation_html .= $this->_getTableNavigation(
5238 $pos_next, $pos_prev, 'top_direction_dropdown', $is_innodb
5241 if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) {
5242 $navigation_html .= "\n";
5245 return $navigation_html;
5247 } // end of the '_getPlacedTableNavigations()' function
5250 * Generates HTML to display the Create view in span tag
5252 * @param array $analyzed_sql the analyzed Query
5253 * @param string $url_query String with URL Parameters
5255 * @return string
5257 * @access private
5259 * @see _getResultsOperations()
5261 private function _getLinkForCreateView($analyzed_sql, $url_query)
5263 $results_operations_html = '';
5264 if (!PMA_DRIZZLE && !isset($analyzed_sql[0]['queryflags']['procedure'])) {
5266 $ajax_class = ' ajax';
5268 $results_operations_html .= '<span>'
5269 . PMA_Util::linkOrButton(
5270 'view_create.php' . $url_query,
5271 PMA_Util::getIcon(
5272 'b_views.png', __('Create view'), true
5274 array('class' => 'create_view' . $ajax_class), true, true, ''
5276 . '</span>' . "\n";
5278 return $results_operations_html;
5283 * Calls the _getResultsOperations with $only_view as true
5285 * @param array $analyzed_sql the analyzed Query
5287 * @return string
5289 * @access public
5292 public function getCreateViewQueryResultOp($analyzed_sql)
5295 $results_operations_html = '';
5296 $fake_display_mode = array();
5297 //calling to _getResultOperations with a fake display mode
5298 //and setting only_view parameter to be true to generate just view
5299 $results_operations_html .= $this->_getResultsOperations(
5300 $fake_display_mode,
5301 $analyzed_sql,
5302 true
5304 return $results_operations_html;
5308 * Get operations that are available on results.
5310 * @param array $the_disp_mode the display mode
5311 * @param array $analyzed_sql the analyzed query
5312 * @param boolean $only_view Whether to show only view
5314 * @return string $results_operations_html html content
5316 * @access private
5318 * @see getTable()
5320 private function _getResultsOperations(
5321 $the_disp_mode, $analyzed_sql, $only_view = false
5323 global $printview;
5325 $results_operations_html = '';
5326 $fields_meta = $this->__get('fields_meta'); // To safe use in foreach
5327 $header_shown = false;
5328 $header = '<fieldset><legend>' . __('Query results operations')
5329 . '</legend>';
5331 $_url_params = array(
5332 'db' => $this->__get('db'),
5333 'table' => $this->__get('table'),
5334 'printview' => '1',
5335 'sql_query' => $this->__get('sql_query'),
5337 $url_query = PMA_URL_getCommon($_url_params);
5339 if (!$header_shown) {
5340 $results_operations_html .= $header;
5341 $header_shown = true;
5343 // if empty result set was produced we need to
5344 // show only view and not other options
5345 if ($only_view == true) {
5346 $results_operations_html .= $this->_getLinkForCreateView(
5347 $analyzed_sql, $url_query
5350 if ($header_shown) {
5351 $results_operations_html .= '</fieldset><br />';
5353 return $results_operations_html;
5356 if (($the_disp_mode[6] == '1') || ($the_disp_mode[9] == '1')) {
5357 // Displays "printable view" link if required
5358 if ($the_disp_mode[9] == '1') {
5360 $results_operations_html
5361 .= PMA_Util::linkOrButton(
5362 'sql.php' . $url_query,
5363 PMA_Util::getIcon(
5364 'b_print.png', __('Print view'), true
5366 array('target' => 'print_view'),
5367 true,
5368 true,
5369 'print_view'
5371 . "\n";
5373 if ($_SESSION['tmpval']['pftext']) {
5375 $_url_params['pftext'] = self::DISPLAY_FULL_TEXT;
5377 $results_operations_html
5378 .= PMA_Util::linkOrButton(
5379 'sql.php' . PMA_URL_getCommon($_url_params),
5380 PMA_Util::getIcon(
5381 'b_print.png',
5382 __('Print view (with full texts)'), true
5384 array('target' => 'print_view'),
5385 true,
5386 true,
5387 'print_view'
5389 . "\n";
5390 unset($_url_params['pftext']);
5392 } // end displays "printable view"
5395 // Export link
5396 // (the url_query has extra parameters that won't be used to export)
5397 // (the single_table parameter is used in display_export.inc.php
5398 // to hide the SQL and the structure export dialogs)
5399 // If the parser found a PROCEDURE clause
5400 // (most probably PROCEDURE ANALYSE()) it makes no sense to
5401 // display the Export link).
5402 if (isset($analyzed_sql[0])
5403 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
5404 && ! isset($printview)
5405 && ! isset($analyzed_sql[0]['queryflags']['procedure'])
5408 if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name'])
5409 && ! isset($analyzed_sql[0]['table_ref'][1]['table_true_name'])
5411 $_url_params['single_table'] = 'true';
5414 if (! $header_shown) {
5415 $results_operations_html .= $header;
5416 $header_shown = true;
5419 $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows');
5422 * At this point we don't know the table name; this can happen
5423 * for example with a query like
5424 * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp
5425 * As a workaround we set in the table parameter the name of the
5426 * first table of this database, so that tbl_export.php and
5427 * the script it calls do not fail
5429 if (empty($_url_params['table']) && ! empty($_url_params['db'])) {
5430 $_url_params['table'] = $GLOBALS['dbi']->fetchValue("SHOW TABLES");
5431 /* No result (probably no database selected) */
5432 if ($_url_params['table'] === false) {
5433 unset($_url_params['table']);
5437 $results_operations_html .= PMA_Util::linkOrButton(
5438 'tbl_export.php' . PMA_URL_getCommon($_url_params),
5439 PMA_Util::getIcon(
5440 'b_tblexport.png', __('Export'), true
5443 true,
5444 true,
5447 . "\n";
5449 // prepare chart
5450 $results_operations_html .= PMA_Util::linkOrButton(
5451 'tbl_chart.php' . PMA_URL_getCommon($_url_params),
5452 PMA_Util::getIcon(
5453 'b_chart.png', __('Display chart'), true
5456 true,
5457 true,
5460 . "\n";
5462 // prepare GIS chart
5463 $geometry_found = false;
5464 // If atleast one geometry field is found
5465 foreach ($fields_meta as $meta) {
5466 if ($meta->type == self::GEOMETRY_FIELD) {
5467 $geometry_found = true;
5468 break;
5472 if ($geometry_found) {
5473 $results_operations_html
5474 .= PMA_Util::linkOrButton(
5475 'tbl_gis_visualization.php'
5476 . PMA_URL_getCommon($_url_params),
5477 PMA_Util::getIcon(
5478 'b_globe.gif', __('Visualize GIS data'), true
5481 true,
5482 true,
5485 . "\n";
5489 // CREATE VIEW
5492 * @todo detect privileges to create a view
5493 * (but see 2006-01-19 note in display_create_table.lib.php,
5494 * I think we cannot detect db-specific privileges reliably)
5495 * Note: we don't display a Create view link if we found a PROCEDURE clause
5497 if (!$header_shown) {
5498 $results_operations_html .= $header;
5499 $header_shown = true;
5502 $results_operations_html .= $this->_getLinkForCreateView(
5503 $analyzed_sql, $url_query
5506 if ($header_shown) {
5507 $results_operations_html .= '</fieldset><br />';
5510 return $results_operations_html;
5512 } // end of the '_getResultsOperations()' function
5516 * Verifies what to do with non-printable contents (binary or BLOB)
5517 * in Browse mode.
5519 * @param string $category BLOB|BINARY|GEOMETRY
5520 * @param string $content the binary content
5521 * @param string $transformation_plugin transformation plugin.
5522 * Can also be the default function:
5523 * PMA_mimeDefaultFunction
5524 * @param array $transform_options transformation parameters
5525 * @param string $default_function default transformation function
5526 * @param object $meta the meta-information about the field
5527 * @param array $url_params parameters that should go to the
5528 * download link
5530 * @return mixed string or float
5532 * @access private
5534 * @see _getDataCellForBlobColumns(),
5535 * _getDataCellForGeometryColumns(),
5536 * _getDataCellForNonNumericAndNonBlobColumns(),
5537 * _getSortedColumnMessage()
5539 private function _handleNonPrintableContents(
5540 $category, $content, $transformation_plugin, $transform_options,
5541 $default_function, $meta, $url_params = array()
5544 $result = '[' . $category;
5546 if (isset($content)) {
5548 $size = strlen($content);
5549 $display_size = PMA_Util::formatByteDown($size, 3, 1);
5550 $result .= ' - ' . $display_size[0] . ' ' . $display_size[1];
5552 } else {
5554 $result .= ' - NULL';
5555 $size = 0;
5559 $result .= ']';
5561 // if we want to use a text transformation on a BLOB column
5562 if (gettype($transformation_plugin) == "object"
5563 && (strpos($transformation_plugin->getMIMESubtype(), 'Octetstream')
5564 || strpos($transformation_plugin->getMIMEtype(), 'Text') !== false)
5566 $result = $content;
5569 if ($size > 0) {
5571 if ($default_function != $transformation_plugin) {
5572 $result = $transformation_plugin->applyTransformation(
5573 $result,
5574 $transform_options,
5575 $meta
5577 } else {
5579 $result = $this->$default_function($result, array(), $meta);
5580 if (stristr($meta->type, self::BLOB_FIELD)
5581 && $_SESSION['tmpval']['display_blob']
5583 // in this case, restart from the original $content
5584 $result = $this->_displayBinaryAsPrintable($content, 'blob');
5587 /* Create link to download */
5588 if (count($url_params) > 0) {
5589 $result = '<a href="tbl_get_field.php'
5590 . PMA_URL_getCommon($url_params)
5591 . '" class="disableAjax">'
5592 . $result . '</a>';
5597 return($result);
5599 } // end of the '_handleNonPrintableContents()' function
5603 * Prepares the displayable content of a data cell in Browse mode,
5604 * taking into account foreign key description field and transformations
5606 * @param string $class css classes for the td element
5607 * @param bool $condition_field whether the column is a part of the
5608 * where clause
5609 * @param array $analyzed_sql the analyzed query
5610 * @param object $meta the meta-information about the field
5611 * @param array $map the list of relations
5612 * @param string $data data
5613 * @param string $transformation_plugin transformation plugin.
5614 * Can also be the default function:
5615 * PMA_mimeDefaultFunction
5616 * @param string $default_function default function
5617 * @param string $nowrap 'nowrap' if the content should not
5618 * be wrapped
5619 * @param string $where_comparison data for the where clause
5620 * @param array $transform_options array of options for transformation
5621 * @param bool $is_field_truncated whether the field is truncated
5623 * @return string formatted data
5625 * @access private
5627 * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
5628 * _getDataCellForNonNumericAndNonBlobColumns(),
5631 private function _getRowData(
5632 $class, $condition_field, $analyzed_sql, $meta, $map, $data,
5633 $transformation_plugin, $default_function, $nowrap, $where_comparison,
5634 $transform_options, $is_field_truncated
5637 $relational_display = $_SESSION['tmpval']['relational_display'];
5638 $printview = $this->__get('printview');
5639 $result = '<td data-decimals="' . $meta->decimals . '" data-type="'
5640 . $meta->type . '" class="'
5641 . $this->_addClass(
5642 $class, $condition_field, $meta, $nowrap,
5643 $is_field_truncated, $transformation_plugin, $default_function
5645 . '">';
5647 if (isset($analyzed_sql[0]['select_expr'])
5648 && is_array($analyzed_sql[0]['select_expr'])
5651 foreach ($analyzed_sql[0]['select_expr']
5652 as $select_expr_position => $select_expr
5655 $alias = $analyzed_sql[0]['select_expr']
5656 [$select_expr_position]['alias'];
5658 if (!isset($alias) || !strlen($alias)) {
5659 continue;
5660 } // end if
5662 $true_column = $analyzed_sql[0]['select_expr']
5663 [$select_expr_position]['column'];
5665 if ($alias == $meta->name) {
5666 // this change in the parameter does not matter
5667 // outside of the function
5668 $meta->name = $true_column;
5669 } // end if
5671 } // end foreach
5672 } // end if
5674 if (isset($map[$meta->name])) {
5676 // Field to display from the foreign table?
5677 if (isset($map[$meta->name][2]) && strlen($map[$meta->name][2])) {
5679 $dispsql = 'SELECT '
5680 . PMA_Util::backquote($map[$meta->name][2])
5681 . ' FROM '
5682 . PMA_Util::backquote($map[$meta->name][3])
5683 . '.'
5684 . PMA_Util::backquote($map[$meta->name][0])
5685 . ' WHERE '
5686 . PMA_Util::backquote($map[$meta->name][1])
5687 . $where_comparison;
5689 $dispresult = $GLOBALS['dbi']->tryQuery(
5690 $dispsql,
5691 null,
5692 PMA_DatabaseInterface::QUERY_STORE
5695 if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) {
5696 list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0);
5697 } else {
5698 $dispval = __('Link not found!');
5701 @$GLOBALS['dbi']->freeResult($dispresult);
5703 } else {
5704 $dispval = '';
5705 } // end if... else...
5707 if (isset($printview) && ($printview == '1')) {
5709 $result .= ($transformation_plugin != $default_function
5710 ? $transformation_plugin->applyTransformation(
5711 $data,
5712 $transform_options,
5713 $meta
5715 : $this->$default_function($data)
5717 . ' <code>[-&gt;' . $dispval . ']</code>';
5719 } else {
5721 if ($relational_display == self::RELATIONAL_KEY) {
5723 // user chose "relational key" in the display options, so
5724 // the title contains the display field
5725 $title = (! empty($dispval))
5726 ? ' title="' . htmlspecialchars($dispval) . '"'
5727 : '';
5729 } else {
5730 $title = ' title="' . htmlspecialchars($data) . '"';
5733 $_url_params = array(
5734 'db' => $map[$meta->name][3],
5735 'table' => $map[$meta->name][0],
5736 'pos' => '0',
5737 'sql_query' => 'SELECT * FROM '
5738 . PMA_Util::backquote(
5739 $map[$meta->name][3]
5740 ) . '.'
5741 . PMA_Util::backquote(
5742 $map[$meta->name][0]
5744 . ' WHERE '
5745 . PMA_Util::backquote(
5746 $map[$meta->name][1]
5748 . $where_comparison,
5751 $result .= '<a class="ajax" href="sql.php'
5752 . PMA_URL_getCommon($_url_params)
5753 . '"' . $title . '>';
5755 if ($transformation_plugin != $default_function) {
5756 // always apply a transformation on the real data,
5757 // not on the display field
5758 $result .= $transformation_plugin->applyTransformation(
5759 $data,
5760 $transform_options,
5761 $meta
5763 } else {
5765 if ($relational_display == self::RELATIONAL_DISPLAY_COLUMN) {
5766 // user chose "relational display field" in the
5767 // display options, so show display field in the cell
5768 $result .= $this->$default_function($dispval);
5769 } else {
5770 // otherwise display data in the cell
5771 $result .= $this->$default_function($data);
5775 $result .= '</a>';
5778 } else {
5779 $result .= ($transformation_plugin != $default_function
5780 ? $transformation_plugin->applyTransformation(
5781 $data,
5782 $transform_options,
5783 $meta
5785 : $this->$default_function($data)
5789 // create hidden field if results from structure table
5790 if (isset($_GET['browse_distinct']) && ($_GET['browse_distinct'] == 1)) {
5792 $where_comparison = " = '" . $data . "'";
5794 $_url_params_for_show_data_row = array(
5795 'db' => $this->__get('db'),
5796 'table' => $meta->orgtable,
5797 'pos' => '0',
5798 'sql_query' => 'SELECT * FROM '
5799 . PMA_Util::backquote($this->__get('db'))
5800 . '.' . PMA_Util::backquote($meta->orgtable)
5801 . ' WHERE '
5802 . PMA_Util::backquote($meta->orgname)
5803 . $where_comparison,
5806 $result .= '<input type="hidden" class="data_browse_link" value="'
5807 . PMA_URL_getCommon($_url_params_for_show_data_row) . '" />';
5811 $result .= '</td>' . "\n";
5813 return $result;
5815 } // end of the '_getRowData()' function
5819 * Prepares a checkbox for multi-row submits
5821 * @param string $del_url delete url
5822 * @param array $is_display array with explicit indexes for all
5823 * the display elements
5824 * @param string $row_no the row number
5825 * @param string $where_clause_html url encoded where clause
5826 * @param array $condition_array array of conditions in the where clause
5827 * @param string $del_query delete query
5828 * @param string $id_suffix suffix for the id
5829 * @param string $class css classes for the td element
5831 * @return string the generated HTML
5833 * @access private
5835 * @see _getTableBody(), _getCheckboxAndLinks()
5837 private function _getCheckboxForMultiRowSubmissions(
5838 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5839 $del_query, $id_suffix, $class
5842 $ret = '';
5844 if (! empty($del_url) && $is_display['del_lnk'] != self::KILL_PROCESS) {
5846 $ret .= '<td ';
5847 if (! empty($class)) {
5848 $ret .= 'class="' . $class . '"';
5851 $ret .= ' class="center">'
5852 . '<input type="checkbox" id="id_rows_to_delete'
5853 . $row_no . $id_suffix
5854 . '" name="rows_to_delete[' . $row_no . ']"'
5855 . ' class="multi_checkbox checkall"'
5856 . ' value="' . $where_clause_html . '" '
5857 . ' />'
5858 . '<input type="hidden" class="condition_array" value="'
5859 . htmlspecialchars(json_encode($condition_array)) . '" />'
5860 . ' </td>';
5863 return $ret;
5865 } // end of the '_getCheckboxForMultiRowSubmissions()' function
5869 * Prepares an Edit link
5871 * @param string $edit_url edit url
5872 * @param string $class css classes for td element
5873 * @param string $edit_str text for the edit link
5874 * @param string $where_clause where clause
5875 * @param string $where_clause_html url encoded where clause
5877 * @return string the generated HTML
5879 * @access private
5881 * @see _getTableBody(), _getCheckboxAndLinks()
5883 private function _getEditLink(
5884 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5887 $ret = '';
5888 if (! empty($edit_url)) {
5890 $ret .= '<td class="' . $class . ' center" ' . ' ><span class="nowrap">'
5891 . PMA_Util::linkOrButton(
5892 $edit_url, $edit_str, array(), false
5895 * Where clause for selecting this row uniquely is provided as
5896 * a hidden input. Used by jQuery scripts for handling grid editing
5898 if (! empty($where_clause)) {
5899 $ret .= '<input type="hidden" class="where_clause" value ="'
5900 . $where_clause_html . '" />';
5902 $ret .= '</span></td>';
5905 return $ret;
5907 } // end of the '_getEditLink()' function
5911 * Prepares an Copy link
5913 * @param string $copy_url copy url
5914 * @param string $copy_str text for the copy link
5915 * @param string $where_clause where clause
5916 * @param string $where_clause_html url encoded where clause
5917 * @param string $class css classes for the td element
5919 * @return string the generated HTML
5921 * @access private
5923 * @see _getTableBody(), _getCheckboxAndLinks()
5925 private function _getCopyLink(
5926 $copy_url, $copy_str, $where_clause, $where_clause_html, $class
5929 $ret = '';
5930 if (! empty($copy_url)) {
5932 $ret .= '<td class="';
5933 if (! empty($class)) {
5934 $ret .= $class . ' ';
5937 $ret .= 'center" ' . ' ><span class="nowrap">'
5938 . PMA_Util::linkOrButton(
5939 $copy_url, $copy_str, array(), false
5943 * Where clause for selecting this row uniquely is provided as
5944 * a hidden input. Used by jQuery scripts for handling grid editing
5946 if (! empty($where_clause)) {
5947 $ret .= '<input type="hidden" class="where_clause" value="'
5948 . $where_clause_html . '" />';
5950 $ret .= '</span></td>';
5953 return $ret;
5955 } // end of the '_getCopyLink()' function
5959 * Prepares a Delete link
5961 * @param string $del_url delete url
5962 * @param string $del_str text for the delete link
5963 * @param string $js_conf text for the JS confirmation
5964 * @param string $class css classes for the td element
5966 * @return string the generated HTML
5968 * @access private
5970 * @see _getTableBody(), _getCheckboxAndLinks()
5972 private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
5975 $ret = '';
5976 if (! empty($del_url)) {
5978 $ret .= '<td class="';
5979 if (! empty($class)) {
5980 $ret .= $class . ' ';
5982 $ajax = PMA_Response::getInstance()->isAjax() ? ' ajax' : '';
5983 $ret .= 'center" ' . ' >'
5984 . PMA_Util::linkOrButton(
5985 $del_url, $del_str, array('class' => 'delete_row' . $ajax), false
5987 . '<div class="hide">' . $js_conf . '</div>'
5988 . '</td>';
5991 return $ret;
5993 } // end of the '_getDeleteLink()' function
5997 * Prepare checkbox and links at some position (left or right)
5998 * (only called for horizontal mode)
6000 * @param string $position the position of the checkbox and links
6001 * @param string $del_url delete url
6002 * @param array $is_display array with explicit indexes for all the
6003 * display elements
6004 * @param string $row_no row number
6005 * @param string $where_clause where clause
6006 * @param string $where_clause_html url encoded where clause
6007 * @param array $condition_array array of conditions in the where clause
6008 * @param string $del_query delete query
6009 * @param string $id_suffix suffix for the id
6010 * @param string $edit_url edit url
6011 * @param string $copy_url copy url
6012 * @param string $class css classes for the td elements
6013 * @param string $edit_str text for the edit link
6014 * @param string $copy_str text for the copy link
6015 * @param string $del_str text for the delete link
6016 * @param string $js_conf text for the JS confirmation
6018 * @return string the generated HTML
6020 * @access private
6022 * @see _getPlacedLinks()
6024 private function _getCheckboxAndLinks(
6025 $position, $del_url, $is_display, $row_no, $where_clause,
6026 $where_clause_html, $condition_array, $del_query, $id_suffix,
6027 $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
6030 $ret = '';
6032 if ($position == self::POSITION_LEFT) {
6034 $ret .= $this->_getCheckboxForMultiRowSubmissions(
6035 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
6036 $del_query, $id_suffix = '_left', ''
6039 $ret .= $this->_getEditLink(
6040 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
6043 $ret .= $this->_getCopyLink(
6044 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
6047 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
6049 } elseif ($position == self::POSITION_RIGHT) {
6051 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
6053 $ret .= $this->_getCopyLink(
6054 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
6057 $ret .= $this->_getEditLink(
6058 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
6061 $ret .= $this->_getCheckboxForMultiRowSubmissions(
6062 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
6063 $del_query, $id_suffix = '_right', ''
6066 } else { // $position == self::POSITION_NONE
6068 $ret .= $this->_getCheckboxForMultiRowSubmissions(
6069 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
6070 $del_query, $id_suffix = '_left', ''
6074 return $ret;
6076 } // end of the '_getCheckboxAndLinks()' function
6080 * Replace some html-unfriendly stuff
6082 * @param string $buffer String to process
6084 * @return String Escaped and cleaned up text suitable for html.
6086 * @access private
6088 * @see _getDataCellForBlobField(), _getRowData(),
6089 * _handleNonPrintableContents()
6091 private function _mimeDefaultFunction($buffer)
6093 $buffer = htmlspecialchars($buffer);
6094 $buffer = str_replace(
6095 "\011",
6096 ' &nbsp;&nbsp;&nbsp;',
6097 str_replace(' ', ' &nbsp;', $buffer)
6099 $buffer = preg_replace("@((\015\012)|(\015)|(\012))@", '<br />', $buffer);
6101 return $buffer;
6105 * Display binary columns as hex string if requested
6106 * otherwise escape the contents using the best possible way
6108 * @param string $content String to parse
6109 * @param string $binary_or_blob binary' or 'blob'
6110 * @param int $hexlength optional, get substring
6112 * @return String Displayable version of the binary string
6114 * @access private
6116 * @see _getDataCellForGeometryColumns
6117 * _getDataCellForNonNumericAndNonBlobColumns
6118 * _handleNonPrintableContents
6120 private function _displayBinaryAsPrintable(
6121 $content, $binary_or_blob, $hexlength = null
6123 if ($binary_or_blob === 'binary'
6124 && $_SESSION['tmpval']['display_binary_as_hex']
6126 $content = bin2hex($content);
6127 if ($hexlength !== null) {
6128 $content = $GLOBALS['PMA_String']->substr($content, $hexlength);
6130 } elseif (PMA_Util::containsNonPrintableAscii($content)) {
6131 if (PMA_PHP_INT_VERSION < 50400) {
6132 $content = htmlspecialchars(
6133 PMA_Util::replaceBinaryContents(
6134 $content
6137 } else {
6138 // The ENT_SUBSTITUTE option is available for PHP >= 5.4.0
6139 $content = htmlspecialchars(
6140 PMA_Util::replaceBinaryContents(
6141 $content
6143 ENT_SUBSTITUTE
6147 return $content;