Translated using Weblate (French)
[phpmyadmin.git] / libraries / DisplayResults.class.php
blobb4ec6a7d1beb734885488f600625982d7ae7fa6b
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 STRING_FIELD = 'string';
51 const GEOMETRY_FIELD = 'geometry';
52 const BLOB_FIELD = 'BLOB';
53 const BINARY_FIELD = 'BINARY';
55 const RELATIONAL_KEY = 'K';
56 const RELATIONAL_DISPLAY_COLUMN = 'D';
58 const GEOMETRY_DISP_GEOM = 'GEOM';
59 const GEOMETRY_DISP_WKT = 'WKT';
60 const GEOMETRY_DISP_WKB = 'WKB';
62 const SMART_SORT_ORDER = 'SMART';
63 const ASCENDING_SORT_DIR = 'ASC';
64 const DESCENDING_SORT_DIR = 'DESC';
66 const TABLE_TYPE_INNO_DB = 'InnoDB';
67 const ALL_ROWS = 'all';
68 const QUERY_TYPE_SELECT = 'SELECT';
70 const ROUTINE_PROCEDURE = 'procedure';
71 const ROUTINE_FUNCTION = 'function';
74 // Declare global fields
76 /** array with properties of the class */
77 private $_property_array = array(
79 /** string Database name */
80 'db' => null,
82 /** string Table name */
83 'table' => null,
85 /** string the URL to go back in case of errors */
86 'goto' => null,
88 /** string the SQL query */
89 'sql_query' => null,
91 /**
92 * integer the total number of rows returned by the SQL query without any
93 * appended "LIMIT" clause programmatically
95 'unlim_num_rows' => null,
97 /** array meta information about fields */
98 'fields_meta' => null,
100 /** boolean */
101 'is_count' => null,
103 /** integer */
104 'is_export' => null,
106 /** boolean */
107 'is_func' => null,
109 /** integer */
110 'is_analyse' => null,
112 /** integer the total number of rows returned by the SQL query */
113 'num_rows' => null,
115 /** integer the total number of fields returned by the SQL query */
116 'fields_cnt' => null,
118 /** double time taken for execute the SQL query */
119 'querytime' => null,
121 /** string path for theme images directory */
122 'pma_theme_image' => null,
124 /** string */
125 'text_dir' => null,
127 /** boolean */
128 'is_maint' => null,
130 /** boolean */
131 'is_explain' => null,
133 /** boolean */
134 'is_show' => null,
136 /** array table definitions */
137 'showtable' => null,
139 /** string */
140 'printview' => null,
142 /** string URL query */
143 'url_query' => null,
145 /** array column names to highlight */
146 'highlight_columns' => null,
148 /** array informations used with vertical display mode */
149 'vertical_display' => null,
151 /** array mime types information of fields */
152 'mime_map' => null,
154 /** boolean */
155 'editable' => null
159 * This variable contains the column transformation information
160 * for some of the system databases.
161 * One element of this array represent all relavant columns in all tables in
162 * one specific database
164 public $transformation_info;
168 * Get any property of this class
170 * @param string $property name of the property
172 * @return if property exist, value of the relavant property
174 public function __get($property)
176 if (array_key_exists($property, $this->_property_array)) {
177 return $this->_property_array[$property];
183 * Set values for any property of this class
185 * @param string $property name of the property
186 * @param any $value value to set
188 * @return void
190 public function __set($property, $value)
192 if (array_key_exists($property, $this->_property_array)) {
193 $this->_property_array[$property] = $value;
199 * Constructor for PMA_DisplayResults class
201 * @param string $db the database name
202 * @param string $table the table name
203 * @param string $goto the URL to go back in case of errors
204 * @param string $sql_query the SQL query
206 * @access public
208 public function __construct($db, $table, $goto, $sql_query)
210 $this->_setDefaultTransformations();
212 $this->__set('db', $db);
213 $this->__set('table', $table);
214 $this->__set('goto', $goto);
215 $this->__set('sql_query', $sql_query);
219 * Sets default transformations for some columns
221 * @return void
223 private function _setDefaultTransformations()
225 $sql_highlighting_data = array(
226 'libraries/plugins/transformations/Text_Plain_Formatted.class.php',
227 'Text_Plain_Formatted',
228 'Text_Plain'
230 $this->transformation_info = array(
231 'information_schema' => array(
232 'events' => array(
233 'event_definition' => $sql_highlighting_data
235 'processlist' => array(
236 'info' => $sql_highlighting_data
238 'routines' => array(
239 'routine_definition' => $sql_highlighting_data
241 'triggers' => array(
242 'action_statement' => $sql_highlighting_data
244 'views' => array(
245 'view_definition' => $sql_highlighting_data
250 $cfgRelation = PMA_getRelationsParam();
251 if ($cfgRelation['db']) {
252 $this->transformation_info[$cfgRelation['db']] = array();
253 $relDb = &$this->transformation_info[$cfgRelation['db']];
254 if ($cfgRelation['history']) {
255 $relDb[$cfgRelation['history']] = array(
256 'sqlquery' => $sql_highlighting_data
259 if ($cfgRelation['bookmark']) {
260 $relDb[$cfgRelation['bookmark']] = array(
261 'query' => $sql_highlighting_data
264 if ($cfgRelation['tracking']) {
265 $relDb[$cfgRelation['tracking']] = array(
266 'schema_sql' => $sql_highlighting_data,
267 'data_sql' => $sql_highlighting_data
274 * Set properties which were not initialized at the constructor
276 * @param type $unlim_num_rows integer the total number of rows returned by
277 * the SQL query without any appended
278 * "LIMIT" clause programmatically
279 * @param type $fields_meta array meta information about fields
280 * @param type $is_count boolean
281 * @param type $is_export integer
282 * @param type $is_func boolean
283 * @param type $is_analyse integer
284 * @param type $num_rows integer total no. of rows returned by SQL query
285 * @param type $fields_cnt integer total no.of fields returned by SQL query
286 * @param type $querytime double time taken for execute the SQL query
287 * @param type $pmaThemeImage string path for theme images directory
288 * @param type $text_dir string
289 * @param type $is_maint boolean
290 * @param type $is_explain boolean
291 * @param type $is_show boolean
292 * @param type $showtable array table definitions
293 * @param type $printview string
294 * @param type $url_query string URL query
295 * @param type $editable boolean whether the resutls set is editable
297 * @return void
299 * @see sql.php
301 public function setProperties(
302 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
303 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
304 $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
305 $editable
308 $this->__set('unlim_num_rows', $unlim_num_rows);
309 $this->__set('fields_meta', $fields_meta);
310 $this->__set('is_count', $is_count);
311 $this->__set('is_export', $is_export);
312 $this->__set('is_func', $is_func);
313 $this->__set('is_analyse', $is_analyse);
314 $this->__set('num_rows', $num_rows);
315 $this->__set('fields_cnt', $fields_cnt);
316 $this->__set('querytime', $querytime);
317 $this->__set('pma_theme_image', $pmaThemeImage);
318 $this->__set('text_dir', $text_dir);
319 $this->__set('is_maint', $is_maint);
320 $this->__set('is_explain', $is_explain);
321 $this->__set('is_show', $is_show);
322 $this->__set('showtable', $showtable);
323 $this->__set('printview', $printview);
324 $this->__set('url_query', $url_query);
325 $this->__set('editable', $editable);
327 } // end of the 'setProperties()' function
331 * Defines the display mode to use for the results of a SQL query
333 * It uses a synthetic string that contains all the required informations.
334 * In this string:
335 * - the first two characters stand for the action to do while
336 * clicking on the "edit" link (e.g. 'ur' for update a row, 'nn' for no
337 * edit link...);
338 * - the next two characters stand for the action to do while
339 * clicking on the "delete" link (e.g. 'kp' for kill a process, 'nn' for
340 * no delete link...);
341 * - the next characters are boolean values (1/0) and respectively stand
342 * for sorting links, navigation bar, "insert a new row" link, the
343 * bookmark feature, the expand/collapse text/blob fields button and
344 * the "display printable view" option.
345 * Of course '0'/'1' means the feature won't/will be enabled.
347 * @param string &$the_disp_mode the synthetic value for display_mode (see a few
348 * lines above for explanations)
349 * @param integer &$the_total the total number of rows returned by the SQL
350 * query without any programmatically appended
351 * LIMIT clause
352 * (just a copy of $unlim_num_rows if it exists,
353 * elsecomputed inside this function)
355 * @return array an array with explicit indexes for all the display
356 * elements
358 * @access private
360 * @see getTable()
362 private function _setDisplayMode(&$the_disp_mode, &$the_total)
365 // Following variables are needed for use in isset/empty or
366 // use with array indexes or safe use in foreach
367 $db = $this->__get('db');
368 $table = $this->__get('table');
369 $unlim_num_rows = $this->__get('unlim_num_rows');
370 $fields_meta = $this->__get('fields_meta');
371 $printview = $this->__get('printview');
373 // 1. Initializes the $do_display array
374 $do_display = array();
375 $do_display['edit_lnk'] = $the_disp_mode[0] . $the_disp_mode[1];
376 $do_display['del_lnk'] = $the_disp_mode[2] . $the_disp_mode[3];
377 $do_display['sort_lnk'] = (string) $the_disp_mode[4];
378 $do_display['nav_bar'] = (string) $the_disp_mode[5];
379 $do_display['ins_row'] = (string) $the_disp_mode[6];
380 $do_display['bkm_form'] = (string) $the_disp_mode[7];
381 $do_display['text_btn'] = (string) $the_disp_mode[8];
382 $do_display['pview_lnk'] = (string) $the_disp_mode[9];
384 // 2. Display mode is not "false for all elements" -> updates the
385 // display mode
386 if ($the_disp_mode != 'nnnn000000') {
388 if (isset($printview) && ($printview == '1')) {
389 // 2.0 Print view -> set all elements to false!
390 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
391 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
392 $do_display['sort_lnk'] = (string) '0';
393 $do_display['nav_bar'] = (string) '0';
394 $do_display['ins_row'] = (string) '0';
395 $do_display['bkm_form'] = (string) '0';
396 $do_display['text_btn'] = (string) '0';
397 $do_display['pview_lnk'] = (string) '0';
399 } elseif ($this->__get('is_count') || $this->__get('is_analyse')
400 || $this->__get('is_maint') || $this->__get('is_explain')
402 // 2.1 Statement is a "SELECT COUNT", a
403 // "CHECK/ANALYZE/REPAIR/OPTIMIZE", an "EXPLAIN" one or
404 // contains a "PROC ANALYSE" part
405 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
406 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
407 $do_display['sort_lnk'] = (string) '0';
408 $do_display['nav_bar'] = (string) '0';
409 $do_display['ins_row'] = (string) '0';
410 $do_display['bkm_form'] = (string) '1';
412 if ($this->__get('is_maint')) {
413 $do_display['text_btn'] = (string) '1';
414 } else {
415 $do_display['text_btn'] = (string) '0';
417 $do_display['pview_lnk'] = (string) '1';
419 } elseif ($this->__get('is_show')) {
420 // 2.2 Statement is a "SHOW..."
422 * 2.2.1
423 * @todo defines edit/delete links depending on show statement
425 $tmp = preg_match(
426 '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
427 . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
428 . ')@i',
429 $this->__get('sql_query'), $which
431 if (isset($which[1])
432 && (strpos(' ' . strtoupper($which[1]), 'PROCESSLIST') > 0)
434 // no edit link
435 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
436 // "kill process" type edit link
437 $do_display['del_lnk'] = self::KILL_PROCESS;
438 } else {
439 // Default case -> no links
440 // no edit link
441 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
442 // no delete link
443 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
445 // 2.2.2 Other settings
446 $do_display['sort_lnk'] = (string) '0';
447 $do_display['nav_bar'] = (string) '0';
448 $do_display['ins_row'] = (string) '0';
449 $do_display['bkm_form'] = (string) '1';
450 $do_display['text_btn'] = (string) '1';
451 $do_display['pview_lnk'] = (string) '1';
453 } else {
454 // 2.3 Other statements (ie "SELECT" ones) -> updates
455 // $do_display['edit_lnk'], $do_display['del_lnk'] and
456 // $do_display['text_btn'] (keeps other default values)
457 $prev_table = $fields_meta[0]->table;
458 $do_display['text_btn'] = (string) '1';
460 for ($i = 0; $i < $this->__get('fields_cnt'); $i++) {
462 $is_link = ($do_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
463 || ($do_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
464 || ($do_display['sort_lnk'] != '0')
465 || ($do_display['ins_row'] != '0');
467 // 2.3.2 Displays edit/delete/sort/insert links?
468 if ($is_link
469 && (($fields_meta[$i]->table == '')
470 || ($fields_meta[$i]->table != $prev_table))
472 // don't display links
473 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
474 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
476 * @todo May be problematic with same field names
477 * in two joined table.
479 // $do_display['sort_lnk'] = (string) '0';
480 $do_display['ins_row'] = (string) '0';
481 if ($do_display['text_btn'] == '1') {
482 break;
484 } // end if (2.3.2)
486 // 2.3.3 Always display print view link
487 $do_display['pview_lnk'] = (string) '1';
488 $prev_table = $fields_meta[$i]->table;
490 } // end for
491 } // end if..elseif...else (2.1 -> 2.3)
492 } // end if (2)
494 // 3. Gets the total number of rows if it is unknown
495 if (isset($unlim_num_rows) && $unlim_num_rows != '') {
496 $the_total = $unlim_num_rows;
497 } elseif ((($do_display['nav_bar'] == '1')
498 || ($do_display['sort_lnk'] == '1'))
499 && (strlen($db) && !empty($table))
501 $the_total = PMA_Table::countRecords($db, $table);
504 // 4. If navigation bar or sorting fields names URLs should be
505 // displayed but there is only one row, change these settings to
506 // false
507 if ($do_display['nav_bar'] == '1' || $do_display['sort_lnk'] == '1') {
509 // - Do not display sort links if less than 2 rows.
510 // - For a VIEW we (probably) did not count the number of rows
511 // so don't test this number here, it would remove the possibility
512 // of sorting VIEW results.
513 if (isset($unlim_num_rows)
514 && ($unlim_num_rows < 2)
515 && ! PMA_Table::isView($db, $table)
517 // force display of navbar for vertical/horizontal display-choice.
518 // $do_display['nav_bar'] = (string) '0';
519 $do_display['sort_lnk'] = (string) '0';
521 } // end if (3)
523 // 5. Updates the synthetic var
524 $the_disp_mode = join('', $do_display);
526 return $do_display;
528 } // end of the 'setDisplayMode()' function
532 * Return true if we are executing a query in the form of
533 * "SELECT * FROM <a table> ..."
535 * @param array $analyzed_sql the analyzed query
537 * @return boolean
539 * @access private
541 * @see _getTableHeaders(), _getColumnParams()
543 private function _isSelect($analyzed_sql)
545 if (!isset($analyzed_sql[0]['select_expr'])) {
546 $analyzed_sql[0]['select_expr'] = 0;
549 return ! ($this->__get('is_count') || $this->__get('is_export')
550 || $this->__get('is_func') || $this->__get('is_analyse'))
551 && (count($analyzed_sql[0]['select_expr']) == 0)
552 && isset($analyzed_sql[0]['queryflags']['select_from'])
553 && (count($analyzed_sql[0]['table_ref']) == 1);
558 * Get a navigation button
560 * @param string $caption iconic caption for button
561 * @param string $title text for button
562 * @param integer $pos position for next query
563 * @param string $html_sql_query query ready for display
564 * @param string $onsubmit optional onsubmit clause
565 * @param string $input_for_real_end optional hidden field for special treatment
566 * @param string $onclick optional onclick clause
568 * @return string html content
570 * @access private
572 * @see _getMoveBackwardButtonsForTableNavigation(),
573 * _getMoveForwardButtonsForTableNavigation()
575 private function _getTableNavigationButton(
576 $caption, $title, $pos, $html_sql_query, $onsubmit = '',
577 $input_for_real_end = '', $onclick = ''
580 $caption_output = '';
581 if (in_array(
582 $GLOBALS['cfg']['TableNavigationLinksMode'],
583 array('icons', 'both')
586 $caption_output .= $caption;
589 if (in_array(
590 $GLOBALS['cfg']['TableNavigationLinksMode'],
591 array('text', 'both')
594 $caption_output .= '&nbsp;' . $title;
596 $title_output = ' title="' . $title . '"';
598 return '<td>'
599 . '<form action="sql.php" method="post" ' . $onsubmit . '>'
600 . PMA_generate_common_hidden_inputs(
601 $this->__get('db'), $this->__get('table')
603 . '<input type="hidden" name="sql_query" value="'
604 . $html_sql_query . '" />'
605 . '<input type="hidden" name="pos" value="' . $pos . '" />'
606 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
607 . '" />'
608 . $input_for_real_end
609 . '<input type="submit" name="navig"'
610 . ' class="ajax" '
611 . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
612 . '</form>'
613 . '</td>';
615 } // end function _getTableNavigationButton()
619 * Get a navigation bar to browse among the results of a SQL query
621 * @param integer $pos_next the offset for the "next" page
622 * @param integer $pos_prev the offset for the "previous" page
623 * @param string $id_for_direction_dropdown the id for the direction dropdown
624 * @param boolean $is_innodb whether its InnoDB or not
626 * @return string html content
628 * @access private
630 * @see _getTable()
632 private function _getTableNavigation(
633 $pos_next, $pos_prev, $id_for_direction_dropdown, $is_innodb
636 $table_navigation_html = '';
637 $showtable = $this->__get('showtable'); // To use in isset
639 // here, using htmlentities() would cause problems if the query
640 // contains accented characters
641 $html_sql_query = htmlspecialchars($this->__get('sql_query'));
644 * @todo move this to a central place
645 * @todo for other future table types
647 $is_innodb = (isset($showtable['Type'])
648 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
650 // Navigation bar
651 $table_navigation_html .= '<table class="navigation nospacing nopadding">'
652 . '<tr>'
653 . '<td class="navigation_separator"></td>';
655 // Move to the beginning or to the previous page
656 if ($_SESSION['tmp_user_values']['pos']
657 && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
660 $table_navigation_html
661 .= $this->_getMoveBackwardButtonsForTableNavigation(
662 $html_sql_query, $pos_prev
665 } // end move back
667 $nbTotalPage = 1;
668 //page redirection
669 // (unless we are showing all records)
670 if ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS) { //if1
672 $pageNow = @floor(
673 $_SESSION['tmp_user_values']['pos']
674 / $_SESSION['tmp_user_values']['max_rows']
675 ) + 1;
677 $nbTotalPage = @ceil(
678 $this->__get('unlim_num_rows')
679 / $_SESSION['tmp_user_values']['max_rows']
682 if ($nbTotalPage > 1) { //if2
684 $table_navigation_html .= '<td>';
685 $_url_params = array(
686 'db' => $this->__get('db'),
687 'table' => $this->__get('table'),
688 'sql_query' => $this->__get('sql_query'),
689 'goto' => $this->__get('goto'),
692 //<form> to keep the form alignment of button < and <<
693 // and also to know what to execute when the selector changes
694 $table_navigation_html .= '<form action="sql.php'
695 . PMA_generate_common_url($_url_params)
696 . '" method="post">';
698 $table_navigation_html .= PMA_Util::pageselector(
699 'pos',
700 $_SESSION['tmp_user_values']['max_rows'],
701 $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
704 $table_navigation_html .= '</form>'
705 . '</td>';
706 } //_if2
707 } //_if1
709 // Display the "Show all" button if allowed
710 if (($this->__get('num_rows') < $this->__get('unlim_num_rows'))
711 && ($GLOBALS['cfg']['ShowAll']
712 || ($GLOBALS['cfg']['MaxRows'] * 5 >= $this->__get('unlim_num_rows')))
715 $table_navigation_html .= $this->_getShowAllButtonForTableNavigation(
716 $html_sql_query
719 } // end show all
721 // Move to the next page or to the last one
722 $endpos = $_SESSION['tmp_user_values']['pos']
723 + $_SESSION['tmp_user_values']['max_rows'];
725 if (($endpos < $this->__get('unlim_num_rows'))
726 && ($this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows'])
727 && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
730 $table_navigation_html
731 .= $this->_getMoveForwardButtonsForTableNavigation(
732 $html_sql_query, $pos_next, $is_innodb
735 } // end move toward
737 // show separator if pagination happen
738 if ($nbTotalPage > 1) {
739 $table_navigation_html
740 .= '<td><div class="navigation_separator">|</div></td>';
743 $table_navigation_html .= '<td>'
744 . '<div class="save_edited hide">'
745 . '<input type="submit" value="' . __('Save edited data') . '" />'
746 . '<div class="navigation_separator">|</div>'
747 . '</div>'
748 . '</td>'
749 . '<td>'
750 . '<div class="restore_column hide">'
751 . '<input type="submit" value="' . __('Restore column order') . '" />'
752 . '<div class="navigation_separator">|</div>'
753 . '</div>'
754 . '</td>';
756 // if displaying a VIEW, $unlim_num_rows could be zero because
757 // of $cfg['MaxExactCountViews']; in this case, avoid passing
758 // the 5th parameter to checkFormElementInRange()
759 // (this means we can't validate the upper limit
760 $table_navigation_html .= '<td class="navigation_goto">';
762 $table_navigation_html .= '<form action="sql.php" method="post" '
763 . 'onsubmit="return '
764 . '(checkFormElementInRange('
765 . 'this, '
766 . '\'session_max_rows\', '
767 . '\''
768 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
769 . '\', '
770 . '1)'
771 . ' &amp;&amp; '
772 . 'checkFormElementInRange('
773 . 'this, '
774 . '\'pos\', '
775 . '\''
776 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
777 . '\', '
778 . '0'
779 . (($this->__get('unlim_num_rows') > 0)
780 ? ', ' . ($this->__get('unlim_num_rows') - 1)
781 : ''
783 . ')'
784 . ')'
785 .'">';
787 $table_navigation_html .= PMA_generate_common_hidden_inputs(
788 $this->__get('db'), $this->__get('table')
791 $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
792 $html_sql_query, $pos_next, $id_for_direction_dropdown
795 $table_navigation_html .= '</form>'
796 . '</td>'
797 . '<td class="navigation_separator"></td>'
798 . '</tr>'
799 . '</table>';
801 return $table_navigation_html;
803 } // end of the '_getTableNavigation()' function
807 * Prepare move backward buttons - previous and first
809 * @param string $html_sql_query the sql encoded by html special characters
810 * @param integer $pos_prev the offset for the "previous" page
812 * @return string html content
814 * @access private
816 * @see _getTableNavigation()
818 private function _getMoveBackwardButtonsForTableNavigation(
819 $html_sql_query, $pos_prev
821 return $this->_getTableNavigationButton(
822 '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query
824 . $this->_getTableNavigationButton(
825 '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
826 $html_sql_query
828 } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
832 * Prepare Show All button for table navigation
834 * @param string $html_sql_query the sql encoded by html special characters
836 * @return string html content
838 * @access private
840 * @see _getTableNavigation()
842 private function _getShowAllButtonForTableNavigation($html_sql_query)
844 return "\n"
845 . '<td>'
846 . '<form action="sql.php" method="post">'
847 . PMA_generate_common_hidden_inputs(
848 $this->__get('db'), $this->__get('table')
850 . '<input type="hidden" name="sql_query" value="'
851 . $html_sql_query . '" />'
852 . '<input type="hidden" name="pos" value="0" />'
853 . '<input type="hidden" name="session_max_rows" value="all" />'
854 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
855 . '" />'
856 . '<input type="submit" name="navig" value="' . __('Show all') . '" />'
857 . '</form>'
858 . '</td>';
859 } // end of the '_getShowAllButtonForTableNavigation()' function
863 * Prepare move farward buttons - next and last
865 * @param string $html_sql_query the sql encoded by html special characters
866 * @param integer $pos_next the offset for the "next" page
867 * @param boolean $is_innodb whether its InnoDB or not
869 * @return string $buttons_html html content
871 * @access private
873 * @see _getTableNavigation()
875 private function _getMoveForwardButtonsForTableNavigation(
876 $html_sql_query, $pos_next, $is_innodb
879 // display the Next button
880 $buttons_html = $this->_getTableNavigationButton(
881 '&gt;',
882 _pgettext('Next page', 'Next'),
883 $pos_next,
884 $html_sql_query
887 // prepare some options for the End button
888 if ($is_innodb
889 && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
891 $input_for_real_end = '<input id="real_end_input" type="hidden" '
892 . 'name="find_real_end" value="1" />';
893 // no backquote around this message
894 $onclick = '';
895 } else {
896 $input_for_real_end = $onclick = '';
899 $onsubmit = 'onsubmit="return '
900 . ($_SESSION['tmp_user_values']['pos']
901 + $_SESSION['tmp_user_values']['max_rows']
902 < $this->__get('unlim_num_rows')
903 && $this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows'])
904 ? 'true'
905 : 'false' . '"';
907 // display the End button
908 $buttons_html .= $this->_getTableNavigationButton(
909 '&gt;&gt;',
910 _pgettext('Last page', 'End'),
911 @((ceil(
912 $this->__get('unlim_num_rows')
913 / $_SESSION['tmp_user_values']['max_rows']
914 )- 1) * $_SESSION['tmp_user_values']['max_rows']),
915 $html_sql_query, $onsubmit, $input_for_real_end, $onclick
918 return $buttons_html;
920 } // end of the '_getMoveForwardButtonsForTableNavigation()' function
924 * Prepare feilds followed by Show button for table navigation
925 * Start row, Number of rows, Headers every
927 * @param string $html_sql_query the sql encoded by html special
928 * characters
929 * @param integer $pos_next the offset for the "next" page
930 * @param string $id_for_direction_dropdown the id for the direction dropdown
932 * @return string $additional_fields_html html content
934 * @access private
936 * @see _getTableNavigation()
938 private function _getAdditionalFieldsForTableNavigation(
939 $html_sql_query, $pos_next, $id_for_direction_dropdown
942 $additional_fields_html = '';
944 $additional_fields_html .= '<input type="hidden" name="sql_query" '
945 . 'value="' . $html_sql_query . '" />'
946 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
947 . '" />'
948 . '<input type="submit" name="navig"'
949 . ' class="ajax"'
950 . ' value="' . __('Show') . ' :" />'
951 . __('Start row') . ': ' . "\n"
952 . '<input type="text" name="pos" size="3" value="'
953 . (($pos_next >= $this->__get('unlim_num_rows')) ? 0 : $pos_next)
954 . '" class="textfield" onfocus="this.select()" />'
955 . __('Number of rows') . ': ' . "\n"
956 . '<input type="text" name="session_max_rows" size="3" value="'
957 . (($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
958 ? $_SESSION['tmp_user_values']['max_rows']
959 : $GLOBALS['cfg']['MaxRows'])
960 . '" class="textfield" onfocus="this.select()" />';
962 if ($GLOBALS['cfg']['ShowDisplayDirection']) {
963 // Display mode (horizontal/vertical and repeat headers)
964 $additional_fields_html .= __('Mode') . ': ' . "\n";
965 $choices = array(
966 'horizontal' => __('horizontal'),
967 'horizontalflipped' => __('horizontal (rotated headers)'),
968 'vertical' => __('vertical')
971 $additional_fields_html .= PMA_Util::getDropdown(
972 'disp_direction', $choices,
973 $_SESSION['tmp_user_values']['disp_direction'],
974 $id_for_direction_dropdown
976 unset($choices);
979 $additional_fields_html .= sprintf(
980 __('Headers every %s rows'),
981 '<input type="text" size="3" name="repeat_cells" value="'
982 . $_SESSION['tmp_user_values']['repeat_cells']
983 . '" class="textfield" /> '
986 return $additional_fields_html;
988 } // end of the '_getAdditionalFieldsForTableNavigation()' function
992 * Get the headers of the results table
994 * @param array &$is_display which elements to display
995 * @param array $analyzed_sql the analyzed query
996 * @param string $sort_expression sort expression
997 * @param string $sort_expression_nodirection sort expression without direction
998 * @param string $sort_direction sort direction
999 * @param boolean $is_limited_display with limited operations or not
1001 * @return string html content
1003 * @access private
1005 * @see getTable()
1007 private function _getTableHeaders(
1008 &$is_display, $analyzed_sql = '',
1009 $sort_expression = '', $sort_expression_nodirection = '',
1010 $sort_direction = '', $is_limited_display = false
1013 $table_headers_html = '';
1014 // Following variable are needed for use in isset/empty or
1015 // use with array indexes/safe use in foreach
1016 $fields_meta = $this->__get('fields_meta');
1017 $highlight_columns = $this->__get('highlight_columns');
1018 $printview = $this->__get('printview');
1019 $vertical_display = $this->__get('vertical_display');
1021 // required to generate sort links that will remember whether the
1022 // "Show all" button has been clicked
1023 $sql_md5 = md5($this->__get('sql_query'));
1024 $session_max_rows = $is_limited_display
1026 : $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'];
1028 $direction = isset($_SESSION['tmp_user_values']['disp_direction'])
1029 ? $_SESSION['tmp_user_values']['disp_direction']
1030 : '';
1032 if ($analyzed_sql == '') {
1033 $analyzed_sql = array();
1036 $directionCondition = ($direction == self::DISP_DIR_HORIZONTAL)
1037 || ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED);
1039 // can the result be sorted?
1040 if ($is_display['sort_lnk'] == '1') {
1042 list($unsorted_sql_query, $drop_down_html)
1043 = $this->_getUnsortedSqlAndSortByKeyDropDown(
1044 $analyzed_sql, $sort_expression
1047 $table_headers_html .= $drop_down_html;
1051 // Output data needed for grid editing
1052 $table_headers_html .= '<input id="save_cells_at_once" type="hidden" value="'
1053 . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
1054 . '<div class="common_hidden_inputs">'
1055 . PMA_generate_common_hidden_inputs(
1056 $this->__get('db'), $this->__get('table')
1058 . '</div>';
1060 // Output data needed for column reordering and show/hide column
1061 if ($this->_isSelect($analyzed_sql)) {
1062 $table_headers_html .= $this->_getDataForResettingColumnOrder();
1065 $vertical_display['emptypre'] = 0;
1066 $vertical_display['emptyafter'] = 0;
1067 $vertical_display['textbtn'] = '';
1068 $full_or_partial_text_link = null;
1070 $this->__set('vertical_display', $vertical_display);
1072 // Display options (if we are not in print view)
1073 if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
1075 $table_headers_html .= $this->_getOptionsBlock();
1077 // prepare full/partial text button or link
1078 $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
1081 // Start of form for multi-rows edit/delete/export
1082 $table_headers_html .= $this->_getFormForMultiRowOperations(
1083 $is_display['del_lnk']
1086 // 1. Set $colspan or $rowspan and generate html with full/partial
1087 // text button or link
1088 list($colspan, $rowspan, $button_html)
1089 = $this->_getFieldVisibilityParams(
1090 $directionCondition, $is_display, $full_or_partial_text_link
1093 $table_headers_html .= $button_html;
1095 // 2. Displays the fields' name
1096 // 2.0 If sorting links should be used, checks if the query is a "JOIN"
1097 // statement (see 2.1.3)
1099 // 2.0.1 Prepare Display column comments if enabled
1100 // ($GLOBALS['cfg']['ShowBrowseComments']).
1101 // Do not show comments, if using horizontalflipped mode,
1102 // because of space usage
1103 $comments_map = $this->_getTableCommentsArray($direction, $analyzed_sql);
1105 if ($GLOBALS['cfgRelation']['commwork']
1106 && $GLOBALS['cfgRelation']['mimework']
1107 && $GLOBALS['cfg']['BrowseMIME']
1108 && ! $_SESSION['tmp_user_values']['hide_transformation']
1110 include_once './libraries/transformations.lib.php';
1111 $this->__set(
1112 'mime_map',
1113 PMA_getMIME($this->__get('db'), $this->__get('table'))
1117 // See if we have to highlight any header fields of a WHERE query.
1118 // Uses SQL-Parser results.
1119 $this->_setHighlightedColumnGlobalField($analyzed_sql);
1121 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
1123 for ($j = 0; $j < $this->__get('fields_cnt'); $j++) {
1125 // assign $i with appropriate column order
1126 $i = $col_order ? $col_order[$j] : $j;
1128 // See if this column should get highlight because it's used in the
1129 // where-query.
1130 $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
1131 || isset($highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)]))
1132 ? true
1133 : false;
1135 // 2.0 Prepare comment-HTML-wrappers for each row, if defined/enabled.
1136 $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
1138 $vertical_display = $this->__get('vertical_display');
1140 if (($is_display['sort_lnk'] == '1') && ! $is_limited_display) {
1142 list($order_link, $sorted_headrer_html)
1143 = $this->_getOrderLinkAndSortedHeaderHtml(
1144 $fields_meta[$i], $sort_expression,
1145 $sort_expression_nodirection, $i, $unsorted_sql_query,
1146 $session_max_rows, $direction, $comments,
1147 $sort_direction, $directionCondition, $col_visib,
1148 $col_visib[$j], $condition_field
1151 $table_headers_html .= $sorted_headrer_html;
1153 $vertical_display['desc'][] = ' <th '
1154 . 'class="draggable'
1155 . ($condition_field ? ' condition' : '')
1156 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1157 . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
1158 } else {
1159 // 2.2 Results can't be sorted
1161 if ($directionCondition) {
1162 $table_headers_html
1163 .= $this->_getDraggableClassForNonSortableColumns(
1164 $col_visib, $col_visib[$j], $condition_field,
1165 $direction, $fields_meta[$i], $comments
1169 $vertical_display['desc'][] = ' <th '
1170 . 'class="draggable'
1171 . ($condition_field ? ' condition"' : '')
1172 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1173 . '">' . "\n" . ' '
1174 . htmlspecialchars($fields_meta[$i]->name)
1175 . "\n" . $comments . ' </th>';
1176 } // end else (2.2)
1178 $this->__set('vertical_display', $vertical_display);
1180 } // end for
1182 // Display column at rightside - checkboxes or empty column
1183 $table_headers_html .= $this->_getColumnAtRightSide(
1184 $is_display, $directionCondition, $full_or_partial_text_link,
1185 $colspan, $rowspan
1188 if ($directionCondition) {
1189 $table_headers_html .= '</tr>'
1190 . '</thead>';
1193 return $table_headers_html;
1195 } // end of the '_getTableHeaders()' function
1199 * Prepare unsorted sql query and sort by key drop down
1201 * @param array $analyzed_sql the analyzed query
1202 * @param string $sort_expression sort expression
1204 * @return array two element array - $unsorted_sql_query, $drop_down_html
1206 * @access private
1208 * @see _getTableHeaders()
1210 private function _getUnsortedSqlAndSortByKeyDropDown(
1211 $analyzed_sql, $sort_expression
1214 $drop_down_html = '';
1216 // Just as fallback
1217 $unsorted_sql_query = $this->__get('sql_query');
1218 if (isset($analyzed_sql[0]['unsorted_query'])) {
1219 $unsorted_sql_query = $analyzed_sql[0]['unsorted_query'];
1221 // Handles the case of multiple clicks on a column's header
1222 // which would add many spaces before "ORDER BY" in the
1223 // generated query.
1224 $unsorted_sql_query = trim($unsorted_sql_query);
1226 // sorting by indexes, only if it makes sense (only one table ref)
1227 if (isset($analyzed_sql)
1228 && isset($analyzed_sql[0])
1229 && isset($analyzed_sql[0]['querytype'])
1230 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
1231 && isset($analyzed_sql[0]['table_ref'])
1232 && (count($analyzed_sql[0]['table_ref']) == 1)
1234 // grab indexes data:
1235 $indexes = PMA_Index::getFromTable(
1236 $this->__get('table'),
1237 $this->__get('db')
1240 // do we have any index?
1241 if ($indexes) {
1242 $drop_down_html = $this->_getSortByKeyDropDown(
1243 $indexes, $sort_expression,
1244 $unsorted_sql_query
1249 return array($unsorted_sql_query, $drop_down_html);
1251 } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function
1255 * Prepare sort by key dropdown - html code segment
1257 * @param array $indexes the indexes of the table for sort criteria
1258 * @param string $sort_expression the sort expression
1259 * @param string $unsorted_sql_query the unsorted sql query
1261 * @return string $drop_down_html html content
1263 * @access private
1265 * @see _getTableHeaders()
1267 private function _getSortByKeyDropDown(
1268 $indexes, $sort_expression, $unsorted_sql_query
1271 $drop_down_html = '';
1273 $drop_down_html .= '<form action="sql.php" method="post">' . "\n"
1274 . PMA_generate_common_hidden_inputs(
1275 $this->__get('db'), $this->__get('table')
1277 . __('Sort by key')
1278 . ': <select name="sql_query" class="autosubmit">' . "\n";
1280 $used_index = false;
1281 $local_order = (isset($sort_expression) ? $sort_expression : '');
1283 foreach ($indexes as $index) {
1285 $asc_sort = '`'
1286 . implode('` ASC, `', array_keys($index->getColumns()))
1287 . '` ASC';
1289 $desc_sort = '`'
1290 . implode('` DESC, `', array_keys($index->getColumns()))
1291 . '` DESC';
1293 $used_index = $used_index
1294 || ($local_order == $asc_sort)
1295 || ($local_order == $desc_sort);
1297 if (preg_match(
1298 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|'
1299 . 'FOR UPDATE|LOCK IN SHARE MODE))@is',
1300 $unsorted_sql_query, $my_reg
1301 )) {
1302 $unsorted_sql_query_first_part = $my_reg[1];
1303 $unsorted_sql_query_second_part = $my_reg[2];
1304 } else {
1305 $unsorted_sql_query_first_part = $unsorted_sql_query;
1306 $unsorted_sql_query_second_part = '';
1309 $drop_down_html .= '<option value="'
1310 . htmlspecialchars(
1311 $unsorted_sql_query_first_part . "\n"
1312 . ' ORDER BY ' . $asc_sort
1313 . $unsorted_sql_query_second_part
1315 . '"' . ($local_order == $asc_sort
1316 ? ' selected="selected"'
1317 : '')
1318 . '>' . htmlspecialchars($index->getName()) . ' ('
1319 . __('Ascending') . ')</option>';
1321 $drop_down_html .= '<option value="'
1322 . htmlspecialchars(
1323 $unsorted_sql_query_first_part . "\n"
1324 . ' ORDER BY ' . $desc_sort
1325 . $unsorted_sql_query_second_part
1327 . '"' . ($local_order == $desc_sort
1328 ? ' selected="selected"'
1329 : '')
1330 . '>' . htmlspecialchars($index->getName()) . ' ('
1331 . __('Descending') . ')</option>';
1334 $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query)
1335 . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None')
1336 . '</option>'
1337 . '</select>' . "\n"
1338 . '</form>' . "\n";
1340 return $drop_down_html;
1342 } // end of the '_getSortByKeyDropDown()' function
1346 * Set column span, row span and prepare html with full/partial
1347 * text button or link
1349 * @param boolean $directionCondition display direction horizontal or
1350 * horizontalflipped
1351 * @param array &$is_display which elements to display
1352 * @param string $full_or_partial_text_link full/partial link or text button
1354 * @return array 3 element array - $colspan, $rowspan, $button_html
1356 * @access private
1358 * @see _getTableHeaders()
1360 private function _getFieldVisibilityParams(
1361 $directionCondition, &$is_display, $full_or_partial_text_link
1364 $button_html = '';
1365 $colspan = $rowspan = null;
1366 $vertical_display = $this->__get('vertical_display');
1368 // 1. Displays the full/partial text button (part 1)...
1369 if ($directionCondition) {
1371 $button_html .= '<thead><tr>' . "\n";
1373 $colspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1374 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1375 ? ' colspan="4"'
1376 : '';
1378 } else {
1379 $rowspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1380 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1381 ? ' rowspan="4"'
1382 : '';
1385 // ... before the result table
1386 if ((($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
1387 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
1388 && ($is_display['text_btn'] == '1')
1391 $vertical_display['emptypre']
1392 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1393 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1395 if ($directionCondition) {
1397 $button_html .= '<th colspan="' . $this->__get('fields_cnt') . '">'
1398 . '</th>'
1399 . '</tr>'
1400 . '<tr>';
1402 // end horizontal/horizontalflipped mode
1403 } else {
1405 $span = $this->__get('num_rows') + 1 + floor(
1406 $this->__get('num_rows')
1407 / $_SESSION['tmp_user_values']['repeat_cells']
1409 $button_html .= '<tr><th colspan="' . $span . '"></th></tr>';
1411 } // end vertical mode
1413 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1414 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1415 && ($is_display['text_btn'] == '1')
1417 // ... at the left column of the result table header if possible
1418 // and required
1420 $vertical_display['emptypre']
1421 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1422 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1424 if ($directionCondition) {
1426 $button_html .= '<th ' . $colspan . '>'
1427 . $full_or_partial_text_link . '</th>';
1428 // end horizontal/horizontalflipped mode
1430 } else {
1432 $vertical_display['textbtn']
1433 = ' <th ' . $rowspan . ' class="vmiddle">' . "\n"
1434 . ' ' . "\n"
1435 . ' </th>' . "\n";
1436 } // end vertical mode
1438 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1439 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1440 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1441 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1443 // ... elseif no button, displays empty(ies) col(s) if required
1445 $vertical_display['emptypre']
1446 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1447 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1449 if ($directionCondition) {
1451 $button_html .= '<td ' . $colspan . '></td>';
1453 // end horizontal/horizontalfipped mode
1454 } else {
1455 $vertical_display['textbtn'] = ' <td' . $rowspan .
1456 '></td>' . "\n";
1457 } // end vertical mode
1459 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
1460 && ($directionCondition)
1462 // ... elseif display an empty column if the actions links are
1463 // disabled to match the rest of the table
1464 $button_html .= '<th></th>';
1467 $this->__set('vertical_display', $vertical_display);
1469 return array($colspan, $rowspan, $button_html);
1471 } // end of the '_getFieldVisibilityParams()' function
1475 * Get table comments as array
1477 * @param boolean $direction display direction, horizontal
1478 * or horizontalflipped
1479 * @param array $analyzed_sql the analyzed query
1481 * @return array $comments_map table comments when condition true
1482 * null when condition falls
1484 * @access private
1486 * @see _getTableHeaders()
1488 private function _getTableCommentsArray($direction, $analyzed_sql)
1491 $comments_map = null;
1493 if ($GLOBALS['cfg']['ShowBrowseComments']
1494 && ($direction != self::DISP_DIR_HORIZONTAL_FLIPPED)
1496 $comments_map = array();
1497 if (isset($analyzed_sql[0])
1498 && is_array($analyzed_sql[0])
1499 && isset($analyzed_sql[0]['table_ref'])
1501 foreach ($analyzed_sql[0]['table_ref'] as $tbl) {
1502 $tb = $tbl['table_true_name'];
1503 $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb);
1504 unset($tb);
1509 return $comments_map;
1511 } // end of the '_getTableCommentsArray()' function
1515 * Set global array for store highlighted header fields
1517 * @param array $analyzed_sql the analyzed query
1519 * @return void
1521 * @access private
1523 * @see _getTableHeaders()
1525 private function _setHighlightedColumnGlobalField($analyzed_sql)
1528 $highlight_columns = array();
1529 if (isset($analyzed_sql) && isset($analyzed_sql[0])
1530 && isset($analyzed_sql[0]['where_clause_identifiers'])
1533 $wi = 0;
1534 if (isset($analyzed_sql[0]['where_clause_identifiers'])
1535 && is_array($analyzed_sql[0]['where_clause_identifiers'])
1537 foreach ($analyzed_sql[0]['where_clause_identifiers']
1538 as $wci_nr => $wci
1540 $highlight_columns[$wci] = 'true';
1545 $this->__set('highlight_columns', $highlight_columns);
1547 } // end of the '_setHighlightedColumnGlobalField()' function
1551 * Prepare data for column restoring and show/hide
1553 * @return string $data_html html content
1555 * @access private
1557 * @see _getTableHeaders()
1559 private function _getDataForResettingColumnOrder()
1562 $data_html = '';
1564 // generate the column order, if it is set
1565 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
1566 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
1568 if ($col_order) {
1569 $data_html .= '<input id="col_order" type="hidden" value="'
1570 . implode(',', $col_order) . '" />';
1573 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
1575 if ($col_visib) {
1576 $data_html .= '<input id="col_visib" type="hidden" value="'
1577 . implode(',', $col_visib) . '" />';
1580 // generate table create time
1581 if (! PMA_Table::isView($this->__get('db'), $this->__get('table'))) {
1582 $data_html .= '<input id="table_create_time" type="hidden" value="'
1583 . PMA_Table::sGetStatusInfo(
1584 $this->__get('db'), $this->__get('table'), 'Create_time'
1585 ) . '" />';
1588 return $data_html;
1590 } // end of the '_getDataForResettingColumnOrder()' function
1594 * Prepare option fields block
1596 * @return string $options_html html content
1598 * @access private
1600 * @see _getTableHeaders()
1602 private function _getOptionsBlock()
1605 $options_html = '';
1607 $options_html .= '<form method="post" action="sql.php" '
1608 . 'name="displayOptionsForm" '
1609 . 'id="displayOptionsForm"';
1611 $options_html .= ' class="ajax" ';
1613 $options_html .= '>';
1614 $url_params = array(
1615 'db' => $this->__get('db'),
1616 'table' => $this->__get('table'),
1617 'sql_query' => $this->__get('sql_query'),
1618 'goto' => $this->__get('goto'),
1619 'display_options_form' => 1
1622 $options_html .= PMA_generate_common_hidden_inputs($url_params)
1623 . '<br />'
1624 . PMA_Util::getDivForSliderEffect(
1625 'displayoptions', __('Options')
1627 . '<fieldset>';
1629 $options_html .= '<div class="formelement">';
1630 $choices = array(
1631 'P' => __('Partial texts'),
1632 'F' => __('Full texts')
1635 $options_html .= PMA_Util::getRadioFields(
1636 'display_text', $choices,
1637 $_SESSION['tmp_user_values']['display_text']
1639 . '</div>';
1641 if ($GLOBALS['cfgRelation']['relwork']
1642 && $GLOBALS['cfgRelation']['displaywork']
1644 $options_html .= '<div class="formelement">';
1645 $choices = array(
1646 'K' => __('Relational key'),
1647 'D' => __('Relational display column')
1650 $options_html .= PMA_Util::getRadioFields(
1651 'relational_display', $choices,
1652 $_SESSION['tmp_user_values']['relational_display']
1654 . '</div>';
1657 $options_html .= '<div class="formelement">'
1658 . PMA_Util::getCheckbox(
1659 'display_binary', __('Show binary contents'),
1660 ! empty($_SESSION['tmp_user_values']['display_binary']), false
1662 . '<br />'
1663 . PMA_Util::getCheckbox(
1664 'display_blob', __('Show BLOB contents'),
1665 ! empty($_SESSION['tmp_user_values']['display_blob']), false
1667 . '<br />'
1668 . PMA_Util::getCheckbox(
1669 'display_binary_as_hex', __('Show binary contents as HEX'),
1670 ! empty($_SESSION['tmp_user_values']['display_binary_as_hex']), false
1672 . '</div>';
1674 // I would have preferred to name this "display_transformation".
1675 // This is the only way I found to be able to keep this setting sticky
1676 // per SQL query, and at the same time have a default that displays
1677 // the transformations.
1678 $options_html .= '<div class="formelement">'
1679 . PMA_Util::getCheckbox(
1680 'hide_transformation', __('Hide browser transformation'),
1681 ! empty($_SESSION['tmp_user_values']['hide_transformation']), false
1683 . '</div>';
1685 if (! PMA_DRIZZLE) {
1686 $options_html .= '<div class="formelement">';
1687 $choices = array(
1688 'GEOM' => __('Geometry'),
1689 'WKT' => __('Well Known Text'),
1690 'WKB' => __('Well Known Binary')
1693 $options_html .= PMA_Util::getRadioFields(
1694 'geometry_display', $choices,
1695 $_SESSION['tmp_user_values']['geometry_display']
1697 . '</div>';
1700 $options_html .= '<div class="clearfloat"></div>'
1701 . '</fieldset>';
1703 $options_html .= '<fieldset class="tblFooters">'
1704 . '<input type="submit" value="' . __('Go') . '" />'
1705 . '</fieldset>'
1706 . '</div>'
1707 . '</form>';
1709 return $options_html;
1711 } // end of the '_getOptionsBlock()' function
1715 * Get full/partial text button or link
1717 * @return string html content
1719 * @access private
1721 * @see _getTableHeaders()
1723 private function _getFullOrPartialTextButtonOrLink()
1726 $url_params_full_text = array(
1727 'db' => $this->__get('db'),
1728 'table' => $this->__get('table'),
1729 'sql_query' => $this->__get('sql_query'),
1730 'goto' => $this->__get('goto'),
1731 'full_text_button' => 1
1734 if ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_FULL_TEXT) {
1735 // currently in fulltext mode so show the opposite link
1736 $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png';
1737 $tmp_txt = __('Partial texts');
1738 $url_params_full_text['display_text'] = self::DISPLAY_PARTIAL_TEXT;
1739 } else {
1740 $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png';
1741 $tmp_txt = __('Full texts');
1742 $url_params_full_text['display_text'] = self::DISPLAY_FULL_TEXT;
1745 $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
1746 . $tmp_txt . '" title="' . $tmp_txt . '" />';
1747 $tmp_url = 'sql.php' . PMA_generate_common_url($url_params_full_text);
1749 return PMA_Util::linkOrButton(
1750 $tmp_url, $tmp_image, array(), false
1753 } // end of the '_getFullOrPartialTextButtonOrLink()' function
1757 * Prepare html form for multi row operations
1759 * @param string $del_lnk the delete link of current row
1761 * @return string $form_html html content
1763 * @access private
1765 * @see _getTableHeaders()
1767 private function _getFormForMultiRowOperations($del_lnk)
1770 $form_html = '';
1772 if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) {
1774 $form_html .= '<form method="post" action="tbl_row_action.php" '
1775 . 'name="resultsForm" id="resultsForm"';
1777 $form_html .= ' class="ajax" ';
1779 $form_html .= '>'
1780 . PMA_generate_common_hidden_inputs(
1781 $this->__get('db'), $this->__get('table'), 1
1783 . '<input type="hidden" name="goto" value="sql.php" />';
1786 $form_html .= '<table id="table_results" class="data';
1787 $form_html .= ' ajax';
1788 $form_html .= '">';
1790 return $form_html;
1792 } // end of the '_getFormForMultiRowOperations()' function
1796 * Get comment for row
1798 * @param array $comments_map comments array
1799 * @param array $fields_meta set of field properties
1801 * @return string $comment html content
1803 * @access private
1805 * @see _getTableHeaders()
1807 private function _getCommentForRow($comments_map, $fields_meta)
1809 $comments = '';
1810 if (isset($comments_map)
1811 && isset($comments_map[$fields_meta->table])
1812 && isset($comments_map[$fields_meta->table][$fields_meta->name])
1814 $comments = '<span class="tblcomment">'
1815 . htmlspecialchars(
1816 $comments_map[$fields_meta->table][$fields_meta->name]
1818 . '</span>';
1820 return $comments;
1821 } // end of the '_getCommentForRow()' function
1825 * Prepare parameters and html for sorted table header fields
1827 * @param array $fields_meta set of field properties
1828 * @param string $sort_expression sort expression
1829 * @param string $sort_expression_nodirection sort expression without direction
1830 * @param integer $column_index the index of the column
1831 * @param string $unsorted_sql_query the unsorted sql query
1832 * @param integer $session_max_rows maximum rows resulted by sql
1833 * @param string $direction the display direction
1834 * @param string $comments comment for row
1835 * @param string $sort_direction sort direction
1836 * @param boolean $directionCondition display direction horizontal
1837 * or horizontalflipped
1838 * @param boolean $col_visib column is visible(false)
1839 * array column isn't visible(string array)
1840 * @param string $col_visib_j element of $col_visib array
1841 * @param boolean $condition_field whether the column is a part of
1842 * the where clause
1844 * @return array 2 element array - $order_link, $sorted_header_html
1846 * @access private
1848 * @see _getTableHeaders()
1850 private function _getOrderLinkAndSortedHeaderHtml(
1851 $fields_meta, $sort_expression, $sort_expression_nodirection,
1852 $column_index, $unsorted_sql_query, $session_max_rows, $direction,
1853 $comments, $sort_direction, $directionCondition, $col_visib,
1854 $col_visib_j, $condition_field
1857 $sorted_header_html = '';
1859 // Checks if the table name is required; it's the case
1860 // for a query with a "JOIN" statement and if the column
1861 // isn't aliased, or in queries like
1862 // SELECT `1`.`master_field` , `2`.`master_field`
1863 // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2`
1865 $sort_tbl = (isset($fields_meta->table)
1866 && strlen($fields_meta->table))
1867 ? PMA_Util::backquote(
1868 $fields_meta->table
1869 ) . '.'
1870 : '';
1872 // Checks if the current column is used to sort the
1873 // results
1874 // the orgname member does not exist for all MySQL versions
1875 // but if found, it's the one on which to sort
1876 $name_to_use_in_sort = $fields_meta->name;
1877 $is_orgname = false;
1878 if (isset($fields_meta->orgname)
1879 && strlen($fields_meta->orgname)
1881 $name_to_use_in_sort = $fields_meta->orgname;
1882 $is_orgname = true;
1885 // $name_to_use_in_sort might contain a space due to
1886 // formatting of function expressions like "COUNT(name )"
1887 // so we remove the space in this situation
1888 $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort);
1890 $is_in_sort = $this->_isInSorted(
1891 $sort_expression, $sort_expression_nodirection,
1892 $sort_tbl, $name_to_use_in_sort
1895 // Check the field name for a bracket.
1896 // If it contains one, it's probably a function column
1897 // like 'COUNT(`field`)'
1898 // It still might be a column name of a view. See bug #3383711
1899 // Check is_orgname.
1900 if ((strpos($name_to_use_in_sort, '(') !== false) && ! $is_orgname) {
1901 $sort_order = "\n" . 'ORDER BY ' . $name_to_use_in_sort . ' ';
1902 } else {
1903 $sort_order = "\n" . 'ORDER BY ' . $sort_tbl
1904 . PMA_Util::backquote(
1905 $name_to_use_in_sort
1906 ) . ' ';
1908 unset($name_to_use_in_sort);
1909 unset($is_orgname);
1911 // Do define the sorting URL
1913 list($sort_order, $order_img) = $this->_getSortingUrlParams(
1914 $is_in_sort, $sort_direction, $fields_meta,
1915 $sort_order, $column_index
1918 if (preg_match(
1919 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|'
1920 . 'LOCK IN SHARE MODE))@is',
1921 $unsorted_sql_query, $regs3
1922 )) {
1923 $sorted_sql_query = $regs3[1] . $sort_order . $regs3[2];
1924 } else {
1925 $sorted_sql_query = $unsorted_sql_query . $sort_order;
1928 $_url_params = array(
1929 'db' => $this->__get('db'),
1930 'table' => $this->__get('table'),
1931 'sql_query' => $sorted_sql_query,
1932 'session_max_rows' => $session_max_rows
1934 $order_url = 'sql.php' . PMA_generate_common_url($_url_params);
1936 // Displays the sorting URL
1937 // enable sort order swapping for image
1938 $order_link = $this->_getSortOrderLink(
1939 $order_img, $column_index, $direction,
1940 $fields_meta, $order_url
1943 if ($directionCondition) {
1944 $sorted_header_html .= $this->_getDraggableClassForSortableColumns(
1945 $col_visib, $col_visib_j, $condition_field, $direction,
1946 $fields_meta, $order_link, $comments
1950 return array($order_link, $sorted_header_html);
1952 } // end of the '_getOrderLinkAndSortedHeaderHtml()' function
1956 * Check whether the column is sorted
1958 * @param string $sort_expression sort expression
1959 * @param string $sort_expression_nodirection sort expression without direction
1960 * @param string $sort_tbl the table name
1961 * @param string $name_to_use_in_sort the sorting column name
1963 * @return boolean $is_in_sort the column sorted or not
1965 * @access private
1967 * @see _getTableHeaders()
1969 private function _isInSorted(
1970 $sort_expression, $sort_expression_nodirection, $sort_tbl,
1971 $name_to_use_in_sort
1974 if (empty($sort_expression)) {
1975 $is_in_sort = false;
1976 } else {
1977 // Field name may be preceded by a space, or any number
1978 // of characters followed by a dot (tablename.fieldname)
1979 // so do a direct comparison for the sort expression;
1980 // this avoids problems with queries like
1981 // "SELECT id, count(id)..." and clicking to sort
1982 // on id or on count(id).
1983 // Another query to test this:
1984 // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p
1985 // (and try clicking on each column's header twice)
1986 if (! empty($sort_tbl)
1987 && strpos($sort_expression_nodirection, $sort_tbl) === false
1988 && strpos($sort_expression_nodirection, '(') === false
1990 $new_sort_expression_nodirection = $sort_tbl
1991 . $sort_expression_nodirection;
1992 } else {
1993 $new_sort_expression_nodirection = $sort_expression_nodirection;
1996 $is_in_sort = false;
1997 $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort;
1999 if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection)
2000 || $sort_name == str_replace('`', '', $sort_expression_nodirection)
2002 $is_in_sort = true;
2006 return $is_in_sort;
2008 } // end of the '_isInSorted()' function
2012 * Get sort url paramaeters - sort order and order image
2014 * @param boolean $is_in_sort the column sorted or not
2015 * @param string $sort_direction the sort direction
2016 * @param array $fields_meta set of field properties
2017 * @param string $sort_order the sorting order
2018 * @param integer $column_index the index of the column
2020 * @return array 2 element array - $sort_order, $order_img
2022 * @access private
2024 * @see _getTableHeaders()
2026 private function _getSortingUrlParams(
2027 $is_in_sort, $sort_direction, $fields_meta, $sort_order, $column_index
2030 if (! $is_in_sort) {
2032 // patch #455484 ("Smart" order)
2033 $GLOBALS['cfg']['Order'] = strtoupper($GLOBALS['cfg']['Order']);
2035 if ($GLOBALS['cfg']['Order'] === self::SMART_SORT_ORDER) {
2036 $sort_order .= (preg_match(
2037 '@time|date@i',
2038 $fields_meta->type
2039 )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
2040 } else {
2041 $sort_order .= $GLOBALS['cfg']['Order'];
2043 $order_img = '';
2045 } elseif ($sort_direction == self::DESCENDING_SORT_DIR) {
2047 $sort_order .= ' ASC';
2048 $order_img = ' ' . PMA_Util::getImage(
2049 's_desc.png', __('Descending'),
2050 array('class' => "soimg$column_index", 'title' => '')
2053 $order_img .= ' ' . PMA_Util::getImage(
2054 's_asc.png', __('Ascending'),
2055 array('class' => "soimg$column_index hide", 'title' => '')
2058 } else {
2060 $sort_order .= ' DESC';
2061 $order_img = ' ' . PMA_Util::getImage(
2062 's_asc.png', __('Ascending'),
2063 array('class' => "soimg$column_index", 'title' => '')
2066 $order_img .= ' ' . PMA_Util::getImage(
2067 's_desc.png', __('Descending'),
2068 array('class' => "soimg$column_index hide", 'title' => '')
2072 return array($sort_order, $order_img);
2074 } // end of the '_getSortingUrlParams()' function
2078 * Get sort order link
2080 * @param string $order_img the sort order image
2081 * @param integer $col_index the index of the column
2082 * @param string $direction the display direction
2083 * @param array $fields_meta set of field properties
2084 * @param string $order_url the url for sort
2086 * @return string the sort order link
2088 * @access private
2090 * @see _getTableHeaders()
2092 private function _getSortOrderLink(
2093 $order_img, $col_index, $direction, $fields_meta, $order_url
2096 $order_link_params = array();
2098 if (isset($order_img) && ($order_img != '')) {
2099 if (strstr($order_img, 'asc')) {
2100 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2101 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2102 } elseif (strstr($order_img, 'desc')) {
2103 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2104 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2108 if ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_AUTO) {
2110 $GLOBALS['cfg']['HeaderFlipType']
2111 = (PMA_USR_BROWSER_AGENT == 'IE')
2112 ? self::HEADER_FLIP_TYPE_CSS
2113 : self::HEADER_FLIP_TYPE_FAKE;
2116 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED
2117 && $GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS
2119 $order_link_params['style'] = 'direction: ltr; writing-mode: tb-rl;';
2122 $order_link_content = (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2123 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE))
2124 ? PMA_Util::flipstring(
2125 htmlspecialchars($fields_meta->name),
2126 "<br />\n"
2128 : htmlspecialchars($fields_meta->name);
2130 return PMA_Util::linkOrButton(
2131 $order_url, $order_link_content . $order_img,
2132 $order_link_params, false, true
2135 } // end of the '_getSortOrderLink()' function
2139 * Prepare columns to draggable effect for sortable columns
2141 * @param boolean $col_visib the column is visible (false)
2142 * array the column is not visible (string array)
2143 * @param string $col_visib_j element of $col_visib array
2144 * @param boolean $condition_field whether to add CSS class condition
2145 * @param string $direction the display direction
2146 * @param array $fields_meta set of field properties
2147 * @param string $order_link the order link
2148 * @param string $comments the comment for the column
2150 * @return string $draggable_html html content
2152 * @access private
2154 * @see _getTableHeaders()
2156 private function _getDraggableClassForSortableColumns(
2157 $col_visib, $col_visib_j, $condition_field, $direction, $fields_meta,
2158 $order_link, $comments
2161 $draggable_html = '<th';
2162 $th_class = array();
2163 $th_class[] = 'draggable';
2165 if ($col_visib && !$col_visib_j) {
2166 $th_class[] = 'hide';
2169 if ($condition_field) {
2170 $th_class[] = 'condition';
2173 $th_class[] = 'column_heading';
2174 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
2175 $th_class[] = 'pointer';
2178 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
2179 $th_class[] = 'marker';
2182 $draggable_html .= ' class="' . implode(' ', $th_class);
2184 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2185 $draggable_html .= ' vbottom';
2188 $draggable_html .= '" data-column="' . htmlspecialchars($fields_meta->name)
2189 . '">' . $order_link . $comments . '</th>';
2191 return $draggable_html;
2193 } // end of the '_getDraggableClassForSortableColumns()' function
2197 * Prepare columns to draggable effect for non sortable columns
2199 * @param boolean $col_visib the column is visible (false)
2200 * array the column is not visible (string array)
2201 * @param string $col_visib_j element of $col_visib array
2202 * @param boolean $condition_field whether to add CSS class condition
2203 * @param string $direction the display direction
2204 * @param array $fields_meta set of field properties
2205 * @param string $comments the comment for the column
2207 * @return string $draggable_html html content
2209 * @access private
2211 * @see _getTableHeaders()
2213 private function _getDraggableClassForNonSortableColumns(
2214 $col_visib, $col_visib_j, $condition_field,
2215 $direction, $fields_meta, $comments
2218 $draggable_html = '<th';
2219 $th_class = array();
2220 $th_class[] = 'draggable';
2222 if ($col_visib && !$col_visib_j) {
2223 $th_class[] = 'hide';
2226 if ($condition_field) {
2227 $th_class[] = 'condition';
2230 $draggable_html .= ' class="' . implode(' ', $th_class);
2231 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2232 $draggable_html .= ' vbottom';
2235 $draggable_html .= '"';
2236 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2237 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS)
2239 $draggable_html .= ' style="direction: ltr; writing-mode: tb-rl;"';
2242 $draggable_html .= ' data-column="'
2243 . htmlspecialchars($fields_meta->name) . '">';
2245 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2246 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE)
2249 $draggable_html .= PMA_Util::flipstring(
2250 htmlspecialchars($fields_meta->name), '<br />'
2253 } else {
2254 $draggable_html .= htmlspecialchars($fields_meta->name);
2257 $draggable_html .= "\n" . $comments . '</th>';
2259 return $draggable_html;
2261 } // end of the '_getDraggableClassForNonSortableColumns()' function
2265 * Prepare column to show at right side - check boxes or empty column
2267 * @param array &$is_display which elements to display
2268 * @param boolean $directionCondition display direction horizontal
2269 * or horizontalflipped
2270 * @param string $full_or_partial_text_link full/partial link or text button
2271 * @param string $colspan column span of table header
2272 * @param string $rowspan row span of table header
2274 * @return string html content
2276 * @access private
2278 * @see _getTableHeaders()
2280 private function _getColumnAtRightSide(
2281 &$is_display, $directionCondition, $full_or_partial_text_link,
2282 $colspan, $rowspan
2285 $right_column_html = '';
2286 $vertical_display = $this->__get('vertical_display');
2288 // Displays the needed checkboxes at the right
2289 // column of the result table header if possible and required...
2290 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2291 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2292 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2293 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
2294 && ($is_display['text_btn'] == '1')
2297 $vertical_display['emptyafter']
2298 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2299 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2301 if ($directionCondition) {
2302 $right_column_html .= "\n"
2303 . '<th ' . $colspan . '>' . $full_or_partial_text_link
2304 . '</th>';
2306 // end horizontal/horizontalflipped mode
2307 } else {
2308 $vertical_display['textbtn'] = ' <th ' . $rowspan
2309 . ' class="vmiddle">' . "\n"
2310 . ' ' . "\n"
2311 . ' </th>' . "\n";
2312 } // end vertical mode
2313 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2314 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2315 && (($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
2316 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
2317 && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent'])
2319 // ... elseif no button, displays empty columns if required
2320 // (unless coming from Browse mode print view)
2322 $vertical_display['emptyafter']
2323 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2324 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2326 if ($directionCondition) {
2327 $right_column_html .= "\n"
2328 . '<td ' . $colspan . '></td>';
2330 // end horizontal/horizontalflipped mode
2331 } else {
2332 $vertical_display['textbtn'] = ' <td' . $rowspan
2333 . '></td>' . "\n";
2334 } // end vertical mode
2337 $this->__set('vertical_display', $vertical_display);
2339 return $right_column_html;
2341 } // end of the '_getColumnAtRightSide()' function
2345 * Prepares the display for a value
2347 * @param string $class class of table cell
2348 * @param bool $condition_field whether to add CSS class condition
2349 * @param string $value value to display
2351 * @return string the td
2353 * @access private
2355 * @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(),
2356 * _getDataCellForNonNumericAndNonBlobColumns()
2358 private function _buildValueDisplay($class, $condition_field, $value)
2360 return '<td class="left ' . $class . ($condition_field ? ' condition' : '')
2361 . '">' . $value . '</td>';
2362 } // end of the '_buildValueDisplay()' function
2366 * Prepares the display for a null value
2368 * @param string $class class of table cell
2369 * @param bool $condition_field whether to add CSS class condition
2370 * @param object $meta the meta-information about this field
2371 * @param string $align cell allignment
2373 * @return string the td
2375 * @access private
2377 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2378 * _getDataCellForGeometryColumns(),
2379 * _getDataCellForNonNumericAndNonBlobColumns()
2381 private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
2383 // the null class is needed for grid editing
2384 return '<td ' . $align . ' class="'
2385 . $this->_addClass(
2386 $class, $condition_field, $meta, ''
2388 . ' null"><i>NULL</i></td>';
2389 } // end of the '_buildNullDisplay()' function
2393 * Prepares the display for an empty value
2395 * @param string $class class of table cell
2396 * @param bool $condition_field whether to add CSS class condition
2397 * @param object $meta the meta-information about this field
2398 * @param string $align cell allignment
2400 * @return string the td
2402 * @access private
2404 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2405 * _getDataCellForGeometryColumns(),
2406 * _getDataCellForNonNumericAndNonBlobColumns()
2408 private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
2410 return '<td ' . $align . ' class="'
2411 . $this->_addClass(
2412 $class, $condition_field, $meta, ' nowrap'
2414 . '"></td>';
2415 } // end of the '_buildEmptyDisplay()' function
2419 * Adds the relavant classes.
2421 * @param string $class class of table cell
2422 * @param bool $condition_field whether to add CSS class condition
2423 * @param object $meta the meta-information about the field
2424 * @param string $nowrap avoid wrapping
2425 * @param bool $is_field_truncated is field truncated (display ...)
2426 * @param string $transformation_plugin transformation plugin.
2427 * Can also be the default function:
2428 * PMA_mimeDefaultFunction
2429 * @param string $default_function default transformation function
2431 * @return string the list of classes
2433 * @access private
2435 * @see _buildNullDisplay(), _getRowData()
2437 private function _addClass(
2438 $class, $condition_field, $meta, $nowrap, $is_field_truncated = false,
2439 $transformation_plugin = '', $default_function = ''
2442 // Define classes to be added to this data field based on the type of data
2443 $enum_class = '';
2444 if (strpos($meta->flags, 'enum') !== false) {
2445 $enum_class = ' enum';
2448 $set_class = '';
2449 if (strpos($meta->flags, 'set') !== false) {
2450 $set_class = ' set';
2453 $bit_class = '';
2454 if (strpos($meta->type, 'bit') !== false) {
2455 $bit_class = ' bit';
2458 $mime_type_class = '';
2459 if (isset($meta->mimetype)) {
2460 $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype);
2463 return $class . ($condition_field ? ' condition' : '') . $nowrap
2464 . ' ' . ($is_field_truncated ? ' truncated' : '')
2465 . ($transformation_plugin != $default_function ? ' transformed' : '')
2466 . $enum_class . $set_class . $bit_class . $mime_type_class;
2468 } // end of the '_addClass()' function
2472 * Prepare the body of the results table
2474 * @param integer &$dt_result the link id associated to the query
2475 * which results have to be displayed
2476 * @param array &$is_display which elements to display
2477 * @param array $map the list of relations
2478 * @param array $analyzed_sql the analyzed query
2479 * @param boolean $is_limited_display with limited operations or not
2481 * @return string $table_body_html html content
2483 * @global array $row current row data
2485 * @access private
2487 * @see getTable()
2489 private function _getTableBody(
2490 &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false
2493 global $row; // mostly because of browser transformations,
2494 // to make the row-data accessible in a plugin
2496 $table_body_html = '';
2498 // query without conditions to shorten URLs when needed, 200 is just
2499 // guess, it should depend on remaining URL length
2500 $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql);
2502 $vertical_display = $this->__get('vertical_display');
2504 if (! is_array($map)) {
2505 $map = array();
2508 $row_no = 0;
2509 $vertical_display['edit'] = array();
2510 $vertical_display['copy'] = array();
2511 $vertical_display['delete'] = array();
2512 $vertical_display['data'] = array();
2513 $vertical_display['row_delete'] = array();
2514 $this->__set('vertical_display', $vertical_display);
2516 // name of the class added to all grid editable elements;
2517 // if we don't have all the columns of a unique key in the result set,
2518 // do not permit grid editing
2519 if ($is_limited_display || ! $this->__get('editable')) {
2520 $grid_edit_class = '';
2521 } else {
2522 switch ($GLOBALS['cfg']['GridEditing']) {
2523 case 'double-click':
2524 // trying to reduce generated HTML by using shorter
2525 // classes like click1 and click2
2526 $grid_edit_class = 'grid_edit click2';
2527 break;
2528 case 'click':
2529 $grid_edit_class = 'grid_edit click1';
2530 break;
2531 case 'disabled':
2532 $grid_edit_class = '';
2533 break;
2537 // prepare to get the column order, if available
2538 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
2540 // Correction University of Virginia 19991216 in the while below
2541 // Previous code assumed that all tables have keys, specifically that
2542 // the phpMyAdmin GUI should support row delete/edit only for such
2543 // tables.
2544 // Although always using keys is arguably the prescribed way of
2545 // defining a relational table, it is not required. This will in
2546 // particular be violated by the novice.
2547 // We want to encourage phpMyAdmin usage by such novices. So the code
2548 // below has been changed to conditionally work as before when the
2549 // table being displayed has one or more keys; but to display
2550 // delete/edit options correctly for tables without keys.
2552 $odd_row = true;
2553 $directionCondition
2554 = ($_SESSION['tmp_user_values']['disp_direction']
2555 == self::DISP_DIR_HORIZONTAL)
2556 || ($_SESSION['tmp_user_values']['disp_direction']
2557 == self::DISP_DIR_HORIZONTAL_FLIPPED);
2559 while ($row = PMA_DBI_fetch_row($dt_result)) {
2561 // "vertical display" mode stuff
2562 $table_body_html .= $this->_getVerticalDisplaySupportSegments(
2563 $vertical_display, $row_no, $directionCondition
2566 $alternating_color_class = ($odd_row ? 'odd' : 'even');
2567 $odd_row = ! $odd_row;
2569 if ($directionCondition) {
2570 // pointer code part
2571 $table_body_html .= '<tr class="' . $alternating_color_class . '">';
2574 // 1. Prepares the row
2575 // 1.1 Results from a "SELECT" statement -> builds the
2576 // WHERE clause to use in links (a unique key if possible)
2578 * @todo $where_clause could be empty, for example a table
2579 * with only one field and it's a BLOB; in this case,
2580 * avoid to display the delete and edit links
2582 list($where_clause, $clause_is_unique, $condition_array)
2583 = PMA_Util::getUniqueCondition(
2584 $dt_result,
2585 $this->__get('fields_cnt'),
2586 $this->__get('fields_meta'),
2587 $row
2589 $where_clause_html = urlencode($where_clause);
2591 // In print view these variable needs toinitialized
2592 $del_url = $del_query = $del_str = $edit_anchor_class
2593 = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
2595 // 1.2 Defines the URLs for the modify/delete link(s)
2597 if (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2598 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
2600 // We need to copy the value
2601 // or else the == 'both' check will always return true
2603 if ($GLOBALS['cfg']['ActionLinksMode'] === self::POSITION_BOTH) {
2604 $iconic_spacer = '<div class="nowrap">';
2605 } else {
2606 $iconic_spacer = '';
2609 // 1.2.1 Modify link(s) - update row case
2610 if ($is_display['edit_lnk'] == self::UPDATE_ROW) {
2612 list($edit_url, $copy_url, $edit_str, $copy_str,
2613 $edit_anchor_class)
2614 = $this->_getModifiedLinks(
2615 $where_clause,
2616 $clause_is_unique, $url_sql_query
2619 } // end if (1.2.1)
2621 // 1.2.2 Delete/Kill link(s)
2622 if (($is_display['del_lnk'] == self::DELETE_ROW)
2623 || ($is_display['del_lnk'] == self::KILL_PROCESS)
2626 list($del_query, $del_url, $del_str, $js_conf)
2627 = $this->_getDeleteAndKillLinks(
2628 $where_clause, $clause_is_unique,
2629 $url_sql_query, $is_display['del_lnk'],
2630 $row
2633 } // end if (1.2.2)
2635 // 1.3 Displays the links at left if required
2636 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2637 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2638 && $directionCondition
2641 $table_body_html .= $this->_getPlacedLinks(
2642 self::POSITION_LEFT, $del_url, $is_display, $row_no,
2643 $where_clause, $where_clause_html, $condition_array,
2644 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2645 $edit_str, $copy_str, $del_str, $js_conf
2648 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
2649 && $directionCondition
2652 $table_body_html .= $this->_getPlacedLinks(
2653 self::POSITION_NONE, $del_url, $is_display, $row_no,
2654 $where_clause, $where_clause_html, $condition_array,
2655 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2656 $edit_str, $copy_str, $del_str, $js_conf
2659 } // end if (1.3)
2660 } // end if (1)
2662 // 2. Displays the rows' values
2663 $table_body_html .= $this->_getRowValues(
2664 $dt_result, $row, $row_no, $col_order, $map,
2665 $grid_edit_class, $col_visib, $where_clause,
2666 $url_sql_query, $analyzed_sql, $directionCondition
2669 // 3. Displays the modify/delete links on the right if required
2670 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2671 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2672 && $directionCondition
2675 $table_body_html .= $this->_getPlacedLinks(
2676 self::POSITION_RIGHT, $del_url, $is_display, $row_no,
2677 $where_clause, $where_clause_html, $condition_array,
2678 $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class,
2679 $edit_str, $copy_str, $del_str, $js_conf
2682 } // end if (3)
2684 if ($directionCondition) {
2685 $table_body_html .= '</tr>';
2686 } // end if
2688 // 4. Gather links of del_urls and edit_urls in an array for later
2689 // output
2690 $this->_gatherLinksForLaterOutputs(
2691 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
2692 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url,
2693 $edit_str, $copy_url, $copy_str, $alternating_color_class,
2694 $condition_array
2697 $table_body_html .= $directionCondition ? "\n" : '';
2698 $row_no++;
2700 } // end while
2702 return $table_body_html;
2704 } // end of the '_getTableBody()' function
2708 * Get the values for one data row
2710 * @param integer &$dt_result the link id associated to the query
2711 * which results have to be displayed
2712 * @param array $row current row data
2713 * @param integer $row_no the index of current row
2714 * @param array $col_order the column order
2715 * false when a property not found
2716 * @param array $map the list of relations
2717 * @param string $grid_edit_class the class for all editable columns
2718 * @param boolean $col_visib column is visible(false)
2719 * array column isn't visible(string array)
2720 * @param string $where_clause where clause
2721 * @param string $url_sql_query the analyzed sql query
2722 * @param array $analyzed_sql the analyzed query
2723 * @param boolean $directionCondition the directional condition
2725 * @return string $row_values_html html content
2727 * @access private
2729 * @see _getTableBody()
2731 private function _getRowValues(
2732 &$dt_result, $row, $row_no, $col_order, $map,
2733 $grid_edit_class, $col_visib, $where_clause,
2734 $url_sql_query, $analyzed_sql, $directionCondition
2737 $row_values_html = '';
2739 // Following variable are needed for use in isset/empty or
2740 // use with array indexes/safe use in foreach
2741 $sql_query = $this->__get('sql_query');
2742 $fields_meta = $this->__get('fields_meta');
2743 $highlight_columns = $this->__get('highlight_columns');
2744 $mime_map = $this->__get('mime_map');
2746 $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order);
2748 for ($currentColumn = 0;
2749 $currentColumn < $this->__get('fields_cnt');
2750 ++$currentColumn) {
2752 // assign $i with appropriate column order
2753 $i = $col_order ? $col_order[$currentColumn] : $currentColumn;
2755 $meta = $fields_meta[$i];
2756 $not_null_class = $meta->not_null ? 'not_null' : '';
2757 $relation_class = isset($map[$meta->name]) ? 'relation' : '';
2758 $hide_class = ($col_visib && ! $col_visib[$currentColumn]
2759 // hide per <td> only if the display dir is not vertical
2760 && ($_SESSION['tmp_user_values']['disp_direction']
2761 != self::DISP_DIR_VERTICAL))
2762 ? 'hide'
2763 : '';
2765 // handle datetime-related class, for grid editing
2766 $field_type_class
2767 = $this->_getClassForDateTimeRelatedFields($meta->type);
2769 $is_field_truncated = false;
2770 // combine all the classes applicable to this column's value
2771 $class = $this->_getClassesForColumn(
2772 $grid_edit_class, $not_null_class, $relation_class,
2773 $hide_class, $field_type_class, $row_no
2776 // See if this column should get highlight because it's used in the
2777 // where-query.
2778 $condition_field = (isset($highlight_columns)
2779 && (isset($highlight_columns[$meta->name])
2780 || isset($highlight_columns[PMA_Util::backquote($meta->name)])))
2781 ? true
2782 : false;
2784 // Wrap MIME-transformations. [MIME]
2785 $default_function = '_mimeDefaultFunction'; // default_function
2786 $transformation_plugin = $default_function;
2787 $transform_options = array();
2789 if ($GLOBALS['cfgRelation']['mimework']
2790 && $GLOBALS['cfg']['BrowseMIME']
2793 if (isset($mime_map[$meta->name]['mimetype'])
2794 && isset($mime_map[$meta->name]['transformation'])
2795 && !empty($mime_map[$meta->name]['transformation'])
2798 $file = $mime_map[$meta->name]['transformation'];
2799 $include_file = 'libraries/plugins/transformations/' . $file;
2801 if (file_exists($include_file)) {
2803 include_once $include_file;
2804 $class_name = str_replace('.class.php', '', $file);
2805 // todo add $plugin_manager
2806 $plugin_manager = null;
2807 $transformation_plugin = new $class_name(
2808 $plugin_manager
2811 $transform_options = PMA_transformation_getOptions(
2812 isset($mime_map[$meta->name]
2813 ['transformation_options']
2815 ? $mime_map[$meta->name]
2816 ['transformation_options']
2817 : ''
2820 $meta->mimetype = str_replace(
2821 '_', '/',
2822 $mime_map[$meta->name]['mimetype']
2825 } // end if file_exists
2826 } // end if transformation is set
2827 } // end if mime/transformation works.
2829 $_url_params = array(
2830 'db' => $this->__get('db'),
2831 'table' => $this->__get('table'),
2832 'where_clause' => $where_clause,
2833 'transform_key' => $meta->name,
2836 if (! empty($sql_query)) {
2837 $_url_params['sql_query'] = $url_sql_query;
2840 $transform_options['wrapper_link']
2841 = PMA_generate_common_url($_url_params);
2843 $vertical_display = $this->__get('vertical_display');
2845 // Check whether the field needs to display with syntax highlighting
2847 if ($this->_isNeedToSyntaxHighlight($meta->name)
2848 && (trim($row[$i]) != '')
2851 $parsed_sql = PMA_SQP_parse($row[$i]);
2852 $row[$i] = PMA_Util::formatSql(
2853 $parsed_sql, $row[$i]
2855 include_once $this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][0];
2856 $transformation_plugin = new $this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][1](null);
2858 $transform_options = PMA_transformation_getOptions(
2859 isset($mime_map[$meta->name]['transformation_options'])
2860 ? $mime_map[$meta->name]['transformation_options']
2861 : ''
2864 $meta->mimetype = str_replace(
2865 '_', '/',
2866 $this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][2]
2871 // Check for the predefined fields need to show as link in schemas
2872 include_once 'libraries/special_schema_links.lib.php';
2874 if (isset($GLOBALS['special_schema_links'])
2875 && ($this->_isFieldNeedToLink(strtolower($meta->name)))
2878 $linking_url = $this->_getSpecialLinkUrl(
2879 $row[$i], $row_info, strtolower($meta->name)
2881 include_once "libraries/plugins/transformations/Text_Plain_Link.class.php";
2882 $transformation_plugin = new Text_Plain_Link(null);
2884 $transform_options = array(
2885 0 => $linking_url,
2886 2 => true
2889 $meta->mimetype = str_replace(
2890 '_', '/',
2891 'Text/Plain'
2896 if ($meta->numeric == 1) {
2897 // n u m e r i c
2899 $vertical_display['data'][$row_no][$i]
2900 = $this->_getDataCellForNumericColumns(
2901 $row[$i], $class, $condition_field, $meta, $map,
2902 $is_field_truncated, $analyzed_sql,
2903 $transformation_plugin, $default_function,
2904 $transform_options
2907 } elseif (stristr($meta->type, self::BLOB_FIELD)) {
2908 // b l o b
2910 // PMA_mysql_fetch_fields returns BLOB in place of
2911 // TEXT fields type so we have to ensure it's really a BLOB
2912 $field_flags = PMA_DBI_field_flags($dt_result, $i);
2914 $vertical_display['data'][$row_no][$i]
2915 = $this->_getDataCellForBlobColumns(
2916 $row[$i], $class, $meta, $_url_params, $field_flags,
2917 $transformation_plugin, $default_function,
2918 $transform_options, $condition_field, $is_field_truncated
2921 } elseif ($meta->type == self::GEOMETRY_FIELD) {
2922 // g e o m e t r y
2924 // Remove 'grid_edit' from $class as we do not allow to
2925 // inline-edit geometry data.
2926 $class = str_replace('grid_edit', '', $class);
2928 $vertical_display['data'][$row_no][$i]
2929 = $this->_getDataCellForGeometryColumns(
2930 $row[$i], $class, $meta, $map, $_url_params,
2931 $condition_field, $transformation_plugin,
2932 $default_function, $transform_options,
2933 $is_field_truncated, $analyzed_sql
2936 } else {
2937 // n o t n u m e r i c a n d n o t B L O B
2939 $vertical_display['data'][$row_no][$i]
2940 = $this->_getDataCellForNonNumericAndNonBlobColumns(
2941 $row[$i], $class, $meta, $map, $_url_params,
2942 $condition_field, $transformation_plugin,
2943 $default_function, $transform_options,
2944 $is_field_truncated, $analyzed_sql, $dt_result, $i
2949 // output stored cell
2950 if ($directionCondition) {
2951 $row_values_html
2952 .= $vertical_display['data'][$row_no][$i];
2955 if (isset($vertical_display['rowdata'][$i][$row_no])) {
2956 $vertical_display['rowdata'][$i][$row_no]
2957 .= $vertical_display['data'][$row_no][$i];
2958 } else {
2959 $vertical_display['rowdata'][$i][$row_no]
2960 = $vertical_display['data'][$row_no][$i];
2963 $this->__set('vertical_display', $vertical_display);
2965 } // end for
2967 return $row_values_html;
2969 } // end of the '_getRowValues()' function
2973 * Gather delete/edit url links for further outputs
2975 * @param integer $row_no the index of current row
2976 * @param array $is_display which elements to display
2977 * @param string $where_clause where clause
2978 * @param string $where_clause_html the html encoded where clause
2979 * @param string $js_conf text for the JS confirmation
2980 * @param string $del_url the url for delete row
2981 * @param string $del_query the query for delete row
2982 * @param string $del_str the label for delete row
2983 * @param string $edit_anchor_class the class for html element for edit
2984 * @param string $edit_url the url for edit row
2985 * @param string $edit_str the label for edit row
2986 * @param string $copy_url the url for copy row
2987 * @param string $copy_str the label for copy row
2988 * @param string $alternating_color_class class for display two colors in rows
2989 * @param array $condition_array array of keys
2990 * (primary,unique,condition)
2992 * @return void
2994 * @access private
2996 * @see _getTableBody()
2998 private function _gatherLinksForLaterOutputs(
2999 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
3000 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, $edit_str,
3001 $copy_url, $copy_str, $alternating_color_class, $condition_array
3004 $vertical_display = $this->__get('vertical_display');
3006 if (! isset($vertical_display['edit'][$row_no])) {
3007 $vertical_display['edit'][$row_no] = '';
3008 $vertical_display['copy'][$row_no] = '';
3009 $vertical_display['delete'][$row_no] = '';
3010 $vertical_display['row_delete'][$row_no] = '';
3013 $vertical_class = ' row_' . $row_no;
3014 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
3015 $vertical_class .= ' vpointer';
3018 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
3019 $vertical_class .= ' vmarker';
3022 if (!empty($del_url)
3023 && ($is_display['del_lnk'] != self::KILL_PROCESS)
3026 $vertical_display['row_delete'][$row_no]
3027 .= $this->_getCheckboxForMultiRowSubmissions(
3028 $del_url, $is_display, $row_no, $where_clause_html,
3029 $condition_array, $del_query, '[%_PMA_CHECKBOX_DIR_%]',
3030 $alternating_color_class . $vertical_class
3033 } else {
3034 unset($vertical_display['row_delete'][$row_no]);
3037 if (isset($edit_url)) {
3039 $vertical_display['edit'][$row_no] .= $this->_getEditLink(
3040 $edit_url,
3041 $alternating_color_class . ' ' . $edit_anchor_class
3042 . $vertical_class, $edit_str,
3043 $where_clause,
3044 $where_clause_html
3047 } else {
3048 unset($vertical_display['edit'][$row_no]);
3051 if (isset($copy_url)) {
3053 $vertical_display['copy'][$row_no] .= $this->_getCopyLink(
3054 $copy_url, $copy_str, $where_clause, $where_clause_html,
3055 $alternating_color_class . $vertical_class
3058 } else {
3059 unset($vertical_display['copy'][$row_no]);
3062 if (isset($del_url)) {
3064 if (! isset($js_conf)) {
3065 $js_conf = '';
3068 $vertical_display['delete'][$row_no]
3069 .= $this->_getDeleteLink(
3070 $del_url, $del_str, $js_conf,
3071 $alternating_color_class . $vertical_class
3074 } else {
3075 unset($vertical_display['delete'][$row_no]);
3078 $this->__set('vertical_display', $vertical_display);
3080 } // end of the '_gatherLinksForLaterOutputs()' function
3084 * Check whether any field is marked as need to syntax highlight
3086 * @param string $field field to check
3088 * @return boolean
3090 private function _isNeedToSyntaxHighlight($field)
3092 if (! empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($field)])) {
3093 return true;
3095 return false;
3099 * Check whether the field needs to be link
3101 * @param string $field field to check
3103 * @return boolean
3105 private function _isFieldNeedToLink($field)
3107 if (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('db'))][strtolower($this->__get('table'))][$field])) {
3108 return true;
3110 return false;
3115 * Get link for display special schema links
3117 * @param string $column_value column value
3118 * @param array $row_info information about row
3119 * @param string $field_name column name
3121 * @return string generated link
3123 private function _getSpecialLinkUrl($column_value, $row_info, $field_name)
3126 $linking_url_params = array();
3127 $link_relations = $GLOBALS['special_schema_links']
3128 [strtolower($this->__get('db'))]
3129 [strtolower($this->__get('table'))]
3130 [$field_name];
3132 if (! is_array($link_relations['link_param'])) {
3133 $linking_url_params[$link_relations['link_param']] = $column_value;
3134 } else {
3135 // Consider only the case of creating link for column field
3136 // sql query need to be pass as url param
3137 $sql = 'SELECT `'.$column_value.'` FROM `'
3138 . $row_info[$link_relations['link_param'][1]] .'`.`'
3139 . $row_info[$link_relations['link_param'][2]] .'`';
3140 $linking_url_params[$link_relations['link_param'][0]] = $sql;
3144 if (! empty($link_relations['link_dependancy_params'])) {
3146 foreach ($link_relations['link_dependancy_params'] as $new_param) {
3148 // If param_info is an array, set the key and value
3149 // from that array
3150 if (is_array($new_param['param_info'])) {
3151 $linking_url_params[$new_param['param_info'][0]]
3152 = $new_param['param_info'][1];
3153 } else {
3155 $linking_url_params[$new_param['param_info']]
3156 = $row_info[strtolower($new_param['column_name'])];
3158 // Special case 1 - when executing routines, according
3159 // to the type of the routine, url param changes
3160 if (!empty($row_info['routine_type'])) {
3161 if (strtolower($row_info['routine_type']) == self::ROUTINE_PROCEDURE
3162 || strtolower($row_info['routine_type']) == self::ROUTINE_FUNCTION
3164 $linking_url_params['edit_item'] = 1;
3173 return $link_relations['default_page']
3174 . PMA_generate_common_url($linking_url_params);
3180 * Prepare row information for display special links
3182 * @param array $row current row data
3183 * @param array $col_order the column order
3185 * @return array $row_info associative array with column nama -> value
3187 private function _getRowInfoForSpecialLinks($row, $col_order)
3190 $row_info = array();
3191 $fields_meta = $this->__get('fields_meta');
3193 for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) {
3194 $m = $col_order ? $col_order[$n] : $n;
3195 $row_info[strtolower($fields_meta[$m]->name)] = $row[$m];
3198 return $row_info;
3204 * Get url sql query without conditions to shorten URLs
3206 * @param array $analyzed_sql analyzed query
3208 * @return string $url_sql analyzed sql query
3210 * @access private
3212 * @see _getTableBody()
3214 private function _getUrlSqlQuery($analyzed_sql)
3217 if (isset($analyzed_sql)
3218 && isset($analyzed_sql[0])
3219 && isset($analyzed_sql[0]['querytype'])
3220 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
3221 && (strlen($this->__get('sql_query')) > 200)
3224 $url_sql_query = 'SELECT ';
3225 if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
3226 $url_sql_query .= ' DISTINCT ';
3229 $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
3230 if (!empty($analyzed_sql[0]['from_clause'])) {
3231 $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
3234 return $url_sql_query;
3237 return $this->__get('sql_query');
3239 } // end of the '_getUrlSqlQuery()' function
3243 * Get column order and column visibility
3245 * @param array $analyzed_sql the analyzed query
3247 * @return array 2 element array - $col_order, $col_visib
3249 * @access private
3251 * @see _getTableBody()
3253 private function _getColumnParams($analyzed_sql)
3255 if ($this->_isSelect($analyzed_sql)) {
3256 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
3257 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
3258 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
3259 } else {
3260 $col_order = false;
3261 $col_visib = false;
3264 return array($col_order, $col_visib);
3265 } // end of the '_getColumnParams()' function
3269 * Prepare vertical display mode necessay HTML stuff
3271 * @param array $vertical_display informations used with vertical
3272 * display mode
3273 * @param integer $row_no the index of current row
3274 * @param boolean $directionCondition the directional condition
3276 * @return string $vertical_disp_html html content
3278 * @access private
3280 * @see _getTableBody()
3282 private function _getVerticalDisplaySupportSegments(
3283 $vertical_display, $row_no, $directionCondition
3286 $support_html = '';
3288 if ((($row_no != 0) && ($_SESSION['tmp_user_values']['repeat_cells'] != 0))
3289 && !($row_no % $_SESSION['tmp_user_values']['repeat_cells'])
3290 && $directionCondition
3293 $support_html .= '<tr>' . "\n";
3295 if ($vertical_display['emptypre'] > 0) {
3297 $support_html .= ' <th colspan="'
3298 . $vertical_display['emptypre'] . '">'
3299 . "\n".' &nbsp;</th>' . "\n";
3301 } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
3302 $support_html .= ' <th></th>' . "\n";
3305 foreach ($vertical_display['desc'] as $val) {
3306 $support_html .= $val;
3309 if ($vertical_display['emptyafter'] > 0) {
3310 $support_html
3311 .= ' <th colspan="' . $vertical_display['emptyafter']
3312 . '">'
3313 . "\n" . ' &nbsp;</th>' . "\n";
3315 $support_html .= '</tr>' . "\n";
3316 } // end if
3318 return $support_html;
3320 } // end of the '_getVerticalDisplaySupportSegments()' function
3324 * Get modified links
3326 * @param string $where_clause the where clause of the sql
3327 * @param boolean $clause_is_unique the unique condition of clause
3328 * @param string $url_sql_query the analyzed sql query
3330 * @return array 5 element array - $edit_url, $copy_url,
3331 * $edit_str, $copy_str, $edit_anchor_class
3333 * @access private
3335 * @see _getTableBody()
3337 private function _getModifiedLinks(
3338 $where_clause, $clause_is_unique, $url_sql_query
3341 $_url_params = array(
3342 'db' => $this->__get('db'),
3343 'table' => $this->__get('table'),
3344 'where_clause' => $where_clause,
3345 'clause_is_unique' => $clause_is_unique,
3346 'sql_query' => $url_sql_query,
3347 'goto' => 'sql.php',
3350 $edit_url = 'tbl_change.php'
3351 . PMA_generate_common_url(
3352 $_url_params + array('default_action' => 'update')
3355 $copy_url = 'tbl_change.php'
3356 . PMA_generate_common_url(
3357 $_url_params + array('default_action' => 'insert')
3360 $edit_str = PMA_Util::getIcon(
3361 'b_edit.png', __('Edit')
3363 $copy_str = PMA_Util::getIcon(
3364 'b_insrow.png', __('Copy')
3367 // Class definitions required for grid editing jQuery scripts
3368 $edit_anchor_class = "edit_row_anchor";
3369 if ( $clause_is_unique == 0) {
3370 $edit_anchor_class .= ' nonunique';
3373 return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
3375 } // end of the '_getModifiedLinks()' function
3379 * Get delete and kill links
3381 * @param string $where_clause the where clause of the sql
3382 * @param boolean $clause_is_unique the unique condition of clause
3383 * @param string $url_sql_query the analyzed sql query
3384 * @param string $del_lnk the delete link of current row
3385 * @param array $row the current row
3387 * @return array 4 element array - $del_query,
3388 * $del_url, $del_str, $js_conf
3390 * @access private
3392 * @see _getTableBody()
3394 private function _getDeleteAndKillLinks(
3395 $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row
3398 $goto = $this->__get('goto');
3400 if ($del_lnk == self::DELETE_ROW) { // delete row case
3402 $_url_params = array(
3403 'db' => $this->__get('db'),
3404 'table' => $this->__get('table'),
3405 'sql_query' => $url_sql_query,
3406 'message_to_show' => __('The row has been deleted'),
3407 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto),
3410 $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
3412 $del_query = 'DELETE FROM '
3413 . PMA_Util::backquote($this->__get('db')) . '.'
3414 . PMA_Util::backquote($this->__get('table'))
3415 . ' WHERE ' . $where_clause .
3416 ($clause_is_unique ? '' : ' LIMIT 1');
3418 $_url_params = array(
3419 'db' => $this->__get('db'),
3420 'table' => $this->__get('table'),
3421 'sql_query' => $del_query,
3422 'message_to_show' => __('The row has been deleted'),
3423 'goto' => $lnk_goto,
3425 $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
3427 $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('db')) . '.'
3428 . PMA_jsFormat($this->__get('table'))
3429 . ' WHERE ' . PMA_jsFormat($where_clause, false)
3430 . ($clause_is_unique ? '' : ' LIMIT 1');
3432 $del_str = PMA_Util::getIcon(
3433 'b_drop.png', __('Delete')
3436 } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case
3438 $_url_params = array(
3439 'db' => $this->__get('db'),
3440 'table' => $this->__get('table'),
3441 'sql_query' => $url_sql_query,
3442 'goto' => 'index.php',
3445 $lnk_goto = 'sql.php'
3446 . PMA_generate_common_url(
3447 $_url_params, 'text'
3450 $_url_params = array(
3451 'db' => 'mysql',
3452 'sql_query' => 'KILL ' . $row[0],
3453 'goto' => $lnk_goto,
3456 $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
3457 $del_query = 'KILL ' . $row[0];
3458 $js_conf = 'KILL ' . $row[0];
3459 $del_str = PMA_Util::getIcon(
3460 'b_drop.png', __('Kill')
3464 return array($del_query, $del_url, $del_str, $js_conf);
3466 } // end of the '_getDeleteAndKillLinks()' function
3470 * Prepare placed links
3472 * @param string $dir the direction of links should place
3473 * @param string $del_url the url for delete row
3474 * @param array $is_display which elements to display
3475 * @param integer $row_no the index of current row
3476 * @param string $where_clause the where clause of the sql
3477 * @param string $where_clause_html the html encoded where clause
3478 * @param array $condition_array array of keys (primary, unique, condition)
3479 * @param string $del_query the query for delete row
3480 * @param string $dir_letter the letter denoted the direction
3481 * @param string $edit_url the url for edit row
3482 * @param string $copy_url the url for copy row
3483 * @param string $edit_anchor_class the class for html element for edit
3484 * @param string $edit_str the label for edit row
3485 * @param string $copy_str the label for copy row
3486 * @param string $del_str the label for delete row
3487 * @param string $js_conf text for the JS confirmation
3489 * @return string html content
3491 * @access private
3493 * @see _getTableBody()
3495 private function _getPlacedLinks(
3496 $dir, $del_url, $is_display, $row_no, $where_clause, $where_clause_html,
3497 $condition_array, $del_query, $dir_letter, $edit_url, $copy_url,
3498 $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
3501 if (! isset($js_conf)) {
3502 $js_conf = '';
3505 return $this->_getCheckboxAndLinks(
3506 $dir, $del_url, $is_display,
3507 $row_no, $where_clause, $where_clause_html, $condition_array,
3508 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
3509 $edit_str, $copy_str, $del_str, $js_conf
3512 } // end of the '_getPlacedLinks()' function
3516 * Get the combined classes for a column
3518 * @param string $grid_edit_class the class for all editable columns
3519 * @param string $not_null_class the class for not null columns
3520 * @param string $relation_class the class for relations in a column
3521 * @param string $hide_class the class for visibility of a column
3522 * @param string $field_type_class the class related to type of the field
3523 * @param integer $row_no the row index
3525 * @return string $class the combined classes
3527 * @access private
3529 * @see _getTableBody()
3531 private function _getClassesForColumn(
3532 $grid_edit_class, $not_null_class, $relation_class,
3533 $hide_class, $field_type_class, $row_no
3536 $printview = $this->__get('printview');
3538 $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' '
3539 . $relation_class . ' ' . $hide_class . ' ' . $field_type_class;
3541 if (($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL)
3542 && (! isset($printview) || ($printview != '1'))
3544 // the row number corresponds to a data row, not HTML table row
3545 $class .= ' row_' . $row_no;
3546 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
3547 $class .= ' vpointer';
3550 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
3551 $class .= ' vmarker';
3555 return $class;
3557 } // end of the '_getClassesForColumn()' function
3561 * Get class for datetime related fields
3563 * @param string $type the type of the column field
3565 * @return string $field_type_class the class for the column
3567 * @access private
3569 * @see _getTableBody()
3571 private function _getClassForDateTimeRelatedFields($type)
3573 if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD)
3574 || ($type == self::DATETIME_FIELD)
3576 $field_type_class = 'datetimefield';
3577 } else if ($type == self::DATE_FIELD) {
3578 $field_type_class = 'datefield';
3579 } else {
3580 $field_type_class = '';
3582 return $field_type_class;
3583 } // end of the '_getClassForDateTimeRelatedFields()' function
3587 * Prepare data cell for numeric type fields
3589 * @param string $column the relavent column in data row
3590 * @param string $class the html class for column
3591 * @param boolean $condition_field the column should highlighted
3592 * or not
3593 * @param object $meta the meta-information about this
3594 * field
3595 * @param array $map the list of relations
3596 * @param boolean $is_field_truncated the condition for blob data
3597 * replacements
3598 * @param array $analyzed_sql the analyzed query
3599 * @param string $transformation_plugin the name of transformation plugin
3600 * @param string $default_function the default transformation function
3601 * @param string $transform_options the transformation parameters
3603 * @return string $cell the prepared cell, html content
3605 * @access private
3607 * @see _getTableBody()
3609 private function _getDataCellForNumericColumns(
3610 $column, $class, $condition_field, $meta, $map, $is_field_truncated,
3611 $analyzed_sql, $transformation_plugin, $default_function,
3612 $transform_options
3615 if (! isset($column) || is_null($column)) {
3617 $cell = $this->_buildNullDisplay(
3618 'right '.$class, $condition_field, $meta, ''
3621 } elseif ($column != '') {
3623 $nowrap = ' nowrap';
3624 $where_comparison = ' = ' . $column;
3626 $cell = $this->_getRowData(
3627 'right '.$class, $condition_field,
3628 $analyzed_sql, $meta, $map, $column,
3629 $transformation_plugin, $default_function, $nowrap,
3630 $where_comparison, $transform_options,
3631 $is_field_truncated
3633 } else {
3635 $cell = $this->_buildEmptyDisplay(
3636 'right '.$class, $condition_field, $meta, ''
3640 return $cell;
3642 } // end of the '_getDataCellForNumericColumns()' function
3646 * Get data cell for blob type fields
3648 * @param string $column the relavent column in data row
3649 * @param string $class the html class for column
3650 * @param object $meta the meta-information about this
3651 * field
3652 * @param array $_url_params the parameters for generate url
3653 * @param string $field_flags field flags for column(blob,
3654 * primary etc)
3655 * @param string $transformation_plugin the name of transformation function
3656 * @param string $default_function the default transformation function
3657 * @param string $transform_options the transformation parameters
3658 * @param boolean $condition_field the column should highlighted
3659 * or not
3660 * @param boolean $is_field_truncated the condition for blob data
3661 * replacements
3663 * @return string $cell the prepared cell, html content
3665 * @access private
3667 * @see _getTableBody()
3669 private function _getDataCellForBlobColumns(
3670 $column, $class, $meta, $_url_params, $field_flags, $transformation_plugin,
3671 $default_function, $transform_options, $condition_field, $is_field_truncated
3674 if (stristr($field_flags, self::BINARY_FIELD)) {
3676 // remove 'grid_edit' from $class as we can't edit binary data.
3677 $class = str_replace('grid_edit', '', $class);
3679 if (! isset($column) || is_null($column)) {
3681 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3683 } else {
3685 $blobtext = $this->_handleNonPrintableContents(
3686 self::BLOB_FIELD, (isset($column) ? $column : ''),
3687 $transformation_plugin, $transform_options,
3688 $default_function, $meta, $_url_params
3691 $cell = $this->_buildValueDisplay(
3692 $class, $condition_field, $blobtext
3694 unset($blobtext);
3696 } else {
3697 // not binary:
3699 if (! isset($column) || is_null($column)) {
3701 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3703 } elseif ($column != '') {
3705 // if a transform function for blob is set, none of these
3706 // replacements will be made
3707 if ((PMA_strlen($column) > $GLOBALS['cfg']['LimitChars'])
3708 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3709 && ! $this->_isNeedToSyntaxHighlight(strtolower($meta->name))
3711 $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars'])
3712 . '...';
3713 $is_field_truncated = true;
3716 // displays all space characters, 4 space
3717 // characters for tabulations and <cr>/<lf>
3718 $column = ($default_function != $transformation_plugin)
3719 ? $transformation_plugin->applyTransformation(
3720 $column,
3721 $transform_options,
3722 $meta
3724 : $this->$default_function($column, array(), $meta);
3726 if ($is_field_truncated) {
3727 $class .= ' truncated';
3730 $cell = $this->_buildValueDisplay($class, $condition_field, $column);
3732 } else {
3733 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3737 return $cell;
3739 } // end of the '_getDataCellForBlobColumns()' function
3743 * Get data cell for geometry type fields
3745 * @param string $column the relavent column in data row
3746 * @param string $class the html class for column
3747 * @param object $meta the meta-information about this field
3748 * @param array $map the list of relations
3749 * @param array $_url_params the parameters for generate url
3750 * @param boolean $condition_field the column should highlighted or not
3751 * @param string $transformation_plugin the name of transformation function
3752 * @param string $default_function the default transformation function
3753 * @param string $transform_options the transformation parameters
3754 * @param boolean $is_field_truncated the condition for blob data replacements
3755 * @param array $analyzed_sql the analyzed query
3757 * @return string $cell the prepared data cell, html content
3759 * @access private
3761 * @see _getTableBody()
3763 private function _getDataCellForGeometryColumns(
3764 $column, $class, $meta, $map, $_url_params, $condition_field,
3765 $transformation_plugin, $default_function, $transform_options,
3766 $is_field_truncated, $analyzed_sql
3769 if (! isset($column) || is_null($column)) {
3771 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3773 } elseif ($column != '') {
3775 // Display as [GEOMETRY - (size)]
3776 if ($_SESSION['tmp_user_values']['geometry_display'] == self::GEOMETRY_DISP_GEOM) {
3778 $geometry_text = $this->_handleNonPrintableContents(
3779 strtoupper(self::GEOMETRY_FIELD),
3780 (isset($column) ? $column : ''), $transformation_plugin,
3781 $transform_options, $default_function, $meta
3784 $cell = $this->_buildValueDisplay(
3785 $class, $condition_field, $geometry_text
3788 } elseif ($_SESSION['tmp_user_values']['geometry_display']
3789 == self::GEOMETRY_DISP_WKT
3791 // Prepare in Well Known Text(WKT) format.
3793 $where_comparison = ' = ' . $column;
3795 // Convert to WKT format
3796 $wktval = PMA_Util::asWKT($column);
3798 if ((PMA_strlen($wktval) > $GLOBALS['cfg']['LimitChars'])
3799 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3801 $wktval = PMA_substr($wktval, 0, $GLOBALS['cfg']['LimitChars'])
3802 . '...';
3803 $is_field_truncated = true;
3806 $cell = $this->_getRowData(
3807 $class, $condition_field, $analyzed_sql, $meta, $map,
3808 $wktval, $transformation_plugin, $default_function, '',
3809 $where_comparison, $transform_options,
3810 $is_field_truncated
3813 } else {
3814 // Prepare in Well Known Binary (WKB) format.
3816 if ($_SESSION['tmp_user_values']['display_binary']) {
3818 $where_comparison = ' = ' . $column;
3820 $wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8);
3822 if ((PMA_strlen($wkbval) > $GLOBALS['cfg']['LimitChars'])
3823 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3825 $wkbval
3826 = PMA_substr($wkbval, 0, $GLOBALS['cfg']['LimitChars'])
3827 . '...';
3828 $is_field_truncated = true;
3831 $cell = $this->_getRowData(
3832 $class, $condition_field,
3833 $analyzed_sql, $meta, $map, $wkbval,
3834 $transformation_plugin, $default_function, '',
3835 $where_comparison, $transform_options,
3836 $is_field_truncated
3839 } else {
3840 $wkbval = $this->_handleNonPrintableContents(
3841 self::BINARY_FIELD, $column, $transformation_plugin,
3842 $transform_options, $default_function, $meta,
3843 $_url_params
3846 $cell = $this->_buildValueDisplay(
3847 $class, $condition_field, $wkbval
3851 } else {
3852 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3855 return $cell;
3857 } // end of the '_getDataCellForGeometryColumns()' function
3861 * Get data cell for non numeric and non blob type fields
3863 * @param string $column the relavent column in data row
3864 * @param string $class the html class for column
3865 * @param object $meta the meta-information about the field
3866 * @param array $map the list of relations
3867 * @param array $_url_params the parameters for generate url
3868 * @param boolean $condition_field the column should highlighted
3869 * or not
3870 * @param string $transformation_plugin the name of transformation function
3871 * @param string $default_function the default transformation function
3872 * @param string $transform_options the transformation parameters
3873 * @param boolean $is_field_truncated the condition for blob data
3874 * replacements
3875 * @param array $analyzed_sql the analyzed query
3876 * @param integer &$dt_result the link id associated to the query
3877 * which results have to be displayed
3878 * @param integer $col_index the column index
3880 * @return string $cell the prepared data cell, html content
3882 * @access private
3884 * @see _getTableBody()
3886 private function _getDataCellForNonNumericAndNonBlobColumns(
3887 $column, $class, $meta, $map, $_url_params, $condition_field,
3888 $transformation_plugin, $default_function, $transform_options,
3889 $is_field_truncated, $analyzed_sql, &$dt_result, $col_index
3892 $is_analyse = $this->__get('is_analyse');
3893 $field_flags = PMA_DBI_field_flags($dt_result, $col_index);
3894 if (stristr($field_flags, self::BINARY_FIELD)
3895 && ($GLOBALS['cfg']['ProtectBinary'] == 'all'
3896 || $GLOBALS['cfg']['ProtectBinary'] == 'noblob')
3898 $class = str_replace('grid_edit', '', $class);
3901 if (! isset($column) || is_null($column)) {
3903 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3905 } elseif ($column != '') {
3907 // Cut all fields to $GLOBALS['cfg']['LimitChars']
3908 // (unless it's a link-type transformation)
3909 if (PMA_strlen($column) > $GLOBALS['cfg']['LimitChars']
3910 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3911 && ! (gettype($transformation_plugin) == "object"
3912 && strpos($transformation_plugin->getName(), 'Link') !== false)
3914 $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars'])
3915 . '...';
3916 $is_field_truncated = true;
3919 $formatted = false;
3920 if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
3922 $column = PMA_Util::printableBitValue(
3923 $column, $meta->length
3926 // some results of PROCEDURE ANALYSE() are reported as
3927 // being BINARY but they are quite readable,
3928 // so don't treat them as BINARY
3929 } elseif (stristr($field_flags, self::BINARY_FIELD)
3930 && ($meta->type == self::STRING_FIELD)
3931 && !(isset($is_analyse) && $is_analyse)
3934 if ($_SESSION['tmp_user_values']['display_binary']) {
3936 // user asked to see the real contents of BINARY
3937 // fields
3938 $column = $this->_displayBinaryAsPrintable($column, 'binary');
3940 } else {
3941 // we show the BINARY message and field's size
3942 // (or maybe use a transformation)
3943 $column = $this->_handleNonPrintableContents(
3944 self::BINARY_FIELD, $column, $transformation_plugin,
3945 $transform_options, $default_function,
3946 $meta, $_url_params
3948 $formatted = true;
3952 if ($formatted) {
3954 $cell = $this->_buildValueDisplay(
3955 $class, $condition_field, $column
3958 } else {
3960 // transform functions may enable no-wrapping:
3961 $function_nowrap = 'applyTransformationNoWrap';
3963 $bool_nowrap = (($default_function != $transformation_plugin)
3964 && function_exists($transformation_plugin->$function_nowrap()))
3965 ? $transformation_plugin->$function_nowrap($transform_options)
3966 : false;
3968 // do not wrap if date field type
3969 $nowrap = (preg_match('@DATE|TIME@i', $meta->type)
3970 || $bool_nowrap) ? ' nowrap' : '';
3972 $where_comparison = ' = \''
3973 . PMA_Util::sqlAddSlashes($column)
3974 . '\'';
3976 $cell = $this->_getRowData(
3977 $class, $condition_field,
3978 $analyzed_sql, $meta, $map, $column,
3979 $transformation_plugin, $default_function, $nowrap,
3980 $where_comparison, $transform_options,
3981 $is_field_truncated
3985 } else {
3986 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3989 return $cell;
3991 } // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function
3995 * Get the resulted table with the vertical direction mode.
3997 * @param array $analyzed_sql the analyzed query
3998 * @param array $is_display display mode
4000 * @return string html content
4002 * @access private
4004 * @see _getTable()
4006 private function _getVerticalTable($analyzed_sql, $is_display)
4009 $vertical_table_html = '';
4010 $vertical_display = $this->__get('vertical_display');
4012 // Prepares "multi row delete" link at top if required
4013 if (($GLOBALS['cfg']['RowActionLinks'] != self::POSITION_RIGHT)
4014 && is_array($vertical_display['row_delete'])
4015 && ((count($vertical_display['row_delete']) > 0)
4016 || !empty($vertical_display['textbtn']))
4019 $vertical_table_html .= '<tr>' . "\n";
4020 if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
4021 // if we are not showing the RowActionLinks, then we need to show
4022 // the Multi-Row-Action checkboxes
4023 $vertical_table_html .= '<th></th>' . "\n";
4026 $vertical_table_html .= $vertical_display['textbtn']
4027 . $this->_getCheckBoxesForMultipleRowOperations('_left', $is_display)
4028 . '</tr>' . "\n";
4029 } // end if
4031 // Prepares "edit" link at top if required
4032 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4033 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4034 && is_array($vertical_display['edit'])
4035 && ((count($vertical_display['edit']) > 0)
4036 || !empty($vertical_display['textbtn']))
4038 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4039 'edit'
4041 } // end if
4043 // Prepares "copy" link at top if required
4044 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4045 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4046 && is_array($vertical_display['copy'])
4047 && ((count($vertical_display['copy']) > 0)
4048 || !empty($vertical_display['textbtn']))
4050 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4051 'copy'
4053 } // end if
4055 // Prepares "delete" link at top if required
4056 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4057 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4058 && is_array($vertical_display['delete'])
4059 && ((count($vertical_display['delete']) > 0)
4060 || !empty($vertical_display['textbtn']))
4062 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4063 'delete'
4065 } // end if
4067 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
4069 // Prepares data
4070 foreach ($vertical_display['desc'] AS $j => $val) {
4072 // assign appropriate key with current column order
4073 $key = $col_order ? $col_order[$j] : $j;
4075 $vertical_table_html .= '<tr'
4076 . (($col_visib && !$col_visib[$j]) ? ' class="hide"' : '')
4077 . '>' . "\n"
4078 . $val;
4080 $cell_displayed = 0;
4081 foreach ($vertical_display['rowdata'][$key] as $subval) {
4083 if (($cell_displayed != 0)
4084 && ($_SESSION['tmp_user_values']['repeat_cells'] != 0)
4085 && ! ($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells'])
4087 $vertical_table_html .= $val;
4090 $vertical_table_html .= $subval;
4091 $cell_displayed++;
4093 } // end while
4095 $vertical_table_html .= '</tr>' . "\n";
4096 } // end while
4098 // Prepares "multi row delete" link at bottom if required
4099 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4100 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4101 && is_array($vertical_display['row_delete'])
4102 && ((count($vertical_display['row_delete']) > 0)
4103 || !empty($vertical_display['textbtn']))
4106 $vertical_table_html .= '<tr>' . "\n"
4107 . $vertical_display['textbtn']
4108 . $this->_getCheckBoxesForMultipleRowOperations('_right', $is_display)
4109 . '</tr>' . "\n";
4110 } // end if
4112 // Prepares "edit" link at bottom if required
4113 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4114 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4115 && is_array($vertical_display['edit'])
4116 && ((count($vertical_display['edit']) > 0)
4117 || !empty($vertical_display['textbtn']))
4119 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4120 'edit'
4122 } // end if
4124 // Prepares "copy" link at bottom if required
4125 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4126 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4127 && is_array($vertical_display['copy'])
4128 && ((count($vertical_display['copy']) > 0)
4129 || !empty($vertical_display['textbtn']))
4131 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4132 'copy'
4134 } // end if
4136 // Prepares "delete" link at bottom if required
4137 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4138 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4139 && is_array($vertical_display['delete'])
4140 && ((count($vertical_display['delete']) > 0)
4141 || !empty($vertical_display['textbtn']))
4143 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4144 'delete'
4148 return $vertical_table_html;
4150 } // end of the '_getVerticalTable' function
4154 * Prepare edit, copy and delete links for verticle table
4156 * @param string $operation edit/copy/delete
4158 * @return string $links_html html content
4160 * @access private
4162 * @see _getVerticalTable()
4164 private function _getOperationLinksForVerticleTable($operation)
4167 $link_html = '<tr>' . "\n";
4168 $vertical_display = $this->__get('vertical_display');
4170 if (! is_array($vertical_display['row_delete'])) {
4172 if (($operation == 'edit') || ($operation == 'copy')) {
4173 $link_html .= $vertical_display['textbtn'];
4175 } elseif ($operation == 'delete') {
4177 if (! is_array($vertical_display['edit'])) {
4178 $link_html .= $vertical_display['textbtn'];
4183 foreach ($vertical_display[$operation] as $val) {
4184 $link_html .= $val;
4185 } // end while
4187 $link_html .= '</tr>' . "\n";
4189 return $link_html;
4191 } // end of the '_getOperationLinksForVerticleTable' function
4195 * Get checkboxes for multiple row data operations
4197 * @param string $dir _left / _right
4198 * @param array $is_display display mode
4200 * @return $checkBoxes_html html content
4202 * @access private
4204 * @see _getVerticalTable()
4206 private function _getCheckBoxesForMultipleRowOperations($dir, $is_display)
4209 $checkBoxes_html = '';
4210 $cell_displayed = 0;
4211 $vertical_display = $this->__get('vertical_display');
4213 foreach ($vertical_display['row_delete'] as $val) {
4215 if (($cell_displayed != 0)
4216 && ($_SESSION['tmp_user_values']['repeat_cells'] != 0)
4217 && !($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells'])
4220 $checkBoxes_html .= '<th'
4221 . (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
4222 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
4223 ? ' rowspan="4"'
4224 : ''
4225 . '></th>' . "\n";
4229 $checkBoxes_html .= str_replace('[%_PMA_CHECKBOX_DIR_%]', $dir, $val);
4230 $cell_displayed++;
4231 } // end while
4233 return $checkBoxes_html;
4235 } // end of the '_getCheckBoxesForMultipleRowOperations' function
4239 * Checks the posted options for viewing query resutls
4240 * and sets appropriate values in the session.
4242 * @todo make maximum remembered queries configurable
4243 * @todo move/split into SQL class!?
4244 * @todo currently this is called twice unnecessary
4245 * @todo ignore LIMIT and ORDER in query!?
4247 * @return void
4249 * @access public
4251 * @see sql.php file
4253 public function setConfigParamsForDisplayTable()
4256 $sql_md5 = md5($this->__get('sql_query'));
4258 $_SESSION['tmp_user_values']['query'][$sql_md5]['sql']
4259 = $this->__get('sql_query');
4261 $valid_disp_dir = PMA_isValid(
4262 $_REQUEST['disp_direction'],
4263 array(self::DISP_DIR_HORIZONTAL, self::DISP_DIR_VERTICAL,
4264 self::DISP_DIR_HORIZONTAL_FLIPPED
4268 if ($valid_disp_dir) {
4269 $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']
4270 = $_REQUEST['disp_direction'];
4271 unset($_REQUEST['disp_direction']);
4272 } elseif (
4273 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'])
4275 $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']
4276 = $GLOBALS['cfg']['DefaultDisplay'];
4279 if (PMA_isValid($_REQUEST['repeat_cells'], 'numeric')) {
4280 $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']
4281 = $_REQUEST['repeat_cells'];
4282 unset($_REQUEST['repeat_cells']);
4283 } elseif (
4284 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'])
4286 $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']
4287 = $GLOBALS['cfg']['RepeatCells'];
4290 // as this is a form value, the type is always string so we cannot
4291 // use PMA_isValid($_REQUEST['session_max_rows'], 'integer')
4292 if ((PMA_isValid($_REQUEST['session_max_rows'], 'numeric')
4293 && ((int) $_REQUEST['session_max_rows'] == $_REQUEST['session_max_rows']))
4294 || ($_REQUEST['session_max_rows'] == self::ALL_ROWS)
4296 $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']
4297 = $_REQUEST['session_max_rows'];
4298 unset($_REQUEST['session_max_rows']);
4299 } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'])) {
4300 $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']
4301 = $GLOBALS['cfg']['MaxRows'];
4304 if (PMA_isValid($_REQUEST['pos'], 'numeric')) {
4305 $_SESSION['tmp_user_values']['query'][$sql_md5]['pos']
4306 = $_REQUEST['pos'];
4307 unset($_REQUEST['pos']);
4308 } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['pos'])) {
4309 $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'] = 0;
4312 if (PMA_isValid(
4313 $_REQUEST['display_text'],
4314 array(
4315 self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT
4319 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']
4320 = $_REQUEST['display_text'];
4321 unset($_REQUEST['display_text']);
4322 } elseif (
4323 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'])
4325 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']
4326 = self::DISPLAY_PARTIAL_TEXT;
4329 if (PMA_isValid(
4330 $_REQUEST['relational_display'],
4331 array(
4332 self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN
4336 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4337 = $_REQUEST['relational_display'];
4338 unset($_REQUEST['relational_display']);
4339 } elseif (
4340 empty(
4341 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4344 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4345 = self::RELATIONAL_KEY;
4348 if (PMA_isValid(
4349 $_REQUEST['geometry_display'],
4350 array(
4351 self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB,
4352 self::GEOMETRY_DISP_GEOM
4356 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4357 = $_REQUEST['geometry_display'];
4358 unset($_REQUEST['geometry_display']);
4359 } elseif (
4360 empty(
4361 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4364 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4365 = self::GEOMETRY_DISP_GEOM;
4368 if (isset($_REQUEST['display_binary'])) {
4369 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true;
4370 unset($_REQUEST['display_binary']);
4371 } elseif (isset($_REQUEST['display_options_form'])) {
4372 // we know that the checkbox was unchecked
4373 unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary']);
4374 } elseif (isset($_REQUEST['full_text_button'])) {
4375 // do nothing to keep the value that is there in the session
4376 } else {
4377 // selected by default because some operations like OPTIMIZE TABLE
4378 // and all queries involving functions return "binary" contents,
4379 // according to low-level field flags
4380 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true;
4383 if (isset($_REQUEST['display_binary_as_hex'])) {
4384 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary_as_hex']
4385 = true;
4386 unset($_REQUEST['display_binary_as_hex']);
4387 } elseif (isset($_REQUEST['display_options_form'])) {
4388 // we know that the checkbox was unchecked
4389 unset($_SESSION['tmp_user_values']['query'][$sql_md5]
4390 ['display_binary_as_hex']
4392 } elseif (isset($_REQUEST['full_text_button'])) {
4393 // do nothing to keep the value that is there in the session
4394 } else {
4395 // display_binary_as_hex config option
4396 if (isset($GLOBALS['cfg']['DisplayBinaryAsHex'])
4397 && ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true)
4399 $_SESSION['tmp_user_values']['query'][$sql_md5]
4400 ['display_binary_as_hex'] = true;
4404 if (isset($_REQUEST['display_blob'])) {
4405 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob'] = true;
4406 unset($_REQUEST['display_blob']);
4407 } elseif (isset($_REQUEST['display_options_form'])) {
4408 // we know that the checkbox was unchecked
4409 unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob']);
4412 if (isset($_REQUEST['hide_transformation'])) {
4413 $_SESSION['tmp_user_values']['query'][$sql_md5]['hide_transformation']
4414 = true;
4415 unset($_REQUEST['hide_transformation']);
4416 } elseif (isset($_REQUEST['display_options_form'])) {
4417 // we know that the checkbox was unchecked
4418 unset($_SESSION['tmp_user_values']['query'][$sql_md5]
4419 ['hide_transformation']
4423 // move current query to the last position, to be removed last
4424 // so only least executed query will be removed if maximum remembered queries
4425 // limit is reached
4426 $tmp = $_SESSION['tmp_user_values']['query'][$sql_md5];
4427 unset($_SESSION['tmp_user_values']['query'][$sql_md5]);
4428 $_SESSION['tmp_user_values']['query'][$sql_md5] = $tmp;
4430 // do not exceed a maximum number of queries to remember
4431 if (count($_SESSION['tmp_user_values']['query']) > 10) {
4432 array_shift($_SESSION['tmp_user_values']['query']);
4433 //echo 'deleting one element ...';
4436 // populate query configuration
4437 $_SESSION['tmp_user_values']['display_text']
4438 = $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'];
4439 $_SESSION['tmp_user_values']['relational_display']
4440 = $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display'];
4441 $_SESSION['tmp_user_values']['geometry_display']
4442 = $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display'];
4443 $_SESSION['tmp_user_values']['display_binary']
4444 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4445 ['display_binary']
4447 ? true
4448 : false;
4449 $_SESSION['tmp_user_values']['display_binary_as_hex']
4450 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4451 ['display_binary_as_hex']
4453 ? true
4454 : false;
4455 $_SESSION['tmp_user_values']['display_blob']
4456 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob'])
4457 ? true
4458 : false;
4459 $_SESSION['tmp_user_values']['hide_transformation']
4460 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4461 ['hide_transformation']
4463 ? true
4464 : false;
4465 $_SESSION['tmp_user_values']['pos']
4466 = $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'];
4467 $_SESSION['tmp_user_values']['max_rows']
4468 = $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'];
4469 $_SESSION['tmp_user_values']['repeat_cells']
4470 = $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'];
4471 $_SESSION['tmp_user_values']['disp_direction']
4472 = $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'];
4478 * Prepare a table of results returned by a SQL query.
4479 * This function is called by the "sql.php" script.
4481 * @param integer &$dt_result the link id associated to the query
4482 * which results have to be displayed
4483 * @param array &$the_disp_mode the display mode
4484 * @param array $analyzed_sql the analyzed query
4485 * @param boolean $is_limited_display With limited operations or not
4487 * @return string $table_html Generated HTML content for resulted table
4489 * @access public
4491 * @see sql.php file
4493 public function getTable(
4494 &$dt_result, &$the_disp_mode, $analyzed_sql, $is_limited_display = false
4497 $table_html = '';
4498 // Following variable are needed for use in isset/empty or
4499 // use with array indexes/safe use in foreach
4500 $fields_meta = $this->__get('fields_meta');
4501 $showtable = $this->__get('showtable');
4502 $printview = $this->__get('printview');
4504 // why was this called here? (already called from sql.php)
4505 //$this->setConfigParamsForDisplayTable();
4508 * @todo move this to a central place
4509 * @todo for other future table types
4511 $is_innodb = (isset($showtable['Type'])
4512 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
4514 if ($is_innodb
4515 && ! isset($analyzed_sql[0]['queryflags']['union'])
4516 && ! isset($analyzed_sql[0]['table_ref'][1]['table_name'])
4517 && (empty($analyzed_sql[0]['where_clause'])
4518 || ($analyzed_sql[0]['where_clause'] == '1 '))
4520 // "j u s t b r o w s i n g"
4521 $pre_count = '~';
4522 $after_count = PMA_Util::showHint(
4523 PMA_sanitize(
4524 __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc]')
4527 } else {
4528 $pre_count = '';
4529 $after_count = '';
4532 // 1. ----- Prepares the work -----
4534 // 1.1 Gets the informations about which functionalities should be
4535 // displayed
4536 $total = '';
4537 $is_display = $this->_setDisplayMode($the_disp_mode, $total);
4539 // 1.2 Defines offsets for the next and previous pages
4540 if ($is_display['nav_bar'] == '1') {
4541 list($pos_next, $pos_prev) = $this->_getOffsets();
4542 } // end if
4543 if (!isset($analyzed_sql[0]['order_by_clause'])) {
4544 $analyzed_sql[0]['order_by_clause'] = "";
4547 // 1.3 Find the sort expression
4548 // we need $sort_expression and $sort_expression_nodirection
4549 // even if there are many table references
4550 list($sort_expression, $sort_expression_nodirection, $sort_direction)
4551 = $this->_getSortParams($analyzed_sql[0]['order_by_clause']);
4554 // 1.4 Prepares display of first and last value of the sorted column
4556 $sorted_column_message = $this->_getSortedColumnMessage(
4557 $dt_result, $sort_expression_nodirection
4561 // 2. ----- Prepare to display the top of the page -----
4563 // 2.1 Prepares a messages with position informations
4564 if (($is_display['nav_bar'] == '1') && isset($pos_next)) {
4566 $message = $this->_setMessageInformation(
4567 $sorted_column_message, $analyzed_sql[0]['limit_clause'],
4568 $total, $pos_next, $pre_count, $after_count
4571 $table_html .= PMA_Util::getMessage(
4572 $message, $this->__get('sql_query'), 'success'
4575 } elseif (! isset($printview) || ($printview != '1')) {
4577 $table_html .= PMA_Util::getMessage(
4578 __('Your SQL query has been executed successfully'),
4579 $this->__get('sql_query'), 'success'
4583 // 2.3 Prepare the navigation bars
4584 if (! strlen($this->__get('table'))) {
4586 if (isset($analyzed_sql[0]['query_type'])
4587 && ($analyzed_sql[0]['query_type'] == self::QUERY_TYPE_SELECT)
4589 // table does not always contain a real table name,
4590 // for example in MySQL 5.0.x, the query SHOW STATUS
4591 // returns STATUS as a table name
4592 $this->__set('table', $fields_meta[0]->table);
4593 } else {
4594 $this->__set('table', '');
4599 if (($is_display['nav_bar'] == '1')
4600 && empty($analyzed_sql[0]['limit_clause'])
4603 $table_html .= $this->_getPlacedTableNavigatoins(
4604 $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN,
4605 "\n", $is_innodb
4608 } elseif (! isset($printview) || ($printview != '1')) {
4609 $table_html .= "\n" . '<br /><br />' . "\n";
4612 // 2b ----- Get field references from Database -----
4613 // (see the 'relation' configuration variable)
4615 // initialize map
4616 $map = array();
4618 // find tables
4619 $target=array();
4620 if (isset($analyzed_sql[0]['table_ref'])
4621 && is_array($analyzed_sql[0]['table_ref'])
4624 foreach ($analyzed_sql[0]['table_ref']
4625 as $table_ref_position => $table_ref) {
4626 $target[] = $analyzed_sql[0]['table_ref']
4627 [$table_ref_position]['table_true_name'];
4632 $tabs = '(\'' . join('\',\'', $target) . '\')';
4634 if (! strlen($this->__get('table'))) {
4635 $exist_rel = false;
4636 } else {
4637 // This method set the values for $map array
4638 $this->_setParamForLinkForeignKeyRelatedTables($map);
4639 } // end if
4640 // end 2b
4642 // 3. ----- Prepare the results table -----
4643 $table_html .= $this->_getTableHeaders(
4644 $is_display, $analyzed_sql, $sort_expression,
4645 $sort_expression_nodirection, $sort_direction, $is_limited_display
4647 . '<tbody>' . "\n";
4649 $url_query = '';
4650 $table_html .= $this->_getTableBody(
4651 $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display
4654 // vertical output case
4655 if ($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL) {
4656 $table_html .= $this->_getVerticalTable($analyzed_sql, $is_display);
4657 } // end if
4659 $this->__set('vertical_display', null);
4661 $table_html .= '</tbody>' . "\n"
4662 . '</table>';
4664 // 4. ----- Prepares the link for multi-fields edit and delete
4666 if ($is_display['del_lnk'] == self::DELETE_ROW
4667 && $is_display['del_lnk'] != self::KILL_PROCESS
4670 $table_html .= $this->_getMultiRowOperationLinks(
4671 $dt_result, $analyzed_sql, $is_display['del_lnk']
4676 // 5. ----- Get the navigation bar at the bottom if required -----
4677 if (($is_display['nav_bar'] == '1')
4678 && empty($analyzed_sql[0]['limit_clause'])
4680 $table_html .= $this->_getPlacedTableNavigatoins(
4681 $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN,
4682 '<br />' . "\n", $is_innodb
4684 } elseif (! isset($printview) || ($printview != '1')) {
4685 $table_html .= "\n" . '<br /><br />' . "\n";
4689 // 6. ----- Prepare "Query results operations"
4690 if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) {
4691 $table_html .= $this->_getResultsOperations(
4692 $the_disp_mode, $analyzed_sql
4696 return $table_html;
4698 } // end of the 'getTable()' function
4702 * Get offsets for next page and previous page
4704 * @return array array with two elements - $pos_next, $pos_prev
4706 * @access private
4708 * @see getTable()
4710 private function _getOffsets()
4713 if ($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS) {
4714 $pos_next = 0;
4715 $pos_prev = 0;
4716 } else {
4718 $pos_next = $_SESSION['tmp_user_values']['pos']
4719 + $_SESSION['tmp_user_values']['max_rows'];
4721 $pos_prev = $_SESSION['tmp_user_values']['pos']
4722 - $_SESSION['tmp_user_values']['max_rows'];
4724 if ($pos_prev < 0) {
4725 $pos_prev = 0;
4729 return array($pos_next, $pos_prev);
4731 } // end of the '_getOffsets()' function
4735 * Get sort parameters
4737 * @param string $order_by_clause the order by clause of the sql query
4739 * @return array 3 element array: $sort_expression,
4740 * $sort_expression_nodirection, $sort_direction
4742 * @access private
4744 * @see getTable()
4746 private function _getSortParams($order_by_clause)
4749 if (! empty($order_by_clause)) {
4751 $sort_expression = trim(
4752 str_replace(' ', ' ', $order_by_clause)
4755 * Get rid of ASC|DESC
4757 preg_match(
4758 '@(.*)([[:space:]]*(ASC|DESC))@si', $sort_expression, $matches
4761 $sort_expression_nodirection = isset($matches[1])
4762 ? trim($matches[1])
4763 : $sort_expression;
4765 $sort_direction = isset($matches[2]) ? trim($matches[2]) : '';
4766 unset($matches);
4768 } else {
4769 $sort_expression = $sort_expression_nodirection = $sort_direction = '';
4772 return array($sort_expression, $sort_expression_nodirection,
4773 $sort_direction
4776 } // end of the '_getSortParams()' function
4780 * Prepare sorted column message
4782 * @param integer &$dt_result the link id associated to the
4783 * query which results have to
4784 * be displayed
4785 * @param string $sort_expression_nodirection sort expression without direction
4787 * @return string html content
4788 * null if not found sorted column
4790 * @access private
4792 * @see getTable()
4794 private function _getSortedColumnMessage(
4795 &$dt_result, $sort_expression_nodirection
4798 $fields_meta = $this->__get('fields_meta'); // To use array indexes
4800 if (! empty($sort_expression_nodirection)) {
4802 if (strpos($sort_expression_nodirection, '.') === false) {
4803 $sort_table = $this->__get('table');
4804 $sort_column = $sort_expression_nodirection;
4805 } else {
4806 list($sort_table, $sort_column)
4807 = explode('.', $sort_expression_nodirection);
4810 $sort_table = PMA_Util::unQuote($sort_table);
4811 $sort_column = PMA_Util::unQuote($sort_column);
4813 // find the sorted column index in row result
4814 // (this might be a multi-table query)
4815 $sorted_column_index = false;
4817 foreach ($fields_meta as $key => $meta) {
4818 if (($meta->table == $sort_table) && ($meta->name == $sort_column)) {
4819 $sorted_column_index = $key;
4820 break;
4824 if ($sorted_column_index !== false) {
4826 // fetch first row of the result set
4827 $row = PMA_DBI_fetch_row($dt_result);
4829 // initializing default arguments
4830 $default_function = '_mimeDefaultFunction';
4831 $transformation_plugin = $default_function;
4832 $transform_options = array();
4834 // check for non printable sorted row data
4835 $meta = $fields_meta[$sorted_column_index];
4837 if (stristr($meta->type, self::BLOB_FIELD)
4838 || ($meta->type == self::GEOMETRY_FIELD)
4841 $column_for_first_row = $this->_handleNonPrintableContents(
4842 $meta->type, $row[$sorted_column_index],
4843 $transformation_plugin, $transform_options,
4844 $default_function, $meta, null
4847 } else {
4848 $column_for_first_row = $row[$sorted_column_index];
4851 $column_for_first_row = strtoupper(
4852 substr($column_for_first_row, 0, $GLOBALS['cfg']['LimitChars'])
4855 // fetch last row of the result set
4856 PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1);
4857 $row = PMA_DBI_fetch_row($dt_result);
4859 // check for non printable sorted row data
4860 $meta = $fields_meta[$sorted_column_index];
4861 if (stristr($meta->type, self::BLOB_FIELD)
4862 || ($meta->type == self::GEOMETRY_FIELD)
4865 $column_for_last_row = $this->_handleNonPrintableContents(
4866 $meta->type, $row[$sorted_column_index],
4867 $transformation_plugin, $transform_options,
4868 $default_function, $meta, null
4871 } else {
4872 $column_for_last_row = $row[$sorted_column_index];
4875 $column_for_last_row = strtoupper(
4876 substr($column_for_last_row, 0, $GLOBALS['cfg']['LimitChars'])
4879 // reset to first row for the loop in _getTableBody()
4880 PMA_DBI_data_seek($dt_result, 0);
4882 // we could also use here $sort_expression_nodirection
4883 return ' [' . htmlspecialchars($sort_column)
4884 . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - '
4885 . htmlspecialchars($column_for_last_row) . '</strong>]';
4889 return null;
4891 } // end of the '_getSortedColumnMessage()' function
4895 * Set the content need to be show in message
4897 * @param string $sorted_column_message the message for sorted column
4898 * @param string $limit_clause the limit clause of analyzed query
4899 * @param integer $total the total number of rows returned by
4900 * the SQL query without any
4901 * programmatically appended LIMIT clause
4902 * @param integer $pos_next the offset for next page
4903 * @param string $pre_count the string renders before row count
4904 * @param string $after_count the string renders after row count
4906 * @return PMA_Message $message an object of PMA_Message
4908 * @access private
4910 * @see getTable()
4912 private function _setMessageInformation(
4913 $sorted_column_message, $limit_clause, $total,
4914 $pos_next, $pre_count, $after_count
4917 $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset()
4919 if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) {
4920 $selectstring = ', ' . $unlim_num_rows . ' ' . __('in query');
4921 } else {
4922 $selectstring = '';
4925 if (! empty($limit_clause)) {
4927 $limit_data
4928 = PMA_Util::analyzeLimitClause($limit_clause);
4929 $first_shown_rec = $limit_data['start'];
4931 if ($limit_data['length'] < $total) {
4932 $last_shown_rec = $limit_data['start'] + $limit_data['length'] - 1;
4933 } else {
4934 $last_shown_rec = $limit_data['start'] + $total - 1;
4937 } elseif (($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS)
4938 || ($pos_next > $total)
4941 $first_shown_rec = $_SESSION['tmp_user_values']['pos'];
4942 $last_shown_rec = $total - 1;
4944 } else {
4946 $first_shown_rec = $_SESSION['tmp_user_values']['pos'];
4947 $last_shown_rec = $pos_next - 1;
4951 if (PMA_Table::isView($this->__get('db'), $this->__get('table'))
4952 && ($total == $GLOBALS['cfg']['MaxExactCountViews'])
4955 $message = PMA_Message::notice(
4957 'This view has at least this number of rows. '
4958 . 'Please refer to %sdocumentation%s.'
4962 $message->addParam('[doc@cfg_MaxExactCount]');
4963 $message->addParam('[/doc]');
4964 $message_view_warning = PMA_Util::showHint($message);
4966 } else {
4967 $message_view_warning = false;
4970 $message = PMA_Message::success(__('Showing rows %1s - %2s'));
4971 $message->addParam($first_shown_rec);
4973 if ($message_view_warning) {
4974 $message->addParam('... ' . $message_view_warning, false);
4975 } else {
4976 $message->addParam($last_shown_rec);
4979 $message->addMessage('(');
4981 if (!$message_view_warning) {
4982 $message_total = PMA_Message::notice($pre_count . __('%d total'));
4983 $message_total->addParam($total);
4985 if (!empty($after_count)) {
4986 $message_total->addMessage($after_count);
4988 $message->addMessage($message_total, '');
4990 $message->addMessage($selectstring, '');
4991 $message->addMessage(', ', '');
4994 $messagge_qt = PMA_Message::notice(__('Query took %01.4f sec') . ')');
4995 $messagge_qt->addParam($this->__get('querytime'));
4997 $message->addMessage($messagge_qt, '');
4998 if (! is_null($sorted_column_message)) {
4999 $message->addMessage($sorted_column_message, '');
5002 return $message;
5004 } // end of the '_setMessageInformation()' function
5008 * Set the value of $map array for linking foreign key related tables
5010 * @param array &$map the list of relations
5012 * @return void
5014 * @access private
5016 * @see getTable()
5018 private function _setParamForLinkForeignKeyRelatedTables(&$map)
5021 // To be able to later display a link to the related table,
5022 // we verify both types of relations: either those that are
5023 // native foreign keys or those defined in the phpMyAdmin
5024 // configuration storage. If no PMA storage, we won't be able
5025 // to use the "column to display" notion (for example show
5026 // the name related to a numeric id).
5027 $exist_rel = PMA_getForeigners(
5028 $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH
5031 if ($exist_rel) {
5033 foreach ($exist_rel as $master_field => $rel) {
5035 $display_field = PMA_getDisplayField(
5036 $rel['foreign_db'], $rel['foreign_table']
5039 $map[$master_field] = array(
5040 $rel['foreign_table'],
5041 $rel['foreign_field'],
5042 $display_field,
5043 $rel['foreign_db']
5045 } // end while
5046 } // end if
5048 } // end of the '_setParamForLinkForeignKeyRelatedTables()' function
5052 * Prepare multi field edit/delete links
5054 * @param integer &$dt_result the link id associated to the query
5055 * which results have to be displayed
5056 * @param array $analyzed_sql the analyzed query
5057 * @param string $del_link the display element - 'del_link'
5059 * @return string $links_html html content
5061 * @access private
5063 * @see getTable()
5065 private function _getMultiRowOperationLinks(
5066 &$dt_result, $analyzed_sql, $del_link
5069 $links_html = '';
5070 $url_query = $this->__get('url_query');
5071 $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill');
5073 $_url_params = array(
5074 'db' => $this->__get('db'),
5075 'table' => $this->__get('table'),
5076 'sql_query' => $this->__get('sql_query'),
5077 'goto' => $this->__get('goto'),
5080 if ($_SESSION['tmp_user_values']['disp_direction'] != self::DISP_DIR_VERTICAL) {
5082 $links_html .= '<img class="selectallarrow" width="38" height="22"'
5083 . ' src="' . $this->__get('pma_theme_image') . 'arrow_'
5084 . $this->__get('text_dir') . '.png' . '"'
5085 . ' alt="' . __('With selected:') . '" />';
5088 $links_html .= '<input type="checkbox" id="checkall" title="'
5089 . __('Check All') . '" /> '
5090 . '<label for="checkall">' . __('Check All') . '</label> '
5091 . '<i style="margin-left: 2em">' . __('With selected:') . '</i>' . "\n";
5093 $links_html .= PMA_Util::getButtonOrImage(
5094 'submit_mult', 'mult_submit', 'submit_mult_change',
5095 __('Change'), 'b_edit.png', 'edit'
5098 $links_html .= PMA_Util::getButtonOrImage(
5099 'submit_mult', 'mult_submit', 'submit_mult_delete',
5100 $delete_text, 'b_drop.png', 'delete'
5103 if (isset($analyzed_sql[0])
5104 && $analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT
5106 $links_html .= PMA_Util::getButtonOrImage(
5107 'submit_mult', 'mult_submit', 'submit_mult_export',
5108 __('Export'), 'b_tblexport.png', 'export'
5112 $links_html .= "\n";
5114 $links_html .= '<input type="hidden" name="sql_query"'
5115 .' value="' . htmlspecialchars($this->__get('sql_query')) . '" />'
5116 . "\n";
5118 if (! empty($url_query)) {
5119 $links_html .= '<input type="hidden" name="url_query"'
5120 .' value="' . $url_query . '" />' . "\n";
5123 // fetch last row of the result set
5124 PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1);
5125 $row = PMA_DBI_fetch_row($dt_result);
5127 // $clause_is_unique is needed by getTable() to generate the proper param
5128 // in the multi-edit and multi-delete form
5129 list($where_clause, $clause_is_unique, $condition_array)
5130 = PMA_Util::getUniqueCondition(
5131 $dt_result,
5132 $this->__get('fields_cnt'),
5133 $this->__get('fields_meta'),
5134 $row
5137 // reset to first row for the loop in _getTableBody()
5138 PMA_DBI_data_seek($dt_result, 0);
5140 $links_html .= '<input type="hidden" name="clause_is_unique"'
5141 .' value="' . $clause_is_unique . '" />' . "\n";
5143 $links_html .= '</form>' . "\n";
5145 return $links_html;
5147 } // end of the '_getMultiRowOperationLinks()' function
5151 * Prepare table navigation bar at the top or bottom
5153 * @param integer $pos_next the offset for the "next" page
5154 * @param integer $pos_prev the offset for the "previous" page
5155 * @param string $place the place to show navigation
5156 * @param string $empty_line empty line depend on the $place
5157 * @param boolean $is_innodb whether its InnoDB or not
5159 * @return string html content of navigation bar
5161 * @access private
5163 * @see _getTable()
5165 private function _getPlacedTableNavigatoins(
5166 $pos_next, $pos_prev, $place, $empty_line, $is_innodb
5169 $navigation_html = '';
5171 if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) {
5172 $navigation_html .= '<br />' . "\n";
5175 $navigation_html .= $this->_getTableNavigation(
5176 $pos_next, $pos_prev, 'top_direction_dropdown', $is_innodb
5179 if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) {
5180 $navigation_html .= "\n";
5183 return $navigation_html;
5185 } // end of the '_getPlacedTableNavigatoins()' function
5189 * Get operations that are available on results.
5191 * @param array $the_disp_mode the display mode
5192 * @param array $analyzed_sql the analyzed query
5194 * @return string $results_operations_html html content
5196 * @access private
5198 * @see getTable()
5200 private function _getResultsOperations($the_disp_mode, $analyzed_sql)
5202 global $printview;
5204 $results_operations_html = '';
5205 $fields_meta = $this->__get('fields_meta'); // To safe use in foreach
5206 $header_shown = false;
5207 $header = '<fieldset><legend>' . __('Query results operations')
5208 . '</legend>';
5210 if (($the_disp_mode[6] == '1') || ($the_disp_mode[9] == '1')) {
5211 // Displays "printable view" link if required
5212 if ($the_disp_mode[9] == '1') {
5214 if (!$header_shown) {
5215 $results_operations_html .= $header;
5216 $header_shown = true;
5219 $_url_params = array(
5220 'db' => $this->__get('db'),
5221 'table' => $this->__get('table'),
5222 'printview' => '1',
5223 'sql_query' => $this->__get('sql_query'),
5225 $url_query = PMA_generate_common_url($_url_params);
5227 $results_operations_html
5228 .= PMA_Util::linkOrButton(
5229 'sql.php' . $url_query,
5230 PMA_Util::getIcon(
5231 'b_print.png', __('Print view'), true
5233 array('target' => 'print_view'),
5234 true,
5235 true,
5236 'print_view'
5238 . "\n";
5240 if ($_SESSION['tmp_user_values']['display_text']) {
5242 $_url_params['display_text'] = self::DISPLAY_FULL_TEXT;
5244 $results_operations_html
5245 .= PMA_Util::linkOrButton(
5246 'sql.php' . PMA_generate_common_url($_url_params),
5247 PMA_Util::getIcon(
5248 'b_print.png',
5249 __('Print view (with full texts)'), true
5251 array('target' => 'print_view'),
5252 true,
5253 true,
5254 'print_view'
5256 . "\n";
5257 unset($_url_params['display_text']);
5259 } // end displays "printable view"
5262 // Export link
5263 // (the url_query has extra parameters that won't be used to export)
5264 // (the single_table parameter is used in display_export.lib.php
5265 // to hide the SQL and the structure export dialogs)
5266 // If the parser found a PROCEDURE clause
5267 // (most probably PROCEDURE ANALYSE()) it makes no sense to
5268 // display the Export link).
5269 if (isset($analyzed_sql[0])
5270 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
5271 && ! isset($printview)
5272 && ! isset($analyzed_sql[0]['queryflags']['procedure'])
5275 if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name'])
5276 && ! isset($analyzed_sql[0]['table_ref'][1]['table_true_name'])
5278 $_url_params['single_table'] = 'true';
5281 if (! $header_shown) {
5282 $results_operations_html .= $header;
5283 $header_shown = true;
5286 $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows');
5289 * At this point we don't know the table name; this can happen
5290 * for example with a query like
5291 * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp
5292 * As a workaround we set in the table parameter the name of the
5293 * first table of this database, so that tbl_export.php and
5294 * the script it calls do not fail
5296 if (empty($_url_params['table']) && ! empty($_url_params['db'])) {
5297 $_url_params['table'] = PMA_DBI_fetch_value("SHOW TABLES");
5298 /* No result (probably no database selected) */
5299 if ($_url_params['table'] === false) {
5300 unset($_url_params['table']);
5304 $results_operations_html .= PMA_Util::linkOrButton(
5305 'tbl_export.php' . PMA_generate_common_url($_url_params),
5306 PMA_Util::getIcon(
5307 'b_tblexport.png', __('Export'), true
5310 true,
5311 true,
5314 . "\n";
5316 // prepare chart
5317 $results_operations_html .= PMA_Util::linkOrButton(
5318 'tbl_chart.php' . PMA_generate_common_url($_url_params),
5319 PMA_Util::getIcon(
5320 'b_chart.png', __('Display chart'), true
5323 true,
5324 true,
5327 . "\n";
5329 // prepare GIS chart
5330 $geometry_found = false;
5331 // If atleast one geometry field is found
5332 foreach ($fields_meta as $meta) {
5333 if ($meta->type == self::GEOMETRY_FIELD) {
5334 $geometry_found = true;
5335 break;
5339 if ($geometry_found) {
5340 $results_operations_html
5341 .= PMA_Util::linkOrButton(
5342 'tbl_gis_visualization.php'
5343 . PMA_generate_common_url($_url_params),
5344 PMA_Util::getIcon(
5345 'b_globe.gif', __('Visualize GIS data'), true
5348 true,
5349 true,
5352 . "\n";
5356 // CREATE VIEW
5359 * @todo detect privileges to create a view
5360 * (but see 2006-01-19 note in display_create_table.lib.php,
5361 * I think we cannot detect db-specific privileges reliably)
5362 * Note: we don't display a Create view link if we found a PROCEDURE clause
5364 if (!$header_shown) {
5365 $results_operations_html .= $header;
5366 $header_shown = true;
5369 if (!PMA_DRIZZLE && !isset($analyzed_sql[0]['queryflags']['procedure'])) {
5371 $ajax_class = ' ajax';
5373 $results_operations_html .= '<span>'
5374 . PMA_Util::linkOrButton(
5375 'view_create.php' . $url_query,
5376 PMA_Util::getIcon(
5377 'b_views.png', __('Create view'), true
5379 array('class' => 'create_view' . $ajax_class), true, true, ''
5381 . '</span>' . "\n";
5384 if ($header_shown) {
5385 $results_operations_html .= '</fieldset><br />';
5388 return $results_operations_html;
5390 } // end of the '_getResultsOperations()' function
5394 * Verifies what to do with non-printable contents (binary or BLOB)
5395 * in Browse mode.
5397 * @param string $category BLOB|BINARY|GEOMETRY
5398 * @param string $content the binary content
5399 * @param string $transformation_plugin transformation plugin.
5400 * Can also be the default function:
5401 * PMA_mimeDefaultFunction
5402 * @param string $transform_options transformation parameters
5403 * @param string $default_function default transformation function
5404 * @param object $meta the meta-information about the field
5405 * @param array $url_params parameters that should go to the
5406 * download link
5408 * @return mixed string or float
5410 * @access private
5412 * @see _getDataCellForBlobColumns(),
5413 * _getDataCellForGeometryColumns(),
5414 * _getDataCellForNonNumericAndNonBlobColumns(),
5415 * _getSortedColumnMessage()
5417 private function _handleNonPrintableContents(
5418 $category, $content, $transformation_plugin, $transform_options,
5419 $default_function, $meta, $url_params = array()
5422 $result = '[' . $category;
5424 if (is_null($content)) {
5426 $result .= ' - NULL';
5427 $size = 0;
5429 } elseif (isset($content)) {
5431 $size = strlen($content);
5432 $display_size
5433 = PMA_Util::formatByteDown($size, 3, 1);
5434 $result .= ' - '. $display_size[0] . ' ' . $display_size[1];
5438 $result .= ']';
5440 if (gettype($transformation_plugin) == "object"
5441 && (strpos($transformation_plugin->getMIMESubtype(), 'Octetstream')
5442 // if we want to use a text transformation on a BLOB column
5443 || strpos($transformation_plugin->getMIMEtype(), 'Text') !== false)
5445 $result = $content;
5448 if ($size > 0) {
5450 if ($default_function != $transformation_plugin) {
5451 $result = $transformation_plugin->applyTransformation(
5452 $result,
5453 $transform_options,
5454 $meta
5456 } else {
5458 $result = $this->$default_function($result, array(), $meta);
5459 if (stristr($meta->type, self::BLOB_FIELD)
5460 && $_SESSION['tmp_user_values']['display_blob']
5462 // in this case, restart from the original $content
5463 $result = $this->_displayBinaryAsPrintable($content, 'blob');
5466 /* Create link to download */
5467 if (count($url_params) > 0) {
5468 $result = '<a href="tbl_get_field.php'
5469 . PMA_generate_common_url($url_params) . '" class="disableAjax">'
5470 . $result . '</a>';
5475 return($result);
5477 } // end of the '_handleNonPrintableContents()' function
5481 * Prepares the displayable content of a data cell in Browse mode,
5482 * taking into account foreign key description field and transformations
5484 * @param string $class css classes for the td element
5485 * @param bool $condition_field whether the column is a part of the
5486 * where clause
5487 * @param string $analyzed_sql the analyzed query
5488 * @param object $meta the meta-information about the field
5489 * @param array $map the list of relations
5490 * @param string $data data
5491 * @param string $transformation_plugin transformation plugin.
5492 * Can also be the default function:
5493 * PMA_mimeDefaultFunction
5494 * @param string $default_function default function
5495 * @param string $nowrap 'nowrap' if the content should not
5496 * be wrapped
5497 * @param string $where_comparison data for the where clause
5498 * @param array $transform_options array of options for transformation
5499 * @param bool $is_field_truncated whether the field is truncated
5501 * @return string formatted data
5503 * @access private
5505 * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
5506 * _getDataCellForNonNumericAndNonBlobColumns(),
5509 private function _getRowData(
5510 $class, $condition_field, $analyzed_sql, $meta, $map, $data,
5511 $transformation_plugin, $default_function, $nowrap, $where_comparison,
5512 $transform_options, $is_field_truncated
5515 $printview = $this->__get('printview');
5516 $result = '<td class="'
5517 . $this->_addClass(
5518 $class, $condition_field, $meta, $nowrap,
5519 $is_field_truncated, $transformation_plugin, $default_function
5521 . '">';
5523 if (isset($analyzed_sql[0]['select_expr'])
5524 && is_array($analyzed_sql[0]['select_expr'])
5527 foreach ($analyzed_sql[0]['select_expr']
5528 as $select_expr_position => $select_expr
5531 $alias = $analyzed_sql[0]['select_expr']
5532 [$select_expr_position]['alias'];
5534 if (isset($alias) && strlen($alias)) {
5535 $true_column = $analyzed_sql[0]['select_expr']
5536 [$select_expr_position]['column'];
5538 if ($alias == $meta->name) {
5539 // this change in the parameter does not matter
5540 // outside of the function
5541 $meta->name = $true_column;
5542 } // end if
5544 } // end if
5545 } // end foreach
5546 } // end if
5548 if (isset($map[$meta->name])) {
5550 // Field to display from the foreign table?
5551 if (isset($map[$meta->name][2]) && strlen($map[$meta->name][2])) {
5553 $dispsql = 'SELECT '
5554 . PMA_Util::backquote($map[$meta->name][2])
5555 . ' FROM '
5556 . PMA_Util::backquote($map[$meta->name][3])
5557 . '.'
5558 . PMA_Util::backquote($map[$meta->name][0])
5559 . ' WHERE '
5560 . PMA_Util::backquote($map[$meta->name][1])
5561 . $where_comparison;
5563 $dispresult = PMA_DBI_try_query($dispsql, null, PMA_DBI_QUERY_STORE);
5565 if ($dispresult && PMA_DBI_num_rows($dispresult) > 0) {
5566 list($dispval) = PMA_DBI_fetch_row($dispresult, 0);
5567 } else {
5568 $dispval = __('Link not found');
5571 @PMA_DBI_free_result($dispresult);
5573 } else {
5574 $dispval = '';
5575 } // end if... else...
5577 if (isset($printview) && ($printview == '1')) {
5579 $result .= ($transformation_plugin != $default_function
5580 ? $transformation_plugin->applyTransformation(
5581 $data,
5582 $transform_options,
5583 $meta
5585 : $this->$default_function($data)
5587 . ' <code>[-&gt;' . $dispval . ']</code>';
5589 } else {
5591 if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_KEY) {
5593 // user chose "relational key" in the display options, so
5594 // the title contains the display field
5595 $title = (! empty($dispval))
5596 ? ' title="' . htmlspecialchars($dispval) . '"'
5597 : '';
5599 } else {
5600 $title = ' title="' . htmlspecialchars($data) . '"';
5603 $_url_params = array(
5604 'db' => $map[$meta->name][3],
5605 'table' => $map[$meta->name][0],
5606 'pos' => '0',
5607 'sql_query' => 'SELECT * FROM '
5608 . PMA_Util::backquote(
5609 $map[$meta->name][3]
5610 ) . '.'
5611 . PMA_Util::backquote(
5612 $map[$meta->name][0]
5614 . ' WHERE '
5615 . PMA_Util::backquote(
5616 $map[$meta->name][1]
5618 . $where_comparison,
5621 $result .= '<a class="ajax" href="sql.php' . PMA_generate_common_url($_url_params)
5622 . '"' . $title . '>';
5624 if ($transformation_plugin != $default_function) {
5625 // always apply a transformation on the real data,
5626 // not on the display field
5627 $result .= $transformation_plugin->applyTransformation(
5628 $data,
5629 $transform_options,
5630 $meta
5632 } else {
5634 if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_DISPLAY_COLUMN) {
5635 // user chose "relational display field" in the
5636 // display options, so show display field in the cell
5637 $result .= $this->$default_function($dispval);
5638 } else {
5639 // otherwise display data in the cell
5640 $result .= $this->$default_function($data);
5644 $result .= '</a>';
5647 } else {
5648 $result .= ($transformation_plugin != $default_function
5649 ? $transformation_plugin->applyTransformation(
5650 $data,
5651 $transform_options,
5652 $meta
5654 : $this->$default_function($data)
5658 // create hidden field if results from structure table
5659 if (isset($_GET['browse_distinct']) && ($_GET['browse_distinct'] == 1)) {
5661 $where_comparison = " = '" . $data . "'";
5663 $_url_params_for_show_data_row = array(
5664 'db' => $this->__get('db'),
5665 'table' => $meta->orgtable,
5666 'pos' => '0',
5667 'sql_query' => 'SELECT * FROM '
5668 . PMA_Util::backquote($this->__get('db'))
5669 . '.' . PMA_Util::backquote($meta->orgtable)
5670 . ' WHERE '
5671 . PMA_Util::backquote($meta->orgname)
5672 . $where_comparison,
5675 $result .= '<input type="hidden" class="data_browse_link" value="'
5676 . PMA_generate_common_url($_url_params_for_show_data_row). '" />';
5680 $result .= '</td>' . "\n";
5682 return $result;
5684 } // end of the '_getRowData()' function
5688 * Prepares a checkbox for multi-row submits
5690 * @param string $del_url delete url
5691 * @param array $is_display array with explicit indexes for all
5692 * the display elements
5693 * @param string $row_no the row number
5694 * @param string $where_clause_html url encoded where clause
5695 * @param array $condition_array array of conditions in the where clause
5696 * @param string $del_query delete query
5697 * @param string $id_suffix suffix for the id
5698 * @param string $class css classes for the td element
5700 * @return string the generated HTML
5702 * @access private
5704 * @see _getTableBody(), _getCheckboxAndLinks()
5706 private function _getCheckboxForMultiRowSubmissions(
5707 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5708 $del_query, $id_suffix, $class
5711 $ret = '';
5713 if (! empty($del_url) && $is_display['del_lnk'] != self::KILL_PROCESS) {
5715 $ret .= '<td ';
5716 if (! empty($class)) {
5717 $ret .= 'class="' . $class . '"';
5720 $ret .= ' class="center">'
5721 . '<input type="checkbox" id="id_rows_to_delete'
5722 . $row_no . $id_suffix
5723 . '" name="rows_to_delete[' . $row_no . ']"'
5724 . ' class="multi_checkbox checkall"'
5725 . ' value="' . $where_clause_html . '" '
5726 . ' />'
5727 . '<input type="hidden" class="condition_array" value="'
5728 . htmlspecialchars(json_encode($condition_array)) . '" />'
5729 . ' </td>';
5732 return $ret;
5734 } // end of the '_getCheckboxForMultiRowSubmissions()' function
5738 * Prepares an Edit link
5740 * @param string $edit_url edit url
5741 * @param string $class css classes for td element
5742 * @param string $edit_str text for the edit link
5743 * @param string $where_clause where clause
5744 * @param string $where_clause_html url encoded where clause
5746 * @return string the generated HTML
5748 * @access private
5750 * @see _getTableBody(), _getCheckboxAndLinks()
5752 private function _getEditLink(
5753 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5756 $ret = '';
5757 if (! empty($edit_url)) {
5759 $ret .= '<td class="' . $class . ' center" ' . ' ><span class="nowrap">'
5760 . PMA_Util::linkOrButton(
5761 $edit_url, $edit_str, array(), false
5764 * Where clause for selecting this row uniquely is provided as
5765 * a hidden input. Used by jQuery scripts for handling grid editing
5767 if (! empty($where_clause)) {
5768 $ret .= '<input type="hidden" class="where_clause" value ="'
5769 . $where_clause_html . '" />';
5771 $ret .= '</span></td>';
5774 return $ret;
5776 } // end of the '_getEditLink()' function
5780 * Prepares an Copy link
5782 * @param string $copy_url copy url
5783 * @param string $copy_str text for the copy link
5784 * @param string $where_clause where clause
5785 * @param string $where_clause_html url encoded where clause
5786 * @param string $class css classes for the td element
5788 * @return string the generated HTML
5790 * @access private
5792 * @see _getTableBody(), _getCheckboxAndLinks()
5794 private function _getCopyLink(
5795 $copy_url, $copy_str, $where_clause, $where_clause_html, $class
5798 $ret = '';
5799 if (! empty($copy_url)) {
5801 $ret .= '<td class="';
5802 if (! empty($class)) {
5803 $ret .= $class . ' ';
5806 $ret .= 'center" ' . ' ><span class="nowrap">'
5807 . PMA_Util::linkOrButton(
5808 $copy_url, $copy_str, array(), false
5812 * Where clause for selecting this row uniquely is provided as
5813 * a hidden input. Used by jQuery scripts for handling grid editing
5815 if (! empty($where_clause)) {
5816 $ret .= '<input type="hidden" class="where_clause" value="'
5817 . $where_clause_html . '" />';
5819 $ret .= '</span></td>';
5822 return $ret;
5824 } // end of the '_getCopyLink()' function
5828 * Prepares a Delete link
5830 * @param string $del_url delete url
5831 * @param string $del_str text for the delete link
5832 * @param string $js_conf text for the JS confirmation
5833 * @param string $class css classes for the td element
5835 * @return string the generated HTML
5837 * @access private
5839 * @see _getTableBody(), _getCheckboxAndLinks()
5841 private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
5844 $ret = '';
5845 if (! empty($del_url)) {
5847 $ret .= '<td class="';
5848 if (! empty($class)) {
5849 $ret .= $class . ' ';
5851 $ajax = PMA_Response::getInstance()->isAjax() ? ' ajax' : '';
5852 $ret .= 'center" ' . ' >'
5853 . PMA_Util::linkOrButton(
5854 $del_url, $del_str, array('class' => 'delete_row' . $ajax), false
5856 . '<div class="hide">' . $js_conf . '</div>'
5857 . '</td>';
5860 return $ret;
5862 } // end of the '_getDeleteLink()' function
5866 * Prepare checkbox and links at some position (left or right)
5867 * (only called for horizontal mode)
5869 * @param string $position the position of the checkbox and links
5870 * @param string $del_url delete url
5871 * @param array $is_display array with explicit indexes for all the
5872 * display elements
5873 * @param string $row_no row number
5874 * @param string $where_clause where clause
5875 * @param string $where_clause_html url encoded where clause
5876 * @param array $condition_array array of conditions in the where clause
5877 * @param string $del_query delete query
5878 * @param string $id_suffix suffix for the id
5879 * @param string $edit_url edit url
5880 * @param string $copy_url copy url
5881 * @param string $class css classes for the td elements
5882 * @param string $edit_str text for the edit link
5883 * @param string $copy_str text for the copy link
5884 * @param string $del_str text for the delete link
5885 * @param string $js_conf text for the JS confirmation
5887 * @return string the generated HTML
5889 * @access private
5891 * @see _getPlacedLinks()
5893 private function _getCheckboxAndLinks(
5894 $position, $del_url, $is_display, $row_no, $where_clause,
5895 $where_clause_html, $condition_array, $del_query, $id_suffix,
5896 $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
5899 $ret = '';
5901 if ($position == self::POSITION_LEFT) {
5903 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5904 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5905 $del_query, $id_suffix = '_left', ''
5908 $ret .= $this->_getEditLink(
5909 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5912 $ret .= $this->_getCopyLink(
5913 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5916 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5918 } elseif ($position == self::POSITION_RIGHT) {
5920 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5922 $ret .= $this->_getCopyLink(
5923 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5926 $ret .= $this->_getEditLink(
5927 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5930 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5931 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5932 $del_query, $id_suffix = '_right', ''
5935 } else { // $position == self::POSITION_NONE
5937 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5938 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5939 $del_query, $id_suffix = '_left', ''
5943 return $ret;
5945 } // end of the '_getCheckboxAndLinks()' function
5949 * Replace some html-unfriendly stuff
5951 * @param string $buffer String to process
5953 * @return Escaped and cleaned up text suitable for html.
5955 * @access private
5957 * @see _getDataCellForBlobField(), _getRowData(),
5958 * _handleNonPrintableContents()
5960 private function _mimeDefaultFunction($buffer)
5962 $buffer = htmlspecialchars($buffer);
5963 $buffer = str_replace(
5964 "\011",
5965 ' &nbsp;&nbsp;&nbsp;',
5966 str_replace(' ', ' &nbsp;', $buffer)
5968 $buffer = preg_replace("@((\015\012)|(\015)|(\012))@", '<br />', $buffer);
5970 return $buffer;
5974 * Display binary fields as hex string for PHP <5.4,
5975 * otherwise escape the contents if it may be displayed as hex
5977 * @param string $content String to parse
5978 * @param string $binary_or_blob 'binary' or 'blob'
5979 * @param int $hexlength optional, get substring
5981 * @return Displayable version of the binary string
5983 * @access private
5985 * @see _getDataCellForGeometryColumns
5986 * _getDataCellForNonNumericAndNonBlobColumns
5987 * _handleNonPrintableContents
5989 private function _displayBinaryAsPrintable(
5990 $content, $binary_or_blob, $hexlength = null
5992 if (PMA_PHP_INT_VERSION < 50400
5993 || ($binary_or_blob === 'binary'
5994 && $_SESSION['tmp_user_values']['display_binary_as_hex']
5995 && PMA_Util::containsNonPrintableAscii($content)
5998 $content = bin2hex($content);
5999 if ($hexlength !== null) {
6000 $content = PMA_substr($content, $hexlength);
6002 } else {
6003 $content = htmlspecialchars(
6004 PMA_Util::replaceBinaryContents(
6005 $content
6007 ENT_SUBSTITUTE
6010 return $content;