Removing old documentation
[openemr.git] / phpmyadmin / libraries / DisplayResults.class.php
blobe435a217f7a2a682fddf492abea3d91c78d20302
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 require_once './libraries/transformations.lib.php';
14 /**
15 * Handle all the functionalities related to displaying results
16 * of sql queries, stored procedure, browsing sql processes or
17 * displaying binary log.
19 * @package PhpMyAdmin
21 class PMA_DisplayResults
24 // Define constants
25 const NO_EDIT_OR_DELETE = 'nn';
26 const UPDATE_ROW = 'ur';
27 const DELETE_ROW = 'dr';
28 const KILL_PROCESS = 'kp';
30 const POSITION_LEFT = 'left';
31 const POSITION_RIGHT = 'right';
32 const POSITION_BOTH = 'both';
33 const POSITION_NONE = 'none';
35 const PLACE_TOP_DIRECTION_DROPDOWN = 'top_direction_dropdown';
36 const PLACE_BOTTOM_DIRECTION_DROPDOWN = 'bottom_direction_dropdown';
38 const DISPLAY_FULL_TEXT = 'F';
39 const DISPLAY_PARTIAL_TEXT = 'P';
41 const HEADER_FLIP_TYPE_AUTO = 'auto';
42 const HEADER_FLIP_TYPE_CSS = 'css';
43 const HEADER_FLIP_TYPE_FAKE = 'fake';
45 const DATE_FIELD = 'date';
46 const DATETIME_FIELD = 'datetime';
47 const TIMESTAMP_FIELD = 'timestamp';
48 const TIME_FIELD = 'time';
49 const STRING_FIELD = 'string';
50 const GEOMETRY_FIELD = 'geometry';
51 const BLOB_FIELD = 'BLOB';
52 const BINARY_FIELD = 'BINARY';
54 const RELATIONAL_KEY = 'K';
55 const RELATIONAL_DISPLAY_COLUMN = 'D';
57 const GEOMETRY_DISP_GEOM = 'GEOM';
58 const GEOMETRY_DISP_WKT = 'WKT';
59 const GEOMETRY_DISP_WKB = 'WKB';
61 const SMART_SORT_ORDER = 'SMART';
62 const ASCENDING_SORT_DIR = 'ASC';
63 const DESCENDING_SORT_DIR = 'DESC';
65 const TABLE_TYPE_INNO_DB = 'InnoDB';
66 const ALL_ROWS = 'all';
67 const QUERY_TYPE_SELECT = 'SELECT';
69 const ROUTINE_PROCEDURE = 'procedure';
70 const ROUTINE_FUNCTION = 'function';
72 const ACTION_LINK_CONTENT_ICONS = 'icons';
73 const ACTION_LINK_CONTENT_TEXT = 'text';
76 // Declare global fields
78 /** array with properties of the class */
79 private $_property_array = array(
81 /** string Database name */
82 'db' => null,
84 /** string Table name */
85 'table' => null,
87 /** string the URL to go back in case of errors */
88 'goto' => null,
90 /** string the SQL query */
91 'sql_query' => null,
93 /**
94 * integer the total number of rows returned by the SQL query without any
95 * appended "LIMIT" clause programmatically
97 'unlim_num_rows' => null,
99 /** array meta information about fields */
100 'fields_meta' => null,
102 /** boolean */
103 'is_count' => null,
105 /** integer */
106 'is_export' => null,
108 /** boolean */
109 'is_func' => null,
111 /** integer */
112 'is_analyse' => null,
114 /** integer the total number of rows returned by the SQL query */
115 'num_rows' => null,
117 /** integer the total number of fields returned by the SQL query */
118 'fields_cnt' => null,
120 /** double time taken for execute the SQL query */
121 'querytime' => null,
123 /** string path for theme images directory */
124 'pma_theme_image' => null,
126 /** string */
127 'text_dir' => null,
129 /** boolean */
130 'is_maint' => null,
132 /** boolean */
133 'is_explain' => null,
135 /** boolean */
136 'is_show' => null,
138 /** boolean */
139 'is_browse_distinct' => null,
141 /** array table definitions */
142 'showtable' => null,
144 /** string */
145 'printview' => null,
147 /** string URL query */
148 'url_query' => null,
150 /** array column names to highlight */
151 'highlight_columns' => null,
153 /** array holding various display information */
154 'display_params' => null,
156 /** array mime types information of fields */
157 'mime_map' => null,
159 /** boolean */
160 'editable' => null,
162 /** random unique ID to distinguish result set */
163 'unique_id' => null,
165 /** where clauses for each row, each table in the row */
166 'whereClauseMap' => array(),
170 * This variable contains the column transformation information
171 * for some of the system databases.
172 * One element of this array represent all relevant columns in all tables in
173 * one specific database
175 public $transformation_info;
179 * Get any property of this class
181 * @param string $property name of the property
183 * @return mixed|void if property exist, value of the relevant property
185 public function __get($property)
187 if (array_key_exists($property, $this->_property_array)) {
188 return $this->_property_array[$property];
194 * Set values for any property of this class
196 * @param string $property name of the property
197 * @param mixed $value value to set
199 * @return void
201 public function __set($property, $value)
203 if (array_key_exists($property, $this->_property_array)) {
204 $this->_property_array[$property] = $value;
210 * Constructor for PMA_DisplayResults class
212 * @param string $db the database name
213 * @param string $table the table name
214 * @param string $goto the URL to go back in case of errors
215 * @param string $sql_query the SQL query
217 * @access public
219 public function __construct($db, $table, $goto, $sql_query)
221 $this->_setDefaultTransformations();
223 $this->__set('db', $db);
224 $this->__set('table', $table);
225 $this->__set('goto', $goto);
226 $this->__set('sql_query', $sql_query);
227 $this->__set('unique_id', rand());
231 * Sets default transformations for some columns
233 * @return void
235 private function _setDefaultTransformations()
237 $json_highlighting_data = array(
238 'libraries/plugins/transformations/output/Text_Plain_Json.class.php',
239 'Text_Plain_Json',
240 'Text_Plain'
242 $sql_highlighting_data = array(
243 'libraries/plugins/transformations/output/Text_Plain_Sql.class.php',
244 'Text_Plain_Sql',
245 'Text_Plain'
247 $blob_sql_highlighting_data = array(
248 'libraries/plugins/transformations/output/Text_Octetstream_Sql.class.php',
249 'Text_Octetstream_Sql',
250 'Text_Octetstream'
252 $link_data = array(
253 'libraries/plugins/transformations/Text_Plain_Link.class.php',
254 'Text_Plain_Link',
255 'Text_Plain'
257 $this->transformation_info = array(
258 'information_schema' => array(
259 'events' => array(
260 'event_definition' => $sql_highlighting_data
262 'processlist' => array(
263 'info' => $sql_highlighting_data
265 'routines' => array(
266 'routine_definition' => $sql_highlighting_data
268 'triggers' => array(
269 'action_statement' => $sql_highlighting_data
271 'views' => array(
272 'view_definition' => $sql_highlighting_data
275 'mysql' => array(
276 'event' => array(
277 'body' => $blob_sql_highlighting_data,
278 'body_utf8' => $blob_sql_highlighting_data
280 'general_log' => array(
281 'argument' => $sql_highlighting_data
283 'help_category' => array(
284 'url' => $link_data
286 'help_topic' => array(
287 'example' => $sql_highlighting_data,
288 'url' => $link_data
290 'proc' => array(
291 'param_list' => $blob_sql_highlighting_data,
292 'returns' => $blob_sql_highlighting_data,
293 'body' => $blob_sql_highlighting_data,
294 'body_utf8' => $blob_sql_highlighting_data
296 'slow_log' => array(
297 'sql_text' => $sql_highlighting_data
302 $cfgRelation = PMA_getRelationsParam();
303 if ($cfgRelation['db']) {
304 $this->transformation_info[$cfgRelation['db']] = array();
305 $relDb = &$this->transformation_info[$cfgRelation['db']];
306 if (! empty($cfgRelation['history'])) {
307 $relDb[$cfgRelation['history']] = array(
308 'sqlquery' => $sql_highlighting_data
311 if (! empty($cfgRelation['bookmark'])) {
312 $relDb[$cfgRelation['bookmark']] = array(
313 'query' => $sql_highlighting_data
316 if (! empty($cfgRelation['tracking'])) {
317 $relDb[$cfgRelation['tracking']] = array(
318 'schema_sql' => $sql_highlighting_data,
319 'data_sql' => $sql_highlighting_data
322 if (! empty($cfgRelation['favorite'])) {
323 $relDb[$cfgRelation['favorite']] = array(
324 'tables' => $json_highlighting_data
327 if (! empty($cfgRelation['recent'])) {
328 $relDb[$cfgRelation['recent']] = array(
329 'tables' => $json_highlighting_data
332 if (! empty($cfgRelation['savedsearches'])) {
333 $relDb[$cfgRelation['savedsearches']] = array(
334 'search_data' => $json_highlighting_data
337 if (! empty($cfgRelation['designer_settings'])) {
338 $relDb[$cfgRelation['designer_settings']] = array(
339 'settings_data' => $json_highlighting_data
342 if (! empty($cfgRelation['table_uiprefs'])) {
343 $relDb[$cfgRelation['table_uiprefs']] = array(
344 'prefs' => $json_highlighting_data
347 if (! empty($cfgRelation['userconfig'])) {
348 $relDb[$cfgRelation['userconfig']] = array(
349 'config_data' => $json_highlighting_data
352 if (! empty($cfgRelation['export_templates'])) {
353 $relDb[$cfgRelation['export_templates']] = array(
354 'template_data' => $json_highlighting_data
361 * Set properties which were not initialized at the constructor
363 * @param integer $unlim_num_rows the total number of rows returned by
364 * the SQL query without any appended
365 * "LIMIT" clause programmatically
366 * @param array $fields_meta meta information about fields
367 * @param boolean $is_count statement is SELECT COUNT
368 * @param integer $is_export statement contains INTO OUTFILE
369 * @param boolean $is_func statement contains a function like SUM()
370 * @param integer $is_analyse statement contains PROCEDURE ANALYSE
371 * @param integer $num_rows total no. of rows returned by SQL query
372 * @param integer $fields_cnt total no.of fields returned by SQL query
373 * @param double $querytime time taken for execute the SQL query
374 * @param string $pmaThemeImage path for theme images directory
375 * @param string $text_dir text direction
376 * @param boolean $is_maint statement contains a maintenance command
377 * @param boolean $is_explain statement contains EXPLAIN
378 * @param boolean $is_show statement contains SHOW
379 * @param array $showtable table definitions
380 * @param string $printview print view was requested
381 * @param string $url_query URL query
382 * @param boolean $editable whether the results set is editable
383 * @param boolean $is_browse_dist whether browsing distinct values
385 * @return void
387 * @see sql.php
389 public function setProperties(
390 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
391 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
392 $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
393 $editable, $is_browse_dist
396 $this->__set('unlim_num_rows', $unlim_num_rows);
397 $this->__set('fields_meta', $fields_meta);
398 $this->__set('is_count', $is_count);
399 $this->__set('is_export', $is_export);
400 $this->__set('is_func', $is_func);
401 $this->__set('is_analyse', $is_analyse);
402 $this->__set('num_rows', $num_rows);
403 $this->__set('fields_cnt', $fields_cnt);
404 $this->__set('querytime', $querytime);
405 $this->__set('pma_theme_image', $pmaThemeImage);
406 $this->__set('text_dir', $text_dir);
407 $this->__set('is_maint', $is_maint);
408 $this->__set('is_explain', $is_explain);
409 $this->__set('is_show', $is_show);
410 $this->__set('showtable', $showtable);
411 $this->__set('printview', $printview);
412 $this->__set('url_query', $url_query);
413 $this->__set('editable', $editable);
414 $this->__set('is_browse_distinct', $is_browse_dist);
416 } // end of the 'setProperties()' function
420 * Defines the parts to display for a print view
422 * @param array $displayParts the parts to display
424 * @return array $displayParts the modified display parts
426 * @access private
429 private function _setDisplayPartsForPrintView($displayParts)
431 // set all elements to false!
432 $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
433 $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
434 $displayParts['sort_lnk'] = (string) '0';
435 $displayParts['nav_bar'] = (string) '0';
436 $displayParts['bkm_form'] = (string) '0';
437 $displayParts['text_btn'] = (string) '0';
438 $displayParts['pview_lnk'] = (string) '0';
440 return $displayParts;
444 * Defines the parts to display for a SHOW statement
446 * @param array $displayParts the parts to display
448 * @return array $displayParts the modified display parts
450 * @access private
453 private function _setDisplayPartsForShow($displayParts)
455 preg_match(
456 '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
457 . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
458 . ')@i',
459 $this->__get('sql_query'), $which
462 $bIsProcessList = isset($which[1]);
463 if ($bIsProcessList) {
464 $str = ' ' . strtoupper($which[1]);
465 $bIsProcessList = $bIsProcessList
466 && strpos($str, 'PROCESSLIST') > 0;
469 if ($bIsProcessList) {
470 // no edit link
471 $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
472 // "kill process" type edit link
473 $displayParts['del_lnk'] = self::KILL_PROCESS;
474 } else {
475 // Default case -> no links
476 // no edit link
477 $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
478 // no delete link
479 $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE;
481 // Other settings
482 $displayParts['sort_lnk'] = (string) '0';
483 $displayParts['nav_bar'] = (string) '0';
484 $displayParts['bkm_form'] = (string) '1';
485 $displayParts['text_btn'] = (string) '1';
486 $displayParts['pview_lnk'] = (string) '1';
488 return $displayParts;
492 * Defines the parts to display for statements not related to data
494 * @param array $displayParts the parts to display
496 * @return array $displayParts the modified display parts
498 * @access private
501 private function _setDisplayPartsForNonData($displayParts)
503 // Statement is a "SELECT COUNT", a
504 // "CHECK/ANALYZE/REPAIR/OPTIMIZE/CHECKSUM", an "EXPLAIN" one or
505 // contains a "PROC ANALYSE" part
506 $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
507 $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
508 $displayParts['sort_lnk'] = (string) '0';
509 $displayParts['nav_bar'] = (string) '0';
510 $displayParts['bkm_form'] = (string) '1';
512 if ($this->__get('is_maint')) {
513 $displayParts['text_btn'] = (string) '1';
514 } else {
515 $displayParts['text_btn'] = (string) '0';
517 $displayParts['pview_lnk'] = (string) '1';
519 return $displayParts;
523 * Defines the parts to display for other statements (probably SELECT)
525 * @param array $displayParts the parts to display
527 * @return array $displayParts the modified display parts
529 * @access private
532 private function _setDisplayPartsForSelect($displayParts)
534 // Other statements (ie "SELECT" ones) -> updates
535 // $displayParts['edit_lnk'], $displayParts['del_lnk'] and
536 // $displayParts['text_btn'] (keeps other default values)
538 $fields_meta = $this->__get('fields_meta');
539 $prev_table = '';
540 $displayParts['text_btn'] = (string) '1';
541 $number_of_columns = $this->__get('fields_cnt');
543 for ($i = 0; $i < $number_of_columns; $i++) {
545 $is_link = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
546 || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)
547 || ($displayParts['sort_lnk'] != '0');
549 // Displays edit/delete/sort/insert links?
550 if ($is_link
551 && $prev_table != ''
552 && $fields_meta[$i]->table != ''
553 && $fields_meta[$i]->table != $prev_table
555 // don't display links
556 $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
557 $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE;
559 * @todo May be problematic with same field names
560 * in two joined table.
562 // $displayParts['sort_lnk'] = (string) '0';
563 if ($displayParts['text_btn'] == '1') {
564 break;
566 } // end if
568 // Always display print view link
569 $displayParts['pview_lnk'] = (string) '1';
570 if ($fields_meta[$i]->table != '') {
571 $prev_table = $fields_meta[$i]->table;
573 } // end for
574 return $displayParts;
578 * Defines the parts to display for the results of a SQL query
580 * @param array $displayParts the parts to display (see a few
581 * lines above for explanations)
582 * @param integer &$the_total the total number of rows returned by the SQL
583 * query without any programmatically appended
584 * LIMIT clause
585 * (just a copy of $unlim_num_rows if it exists,
586 * elsecomputed inside this function)
588 * @return array an array with explicit indexes for all the display
589 * elements
591 * @access private
593 * @see getTable()
595 private function _setDisplayParts($displayParts, &$the_total)
597 // 1. Following variables are needed for use in isset/empty or
598 // use with array indexes or safe use in foreach
599 $db = $this->__get('db');
600 $table = $this->__get('table');
601 $unlim_num_rows = $this->__get('unlim_num_rows');
602 $num_rows = $this->__get('num_rows');
603 $printview = $this->__get('printview');
605 // 2. Updates the display parts
606 if ($printview == '1') {
607 $displayParts = $this->_setDisplayPartsForPrintView($displayParts);
609 } elseif ($this->__get('is_count') || $this->__get('is_analyse')
610 || $this->__get('is_maint') || $this->__get('is_explain')
612 $displayParts = $this->_setDisplayPartsForNonData($displayParts);
614 } elseif ($this->__get('is_show')) {
615 $displayParts = $this->_setDisplayPartsForShow($displayParts);
617 } else {
618 $displayParts = $this->_setDisplayPartsForSelect($displayParts);
619 } // end if..elseif...else
621 // 3. Gets the total number of rows if it is unknown
622 if (isset($unlim_num_rows) && $unlim_num_rows != '') {
623 $the_total = $unlim_num_rows;
624 } elseif ((($displayParts['nav_bar'] == '1')
625 || ($displayParts['sort_lnk'] == '1'))
626 && (/*overload*/mb_strlen($db) && !empty($table))
628 $the_total = $GLOBALS['dbi']->getTable($db, $table)->countRecords();
631 // if for COUNT query, number of rows returned more than 1
632 // (may be being used GROUP BY)
633 if ($this->__get('is_count') && isset($num_rows) && $num_rows > 1) {
634 $displayParts['nav_bar'] = (string) '1';
635 $displayParts['sort_lnk'] = (string) '1';
637 // 4. If navigation bar or sorting fields names URLs should be
638 // displayed but there is only one row, change these settings to
639 // false
640 if ($displayParts['nav_bar'] == '1' || $displayParts['sort_lnk'] == '1') {
642 // - Do not display sort links if less than 2 rows.
643 // - For a VIEW we (probably) did not count the number of rows
644 // so don't test this number here, it would remove the possibility
645 // of sorting VIEW results.
646 $_table = new PMA_Table($table, $db);
647 if (isset($unlim_num_rows)
648 && ($unlim_num_rows < 2)
649 && ! $_table->isView()
651 $displayParts['sort_lnk'] = (string) '0';
653 } // end if (3)
655 return $displayParts;
657 } // end of the 'setDisplayParts()' function
661 * Return true if we are executing a query in the form of
662 * "SELECT * FROM <a table> ..."
664 * @param array $analyzed_sql_results analyzed sql results
666 * @return boolean
668 * @access private
670 * @see _getTableHeaders(), _getColumnParams()
672 private function _isSelect($analyzed_sql_results)
674 return ! ($this->__get('is_count')
675 || $this->__get('is_export')
676 || $this->__get('is_func')
677 || $this->__get('is_analyse'))
678 && !empty($analyzed_sql_results['select_from'])
679 && !empty($analyzed_sql_results['statement']->from)
680 && (count($analyzed_sql_results['statement']->from) == 1)
681 && !empty($analyzed_sql_results['statement']->from[0]->table);
686 * Get a navigation button
688 * @param string $caption iconic caption for button
689 * @param string $title text for button
690 * @param integer $pos position for next query
691 * @param string $html_sql_query query ready for display
692 * @param boolean $back whether 'begin' or 'previous'
693 * @param string $onsubmit optional onsubmit clause
694 * @param string $input_for_real_end optional hidden field for special treatment
695 * @param string $onclick optional onclick clause
697 * @return string html content
699 * @access private
701 * @see _getMoveBackwardButtonsForTableNavigation(),
702 * _getMoveForwardButtonsForTableNavigation()
704 private function _getTableNavigationButton(
705 $caption, $title, $pos, $html_sql_query, $back, $onsubmit = '',
706 $input_for_real_end = '', $onclick = ''
709 $caption_output = '';
710 if ($back) {
711 if (PMA_Util::showIcons('TableNavigationLinksMode')) {
712 $caption_output .= $caption;
714 if (PMA_Util::showText('TableNavigationLinksMode')) {
715 $caption_output .= '&nbsp;' . $title;
717 } else {
718 if (PMA_Util::showText('TableNavigationLinksMode')) {
719 $caption_output .= $title;
721 if (PMA_Util::showIcons('TableNavigationLinksMode')) {
722 $caption_output .= '&nbsp;' . $caption;
725 $title_output = ' title="' . $title . '"';
727 return '<td>'
728 . '<form action="sql.php" method="post" ' . $onsubmit . '>'
729 . PMA_URL_getHiddenInputs(
730 $this->__get('db'), $this->__get('table')
732 . '<input type="hidden" name="sql_query" value="'
733 . $html_sql_query . '" />'
734 . '<input type="hidden" name="pos" value="' . $pos . '" />'
735 . '<input type="hidden" name="is_browse_distinct" value="'
736 . $this->__get('is_browse_distinct') . '" />'
737 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
738 . '" />'
739 . $input_for_real_end
740 . '<input type="submit" name="navig"'
741 . ' class="ajax" '
742 . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
743 . '</form>'
744 . '</td>';
746 } // end function _getTableNavigationButton()
750 * Possibly return a page selector for table navigation
752 * @param string $table_navigation_html the current navigation HTML
754 * @return array ($table_navigation_html, $nbTotalPage)
756 * @access private
759 private function _getHtmlPageSelector($table_navigation_html)
761 $pageNow = @floor(
762 $_SESSION['tmpval']['pos']
763 / $_SESSION['tmpval']['max_rows']
764 ) + 1;
766 $nbTotalPage = @ceil(
767 $this->__get('unlim_num_rows')
768 / $_SESSION['tmpval']['max_rows']
771 if ($nbTotalPage > 1) {
772 $table_navigation_html .= '<td>';
773 $_url_params = array(
774 'db' => $this->__get('db'),
775 'table' => $this->__get('table'),
776 'sql_query' => $this->__get('sql_query'),
777 'goto' => $this->__get('goto'),
778 'is_browse_distinct' => $this->__get('is_browse_distinct'),
781 //<form> to keep the form alignment of button < and <<
782 // and also to know what to execute when the selector changes
783 $table_navigation_html .= '<form action="sql.php'
784 . PMA_URL_getCommon($_url_params)
785 . '" method="post">';
787 $table_navigation_html .= PMA_Util::pageselector(
788 'pos',
789 $_SESSION['tmpval']['max_rows'],
790 $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
793 $table_navigation_html .= '</form>'
794 . '</td>';
796 return array($table_navigation_html, $nbTotalPage);
800 * Get a navigation bar to browse among the results of a SQL query
802 * @param integer $pos_next the offset for the "next" page
803 * @param integer $pos_prev the offset for the "previous" page
804 * @param boolean $is_innodb whether its InnoDB or not
806 * @return string html content
808 * @access private
810 * @see _getTable()
812 private function _getTableNavigation(
813 $pos_next, $pos_prev, $is_innodb
816 $table_navigation_html = '';
818 // here, using htmlentities() would cause problems if the query
819 // contains accented characters
820 $html_sql_query = htmlspecialchars($this->__get('sql_query'));
822 // Navigation bar
823 $table_navigation_html .= '<table class="navigation nospacing nopadding print_ignore">'
824 . '<tr>'
825 . '<td class="navigation_separator"></td>';
827 // Move to the beginning or to the previous page
828 if ($_SESSION['tmpval']['pos']
829 && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
832 $table_navigation_html
833 .= $this->_getMoveBackwardButtonsForTableNavigation(
834 $html_sql_query, $pos_prev
837 } // end move back
839 $nbTotalPage = 1;
840 //page redirection
841 // (unless we are showing all records)
842 if ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) {
843 list(
844 $table_navigation_html,
845 $nbTotalPage
846 ) = $this->_getHtmlPageSelector($table_navigation_html);
849 $showing_all = false;
850 if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
851 $showing_all = true;
854 // Move to the next page or to the last one
855 $endpos = $_SESSION['tmpval']['pos']
856 + $_SESSION['tmpval']['max_rows'];
858 if (($endpos < $this->__get('unlim_num_rows'))
859 && ($this->__get('num_rows') >= $_SESSION['tmpval']['max_rows'])
860 && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
863 $table_navigation_html
864 .= $this->_getMoveForwardButtonsForTableNavigation(
865 $html_sql_query, $pos_next, $is_innodb
868 } // end move toward
870 // show separator if pagination happen
871 if ($nbTotalPage > 1) {
872 $table_navigation_html
873 .= '<td><div class="navigation_separator">|</div></td>';
876 // Display the "Show all" button if allowed
877 if ($GLOBALS['cfg']['ShowAll'] || ($this->__get('unlim_num_rows') <= 500) ) {
879 $table_navigation_html .= $this->_getShowAllCheckboxForTableNavigation(
880 $showing_all, $html_sql_query
883 $table_navigation_html
884 .= '<td><div class="navigation_separator">|</div></td>';
886 } // end show all
888 $table_navigation_html .= '<td>'
889 . '<div class="save_edited hide">'
890 . '<input type="submit" value="' . __('Save edited data') . '" />'
891 . '<div class="navigation_separator">|</div>'
892 . '</div>'
893 . '</td>'
894 . '<td>'
895 . '<div class="restore_column hide">'
896 . '<input type="submit" value="' . __('Restore column order') . '" />'
897 . '<div class="navigation_separator">|</div>'
898 . '</div>'
899 . '</td>';
901 // if displaying a VIEW, $unlim_num_rows could be zero because
902 // of $cfg['MaxExactCountViews']; in this case, avoid passing
903 // the 5th parameter to checkFormElementInRange()
904 // (this means we can't validate the upper limit
905 $table_navigation_html .= '<td class="navigation_goto">';
907 $table_navigation_html .= '<form action="sql.php" method="post" '
908 . 'onsubmit="return '
909 . '(checkFormElementInRange('
910 . 'this, '
911 . '\'session_max_rows\', '
912 . '\''
913 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
914 . '\', '
915 . '1)'
916 . ' &amp;&amp; '
917 . 'checkFormElementInRange('
918 . 'this, '
919 . '\'pos\', '
920 . '\''
921 . str_replace('\'', '\\\'', __('%d is not valid row number.'))
922 . '\', '
923 . '0'
924 . (($this->__get('unlim_num_rows') > 0)
925 ? ', ' . ($this->__get('unlim_num_rows') - 1)
926 : ''
928 . ')'
929 . ')'
930 . '">';
932 $table_navigation_html .= PMA_URL_getHiddenInputs(
933 $this->__get('db'), $this->__get('table')
936 $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
937 $html_sql_query
940 $table_navigation_html .= '</form>'
941 . '</td>'
942 . '<td class="navigation_separator"></td>'
943 . '<td>'
944 . '<span>' . __('Filter rows') . ':</span>'
945 . '<input type="text" class="filter_rows"'
946 . ' placeholder="' . __('Search this table') . '"'
947 . ' data-for="' . $this->__get('unique_id') . '" />'
948 . '</td>'
949 . '<td class="navigation_separator"></td>'
950 . '</tr>'
951 . '</table>';
953 return $table_navigation_html;
955 } // end of the '_getTableNavigation()' function
959 * Prepare move backward buttons - previous and first
961 * @param string $html_sql_query the sql encoded by html special characters
962 * @param integer $pos_prev the offset for the "previous" page
964 * @return string html content
966 * @access private
968 * @see _getTableNavigation()
970 private function _getMoveBackwardButtonsForTableNavigation(
971 $html_sql_query, $pos_prev
973 return $this->_getTableNavigationButton(
974 '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query, true
976 . $this->_getTableNavigationButton(
977 '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
978 $html_sql_query, true
980 } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
984 * Prepare Show All checkbox for table navigation
986 * @param bool $showing_all whether all rows are shown currently
987 * @param string $html_sql_query the sql encoded by html special characters
989 * @return string html content
991 * @access private
993 * @see _getTableNavigation()
995 private function _getShowAllCheckboxForTableNavigation(
996 $showing_all, $html_sql_query
998 return "\n"
999 . '<td>'
1000 . '<form action="sql.php" method="post">'
1001 . PMA_URL_getHiddenInputs(
1002 $this->__get('db'), $this->__get('table')
1004 . '<input type="hidden" name="sql_query" value="'
1005 . $html_sql_query . '" />'
1006 . '<input type="hidden" name="pos" value="0" />'
1007 . '<input type="hidden" name="is_browse_distinct" value="'
1008 . $this->__get('is_browse_distinct') . '" />'
1009 . '<input type="hidden" name="session_max_rows" value="'
1010 . (! $showing_all ? 'all' : $GLOBALS['cfg']['MaxRows']) . '" />'
1011 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
1012 . '" />'
1013 . '<input type="checkbox" name="navig"'
1014 . ' id="showAll_' . $this->__get('unique_id') . '" class="showAllRows"'
1015 . (! $showing_all ? '' : ' checked="checked"') . ' value="all" />'
1016 . '<label for="showAll_' . $this->__get('unique_id') . '">'
1017 . __('Show all') . '</label>'
1018 . '</form>'
1019 . '</td>';
1020 } // end of the '_getShowAllButtonForTableNavigation()' function
1024 * Prepare move forward buttons - next and last
1026 * @param string $html_sql_query the sql encoded by htmlspecialchars()
1027 * @param integer $pos_next the offset for the "next" page
1028 * @param boolean $is_innodb whether it's InnoDB or not
1030 * @return string $buttons_html html content
1032 * @access private
1034 * @see _getTableNavigation()
1036 private function _getMoveForwardButtonsForTableNavigation(
1037 $html_sql_query, $pos_next, $is_innodb
1040 // display the Next button
1041 $buttons_html = $this->_getTableNavigationButton(
1042 '&gt;',
1043 _pgettext('Next page', 'Next'),
1044 $pos_next,
1045 $html_sql_query,
1046 false
1049 // prepare some options for the End button
1050 if ($is_innodb
1051 && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
1053 $input_for_real_end = '<input id="real_end_input" type="hidden" '
1054 . 'name="find_real_end" value="1" />';
1055 // no backquote around this message
1056 $onclick = '';
1057 } else {
1058 $input_for_real_end = $onclick = '';
1061 $maxRows = $_SESSION['tmpval']['max_rows'];
1062 $onsubmit = 'onsubmit="return '
1063 . ($_SESSION['tmpval']['pos']
1064 + $maxRows
1065 < $this->__get('unlim_num_rows')
1066 && $this->__get('num_rows') >= $maxRows)
1067 ? 'true'
1068 : 'false' . '"';
1070 // display the End button
1071 $buttons_html .= $this->_getTableNavigationButton(
1072 '&gt;&gt;',
1073 _pgettext('Last page', 'End'),
1074 @((ceil(
1075 $this->__get('unlim_num_rows')
1076 / $_SESSION['tmpval']['max_rows']
1077 )- 1) * $maxRows),
1078 $html_sql_query, false, $onsubmit, $input_for_real_end, $onclick
1081 return $buttons_html;
1083 } // end of the '_getMoveForwardButtonsForTableNavigation()' function
1087 * Prepare fields for table navigation
1088 * Number of rows
1090 * @param string $html_sql_query the sql encoded by htmlspecialchars()
1092 * @return string $additional_fields_html html content
1094 * @access private
1096 * @see _getTableNavigation()
1098 private function _getAdditionalFieldsForTableNavigation(
1099 $html_sql_query
1102 $additional_fields_html = '';
1104 $additional_fields_html .= '<input type="hidden" name="sql_query" '
1105 . 'value="' . $html_sql_query . '" />'
1106 . '<input type="hidden" name="goto" value="' . $this->__get('goto')
1107 . '" />'
1108 . '<input type="hidden" name="pos" size="3" value="'
1109 // Do not change the position when changing the number of rows
1110 . $_SESSION['tmpval']['pos'] . '" />'
1111 . '<input type="hidden" name="is_browse_distinct" value="'
1112 . $this->__get('is_browse_distinct') . '" />' ;
1114 $numberOfRowsPlaceholder = null;
1115 if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
1116 $numberOfRowsPlaceholder = __('All');
1119 $numberOfRowsChoices = array(
1120 '25' => 25,
1121 '50' => 50,
1122 '100' => 100,
1123 '250' => 250,
1124 '500' => 500
1126 $additional_fields_html .= __('Number of rows:') . ' ';
1127 $additional_fields_html .= PMA_Util::getDropdown(
1128 'session_max_rows', $numberOfRowsChoices,
1129 $_SESSION['tmpval']['max_rows'], '',
1130 'autosubmit', $numberOfRowsPlaceholder
1133 return $additional_fields_html;
1135 } // end of the '_getAdditionalFieldsForTableNavigation()' function
1139 * Get the headers of the results table, for all of the columns
1141 * @param array $displayParts which elements to display
1142 * @param array $analyzed_sql_results analyzed sql results
1143 * @param array $sort_expression sort expression
1144 * @param string $sort_expression_nodirection sort expression
1145 * without direction
1146 * @param string $sort_direction sort direction
1147 * @param boolean $is_limited_display with limited operations
1148 * or not
1149 * @param string $unsorted_sql_query query without the sort part
1151 * @return string html content
1153 * @access private
1155 * @see getTableHeaders()
1157 private function _getTableHeadersForColumns(
1158 $displayParts, $analyzed_sql_results, $sort_expression,
1159 $sort_expression_nodirection, $sort_direction, $is_limited_display,
1160 $unsorted_sql_query
1162 $html = '';
1164 // required to generate sort links that will remember whether the
1165 // "Show all" button has been clicked
1166 $sql_md5 = md5($this->__get('sql_query'));
1167 $session_max_rows = $is_limited_display
1169 : $_SESSION['tmpval']['query'][$sql_md5]['max_rows'];
1171 // Following variable are needed for use in isset/empty or
1172 // use with array indexes/safe use in the for loop
1173 $highlight_columns = $this->__get('highlight_columns');
1174 $fields_meta = $this->__get('fields_meta');
1176 // Prepare Display column comments if enabled
1177 // ($GLOBALS['cfg']['ShowBrowseComments']).
1178 $comments_map = $this->_getTableCommentsArray($analyzed_sql_results);
1180 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql_results);
1182 // optimize: avoid calling a method on each iteration
1183 $number_of_columns = $this->__get('fields_cnt');
1185 for ($j = 0; $j < $number_of_columns; $j++) {
1187 // assign $i with the appropriate column order
1188 $i = $col_order ? $col_order[$j] : $j;
1190 // See if this column should get highlight because it's used in the
1191 // where-query.
1192 $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
1193 || isset(
1194 $highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)])
1196 ? true
1197 : false;
1199 // Prepare comment-HTML-wrappers for each row, if defined/enabled.
1200 $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
1201 $display_params = $this->__get('display_params');
1203 if (($displayParts['sort_lnk'] == '1') && ! $is_limited_display) {
1205 list($order_link, $sorted_header_html)
1206 = $this->_getOrderLinkAndSortedHeaderHtml(
1207 $fields_meta[$i], $sort_expression,
1208 $sort_expression_nodirection, $i, $unsorted_sql_query,
1209 $session_max_rows, $comments,
1210 $sort_direction, $col_visib,
1211 $col_visib[$j]
1214 $html .= $sorted_header_html;
1216 $display_params['desc'][] = ' <th '
1217 . 'class="draggable'
1218 . ($condition_field ? ' condition' : '')
1219 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1220 . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
1221 } else {
1222 // Results can't be sorted
1223 $html
1224 .= $this->_getDraggableClassForNonSortableColumns(
1225 $col_visib, $col_visib[$j], $condition_field,
1226 $fields_meta[$i], $comments
1229 $display_params['desc'][] = ' <th '
1230 . 'class="draggable'
1231 . ($condition_field ? ' condition"' : '')
1232 . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
1233 . '">' . ' '
1234 . htmlspecialchars($fields_meta[$i]->name)
1235 . $comments . ' </th>';
1236 } // end else
1238 $this->__set('display_params', $display_params);
1240 } // end for
1241 return $html;
1245 * Get the headers of the results table
1247 * @param array &$displayParts which elements to display
1248 * @param array $analyzed_sql_results analyzed sql results
1249 * @param array $sort_expression sort expression
1250 * @param string $sort_expression_nodirection sort expression
1251 * without direction
1252 * @param string $sort_direction sort direction
1253 * @param boolean $is_limited_display with limited operations
1254 * or not
1256 * @return string html content
1258 * @access private
1260 * @see getTable()
1262 private function _getTableHeaders(
1263 &$displayParts, $analyzed_sql_results, $sort_expression = array(),
1264 $sort_expression_nodirection = '', $sort_direction = '',
1265 $is_limited_display = false
1268 $table_headers_html = '';
1269 // Needed for use in isset/empty or
1270 // use with array indexes/safe use in foreach
1271 $printview = $this->__get('printview');
1272 $display_params = $this->__get('display_params');
1274 // can the result be sorted?
1275 if ($displayParts['sort_lnk'] == '1') {
1277 // At this point, $sort_expression is an array but we only verify
1278 // the first element in case we could find that the table is
1279 // sorted by one of the choices listed in the
1280 // "Sort by key" drop-down
1281 list($unsorted_sql_query, $drop_down_html)
1282 = $this->_getUnsortedSqlAndSortByKeyDropDown(
1283 $analyzed_sql_results, $sort_expression[0]
1286 $table_headers_html .= $drop_down_html;
1288 } else {
1289 $unsorted_sql_query = '';
1292 // Output data needed for grid editing
1293 $table_headers_html .= '<input class="save_cells_at_once" type="hidden"'
1294 . ' value="' . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
1295 . '<div class="common_hidden_inputs">'
1296 . PMA_URL_getHiddenInputs(
1297 $this->__get('db'), $this->__get('table')
1299 . '</div>';
1301 // Output data needed for column reordering and show/hide column
1302 if ($this->_isSelect($analyzed_sql_results)) {
1303 $table_headers_html .= $this->_getDataForResettingColumnOrder();
1306 $display_params['emptypre'] = 0;
1307 $display_params['emptyafter'] = 0;
1308 $display_params['textbtn'] = '';
1309 $full_or_partial_text_link = null;
1311 $this->__set('display_params', $display_params);
1313 // Display options (if we are not in print view)
1314 if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
1316 $table_headers_html .= $this->_getOptionsBlock();
1318 // prepare full/partial text button or link
1319 $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
1322 // Start of form for multi-rows edit/delete/export
1323 $table_headers_html .= $this->_getFormForMultiRowOperations(
1324 $displayParts['del_lnk']
1327 // 1. Set $colspan and generate html with full/partial
1328 // text button or link
1329 list($colspan, $button_html)
1330 = $this->_getFieldVisibilityParams(
1331 $displayParts, $full_or_partial_text_link
1334 $table_headers_html .= $button_html;
1336 // 2. Displays the fields' name
1337 // 2.0 If sorting links should be used, checks if the query is a "JOIN"
1338 // statement (see 2.1.3)
1340 // See if we have to highlight any header fields of a WHERE query.
1341 // Uses SQL-Parser results.
1342 $this->_setHighlightedColumnGlobalField($analyzed_sql_results);
1344 // Get the headers for all of the columns
1345 $table_headers_html .= $this->_getTableHeadersForColumns(
1346 $displayParts, $analyzed_sql_results, $sort_expression,
1347 $sort_expression_nodirection, $sort_direction,
1348 $is_limited_display, $unsorted_sql_query
1351 // Display column at rightside - checkboxes or empty column
1352 if (! $printview) {
1353 $table_headers_html .= $this->_getColumnAtRightSide(
1354 $displayParts, $full_or_partial_text_link, $colspan
1357 $table_headers_html .= '</tr>' . '</thead>';
1359 return $table_headers_html;
1361 } // end of the '_getTableHeaders()' function
1365 * Prepare unsorted sql query and sort by key drop down
1367 * @param array $analyzed_sql_results analyzed sql results
1368 * @param string $sort_expression sort expression
1370 * @return array two element array - $unsorted_sql_query, $drop_down_html
1372 * @access private
1374 * @see _getTableHeaders()
1376 private function _getUnsortedSqlAndSortByKeyDropDown(
1377 $analyzed_sql_results, $sort_expression
1379 $drop_down_html = '';
1381 $unsorted_sql_query = SqlParser\Utils\Query::replaceClause(
1382 $analyzed_sql_results['statement'],
1383 $analyzed_sql_results['parser']->list,
1384 'ORDER BY',
1388 // Data is sorted by indexes only if it there is only one table.
1389 if ($this->_isSelect($analyzed_sql_results)) {
1390 // grab indexes data:
1391 $indexes = PMA_Index::getFromTable(
1392 $this->__get('table'),
1393 $this->__get('db')
1396 // do we have any index?
1397 if (! empty($indexes)) {
1398 $drop_down_html = $this->_getSortByKeyDropDown(
1399 $indexes, $sort_expression,
1400 $unsorted_sql_query
1405 return array($unsorted_sql_query, $drop_down_html);
1407 } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function
1411 * Prepare sort by key dropdown - html code segment
1413 * @param PMA_Index[] $indexes the indexes of the table for sort
1414 * criteria
1415 * @param string $sort_expression the sort expression
1416 * @param string $unsorted_sql_query the unsorted sql query
1418 * @return string $drop_down_html html content
1420 * @access private
1422 * @see _getTableHeaders()
1424 private function _getSortByKeyDropDown(
1425 $indexes, $sort_expression, $unsorted_sql_query
1428 $drop_down_html = '';
1430 $drop_down_html .= '<form action="sql.php" method="post" class="print_ignore">' . "\n"
1431 . PMA_URL_getHiddenInputs(
1432 $this->__get('db'), $this->__get('table')
1434 // to avoid calling PMA_handleSortOrder() later
1435 . PMA_getHiddenFields(array('sort_by_key' => '1'))
1436 . __('Sort by key')
1437 . ': <select name="sql_query" class="autosubmit">' . "\n";
1439 $used_index = false;
1440 $local_order = (isset($sort_expression) ? $sort_expression : '');
1442 foreach ($indexes as $index) {
1444 $asc_sort = '`'
1445 . implode('` ASC, `', array_keys($index->getColumns()))
1446 . '` ASC';
1448 $desc_sort = '`'
1449 . implode('` DESC, `', array_keys($index->getColumns()))
1450 . '` DESC';
1452 $used_index = $used_index
1453 || ($local_order == $asc_sort)
1454 || ($local_order == $desc_sort);
1456 if (preg_match(
1457 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|'
1458 . 'FOR UPDATE|LOCK IN SHARE MODE))@is',
1459 $unsorted_sql_query, $my_reg
1460 )) {
1461 $unsorted_sql_query_first_part = $my_reg[1];
1462 $unsorted_sql_query_second_part = $my_reg[2];
1463 } else {
1464 $unsorted_sql_query_first_part = $unsorted_sql_query;
1465 $unsorted_sql_query_second_part = '';
1468 $drop_down_html .= '<option value="'
1469 . htmlspecialchars(
1470 $unsorted_sql_query_first_part . "\n"
1471 . ' ORDER BY ' . $asc_sort
1472 . $unsorted_sql_query_second_part
1474 . '"' . ($local_order == $asc_sort
1475 ? ' selected="selected"'
1476 : '')
1477 . '>' . htmlspecialchars($index->getName()) . ' ('
1478 . __('Ascending') . ')</option>';
1480 $drop_down_html .= '<option value="'
1481 . htmlspecialchars(
1482 $unsorted_sql_query_first_part . "\n"
1483 . ' ORDER BY ' . $desc_sort
1484 . $unsorted_sql_query_second_part
1486 . '"' . ($local_order == $desc_sort
1487 ? ' selected="selected"'
1488 : '')
1489 . '>' . htmlspecialchars($index->getName()) . ' ('
1490 . __('Descending') . ')</option>';
1493 $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query)
1494 . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None')
1495 . '</option>'
1496 . '</select>' . "\n"
1497 . '</form>' . "\n";
1499 return $drop_down_html;
1501 } // end of the '_getSortByKeyDropDown()' function
1505 * Set column span, row span and prepare html with full/partial
1506 * text button or link
1508 * @param array &$displayParts which elements to display
1509 * @param string $full_or_partial_text_link full/partial link or text button
1511 * @return array 2 element array - $colspan, $button_html
1513 * @access private
1515 * @see _getTableHeaders()
1517 private function _getFieldVisibilityParams(
1518 &$displayParts, $full_or_partial_text_link
1521 $button_html = '';
1522 $display_params = $this->__get('display_params');
1524 // 1. Displays the full/partial text button (part 1)...
1525 $button_html .= '<thead><tr>' . "\n";
1527 $colspan = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1528 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE))
1529 ? ' colspan="4"'
1530 : '';
1532 // ... before the result table
1533 if ((($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE)
1534 && ($displayParts['del_lnk'] == self::NO_EDIT_OR_DELETE))
1535 && ($displayParts['text_btn'] == '1')
1538 $display_params['emptypre']
1539 = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1540 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1542 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1543 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1544 && ($displayParts['text_btn'] == '1')
1546 // ... at the left column of the result table header if possible
1547 // and required
1549 $display_params['emptypre']
1550 = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1551 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1553 $button_html .= '<th class="column_action print_ignore" ' . $colspan . '>'
1554 . $full_or_partial_text_link . '</th>';
1556 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
1557 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
1558 && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1559 || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE))
1561 // ... elseif no button, displays empty(ies) col(s) if required
1563 $display_params['emptypre']
1564 = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
1565 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0;
1567 $button_html .= '<td ' . $colspan . '></td>';
1569 } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)) {
1570 // ... elseif display an empty column if the actions links are
1571 // disabled to match the rest of the table
1572 $button_html .= '<th class="column_action"></th>';
1575 $this->__set('display_params', $display_params);
1577 return array($colspan, $button_html);
1579 } // end of the '_getFieldVisibilityParams()' function
1583 * Get table comments as array
1585 * @param array $analyzed_sql_results analyzed sql results
1587 * @return array $comments_map table comments
1589 * @access private
1591 * @see _getTableHeaders()
1593 private function _getTableCommentsArray($analyzed_sql_results)
1595 if ((!$GLOBALS['cfg']['ShowBrowseComments'])
1596 || (empty($analyzed_sql_results['statement']->from))
1598 return array();
1601 $ret = array();
1602 foreach ($analyzed_sql_results['statement']->from as $field) {
1603 if (empty($field->table)) {
1604 continue;
1606 $ret[$field->table] = PMA_getComments(
1607 empty($field->database) ? $this->__get('db') : $field->database,
1608 $field->table
1612 return $ret;
1614 } // end of the '_getTableCommentsArray()' function
1618 * Set global array for store highlighted header fields
1620 * @param array $analyzed_sql_results analyzed sql results
1622 * @return void
1624 * @access private
1626 * @see _getTableHeaders()
1628 private function _setHighlightedColumnGlobalField($analyzed_sql_results)
1630 $highlight_columns = array();
1632 if (!empty($analyzed_sql_results['statement']->where)) {
1633 foreach ($analyzed_sql_results['statement']->where as $expr) {
1634 foreach ($expr->identifiers as $identifier) {
1635 $highlight_columns[$identifier] = 'true';
1640 $this->__set('highlight_columns', $highlight_columns);
1642 } // end of the '_setHighlightedColumnGlobalField()' function
1646 * Prepare data for column restoring and show/hide
1648 * @return string $data_html html content
1650 * @access private
1652 * @see _getTableHeaders()
1654 private function _getDataForResettingColumnOrder()
1657 $data_html = '';
1659 // generate the column order, if it is set
1660 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
1661 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
1663 if ($col_order) {
1664 $data_html .= '<input class="col_order" type="hidden" value="'
1665 . implode(',', $col_order) . '" />';
1668 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
1670 if ($col_visib) {
1671 $data_html .= '<input class="col_visib" type="hidden" value="'
1672 . implode(',', $col_visib) . '" />';
1675 // generate table create time
1676 $table = new PMA_Table($this->__get('table'), $this->__get('db'));
1677 if (! $table->isView()) {
1678 $data_html .= '<input class="table_create_time" type="hidden" value="'
1679 . $GLOBALS['dbi']->getTable(
1680 $this->__get('db'), $this->__get('table')
1681 )->getStatusInfo('Create_time')
1682 . '" />';
1685 return $data_html;
1687 } // end of the '_getDataForResettingColumnOrder()' function
1691 * Prepare option fields block
1693 * @return string $options_html html content
1695 * @access private
1697 * @see _getTableHeaders()
1699 private function _getOptionsBlock()
1702 $options_html = '';
1704 $options_html .= '<form method="post" action="sql.php" '
1705 . 'name="displayOptionsForm"';
1707 $options_html .= ' class="ajax print_ignore" ';
1709 $options_html .= '>';
1710 $url_params = array(
1711 'db' => $this->__get('db'),
1712 'table' => $this->__get('table'),
1713 'sql_query' => $this->__get('sql_query'),
1714 'goto' => $this->__get('goto'),
1715 'display_options_form' => 1
1718 $options_html .= PMA_URL_getHiddenInputs($url_params)
1719 . '<br />'
1720 . PMA_Util::getDivForSliderEffect(
1721 '', __('Options')
1723 . '<fieldset>';
1725 $options_html .= '<div class="formelement">';
1726 $choices = array(
1727 'P' => __('Partial texts'),
1728 'F' => __('Full texts')
1731 // pftext means "partial or full texts" (done to reduce line lengths)
1732 $options_html .= PMA_Util::getRadioFields(
1733 'pftext', $choices,
1734 $_SESSION['tmpval']['pftext'],
1735 true, true, '', 'pftext_' . $this->__get('unique_id')
1737 . '</div>';
1739 if ($GLOBALS['cfgRelation']['relwork']
1740 && $GLOBALS['cfgRelation']['displaywork']
1742 $options_html .= '<div class="formelement">';
1743 $choices = array(
1744 'K' => __('Relational key'),
1745 'D' => __('Display column for relations')
1748 $options_html .= PMA_Util::getRadioFields(
1749 'relational_display', $choices,
1750 $_SESSION['tmpval']['relational_display'],
1751 true, true, '', 'relational_display_' . $this->__get('unique_id')
1753 . '</div>';
1756 $options_html .= '<div class="formelement">'
1757 . PMA_Util::getCheckbox(
1758 'display_binary', __('Show binary contents'),
1759 ! empty($_SESSION['tmpval']['display_binary']), false,
1760 'display_binary_' . $this->__get('unique_id')
1762 . '<br />'
1763 . PMA_Util::getCheckbox(
1764 'display_blob', __('Show BLOB contents'),
1765 ! empty($_SESSION['tmpval']['display_blob']), false,
1766 'display_blob_' . $this->__get('unique_id')
1768 . '</div>';
1770 // I would have preferred to name this "display_transformation".
1771 // This is the only way I found to be able to keep this setting sticky
1772 // per SQL query, and at the same time have a default that displays
1773 // the transformations.
1774 $options_html .= '<div class="formelement">'
1775 . PMA_Util::getCheckbox(
1776 'hide_transformation', __('Hide browser transformation'),
1777 ! empty($_SESSION['tmpval']['hide_transformation']), false,
1778 'hide_transformation_' . $this->__get('unique_id')
1780 . '</div>';
1782 if (! PMA_DRIZZLE) {
1783 $options_html .= '<div class="formelement">';
1784 $choices = array(
1785 'GEOM' => __('Geometry'),
1786 'WKT' => __('Well Known Text'),
1787 'WKB' => __('Well Known Binary')
1790 $options_html .= PMA_Util::getRadioFields(
1791 'geoOption', $choices,
1792 $_SESSION['tmpval']['geoOption'],
1793 true, true, '', 'geoOption_' . $this->__get('unique_id')
1795 . '</div>';
1798 $options_html .= '<div class="clearfloat"></div>'
1799 . '</fieldset>';
1801 $options_html .= '<fieldset class="tblFooters">'
1802 . '<input type="submit" value="' . __('Go') . '" />'
1803 . '</fieldset>'
1804 . '</div>'
1805 . '</form>';
1807 return $options_html;
1809 } // end of the '_getOptionsBlock()' function
1813 * Get full/partial text button or link
1815 * @return string html content
1817 * @access private
1819 * @see _getTableHeaders()
1821 private function _getFullOrPartialTextButtonOrLink()
1824 $url_params_full_text = array(
1825 'db' => $this->__get('db'),
1826 'table' => $this->__get('table'),
1827 'sql_query' => $this->__get('sql_query'),
1828 'goto' => $this->__get('goto'),
1829 'full_text_button' => 1
1832 if ($_SESSION['tmpval']['pftext'] == self::DISPLAY_FULL_TEXT) {
1833 // currently in fulltext mode so show the opposite link
1834 $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png';
1835 $tmp_txt = __('Partial texts');
1836 $url_params_full_text['pftext'] = self::DISPLAY_PARTIAL_TEXT;
1837 } else {
1838 $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png';
1839 $tmp_txt = __('Full texts');
1840 $url_params_full_text['pftext'] = self::DISPLAY_FULL_TEXT;
1843 $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="'
1844 . $tmp_txt . '" title="' . $tmp_txt . '" />';
1845 $tmp_url = 'sql.php' . PMA_URL_getCommon($url_params_full_text);
1847 return PMA_Util::linkOrButton(
1848 $tmp_url, $tmp_image, array(), false
1851 } // end of the '_getFullOrPartialTextButtonOrLink()' function
1855 * Prepare html form for multi row operations
1857 * @param string $del_lnk the delete link of current row
1859 * @return string $form_html html content
1861 * @access private
1863 * @see _getTableHeaders()
1865 private function _getFormForMultiRowOperations($del_lnk)
1868 $form_html = '';
1870 if (($del_lnk == self::DELETE_ROW) || ($del_lnk == self::KILL_PROCESS)) {
1872 $form_html .= '<form method="post" action="tbl_row_action.php" '
1873 . 'name="resultsForm"'
1874 . ' id="resultsForm_' . $this->__get('unique_id') . '"';
1876 $form_html .= ' class="ajax" ';
1878 $form_html .= '>'
1879 . PMA_URL_getHiddenInputs(
1880 $this->__get('db'), $this->__get('table'), 1
1882 . '<input type="hidden" name="goto" value="sql.php" />';
1885 $form_html .= '<table class="table_results data ajax"';
1886 $form_html .= ' data-uniqueId="' . $this->__get('unique_id') . '"';
1887 $form_html .= '>';
1889 return $form_html;
1891 } // end of the '_getFormForMultiRowOperations()' function
1895 * Get comment for row
1897 * @param array $comments_map comments array
1898 * @param array $fields_meta set of field properties
1900 * @return string $comment html content
1902 * @access private
1904 * @see _getTableHeaders()
1906 private function _getCommentForRow($comments_map, $fields_meta)
1908 $comments = '';
1909 if (isset($comments_map[$fields_meta->table])
1910 && isset($comments_map[$fields_meta->table][$fields_meta->name])
1912 $sanitized_comments = htmlspecialchars(
1913 $comments_map[$fields_meta->table][$fields_meta->name]
1916 $comments = '<span class="tblcomment" title="'
1917 . $sanitized_comments . '">';
1918 $limitChars = $GLOBALS['cfg']['LimitChars'];
1919 if (/*overload*/mb_strlen($sanitized_comments) > $limitChars) {
1920 $sanitized_comments = /*overload*/mb_substr(
1921 $sanitized_comments, 0, $limitChars
1922 ) . '…';
1924 $comments .= $sanitized_comments;
1925 $comments .= '</span>';
1927 return $comments;
1928 } // end of the '_getCommentForRow()' function
1932 * Prepare parameters and html for sorted table header fields
1934 * @param array $fields_meta set of field properties
1935 * @param array $sort_expression sort expression
1936 * @param string $sort_expression_nodirection sort expression without direction
1937 * @param integer $column_index the index of the column
1938 * @param string $unsorted_sql_query the unsorted sql query
1939 * @param integer $session_max_rows maximum rows resulted by sql
1940 * @param string $comments comment for row
1941 * @param string $sort_direction sort direction
1942 * @param boolean $col_visib column is visible(false)
1943 * array column isn't visible(string array)
1944 * @param string $col_visib_j element of $col_visib array
1946 * @return array 2 element array - $order_link, $sorted_header_html
1948 * @access private
1950 * @see _getTableHeaders()
1952 private function _getOrderLinkAndSortedHeaderHtml(
1953 $fields_meta, $sort_expression, $sort_expression_nodirection,
1954 $column_index, $unsorted_sql_query, $session_max_rows,
1955 $comments, $sort_direction, $col_visib, $col_visib_j
1958 $sorted_header_html = '';
1960 // Checks if the table name is required; it's the case
1961 // for a query with a "JOIN" statement and if the column
1962 // isn't aliased, or in queries like
1963 // SELECT `1`.`master_field` , `2`.`master_field`
1964 // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2`
1966 $sort_tbl = (isset($fields_meta->table)
1967 && /*overload*/mb_strlen($fields_meta->table)
1968 && $fields_meta->orgname == $fields_meta->name)
1969 ? PMA_Util::backquote(
1970 $fields_meta->table
1971 ) . '.'
1972 : '';
1974 $name_to_use_in_sort = $fields_meta->name;
1976 // Generates the orderby clause part of the query which is part
1977 // of URL
1978 list($single_sort_order, $multi_sort_order, $order_img)
1979 = $this->_getSingleAndMultiSortUrls(
1980 $sort_expression, $sort_expression_nodirection, $sort_tbl,
1981 $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
1984 if (preg_match(
1985 '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|'
1986 . 'LOCK IN SHARE MODE))@is',
1987 $unsorted_sql_query, $regs3
1988 )) {
1989 $single_sorted_sql_query = $regs3[1] . $single_sort_order . $regs3[2];
1990 $multi_sorted_sql_query = $regs3[1] . $multi_sort_order . $regs3[2];
1991 } else {
1992 $single_sorted_sql_query = $unsorted_sql_query . $single_sort_order;
1993 $multi_sorted_sql_query = $unsorted_sql_query . $multi_sort_order;
1996 $_single_url_params = array(
1997 'db' => $this->__get('db'),
1998 'table' => $this->__get('table'),
1999 'sql_query' => $single_sorted_sql_query,
2000 'session_max_rows' => $session_max_rows,
2001 'is_browse_distinct' => $this->__get('is_browse_distinct'),
2004 $_multi_url_params = array(
2005 'db' => $this->__get('db'),
2006 'table' => $this->__get('table'),
2007 'sql_query' => $multi_sorted_sql_query,
2008 'session_max_rows' => $session_max_rows,
2009 'is_browse_distinct' => $this->__get('is_browse_distinct'),
2011 $single_order_url = 'sql.php' . PMA_URL_getCommon($_single_url_params);
2012 $multi_order_url = 'sql.php' . PMA_URL_getCommon($_multi_url_params);
2014 // Displays the sorting URL
2015 // enable sort order swapping for image
2016 $order_link = $this->_getSortOrderLink(
2017 $order_img, $column_index,
2018 $fields_meta, $single_order_url, $multi_order_url
2021 $sorted_header_html .= $this->_getDraggableClassForSortableColumns(
2022 $col_visib, $col_visib_j,
2023 $fields_meta, $order_link, $comments
2026 return array($order_link, $sorted_header_html);
2028 } // end of the '_getOrderLinkAndSortedHeaderHtml()' function
2031 * Prepare parameters and html for sorted table header fields
2033 * @param array $sort_expression sort expression
2034 * @param string $sort_expression_nodirection sort expression without direction
2035 * @param string $sort_tbl The name of the table to which
2036 * the current column belongs to
2037 * @param string $name_to_use_in_sort The current column under
2038 * consideration
2039 * @param string $sort_direction sort direction
2040 * @param array $fields_meta set of field properties
2041 * @param integer $column_index The index number to current column
2043 * @return array 3 element array - $single_sort_order, $sort_order, $order_img
2045 * @access private
2047 * @see _getOrderLinkAndSortedHeaderHtml()
2049 private function _getSingleAndMultiSortUrls(
2050 $sort_expression, $sort_expression_nodirection, $sort_tbl,
2051 $name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
2053 $sort_order = "";
2054 // Check if the current column is in the order by clause
2055 $is_in_sort = $this->_isInSorted(
2056 $sort_expression, $sort_expression_nodirection,
2057 $sort_tbl, $name_to_use_in_sort
2059 $current_name = $name_to_use_in_sort;
2060 if ($sort_expression_nodirection[0] == '' || !$is_in_sort) {
2061 $special_index = $sort_expression_nodirection[0] == ''
2063 : count($sort_expression_nodirection);
2064 $sort_expression_nodirection[$special_index]
2065 = PMA_Util::backquote(
2066 $current_name
2068 $sort_direction[$special_index] = (preg_match(
2069 '@time|date@i',
2070 $fields_meta->type
2071 )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
2075 $sort_expression_nodirection = array_filter($sort_expression_nodirection);
2076 $single_sort_order = null;
2077 foreach ($sort_expression_nodirection as $index=>$expression) {
2078 // check if this is the first clause,
2079 // if it is then we have to add "order by"
2080 $is_first_clause = ($index == 0);
2081 $name_to_use_in_sort = $expression;
2082 $sort_tbl_new = $sort_tbl;
2083 // Test to detect if the column name is a standard name
2084 // Standard name has the table name prefixed to the column name
2085 if (/*overload*/mb_strpos($name_to_use_in_sort, '.') !== false) {
2086 $matches = explode('.', $name_to_use_in_sort);
2087 // Matches[0] has the table name
2088 // Matches[1] has the column name
2089 $name_to_use_in_sort = $matches[1];
2090 $sort_tbl_new = $matches[0];
2093 // $name_to_use_in_sort might contain a space due to
2094 // formatting of function expressions like "COUNT(name )"
2095 // so we remove the space in this situation
2096 $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort);
2097 $name_to_use_in_sort = str_replace('``', '`', $name_to_use_in_sort);
2098 $name_to_use_in_sort = trim($name_to_use_in_sort, '`');
2100 // If this the first column name in the order by clause add
2101 // order by clause to the column name
2102 $query_head = $is_first_clause ? "\nORDER BY " : "";
2103 // Again a check to see if the given column is a aggregate column
2104 if (/*overload*/mb_strpos($name_to_use_in_sort, '(') !== false) {
2105 $sort_order .= $query_head . $name_to_use_in_sort . ' ' ;
2106 } else {
2107 if (/*overload*/mb_strlen($sort_tbl_new) > 0) {
2108 $sort_tbl_new .= ".";
2110 $sort_order .= $query_head . $sort_tbl_new
2111 . PMA_Util::backquote(
2112 $name_to_use_in_sort
2113 ) . ' ' ;
2116 // For a special case where the code generates two dots between
2117 // column name and table name.
2118 $sort_order = preg_replace("/\.\./", ".", $sort_order);
2119 // Incase this is the current column save $single_sort_order
2120 if ($current_name == $name_to_use_in_sort) {
2121 if (/*overload*/mb_strpos($current_name, '(') !== false) {
2122 $single_sort_order = "\n" . 'ORDER BY ' . $current_name . ' ';
2123 } else {
2124 $single_sort_order = "\n" . 'ORDER BY ' . $sort_tbl
2125 . PMA_Util::backquote(
2126 $current_name
2127 ) . ' ';
2129 if ($is_in_sort) {
2130 list($single_sort_order, $order_img)
2131 = $this->_getSortingUrlParams(
2132 $sort_direction, $single_sort_order,
2133 $column_index, $index
2135 } else {
2136 $single_sort_order .= strtoupper($sort_direction[$index]);
2139 if ($current_name == $name_to_use_in_sort && $is_in_sort) {
2140 // We need to generate the arrow button and related html
2141 list($sort_order, $order_img) = $this->_getSortingUrlParams(
2142 $sort_direction, $sort_order, $column_index, $index
2144 $order_img .= " <small>" . ($index + 1) . "</small>";
2145 } else {
2146 $sort_order .= strtoupper($sort_direction[$index]);
2148 // Separate columns by a comma
2149 $sort_order .= ", ";
2151 unset($name_to_use_in_sort);
2153 // remove the comma from the last column name in the newly
2154 // constructed clause
2155 $sort_order = /*overload*/mb_substr(
2156 $sort_order,
2158 /*overload*/mb_strlen($sort_order)-2
2160 if (empty($order_img)) {
2161 $order_img = '';
2163 return array($single_sort_order, $sort_order, $order_img);
2167 * Check whether the column is sorted
2169 * @param array $sort_expression sort expression
2170 * @param array $sort_expression_nodirection sort expression without direction
2171 * @param string $sort_tbl the table name
2172 * @param string $name_to_use_in_sort the sorting column name
2174 * @return boolean $is_in_sort the column sorted or not
2176 * @access private
2178 * @see _getTableHeaders()
2180 private function _isInSorted(
2181 $sort_expression, $sort_expression_nodirection, $sort_tbl,
2182 $name_to_use_in_sort
2185 $index_in_expression = 0;
2187 foreach ($sort_expression_nodirection as $index => $clause) {
2188 if (/*overload*/mb_strpos($clause, '.') !== false) {
2189 $fragments = explode('.', $clause);
2190 $clause2 = $fragments[0] . "." . str_replace('`', '', $fragments[1]);
2191 } else {
2192 $clause2 = $sort_tbl . str_replace('`', '', $clause);
2194 if ($clause2 === $sort_tbl . $name_to_use_in_sort) {
2195 $index_in_expression = $index;
2196 break;
2199 if (empty($sort_expression[$index_in_expression])) {
2200 $is_in_sort = false;
2201 } else {
2202 // Field name may be preceded by a space, or any number
2203 // of characters followed by a dot (tablename.fieldname)
2204 // so do a direct comparison for the sort expression;
2205 // this avoids problems with queries like
2206 // "SELECT id, count(id)..." and clicking to sort
2207 // on id or on count(id).
2208 // Another query to test this:
2209 // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p
2210 // (and try clicking on each column's header twice)
2211 $noSortTable = empty($sort_tbl) || /*overload*/mb_strpos(
2212 $sort_expression_nodirection[$index_in_expression], $sort_tbl
2213 ) === false;
2214 $noOpenParenthesis = /*overload*/mb_strpos(
2215 $sort_expression_nodirection[$index_in_expression], '('
2216 ) === false;
2217 if (! empty($sort_tbl) && $noSortTable && $noOpenParenthesis) {
2218 $new_sort_expression_nodirection = $sort_tbl
2219 . $sort_expression_nodirection[$index_in_expression];
2220 } else {
2221 $new_sort_expression_nodirection
2222 = $sort_expression_nodirection[$index_in_expression];
2225 //Back quotes are removed in next comparison, so remove them from value
2226 //to compare.
2227 $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort);
2229 $is_in_sort = false;
2230 $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort;
2232 if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection)
2233 || $sort_name == str_replace('`', '', $sort_expression_nodirection[$index_in_expression])
2235 $is_in_sort = true;
2239 return $is_in_sort;
2241 } // end of the '_isInSorted()' function
2245 * Get sort url parameters - sort order and order image
2247 * @param array $sort_direction the sort direction
2248 * @param string $sort_order the sorting order
2249 * @param integer $column_index the index of the column
2250 * @param integer $index the index of sort direction array.
2252 * @return array 2 element array - $sort_order, $order_img
2254 * @access private
2256 * @see _getSingleAndMultiSortUrls()
2258 private function _getSortingUrlParams(
2259 $sort_direction, $sort_order, $column_index, $index
2261 if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) {
2262 $sort_order .= ' ASC';
2263 $order_img = ' ' . PMA_Util::getImage(
2264 's_desc.png', __('Descending'),
2265 array('class' => "soimg$column_index", 'title' => '')
2267 $order_img .= ' ' . PMA_Util::getImage(
2268 's_asc.png', __('Ascending'),
2269 array('class' => "soimg$column_index hide", 'title' => '')
2271 } else {
2272 $sort_order .= ' DESC';
2273 $order_img = ' ' . PMA_Util::getImage(
2274 's_asc.png', __('Ascending'),
2275 array('class' => "soimg$column_index", 'title' => '')
2277 $order_img .= ' ' . PMA_Util::getImage(
2278 's_desc.png', __('Descending'),
2279 array('class' => "soimg$column_index hide", 'title' => '')
2282 return array($sort_order, $order_img);
2283 } // end of the '_getSortingUrlParams()' function
2287 * Get sort order link
2289 * @param string $order_img the sort order image
2290 * @param integer $col_index the index of the column
2291 * @param array $fields_meta set of field properties
2292 * @param string $order_url the url for sort
2293 * @param string $multi_order_url the url for sort
2295 * @return string the sort order link
2297 * @access private
2299 * @see _getTableHeaders()
2301 private function _getSortOrderLink(
2302 $order_img, $col_index,
2303 $fields_meta, $order_url, $multi_order_url
2305 $order_link_params = array();
2306 if (isset($order_img) && ($order_img != '')) {
2307 if (/*overload*/mb_strstr($order_img, 'asc')) {
2308 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2309 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2310 } elseif (/*overload*/mb_strstr($order_img, 'desc')) {
2311 $order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
2312 $order_link_params['onmouseout'] = "$('.soimg$col_index').toggle()";
2316 $order_link_content = htmlspecialchars($fields_meta->name);
2317 $inner_link_content = $order_link_content . $order_img
2318 . '<input type="hidden" value="' . $multi_order_url . '" />';
2320 return PMA_Util::linkOrButton(
2321 $order_url, $inner_link_content,
2322 $order_link_params, false, true
2325 } // end of the '_getSortOrderLink()' function
2328 * Check if the column contains numeric data. If yes, then set the
2329 * column header's alignment right
2331 * @param array $fields_meta set of field properties
2332 * @param array &$th_class array containing classes
2334 * @return void
2336 * @see _getDraggableClassForSortableColumns()
2338 private function _getClassForNumericColumnType($fields_meta,&$th_class)
2340 if (preg_match(
2341 '@int|decimal|float|double|real|bit|boolean|serial@i',
2342 $fields_meta->type
2343 )) {
2344 $th_class[] = 'right';
2349 * Prepare columns to draggable effect for sortable columns
2351 * @param boolean $col_visib the column is visible (false)
2352 * array the column is not visible (string array)
2353 * @param string $col_visib_j element of $col_visib array
2354 * @param array $fields_meta set of field properties
2355 * @param string $order_link the order link
2356 * @param string $comments the comment for the column
2358 * @return string $draggable_html html content
2360 * @access private
2362 * @see _getTableHeaders()
2364 private function _getDraggableClassForSortableColumns(
2365 $col_visib, $col_visib_j, $fields_meta,
2366 $order_link, $comments
2369 $draggable_html = '<th';
2370 $th_class = array();
2371 $th_class[] = 'draggable';
2372 $this->_getClassForNumericColumnType($fields_meta, $th_class);
2373 if ($col_visib && !$col_visib_j) {
2374 $th_class[] = 'hide';
2377 $th_class[] = 'column_heading';
2378 if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
2379 $th_class[] = 'pointer';
2382 if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
2383 $th_class[] = 'marker';
2386 $draggable_html .= ' class="' . implode(' ', $th_class) . '"';
2388 $draggable_html .= ' data-column="' . htmlspecialchars($fields_meta->name)
2389 . '">' . $order_link . $comments . '</th>';
2391 return $draggable_html;
2393 } // end of the '_getDraggableClassForSortableColumns()' function
2397 * Prepare columns to draggable effect for non sortable columns
2399 * @param boolean $col_visib the column is visible (false)
2400 * array the column is not visible (string array)
2401 * @param string $col_visib_j element of $col_visib array
2402 * @param boolean $condition_field whether to add CSS class condition
2403 * @param array $fields_meta set of field properties
2404 * @param string $comments the comment for the column
2406 * @return string $draggable_html html content
2408 * @access private
2410 * @see _getTableHeaders()
2412 private function _getDraggableClassForNonSortableColumns(
2413 $col_visib, $col_visib_j, $condition_field,
2414 $fields_meta, $comments
2417 $draggable_html = '<th';
2418 $th_class = array();
2419 $th_class[] = 'draggable';
2420 $this->_getClassForNumericColumnType($fields_meta, $th_class);
2421 if ($col_visib && !$col_visib_j) {
2422 $th_class[] = 'hide';
2425 if ($condition_field) {
2426 $th_class[] = 'condition';
2429 $draggable_html .= ' class="' . implode(' ', $th_class) . '"';
2431 $draggable_html .= ' data-column="'
2432 . htmlspecialchars($fields_meta->name) . '">';
2434 $draggable_html .= htmlspecialchars($fields_meta->name);
2436 $draggable_html .= "\n" . $comments . '</th>';
2438 return $draggable_html;
2440 } // end of the '_getDraggableClassForNonSortableColumns()' function
2444 * Prepare column to show at right side - check boxes or empty column
2446 * @param array &$displayParts which elements to display
2447 * @param string $full_or_partial_text_link full/partial link or text button
2448 * @param string $colspan column span of table header
2450 * @return string html content
2452 * @access private
2454 * @see _getTableHeaders()
2456 private function _getColumnAtRightSide(
2457 &$displayParts, $full_or_partial_text_link, $colspan
2460 $right_column_html = '';
2461 $display_params = $this->__get('display_params');
2463 // Displays the needed checkboxes at the right
2464 // column of the result table header if possible and required...
2465 if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2466 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2467 && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2468 || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE))
2469 && ($displayParts['text_btn'] == '1')
2472 $display_params['emptyafter']
2473 = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2474 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2476 $right_column_html .= "\n"
2477 . '<th class="column_action print_ignore" ' . $colspan . '>'
2478 . $full_or_partial_text_link
2479 . '</th>';
2481 } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2482 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH))
2483 && (($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE)
2484 && ($displayParts['del_lnk'] == self::NO_EDIT_OR_DELETE))
2485 && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent'])
2487 // ... elseif no button, displays empty columns if required
2488 // (unless coming from Browse mode print view)
2490 $display_params['emptyafter']
2491 = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2492 && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1;
2494 $right_column_html .= "\n" . '<td class="print_ignore" ' . $colspan . '></td>';
2497 $this->__set('display_params', $display_params);
2499 return $right_column_html;
2501 } // end of the '_getColumnAtRightSide()' function
2505 * Prepares the display for a value
2507 * @param string $class class of table cell
2508 * @param bool $condition_field whether to add CSS class condition
2509 * @param string $value value to display
2511 * @return string the td
2513 * @access private
2515 * @see _getDataCellForGeometryColumns(),
2516 * _getDataCellForNonNumericColumns()
2518 private function _buildValueDisplay($class, $condition_field, $value)
2520 return '<td class="left ' . $class . ($condition_field ? ' condition' : '')
2521 . '">' . $value . '</td>';
2522 } // end of the '_buildValueDisplay()' function
2526 * Prepares the display for a null value
2528 * @param string $class class of table cell
2529 * @param bool $condition_field whether to add CSS class condition
2530 * @param object $meta the meta-information about this field
2531 * @param string $align cell alignment
2533 * @return string the td
2535 * @access private
2537 * @see _getDataCellForNumericColumns(),
2538 * _getDataCellForGeometryColumns(),
2539 * _getDataCellForNonNumericColumns()
2541 private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
2543 // the null class is needed for grid editing
2544 $decimals = isset($meta->decimals) ? $meta->decimals : '-1';
2545 return '<td ' . $align . ' data-decimals="' . $decimals
2546 . '" data-type="' . $meta->type . '" class="'
2547 . $this->_addClass(
2548 $class, $condition_field, $meta, ''
2550 . ' null"><i>NULL</i></td>';
2551 } // end of the '_buildNullDisplay()' function
2555 * Prepares the display for an empty value
2557 * @param string $class class of table cell
2558 * @param bool $condition_field whether to add CSS class condition
2559 * @param object $meta the meta-information about this field
2560 * @param string $align cell alignment
2562 * @return string the td
2564 * @access private
2566 * @see _getDataCellForNumericColumns(),
2567 * _getDataCellForGeometryColumns(),
2568 * _getDataCellForNonNumericColumns()
2570 private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
2572 return '<td ' . $align . ' class="'
2573 . $this->_addClass(
2574 $class, $condition_field, $meta, 'nowrap'
2576 . '"></td>';
2577 } // end of the '_buildEmptyDisplay()' function
2581 * Adds the relevant classes.
2583 * @param string $class class of table cell
2584 * @param bool $condition_field whether to add CSS class
2585 * condition
2586 * @param object $meta the meta-information about the
2587 * field
2588 * @param string $nowrap avoid wrapping
2589 * @param bool $is_field_truncated is field truncated (display ...)
2590 * @param object|string $transformation_plugin transformation plugin.
2591 * Can also be the default function:
2592 * PMA_mimeDefaultFunction
2593 * @param string $default_function default transformation function
2595 * @return string the list of classes
2597 * @access private
2599 * @see _buildNullDisplay(), _getRowData()
2601 private function _addClass(
2602 $class, $condition_field, $meta, $nowrap, $is_field_truncated = false,
2603 $transformation_plugin = '', $default_function = ''
2605 $classes = array(
2606 $class,
2607 $nowrap,
2610 if (isset($meta->mimetype)) {
2611 $classes[] = preg_replace('/\//', '_', $meta->mimetype);
2614 if ($condition_field) {
2615 $classes[] = 'condition';
2618 if ($is_field_truncated) {
2619 $classes[] = 'truncated';
2622 $mime_map = $this->__get('mime_map');
2623 $orgFullColName = $this->__get('db') . '.' . $meta->orgtable
2624 . '.' . $meta->orgname;
2625 if ($transformation_plugin != $default_function
2626 || !empty($mime_map[$orgFullColName]['input_transformation'])
2628 $classes[] = 'transformed';
2631 // Define classes to be added to this data field based on the type of data
2632 $matches = array(
2633 'enum' => 'enum',
2634 'set' => 'set',
2635 'binary' => 'hex',
2638 foreach ($matches as $key => $value) {
2639 if (/*overload*/mb_strpos($meta->flags, $key) !== false) {
2640 $classes[] = $value;
2644 if (/*overload*/mb_strpos($meta->type, 'bit') !== false) {
2645 $classes[] = 'bit';
2648 return implode(' ', $classes);
2649 } // end of the '_addClass()' function
2653 * Prepare the body of the results table
2655 * @param integer &$dt_result the link id associated to the query which results have to be displayed
2656 * which results have to be displayed
2657 * @param array &$displayParts which elements to display
2658 * @param array $map the list of relations
2659 * @param array $analyzed_sql_results analyzed sql results
2660 * @param boolean $is_limited_display with limited operations or not
2662 * @return string $table_body_html html content
2664 * @global array $row current row data
2666 * @access private
2668 * @see getTable()
2670 private function _getTableBody(
2671 &$dt_result, &$displayParts, $map, $analyzed_sql_results,
2672 $is_limited_display = false
2675 global $row; // mostly because of browser transformations,
2676 // to make the row-data accessible in a plugin
2678 $table_body_html = '';
2680 // query without conditions to shorten URLs when needed, 200 is just
2681 // guess, it should depend on remaining URL length
2682 $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql_results);
2684 $display_params = $this->__get('display_params');
2686 if (! is_array($map)) {
2687 $map = array();
2690 $row_no = 0;
2691 $display_params['edit'] = array();
2692 $display_params['copy'] = array();
2693 $display_params['delete'] = array();
2694 $display_params['data'] = array();
2695 $display_params['row_delete'] = array();
2696 $this->__set('display_params', $display_params);
2698 // name of the class added to all grid editable elements;
2699 // if we don't have all the columns of a unique key in the result set,
2700 // do not permit grid editing
2701 if ($is_limited_display || ! $this->__get('editable')) {
2702 $grid_edit_class = '';
2703 } else {
2704 switch ($GLOBALS['cfg']['GridEditing']) {
2705 case 'double-click':
2706 // trying to reduce generated HTML by using shorter
2707 // classes like click1 and click2
2708 $grid_edit_class = 'grid_edit click2';
2709 break;
2710 case 'click':
2711 $grid_edit_class = 'grid_edit click1';
2712 break;
2713 default: // 'disabled'
2714 $grid_edit_class = '';
2715 break;
2719 // prepare to get the column order, if available
2720 list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql_results);
2722 // Correction University of Virginia 19991216 in the while below
2723 // Previous code assumed that all tables have keys, specifically that
2724 // the phpMyAdmin GUI should support row delete/edit only for such
2725 // tables.
2726 // Although always using keys is arguably the prescribed way of
2727 // defining a relational table, it is not required. This will in
2728 // particular be violated by the novice.
2729 // We want to encourage phpMyAdmin usage by such novices. So the code
2730 // below has been changed to conditionally work as before when the
2731 // table being displayed has one or more keys; but to display
2732 // delete/edit options correctly for tables without keys.
2734 $odd_row = true;
2736 $whereClauseMap = $this->__get('whereClauseMap');
2737 while ($row = $GLOBALS['dbi']->fetchRow($dt_result)) {
2739 // add repeating headers
2740 if ((($row_no != 0) && ($_SESSION['tmpval']['repeat_cells'] != 0))
2741 && !($row_no % $_SESSION['tmpval']['repeat_cells'])
2743 $table_body_html .= $this->_getRepeatingHeaders(
2744 $display_params
2748 $tr_class = array();
2749 if ($GLOBALS['cfg']['BrowsePointerEnable'] != true) {
2750 $tr_class[] = 'nopointer';
2752 if ($GLOBALS['cfg']['BrowseMarkerEnable'] != true) {
2753 $tr_class[] = 'nomarker';
2755 $tr_class[] = ($odd_row ? 'odd' : 'even');
2756 $odd_row = ! $odd_row;
2758 // pointer code part
2759 $table_body_html .= '<tr class="' . implode(' ', $tr_class) . '">';
2761 // 1. Prepares the row
2763 // In print view these variable needs to be initialized
2764 $del_url = $del_str = $edit_anchor_class
2765 = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null;
2767 // 1.2 Defines the URLs for the modify/delete link(s)
2769 if (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2770 || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)
2773 // Results from a "SELECT" statement -> builds the
2774 // WHERE clause to use in links (a unique key if possible)
2776 * @todo $where_clause could be empty, for example a table
2777 * with only one field and it's a BLOB; in this case,
2778 * avoid to display the delete and edit links
2780 list($where_clause, $clause_is_unique, $condition_array)
2781 = PMA_Util::getUniqueCondition(
2782 $dt_result, // handle
2783 $this->__get('fields_cnt'), // fields_cnt
2784 $this->__get('fields_meta'), // fields_meta
2785 $row, // row
2786 false, // force_unique
2787 $this->__get('table'), // restrict_to_table
2788 $analyzed_sql_results // analyzed_sql_results
2790 $whereClauseMap[$row_no][$this->__get('table')] = $where_clause;
2791 $this->__set('whereClauseMap', $whereClauseMap);
2793 $where_clause_html = urlencode($where_clause);
2795 // 1.2.1 Modify link(s) - update row case
2796 if ($displayParts['edit_lnk'] == self::UPDATE_ROW) {
2798 list($edit_url, $copy_url, $edit_str, $copy_str,
2799 $edit_anchor_class)
2800 = $this->_getModifiedLinks(
2801 $where_clause,
2802 $clause_is_unique, $url_sql_query
2805 } // end if (1.2.1)
2807 // 1.2.2 Delete/Kill link(s)
2808 list($del_url, $del_str, $js_conf)
2809 = $this->_getDeleteAndKillLinks(
2810 $where_clause, $clause_is_unique,
2811 $url_sql_query, $displayParts['del_lnk'],
2812 $row
2815 // 1.3 Displays the links at left if required
2816 if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT)
2817 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)
2820 $table_body_html .= $this->_getPlacedLinks(
2821 self::POSITION_LEFT, $del_url, $displayParts, $row_no,
2822 $where_clause, $where_clause_html, $condition_array,
2823 $edit_url, $copy_url, $edit_anchor_class,
2824 $edit_str, $copy_str, $del_str, $js_conf
2827 } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
2829 $table_body_html .= $this->_getPlacedLinks(
2830 self::POSITION_NONE, $del_url, $displayParts, $row_no,
2831 $where_clause, $where_clause_html, $condition_array,
2832 $edit_url, $copy_url, $edit_anchor_class,
2833 $edit_str, $copy_str, $del_str, $js_conf
2836 } // end if (1.3)
2837 } // end if (1)
2839 // 2. Displays the rows' values
2840 if (is_null($this->__get('mime_map'))) {
2841 $this->_setMimeMap();
2843 $table_body_html .= $this->_getRowValues(
2844 $dt_result,
2845 $row,
2846 $row_no,
2847 $col_order,
2848 $map,
2849 $grid_edit_class,
2850 $col_visib,
2851 $url_sql_query,
2852 $analyzed_sql_results
2855 // 3. Displays the modify/delete links on the right if required
2856 if (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
2857 || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)
2859 if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT)
2860 || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)
2863 $table_body_html .= $this->_getPlacedLinks(
2864 self::POSITION_RIGHT, $del_url, $displayParts, $row_no,
2865 $where_clause, $where_clause_html, $condition_array,
2866 $edit_url, $copy_url, $edit_anchor_class,
2867 $edit_str, $copy_str, $del_str, $js_conf
2871 } // end if (3)
2873 $table_body_html .= '</tr>';
2874 $table_body_html .= "\n";
2875 $row_no++;
2877 } // end while
2879 return $table_body_html;
2881 } // end of the '_getTableBody()' function
2884 * Sets the MIME details of the columns in the results set
2886 * @return void
2888 private function _setMimeMap()
2890 $fields_meta = $this->__get('fields_meta');
2891 $mimeMap = array();
2892 $added = array();
2894 for ($currentColumn = 0;
2895 $currentColumn < $this->__get('fields_cnt');
2896 ++$currentColumn) {
2898 $meta = $fields_meta[$currentColumn];
2899 $orgFullTableName = $this->__get('db') . '.' . $meta->orgtable;
2901 if ($GLOBALS['cfgRelation']['commwork']
2902 && $GLOBALS['cfgRelation']['mimework']
2903 && $GLOBALS['cfg']['BrowseMIME']
2904 && ! $_SESSION['tmpval']['hide_transformation']
2905 && empty($added[$orgFullTableName])
2907 $mimeMap = array_merge(
2908 $mimeMap,
2909 PMA_getMIME($this->__get('db'), $meta->orgtable, false, true)
2911 $added[$orgFullTableName] = true;
2915 // special browser transformation for some SHOW statements
2916 if ($this->__get('is_show')
2917 && ! $_SESSION['tmpval']['hide_transformation']
2919 preg_match(
2920 '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
2921 . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
2922 . ')@i',
2923 $this->__get('sql_query'), $which
2926 if (isset($which[1])) {
2927 $str = ' ' . strtoupper($which[1]);
2928 $isShowProcessList = strpos($str, 'PROCESSLIST') > 0;
2929 if ($isShowProcessList) {
2930 $mimeMap['..Info'] = array(
2931 'mimetype' => 'Text_Plain',
2932 'transformation' => 'output/Text_Plain_Sql.class.php',
2936 $isShowCreateTable = preg_match(
2937 '@CREATE[[:space:]]+TABLE@i', $this->__get('sql_query')
2939 if ($isShowCreateTable) {
2940 $mimeMap['..Create Table'] = array(
2941 'mimetype' => 'Text_Plain',
2942 'transformation' => 'output/Text_Plain_Sql.class.php',
2948 $this->__set('mime_map', $mimeMap);
2953 * Get the values for one data row
2955 * @param integer &$dt_result the link id associated to the query which results have to be displayed
2956 * which results have to be displayed
2957 * @param array $row current row data
2958 * @param integer $row_no the index of current row
2959 * @param array $col_order the column order false when a property not found
2960 * false when a property not found
2961 * @param array $map the list of relations
2962 * @param string $grid_edit_class the class for all editable columns
2963 * @param boolean $col_visib column is visible(false) array column isn't visible(string array)
2964 * array column isn't visible(string array)
2965 * @param string $url_sql_query the analyzed sql query
2966 * @param array $analyzed_sql_results analyzed sql results
2968 * @return string $row_values_html html content
2970 * @access private
2972 * @see _getTableBody()
2974 private function _getRowValues(
2975 &$dt_result, $row, $row_no, $col_order, $map,
2976 $grid_edit_class, $col_visib,
2977 $url_sql_query, $analyzed_sql_results
2979 $row_values_html = '';
2981 // Following variable are needed for use in isset/empty or
2982 // use with array indexes/safe use in foreach
2983 $sql_query = $this->__get('sql_query');
2984 $fields_meta = $this->__get('fields_meta');
2985 $highlight_columns = $this->__get('highlight_columns');
2986 $mime_map = $this->__get('mime_map');
2988 $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order);
2990 $whereClauseMap = $this->__get('whereClauseMap');
2992 $columnCount = $this->__get('fields_cnt');
2993 for ($currentColumn = 0;
2994 $currentColumn < $columnCount;
2995 ++$currentColumn) {
2997 // assign $i with appropriate column order
2998 $i = $col_order ? $col_order[$currentColumn] : $currentColumn;
3000 $meta = $fields_meta[$i];
3001 $orgFullColName
3002 = $this->__get('db') . '.' . $meta->orgtable . '.' . $meta->orgname;
3004 $not_null_class = $meta->not_null ? 'not_null' : '';
3005 $relation_class = isset($map[$meta->name]) ? 'relation' : '';
3006 $hide_class = ($col_visib && ! $col_visib[$currentColumn])
3007 ? 'hide'
3008 : '';
3009 $grid_edit = $meta->orgtable != '' ? $grid_edit_class : '';
3011 // handle datetime-related class, for grid editing
3012 $field_type_class
3013 = $this->_getClassForDateTimeRelatedFields($meta->type);
3015 $is_field_truncated = false;
3016 // combine all the classes applicable to this column's value
3017 $class = $this->_getClassesForColumn(
3018 $grid_edit, $not_null_class, $relation_class,
3019 $hide_class, $field_type_class
3022 // See if this column should get highlight because it's used in the
3023 // where-query.
3024 $condition_field = (isset($highlight_columns)
3025 && (isset($highlight_columns[$meta->name])
3026 || isset($highlight_columns[PMA_Util::backquote($meta->name)])))
3027 ? true
3028 : false;
3030 // Wrap MIME-transformations. [MIME]
3031 $default_function = 'PMA_mimeDefaultFunction'; // default_function
3032 $transformation_plugin = $default_function;
3033 $transform_options = array();
3035 if ($GLOBALS['cfgRelation']['mimework']
3036 && $GLOBALS['cfg']['BrowseMIME']
3039 if (isset($mime_map[$orgFullColName]['mimetype'])
3040 && !empty($mime_map[$orgFullColName]['transformation'])
3043 $file = $mime_map[$orgFullColName]['transformation'];
3044 $include_file = 'libraries/plugins/transformations/' . $file;
3046 if (file_exists($include_file)) {
3048 include_once $include_file;
3049 $class_name = PMA_getTransformationClassName($file);
3050 // todo add $plugin_manager
3051 $plugin_manager = null;
3052 $transformation_plugin = new $class_name(
3053 $plugin_manager
3056 $transform_options = PMA_Transformation_getOptions(
3057 isset($mime_map[$orgFullColName]
3058 ['transformation_options']
3060 ? $mime_map[$orgFullColName]
3061 ['transformation_options']
3062 : ''
3065 $meta->mimetype = str_replace(
3066 '_', '/',
3067 $mime_map[$orgFullColName]['mimetype']
3070 } // end if file_exists
3071 } // end if transformation is set
3072 } // end if mime/transformation works.
3074 // Check whether the field needs to display with syntax highlighting
3076 $dbLower = /*overload*/mb_strtolower($this->__get('db'));
3077 $tblLower = /*overload*/mb_strtolower($meta->orgtable);
3078 $nameLower = /*overload*/mb_strtolower($meta->orgname);
3079 if (! empty($this->transformation_info[$dbLower][$tblLower][$nameLower])
3080 && (trim($row[$i]) != '')
3081 && ! $_SESSION['tmpval']['hide_transformation']
3083 include_once $this->transformation_info
3084 [$dbLower][$tblLower][$nameLower][0];
3085 $transformation_plugin = new $this->transformation_info
3086 [$dbLower][$tblLower][$nameLower][1](null);
3088 $transform_options = PMA_Transformation_getOptions(
3089 isset($mime_map[$orgFullColName]['transformation_options'])
3090 ? $mime_map[$orgFullColName]['transformation_options']
3091 : ''
3094 $meta->mimetype = str_replace(
3095 '_', '/',
3096 $this->transformation_info[$dbLower]
3097 [/*overload*/mb_strtolower($meta->orgtable)]
3098 [/*overload*/mb_strtolower($meta->orgname)][2]
3103 // Check for the predefined fields need to show as link in schemas
3104 include_once 'libraries/special_schema_links.lib.php';
3106 if (isset($GLOBALS['special_schema_links'])
3107 && (! empty($GLOBALS['special_schema_links'][$dbLower][$tblLower][$nameLower]))
3110 $linking_url = $this->_getSpecialLinkUrl(
3111 $row[$i], $row_info, /*overload*/mb_strtolower($meta->orgname)
3113 include_once
3114 "libraries/plugins/transformations/Text_Plain_Link.class.php";
3115 $transformation_plugin = new Text_Plain_Link();
3117 $transform_options = array(
3118 0 => $linking_url,
3119 2 => true
3122 $meta->mimetype = str_replace(
3123 '_', '/',
3124 'Text/Plain'
3130 * The result set can have columns from more than one table,
3131 * this is why we have to check for the unique conditions
3132 * related to this table; however getUniqueCondition() is
3133 * costly and does not need to be called if we already know
3134 * the conditions for the current table.
3136 if (! isset($whereClauseMap[$row_no][$meta->orgtable])) {
3137 $unique_conditions = PMA_Util::getUniqueCondition(
3138 $dt_result, // handle
3139 $this->__get('fields_cnt'), // fields_cnt
3140 $this->__get('fields_meta'), // fields_meta
3141 $row, // row
3142 false, // force_unique
3143 $meta->orgtable, // restrict_to_table
3144 $analyzed_sql_results // analyzed_sql_results
3146 $whereClauseMap[$row_no][$meta->orgtable] = $unique_conditions[0];
3149 $_url_params = array(
3150 'db' => $this->__get('db'),
3151 'table' => $meta->orgtable,
3152 'where_clause' => $whereClauseMap[$row_no][$meta->orgtable],
3153 'transform_key' => $meta->orgname
3156 if (! empty($sql_query)) {
3157 $_url_params['sql_query'] = $url_sql_query;
3160 $transform_options['wrapper_link']
3161 = PMA_URL_getCommon($_url_params);
3163 $display_params = $this->__get('display_params');
3165 // in some situations (issue 11406), numeric returns 1
3166 // even for a string type
3167 if ($meta->numeric == 1 && $meta->type != 'string') {
3168 // n u m e r i c
3170 $display_params['data'][$row_no][$i]
3171 = $this->_getDataCellForNumericColumns(
3172 $row[$i],
3173 $class,
3174 $condition_field,
3175 $meta,
3176 $map,
3177 $is_field_truncated,
3178 $analyzed_sql_results,
3179 $transformation_plugin,
3180 $default_function,
3181 $transform_options
3184 } elseif ($meta->type == self::GEOMETRY_FIELD) {
3185 // g e o m e t r y
3187 // Remove 'grid_edit' from $class as we do not allow to
3188 // inline-edit geometry data.
3189 $class = str_replace('grid_edit', '', $class);
3191 $display_params['data'][$row_no][$i]
3192 = $this->_getDataCellForGeometryColumns(
3193 $row[$i],
3194 $class,
3195 $meta,
3196 $map,
3197 $_url_params,
3198 $condition_field,
3199 $transformation_plugin,
3200 $default_function,
3201 $transform_options,
3202 $analyzed_sql_results
3205 } else {
3206 // n o t n u m e r i c
3208 $display_params['data'][$row_no][$i]
3209 = $this->_getDataCellForNonNumericColumns(
3210 $row[$i],
3211 $class,
3212 $meta,
3213 $map,
3214 $_url_params,
3215 $condition_field,
3216 $transformation_plugin,
3217 $default_function,
3218 $transform_options,
3219 $is_field_truncated,
3220 $analyzed_sql_results,
3221 $dt_result,
3227 // output stored cell
3228 $row_values_html .= $display_params['data'][$row_no][$i];
3230 if (isset($display_params['rowdata'][$i][$row_no])) {
3231 $display_params['rowdata'][$i][$row_no]
3232 .= $display_params['data'][$row_no][$i];
3233 } else {
3234 $display_params['rowdata'][$i][$row_no]
3235 = $display_params['data'][$row_no][$i];
3238 $this->__set('display_params', $display_params);
3240 } // end for
3242 return $row_values_html;
3244 } // end of the '_getRowValues()' function
3247 * Get link for display special schema links
3249 * @param string $column_value column value
3250 * @param array $row_info information about row
3251 * @param string $field_name column name
3253 * @return string generated link
3255 private function _getSpecialLinkUrl($column_value, $row_info, $field_name)
3258 $linking_url_params = array();
3259 $link_relations = $GLOBALS['special_schema_links']
3260 [/*overload*/mb_strtolower($this->__get('db'))]
3261 [/*overload*/mb_strtolower($this->__get('table'))]
3262 [$field_name];
3264 if (! is_array($link_relations['link_param'])) {
3265 $linking_url_params[$link_relations['link_param']] = $column_value;
3266 } else {
3267 // Consider only the case of creating link for column field
3268 // sql query that needs to be passed as url param
3269 $sql = 'SELECT `' . $column_value . '` FROM `'
3270 . $row_info[$link_relations['link_param'][1]] . '`.`'
3271 . $row_info[$link_relations['link_param'][2]] . '`';
3272 $linking_url_params[$link_relations['link_param'][0]] = $sql;
3275 $divider = strpos($link_relations['default_page'], '?') ? '&' : '?';
3276 if (empty($link_relations['link_dependancy_params'])) {
3277 return $link_relations['default_page']
3278 . PMA_URL_getCommon($linking_url_params, 'html', $divider);
3281 foreach ($link_relations['link_dependancy_params'] as $new_param) {
3283 // If param_info is an array, set the key and value
3284 // from that array
3285 if (is_array($new_param['param_info'])) {
3286 $linking_url_params[$new_param['param_info'][0]]
3287 = $new_param['param_info'][1];
3288 continue;
3291 $linking_url_params[$new_param['param_info']]
3292 = $row_info[/*overload*/mb_strtolower($new_param['column_name'])];
3294 // Special case 1 - when executing routines, according
3295 // to the type of the routine, url param changes
3296 if (empty($row_info['routine_type'])) {
3297 continue;
3301 return $link_relations['default_page']
3302 . PMA_URL_getCommon($linking_url_params, 'html', $divider);
3307 * Prepare row information for display special links
3309 * @param array $row current row data
3310 * @param array $col_order the column order
3312 * @return array $row_info associative array with column nama -> value
3314 private function _getRowInfoForSpecialLinks($row, $col_order)
3317 $row_info = array();
3318 $fields_meta = $this->__get('fields_meta');
3320 for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) {
3321 $m = $col_order ? $col_order[$n] : $n;
3322 $row_info[/*overload*/mb_strtolower($fields_meta[$m]->name)]
3323 = $row[$m];
3326 return $row_info;
3331 * Get url sql query without conditions to shorten URLs
3333 * @param array $analyzed_sql_results analyzed sql results
3335 * @return string $url_sql analyzed sql query
3337 * @access private
3339 * @see _getTableBody()
3341 private function _getUrlSqlQuery($analyzed_sql_results)
3343 if (($analyzed_sql_results['querytype'] != 'SELECT')
3344 || (/*overload*/mb_strlen($this->__get('sql_query')) < 200)
3346 return $this->__get('sql_query');
3349 $query = 'SELECT ' . SqlParser\Utils\Query::getClause(
3350 $analyzed_sql_results['statement'],
3351 $analyzed_sql_results['parser']->list,
3352 'SELECT'
3355 $from_clause = SqlParser\Utils\Query::getClause(
3356 $analyzed_sql_results['statement'],
3357 $analyzed_sql_results['parser']->list,
3358 'FROM'
3361 if (!empty($from_clause)) {
3362 $query .= ' FROM ' . $from_clause;
3365 return $query;
3367 } // end of the '_getUrlSqlQuery()' function
3371 * Get column order and column visibility
3373 * @param array $analyzed_sql_results analyzed sql results
3375 * @return array 2 element array - $col_order, $col_visib
3377 * @access private
3379 * @see _getTableBody()
3381 private function _getColumnParams($analyzed_sql_results)
3383 if ($this->_isSelect($analyzed_sql_results)) {
3384 $pmatable = new PMA_Table($this->__get('table'), $this->__get('db'));
3385 $col_order = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_ORDER);
3386 $col_visib = $pmatable->getUiProp(PMA_Table::PROP_COLUMN_VISIB);
3387 } else {
3388 $col_order = false;
3389 $col_visib = false;
3392 return array($col_order, $col_visib);
3393 } // end of the '_getColumnParams()' function
3397 * Get HTML for repeating headers
3399 * @param array $display_params holds various display info
3401 * @return string $header_html html content
3403 * @access private
3405 * @see _getTableBody()
3407 private function _getRepeatingHeaders(
3408 $display_params
3410 $header_html = '<tr>' . "\n";
3412 if ($display_params['emptypre'] > 0) {
3414 $header_html .= ' <th colspan="'
3415 . $display_params['emptypre'] . '">'
3416 . "\n" . ' &nbsp;</th>' . "\n";
3418 } else if ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) {
3419 $header_html .= ' <th></th>' . "\n";
3422 foreach ($display_params['desc'] as $val) {
3423 $header_html .= $val;
3426 if ($display_params['emptyafter'] > 0) {
3427 $header_html
3428 .= ' <th colspan="' . $display_params['emptyafter']
3429 . '">'
3430 . "\n" . ' &nbsp;</th>' . "\n";
3432 $header_html .= '</tr>' . "\n";
3434 return $header_html;
3436 } // end of the '_getRepeatingHeaders()' function
3440 * Get modified links
3442 * @param string $where_clause the where clause of the sql
3443 * @param boolean $clause_is_unique the unique condition of clause
3444 * @param string $url_sql_query the analyzed sql query
3446 * @return array 5 element array - $edit_url, $copy_url,
3447 * $edit_str, $copy_str, $edit_anchor_class
3449 * @access private
3451 * @see _getTableBody()
3453 private function _getModifiedLinks(
3454 $where_clause, $clause_is_unique, $url_sql_query
3457 $_url_params = array(
3458 'db' => $this->__get('db'),
3459 'table' => $this->__get('table'),
3460 'where_clause' => $where_clause,
3461 'clause_is_unique' => $clause_is_unique,
3462 'sql_query' => $url_sql_query,
3463 'goto' => 'sql.php',
3466 $edit_url = 'tbl_change.php'
3467 . PMA_URL_getCommon(
3468 $_url_params + array('default_action' => 'update')
3471 $copy_url = 'tbl_change.php'
3472 . PMA_URL_getCommon(
3473 $_url_params + array('default_action' => 'insert')
3476 $edit_str = $this->_getActionLinkContent(
3477 'b_edit.png', __('Edit')
3479 $copy_str = $this->_getActionLinkContent(
3480 'b_insrow.png', __('Copy')
3483 // Class definitions required for grid editing jQuery scripts
3484 $edit_anchor_class = "edit_row_anchor";
3485 if ($clause_is_unique == 0) {
3486 $edit_anchor_class .= ' nonunique';
3489 return array($edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class);
3491 } // end of the '_getModifiedLinks()' function
3495 * Get delete and kill links
3497 * @param string $where_clause the where clause of the sql
3498 * @param boolean $clause_is_unique the unique condition of clause
3499 * @param string $url_sql_query the analyzed sql query
3500 * @param string $del_lnk the delete link of current row
3501 * @param array $row the current row
3503 * @return array 3 element array
3504 * $del_url, $del_str, $js_conf
3506 * @access private
3508 * @see _getTableBody()
3510 private function _getDeleteAndKillLinks(
3511 $where_clause, $clause_is_unique, $url_sql_query, $del_lnk, $row
3514 $goto = $this->__get('goto');
3516 if ($del_lnk == self::DELETE_ROW) { // delete row case
3518 $_url_params = array(
3519 'db' => $this->__get('db'),
3520 'table' => $this->__get('table'),
3521 'sql_query' => $url_sql_query,
3522 'message_to_show' => __('The row has been deleted.'),
3523 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto),
3526 $lnk_goto = 'sql.php' . PMA_URL_getCommon($_url_params, 'text');
3528 $del_query = 'DELETE FROM '
3529 . PMA_Util::backquote($this->__get('table'))
3530 . ' WHERE ' . $where_clause .
3531 ($clause_is_unique ? '' : ' LIMIT 1');
3533 $_url_params = array(
3534 'db' => $this->__get('db'),
3535 'table' => $this->__get('table'),
3536 'sql_query' => $del_query,
3537 'message_to_show' => __('The row has been deleted.'),
3538 'goto' => $lnk_goto,
3540 $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
3542 $js_conf = 'DELETE FROM ' . PMA_jsFormat($this->__get('table'))
3543 . ' WHERE ' . PMA_jsFormat($where_clause, false)
3544 . ($clause_is_unique ? '' : ' LIMIT 1');
3546 $del_str = $this->_getActionLinkContent('b_drop.png', __('Delete'));
3548 } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case
3550 $_url_params = array(
3551 'db' => $this->__get('db'),
3552 'table' => $this->__get('table'),
3553 'sql_query' => $url_sql_query,
3554 'goto' => 'index.php',
3557 $lnk_goto = 'sql.php'
3558 . PMA_URL_getCommon(
3559 $_url_params, 'text'
3562 $kill = $GLOBALS['dbi']->getKillQuery($row[0]);
3564 $_url_params = array(
3565 'db' => 'mysql',
3566 'sql_query' => $kill,
3567 'goto' => $lnk_goto,
3570 $del_url = 'sql.php' . PMA_URL_getCommon($_url_params);
3571 $js_conf = $kill;
3572 $del_str = PMA_Util::getIcon(
3573 'b_drop.png', __('Kill')
3575 } else {
3576 $del_url = $del_str = $js_conf = null;
3579 return array($del_url, $del_str, $js_conf);
3581 } // end of the '_getDeleteAndKillLinks()' function
3585 * Get content inside the table row action links (Edit/Copy/Delete)
3587 * @param string $icon The name of the file to get
3588 * @param string $display_text The text displaying after the image icon
3590 * @return string
3592 * @access private
3594 * @see _getModifiedLinks(), _getDeleteAndKillLinks()
3596 private function _getActionLinkContent($icon, $display_text)
3599 $linkContent = '';
3601 if (isset($GLOBALS['cfg']['RowActionType'])
3602 && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_ICONS
3605 $linkContent .= '<span class="nowrap">'
3606 . PMA_Util::getImage(
3607 $icon, $display_text
3609 . '</span>';
3611 } else if (isset($GLOBALS['cfg']['RowActionType'])
3612 && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_TEXT
3615 $linkContent .= '<span class="nowrap">' . $display_text . '</span>';
3617 } else {
3619 $linkContent .= PMA_Util::getIcon(
3620 $icon, $display_text
3625 return $linkContent;
3631 * Prepare placed links
3633 * @param string $dir the direction of links should place
3634 * @param string $del_url the url for delete row
3635 * @param array $displayParts which elements to display
3636 * @param integer $row_no the index of current row
3637 * @param string $where_clause the where clause of the sql
3638 * @param string $where_clause_html the html encoded where clause
3639 * @param array $condition_array array of keys (primary, unique, condition)
3640 * @param string $edit_url the url for edit row
3641 * @param string $copy_url the url for copy row
3642 * @param string $edit_anchor_class the class for html element for edit
3643 * @param string $edit_str the label for edit row
3644 * @param string $copy_str the label for copy row
3645 * @param string $del_str the label for delete row
3646 * @param string $js_conf text for the JS confirmation
3648 * @return string html content
3650 * @access private
3652 * @see _getTableBody()
3654 private function _getPlacedLinks(
3655 $dir, $del_url, $displayParts, $row_no, $where_clause, $where_clause_html,
3656 $condition_array, $edit_url, $copy_url,
3657 $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf
3660 if (! isset($js_conf)) {
3661 $js_conf = '';
3664 return $this->_getCheckboxAndLinks(
3665 $dir, $del_url, $displayParts,
3666 $row_no, $where_clause, $where_clause_html, $condition_array,
3667 $edit_url, $copy_url, $edit_anchor_class,
3668 $edit_str, $copy_str, $del_str, $js_conf
3671 } // end of the '_getPlacedLinks()' function
3675 * Get the combined classes for a column
3677 * @param string $grid_edit_class the class for all editable columns
3678 * @param string $not_null_class the class for not null columns
3679 * @param string $relation_class the class for relations in a column
3680 * @param string $hide_class the class for visibility of a column
3681 * @param string $field_type_class the class related to type of the field
3683 * @return string $class the combined classes
3685 * @access private
3687 * @see _getTableBody()
3689 private function _getClassesForColumn(
3690 $grid_edit_class, $not_null_class, $relation_class,
3691 $hide_class, $field_type_class
3693 $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' '
3694 . $relation_class . ' ' . $hide_class . ' ' . $field_type_class;
3696 return $class;
3698 } // end of the '_getClassesForColumn()' function
3702 * Get class for datetime related fields
3704 * @param string $type the type of the column field
3706 * @return string $field_type_class the class for the column
3708 * @access private
3710 * @see _getTableBody()
3712 private function _getClassForDateTimeRelatedFields($type)
3714 if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD)
3715 || ($type == self::DATETIME_FIELD)
3717 $field_type_class = 'datetimefield';
3718 } elseif ($type == self::DATE_FIELD) {
3719 $field_type_class = 'datefield';
3720 } elseif ($type == self::TIME_FIELD) {
3721 $field_type_class = 'timefield';
3722 } elseif ($type == self::STRING_FIELD) {
3723 $field_type_class = 'text';
3724 } else {
3725 $field_type_class = '';
3727 return $field_type_class;
3728 } // end of the '_getClassForDateTimeRelatedFields()' function
3732 * Prepare data cell for numeric type fields
3734 * @param string $column the column's value
3735 * @param string $class the html class for column
3736 * @param boolean $condition_field the column should highlighted
3737 * or not
3738 * @param object $meta the meta-information about this
3739 * field
3740 * @param array $map the list of relations
3741 * @param boolean $is_field_truncated the condition for blob data
3742 * replacements
3743 * @param array $analyzed_sql_results the analyzed query
3744 * @param object|string $transformation_plugin the name of transformation plugin
3745 * @param string $default_function the default transformation
3746 * function
3747 * @param string $transform_options the transformation parameters
3749 * @return string $cell the prepared cell, html content
3751 * @access private
3753 * @see _getTableBody()
3755 private function _getDataCellForNumericColumns(
3756 $column, $class, $condition_field, $meta, $map, $is_field_truncated,
3757 $analyzed_sql_results, $transformation_plugin, $default_function,
3758 $transform_options
3761 if (! isset($column) || is_null($column)) {
3763 $cell = $this->_buildNullDisplay(
3764 'right ' . $class, $condition_field, $meta, ''
3767 } elseif ($column != '') {
3769 $nowrap = ' nowrap';
3770 $where_comparison = ' = ' . $column;
3772 $cell = $this->_getRowData(
3773 'right ' . $class, $condition_field,
3774 $analyzed_sql_results, $meta, $map, $column,
3775 $transformation_plugin, $default_function, $nowrap,
3776 $where_comparison, $transform_options,
3777 $is_field_truncated, ''
3779 } else {
3781 $cell = $this->_buildEmptyDisplay(
3782 'right ' . $class, $condition_field, $meta, ''
3786 return $cell;
3788 } // end of the '_getDataCellForNumericColumns()' function
3792 * Get data cell for geometry type fields
3794 * @param string $column the relevant column in data row
3795 * @param string $class the html class for column
3796 * @param object $meta the meta-information about
3797 * this field
3798 * @param array $map the list of relations
3799 * @param array $_url_params the parameters for generate url
3800 * @param boolean $condition_field the column should highlighted
3801 * or not
3802 * @param object|string $transformation_plugin the name of transformation
3803 * function
3804 * @param string $default_function the default transformation
3805 * function
3806 * @param string $transform_options the transformation parameters
3807 * @param array $analyzed_sql_results the analyzed query
3809 * @return string $cell the prepared data cell, html content
3811 * @access private
3813 * @see _getTableBody()
3815 private function _getDataCellForGeometryColumns(
3816 $column, $class, $meta, $map, $_url_params, $condition_field,
3817 $transformation_plugin, $default_function, $transform_options,
3818 $analyzed_sql_results
3820 if (! isset($column) || is_null($column)) {
3821 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3822 return $cell;
3825 if ($column == '') {
3826 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3827 return $cell;
3830 // Display as [GEOMETRY - (size)]
3831 if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) {
3832 $geometry_text = $this->_handleNonPrintableContents(
3833 strtoupper(self::GEOMETRY_FIELD), $column, $transformation_plugin,
3834 $transform_options, $default_function, $meta, $_url_params
3837 $cell = $this->_buildValueDisplay(
3838 $class, $condition_field, $geometry_text
3840 return $cell;
3843 if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_WKT) {
3844 // Prepare in Well Known Text(WKT) format.
3845 $where_comparison = ' = ' . $column;
3847 // Convert to WKT format
3848 $wktval = PMA_Util::asWKT($column);
3849 list(
3850 $is_field_truncated,
3851 $wktval,
3852 // skip 3rd param
3853 ) = $this->_getPartialText($wktval);
3855 $cell = $this->_getRowData(
3856 $class, $condition_field, $analyzed_sql_results, $meta, $map,
3857 $wktval, $transformation_plugin, $default_function, '',
3858 $where_comparison, $transform_options,
3859 $is_field_truncated, ''
3861 return $cell;
3864 // Prepare in Well Known Binary (WKB) format.
3866 if ($_SESSION['tmpval']['display_binary']) {
3867 $where_comparison = ' = ' . $column;
3869 $wkbval = substr(bin2hex($column), 8);
3870 list(
3871 $is_field_truncated,
3872 $wkbval,
3873 // skip 3rd param
3874 ) = $this->_getPartialText($wkbval);
3876 $cell = $this->_getRowData(
3877 $class, $condition_field,
3878 $analyzed_sql_results, $meta, $map, $wkbval,
3879 $transformation_plugin, $default_function, '',
3880 $where_comparison, $transform_options,
3881 $is_field_truncated, ''
3883 return $cell;
3886 $wkbval = $this->_handleNonPrintableContents(
3887 self::BINARY_FIELD, $column, $transformation_plugin,
3888 $transform_options, $default_function, $meta,
3889 $_url_params
3892 $cell = $this->_buildValueDisplay(
3893 $class, $condition_field, $wkbval
3896 return $cell;
3898 } // end of the '_getDataCellForGeometryColumns()' function
3902 * Get data cell for non numeric type fields
3904 * @param string $column the relevant column in data row
3905 * @param string $class the html class for column
3906 * @param object $meta the meta-information about
3907 * the field
3908 * @param array $map the list of relations
3909 * @param array $_url_params the parameters for generate
3910 * url
3911 * @param boolean $condition_field the column should highlighted
3912 * or not
3913 * @param object|string $transformation_plugin the name of transformation
3914 * function
3915 * @param string $default_function the default transformation
3916 * function
3917 * @param string $transform_options the transformation parameters
3918 * @param boolean $is_field_truncated is data truncated due to
3919 * LimitChars
3920 * @param array $analyzed_sql_results the analyzed query
3921 * @param integer &$dt_result the link id associated to
3922 * the query which results
3923 * have to be displayed
3924 * @param integer $col_index the column index
3926 * @return string $cell the prepared data cell, html content
3928 * @access private
3930 * @see _getTableBody()
3932 private function _getDataCellForNonNumericColumns(
3933 $column, $class, $meta, $map, $_url_params, $condition_field,
3934 $transformation_plugin, $default_function, $transform_options,
3935 $is_field_truncated, $analyzed_sql_results, &$dt_result, $col_index
3937 $original_length = 0;
3939 $is_analyse = $this->__get('is_analyse');
3940 $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index);
3942 $bIsText = gettype($transformation_plugin) === 'object'
3943 && strpos($transformation_plugin->getMIMEtype(), 'Text')
3944 === false;
3946 // disable inline grid editing
3947 // if binary fields are protected
3948 // or transformation plugin is of non text type
3949 // such as image
3950 if ((stristr($field_flags, self::BINARY_FIELD)
3951 && ($GLOBALS['cfg']['ProtectBinary'] === 'all'
3952 || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob'
3953 && !stristr($meta->type, self::BLOB_FIELD))
3954 || ($GLOBALS['cfg']['ProtectBinary'] === 'blob'
3955 && stristr($meta->type, self::BLOB_FIELD))))
3956 || $bIsText
3958 $class = str_replace('grid_edit', '', $class);
3961 if (! isset($column) || is_null($column)) {
3962 $cell = $this->_buildNullDisplay($class, $condition_field, $meta);
3963 return $cell;
3966 if ($column == '') {
3967 $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
3968 return $cell;
3971 // Cut all fields to $GLOBALS['cfg']['LimitChars']
3972 // (unless it's a link-type transformation or binary)
3973 if (!(gettype($transformation_plugin) === "object"
3974 && strpos($transformation_plugin->getName(), 'Link') !== false)
3975 && !stristr($field_flags, self::BINARY_FIELD)
3977 list(
3978 $is_field_truncated,
3979 $column,
3980 $original_length
3981 ) = $this->_getPartialText($column);
3984 $formatted = false;
3985 if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
3987 $column = PMA_Util::printableBitValue(
3988 $column, $meta->length
3991 // some results of PROCEDURE ANALYSE() are reported as
3992 // being BINARY but they are quite readable,
3993 // so don't treat them as BINARY
3994 } elseif (stristr($field_flags, self::BINARY_FIELD)
3995 && !(isset($is_analyse) && $is_analyse)
3997 // we show the BINARY or BLOB message and field's size
3998 // (or maybe use a transformation)
3999 $binary_or_blob = self::BLOB_FIELD;
4000 if ($meta->type === self::STRING_FIELD) {
4001 $binary_or_blob = self::BINARY_FIELD;
4003 $column = $this->_handleNonPrintableContents(
4004 $binary_or_blob, $column, $transformation_plugin,
4005 $transform_options, $default_function,
4006 $meta, $_url_params, $is_field_truncated
4008 $class = $this->_addClass(
4009 $class, $condition_field, $meta, '',
4010 $is_field_truncated, $transformation_plugin, $default_function
4012 $result = strip_tags($column);
4013 // disable inline grid editing
4014 // if binary or blob data is not shown
4015 if (stristr($result, $binary_or_blob)) {
4016 $class = str_replace('grid_edit', '', $class);
4018 $formatted = true;
4021 if ($formatted) {
4022 $cell = $this->_buildValueDisplay(
4023 $class, $condition_field, $column
4025 return $cell;
4028 // transform functions may enable no-wrapping:
4029 $function_nowrap = 'applyTransformationNoWrap';
4031 $bool_nowrap = (($default_function != $transformation_plugin)
4032 && function_exists($transformation_plugin->$function_nowrap()))
4033 ? $transformation_plugin->$function_nowrap($transform_options)
4034 : false;
4036 // do not wrap if date field type
4037 $nowrap = (preg_match('@DATE|TIME@i', $meta->type)
4038 || $bool_nowrap) ? ' nowrap' : '';
4040 $where_comparison = ' = \''
4041 . PMA_Util::sqlAddSlashes($column)
4042 . '\'';
4044 $cell = $this->_getRowData(
4045 $class, $condition_field,
4046 $analyzed_sql_results, $meta, $map, $column,
4047 $transformation_plugin, $default_function, $nowrap,
4048 $where_comparison, $transform_options,
4049 $is_field_truncated, $original_length
4052 return $cell;
4054 } // end of the '_getDataCellForNonNumericColumns()' function
4057 * Checks the posted options for viewing query results
4058 * and sets appropriate values in the session.
4060 * @todo make maximum remembered queries configurable
4061 * @todo move/split into SQL class!?
4062 * @todo currently this is called twice unnecessary
4063 * @todo ignore LIMIT and ORDER in query!?
4065 * @return void
4067 * @access public
4069 * @see sql.php file
4071 public function setConfigParamsForDisplayTable()
4074 $sql_md5 = md5($this->__get('sql_query'));
4075 $query = array();
4076 if (isset($_SESSION['tmpval']['query'][$sql_md5])) {
4077 $query = $_SESSION['tmpval']['query'][$sql_md5];
4080 $query['sql'] = $this->__get('sql_query');
4082 if (empty($query['repeat_cells'])) {
4083 $query['repeat_cells'] = $GLOBALS['cfg']['RepeatCells'];
4086 // as this is a form value, the type is always string so we cannot
4087 // use PMA_isValid($_REQUEST['session_max_rows'], 'integer')
4088 if (PMA_isValid($_REQUEST['session_max_rows'], 'numeric')) {
4089 $query['max_rows'] = (int)$_REQUEST['session_max_rows'];
4090 unset($_REQUEST['session_max_rows']);
4091 } elseif ($_REQUEST['session_max_rows'] == self::ALL_ROWS) {
4092 $query['max_rows'] = self::ALL_ROWS;
4093 unset($_REQUEST['session_max_rows']);
4094 } elseif (empty($query['max_rows'])) {
4095 $query['max_rows'] = $GLOBALS['cfg']['MaxRows'];
4098 if (PMA_isValid($_REQUEST['pos'], 'numeric')) {
4099 $query['pos'] = $_REQUEST['pos'];
4100 unset($_REQUEST['pos']);
4101 } elseif (empty($query['pos'])) {
4102 $query['pos'] = 0;
4105 if (PMA_isValid(
4106 $_REQUEST['pftext'],
4107 array(
4108 self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT
4112 $query['pftext'] = $_REQUEST['pftext'];
4113 unset($_REQUEST['pftext']);
4114 } elseif (empty($query['pftext'])) {
4115 $query['pftext'] = self::DISPLAY_PARTIAL_TEXT;
4118 if (PMA_isValid(
4119 $_REQUEST['relational_display'],
4120 array(
4121 self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN
4125 $query['relational_display'] = $_REQUEST['relational_display'];
4126 unset($_REQUEST['relational_display']);
4127 } elseif (empty($query['relational_display'])) {
4128 // The current session value has priority over a
4129 // change via Settings; this change will be apparent
4130 // starting from the next session
4131 $query['relational_display'] = $GLOBALS['cfg']['RelationalDisplay'];
4134 if (PMA_isValid(
4135 $_REQUEST['geoOption'],
4136 array(
4137 self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB,
4138 self::GEOMETRY_DISP_GEOM
4142 $query['geoOption'] = $_REQUEST['geoOption'];
4143 unset($_REQUEST['geoOption']);
4144 } elseif (empty($query['geoOption'])) {
4145 $query['geoOption'] = self::GEOMETRY_DISP_GEOM;
4148 if (isset($_REQUEST['display_binary'])) {
4149 $query['display_binary'] = true;
4150 unset($_REQUEST['display_binary']);
4151 } elseif (isset($_REQUEST['display_options_form'])) {
4152 // we know that the checkbox was unchecked
4153 unset($query['display_binary']);
4154 } elseif (isset($_REQUEST['full_text_button'])) {
4155 // do nothing to keep the value that is there in the session
4156 } else {
4157 // selected by default because some operations like OPTIMIZE TABLE
4158 // and all queries involving functions return "binary" contents,
4159 // according to low-level field flags
4160 $query['display_binary'] = true;
4163 if (isset($_REQUEST['display_blob'])) {
4164 $query['display_blob'] = true;
4165 unset($_REQUEST['display_blob']);
4166 } elseif (isset($_REQUEST['display_options_form'])) {
4167 // we know that the checkbox was unchecked
4168 unset($query['display_blob']);
4171 if (isset($_REQUEST['hide_transformation'])) {
4172 $query['hide_transformation'] = true;
4173 unset($_REQUEST['hide_transformation']);
4174 } elseif (isset($_REQUEST['display_options_form'])) {
4175 // we know that the checkbox was unchecked
4176 unset($query['hide_transformation']);
4179 // move current query to the last position, to be removed last
4180 // so only least executed query will be removed if maximum remembered
4181 // queries limit is reached
4182 unset($_SESSION['tmpval']['query'][$sql_md5]);
4183 $_SESSION['tmpval']['query'][$sql_md5] = $query;
4185 // do not exceed a maximum number of queries to remember
4186 if (count($_SESSION['tmpval']['query']) > 10) {
4187 array_shift($_SESSION['tmpval']['query']);
4188 //echo 'deleting one element ...';
4191 // populate query configuration
4192 $_SESSION['tmpval']['pftext']
4193 = $query['pftext'];
4194 $_SESSION['tmpval']['relational_display']
4195 = $query['relational_display'];
4196 $_SESSION['tmpval']['geoOption']
4197 = $query['geoOption'];
4198 $_SESSION['tmpval']['display_binary'] = isset(
4199 $query['display_binary']
4201 $_SESSION['tmpval']['display_blob'] = isset(
4202 $query['display_blob']
4204 $_SESSION['tmpval']['hide_transformation'] = isset(
4205 $query['hide_transformation']
4207 $_SESSION['tmpval']['pos']
4208 = $query['pos'];
4209 $_SESSION['tmpval']['max_rows']
4210 = $query['max_rows'];
4211 $_SESSION['tmpval']['repeat_cells']
4212 = $query['repeat_cells'];
4216 * Prepare a table of results returned by a SQL query.
4218 * @param integer &$dt_result the link id associated to the query
4219 * which results have to be displayed
4220 * @param array &$displayParts the parts to display
4221 * @param array $analyzed_sql_results analyzed sql results
4222 * @param boolean $is_limited_display With limited operations or not
4224 * @return string $table_html Generated HTML content for resulted table
4226 * @access public
4228 * @see sql.php file
4230 public function getTable(
4231 &$dt_result, &$displayParts, $analyzed_sql_results,
4232 $is_limited_display = false
4236 * The statement this table is built for.
4237 * @var SqlParser\Statements\SelectStatement
4239 $statement = $analyzed_sql_results['statement'];
4241 $table_html = '';
4242 // Following variable are needed for use in isset/empty or
4243 // use with array indexes/safe use in foreach
4244 $fields_meta = $this->__get('fields_meta');
4245 $showtable = $this->__get('showtable');
4246 $printview = $this->__get('printview');
4248 // why was this called here? (already called from sql.php)
4249 //$this->setConfigParamsForDisplayTable();
4252 * @todo move this to a central place
4253 * @todo for other future table types
4255 $is_innodb = (isset($showtable['Type'])
4256 && $showtable['Type'] == self::TABLE_TYPE_INNO_DB);
4258 if ($is_innodb
4259 && PMA_isJustBrowsing($analyzed_sql_results, true)
4261 // "j u s t b r o w s i n g"
4262 $pre_count = '~';
4263 $after_count = PMA_Util::showHint(
4264 PMA_sanitize(
4265 __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc].')
4268 } else {
4269 $pre_count = '';
4270 $after_count = '';
4273 // 1. ----- Prepares the work -----
4275 // 1.1 Gets the information about which functionalities should be
4276 // displayed
4277 $total = '';
4278 $displayParts = $this->_setDisplayParts($displayParts, $total);
4280 // 1.2 Defines offsets for the next and previous pages
4281 if ($displayParts['nav_bar'] == '1') {
4282 list($pos_next, $pos_prev) = $this->_getOffsets();
4283 } // end if
4285 // 1.3 Extract sorting expressions.
4286 // we need $sort_expression and $sort_expression_nodirection
4287 // even if there are many table references
4288 $sort_expression = array();
4289 $sort_expression_nodirection = array();
4290 $sort_direction = array();
4292 if (!empty($statement->order)) {
4293 foreach ($statement->order as $o) {
4294 $sort_expression[] = $o->expr->expr . ' ' . $o->type;
4295 $sort_expression_nodirection[] = $o->expr->expr;
4296 $sort_direction[] = $o->type;
4298 } else {
4299 $sort_expression[] = '';
4300 $sort_expression_nodirection[] = '';
4301 $sort_direction[] = '';
4304 $number_of_columns = count($sort_expression_nodirection);
4306 // 1.4 Prepares display of first and last value of the sorted column
4307 $sorted_column_message = '';
4308 for ( $i = 0; $i < $number_of_columns; $i++ ) {
4309 $sorted_column_message .= $this->_getSortedColumnMessage(
4310 $dt_result, $sort_expression_nodirection[$i]
4314 // 2. ----- Prepare to display the top of the page -----
4316 // 2.1 Prepares a messages with position information
4317 if (($displayParts['nav_bar'] == '1') && isset($pos_next)) {
4319 $message = $this->_setMessageInformation(
4320 $sorted_column_message,
4321 $analyzed_sql_results,
4322 $total,
4323 $pos_next,
4324 $pre_count,
4325 $after_count
4328 $table_html .= PMA_Util::getMessage(
4329 $message, $this->__get('sql_query'), 'success'
4332 } elseif (! isset($printview) || ($printview != '1')) {
4334 $table_html .= PMA_Util::getMessage(
4335 __('Your SQL query has been executed successfully.'),
4336 $this->__get('sql_query'), 'success'
4340 // 2.3 Prepare the navigation bars
4341 if (!/*overload*/mb_strlen($this->__get('table'))) {
4343 if ($analyzed_sql_results['querytype'] == 'SELECT') {
4344 // table does not always contain a real table name,
4345 // for example in MySQL 5.0.x, the query SHOW STATUS
4346 // returns STATUS as a table name
4347 $this->__set('table', $fields_meta[0]->table);
4348 } else {
4349 $this->__set('table', '');
4354 if (($displayParts['nav_bar'] == '1') && (empty($statement->limit))) {
4355 $table_html .= $this->_getPlacedTableNavigations(
4356 $pos_next, $pos_prev, self::PLACE_TOP_DIRECTION_DROPDOWN,
4357 $is_innodb
4359 } elseif (! isset($printview) || ($printview != '1')) {
4360 $table_html .= "\n" . '<br /><br />' . "\n";
4363 // 2b ----- Get field references from Database -----
4364 // (see the 'relation' configuration variable)
4366 // initialize map
4367 $map = array();
4369 $target = array();
4370 if (!empty($statement->from)) {
4371 foreach ($statement->from as $field) {
4372 if (!empty($field->table)) {
4373 $target[] = $field->table;
4378 if (/*overload*/mb_strlen($this->__get('table'))) {
4379 // This method set the values for $map array
4380 $this->_setParamForLinkForeignKeyRelatedTables($map);
4382 // Coming from 'Distinct values' action of structure page
4383 // We manipulate relations mechanism to show a link to related rows.
4384 if ($this->__get('is_browse_distinct')) {
4385 $map[$fields_meta[1]->name] = array(
4386 $this->__get('table'),
4387 $fields_meta[1]->name,
4389 $this->__get('db')
4392 } // end if
4393 // end 2b
4395 // 3. ----- Prepare the results table -----
4396 $table_html .= $this->_getTableHeaders(
4397 $displayParts,
4398 $analyzed_sql_results,
4399 $sort_expression,
4400 $sort_expression_nodirection,
4401 $sort_direction,
4402 $is_limited_display
4405 $table_html .= '<tbody>' . "\n";
4407 $table_html .= $this->_getTableBody(
4408 $dt_result,
4409 $displayParts,
4410 $map,
4411 $analyzed_sql_results,
4412 $is_limited_display
4415 $this->__set('display_params', null);
4417 $table_html .= '</tbody>' . "\n" . '</table>';
4419 // 4. ----- Prepares the link for multi-fields edit and delete
4421 if ($displayParts['del_lnk'] == self::DELETE_ROW
4422 && $displayParts['del_lnk'] != self::KILL_PROCESS
4425 $table_html .= $this->_getMultiRowOperationLinks(
4426 $dt_result,
4427 $analyzed_sql_results,
4428 $displayParts['del_lnk']
4433 // 5. ----- Get the navigation bar at the bottom if required -----
4434 if (($displayParts['nav_bar'] == '1') && empty($statement->limit)) {
4435 $table_html .= $this->_getPlacedTableNavigations(
4436 $pos_next, $pos_prev, self::PLACE_BOTTOM_DIRECTION_DROPDOWN,
4437 $is_innodb
4439 } elseif (! isset($printview) || ($printview != '1')) {
4440 $table_html .= "\n" . '<br /><br />' . "\n";
4443 // 6. ----- Prepare "Query results operations"
4444 if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) {
4445 $table_html .= $this->_getResultsOperations(
4446 $displayParts, $analyzed_sql_results
4450 return $table_html;
4452 } // end of the 'getTable()' function
4456 * Get offsets for next page and previous page
4458 * @return array array with two elements - $pos_next, $pos_prev
4460 * @access private
4462 * @see getTable()
4464 private function _getOffsets()
4467 if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
4468 $pos_next = 0;
4469 $pos_prev = 0;
4470 } else {
4472 $pos_next = $_SESSION['tmpval']['pos']
4473 + $_SESSION['tmpval']['max_rows'];
4475 $pos_prev = $_SESSION['tmpval']['pos']
4476 - $_SESSION['tmpval']['max_rows'];
4478 if ($pos_prev < 0) {
4479 $pos_prev = 0;
4483 return array($pos_next, $pos_prev);
4485 } // end of the '_getOffsets()' function
4489 * Prepare sorted column message
4491 * @param integer &$dt_result the link id associated to the
4492 * query which results have to
4493 * be displayed
4494 * @param string $sort_expression_nodirection sort expression without direction
4496 * @return string html content
4497 * null if not found sorted column
4499 * @access private
4501 * @see getTable()
4503 private function _getSortedColumnMessage(
4504 &$dt_result, $sort_expression_nodirection
4507 $fields_meta = $this->__get('fields_meta'); // To use array indexes
4509 if (empty($sort_expression_nodirection)) {
4510 return null;
4513 if (/*overload*/mb_strpos($sort_expression_nodirection, '.') === false) {
4514 $sort_table = $this->__get('table');
4515 $sort_column = $sort_expression_nodirection;
4516 } else {
4517 list($sort_table, $sort_column)
4518 = explode('.', $sort_expression_nodirection);
4521 $sort_table = PMA_Util::unQuote($sort_table);
4522 $sort_column = PMA_Util::unQuote($sort_column);
4524 // find the sorted column index in row result
4525 // (this might be a multi-table query)
4526 $sorted_column_index = false;
4528 foreach ($fields_meta as $key => $meta) {
4529 if (($meta->table == $sort_table) && ($meta->name == $sort_column)) {
4530 $sorted_column_index = $key;
4531 break;
4535 if ($sorted_column_index === false) {
4536 return null;
4539 // fetch first row of the result set
4540 $row = $GLOBALS['dbi']->fetchRow($dt_result);
4542 // initializing default arguments
4543 $default_function = 'PMA_mimeDefaultFunction';
4544 $transformation_plugin = $default_function;
4545 $transform_options = array();
4547 // check for non printable sorted row data
4548 $meta = $fields_meta[$sorted_column_index];
4550 if (stristr($meta->type, self::BLOB_FIELD)
4551 || ($meta->type == self::GEOMETRY_FIELD)
4554 $column_for_first_row = $this->_handleNonPrintableContents(
4555 $meta->type, $row[$sorted_column_index],
4556 $transformation_plugin, $transform_options,
4557 $default_function, $meta
4560 } else {
4561 $column_for_first_row = $row[$sorted_column_index];
4564 $column_for_first_row = /*overload*/mb_strtoupper(
4565 /*overload*/mb_substr(
4566 $column_for_first_row, 0, $GLOBALS['cfg']['LimitChars']
4567 ) . '...'
4570 // fetch last row of the result set
4571 $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
4572 $row = $GLOBALS['dbi']->fetchRow($dt_result);
4574 // check for non printable sorted row data
4575 $meta = $fields_meta[$sorted_column_index];
4576 if (stristr($meta->type, self::BLOB_FIELD)
4577 || ($meta->type == self::GEOMETRY_FIELD)
4580 $column_for_last_row = $this->_handleNonPrintableContents(
4581 $meta->type, $row[$sorted_column_index],
4582 $transformation_plugin, $transform_options,
4583 $default_function, $meta
4586 } else {
4587 $column_for_last_row = $row[$sorted_column_index];
4590 $column_for_last_row = /*overload*/mb_strtoupper(
4591 /*overload*/mb_substr(
4592 $column_for_last_row, 0, $GLOBALS['cfg']['LimitChars']
4593 ) . '...'
4596 // reset to first row for the loop in _getTableBody()
4597 $GLOBALS['dbi']->dataSeek($dt_result, 0);
4599 // we could also use here $sort_expression_nodirection
4600 return ' [' . htmlspecialchars($sort_column)
4601 . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - '
4602 . htmlspecialchars($column_for_last_row) . '</strong>]';
4603 } // end of the '_getSortedColumnMessage()' function
4607 * Set the content that needs to be shown in message
4609 * @param string $sorted_column_message the message for sorted column
4610 * @param array $analyzed_sql_results the analyzed query
4611 * @param integer $total the total number of rows returned by
4612 * the SQL query without any
4613 * programmatically appended LIMIT clause
4614 * @param integer $pos_next the offset for next page
4615 * @param string $pre_count the string renders before row count
4616 * @param string $after_count the string renders after row count
4618 * @return PMA_Message $message an object of PMA_Message
4620 * @access private
4622 * @see getTable()
4624 private function _setMessageInformation(
4625 $sorted_column_message, $analyzed_sql_results, $total,
4626 $pos_next, $pre_count, $after_count
4629 $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset()
4631 if (!empty($analyzed_sql_results['statement']->limit)) {
4633 $first_shown_rec = $analyzed_sql_results['statement']->limit->offset;
4634 $row_count = $analyzed_sql_results['statement']->limit->rowCount;
4636 if ($row_count < $total) {
4637 $last_shown_rec = $first_shown_rec + $row_count - 1;
4638 } else {
4639 $last_shown_rec = $first_shown_rec + $total - 1;
4642 } elseif (($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS)
4643 || ($pos_next > $total)
4646 $first_shown_rec = $_SESSION['tmpval']['pos'];
4647 $last_shown_rec = $total - 1;
4649 } else {
4651 $first_shown_rec = $_SESSION['tmpval']['pos'];
4652 $last_shown_rec = $pos_next - 1;
4656 $table = new PMA_Table($this->__get('table'), $this->__get('db'));
4657 if ($table->isView()
4658 && ($total == $GLOBALS['cfg']['MaxExactCountViews'])
4661 $message = PMA_Message::notice(
4663 'This view has at least this number of rows. '
4664 . 'Please refer to %sdocumentation%s.'
4668 $message->addParam('[doc@cfg_MaxExactCount]');
4669 $message->addParam('[/doc]');
4670 $message_view_warning = PMA_Util::showHint($message);
4672 } else {
4673 $message_view_warning = false;
4676 $message = PMA_Message::success(__('Showing rows %1s - %2s'));
4677 $message->addParam($first_shown_rec);
4679 if ($message_view_warning !== false) {
4680 $message->addParam('... ' . $message_view_warning, false);
4681 } else {
4682 $message->addParam($last_shown_rec);
4685 $message->addMessage('(');
4687 if ($message_view_warning === false) {
4689 if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) {
4690 $message_total = PMA_Message::notice(
4691 $pre_count . __('%1$d total, %2$d in query')
4693 $message_total->addParam($total);
4694 $message_total->addParam($unlim_num_rows);
4695 } else {
4696 $message_total = PMA_Message::notice($pre_count . __('%d total'));
4697 $message_total->addParam($total);
4700 if (!empty($after_count)) {
4701 $message_total->addMessage($after_count);
4703 $message->addMessage($message_total, '');
4705 $message->addMessage(', ', '');
4708 $message_qt = PMA_Message::notice(__('Query took %01.4f seconds.') . ')');
4709 $message_qt->addParam($this->__get('querytime'));
4711 $message->addMessage($message_qt, '');
4712 if (! is_null($sorted_column_message)) {
4713 $message->addMessage($sorted_column_message, '');
4716 return $message;
4718 } // end of the '_setMessageInformation()' function
4722 * Set the value of $map array for linking foreign key related tables
4724 * @param array &$map the list of relations
4726 * @return void
4728 * @access private
4730 * @see getTable()
4732 private function _setParamForLinkForeignKeyRelatedTables(&$map)
4735 // To be able to later display a link to the related table,
4736 // we verify both types of relations: either those that are
4737 // native foreign keys or those defined in the phpMyAdmin
4738 // configuration storage. If no PMA storage, we won't be able
4739 // to use the "column to display" notion (for example show
4740 // the name related to a numeric id).
4741 $exist_rel = PMA_getForeigners(
4742 $this->__get('db'), $this->__get('table'), '', self::POSITION_BOTH
4745 if (! empty($exist_rel)) {
4747 foreach ($exist_rel as $master_field => $rel) {
4748 if ($master_field != 'foreign_keys_data') {
4749 $display_field = PMA_getDisplayField(
4750 $rel['foreign_db'], $rel['foreign_table']
4752 $map[$master_field] = array(
4753 $rel['foreign_table'],
4754 $rel['foreign_field'],
4755 $display_field,
4756 $rel['foreign_db']
4758 } else {
4759 foreach ($rel as $key => $one_key) {
4760 foreach ($one_key['index_list'] as $index => $one_field) {
4761 $display_field = PMA_getDisplayField(
4762 isset($one_key['ref_db_name'])
4763 ? $one_key['ref_db_name']
4764 : $GLOBALS['db'],
4765 $one_key['ref_table_name']
4768 $map[$one_field] = array(
4769 $one_key['ref_table_name'],
4770 $one_key['ref_index_list'][$index],
4771 $display_field,
4772 isset($one_key['ref_db_name'])
4773 ? $one_key['ref_db_name']
4774 : $GLOBALS['db']
4779 } // end while
4780 } // end if
4782 } // end of the '_setParamForLinkForeignKeyRelatedTables()' function
4786 * Prepare multi field edit/delete links
4788 * @param integer &$dt_result the link id associated to the query which results have to be displayed
4789 * which results have to be displayed
4790 * @param array $analyzed_sql_results analyzed sql results
4791 * @param string $del_link the display element - 'del_link'
4793 * @return string $links_html html content
4795 * @access private
4797 * @see getTable()
4799 private function _getMultiRowOperationLinks(
4800 &$dt_result, $analyzed_sql_results, $del_link
4803 $links_html = '<div class="print_ignore" >';
4804 $url_query = $this->__get('url_query');
4805 $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill');
4807 $links_html .= '<img class="selectallarrow" width="38" height="22"'
4808 . ' src="' . $this->__get('pma_theme_image') . 'arrow_'
4809 . $this->__get('text_dir') . '.png' . '"'
4810 . ' alt="' . __('With selected:') . '" />';
4812 $links_html .= '<input type="checkbox" '
4813 . 'id="resultsForm_' . $this->__get('unique_id') . '_checkall" '
4814 . 'class="checkall_box" title="' . __('Check all') . '" /> '
4815 . '<label for="resultsForm_' . $this->__get('unique_id') . '_checkall">'
4816 . __('Check all') . '</label> '
4817 . '<i style="margin-left: 2em">' . __('With selected:') . '</i>' . "\n";
4819 $links_html .= PMA_Util::getButtonOrImage(
4820 'submit_mult', 'mult_submit', 'submit_mult_change',
4821 __('Edit'), 'b_edit.png', 'edit'
4824 $links_html .= PMA_Util::getButtonOrImage(
4825 'submit_mult', 'mult_submit', 'submit_mult_copy',
4826 __('Copy'), 'b_insrow.png', 'copy'
4829 $links_html .= PMA_Util::getButtonOrImage(
4830 'submit_mult', 'mult_submit', 'submit_mult_delete',
4831 $delete_text, 'b_drop.png', 'delete'
4834 if ($analyzed_sql_results['querytype'] == 'SELECT') {
4835 $links_html .= PMA_Util::getButtonOrImage(
4836 'submit_mult', 'mult_submit', 'submit_mult_export',
4837 __('Export'), 'b_tblexport.png', 'export'
4841 $links_html .= "</div>\n";
4843 $links_html .= '<input type="hidden" name="sql_query"'
4844 . ' value="' . htmlspecialchars($this->__get('sql_query')) . '" />'
4845 . "\n";
4847 if (! empty($url_query)) {
4848 $links_html .= '<input type="hidden" name="url_query"'
4849 . ' value="' . $url_query . '" />' . "\n";
4852 // fetch last row of the result set
4853 $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1);
4854 $row = $GLOBALS['dbi']->fetchRow($dt_result);
4856 // $clause_is_unique is needed by getTable() to generate the proper param
4857 // in the multi-edit and multi-delete form
4858 list($where_clause, $clause_is_unique, $condition_array)
4859 = PMA_Util::getUniqueCondition(
4860 $dt_result, // handle
4861 $this->__get('fields_cnt'), // fields_cnt
4862 $this->__get('fields_meta'), // fields_meta
4863 $row, // row
4864 false, // force_unique
4865 false, // restrict_to_table
4866 $analyzed_sql_results // analyzed_sql_results
4868 unset($where_clause, $condition_array);
4870 // reset to first row for the loop in _getTableBody()
4871 $GLOBALS['dbi']->dataSeek($dt_result, 0);
4873 $links_html .= '<input type="hidden" name="clause_is_unique"'
4874 . ' value="' . $clause_is_unique . '" />' . "\n";
4876 $links_html .= '</form>' . "\n";
4878 return $links_html;
4880 } // end of the '_getMultiRowOperationLinks()' function
4884 * Prepare table navigation bar at the top or bottom
4886 * @param integer $pos_next the offset for the "next" page
4887 * @param integer $pos_prev the offset for the "previous" page
4888 * @param string $place the place to show navigation
4889 * @param boolean $is_innodb whether its InnoDB or not
4891 * @return string html content of navigation bar
4893 * @access private
4895 * @see _getTable()
4897 private function _getPlacedTableNavigations(
4898 $pos_next, $pos_prev, $place, $is_innodb
4901 $navigation_html = '';
4903 if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) {
4904 $navigation_html .= '<br />' . "\n";
4907 $navigation_html .= $this->_getTableNavigation(
4908 $pos_next, $pos_prev, $is_innodb
4911 if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) {
4912 $navigation_html .= "\n";
4915 return $navigation_html;
4917 } // end of the '_getPlacedTableNavigations()' function
4920 * Generates HTML to display the Create view in span tag
4922 * @param array $analyzed_sql_results analyzed sql results
4923 * @param string $url_query String with URL Parameters
4925 * @return string
4927 * @access private
4929 * @see _getResultsOperations()
4931 private function _getLinkForCreateView($analyzed_sql_results, $url_query)
4933 $results_operations_html = '';
4934 if (!PMA_DRIZZLE && empty($analyzed_sql_results['procedure'])) {
4936 $ajax_class = ' ajax';
4938 $results_operations_html .= '<span>'
4939 . PMA_Util::linkOrButton(
4940 'view_create.php' . $url_query,
4941 PMA_Util::getIcon(
4942 'b_view_add.png', __('Create view'), true
4944 array('class' => 'create_view' . $ajax_class), true, true, ''
4946 . '</span>' . "\n";
4948 return $results_operations_html;
4953 * Calls the _getResultsOperations with $only_view as true
4955 * @param array $analyzed_sql_results analyzed sql results
4957 * @return string
4959 * @access public
4962 public function getCreateViewQueryResultOp($analyzed_sql_results)
4965 $results_operations_html = '';
4966 //calling to _getResultOperations with a fake $displayParts
4967 //and setting only_view parameter to be true to generate just view
4968 $results_operations_html .= $this->_getResultsOperations(
4969 array(),
4970 $analyzed_sql_results,
4971 true
4973 return $results_operations_html;
4977 * Get printview links for results operations
4979 * @return string $html
4981 * @access private
4983 private function _getPrintviewLinks()
4985 $html = PMA_Util::linkOrButton(
4986 '#',
4987 PMA_Util::getIcon(
4988 'b_print.png', __('Print view'), true
4990 array('id' => 'printView'),
4991 true,
4992 true,
4993 'print_view'
4996 return $html;
5000 * Get operations that are available on results.
5002 * @param array $displayParts the parts to display
5003 * @param array $analyzed_sql_results analyzed sql results
5004 * @param boolean $only_view Whether to show only view
5006 * @return string $results_operations_html html content
5008 * @access private
5010 * @see getTable()
5012 private function _getResultsOperations(
5013 $displayParts, $analyzed_sql_results, $only_view = false
5015 global $printview;
5017 $results_operations_html = '';
5018 $fields_meta = $this->__get('fields_meta'); // To safe use in foreach
5019 $header_shown = false;
5020 $header = '<fieldset class="print_ignore" ><legend>' . __('Query results operations')
5021 . '</legend>';
5023 $_url_params = array(
5024 'db' => $this->__get('db'),
5025 'table' => $this->__get('table'),
5026 'printview' => '1',
5027 'sql_query' => $this->__get('sql_query'),
5029 $url_query = PMA_URL_getCommon($_url_params);
5031 if (!$header_shown) {
5032 $results_operations_html .= $header;
5033 $header_shown = true;
5035 // if empty result set was produced we need to
5036 // show only view and not other options
5037 if ($only_view) {
5038 $results_operations_html .= $this->_getLinkForCreateView(
5039 $analyzed_sql_results, $url_query
5042 if ($header_shown) {
5043 $results_operations_html .= '</fieldset><br />';
5045 return $results_operations_html;
5048 // Displays "printable view" link if required
5049 if ($displayParts['pview_lnk'] == '1') {
5050 $results_operations_html .= $this->_getPrintviewLinks();
5051 } // end displays "printable view"
5053 // Export link
5054 // (the url_query has extra parameters that won't be used to export)
5055 // (the single_table parameter is used in display_export.inc.php
5056 // to hide the SQL and the structure export dialogs)
5057 // If the parser found a PROCEDURE clause
5058 // (most probably PROCEDURE ANALYSE()) it makes no sense to
5059 // display the Export link).
5060 if (($analyzed_sql_results['querytype'] == self::QUERY_TYPE_SELECT)
5061 && ! isset($printview)
5062 && empty($analyzed_sql_results['procedure'])
5065 if (count($analyzed_sql_results['select_tables']) == 1) {
5066 $_url_params['single_table'] = 'true';
5069 if (! $header_shown) {
5070 $results_operations_html .= $header;
5071 $header_shown = true;
5074 $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows');
5077 * At this point we don't know the table name; this can happen
5078 * for example with a query like
5079 * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp
5080 * As a workaround we set in the table parameter the name of the
5081 * first table of this database, so that tbl_export.php and
5082 * the script it calls do not fail
5084 if (empty($_url_params['table']) && ! empty($_url_params['db'])) {
5085 $_url_params['table'] = $GLOBALS['dbi']->fetchValue("SHOW TABLES");
5086 /* No result (probably no database selected) */
5087 if ($_url_params['table'] === false) {
5088 unset($_url_params['table']);
5092 $results_operations_html .= PMA_Util::linkOrButton(
5093 'tbl_export.php' . PMA_URL_getCommon($_url_params),
5094 PMA_Util::getIcon(
5095 'b_tblexport.png', __('Export'), true
5098 true,
5099 true,
5102 . "\n";
5104 // prepare chart
5105 $results_operations_html .= PMA_Util::linkOrButton(
5106 'tbl_chart.php' . PMA_URL_getCommon($_url_params),
5107 PMA_Util::getIcon(
5108 'b_chart.png', __('Display chart'), true
5111 true,
5112 true,
5115 . "\n";
5117 // prepare GIS chart
5118 $geometry_found = false;
5119 // If at least one geometry field is found
5120 foreach ($fields_meta as $meta) {
5121 if ($meta->type == self::GEOMETRY_FIELD) {
5122 $geometry_found = true;
5123 break;
5127 if ($geometry_found) {
5128 $results_operations_html
5129 .= PMA_Util::linkOrButton(
5130 'tbl_gis_visualization.php'
5131 . PMA_URL_getCommon($_url_params),
5132 PMA_Util::getIcon(
5133 'b_globe.gif', __('Visualize GIS data'), true
5136 true,
5137 true,
5140 . "\n";
5144 // CREATE VIEW
5147 * @todo detect privileges to create a view
5148 * (but see 2006-01-19 note in display_create_table.lib.php,
5149 * I think we cannot detect db-specific privileges reliably)
5150 * Note: we don't display a Create view link if we found a PROCEDURE clause
5152 if (!$header_shown) {
5153 $results_operations_html .= $header;
5154 $header_shown = true;
5157 $results_operations_html .= $this->_getLinkForCreateView(
5158 $analyzed_sql_results, $url_query
5161 if ($header_shown) {
5162 $results_operations_html .= '</fieldset><br />';
5165 return $results_operations_html;
5167 } // end of the '_getResultsOperations()' function
5171 * Verifies what to do with non-printable contents (binary or BLOB)
5172 * in Browse mode.
5174 * @param string $category BLOB|BINARY|GEOMETRY
5175 * @param string $content the binary content
5176 * @param mixed $transformation_plugin transformation plugin.
5177 * Can also be the default function:
5178 * PMA_mimeDefaultFunction
5179 * @param string $transform_options transformation parameters
5180 * @param string $default_function default transformation function
5181 * @param object $meta the meta-information about the field
5182 * @param array $url_params parameters that should go to the
5183 * download link
5184 * @param boolean &$is_truncated the result is truncated or not
5186 * @return mixed string or float
5188 * @access private
5190 * @see _getDataCellForGeometryColumns(),
5191 * _getDataCellForNonNumericColumns(),
5192 * _getSortedColumnMessage()
5194 private function _handleNonPrintableContents(
5195 $category, $content, $transformation_plugin, $transform_options,
5196 $default_function, $meta, $url_params = array(), &$is_truncated = null
5199 $is_truncated = false;
5200 $result = '[' . $category;
5202 if (isset($content)) {
5204 $size = /*overload*/mb_strlen($content, '8bit');
5205 $display_size = PMA_Util::formatByteDown($size, 3, 1);
5206 $result .= ' - ' . $display_size[0] . ' ' . $display_size[1];
5208 } else {
5210 $result .= ' - NULL';
5211 $size = 0;
5215 $result .= ']';
5217 // if we want to use a text transformation on a BLOB column
5218 if (gettype($transformation_plugin) === "object") {
5219 $posMimeOctetstream = strpos(
5220 $transformation_plugin->getMIMESubtype(),
5221 'Octetstream'
5223 $posMimeText = strpos($transformation_plugin->getMIMEtype(), 'Text');
5224 if ($posMimeOctetstream
5225 || $posMimeText !== false
5227 // Applying Transformations on hex string of binary data
5228 // seems more appropriate
5229 $result = pack("H*", bin2hex($content));
5233 if ($size <= 0) {
5234 return($result);
5237 if ($default_function != $transformation_plugin) {
5238 $result = $transformation_plugin->applyTransformation(
5239 $result,
5240 $transform_options,
5241 $meta
5243 return($result);
5246 $result = $default_function($result, array(), $meta);
5247 if (($_SESSION['tmpval']['display_binary']
5248 && $meta->type === self::STRING_FIELD)
5249 || ($_SESSION['tmpval']['display_blob']
5250 && stristr($meta->type, self::BLOB_FIELD))
5252 // in this case, restart from the original $content
5253 $result = bin2hex($content);
5254 list(
5255 $is_truncated,
5256 $result,
5257 // skip 3rd param
5258 ) = $this->_getPartialText($result);
5261 /* Create link to download */
5263 // in PHP < 5.5, empty() only checks variables
5264 $tmpdb = $this->__get('db');
5265 if ((count($url_params) > 0) && (! empty($tmpdb) && ! empty($meta->orgtable))) {
5266 $result = '<a href="tbl_get_field.php'
5267 . PMA_URL_getCommon($url_params)
5268 . '" class="disableAjax">'
5269 . $result . '</a>';
5272 return($result);
5274 } // end of the '_handleNonPrintableContents()' function
5278 * Retrieves the associated foreign key info for a data cell
5280 * @param array $map the list of relations
5281 * @param object $meta the meta-information about the field
5282 * @param string $where_comparison data for the where clause
5284 * @return string formatted data
5286 * @access private
5289 private function _getFromForeign($map, $meta, $where_comparison)
5291 $dispsql = 'SELECT '
5292 . PMA_Util::backquote($map[$meta->name][2])
5293 . ' FROM '
5294 . PMA_Util::backquote($map[$meta->name][3])
5295 . '.'
5296 . PMA_Util::backquote($map[$meta->name][0])
5297 . ' WHERE '
5298 . PMA_Util::backquote($map[$meta->name][1])
5299 . $where_comparison;
5301 $dispresult = $GLOBALS['dbi']->tryQuery(
5302 $dispsql,
5303 null,
5304 PMA_DatabaseInterface::QUERY_STORE
5307 if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) {
5308 list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0);
5309 } else {
5310 $dispval = __('Link not found!');
5313 @$GLOBALS['dbi']->freeResult($dispresult);
5315 return $dispval;
5319 * Prepares the displayable content of a data cell in Browse mode,
5320 * taking into account foreign key description field and transformations
5322 * @param string $class css classes for the td element
5323 * @param bool $condition_field whether the column is a part of
5324 * the where clause
5325 * @param array $analyzed_sql_results the analyzed query
5326 * @param object $meta the meta-information about the
5327 * field
5328 * @param array $map the list of relations
5329 * @param string $data data
5330 * @param object|string $transformation_plugin transformation plugin.
5331 * Can also be the default function:
5332 * PMA_mimeDefaultFunction
5333 * @param string $default_function default function
5334 * @param string $nowrap 'nowrap' if the content should
5335 * not be wrapped
5336 * @param string $where_comparison data for the where clause
5337 * @param array $transform_options options for transformation
5338 * @param bool $is_field_truncated whether the field is truncated
5339 * @param string $original_length of a truncated column, or ''
5341 * @return string formatted data
5343 * @access private
5345 * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
5346 * _getDataCellForNonNumericColumns(),
5349 private function _getRowData(
5350 $class, $condition_field, $analyzed_sql_results, $meta, $map, $data,
5351 $transformation_plugin, $default_function, $nowrap, $where_comparison,
5352 $transform_options, $is_field_truncated, $original_length=''
5354 $relational_display = $_SESSION['tmpval']['relational_display'];
5355 $printview = $this->__get('printview');
5356 $decimals = isset($meta->decimals) ? $meta->decimals : '-1';
5357 $result = '<td data-decimals="' . $decimals . '"'
5358 . ' data-type="' . $meta->type . '"';
5360 if (! empty($original_length)) {
5361 // cannot use data-original-length
5362 $result .= ' data-originallength="' . $original_length . '"';
5365 $result .= ' class="'
5366 . $this->_addClass(
5367 $class, $condition_field, $meta, $nowrap,
5368 $is_field_truncated, $transformation_plugin, $default_function
5370 . '">';
5372 if (!empty($analyzed_sql_results['statement']->expr)) {
5373 foreach ($analyzed_sql_results['statement']->expr as $expr) {
5374 if ((empty($expr->alias)) || (empty($expr->column))) {
5375 continue;
5377 if (strcasecmp($meta->name, $expr->alias) == 0) {
5378 $meta->name = $expr->column;
5383 if (isset($map[$meta->name])) {
5385 // Field to display from the foreign table?
5386 if (isset($map[$meta->name][2])
5387 && /*overload*/mb_strlen($map[$meta->name][2])
5389 $dispval = $this->_getFromForeign(
5390 $map, $meta, $where_comparison
5392 } else {
5393 $dispval = '';
5394 } // end if... else...
5396 if (isset($printview) && ($printview == '1')) {
5398 $result .= ($transformation_plugin != $default_function
5399 ? $transformation_plugin->applyTransformation(
5400 $data,
5401 $transform_options,
5402 $meta
5404 : $default_function($data)
5406 . ' <code>[-&gt;' . $dispval . ']</code>';
5408 } else {
5410 if ($relational_display == self::RELATIONAL_KEY) {
5412 // user chose "relational key" in the display options, so
5413 // the title contains the display field
5414 $title = (! empty($dispval))
5415 ? ' title="' . htmlspecialchars($dispval) . '"'
5416 : '';
5418 } else {
5419 $title = ' title="' . htmlspecialchars($data) . '"';
5422 $_url_params = array(
5423 'db' => $map[$meta->name][3],
5424 'table' => $map[$meta->name][0],
5425 'pos' => '0',
5426 'sql_query' => 'SELECT * FROM '
5427 . PMA_Util::backquote($map[$meta->name][3]) . '.'
5428 . PMA_Util::backquote($map[$meta->name][0])
5429 . ' WHERE '
5430 . PMA_Util::backquote($map[$meta->name][1])
5431 . $where_comparison,
5434 $result .= '<a class="ajax" href="sql.php'
5435 . PMA_URL_getCommon($_url_params)
5436 . '"' . $title . '>';
5438 if ($transformation_plugin != $default_function) {
5439 // always apply a transformation on the real data,
5440 // not on the display field
5441 $result .= $transformation_plugin->applyTransformation(
5442 $data,
5443 $transform_options,
5444 $meta
5446 } else {
5448 if ($relational_display == self::RELATIONAL_DISPLAY_COLUMN
5449 && ! empty($map[$meta->name][2])
5451 // user chose "relational display field" in the
5452 // display options, so show display field in the cell
5453 $result .= $default_function($dispval);
5454 } else {
5455 // otherwise display data in the cell
5456 $result .= $default_function($data);
5460 $result .= '</a>';
5463 } else {
5464 $result .= ($transformation_plugin != $default_function
5465 ? $transformation_plugin->applyTransformation(
5466 $data,
5467 $transform_options,
5468 $meta
5470 : $default_function($data)
5474 $result .= '</td>' . "\n";
5476 return $result;
5478 } // end of the '_getRowData()' function
5482 * Prepares a checkbox for multi-row submits
5484 * @param string $del_url delete url
5485 * @param array $displayParts array with explicit indexes for all
5486 * the display elements
5487 * @param string $row_no the row number
5488 * @param string $where_clause_html url encoded where clause
5489 * @param array $condition_array array of conditions in the where clause
5490 * @param string $id_suffix suffix for the id
5491 * @param string $class css classes for the td element
5493 * @return string the generated HTML
5495 * @access private
5497 * @see _getTableBody(), _getCheckboxAndLinks()
5499 private function _getCheckboxForMultiRowSubmissions(
5500 $del_url, $displayParts, $row_no, $where_clause_html, $condition_array,
5501 $id_suffix, $class
5504 $ret = '';
5506 if (! empty($del_url) && $displayParts['del_lnk'] != self::KILL_PROCESS) {
5508 $ret .= '<td ';
5509 if (! empty($class)) {
5510 $ret .= 'class="' . $class . '"';
5513 $ret .= ' class="center print_ignore">'
5514 . '<input type="checkbox" id="id_rows_to_delete'
5515 . $row_no . $id_suffix
5516 . '" name="rows_to_delete[' . $row_no . ']"'
5517 . ' class="multi_checkbox checkall"'
5518 . ' value="' . $where_clause_html . '" '
5519 . ' />'
5520 . '<input type="hidden" class="condition_array" value="'
5521 . htmlspecialchars(json_encode($condition_array)) . '" />'
5522 . ' </td>';
5525 return $ret;
5527 } // end of the '_getCheckboxForMultiRowSubmissions()' function
5531 * Prepares an Edit link
5533 * @param string $edit_url edit url
5534 * @param string $class css classes for td element
5535 * @param string $edit_str text for the edit link
5536 * @param string $where_clause where clause
5537 * @param string $where_clause_html url encoded where clause
5539 * @return string the generated HTML
5541 * @access private
5543 * @see _getTableBody(), _getCheckboxAndLinks()
5545 private function _getEditLink(
5546 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5549 $ret = '';
5550 if (! empty($edit_url)) {
5552 $ret .= '<td class="' . $class . ' center print_ignore" ' . ' ><span class="nowrap">'
5553 . PMA_Util::linkOrButton(
5554 $edit_url, $edit_str, array(), false
5557 * Where clause for selecting this row uniquely is provided as
5558 * a hidden input. Used by jQuery scripts for handling grid editing
5560 if (! empty($where_clause)) {
5561 $ret .= '<input type="hidden" class="where_clause" value ="'
5562 . $where_clause_html . '" />';
5564 $ret .= '</span></td>';
5567 return $ret;
5569 } // end of the '_getEditLink()' function
5573 * Prepares an Copy link
5575 * @param string $copy_url copy url
5576 * @param string $copy_str text for the copy link
5577 * @param string $where_clause where clause
5578 * @param string $where_clause_html url encoded where clause
5579 * @param string $class css classes for the td element
5581 * @return string the generated HTML
5583 * @access private
5585 * @see _getTableBody(), _getCheckboxAndLinks()
5587 private function _getCopyLink(
5588 $copy_url, $copy_str, $where_clause, $where_clause_html, $class
5591 $ret = '';
5592 if (! empty($copy_url)) {
5594 $ret .= '<td class="';
5595 if (! empty($class)) {
5596 $ret .= $class . ' ';
5599 $ret .= 'center print_ignore" ' . ' ><span class="nowrap">'
5600 . PMA_Util::linkOrButton(
5601 $copy_url, $copy_str, array(), false
5605 * Where clause for selecting this row uniquely is provided as
5606 * a hidden input. Used by jQuery scripts for handling grid editing
5608 if (! empty($where_clause)) {
5609 $ret .= '<input type="hidden" class="where_clause" value="'
5610 . $where_clause_html . '" />';
5612 $ret .= '</span></td>';
5615 return $ret;
5617 } // end of the '_getCopyLink()' function
5621 * Prepares a Delete link
5623 * @param string $del_url delete url
5624 * @param string $del_str text for the delete link
5625 * @param string $js_conf text for the JS confirmation
5626 * @param string $class css classes for the td element
5628 * @return string the generated HTML
5630 * @access private
5632 * @see _getTableBody(), _getCheckboxAndLinks()
5634 private function _getDeleteLink($del_url, $del_str, $js_conf, $class)
5637 $ret = '';
5638 if (! empty($del_url)) {
5640 $ret .= '<td class="';
5641 if (! empty($class)) {
5642 $ret .= $class . ' ';
5644 $ajax = PMA_Response::getInstance()->isAjax() ? ' ajax' : '';
5645 $ret .= 'center print_ignore" ' . ' >'
5646 . PMA_Util::linkOrButton(
5647 $del_url, $del_str, array('class' => 'delete_row requireConfirm' . $ajax), false
5649 . '<div class="hide">' . $js_conf . '</div>'
5650 . '</td>';
5653 return $ret;
5655 } // end of the '_getDeleteLink()' function
5659 * Prepare checkbox and links at some position (left or right)
5660 * (only called for horizontal mode)
5662 * @param string $position the position of the checkbox and links
5663 * @param string $del_url delete url
5664 * @param array $displayParts array with explicit indexes for all the
5665 * display elements
5666 * @param string $row_no row number
5667 * @param string $where_clause where clause
5668 * @param string $where_clause_html url encoded where clause
5669 * @param array $condition_array array of conditions in the where clause
5670 * @param string $edit_url edit url
5671 * @param string $copy_url copy url
5672 * @param string $class css classes for the td elements
5673 * @param string $edit_str text for the edit link
5674 * @param string $copy_str text for the copy link
5675 * @param string $del_str text for the delete link
5676 * @param string $js_conf text for the JS confirmation
5678 * @return string the generated HTML
5680 * @access private
5682 * @see _getPlacedLinks()
5684 private function _getCheckboxAndLinks(
5685 $position, $del_url, $displayParts, $row_no, $where_clause,
5686 $where_clause_html, $condition_array,
5687 $edit_url, $copy_url, $class, $edit_str, $copy_str, $del_str, $js_conf
5690 $ret = '';
5692 if ($position == self::POSITION_LEFT) {
5694 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5695 $del_url, $displayParts, $row_no, $where_clause_html,
5696 $condition_array, '_left', ''
5699 $ret .= $this->_getEditLink(
5700 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5703 $ret .= $this->_getCopyLink(
5704 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5707 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5709 } elseif ($position == self::POSITION_RIGHT) {
5711 $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, '');
5713 $ret .= $this->_getCopyLink(
5714 $copy_url, $copy_str, $where_clause, $where_clause_html, ''
5717 $ret .= $this->_getEditLink(
5718 $edit_url, $class, $edit_str, $where_clause, $where_clause_html
5721 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5722 $del_url, $displayParts, $row_no, $where_clause_html,
5723 $condition_array, '_right', ''
5726 } else { // $position == self::POSITION_NONE
5728 $ret .= $this->_getCheckboxForMultiRowSubmissions(
5729 $del_url, $displayParts, $row_no, $where_clause_html,
5730 $condition_array, '_left', ''
5734 return $ret;
5736 } // end of the '_getCheckboxAndLinks()' function
5739 * Truncates given string based on LimitChars configuration
5740 * and Session pftext variable
5741 * (string is truncated only if necessary)
5743 * @param string $str string to be truncated
5745 * @return mixed
5747 * @access private
5749 * @see _handleNonPrintableContents(), _getDataCellForGeometryColumns(),
5750 * _getDataCellForNonNumericColumns
5752 private function _getPartialText($str)
5754 $original_length = /*overload*/mb_strlen($str);
5755 if ($original_length > $GLOBALS['cfg']['LimitChars']
5756 && $_SESSION['tmpval']['pftext'] === self::DISPLAY_PARTIAL_TEXT
5758 $str = /*overload*/mb_substr(
5759 $str, 0, $GLOBALS['cfg']['LimitChars']
5760 ) . '...';
5761 $truncated = true;
5762 } else {
5763 $truncated = false;
5766 return array($truncated, $str, $original_length);