Upgraded phpmyadmin to 4.0.4 (All Languages) - No modifications yet
[openemr.git] / phpmyadmin / libraries / DisplayResults.class.php
blob35dd112eaffda0c1baa78393d8bc8c62cdec762d
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 global variable represent the columns which needs to be syntax
160 * highlighted in each database tables
161 * One element of this array represent all relavant columns in all tables in
162 * one specific database
164 public $syntax_highlighting_column_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->syntax_highlighting_column_info = array(
211 'information_schema' => array(
212 'processlist' => array(
213 'info' => array(
214 'libraries/plugins/transformations/'
215 . 'Text_Plain_Formatted.class.php',
216 'Text_Plain_Formatted',
217 'Text_Plain'
223 $this->__set('db', $db);
224 $this->__set('table', $table);
225 $this->__set('goto', $goto);
226 $this->__set('sql_query', $sql_query);
231 * Set properties which were not initialized at the constructor
233 * @param type $unlim_num_rows integer the total number of rows returned by
234 * the SQL query without any appended
235 * "LIMIT" clause programmatically
236 * @param type $fields_meta array meta information about fields
237 * @param type $is_count boolean
238 * @param type $is_export integer
239 * @param type $is_func boolean
240 * @param type $is_analyse integer
241 * @param type $num_rows integer total no. of rows returned by SQL query
242 * @param type $fields_cnt integer total no.of fields returned by SQL query
243 * @param type $querytime double time taken for execute the SQL query
244 * @param type $pmaThemeImage string path for theme images directory
245 * @param type $text_dir string
246 * @param type $is_maint boolean
247 * @param type $is_explain boolean
248 * @param type $is_show boolean
249 * @param type $showtable array table definitions
250 * @param type $printview string
251 * @param type $url_query string URL query
252 * @param type $editable boolean whether the resutls set is editable
254 * @return void
256 * @see sql.php
258 public function setProperties(
259 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
260 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
261 $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
262 $editable
265 $this->__set('unlim_num_rows', $unlim_num_rows);
266 $this->__set('fields_meta', $fields_meta);
267 $this->__set('is_count', $is_count);
268 $this->__set('is_export', $is_export);
269 $this->__set('is_func', $is_func);
270 $this->__set('is_analyse', $is_analyse);
271 $this->__set('num_rows', $num_rows);
272 $this->__set('fields_cnt', $fields_cnt);
273 $this->__set('querytime', $querytime);
274 $this->__set('pma_theme_image', $pmaThemeImage);
275 $this->__set('text_dir', $text_dir);
276 $this->__set('is_maint', $is_maint);
277 $this->__set('is_explain', $is_explain);
278 $this->__set('is_show', $is_show);
279 $this->__set('showtable', $showtable);
280 $this->__set('printview', $printview);
281 $this->__set('url_query', $url_query);
282 $this->__set('editable', $editable);
284 } // end of the 'setProperties()' function
288 * Defines the display mode to use for the results of a SQL query
290 * It uses a synthetic string that contains all the required informations.
291 * In this string:
292 * - the first two characters stand for the action to do while
293 * clicking on the "edit" link (e.g. 'ur' for update a row, 'nn' for no
294 * edit link...);
295 * - the next two characters stand for the action to do while
296 * clicking on the "delete" link (e.g. 'kp' for kill a process, 'nn' for
297 * no delete link...);
298 * - the next characters are boolean values (1/0) and respectively stand
299 * for sorting links, navigation bar, "insert a new row" link, the
300 * bookmark feature, the expand/collapse text/blob fields button and
301 * the "display printable view" option.
302 * Of course '0'/'1' means the feature won't/will be enabled.
304 * @param string &$the_disp_mode the synthetic value for display_mode (see a few
305 * lines above for explanations)
306 * @param integer &$the_total the total number of rows returned by the SQL
307 * query without any programmatically appended
308 * LIMIT clause
309 * (just a copy of $unlim_num_rows if it exists,
310 * elsecomputed inside this function)
312 * @return array an array with explicit indexes for all the display
313 * elements
315 * @access private
317 * @see getTable()
319 private function _setDisplayMode(&$the_disp_mode, &$the_total)
322 // Following variables are needed for use in isset/empty or
323 // use with array indexes or safe use in foreach
324 $db = $this->__get('db');
325 $table = $this->__get('table');
326 $unlim_num_rows = $this->__get('unlim_num_rows');
327 $fields_meta = $this->__get('fields_meta');
328 $printview = $this->__get('printview');
330 // 1. Initializes the $do_display array
331 $do_display = array();
332 $do_display['edit_lnk'] = $the_disp_mode[0] . $the_disp_mode[1];
333 $do_display['del_lnk'] = $the_disp_mode[2] . $the_disp_mode[3];
334 $do_display['sort_lnk'] = (string) $the_disp_mode[4];
335 $do_display['nav_bar'] = (string) $the_disp_mode[5];
336 $do_display['ins_row'] = (string) $the_disp_mode[6];
337 $do_display['bkm_form'] = (string) $the_disp_mode[7];
338 $do_display['text_btn'] = (string) $the_disp_mode[8];
339 $do_display['pview_lnk'] = (string) $the_disp_mode[9];
341 // 2. Display mode is not "false for all elements" -> updates the
342 // display mode
343 if ($the_disp_mode != 'nnnn000000') {
345 if (isset($printview) && ($printview == '1')) {
346 // 2.0 Print view -> set all elements to false!
347 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
348 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
349 $do_display['sort_lnk'] = (string) '0';
350 $do_display['nav_bar'] = (string) '0';
351 $do_display['ins_row'] = (string) '0';
352 $do_display['bkm_form'] = (string) '0';
353 $do_display['text_btn'] = (string) '0';
354 $do_display['pview_lnk'] = (string) '0';
356 } elseif ($this->__get('is_count') || $this->__get('is_analyse')
357 || $this->__get('is_maint') || $this->__get('is_explain')
359 // 2.1 Statement is a "SELECT COUNT", a
360 // "CHECK/ANALYZE/REPAIR/OPTIMIZE", an "EXPLAIN" one or
361 // contains a "PROC ANALYSE" part
362 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
363 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
364 $do_display['sort_lnk'] = (string) '0';
365 $do_display['nav_bar'] = (string) '0';
366 $do_display['ins_row'] = (string) '0';
367 $do_display['bkm_form'] = (string) '1';
369 if ($this->__get('is_maint')) {
370 $do_display['text_btn'] = (string) '1';
371 } else {
372 $do_display['text_btn'] = (string) '0';
374 $do_display['pview_lnk'] = (string) '1';
376 } elseif ($this->__get('is_show')) {
377 // 2.2 Statement is a "SHOW..."
379 * 2.2.1
380 * @todo defines edit/delete links depending on show statement
382 $tmp = preg_match(
383 '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
384 . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
385 . ')@i',
386 $this->__get('sql_query'), $which
388 if (isset($which[1])
389 && (strpos(' ' . strtoupper($which[1]), 'PROCESSLIST') > 0)
391 // no edit link
392 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
393 // "kill process" type edit link
394 $do_display['del_lnk'] = self::KILL_PROCESS;
395 } else {
396 // Default case -> no links
397 // no edit link
398 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
399 // no delete link
400 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
402 // 2.2.2 Other settings
403 $do_display['sort_lnk'] = (string) '0';
404 $do_display['nav_bar'] = (string) '0';
405 $do_display['ins_row'] = (string) '0';
406 $do_display['bkm_form'] = (string) '1';
407 $do_display['text_btn'] = (string) '1';
408 $do_display['pview_lnk'] = (string) '1';
410 } else {
411 // 2.3 Other statements (ie "SELECT" ones) -> updates
412 // $do_display['edit_lnk'], $do_display['del_lnk'] and
413 // $do_display['text_btn'] (keeps other default values)
414 $prev_table = $fields_meta[0]->table;
415 $do_display['text_btn'] = (string) '1';
417 for ($i = 0; $i < $this->__get('fields_cnt'); $i++) {
419 $is_link = ($do_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
420 || ($do_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
421 || ($do_display['sort_lnk'] != '0')
422 || ($do_display['ins_row'] != '0');
424 // 2.3.2 Displays edit/delete/sort/insert links?
425 if ($is_link
426 && (($fields_meta[$i]->table == '')
427 || ($fields_meta[$i]->table != $prev_table))
429 // don't display links
430 $do_display['edit_lnk'] = self::NO_EDIT_OR_DELETE;
431 $do_display['del_lnk'] = self::NO_EDIT_OR_DELETE;
433 * @todo May be problematic with same field names
434 * in two joined table.
436 // $do_display['sort_lnk'] = (string) '0';
437 $do_display['ins_row'] = (string) '0';
438 if ($do_display['text_btn'] == '1') {
439 break;
441 } // end if (2.3.2)
443 // 2.3.3 Always display print view link
444 $do_display['pview_lnk'] = (string) '1';
445 $prev_table = $fields_meta[$i]->table;
447 } // end for
448 } // end if..elseif...else (2.1 -> 2.3)
449 } // end if (2)
451 // 3. Gets the total number of rows if it is unknown
452 if (isset($unlim_num_rows) && $unlim_num_rows != '') {
453 $the_total = $unlim_num_rows;
454 } elseif ((($do_display['nav_bar'] == '1')
455 || ($do_display['sort_lnk'] == '1'))
456 && (strlen($db) && !empty($table))
458 $the_total = PMA_Table::countRecords($db, $table);
461 // 4. If navigation bar or sorting fields names URLs should be
462 // displayed but there is only one row, change these settings to
463 // false
464 if ($do_display['nav_bar'] == '1' || $do_display['sort_lnk'] == '1') {
466 // - Do not display sort links if less than 2 rows.
467 // - For a VIEW we (probably) did not count the number of rows
468 // so don't test this number here, it would remove the possibility
469 // of sorting VIEW results.
470 if (isset($unlim_num_rows)
471 && ($unlim_num_rows < 2)
472 && ! PMA_Table::isView($db, $table)
474 // force display of navbar for vertical/horizontal display-choice.
475 // $do_display['nav_bar'] = (string) '0';
476 $do_display['sort_lnk'] = (string) '0';
478 } // end if (3)
480 // 5. Updates the synthetic var
481 $the_disp_mode = join('', $do_display);
483 return $do_display;
485 } // end of the 'setDisplayMode()' function
489 * Return true if we are executing a query in the form of
490 * "SELECT * FROM <a table> ..."
492 * @param array $analyzed_sql the analyzed query
494 * @return boolean
496 * @access private
498 * @see _getTableHeaders(), _getColumnParams()
500 private function _isSelect($analyzed_sql)
502 if (!isset($analyzed_sql[0]['select_expr'])) {
503 $analyzed_sql[0]['select_expr'] = 0;
506 return ! ($this->__get('is_count') || $this->__get('is_export')
507 || $this->__get('is_func') || $this->__get('is_analyse'))
508 && (count($analyzed_sql[0]['select_expr']) == 0)
509 && isset($analyzed_sql[0]['queryflags']['select_from'])
510 && (count($analyzed_sql[0]['table_ref']) == 1);
515 * Get a navigation button
517 * @param string $caption iconic caption for button
518 * @param string $title text for button
519 * @param integer $pos position for next query
520 * @param string $html_sql_query query ready for display
521 * @param string $onsubmit optional onsubmit clause
522 * @param string $input_for_real_end optional hidden field for special treatment
523 * @param string $onclick optional onclick clause
525 * @return string html content
527 * @access private
529 * @see _getMoveBackwardButtonsForTableNavigation(),
530 * _getMoveForwardButtonsForTableNavigation()
532 private function _getTableNavigationButton(
533 $caption, $title, $pos, $html_sql_query, $onsubmit = '',
534 $input_for_real_end = '', $onclick = ''
537 $caption_output = '';
538 // for true or 'both'
539 if ($GLOBALS['cfg']['NavigationBarIconic']) {
540 $caption_output .= $caption;
543 // for false or 'both'
544 if (($GLOBALS['cfg']['NavigationBarIconic'] === false)
545 || ($GLOBALS['cfg']['NavigationBarIconic'] === self::POSITION_BOTH)
547 $caption_output .= '&nbsp;' . $title;
549 $title_output = ' title="' . $title . '"';
551 return '<td>'
552 . '<form action="sql.php" method="post" ' . $onsubmit . '>'
553 . PMA_generate_common_hidden_inputs(
554 $this->__get('db'), $this->__get('table')
556 . '<input type="hidden" name="sql_query" value="'
557 . $html_sql_query . '" />'
558 . '<input type="hidden" name="pos" value="' . $pos . '" />'
559 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
560 . '" />'
561 . $input_for_real_end
562 . '<input type="submit" name="navig"'
563 . ' class="ajax" '
564 . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
565 . '</form>'
566 . '</td>';
568 } // end function _getTableNavigationButton()
572 * Get a navigation bar to browse among the results of a SQL query
574 * @param integer $pos_next the offset for the "next" page
575 * @param integer $pos_prev the offset for the "previous" page
576 * @param string $id_for_direction_dropdown the id for the direction dropdown
577 * @param boolean $is_innodb whether its InnoDB or not
579 * @return string html content
581 * @access private
583 * @see _getTable()
585 private function _getTableNavigation(
586 $pos_next, $pos_prev, $id_for_direction_dropdown, $is_innodb
589 $table_navigation_html = '';
590 $showtable = $this->__get('showtable'); // To use in isset
592 // here, using htmlentities() would cause problems if the query
593 // contains accented characters
594 $html_sql_query = htmlspecialchars($this->__get('sql_query'));
597 * @todo move this to a central place
598 * @todo for other future table types
600 $is_innodb = (isset($showtable['Type'])
601 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
603 // Navigation bar
604 $table_navigation_html .= '<table class="navigation nospacing nopadding">'
605 . '<tr>'
606 . '<td class="navigation_separator"></td>';
608 // Move to the beginning or to the previous page
609 if ($_SESSION['tmp_user_values']['pos']
610 && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
613 $table_navigation_html
614 .= $this->_getMoveBackwardButtonsForTableNavigation(
615 $html_sql_query, $pos_prev
618 } // end move back
620 $nbTotalPage = 1;
621 //page redirection
622 // (unless we are showing all records)
623 if ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS) { //if1
625 $pageNow = @floor(
626 $_SESSION['tmp_user_values']['pos']
627 / $_SESSION['tmp_user_values']['max_rows']
628 ) + 1;
630 $nbTotalPage = @ceil(
631 $this->__get('unlim_num_rows')
632 / $_SESSION['tmp_user_values']['max_rows']
635 if ($nbTotalPage > 1) { //if2
637 $table_navigation_html .= '<td>';
638 $_url_params = array(
639 'db' => $this->__get('db'),
640 'table' => $this->__get('table'),
641 'sql_query' => $this->__get('sql_query'),
642 'goto' => $this->__get('goto'),
645 //<form> to keep the form alignment of button < and <<
646 // and also to know what to execute when the selector changes
647 $table_navigation_html .= '<form action="sql.php'
648 . PMA_generate_common_url($_url_params)
649 . '" method="post">';
651 $table_navigation_html .= PMA_Util::pageselector(
652 'pos',
653 $_SESSION['tmp_user_values']['max_rows'],
654 $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
657 $table_navigation_html .= '</form>'
658 . '</td>';
659 } //_if2
660 } //_if1
662 // Display the "Show all" button if allowed
663 if (($this->__get('num_rows') < $this->__get('unlim_num_rows'))
664 && ($GLOBALS['cfg']['ShowAll']
665 || ($GLOBALS['cfg']['MaxRows'] * 5 >= $this->__get('unlim_num_rows')))
668 $table_navigation_html .= $this->_getShowAllButtonForTableNavigation(
669 $html_sql_query
672 } // end show all
674 // Move to the next page or to the last one
675 $endpos = $_SESSION['tmp_user_values']['pos']
676 + $_SESSION['tmp_user_values']['max_rows'];
678 if (($endpos < $this->__get('unlim_num_rows'))
679 && ($this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows'])
680 && ($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
683 $table_navigation_html
684 .= $this->_getMoveForwardButtonsForTableNavigation(
685 $html_sql_query, $pos_next, $is_innodb
688 } // end move toward
690 // show separator if pagination happen
691 if ($nbTotalPage > 1) {
692 $table_navigation_html
693 .= '<td><div class="navigation_separator">|</div></td>';
696 $table_navigation_html .= '<td>'
697 . '<div class="save_edited hide">'
698 . '<input type="submit" value="' . __('Save edited data') . '" />'
699 . '<div class="navigation_separator">|</div>'
700 . '</div>'
701 . '</td>'
702 . '<td>'
703 . '<div class="restore_column hide">'
704 . '<input type="submit" value="' . __('Restore column order') . '" />'
705 . '<div class="navigation_separator">|</div>'
706 . '</div>'
707 . '</td>';
709 // if displaying a VIEW, $unlim_num_rows could be zero because
710 // of $cfg['MaxExactCountViews']; in this case, avoid passing
711 // the 5th parameter to checkFormElementInRange()
712 // (this means we can't validate the upper limit
713 $table_navigation_html .= '<td class="navigation_goto">';
715 $table_navigation_html .= '<form action="sql.php" method="post" '
716 . 'onsubmit="return '
717 . '(checkFormElementInRange('
718 . 'this, '
719 . '\'session_max_rows\', '
720 . '\''
721 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
722 . '\', '
723 . '1)'
724 . ' &amp;&amp; '
725 . 'checkFormElementInRange('
726 . 'this, '
727 . '\'pos\', '
728 . '\''
729 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
730 . '\', '
731 . '0'
732 . (($this->__get('unlim_num_rows') > 0)
733 ? ', ' . ($this->__get('unlim_num_rows') - 1)
734 : ''
736 . ')'
737 . ')'
738 .'">';
740 $table_navigation_html .= PMA_generate_common_hidden_inputs(
741 $this->__get('db'), $this->__get('table')
744 $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
745 $html_sql_query, $pos_next, $id_for_direction_dropdown
748 $table_navigation_html .= '</form>'
749 . '</td>'
750 . '<td class="navigation_separator"></td>'
751 . '</tr>'
752 . '</table>';
754 return $table_navigation_html;
756 } // end of the '_getTableNavigation()' function
760 * Prepare move backward buttons - previous and first
762 * @param string $html_sql_query the sql encoded by html special characters
763 * @param integer $pos_prev the offset for the "previous" page
765 * @return string html content
767 * @access private
769 * @see _getTableNavigation()
771 private function _getMoveBackwardButtonsForTableNavigation(
772 $html_sql_query, $pos_prev
774 return $this->_getTableNavigationButton(
775 '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query
777 . $this->_getTableNavigationButton(
778 '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
779 $html_sql_query
781 } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
785 * Prepare Show All button for table navigation
787 * @param string $html_sql_query the sql encoded by html special characters
789 * @return string html content
791 * @access private
793 * @see _getTableNavigation()
795 private function _getShowAllButtonForTableNavigation($html_sql_query)
797 return "\n"
798 . '<td>'
799 . '<form action="sql.php" method="post">'
800 . PMA_generate_common_hidden_inputs(
801 $this->__get('db'), $this->__get('table')
803 . '<input type="hidden" name="sql_query" value="'
804 . $html_sql_query . '" />'
805 . '<input type="hidden" name="pos" value="0" />'
806 . '<input type="hidden" name="session_max_rows" value="all" />'
807 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
808 . '" />'
809 . '<input type="submit" name="navig" value="' . __('Show all') . '" />'
810 . '</form>'
811 . '</td>';
812 } // end of the '_getShowAllButtonForTableNavigation()' function
816 * Prepare move farward buttons - next and last
818 * @param string $html_sql_query the sql encoded by html special characters
819 * @param integer $pos_next the offset for the "next" page
820 * @param boolean $is_innodb whether its InnoDB or not
822 * @return string $buttons_html html content
824 * @access private
826 * @see _getTableNavigation()
828 private function _getMoveForwardButtonsForTableNavigation(
829 $html_sql_query, $pos_next, $is_innodb
832 // display the Next button
833 $buttons_html = $this->_getTableNavigationButton(
834 '&gt;',
835 _pgettext('Next page', 'Next'),
836 $pos_next,
837 $html_sql_query
840 // prepare some options for the End button
841 if ($is_innodb
842 && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
844 $input_for_real_end = '<input id="real_end_input" type="hidden" '
845 . 'name="find_real_end" value="1" />';
846 // no backquote around this message
847 $onclick = '';
848 } else {
849 $input_for_real_end = $onclick = '';
852 $onsubmit = 'onsubmit="return '
853 . ($_SESSION['tmp_user_values']['pos']
854 + $_SESSION['tmp_user_values']['max_rows']
855 < $this->__get('unlim_num_rows')
856 && $this->__get('num_rows') >= $_SESSION['tmp_user_values']['max_rows'])
857 ? 'true'
858 : 'false' . '"';
860 // display the End button
861 $buttons_html .= $this->_getTableNavigationButton(
862 '&gt;&gt;',
863 _pgettext('Last page', 'End'),
864 @((ceil(
865 $this->__get('unlim_num_rows')
866 / $_SESSION['tmp_user_values']['max_rows']
867 )- 1) * $_SESSION['tmp_user_values']['max_rows']),
868 $html_sql_query, $onsubmit, $input_for_real_end, $onclick
871 return $buttons_html;
873 } // end of the '_getMoveForwardButtonsForTableNavigation()' function
877 * Prepare feilds followed by Show button for table navigation
878 * Start row, Number of rows, Headers every
880 * @param string $html_sql_query the sql encoded by html special
881 * characters
882 * @param integer $pos_next the offset for the "next" page
883 * @param string $id_for_direction_dropdown the id for the direction dropdown
885 * @return string $additional_fields_html html content
887 * @access private
889 * @see _getTableNavigation()
891 private function _getAdditionalFieldsForTableNavigation(
892 $html_sql_query, $pos_next, $id_for_direction_dropdown
895 $additional_fields_html = '';
897 $additional_fields_html .= '<input type="hidden" name="sql_query" '
898 . 'value="' . $html_sql_query . '" />'
899 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
900 . '" />'
901 . '<input type="submit" name="navig"'
902 . ' class="ajax"'
903 . ' value="' . __('Show') . ' :" />'
904 . __('Start row') . ': ' . "\n"
905 . '<input type="text" name="pos" size="3" value="'
906 . (($pos_next >= $this->__get('unlim_num_rows')) ? 0 : $pos_next)
907 . '" class="textfield" onfocus="this.select()" />'
908 . __('Number of rows') . ': ' . "\n"
909 . '<input type="text" name="session_max_rows" size="3" value="'
910 . (($_SESSION['tmp_user_values']['max_rows'] != self::ALL_ROWS)
911 ? $_SESSION['tmp_user_values']['max_rows']
912 : $GLOBALS['cfg']['MaxRows'])
913 . '" class="textfield" onfocus="this.select()" />';
915 if ($GLOBALS['cfg']['ShowDisplayDirection']) {
916 // Display mode (horizontal/vertical and repeat headers)
917 $additional_fields_html .= __('Mode') . ': ' . "\n";
918 $choices = array(
919 'horizontal' => __('horizontal'),
920 'horizontalflipped' => __('horizontal (rotated headers)'),
921 'vertical' => __('vertical')
924 $additional_fields_html .= PMA_Util::getDropdown(
925 'disp_direction', $choices,
926 $_SESSION['tmp_user_values']['disp_direction'],
927 $id_for_direction_dropdown
929 unset($choices);
932 $additional_fields_html .= sprintf(
933 __('Headers every %s rows'),
934 '<input type="text" size="3" name="repeat_cells" value="'
935 . $_SESSION['tmp_user_values']['repeat_cells']
936 . '" class="textfield" /> '
939 return $additional_fields_html;
941 } // end of the '_getAdditionalFieldsForTableNavigation()' function
945 * Get the headers of the results table
947 * @param array &$is_display which elements to display
948 * @param array $analyzed_sql the analyzed query
949 * @param string $sort_expression sort expression
950 * @param string $sort_expression_nodirection sort expression without direction
951 * @param string $sort_direction sort direction
952 * @param boolean $is_limited_display with limited operations or not
954 * @return string html content
956 * @access private
958 * @see getTable()
960 private function _getTableHeaders(
961 &$is_display, $analyzed_sql = '',
962 $sort_expression = '', $sort_expression_nodirection = '',
963 $sort_direction = '', $is_limited_display = false
966 $table_headers_html = '';
967 // Following variable are needed for use in isset/empty or
968 // use with array indexes/safe use in foreach
969 $fields_meta = $this->__get('fields_meta');
970 $highlight_columns = $this->__get('highlight_columns');
971 $printview = $this->__get('printview');
972 $vertical_display = $this->__get('vertical_display');
974 // required to generate sort links that will remember whether the
975 // "Show all" button has been clicked
976 $sql_md5 = md5($this->__get('sql_query'));
977 $session_max_rows = $is_limited_display
979 : $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'];
981 $direction = isset($_SESSION['tmp_user_values']['disp_direction'])
982 ? $_SESSION['tmp_user_values']['disp_direction']
983 : '';
985 if ($analyzed_sql == '') {
986 $analyzed_sql = array();
989 $directionCondition = ($direction == self::DISP_DIR_HORIZONTAL)
990 || ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED);
992 // can the result be sorted?
993 if ($is_display['sort_lnk'] == '1') {
995 list($unsorted_sql_query, $drop_down_html)
996 = $this->_getUnsortedSqlAndSortByKeyDropDown(
997 $analyzed_sql, $sort_expression
1000 $table_headers_html .= $drop_down_html;
1004 // Output data needed for grid editing
1005 $table_headers_html .= '<input id="save_cells_at_once" type="hidden" value="'
1006 . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
1007 . '<div class="common_hidden_inputs">'
1008 . PMA_generate_common_hidden_inputs(
1009 $this->__get('db'), $this->__get('table')
1011 . '</div>';
1013 // Output data needed for column reordering and show/hide column
1014 if ($this->_isSelect($analyzed_sql)) {
1015 $table_headers_html .= $this->_getDataForResettingColumnOrder();
1018 $vertical_display['emptypre'] = 0;
1019 $vertical_display['emptyafter'] = 0;
1020 $vertical_display['textbtn'] = '';
1021 $full_or_partial_text_link = null;
1023 $this->__set('vertical_display', $vertical_display);
1025 // Display options (if we are not in print view)
1026 if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
1028 $table_headers_html .= $this->_getOptionsBlock();
1030 // prepare full/partial text button or link
1031 $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
1034 // Start of form for multi-rows edit/delete/export
1035 $table_headers_html .= $this->_getFormForMultiRowOperations(
1036 $is_display['del_lnk']
1039 // 1. Set $colspan or $rowspan and generate html with full/partial
1040 // text button or link
1041 list($colspan, $rowspan, $button_html)
1042 = $this->_getFieldVisibilityParams(
1043 $directionCondition, $is_display, $full_or_partial_text_link
1046 $table_headers_html .= $button_html;
1048 // 2. Displays the fields' name
1049 // 2.0 If sorting links should be used, checks if the query is a "JOIN"
1050 // statement (see 2.1.3)
1052 // 2.0.1 Prepare Display column comments if enabled
1053 // ($GLOBALS['cfg']['ShowBrowseComments']).
1054 // Do not show comments, if using horizontalflipped mode,
1055 // because of space usage
1056 $comments_map = $this->_getTableCommentsArray($direction, $analyzed_sql);
1058 if ($GLOBALS['cfgRelation']['commwork']
1059 && $GLOBALS['cfgRelation']['mimework']
1060 && $GLOBALS['cfg']['BrowseMIME']
1061 && ! $_SESSION['tmp_user_values']['hide_transformation']
1063 include_once './libraries/transformations.lib.php';
1064 $this->__set(
1065 'mime_map',
1066 PMA_getMIME($this->__get('db'), $this->__get('table'))
1070 // See if we have to highlight any header fields of a WHERE query.
1071 // Uses SQL-Parser results.
1072 $this->_setHighlightedColumnGlobalField($analyzed_sql);
1074 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
1076 for ($j = 0; $j < $this->__get('fields_cnt'); $j++) {
1078 // assign $i with appropriate column order
1079 $i = $col_order ? $col_order[$j] : $j;
1081 // See if this column should get highlight because it's used in the
1082 // where-query.
1083 $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
1084 || isset($highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)]))
1085 ? true
1086 : false;
1088 // 2.0 Prepare comment-HTML-wrappers for each row, if defined/enabled.
1089 $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
1091 $vertical_display = $this->__get('vertical_display');
1093 if (($is_display['sort_lnk'] == '1') && ! $is_limited_display) {
1095 list($order_link, $sorted_headrer_html)
1096 = $this->_getOrderLinkAndSortedHeaderHtml(
1097 $fields_meta[$i], $sort_expression,
1098 $sort_expression_nodirection, $i, $unsorted_sql_query,
1099 $session_max_rows, $direction, $comments,
1100 $sort_direction, $directionCondition, $col_visib,
1101 $col_visib[$j], $condition_field
1104 $table_headers_html .= $sorted_headrer_html;
1106 $vertical_display['desc'][] = ' <th '
1107 . 'class="draggable'
1108 . ($condition_field ? ' condition' : '')
1109 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1110 . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
1111 } else {
1112 // 2.2 Results can't be sorted
1114 if ($directionCondition) {
1115 $table_headers_html
1116 .= $this->_getDraggableClassForNonSortableColumns(
1117 $col_visib, $col_visib[$j], $condition_field,
1118 $direction, $fields_meta[$i], $comments
1122 $vertical_display['desc'][] = ' <th '
1123 . 'class="draggable'
1124 . ($condition_field ? ' condition"' : '')
1125 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1126 . '">' . "\n" . ' '
1127 . htmlspecialchars($fields_meta[$i]->name)
1128 . "\n" . $comments . ' </th>';
1129 } // end else (2.2)
1131 $this->__set('vertical_display', $vertical_display);
1133 } // end for
1135 // Display column at rightside - checkboxes or empty column
1136 $table_headers_html .= $this->_getColumnAtRightSide(
1137 $is_display, $directionCondition, $full_or_partial_text_link,
1138 $colspan, $rowspan
1141 if ($directionCondition) {
1142 $table_headers_html .= '</tr>'
1143 . '</thead>';
1146 return $table_headers_html;
1148 } // end of the '_getTableHeaders()' function
1152 * Prepare unsorted sql query and sort by key drop down
1154 * @param array $analyzed_sql the analyzed query
1155 * @param string $sort_expression sort expression
1157 * @return array two element array - $unsorted_sql_query, $drop_down_html
1159 * @access private
1161 * @see _getTableHeaders()
1163 private function _getUnsortedSqlAndSortByKeyDropDown(
1164 $analyzed_sql, $sort_expression
1167 $drop_down_html = '';
1169 // Just as fallback
1170 $unsorted_sql_query = $this->__get('sql_query');
1171 if (isset($analyzed_sql[0]['unsorted_query'])) {
1172 $unsorted_sql_query = $analyzed_sql[0]['unsorted_query'];
1174 // Handles the case of multiple clicks on a column's header
1175 // which would add many spaces before "ORDER BY" in the
1176 // generated query.
1177 $unsorted_sql_query = trim($unsorted_sql_query);
1179 // sorting by indexes, only if it makes sense (only one table ref)
1180 if (isset($analyzed_sql)
1181 && isset($analyzed_sql[0])
1182 && isset($analyzed_sql[0]['querytype'])
1183 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
1184 && isset($analyzed_sql[0]['table_ref'])
1185 && (count($analyzed_sql[0]['table_ref']) == 1)
1187 // grab indexes data:
1188 $indexes = PMA_Index::getFromTable(
1189 $this->__get('table'),
1190 $this->__get('db')
1193 // do we have any index?
1194 if ($indexes) {
1195 $drop_down_html = $this->_getSortByKeyDropDown(
1196 $indexes, $sort_expression,
1197 $unsorted_sql_query
1202 return array($unsorted_sql_query, $drop_down_html);
1204 } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function
1208 * Prepare sort by key dropdown - html code segment
1210 * @param array $indexes the indexes of the table for sort criteria
1211 * @param string $sort_expression the sort expression
1212 * @param string $unsorted_sql_query the unsorted sql query
1214 * @return string $drop_down_html html content
1216 * @access private
1218 * @see _getTableHeaders()
1220 private function _getSortByKeyDropDown(
1221 $indexes, $sort_expression, $unsorted_sql_query
1224 $drop_down_html = '';
1226 $drop_down_html .= '<form action="sql.php" method="post">' . "\n"
1227 . PMA_generate_common_hidden_inputs(
1228 $this->__get('db'), $this->__get('table')
1230 . __('Sort by key')
1231 . ': <select name="sql_query" class="autosubmit">' . "\n";
1233 $used_index = false;
1234 $local_order = (isset($sort_expression) ? $sort_expression : '');
1236 foreach ($indexes as $index) {
1238 $asc_sort = '`'
1239 . implode('` ASC, `', array_keys($index->getColumns()))
1240 . '` ASC';
1242 $desc_sort = '`'
1243 . implode('` DESC, `', array_keys($index->getColumns()))
1244 . '` DESC';
1246 $used_index = $used_index
1247 || ($local_order == $asc_sort)
1248 || ($local_order == $desc_sort);
1250 if (preg_match(
1251 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|'
1252 . 'FOR UPDATE|LOCK IN SHARE MODE))@is',
1253 $unsorted_sql_query, $my_reg
1254 )) {
1255 $unsorted_sql_query_first_part = $my_reg[1];
1256 $unsorted_sql_query_second_part = $my_reg[2];
1257 } else {
1258 $unsorted_sql_query_first_part = $unsorted_sql_query;
1259 $unsorted_sql_query_second_part = '';
1262 $drop_down_html .= '<option value="'
1263 . htmlspecialchars(
1264 $unsorted_sql_query_first_part . "\n"
1265 . ' ORDER BY ' . $asc_sort
1266 . $unsorted_sql_query_second_part
1268 . '"' . ($local_order == $asc_sort
1269 ? ' selected="selected"'
1270 : '')
1271 . '>' . htmlspecialchars($index->getName()) . ' ('
1272 . __('Ascending') . ')</option>';
1274 $drop_down_html .= '<option value="'
1275 . htmlspecialchars(
1276 $unsorted_sql_query_first_part . "\n"
1277 . ' ORDER BY ' . $desc_sort
1278 . $unsorted_sql_query_second_part
1280 . '"' . ($local_order == $desc_sort
1281 ? ' selected="selected"'
1282 : '')
1283 . '>' . htmlspecialchars($index->getName()) . ' ('
1284 . __('Descending') . ')</option>';
1287 $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query)
1288 . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None')
1289 . '</option>'
1290 . '</select>' . "\n"
1291 . '</form>' . "\n";
1293 return $drop_down_html;
1295 } // end of the '_getSortByKeyDropDown()' function
1299 * Set column span, row span and prepare html with full/partial
1300 * text button or link
1302 * @param boolean $directionCondition display direction horizontal or
1303 * horizontalflipped
1304 * @param array &$is_display which elements to display
1305 * @param string $full_or_partial_text_link full/partial link or text button
1307 * @return array 3 element array - $colspan, $rowspan, $button_html
1309 * @access private
1311 * @see _getTableHeaders()
1313 private function _getFieldVisibilityParams(
1314 $directionCondition, &$is_display, $full_or_partial_text_link
1317 $button_html = '';
1318 $colspan = $rowspan = null;
1319 $vertical_display = $this->__get('vertical_display');
1321 // 1. Displays the full/partial text button (part 1)...
1322 if ($directionCondition) {
1324 $button_html .= '<thead><tr>' . "\n";
1326 $colspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1327 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1328 ? ' colspan="4"'
1329 : '';
1331 } else {
1332 $rowspan = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1333 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1334 ? ' rowspan="4"'
1335 : '';
1338 // ... before the result table
1339 if ((($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
1340 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
1341 && ($is_display['text_btn'] == '1')
1344 $vertical_display['emptypre']
1345 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1346 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1348 if ($directionCondition) {
1350 $button_html .= '<th colspan="' . $this->__get('fields_cnt') . '">'
1351 . '</th>'
1352 . '</tr>'
1353 . '<tr>';
1355 // end horizontal/horizontalflipped mode
1356 } else {
1358 $span = $this->__get('num_rows') + 1 + floor(
1359 $this->__get('num_rows')
1360 / $_SESSION['tmp_user_values']['repeat_cells']
1362 $button_html .= '<tr><th colspan="' . $span . '"></th></tr>';
1364 } // end vertical mode
1366 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1367 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1368 && ($is_display['text_btn'] == '1')
1370 // ... at the left column of the result table header if possible
1371 // and required
1373 $vertical_display['emptypre']
1374 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1375 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1377 if ($directionCondition) {
1379 $button_html .= '<th ' . $colspan . '>'
1380 . $full_or_partial_text_link . '</th>';
1381 // end horizontal/horizontalflipped mode
1383 } else {
1385 $vertical_display['textbtn']
1386 = ' <th ' . $rowspan . ' class="vmiddle">' . "\n"
1387 . ' ' . "\n"
1388 . ' </th>' . "\n";
1389 } // end vertical mode
1391 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1392 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1393 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1394 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
1396 // ... elseif no button, displays empty(ies) col(s) if required
1398 $vertical_display['emptypre']
1399 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1400 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1402 if ($directionCondition) {
1404 $button_html .= '<td ' . $colspan . '></td>';
1406 // end horizontal/horizontalfipped mode
1407 } else {
1408 $vertical_display['textbtn'] = ' <td' . $rowspan .
1409 '></td>' . "\n";
1410 } // end vertical mode
1412 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
1413 && ($directionCondition)
1415 // ... elseif display an empty column if the actions links are
1416 // disabled to match the rest of the table
1417 $button_html .= '<th></th>';
1420 $this->__set('vertical_display', $vertical_display);
1422 return array($colspan, $rowspan, $button_html);
1424 } // end of the '_getFieldVisibilityParams()' function
1428 * Get table comments as array
1430 * @param boolean $direction display direction, horizontal
1431 * or horizontalflipped
1432 * @param array $analyzed_sql the analyzed query
1434 * @return array $comments_map table comments when condition true
1435 * null when condition falls
1437 * @access private
1439 * @see _getTableHeaders()
1441 private function _getTableCommentsArray($direction, $analyzed_sql)
1444 $comments_map = null;
1446 if ($GLOBALS['cfg']['ShowBrowseComments']
1447 && ($direction != self::DISP_DIR_HORIZONTAL_FLIPPED)
1449 $comments_map = array();
1450 if (isset($analyzed_sql[0])
1451 && is_array($analyzed_sql[0])
1452 && isset($analyzed_sql[0]['table_ref'])
1454 foreach ($analyzed_sql[0]['table_ref'] as $tbl) {
1455 $tb = $tbl['table_true_name'];
1456 $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb);
1457 unset($tb);
1462 return $comments_map;
1464 } // end of the '_getTableCommentsArray()' function
1468 * Set global array for store highlighted header fields
1470 * @param array $analyzed_sql the analyzed query
1472 * @return void
1474 * @access private
1476 * @see _getTableHeaders()
1478 private function _setHighlightedColumnGlobalField($analyzed_sql)
1481 $highlight_columns = array();
1482 if (isset($analyzed_sql) && isset($analyzed_sql[0])
1483 && isset($analyzed_sql[0]['where_clause_identifiers'])
1486 $wi = 0;
1487 if (isset($analyzed_sql[0]['where_clause_identifiers'])
1488 && is_array($analyzed_sql[0]['where_clause_identifiers'])
1490 foreach ($analyzed_sql[0]['where_clause_identifiers']
1491 as $wci_nr => $wci
1493 $highlight_columns[$wci] = 'true';
1498 $this->__set('highlight_columns', $highlight_columns);
1500 } // end of the '_setHighlightedColumnGlobalField()' function
1504 * Prepare data for column restoring and show/hide
1506 * @return string $data_html html content
1508 * @access private
1510 * @see _getTableHeaders()
1512 private function _getDataForResettingColumnOrder()
1515 $data_html = '';
1517 // generate the column order, if it is set
1518 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
1519 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
1521 if ($col_order) {
1522 $data_html .= '<input id="col_order" type="hidden" value="'
1523 . implode(',', $col_order) . '" />';
1526 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
1528 if ($col_visib) {
1529 $data_html .= '<input id="col_visib" type="hidden" value="'
1530 . implode(',', $col_visib) . '" />';
1533 // generate table create time
1534 if (! PMA_Table::isView($this->__get('db'), $this->__get('table'))) {
1535 $data_html .= '<input id="table_create_time" type="hidden" value="'
1536 . PMA_Table::sGetStatusInfo(
1537 $this->__get('db'), $this->__get('table'), 'Create_time'
1538 ) . '" />';
1541 return $data_html;
1543 } // end of the '_getDataForResettingColumnOrder()' function
1547 * Prepare option fields block
1549 * @return string $options_html html content
1551 * @access private
1553 * @see _getTableHeaders()
1555 private function _getOptionsBlock()
1558 $options_html = '';
1560 $options_html .= '<form method="post" action="sql.php" '
1561 . 'name="displayOptionsForm" '
1562 . 'id="displayOptionsForm"';
1564 $options_html .= ' class="ajax" ';
1566 $options_html .= '>';
1567 $url_params = array(
1568 'db' => $this->__get('db'),
1569 'table' => $this->__get('table'),
1570 'sql_query' => $this->__get('sql_query'),
1571 'goto' => $this->__get('goto'),
1572 'display_options_form' => 1
1575 $options_html .= PMA_generate_common_hidden_inputs($url_params)
1576 . '<br />'
1577 . PMA_Util::getDivForSliderEffect(
1578 'displayoptions', __('Options')
1580 . '<fieldset>';
1582 $options_html .= '<div class="formelement">';
1583 $choices = array(
1584 'P' => __('Partial texts'),
1585 'F' => __('Full texts')
1588 $options_html .= PMA_Util::getRadioFields(
1589 'display_text', $choices,
1590 $_SESSION['tmp_user_values']['display_text']
1592 . '</div>';
1594 if ($GLOBALS['cfgRelation']['relwork']
1595 && $GLOBALS['cfgRelation']['displaywork']
1597 $options_html .= '<div class="formelement">';
1598 $choices = array(
1599 'K' => __('Relational key'),
1600 'D' => __('Relational display column')
1603 $options_html .= PMA_Util::getRadioFields(
1604 'relational_display', $choices,
1605 $_SESSION['tmp_user_values']['relational_display']
1607 . '</div>';
1610 $options_html .= '<div class="formelement">'
1611 . PMA_Util::getCheckbox(
1612 'display_binary', __('Show binary contents'),
1613 ! empty($_SESSION['tmp_user_values']['display_binary']), false
1615 . '<br />'
1616 . PMA_Util::getCheckbox(
1617 'display_blob', __('Show BLOB contents'),
1618 ! empty($_SESSION['tmp_user_values']['display_blob']), false
1620 . '<br />'
1621 . PMA_Util::getCheckbox(
1622 'display_binary_as_hex', __('Show binary contents as HEX'),
1623 ! empty($_SESSION['tmp_user_values']['display_binary_as_hex']), false
1625 . '</div>';
1627 // I would have preferred to name this "display_transformation".
1628 // This is the only way I found to be able to keep this setting sticky
1629 // per SQL query, and at the same time have a default that displays
1630 // the transformations.
1631 $options_html .= '<div class="formelement">'
1632 . PMA_Util::getCheckbox(
1633 'hide_transformation', __('Hide browser transformation'),
1634 ! empty($_SESSION['tmp_user_values']['hide_transformation']), false
1636 . '</div>';
1638 if (! PMA_DRIZZLE) {
1639 $options_html .= '<div class="formelement">';
1640 $choices = array(
1641 'GEOM' => __('Geometry'),
1642 'WKT' => __('Well Known Text'),
1643 'WKB' => __('Well Known Binary')
1646 $options_html .= PMA_Util::getRadioFields(
1647 'geometry_display', $choices,
1648 $_SESSION['tmp_user_values']['geometry_display']
1650 . '</div>';
1653 $options_html .= '<div class="clearfloat"></div>'
1654 . '</fieldset>';
1656 $options_html .= '<fieldset class="tblFooters">'
1657 . '<input type="submit" value="' . __('Go') . '" />'
1658 . '</fieldset>'
1659 . '</div>'
1660 . '</form>';
1662 return $options_html;
1664 } // end of the '_getOptionsBlock()' function
1668 * Get full/partial text button or link
1670 * @return string html content
1672 * @access private
1674 * @see _getTableHeaders()
1676 private function _getFullOrPartialTextButtonOrLink()
1679 $url_params_full_text = array(
1680 'db' => $this->__get('db'),
1681 'table' => $this->__get('table'),
1682 'sql_query' => $this->__get('sql_query'),
1683 'goto' => $this->__get('goto'),
1684 'full_text_button' => 1
1687 if ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_FULL_TEXT) {
1688 // currently in fulltext mode so show the opposite link
1689 $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png';
1690 $tmp_txt = __('Partial texts');
1691 $url_params_full_text['display_text'] = self::DISPLAY_PARTIAL_TEXT;
1692 } else {
1693 $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png';
1694 $tmp_txt = __('Full texts');
1695 $url_params_full_text['display_text'] = self::DISPLAY_FULL_TEXT;
1698 $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
1699 . $tmp_txt . '" title="' . $tmp_txt . '" />';
1700 $tmp_url = 'sql.php' . PMA_generate_common_url($url_params_full_text);
1702 return PMA_Util::linkOrButton(
1703 $tmp_url, $tmp_image, array(), false
1706 } // end of the '_getFullOrPartialTextButtonOrLink()' function
1710 * Prepare html form for multi row operations
1712 * @param string $del_lnk the delete link of current row
1714 * @return string $form_html html content
1716 * @access private
1718 * @see _getTableHeaders()
1720 private function _getFormForMultiRowOperations($del_lnk)
1723 $form_html = '';
1725 if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) {
1727 $form_html .= '<form method="post" action="tbl_row_action.php" '
1728 . 'name="resultsForm" id="resultsForm"';
1730 $form_html .= ' class="ajax" ';
1732 $form_html .= '>'
1733 . PMA_generate_common_hidden_inputs(
1734 $this->__get('db'), $this->__get('table'), 1
1736 . '<input type="hidden" name="goto" value="sql.php" />';
1739 $form_html .= '<table id="table_results" class="data';
1740 $form_html .= ' ajax';
1741 $form_html .= '">';
1743 return $form_html;
1745 } // end of the '_getFormForMultiRowOperations()' function
1749 * Get comment for row
1751 * @param array $comments_map comments array
1752 * @param array $fields_meta set of field properties
1754 * @return string $comment html content
1756 * @access private
1758 * @see _getTableHeaders()
1760 private function _getCommentForRow($comments_map, $fields_meta)
1762 $comments = '';
1763 if (isset($comments_map)
1764 && isset($comments_map[$fields_meta->table])
1765 && isset($comments_map[$fields_meta->table][$fields_meta->name])
1767 $comments = '<span class="tblcomment">'
1768 . htmlspecialchars(
1769 $comments_map[$fields_meta->table][$fields_meta->name]
1771 . '</span>';
1773 return $comments;
1774 } // end of the '_getCommentForRow()' function
1778 * Prepare parameters and html for sorted table header fields
1780 * @param array $fields_meta set of field properties
1781 * @param string $sort_expression sort expression
1782 * @param string $sort_expression_nodirection sort expression without direction
1783 * @param integer $column_index the index of the column
1784 * @param string $unsorted_sql_query the unsorted sql query
1785 * @param integer $session_max_rows maximum rows resulted by sql
1786 * @param string $direction the display direction
1787 * @param string $comments comment for row
1788 * @param string $sort_direction sort direction
1789 * @param boolean $directionCondition display direction horizontal
1790 * or horizontalflipped
1791 * @param boolean $col_visib column is visible(false)
1792 * array column isn't visible(string array)
1793 * @param string $col_visib_j element of $col_visib array
1794 * @param boolean $condition_field whether the column is a part of
1795 * the where clause
1797 * @return array 2 element array - $order_link, $sorted_header_html
1799 * @access private
1801 * @see _getTableHeaders()
1803 private function _getOrderLinkAndSortedHeaderHtml(
1804 $fields_meta, $sort_expression, $sort_expression_nodirection,
1805 $column_index, $unsorted_sql_query, $session_max_rows, $direction,
1806 $comments, $sort_direction, $directionCondition, $col_visib,
1807 $col_visib_j, $condition_field
1810 $sorted_header_html = '';
1812 // Checks if the table name is required; it's the case
1813 // for a query with a "JOIN" statement and if the column
1814 // isn't aliased, or in queries like
1815 // SELECT `1`.`master_field` , `2`.`master_field`
1816 // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2`
1818 $sort_tbl = (isset($fields_meta->table)
1819 && strlen($fields_meta->table))
1820 ? PMA_Util::backquote(
1821 $fields_meta->table
1822 ) . '.'
1823 : '';
1825 // Checks if the current column is used to sort the
1826 // results
1827 // the orgname member does not exist for all MySQL versions
1828 // but if found, it's the one on which to sort
1829 $name_to_use_in_sort = $fields_meta->name;
1830 $is_orgname = false;
1831 if (isset($fields_meta->orgname)
1832 && strlen($fields_meta->orgname)
1834 $name_to_use_in_sort = $fields_meta->orgname;
1835 $is_orgname = true;
1838 // $name_to_use_in_sort might contain a space due to
1839 // formatting of function expressions like "COUNT(name )"
1840 // so we remove the space in this situation
1841 $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort);
1843 $is_in_sort = $this->_isInSorted(
1844 $sort_expression, $sort_expression_nodirection,
1845 $sort_tbl, $name_to_use_in_sort
1848 // Check the field name for a bracket.
1849 // If it contains one, it's probably a function column
1850 // like 'COUNT(`field`)'
1851 // It still might be a column name of a view. See bug #3383711
1852 // Check is_orgname.
1853 if ((strpos($name_to_use_in_sort, '(') !== false) && ! $is_orgname) {
1854 $sort_order = "\n" . 'ORDER BY ' . $name_to_use_in_sort . ' ';
1855 } else {
1856 $sort_order = "\n" . 'ORDER BY ' . $sort_tbl
1857 . PMA_Util::backquote(
1858 $name_to_use_in_sort
1859 ) . ' ';
1861 unset($name_to_use_in_sort);
1862 unset($is_orgname);
1864 // Do define the sorting URL
1866 list($sort_order, $order_img) = $this->_getSortingUrlParams(
1867 $is_in_sort, $sort_direction, $fields_meta,
1868 $sort_order, $column_index
1871 if (preg_match(
1872 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|'
1873 . 'LOCK IN SHARE MODE))@is',
1874 $unsorted_sql_query, $regs3
1875 )) {
1876 $sorted_sql_query = $regs3[1] . $sort_order . $regs3[2];
1877 } else {
1878 $sorted_sql_query = $unsorted_sql_query . $sort_order;
1881 $_url_params = array(
1882 'db' => $this->__get('db'),
1883 'table' => $this->__get('table'),
1884 'sql_query' => $sorted_sql_query,
1885 'session_max_rows' => $session_max_rows
1887 $order_url = 'sql.php' . PMA_generate_common_url($_url_params);
1889 // Displays the sorting URL
1890 // enable sort order swapping for image
1891 $order_link = $this->_getSortOrderLink(
1892 $order_img, $column_index, $direction,
1893 $fields_meta, $order_url
1896 if ($directionCondition) {
1897 $sorted_header_html .= $this->_getDraggableClassForSortableColumns(
1898 $col_visib, $col_visib_j, $condition_field, $direction,
1899 $fields_meta, $order_link, $comments
1903 return array($order_link, $sorted_header_html);
1905 } // end of the '_getOrderLinkAndSortedHeaderHtml()' function
1909 * Check whether the column is sorted
1911 * @param string $sort_expression sort expression
1912 * @param string $sort_expression_nodirection sort expression without direction
1913 * @param string $sort_tbl the table name
1914 * @param string $name_to_use_in_sort the sorting column name
1916 * @return boolean $is_in_sort the column sorted or not
1918 * @access private
1920 * @see _getTableHeaders()
1922 private function _isInSorted(
1923 $sort_expression, $sort_expression_nodirection, $sort_tbl,
1924 $name_to_use_in_sort
1927 if (empty($sort_expression)) {
1928 $is_in_sort = false;
1929 } else {
1930 // Field name may be preceded by a space, or any number
1931 // of characters followed by a dot (tablename.fieldname)
1932 // so do a direct comparison for the sort expression;
1933 // this avoids problems with queries like
1934 // "SELECT id, count(id)..." and clicking to sort
1935 // on id or on count(id).
1936 // Another query to test this:
1937 // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p
1938 // (and try clicking on each column's header twice)
1939 if (! empty($sort_tbl)
1940 && strpos($sort_expression_nodirection, $sort_tbl) === false
1941 && strpos($sort_expression_nodirection, '(') === false
1943 $new_sort_expression_nodirection = $sort_tbl
1944 . $sort_expression_nodirection;
1945 } else {
1946 $new_sort_expression_nodirection = $sort_expression_nodirection;
1949 $is_in_sort = false;
1950 $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort;
1952 if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection)
1953 || $sort_name == str_replace('`', '', $sort_expression_nodirection)
1955 $is_in_sort = true;
1959 return $is_in_sort;
1961 } // end of the '_isInSorted()' function
1965 * Get sort url paramaeters - sort order and order image
1967 * @param boolean $is_in_sort the column sorted or not
1968 * @param string $sort_direction the sort direction
1969 * @param array $fields_meta set of field properties
1970 * @param string $sort_order the sorting order
1971 * @param integer $column_index the index of the column
1973 * @return array 2 element array - $sort_order, $order_img
1975 * @access private
1977 * @see _getTableHeaders()
1979 private function _getSortingUrlParams(
1980 $is_in_sort, $sort_direction, $fields_meta, $sort_order, $column_index
1983 if (! $is_in_sort) {
1985 // patch #455484 ("Smart" order)
1986 $GLOBALS['cfg']['Order'] = strtoupper($GLOBALS['cfg']['Order']);
1988 if ($GLOBALS['cfg']['Order'] === self::SMART_SORT_ORDER) {
1989 $sort_order .= (preg_match(
1990 '@time|date@i',
1991 $fields_meta->type
1992 )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
1993 } else {
1994 $sort_order .= $GLOBALS['cfg']['Order'];
1996 $order_img = '';
1998 } elseif ($sort_direction == self::DESCENDING_SORT_DIR) {
2000 $sort_order .= ' ASC';
2001 $order_img = ' ' . PMA_Util::getImage(
2002 's_desc.png', __('Descending'),
2003 array('class' => "soimg$column_index", 'title' => '')
2006 $order_img .= ' ' . PMA_Util::getImage(
2007 's_asc.png', __('Ascending'),
2008 array('class' => "soimg$column_index hide", 'title' => '')
2011 } else {
2013 $sort_order .= ' DESC';
2014 $order_img = ' ' . PMA_Util::getImage(
2015 's_asc.png', __('Ascending'),
2016 array('class' => "soimg$column_index", 'title' => '')
2019 $order_img .= ' ' . PMA_Util::getImage(
2020 's_desc.png', __('Descending'),
2021 array('class' => "soimg$column_index hide", 'title' => '')
2025 return array($sort_order, $order_img);
2027 } // end of the '_getSortingUrlParams()' function
2031 * Get sort order link
2033 * @param string $order_img the sort order image
2034 * @param integer $col_index the index of the column
2035 * @param string $direction the display direction
2036 * @param array $fields_meta set of field properties
2037 * @param string $order_url the url for sort
2039 * @return string the sort order link
2041 * @access private
2043 * @see _getTableHeaders()
2045 private function _getSortOrderLink(
2046 $order_img, $col_index, $direction, $fields_meta, $order_url
2049 $order_link_params = array();
2051 if (isset($order_img) && ($order_img != '')) {
2052 if (strstr($order_img, 'asc')) {
2053 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2054 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2055 } elseif (strstr($order_img, 'desc')) {
2056 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2057 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2061 if ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_AUTO) {
2063 $GLOBALS['cfg']['HeaderFlipType']
2064 = (PMA_USR_BROWSER_AGENT == 'IE')
2065 ? self::HEADER_FLIP_TYPE_CSS
2066 : self::HEADER_FLIP_TYPE_FAKE;
2069 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED
2070 && $GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS
2072 $order_link_params['style'] = 'direction: ltr; writing-mode: tb-rl;';
2075 $order_link_content = (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2076 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE))
2077 ? PMA_Util::flipstring(
2078 htmlspecialchars($fields_meta->name),
2079 "<br />\n"
2081 : htmlspecialchars($fields_meta->name);
2083 return PMA_Util::linkOrButton(
2084 $order_url, $order_link_content . $order_img,
2085 $order_link_params, false, true
2088 } // end of the '_getSortOrderLink()' function
2092 * Prepare columns to draggable effect for sortable columns
2094 * @param boolean $col_visib the column is visible (false)
2095 * array the column is not visible (string array)
2096 * @param string $col_visib_j element of $col_visib array
2097 * @param boolean $condition_field whether to add CSS class condition
2098 * @param string $direction the display direction
2099 * @param array $fields_meta set of field properties
2100 * @param string $order_link the order link
2101 * @param string $comments the comment for the column
2103 * @return string $draggable_html html content
2105 * @access private
2107 * @see _getTableHeaders()
2109 private function _getDraggableClassForSortableColumns(
2110 $col_visib, $col_visib_j, $condition_field, $direction, $fields_meta,
2111 $order_link, $comments
2114 $draggable_html = '<th';
2115 $th_class = array();
2116 $th_class[] = 'draggable';
2118 if ($col_visib && !$col_visib_j) {
2119 $th_class[] = 'hide';
2122 if ($condition_field) {
2123 $th_class[] = 'condition';
2126 $th_class[] = 'column_heading';
2127 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
2128 $th_class[] = 'pointer';
2131 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
2132 $th_class[] = 'marker';
2135 $draggable_html .= ' class="' . implode(' ', $th_class);
2137 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2138 $draggable_html .= ' vbottom';
2141 $draggable_html .= '" data-column="' . htmlspecialchars($fields_meta->name)
2142 . '">' . $order_link . $comments . '</th>';
2144 return $draggable_html;
2146 } // end of the '_getDraggableClassForSortableColumns()' function
2150 * Prepare columns to draggable effect for non sortable columns
2152 * @param boolean $col_visib the column is visible (false)
2153 * array the column is not visible (string array)
2154 * @param string $col_visib_j element of $col_visib array
2155 * @param boolean $condition_field whether to add CSS class condition
2156 * @param string $direction the display direction
2157 * @param array $fields_meta set of field properties
2158 * @param string $comments the comment for the column
2160 * @return string $draggable_html html content
2162 * @access private
2164 * @see _getTableHeaders()
2166 private function _getDraggableClassForNonSortableColumns(
2167 $col_visib, $col_visib_j, $condition_field,
2168 $direction, $fields_meta, $comments
2171 $draggable_html = '<th';
2172 $th_class = array();
2173 $th_class[] = 'draggable';
2175 if ($col_visib && !$col_visib_j) {
2176 $th_class[] = 'hide';
2179 if ($condition_field) {
2180 $th_class[] = 'condition';
2183 $draggable_html .= ' class="' . implode(' ', $th_class);
2184 if ($direction == self::DISP_DIR_HORIZONTAL_FLIPPED) {
2185 $draggable_html .= ' vbottom';
2188 $draggable_html .= '"';
2189 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2190 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_CSS)
2192 $draggable_html .= ' style="direction: ltr; writing-mode: tb-rl;"';
2195 $draggable_html .= ' data-column="'
2196 . htmlspecialchars($fields_meta->name) . '">';
2198 if (($direction == self::DISP_DIR_HORIZONTAL_FLIPPED)
2199 && ($GLOBALS['cfg']['HeaderFlipType'] == self::HEADER_FLIP_TYPE_FAKE)
2202 $draggable_html .= PMA_Util::flipstring(
2203 htmlspecialchars($fields_meta->name), '<br />'
2206 } else {
2207 $draggable_html .= htmlspecialchars($fields_meta->name);
2210 $draggable_html .= "\n" . $comments . '</th>';
2212 return $draggable_html;
2214 } // end of the '_getDraggableClassForNonSortableColumns()' function
2218 * Prepare column to show at right side - check boxes or empty column
2220 * @param array &$is_display which elements to display
2221 * @param boolean $directionCondition display direction horizontal
2222 * or horizontalflipped
2223 * @param string $full_or_partial_text_link full/partial link or text button
2224 * @param string $colspan column span of table header
2225 * @param string $rowspan row span of table header
2227 * @return string html content
2229 * @access private
2231 * @see _getTableHeaders()
2233 private function _getColumnAtRightSide(
2234 &$is_display, $directionCondition, $full_or_partial_text_link,
2235 $colspan, $rowspan
2238 $right_column_html = '';
2239 $vertical_display = $this->__get('vertical_display');
2241 // Displays the needed checkboxes at the right
2242 // column of the result table header if possible and required...
2243 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2244 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2245 && (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2246 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
2247 && ($is_display['text_btn'] == '1')
2250 $vertical_display['emptyafter']
2251 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2252 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2254 if ($directionCondition) {
2255 $right_column_html .= "\n"
2256 . '<th ' . $colspan . '>' . $full_or_partial_text_link
2257 . '</th>';
2259 // end horizontal/horizontalflipped mode
2260 } else {
2261 $vertical_display['textbtn'] = ' <th ' . $rowspan
2262 . ' class="vmiddle">' . "\n"
2263 . ' ' . "\n"
2264 . ' </th>' . "\n";
2265 } // end vertical mode
2266 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2267 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2268 && (($is_display['edit_lnk'] == self::NO_EDIT_OR_DELETE)
2269 && ($is_display['del_lnk'] == self::NO_EDIT_OR_DELETE))
2270 && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent'])
2272 // ... elseif no button, displays empty columns if required
2273 // (unless coming from Browse mode print view)
2275 $vertical_display['emptyafter']
2276 = (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2277 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2279 if ($directionCondition) {
2280 $right_column_html .= "\n"
2281 . '<td ' . $colspan . '></td>';
2283 // end horizontal/horizontalflipped mode
2284 } else {
2285 $vertical_display['textbtn'] = ' <td' . $rowspan
2286 . '></td>' . "\n";
2287 } // end vertical mode
2290 $this->__set('vertical_display', $vertical_display);
2292 return $right_column_html;
2294 } // end of the '_getColumnAtRightSide()' function
2298 * Prepares the display for a value
2300 * @param string $class class of table cell
2301 * @param bool $condition_field whether to add CSS class condition
2302 * @param string $value value to display
2304 * @return string the td
2306 * @access private
2308 * @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(),
2309 * _getDataCellForNonNumericAndNonBlobColumns()
2311 private function _buildValueDisplay($class, $condition_field, $value)
2313 return '<td class="left ' . $class . ($condition_field ? ' condition' : '')
2314 . '">' . $value . '</td>';
2315 } // end of the '_buildValueDisplay()' function
2319 * Prepares the display for a null value
2321 * @param string $class class of table cell
2322 * @param bool $condition_field whether to add CSS class condition
2323 * @param object $meta the meta-information about this field
2324 * @param string $align cell allignment
2326 * @return string the td
2328 * @access private
2330 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2331 * _getDataCellForGeometryColumns(),
2332 * _getDataCellForNonNumericAndNonBlobColumns()
2334 private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
2336 // the null class is needed for grid editing
2337 return '<td ' . $align . ' class="'
2338 . $this->_addClass(
2339 $class, $condition_field, $meta, ''
2341 . ' null"><i>NULL</i></td>';
2342 } // end of the '_buildNullDisplay()' function
2346 * Prepares the display for an empty value
2348 * @param string $class class of table cell
2349 * @param bool $condition_field whether to add CSS class condition
2350 * @param object $meta the meta-information about this field
2351 * @param string $align cell allignment
2353 * @return string the td
2355 * @access private
2357 * @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
2358 * _getDataCellForGeometryColumns(),
2359 * _getDataCellForNonNumericAndNonBlobColumns()
2361 private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
2363 return '<td ' . $align . ' class="'
2364 . $this->_addClass(
2365 $class, $condition_field, $meta, ' nowrap'
2367 . '"></td>';
2368 } // end of the '_buildEmptyDisplay()' function
2372 * Adds the relavant classes.
2374 * @param string $class class of table cell
2375 * @param bool $condition_field whether to add CSS class condition
2376 * @param object $meta the meta-information about the field
2377 * @param string $nowrap avoid wrapping
2378 * @param bool $is_field_truncated is field truncated (display ...)
2379 * @param string $transformation_plugin transformation plugin.
2380 * Can also be the default function:
2381 * PMA_mimeDefaultFunction
2382 * @param string $default_function default transformation function
2384 * @return string the list of classes
2386 * @access private
2388 * @see _buildNullDisplay(), _getRowData()
2390 private function _addClass(
2391 $class, $condition_field, $meta, $nowrap, $is_field_truncated = false,
2392 $transformation_plugin = '', $default_function = ''
2395 // Define classes to be added to this data field based on the type of data
2396 $enum_class = '';
2397 if (strpos($meta->flags, 'enum') !== false) {
2398 $enum_class = ' enum';
2401 $set_class = '';
2402 if (strpos($meta->flags, 'set') !== false) {
2403 $set_class = ' set';
2406 $bit_class = '';
2407 if (strpos($meta->type, 'bit') !== false) {
2408 $bit_class = ' bit';
2411 $mime_type_class = '';
2412 if (isset($meta->mimetype)) {
2413 $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype);
2416 return $class . ($condition_field ? ' condition' : '') . $nowrap
2417 . ' ' . ($is_field_truncated ? ' truncated' : '')
2418 . ($transformation_plugin != $default_function ? ' transformed' : '')
2419 . $enum_class . $set_class . $bit_class . $mime_type_class;
2421 } // end of the '_addClass()' function
2425 * Prepare the body of the results table
2427 * @param integer &$dt_result the link id associated to the query
2428 * which results have to be displayed
2429 * @param array &$is_display which elements to display
2430 * @param array $map the list of relations
2431 * @param array $analyzed_sql the analyzed query
2432 * @param boolean $is_limited_display with limited operations or not
2434 * @return string $table_body_html html content
2436 * @global array $row current row data
2438 * @access private
2440 * @see getTable()
2442 private function _getTableBody(
2443 &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false
2446 global $row; // mostly because of browser transformations,
2447 // to make the row-data accessible in a plugin
2449 $table_body_html = '';
2451 // query without conditions to shorten URLs when needed, 200 is just
2452 // guess, it should depend on remaining URL length
2453 $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql);
2455 $vertical_display = $this->__get('vertical_display');
2457 if (! is_array($map)) {
2458 $map = array();
2461 $row_no = 0;
2462 $vertical_display['edit'] = array();
2463 $vertical_display['copy'] = array();
2464 $vertical_display['delete'] = array();
2465 $vertical_display['data'] = array();
2466 $vertical_display['row_delete'] = array();
2467 $this->__set('vertical_display', $vertical_display);
2469 // name of the class added to all grid editable elements;
2470 // if we don't have all the columns of a unique key in the result set,
2471 // do not permit grid editing
2472 if ($is_limited_display || ! $this->__get('editable')) {
2473 $grid_edit_class = '';
2474 } else {
2475 switch ($GLOBALS['cfg']['GridEditing']) {
2476 case 'double-click':
2477 // trying to reduce generated HTML by using shorter
2478 // classes like click1 and click2
2479 $grid_edit_class = 'grid_edit click2';
2480 break;
2481 case 'click':
2482 $grid_edit_class = 'grid_edit click1';
2483 break;
2484 case 'disabled':
2485 $grid_edit_class = '';
2486 break;
2490 // prepare to get the column order, if available
2491 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
2493 // Correction University of Virginia 19991216 in the while below
2494 // Previous code assumed that all tables have keys, specifically that
2495 // the phpMyAdmin GUI should support row delete/edit only for such
2496 // tables.
2497 // Although always using keys is arguably the prescribed way of
2498 // defining a relational table, it is not required. This will in
2499 // particular be violated by the novice.
2500 // We want to encourage phpMyAdmin usage by such novices. So the code
2501 // below has been changed to conditionally work as before when the
2502 // table being displayed has one or more keys; but to display
2503 // delete/edit options correctly for tables without keys.
2505 $odd_row = true;
2506 $directionCondition
2507 = ($_SESSION['tmp_user_values']['disp_direction']
2508 == self::DISP_DIR_HORIZONTAL)
2509 || ($_SESSION['tmp_user_values']['disp_direction']
2510 == self::DISP_DIR_HORIZONTAL_FLIPPED);
2512 while ($row = PMA_DBI_fetch_row($dt_result)) {
2514 // "vertical display" mode stuff
2515 $table_body_html .= $this->_getVerticalDisplaySupportSegments(
2516 $vertical_display, $row_no, $directionCondition
2519 $alternating_color_class = ($odd_row ? 'odd' : 'even');
2520 $odd_row = ! $odd_row;
2522 if ($directionCondition) {
2523 // pointer code part
2524 $table_body_html .= '<tr class="' . $alternating_color_class . '">';
2527 // 1. Prepares the row
2528 // 1.1 Results from a "SELECT" statement -> builds the
2529 // WHERE clause to use in links (a unique key if possible)
2531 * @todo $where_clause could be empty, for example a table
2532 * with only one field and it's a BLOB; in this case,
2533 * avoid to display the delete and edit links
2535 list($where_clause, $clause_is_unique, $condition_array)
2536 = PMA_Util::getUniqueCondition(
2537 $dt_result,
2538 $this->__get('fields_cnt'),
2539 $this->__get('fields_meta'),
2540 $row
2542 $where_clause_html = urlencode($where_clause);
2544 // In print view these variable needs toinitialized
2545 $del_url = $del_query = $del_str = $edit_anchor_class
2546 = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
2548 // 1.2 Defines the URLs for the modify/delete link(s)
2550 if (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2551 || ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE)
2553 // We need to copy the value
2554 // or else the == 'both' check will always return true
2556 if ($GLOBALS['cfg']['PropertiesIconic'] === self::POSITION_BOTH) {
2557 $iconic_spacer = '<div class="nowrap">';
2558 } else {
2559 $iconic_spacer = '';
2562 // 1.2.1 Modify link(s) - update row case
2563 if ($is_display['edit_lnk'] == self::UPDATE_ROW) {
2565 list($edit_url, $copy_url, $edit_str, $copy_str,
2566 $edit_anchor_class)
2567 = $this->_getModifiedLinks(
2568 $where_clause,
2569 $clause_is_unique, $url_sql_query
2572 } // end if (1.2.1)
2574 // 1.2.2 Delete/Kill link(s)
2575 if (($is_display['del_lnk'] == self::DELETE_ROW)
2576 || ($is_display['del_lnk'] == self::KILL_PROCESS)
2579 list($del_query, $del_url, $del_str, $js_conf)
2580 = $this->_getDeleteAndKillLinks(
2581 $where_clause, $clause_is_unique,
2582 $url_sql_query, $is_display['del_lnk'],
2583 $row
2586 } // end if (1.2.2)
2588 // 1.3 Displays the links at left if required
2589 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2590 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2591 && $directionCondition
2594 $table_body_html .= $this->_getPlacedLinks(
2595 self::POSITION_LEFT, $del_url, $is_display, $row_no,
2596 $where_clause, $where_clause_html, $condition_array,
2597 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2598 $edit_str, $copy_str, $del_str, $js_conf
2601 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)
2602 && $directionCondition
2605 $table_body_html .= $this->_getPlacedLinks(
2606 self::POSITION_NONE, $del_url, $is_display, $row_no,
2607 $where_clause, $where_clause_html, $condition_array,
2608 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
2609 $edit_str, $copy_str, $del_str, $js_conf
2612 } // end if (1.3)
2613 } // end if (1)
2615 // 2. Displays the rows' values
2616 $table_body_html .= $this->_getRowValues(
2617 $dt_result, $row, $row_no, $col_order, $map,
2618 $grid_edit_class, $col_visib, $where_clause,
2619 $url_sql_query, $analyzed_sql, $directionCondition
2622 // 3. Displays the modify/delete links on the right if required
2623 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2624 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2625 && $directionCondition
2628 $table_body_html .= $this->_getPlacedLinks(
2629 self::POSITION_RIGHT, $del_url, $is_display, $row_no,
2630 $where_clause, $where_clause_html, $condition_array,
2631 $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class,
2632 $edit_str, $copy_str, $del_str, $js_conf
2635 } // end if (3)
2637 if ($directionCondition) {
2638 $table_body_html .= '</tr>';
2639 } // end if
2641 // 4. Gather links of del_urls and edit_urls in an array for later
2642 // output
2643 $this->_gatherLinksForLaterOutputs(
2644 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
2645 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url,
2646 $edit_str, $copy_url, $copy_str, $alternating_color_class,
2647 $condition_array
2650 $table_body_html .= $directionCondition ? "\n" : '';
2651 $row_no++;
2653 } // end while
2655 return $table_body_html;
2657 } // end of the '_getTableBody()' function
2661 * Get the values for one data row
2663 * @param integer &$dt_result the link id associated to the query
2664 * which results have to be displayed
2665 * @param array $row current row data
2666 * @param integer $row_no the index of current row
2667 * @param array $col_order the column order
2668 * false when a property not found
2669 * @param array $map the list of relations
2670 * @param string $grid_edit_class the class for all editable columns
2671 * @param boolean $col_visib column is visible(false)
2672 * array column isn't visible(string array)
2673 * @param string $where_clause where clause
2674 * @param string $url_sql_query the analyzed sql query
2675 * @param array $analyzed_sql the analyzed query
2676 * @param boolean $directionCondition the directional condition
2678 * @return string $row_values_html html content
2680 * @access private
2682 * @see _getTableBody()
2684 private function _getRowValues(
2685 &$dt_result, $row, $row_no, $col_order, $map,
2686 $grid_edit_class, $col_visib, $where_clause,
2687 $url_sql_query, $analyzed_sql, $directionCondition
2690 $row_values_html = '';
2692 // Following variable are needed for use in isset/empty or
2693 // use with array indexes/safe use in foreach
2694 $sql_query = $this->__get('sql_query');
2695 $fields_meta = $this->__get('fields_meta');
2696 $highlight_columns = $this->__get('highlight_columns');
2697 $mime_map = $this->__get('mime_map');
2699 $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order);
2701 for ($currentColumn = 0;
2702 $currentColumn < $this->__get('fields_cnt');
2703 ++$currentColumn) {
2705 // assign $i with appropriate column order
2706 $i = $col_order ? $col_order[$currentColumn] : $currentColumn;
2708 $meta = $fields_meta[$i];
2709 $not_null_class = $meta->not_null ? 'not_null' : '';
2710 $relation_class = isset($map[$meta->name]) ? 'relation' : '';
2711 $hide_class = ($col_visib && ! $col_visib[$currentColumn]
2712 // hide per <td> only if the display dir is not vertical
2713 && ($_SESSION['tmp_user_values']['disp_direction']
2714 != self::DISP_DIR_VERTICAL))
2715 ? 'hide'
2716 : '';
2718 // handle datetime-related class, for grid editing
2719 $field_type_class
2720 = $this->_getClassForDateTimeRelatedFields($meta->type);
2722 $is_field_truncated = false;
2723 // combine all the classes applicable to this column's value
2724 $class = $this->_getClassesForColumn(
2725 $grid_edit_class, $not_null_class, $relation_class,
2726 $hide_class, $field_type_class, $row_no
2729 // See if this column should get highlight because it's used in the
2730 // where-query.
2731 $condition_field = (isset($highlight_columns)
2732 && (isset($highlight_columns[$meta->name])
2733 || isset($highlight_columns[PMA_Util::backquote($meta->name)])))
2734 ? true
2735 : false;
2737 // Wrap MIME-transformations. [MIME]
2738 $default_function = '_mimeDefaultFunction'; // default_function
2739 $transformation_plugin = $default_function;
2740 $transform_options = array();
2742 if ($GLOBALS['cfgRelation']['mimework']
2743 && $GLOBALS['cfg']['BrowseMIME']
2746 if (isset($mime_map[$meta->name]['mimetype'])
2747 && isset($mime_map[$meta->name]['transformation'])
2748 && !empty($mime_map[$meta->name]['transformation'])
2751 $file = $mime_map[$meta->name]['transformation'];
2752 $include_file = 'libraries/plugins/transformations/' . $file;
2754 if (file_exists($include_file)) {
2756 include_once $include_file;
2757 $class_name = str_replace('.class.php', '', $file);
2758 // todo add $plugin_manager
2759 $plugin_manager = null;
2760 $transformation_plugin = new $class_name(
2761 $plugin_manager
2764 $transform_options = PMA_transformation_getOptions(
2765 isset($mime_map[$meta->name]
2766 ['transformation_options']
2768 ? $mime_map[$meta->name]
2769 ['transformation_options']
2770 : ''
2773 $meta->mimetype = str_replace(
2774 '_', '/',
2775 $mime_map[$meta->name]['mimetype']
2778 } // end if file_exists
2779 } // end if transformation is set
2780 } // end if mime/transformation works.
2782 $_url_params = array(
2783 'db' => $this->__get('db'),
2784 'table' => $this->__get('table'),
2785 'where_clause' => $where_clause,
2786 'transform_key' => $meta->name,
2789 if (! empty($sql_query)) {
2790 $_url_params['sql_query'] = $url_sql_query;
2793 $transform_options['wrapper_link']
2794 = PMA_generate_common_url($_url_params);
2796 $vertical_display = $this->__get('vertical_display');
2798 // Check whether the field needs to display with syntax highlighting
2800 if ($this->_isNeedToSyntaxHighlight($meta->name)
2801 && (trim($row[$i]) != '')
2804 $parsed_sql = PMA_SQP_parse($row[$i]);
2805 $row[$i] = PMA_Util::formatSql(
2806 $parsed_sql, $row[$i]
2808 include_once $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][0];
2809 $transformation_plugin = new $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][1](null);
2811 $transform_options = PMA_transformation_getOptions(
2812 isset($mime_map[$meta->name]['transformation_options'])
2813 ? $mime_map[$meta->name]['transformation_options']
2814 : ''
2817 $meta->mimetype = str_replace(
2818 '_', '/',
2819 $this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($meta->name)][2]
2824 // Check for the predefined fields need to show as link in schemas
2825 include_once 'libraries/special_schema_links.lib.php';
2827 if (isset($GLOBALS['special_schema_links'])
2828 && ($this->_isFieldNeedToLink(strtolower($meta->name)))
2831 $linking_url = $this->_getSpecialLinkUrl(
2832 $row[$i], $row_info, strtolower($meta->name)
2834 include_once "libraries/plugins/transformations/Text_Plain_Link.class.php";
2835 $transformation_plugin = new Text_Plain_Link(null);
2837 $transform_options = array(
2838 0 => $linking_url,
2839 2 => true
2842 $meta->mimetype = str_replace(
2843 '_', '/',
2844 'Text/Plain'
2849 if ($meta->numeric == 1) {
2850 // n u m e r i c
2852 $vertical_display['data'][$row_no][$i]
2853 = $this->_getDataCellForNumericColumns(
2854 $row[$i], $class, $condition_field, $meta, $map,
2855 $is_field_truncated, $analyzed_sql,
2856 $transformation_plugin, $default_function,
2857 $transform_options
2860 } elseif (stristr($meta->type, self::BLOB_FIELD)) {
2861 // b l o b
2863 // PMA_mysql_fetch_fields returns BLOB in place of
2864 // TEXT fields type so we have to ensure it's really a BLOB
2865 $field_flags = PMA_DBI_field_flags($dt_result, $i);
2867 $vertical_display['data'][$row_no][$i]
2868 = $this->_getDataCellForBlobColumns(
2869 $row[$i], $class, $meta, $_url_params, $field_flags,
2870 $transformation_plugin, $default_function,
2871 $transform_options, $condition_field, $is_field_truncated
2874 } elseif ($meta->type == self::GEOMETRY_FIELD) {
2875 // g e o m e t r y
2877 // Remove 'grid_edit' from $class as we do not allow to
2878 // inline-edit geometry data.
2879 $class = str_replace('grid_edit', '', $class);
2881 $vertical_display['data'][$row_no][$i]
2882 = $this->_getDataCellForGeometryColumns(
2883 $row[$i], $class, $meta, $map, $_url_params,
2884 $condition_field, $transformation_plugin,
2885 $default_function, $transform_options,
2886 $is_field_truncated, $analyzed_sql
2889 } else {
2890 // n o t n u m e r i c a n d n o t B L O B
2892 $vertical_display['data'][$row_no][$i]
2893 = $this->_getDataCellForNonNumericAndNonBlobColumns(
2894 $row[$i], $class, $meta, $map, $_url_params,
2895 $condition_field, $transformation_plugin,
2896 $default_function, $transform_options,
2897 $is_field_truncated, $analyzed_sql, $dt_result, $i
2902 // output stored cell
2903 if ($directionCondition) {
2904 $row_values_html
2905 .= $vertical_display['data'][$row_no][$i];
2908 if (isset($vertical_display['rowdata'][$i][$row_no])) {
2909 $vertical_display['rowdata'][$i][$row_no]
2910 .= $vertical_display['data'][$row_no][$i];
2911 } else {
2912 $vertical_display['rowdata'][$i][$row_no]
2913 = $vertical_display['data'][$row_no][$i];
2916 $this->__set('vertical_display', $vertical_display);
2918 } // end for
2920 return $row_values_html;
2922 } // end of the '_getRowValues()' function
2926 * Gather delete/edit url links for further outputs
2928 * @param integer $row_no the index of current row
2929 * @param array $is_display which elements to display
2930 * @param string $where_clause where clause
2931 * @param string $where_clause_html the html encoded where clause
2932 * @param string $js_conf text for the JS confirmation
2933 * @param string $del_url the url for delete row
2934 * @param string $del_query the query for delete row
2935 * @param string $del_str the label for delete row
2936 * @param string $edit_anchor_class the class for html element for edit
2937 * @param string $edit_url the url for edit row
2938 * @param string $edit_str the label for edit row
2939 * @param string $copy_url the url for copy row
2940 * @param string $copy_str the label for copy row
2941 * @param string $alternating_color_class class for display two colors in rows
2942 * @param array $condition_array array of keys
2943 * (primary,unique,condition)
2945 * @return void
2947 * @access private
2949 * @see _getTableBody()
2951 private function _gatherLinksForLaterOutputs(
2952 $row_no, $is_display, $where_clause, $where_clause_html, $js_conf,
2953 $del_url, $del_query, $del_str, $edit_anchor_class, $edit_url, $edit_str,
2954 $copy_url, $copy_str, $alternating_color_class, $condition_array
2957 $vertical_display = $this->__get('vertical_display');
2959 if (! isset($vertical_display['edit'][$row_no])) {
2960 $vertical_display['edit'][$row_no] = '';
2961 $vertical_display['copy'][$row_no] = '';
2962 $vertical_display['delete'][$row_no] = '';
2963 $vertical_display['row_delete'][$row_no] = '';
2966 $vertical_class = ' row_' . $row_no;
2967 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
2968 $vertical_class .= ' vpointer';
2971 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
2972 $vertical_class .= ' vmarker';
2975 if (!empty($del_url)
2976 && ($is_display['del_lnk'] != self::KILL_PROCESS)
2979 $vertical_display['row_delete'][$row_no]
2980 .= $this->_getCheckboxForMultiRowSubmissions(
2981 $del_url, $is_display, $row_no, $where_clause_html,
2982 $condition_array, $del_query, '[%_PMA_CHECKBOX_DIR_%]',
2983 $alternating_color_class . $vertical_class
2986 } else {
2987 unset($vertical_display['row_delete'][$row_no]);
2990 if (isset($edit_url)) {
2992 $vertical_display['edit'][$row_no] .= $this->_getEditLink(
2993 $edit_url,
2994 $alternating_color_class . ' ' . $edit_anchor_class
2995 . $vertical_class, $edit_str,
2996 $where_clause,
2997 $where_clause_html
3000 } else {
3001 unset($vertical_display['edit'][$row_no]);
3004 if (isset($copy_url)) {
3006 $vertical_display['copy'][$row_no] .= $this->_getCopyLink(
3007 $copy_url, $copy_str, $where_clause, $where_clause_html,
3008 $alternating_color_class . $vertical_class
3011 } else {
3012 unset($vertical_display['copy'][$row_no]);
3015 if (isset($del_url)) {
3017 if (! isset($js_conf)) {
3018 $js_conf = '';
3021 $vertical_display['delete'][$row_no]
3022 .= $this->_getDeleteLink(
3023 $del_url, $del_str, $js_conf,
3024 $alternating_color_class . $vertical_class
3027 } else {
3028 unset($vertical_display['delete'][$row_no]);
3031 $this->__set('vertical_display', $vertical_display);
3033 } // end of the '_gatherLinksForLaterOutputs()' function
3037 * Check whether any field is marked as need to syntax highlight
3039 * @param string $field field to check
3041 * @return boolean
3043 private function _isNeedToSyntaxHighlight($field)
3045 if (! empty($this->syntax_highlighting_column_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower($field)])) {
3046 return true;
3048 return false;
3052 * Check whether the field needs to be link
3054 * @param string $field field to check
3056 * @return boolean
3058 private function _isFieldNeedToLink($field)
3060 if (! empty($GLOBALS['special_schema_links'][strtolower($this->__get('db'))][strtolower($this->__get('table'))][$field])) {
3061 return true;
3063 return false;
3068 * Get link for display special schema links
3070 * @param string $column_value column value
3071 * @param array $row_info information about row
3072 * @param string $field_name column name
3074 * @return string generated link
3076 private function _getSpecialLinkUrl($column_value, $row_info, $field_name)
3079 $linking_url_params = array();
3080 $link_relations = $GLOBALS['special_schema_links']
3081 [strtolower($this->__get('db'))]
3082 [strtolower($this->__get('table'))]
3083 [$field_name];
3085 if (! is_array($link_relations['link_param'])) {
3086 $linking_url_params[$link_relations['link_param']] = $column_value;
3087 } else {
3088 // Consider only the case of creating link for column field
3089 // sql query need to be pass as url param
3090 $sql = 'SELECT `'.$column_value.'` FROM `'
3091 . $row_info[$link_relations['link_param'][1]] .'`.`'
3092 . $row_info[$link_relations['link_param'][2]] .'`';
3093 $linking_url_params[$link_relations['link_param'][0]] = $sql;
3097 if (! empty($link_relations['link_dependancy_params'])) {
3099 foreach ($link_relations['link_dependancy_params'] as $new_param) {
3101 // If param_info is an array, set the key and value
3102 // from that array
3103 if (is_array($new_param['param_info'])) {
3104 $linking_url_params[$new_param['param_info'][0]]
3105 = $new_param['param_info'][1];
3106 } else {
3108 $linking_url_params[$new_param['param_info']]
3109 = $row_info[strtolower($new_param['column_name'])];
3111 // Special case 1 - when executing routines, according
3112 // to the type of the routine, url param changes
3113 if (!empty($row_info['routine_type'])) {
3114 if (strtolower($row_info['routine_type']) == self::ROUTINE_PROCEDURE) {
3115 $linking_url_params['execute_routine'] = 1;
3116 } else if (strtolower($row_info['routine_type']) == self::ROUTINE_FUNCTION) {
3117 $linking_url_params['execute_dialog'] = 1;
3126 return $link_relations['default_page']
3127 . PMA_generate_common_url($linking_url_params);
3133 * Prepare row information for display special links
3135 * @param array $row current row data
3136 * @param array $col_order the column order
3138 * @return array $row_info associative array with column nama -> value
3140 private function _getRowInfoForSpecialLinks($row, $col_order)
3143 $row_info = array();
3144 $fields_meta = $this->__get('fields_meta');
3146 for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) {
3147 $m = $col_order ? $col_order[$n] : $n;
3148 $row_info[strtolower($fields_meta[$m]->name)] = $row[$m];
3151 return $row_info;
3157 * Get url sql query without conditions to shorten URLs
3159 * @param array $analyzed_sql analyzed query
3161 * @return string $url_sql analyzed sql query
3163 * @access private
3165 * @see _getTableBody()
3167 private function _getUrlSqlQuery($analyzed_sql)
3170 if (isset($analyzed_sql)
3171 && isset($analyzed_sql[0])
3172 && isset($analyzed_sql[0]['querytype'])
3173 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
3174 && (strlen($this->__get('sql_query')) > 200)
3177 $url_sql_query = 'SELECT ';
3178 if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
3179 $url_sql_query .= ' DISTINCT ';
3182 $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
3183 if (!empty($analyzed_sql[0]['from_clause'])) {
3184 $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
3187 return $url_sql_query;
3190 return $this->__get('sql_query');
3192 } // end of the '_getUrlSqlQuery()' function
3196 * Get column order and column visibility
3198 * @param array $analyzed_sql the analyzed query
3200 * @return array 2 element array - $col_order, $col_visib
3202 * @access private
3204 * @see _getTableBody()
3206 private function _getColumnParams($analyzed_sql)
3208 if ($this->_isSelect($analyzed_sql)) {
3209 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
3210 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
3211 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
3212 } else {
3213 $col_order = false;
3214 $col_visib = false;
3217 return array($col_order, $col_visib);
3218 } // end of the '_getColumnParams()' function
3222 * Prepare vertical display mode necessay HTML stuff
3224 * @param array $vertical_display informations used with vertical
3225 * display mode
3226 * @param integer $row_no the index of current row
3227 * @param boolean $directionCondition the directional condition
3229 * @return string $vertical_disp_html html content
3231 * @access private
3233 * @see _getTableBody()
3235 private function _getVerticalDisplaySupportSegments(
3236 $vertical_display, $row_no, $directionCondition
3239 $support_html = '';
3241 if ((($row_no != 0) && ($_SESSION['tmp_user_values']['repeat_cells'] != 0))
3242 && !($row_no % $_SESSION['tmp_user_values']['repeat_cells'])
3243 && $directionCondition
3246 $support_html .= '<tr>' . "\n";
3248 if ($vertical_display['emptypre'] > 0) {
3250 $support_html .= ' <th colspan="'
3251 . $vertical_display['emptypre'] . '">'
3252 . "\n".' &nbsp;</th>' . "\n";
3254 } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
3255 $support_html .= ' <th></th>' . "\n";
3258 foreach ($vertical_display['desc'] as $val) {
3259 $support_html .= $val;
3262 if ($vertical_display['emptyafter'] > 0) {
3263 $support_html
3264 .= ' <th colspan="' . $vertical_display['emptyafter']
3265 . '">'
3266 . "\n" . ' &nbsp;</th>' . "\n";
3268 $support_html .= '</tr>' . "\n";
3269 } // end if
3271 return $support_html;
3273 } // end of the '_getVerticalDisplaySupportSegments()' function
3277 * Get modified links
3279 * @param string $where_clause the where clause of the sql
3280 * @param boolean $clause_is_unique the unique condition of clause
3281 * @param string $url_sql_query the analyzed sql query
3283 * @return array 5 element array - $edit_url, $copy_url,
3284 * $edit_str, $copy_str, $edit_anchor_class
3286 * @access private
3288 * @see _getTableBody()
3290 private function _getModifiedLinks(
3291 $where_clause, $clause_is_unique, $url_sql_query
3294 $_url_params = array(
3295 'db' => $this->__get('db'),
3296 'table' => $this->__get('table'),
3297 'where_clause' => $where_clause,
3298 'clause_is_unique' => $clause_is_unique,
3299 'sql_query' => $url_sql_query,
3300 'goto' => 'sql.php',
3303 $edit_url = 'tbl_change.php'
3304 . PMA_generate_common_url(
3305 $_url_params + array('default_action' => 'update')
3308 $copy_url = 'tbl_change.php'
3309 . PMA_generate_common_url(
3310 $_url_params + array('default_action' => 'insert')
3313 $edit_str = PMA_Util::getIcon(
3314 'b_edit.png', __('Edit')
3316 $copy_str = PMA_Util::getIcon(
3317 'b_insrow.png', __('Copy')
3320 // Class definitions required for grid editing jQuery scripts
3321 $edit_anchor_class = "edit_row_anchor";
3322 if ( $clause_is_unique == 0) {
3323 $edit_anchor_class .= ' nonunique';
3326 return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
3328 } // end of the '_getModifiedLinks()' function
3332 * Get delete and kill links
3334 * @param string $where_clause the where clause of the sql
3335 * @param boolean $clause_is_unique the unique condition of clause
3336 * @param string $url_sql_query the analyzed sql query
3337 * @param string $del_lnk the delete link of current row
3338 * @param array $row the current row
3340 * @return array 4 element array - $del_query,
3341 * $del_url, $del_str, $js_conf
3343 * @access private
3345 * @see _getTableBody()
3347 private function _getDeleteAndKillLinks(
3348 $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row
3351 $goto = $this->__get('goto');
3353 if ($del_lnk == self::DELETE_ROW) { // delete row case
3355 $_url_params = array(
3356 'db' => $this->__get('db'),
3357 'table' => $this->__get('table'),
3358 'sql_query' => $url_sql_query,
3359 'message_to_show' => __('The row has been deleted'),
3360 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto),
3363 $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
3365 $del_query = 'DELETE FROM '
3366 . PMA_Util::backquote($this->__get('db')) . '.'
3367 . PMA_Util::backquote($this->__get('table'))
3368 . ' WHERE ' . $where_clause .
3369 ($clause_is_unique ? '' : ' LIMIT 1');
3371 $_url_params = array(
3372 'db' => $this->__get('db'),
3373 'table' => $this->__get('table'),
3374 'sql_query' => $del_query,
3375 'message_to_show' => __('The row has been deleted'),
3376 'goto' => $lnk_goto,
3378 $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
3380 $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('db')) . '.'
3381 . PMA_jsFormat($this->__get('table'))
3382 . ' WHERE ' . PMA_jsFormat($where_clause, false)
3383 . ($clause_is_unique ? '' : ' LIMIT 1');
3385 $del_str = PMA_Util::getIcon(
3386 'b_drop.png', __('Delete')
3389 } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case
3391 $_url_params = array(
3392 'db' => $this->__get('db'),
3393 'table' => $this->__get('table'),
3394 'sql_query' => $url_sql_query,
3395 'goto' => 'index.php',
3398 $lnk_goto = 'sql.php'
3399 . PMA_generate_common_url(
3400 $_url_params, 'text'
3403 $_url_params = array(
3404 'db' => 'mysql',
3405 'sql_query' => 'KILL ' . $row[0],
3406 'goto' => $lnk_goto,
3409 $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
3410 $del_query = 'KILL ' . $row[0];
3411 $js_conf = 'KILL ' . $row[0];
3412 $del_str = PMA_Util::getIcon(
3413 'b_drop.png', __('Kill')
3417 return array($del_query, $del_url, $del_str, $js_conf);
3419 } // end of the '_getDeleteAndKillLinks()' function
3423 * Prepare placed links
3425 * @param string $dir the direction of links should place
3426 * @param string $del_url the url for delete row
3427 * @param array $is_display which elements to display
3428 * @param integer $row_no the index of current row
3429 * @param string $where_clause the where clause of the sql
3430 * @param string $where_clause_html the html encoded where clause
3431 * @param array $condition_array array of keys (primary, unique, condition)
3432 * @param string $del_query the query for delete row
3433 * @param string $dir_letter the letter denoted the direction
3434 * @param string $edit_url the url for edit row
3435 * @param string $copy_url the url for copy row
3436 * @param string $edit_anchor_class the class for html element for edit
3437 * @param string $edit_str the label for edit row
3438 * @param string $copy_str the label for copy row
3439 * @param string $del_str the label for delete row
3440 * @param string $js_conf text for the JS confirmation
3442 * @return string html content
3444 * @access private
3446 * @see _getTableBody()
3448 private function _getPlacedLinks(
3449 $dir, $del_url, $is_display, $row_no, $where_clause, $where_clause_html,
3450 $condition_array, $del_query, $dir_letter, $edit_url, $copy_url,
3451 $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
3454 if (! isset($js_conf)) {
3455 $js_conf = '';
3458 return $this->_getCheckboxAndLinks(
3459 $dir, $del_url, $is_display,
3460 $row_no, $where_clause, $where_clause_html, $condition_array,
3461 $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class,
3462 $edit_str, $copy_str, $del_str, $js_conf
3465 } // end of the '_getPlacedLinks()' function
3469 * Get the combined classes for a column
3471 * @param string $grid_edit_class the class for all editable columns
3472 * @param string $not_null_class the class for not null columns
3473 * @param string $relation_class the class for relations in a column
3474 * @param string $hide_class the class for visibility of a column
3475 * @param string $field_type_class the class related to type of the field
3476 * @param integer $row_no the row index
3478 * @return string $class the combined classes
3480 * @access private
3482 * @see _getTableBody()
3484 private function _getClassesForColumn(
3485 $grid_edit_class, $not_null_class, $relation_class,
3486 $hide_class, $field_type_class, $row_no
3489 $printview = $this->__get('printview');
3491 $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' '
3492 . $relation_class . ' ' . $hide_class . ' ' . $field_type_class;
3494 if (($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL)
3495 && (! isset($printview) || ($printview != '1'))
3497 // the row number corresponds to a data row, not HTML table row
3498 $class .= ' row_' . $row_no;
3499 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
3500 $class .= ' vpointer';
3503 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
3504 $class .= ' vmarker';
3508 return $class;
3510 } // end of the '_getClassesForColumn()' function
3514 * Get class for datetime related fields
3516 * @param string $type the type of the column field
3518 * @return string $field_type_class the class for the column
3520 * @access private
3522 * @see _getTableBody()
3524 private function _getClassForDateTimeRelatedFields($type)
3526 if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD)
3527 || ($type == self::DATETIME_FIELD)
3529 $field_type_class = 'datetimefield';
3530 } else if ($type == self::DATE_FIELD) {
3531 $field_type_class = 'datefield';
3532 } else {
3533 $field_type_class = '';
3535 return $field_type_class;
3536 } // end of the '_getClassForDateTimeRelatedFields()' function
3540 * Prepare data cell for numeric type fields
3542 * @param string $column the relavent column in data row
3543 * @param string $class the html class for column
3544 * @param boolean $condition_field the column should highlighted
3545 * or not
3546 * @param object $meta the meta-information about this
3547 * field
3548 * @param array $map the list of relations
3549 * @param boolean $is_field_truncated the condition for blob data
3550 * replacements
3551 * @param array $analyzed_sql the analyzed query
3552 * @param string $transformation_plugin the name of transformation plugin
3553 * @param string $default_function the default transformation function
3554 * @param string $transform_options the transformation parameters
3556 * @return string $cell the prepared cell, html content
3558 * @access private
3560 * @see _getTableBody()
3562 private function _getDataCellForNumericColumns(
3563 $column, $class, $condition_field, $meta, $map, $is_field_truncated,
3564 $analyzed_sql, $transformation_plugin, $default_function,
3565 $transform_options
3568 if (! isset($column) || is_null($column)) {
3570 $cell = $this->_buildNullDisplay(
3571 'right '.$class, $condition_field, $meta, ''
3574 } elseif ($column != '') {
3576 $nowrap = ' nowrap';
3577 $where_comparison = ' = ' . $column;
3579 $cell = $this->_getRowData(
3580 'right '.$class, $condition_field,
3581 $analyzed_sql, $meta, $map, $column,
3582 $transformation_plugin, $default_function, $nowrap,
3583 $where_comparison, $transform_options,
3584 $is_field_truncated
3586 } else {
3588 $cell = $this->_buildEmptyDisplay(
3589 'right '.$class, $condition_field, $meta, ''
3593 return $cell;
3595 } // end of the '_getDataCellForNumericColumns()' function
3599 * Get data cell for blob type fields
3601 * @param string $column the relavent column in data row
3602 * @param string $class the html class for column
3603 * @param object $meta the meta-information about this
3604 * field
3605 * @param array $_url_params the parameters for generate url
3606 * @param string $field_flags field flags for column(blob,
3607 * primary etc)
3608 * @param string $transformation_plugin the name of transformation function
3609 * @param string $default_function the default transformation function
3610 * @param string $transform_options the transformation parameters
3611 * @param boolean $condition_field the column should highlighted
3612 * or not
3613 * @param boolean $is_field_truncated the condition for blob data
3614 * replacements
3616 * @return string $cell the prepared cell, html content
3618 * @access private
3620 * @see _getTableBody()
3622 private function _getDataCellForBlobColumns(
3623 $column, $class, $meta, $_url_params, $field_flags, $transformation_plugin,
3624 $default_function, $transform_options, $condition_field, $is_field_truncated
3627 if (stristr($field_flags, self::BINARY_FIELD)) {
3629 // remove 'grid_edit' from $class as we can't edit binary data.
3630 $class = str_replace('grid_edit', '', $class);
3632 if (! isset($column) || is_null($column)) {
3634 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3636 } else {
3638 $blobtext = $this->_handleNonPrintableContents(
3639 self::BLOB_FIELD, (isset($column) ? $column : ''),
3640 $transformation_plugin, $transform_options,
3641 $default_function, $meta, $_url_params
3644 $cell = $this->_buildValueDisplay(
3645 $class, $condition_field, $blobtext
3647 unset($blobtext);
3649 } else {
3650 // not binary:
3652 if (! isset($column) || is_null($column)) {
3654 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3656 } elseif ($column != '') {
3658 // if a transform function for blob is set, none of these
3659 // replacements will be made
3660 if ((PMA_strlen($column) > $GLOBALS['cfg']['LimitChars'])
3661 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3662 && ! $this->_isNeedToSyntaxHighlight(strtolower($meta->name))
3664 $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars'])
3665 . '...';
3666 $is_field_truncated = true;
3669 // displays all space characters, 4 space
3670 // characters for tabulations and <cr>/<lf>
3671 $column = ($default_function != $transformation_plugin)
3672 ? $transformation_plugin->applyTransformation(
3673 $column,
3674 $transform_options,
3675 $meta
3677 : $this->$default_function($column, array(), $meta);
3679 if ($is_field_truncated) {
3680 $class .= ' truncated';
3683 $cell = $this->_buildValueDisplay($class, $condition_field, $column);
3685 } else {
3686 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3690 return $cell;
3692 } // end of the '_getDataCellForBlobColumns()' function
3696 * Get data cell for geometry type fields
3698 * @param string $column the relavent column in data row
3699 * @param string $class the html class for column
3700 * @param object $meta the meta-information about this field
3701 * @param array $map the list of relations
3702 * @param array $_url_params the parameters for generate url
3703 * @param boolean $condition_field the column should highlighted or not
3704 * @param string $transformation_plugin the name of transformation function
3705 * @param string $default_function the default transformation function
3706 * @param string $transform_options the transformation parameters
3707 * @param boolean $is_field_truncated the condition for blob data replacements
3708 * @param array $analyzed_sql the analyzed query
3710 * @return string $cell the prepared data cell, html content
3712 * @access private
3714 * @see _getTableBody()
3716 private function _getDataCellForGeometryColumns(
3717 $column, $class, $meta, $map, $_url_params, $condition_field,
3718 $transformation_plugin, $default_function, $transform_options,
3719 $is_field_truncated, $analyzed_sql
3722 if (! isset($column) || is_null($column)) {
3724 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3726 } elseif ($column != '') {
3728 // Display as [GEOMETRY - (size)]
3729 if ($_SESSION['tmp_user_values']['geometry_display'] == self::GEOMETRY_DISP_GEOM) {
3731 $geometry_text = $this->_handleNonPrintableContents(
3732 strtoupper(self::GEOMETRY_FIELD),
3733 (isset($column) ? $column : ''), $transformation_plugin,
3734 $transform_options, $default_function, $meta
3737 $cell = $this->_buildValueDisplay(
3738 $class, $condition_field, $geometry_text
3741 } elseif ($_SESSION['tmp_user_values']['geometry_display']
3742 == self::GEOMETRY_DISP_WKT
3744 // Prepare in Well Known Text(WKT) format.
3746 $where_comparison = ' = ' . $column;
3748 // Convert to WKT format
3749 $wktval = PMA_Util::asWKT($column);
3751 if ((PMA_strlen($wktval) > $GLOBALS['cfg']['LimitChars'])
3752 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3754 $wktval = PMA_substr($wktval, 0, $GLOBALS['cfg']['LimitChars'])
3755 . '...';
3756 $is_field_truncated = true;
3759 $cell = $this->_getRowData(
3760 $class, $condition_field, $analyzed_sql, $meta, $map,
3761 $wktval, $transformation_plugin, $default_function, '',
3762 $where_comparison, $transform_options,
3763 $is_field_truncated
3766 } else {
3767 // Prepare in Well Known Binary (WKB) format.
3769 if ($_SESSION['tmp_user_values']['display_binary']) {
3771 $where_comparison = ' = ' . $column;
3773 $wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8);
3775 if ((PMA_strlen($wkbval) > $GLOBALS['cfg']['LimitChars'])
3776 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3778 $wkbval
3779 = PMA_substr($wkbval, 0, $GLOBALS['cfg']['LimitChars'])
3780 . '...';
3781 $is_field_truncated = true;
3784 $cell = $this->_getRowData(
3785 $class, $condition_field,
3786 $analyzed_sql, $meta, $map, $wkbval,
3787 $transformation_plugin, $default_function, '',
3788 $where_comparison, $transform_options,
3789 $is_field_truncated
3792 } else {
3793 $wkbval = $this->_handleNonPrintableContents(
3794 self::BINARY_FIELD, $column, $transformation_plugin,
3795 $transform_options, $default_function, $meta,
3796 $_url_params
3799 $cell = $this->_buildValueDisplay(
3800 $class, $condition_field, $wkbval
3804 } else {
3805 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3808 return $cell;
3810 } // end of the '_getDataCellForGeometryColumns()' function
3814 * Get data cell for non numeric and non blob type fields
3816 * @param string $column the relavent column in data row
3817 * @param string $class the html class for column
3818 * @param object $meta the meta-information about the field
3819 * @param array $map the list of relations
3820 * @param array $_url_params the parameters for generate url
3821 * @param boolean $condition_field the column should highlighted
3822 * or not
3823 * @param string $transformation_plugin the name of transformation function
3824 * @param string $default_function the default transformation function
3825 * @param string $transform_options the transformation parameters
3826 * @param boolean $is_field_truncated the condition for blob data
3827 * replacements
3828 * @param array $analyzed_sql the analyzed query
3829 * @param integer &$dt_result the link id associated to the query
3830 * which results have to be displayed
3831 * @param integer $col_index the column index
3833 * @return string $cell the prepared data cell, html content
3835 * @access private
3837 * @see _getTableBody()
3839 private function _getDataCellForNonNumericAndNonBlobColumns(
3840 $column, $class, $meta, $map, $_url_params, $condition_field,
3841 $transformation_plugin, $default_function, $transform_options,
3842 $is_field_truncated, $analyzed_sql, &$dt_result, $col_index
3845 $is_analyse = $this->__get('is_analyse');
3846 $field_flags = PMA_DBI_field_flags($dt_result, $col_index);
3847 if (stristr($field_flags, self::BINARY_FIELD)
3848 && ($GLOBALS['cfg']['ProtectBinary'] == 'all'
3849 || $GLOBALS['cfg']['ProtectBinary'] == 'noblob')
3851 $class = str_replace('grid_edit', '', $class);
3854 if (! isset($column) || is_null($column)) {
3856 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3858 } elseif ($column != '') {
3860 // Cut all fields to $GLOBALS['cfg']['LimitChars']
3861 // (unless it's a link-type transformation)
3862 if (PMA_strlen($column) > $GLOBALS['cfg']['LimitChars']
3863 && ($_SESSION['tmp_user_values']['display_text'] == self::DISPLAY_PARTIAL_TEXT)
3864 && gettype($transformation_plugin) == "object"
3865 && ! strpos($transformation_plugin->getName(), 'Link') === true
3867 $column = PMA_substr($column, 0, $GLOBALS['cfg']['LimitChars'])
3868 . '...';
3869 $is_field_truncated = true;
3872 $formatted = false;
3873 if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
3875 $column = PMA_Util::printableBitValue(
3876 $column, $meta->length
3879 // some results of PROCEDURE ANALYSE() are reported as
3880 // being BINARY but they are quite readable,
3881 // so don't treat them as BINARY
3882 } elseif (stristr($field_flags, self::BINARY_FIELD)
3883 && ($meta->type == self::STRING_FIELD)
3884 && !(isset($is_analyse) && $is_analyse)
3887 if ($_SESSION['tmp_user_values']['display_binary']) {
3889 // user asked to see the real contents of BINARY
3890 // fields
3891 $column = $this->_displayBinaryAsPrintable($column, 'binary');
3893 } else {
3894 // we show the BINARY message and field's size
3895 // (or maybe use a transformation)
3896 $column = $this->_handleNonPrintableContents(
3897 self::BINARY_FIELD, $column, $transformation_plugin,
3898 $transform_options, $default_function,
3899 $meta, $_url_params
3901 $formatted = true;
3905 if ($formatted) {
3907 $cell = $this->_buildValueDisplay(
3908 $class, $condition_field, $column
3911 } else {
3913 // transform functions may enable no-wrapping:
3914 $function_nowrap = 'applyTransformationNoWrap';
3916 $bool_nowrap = (($default_function != $transformation_plugin)
3917 && function_exists($transformation_plugin->$function_nowrap()))
3918 ? $transformation_plugin->$function_nowrap($transform_options)
3919 : false;
3921 // do not wrap if date field type
3922 $nowrap = (preg_match('@DATE|TIME@i', $meta->type)
3923 || $bool_nowrap) ? ' nowrap' : '';
3925 $where_comparison = ' = \''
3926 . PMA_Util::sqlAddSlashes($column)
3927 . '\'';
3929 $cell = $this->_getRowData(
3930 $class, $condition_field,
3931 $analyzed_sql, $meta, $map, $column,
3932 $transformation_plugin, $default_function, $nowrap,
3933 $where_comparison, $transform_options,
3934 $is_field_truncated
3938 } else {
3939 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3942 return $cell;
3944 } // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function
3948 * Get the resulted table with the vertical direction mode.
3950 * @param array $analyzed_sql the analyzed query
3951 * @param array $is_display display mode
3953 * @return string html content
3955 * @access private
3957 * @see _getTable()
3959 private function _getVerticalTable($analyzed_sql, $is_display)
3962 $vertical_table_html = '';
3963 $vertical_display = $this->__get('vertical_display');
3965 // Prepares "multi row delete" link at top if required
3966 if (($GLOBALS['cfg']['RowActionLinks'] != self::POSITION_RIGHT)
3967 && is_array($vertical_display['row_delete'])
3968 && ((count($vertical_display['row_delete']) > 0)
3969 || !empty($vertical_display['textbtn']))
3972 $vertical_table_html .= '<tr>' . "\n";
3973 if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
3974 // if we are not showing the RowActionLinks, then we need to show
3975 // the Multi-Row-Action checkboxes
3976 $vertical_table_html .= '<th></th>' . "\n";
3979 $vertical_table_html .= $vertical_display['textbtn']
3980 . $this->_getCheckBoxesForMultipleRowOperations('_left', $is_display)
3981 . '</tr>' . "\n";
3982 } // end if
3984 // Prepares "edit" link at top if required
3985 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
3986 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
3987 && is_array($vertical_display['edit'])
3988 && ((count($vertical_display['edit']) > 0)
3989 || !empty($vertical_display['textbtn']))
3991 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
3992 'edit'
3994 } // end if
3996 // Prepares "copy" link at top if required
3997 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
3998 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
3999 && is_array($vertical_display['copy'])
4000 && ((count($vertical_display['copy']) > 0)
4001 || !empty($vertical_display['textbtn']))
4003 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4004 'copy'
4006 } // end if
4008 // Prepares "delete" link at top if required
4009 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
4010 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4011 && is_array($vertical_display['delete'])
4012 && ((count($vertical_display['delete']) > 0)
4013 || !empty($vertical_display['textbtn']))
4015 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4016 'delete'
4018 } // end if
4020 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql);
4022 // Prepares data
4023 foreach ($vertical_display['desc'] AS $j => $val) {
4025 // assign appropriate key with current column order
4026 $key = $col_order ? $col_order[$j] : $j;
4028 $vertical_table_html .= '<tr'
4029 . (($col_visib && !$col_visib[$j]) ? ' class="hide"' : '')
4030 . '>' . "\n"
4031 . $val;
4033 $cell_displayed = 0;
4034 foreach ($vertical_display['rowdata'][$key] as $subval) {
4036 if (($cell_displayed != 0)
4037 && ($_SESSION['tmp_user_values']['repeat_cells'] != 0)
4038 && ! ($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells'])
4040 $vertical_table_html .= $val;
4043 $vertical_table_html .= $subval;
4044 $cell_displayed++;
4046 } // end while
4048 $vertical_table_html .= '</tr>' . "\n";
4049 } // end while
4051 // Prepares "multi row delete" link at bottom if required
4052 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4053 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4054 && is_array($vertical_display['row_delete'])
4055 && ((count($vertical_display['row_delete']) > 0)
4056 || !empty($vertical_display['textbtn']))
4059 $vertical_table_html .= '<tr>' . "\n"
4060 . $vertical_display['textbtn']
4061 . $this->_getCheckBoxesForMultipleRowOperations('_right', $is_display)
4062 . '</tr>' . "\n";
4063 } // end if
4065 // Prepares "edit" link at bottom if required
4066 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4067 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4068 && is_array($vertical_display['edit'])
4069 && ((count($vertical_display['edit']) > 0)
4070 || !empty($vertical_display['textbtn']))
4072 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4073 'edit'
4075 } // end if
4077 // Prepares "copy" link at bottom if required
4078 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4079 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4080 && is_array($vertical_display['copy'])
4081 && ((count($vertical_display['copy']) > 0)
4082 || !empty($vertical_display['textbtn']))
4084 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4085 'copy'
4087 } // end if
4089 // Prepares "delete" link at bottom if required
4090 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
4091 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
4092 && is_array($vertical_display['delete'])
4093 && ((count($vertical_display['delete']) > 0)
4094 || !empty($vertical_display['textbtn']))
4096 $vertical_table_html .= $this->_getOperationLinksForVerticleTable(
4097 'delete'
4101 return $vertical_table_html;
4103 } // end of the '_getVerticalTable' function
4107 * Prepare edit, copy and delete links for verticle table
4109 * @param string $operation edit/copy/delete
4111 * @return string $links_html html content
4113 * @access private
4115 * @see _getVerticalTable()
4117 private function _getOperationLinksForVerticleTable($operation)
4120 $link_html = '<tr>' . "\n";
4121 $vertical_display = $this->__get('vertical_display');
4123 if (! is_array($vertical_display['row_delete'])) {
4125 if (($operation == 'edit') || ($operation == 'copy')) {
4126 $link_html .= $vertical_display['textbtn'];
4128 } elseif ($operation == 'delete') {
4130 if (! is_array($vertical_display['edit'])) {
4131 $link_html .= $vertical_display['textbtn'];
4136 foreach ($vertical_display[$operation] as $val) {
4137 $link_html .= $val;
4138 } // end while
4140 $link_html .= '</tr>' . "\n";
4142 return $link_html;
4144 } // end of the '_getOperationLinksForVerticleTable' function
4148 * Get checkboxes for multiple row data operations
4150 * @param string $dir _left / _right
4151 * @param array $is_display display mode
4153 * @return $checkBoxes_html html content
4155 * @access private
4157 * @see _getVerticalTable()
4159 private function _getCheckBoxesForMultipleRowOperations($dir, $is_display)
4162 $checkBoxes_html = '';
4163 $cell_displayed = 0;
4164 $vertical_display = $this->__get('vertical_display');
4166 foreach ($vertical_display['row_delete'] as $val) {
4168 if (($cell_displayed != 0)
4169 && ($_SESSION['tmp_user_values']['repeat_cells'] != 0)
4170 && !($cell_displayed % $_SESSION['tmp_user_values']['repeat_cells'])
4173 $checkBoxes_html .= '<th'
4174 . (($is_display['edit_lnk'] != self::NO_EDIT_OR_DELETE)
4175 && ($is_display['del_lnk'] != self::NO_EDIT_OR_DELETE))
4176 ? ' rowspan="4"'
4177 : ''
4178 . '></th>' . "\n";
4182 $checkBoxes_html .= str_replace('[%_PMA_CHECKBOX_DIR_%]', $dir, $val);
4183 $cell_displayed++;
4184 } // end while
4186 return $checkBoxes_html;
4188 } // end of the '_getCheckBoxesForMultipleRowOperations' function
4192 * Checks the posted options for viewing query resutls
4193 * and sets appropriate values in the session.
4195 * @todo make maximum remembered queries configurable
4196 * @todo move/split into SQL class!?
4197 * @todo currently this is called twice unnecessary
4198 * @todo ignore LIMIT and ORDER in query!?
4200 * @return void
4202 * @access public
4204 * @see sql.php file
4206 public function setConfigParamsForDisplayTable()
4209 $sql_md5 = md5($this->__get('sql_query'));
4211 $_SESSION['tmp_user_values']['query'][$sql_md5]['sql']
4212 = $this->__get('sql_query');
4214 $valid_disp_dir = PMA_isValid(
4215 $_REQUEST['disp_direction'],
4216 array(self::DISP_DIR_HORIZONTAL, self::DISP_DIR_VERTICAL,
4217 self::DISP_DIR_HORIZONTAL_FLIPPED
4221 if ($valid_disp_dir) {
4222 $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']
4223 = $_REQUEST['disp_direction'];
4224 unset($_REQUEST['disp_direction']);
4225 } elseif (
4226 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'])
4228 $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction']
4229 = $GLOBALS['cfg']['DefaultDisplay'];
4232 if (PMA_isValid($_REQUEST['repeat_cells'], 'numeric')) {
4233 $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']
4234 = $_REQUEST['repeat_cells'];
4235 unset($_REQUEST['repeat_cells']);
4236 } elseif (
4237 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'])
4239 $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells']
4240 = $GLOBALS['cfg']['RepeatCells'];
4243 // as this is a form value, the type is always string so we cannot
4244 // use PMA_isValid($_REQUEST['session_max_rows'], 'integer')
4245 if ((PMA_isValid($_REQUEST['session_max_rows'], 'numeric')
4246 && ((int) $_REQUEST['session_max_rows'] == $_REQUEST['session_max_rows']))
4247 || ($_REQUEST['session_max_rows'] == self::ALL_ROWS)
4249 $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']
4250 = $_REQUEST['session_max_rows'];
4251 unset($_REQUEST['session_max_rows']);
4252 } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'])) {
4253 $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']
4254 = $GLOBALS['cfg']['MaxRows'];
4257 if (PMA_isValid($_REQUEST['pos'], 'numeric')) {
4258 $_SESSION['tmp_user_values']['query'][$sql_md5]['pos']
4259 = $_REQUEST['pos'];
4260 unset($_REQUEST['pos']);
4261 } elseif (empty($_SESSION['tmp_user_values']['query'][$sql_md5]['pos'])) {
4262 $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'] = 0;
4265 if (PMA_isValid(
4266 $_REQUEST['display_text'],
4267 array(
4268 self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT
4272 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']
4273 = $_REQUEST['display_text'];
4274 unset($_REQUEST['display_text']);
4275 } elseif (
4276 empty($_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'])
4278 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text']
4279 = self::DISPLAY_PARTIAL_TEXT;
4282 if (PMA_isValid(
4283 $_REQUEST['relational_display'],
4284 array(
4285 self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN
4289 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4290 = $_REQUEST['relational_display'];
4291 unset($_REQUEST['relational_display']);
4292 } elseif (
4293 empty(
4294 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4297 $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display']
4298 = self::RELATIONAL_KEY;
4301 if (PMA_isValid(
4302 $_REQUEST['geometry_display'],
4303 array(
4304 self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB,
4305 self::GEOMETRY_DISP_GEOM
4309 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4310 = $_REQUEST['geometry_display'];
4311 unset($_REQUEST['geometry_display']);
4312 } elseif (
4313 empty(
4314 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4317 $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display']
4318 = self::GEOMETRY_DISP_GEOM;
4321 if (isset($_REQUEST['display_binary'])) {
4322 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true;
4323 unset($_REQUEST['display_binary']);
4324 } elseif (isset($_REQUEST['display_options_form'])) {
4325 // we know that the checkbox was unchecked
4326 unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary']);
4327 } elseif (isset($_REQUEST['full_text_button'])) {
4328 // do nothing to keep the value that is there in the session
4329 } else {
4330 // selected by default because some operations like OPTIMIZE TABLE
4331 // and all queries involving functions return "binary" contents,
4332 // according to low-level field flags
4333 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary'] = true;
4336 if (isset($_REQUEST['display_binary_as_hex'])) {
4337 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_binary_as_hex']
4338 = true;
4339 unset($_REQUEST['display_binary_as_hex']);
4340 } elseif (isset($_REQUEST['display_options_form'])) {
4341 // we know that the checkbox was unchecked
4342 unset($_SESSION['tmp_user_values']['query'][$sql_md5]
4343 ['display_binary_as_hex']
4345 } elseif (isset($_REQUEST['full_text_button'])) {
4346 // do nothing to keep the value that is there in the session
4347 } else {
4348 // display_binary_as_hex config option
4349 if (isset($GLOBALS['cfg']['DisplayBinaryAsHex'])
4350 && ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true)
4352 $_SESSION['tmp_user_values']['query'][$sql_md5]
4353 ['display_binary_as_hex'] = true;
4357 if (isset($_REQUEST['display_blob'])) {
4358 $_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob'] = true;
4359 unset($_REQUEST['display_blob']);
4360 } elseif (isset($_REQUEST['display_options_form'])) {
4361 // we know that the checkbox was unchecked
4362 unset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob']);
4365 if (isset($_REQUEST['hide_transformation'])) {
4366 $_SESSION['tmp_user_values']['query'][$sql_md5]['hide_transformation']
4367 = true;
4368 unset($_REQUEST['hide_transformation']);
4369 } elseif (isset($_REQUEST['display_options_form'])) {
4370 // we know that the checkbox was unchecked
4371 unset($_SESSION['tmp_user_values']['query'][$sql_md5]
4372 ['hide_transformation']
4376 // move current query to the last position, to be removed last
4377 // so only least executed query will be removed if maximum remembered queries
4378 // limit is reached
4379 $tmp = $_SESSION['tmp_user_values']['query'][$sql_md5];
4380 unset($_SESSION['tmp_user_values']['query'][$sql_md5]);
4381 $_SESSION['tmp_user_values']['query'][$sql_md5] = $tmp;
4383 // do not exceed a maximum number of queries to remember
4384 if (count($_SESSION['tmp_user_values']['query']) > 10) {
4385 array_shift($_SESSION['tmp_user_values']['query']);
4386 //echo 'deleting one element ...';
4389 // populate query configuration
4390 $_SESSION['tmp_user_values']['display_text']
4391 = $_SESSION['tmp_user_values']['query'][$sql_md5]['display_text'];
4392 $_SESSION['tmp_user_values']['relational_display']
4393 = $_SESSION['tmp_user_values']['query'][$sql_md5]['relational_display'];
4394 $_SESSION['tmp_user_values']['geometry_display']
4395 = $_SESSION['tmp_user_values']['query'][$sql_md5]['geometry_display'];
4396 $_SESSION['tmp_user_values']['display_binary']
4397 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4398 ['display_binary']
4400 ? true
4401 : false;
4402 $_SESSION['tmp_user_values']['display_binary_as_hex']
4403 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4404 ['display_binary_as_hex']
4406 ? true
4407 : false;
4408 $_SESSION['tmp_user_values']['display_blob']
4409 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]['display_blob'])
4410 ? true
4411 : false;
4412 $_SESSION['tmp_user_values']['hide_transformation']
4413 = isset($_SESSION['tmp_user_values']['query'][$sql_md5]
4414 ['hide_transformation']
4416 ? true
4417 : false;
4418 $_SESSION['tmp_user_values']['pos']
4419 = $_SESSION['tmp_user_values']['query'][$sql_md5]['pos'];
4420 $_SESSION['tmp_user_values']['max_rows']
4421 = $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows'];
4422 $_SESSION['tmp_user_values']['repeat_cells']
4423 = $_SESSION['tmp_user_values']['query'][$sql_md5]['repeat_cells'];
4424 $_SESSION['tmp_user_values']['disp_direction']
4425 = $_SESSION['tmp_user_values']['query'][$sql_md5]['disp_direction'];
4431 * Prepare a table of results returned by a SQL query.
4432 * This function is called by the "sql.php" script.
4434 * @param integer &$dt_result the link id associated to the query
4435 * which results have to be displayed
4436 * @param array &$the_disp_mode the display mode
4437 * @param array $analyzed_sql the analyzed query
4438 * @param boolean $is_limited_display With limited operations or not
4440 * @return string $table_html Generated HTML content for resulted table
4442 * @access public
4444 * @see sql.php file
4446 public function getTable(
4447 &$dt_result, &$the_disp_mode, $analyzed_sql, $is_limited_display = false
4450 $table_html = '';
4451 // Following variable are needed for use in isset/empty or
4452 // use with array indexes/safe use in foreach
4453 $fields_meta = $this->__get('fields_meta');
4454 $showtable = $this->__get('showtable');
4455 $printview = $this->__get('printview');
4457 // why was this called here? (already called from sql.php)
4458 //$this->setConfigParamsForDisplayTable();
4461 * @todo move this to a central place
4462 * @todo for other future table types
4464 $is_innodb = (isset($showtable['Type'])
4465 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
4467 if ($is_innodb
4468 && ! isset($analyzed_sql[0]['queryflags']['union'])
4469 && ! isset($analyzed_sql[0]['table_ref'][1]['table_name'])
4470 && (empty($analyzed_sql[0]['where_clause'])
4471 || ($analyzed_sql[0]['where_clause'] == '1 '))
4473 // "j u s t b r o w s i n g"
4474 $pre_count = '~';
4475 $after_count = PMA_Util::showHint(
4476 PMA_sanitize(
4477 __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc]')
4480 } else {
4481 $pre_count = '';
4482 $after_count = '';
4485 // 1. ----- Prepares the work -----
4487 // 1.1 Gets the informations about which functionalities should be
4488 // displayed
4489 $total = '';
4490 $is_display = $this->_setDisplayMode($the_disp_mode, $total);
4492 // 1.2 Defines offsets for the next and previous pages
4493 if ($is_display['nav_bar'] == '1') {
4494 list($pos_next, $pos_prev) = $this->_getOffsets();
4495 } // end if
4496 if (!isset($analyzed_sql[0]['order_by_clause'])) {
4497 $analyzed_sql[0]['order_by_clause'] = "";
4500 // 1.3 Find the sort expression
4501 // we need $sort_expression and $sort_expression_nodirection
4502 // even if there are many table references
4503 list($sort_expression, $sort_expression_nodirection, $sort_direction)
4504 = $this->_getSortParams($analyzed_sql[0]['order_by_clause']);
4507 // 1.4 Prepares display of first and last value of the sorted column
4509 $sorted_column_message = $this->_getSortedColumnMessage(
4510 $dt_result, $sort_expression_nodirection
4514 // 2. ----- Prepare to display the top of the page -----
4516 // 2.1 Prepares a messages with position informations
4517 if (($is_display['nav_bar'] == '1') && isset($pos_next)) {
4519 $message = $this->_setMessageInformation(
4520 $sorted_column_message, $analyzed_sql[0]['limit_clause'],
4521 $total, $pos_next, $pre_count, $after_count
4524 $table_html .= PMA_Util::getMessage(
4525 $message, $this->__get('sql_query'), 'success'
4528 } elseif (! isset($printview) || ($printview != '1')) {
4530 $table_html .= PMA_Util::getMessage(
4531 __('Your SQL query has been executed successfully'),
4532 $this->__get('sql_query'), 'success'
4536 // 2.3 Prepare the navigation bars
4537 if (! strlen($this->__get('table'))) {
4539 if (isset($analyzed_sql[0]['query_type'])
4540 && ($analyzed_sql[0]['query_type'] == self::QUERY_TYPE_SELECT)
4542 // table does not always contain a real table name,
4543 // for example in MySQL 5.0.x, the query SHOW STATUS
4544 // returns STATUS as a table name
4545 $this->__set('table', $fields_meta[0]->table);
4546 } else {
4547 $this->__set('table', '');
4552 if (($is_display['nav_bar'] == '1')
4553 && empty($analyzed_sql[0]['limit_clause'])
4556 $table_html .= $this->_getPlacedTableNavigatoins(
4557 $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN,
4558 "\n", $is_innodb
4561 } elseif (! isset($printview) || ($printview != '1')) {
4562 $table_html .= "\n" . '<br /><br />' . "\n";
4565 // 2b ----- Get field references from Database -----
4566 // (see the 'relation' configuration variable)
4568 // initialize map
4569 $map = array();
4571 // find tables
4572 $target=array();
4573 if (isset($analyzed_sql[0]['table_ref'])
4574 && is_array($analyzed_sql[0]['table_ref'])
4577 foreach ($analyzed_sql[0]['table_ref']
4578 as $table_ref_position => $table_ref) {
4579 $target[] = $analyzed_sql[0]['table_ref']
4580 [$table_ref_position]['table_true_name'];
4585 $tabs = '(\'' . join('\',\'', $target) . '\')';
4587 if (! strlen($this->__get('table'))) {
4588 $exist_rel = false;
4589 } else {
4590 // This method set the values for $map array
4591 $this->_setParamForLinkForeignKeyRelatedTables($map);
4592 } // end if
4593 // end 2b
4595 // 3. ----- Prepare the results table -----
4596 $table_html .= $this->_getTableHeaders(
4597 $is_display, $analyzed_sql, $sort_expression,
4598 $sort_expression_nodirection, $sort_direction, $is_limited_display
4600 . '<tbody>' . "\n";
4602 $url_query = '';
4603 $table_html .= $this->_getTableBody(
4604 $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display
4607 // vertical output case
4608 if ($_SESSION['tmp_user_values']['disp_direction'] == self::DISP_DIR_VERTICAL) {
4609 $table_html .= $this->_getVerticalTable($analyzed_sql, $is_display);
4610 } // end if
4612 $this->__set('vertical_display', null);
4614 $table_html .= '</tbody>' . "\n"
4615 . '</table>';
4617 // 4. ----- Prepares the link for multi-fields edit and delete
4619 if ($is_display['del_lnk'] == self::DELETE_ROW
4620 && $is_display['del_lnk'] != self::KILL_PROCESS
4623 $table_html .= $this->_getMultiRowOperationLinks(
4624 $dt_result, $analyzed_sql, $is_display['del_lnk']
4629 // 5. ----- Get the navigation bar at the bottom if required -----
4630 if (($is_display['nav_bar'] == '1')
4631 && empty($analyzed_sql[0]['limit_clause'])
4633 $table_html .= $this->_getPlacedTableNavigatoins(
4634 $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN,
4635 '<br />' . "\n", $is_innodb
4637 } elseif (! isset($printview) || ($printview != '1')) {
4638 $table_html .= "\n" . '<br /><br />' . "\n";
4642 // 6. ----- Prepare "Query results operations"
4643 if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) {
4644 $table_html .= $this->_getResultsOperations(
4645 $the_disp_mode, $analyzed_sql
4649 return $table_html;
4651 } // end of the 'getTable()' function
4655 * Get offsets for next page and previous page
4657 * @return array array with two elements - $pos_next, $pos_prev
4659 * @access private
4661 * @see getTable()
4663 private function _getOffsets()
4666 if ($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS) {
4667 $pos_next = 0;
4668 $pos_prev = 0;
4669 } else {
4671 $pos_next = $_SESSION['tmp_user_values']['pos']
4672 + $_SESSION['tmp_user_values']['max_rows'];
4674 $pos_prev = $_SESSION['tmp_user_values']['pos']
4675 - $_SESSION['tmp_user_values']['max_rows'];
4677 if ($pos_prev < 0) {
4678 $pos_prev = 0;
4682 return array($pos_next, $pos_prev);
4684 } // end of the '_getOffsets()' function
4688 * Get sort parameters
4690 * @param string $order_by_clause the order by clause of the sql query
4692 * @return array 3 element array: $sort_expression,
4693 * $sort_expression_nodirection, $sort_direction
4695 * @access private
4697 * @see getTable()
4699 private function _getSortParams($order_by_clause)
4702 if (! empty($order_by_clause)) {
4704 $sort_expression = trim(
4705 str_replace(' ', ' ', $order_by_clause)
4708 * Get rid of ASC|DESC
4710 preg_match(
4711 '@(.*)([[:space:]]*(ASC|DESC))@si', $sort_expression, $matches
4714 $sort_expression_nodirection = isset($matches[1])
4715 ? trim($matches[1])
4716 : $sort_expression;
4718 $sort_direction = isset($matches[2]) ? trim($matches[2]) : '';
4719 unset($matches);
4721 } else {
4722 $sort_expression = $sort_expression_nodirection = $sort_direction = '';
4725 return array($sort_expression, $sort_expression_nodirection,
4726 $sort_direction
4729 } // end of the '_getSortParams()' function
4733 * Prepare sorted column message
4735 * @param integer &$dt_result the link id associated to the
4736 * query which results have to
4737 * be displayed
4738 * @param string $sort_expression_nodirection sort expression without direction
4740 * @return string html content
4741 * null if not found sorted column
4743 * @access private
4745 * @see getTable()
4747 private function _getSortedColumnMessage(
4748 &$dt_result, $sort_expression_nodirection
4751 $fields_meta = $this->__get('fields_meta'); // To use array indexes
4753 if (! empty($sort_expression_nodirection)) {
4755 if (strpos($sort_expression_nodirection, '.') === false) {
4756 $sort_table = $this->__get('table');
4757 $sort_column = $sort_expression_nodirection;
4758 } else {
4759 list($sort_table, $sort_column)
4760 = explode('.', $sort_expression_nodirection);
4763 $sort_table = PMA_Util::unQuote($sort_table);
4764 $sort_column = PMA_Util::unQuote($sort_column);
4766 // find the sorted column index in row result
4767 // (this might be a multi-table query)
4768 $sorted_column_index = false;
4770 foreach ($fields_meta as $key => $meta) {
4771 if (($meta->table == $sort_table) && ($meta->name == $sort_column)) {
4772 $sorted_column_index = $key;
4773 break;
4777 if ($sorted_column_index !== false) {
4779 // fetch first row of the result set
4780 $row = PMA_DBI_fetch_row($dt_result);
4782 // initializing default arguments
4783 $default_function = '_mimeDefaultFunction';
4784 $transformation_plugin = $default_function;
4785 $transform_options = array();
4787 // check for non printable sorted row data
4788 $meta = $fields_meta[$sorted_column_index];
4790 if (stristr($meta->type, self::BLOB_FIELD)
4791 || ($meta->type == self::GEOMETRY_FIELD)
4794 $column_for_first_row = $this->_handleNonPrintableContents(
4795 $meta->type, $row[$sorted_column_index],
4796 $transformation_plugin, $transform_options,
4797 $default_function, $meta, null
4800 } else {
4801 $column_for_first_row = $row[$sorted_column_index];
4804 $column_for_first_row = strtoupper(
4805 substr($column_for_first_row, 0, $GLOBALS['cfg']['LimitChars'])
4808 // fetch last row of the result set
4809 PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1);
4810 $row = PMA_DBI_fetch_row($dt_result);
4812 // check for non printable sorted row data
4813 $meta = $fields_meta[$sorted_column_index];
4814 if (stristr($meta->type, self::BLOB_FIELD)
4815 || ($meta->type == self::GEOMETRY_FIELD)
4818 $column_for_last_row = $this->_handleNonPrintableContents(
4819 $meta->type, $row[$sorted_column_index],
4820 $transformation_plugin, $transform_options,
4821 $default_function, $meta, null
4824 } else {
4825 $column_for_last_row = $row[$sorted_column_index];
4828 $column_for_last_row = strtoupper(
4829 substr($column_for_last_row, 0, $GLOBALS['cfg']['LimitChars'])
4832 // reset to first row for the loop in _getTableBody()
4833 PMA_DBI_data_seek($dt_result, 0);
4835 // we could also use here $sort_expression_nodirection
4836 return ' [' . htmlspecialchars($sort_column)
4837 . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - '
4838 . htmlspecialchars($column_for_last_row) . '</strong>]';
4842 return null;
4844 } // end of the '_getSortedColumnMessage()' function
4848 * Set the content need to be show in message
4850 * @param string $sorted_column_message the message for sorted column
4851 * @param string $limit_clause the limit clause of analyzed query
4852 * @param integer $total the total number of rows returned by
4853 * the SQL query without any
4854 * programmatically appended LIMIT clause
4855 * @param integer $pos_next the offset for next page
4856 * @param string $pre_count the string renders before row count
4857 * @param string $after_count the string renders after row count
4859 * @return PMA_Message $message an object of PMA_Message
4861 * @access private
4863 * @see getTable()
4865 private function _setMessageInformation(
4866 $sorted_column_message, $limit_clause, $total,
4867 $pos_next, $pre_count, $after_count
4870 $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset()
4872 if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) {
4873 $selectstring = ', ' . $unlim_num_rows . ' ' . __('in query');
4874 } else {
4875 $selectstring = '';
4878 if (! empty($limit_clause)) {
4880 $limit_data
4881 = PMA_Util::analyzeLimitClause($limit_clause);
4882 $first_shown_rec = $limit_data['start'];
4884 if ($limit_data['length'] < $total) {
4885 $last_shown_rec = $limit_data['start'] + $limit_data['length'] - 1;
4886 } else {
4887 $last_shown_rec = $limit_data['start'] + $total - 1;
4890 } elseif (($_SESSION['tmp_user_values']['max_rows'] == self::ALL_ROWS)
4891 || ($pos_next > $total)
4894 $first_shown_rec = $_SESSION['tmp_user_values']['pos'];
4895 $last_shown_rec = $total - 1;
4897 } else {
4899 $first_shown_rec = $_SESSION['tmp_user_values']['pos'];
4900 $last_shown_rec = $pos_next - 1;
4904 if (PMA_Table::isView($this->__get('db'), $this->__get('table'))
4905 && ($total == $GLOBALS['cfg']['MaxExactCountViews'])
4908 $message = PMA_Message::notice(
4910 'This view has at least this number of rows. '
4911 . 'Please refer to %sdocumentation%s.'
4915 $message->addParam('[doc@cfg_MaxExactCount]');
4916 $message->addParam('[/doc]');
4917 $message_view_warning = PMA_Util::showHint($message);
4919 } else {
4920 $message_view_warning = false;
4923 $message = PMA_Message::success(__('Showing rows'));
4924 $message->addMessage($first_shown_rec);
4926 if ($message_view_warning) {
4928 $message->addMessage('...', ' - ');
4929 $message->addMessage($message_view_warning);
4930 $message->addMessage('(');
4932 } else {
4934 $message->addMessage($last_shown_rec, ' - ');
4935 $message->addMessage(' (');
4936 $message->addMessage(
4937 $pre_count . PMA_Util::formatNumber($total, 0)
4939 $message->addString(__('total'));
4941 if (!empty($after_count)) {
4942 $message->addMessage($after_count);
4945 $message->addMessage($selectstring, '');
4946 $message->addMessage(', ', '');
4950 $messagge_qt = PMA_Message::notice(__('Query took %01.4f sec') . ')');
4951 $messagge_qt->addParam($this->__get('querytime'));
4953 $message->addMessage($messagge_qt, '');
4954 if (! is_null($sorted_column_message)) {
4955 $message->addMessage($sorted_column_message, '');
4958 return $message;
4960 } // end of the '_setMessageInformation()' function
4964 * Set the value of $map array for linking foreign key related tables
4966 * @param array &$map the list of relations
4968 * @return void
4970 * @access private
4972 * @see getTable()
4974 private function _setParamForLinkForeignKeyRelatedTables(&$map)
4977 // To be able to later display a link to the related table,
4978 // we verify both types of relations: either those that are
4979 // native foreign keys or those defined in the phpMyAdmin
4980 // configuration storage. If no PMA storage, we won't be able
4981 // to use the "column to display" notion (for example show
4982 // the name related to a numeric id).
4983 $exist_rel = PMA_getForeigners(
4984 $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH
4987 if ($exist_rel) {
4989 foreach ($exist_rel as $master_field => $rel) {
4991 $display_field = PMA_getDisplayField(
4992 $rel['foreign_db'], $rel['foreign_table']
4995 $map[$master_field] = array(
4996 $rel['foreign_table'],
4997 $rel['foreign_field'],
4998 $display_field,
4999 $rel['foreign_db']
5001 } // end while
5002 } // end if
5004 } // end of the '_setParamForLinkForeignKeyRelatedTables()' function
5008 * Prepare multi field edit/delete links
5010 * @param integer &$dt_result the link id associated to the query
5011 * which results have to be displayed
5012 * @param array $analyzed_sql the analyzed query
5013 * @param string $del_link the display element - 'del_link'
5015 * @return string $links_html html content
5017 * @access private
5019 * @see getTable()
5021 private function _getMultiRowOperationLinks(
5022 &$dt_result, $analyzed_sql, $del_link
5025 $links_html = '';
5026 $url_query = $this->__get('url_query');
5027 $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill');
5029 $_url_params = array(
5030 'db' => $this->__get('db'),
5031 'table' => $this->__get('table'),
5032 'sql_query' => $this->__get('sql_query'),
5033 'goto' => $this->__get('goto'),
5036 if ($_SESSION['tmp_user_values']['disp_direction'] != self::DISP_DIR_VERTICAL) {
5038 $links_html .= '<img class="selectallarrow" width="38" height="22"'
5039 . ' src="' . $this->__get('pma_theme_image') . 'arrow_'
5040 . $this->__get('text_dir') . '.png' . '"'
5041 . ' alt="' . __('With selected:') . '" />';
5044 $links_html .= '<input type="checkbox" id="checkall" title="'
5045 . __('Check All') . '" /> '
5046 . '<label for="checkall">' . __('Check All') . '</label> '
5047 . '<i style="margin-left: 2em">' . __('With selected:') . '</i>' . "\n";
5049 $links_html .= PMA_Util::getButtonOrImage(
5050 'submit_mult', 'mult_submit', 'submit_mult_change',
5051 __('Change'), 'b_edit.png', 'edit'
5054 $links_html .= PMA_Util::getButtonOrImage(
5055 'submit_mult', 'mult_submit', 'submit_mult_delete',
5056 $delete_text, 'b_drop.png', 'delete'
5059 if (isset($analyzed_sql[0])
5060 && $analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT
5062 $links_html .= PMA_Util::getButtonOrImage(
5063 'submit_mult', 'mult_submit', 'submit_mult_export',
5064 __('Export'), 'b_tblexport.png', 'export'
5068 $links_html .= "\n";
5070 $links_html .= '<input type="hidden" name="sql_query"'
5071 .' value="' . htmlspecialchars($this->__get('sql_query')) . '" />'
5072 . "\n";
5074 if (! empty($url_query)) {
5075 $links_html .= '<input type="hidden" name="url_query"'
5076 .' value="' . $url_query . '" />' . "\n";
5079 // fetch last row of the result set
5080 PMA_DBI_data_seek($dt_result, $this->__get('num_rows') - 1);
5081 $row = PMA_DBI_fetch_row($dt_result);
5083 // $clause_is_unique is needed by getTable() to generate the proper param
5084 // in the multi-edit and multi-delete form
5085 list($where_clause, $clause_is_unique, $condition_array)
5086 = PMA_Util::getUniqueCondition(
5087 $dt_result,
5088 $this->__get('fields_cnt'),
5089 $this->__get('fields_meta'),
5090 $row
5093 // reset to first row for the loop in _getTableBody()
5094 PMA_DBI_data_seek($dt_result, 0);
5096 $links_html .= '<input type="hidden" name="clause_is_unique"'
5097 .' value="' . $clause_is_unique . '" />' . "\n";
5099 $links_html .= '</form>' . "\n";
5101 return $links_html;
5103 } // end of the '_getMultiRowOperationLinks()' function
5107 * Prepare table navigation bar at the top or bottom
5109 * @param integer $pos_next the offset for the "next" page
5110 * @param integer $pos_prev the offset for the "previous" page
5111 * @param string $place the place to show navigation
5112 * @param string $empty_line empty line depend on the $place
5113 * @param boolean $is_innodb whether its InnoDB or not
5115 * @return string html content of navigation bar
5117 * @access private
5119 * @see _getTable()
5121 private function _getPlacedTableNavigatoins(
5122 $pos_next, $pos_prev, $place, $empty_line, $is_innodb
5125 $navigation_html = '';
5127 if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) {
5128 $navigation_html .= '<br />' . "\n";
5131 $navigation_html .= $this->_getTableNavigation(
5132 $pos_next, $pos_prev, 'top_direction_dropdown', $is_innodb
5135 if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) {
5136 $navigation_html .= "\n";
5139 return $navigation_html;
5141 } // end of the '_getPlacedTableNavigatoins()' function
5145 * Get operations that are available on results.
5147 * @param array $the_disp_mode the display mode
5148 * @param array $analyzed_sql the analyzed query
5150 * @return string $results_operations_html html content
5152 * @access private
5154 * @see getTable()
5156 private function _getResultsOperations($the_disp_mode, $analyzed_sql)
5158 global $printview;
5160 $results_operations_html = '';
5161 $fields_meta = $this->__get('fields_meta'); // To safe use in foreach
5162 $header_shown = false;
5163 $header = '<fieldset><legend>' . __('Query results operations')
5164 . '</legend>';
5166 if (($the_disp_mode[6] == '1') || ($the_disp_mode[9] == '1')) {
5167 // Displays "printable view" link if required
5168 if ($the_disp_mode[9] == '1') {
5170 if (!$header_shown) {
5171 $results_operations_html .= $header;
5172 $header_shown = true;
5175 $_url_params = array(
5176 'db' => $this->__get('db'),
5177 'table' => $this->__get('table'),
5178 'printview' => '1',
5179 'sql_query' => $this->__get('sql_query'),
5181 $url_query = PMA_generate_common_url($_url_params);
5183 $results_operations_html
5184 .= PMA_Util::linkOrButton(
5185 'sql.php' . $url_query,
5186 PMA_Util::getIcon(
5187 'b_print.png', __('Print view'), true
5189 array('target' => 'print_view'),
5190 true,
5191 true,
5192 'print_view'
5194 . "\n";
5196 if ($_SESSION['tmp_user_values']['display_text']) {
5198 $_url_params['display_text'] = self::DISPLAY_FULL_TEXT;
5200 $results_operations_html
5201 .= PMA_Util::linkOrButton(
5202 'sql.php' . PMA_generate_common_url($_url_params),
5203 PMA_Util::getIcon(
5204 'b_print.png',
5205 __('Print view (with full texts)'), true
5207 array('target' => 'print_view'),
5208 true,
5209 true,
5210 'print_view'
5212 . "\n";
5213 unset($_url_params['display_text']);
5215 } // end displays "printable view"
5218 // Export link
5219 // (the url_query has extra parameters that won't be used to export)
5220 // (the single_table parameter is used in display_export.lib.php
5221 // to hide the SQL and the structure export dialogs)
5222 // If the parser found a PROCEDURE clause
5223 // (most probably PROCEDURE ANALYSE()) it makes no sense to
5224 // display the Export link).
5225 if (isset($analyzed_sql[0])
5226 && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT)
5227 && ! isset($printview)
5228 && ! isset($analyzed_sql[0]['queryflags']['procedure'])
5231 if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name'])
5232 && ! isset($analyzed_sql[0]['table_ref'][1]['table_true_name'])
5234 $_url_params['single_table'] = 'true';
5237 if (! $header_shown) {
5238 $results_operations_html .= $header;
5239 $header_shown = true;
5242 $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows');
5245 * At this point we don't know the table name; this can happen
5246 * for example with a query like
5247 * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp
5248 * As a workaround we set in the table parameter the name of the
5249 * first table of this database, so that tbl_export.php and
5250 * the script it calls do not fail
5252 if (empty($_url_params['table']) && ! empty($_url_params['db'])) {
5253 $_url_params['table'] = PMA_DBI_fetch_value("SHOW TABLES");
5254 /* No result (probably no database selected) */
5255 if ($_url_params['table'] === false) {
5256 unset($_url_params['table']);
5260 $results_operations_html .= PMA_Util::linkOrButton(
5261 'tbl_export.php' . PMA_generate_common_url($_url_params),
5262 PMA_Util::getIcon(
5263 'b_tblexport.png', __('Export'), true
5266 true,
5267 true,
5270 . "\n";
5272 // prepare chart
5273 $results_operations_html .= PMA_Util::linkOrButton(
5274 'tbl_chart.php' . PMA_generate_common_url($_url_params),
5275 PMA_Util::getIcon(
5276 'b_chart.png', __('Display chart'), true
5279 true,
5280 true,
5283 . "\n";
5285 // prepare GIS chart
5286 $geometry_found = false;
5287 // If atleast one geometry field is found
5288 foreach ($fields_meta as $meta) {
5289 if ($meta->type == self::GEOMETRY_FIELD) {
5290 $geometry_found = true;
5291 break;
5295 if ($geometry_found) {
5296 $results_operations_html
5297 .= PMA_Util::linkOrButton(
5298 'tbl_gis_visualization.php'
5299 . PMA_generate_common_url($_url_params),
5300 PMA_Util::getIcon(
5301 'b_globe.gif', __('Visualize GIS data'), true
5304 true,
5305 true,
5308 . "\n";
5312 // CREATE VIEW
5315 * @todo detect privileges to create a view
5316 * (but see 2006-01-19 note in display_create_table.lib.php,
5317 * I think we cannot detect db-specific privileges reliably)
5318 * Note: we don't display a Create view link if we found a PROCEDURE clause
5320 if (!$header_shown) {
5321 $results_operations_html .= $header;
5322 $header_shown = true;
5325 if (!PMA_DRIZZLE && !isset($analyzed_sql[0]['queryflags']['procedure'])) {
5327 $ajax_class = ' ajax';
5329 $results_operations_html .= '<span>'
5330 . PMA_Util::linkOrButton(
5331 'view_create.php' . $url_query,
5332 PMA_Util::getIcon(
5333 'b_views.png', __('Create view'), true
5335 array('class' => 'create_view' . $ajax_class), true, true, ''
5337 . '</span>' . "\n";
5340 if ($header_shown) {
5341 $results_operations_html .= '</fieldset><br />';
5344 return $results_operations_html;
5346 } // end of the '_getResultsOperations()' function
5350 * Verifies what to do with non-printable contents (binary or BLOB)
5351 * in Browse mode.
5353 * @param string $category BLOB|BINARY|GEOMETRY
5354 * @param string $content the binary content
5355 * @param string $transformation_plugin transformation plugin.
5356 * Can also be the default function:
5357 * PMA_mimeDefaultFunction
5358 * @param string $transform_options transformation parameters
5359 * @param string $default_function default transformation function
5360 * @param object $meta the meta-information about the field
5361 * @param array $url_params parameters that should go to the
5362 * download link
5364 * @return mixed string or float
5366 * @access private
5368 * @see _getDataCellForBlobColumns(),
5369 * _getDataCellForGeometryColumns(),
5370 * _getDataCellForNonNumericAndNonBlobColumns(),
5371 * _getSortedColumnMessage()
5373 private function _handleNonPrintableContents(
5374 $category, $content, $transformation_plugin, $transform_options,
5375 $default_function, $meta, $url_params = array()
5378 $result = '[' . $category;
5380 if (is_null($content)) {
5382 $result .= ' - NULL';
5383 $size = 0;
5385 } elseif (isset($content)) {
5387 $size = strlen($content);
5388 $display_size
5389 = PMA_Util::formatByteDown($size, 3, 1);
5390 $result .= ' - '. $display_size[0] . ' ' . $display_size[1];
5394 $result .= ']';
5396 if (gettype($transformation_plugin) == "object"
5397 && strpos($transformation_plugin->getMIMESubtype(), 'Octetstream')
5399 $result = $content;
5402 if ($size > 0) {
5404 if ($default_function != $transformation_plugin) {
5405 $result = $transformation_plugin->applyTransformation(
5406 $result,
5407 $transform_options,
5408 $meta
5410 } else {
5412 $result = $this->$default_function($result, array(), $meta);
5413 if (stristr($meta->type, self::BLOB_FIELD)
5414 && $_SESSION['tmp_user_values']['display_blob']
5416 // in this case, restart from the original $content
5417 $result = $this->_displayBinaryAsPrintable($content, 'blob');
5420 /* Create link to download */
5421 if (count($url_params) > 0) {
5422 $result = '<a href="tbl_get_field.php'
5423 . PMA_generate_common_url($url_params) . '" class="disableAjax">'
5424 . $result . '</a>';
5429 return($result);
5431 } // end of the '_handleNonPrintableContents()' function
5435 * Prepares the displayable content of a data cell in Browse mode,
5436 * taking into account foreign key description field and transformations
5438 * @param string $class css classes for the td element
5439 * @param bool $condition_field whether the column is a part of the
5440 * where clause
5441 * @param string $analyzed_sql the analyzed query
5442 * @param object $meta the meta-information about the field
5443 * @param array $map the list of relations
5444 * @param string $data data
5445 * @param string $transformation_plugin transformation plugin.
5446 * Can also be the default function:
5447 * PMA_mimeDefaultFunction
5448 * @param string $default_function default function
5449 * @param string $nowrap 'nowrap' if the content should not
5450 * be wrapped
5451 * @param string $where_comparison data for the where clause
5452 * @param array $transform_options array of options for transformation
5453 * @param bool $is_field_truncated whether the field is truncated
5455 * @return string formatted data
5457 * @access private
5459 * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
5460 * _getDataCellForNonNumericAndNonBlobColumns(),
5463 private function _getRowData(
5464 $class, $condition_field, $analyzed_sql, $meta, $map, $data,
5465 $transformation_plugin, $default_function, $nowrap, $where_comparison,
5466 $transform_options, $is_field_truncated
5469 $printview = $this->__get('printview');
5470 $result = '<td class="'
5471 . $this->_addClass(
5472 $class, $condition_field, $meta, $nowrap,
5473 $is_field_truncated, $transformation_plugin, $default_function
5475 . '">';
5477 if (isset($analyzed_sql[0]['select_expr'])
5478 && is_array($analyzed_sql[0]['select_expr'])
5481 foreach ($analyzed_sql[0]['select_expr']
5482 as $select_expr_position => $select_expr
5485 $alias = $analyzed_sql[0]['select_expr']
5486 [$select_expr_position]['alias'];
5488 if (isset($alias) && strlen($alias)) {
5489 $true_column = $analyzed_sql[0]['select_expr']
5490 [$select_expr_position]['column'];
5492 if ($alias == $meta->name) {
5493 // this change in the parameter does not matter
5494 // outside of the function
5495 $meta->name = $true_column;
5496 } // end if
5498 } // end if
5499 } // end foreach
5500 } // end if
5502 if (isset($map[$meta->name])) {
5504 // Field to display from the foreign table?
5505 if (isset($map[$meta->name][2]) && strlen($map[$meta->name][2])) {
5507 $dispsql = 'SELECT '
5508 . PMA_Util::backquote($map[$meta->name][2])
5509 . ' FROM '
5510 . PMA_Util::backquote($map[$meta->name][3])
5511 . '.'
5512 . PMA_Util::backquote($map[$meta->name][0])
5513 . ' WHERE '
5514 . PMA_Util::backquote($map[$meta->name][1])
5515 . $where_comparison;
5517 $dispresult = PMA_DBI_try_query($dispsql, null, PMA_DBI_QUERY_STORE);
5519 if ($dispresult && PMA_DBI_num_rows($dispresult) > 0) {
5520 list($dispval) = PMA_DBI_fetch_row($dispresult, 0);
5521 } else {
5522 $dispval = __('Link not found');
5525 @PMA_DBI_free_result($dispresult);
5527 } else {
5528 $dispval = '';
5529 } // end if... else...
5531 if (isset($printview) && ($printview == '1')) {
5533 $result .= ($transformation_plugin != $default_function
5534 ? $transformation_plugin->applyTransformation(
5535 $data,
5536 $transform_options,
5537 $meta
5539 : $this->$default_function($data)
5541 . ' <code>[-&gt;' . $dispval . ']</code>';
5543 } else {
5545 if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_KEY) {
5547 // user chose "relational key" in the display options, so
5548 // the title contains the display field
5549 $title = (! empty($dispval))
5550 ? ' title="' . htmlspecialchars($dispval) . '"'
5551 : '';
5553 } else {
5554 $title = ' title="' . htmlspecialchars($data) . '"';
5557 $_url_params = array(
5558 'db' => $map[$meta->name][3],
5559 'table' => $map[$meta->name][0],
5560 'pos' => '0',
5561 'sql_query' => 'SELECT * FROM '
5562 . PMA_Util::backquote(
5563 $map[$meta->name][3]
5564 ) . '.'
5565 . PMA_Util::backquote(
5566 $map[$meta->name][0]
5568 . ' WHERE '
5569 . PMA_Util::backquote(
5570 $map[$meta->name][1]
5572 . $where_comparison,
5575 $result .= '<a class="ajax" href="sql.php' . PMA_generate_common_url($_url_params)
5576 . '"' . $title . '>';
5578 if ($transformation_plugin != $default_function) {
5579 // always apply a transformation on the real data,
5580 // not on the display field
5581 $result .= $transformation_plugin->applyTransformation(
5582 $data,
5583 $transform_options,
5584 $meta
5586 } else {
5588 if ($_SESSION['tmp_user_values']['relational_display'] == self::RELATIONAL_DISPLAY_COLUMN) {
5589 // user chose "relational display field" in the
5590 // display options, so show display field in the cell
5591 $result .= $this->$default_function($dispval);
5592 } else {
5593 // otherwise display data in the cell
5594 $result .= $this->$default_function($data);
5598 $result .= '</a>';
5601 } else {
5602 $result .= ($transformation_plugin != $default_function
5603 ? $transformation_plugin->applyTransformation(
5604 $data,
5605 $transform_options,
5606 $meta
5608 : $this->$default_function($data)
5612 // create hidden field if results from structure table
5613 if (isset($_GET['browse_distinct']) && ($_GET['browse_distinct'] == 1)) {
5615 $where_comparison = " = '" . $data . "'";
5617 $_url_params_for_show_data_row = array(
5618 'db' => $this->__get('db'),
5619 'table' => $meta->orgtable,
5620 'pos' => '0',
5621 'sql_query' => 'SELECT * FROM '
5622 . PMA_Util::backquote($this->__get('db'))
5623 . '.' . PMA_Util::backquote($meta->orgtable)
5624 . ' WHERE '
5625 . PMA_Util::backquote($meta->orgname)
5626 . $where_comparison,
5629 $result .= '<input type="hidden" class="data_browse_link" value="'
5630 . PMA_generate_common_url($_url_params_for_show_data_row). '" />';
5634 $result .= '</td>' . "\n";
5636 return $result;
5638 } // end of the '_getRowData()' function
5642 * Prepares a checkbox for multi-row submits
5644 * @param string $del_url delete url
5645 * @param array $is_display array with explicit indexes for all
5646 * the display elements
5647 * @param string $row_no the row number
5648 * @param string $where_clause_html url encoded where clause
5649 * @param array $condition_array array of conditions in the where clause
5650 * @param string $del_query delete query
5651 * @param string $id_suffix suffix for the id
5652 * @param string $class css classes for the td element
5654 * @return string the generated HTML
5656 * @access private
5658 * @see _getTableBody(), _getCheckboxAndLinks()
5660 private function _getCheckboxForMultiRowSubmissions(
5661 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5662 $del_query, $id_suffix, $class
5665 $ret = '';
5667 if (! empty($del_url) && $is_display['del_lnk'] != self::KILL_PROCESS) {
5669 $ret .= '<td ';
5670 if (! empty($class)) {
5671 $ret .= 'class="' . $class . '"';
5674 $ret .= ' class="center">'
5675 . '<input type="checkbox" id="id_rows_to_delete'
5676 . $row_no . $id_suffix
5677 . '" name="rows_to_delete[' . $row_no . ']"'
5678 . ' class="multi_checkbox checkall"'
5679 . ' value="' . $where_clause_html . '" '
5680 . ' />'
5681 . '<input type="hidden" class="condition_array" value="'
5682 . htmlspecialchars(json_encode($condition_array)) . '" />'
5683 . ' </td>';
5686 return $ret;
5688 } // end of the '_getCheckboxForMultiRowSubmissions()' function
5692 * Prepares an Edit link
5694 * @param string $edit_url edit url
5695 * @param string $class css classes for td element
5696 * @param string $edit_str text for the edit link
5697 * @param string $where_clause where clause
5698 * @param string $where_clause_html url encoded where clause
5700 * @return string the generated HTML
5702 * @access private
5704 * @see _getTableBody(), _getCheckboxAndLinks()
5706 private function _getEditLink(
5707 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5710 $ret = '';
5711 if (! empty($edit_url)) {
5713 $ret .= '<td class="' . $class . ' center" ' . ' ><span class="nowrap">'
5714 . PMA_Util::linkOrButton(
5715 $edit_url, $edit_str, array(), false
5718 * Where clause for selecting this row uniquely is provided as
5719 * a hidden input. Used by jQuery scripts for handling grid editing
5721 if (! empty($where_clause)) {
5722 $ret .= '<input type="hidden" class="where_clause" value ="'
5723 . $where_clause_html . '" />';
5725 $ret .= '</span></td>';
5728 return $ret;
5730 } // end of the '_getEditLink()' function
5734 * Prepares an Copy link
5736 * @param string $copy_url copy url
5737 * @param string $copy_str text for the copy link
5738 * @param string $where_clause where clause
5739 * @param string $where_clause_html url encoded where clause
5740 * @param string $class css classes for the td element
5742 * @return string the generated HTML
5744 * @access private
5746 * @see _getTableBody(), _getCheckboxAndLinks()
5748 private function _getCopyLink(
5749 $copy_url, $copy_str, $where_clause, $where_clause_html, $class
5752 $ret = '';
5753 if (! empty($copy_url)) {
5755 $ret .= '<td class="';
5756 if (! empty($class)) {
5757 $ret .= $class . ' ';
5760 $ret .= 'center" ' . ' ><span class="nowrap">'
5761 . PMA_Util::linkOrButton(
5762 $copy_url, $copy_str, array(), false
5766 * Where clause for selecting this row uniquely is provided as
5767 * a hidden input. Used by jQuery scripts for handling grid editing
5769 if (! empty($where_clause)) {
5770 $ret .= '<input type="hidden" class="where_clause" value="'
5771 . $where_clause_html . '" />';
5773 $ret .= '</span></td>';
5776 return $ret;
5778 } // end of the '_getCopyLink()' function
5782 * Prepares a Delete link
5784 * @param string $del_url delete url
5785 * @param string $del_str text for the delete link
5786 * @param string $js_conf text for the JS confirmation
5787 * @param string $class css classes for the td element
5789 * @return string the generated HTML
5791 * @access private
5793 * @see _getTableBody(), _getCheckboxAndLinks()
5795 private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
5798 $ret = '';
5799 if (! empty($del_url)) {
5801 $ret .= '<td class="';
5802 if (! empty($class)) {
5803 $ret .= $class . ' ';
5805 $ajax = PMA_Response::getInstance()->isAjax() ? ' ajax' : '';
5806 $ret .= 'center" ' . ' >'
5807 . PMA_Util::linkOrButton(
5808 $del_url, $del_str, array('class' => 'delete_row' . $ajax), false
5810 . '<div class="hide">' . $js_conf . '</div>'
5811 . '</td>';
5814 return $ret;
5816 } // end of the '_getDeleteLink()' function
5820 * Prepare checkbox and links at some position (left or right)
5821 * (only called for horizontal mode)
5823 * @param string $position the position of the checkbox and links
5824 * @param string $del_url delete url
5825 * @param array $is_display array with explicit indexes for all the
5826 * display elements
5827 * @param string $row_no row number
5828 * @param string $where_clause where clause
5829 * @param string $where_clause_html url encoded where clause
5830 * @param array $condition_array array of conditions in the where clause
5831 * @param string $del_query delete query
5832 * @param string $id_suffix suffix for the id
5833 * @param string $edit_url edit url
5834 * @param string $copy_url copy url
5835 * @param string $class css classes for the td elements
5836 * @param string $edit_str text for the edit link
5837 * @param string $copy_str text for the copy link
5838 * @param string $del_str text for the delete link
5839 * @param string $js_conf text for the JS confirmation
5841 * @return string the generated HTML
5843 * @access private
5845 * @see _getPlacedLinks()
5847 private function _getCheckboxAndLinks(
5848 $position, $del_url, $is_display, $row_no, $where_clause,
5849 $where_clause_html, $condition_array, $del_query, $id_suffix,
5850 $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
5853 $ret = '';
5855 if ($position == self::POSITION_LEFT) {
5857 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5858 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5859 $del_query, $id_suffix = '_left', ''
5862 $ret .= $this->_getEditLink(
5863 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5866 $ret .= $this->_getCopyLink(
5867 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5870 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5872 } elseif ($position == self::POSITION_RIGHT) {
5874 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5876 $ret .= $this->_getCopyLink(
5877 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5880 $ret .= $this->_getEditLink(
5881 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5884 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5885 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5886 $del_query, $id_suffix = '_right', ''
5889 } else { // $position == self::POSITION_NONE
5891 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5892 $del_url, $is_display, $row_no, $where_clause_html, $condition_array,
5893 $del_query, $id_suffix = '_left', ''
5897 return $ret;
5899 } // end of the '_getCheckboxAndLinks()' function
5903 * Replace some html-unfriendly stuff
5905 * @param string $buffer String to process
5907 * @return Escaped and cleaned up text suitable for html.
5909 * @access private
5911 * @see _getDataCellForBlobField(), _getRowData(),
5912 * _handleNonPrintableContents()
5914 private function _mimeDefaultFunction($buffer)
5916 $buffer = htmlspecialchars($buffer);
5917 $buffer = str_replace(
5918 "\011",
5919 ' &nbsp;&nbsp;&nbsp;',
5920 str_replace(' ', ' &nbsp;', $buffer)
5922 $buffer = preg_replace("@((\015\012)|(\015)|(\012))@", '<br />', $buffer);
5924 return $buffer;
5928 * Display binary fields as hex string for PHP <5.4,
5929 * otherwise escape the contents if it may be displayed as hex
5931 * @param string $content String to parse
5932 * @param string $binary_or_blob 'binary' or 'blob'
5933 * @param int $hexlength optional, get substring
5935 * @return Displayable version of the binary string
5937 * @access private
5939 * @see _getDataCellForGeometryColumns
5940 * _getDataCellForNonNumericAndNonBlobColumns
5941 * _handleNonPrintableContents
5943 private function _displayBinaryAsPrintable(
5944 $content, $binary_or_blob, $hexlength = null
5946 if (PMA_PHP_INT_VERSION < 50400
5947 || ($binary_or_blob === 'binary'
5948 && $_SESSION['tmp_user_values']['display_binary_as_hex']
5949 && PMA_Util::containsNonPrintableAscii($content)
5952 $content = bin2hex($content);
5953 if ($hexlength !== null) {
5954 $content = PMA_substr($content, $hexlength);
5956 } else {
5957 $content = htmlspecialchars(
5958 PMA_Util::replaceBinaryContents(
5959 $content
5961 ENT_SUBSTITUTE
5964 return $content;