1 | <?php |
||
2 | /* vim: set expandtab sw=4 ts=4 sts=4: */ |
||
3 | /** |
||
4 | * Hold the PhpMyAdmin\Display\Results class |
||
5 | * |
||
6 | * @package PhpMyAdmin |
||
7 | */ |
||
8 | declare(strict_types=1); |
||
9 | |||
10 | namespace PhpMyAdmin\Display; |
||
11 | |||
12 | use PhpMyAdmin\Core; |
||
13 | use PhpMyAdmin\DatabaseInterface; |
||
14 | use PhpMyAdmin\Index; |
||
15 | use PhpMyAdmin\Message; |
||
16 | use PhpMyAdmin\Plugins\Transformations\Text_Plain_Link; |
||
17 | use PhpMyAdmin\Relation; |
||
18 | use PhpMyAdmin\Response; |
||
19 | use PhpMyAdmin\Sanitize; |
||
20 | use PhpMyAdmin\Sql; |
||
21 | use PhpMyAdmin\SqlParser\Utils\Query; |
||
22 | use PhpMyAdmin\Table; |
||
23 | use PhpMyAdmin\Template; |
||
24 | use PhpMyAdmin\Transformations; |
||
25 | use PhpMyAdmin\Url; |
||
26 | use PhpMyAdmin\Util; |
||
27 | use \stdClass; |
||
28 | use PhpMyAdmin\Plugins\TransformationsPlugin; |
||
29 | |||
30 | /** |
||
31 | * Handle all the functionalities related to displaying results |
||
32 | * of sql queries, stored procedure, browsing sql processes or |
||
33 | * displaying binary log. |
||
34 | * |
||
35 | * @package PhpMyAdmin |
||
36 | */ |
||
37 | class Results |
||
38 | { |
||
39 | // Define constants |
||
40 | public const NO_EDIT_OR_DELETE = 'nn'; |
||
41 | public const UPDATE_ROW = 'ur'; |
||
42 | public const DELETE_ROW = 'dr'; |
||
43 | public const KILL_PROCESS = 'kp'; |
||
44 | |||
45 | public const POSITION_LEFT = 'left'; |
||
46 | public const POSITION_RIGHT = 'right'; |
||
47 | public const POSITION_BOTH = 'both'; |
||
48 | public const POSITION_NONE = 'none'; |
||
49 | |||
50 | public const PLACE_TOP_DIRECTION_DROPDOWN = 'top_direction_dropdown'; |
||
51 | public const PLACE_BOTTOM_DIRECTION_DROPDOWN = 'bottom_direction_dropdown'; |
||
52 | |||
53 | public const DISPLAY_FULL_TEXT = 'F'; |
||
54 | public const DISPLAY_PARTIAL_TEXT = 'P'; |
||
55 | |||
56 | public const HEADER_FLIP_TYPE_AUTO = 'auto'; |
||
57 | public const HEADER_FLIP_TYPE_CSS = 'css'; |
||
58 | public const HEADER_FLIP_TYPE_FAKE = 'fake'; |
||
59 | |||
60 | public const DATE_FIELD = 'date'; |
||
61 | public const DATETIME_FIELD = 'datetime'; |
||
62 | public const TIMESTAMP_FIELD = 'timestamp'; |
||
63 | public const TIME_FIELD = 'time'; |
||
64 | public const STRING_FIELD = 'string'; |
||
65 | public const GEOMETRY_FIELD = 'geometry'; |
||
66 | public const BLOB_FIELD = 'BLOB'; |
||
67 | public const BINARY_FIELD = 'BINARY'; |
||
68 | |||
69 | public const RELATIONAL_KEY = 'K'; |
||
70 | public const RELATIONAL_DISPLAY_COLUMN = 'D'; |
||
71 | |||
72 | public const GEOMETRY_DISP_GEOM = 'GEOM'; |
||
73 | public const GEOMETRY_DISP_WKT = 'WKT'; |
||
74 | public const GEOMETRY_DISP_WKB = 'WKB'; |
||
75 | |||
76 | public const SMART_SORT_ORDER = 'SMART'; |
||
77 | public const ASCENDING_SORT_DIR = 'ASC'; |
||
78 | public const DESCENDING_SORT_DIR = 'DESC'; |
||
79 | |||
80 | public const TABLE_TYPE_INNO_DB = 'InnoDB'; |
||
81 | public const ALL_ROWS = 'all'; |
||
82 | public const QUERY_TYPE_SELECT = 'SELECT'; |
||
83 | |||
84 | public const ROUTINE_PROCEDURE = 'procedure'; |
||
85 | public const ROUTINE_FUNCTION = 'function'; |
||
86 | |||
87 | public const ACTION_LINK_CONTENT_ICONS = 'icons'; |
||
88 | public const ACTION_LINK_CONTENT_TEXT = 'text'; |
||
89 | |||
90 | |||
91 | // Declare global fields |
||
92 | |||
93 | /** array with properties of the class */ |
||
94 | private $_property_array = [ |
||
95 | |||
96 | /** string Database name */ |
||
97 | 'db' => null, |
||
98 | |||
99 | /** string Table name */ |
||
100 | 'table' => null, |
||
101 | |||
102 | /** string the URL to go back in case of errors */ |
||
103 | 'goto' => null, |
||
104 | |||
105 | /** string the SQL query */ |
||
106 | 'sql_query' => null, |
||
107 | |||
108 | /** |
||
109 | * integer the total number of rows returned by the SQL query without any |
||
110 | * appended "LIMIT" clause programmatically |
||
111 | */ |
||
112 | 'unlim_num_rows' => null, |
||
113 | |||
114 | /** array meta information about fields */ |
||
115 | 'fields_meta' => null, |
||
116 | |||
117 | /** boolean */ |
||
118 | 'is_count' => null, |
||
119 | |||
120 | /** integer */ |
||
121 | 'is_export' => null, |
||
122 | |||
123 | /** boolean */ |
||
124 | 'is_func' => null, |
||
125 | |||
126 | /** integer */ |
||
127 | 'is_analyse' => null, |
||
128 | |||
129 | /** integer the total number of rows returned by the SQL query */ |
||
130 | 'num_rows' => null, |
||
131 | |||
132 | /** integer the total number of fields returned by the SQL query */ |
||
133 | 'fields_cnt' => null, |
||
134 | |||
135 | /** double time taken for execute the SQL query */ |
||
136 | 'querytime' => null, |
||
137 | |||
138 | /** string path for theme images directory */ |
||
139 | 'pma_theme_image' => null, |
||
140 | |||
141 | /** string */ |
||
142 | 'text_dir' => null, |
||
143 | |||
144 | /** boolean */ |
||
145 | 'is_maint' => null, |
||
146 | |||
147 | /** boolean */ |
||
148 | 'is_explain' => null, |
||
149 | |||
150 | /** boolean */ |
||
151 | 'is_show' => null, |
||
152 | |||
153 | /** boolean */ |
||
154 | 'is_browse_distinct' => null, |
||
155 | |||
156 | /** array table definitions */ |
||
157 | 'showtable' => null, |
||
158 | |||
159 | /** string */ |
||
160 | 'printview' => null, |
||
161 | |||
162 | /** string URL query */ |
||
163 | 'url_query' => null, |
||
164 | |||
165 | /** array column names to highlight */ |
||
166 | 'highlight_columns' => null, |
||
167 | |||
168 | /** array holding various display information */ |
||
169 | 'display_params' => null, |
||
170 | |||
171 | /** array mime types information of fields */ |
||
172 | 'mime_map' => null, |
||
173 | |||
174 | /** boolean */ |
||
175 | 'editable' => null, |
||
176 | |||
177 | /** random unique ID to distinguish result set */ |
||
178 | 'unique_id' => null, |
||
179 | |||
180 | /** where clauses for each row, each table in the row */ |
||
181 | 'whereClauseMap' => [], |
||
182 | ]; |
||
183 | |||
184 | /** |
||
185 | * This variable contains the column transformation information |
||
186 | * for some of the system databases. |
||
187 | * One element of this array represent all relevant columns in all tables in |
||
188 | * one specific database |
||
189 | */ |
||
190 | public $transformation_info; |
||
191 | |||
192 | /** |
||
193 | * @var Relation |
||
194 | */ |
||
195 | private $relation; |
||
196 | |||
197 | /** |
||
198 | * @var Transformations |
||
199 | */ |
||
200 | private $transformations; |
||
201 | |||
202 | /** |
||
203 | * @var Template |
||
204 | */ |
||
205 | public $template; |
||
206 | |||
207 | /** |
||
208 | * Constructor for PhpMyAdmin\Display\Results class |
||
209 | * |
||
210 | * @param string $db the database name |
||
211 | * @param string $table the table name |
||
212 | * @param string $goto the URL to go back in case of errors |
||
213 | * @param string $sql_query the SQL query |
||
214 | * |
||
215 | * @access public |
||
216 | */ |
||
217 | public function __construct($db, $table, $goto, $sql_query) |
||
218 | { |
||
219 | $this->relation = new Relation($GLOBALS['dbi']); |
||
220 | $this->transformations = new Transformations(); |
||
221 | $this->template = new Template(); |
||
222 | |||
223 | $this->_setDefaultTransformations(); |
||
224 | |||
225 | $this->__set('db', $db); |
||
226 | $this->__set('table', $table); |
||
227 | $this->__set('goto', $goto); |
||
228 | $this->__set('sql_query', $sql_query); |
||
229 | $this->__set('unique_id', rand()); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Get any property of this class |
||
234 | * |
||
235 | * @param string $property name of the property |
||
236 | * |
||
237 | * @return mixed|void if property exist, value of the relevant property |
||
238 | */ |
||
239 | public function __get($property) |
||
240 | { |
||
241 | if (array_key_exists($property, $this->_property_array)) { |
||
242 | return $this->_property_array[$property]; |
||
243 | } |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Set values for any property of this class |
||
248 | * |
||
249 | * @param string $property name of the property |
||
250 | * @param mixed $value value to set |
||
251 | * |
||
252 | * @return void |
||
253 | */ |
||
254 | public function __set($property, $value) |
||
255 | { |
||
256 | if (array_key_exists($property, $this->_property_array)) { |
||
257 | $this->_property_array[$property] = $value; |
||
258 | } |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Sets default transformations for some columns |
||
263 | * |
||
264 | * @return void |
||
265 | */ |
||
266 | private function _setDefaultTransformations() |
||
267 | { |
||
268 | $json_highlighting_data = [ |
||
269 | 'libraries/classes/Plugins/Transformations/Output/Text_Plain_Json.php', |
||
270 | 'PhpMyAdmin\Plugins\Transformations\Output\Text_Plain_Json', |
||
271 | 'Text_Plain' |
||
272 | ]; |
||
273 | $sql_highlighting_data = [ |
||
274 | 'libraries/classes/Plugins/Transformations/Output/Text_Plain_Sql.php', |
||
275 | 'PhpMyAdmin\Plugins\Transformations\Output\Text_Plain_Sql', |
||
276 | 'Text_Plain' |
||
277 | ]; |
||
278 | $blob_sql_highlighting_data = [ |
||
279 | 'libraries/classes/Plugins/Transformations/Output/Text_Octetstream_Sql.php', |
||
280 | 'PhpMyAdmin\Plugins\Transformations\Output\Text_Octetstream_Sql', |
||
281 | 'Text_Octetstream' |
||
282 | ]; |
||
283 | $link_data = [ |
||
284 | 'libraries/classes/Plugins/Transformations/Text_Plain_Link.php', |
||
285 | 'PhpMyAdmin\Plugins\Transformations\Text_Plain_Link', |
||
286 | 'Text_Plain' |
||
287 | ]; |
||
288 | $this->transformation_info = [ |
||
289 | 'information_schema' => [ |
||
290 | 'events' => [ |
||
291 | 'event_definition' => $sql_highlighting_data |
||
292 | ], |
||
293 | 'processlist' => [ |
||
294 | 'info' => $sql_highlighting_data |
||
295 | ], |
||
296 | 'routines' => [ |
||
297 | 'routine_definition' => $sql_highlighting_data |
||
298 | ], |
||
299 | 'triggers' => [ |
||
300 | 'action_statement' => $sql_highlighting_data |
||
301 | ], |
||
302 | 'views' => [ |
||
303 | 'view_definition' => $sql_highlighting_data |
||
304 | ] |
||
305 | ], |
||
306 | 'mysql' => [ |
||
307 | 'event' => [ |
||
308 | 'body' => $blob_sql_highlighting_data, |
||
309 | 'body_utf8' => $blob_sql_highlighting_data |
||
310 | ], |
||
311 | 'general_log' => [ |
||
312 | 'argument' => $sql_highlighting_data |
||
313 | ], |
||
314 | 'help_category' => [ |
||
315 | 'url' => $link_data |
||
316 | ], |
||
317 | 'help_topic' => [ |
||
318 | 'example' => $sql_highlighting_data, |
||
319 | 'url' => $link_data |
||
320 | ], |
||
321 | 'proc' => [ |
||
322 | 'param_list' => $blob_sql_highlighting_data, |
||
323 | 'returns' => $blob_sql_highlighting_data, |
||
324 | 'body' => $blob_sql_highlighting_data, |
||
325 | 'body_utf8' => $blob_sql_highlighting_data |
||
326 | ], |
||
327 | 'slow_log' => [ |
||
328 | 'sql_text' => $sql_highlighting_data |
||
329 | ] |
||
330 | ] |
||
331 | ]; |
||
332 | |||
333 | $cfgRelation = $this->relation->getRelationsParam(); |
||
334 | if ($cfgRelation['db']) { |
||
335 | $this->transformation_info[$cfgRelation['db']] = []; |
||
336 | $relDb = &$this->transformation_info[$cfgRelation['db']]; |
||
337 | if (! empty($cfgRelation['history'])) { |
||
338 | $relDb[$cfgRelation['history']] = [ |
||
339 | 'sqlquery' => $sql_highlighting_data |
||
340 | ]; |
||
341 | } |
||
342 | if (! empty($cfgRelation['bookmark'])) { |
||
343 | $relDb[$cfgRelation['bookmark']] = [ |
||
344 | 'query' => $sql_highlighting_data |
||
345 | ]; |
||
346 | } |
||
347 | if (! empty($cfgRelation['tracking'])) { |
||
348 | $relDb[$cfgRelation['tracking']] = [ |
||
349 | 'schema_sql' => $sql_highlighting_data, |
||
350 | 'data_sql' => $sql_highlighting_data |
||
351 | ]; |
||
352 | } |
||
353 | if (! empty($cfgRelation['favorite'])) { |
||
354 | $relDb[$cfgRelation['favorite']] = [ |
||
355 | 'tables' => $json_highlighting_data |
||
356 | ]; |
||
357 | } |
||
358 | if (! empty($cfgRelation['recent'])) { |
||
359 | $relDb[$cfgRelation['recent']] = [ |
||
360 | 'tables' => $json_highlighting_data |
||
361 | ]; |
||
362 | } |
||
363 | if (! empty($cfgRelation['savedsearches'])) { |
||
364 | $relDb[$cfgRelation['savedsearches']] = [ |
||
365 | 'search_data' => $json_highlighting_data |
||
366 | ]; |
||
367 | } |
||
368 | if (! empty($cfgRelation['designer_settings'])) { |
||
369 | $relDb[$cfgRelation['designer_settings']] = [ |
||
370 | 'settings_data' => $json_highlighting_data |
||
371 | ]; |
||
372 | } |
||
373 | if (! empty($cfgRelation['table_uiprefs'])) { |
||
374 | $relDb[$cfgRelation['table_uiprefs']] = [ |
||
375 | 'prefs' => $json_highlighting_data |
||
376 | ]; |
||
377 | } |
||
378 | if (! empty($cfgRelation['userconfig'])) { |
||
379 | $relDb[$cfgRelation['userconfig']] = [ |
||
380 | 'config_data' => $json_highlighting_data |
||
381 | ]; |
||
382 | } |
||
383 | if (! empty($cfgRelation['export_templates'])) { |
||
384 | $relDb[$cfgRelation['export_templates']] = [ |
||
385 | 'template_data' => $json_highlighting_data |
||
386 | ]; |
||
387 | } |
||
388 | } |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Set properties which were not initialized at the constructor |
||
393 | * |
||
394 | * @param integer $unlim_num_rows the total number of rows returned by |
||
395 | * the SQL query without any appended |
||
396 | * "LIMIT" clause programmatically |
||
397 | * @param stdClass $fields_meta meta information about fields |
||
398 | * @param boolean $is_count statement is SELECT COUNT |
||
399 | * @param integer $is_export statement contains INTO OUTFILE |
||
400 | * @param boolean $is_func statement contains a function like SUM() |
||
401 | * @param integer $is_analyse statement contains PROCEDURE ANALYSE |
||
402 | * @param integer $num_rows total no. of rows returned by SQL query |
||
403 | * @param integer $fields_cnt total no.of fields returned by SQL query |
||
404 | * @param double $querytime time taken for execute the SQL query |
||
405 | * @param string $pmaThemeImage path for theme images directory |
||
406 | * @param string $text_dir text direction |
||
407 | * @param boolean $is_maint statement contains a maintenance command |
||
408 | * @param boolean $is_explain statement contains EXPLAIN |
||
409 | * @param boolean $is_show statement contains SHOW |
||
410 | * @param array $showtable table definitions |
||
411 | * @param string $printview print view was requested |
||
412 | * @param string $url_query URL query |
||
413 | * @param boolean $editable whether the results set is editable |
||
414 | * @param boolean $is_browse_dist whether browsing distinct values |
||
415 | * |
||
416 | * @return void |
||
417 | * |
||
418 | * @see sql.php |
||
419 | */ |
||
420 | public function setProperties( |
||
421 | $unlim_num_rows, |
||
422 | $fields_meta, |
||
423 | $is_count, |
||
424 | $is_export, |
||
425 | $is_func, |
||
426 | $is_analyse, |
||
427 | $num_rows, |
||
428 | $fields_cnt, |
||
429 | $querytime, |
||
430 | $pmaThemeImage, |
||
431 | $text_dir, |
||
432 | $is_maint, |
||
433 | $is_explain, |
||
434 | $is_show, |
||
435 | $showtable, |
||
436 | $printview, |
||
437 | $url_query, |
||
438 | $editable, |
||
439 | $is_browse_dist |
||
440 | ) { |
||
441 | |||
442 | $this->__set('unlim_num_rows', $unlim_num_rows); |
||
443 | $this->__set('fields_meta', $fields_meta); |
||
444 | $this->__set('is_count', $is_count); |
||
445 | $this->__set('is_export', $is_export); |
||
446 | $this->__set('is_func', $is_func); |
||
447 | $this->__set('is_analyse', $is_analyse); |
||
448 | $this->__set('num_rows', $num_rows); |
||
449 | $this->__set('fields_cnt', $fields_cnt); |
||
450 | $this->__set('querytime', $querytime); |
||
451 | $this->__set('pma_theme_image', $pmaThemeImage); |
||
452 | $this->__set('text_dir', $text_dir); |
||
453 | $this->__set('is_maint', $is_maint); |
||
454 | $this->__set('is_explain', $is_explain); |
||
455 | $this->__set('is_show', $is_show); |
||
456 | $this->__set('showtable', $showtable); |
||
457 | $this->__set('printview', $printview); |
||
458 | $this->__set('url_query', $url_query); |
||
459 | $this->__set('editable', $editable); |
||
460 | $this->__set('is_browse_distinct', $is_browse_dist); |
||
461 | } // end of the 'setProperties()' function |
||
462 | |||
463 | |||
464 | /** |
||
465 | * Defines the parts to display for a print view |
||
466 | * |
||
467 | * @param array $displayParts the parts to display |
||
468 | * |
||
469 | * @return array the modified display parts |
||
470 | * |
||
471 | * @access private |
||
472 | * |
||
473 | */ |
||
474 | private function _setDisplayPartsForPrintView(array $displayParts) |
||
475 | { |
||
476 | // set all elements to false! |
||
477 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link |
||
478 | $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link |
||
479 | $displayParts['sort_lnk'] = (string) '0'; |
||
480 | $displayParts['nav_bar'] = (string) '0'; |
||
481 | $displayParts['bkm_form'] = (string) '0'; |
||
482 | $displayParts['text_btn'] = (string) '0'; |
||
483 | $displayParts['pview_lnk'] = (string) '0'; |
||
484 | |||
485 | return $displayParts; |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Defines the parts to display for a SHOW statement |
||
490 | * |
||
491 | * @param array $displayParts the parts to display |
||
492 | * |
||
493 | * @return array the modified display parts |
||
494 | * |
||
495 | * @access private |
||
496 | * |
||
497 | */ |
||
498 | private function _setDisplayPartsForShow(array $displayParts) |
||
499 | { |
||
500 | preg_match( |
||
501 | '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?' |
||
502 | . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS' |
||
503 | . ')@i', |
||
504 | $this->__get('sql_query'), |
||
505 | $which |
||
506 | ); |
||
507 | |||
508 | $bIsProcessList = isset($which[1]); |
||
509 | if ($bIsProcessList) { |
||
510 | $str = ' ' . strtoupper($which[1]); |
||
511 | $bIsProcessList = $bIsProcessList |
||
512 | && strpos($str, 'PROCESSLIST') > 0; |
||
513 | } |
||
514 | |||
515 | if ($bIsProcessList) { |
||
516 | // no edit link |
||
517 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; |
||
518 | // "kill process" type edit link |
||
519 | $displayParts['del_lnk'] = self::KILL_PROCESS; |
||
520 | } else { |
||
521 | // Default case -> no links |
||
522 | // no edit link |
||
523 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; |
||
524 | // no delete link |
||
525 | $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; |
||
526 | } |
||
527 | // Other settings |
||
528 | $displayParts['sort_lnk'] = (string) '0'; |
||
529 | $displayParts['nav_bar'] = (string) '0'; |
||
530 | $displayParts['bkm_form'] = (string) '1'; |
||
531 | $displayParts['text_btn'] = (string) '1'; |
||
532 | $displayParts['pview_lnk'] = (string) '1'; |
||
533 | |||
534 | return $displayParts; |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * Defines the parts to display for statements not related to data |
||
539 | * |
||
540 | * @param array $displayParts the parts to display |
||
541 | * |
||
542 | * @return array the modified display parts |
||
543 | * |
||
544 | * @access private |
||
545 | * |
||
546 | */ |
||
547 | private function _setDisplayPartsForNonData(array $displayParts) |
||
548 | { |
||
549 | // Statement is a "SELECT COUNT", a |
||
550 | // "CHECK/ANALYZE/REPAIR/OPTIMIZE/CHECKSUM", an "EXPLAIN" one or |
||
551 | // contains a "PROC ANALYSE" part |
||
552 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link |
||
553 | $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link |
||
554 | $displayParts['sort_lnk'] = (string) '0'; |
||
555 | $displayParts['nav_bar'] = (string) '0'; |
||
556 | $displayParts['bkm_form'] = (string) '1'; |
||
557 | |||
558 | if ($this->__get('is_maint')) { |
||
559 | $displayParts['text_btn'] = (string) '1'; |
||
560 | } else { |
||
561 | $displayParts['text_btn'] = (string) '0'; |
||
562 | } |
||
563 | $displayParts['pview_lnk'] = (string) '1'; |
||
564 | |||
565 | return $displayParts; |
||
566 | } |
||
567 | |||
568 | /** |
||
569 | * Defines the parts to display for other statements (probably SELECT) |
||
570 | * |
||
571 | * @param array $displayParts the parts to display |
||
572 | * |
||
573 | * @return array the modified display parts |
||
574 | * |
||
575 | * @access private |
||
576 | * |
||
577 | */ |
||
578 | private function _setDisplayPartsForSelect(array $displayParts) |
||
579 | { |
||
580 | // Other statements (ie "SELECT" ones) -> updates |
||
581 | // $displayParts['edit_lnk'], $displayParts['del_lnk'] and |
||
582 | // $displayParts['text_btn'] (keeps other default values) |
||
583 | |||
584 | $fields_meta = $this->__get('fields_meta'); |
||
585 | $prev_table = ''; |
||
586 | $displayParts['text_btn'] = (string) '1'; |
||
587 | $number_of_columns = $this->__get('fields_cnt'); |
||
588 | |||
589 | for ($i = 0; $i < $number_of_columns; $i++) { |
||
590 | $is_link = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
591 | || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) |
||
592 | || ($displayParts['sort_lnk'] != '0'); |
||
593 | |||
594 | // Displays edit/delete/sort/insert links? |
||
595 | if ($is_link |
||
596 | && $prev_table != '' |
||
597 | && $fields_meta[$i]->table != '' |
||
598 | && $fields_meta[$i]->table != $prev_table |
||
599 | ) { |
||
600 | // don't display links |
||
601 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; |
||
602 | $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; |
||
603 | /** |
||
604 | * @todo May be problematic with same field names |
||
605 | * in two joined table. |
||
606 | */ |
||
607 | // $displayParts['sort_lnk'] = (string) '0'; |
||
608 | if ($displayParts['text_btn'] == '1') { |
||
609 | break; |
||
610 | } |
||
611 | } // end if |
||
612 | |||
613 | // Always display print view link |
||
614 | $displayParts['pview_lnk'] = (string) '1'; |
||
615 | if ($fields_meta[$i]->table != '') { |
||
616 | $prev_table = $fields_meta[$i]->table; |
||
617 | } |
||
618 | } // end for |
||
619 | |||
620 | if ($prev_table == '') { // no table for any of the columns |
||
621 | // don't display links |
||
622 | $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; |
||
623 | $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; |
||
624 | } |
||
625 | |||
626 | return $displayParts; |
||
627 | } |
||
628 | |||
629 | /** |
||
630 | * Defines the parts to display for the results of a SQL query |
||
631 | * and the total number of rows |
||
632 | * |
||
633 | * @param array $displayParts the parts to display (see a few |
||
634 | * lines above for explanations) |
||
635 | * |
||
636 | * @return array the first element is an array with explicit indexes |
||
637 | * for all the display elements |
||
638 | * the second element is the total number of rows returned |
||
639 | * by the SQL query without any programmatically appended |
||
640 | * LIMIT clause (just a copy of $unlim_num_rows if it exists, |
||
641 | * else computed inside this function) |
||
642 | * |
||
643 | * |
||
644 | * @access private |
||
645 | * |
||
646 | * @see getTable() |
||
647 | */ |
||
648 | private function _setDisplayPartsAndTotal(array $displayParts) |
||
649 | { |
||
650 | $the_total = 0; |
||
651 | |||
652 | // 1. Following variables are needed for use in isset/empty or |
||
653 | // use with array indexes or safe use in foreach |
||
654 | $db = $this->__get('db'); |
||
655 | $table = $this->__get('table'); |
||
656 | $unlim_num_rows = $this->__get('unlim_num_rows'); |
||
657 | $num_rows = $this->__get('num_rows'); |
||
658 | $printview = $this->__get('printview'); |
||
659 | |||
660 | // 2. Updates the display parts |
||
661 | if ($printview == '1') { |
||
662 | $displayParts = $this->_setDisplayPartsForPrintView($displayParts); |
||
663 | } elseif ($this->__get('is_count') || $this->__get('is_analyse') |
||
664 | || $this->__get('is_maint') || $this->__get('is_explain') |
||
665 | ) { |
||
666 | $displayParts = $this->_setDisplayPartsForNonData($displayParts); |
||
667 | } elseif ($this->__get('is_show')) { |
||
668 | $displayParts = $this->_setDisplayPartsForShow($displayParts); |
||
669 | } else { |
||
670 | $displayParts = $this->_setDisplayPartsForSelect($displayParts); |
||
671 | } // end if..elseif...else |
||
672 | |||
673 | // 3. Gets the total number of rows if it is unknown |
||
674 | if (isset($unlim_num_rows) && $unlim_num_rows != '') { |
||
675 | $the_total = $unlim_num_rows; |
||
676 | } elseif ((($displayParts['nav_bar'] == '1') |
||
677 | || ($displayParts['sort_lnk'] == '1')) |
||
678 | && (strlen($db) > 0 && strlen($table) > 0) |
||
679 | ) { |
||
680 | $the_total = $GLOBALS['dbi']->getTable($db, $table)->countRecords(); |
||
681 | } |
||
682 | |||
683 | // if for COUNT query, number of rows returned more than 1 |
||
684 | // (may be being used GROUP BY) |
||
685 | if ($this->__get('is_count') && isset($num_rows) && $num_rows > 1) { |
||
686 | $displayParts['nav_bar'] = (string) '1'; |
||
687 | $displayParts['sort_lnk'] = (string) '1'; |
||
688 | } |
||
689 | // 4. If navigation bar or sorting fields names URLs should be |
||
690 | // displayed but there is only one row, change these settings to |
||
691 | // false |
||
692 | if ($displayParts['nav_bar'] == '1' || $displayParts['sort_lnk'] == '1') { |
||
693 | // - Do not display sort links if less than 2 rows. |
||
694 | // - For a VIEW we (probably) did not count the number of rows |
||
695 | // so don't test this number here, it would remove the possibility |
||
696 | // of sorting VIEW results. |
||
697 | $_table = new Table($table, $db); |
||
698 | if (isset($unlim_num_rows) |
||
699 | && ($unlim_num_rows < 2) |
||
700 | && ! $_table->isView() |
||
701 | ) { |
||
702 | $displayParts['sort_lnk'] = (string) '0'; |
||
703 | } |
||
704 | } // end if (3) |
||
705 | |||
706 | return [$displayParts, $the_total]; |
||
707 | } // end of the 'setDisplayPartsAndTotal()' function |
||
708 | |||
709 | |||
710 | /** |
||
711 | * Return true if we are executing a query in the form of |
||
712 | * "SELECT * FROM <a table> ..." |
||
713 | * |
||
714 | * @param array $analyzed_sql_results analyzed sql results |
||
715 | * |
||
716 | * @return boolean |
||
717 | * |
||
718 | * @access private |
||
719 | * |
||
720 | * @see _getTableHeaders(), _getColumnParams() |
||
721 | */ |
||
722 | private function _isSelect(array $analyzed_sql_results) |
||
723 | { |
||
724 | return ! ($this->__get('is_count') |
||
725 | || $this->__get('is_export') |
||
726 | || $this->__get('is_func') |
||
727 | || $this->__get('is_analyse')) |
||
728 | && !empty($analyzed_sql_results['select_from']) |
||
729 | && !empty($analyzed_sql_results['statement']->from) |
||
730 | && (count($analyzed_sql_results['statement']->from) == 1) |
||
731 | && !empty($analyzed_sql_results['statement']->from[0]->table); |
||
732 | } |
||
733 | |||
734 | |||
735 | /** |
||
736 | * Get a navigation button |
||
737 | * |
||
738 | * @param string $caption iconic caption for button |
||
739 | * @param string $title text for button |
||
740 | * @param integer $pos position for next query |
||
741 | * @param string $html_sql_query query ready for display |
||
742 | * @param boolean $back whether 'begin' or 'previous' |
||
743 | * @param string $onsubmit optional onsubmit clause |
||
744 | * @param string $input_for_real_end optional hidden field for special treatment |
||
745 | * @param string $onclick optional onclick clause |
||
746 | * |
||
747 | * @return string html content |
||
748 | * |
||
749 | * @access private |
||
750 | * |
||
751 | * @see _getMoveBackwardButtonsForTableNavigation(), |
||
752 | * _getMoveForwardButtonsForTableNavigation() |
||
753 | */ |
||
754 | private function _getTableNavigationButton( |
||
755 | $caption, |
||
756 | $title, |
||
757 | $pos, |
||
758 | $html_sql_query, |
||
759 | $back, |
||
760 | $onsubmit = '', |
||
761 | $input_for_real_end = '', |
||
762 | $onclick = '' |
||
763 | ) { |
||
764 | $caption_output = ''; |
||
765 | if ($back) { |
||
766 | if (Util::showIcons('TableNavigationLinksMode')) { |
||
767 | $caption_output .= $caption; |
||
768 | } |
||
769 | if (Util::showText('TableNavigationLinksMode')) { |
||
770 | $caption_output .= ' ' . $title; |
||
771 | } |
||
772 | } else { |
||
773 | if (Util::showText('TableNavigationLinksMode')) { |
||
774 | $caption_output .= $title; |
||
775 | } |
||
776 | if (Util::showIcons('TableNavigationLinksMode')) { |
||
777 | $caption_output .= ' ' . $caption; |
||
778 | } |
||
779 | } |
||
780 | |||
781 | return $this->template->render('display/results/table_navigation_button', [ |
||
782 | 'db' => $this->__get('db'), |
||
783 | 'table' => $this->__get('table'), |
||
784 | 'sql_query' => $html_sql_query, |
||
785 | 'pos' => $pos, |
||
786 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
787 | 'goto' => $this->__get('goto'), |
||
788 | 'input_for_real_end' => $input_for_real_end, |
||
789 | 'caption_output' => $caption_output, |
||
790 | 'title' => $title, |
||
791 | 'onsubmit' => $onsubmit, |
||
792 | 'onclick' => $onclick, |
||
793 | ]); |
||
794 | } |
||
795 | |||
796 | /** |
||
797 | * Possibly return a page selector for table navigation |
||
798 | * |
||
799 | * @param string $table_navigation_html the current navigation HTML |
||
800 | * |
||
801 | * @return array ($table_navigation_html, $nbTotalPage) |
||
802 | * |
||
803 | * @access private |
||
804 | * |
||
805 | */ |
||
806 | private function _getHtmlPageSelector($table_navigation_html) |
||
807 | { |
||
808 | $pageNow = @floor( |
||
809 | $_SESSION['tmpval']['pos'] |
||
810 | / $_SESSION['tmpval']['max_rows'] |
||
811 | ) + 1; |
||
812 | |||
813 | $nbTotalPage = @ceil( |
||
814 | $this->__get('unlim_num_rows') |
||
815 | / $_SESSION['tmpval']['max_rows'] |
||
816 | ); |
||
817 | |||
818 | if ($nbTotalPage > 1) { |
||
819 | $table_navigation_html .= '<td>'; |
||
820 | $_url_params = [ |
||
821 | 'db' => $this->__get('db'), |
||
822 | 'table' => $this->__get('table'), |
||
823 | 'sql_query' => $this->__get('sql_query'), |
||
824 | 'goto' => $this->__get('goto'), |
||
825 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
826 | ]; |
||
827 | |||
828 | //<form> to keep the form alignment of button < and << |
||
829 | // and also to know what to execute when the selector changes |
||
830 | $table_navigation_html .= '<form action="sql.php" method="post">'; |
||
831 | $table_navigation_html .= Url::getHiddenInputs($_url_params); |
||
832 | |||
833 | $table_navigation_html .= Util::pageselector( |
||
834 | 'pos', |
||
835 | $_SESSION['tmpval']['max_rows'], |
||
836 | $pageNow, |
||
837 | $nbTotalPage, |
||
838 | 200, |
||
839 | 5, |
||
840 | 5, |
||
841 | 20, |
||
842 | 10 |
||
843 | ); |
||
844 | |||
845 | $table_navigation_html .= '</form>' |
||
846 | . '</td>'; |
||
847 | } |
||
848 | return [$table_navigation_html, $nbTotalPage]; |
||
849 | } |
||
850 | |||
851 | /** |
||
852 | * Get a navigation bar to browse among the results of a SQL query |
||
853 | * |
||
854 | * @param integer $pos_next the offset for the "next" page |
||
855 | * @param integer $pos_prev the offset for the "previous" page |
||
856 | * @param boolean $is_innodb whether its InnoDB or not |
||
857 | * @param string $sort_by_key_html the sort by key dialog |
||
858 | * |
||
859 | * @return string html content |
||
860 | * |
||
861 | * @access private |
||
862 | * |
||
863 | * @see _getTable() |
||
864 | */ |
||
865 | private function _getTableNavigation( |
||
866 | $pos_next, |
||
867 | $pos_prev, |
||
868 | $is_innodb, |
||
869 | $sort_by_key_html |
||
870 | ) { |
||
871 | |||
872 | $table_navigation_html = ''; |
||
873 | |||
874 | // here, using htmlentities() would cause problems if the query |
||
875 | // contains accented characters |
||
876 | $html_sql_query = htmlspecialchars($this->__get('sql_query')); |
||
877 | |||
878 | // Navigation bar |
||
879 | $table_navigation_html |
||
880 | .= '<table class="navigation nospacing nopadding print_ignore">' |
||
881 | . '<tr>' |
||
882 | . '<td class="navigation_separator"></td>'; |
||
883 | |||
884 | // Move to the beginning or to the previous page |
||
885 | if ($_SESSION['tmpval']['pos'] |
||
886 | && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) |
||
887 | ) { |
||
888 | $table_navigation_html |
||
889 | .= $this->_getMoveBackwardButtonsForTableNavigation( |
||
890 | $html_sql_query, |
||
891 | $pos_prev |
||
892 | ); |
||
893 | } // end move back |
||
894 | |||
895 | $nbTotalPage = 1; |
||
896 | //page redirection |
||
897 | // (unless we are showing all records) |
||
898 | if ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) { |
||
899 | list( |
||
900 | $table_navigation_html, |
||
901 | $nbTotalPage |
||
902 | ) = $this->_getHtmlPageSelector($table_navigation_html); |
||
903 | } |
||
904 | |||
905 | $showing_all = false; |
||
906 | if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) { |
||
907 | $showing_all = true; |
||
908 | } |
||
909 | |||
910 | // Move to the next page or to the last one |
||
911 | if ($this->__get('unlim_num_rows') === false // view with unknown number of rows |
||
912 | || ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS |
||
913 | && $_SESSION['tmpval']['pos'] + $_SESSION['tmpval']['max_rows'] < $this->__get('unlim_num_rows') |
||
914 | && $this->__get('num_rows') >= $_SESSION['tmpval']['max_rows']) |
||
915 | ) { |
||
916 | $table_navigation_html |
||
917 | .= $this->_getMoveForwardButtonsForTableNavigation( |
||
918 | $html_sql_query, |
||
919 | $pos_next, |
||
920 | $is_innodb |
||
921 | ); |
||
922 | } // end move toward |
||
923 | |||
924 | // show separator if pagination happen |
||
925 | if ($nbTotalPage > 1) { |
||
926 | $table_navigation_html |
||
927 | .= '<td><div class="navigation_separator">|</div></td>'; |
||
928 | } |
||
929 | |||
930 | // Display the "Show all" button if allowed |
||
931 | if ($GLOBALS['cfg']['ShowAll'] || ($this->__get('unlim_num_rows') <= 500)) { |
||
932 | $table_navigation_html .= $this->_getShowAllCheckboxForTableNavigation( |
||
933 | $showing_all, |
||
934 | $html_sql_query |
||
935 | ); |
||
936 | |||
937 | $table_navigation_html |
||
938 | .= '<td><div class="navigation_separator">|</div></td>'; |
||
939 | } // end show all |
||
940 | |||
941 | $table_navigation_html .= '<td>' |
||
942 | . '<div class="save_edited hide">' |
||
943 | . '<input type="submit" value="' . __('Save edited data') . '" />' |
||
944 | . '<div class="navigation_separator">|</div>' |
||
945 | . '</div>' |
||
946 | . '</td>' |
||
947 | . '<td>' |
||
948 | . '<div class="restore_column hide">' |
||
949 | . '<input type="submit" value="' . __('Restore column order') . '" />' |
||
950 | . '<div class="navigation_separator">|</div>' |
||
951 | . '</div>' |
||
952 | . '</td>'; |
||
953 | |||
954 | // if displaying a VIEW, $unlim_num_rows could be zero because |
||
955 | // of $cfg['MaxExactCountViews']; in this case, avoid passing |
||
956 | // the 5th parameter to checkFormElementInRange() |
||
957 | // (this means we can't validate the upper limit |
||
958 | $table_navigation_html .= '<td class="navigation_goto">'; |
||
959 | |||
960 | $table_navigation_html .= '<form action="sql.php" method="post" ' |
||
961 | . 'onsubmit="return ' |
||
962 | . '(checkFormElementInRange(' |
||
963 | . 'this, ' |
||
964 | . '\'session_max_rows\', ' |
||
965 | . '\'' |
||
966 | . str_replace('\'', '\\\'', __('%d is not valid row number.')) |
||
967 | . '\', ' |
||
968 | . '1)' |
||
969 | . ' && ' |
||
970 | . 'checkFormElementInRange(' |
||
971 | . 'this, ' |
||
972 | . '\'pos\', ' |
||
973 | . '\'' |
||
974 | . str_replace('\'', '\\\'', __('%d is not valid row number.')) |
||
975 | . '\', ' |
||
976 | . '0' |
||
977 | . (($this->__get('unlim_num_rows') > 0) |
||
978 | ? ', ' . ($this->__get('unlim_num_rows') - 1) |
||
979 | : '' |
||
980 | ) |
||
981 | . ')' |
||
982 | . ')' |
||
983 | . '">'; |
||
984 | |||
985 | $table_navigation_html .= Url::getHiddenInputs( |
||
986 | $this->__get('db'), |
||
987 | $this->__get('table') |
||
988 | ); |
||
989 | |||
990 | $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation( |
||
991 | $html_sql_query |
||
992 | ); |
||
993 | |||
994 | $table_navigation_html .= '</form>' |
||
995 | . '</td>' |
||
996 | . '<td class="navigation_separator"></td>' |
||
997 | . '<td class="largescreenonly">' |
||
998 | . '<span>' . __('Filter rows') . ':</span>' |
||
999 | . '<input type="text" class="filter_rows"' |
||
1000 | . ' placeholder="' . __('Search this table') . '"' |
||
1001 | . ' data-for="' . $this->__get('unique_id') . '" />' |
||
1002 | . '</td>'; |
||
1003 | |||
1004 | $table_navigation_html .= '<td class="largescreenonly">' . $sort_by_key_html . '</td>'; |
||
1005 | |||
1006 | $table_navigation_html .= '<td class="navigation_separator"></td>' |
||
1007 | . '</tr>' |
||
1008 | . '</table>'; |
||
1009 | |||
1010 | return $table_navigation_html; |
||
1011 | } // end of the '_getTableNavigation()' function |
||
1012 | |||
1013 | |||
1014 | /** |
||
1015 | * Prepare move backward buttons - previous and first |
||
1016 | * |
||
1017 | * @param string $html_sql_query the sql encoded by html special characters |
||
1018 | * @param integer $pos_prev the offset for the "previous" page |
||
1019 | * |
||
1020 | * @return string html content |
||
1021 | * |
||
1022 | * @access private |
||
1023 | * |
||
1024 | * @see _getTableNavigation() |
||
1025 | */ |
||
1026 | private function _getMoveBackwardButtonsForTableNavigation( |
||
1027 | $html_sql_query, |
||
1028 | $pos_prev |
||
1029 | ) { |
||
1030 | return $this->_getTableNavigationButton( |
||
1031 | '<<', |
||
1032 | _pgettext('First page', 'Begin'), |
||
1033 | 0, |
||
1034 | $html_sql_query, |
||
1035 | true |
||
1036 | ) |
||
1037 | . $this->_getTableNavigationButton( |
||
1038 | '<', |
||
1039 | _pgettext('Previous page', 'Previous'), |
||
1040 | $pos_prev, |
||
1041 | $html_sql_query, |
||
1042 | true |
||
1043 | ); |
||
1044 | } // end of the '_getMoveBackwardButtonsForTableNavigation()' function |
||
1045 | |||
1046 | |||
1047 | /** |
||
1048 | * Prepare Show All checkbox for table navigation |
||
1049 | * |
||
1050 | * @param bool $showing_all whether all rows are shown currently |
||
1051 | * @param string $html_sql_query the sql encoded by html special characters |
||
1052 | * |
||
1053 | * @return string html content |
||
1054 | * |
||
1055 | * @access private |
||
1056 | * |
||
1057 | * @see _getTableNavigation() |
||
1058 | */ |
||
1059 | private function _getShowAllCheckboxForTableNavigation( |
||
1060 | $showing_all, |
||
1061 | $html_sql_query |
||
1062 | ) { |
||
1063 | return $this->template->render('display/results/show_all_checkbox', [ |
||
1064 | 'db' => $this->__get('db'), |
||
1065 | 'table' => $this->__get('table'), |
||
1066 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
1067 | 'goto' => $this->__get('goto'), |
||
1068 | 'unique_id' => $this->__get('unique_id'), |
||
1069 | 'html_sql_query' => $html_sql_query, |
||
1070 | 'showing_all' => $showing_all, |
||
1071 | 'max_rows' => intval($GLOBALS['cfg']['MaxRows']), |
||
1072 | ]); |
||
1073 | } // end of the '_getShowAllButtonForTableNavigation()' function |
||
1074 | |||
1075 | |||
1076 | /** |
||
1077 | * Prepare move forward buttons - next and last |
||
1078 | * |
||
1079 | * @param string $html_sql_query the sql encoded by htmlspecialchars() |
||
1080 | * @param integer $pos_next the offset for the "next" page |
||
1081 | * @param boolean $is_innodb whether it's InnoDB or not |
||
1082 | * |
||
1083 | * @return string html content |
||
1084 | * |
||
1085 | * @access private |
||
1086 | * |
||
1087 | * @see _getTableNavigation() |
||
1088 | */ |
||
1089 | private function _getMoveForwardButtonsForTableNavigation( |
||
1090 | $html_sql_query, |
||
1091 | $pos_next, |
||
1092 | $is_innodb |
||
1093 | ) { |
||
1094 | |||
1095 | // display the Next button |
||
1096 | $buttons_html = $this->_getTableNavigationButton( |
||
1097 | '>', |
||
1098 | _pgettext('Next page', 'Next'), |
||
1099 | $pos_next, |
||
1100 | $html_sql_query, |
||
1101 | false |
||
1102 | ); |
||
1103 | |||
1104 | // prepare some options for the End button |
||
1105 | if ($is_innodb |
||
1106 | && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount'] |
||
1107 | ) { |
||
1108 | $input_for_real_end = '<input id="real_end_input" type="hidden" ' |
||
1109 | . 'name="find_real_end" value="1" />'; |
||
1110 | // no backquote around this message |
||
1111 | $onclick = ''; |
||
1112 | } else { |
||
1113 | $input_for_real_end = $onclick = ''; |
||
1114 | } |
||
1115 | |||
1116 | $maxRows = $_SESSION['tmpval']['max_rows']; |
||
1117 | $onsubmit = 'onsubmit="return ' |
||
1118 | . (($_SESSION['tmpval']['pos'] |
||
1119 | + $maxRows |
||
1120 | < $this->__get('unlim_num_rows') |
||
1121 | && $this->__get('num_rows') >= $maxRows) |
||
1122 | ? 'true' |
||
1123 | : 'false') . '"'; |
||
1124 | |||
1125 | // display the End button |
||
1126 | $buttons_html .= $this->_getTableNavigationButton( |
||
1127 | '>>', |
||
1128 | _pgettext('Last page', 'End'), |
||
1129 | @((ceil( |
||
1130 | $this->__get('unlim_num_rows') |
||
1131 | / $_SESSION['tmpval']['max_rows'] |
||
1132 | ) - 1) * $maxRows), |
||
1133 | $html_sql_query, |
||
1134 | false, |
||
1135 | $onsubmit, |
||
1136 | $input_for_real_end, |
||
1137 | $onclick |
||
1138 | ); |
||
1139 | |||
1140 | return $buttons_html; |
||
1141 | } // end of the '_getMoveForwardButtonsForTableNavigation()' function |
||
1142 | |||
1143 | |||
1144 | /** |
||
1145 | * Prepare fields for table navigation |
||
1146 | * Number of rows |
||
1147 | * |
||
1148 | * @param string $sqlQuery the sql encoded by htmlspecialchars() |
||
1149 | * |
||
1150 | * @return string html content |
||
1151 | * |
||
1152 | * @access private |
||
1153 | * |
||
1154 | * @see _getTableNavigation() |
||
1155 | */ |
||
1156 | private function _getAdditionalFieldsForTableNavigation($sqlQuery) |
||
1157 | { |
||
1158 | $numberOfRowsPlaceholder = null; |
||
1159 | if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) { |
||
1160 | $numberOfRowsPlaceholder = __('All'); |
||
1161 | } |
||
1162 | |||
1163 | $numberOfRowsChoices = [ |
||
1164 | '25' => 25, |
||
1165 | '50' => 50, |
||
1166 | '100' => 100, |
||
1167 | '250' => 250, |
||
1168 | '500' => 500 |
||
1169 | ]; |
||
1170 | |||
1171 | return $this->template->render('display/results/additional_fields', [ |
||
1172 | 'goto' => $this->__get('goto'), |
||
1173 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
1174 | 'sql_query' => $sqlQuery, |
||
1175 | 'number_of_rows_choices' => $numberOfRowsChoices, |
||
1176 | 'number_of_rows_placeholder' => $numberOfRowsPlaceholder, |
||
1177 | 'pos' => $_SESSION['tmpval']['pos'], |
||
1178 | 'max_rows' => $_SESSION['tmpval']['max_rows'], |
||
1179 | ]); |
||
1180 | } |
||
1181 | |||
1182 | /** |
||
1183 | * Get the headers of the results table, for all of the columns |
||
1184 | * |
||
1185 | * @param array $displayParts which elements to display |
||
1186 | * @param array $analyzed_sql_results analyzed sql results |
||
1187 | * @param array $sort_expression sort expression |
||
1188 | * @param array $sort_expression_nodirection sort expression |
||
1189 | * without direction |
||
1190 | * @param array $sort_direction sort direction |
||
1191 | * @param boolean $is_limited_display with limited operations |
||
1192 | * or not |
||
1193 | * @param string $unsorted_sql_query query without the sort part |
||
1194 | * |
||
1195 | * @return string html content |
||
1196 | * |
||
1197 | * @access private |
||
1198 | * |
||
1199 | * @see getTableHeaders() |
||
1200 | */ |
||
1201 | private function _getTableHeadersForColumns( |
||
1202 | array $displayParts, |
||
1203 | array $analyzed_sql_results, |
||
1204 | array $sort_expression, |
||
1205 | array $sort_expression_nodirection, |
||
1206 | array $sort_direction, |
||
1207 | $is_limited_display, |
||
1208 | $unsorted_sql_query |
||
1209 | ) { |
||
1210 | $html = ''; |
||
1211 | |||
1212 | // required to generate sort links that will remember whether the |
||
1213 | // "Show all" button has been clicked |
||
1214 | $sql_md5 = md5($this->__get('sql_query')); |
||
1215 | $session_max_rows = $is_limited_display |
||
1216 | ? 0 |
||
1217 | : $_SESSION['tmpval']['query'][$sql_md5]['max_rows']; |
||
1218 | |||
1219 | // Following variable are needed for use in isset/empty or |
||
1220 | // use with array indexes/safe use in the for loop |
||
1221 | $highlight_columns = $this->__get('highlight_columns'); |
||
1222 | $fields_meta = $this->__get('fields_meta'); |
||
1223 | |||
1224 | // Prepare Display column comments if enabled |
||
1225 | // ($GLOBALS['cfg']['ShowBrowseComments']). |
||
1226 | $comments_map = $this->_getTableCommentsArray($analyzed_sql_results); |
||
1227 | |||
1228 | list($col_order, $col_visib) = $this->_getColumnParams( |
||
1229 | $analyzed_sql_results |
||
1230 | ); |
||
1231 | |||
1232 | // optimize: avoid calling a method on each iteration |
||
1233 | $number_of_columns = $this->__get('fields_cnt'); |
||
1234 | |||
1235 | for ($j = 0; $j < $number_of_columns; $j++) { |
||
1236 | // assign $i with the appropriate column order |
||
1237 | $i = $col_order ? $col_order[$j] : $j; |
||
1238 | |||
1239 | // See if this column should get highlight because it's used in the |
||
1240 | // where-query. |
||
1241 | $name = $fields_meta[$i]->name; |
||
1242 | $condition_field = (isset($highlight_columns[$name]) |
||
1243 | || isset($highlight_columns[Util::backquote($name)])) |
||
1244 | ? true |
||
1245 | : false; |
||
1246 | |||
1247 | // Prepare comment-HTML-wrappers for each row, if defined/enabled. |
||
1248 | $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]); |
||
1249 | $display_params = $this->__get('display_params'); |
||
1250 | |||
1251 | if (($displayParts['sort_lnk'] == '1') && ! $is_limited_display) { |
||
1252 | list($order_link, $sorted_header_html) |
||
1253 | = $this->_getOrderLinkAndSortedHeaderHtml( |
||
1254 | $fields_meta[$i], |
||
1255 | $sort_expression, |
||
1256 | $sort_expression_nodirection, |
||
1257 | $i, |
||
1258 | $unsorted_sql_query, |
||
1259 | $session_max_rows, |
||
1260 | $comments, |
||
1261 | $sort_direction, |
||
1262 | $col_visib, |
||
1263 | $col_visib[$j] |
||
1264 | ); |
||
1265 | |||
1266 | $html .= $sorted_header_html; |
||
1267 | |||
1268 | $display_params['desc'][] = ' <th ' |
||
1269 | . 'class="draggable' |
||
1270 | . ($condition_field ? ' condition' : '') |
||
1271 | . '" data-column="' . htmlspecialchars($fields_meta[$i]->name) |
||
1272 | . '">' . "\n" . $order_link . $comments . ' </th>' . "\n"; |
||
1273 | } else { |
||
1274 | // Results can't be sorted |
||
1275 | $html |
||
1276 | .= $this->_getDraggableClassForNonSortableColumns( |
||
1277 | $col_visib, |
||
1278 | $col_visib[$j], |
||
1279 | $condition_field, |
||
1280 | $fields_meta[$i], |
||
1281 | $comments |
||
1282 | ); |
||
1283 | |||
1284 | $display_params['desc'][] = ' <th ' |
||
1285 | . 'class="draggable' |
||
1286 | . ($condition_field ? ' condition"' : '') |
||
1287 | . '" data-column="' . htmlspecialchars((string) $fields_meta[$i]->name) |
||
1288 | . '">' . ' ' |
||
1289 | . htmlspecialchars((string) $fields_meta[$i]->name) |
||
1290 | . $comments . ' </th>'; |
||
1291 | } // end else |
||
1292 | |||
1293 | $this->__set('display_params', $display_params); |
||
1294 | } // end for |
||
1295 | return $html; |
||
1296 | } |
||
1297 | |||
1298 | /** |
||
1299 | * Get the headers of the results table |
||
1300 | * |
||
1301 | * @param array &$displayParts which elements to display |
||
1302 | * @param array $analyzed_sql_results analyzed sql results |
||
1303 | * @param string $unsorted_sql_query the unsorted sql query |
||
1304 | * @param array $sort_expression sort expression |
||
1305 | * @param array|string $sort_expression_nodirection sort expression |
||
1306 | * without direction |
||
1307 | * @param array $sort_direction sort direction |
||
1308 | * @param boolean $is_limited_display with limited operations |
||
1309 | * or not |
||
1310 | * |
||
1311 | * @return string html content |
||
1312 | * |
||
1313 | * @access private |
||
1314 | * |
||
1315 | * @see getTable() |
||
1316 | */ |
||
1317 | private function _getTableHeaders( |
||
1318 | array &$displayParts, |
||
1319 | array $analyzed_sql_results, |
||
1320 | $unsorted_sql_query, |
||
1321 | array $sort_expression = [], |
||
1322 | $sort_expression_nodirection = '', |
||
1323 | array $sort_direction = [], |
||
1324 | $is_limited_display = false |
||
1325 | ) { |
||
1326 | |||
1327 | $table_headers_html = ''; |
||
1328 | // Needed for use in isset/empty or |
||
1329 | // use with array indexes/safe use in foreach |
||
1330 | $printview = $this->__get('printview'); |
||
1331 | $display_params = $this->__get('display_params'); |
||
1332 | |||
1333 | // Output data needed for grid editing |
||
1334 | $table_headers_html .= '<input class="save_cells_at_once" type="hidden"' |
||
1335 | . ' value="' . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />' |
||
1336 | . '<div class="common_hidden_inputs">' |
||
1337 | . Url::getHiddenInputs( |
||
1338 | $this->__get('db'), |
||
1339 | $this->__get('table') |
||
1340 | ) |
||
1341 | . '</div>'; |
||
1342 | |||
1343 | // Output data needed for column reordering and show/hide column |
||
1344 | $table_headers_html .= $this->_getDataForResettingColumnOrder($analyzed_sql_results); |
||
1345 | |||
1346 | $display_params['emptypre'] = 0; |
||
1347 | $display_params['emptyafter'] = 0; |
||
1348 | $display_params['textbtn'] = ''; |
||
1349 | $full_or_partial_text_link = null; |
||
1350 | |||
1351 | $this->__set('display_params', $display_params); |
||
1352 | |||
1353 | // Display options (if we are not in print view) |
||
1354 | if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) { |
||
1355 | $table_headers_html .= $this->_getOptionsBlock(); |
||
1356 | |||
1357 | // prepare full/partial text button or link |
||
1358 | $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink(); |
||
1359 | } |
||
1360 | |||
1361 | // Start of form for multi-rows edit/delete/export |
||
1362 | $table_headers_html .= $this->_getFormForMultiRowOperations( |
||
1363 | $displayParts['del_lnk'] |
||
1364 | ); |
||
1365 | |||
1366 | // 1. Set $colspan and generate html with full/partial |
||
1367 | // text button or link |
||
1368 | list($colspan, $button_html) |
||
1369 | = $this->_getFieldVisibilityParams( |
||
1370 | $displayParts, |
||
1371 | $full_or_partial_text_link |
||
1372 | ); |
||
1373 | |||
1374 | $table_headers_html .= $button_html; |
||
1375 | |||
1376 | // 2. Displays the fields' name |
||
1377 | // 2.0 If sorting links should be used, checks if the query is a "JOIN" |
||
1378 | // statement (see 2.1.3) |
||
1379 | |||
1380 | // See if we have to highlight any header fields of a WHERE query. |
||
1381 | // Uses SQL-Parser results. |
||
1382 | $this->_setHighlightedColumnGlobalField($analyzed_sql_results); |
||
1383 | |||
1384 | // Get the headers for all of the columns |
||
1385 | $table_headers_html .= $this->_getTableHeadersForColumns( |
||
1386 | $displayParts, |
||
1387 | $analyzed_sql_results, |
||
1388 | $sort_expression, |
||
1389 | $sort_expression_nodirection, |
||
1390 | $sort_direction, |
||
1391 | $is_limited_display, |
||
1392 | $unsorted_sql_query |
||
1393 | ); |
||
1394 | |||
1395 | // Display column at rightside - checkboxes or empty column |
||
1396 | if (! $printview) { |
||
1397 | $table_headers_html .= $this->_getColumnAtRightSide( |
||
1398 | $displayParts, |
||
1399 | $full_or_partial_text_link, |
||
1400 | $colspan |
||
1401 | ); |
||
1402 | } |
||
1403 | $table_headers_html .= '</tr>' . '</thead>'; |
||
1404 | |||
1405 | return $table_headers_html; |
||
1406 | } // end of the '_getTableHeaders()' function |
||
1407 | |||
1408 | |||
1409 | /** |
||
1410 | * Prepare unsorted sql query and sort by key drop down |
||
1411 | * |
||
1412 | * @param array $analyzed_sql_results analyzed sql results |
||
1413 | * @param array|null $sort_expression sort expression |
||
1414 | * |
||
1415 | * @return array two element array - $unsorted_sql_query, $drop_down_html |
||
1416 | * |
||
1417 | * @access private |
||
1418 | * |
||
1419 | * @see _getTableHeaders() |
||
1420 | */ |
||
1421 | private function _getUnsortedSqlAndSortByKeyDropDown( |
||
1422 | array $analyzed_sql_results, |
||
1423 | ?array $sort_expression |
||
1424 | ) { |
||
1425 | $drop_down_html = ''; |
||
1426 | |||
1427 | $unsorted_sql_query = Query::replaceClause( |
||
1428 | $analyzed_sql_results['statement'], |
||
1429 | $analyzed_sql_results['parser']->list, |
||
1430 | 'ORDER BY', |
||
1431 | '' |
||
1432 | ); |
||
1433 | |||
1434 | // Data is sorted by indexes only if it there is only one table. |
||
1435 | if ($this->_isSelect($analyzed_sql_results)) { |
||
1436 | // grab indexes data: |
||
1437 | $indexes = Index::getFromTable( |
||
1438 | $this->__get('table'), |
||
1439 | $this->__get('db') |
||
1440 | ); |
||
1441 | |||
1442 | // do we have any index? |
||
1443 | if (! empty($indexes)) { |
||
1444 | $drop_down_html = $this->_getSortByKeyDropDown( |
||
1445 | $indexes, |
||
1446 | $sort_expression, |
||
1447 | $unsorted_sql_query |
||
1448 | ); |
||
1449 | } |
||
1450 | } |
||
1451 | |||
1452 | return [$unsorted_sql_query, $drop_down_html]; |
||
1453 | } // end of the '_getUnsortedSqlAndSortByKeyDropDown()' function |
||
1454 | |||
1455 | /** |
||
1456 | * Prepare sort by key dropdown - html code segment |
||
1457 | * |
||
1458 | * @param Index[] $indexes the indexes of the table for sort criteria |
||
1459 | * @param array|null $sort_expression the sort expression |
||
1460 | * @param string $unsorted_sql_query the unsorted sql query |
||
1461 | * |
||
1462 | * @return string html content |
||
1463 | * |
||
1464 | * @access private |
||
1465 | * |
||
1466 | * @see _getTableHeaders() |
||
1467 | */ |
||
1468 | private function _getSortByKeyDropDown( |
||
1469 | $indexes, |
||
1470 | ?array $sort_expression, |
||
1471 | $unsorted_sql_query |
||
1472 | ) { |
||
1473 | |||
1474 | $drop_down_html = ''; |
||
1475 | |||
1476 | $drop_down_html .= '<form action="sql.php" method="post" ' . |
||
1477 | 'class="print_ignore">' . "\n" |
||
1478 | . Url::getHiddenInputs( |
||
1479 | $this->__get('db'), |
||
1480 | $this->__get('table') |
||
1481 | ) |
||
1482 | . Url::getHiddenFields(['sort_by_key' => '1'], '', true) |
||
1483 | . __('Sort by key') |
||
1484 | . ': <select name="sql_query" class="autosubmit">' . "\n"; |
||
1485 | |||
1486 | $used_index = false; |
||
1487 | $local_order = (is_array($sort_expression) ? implode(', ',$sort_expression) : ''); |
||
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
1488 | |||
1489 | foreach ($indexes as $index) { |
||
1490 | $asc_sort = '`' |
||
1491 | . implode('` ASC, `', array_keys($index->getColumns())) |
||
1492 | . '` ASC'; |
||
1493 | |||
1494 | $desc_sort = '`' |
||
1495 | . implode('` DESC, `', array_keys($index->getColumns())) |
||
1496 | . '` DESC'; |
||
1497 | |||
1498 | $used_index = $used_index |
||
1499 | || ($local_order == $asc_sort) |
||
1500 | || ($local_order == $desc_sort); |
||
1501 | |||
1502 | if (preg_match( |
||
1503 | '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|' |
||
1504 | . 'FOR UPDATE|LOCK IN SHARE MODE))@is', |
||
1505 | $unsorted_sql_query, |
||
1506 | $my_reg |
||
1507 | )) { |
||
1508 | $unsorted_sql_query_first_part = $my_reg[1]; |
||
1509 | $unsorted_sql_query_second_part = $my_reg[2]; |
||
1510 | } else { |
||
1511 | $unsorted_sql_query_first_part = $unsorted_sql_query; |
||
1512 | $unsorted_sql_query_second_part = ''; |
||
1513 | } |
||
1514 | |||
1515 | $drop_down_html .= '<option value="' |
||
1516 | . htmlspecialchars( |
||
1517 | $unsorted_sql_query_first_part . "\n" |
||
1518 | . ' ORDER BY ' . $asc_sort |
||
1519 | . $unsorted_sql_query_second_part |
||
1520 | ) |
||
1521 | . '"' . ($local_order == $asc_sort |
||
1522 | ? ' selected="selected"' |
||
1523 | : '') |
||
1524 | . '>' . htmlspecialchars($index->getName()) . ' (ASC)</option>'; |
||
1525 | |||
1526 | $drop_down_html .= '<option value="' |
||
1527 | . htmlspecialchars( |
||
1528 | $unsorted_sql_query_first_part . "\n" |
||
1529 | . ' ORDER BY ' . $desc_sort |
||
1530 | . $unsorted_sql_query_second_part |
||
1531 | ) |
||
1532 | . '"' . ($local_order == $desc_sort |
||
1533 | ? ' selected="selected"' |
||
1534 | : '') |
||
1535 | . '>' . htmlspecialchars($index->getName()) . ' (DESC)</option>'; |
||
1536 | } |
||
1537 | |||
1538 | $drop_down_html .= '<option value="' . htmlspecialchars($unsorted_sql_query) |
||
1539 | . '"' . ($used_index ? '' : ' selected="selected"') . '>' . __('None') |
||
1540 | . '</option>' |
||
1541 | . '</select>' . "\n" |
||
1542 | . '</form>' . "\n"; |
||
1543 | |||
1544 | return $drop_down_html; |
||
1545 | } // end of the '_getSortByKeyDropDown()' function |
||
1546 | |||
1547 | |||
1548 | /** |
||
1549 | * Set column span, row span and prepare html with full/partial |
||
1550 | * text button or link |
||
1551 | * |
||
1552 | * @param array &$displayParts which elements to display |
||
1553 | * @param string $full_or_partial_text_link full/partial link or text button |
||
1554 | * |
||
1555 | * @return array 2 element array - $colspan, $button_html |
||
1556 | * |
||
1557 | * @access private |
||
1558 | * |
||
1559 | * @see _getTableHeaders() |
||
1560 | */ |
||
1561 | private function _getFieldVisibilityParams( |
||
1562 | array &$displayParts, |
||
1563 | $full_or_partial_text_link |
||
1564 | ) { |
||
1565 | |||
1566 | $button_html = ''; |
||
1567 | $display_params = $this->__get('display_params'); |
||
1568 | |||
1569 | // 1. Displays the full/partial text button (part 1)... |
||
1570 | $button_html .= '<thead><tr>' . "\n"; |
||
1571 | |||
1572 | $colspan = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
1573 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) |
||
1574 | ? ' colspan="4"' |
||
1575 | : ''; |
||
1576 | |||
1577 | // ... before the result table |
||
1578 | if ((($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE) |
||
1579 | && ($displayParts['del_lnk'] == self::NO_EDIT_OR_DELETE)) |
||
1580 | && ($displayParts['text_btn'] == '1') |
||
1581 | ) { |
||
1582 | $display_params['emptypre'] |
||
1583 | = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
1584 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; |
||
1585 | } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) |
||
1586 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) |
||
1587 | && ($displayParts['text_btn'] == '1') |
||
1588 | ) { |
||
1589 | // ... at the left column of the result table header if possible |
||
1590 | // and required |
||
1591 | |||
1592 | $display_params['emptypre'] |
||
1593 | = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
1594 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; |
||
1595 | |||
1596 | $button_html .= '<th class="column_action print_ignore" ' . $colspan |
||
1597 | . '>' . $full_or_partial_text_link . '</th>'; |
||
1598 | } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) |
||
1599 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) |
||
1600 | && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
1601 | || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) |
||
1602 | ) { |
||
1603 | // ... elseif no button, displays empty(ies) col(s) if required |
||
1604 | |||
1605 | $display_params['emptypre'] |
||
1606 | = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
1607 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 0; |
||
1608 | |||
1609 | $button_html .= '<td ' . $colspan . '></td>'; |
||
1610 | } elseif (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE)) { |
||
1611 | // ... elseif display an empty column if the actions links are |
||
1612 | // disabled to match the rest of the table |
||
1613 | $button_html .= '<th class="column_action"></th>'; |
||
1614 | } |
||
1615 | |||
1616 | $this->__set('display_params', $display_params); |
||
1617 | |||
1618 | return [$colspan, $button_html]; |
||
1619 | } // end of the '_getFieldVisibilityParams()' function |
||
1620 | |||
1621 | |||
1622 | /** |
||
1623 | * Get table comments as array |
||
1624 | * |
||
1625 | * @param array $analyzed_sql_results analyzed sql results |
||
1626 | * |
||
1627 | * @return array table comments |
||
1628 | * |
||
1629 | * @access private |
||
1630 | * |
||
1631 | * @see _getTableHeaders() |
||
1632 | */ |
||
1633 | private function _getTableCommentsArray(array $analyzed_sql_results) |
||
1634 | { |
||
1635 | if ((!$GLOBALS['cfg']['ShowBrowseComments']) |
||
1636 | || (empty($analyzed_sql_results['statement']->from)) |
||
1637 | ) { |
||
1638 | return []; |
||
1639 | } |
||
1640 | |||
1641 | $ret = []; |
||
1642 | foreach ($analyzed_sql_results['statement']->from as $field) { |
||
1643 | if (empty($field->table)) { |
||
1644 | continue; |
||
1645 | } |
||
1646 | $ret[$field->table] = $this->relation->getComments( |
||
1647 | empty($field->database) ? $this->__get('db') : $field->database, |
||
1648 | $field->table |
||
1649 | ); |
||
1650 | } |
||
1651 | |||
1652 | return $ret; |
||
1653 | } // end of the '_getTableCommentsArray()' function |
||
1654 | |||
1655 | |||
1656 | /** |
||
1657 | * Set global array for store highlighted header fields |
||
1658 | * |
||
1659 | * @param array $analyzed_sql_results analyzed sql results |
||
1660 | * |
||
1661 | * @return void |
||
1662 | * |
||
1663 | * @access private |
||
1664 | * |
||
1665 | * @see _getTableHeaders() |
||
1666 | */ |
||
1667 | private function _setHighlightedColumnGlobalField(array $analyzed_sql_results) |
||
1668 | { |
||
1669 | $highlight_columns = []; |
||
1670 | |||
1671 | if (!empty($analyzed_sql_results['statement']->where)) { |
||
1672 | foreach ($analyzed_sql_results['statement']->where as $expr) { |
||
1673 | foreach ($expr->identifiers as $identifier) { |
||
1674 | $highlight_columns[$identifier] = 'true'; |
||
1675 | } |
||
1676 | } |
||
1677 | } |
||
1678 | |||
1679 | $this->__set('highlight_columns', $highlight_columns); |
||
1680 | } // end of the '_setHighlightedColumnGlobalField()' function |
||
1681 | |||
1682 | |||
1683 | /** |
||
1684 | * Prepare data for column restoring and show/hide |
||
1685 | * |
||
1686 | * @param array $analyzed_sql_results analyzed sql results |
||
1687 | * |
||
1688 | * @return string html content |
||
1689 | * |
||
1690 | * @access private |
||
1691 | * |
||
1692 | * @see _getTableHeaders() |
||
1693 | */ |
||
1694 | private function _getDataForResettingColumnOrder(array $analyzed_sql_results) |
||
1695 | { |
||
1696 | if (! $this->_isSelect($analyzed_sql_results)) { |
||
1697 | return ''; |
||
1698 | } |
||
1699 | |||
1700 | // generate the column order, if it is set |
||
1701 | list($col_order, $col_visib) = $this->_getColumnParams( |
||
1702 | $analyzed_sql_results |
||
1703 | ); |
||
1704 | |||
1705 | $data_html = ''; |
||
1706 | |||
1707 | if ($col_order) { |
||
1708 | $data_html .= '<input class="col_order" type="hidden" value="' |
||
1709 | . implode(',', $col_order) . '" />'; |
||
1710 | } |
||
1711 | |||
1712 | if ($col_visib) { |
||
1713 | $data_html .= '<input class="col_visib" type="hidden" value="' |
||
1714 | . implode(',', $col_visib) . '" />'; |
||
1715 | } |
||
1716 | |||
1717 | // generate table create time |
||
1718 | $table = new Table($this->__get('table'), $this->__get('db')); |
||
1719 | if (! $table->isView()) { |
||
1720 | $data_html .= '<input class="table_create_time" type="hidden" value="' |
||
1721 | . $GLOBALS['dbi']->getTable( |
||
1722 | $this->__get('db'), |
||
1723 | $this->__get('table') |
||
1724 | )->getStatusInfo('Create_time') |
||
1725 | . '" />'; |
||
1726 | } |
||
1727 | |||
1728 | return $data_html; |
||
1729 | } // end of the '_getDataForResettingColumnOrder()' function |
||
1730 | |||
1731 | |||
1732 | /** |
||
1733 | * Prepare option fields block |
||
1734 | * |
||
1735 | * @return string html content |
||
1736 | * |
||
1737 | * @access private |
||
1738 | * |
||
1739 | * @see _getTableHeaders() |
||
1740 | */ |
||
1741 | private function _getOptionsBlock() |
||
1742 | { |
||
1743 | if (isset($_SESSION['tmpval']['possible_as_geometry']) && $_SESSION['tmpval']['possible_as_geometry'] == false) { |
||
1744 | if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) { |
||
1745 | $_SESSION['tmpval']['geoOption'] = self::GEOMETRY_DISP_WKT; |
||
1746 | } |
||
1747 | } |
||
1748 | return $this->template->render('display/results/options_block', [ |
||
1749 | 'unique_id' => $this->__get('unique_id'), |
||
1750 | 'geo_option' => $_SESSION['tmpval']['geoOption'], |
||
1751 | 'hide_transformation' => $_SESSION['tmpval']['hide_transformation'], |
||
1752 | 'display_blob' => $_SESSION['tmpval']['display_blob'], |
||
1753 | 'display_binary' => $_SESSION['tmpval']['display_binary'], |
||
1754 | 'relational_display' => $_SESSION['tmpval']['relational_display'], |
||
1755 | 'displaywork' => $GLOBALS['cfgRelation']['displaywork'], |
||
1756 | 'relwork' => $GLOBALS['cfgRelation']['relwork'], |
||
1757 | 'possible_as_geometry' => $_SESSION['tmpval']['possible_as_geometry'], |
||
1758 | 'pftext' => $_SESSION['tmpval']['pftext'], |
||
1759 | 'db' => $this->__get('db'), |
||
1760 | 'table' => $this->__get('table'), |
||
1761 | 'sql_query' => $this->__get('sql_query'), |
||
1762 | 'goto' => $this->__get('goto'), |
||
1763 | 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'], |
||
1764 | ]); |
||
1765 | } |
||
1766 | |||
1767 | /** |
||
1768 | * Get full/partial text button or link |
||
1769 | * |
||
1770 | * @return string html content |
||
1771 | * |
||
1772 | * @access private |
||
1773 | * |
||
1774 | * @see _getTableHeaders() |
||
1775 | */ |
||
1776 | private function _getFullOrPartialTextButtonOrLink() |
||
1777 | { |
||
1778 | |||
1779 | $url_params_full_text = [ |
||
1780 | 'db' => $this->__get('db'), |
||
1781 | 'table' => $this->__get('table'), |
||
1782 | 'sql_query' => $this->__get('sql_query'), |
||
1783 | 'goto' => $this->__get('goto'), |
||
1784 | 'full_text_button' => 1 |
||
1785 | ]; |
||
1786 | |||
1787 | if ($_SESSION['tmpval']['pftext'] == self::DISPLAY_FULL_TEXT) { |
||
1788 | // currently in fulltext mode so show the opposite link |
||
1789 | $tmp_image_file = $this->__get('pma_theme_image') . 's_partialtext.png'; |
||
1790 | $tmp_txt = __('Partial texts'); |
||
1791 | $url_params_full_text['pftext'] = self::DISPLAY_PARTIAL_TEXT; |
||
1792 | } else { |
||
1793 | $tmp_image_file = $this->__get('pma_theme_image') . 's_fulltext.png'; |
||
1794 | $tmp_txt = __('Full texts'); |
||
1795 | $url_params_full_text['pftext'] = self::DISPLAY_FULL_TEXT; |
||
1796 | } |
||
1797 | |||
1798 | $tmp_image = '<img class="fulltext" src="' . $tmp_image_file . '" alt="' |
||
1799 | . $tmp_txt . '" title="' . $tmp_txt . '" />'; |
||
1800 | $tmp_url = 'sql.php' . Url::getCommon($url_params_full_text); |
||
1801 | |||
1802 | return Util::linkOrButton($tmp_url, $tmp_image); |
||
1803 | } // end of the '_getFullOrPartialTextButtonOrLink()' function |
||
1804 | |||
1805 | |||
1806 | /** |
||
1807 | * Prepare html form for multi row operations |
||
1808 | * |
||
1809 | * @param string $deleteLink the delete link of current row |
||
1810 | * |
||
1811 | * @return string html content |
||
1812 | * |
||
1813 | * @access private |
||
1814 | * |
||
1815 | * @see _getTableHeaders() |
||
1816 | */ |
||
1817 | private function _getFormForMultiRowOperations($deleteLink) |
||
1818 | { |
||
1819 | return $this->template->render('display/results/multi_row_operations_form', [ |
||
1820 | 'delete_link' => $deleteLink, |
||
1821 | 'delete_row' => self::DELETE_ROW, |
||
1822 | 'kill_process' => self::KILL_PROCESS, |
||
1823 | 'unique_id' => $this->__get('unique_id'), |
||
1824 | 'db' => $this->__get('db'), |
||
1825 | 'table' => $this->__get('table'), |
||
1826 | ]); |
||
1827 | } |
||
1828 | |||
1829 | /** |
||
1830 | * Get comment for row |
||
1831 | * |
||
1832 | * @param array $commentsMap comments array |
||
1833 | * @param array $fieldsMeta set of field properties |
||
1834 | * |
||
1835 | * @return string html content |
||
1836 | * |
||
1837 | * @access private |
||
1838 | * |
||
1839 | * @see _getTableHeaders() |
||
1840 | */ |
||
1841 | private function _getCommentForRow(array $commentsMap, $fieldsMeta) |
||
1842 | { |
||
1843 | return $this->template->render('display/results/comment_for_row', [ |
||
1844 | 'comments_map' => $commentsMap, |
||
1845 | 'fields_meta' => $fieldsMeta, |
||
1846 | 'limit_chars' => $GLOBALS['cfg']['LimitChars'], |
||
1847 | ]); |
||
1848 | } |
||
1849 | |||
1850 | /** |
||
1851 | * Prepare parameters and html for sorted table header fields |
||
1852 | * |
||
1853 | * @param stdClass $fields_meta set of field properties |
||
1854 | * @param array $sort_expression sort expression |
||
1855 | * @param array $sort_expression_nodirection sort expression without direction |
||
1856 | * @param integer $column_index the index of the column |
||
1857 | * @param string $unsorted_sql_query the unsorted sql query |
||
1858 | * @param integer $session_max_rows maximum rows resulted by sql |
||
1859 | * @param string $comments comment for row |
||
1860 | * @param array $sort_direction sort direction |
||
1861 | * @param boolean $col_visib column is visible(false) |
||
1862 | * array column isn't visible(string array) |
||
1863 | * @param string $col_visib_j element of $col_visib array |
||
1864 | * |
||
1865 | * @return array 2 element array - $order_link, $sorted_header_html |
||
1866 | * |
||
1867 | * @access private |
||
1868 | * |
||
1869 | * @see _getTableHeaders() |
||
1870 | */ |
||
1871 | private function _getOrderLinkAndSortedHeaderHtml( |
||
1872 | $fields_meta, |
||
1873 | array $sort_expression, |
||
1874 | array $sort_expression_nodirection, |
||
1875 | $column_index, |
||
1876 | $unsorted_sql_query, |
||
1877 | $session_max_rows, |
||
1878 | $comments, |
||
1879 | array $sort_direction, |
||
1880 | $col_visib, |
||
1881 | $col_visib_j |
||
1882 | ) { |
||
1883 | |||
1884 | $sorted_header_html = ''; |
||
1885 | |||
1886 | // Checks if the table name is required; it's the case |
||
1887 | // for a query with a "JOIN" statement and if the column |
||
1888 | // isn't aliased, or in queries like |
||
1889 | // SELECT `1`.`master_field` , `2`.`master_field` |
||
1890 | // FROM `PMA_relation` AS `1` , `PMA_relation` AS `2` |
||
1891 | |||
1892 | $sort_tbl = (isset($fields_meta->table) |
||
1893 | && strlen($fields_meta->table) > 0 |
||
1894 | && $fields_meta->orgname == $fields_meta->name) |
||
1895 | ? Util::backquote( |
||
1896 | $fields_meta->table |
||
1897 | ) . '.' |
||
1898 | : ''; |
||
1899 | |||
1900 | $name_to_use_in_sort = $fields_meta->name; |
||
1901 | |||
1902 | // Generates the orderby clause part of the query which is part |
||
1903 | // of URL |
||
1904 | list($single_sort_order, $multi_sort_order, $order_img) |
||
1905 | = $this->_getSingleAndMultiSortUrls( |
||
1906 | $sort_expression, |
||
1907 | $sort_expression_nodirection, |
||
1908 | $sort_tbl, |
||
1909 | $name_to_use_in_sort, |
||
1910 | $sort_direction, |
||
1911 | $fields_meta, |
||
1912 | $column_index |
||
1913 | ); |
||
1914 | |||
1915 | if (preg_match( |
||
1916 | '@(.*)([[:space:]](LIMIT (.*)|PROCEDURE (.*)|FOR UPDATE|' |
||
1917 | . 'LOCK IN SHARE MODE))@is', |
||
1918 | $unsorted_sql_query, |
||
1919 | $regs3 |
||
1920 | )) { |
||
1921 | $single_sorted_sql_query = $regs3[1] . $single_sort_order . $regs3[2]; |
||
1922 | $multi_sorted_sql_query = $regs3[1] . $multi_sort_order . $regs3[2]; |
||
1923 | } else { |
||
1924 | $single_sorted_sql_query = $unsorted_sql_query . $single_sort_order; |
||
1925 | $multi_sorted_sql_query = $unsorted_sql_query . $multi_sort_order; |
||
1926 | } |
||
1927 | |||
1928 | $_single_url_params = [ |
||
1929 | 'db' => $this->__get('db'), |
||
1930 | 'table' => $this->__get('table'), |
||
1931 | 'sql_query' => $single_sorted_sql_query, |
||
1932 | 'session_max_rows' => $session_max_rows, |
||
1933 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
1934 | ]; |
||
1935 | |||
1936 | $_multi_url_params = [ |
||
1937 | 'db' => $this->__get('db'), |
||
1938 | 'table' => $this->__get('table'), |
||
1939 | 'sql_query' => $multi_sorted_sql_query, |
||
1940 | 'session_max_rows' => $session_max_rows, |
||
1941 | 'is_browse_distinct' => $this->__get('is_browse_distinct'), |
||
1942 | ]; |
||
1943 | $single_order_url = 'sql.php' . Url::getCommon($_single_url_params); |
||
1944 | $multi_order_url = 'sql.php' . Url::getCommon($_multi_url_params); |
||
1945 | |||
1946 | // Displays the sorting URL |
||
1947 | // enable sort order swapping for image |
||
1948 | $order_link = $this->_getSortOrderLink( |
||
1949 | $order_img, |
||
1950 | $fields_meta, |
||
1951 | $single_order_url, |
||
1952 | $multi_order_url |
||
1953 | ); |
||
1954 | |||
1955 | $sorted_header_html .= $this->_getDraggableClassForSortableColumns( |
||
1956 | $col_visib, |
||
1957 | $col_visib_j, |
||
1958 | $fields_meta, |
||
1959 | $order_link, |
||
1960 | $comments |
||
1961 | ); |
||
1962 | |||
1963 | return [$order_link, $sorted_header_html]; |
||
1964 | } // end of the '_getOrderLinkAndSortedHeaderHtml()' function |
||
1965 | |||
1966 | /** |
||
1967 | * Prepare parameters and html for sorted table header fields |
||
1968 | * |
||
1969 | * @param array $sort_expression sort expression |
||
1970 | * @param array $sort_expression_nodirection sort expression without direction |
||
1971 | * @param string $sort_tbl The name of the table to which |
||
1972 | * the current column belongs to |
||
1973 | * @param string $name_to_use_in_sort The current column under |
||
1974 | * consideration |
||
1975 | * @param array $sort_direction sort direction |
||
1976 | * @param stdClass $fields_meta set of field properties |
||
1977 | * @param integer $column_index The index number to current column |
||
1978 | * |
||
1979 | * @return array 3 element array - $single_sort_order, $sort_order, $order_img |
||
1980 | * |
||
1981 | * @access private |
||
1982 | * |
||
1983 | * @see _getOrderLinkAndSortedHeaderHtml() |
||
1984 | */ |
||
1985 | private function _getSingleAndMultiSortUrls( |
||
1986 | array $sort_expression, |
||
1987 | array $sort_expression_nodirection, |
||
1988 | $sort_tbl, |
||
1989 | $name_to_use_in_sort, |
||
1990 | array $sort_direction, |
||
1991 | $fields_meta, |
||
1992 | $column_index |
||
1993 | ) { |
||
1994 | $sort_order = ""; |
||
1995 | // Check if the current column is in the order by clause |
||
1996 | $is_in_sort = $this->_isInSorted( |
||
1997 | $sort_expression, |
||
1998 | $sort_expression_nodirection, |
||
1999 | $sort_tbl, |
||
2000 | $name_to_use_in_sort |
||
2001 | ); |
||
2002 | $current_name = $name_to_use_in_sort; |
||
2003 | if ($sort_expression_nodirection[0] == '' || !$is_in_sort) { |
||
2004 | $special_index = $sort_expression_nodirection[0] == '' |
||
2005 | ? 0 |
||
2006 | : count($sort_expression_nodirection); |
||
2007 | $sort_expression_nodirection[$special_index] |
||
2008 | = Util::backquote( |
||
2009 | $current_name |
||
2010 | ); |
||
2011 | $sort_direction[$special_index] = (preg_match( |
||
2012 | '@time|date@i', |
||
2013 | $fields_meta->type |
||
2014 | )) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR; |
||
2015 | } |
||
2016 | |||
2017 | $sort_expression_nodirection = array_filter($sort_expression_nodirection); |
||
2018 | $single_sort_order = null; |
||
2019 | foreach ($sort_expression_nodirection as $index => $expression) { |
||
2020 | // check if this is the first clause, |
||
2021 | // if it is then we have to add "order by" |
||
2022 | $is_first_clause = ($index == 0); |
||
2023 | $name_to_use_in_sort = $expression; |
||
2024 | $sort_tbl_new = $sort_tbl; |
||
2025 | // Test to detect if the column name is a standard name |
||
2026 | // Standard name has the table name prefixed to the column name |
||
2027 | if (mb_strpos($name_to_use_in_sort, '.') !== false) { |
||
2028 | $matches = explode('.', $name_to_use_in_sort); |
||
2029 | // Matches[0] has the table name |
||
2030 | // Matches[1] has the column name |
||
2031 | $name_to_use_in_sort = $matches[1]; |
||
2032 | $sort_tbl_new = $matches[0]; |
||
2033 | } |
||
2034 | |||
2035 | // $name_to_use_in_sort might contain a space due to |
||
2036 | // formatting of function expressions like "COUNT(name )" |
||
2037 | // so we remove the space in this situation |
||
2038 | $name_to_use_in_sort = str_replace(' )', ')', $name_to_use_in_sort); |
||
2039 | $name_to_use_in_sort = str_replace('``', '`', $name_to_use_in_sort); |
||
2040 | $name_to_use_in_sort = trim($name_to_use_in_sort, '`'); |
||
2041 | |||
2042 | // If this the first column name in the order by clause add |
||
2043 | // order by clause to the column name |
||
2044 | $query_head = $is_first_clause ? "\nORDER BY " : ""; |
||
2045 | // Again a check to see if the given column is a aggregate column |
||
2046 | if (mb_strpos($name_to_use_in_sort, '(') !== false) { |
||
2047 | $sort_order .= $query_head . $name_to_use_in_sort . ' ' ; |
||
2048 | } else { |
||
2049 | if (strlen($sort_tbl_new) > 0) { |
||
2050 | $sort_tbl_new .= "."; |
||
2051 | } |
||
2052 | $sort_order .= $query_head . $sort_tbl_new |
||
2053 | . Util::backquote( |
||
2054 | $name_to_use_in_sort |
||
2055 | ) . ' ' ; |
||
2056 | } |
||
2057 | |||
2058 | // For a special case where the code generates two dots between |
||
2059 | // column name and table name. |
||
2060 | $sort_order = preg_replace("/\.\./", ".", $sort_order); |
||
2061 | // Incase this is the current column save $single_sort_order |
||
2062 | if ($current_name == $name_to_use_in_sort) { |
||
2063 | if (mb_strpos($current_name, '(') !== false) { |
||
2064 | $single_sort_order = "\n" . 'ORDER BY ' . Util::backquote($current_name) . ' '; |
||
2065 | } else { |
||
2066 | $single_sort_order = "\n" . 'ORDER BY ' . $sort_tbl |
||
2067 | . Util::backquote( |
||
2068 | $current_name |
||
2069 | ) . ' '; |
||
2070 | } |
||
2071 | if ($is_in_sort) { |
||
2072 | list($single_sort_order, $order_img) |
||
2073 | = $this->_getSortingUrlParams( |
||
2074 | $sort_direction, |
||
2075 | $single_sort_order, |
||
2076 | $index |
||
2077 | ); |
||
2078 | } else { |
||
2079 | $single_sort_order .= strtoupper($sort_direction[$index]); |
||
2080 | } |
||
2081 | } |
||
2082 | if ($current_name == $name_to_use_in_sort && $is_in_sort) { |
||
2083 | // We need to generate the arrow button and related html |
||
2084 | list($sort_order, $order_img) = $this->_getSortingUrlParams( |
||
2085 | $sort_direction, |
||
2086 | $sort_order, |
||
2087 | $index |
||
2088 | ); |
||
2089 | $order_img .= " <small>" . ($index + 1) . "</small>"; |
||
2090 | } else { |
||
2091 | $sort_order .= strtoupper($sort_direction[$index]); |
||
2092 | } |
||
2093 | // Separate columns by a comma |
||
2094 | $sort_order .= ", "; |
||
2095 | |||
2096 | unset($name_to_use_in_sort); |
||
2097 | } |
||
2098 | // remove the comma from the last column name in the newly |
||
2099 | // constructed clause |
||
2100 | $sort_order = mb_substr( |
||
2101 | $sort_order, |
||
2102 | 0, |
||
2103 | mb_strlen($sort_order) - 2 |
||
2104 | ); |
||
2105 | if (empty($order_img)) { |
||
2106 | $order_img = ''; |
||
2107 | } |
||
2108 | return [$single_sort_order, $sort_order, $order_img]; |
||
2109 | } |
||
2110 | |||
2111 | /** |
||
2112 | * Check whether the column is sorted |
||
2113 | * |
||
2114 | * @param array $sort_expression sort expression |
||
2115 | * @param array $sort_expression_nodirection sort expression without direction |
||
2116 | * @param string $sort_tbl the table name |
||
2117 | * @param string $name_to_use_in_sort the sorting column name |
||
2118 | * |
||
2119 | * @return boolean the column sorted or not |
||
2120 | * |
||
2121 | * @access private |
||
2122 | * |
||
2123 | * @see _getTableHeaders() |
||
2124 | */ |
||
2125 | private function _isInSorted( |
||
2126 | array $sort_expression, |
||
2127 | array $sort_expression_nodirection, |
||
2128 | $sort_tbl, |
||
2129 | $name_to_use_in_sort |
||
2130 | ) { |
||
2131 | |||
2132 | $index_in_expression = 0; |
||
2133 | |||
2134 | foreach ($sort_expression_nodirection as $index => $clause) { |
||
2135 | if (mb_strpos($clause, '.') !== false) { |
||
2136 | $fragments = explode('.', $clause); |
||
2137 | $clause2 = $fragments[0] . "." . str_replace('`', '', $fragments[1]); |
||
2138 | } else { |
||
2139 | $clause2 = $sort_tbl . str_replace('`', '', $clause); |
||
2140 | } |
||
2141 | if ($clause2 === $sort_tbl . $name_to_use_in_sort) { |
||
2142 | $index_in_expression = $index; |
||
2143 | break; |
||
2144 | } |
||
2145 | } |
||
2146 | if (empty($sort_expression[$index_in_expression])) { |
||
2147 | $is_in_sort = false; |
||
2148 | } else { |
||
2149 | // Field name may be preceded by a space, or any number |
||
2150 | // of characters followed by a dot (tablename.fieldname) |
||
2151 | // so do a direct comparison for the sort expression; |
||
2152 | // this avoids problems with queries like |
||
2153 | // "SELECT id, count(id)..." and clicking to sort |
||
2154 | // on id or on count(id). |
||
2155 | // Another query to test this: |
||
2156 | // SELECT p.*, FROM_UNIXTIME(p.temps) FROM mytable AS p |
||
2157 | // (and try clicking on each column's header twice) |
||
2158 | $noSortTable = empty($sort_tbl) || mb_strpos( |
||
2159 | $sort_expression_nodirection[$index_in_expression], |
||
2160 | $sort_tbl |
||
2161 | ) === false; |
||
2162 | $noOpenParenthesis = mb_strpos( |
||
2163 | $sort_expression_nodirection[$index_in_expression], |
||
2164 | '(' |
||
2165 | ) === false; |
||
2166 | if (! empty($sort_tbl) && $noSortTable && $noOpenParenthesis) { |
||
2167 | $new_sort_expression_nodirection = $sort_tbl |
||
2168 | . $sort_expression_nodirection[$index_in_expression]; |
||
2169 | } else { |
||
2170 | $new_sort_expression_nodirection |
||
2171 | = $sort_expression_nodirection[$index_in_expression]; |
||
2172 | } |
||
2173 | |||
2174 | //Back quotes are removed in next comparison, so remove them from value |
||
2175 | //to compare. |
||
2176 | $name_to_use_in_sort = str_replace('`', '', $name_to_use_in_sort); |
||
2177 | |||
2178 | $is_in_sort = false; |
||
2179 | $sort_name = str_replace('`', '', $sort_tbl) . $name_to_use_in_sort; |
||
2180 | |||
2181 | if ($sort_name == str_replace('`', '', $new_sort_expression_nodirection) |
||
2182 | || $sort_name == str_replace('`', '', $sort_expression_nodirection[$index_in_expression]) |
||
2183 | ) { |
||
2184 | $is_in_sort = true; |
||
2185 | } |
||
2186 | } |
||
2187 | |||
2188 | return $is_in_sort; |
||
2189 | } // end of the '_isInSorted()' function |
||
2190 | |||
2191 | |||
2192 | /** |
||
2193 | * Get sort url parameters - sort order and order image |
||
2194 | * |
||
2195 | * @param array $sort_direction the sort direction |
||
2196 | * @param string $sort_order the sorting order |
||
2197 | * @param integer $index the index of sort direction array. |
||
2198 | * |
||
2199 | * @return array 2 element array - $sort_order, $order_img |
||
2200 | * |
||
2201 | * @access private |
||
2202 | * |
||
2203 | * @see _getSingleAndMultiSortUrls() |
||
2204 | */ |
||
2205 | private function _getSortingUrlParams(array $sort_direction, $sort_order, $index) |
||
2206 | { |
||
2207 | if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) { |
||
2208 | $sort_order .= ' ASC'; |
||
2209 | $order_img = ' ' . Util::getImage( |
||
2210 | 's_desc', |
||
2211 | __('Descending'), |
||
2212 | ['class' => "soimg", 'title' => ''] |
||
2213 | ); |
||
2214 | $order_img .= ' ' . Util::getImage( |
||
2215 | 's_asc', |
||
2216 | __('Ascending'), |
||
2217 | ['class' => "soimg hide", 'title' => ''] |
||
2218 | ); |
||
2219 | } else { |
||
2220 | $sort_order .= ' DESC'; |
||
2221 | $order_img = ' ' . Util::getImage( |
||
2222 | 's_asc', |
||
2223 | __('Ascending'), |
||
2224 | ['class' => "soimg", 'title' => ''] |
||
2225 | ); |
||
2226 | $order_img .= ' ' . Util::getImage( |
||
2227 | 's_desc', |
||
2228 | __('Descending'), |
||
2229 | ['class' => "soimg hide", 'title' => ''] |
||
2230 | ); |
||
2231 | } |
||
2232 | return [$sort_order, $order_img]; |
||
2233 | } // end of the '_getSortingUrlParams()' function |
||
2234 | |||
2235 | |||
2236 | /** |
||
2237 | * Get sort order link |
||
2238 | * |
||
2239 | * @param string $order_img the sort order image |
||
2240 | * @param stdClass $fields_meta set of field properties |
||
2241 | * @param string $order_url the url for sort |
||
2242 | * @param string $multi_order_url the url for sort |
||
2243 | * |
||
2244 | * @return string the sort order link |
||
2245 | * |
||
2246 | * @access private |
||
2247 | * |
||
2248 | * @see _getTableHeaders() |
||
2249 | */ |
||
2250 | private function _getSortOrderLink( |
||
2251 | $order_img, |
||
2252 | $fields_meta, |
||
2253 | $order_url, |
||
2254 | $multi_order_url |
||
2255 | ) { |
||
2256 | $order_link_params = [ |
||
2257 | 'class' => 'sortlink' |
||
2258 | ]; |
||
2259 | |||
2260 | $order_link_content = htmlspecialchars($fields_meta->name); |
||
2261 | $inner_link_content = $order_link_content . $order_img |
||
2262 | . '<input type="hidden" value="' . $multi_order_url . '" />'; |
||
2263 | |||
2264 | return Util::linkOrButton( |
||
2265 | $order_url, |
||
2266 | $inner_link_content, |
||
2267 | $order_link_params |
||
2268 | ); |
||
2269 | } // end of the '_getSortOrderLink()' function |
||
2270 | |||
2271 | /** |
||
2272 | * Check if the column contains numeric data. If yes, then set the |
||
2273 | * column header's alignment right |
||
2274 | * |
||
2275 | * @param stdClass $fields_meta set of field properties |
||
2276 | * @param array &$th_class array containing classes |
||
2277 | * |
||
2278 | * @return void |
||
2279 | * |
||
2280 | * @see _getDraggableClassForSortableColumns() |
||
2281 | */ |
||
2282 | private function _getClassForNumericColumnType($fields_meta, array &$th_class) |
||
2283 | { |
||
2284 | if (preg_match( |
||
2285 | '@int|decimal|float|double|real|bit|boolean|serial@i', |
||
2286 | (string) $fields_meta->type |
||
2287 | )) { |
||
2288 | $th_class[] = 'right'; |
||
2289 | } |
||
2290 | } |
||
2291 | |||
2292 | /** |
||
2293 | * Prepare columns to draggable effect for sortable columns |
||
2294 | * |
||
2295 | * @param boolean $col_visib the column is visible (false) |
||
2296 | * array the column is not visible (string array) |
||
2297 | * @param string $col_visib_j element of $col_visib array |
||
2298 | * @param stdClass $fields_meta set of field properties |
||
2299 | * @param string $order_link the order link |
||
2300 | * @param string $comments the comment for the column |
||
2301 | * |
||
2302 | * @return string html content |
||
2303 | * |
||
2304 | * @access private |
||
2305 | * |
||
2306 | * @see _getTableHeaders() |
||
2307 | */ |
||
2308 | private function _getDraggableClassForSortableColumns( |
||
2309 | $col_visib, |
||
2310 | $col_visib_j, |
||
2311 | $fields_meta, |
||
2312 | $order_link, |
||
2313 | $comments |
||
2314 | ) { |
||
2315 | |||
2316 | $draggable_html = '<th'; |
||
2317 | $th_class = []; |
||
2318 | $th_class[] = 'draggable'; |
||
2319 | $this->_getClassForNumericColumnType($fields_meta, $th_class); |
||
2320 | if ($col_visib && !$col_visib_j) { |
||
2321 | $th_class[] = 'hide'; |
||
2322 | } |
||
2323 | |||
2324 | $th_class[] = 'column_heading'; |
||
2325 | if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) { |
||
2326 | $th_class[] = 'pointer'; |
||
2327 | } |
||
2328 | |||
2329 | if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) { |
||
2330 | $th_class[] = 'marker'; |
||
2331 | } |
||
2332 | |||
2333 | $draggable_html .= ' class="' . implode(' ', $th_class) . '"'; |
||
2334 | |||
2335 | $draggable_html .= ' data-column="' . htmlspecialchars($fields_meta->name) |
||
2336 | . '">' . $order_link . $comments . '</th>'; |
||
2337 | |||
2338 | return $draggable_html; |
||
2339 | } // end of the '_getDraggableClassForSortableColumns()' function |
||
2340 | |||
2341 | |||
2342 | /** |
||
2343 | * Prepare columns to draggable effect for non sortable columns |
||
2344 | * |
||
2345 | * @param boolean $col_visib the column is visible (false) |
||
2346 | * array the column is not visible (string array) |
||
2347 | * @param string $col_visib_j element of $col_visib array |
||
2348 | * @param boolean $condition_field whether to add CSS class condition |
||
2349 | * @param stdClass $fields_meta set of field properties |
||
2350 | * @param string $comments the comment for the column |
||
2351 | * |
||
2352 | * @return string html content |
||
2353 | * |
||
2354 | * @access private |
||
2355 | * |
||
2356 | * @see _getTableHeaders() |
||
2357 | */ |
||
2358 | private function _getDraggableClassForNonSortableColumns( |
||
2359 | $col_visib, |
||
2360 | $col_visib_j, |
||
2361 | $condition_field, |
||
2362 | $fields_meta, |
||
2363 | $comments |
||
2364 | ) { |
||
2365 | |||
2366 | $draggable_html = '<th'; |
||
2367 | $th_class = []; |
||
2368 | $th_class[] = 'draggable'; |
||
2369 | $this->_getClassForNumericColumnType($fields_meta, $th_class); |
||
2370 | if ($col_visib && !$col_visib_j) { |
||
2371 | $th_class[] = 'hide'; |
||
2372 | } |
||
2373 | |||
2374 | if ($condition_field) { |
||
2375 | $th_class[] = 'condition'; |
||
2376 | } |
||
2377 | |||
2378 | $draggable_html .= ' class="' . implode(' ', $th_class) . '"'; |
||
2379 | |||
2380 | $draggable_html .= ' data-column="' |
||
2381 | . htmlspecialchars((string) $fields_meta->name) . '">'; |
||
2382 | |||
2383 | $draggable_html .= htmlspecialchars((string) $fields_meta->name); |
||
2384 | |||
2385 | $draggable_html .= "\n" . $comments . '</th>'; |
||
2386 | |||
2387 | return $draggable_html; |
||
2388 | } // end of the '_getDraggableClassForNonSortableColumns()' function |
||
2389 | |||
2390 | |||
2391 | /** |
||
2392 | * Prepare column to show at right side - check boxes or empty column |
||
2393 | * |
||
2394 | * @param array &$displayParts which elements to display |
||
2395 | * @param string $full_or_partial_text_link full/partial link or text button |
||
2396 | * @param string $colspan column span of table header |
||
2397 | * |
||
2398 | * @return string html content |
||
2399 | * |
||
2400 | * @access private |
||
2401 | * |
||
2402 | * @see _getTableHeaders() |
||
2403 | */ |
||
2404 | private function _getColumnAtRightSide( |
||
2405 | array &$displayParts, |
||
2406 | $full_or_partial_text_link, |
||
2407 | $colspan |
||
2408 | ) { |
||
2409 | |||
2410 | $right_column_html = ''; |
||
2411 | $display_params = $this->__get('display_params'); |
||
2412 | |||
2413 | // Displays the needed checkboxes at the right |
||
2414 | // column of the result table header if possible and required... |
||
2415 | if ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) |
||
2416 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) |
||
2417 | && (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2418 | || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) |
||
2419 | && ($displayParts['text_btn'] == '1') |
||
2420 | ) { |
||
2421 | $display_params['emptyafter'] |
||
2422 | = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2423 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1; |
||
2424 | |||
2425 | $right_column_html .= "\n" |
||
2426 | . '<th class="column_action print_ignore" ' . $colspan . '>' |
||
2427 | . $full_or_partial_text_link |
||
2428 | . '</th>'; |
||
2429 | } elseif ((($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) |
||
2430 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH)) |
||
2431 | && (($displayParts['edit_lnk'] == self::NO_EDIT_OR_DELETE) |
||
2432 | && ($displayParts['del_lnk'] == self::NO_EDIT_OR_DELETE)) |
||
2433 | && (! isset($GLOBALS['is_header_sent']) || ! $GLOBALS['is_header_sent']) |
||
2434 | ) { |
||
2435 | // ... elseif no button, displays empty columns if required |
||
2436 | // (unless coming from Browse mode print view) |
||
2437 | |||
2438 | $display_params['emptyafter'] |
||
2439 | = (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2440 | && ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)) ? 4 : 1; |
||
2441 | |||
2442 | $right_column_html .= "\n" . '<td class="print_ignore" ' . $colspan |
||
2443 | . '></td>'; |
||
2444 | } |
||
2445 | |||
2446 | $this->__set('display_params', $display_params); |
||
2447 | |||
2448 | return $right_column_html; |
||
2449 | } // end of the '_getColumnAtRightSide()' function |
||
2450 | |||
2451 | |||
2452 | /** |
||
2453 | * Prepares the display for a value |
||
2454 | * |
||
2455 | * @param string $class class of table cell |
||
2456 | * @param bool $conditionField whether to add CSS class condition |
||
2457 | * @param string $value value to display |
||
2458 | * |
||
2459 | * @return string the td |
||
2460 | * |
||
2461 | * @access private |
||
2462 | * |
||
2463 | * @see _getDataCellForGeometryColumns(), |
||
2464 | * _getDataCellForNonNumericColumns() |
||
2465 | */ |
||
2466 | private function _buildValueDisplay($class, $conditionField, $value) |
||
2467 | { |
||
2468 | return $this->template->render('display/results/value_display', [ |
||
2469 | 'class' => $class, |
||
2470 | 'condition_field' => $conditionField, |
||
2471 | 'value' => $value, |
||
2472 | ]); |
||
2473 | } |
||
2474 | |||
2475 | /** |
||
2476 | * Prepares the display for a null value |
||
2477 | * |
||
2478 | * @param string $class class of table cell |
||
2479 | * @param bool $conditionField whether to add CSS class condition |
||
2480 | * @param stdClass $meta the meta-information about this field |
||
2481 | * @param string $align cell alignment |
||
2482 | * |
||
2483 | * @return string the td |
||
2484 | * |
||
2485 | * @access private |
||
2486 | * |
||
2487 | * @see _getDataCellForNumericColumns(), |
||
2488 | * _getDataCellForGeometryColumns(), |
||
2489 | * _getDataCellForNonNumericColumns() |
||
2490 | */ |
||
2491 | private function _buildNullDisplay($class, $conditionField, $meta, $align = '') |
||
2492 | { |
||
2493 | $classes = $this->_addClass($class, $conditionField, $meta, ''); |
||
2494 | |||
2495 | return $this->template->render('display/results/null_display', [ |
||
2496 | 'align' => $align, |
||
2497 | 'meta' => $meta, |
||
2498 | 'classes' => $classes, |
||
2499 | ]); |
||
2500 | } |
||
2501 | |||
2502 | /** |
||
2503 | * Prepares the display for an empty value |
||
2504 | * |
||
2505 | * @param string $class class of table cell |
||
2506 | * @param bool $conditionField whether to add CSS class condition |
||
2507 | * @param stdClass $meta the meta-information about this field |
||
2508 | * @param string $align cell alignment |
||
2509 | * |
||
2510 | * @return string the td |
||
2511 | * |
||
2512 | * @access private |
||
2513 | * |
||
2514 | * @see _getDataCellForNumericColumns(), |
||
2515 | * _getDataCellForGeometryColumns(), |
||
2516 | * _getDataCellForNonNumericColumns() |
||
2517 | */ |
||
2518 | private function _buildEmptyDisplay($class, $conditionField, $meta, $align = '') |
||
2519 | { |
||
2520 | $classes = $this->_addClass($class, $conditionField, $meta, 'nowrap'); |
||
2521 | |||
2522 | return $this->template->render('display/results/empty_display', [ |
||
2523 | 'align' => $align, |
||
2524 | 'classes' => $classes, |
||
2525 | ]); |
||
2526 | } |
||
2527 | |||
2528 | /** |
||
2529 | * Adds the relevant classes. |
||
2530 | * |
||
2531 | * @param string $class class of table cell |
||
2532 | * @param bool $condition_field whether to add CSS class |
||
2533 | * condition |
||
2534 | * @param stdClass $meta the meta-information about the |
||
2535 | * field |
||
2536 | * @param string $nowrap avoid wrapping |
||
2537 | * @param bool $is_field_truncated is field truncated (display ...) |
||
2538 | * @param TransformationsPlugin $transformation_plugin transformation plugin. |
||
2539 | * Can also be the default function: |
||
2540 | * Core::mimeDefaultFunction |
||
2541 | * @param string $default_function default transformation function |
||
2542 | * |
||
2543 | * @return string the list of classes |
||
2544 | * |
||
2545 | * @access private |
||
2546 | * |
||
2547 | * @see _buildNullDisplay(), _getRowData() |
||
2548 | */ |
||
2549 | private function _addClass( |
||
2550 | $class, |
||
2551 | $condition_field, |
||
2552 | $meta, |
||
2553 | $nowrap, |
||
2554 | $is_field_truncated = false, |
||
2555 | $transformation_plugin = '', |
||
2556 | $default_function = '' |
||
2557 | ) { |
||
2558 | $classes = [ |
||
2559 | $class, |
||
2560 | $nowrap, |
||
2561 | ]; |
||
2562 | |||
2563 | if (isset($meta->mimetype)) { |
||
2564 | $classes[] = preg_replace('/\//', '_', $meta->mimetype); |
||
2565 | } |
||
2566 | |||
2567 | if ($condition_field) { |
||
2568 | $classes[] = 'condition'; |
||
2569 | } |
||
2570 | |||
2571 | if ($is_field_truncated) { |
||
2572 | $classes[] = 'truncated'; |
||
2573 | } |
||
2574 | |||
2575 | $mime_map = $this->__get('mime_map'); |
||
2576 | $orgFullColName = $this->__get('db') . '.' . $meta->orgtable |
||
2577 | . '.' . $meta->orgname; |
||
2578 | if ($transformation_plugin != $default_function |
||
2579 | || !empty($mime_map[$orgFullColName]['input_transformation']) |
||
2580 | ) { |
||
2581 | $classes[] = 'transformed'; |
||
2582 | } |
||
2583 | |||
2584 | // Define classes to be added to this data field based on the type of data |
||
2585 | $matches = [ |
||
2586 | 'enum' => 'enum', |
||
2587 | 'set' => 'set', |
||
2588 | 'binary' => 'hex', |
||
2589 | ]; |
||
2590 | |||
2591 | foreach ($matches as $key => $value) { |
||
2592 | if (mb_strpos($meta->flags, $key) !== false) { |
||
2593 | $classes[] = $value; |
||
2594 | } |
||
2595 | } |
||
2596 | |||
2597 | if (mb_strpos($meta->type, 'bit') !== false) { |
||
2598 | $classes[] = 'bit'; |
||
2599 | } |
||
2600 | |||
2601 | return implode(' ', $classes); |
||
2602 | } // end of the '_addClass()' function |
||
2603 | |||
2604 | /** |
||
2605 | * Prepare the body of the results table |
||
2606 | * |
||
2607 | * @param integer &$dt_result the link id associated to the query |
||
2608 | * which results have to be displayed which |
||
2609 | * results have to be displayed |
||
2610 | * @param array &$displayParts which elements to display |
||
2611 | * @param array $map the list of relations |
||
2612 | * @param array $analyzed_sql_results analyzed sql results |
||
2613 | * @param boolean $is_limited_display with limited operations or not |
||
2614 | * |
||
2615 | * @return string html content |
||
2616 | * |
||
2617 | * @global array $row current row data |
||
2618 | * |
||
2619 | * @access private |
||
2620 | * |
||
2621 | * @see getTable() |
||
2622 | */ |
||
2623 | private function _getTableBody( |
||
2624 | &$dt_result, |
||
2625 | array &$displayParts, |
||
2626 | array $map, |
||
2627 | array $analyzed_sql_results, |
||
2628 | $is_limited_display = false |
||
2629 | ) { |
||
2630 | |||
2631 | global $row; // mostly because of browser transformations, |
||
2632 | // to make the row-data accessible in a plugin |
||
2633 | |||
2634 | $table_body_html = ''; |
||
2635 | |||
2636 | // query without conditions to shorten URLs when needed, 200 is just |
||
2637 | // guess, it should depend on remaining URL length |
||
2638 | $url_sql_query = $this->_getUrlSqlQuery($analyzed_sql_results); |
||
2639 | |||
2640 | $display_params = $this->__get('display_params'); |
||
2641 | |||
2642 | if (! is_array($map)) { |
||
2643 | $map = []; |
||
2644 | } |
||
2645 | |||
2646 | $row_no = 0; |
||
2647 | $display_params['edit'] = []; |
||
2648 | $display_params['copy'] = []; |
||
2649 | $display_params['delete'] = []; |
||
2650 | $display_params['data'] = []; |
||
2651 | $display_params['row_delete'] = []; |
||
2652 | $this->__set('display_params', $display_params); |
||
2653 | |||
2654 | // name of the class added to all grid editable elements; |
||
2655 | // if we don't have all the columns of a unique key in the result set, |
||
2656 | // do not permit grid editing |
||
2657 | if ($is_limited_display || ! $this->__get('editable')) { |
||
2658 | $grid_edit_class = ''; |
||
2659 | } else { |
||
2660 | switch ($GLOBALS['cfg']['GridEditing']) { |
||
2661 | case 'double-click': |
||
2662 | // trying to reduce generated HTML by using shorter |
||
2663 | // classes like click1 and click2 |
||
2664 | $grid_edit_class = 'grid_edit click2'; |
||
2665 | break; |
||
2666 | case 'click': |
||
2667 | $grid_edit_class = 'grid_edit click1'; |
||
2668 | break; |
||
2669 | default: // 'disabled' |
||
2670 | $grid_edit_class = ''; |
||
2671 | break; |
||
2672 | } |
||
2673 | } |
||
2674 | |||
2675 | // prepare to get the column order, if available |
||
2676 | list($col_order, $col_visib) = $this->_getColumnParams( |
||
2677 | $analyzed_sql_results |
||
2678 | ); |
||
2679 | |||
2680 | // Correction University of Virginia 19991216 in the while below |
||
2681 | // Previous code assumed that all tables have keys, specifically that |
||
2682 | // the phpMyAdmin GUI should support row delete/edit only for such |
||
2683 | // tables. |
||
2684 | // Although always using keys is arguably the prescribed way of |
||
2685 | // defining a relational table, it is not required. This will in |
||
2686 | // particular be violated by the novice. |
||
2687 | // We want to encourage phpMyAdmin usage by such novices. So the code |
||
2688 | // below has been changed to conditionally work as before when the |
||
2689 | // table being displayed has one or more keys; but to display |
||
2690 | // delete/edit options correctly for tables without keys. |
||
2691 | |||
2692 | $whereClauseMap = $this->__get('whereClauseMap'); |
||
2693 | while ($row = $GLOBALS['dbi']->fetchRow($dt_result)) { |
||
2694 | // add repeating headers |
||
2695 | if ((($row_no != 0) && ($_SESSION['tmpval']['repeat_cells'] != 0)) |
||
2696 | && !($row_no % $_SESSION['tmpval']['repeat_cells']) |
||
2697 | ) { |
||
2698 | $table_body_html .= $this->_getRepeatingHeaders( |
||
2699 | $display_params |
||
2700 | ); |
||
2701 | } |
||
2702 | |||
2703 | $tr_class = []; |
||
2704 | if ($GLOBALS['cfg']['BrowsePointerEnable'] != true) { |
||
2705 | $tr_class[] = 'nopointer'; |
||
2706 | } |
||
2707 | if ($GLOBALS['cfg']['BrowseMarkerEnable'] != true) { |
||
2708 | $tr_class[] = 'nomarker'; |
||
2709 | } |
||
2710 | |||
2711 | // pointer code part |
||
2712 | $classes = (empty($tr_class) ? ' ' : 'class="' . implode(' ', $tr_class) . '"'); |
||
2713 | $table_body_html .= '<tr ' . $classes . ' >'; |
||
2714 | |||
2715 | // 1. Prepares the row |
||
2716 | |||
2717 | // In print view these variable needs to be initialized |
||
2718 | $del_url = $del_str = $edit_anchor_class |
||
2719 | = $edit_str = $js_conf = $copy_url = $copy_str = $edit_url = null; |
||
2720 | |||
2721 | // 1.2 Defines the URLs for the modify/delete link(s) |
||
2722 | |||
2723 | if (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2724 | || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2725 | ) { |
||
2726 | // Results from a "SELECT" statement -> builds the |
||
2727 | // WHERE clause to use in links (a unique key if possible) |
||
2728 | /** |
||
2729 | * @todo $where_clause could be empty, for example a table |
||
2730 | * with only one field and it's a BLOB; in this case, |
||
2731 | * avoid to display the delete and edit links |
||
2732 | */ |
||
2733 | list($where_clause, $clause_is_unique, $condition_array) |
||
2734 | = Util::getUniqueCondition( |
||
2735 | $dt_result, // handle |
||
2736 | $this->__get('fields_cnt'), // fields_cnt |
||
2737 | $this->__get('fields_meta'), // fields_meta |
||
2738 | $row, // row |
||
2739 | false, // force_unique |
||
2740 | $this->__get('table'), // restrict_to_table |
||
2741 | $analyzed_sql_results // analyzed_sql_results |
||
2742 | ); |
||
2743 | $whereClauseMap[$row_no][$this->__get('table')] = $where_clause; |
||
2744 | $this->__set('whereClauseMap', $whereClauseMap); |
||
2745 | |||
2746 | $where_clause_html = htmlspecialchars($where_clause); |
||
2747 | |||
2748 | // 1.2.1 Modify link(s) - update row case |
||
2749 | if ($displayParts['edit_lnk'] == self::UPDATE_ROW) { |
||
2750 | list($edit_url, $copy_url, $edit_str, $copy_str, |
||
2751 | $edit_anchor_class) |
||
2752 | = $this->_getModifiedLinks( |
||
2753 | $where_clause, |
||
2754 | $clause_is_unique, |
||
2755 | $url_sql_query |
||
2756 | ); |
||
2757 | } // end if (1.2.1) |
||
2758 | |||
2759 | // 1.2.2 Delete/Kill link(s) |
||
2760 | list($del_url, $del_str, $js_conf) |
||
2761 | = $this->_getDeleteAndKillLinks( |
||
2762 | $where_clause, |
||
2763 | $clause_is_unique, |
||
2764 | $url_sql_query, |
||
2765 | $displayParts['del_lnk'], |
||
2766 | $row |
||
2767 | ); |
||
2768 | |||
2769 | // 1.3 Displays the links at left if required |
||
2770 | if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_LEFT) |
||
2771 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH) |
||
2772 | ) { |
||
2773 | $table_body_html .= $this->_getPlacedLinks( |
||
2774 | self::POSITION_LEFT, |
||
2775 | $del_url, |
||
2776 | $displayParts, |
||
2777 | $row_no, |
||
2778 | $where_clause, |
||
2779 | $where_clause_html, |
||
2780 | $condition_array, |
||
2781 | $edit_url, |
||
2782 | $copy_url, |
||
2783 | $edit_anchor_class, |
||
2784 | $edit_str, |
||
2785 | $copy_str, |
||
2786 | $del_str, |
||
2787 | $js_conf |
||
2788 | ); |
||
2789 | } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { |
||
2790 | $table_body_html .= $this->_getPlacedLinks( |
||
2791 | self::POSITION_NONE, |
||
2792 | $del_url, |
||
2793 | $displayParts, |
||
2794 | $row_no, |
||
2795 | $where_clause, |
||
2796 | $where_clause_html, |
||
2797 | $condition_array, |
||
2798 | $edit_url, |
||
2799 | $copy_url, |
||
2800 | $edit_anchor_class, |
||
2801 | $edit_str, |
||
2802 | $copy_str, |
||
2803 | $del_str, |
||
2804 | $js_conf |
||
2805 | ); |
||
2806 | } // end if (1.3) |
||
2807 | } // end if (1) |
||
2808 | |||
2809 | // 2. Displays the rows' values |
||
2810 | if (is_null($this->__get('mime_map'))) { |
||
2811 | $this->_setMimeMap(); |
||
2812 | } |
||
2813 | $table_body_html .= $this->_getRowValues( |
||
2814 | $dt_result, |
||
2815 | $row, |
||
2816 | $row_no, |
||
2817 | $col_order, |
||
2818 | $map, |
||
2819 | $grid_edit_class, |
||
2820 | $col_visib, |
||
2821 | $url_sql_query, |
||
2822 | $analyzed_sql_results |
||
2823 | ); |
||
2824 | |||
2825 | // 3. Displays the modify/delete links on the right if required |
||
2826 | if (($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2827 | || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE) |
||
2828 | ) { |
||
2829 | if (($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_RIGHT) |
||
2830 | || ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_BOTH) |
||
2831 | ) { |
||
2832 | $table_body_html .= $this->_getPlacedLinks( |
||
2833 | self::POSITION_RIGHT, |
||
2834 | $del_url, |
||
2835 | $displayParts, |
||
2836 | $row_no, |
||
2837 | $where_clause, |
||
2838 | $where_clause_html, |
||
2839 | $condition_array, |
||
2840 | $edit_url, |
||
2841 | $copy_url, |
||
2842 | $edit_anchor_class, |
||
2843 | $edit_str, |
||
2844 | $copy_str, |
||
2845 | $del_str, |
||
2846 | $js_conf |
||
2847 | ); |
||
2848 | } |
||
2849 | } // end if (3) |
||
2850 | |||
2851 | $table_body_html .= '</tr>'; |
||
2852 | $table_body_html .= "\n"; |
||
2853 | $row_no++; |
||
2854 | } // end while |
||
2855 | |||
2856 | return $table_body_html; |
||
2857 | } // end of the '_getTableBody()' function |
||
2858 | |||
2859 | /** |
||
2860 | * Sets the MIME details of the columns in the results set |
||
2861 | * |
||
2862 | * @return void |
||
2863 | */ |
||
2864 | private function _setMimeMap() |
||
2865 | { |
||
2866 | $fields_meta = $this->__get('fields_meta'); |
||
2867 | $mimeMap = []; |
||
2868 | $added = []; |
||
2869 | |||
2870 | for ($currentColumn = 0; |
||
2871 | $currentColumn < $this->__get('fields_cnt'); |
||
2872 | ++$currentColumn) { |
||
2873 | $meta = $fields_meta[$currentColumn]; |
||
2874 | $orgFullTableName = $this->__get('db') . '.' . $meta->orgtable; |
||
2875 | |||
2876 | if ($GLOBALS['cfgRelation']['commwork'] |
||
2877 | && $GLOBALS['cfgRelation']['mimework'] |
||
2878 | && $GLOBALS['cfg']['BrowseMIME'] |
||
2879 | && ! $_SESSION['tmpval']['hide_transformation'] |
||
2880 | && empty($added[$orgFullTableName]) |
||
2881 | ) { |
||
2882 | $mimeMap = array_merge( |
||
2883 | $mimeMap, |
||
2884 | $this->transformations->getMime($this->__get('db'), $meta->orgtable, false, true) |
||
2885 | ); |
||
2886 | $added[$orgFullTableName] = true; |
||
2887 | } |
||
2888 | } |
||
2889 | |||
2890 | // special browser transformation for some SHOW statements |
||
2891 | if ($this->__get('is_show') |
||
2892 | && ! $_SESSION['tmpval']['hide_transformation'] |
||
2893 | ) { |
||
2894 | preg_match( |
||
2895 | '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?' |
||
2896 | . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS' |
||
2897 | . ')@i', |
||
2898 | $this->__get('sql_query'), |
||
2899 | $which |
||
2900 | ); |
||
2901 | |||
2902 | if (isset($which[1])) { |
||
2903 | $str = ' ' . strtoupper($which[1]); |
||
2904 | $isShowProcessList = strpos($str, 'PROCESSLIST') > 0; |
||
2905 | if ($isShowProcessList) { |
||
2906 | $mimeMap['..Info'] = [ |
||
2907 | 'mimetype' => 'Text_Plain', |
||
2908 | 'transformation' => 'output/Text_Plain_Sql.php', |
||
2909 | ]; |
||
2910 | } |
||
2911 | |||
2912 | $isShowCreateTable = preg_match( |
||
2913 | '@CREATE[[:space:]]+TABLE@i', |
||
2914 | $this->__get('sql_query') |
||
2915 | ); |
||
2916 | if ($isShowCreateTable) { |
||
2917 | $mimeMap['..Create Table'] = [ |
||
2918 | 'mimetype' => 'Text_Plain', |
||
2919 | 'transformation' => 'output/Text_Plain_Sql.php', |
||
2920 | ]; |
||
2921 | } |
||
2922 | } |
||
2923 | } |
||
2924 | |||
2925 | $this->__set('mime_map', $mimeMap); |
||
2926 | } |
||
2927 | |||
2928 | /** |
||
2929 | * Get the values for one data row |
||
2930 | * |
||
2931 | * @param integer &$dt_result the link id associated to |
||
2932 | * the query which results |
||
2933 | * have to be displayed which |
||
2934 | * results have to be |
||
2935 | * displayed |
||
2936 | * @param array $row current row data |
||
2937 | * @param integer $row_no the index of current row |
||
2938 | * @param array|boolean $col_order the column order false when |
||
2939 | * a property not found false |
||
2940 | * when a property not found |
||
2941 | * @param array $map the list of relations |
||
2942 | * @param string $grid_edit_class the class for all editable |
||
2943 | * columns |
||
2944 | * @param boolean|array|string $col_visib column is visible(false); |
||
2945 | * column isn't visible(string |
||
2946 | * array) |
||
2947 | * @param string $url_sql_query the analyzed sql query |
||
2948 | * @param array $analyzed_sql_results analyzed sql results |
||
2949 | * |
||
2950 | * @return string html content |
||
2951 | * |
||
2952 | * @access private |
||
2953 | * |
||
2954 | * @see _getTableBody() |
||
2955 | */ |
||
2956 | private function _getRowValues( |
||
2957 | &$dt_result, |
||
2958 | array $row, |
||
2959 | $row_no, |
||
2960 | $col_order, |
||
2961 | array $map, |
||
2962 | $grid_edit_class, |
||
2963 | $col_visib, |
||
2964 | $url_sql_query, |
||
2965 | array $analyzed_sql_results |
||
2966 | ) { |
||
2967 | $row_values_html = ''; |
||
2968 | |||
2969 | // Following variable are needed for use in isset/empty or |
||
2970 | // use with array indexes/safe use in foreach |
||
2971 | $sql_query = $this->__get('sql_query'); |
||
2972 | $fields_meta = $this->__get('fields_meta'); |
||
2973 | $highlight_columns = $this->__get('highlight_columns'); |
||
2974 | $mime_map = $this->__get('mime_map'); |
||
2975 | |||
2976 | $row_info = $this->_getRowInfoForSpecialLinks($row, $col_order); |
||
2977 | |||
2978 | $whereClauseMap = $this->__get('whereClauseMap'); |
||
2979 | |||
2980 | $columnCount = $this->__get('fields_cnt'); |
||
2981 | for ($currentColumn = 0; |
||
2982 | $currentColumn < $columnCount; |
||
2983 | ++$currentColumn) { |
||
2984 | // assign $i with appropriate column order |
||
2985 | $i = $col_order ? $col_order[$currentColumn] : $currentColumn; |
||
2986 | |||
2987 | $meta = $fields_meta[$i]; |
||
2988 | $orgFullColName |
||
2989 | = $this->__get('db') . '.' . $meta->orgtable . '.' . $meta->orgname; |
||
2990 | |||
2991 | $not_null_class = $meta->not_null ? 'not_null' : ''; |
||
2992 | $relation_class = isset($map[$meta->name]) ? 'relation' : ''; |
||
2993 | $hide_class = ($col_visib && ! $col_visib[$currentColumn]) |
||
2994 | ? 'hide' |
||
2995 | : ''; |
||
2996 | $grid_edit = $meta->orgtable != '' ? $grid_edit_class : ''; |
||
2997 | |||
2998 | // handle datetime-related class, for grid editing |
||
2999 | $field_type_class |
||
3000 | = $this->_getClassForDateTimeRelatedFields($meta->type); |
||
3001 | |||
3002 | $is_field_truncated = false; |
||
3003 | // combine all the classes applicable to this column's value |
||
3004 | $class = $this->_getClassesForColumn( |
||
3005 | $grid_edit, |
||
3006 | $not_null_class, |
||
3007 | $relation_class, |
||
3008 | $hide_class, |
||
3009 | $field_type_class |
||
3010 | ); |
||
3011 | |||
3012 | // See if this column should get highlight because it's used in the |
||
3013 | // where-query. |
||
3014 | $condition_field = (isset($highlight_columns) |
||
3015 | && (isset($highlight_columns[$meta->name]) |
||
3016 | || isset($highlight_columns[Util::backquote($meta->name)]))) |
||
3017 | ? true |
||
3018 | : false; |
||
3019 | |||
3020 | // Wrap MIME-transformations. [MIME] |
||
3021 | $default_function = [Core::class, 'mimeDefaultFunction']; // default_function |
||
3022 | $transformation_plugin = $default_function; |
||
3023 | $transform_options = []; |
||
3024 | |||
3025 | if ($GLOBALS['cfgRelation']['mimework'] |
||
3026 | && $GLOBALS['cfg']['BrowseMIME'] |
||
3027 | ) { |
||
3028 | if (isset($mime_map[$orgFullColName]['mimetype']) |
||
3029 | && !empty($mime_map[$orgFullColName]['transformation']) |
||
3030 | ) { |
||
3031 | $file = $mime_map[$orgFullColName]['transformation']; |
||
3032 | $include_file = 'libraries/classes/Plugins/Transformations/' . $file; |
||
3033 | |||
3034 | if (@file_exists($include_file)) { |
||
3035 | include_once $include_file; |
||
3036 | $class_name = $this->transformations->getClassName($include_file); |
||
3037 | // todo add $plugin_manager |
||
3038 | $plugin_manager = null; |
||
3039 | $transformation_plugin = new $class_name( |
||
3040 | $plugin_manager |
||
3041 | ); |
||
3042 | |||
3043 | $transform_options = $this->transformations->getOptions( |
||
3044 | isset( |
||
3045 | $mime_map[$orgFullColName] |
||
3046 | ['transformation_options'] |
||
3047 | ) |
||
3048 | ? $mime_map[$orgFullColName] |
||
3049 | ['transformation_options'] |
||
3050 | : '' |
||
3051 | ); |
||
3052 | |||
3053 | $meta->mimetype = str_replace( |
||
3054 | '_', |
||
3055 | '/', |
||
3056 | $mime_map[$orgFullColName]['mimetype'] |
||
3057 | ); |
||
3058 | } // end if file_exists |
||
3059 | } // end if transformation is set |
||
3060 | } // end if mime/transformation works. |
||
3061 | |||
3062 | // Check whether the field needs to display with syntax highlighting |
||
3063 | |||
3064 | $dbLower = mb_strtolower($this->__get('db')); |
||
3065 | $tblLower = mb_strtolower($meta->orgtable); |
||
3066 | $nameLower = mb_strtolower($meta->orgname); |
||
3067 | if (! empty($this->transformation_info[$dbLower][$tblLower][$nameLower]) |
||
3068 | && (trim($row[$i]) != '') |
||
3069 | && ! $_SESSION['tmpval']['hide_transformation'] |
||
3070 | ) { |
||
3071 | include_once $this->transformation_info |
||
3072 | [$dbLower][$tblLower][$nameLower][0]; |
||
3073 | $transformation_plugin = new $this->transformation_info |
||
3074 | [$dbLower][$tblLower][$nameLower][1](null); |
||
3075 | |||
3076 | $transform_options = $this->transformations->getOptions( |
||
3077 | isset($mime_map[$orgFullColName]['transformation_options']) |
||
3078 | ? $mime_map[$orgFullColName]['transformation_options'] |
||
3079 | : '' |
||
3080 | ); |
||
3081 | |||
3082 | $meta->mimetype = str_replace( |
||
3083 | '_', |
||
3084 | '/', |
||
3085 | $this->transformation_info[$dbLower] |
||
3086 | [mb_strtolower($meta->orgtable)] |
||
3087 | [mb_strtolower($meta->orgname)][2] |
||
3088 | ); |
||
3089 | } |
||
3090 | |||
3091 | // Check for the predefined fields need to show as link in schemas |
||
3092 | include_once 'libraries/special_schema_links.inc.php'; |
||
3093 | |||
3094 | if (isset($GLOBALS['special_schema_links']) |
||
3095 | && (! empty($GLOBALS['special_schema_links'][$dbLower][$tblLower][$nameLower])) |
||
3096 | ) { |
||
3097 | $linking_url = $this->_getSpecialLinkUrl( |
||
3098 | $row[$i], |
||
3099 | $row_info, |
||
3100 | mb_strtolower($meta->orgname) |
||
3101 | ); |
||
3102 | $transformation_plugin = new Text_Plain_Link(); |
||
3103 | |||
3104 | $transform_options = [ |
||
3105 | 0 => $linking_url, |
||
3106 | 2 => true |
||
3107 | ]; |
||
3108 | |||
3109 | $meta->mimetype = str_replace( |
||
3110 | '_', |
||
3111 | '/', |
||
3112 | 'Text/Plain' |
||
3113 | ); |
||
3114 | } |
||
3115 | |||
3116 | /* |
||
3117 | * The result set can have columns from more than one table, |
||
3118 | * this is why we have to check for the unique conditions |
||
3119 | * related to this table; however getUniqueCondition() is |
||
3120 | * costly and does not need to be called if we already know |
||
3121 | * the conditions for the current table. |
||
3122 | */ |
||
3123 | if (! isset($whereClauseMap[$row_no][$meta->orgtable])) { |
||
3124 | $unique_conditions = Util::getUniqueCondition( |
||
3125 | $dt_result, // handle |
||
3126 | $this->__get('fields_cnt'), // fields_cnt |
||
3127 | $this->__get('fields_meta'), // fields_meta |
||
3128 | $row, // row |
||
3129 | false, // force_unique |
||
3130 | $meta->orgtable, // restrict_to_table |
||
3131 | $analyzed_sql_results // analyzed_sql_results |
||
3132 | ); |
||
3133 | $whereClauseMap[$row_no][$meta->orgtable] = $unique_conditions[0]; |
||
3134 | } |
||
3135 | |||
3136 | $_url_params = [ |
||
3137 | 'db' => $this->__get('db'), |
||
3138 | 'table' => $meta->orgtable, |
||
3139 | 'where_clause' => $whereClauseMap[$row_no][$meta->orgtable], |
||
3140 | 'transform_key' => $meta->orgname |
||
3141 | ]; |
||
3142 | |||
3143 | if (! empty($sql_query)) { |
||
3144 | $_url_params['sql_query'] = $url_sql_query; |
||
3145 | } |
||
3146 | |||
3147 | $transform_options['wrapper_link'] = Url::getCommon($_url_params); |
||
3148 | |||
3149 | $display_params = $this->__get('display_params'); |
||
3150 | |||
3151 | // in some situations (issue 11406), numeric returns 1 |
||
3152 | // even for a string type |
||
3153 | // for decimal numeric is returning 1 |
||
3154 | // have to improve logic |
||
3155 | if (($meta->numeric == 1 && $meta->type != 'string') || $meta->type == 'real') { |
||
3156 | // n u m e r i c |
||
3157 | |||
3158 | $display_params['data'][$row_no][$i] |
||
3159 | = $this->_getDataCellForNumericColumns( |
||
3160 | (string) $row[$i], |
||
3161 | $class, |
||
3162 | $condition_field, |
||
3163 | $meta, |
||
3164 | $map, |
||
3165 | $is_field_truncated, |
||
3166 | $analyzed_sql_results, |
||
3167 | $transformation_plugin, |
||
3168 | $default_function, |
||
3169 | $transform_options |
||
3170 | ); |
||
3171 | } elseif ($meta->type == self::GEOMETRY_FIELD) { |
||
3172 | // g e o m e t r y |
||
3173 | |||
3174 | // Remove 'grid_edit' from $class as we do not allow to |
||
3175 | // inline-edit geometry data. |
||
3176 | $class = str_replace('grid_edit', '', $class); |
||
3177 | |||
3178 | $display_params['data'][$row_no][$i] |
||
3179 | = $this->_getDataCellForGeometryColumns( |
||
3180 | $row[$i], |
||
3181 | $class, |
||
3182 | $meta, |
||
3183 | $map, |
||
3184 | $_url_params, |
||
3185 | $condition_field, |
||
3186 | $transformation_plugin, |
||
3187 | $default_function, |
||
3188 | $transform_options, |
||
3189 | $analyzed_sql_results |
||
3190 | ); |
||
3191 | } else { |
||
3192 | // n o t n u m e r i c |
||
3193 | |||
3194 | $display_params['data'][$row_no][$i] |
||
3195 | = $this->_getDataCellForNonNumericColumns( |
||
3196 | $row[$i], |
||
3197 | $class, |
||
3198 | $meta, |
||
3199 | $map, |
||
3200 | $_url_params, |
||
3201 | $condition_field, |
||
3202 | $transformation_plugin, |
||
3203 | $default_function, |
||
3204 | $transform_options, |
||
3205 | $is_field_truncated, |
||
3206 | $analyzed_sql_results, |
||
3207 | $dt_result, |
||
3208 | $i |
||
3209 | ); |
||
3210 | } |
||
3211 | |||
3212 | // output stored cell |
||
3213 | $row_values_html .= $display_params['data'][$row_no][$i]; |
||
3214 | |||
3215 | if (isset($display_params['rowdata'][$i][$row_no])) { |
||
3216 | $display_params['rowdata'][$i][$row_no] |
||
3217 | .= $display_params['data'][$row_no][$i]; |
||
3218 | } else { |
||
3219 | $display_params['rowdata'][$i][$row_no] |
||
3220 | = $display_params['data'][$row_no][$i]; |
||
3221 | } |
||
3222 | |||
3223 | $this->__set('display_params', $display_params); |
||
3224 | } // end for |
||
3225 | |||
3226 | return $row_values_html; |
||
3227 | } // end of the '_getRowValues()' function |
||
3228 | |||
3229 | /** |
||
3230 | * Get link for display special schema links |
||
3231 | * |
||
3232 | * @param string $column_value column value |
||
3233 | * @param array $row_info information about row |
||
3234 | * @param string $field_name column name |
||
3235 | * |
||
3236 | * @return string generated link |
||
3237 | */ |
||
3238 | private function _getSpecialLinkUrl($column_value, array $row_info, $field_name) |
||
3239 | { |
||
3240 | |||
3241 | $linking_url_params = []; |
||
3242 | $link_relations = $GLOBALS['special_schema_links'] |
||
3243 | [mb_strtolower($this->__get('db'))] |
||
3244 | [mb_strtolower($this->__get('table'))] |
||
3245 | [$field_name]; |
||
3246 | |||
3247 | if (! is_array($link_relations['link_param'])) { |
||
3248 | $linking_url_params[$link_relations['link_param']] = $column_value; |
||
3249 | } else { |
||
3250 | // Consider only the case of creating link for column field |
||
3251 | // sql query that needs to be passed as url param |
||
3252 | $sql = 'SELECT `' . $column_value . '` FROM `' |
||
3253 | . $row_info[$link_relations['link_param'][1]] . '`.`' |
||
3254 | . $row_info[$link_relations['link_param'][2]] . '`'; |
||
3255 | $linking_url_params[$link_relations['link_param'][0]] = $sql; |
||
3256 | } |
||
3257 | |||
3258 | $divider = strpos($link_relations['default_page'], '?') ? '&' : '?'; |
||
3259 | if (empty($link_relations['link_dependancy_params'])) { |
||
3260 | return $link_relations['default_page'] |
||
3261 | . Url::getCommonRaw($linking_url_params, $divider); |
||
3262 | } |
||
3263 | |||
3264 | foreach ($link_relations['link_dependancy_params'] as $new_param) { |
||
3265 | // If param_info is an array, set the key and value |
||
3266 | // from that array |
||
3267 | if (is_array($new_param['param_info'])) { |
||
3268 | $linking_url_params[$new_param['param_info'][0]] |
||
3269 | = $new_param['param_info'][1]; |
||
3270 | continue; |
||
3271 | } |
||
3272 | |||
3273 | $linking_url_params[$new_param['param_info']] |
||
3274 | = $row_info[mb_strtolower($new_param['column_name'])]; |
||
3275 | |||
3276 | // Special case 1 - when executing routines, according |
||
3277 | // to the type of the routine, url param changes |
||
3278 | if (empty($row_info['routine_type'])) { |
||
3279 | continue; |
||
3280 | } |
||
3281 | } |
||
3282 | |||
3283 | return $link_relations['default_page'] |
||
3284 | . Url::getCommonRaw($linking_url_params, $divider); |
||
3285 | } |
||
3286 | |||
3287 | |||
3288 | /** |
||
3289 | * Prepare row information for display special links |
||
3290 | * |
||
3291 | * @param array $row current row data |
||
3292 | * @param array|boolean $col_order the column order |
||
3293 | * |
||
3294 | * @return array associative array with column nama -> value |
||
3295 | */ |
||
3296 | private function _getRowInfoForSpecialLinks(array $row, $col_order) |
||
3297 | { |
||
3298 | |||
3299 | $row_info = []; |
||
3300 | $fields_meta = $this->__get('fields_meta'); |
||
3301 | |||
3302 | for ($n = 0; $n < $this->__get('fields_cnt'); ++$n) { |
||
3303 | $m = $col_order ? $col_order[$n] : $n; |
||
3304 | $row_info[mb_strtolower($fields_meta[$m]->orgname)] |
||
3305 | = $row[$m]; |
||
3306 | } |
||
3307 | |||
3308 | return $row_info; |
||
3309 | } |
||
3310 | |||
3311 | /** |
||
3312 | * Get url sql query without conditions to shorten URLs |
||
3313 | * |
||
3314 | * @param array $analyzed_sql_results analyzed sql results |
||
3315 | * |
||
3316 | * @return string analyzed sql query |
||
3317 | * |
||
3318 | * @access private |
||
3319 | * |
||
3320 | * @see _getTableBody() |
||
3321 | */ |
||
3322 | private function _getUrlSqlQuery(array $analyzed_sql_results) |
||
3323 | { |
||
3324 | if (($analyzed_sql_results['querytype'] != 'SELECT') |
||
3325 | || (mb_strlen($this->__get('sql_query')) < 200) |
||
3326 | ) { |
||
3327 | return $this->__get('sql_query'); |
||
3328 | } |
||
3329 | |||
3330 | $query = 'SELECT ' . Query::getClause( |
||
3331 | $analyzed_sql_results['statement'], |
||
3332 | $analyzed_sql_results['parser']->list, |
||
3333 | 'SELECT' |
||
3334 | ); |
||
3335 | |||
3336 | $from_clause = Query::getClause( |
||
3337 | $analyzed_sql_results['statement'], |
||
3338 | $analyzed_sql_results['parser']->list, |
||
3339 | 'FROM' |
||
3340 | ); |
||
3341 | |||
3342 | if (!empty($from_clause)) { |
||
3343 | $query .= ' FROM ' . $from_clause; |
||
3344 | } |
||
3345 | |||
3346 | return $query; |
||
3347 | } // end of the '_getUrlSqlQuery()' function |
||
3348 | |||
3349 | |||
3350 | /** |
||
3351 | * Get column order and column visibility |
||
3352 | * |
||
3353 | * @param array $analyzed_sql_results analyzed sql results |
||
3354 | * |
||
3355 | * @return array 2 element array - $col_order, $col_visib |
||
3356 | * |
||
3357 | * @access private |
||
3358 | * |
||
3359 | * @see _getTableBody() |
||
3360 | */ |
||
3361 | private function _getColumnParams(array $analyzed_sql_results) |
||
3362 | { |
||
3363 | if ($this->_isSelect($analyzed_sql_results)) { |
||
3364 | $pmatable = new Table($this->__get('table'), $this->__get('db')); |
||
3365 | $col_order = $pmatable->getUiProp(Table::PROP_COLUMN_ORDER); |
||
3366 | /* Validate the value */ |
||
3367 | if ($col_order !== false) { |
||
3368 | $fields_cnt = $this->__get('fields_cnt'); |
||
3369 | foreach ($col_order as $value) { |
||
3370 | if ($value >= $fields_cnt) { |
||
3371 | $pmatable->removeUiProp(Table::PROP_COLUMN_ORDER); |
||
3372 | $fields_cnt = false; |
||
3373 | } |
||
3374 | } |
||
3375 | } |
||
3376 | $col_visib = $pmatable->getUiProp(Table::PROP_COLUMN_VISIB); |
||
3377 | } else { |
||
3378 | $col_order = false; |
||
3379 | $col_visib = false; |
||
3380 | } |
||
3381 | |||
3382 | return [$col_order, $col_visib]; |
||
3383 | } // end of the '_getColumnParams()' function |
||
3384 | |||
3385 | |||
3386 | /** |
||
3387 | * Get HTML for repeating headers |
||
3388 | * |
||
3389 | * @param array $display_params holds various display info |
||
3390 | * |
||
3391 | * @return string html content |
||
3392 | * |
||
3393 | * @access private |
||
3394 | * |
||
3395 | * @see _getTableBody() |
||
3396 | */ |
||
3397 | private function _getRepeatingHeaders( |
||
3398 | array $display_params |
||
3399 | ) { |
||
3400 | $header_html = '<tr>' . "\n"; |
||
3401 | |||
3402 | if ($display_params['emptypre'] > 0) { |
||
3403 | $header_html .= ' <th colspan="' |
||
3404 | . $display_params['emptypre'] . '">' |
||
3405 | . "\n" . ' </th>' . "\n"; |
||
3406 | } elseif ($GLOBALS['cfg']['RowActionLinks'] == self::POSITION_NONE) { |
||
3407 | $header_html .= ' <th></th>' . "\n"; |
||
3408 | } |
||
3409 | |||
3410 | foreach ($display_params['desc'] as $val) { |
||
3411 | $header_html .= $val; |
||
3412 | } |
||
3413 | |||
3414 | if ($display_params['emptyafter'] > 0) { |
||
3415 | $header_html |
||
3416 | .= ' <th colspan="' . $display_params['emptyafter'] |
||
3417 | . '">' |
||
3418 | . "\n" . ' </th>' . "\n"; |
||
3419 | } |
||
3420 | $header_html .= '</tr>' . "\n"; |
||
3421 | |||
3422 | return $header_html; |
||
3423 | } // end of the '_getRepeatingHeaders()' function |
||
3424 | |||
3425 | |||
3426 | /** |
||
3427 | * Get modified links |
||
3428 | * |
||
3429 | * @param string $where_clause the where clause of the sql |
||
3430 | * @param boolean $clause_is_unique the unique condition of clause |
||
3431 | * @param string $url_sql_query the analyzed sql query |
||
3432 | * |
||
3433 | * @return array 5 element array - $edit_url, $copy_url, |
||
3434 | * $edit_str, $copy_str, $edit_anchor_class |
||
3435 | * |
||
3436 | * @access private |
||
3437 | * |
||
3438 | * @see _getTableBody() |
||
3439 | */ |
||
3440 | private function _getModifiedLinks( |
||
3441 | $where_clause, |
||
3442 | $clause_is_unique, |
||
3443 | $url_sql_query |
||
3444 | ) { |
||
3445 | |||
3446 | $_url_params = [ |
||
3447 | 'db' => $this->__get('db'), |
||
3448 | 'table' => $this->__get('table'), |
||
3449 | 'where_clause' => $where_clause, |
||
3450 | 'clause_is_unique' => $clause_is_unique, |
||
3451 | 'sql_query' => $url_sql_query, |
||
3452 | 'goto' => 'sql.php', |
||
3453 | ]; |
||
3454 | |||
3455 | $edit_url = 'tbl_change.php' |
||
3456 | . Url::getCommon( |
||
3457 | $_url_params + ['default_action' => 'update'] |
||
3458 | ); |
||
3459 | |||
3460 | $copy_url = 'tbl_change.php' |
||
3461 | . Url::getCommon( |
||
3462 | $_url_params + ['default_action' => 'insert'] |
||
3463 | ); |
||
3464 | |||
3465 | $edit_str = $this->_getActionLinkContent( |
||
3466 | 'b_edit', |
||
3467 | __('Edit') |
||
3468 | ); |
||
3469 | $copy_str = $this->_getActionLinkContent( |
||
3470 | 'b_insrow', |
||
3471 | __('Copy') |
||
3472 | ); |
||
3473 | |||
3474 | // Class definitions required for grid editing jQuery scripts |
||
3475 | $edit_anchor_class = "edit_row_anchor"; |
||
3476 | if ($clause_is_unique == 0) { |
||
3477 | $edit_anchor_class .= ' nonunique'; |
||
3478 | } |
||
3479 | |||
3480 | return [$edit_url, $copy_url, $edit_str, $copy_str, $edit_anchor_class]; |
||
3481 | } // end of the '_getModifiedLinks()' function |
||
3482 | |||
3483 | |||
3484 | /** |
||
3485 | * Get delete and kill links |
||
3486 | * |
||
3487 | * @param string $where_clause the where clause of the sql |
||
3488 | * @param boolean $clause_is_unique the unique condition of clause |
||
3489 | * @param string $url_sql_query the analyzed sql query |
||
3490 | * @param string $del_lnk the delete link of current row |
||
3491 | * @param array $row the current row |
||
3492 | * |
||
3493 | * @return array 3 element array |
||
3494 | * $del_url, $del_str, $js_conf |
||
3495 | * |
||
3496 | * @access private |
||
3497 | * |
||
3498 | * @see _getTableBody() |
||
3499 | */ |
||
3500 | private function _getDeleteAndKillLinks( |
||
3501 | $where_clause, |
||
3502 | $clause_is_unique, |
||
3503 | $url_sql_query, |
||
3504 | $del_lnk, |
||
3505 | array $row |
||
3506 | ) { |
||
3507 | |||
3508 | $goto = $this->__get('goto'); |
||
3509 | |||
3510 | if ($del_lnk == self::DELETE_ROW) { // delete row case |
||
3511 | $_url_params = [ |
||
3512 | 'db' => $this->__get('db'), |
||
3513 | 'table' => $this->__get('table'), |
||
3514 | 'sql_query' => $url_sql_query, |
||
3515 | 'message_to_show' => __('The row has been deleted.'), |
||
3516 | 'goto' => (empty($goto) ? 'tbl_sql.php' : $goto), |
||
3517 | ]; |
||
3518 | |||
3519 | $lnk_goto = 'sql.php' . Url::getCommonRaw($_url_params); |
||
3520 | |||
3521 | $del_query = 'DELETE FROM ' |
||
3522 | . Util::backquote($this->__get('table')) |
||
3523 | . ' WHERE ' . $where_clause . |
||
3524 | ($clause_is_unique ? '' : ' LIMIT 1'); |
||
3525 | |||
3526 | $_url_params = [ |
||
3527 | 'db' => $this->__get('db'), |
||
3528 | 'table' => $this->__get('table'), |
||
3529 | 'sql_query' => $del_query, |
||
3530 | 'message_to_show' => __('The row has been deleted.'), |
||
3531 | 'goto' => $lnk_goto, |
||
3532 | ]; |
||
3533 | $del_url = 'sql.php' . Url::getCommon($_url_params); |
||
3534 | |||
3535 | $js_conf = 'DELETE FROM ' . Sanitize::jsFormat($this->__get('table')) |
||
3536 | . ' WHERE ' . Sanitize::jsFormat($where_clause, false) |
||
3537 | . ($clause_is_unique ? '' : ' LIMIT 1'); |
||
3538 | |||
3539 | $del_str = $this->_getActionLinkContent('b_drop', __('Delete')); |
||
3540 | } elseif ($del_lnk == self::KILL_PROCESS) { // kill process case |
||
3541 | $_url_params = [ |
||
3542 | 'db' => $this->__get('db'), |
||
3543 | 'table' => $this->__get('table'), |
||
3544 | 'sql_query' => $url_sql_query, |
||
3545 | 'goto' => 'index.php', |
||
3546 | ]; |
||
3547 | |||
3548 | $lnk_goto = 'sql.php' . Url::getCommonRaw($_url_params); |
||
3549 | |||
3550 | $kill = $GLOBALS['dbi']->getKillQuery($row[0]); |
||
3551 | |||
3552 | $_url_params = [ |
||
3553 | 'db' => 'mysql', |
||
3554 | 'sql_query' => $kill, |
||
3555 | 'goto' => $lnk_goto, |
||
3556 | ]; |
||
3557 | |||
3558 | $del_url = 'sql.php' . Url::getCommon($_url_params); |
||
3559 | $js_conf = $kill; |
||
3560 | $del_str = Util::getIcon( |
||
3561 | 'b_drop', |
||
3562 | __('Kill') |
||
3563 | ); |
||
3564 | } else { |
||
3565 | $del_url = $del_str = $js_conf = null; |
||
3566 | } |
||
3567 | |||
3568 | return [$del_url, $del_str, $js_conf]; |
||
3569 | } // end of the '_getDeleteAndKillLinks()' function |
||
3570 | |||
3571 | |||
3572 | /** |
||
3573 | * Get content inside the table row action links (Edit/Copy/Delete) |
||
3574 | * |
||
3575 | * @param string $icon The name of the file to get |
||
3576 | * @param string $display_text The text displaying after the image icon |
||
3577 | * |
||
3578 | * @return string |
||
3579 | * |
||
3580 | * @access private |
||
3581 | * |
||
3582 | * @see _getModifiedLinks(), _getDeleteAndKillLinks() |
||
3583 | */ |
||
3584 | private function _getActionLinkContent($icon, $display_text) |
||
3585 | { |
||
3586 | |||
3587 | $linkContent = ''; |
||
3588 | |||
3589 | if (isset($GLOBALS['cfg']['RowActionType']) |
||
3590 | && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_ICONS |
||
3591 | ) { |
||
3592 | $linkContent .= '<span class="nowrap">' |
||
3593 | . Util::getImage( |
||
3594 | $icon, |
||
3595 | $display_text |
||
3596 | ) |
||
3597 | . '</span>'; |
||
3598 | } elseif (isset($GLOBALS['cfg']['RowActionType']) |
||
3599 | && $GLOBALS['cfg']['RowActionType'] == self::ACTION_LINK_CONTENT_TEXT |
||
3600 | ) { |
||
3601 | $linkContent .= '<span class="nowrap">' . $display_text . '</span>'; |
||
3602 | } else { |
||
3603 | $linkContent .= Util::getIcon( |
||
3604 | $icon, |
||
3605 | $display_text |
||
3606 | ); |
||
3607 | } |
||
3608 | |||
3609 | return $linkContent; |
||
3610 | } |
||
3611 | |||
3612 | |||
3613 | /** |
||
3614 | * Prepare placed links |
||
3615 | * |
||
3616 | * @param string $dir the direction of links should place |
||
3617 | * @param string $del_url the url for delete row |
||
3618 | * @param array $displayParts which elements to display |
||
3619 | * @param integer $row_no the index of current row |
||
3620 | * @param string $where_clause the where clause of the sql |
||
3621 | * @param string $where_clause_html the html encoded where clause |
||
3622 | * @param array $condition_array array of keys (primary, unique, condition) |
||
3623 | * @param string $edit_url the url for edit row |
||
3624 | * @param string $copy_url the url for copy row |
||
3625 | * @param string $edit_anchor_class the class for html element for edit |
||
3626 | * @param string $edit_str the label for edit row |
||
3627 | * @param string $copy_str the label for copy row |
||
3628 | * @param string $del_str the label for delete row |
||
3629 | * @param string|null $js_conf text for the JS confirmation |
||
3630 | * |
||
3631 | * @return string html content |
||
3632 | * |
||
3633 | * @access private |
||
3634 | * |
||
3635 | * @see _getTableBody() |
||
3636 | */ |
||
3637 | private function _getPlacedLinks( |
||
3638 | $dir, |
||
3639 | $del_url, |
||
3640 | array $displayParts, |
||
3641 | $row_no, |
||
3642 | $where_clause, |
||
3643 | $where_clause_html, |
||
3644 | array $condition_array, |
||
3645 | $edit_url, |
||
3646 | $copy_url, |
||
3647 | $edit_anchor_class, |
||
3648 | $edit_str, |
||
3649 | $copy_str, |
||
3650 | $del_str, |
||
3651 | ?string $js_conf |
||
3652 | ) { |
||
3653 | |||
3654 | if (! isset($js_conf)) { |
||
3655 | $js_conf = ''; |
||
3656 | } |
||
3657 | |||
3658 | return $this->_getCheckboxAndLinks( |
||
3659 | $dir, |
||
3660 | $del_url, |
||
3661 | $displayParts, |
||
3662 | $row_no, |
||
3663 | $where_clause, |
||
3664 | $where_clause_html, |
||
3665 | $condition_array, |
||
3666 | $edit_url, |
||
3667 | $copy_url, |
||
3668 | $edit_anchor_class, |
||
3669 | $edit_str, |
||
3670 | $copy_str, |
||
3671 | $del_str, |
||
3672 | $js_conf |
||
3673 | ); |
||
3674 | } // end of the '_getPlacedLinks()' function |
||
3675 | |||
3676 | |||
3677 | /** |
||
3678 | * Get the combined classes for a column |
||
3679 | * |
||
3680 | * @param string $grid_edit_class the class for all editable columns |
||
3681 | * @param string $not_null_class the class for not null columns |
||
3682 | * @param string $relation_class the class for relations in a column |
||
3683 | * @param string $hide_class the class for visibility of a column |
||
3684 | * @param string $field_type_class the class related to type of the field |
||
3685 | * |
||
3686 | * @return string the combined classes |
||
3687 | * |
||
3688 | * @access private |
||
3689 | * |
||
3690 | * @see _getTableBody() |
||
3691 | */ |
||
3692 | private function _getClassesForColumn( |
||
3693 | $grid_edit_class, |
||
3694 | $not_null_class, |
||
3695 | $relation_class, |
||
3696 | $hide_class, |
||
3697 | $field_type_class |
||
3698 | ) { |
||
3699 | $class = 'data ' . $grid_edit_class . ' ' . $not_null_class . ' ' |
||
3700 | . $relation_class . ' ' . $hide_class . ' ' . $field_type_class; |
||
3701 | |||
3702 | return $class; |
||
3703 | } // end of the '_getClassesForColumn()' function |
||
3704 | |||
3705 | |||
3706 | /** |
||
3707 | * Get class for datetime related fields |
||
3708 | * |
||
3709 | * @param string $type the type of the column field |
||
3710 | * |
||
3711 | * @return string the class for the column |
||
3712 | * |
||
3713 | * @access private |
||
3714 | * |
||
3715 | * @see _getTableBody() |
||
3716 | */ |
||
3717 | private function _getClassForDateTimeRelatedFields($type) |
||
3718 | { |
||
3719 | if ((substr($type, 0, 9) == self::TIMESTAMP_FIELD) |
||
3720 | || ($type == self::DATETIME_FIELD) |
||
3721 | ) { |
||
3722 | $field_type_class = 'datetimefield'; |
||
3723 | } elseif ($type == self::DATE_FIELD) { |
||
3724 | $field_type_class = 'datefield'; |
||
3725 | } elseif ($type == self::TIME_FIELD) { |
||
3726 | $field_type_class = 'timefield'; |
||
3727 | } elseif ($type == self::STRING_FIELD) { |
||
3728 | $field_type_class = 'text'; |
||
3729 | } else { |
||
3730 | $field_type_class = ''; |
||
3731 | } |
||
3732 | return $field_type_class; |
||
3733 | } // end of the '_getClassForDateTimeRelatedFields()' function |
||
3734 | |||
3735 | |||
3736 | /** |
||
3737 | * Prepare data cell for numeric type fields |
||
3738 | * |
||
3739 | * @param string|null $column the column's value |
||
3740 | * @param string $class the html class for column |
||
3741 | * @param boolean $condition_field the column should highlighted |
||
3742 | * or not |
||
3743 | * @param stdClass $meta the meta-information about this |
||
3744 | * field |
||
3745 | * @param array $map the list of relations |
||
3746 | * @param boolean $is_field_truncated the condition for blob data |
||
3747 | * replacements |
||
3748 | * @param array $analyzed_sql_results the analyzed query |
||
3749 | * @param TransformationsPlugin $transformation_plugin the name of transformation plugin |
||
3750 | * @param string $default_function the default transformation |
||
3751 | * function |
||
3752 | * @param array $transform_options the transformation parameters |
||
3753 | * |
||
3754 | * @return string the prepared cell, html content |
||
3755 | * |
||
3756 | * @access private |
||
3757 | * |
||
3758 | * @see _getTableBody() |
||
3759 | */ |
||
3760 | private function _getDataCellForNumericColumns( |
||
3761 | ?string $column, |
||
3762 | $class, |
||
3763 | $condition_field, |
||
3764 | $meta, |
||
3765 | array $map, |
||
3766 | $is_field_truncated, |
||
3767 | array $analyzed_sql_results, |
||
3768 | $transformation_plugin, |
||
3769 | $default_function, |
||
3770 | array $transform_options |
||
3771 | ) { |
||
3772 | |||
3773 | if (! isset($column) || is_null($column)) { |
||
3774 | $cell = $this->_buildNullDisplay( |
||
3775 | 'right ' . $class, |
||
3776 | $condition_field, |
||
3777 | $meta, |
||
3778 | '' |
||
3779 | ); |
||
3780 | } elseif ($column != '') { |
||
3781 | $nowrap = ' nowrap'; |
||
3782 | $where_comparison = ' = ' . $column; |
||
3783 | |||
3784 | $cell = $this->_getRowData( |
||
3785 | 'right ' . $class, |
||
3786 | $condition_field, |
||
3787 | $analyzed_sql_results, |
||
3788 | $meta, |
||
3789 | $map, |
||
3790 | $column, |
||
3791 | $transformation_plugin, |
||
3792 | $default_function, |
||
3793 | $nowrap, |
||
3794 | $where_comparison, |
||
3795 | $transform_options, |
||
3796 | $is_field_truncated, |
||
3797 | '' |
||
3798 | ); |
||
3799 | } else { |
||
3800 | $cell = $this->_buildEmptyDisplay( |
||
3801 | 'right ' . $class, |
||
3802 | $condition_field, |
||
3803 | $meta, |
||
3804 | '' |
||
3805 | ); |
||
3806 | } |
||
3807 | |||
3808 | return $cell; |
||
3809 | } // end of the '_getDataCellForNumericColumns()' function |
||
3810 | |||
3811 | |||
3812 | /** |
||
3813 | * Get data cell for geometry type fields |
||
3814 | * |
||
3815 | * @param string|null $column the relevant column in data row |
||
3816 | * @param string $class the html class for column |
||
3817 | * @param stdClass $meta the meta-information about |
||
3818 | * this field |
||
3819 | * @param array $map the list of relations |
||
3820 | * @param array $_url_params the parameters for generate url |
||
3821 | * @param boolean $condition_field the column should highlighted |
||
3822 | * or not |
||
3823 | * @param TransformationsPlugin $transformation_plugin the name of transformation |
||
3824 | * function |
||
3825 | * @param string $default_function the default transformation |
||
3826 | * function |
||
3827 | * @param string $transform_options the transformation parameters |
||
3828 | * @param array $analyzed_sql_results the analyzed query |
||
3829 | * |
||
3830 | * @return string the prepared data cell, html content |
||
3831 | * |
||
3832 | * @access private |
||
3833 | * |
||
3834 | * @see _getTableBody() |
||
3835 | */ |
||
3836 | private function _getDataCellForGeometryColumns( |
||
3837 | ?string $column, |
||
3838 | $class, |
||
3839 | $meta, |
||
3840 | array $map, |
||
3841 | array $_url_params, |
||
3842 | $condition_field, |
||
3843 | $transformation_plugin, |
||
3844 | $default_function, |
||
3845 | $transform_options, |
||
3846 | array $analyzed_sql_results |
||
3847 | ) { |
||
3848 | if (! isset($column) || is_null($column)) { |
||
3849 | $cell = $this->_buildNullDisplay($class, $condition_field, $meta); |
||
3850 | return $cell; |
||
3851 | } |
||
3852 | |||
3853 | if ($column == '') { |
||
3854 | $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); |
||
3855 | return $cell; |
||
3856 | } |
||
3857 | |||
3858 | // Display as [GEOMETRY - (size)] |
||
3859 | if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_GEOM) { |
||
3860 | $geometry_text = $this->_handleNonPrintableContents( |
||
3861 | strtoupper(self::GEOMETRY_FIELD), |
||
3862 | $column, |
||
3863 | $transformation_plugin, |
||
3864 | $transform_options, |
||
3865 | $default_function, |
||
3866 | $meta, |
||
3867 | $_url_params |
||
3868 | ); |
||
3869 | |||
3870 | $cell = $this->_buildValueDisplay( |
||
3871 | $class, |
||
3872 | $condition_field, |
||
3873 | $geometry_text |
||
3874 | ); |
||
3875 | return $cell; |
||
3876 | } |
||
3877 | |||
3878 | if ($_SESSION['tmpval']['geoOption'] == self::GEOMETRY_DISP_WKT) { |
||
3879 | // Prepare in Well Known Text(WKT) format. |
||
3880 | $where_comparison = ' = ' . $column; |
||
3881 | |||
3882 | // Convert to WKT format |
||
3883 | $wktval = Util::asWKT($column); |
||
3884 | list( |
||
3885 | $is_field_truncated, |
||
3886 | $wktval, |
||
3887 | // skip 3rd param |
||
3888 | ) = $this->_getPartialText($wktval); |
||
3889 | |||
3890 | $cell = $this->_getRowData( |
||
3891 | $class, |
||
3892 | $condition_field, |
||
3893 | $analyzed_sql_results, |
||
3894 | $meta, |
||
3895 | $map, |
||
3896 | $wktval, |
||
3897 | $transformation_plugin, |
||
3898 | $default_function, |
||
3899 | '', |
||
3900 | $where_comparison, |
||
3901 | $transform_options, |
||
3902 | $is_field_truncated, |
||
3903 | '' |
||
3904 | ); |
||
3905 | return $cell; |
||
3906 | } |
||
3907 | |||
3908 | // Prepare in Well Known Binary (WKB) format. |
||
3909 | |||
3910 | if ($_SESSION['tmpval']['display_binary']) { |
||
3911 | $where_comparison = ' = ' . $column; |
||
3912 | |||
3913 | $wkbval = substr(bin2hex($column), 8); |
||
3914 | list( |
||
3915 | $is_field_truncated, |
||
3916 | $wkbval, |
||
3917 | // skip 3rd param |
||
3918 | ) = $this->_getPartialText($wkbval); |
||
3919 | |||
3920 | $cell = $this->_getRowData( |
||
3921 | $class, |
||
3922 | $condition_field, |
||
3923 | $analyzed_sql_results, |
||
3924 | $meta, |
||
3925 | $map, |
||
3926 | $wkbval, |
||
3927 | $transformation_plugin, |
||
3928 | $default_function, |
||
3929 | '', |
||
3930 | $where_comparison, |
||
3931 | $transform_options, |
||
3932 | $is_field_truncated, |
||
3933 | '' |
||
3934 | ); |
||
3935 | return $cell; |
||
3936 | } |
||
3937 | |||
3938 | $wkbval = $this->_handleNonPrintableContents( |
||
3939 | self::BINARY_FIELD, |
||
3940 | $column, |
||
3941 | $transformation_plugin, |
||
3942 | $transform_options, |
||
3943 | $default_function, |
||
3944 | $meta, |
||
3945 | $_url_params |
||
3946 | ); |
||
3947 | |||
3948 | $cell = $this->_buildValueDisplay( |
||
3949 | $class, |
||
3950 | $condition_field, |
||
3951 | $wkbval |
||
3952 | ); |
||
3953 | |||
3954 | return $cell; |
||
3955 | } // end of the '_getDataCellForGeometryColumns()' function |
||
3956 | |||
3957 | |||
3958 | /** |
||
3959 | * Get data cell for non numeric type fields |
||
3960 | * |
||
3961 | * @param string|null $column the relevant column in data row |
||
3962 | * @param string $class the html class for column |
||
3963 | * @param stdClass $meta the meta-information about |
||
3964 | * the field |
||
3965 | * @param array $map the list of relations |
||
3966 | * @param array $_url_params the parameters for generate |
||
3967 | * url |
||
3968 | * @param boolean $condition_field the column should highlighted |
||
3969 | * or not |
||
3970 | * @param TransformationsPlugin $transformation_plugin the name of transformation |
||
3971 | * function |
||
3972 | * @param string $default_function the default transformation |
||
3973 | * function |
||
3974 | * @param string $transform_options the transformation parameters |
||
3975 | * @param boolean $is_field_truncated is data truncated due to |
||
3976 | * LimitChars |
||
3977 | * @param array $analyzed_sql_results the analyzed query |
||
3978 | * @param integer &$dt_result the link id associated to |
||
3979 | * the query which results |
||
3980 | * have to be displayed |
||
3981 | * @param integer $col_index the column index |
||
3982 | * |
||
3983 | * @return string the prepared data cell, html content |
||
3984 | * |
||
3985 | * @access private |
||
3986 | * |
||
3987 | * @see _getTableBody() |
||
3988 | */ |
||
3989 | private function _getDataCellForNonNumericColumns( |
||
3990 | ?string $column, |
||
3991 | $class, |
||
3992 | $meta, |
||
3993 | array $map, |
||
3994 | array $_url_params, |
||
3995 | $condition_field, |
||
3996 | $transformation_plugin, |
||
3997 | $default_function, |
||
3998 | $transform_options, |
||
3999 | $is_field_truncated, |
||
4000 | array $analyzed_sql_results, |
||
4001 | &$dt_result, |
||
4002 | $col_index |
||
4003 | ) { |
||
4004 | $original_length = 0; |
||
4005 | |||
4006 | $is_analyse = $this->__get('is_analyse'); |
||
4007 | $field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index); |
||
4008 | |||
4009 | $bIsText = gettype($transformation_plugin) === 'object' |
||
4010 | && strpos($transformation_plugin->getMIMEtype(), 'Text') |
||
4011 | === false; |
||
4012 | |||
4013 | // disable inline grid editing |
||
4014 | // if binary fields are protected |
||
4015 | // or transformation plugin is of non text type |
||
4016 | // such as image |
||
4017 | if ((stristr($field_flags, self::BINARY_FIELD) |
||
4018 | && ($GLOBALS['cfg']['ProtectBinary'] === 'all' |
||
4019 | || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' |
||
4020 | && !stristr($meta->type, self::BLOB_FIELD)) |
||
4021 | || ($GLOBALS['cfg']['ProtectBinary'] === 'blob' |
||
4022 | && stristr($meta->type, self::BLOB_FIELD)))) |
||
4023 | || $bIsText |
||
4024 | ) { |
||
4025 | $class = str_replace('grid_edit', '', $class); |
||
4026 | } |
||
4027 | |||
4028 | if (! isset($column) || is_null($column)) { |
||
4029 | $cell = $this->_buildNullDisplay($class, $condition_field, $meta); |
||
4030 | return $cell; |
||
4031 | } |
||
4032 | |||
4033 | if ($column == '') { |
||
4034 | $cell = $this->_buildEmptyDisplay($class, $condition_field, $meta); |
||
4035 | return $cell; |
||
4036 | } |
||
4037 | |||
4038 | // Cut all fields to $GLOBALS['cfg']['LimitChars'] |
||
4039 | // (unless it's a link-type transformation or binary) |
||
4040 | if (!(gettype($transformation_plugin) === "object" |
||
4041 | && strpos($transformation_plugin->getName(), 'Link') !== false) |
||
4042 | && !stristr($field_flags, self::BINARY_FIELD) |
||
4043 | ) { |
||
4044 | list( |
||
4045 | $is_field_truncated, |
||
4046 | $column, |
||
4047 | $original_length |
||
4048 | ) = $this->_getPartialText($column); |
||
4049 | } |
||
4050 | |||
4051 | $formatted = false; |
||
4052 | if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) { |
||
4053 | $column = Util::printableBitValue( |
||
4054 | (int) $column, |
||
4055 | (int) $meta->length |
||
4056 | ); |
||
4057 | |||
4058 | // some results of PROCEDURE ANALYSE() are reported as |
||
4059 | // being BINARY but they are quite readable, |
||
4060 | // so don't treat them as BINARY |
||
4061 | } elseif (stristr($field_flags, self::BINARY_FIELD) |
||
4062 | && !(isset($is_analyse) && $is_analyse) |
||
4063 | ) { |
||
4064 | // we show the BINARY or BLOB message and field's size |
||
4065 | // (or maybe use a transformation) |
||
4066 | $binary_or_blob = self::BLOB_FIELD; |
||
4067 | if ($meta->type === self::STRING_FIELD) { |
||
4068 | $binary_or_blob = self::BINARY_FIELD; |
||
4069 | } |
||
4070 | $column = $this->_handleNonPrintableContents( |
||
4071 | $binary_or_blob, |
||
4072 | $column, |
||
4073 | $transformation_plugin, |
||
4074 | $transform_options, |
||
4075 | $default_function, |
||
4076 | $meta, |
||
4077 | $_url_params, |
||
4078 | $is_field_truncated |
||
4079 | ); |
||
4080 | $class = $this->_addClass( |
||
4081 | $class, |
||
4082 | $condition_field, |
||
4083 | $meta, |
||
4084 | '', |
||
4085 | $is_field_truncated, |
||
4086 | $transformation_plugin, |
||
4087 | $default_function |
||
4088 | ); |
||
4089 | $result = strip_tags($column); |
||
4090 | // disable inline grid editing |
||
4091 | // if binary or blob data is not shown |
||
4092 | if (stristr($result, $binary_or_blob)) { |
||
4093 | $class = str_replace('grid_edit', '', $class); |
||
4094 | } |
||
4095 | $formatted = true; |
||
4096 | } |
||
4097 | |||
4098 | if ($formatted) { |
||
4099 | $cell = $this->_buildValueDisplay( |
||
4100 | $class, |
||
4101 | $condition_field, |
||
4102 | $column |
||
4103 | ); |
||
4104 | return $cell; |
||
4105 | } |
||
4106 | |||
4107 | // transform functions may enable no-wrapping: |
||
4108 | $function_nowrap = 'applyTransformationNoWrap'; |
||
4109 | |||
4110 | $bool_nowrap = (($default_function != $transformation_plugin) |
||
4111 | && function_exists((string) $transformation_plugin->$function_nowrap())) |
||
4112 | ? $transformation_plugin->$function_nowrap($transform_options) |
||
4113 | : false; |
||
4114 | |||
4115 | // do not wrap if date field type |
||
4116 | $nowrap = (preg_match('@DATE|TIME@i', $meta->type) |
||
4117 | || $bool_nowrap) ? ' nowrap' : ''; |
||
4118 | |||
4119 | $where_comparison = ' = \'' |
||
4120 | . $GLOBALS['dbi']->escapeString($column) |
||
4121 | . '\''; |
||
4122 | |||
4123 | $cell = $this->_getRowData( |
||
4124 | $class, |
||
4125 | $condition_field, |
||
4126 | $analyzed_sql_results, |
||
4127 | $meta, |
||
4128 | $map, |
||
4129 | $column, |
||
4130 | $transformation_plugin, |
||
4131 | $default_function, |
||
4132 | $nowrap, |
||
4133 | $where_comparison, |
||
4134 | $transform_options, |
||
4135 | $is_field_truncated, |
||
4136 | $original_length |
||
4137 | ); |
||
4138 | |||
4139 | return $cell; |
||
4140 | } // end of the '_getDataCellForNonNumericColumns()' function |
||
4141 | |||
4142 | /** |
||
4143 | * Checks the posted options for viewing query results |
||
4144 | * and sets appropriate values in the session. |
||
4145 | * |
||
4146 | * @todo make maximum remembered queries configurable |
||
4147 | * @todo move/split into SQL class!? |
||
4148 | * @todo currently this is called twice unnecessary |
||
4149 | * @todo ignore LIMIT and ORDER in query!? |
||
4150 | * |
||
4151 | * @return void |
||
4152 | * |
||
4153 | * @access public |
||
4154 | * |
||
4155 | * @see sql.php file |
||
4156 | */ |
||
4157 | public function setConfigParamsForDisplayTable() |
||
4158 | { |
||
4159 | |||
4160 | $sql_md5 = md5($this->__get('sql_query')); |
||
4161 | $query = []; |
||
4162 | if (isset($_SESSION['tmpval']['query'][$sql_md5])) { |
||
4163 | $query = $_SESSION['tmpval']['query'][$sql_md5]; |
||
4164 | } |
||
4165 | |||
4166 | $query['sql'] = $this->__get('sql_query'); |
||
4167 | |||
4168 | if (empty($query['repeat_cells'])) { |
||
4169 | $query['repeat_cells'] = $GLOBALS['cfg']['RepeatCells']; |
||
4170 | } |
||
4171 | |||
4172 | // as this is a form value, the type is always string so we cannot |
||
4173 | // use Core::isValid($_REQUEST['session_max_rows'], 'integer') |
||
4174 | if (Core::isValid($_REQUEST['session_max_rows'], 'numeric')) { |
||
4175 | $query['max_rows'] = (int)$_REQUEST['session_max_rows']; |
||
4176 | unset($_REQUEST['session_max_rows']); |
||
4177 | } elseif ($_REQUEST['session_max_rows'] == self::ALL_ROWS) { |
||
4178 | $query['max_rows'] = self::ALL_ROWS; |
||
4179 | unset($_REQUEST['session_max_rows']); |
||
4180 | } elseif (empty($query['max_rows'])) { |
||
4181 | $query['max_rows'] = intval($GLOBALS['cfg']['MaxRows']); |
||
4182 | } |
||
4183 | |||
4184 | if (Core::isValid($_REQUEST['pos'], 'numeric')) { |
||
4185 | $query['pos'] = $_REQUEST['pos']; |
||
4186 | unset($_REQUEST['pos']); |
||
4187 | } elseif (empty($query['pos'])) { |
||
4188 | $query['pos'] = 0; |
||
4189 | } |
||
4190 | |||
4191 | if (Core::isValid( |
||
4192 | $_REQUEST['pftext'], |
||
4193 | [ |
||
4194 | self::DISPLAY_PARTIAL_TEXT, self::DISPLAY_FULL_TEXT |
||
4195 | ] |
||
4196 | ) |
||
4197 | ) { |
||
4198 | $query['pftext'] = $_REQUEST['pftext']; |
||
4199 | unset($_REQUEST['pftext']); |
||
4200 | } elseif (empty($query['pftext'])) { |
||
4201 | $query['pftext'] = self::DISPLAY_PARTIAL_TEXT; |
||
4202 | } |
||
4203 | |||
4204 | if (Core::isValid( |
||
4205 | $_REQUEST['relational_display'], |
||
4206 | [ |
||
4207 | self::RELATIONAL_KEY, self::RELATIONAL_DISPLAY_COLUMN |
||
4208 | ] |
||
4209 | ) |
||
4210 | ) { |
||
4211 | $query['relational_display'] = $_REQUEST['relational_display']; |
||
4212 | unset($_REQUEST['relational_display']); |
||
4213 | } elseif (empty($query['relational_display'])) { |
||
4214 | // The current session value has priority over a |
||
4215 | // change via Settings; this change will be apparent |
||
4216 | // starting from the next session |
||
4217 | $query['relational_display'] = $GLOBALS['cfg']['RelationalDisplay']; |
||
4218 | } |
||
4219 | |||
4220 | if (Core::isValid( |
||
4221 | $_REQUEST['geoOption'], |
||
4222 | [ |
||
4223 | self::GEOMETRY_DISP_WKT, self::GEOMETRY_DISP_WKB, |
||
4224 | self::GEOMETRY_DISP_GEOM |
||
4225 | ] |
||
4226 | ) |
||
4227 | ) { |
||
4228 | $query['geoOption'] = $_REQUEST['geoOption']; |
||
4229 | unset($_REQUEST['geoOption']); |
||
4230 | } elseif (empty($query['geoOption'])) { |
||
4231 | $query['geoOption'] = self::GEOMETRY_DISP_GEOM; |
||
4232 | } |
||
4233 | |||
4234 | if (isset($_REQUEST['display_binary'])) { |
||
4235 | $query['display_binary'] = true; |
||
4236 | unset($_REQUEST['display_binary']); |
||
4237 | } elseif (isset($_REQUEST['display_options_form'])) { |
||
4238 | // we know that the checkbox was unchecked |
||
4239 | unset($query['display_binary']); |
||
4240 | } elseif (isset($_REQUEST['full_text_button'])) { |
||
4241 | // do nothing to keep the value that is there in the session |
||
4242 | } else { |
||
4243 | // selected by default because some operations like OPTIMIZE TABLE |
||
4244 | // and all queries involving functions return "binary" contents, |
||
4245 | // according to low-level field flags |
||
4246 | $query['display_binary'] = true; |
||
4247 | } |
||
4248 | |||
4249 | if (isset($_REQUEST['display_blob'])) { |
||
4250 | $query['display_blob'] = true; |
||
4251 | unset($_REQUEST['display_blob']); |
||
4252 | } elseif (isset($_REQUEST['display_options_form'])) { |
||
4253 | // we know that the checkbox was unchecked |
||
4254 | unset($query['display_blob']); |
||
4255 | } |
||
4256 | |||
4257 | if (isset($_REQUEST['hide_transformation'])) { |
||
4258 | $query['hide_transformation'] = true; |
||
4259 | unset($_REQUEST['hide_transformation']); |
||
4260 | } elseif (isset($_REQUEST['display_options_form'])) { |
||
4261 | // we know that the checkbox was unchecked |
||
4262 | unset($query['hide_transformation']); |
||
4263 | } |
||
4264 | |||
4265 | // move current query to the last position, to be removed last |
||
4266 | // so only least executed query will be removed if maximum remembered |
||
4267 | // queries limit is reached |
||
4268 | unset($_SESSION['tmpval']['query'][$sql_md5]); |
||
4269 | $_SESSION['tmpval']['query'][$sql_md5] = $query; |
||
4270 | |||
4271 | // do not exceed a maximum number of queries to remember |
||
4272 | if (count($_SESSION['tmpval']['query']) > 10) { |
||
4273 | array_shift($_SESSION['tmpval']['query']); |
||
4274 | //echo 'deleting one element ...'; |
||
4275 | } |
||
4276 | |||
4277 | // populate query configuration |
||
4278 | $_SESSION['tmpval']['pftext'] |
||
4279 | = $query['pftext']; |
||
4280 | $_SESSION['tmpval']['relational_display'] |
||
4281 | = $query['relational_display']; |
||
4282 | $_SESSION['tmpval']['geoOption'] |
||
4283 | = $query['geoOption']; |
||
4284 | $_SESSION['tmpval']['display_binary'] = isset( |
||
4285 | $query['display_binary'] |
||
4286 | ); |
||
4287 | $_SESSION['tmpval']['display_blob'] = isset( |
||
4288 | $query['display_blob'] |
||
4289 | ); |
||
4290 | $_SESSION['tmpval']['hide_transformation'] = isset( |
||
4291 | $query['hide_transformation'] |
||
4292 | ); |
||
4293 | $_SESSION['tmpval']['pos'] |
||
4294 | = $query['pos']; |
||
4295 | $_SESSION['tmpval']['max_rows'] |
||
4296 | = $query['max_rows']; |
||
4297 | $_SESSION['tmpval']['repeat_cells'] |
||
4298 | = $query['repeat_cells']; |
||
4299 | } |
||
4300 | |||
4301 | /** |
||
4302 | * Prepare a table of results returned by a SQL query. |
||
4303 | * |
||
4304 | * @param integer &$dt_result the link id associated to the query |
||
4305 | * which results have to be displayed |
||
4306 | * @param array &$displayParts the parts to display |
||
4307 | * @param array $analyzed_sql_results analyzed sql results |
||
4308 | * @param boolean $is_limited_display With limited operations or not |
||
4309 | * |
||
4310 | * @return string Generated HTML content for resulted table |
||
4311 | * |
||
4312 | * @access public |
||
4313 | * |
||
4314 | * @see sql.php file |
||
4315 | */ |
||
4316 | public function getTable( |
||
4317 | &$dt_result, |
||
4318 | array &$displayParts, |
||
4319 | array $analyzed_sql_results, |
||
4320 | $is_limited_display = false |
||
4321 | ) { |
||
4322 | |||
4323 | /** |
||
4324 | * The statement this table is built for. |
||
4325 | * @var \PhpMyAdmin\SqlParser\Statements\SelectStatement |
||
4326 | */ |
||
4327 | if (isset($analyzed_sql_results['statement'])) { |
||
4328 | $statement = $analyzed_sql_results['statement']; |
||
4329 | } else { |
||
4330 | $statement = null; |
||
4331 | } |
||
4332 | |||
4333 | $table_html = ''; |
||
4334 | // Following variable are needed for use in isset/empty or |
||
4335 | // use with array indexes/safe use in foreach |
||
4336 | $fields_meta = $this->__get('fields_meta'); |
||
4337 | $showtable = $this->__get('showtable'); |
||
4338 | $printview = $this->__get('printview'); |
||
4339 | |||
4340 | /** |
||
4341 | * @todo move this to a central place |
||
4342 | * @todo for other future table types |
||
4343 | */ |
||
4344 | $is_innodb = (isset($showtable['Type']) |
||
4345 | && $showtable['Type'] == self::TABLE_TYPE_INNO_DB); |
||
4346 | |||
4347 | $sql = new Sql(); |
||
4348 | if ($is_innodb && $sql->isJustBrowsing($analyzed_sql_results, true)) { |
||
4349 | // "j u s t b r o w s i n g" |
||
4350 | $pre_count = '~'; |
||
4351 | $after_count = Util::showHint( |
||
4352 | Sanitize::sanitize( |
||
4353 | __('May be approximate. See [doc@faq3-11]FAQ 3.11[/doc].') |
||
4354 | ) |
||
4355 | ); |
||
4356 | } else { |
||
4357 | $pre_count = ''; |
||
4358 | $after_count = ''; |
||
4359 | } |
||
4360 | |||
4361 | // 1. ----- Prepares the work ----- |
||
4362 | |||
4363 | // 1.1 Gets the information about which functionalities should be |
||
4364 | // displayed |
||
4365 | |||
4366 | list( |
||
4367 | $displayParts, |
||
4368 | $total |
||
4369 | ) = $this->_setDisplayPartsAndTotal($displayParts); |
||
4370 | |||
4371 | // 1.2 Defines offsets for the next and previous pages |
||
4372 | if ($displayParts['nav_bar'] == '1') { |
||
4373 | list($pos_next, $pos_prev) = $this->_getOffsets(); |
||
4374 | } // end if |
||
4375 | |||
4376 | // 1.3 Extract sorting expressions. |
||
4377 | // we need $sort_expression and $sort_expression_nodirection |
||
4378 | // even if there are many table references |
||
4379 | $sort_expression = []; |
||
4380 | $sort_expression_nodirection = []; |
||
4381 | $sort_direction = []; |
||
4382 | |||
4383 | if (!is_null($statement) && !empty($statement->order)) { |
||
4384 | foreach ($statement->order as $o) { |
||
4385 | $sort_expression[] = $o->expr->expr . ' ' . $o->type; |
||
4386 | $sort_expression_nodirection[] = $o->expr->expr; |
||
4387 | $sort_direction[] = $o->type; |
||
4388 | } |
||
4389 | } else { |
||
4390 | $sort_expression[] = ''; |
||
4391 | $sort_expression_nodirection[] = ''; |
||
4392 | $sort_direction[] = ''; |
||
4393 | } |
||
4394 | |||
4395 | $number_of_columns = count($sort_expression_nodirection); |
||
4396 | |||
4397 | // 1.4 Prepares display of first and last value of the sorted column |
||
4398 | $sorted_column_message = ''; |
||
4399 | for ($i = 0; $i < $number_of_columns; $i++) { |
||
4400 | $sorted_column_message .= $this->_getSortedColumnMessage( |
||
4401 | $dt_result, |
||
4402 | $sort_expression_nodirection[$i] |
||
4403 | ); |
||
4404 | } |
||
4405 | |||
4406 | // 2. ----- Prepare to display the top of the page ----- |
||
4407 | |||
4408 | // 2.1 Prepares a messages with position information |
||
4409 | if (($displayParts['nav_bar'] == '1') && isset($pos_next)) { |
||
4410 | $message = $this->_setMessageInformation( |
||
4411 | $sorted_column_message, |
||
4412 | $analyzed_sql_results, |
||
4413 | $total, |
||
4414 | $pos_next, |
||
4415 | $pre_count, |
||
4416 | $after_count |
||
4417 | ); |
||
4418 | |||
4419 | $table_html .= Util::getMessage( |
||
4420 | $message, |
||
4421 | $this->__get('sql_query'), |
||
4422 | 'success' |
||
4423 | ); |
||
4424 | } elseif ((!isset($printview) || ($printview != '1')) && !$is_limited_display) { |
||
4425 | $table_html .= Util::getMessage( |
||
4426 | __('Your SQL query has been executed successfully.'), |
||
4427 | $this->__get('sql_query'), |
||
4428 | 'success' |
||
4429 | ); |
||
4430 | } |
||
4431 | |||
4432 | // 2.3 Prepare the navigation bars |
||
4433 | if (strlen($this->__get('table')) === 0) { |
||
4434 | if ($analyzed_sql_results['querytype'] == 'SELECT') { |
||
4435 | // table does not always contain a real table name, |
||
4436 | // for example in MySQL 5.0.x, the query SHOW STATUS |
||
4437 | // returns STATUS as a table name |
||
4438 | $this->__set('table', $fields_meta[0]->table); |
||
4439 | } else { |
||
4440 | $this->__set('table', ''); |
||
4441 | } |
||
4442 | } |
||
4443 | |||
4444 | // can the result be sorted? |
||
4445 | if ($displayParts['sort_lnk'] == '1' && ! is_null($analyzed_sql_results['statement'])) { |
||
4446 | // At this point, $sort_expression is an array |
||
4447 | list($unsorted_sql_query, $sort_by_key_html) |
||
4448 | = $this->_getUnsortedSqlAndSortByKeyDropDown( |
||
4449 | $analyzed_sql_results, |
||
4450 | $sort_expression |
||
4451 | ); |
||
4452 | } else { |
||
4453 | $sort_by_key_html = $unsorted_sql_query = ''; |
||
4454 | } |
||
4455 | |||
4456 | if (($displayParts['nav_bar'] == '1') && !is_null($statement) && (empty($statement->limit))) { |
||
4457 | $table_html .= $this->_getPlacedTableNavigations( |
||
4458 | $pos_next, |
||
4459 | $pos_prev, |
||
4460 | self::PLACE_TOP_DIRECTION_DROPDOWN, |
||
4461 | $is_innodb, |
||
4462 | $sort_by_key_html |
||
4463 | ); |
||
4464 | } |
||
4465 | |||
4466 | // 2b ----- Get field references from Database ----- |
||
4467 | // (see the 'relation' configuration variable) |
||
4468 | |||
4469 | // initialize map |
||
4470 | $map = []; |
||
4471 | |||
4472 | $target = []; |
||
4473 | if (!is_null($statement) && !empty($statement->from)) { |
||
4474 | foreach ($statement->from as $field) { |
||
4475 | if (!empty($field->table)) { |
||
4476 | $target[] = $field->table; |
||
4477 | } |
||
4478 | } |
||
4479 | } |
||
4480 | |||
4481 | if (strlen($this->__get('table')) > 0) { |
||
4482 | // This method set the values for $map array |
||
4483 | $this->_setParamForLinkForeignKeyRelatedTables($map); |
||
4484 | |||
4485 | // Coming from 'Distinct values' action of structure page |
||
4486 | // We manipulate relations mechanism to show a link to related rows. |
||
4487 | if ($this->__get('is_browse_distinct')) { |
||
4488 | $map[$fields_meta[1]->name] = [ |
||
4489 | $this->__get('table'), |
||
4490 | $fields_meta[1]->name, |
||
4491 | '', |
||
4492 | $this->__get('db') |
||
4493 | ]; |
||
4494 | } |
||
4495 | } // end if |
||
4496 | // end 2b |
||
4497 | |||
4498 | // 3. ----- Prepare the results table ----- |
||
4499 | if ($is_limited_display) { |
||
4500 | $table_html .= "<br>"; |
||
4501 | } |
||
4502 | |||
4503 | $table_html .= $this->_getTableHeaders( |
||
4504 | $displayParts, |
||
4505 | $analyzed_sql_results, |
||
4506 | $unsorted_sql_query, |
||
4507 | $sort_expression, |
||
4508 | $sort_expression_nodirection, |
||
4509 | $sort_direction, |
||
4510 | $is_limited_display |
||
4511 | ); |
||
4512 | |||
4513 | $table_html .= '<tbody>' . "\n"; |
||
4514 | |||
4515 | $table_html .= $this->_getTableBody( |
||
4516 | $dt_result, |
||
4517 | $displayParts, |
||
4518 | $map, |
||
4519 | $analyzed_sql_results, |
||
4520 | $is_limited_display |
||
4521 | ); |
||
4522 | |||
4523 | $this->__set('display_params', null); |
||
4524 | |||
4525 | $table_html .= '</tbody>' . "\n" . '</table></div>'; |
||
4526 | |||
4527 | // 4. ----- Prepares the link for multi-fields edit and delete |
||
4528 | |||
4529 | if ($displayParts['del_lnk'] == self::DELETE_ROW |
||
4530 | && $displayParts['del_lnk'] != self::KILL_PROCESS |
||
4531 | ) { |
||
4532 | $table_html .= $this->_getMultiRowOperationLinks( |
||
4533 | $dt_result, |
||
4534 | $analyzed_sql_results, |
||
4535 | $displayParts['del_lnk'] |
||
4536 | ); |
||
4537 | } |
||
4538 | |||
4539 | // 5. ----- Get the navigation bar at the bottom if required ----- |
||
4540 | if (($displayParts['nav_bar'] == '1') && !is_null($statement) && empty($statement->limit)) { |
||
4541 | $table_html .= $this->_getPlacedTableNavigations( |
||
4542 | $pos_next, |
||
4543 | $pos_prev, |
||
4544 | self::PLACE_BOTTOM_DIRECTION_DROPDOWN, |
||
4545 | $is_innodb, |
||
4546 | $sort_by_key_html |
||
4547 | ); |
||
4548 | } elseif (! isset($printview) || ($printview != '1')) { |
||
4549 | $table_html .= "\n" . '<br /><br />' . "\n"; |
||
4550 | } |
||
4551 | |||
4552 | // 6. ----- Prepare "Query results operations" |
||
4553 | if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) { |
||
4554 | $table_html .= $this->_getResultsOperations( |
||
4555 | $displayParts, |
||
4556 | $analyzed_sql_results |
||
4557 | ); |
||
4558 | } |
||
4559 | |||
4560 | return $table_html; |
||
4561 | } // end of the 'getTable()' function |
||
4562 | |||
4563 | |||
4564 | /** |
||
4565 | * Get offsets for next page and previous page |
||
4566 | * |
||
4567 | * @return array array with two elements - $pos_next, $pos_prev |
||
4568 | * |
||
4569 | * @access private |
||
4570 | * |
||
4571 | * @see getTable() |
||
4572 | */ |
||
4573 | private function _getOffsets() |
||
4574 | { |
||
4575 | |||
4576 | if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) { |
||
4577 | $pos_next = 0; |
||
4578 | $pos_prev = 0; |
||
4579 | } else { |
||
4580 | $pos_next = $_SESSION['tmpval']['pos'] |
||
4581 | + $_SESSION['tmpval']['max_rows']; |
||
4582 | |||
4583 | $pos_prev = $_SESSION['tmpval']['pos'] |
||
4584 | - $_SESSION['tmpval']['max_rows']; |
||
4585 | |||
4586 | if ($pos_prev < 0) { |
||
4587 | $pos_prev = 0; |
||
4588 | } |
||
4589 | } |
||
4590 | |||
4591 | return [$pos_next, $pos_prev]; |
||
4592 | } // end of the '_getOffsets()' function |
||
4593 | |||
4594 | |||
4595 | /** |
||
4596 | * Prepare sorted column message |
||
4597 | * |
||
4598 | * @param integer &$dt_result the link id associated to the |
||
4599 | * query which results have to |
||
4600 | * be displayed |
||
4601 | * @param string $sort_expression_nodirection sort expression without direction |
||
4602 | * |
||
4603 | * @return string html content |
||
4604 | * null if not found sorted column |
||
4605 | * |
||
4606 | * @access private |
||
4607 | * |
||
4608 | * @see getTable() |
||
4609 | */ |
||
4610 | private function _getSortedColumnMessage( |
||
4611 | &$dt_result, |
||
4612 | $sort_expression_nodirection |
||
4613 | ) { |
||
4614 | |||
4615 | $fields_meta = $this->__get('fields_meta'); // To use array indexes |
||
4616 | |||
4617 | if (empty($sort_expression_nodirection)) { |
||
4618 | return null; |
||
4619 | } |
||
4620 | |||
4621 | if (mb_strpos($sort_expression_nodirection, '.') === false) { |
||
4622 | $sort_table = $this->__get('table'); |
||
4623 | $sort_column = $sort_expression_nodirection; |
||
4624 | } else { |
||
4625 | list($sort_table, $sort_column) |
||
4626 | = explode('.', $sort_expression_nodirection); |
||
4627 | } |
||
4628 | |||
4629 | $sort_table = Util::unQuote($sort_table); |
||
4630 | $sort_column = Util::unQuote($sort_column); |
||
4631 | |||
4632 | // find the sorted column index in row result |
||
4633 | // (this might be a multi-table query) |
||
4634 | $sorted_column_index = false; |
||
4635 | |||
4636 | foreach ($fields_meta as $key => $meta) { |
||
4637 | if (($meta->table == $sort_table) && ($meta->name == $sort_column)) { |
||
4638 | $sorted_column_index = $key; |
||
4639 | break; |
||
4640 | } |
||
4641 | } |
||
4642 | |||
4643 | if ($sorted_column_index === false) { |
||
4644 | return null; |
||
4645 | } |
||
4646 | |||
4647 | // fetch first row of the result set |
||
4648 | $row = $GLOBALS['dbi']->fetchRow($dt_result); |
||
4649 | |||
4650 | // initializing default arguments |
||
4651 | $default_function = [Core::class, 'mimeDefaultFunction']; |
||
4652 | $transformation_plugin = $default_function; |
||
4653 | $transform_options = []; |
||
4654 | |||
4655 | // check for non printable sorted row data |
||
4656 | $meta = $fields_meta[$sorted_column_index]; |
||
4657 | |||
4658 | if (stristr($meta->type, self::BLOB_FIELD) |
||
4659 | || ($meta->type == self::GEOMETRY_FIELD) |
||
4660 | ) { |
||
4661 | $column_for_first_row = $this->_handleNonPrintableContents( |
||
4662 | $meta->type, |
||
4663 | $row[$sorted_column_index], |
||
4664 | $transformation_plugin, |
||
4665 | $transform_options, |
||
4666 | $default_function, |
||
4667 | $meta |
||
4668 | ); |
||
4669 | } else { |
||
4670 | $column_for_first_row = $row[$sorted_column_index]; |
||
4671 | } |
||
4672 | |||
4673 | $column_for_first_row = mb_strtoupper( |
||
4674 | mb_substr( |
||
4675 | (string) $column_for_first_row, |
||
4676 | 0, |
||
4677 | $GLOBALS['cfg']['LimitChars'] |
||
4678 | ) . '...' |
||
4679 | ); |
||
4680 | |||
4681 | // fetch last row of the result set |
||
4682 | $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1); |
||
4683 | $row = $GLOBALS['dbi']->fetchRow($dt_result); |
||
4684 | |||
4685 | // check for non printable sorted row data |
||
4686 | $meta = $fields_meta[$sorted_column_index]; |
||
4687 | if (stristr($meta->type, self::BLOB_FIELD) |
||
4688 | || ($meta->type == self::GEOMETRY_FIELD) |
||
4689 | ) { |
||
4690 | $column_for_last_row = $this->_handleNonPrintableContents( |
||
4691 | $meta->type, |
||
4692 | $row[$sorted_column_index], |
||
4693 | $transformation_plugin, |
||
4694 | $transform_options, |
||
4695 | $default_function, |
||
4696 | $meta |
||
4697 | ); |
||
4698 | } else { |
||
4699 | $column_for_last_row = $row[$sorted_column_index]; |
||
4700 | } |
||
4701 | |||
4702 | $column_for_last_row = mb_strtoupper( |
||
4703 | mb_substr( |
||
4704 | (string) $column_for_last_row, |
||
4705 | 0, |
||
4706 | $GLOBALS['cfg']['LimitChars'] |
||
4707 | ) . '...' |
||
4708 | ); |
||
4709 | |||
4710 | // reset to first row for the loop in _getTableBody() |
||
4711 | $GLOBALS['dbi']->dataSeek($dt_result, 0); |
||
4712 | |||
4713 | // we could also use here $sort_expression_nodirection |
||
4714 | return ' [' . htmlspecialchars($sort_column) |
||
4715 | . ': <strong>' . htmlspecialchars($column_for_first_row) . ' - ' |
||
4716 | . htmlspecialchars($column_for_last_row) . '</strong>]'; |
||
4717 | } // end of the '_getSortedColumnMessage()' function |
||
4718 | |||
4719 | |||
4720 | /** |
||
4721 | * Set the content that needs to be shown in message |
||
4722 | * |
||
4723 | * @param string $sorted_column_message the message for sorted column |
||
4724 | * @param array $analyzed_sql_results the analyzed query |
||
4725 | * @param integer $total the total number of rows returned by |
||
4726 | * the SQL query without any |
||
4727 | * programmatically appended LIMIT clause |
||
4728 | * @param integer $pos_next the offset for next page |
||
4729 | * @param string $pre_count the string renders before row count |
||
4730 | * @param string $after_count the string renders after row count |
||
4731 | * |
||
4732 | * @return Message an object of Message |
||
4733 | * |
||
4734 | * @access private |
||
4735 | * |
||
4736 | * @see getTable() |
||
4737 | */ |
||
4738 | private function _setMessageInformation( |
||
4739 | $sorted_column_message, |
||
4740 | array $analyzed_sql_results, |
||
4741 | $total, |
||
4742 | $pos_next, |
||
4743 | $pre_count, |
||
4744 | $after_count |
||
4745 | ) { |
||
4746 | |||
4747 | $unlim_num_rows = $this->__get('unlim_num_rows'); // To use in isset() |
||
4748 | |||
4749 | if (!empty($analyzed_sql_results['statement']->limit)) { |
||
4750 | $first_shown_rec = $analyzed_sql_results['statement']->limit->offset; |
||
4751 | $row_count = $analyzed_sql_results['statement']->limit->rowCount; |
||
4752 | |||
4753 | if ($row_count < $total) { |
||
4754 | $last_shown_rec = $first_shown_rec + $row_count - 1; |
||
4755 | } else { |
||
4756 | $last_shown_rec = $first_shown_rec + $total - 1; |
||
4757 | } |
||
4758 | } elseif (($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) |
||
4759 | || ($pos_next > $total) |
||
4760 | ) { |
||
4761 | $first_shown_rec = $_SESSION['tmpval']['pos']; |
||
4762 | $last_shown_rec = $total - 1; |
||
4763 | } else { |
||
4764 | $first_shown_rec = $_SESSION['tmpval']['pos']; |
||
4765 | $last_shown_rec = $pos_next - 1; |
||
4766 | } |
||
4767 | |||
4768 | $table = new Table($this->__get('table'), $this->__get('db')); |
||
4769 | if ($table->isView() |
||
4770 | && ($total == $GLOBALS['cfg']['MaxExactCountViews']) |
||
4771 | ) { |
||
4772 | $message = Message::notice( |
||
4773 | __( |
||
4774 | 'This view has at least this number of rows. ' |
||
4775 | . 'Please refer to %sdocumentation%s.' |
||
4776 | ) |
||
4777 | ); |
||
4778 | |||
4779 | $message->addParam('[doc@cfg_MaxExactCount]'); |
||
4780 | $message->addParam('[/doc]'); |
||
4781 | $message_view_warning = Util::showHint($message); |
||
4782 | } else { |
||
4783 | $message_view_warning = false; |
||
4784 | } |
||
4785 | |||
4786 | $message = Message::success(__('Showing rows %1s - %2s')); |
||
4787 | $message->addParam($first_shown_rec); |
||
4788 | |||
4789 | if ($message_view_warning !== false) { |
||
4790 | $message->addParamHtml('... ' . $message_view_warning); |
||
4791 | } else { |
||
4792 | $message->addParam($last_shown_rec); |
||
4793 | } |
||
4794 | |||
4795 | $message->addText('('); |
||
4796 | |||
4797 | if ($message_view_warning === false) { |
||
4798 | if (isset($unlim_num_rows) && ($unlim_num_rows != $total)) { |
||
4799 | $message_total = Message::notice( |
||
4800 | $pre_count . __('%1$d total, %2$d in query') |
||
4801 | ); |
||
4802 | $message_total->addParam($total); |
||
4803 | $message_total->addParam($unlim_num_rows); |
||
4804 | } else { |
||
4805 | $message_total = Message::notice($pre_count . __('%d total')); |
||
4806 | $message_total->addParam($total); |
||
4807 | } |
||
4808 | |||
4809 | if (!empty($after_count)) { |
||
4810 | $message_total->addHtml($after_count); |
||
4811 | } |
||
4812 | $message->addMessage($message_total, ''); |
||
4813 | |||
4814 | $message->addText(', ', ''); |
||
4815 | } |
||
4816 | |||
4817 | $message_qt = Message::notice(__('Query took %01.4f seconds.') . ')'); |
||
4818 | $message_qt->addParam($this->__get('querytime')); |
||
4819 | |||
4820 | $message->addMessage($message_qt, ''); |
||
4821 | if (! is_null($sorted_column_message)) { |
||
4822 | $message->addHtml($sorted_column_message, ''); |
||
4823 | } |
||
4824 | |||
4825 | return $message; |
||
4826 | } // end of the '_setMessageInformation()' function |
||
4827 | |||
4828 | /** |
||
4829 | * Set the value of $map array for linking foreign key related tables |
||
4830 | * |
||
4831 | * @param array &$map the list of relations |
||
4832 | * |
||
4833 | * @return void |
||
4834 | * |
||
4835 | * @access private |
||
4836 | * |
||
4837 | * @see getTable() |
||
4838 | */ |
||
4839 | private function _setParamForLinkForeignKeyRelatedTables(array &$map) |
||
4840 | { |
||
4841 | // To be able to later display a link to the related table, |
||
4842 | // we verify both types of relations: either those that are |
||
4843 | // native foreign keys or those defined in the phpMyAdmin |
||
4844 | // configuration storage. If no PMA storage, we won't be able |
||
4845 | // to use the "column to display" notion (for example show |
||
4846 | // the name related to a numeric id). |
||
4847 | $exist_rel = $this->relation->getForeigners( |
||
4848 | $this->__get('db'), |
||
4849 | $this->__get('table'), |
||
4850 | '', |
||
4851 | self::POSITION_BOTH |
||
4852 | ); |
||
4853 | |||
4854 | if (! empty($exist_rel)) { |
||
4855 | foreach ($exist_rel as $master_field => $rel) { |
||
4856 | if ($master_field != 'foreign_keys_data') { |
||
4857 | $display_field = $this->relation->getDisplayField( |
||
4858 | $rel['foreign_db'], |
||
4859 | $rel['foreign_table'] |
||
4860 | ); |
||
4861 | $map[$master_field] = [ |
||
4862 | $rel['foreign_table'], |
||
4863 | $rel['foreign_field'], |
||
4864 | $display_field, |
||
4865 | $rel['foreign_db'] |
||
4866 | ]; |
||
4867 | } else { |
||
4868 | foreach ($rel as $key => $one_key) { |
||
4869 | foreach ($one_key['index_list'] as $index => $one_field) { |
||
4870 | $display_field = $this->relation->getDisplayField( |
||
4871 | isset($one_key['ref_db_name']) |
||
4872 | ? $one_key['ref_db_name'] |
||
4873 | : $GLOBALS['db'], |
||
4874 | $one_key['ref_table_name'] |
||
4875 | ); |
||
4876 | |||
4877 | $map[$one_field] = [ |
||
4878 | $one_key['ref_table_name'], |
||
4879 | $one_key['ref_index_list'][$index], |
||
4880 | $display_field, |
||
4881 | isset($one_key['ref_db_name']) |
||
4882 | ? $one_key['ref_db_name'] |
||
4883 | : $GLOBALS['db'] |
||
4884 | ]; |
||
4885 | } |
||
4886 | } |
||
4887 | } |
||
4888 | } // end while |
||
4889 | } // end if |
||
4890 | } // end of the '_setParamForLinkForeignKeyRelatedTables()' function |
||
4891 | |||
4892 | |||
4893 | /** |
||
4894 | * Prepare multi field edit/delete links |
||
4895 | * |
||
4896 | * @param integer &$dt_result the link id associated to the query which |
||
4897 | * results have to be displayed |
||
4898 | * @param array $analyzed_sql_results analyzed sql results |
||
4899 | * @param string $del_link the display element - 'del_link' |
||
4900 | * |
||
4901 | * @return string html content |
||
4902 | * |
||
4903 | * @access private |
||
4904 | * |
||
4905 | * @see getTable() |
||
4906 | */ |
||
4907 | private function _getMultiRowOperationLinks( |
||
4908 | &$dt_result, |
||
4909 | array $analyzed_sql_results, |
||
4910 | $del_link |
||
4911 | ) { |
||
4912 | |||
4913 | $links_html = '<div class="print_ignore" >'; |
||
4914 | $url_query = $this->__get('url_query'); |
||
4915 | $delete_text = ($del_link == self::DELETE_ROW) ? __('Delete') : __('Kill'); |
||
4916 | |||
4917 | $links_html .= $this->template->render('select_all', [ |
||
4918 | 'pma_theme_image' => $this->__get('pma_theme_image'), |
||
4919 | 'text_dir' => $this->__get('text_dir'), |
||
4920 | 'form_name' => 'resultsForm_' . $this->__get('unique_id'), |
||
4921 | ]); |
||
4922 | |||
4923 | $links_html .= Util::getButtonOrImage( |
||
4924 | 'submit_mult', |
||
4925 | 'mult_submit', |
||
4926 | __('Edit'), |
||
4927 | 'b_edit', |
||
4928 | 'edit' |
||
4929 | ); |
||
4930 | |||
4931 | $links_html .= Util::getButtonOrImage( |
||
4932 | 'submit_mult', |
||
4933 | 'mult_submit', |
||
4934 | __('Copy'), |
||
4935 | 'b_insrow', |
||
4936 | 'copy' |
||
4937 | ); |
||
4938 | |||
4939 | $links_html .= Util::getButtonOrImage( |
||
4940 | 'submit_mult', |
||
4941 | 'mult_submit', |
||
4942 | $delete_text, |
||
4943 | 'b_drop', |
||
4944 | 'delete' |
||
4945 | ); |
||
4946 | |||
4947 | if ($analyzed_sql_results['querytype'] == 'SELECT') { |
||
4948 | $links_html .= Util::getButtonOrImage( |
||
4949 | 'submit_mult', |
||
4950 | 'mult_submit', |
||
4951 | __('Export'), |
||
4952 | 'b_tblexport', |
||
4953 | 'export' |
||
4954 | ); |
||
4955 | } |
||
4956 | |||
4957 | $links_html .= "</div>\n"; |
||
4958 | |||
4959 | $links_html .= '<input type="hidden" name="sql_query"' |
||
4960 | . ' value="' . htmlspecialchars($this->__get('sql_query')) . '" />' |
||
4961 | . "\n"; |
||
4962 | |||
4963 | if (! empty($url_query)) { |
||
4964 | $links_html .= '<input type="hidden" name="url_query"' |
||
4965 | . ' value="' . $url_query . '" />' . "\n"; |
||
4966 | } |
||
4967 | |||
4968 | // fetch last row of the result set |
||
4969 | $GLOBALS['dbi']->dataSeek($dt_result, $this->__get('num_rows') - 1); |
||
4970 | $row = $GLOBALS['dbi']->fetchRow($dt_result); |
||
4971 | |||
4972 | // @see DbiMysqi::fetchRow & DatabaseInterface::fetchRow |
||
4973 | if (! is_array($row)) { |
||
4974 | $row = []; |
||
4975 | } |
||
4976 | |||
4977 | // $clause_is_unique is needed by getTable() to generate the proper param |
||
4978 | // in the multi-edit and multi-delete form |
||
4979 | list($where_clause, $clause_is_unique, $condition_array) |
||
4980 | = Util::getUniqueCondition( |
||
4981 | $dt_result, // handle |
||
4982 | $this->__get('fields_cnt'), // fields_cnt |
||
4983 | $this->__get('fields_meta'), // fields_meta |
||
4984 | $row, // row |
||
4985 | false, // force_unique |
||
4986 | false, // restrict_to_table |
||
4987 | $analyzed_sql_results // analyzed_sql_results |
||
4988 | ); |
||
4989 | unset($where_clause, $condition_array); |
||
4990 | |||
4991 | // reset to first row for the loop in _getTableBody() |
||
4992 | $GLOBALS['dbi']->dataSeek($dt_result, 0); |
||
4993 | |||
4994 | $links_html .= '<input type="hidden" name="clause_is_unique"' |
||
4995 | . ' value="' . $clause_is_unique . '" />' . "\n"; |
||
4996 | |||
4997 | $links_html .= '</form>' . "\n"; |
||
4998 | |||
4999 | return $links_html; |
||
5000 | } // end of the '_getMultiRowOperationLinks()' function |
||
5001 | |||
5002 | |||
5003 | /** |
||
5004 | * Prepare table navigation bar at the top or bottom |
||
5005 | * |
||
5006 | * @param integer $pos_next the offset for the "next" page |
||
5007 | * @param integer $pos_prev the offset for the "previous" page |
||
5008 | * @param string $place the place to show navigation |
||
5009 | * @param boolean $is_innodb whether its InnoDB or not |
||
5010 | * @param string $sort_by_key_html the sort by key dialog |
||
5011 | * |
||
5012 | * @return string html content of navigation bar |
||
5013 | * |
||
5014 | * @access private |
||
5015 | * |
||
5016 | * @see _getTable() |
||
5017 | */ |
||
5018 | private function _getPlacedTableNavigations( |
||
5019 | $pos_next, |
||
5020 | $pos_prev, |
||
5021 | $place, |
||
5022 | $is_innodb, |
||
5023 | $sort_by_key_html |
||
5024 | ) { |
||
5025 | |||
5026 | $navigation_html = ''; |
||
5027 | |||
5028 | if ($place == self::PLACE_BOTTOM_DIRECTION_DROPDOWN) { |
||
5029 | $navigation_html .= '<br />' . "\n"; |
||
5030 | } |
||
5031 | |||
5032 | $navigation_html .= $this->_getTableNavigation( |
||
5033 | $pos_next, |
||
5034 | $pos_prev, |
||
5035 | $is_innodb, |
||
5036 | $sort_by_key_html |
||
5037 | ); |
||
5038 | |||
5039 | if ($place == self::PLACE_TOP_DIRECTION_DROPDOWN) { |
||
5040 | $navigation_html .= "\n"; |
||
5041 | } |
||
5042 | |||
5043 | return $navigation_html; |
||
5044 | } // end of the '_getPlacedTableNavigations()' function |
||
5045 | |||
5046 | /** |
||
5047 | * Generates HTML to display the Create view in span tag |
||
5048 | * |
||
5049 | * @param array $analyzed_sql_results analyzed sql results |
||
5050 | * @param string $url_query String with URL Parameters |
||
5051 | * |
||
5052 | * @return string |
||
5053 | * |
||
5054 | * @access private |
||
5055 | * |
||
5056 | * @see _getResultsOperations() |
||
5057 | */ |
||
5058 | private function _getLinkForCreateView(array $analyzed_sql_results, $url_query) |
||
5059 | { |
||
5060 | $results_operations_html = ''; |
||
5061 | if (empty($analyzed_sql_results['procedure'])) { |
||
5062 | $results_operations_html .= '<span>' |
||
5063 | . Util::linkOrButton( |
||
5064 | 'view_create.php' . $url_query, |
||
5065 | Util::getIcon( |
||
5066 | 'b_view_add', |
||
5067 | __('Create view'), |
||
5068 | true |
||
5069 | ), |
||
5070 | ['class' => 'create_view ajax'] |
||
5071 | ) |
||
5072 | . '</span>' . "\n"; |
||
5073 | } |
||
5074 | return $results_operations_html; |
||
5075 | } |
||
5076 | |||
5077 | /** |
||
5078 | * Calls the _getResultsOperations with $only_view as true |
||
5079 | * |
||
5080 | * @param array $analyzed_sql_results analyzed sql results |
||
5081 | * |
||
5082 | * @return string |
||
5083 | * |
||
5084 | * @access public |
||
5085 | * |
||
5086 | */ |
||
5087 | public function getCreateViewQueryResultOp(array $analyzed_sql_results) |
||
5088 | { |
||
5089 | |||
5090 | $results_operations_html = ''; |
||
5091 | //calling to _getResultOperations with a fake $displayParts |
||
5092 | //and setting only_view parameter to be true to generate just view |
||
5093 | $results_operations_html .= $this->_getResultsOperations( |
||
5094 | [], |
||
5095 | $analyzed_sql_results, |
||
5096 | true |
||
5097 | ); |
||
5098 | return $results_operations_html; |
||
5099 | } |
||
5100 | |||
5101 | /** |
||
5102 | * Get copy to clipboard links for results operations |
||
5103 | * |
||
5104 | * @return string |
||
5105 | * |
||
5106 | * @access private |
||
5107 | */ |
||
5108 | private function _getCopytoclipboardLinks() |
||
5109 | { |
||
5110 | $html = Util::linkOrButton( |
||
5111 | '#', |
||
5112 | Util::getIcon( |
||
5113 | 'b_insrow', |
||
5114 | __('Copy to clipboard'), |
||
5115 | true |
||
5116 | ), |
||
5117 | ['id' => 'copyToClipBoard'] |
||
5118 | ); |
||
5119 | |||
5120 | return $html; |
||
5121 | } |
||
5122 | |||
5123 | /** |
||
5124 | * Get printview links for results operations |
||
5125 | * |
||
5126 | * @return string |
||
5127 | * |
||
5128 | * @access private |
||
5129 | */ |
||
5130 | private function _getPrintviewLinks() |
||
5131 | { |
||
5132 | $html = Util::linkOrButton( |
||
5133 | '#', |
||
5134 | Util::getIcon( |
||
5135 | 'b_print', |
||
5136 | __('Print'), |
||
5137 | true |
||
5138 | ), |
||
5139 | ['id' => 'printView'], |
||
5140 | 'print_view' |
||
5141 | ); |
||
5142 | |||
5143 | return $html; |
||
5144 | } |
||
5145 | |||
5146 | /** |
||
5147 | * Get operations that are available on results. |
||
5148 | * |
||
5149 | * @param array $displayParts the parts to display |
||
5150 | * @param array $analyzed_sql_results analyzed sql results |
||
5151 | * @param boolean $only_view Whether to show only view |
||
5152 | * |
||
5153 | * @return string html content |
||
5154 | * |
||
5155 | * @access private |
||
5156 | * |
||
5157 | * @see getTable() |
||
5158 | */ |
||
5159 | private function _getResultsOperations( |
||
5160 | array $displayParts, |
||
5161 | array $analyzed_sql_results, |
||
5162 | $only_view = false |
||
5163 | ) { |
||
5164 | global $printview; |
||
5165 | |||
5166 | $results_operations_html = ''; |
||
5167 | $fields_meta = $this->__get('fields_meta'); // To safe use in foreach |
||
5168 | $header_shown = false; |
||
5169 | $header = '<fieldset class="print_ignore" ><legend>' |
||
5170 | . __('Query results operations') . '</legend>'; |
||
5171 | |||
5172 | $_url_params = [ |
||
5173 | 'db' => $this->__get('db'), |
||
5174 | 'table' => $this->__get('table'), |
||
5175 | 'printview' => '1', |
||
5176 | 'sql_query' => $this->__get('sql_query'), |
||
5177 | ]; |
||
5178 | $url_query = Url::getCommon($_url_params); |
||
5179 | |||
5180 | if (!$header_shown) { |
||
5181 | $results_operations_html .= $header; |
||
5182 | $header_shown = true; |
||
5183 | } |
||
5184 | // if empty result set was produced we need to |
||
5185 | // show only view and not other options |
||
5186 | if ($only_view) { |
||
5187 | $results_operations_html .= $this->_getLinkForCreateView( |
||
5188 | $analyzed_sql_results, |
||
5189 | $url_query |
||
5190 | ); |
||
5191 | |||
5192 | if ($header_shown) { |
||
5193 | $results_operations_html .= '</fieldset><br />'; |
||
5194 | } |
||
5195 | return $results_operations_html; |
||
5196 | } |
||
5197 | |||
5198 | // Displays "printable view" link if required |
||
5199 | if ($displayParts['pview_lnk'] == '1') { |
||
5200 | $results_operations_html .= $this->_getPrintviewLinks(); |
||
5201 | $results_operations_html .= $this->_getCopytoclipboardLinks(); |
||
5202 | } // end displays "printable view" |
||
5203 | |||
5204 | // Export link |
||
5205 | // (the url_query has extra parameters that won't be used to export) |
||
5206 | // (the single_table parameter is used in \PhpMyAdmin\Export->getDisplay() |
||
5207 | // to hide the SQL and the structure export dialogs) |
||
5208 | // If the parser found a PROCEDURE clause |
||
5209 | // (most probably PROCEDURE ANALYSE()) it makes no sense to |
||
5210 | // display the Export link). |
||
5211 | if (($analyzed_sql_results['querytype'] == self::QUERY_TYPE_SELECT) |
||
5212 | && ! isset($printview) |
||
5213 | && empty($analyzed_sql_results['procedure']) |
||
5214 | ) { |
||
5215 | if (count($analyzed_sql_results['select_tables']) == 1) { |
||
5216 | $_url_params['single_table'] = 'true'; |
||
5217 | } |
||
5218 | |||
5219 | if (! $header_shown) { |
||
5220 | $results_operations_html .= $header; |
||
5221 | $header_shown = true; |
||
5222 | } |
||
5223 | |||
5224 | $_url_params['unlim_num_rows'] = $this->__get('unlim_num_rows'); |
||
5225 | |||
5226 | /** |
||
5227 | * At this point we don't know the table name; this can happen |
||
5228 | * for example with a query like |
||
5229 | * SELECT bike_code FROM (SELECT bike_code FROM bikes) tmp |
||
5230 | * As a workaround we set in the table parameter the name of the |
||
5231 | * first table of this database, so that tbl_export.php and |
||
5232 | * the script it calls do not fail |
||
5233 | */ |
||
5234 | if (empty($_url_params['table']) && ! empty($_url_params['db'])) { |
||
5235 | $_url_params['table'] = $GLOBALS['dbi']->fetchValue("SHOW TABLES"); |
||
5236 | /* No result (probably no database selected) */ |
||
5237 | if ($_url_params['table'] === false) { |
||
5238 | unset($_url_params['table']); |
||
5239 | } |
||
5240 | } |
||
5241 | |||
5242 | $results_operations_html .= Util::linkOrButton( |
||
5243 | 'tbl_export.php' . Url::getCommon($_url_params), |
||
5244 | Util::getIcon( |
||
5245 | 'b_tblexport', |
||
5246 | __('Export'), |
||
5247 | true |
||
5248 | ) |
||
5249 | ) |
||
5250 | . "\n"; |
||
5251 | |||
5252 | // prepare chart |
||
5253 | $results_operations_html .= Util::linkOrButton( |
||
5254 | 'tbl_chart.php' . Url::getCommon($_url_params), |
||
5255 | Util::getIcon( |
||
5256 | 'b_chart', |
||
5257 | __('Display chart'), |
||
5258 | true |
||
5259 | ) |
||
5260 | ) |
||
5261 | . "\n"; |
||
5262 | |||
5263 | // prepare GIS chart |
||
5264 | $geometry_found = false; |
||
5265 | // If at least one geometry field is found |
||
5266 | foreach ($fields_meta as $meta) { |
||
5267 | if ($meta->type == self::GEOMETRY_FIELD) { |
||
5268 | $geometry_found = true; |
||
5269 | break; |
||
5270 | } |
||
5271 | } |
||
5272 | |||
5273 | if ($geometry_found) { |
||
5274 | $results_operations_html |
||
5275 | .= Util::linkOrButton( |
||
5276 | 'tbl_gis_visualization.php' |
||
5277 | . Url::getCommon($_url_params), |
||
5278 | Util::getIcon( |
||
5279 | 'b_globe', |
||
5280 | __('Visualize GIS data'), |
||
5281 | true |
||
5282 | ) |
||
5283 | ) |
||
5284 | . "\n"; |
||
5285 | } |
||
5286 | } |
||
5287 | |||
5288 | // CREATE VIEW |
||
5289 | /** |
||
5290 | * |
||
5291 | * @todo detect privileges to create a view |
||
5292 | * (but see 2006-01-19 note in PhpMyAdmin\Display\CreateTable, |
||
5293 | * I think we cannot detect db-specific privileges reliably) |
||
5294 | * Note: we don't display a Create view link if we found a PROCEDURE clause |
||
5295 | */ |
||
5296 | if (!$header_shown) { |
||
5297 | $results_operations_html .= $header; |
||
5298 | $header_shown = true; |
||
5299 | } |
||
5300 | |||
5301 | $results_operations_html .= $this->_getLinkForCreateView( |
||
5302 | $analyzed_sql_results, |
||
5303 | $url_query |
||
5304 | ); |
||
5305 | |||
5306 | if ($header_shown) { |
||
5307 | $results_operations_html .= '</fieldset><br />'; |
||
5308 | } |
||
5309 | |||
5310 | return $results_operations_html; |
||
5311 | } // end of the '_getResultsOperations()' function |
||
5312 | |||
5313 | |||
5314 | /** |
||
5315 | * Verifies what to do with non-printable contents (binary or BLOB) |
||
5316 | * in Browse mode. |
||
5317 | * |
||
5318 | * @param string $category BLOB|BINARY|GEOMETRY |
||
5319 | * @param string|null $content the binary content |
||
5320 | * @param mixed $transformation_plugin transformation plugin. |
||
5321 | * Can also be the |
||
5322 | * default function: |
||
5323 | * Core::mimeDefaultFunction |
||
5324 | * @param string $transform_options transformation parameters |
||
5325 | * @param string $default_function default transformation function |
||
5326 | * @param stdClass $meta the meta-information about the field |
||
5327 | * @param array $url_params parameters that should go to the |
||
5328 | * download link |
||
5329 | * @param boolean &$is_truncated the result is truncated or not |
||
5330 | * |
||
5331 | * @return mixed string or float |
||
5332 | * |
||
5333 | * @access private |
||
5334 | * |
||
5335 | * @see _getDataCellForGeometryColumns(), |
||
5336 | * _getDataCellForNonNumericColumns(), |
||
5337 | * _getSortedColumnMessage() |
||
5338 | */ |
||
5339 | private function _handleNonPrintableContents( |
||
5340 | $category, |
||
5341 | ?string $content, |
||
5342 | $transformation_plugin, |
||
5343 | $transform_options, |
||
5344 | $default_function, |
||
5345 | $meta, |
||
5346 | array $url_params = [], |
||
5347 | &$is_truncated = null |
||
5348 | ) { |
||
5349 | |||
5350 | $is_truncated = false; |
||
5351 | $result = '[' . $category; |
||
5352 | |||
5353 | if (isset($content)) { |
||
5354 | $size = strlen($content); |
||
5355 | $display_size = Util::formatByteDown($size, 3, 1); |
||
5356 | $result .= ' - ' . $display_size[0] . ' ' . $display_size[1]; |
||
5357 | } else { |
||
5358 | $result .= ' - NULL'; |
||
5359 | $size = 0; |
||
5360 | } |
||
5361 | |||
5362 | $result .= ']'; |
||
5363 | |||
5364 | // if we want to use a text transformation on a BLOB column |
||
5365 | if (gettype($transformation_plugin) === "object") { |
||
5366 | $posMimeOctetstream = strpos( |
||
5367 | $transformation_plugin->getMIMESubtype(), |
||
5368 | 'Octetstream' |
||
5369 | ); |
||
5370 | $posMimeText = strpos($transformation_plugin->getMIMEtype(), 'Text'); |
||
5371 | if ($posMimeOctetstream |
||
5372 | || $posMimeText !== false |
||
5373 | ) { |
||
5374 | // Applying Transformations on hex string of binary data |
||
5375 | // seems more appropriate |
||
5376 | $result = pack("H*", bin2hex($content)); |
||
5377 | } |
||
5378 | } |
||
5379 | |||
5380 | if ($size <= 0) { |
||
5381 | return($result); |
||
5382 | } |
||
5383 | |||
5384 | if ($default_function != $transformation_plugin) { |
||
5385 | $result = $transformation_plugin->applyTransformation( |
||
5386 | $result, |
||
5387 | $transform_options, |
||
5388 | $meta |
||
5389 | ); |
||
5390 | return($result); |
||
5391 | } |
||
5392 | |||
5393 | $result = $default_function($result, [], $meta); |
||
5394 | if (($_SESSION['tmpval']['display_binary'] |
||
5395 | && $meta->type === self::STRING_FIELD) |
||
5396 | || ($_SESSION['tmpval']['display_blob'] |
||
5397 | && stristr($meta->type, self::BLOB_FIELD)) |
||
5398 | ) { |
||
5399 | // in this case, restart from the original $content |
||
5400 | if (mb_check_encoding($content, 'utf-8') |
||
5401 | && !preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', $content) |
||
5402 | ) { |
||
5403 | // show as text if it's valid utf-8 |
||
5404 | $result = htmlspecialchars($content); |
||
5405 | } else { |
||
5406 | $result = '0x' . bin2hex($content); |
||
5407 | } |
||
5408 | list( |
||
5409 | $is_truncated, |
||
5410 | $result, |
||
5411 | // skip 3rd param |
||
5412 | ) = $this->_getPartialText($result); |
||
5413 | } |
||
5414 | |||
5415 | /* Create link to download */ |
||
5416 | |||
5417 | // in PHP < 5.5, empty() only checks variables |
||
5418 | $tmpdb = $this->__get('db'); |
||
5419 | if (count($url_params) > 0 |
||
5420 | && (!empty($tmpdb) && !empty($meta->orgtable)) |
||
5421 | ) { |
||
5422 | $result = '<a href="tbl_get_field.php' |
||
5423 | . Url::getCommon($url_params) |
||
5424 | . '" class="disableAjax">' |
||
5425 | . $result . '</a>'; |
||
5426 | } |
||
5427 | |||
5428 | return($result); |
||
5429 | } // end of the '_handleNonPrintableContents()' function |
||
5430 | |||
5431 | |||
5432 | /** |
||
5433 | * Retrieves the associated foreign key info for a data cell |
||
5434 | * |
||
5435 | * @param array $map the list of relations |
||
5436 | * @param stdClass $meta the meta-information about the field |
||
5437 | * @param string $where_comparison data for the where clause |
||
5438 | * |
||
5439 | * @return string formatted data |
||
5440 | * |
||
5441 | * @access private |
||
5442 | * |
||
5443 | */ |
||
5444 | private function _getFromForeign(array $map, $meta, $where_comparison) |
||
5445 | { |
||
5446 | $dispsql = 'SELECT ' |
||
5447 | . Util::backquote($map[$meta->name][2]) |
||
5448 | . ' FROM ' |
||
5449 | . Util::backquote($map[$meta->name][3]) |
||
5450 | . '.' |
||
5451 | . Util::backquote($map[$meta->name][0]) |
||
5452 | . ' WHERE ' |
||
5453 | . Util::backquote($map[$meta->name][1]) |
||
5454 | . $where_comparison; |
||
5455 | |||
5456 | $dispresult = $GLOBALS['dbi']->tryQuery( |
||
5457 | $dispsql, |
||
5458 | DatabaseInterface::CONNECT_USER, |
||
5459 | DatabaseInterface::QUERY_STORE |
||
5460 | ); |
||
5461 | |||
5462 | if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) { |
||
5463 | list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0); |
||
5464 | } else { |
||
5465 | $dispval = __('Link not found!'); |
||
5466 | } |
||
5467 | |||
5468 | $GLOBALS['dbi']->freeResult($dispresult); |
||
5469 | |||
5470 | return $dispval; |
||
5471 | } |
||
5472 | |||
5473 | /** |
||
5474 | * Prepares the displayable content of a data cell in Browse mode, |
||
5475 | * taking into account foreign key description field and transformations |
||
5476 | * |
||
5477 | * @param string $class css classes for the td element |
||
5478 | * @param bool $condition_field whether the column is a part of |
||
5479 | * the where clause |
||
5480 | * @param array $analyzed_sql_results the analyzed query |
||
5481 | * @param stdClass $meta the meta-information about the |
||
5482 | * field |
||
5483 | * @param array $map the list of relations |
||
5484 | * @param string $data data |
||
5485 | * @param TransformationsPlugin $transformation_plugin transformation plugin. |
||
5486 | * Can also be the default function: |
||
5487 | * Core::mimeDefaultFunction |
||
5488 | * @param string $default_function default function |
||
5489 | * @param string $nowrap 'nowrap' if the content should |
||
5490 | * not be wrapped |
||
5491 | * @param string $where_comparison data for the where clause |
||
5492 | * @param array $transform_options options for transformation |
||
5493 | * @param bool $is_field_truncated whether the field is truncated |
||
5494 | * @param string $original_length of a truncated column, or '' |
||
5495 | * |
||
5496 | * @return string formatted data |
||
5497 | * |
||
5498 | * @access private |
||
5499 | * |
||
5500 | * @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(), |
||
5501 | * _getDataCellForNonNumericColumns(), |
||
5502 | * |
||
5503 | */ |
||
5504 | private function _getRowData( |
||
5505 | $class, |
||
5506 | $condition_field, |
||
5507 | array $analyzed_sql_results, |
||
5508 | $meta, |
||
5509 | array $map, |
||
5510 | $data, |
||
5511 | $transformation_plugin, |
||
5512 | $default_function, |
||
5513 | $nowrap, |
||
5514 | $where_comparison, |
||
5515 | array $transform_options, |
||
5516 | $is_field_truncated, |
||
5517 | $original_length = '' |
||
5518 | ) { |
||
5519 | $relational_display = $_SESSION['tmpval']['relational_display']; |
||
5520 | $printview = $this->__get('printview'); |
||
5521 | $decimals = isset($meta->decimals) ? $meta->decimals : '-1'; |
||
5522 | $result = '<td data-decimals="' . $decimals . '"' |
||
5523 | . ' data-type="' . $meta->type . '"'; |
||
5524 | |||
5525 | if (! empty($original_length)) { |
||
5526 | // cannot use data-original-length |
||
5527 | $result .= ' data-originallength="' . $original_length . '"'; |
||
5528 | } |
||
5529 | |||
5530 | $result .= ' class="' |
||
5531 | . $this->_addClass( |
||
5532 | $class, |
||
5533 | $condition_field, |
||
5534 | $meta, |
||
5535 | $nowrap, |
||
5536 | $is_field_truncated, |
||
5537 | $transformation_plugin, |
||
5538 | $default_function |
||
5539 | ) |
||
5540 | . '">'; |
||
5541 | |||
5542 | if (!empty($analyzed_sql_results['statement']->expr)) { |
||
5543 | foreach ($analyzed_sql_results['statement']->expr as $expr) { |
||
5544 | if ((empty($expr->alias)) || (empty($expr->column))) { |
||
5545 | continue; |
||
5546 | } |
||
5547 | if (strcasecmp($meta->name, $expr->alias) == 0) { |
||
5548 | $meta->name = $expr->column; |
||
5549 | } |
||
5550 | } |
||
5551 | } |
||
5552 | |||
5553 | if (isset($map[$meta->name])) { |
||
5554 | // Field to display from the foreign table? |
||
5555 | if (isset($map[$meta->name][2]) |
||
5556 | && strlen((string) $map[$meta->name][2]) > 0 |
||
5557 | ) { |
||
5558 | $dispval = $this->_getFromForeign( |
||
5559 | $map, |
||
5560 | $meta, |
||
5561 | $where_comparison |
||
5562 | ); |
||
5563 | } else { |
||
5564 | $dispval = ''; |
||
5565 | } // end if... else... |
||
5566 | |||
5567 | if (isset($printview) && ($printview == '1')) { |
||
5568 | $result .= ($transformation_plugin != $default_function |
||
5569 | ? $transformation_plugin->applyTransformation( |
||
5570 | $data, |
||
5571 | $transform_options, |
||
5572 | $meta |
||
5573 | ) |
||
5574 | : $default_function($data) |
||
5575 | ) |
||
5576 | . ' <code>[->' . $dispval . ']</code>'; |
||
5577 | } else { |
||
5578 | if ($relational_display == self::RELATIONAL_KEY) { |
||
5579 | // user chose "relational key" in the display options, so |
||
5580 | // the title contains the display field |
||
5581 | $title = (! empty($dispval)) |
||
5582 | ? htmlspecialchars($dispval) |
||
5583 | : ''; |
||
5584 | } else { |
||
5585 | $title = htmlspecialchars($data); |
||
5586 | } |
||
5587 | |||
5588 | $_url_params = [ |
||
5589 | 'db' => $map[$meta->name][3], |
||
5590 | 'table' => $map[$meta->name][0], |
||
5591 | 'pos' => '0', |
||
5592 | 'sql_query' => 'SELECT * FROM ' |
||
5593 | . Util::backquote($map[$meta->name][3]) . '.' |
||
5594 | . Util::backquote($map[$meta->name][0]) |
||
5595 | . ' WHERE ' |
||
5596 | . Util::backquote($map[$meta->name][1]) |
||
5597 | . $where_comparison, |
||
5598 | ]; |
||
5599 | |||
5600 | if ($transformation_plugin != $default_function) { |
||
5601 | // always apply a transformation on the real data, |
||
5602 | // not on the display field |
||
5603 | $message = $transformation_plugin->applyTransformation( |
||
5604 | $data, |
||
5605 | $transform_options, |
||
5606 | $meta |
||
5607 | ); |
||
5608 | } else { |
||
5609 | if ($relational_display == self::RELATIONAL_DISPLAY_COLUMN |
||
5610 | && ! empty($map[$meta->name][2]) |
||
5611 | ) { |
||
5612 | // user chose "relational display field" in the |
||
5613 | // display options, so show display field in the cell |
||
5614 | $message = $default_function($dispval); |
||
5615 | } else { |
||
5616 | // otherwise display data in the cell |
||
5617 | $message = $default_function($data); |
||
5618 | } |
||
5619 | } |
||
5620 | |||
5621 | $tag_params = ['title' => $title]; |
||
5622 | if (strpos($class, 'grid_edit') !== false) { |
||
5623 | $tag_params['class'] = 'ajax'; |
||
5624 | } |
||
5625 | $result .= Util::linkOrButton( |
||
5626 | 'sql.php' . Url::getCommon($_url_params), |
||
5627 | $message, |
||
5628 | $tag_params |
||
5629 | ); |
||
5630 | } |
||
5631 | } else { |
||
5632 | $result .= ($transformation_plugin != $default_function |
||
5633 | ? $transformation_plugin->applyTransformation( |
||
5634 | $data, |
||
5635 | $transform_options, |
||
5636 | $meta |
||
5637 | ) |
||
5638 | : $default_function($data) |
||
5639 | ); |
||
5640 | } |
||
5641 | |||
5642 | $result .= '</td>' . "\n"; |
||
5643 | |||
5644 | return $result; |
||
5645 | } // end of the '_getRowData()' function |
||
5646 | |||
5647 | |||
5648 | /** |
||
5649 | * Prepares a checkbox for multi-row submits |
||
5650 | * |
||
5651 | * @param string $del_url delete url |
||
5652 | * @param array $displayParts array with explicit indexes for all |
||
5653 | * the display elements |
||
5654 | * @param string $row_no the row number |
||
5655 | * @param string $where_clause_html url encoded where clause |
||
5656 | * @param array $condition_array array of conditions in the where clause |
||
5657 | * @param string $id_suffix suffix for the id |
||
5658 | * @param string $class css classes for the td element |
||
5659 | * |
||
5660 | * @return string the generated HTML |
||
5661 | * |
||
5662 | * @access private |
||
5663 | * |
||
5664 | * @see _getTableBody(), _getCheckboxAndLinks() |
||
5665 | */ |
||
5666 | private function _getCheckboxForMultiRowSubmissions( |
||
5667 | $del_url, |
||
5668 | array $displayParts, |
||
5669 | $row_no, |
||
5670 | $where_clause_html, |
||
5671 | array $condition_array, |
||
5672 | $id_suffix, |
||
5673 | $class |
||
5674 | ) { |
||
5675 | |||
5676 | $ret = ''; |
||
5677 | |||
5678 | if (! empty($del_url) && $displayParts['del_lnk'] != self::KILL_PROCESS) { |
||
5679 | $ret .= '<td '; |
||
5680 | if (! empty($class)) { |
||
5681 | $ret .= 'class="' . $class . '"'; |
||
5682 | } |
||
5683 | |||
5684 | $ret .= ' class="center print_ignore">' |
||
5685 | . '<input type="checkbox" id="id_rows_to_delete' |
||
5686 | . $row_no . $id_suffix |
||
5687 | . '" name="rows_to_delete[' . $row_no . ']"' |
||
5688 | . ' class="multi_checkbox checkall"' |
||
5689 | . ' value="' . $where_clause_html . '" ' |
||
5690 | . ' />' |
||
5691 | . '<input type="hidden" class="condition_array" value="' |
||
5692 | . htmlspecialchars(json_encode($condition_array)) . '" />' |
||
5693 | . ' </td>'; |
||
5694 | } |
||
5695 | |||
5696 | return $ret; |
||
5697 | } // end of the '_getCheckboxForMultiRowSubmissions()' function |
||
5698 | |||
5699 | |||
5700 | /** |
||
5701 | * Prepares an Edit link |
||
5702 | * |
||
5703 | * @param string $edit_url edit url |
||
5704 | * @param string $class css classes for td element |
||
5705 | * @param string $edit_str text for the edit link |
||
5706 | * @param string $where_clause where clause |
||
5707 | * @param string $where_clause_html url encoded where clause |
||
5708 | * |
||
5709 | * @return string the generated HTML |
||
5710 | * |
||
5711 | * @access private |
||
5712 | * |
||
5713 | * @see _getTableBody(), _getCheckboxAndLinks() |
||
5714 | */ |
||
5715 | private function _getEditLink( |
||
5716 | $edit_url, |
||
5717 | $class, |
||
5718 | $edit_str, |
||
5719 | $where_clause, |
||
5720 | $where_clause_html |
||
5721 | ) { |
||
5722 | |||
5723 | $ret = ''; |
||
5724 | if (! empty($edit_url)) { |
||
5725 | $ret .= '<td class="' . $class . ' center print_ignore" ' |
||
5726 | . ' ><span class="nowrap">' |
||
5727 | . Util::linkOrButton($edit_url, $edit_str); |
||
5728 | /* |
||
5729 | * Where clause for selecting this row uniquely is provided as |
||
5730 | * a hidden input. Used by jQuery scripts for handling grid editing |
||
5731 | */ |
||
5732 | if (! empty($where_clause)) { |
||
5733 | $ret .= '<input type="hidden" class="where_clause" value ="' |
||
5734 | . $where_clause_html . '" />'; |
||
5735 | } |
||
5736 | $ret .= '</span></td>'; |
||
5737 | } |
||
5738 | |||
5739 | return $ret; |
||
5740 | } // end of the '_getEditLink()' function |
||
5741 | |||
5742 | |||
5743 | /** |
||
5744 | * Prepares an Copy link |
||
5745 | * |
||
5746 | * @param string $copy_url copy url |
||
5747 | * @param string $copy_str text for the copy link |
||
5748 | * @param string $where_clause where clause |
||
5749 | * @param string $where_clause_html url encoded where clause |
||
5750 | * @param string $class css classes for the td element |
||
5751 | * |
||
5752 | * @return string the generated HTML |
||
5753 | * |
||
5754 | * @access private |
||
5755 | * |
||
5756 | * @see _getTableBody(), _getCheckboxAndLinks() |
||
5757 | */ |
||
5758 | private function _getCopyLink( |
||
5759 | $copy_url, |
||
5760 | $copy_str, |
||
5761 | $where_clause, |
||
5762 | $where_clause_html, |
||
5763 | $class |
||
5764 | ) { |
||
5765 | |||
5766 | $ret = ''; |
||
5767 | if (! empty($copy_url)) { |
||
5768 | $ret .= '<td class="'; |
||
5769 | if (! empty($class)) { |
||
5770 | $ret .= $class . ' '; |
||
5771 | } |
||
5772 | |||
5773 | $ret .= 'center print_ignore" ' . ' ><span class="nowrap">' |
||
5774 | . Util::linkOrButton($copy_url, $copy_str); |
||
5775 | |||
5776 | /* |
||
5777 | * Where clause for selecting this row uniquely is provided as |
||
5778 | * a hidden input. Used by jQuery scripts for handling grid editing |
||
5779 | */ |
||
5780 | if (! empty($where_clause)) { |
||
5781 | $ret .= '<input type="hidden" class="where_clause" value="' |
||
5782 | . $where_clause_html . '" />'; |
||
5783 | } |
||
5784 | $ret .= '</span></td>'; |
||
5785 | } |
||
5786 | |||
5787 | return $ret; |
||
5788 | } // end of the '_getCopyLink()' function |
||
5789 | |||
5790 | |||
5791 | /** |
||
5792 | * Prepares a Delete link |
||
5793 | * |
||
5794 | * @param string $del_url delete url |
||
5795 | * @param string $del_str text for the delete link |
||
5796 | * @param string $js_conf text for the JS confirmation |
||
5797 | * @param string $class css classes for the td element |
||
5798 | * |
||
5799 | * @return string the generated HTML |
||
5800 | * |
||
5801 | * @access private |
||
5802 | * |
||
5803 | * @see _getTableBody(), _getCheckboxAndLinks() |
||
5804 | */ |
||
5805 | private function _getDeleteLink($del_url, $del_str, $js_conf, $class) |
||
5806 | { |
||
5807 | |||
5808 | $ret = ''; |
||
5809 | if (empty($del_url)) { |
||
5810 | return $ret; |
||
5811 | } |
||
5812 | |||
5813 | $ret .= '<td class="'; |
||
5814 | if (! empty($class)) { |
||
5815 | $ret .= $class . ' '; |
||
5816 | } |
||
5817 | $ajax = Response::getInstance()->isAjax() ? ' ajax' : ''; |
||
5818 | $ret .= 'center print_ignore" ' . ' >' |
||
5819 | . Util::linkOrButton( |
||
5820 | $del_url, |
||
5821 | $del_str, |
||
5822 | ['class' => 'delete_row requireConfirm' . $ajax] |
||
5823 | ) |
||
5824 | . '<div class="hide">' . $js_conf . '</div>' |
||
5825 | . '</td>'; |
||
5826 | |||
5827 | return $ret; |
||
5828 | } // end of the '_getDeleteLink()' function |
||
5829 | |||
5830 | |||
5831 | /** |
||
5832 | * Prepare checkbox and links at some position (left or right) |
||
5833 | * (only called for horizontal mode) |
||
5834 | * |
||
5835 | * @param string $position the position of the checkbox and links |
||
5836 | * @param string $del_url delete url |
||
5837 | * @param array $displayParts array with explicit indexes for all the |
||
5838 | * display elements |
||
5839 | * @param string $row_no row number |
||
5840 | * @param string $where_clause where clause |
||
5841 | * @param string $where_clause_html url encoded where clause |
||
5842 | * @param array $condition_array array of conditions in the where clause |
||
5843 | * @param string $edit_url edit url |
||
5844 | * @param string $copy_url copy url |
||
5845 | * @param string $class css classes for the td elements |
||
5846 | * @param string $edit_str text for the edit link |
||
5847 | * @param string $copy_str text for the copy link |
||
5848 | * @param string $del_str text for the delete link |
||
5849 | * @param string $js_conf text for the JS confirmation |
||
5850 | * |
||
5851 | * @return string the generated HTML |
||
5852 | * |
||
5853 | * @access private |
||
5854 | * |
||
5855 | * @see _getPlacedLinks() |
||
5856 | */ |
||
5857 | private function _getCheckboxAndLinks( |
||
5858 | $position, |
||
5859 | $del_url, |
||
5860 | array $displayParts, |
||
5861 | $row_no, |
||
5862 | $where_clause, |
||
5863 | $where_clause_html, |
||
5864 | array $condition_array, |
||
5865 | $edit_url, |
||
5866 | $copy_url, |
||
5867 | $class, |
||
5868 | $edit_str, |
||
5869 | $copy_str, |
||
5870 | $del_str, |
||
5871 | $js_conf |
||
5872 | ) { |
||
5873 | |||
5874 | $ret = ''; |
||
5875 | |||
5876 | if ($position == self::POSITION_LEFT) { |
||
5877 | $ret .= $this->_getCheckboxForMultiRowSubmissions( |
||
5878 | $del_url, |
||
5879 | $displayParts, |
||
5880 | $row_no, |
||
5881 | $where_clause_html, |
||
5882 | $condition_array, |
||
5883 | '_left', |
||
5884 | '' |
||
5885 | ); |
||
5886 | |||
5887 | $ret .= $this->_getEditLink( |
||
5888 | $edit_url, |
||
5889 | $class, |
||
5890 | $edit_str, |
||
5891 | $where_clause, |
||
5892 | $where_clause_html |
||
5893 | ); |
||
5894 | |||
5895 | $ret .= $this->_getCopyLink( |
||
5896 | $copy_url, |
||
5897 | $copy_str, |
||
5898 | $where_clause, |
||
5899 | $where_clause_html, |
||
5900 | '' |
||
5901 | ); |
||
5902 | |||
5903 | $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, ''); |
||
5904 | } elseif ($position == self::POSITION_RIGHT) { |
||
5905 | $ret .= $this->_getDeleteLink($del_url, $del_str, $js_conf, ''); |
||
5906 | |||
5907 | $ret .= $this->_getCopyLink( |
||
5908 | $copy_url, |
||
5909 | $copy_str, |
||
5910 | $where_clause, |
||
5911 | $where_clause_html, |
||
5912 | '' |
||
5913 | ); |
||
5914 | |||
5915 | $ret .= $this->_getEditLink( |
||
5916 | $edit_url, |
||
5917 | $class, |
||
5918 | $edit_str, |
||
5919 | $where_clause, |
||
5920 | $where_clause_html |
||
5921 | ); |
||
5922 | |||
5923 | $ret .= $this->_getCheckboxForMultiRowSubmissions( |
||
5924 | $del_url, |
||
5925 | $displayParts, |
||
5926 | $row_no, |
||
5927 | $where_clause_html, |
||
5928 | $condition_array, |
||
5929 | '_right', |
||
5930 | '' |
||
5931 | ); |
||
5932 | } else { // $position == self::POSITION_NONE |
||
5933 | $ret .= $this->_getCheckboxForMultiRowSubmissions( |
||
5934 | $del_url, |
||
5935 | $displayParts, |
||
5936 | $row_no, |
||
5937 | $where_clause_html, |
||
5938 | $condition_array, |
||
5939 | '_left', |
||
5940 | '' |
||
5941 | ); |
||
5942 | } |
||
5943 | |||
5944 | return $ret; |
||
5945 | } // end of the '_getCheckboxAndLinks()' function |
||
5946 | |||
5947 | /** |
||
5948 | * Truncates given string based on LimitChars configuration |
||
5949 | * and Session pftext variable |
||
5950 | * (string is truncated only if necessary) |
||
5951 | * |
||
5952 | * @param string $str string to be truncated |
||
5953 | * |
||
5954 | * @return mixed |
||
5955 | * |
||
5956 | * @access private |
||
5957 | * |
||
5958 | * @see _handleNonPrintableContents(), _getDataCellForGeometryColumns(), |
||
5959 | * _getDataCellForNonNumericColumns |
||
5960 | */ |
||
5961 | private function _getPartialText($str) |
||
5962 | { |
||
5963 | $original_length = mb_strlen($str); |
||
5964 | if ($original_length > $GLOBALS['cfg']['LimitChars'] |
||
5965 | && $_SESSION['tmpval']['pftext'] === self::DISPLAY_PARTIAL_TEXT |
||
5966 | ) { |
||
5967 | $str = mb_substr( |
||
5968 | $str, |
||
5969 | 0, |
||
5970 | $GLOBALS['cfg']['LimitChars'] |
||
5971 | ) . '...'; |
||
5972 | $truncated = true; |
||
5973 | } else { |
||
5974 | $truncated = false; |
||
5975 | } |
||
5976 | |||
5977 | return [$truncated, $str, $original_length]; |
||
5978 | } |
||
5979 | } |
||
5980 |