1 | <?php |
||
2 | /* vim: set expandtab sw=4 ts=4 sts=4: */ |
||
3 | /** |
||
4 | * set of functions with the insert/edit features in pma |
||
5 | * |
||
6 | * @package PhpMyAdmin |
||
7 | */ |
||
8 | declare(strict_types=1); |
||
9 | |||
10 | namespace PhpMyAdmin; |
||
11 | |||
12 | use PhpMyAdmin\DatabaseInterface; |
||
13 | use PhpMyAdmin\FileListing; |
||
14 | use PhpMyAdmin\Message; |
||
15 | use PhpMyAdmin\Plugins\TransformationsPlugin; |
||
16 | use PhpMyAdmin\Relation; |
||
17 | use PhpMyAdmin\Response; |
||
18 | use PhpMyAdmin\Sanitize; |
||
19 | use PhpMyAdmin\Template; |
||
20 | use PhpMyAdmin\Transformations; |
||
21 | use PhpMyAdmin\Url; |
||
22 | use PhpMyAdmin\Util; |
||
23 | |||
24 | /** |
||
25 | * PhpMyAdmin\InsertEdit class |
||
26 | * |
||
27 | * @package PhpMyAdmin |
||
28 | */ |
||
29 | class InsertEdit |
||
30 | { |
||
31 | /** |
||
32 | * DatabaseInterface instance |
||
33 | * |
||
34 | * @var DatabaseInterface |
||
35 | */ |
||
36 | private $dbi; |
||
37 | |||
38 | /** |
||
39 | * @var Relation |
||
40 | */ |
||
41 | private $relation; |
||
42 | |||
43 | /** |
||
44 | * @var Transformations |
||
45 | */ |
||
46 | private $transformations; |
||
47 | |||
48 | /** |
||
49 | * @var FileListing |
||
50 | */ |
||
51 | private $fileListing; |
||
52 | |||
53 | /** |
||
54 | * @var Template |
||
55 | */ |
||
56 | public $template; |
||
57 | |||
58 | /** |
||
59 | * Constructor |
||
60 | * |
||
61 | * @param DatabaseInterface $dbi DatabaseInterface instance |
||
62 | */ |
||
63 | public function __construct(DatabaseInterface $dbi) |
||
64 | { |
||
65 | $this->dbi = $dbi; |
||
66 | $this->relation = new Relation($GLOBALS['dbi']); |
||
67 | $this->transformations = new Transformations(); |
||
68 | $this->fileListing = new FileListing(); |
||
69 | $this->template = new Template(); |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Retrieve form parameters for insert/edit form |
||
74 | * |
||
75 | * @param string $db name of the database |
||
76 | * @param string $table name of the table |
||
77 | * @param array|null $where_clauses where clauses |
||
78 | * @param array $where_clause_array array of where clauses |
||
79 | * @param string $err_url error url |
||
80 | * |
||
81 | * @return array array of insert/edit form parameters |
||
82 | */ |
||
83 | public function getFormParametersForInsertForm( |
||
84 | $db, |
||
85 | $table, |
||
86 | ?array $where_clauses, |
||
87 | array $where_clause_array, |
||
88 | $err_url |
||
89 | ) { |
||
90 | $_form_params = [ |
||
91 | 'db' => $db, |
||
92 | 'table' => $table, |
||
93 | 'goto' => $GLOBALS['goto'], |
||
94 | 'err_url' => $err_url, |
||
95 | 'sql_query' => $_POST['sql_query'], |
||
96 | ]; |
||
97 | if (isset($where_clauses)) { |
||
98 | foreach ($where_clause_array as $key_id => $where_clause) { |
||
99 | $_form_params['where_clause[' . $key_id . ']'] = trim($where_clause); |
||
100 | } |
||
101 | } |
||
102 | if (isset($_REQUEST['clause_is_unique'])) { |
||
103 | $_form_params['clause_is_unique'] = $_REQUEST['clause_is_unique']; |
||
104 | } |
||
105 | return $_form_params; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Creates array of where clauses |
||
110 | * |
||
111 | * @param array|string|null $where_clause where clause |
||
112 | * |
||
113 | * @return array whereClauseArray array of where clauses |
||
114 | */ |
||
115 | private function getWhereClauseArray($where_clause) |
||
116 | { |
||
117 | if (!isset($where_clause)) { |
||
118 | return []; |
||
119 | } |
||
120 | |||
121 | if (is_array($where_clause)) { |
||
122 | return $where_clause; |
||
123 | } |
||
124 | |||
125 | return [0 => $where_clause]; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Analysing where clauses array |
||
130 | * |
||
131 | * @param array $where_clause_array array of where clauses |
||
132 | * @param string $table name of the table |
||
133 | * @param string $db name of the database |
||
134 | * |
||
135 | * @return array $where_clauses, $result, $rows, $found_unique_key |
||
136 | */ |
||
137 | private function analyzeWhereClauses( |
||
138 | array $where_clause_array, |
||
139 | $table, |
||
140 | $db |
||
141 | ) { |
||
142 | $rows = []; |
||
143 | $result = []; |
||
144 | $where_clauses = []; |
||
145 | $found_unique_key = false; |
||
146 | foreach ($where_clause_array as $key_id => $where_clause) { |
||
147 | $local_query = 'SELECT * FROM ' |
||
148 | . Util::backquote($db) . '.' |
||
149 | . Util::backquote($table) |
||
150 | . ' WHERE ' . $where_clause . ';'; |
||
151 | $result[$key_id] = $this->dbi->query( |
||
152 | $local_query, |
||
153 | DatabaseInterface::CONNECT_USER, |
||
154 | DatabaseInterface::QUERY_STORE |
||
155 | ); |
||
156 | $rows[$key_id] = $this->dbi->fetchAssoc($result[$key_id]); |
||
157 | |||
158 | $where_clauses[$key_id] = str_replace('\\', '\\\\', $where_clause); |
||
159 | $has_unique_condition = $this->showEmptyResultMessageOrSetUniqueCondition( |
||
160 | $rows, |
||
161 | $key_id, |
||
162 | $where_clause_array, |
||
163 | $local_query, |
||
164 | $result |
||
165 | ); |
||
166 | if ($has_unique_condition) { |
||
167 | $found_unique_key = true; |
||
168 | } |
||
169 | } |
||
170 | return [$where_clauses, $result, $rows, $found_unique_key]; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Show message for empty result or set the unique_condition |
||
175 | * |
||
176 | * @param array $rows MySQL returned rows |
||
177 | * @param string $key_id ID in current key |
||
178 | * @param array $where_clause_array array of where clauses |
||
179 | * @param string $local_query query performed |
||
180 | * @param array $result MySQL result handle |
||
181 | * |
||
182 | * @return boolean |
||
183 | */ |
||
184 | private function showEmptyResultMessageOrSetUniqueCondition( |
||
185 | array $rows, |
||
186 | $key_id, |
||
187 | array $where_clause_array, |
||
188 | $local_query, |
||
189 | array $result |
||
190 | ) { |
||
191 | $has_unique_condition = false; |
||
192 | |||
193 | // No row returned |
||
194 | if (! $rows[$key_id]) { |
||
195 | unset($rows[$key_id], $where_clause_array[$key_id]); |
||
196 | Response::getInstance()->addHtml( |
||
197 | Util::getMessage( |
||
198 | __('MySQL returned an empty result set (i.e. zero rows).'), |
||
199 | $local_query |
||
200 | ) |
||
201 | ); |
||
202 | /** |
||
203 | * @todo not sure what should be done at this point, but we must not |
||
204 | * exit if we want the message to be displayed |
||
205 | */ |
||
206 | } else {// end if (no row returned) |
||
207 | $meta = $this->dbi->getFieldsMeta($result[$key_id]); |
||
208 | |||
209 | list($unique_condition, $tmp_clause_is_unique) |
||
210 | = Util::getUniqueCondition( |
||
211 | $result[$key_id], // handle |
||
212 | count($meta), // fields_cnt |
||
213 | $meta, // fields_meta |
||
214 | $rows[$key_id], // row |
||
215 | true, // force_unique |
||
216 | false, // restrict_to_table |
||
217 | null // analyzed_sql_results |
||
218 | ); |
||
219 | |||
220 | if (! empty($unique_condition)) { |
||
221 | $has_unique_condition = true; |
||
222 | } |
||
223 | unset($unique_condition, $tmp_clause_is_unique); |
||
224 | } |
||
225 | return $has_unique_condition; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * No primary key given, just load first row |
||
230 | * |
||
231 | * @param string $table name of the table |
||
232 | * @param string $db name of the database |
||
233 | * |
||
234 | * @return array containing $result and $rows arrays |
||
235 | */ |
||
236 | private function loadFirstRow($table, $db) |
||
237 | { |
||
238 | $result = $this->dbi->query( |
||
239 | 'SELECT * FROM ' . Util::backquote($db) |
||
240 | . '.' . Util::backquote($table) . ' LIMIT 1;', |
||
241 | DatabaseInterface::CONNECT_USER, |
||
242 | DatabaseInterface::QUERY_STORE |
||
243 | ); |
||
244 | $rows = array_fill(0, $GLOBALS['cfg']['InsertRows'], false); |
||
245 | return [$result, $rows]; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Add some url parameters |
||
250 | * |
||
251 | * @param array $url_params containing $db and $table as url parameters |
||
252 | * @param array $where_clause_array where clauses array |
||
253 | * @param string|null $where_clause where clause |
||
254 | * |
||
255 | * @return array Add some url parameters to $url_params array and return it |
||
256 | */ |
||
257 | public function urlParamsInEditMode( |
||
258 | array $url_params, |
||
259 | array $where_clause_array, |
||
260 | ?string $where_clause |
||
261 | ) { |
||
262 | if (isset($where_clause)) { |
||
263 | foreach ($where_clause_array as $where_clause) { |
||
264 | $url_params['where_clause'] = trim($where_clause); |
||
265 | } |
||
266 | } |
||
267 | if (! empty($_POST['sql_query'])) { |
||
268 | $url_params['sql_query'] = $_POST['sql_query']; |
||
269 | } |
||
270 | return $url_params; |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * Show type information or function selectors in Insert/Edit |
||
275 | * |
||
276 | * @param string $which function|type |
||
277 | * @param array $url_params containing url parameters |
||
278 | * @param boolean $is_show whether to show the element in $which |
||
279 | * |
||
280 | * @return string an HTML snippet |
||
281 | */ |
||
282 | public function showTypeOrFunction($which, array $url_params, $is_show) |
||
283 | { |
||
284 | $params = []; |
||
285 | |||
286 | switch ($which) { |
||
287 | case 'function': |
||
288 | $params['ShowFunctionFields'] = ($is_show ? 0 : 1); |
||
289 | $params['ShowFieldTypesInDataEditView'] |
||
290 | = $GLOBALS['cfg']['ShowFieldTypesInDataEditView']; |
||
291 | break; |
||
292 | case 'type': |
||
293 | $params['ShowFieldTypesInDataEditView'] = ($is_show ? 0 : 1); |
||
294 | $params['ShowFunctionFields'] |
||
295 | = $GLOBALS['cfg']['ShowFunctionFields']; |
||
296 | break; |
||
297 | } |
||
298 | |||
299 | $params['goto'] = 'sql.php'; |
||
300 | $this_url_params = array_merge($url_params, $params); |
||
301 | |||
302 | if (! $is_show) { |
||
303 | return ' : <a href="tbl_change.php' |
||
304 | . Url::getCommon($this_url_params) . '">' |
||
305 | . $this->showTypeOrFunctionLabel($which) |
||
306 | . '</a>'; |
||
307 | } |
||
308 | return '<th><a href="tbl_change.php' |
||
309 | . Url::getCommon($this_url_params) |
||
310 | . '" title="' . __('Hide') . '">' |
||
311 | . $this->showTypeOrFunctionLabel($which) |
||
312 | . '</a></th>'; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * Show type information or function selectors labels in Insert/Edit |
||
317 | * |
||
318 | * @param string $which function|type |
||
319 | * |
||
320 | * @return string an HTML snippet |
||
321 | */ |
||
322 | private function showTypeOrFunctionLabel($which) |
||
323 | { |
||
324 | switch ($which) { |
||
325 | case 'function': |
||
326 | return __('Function'); |
||
327 | case 'type': |
||
328 | return __('Type'); |
||
329 | } |
||
330 | |||
331 | return null; |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Analyze the table column array |
||
336 | * |
||
337 | * @param array $column description of column in given table |
||
338 | * @param array $comments_map comments for every column that has a comment |
||
339 | * @param boolean $timestamp_seen whether a timestamp has been seen |
||
340 | * |
||
341 | * @return array description of column in given table |
||
342 | */ |
||
343 | private function analyzeTableColumnsArray( |
||
344 | array $column, |
||
345 | array $comments_map, |
||
346 | $timestamp_seen |
||
347 | ) { |
||
348 | $column['Field_html'] = htmlspecialchars($column['Field']); |
||
349 | $column['Field_md5'] = md5($column['Field']); |
||
350 | // True_Type contains only the type (stops at first bracket) |
||
351 | $column['True_Type'] = preg_replace('@\(.*@s', '', $column['Type']); |
||
352 | $column['len'] = preg_match('@float|double@', $column['Type']) ? 100 : -1; |
||
353 | $column['Field_title'] = $this->getColumnTitle($column, $comments_map); |
||
354 | $column['is_binary'] = $this->isColumn( |
||
355 | $column, |
||
356 | ['binary', 'varbinary'] |
||
357 | ); |
||
358 | $column['is_blob'] = $this->isColumn( |
||
359 | $column, |
||
360 | ['blob', 'tinyblob', 'mediumblob', 'longblob'] |
||
361 | ); |
||
362 | $column['is_char'] = $this->isColumn( |
||
363 | $column, |
||
364 | ['char', 'varchar'] |
||
365 | ); |
||
366 | |||
367 | list($column['pma_type'], $column['wrap'], $column['first_timestamp']) |
||
368 | = $this->getEnumSetAndTimestampColumns($column, $timestamp_seen); |
||
369 | |||
370 | return $column; |
||
371 | } |
||
372 | |||
373 | /** |
||
374 | * Retrieve the column title |
||
375 | * |
||
376 | * @param array $column description of column in given table |
||
377 | * @param array $comments_map comments for every column that has a comment |
||
378 | * |
||
379 | * @return string column title |
||
380 | */ |
||
381 | private function getColumnTitle(array $column, array $comments_map) |
||
382 | { |
||
383 | if (isset($comments_map[$column['Field']])) { |
||
384 | return '<span style="border-bottom: 1px dashed black;" title="' |
||
385 | . htmlspecialchars($comments_map[$column['Field']]) . '">' |
||
386 | . $column['Field_html'] . '</span>'; |
||
387 | } |
||
388 | |||
389 | return $column['Field_html']; |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * check whether the column is of a certain type |
||
394 | * the goal is to ensure that types such as "enum('one','two','binary',..)" |
||
395 | * or "enum('one','two','varbinary',..)" are not categorized as binary |
||
396 | * |
||
397 | * @param array $column description of column in given table |
||
398 | * @param array $types the types to verify |
||
399 | * |
||
400 | * @return boolean whether the column's type if one of the $types |
||
401 | */ |
||
402 | public function isColumn(array $column, array $types) |
||
403 | { |
||
404 | foreach ($types as $one_type) { |
||
405 | if (mb_stripos($column['Type'], $one_type) === 0) { |
||
406 | return true; |
||
407 | } |
||
408 | } |
||
409 | return false; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Retrieve set, enum, timestamp table columns |
||
414 | * |
||
415 | * @param array $column description of column in given table |
||
416 | * @param boolean $timestamp_seen whether a timestamp has been seen |
||
417 | * |
||
418 | * @return array $column['pma_type'], $column['wrap'], $column['first_timestamp'] |
||
419 | */ |
||
420 | private function getEnumSetAndTimestampColumns(array $column, $timestamp_seen) |
||
421 | { |
||
422 | $column['first_timestamp'] = false; |
||
423 | switch ($column['True_Type']) { |
||
424 | case 'set': |
||
425 | $column['pma_type'] = 'set'; |
||
426 | $column['wrap'] = ''; |
||
427 | break; |
||
428 | case 'enum': |
||
429 | $column['pma_type'] = 'enum'; |
||
430 | $column['wrap'] = ''; |
||
431 | break; |
||
432 | case 'timestamp': |
||
433 | if (! $timestamp_seen) { // can only occur once per table |
||
434 | $column['first_timestamp'] = true; |
||
435 | } |
||
436 | $column['pma_type'] = $column['Type']; |
||
437 | $column['wrap'] = ' nowrap'; |
||
438 | break; |
||
439 | |||
440 | default: |
||
441 | $column['pma_type'] = $column['Type']; |
||
442 | $column['wrap'] = ' nowrap'; |
||
443 | break; |
||
444 | } |
||
445 | return [$column['pma_type'], $column['wrap'], $column['first_timestamp']]; |
||
446 | } |
||
447 | |||
448 | /** |
||
449 | * The function column |
||
450 | * We don't want binary data to be destroyed |
||
451 | * Note: from the MySQL manual: "BINARY doesn't affect how the column is |
||
452 | * stored or retrieved" so it does not mean that the contents is binary |
||
453 | * |
||
454 | * @param array $column description of column in given table |
||
455 | * @param boolean $is_upload upload or no |
||
456 | * @param string $column_name_appendix the name attribute |
||
457 | * @param string $onChangeClause onchange clause for fields |
||
458 | * @param array $no_support_types list of datatypes that are not (yet) |
||
459 | * handled by PMA |
||
460 | * @param integer $tabindex_for_function +3000 |
||
461 | * @param integer $tabindex tab index |
||
462 | * @param integer $idindex id index |
||
463 | * @param boolean $insert_mode insert mode or edit mode |
||
464 | * @param boolean $readOnly is column read only or not |
||
465 | * @param array $foreignData foreign key data |
||
466 | * |
||
467 | * @return string an html snippet |
||
468 | */ |
||
469 | private function getFunctionColumn( |
||
470 | array $column, |
||
471 | $is_upload, |
||
472 | $column_name_appendix, |
||
473 | $onChangeClause, |
||
474 | array $no_support_types, |
||
475 | $tabindex_for_function, |
||
476 | $tabindex, |
||
477 | $idindex, |
||
478 | $insert_mode, |
||
479 | $readOnly, |
||
480 | array $foreignData |
||
481 | ) { |
||
482 | $html_output = ''; |
||
483 | if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' |
||
484 | && $column['is_blob'] && !$is_upload) |
||
485 | || ($GLOBALS['cfg']['ProtectBinary'] === 'all' |
||
486 | && $column['is_binary']) |
||
487 | || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' |
||
488 | && $column['is_binary']) |
||
489 | ) { |
||
490 | $html_output .= '<td class="center">' . __('Binary') . '</td>' . "\n"; |
||
491 | } elseif ($readOnly |
||
492 | || mb_strstr($column['True_Type'], 'enum') |
||
493 | || mb_strstr($column['True_Type'], 'set') |
||
494 | || in_array($column['pma_type'], $no_support_types) |
||
495 | ) { |
||
496 | $html_output .= '<td class="center">--</td>' . "\n"; |
||
497 | } else { |
||
498 | $html_output .= '<td>' . "\n"; |
||
499 | |||
500 | $html_output .= '<select name="funcs' . $column_name_appendix . '"' |
||
501 | . ' ' . $onChangeClause |
||
502 | . ' tabindex="' . ($tabindex + $tabindex_for_function) . '"' |
||
503 | . ' id="field_' . $idindex . '_1">'; |
||
504 | $html_output .= Util::getFunctionsForField( |
||
505 | $column, |
||
506 | $insert_mode, |
||
507 | $foreignData |
||
508 | ) . "\n"; |
||
509 | |||
510 | $html_output .= '</select>' . "\n"; |
||
511 | $html_output .= '</td>' . "\n"; |
||
512 | } |
||
513 | return $html_output; |
||
514 | } |
||
515 | |||
516 | /** |
||
517 | * The null column |
||
518 | * |
||
519 | * @param array $column description of column in given table |
||
520 | * @param string $column_name_appendix the name attribute |
||
521 | * @param boolean $real_null_value is column value null or not null |
||
522 | * @param integer $tabindex tab index |
||
523 | * @param integer $tabindex_for_null +6000 |
||
524 | * @param integer $idindex id index |
||
525 | * @param string $vkey [multi_edit]['row_id'] |
||
526 | * @param array $foreigners keys into foreign fields |
||
527 | * @param array $foreignData data about the foreign keys |
||
528 | * @param boolean $readOnly is column read only or not |
||
529 | * |
||
530 | * @return string an html snippet |
||
531 | */ |
||
532 | private function getNullColumn( |
||
533 | array $column, |
||
534 | $column_name_appendix, |
||
535 | $real_null_value, |
||
536 | $tabindex, |
||
537 | $tabindex_for_null, |
||
538 | $idindex, |
||
539 | $vkey, |
||
540 | array $foreigners, |
||
541 | array $foreignData, |
||
542 | $readOnly |
||
543 | ) { |
||
544 | if ($column['Null'] != 'YES' || $readOnly) { |
||
545 | return "<td></td>\n"; |
||
546 | } |
||
547 | $html_output = ''; |
||
548 | $html_output .= '<td>' . "\n"; |
||
549 | $html_output .= '<input type="hidden" name="fields_null_prev' |
||
550 | . $column_name_appendix . '"'; |
||
551 | if ($real_null_value && !$column['first_timestamp']) { |
||
552 | $html_output .= ' value="on"'; |
||
553 | } |
||
554 | $html_output .= ' />' . "\n"; |
||
555 | |||
556 | $html_output .= '<input type="checkbox" class="checkbox_null" tabindex="' |
||
557 | . ($tabindex + $tabindex_for_null) . '"' |
||
558 | . ' name="fields_null' . $column_name_appendix . '"'; |
||
559 | if ($real_null_value) { |
||
560 | $html_output .= ' checked="checked"'; |
||
561 | } |
||
562 | $html_output .= ' id="field_' . ($idindex) . '_2" />'; |
||
563 | |||
564 | // nullify_code is needed by the js nullify() function |
||
565 | $nullify_code = $this->getNullifyCodeForNullColumn( |
||
566 | $column, |
||
567 | $foreigners, |
||
568 | $foreignData |
||
569 | ); |
||
570 | // to be able to generate calls to nullify() in jQuery |
||
571 | $html_output .= '<input type="hidden" class="nullify_code" name="nullify_code' |
||
572 | . $column_name_appendix . '" value="' . $nullify_code . '" />'; |
||
573 | $html_output .= '<input type="hidden" class="hashed_field" name="hashed_field' |
||
574 | . $column_name_appendix . '" value="' . $column['Field_md5'] . '" />'; |
||
575 | $html_output .= '<input type="hidden" class="multi_edit" name="multi_edit' |
||
576 | . $column_name_appendix . '" value="' . Sanitize::escapeJsString($vkey) . '" />'; |
||
577 | $html_output .= '</td>' . "\n"; |
||
578 | |||
579 | return $html_output; |
||
580 | } |
||
581 | |||
582 | /** |
||
583 | * Retrieve the nullify code for the null column |
||
584 | * |
||
585 | * @param array $column description of column in given table |
||
586 | * @param array $foreigners keys into foreign fields |
||
587 | * @param array $foreignData data about the foreign keys |
||
588 | * |
||
589 | * @return integer |
||
590 | */ |
||
591 | private function getNullifyCodeForNullColumn( |
||
592 | array $column, |
||
593 | array $foreigners, |
||
594 | array $foreignData |
||
595 | ) { |
||
596 | $foreigner = $this->relation->searchColumnInForeigners($foreigners, $column['Field']); |
||
597 | if (mb_strstr($column['True_Type'], 'enum')) { |
||
598 | if (mb_strlen((string) $column['Type']) > 20) { |
||
599 | $nullify_code = '1'; |
||
600 | } else { |
||
601 | $nullify_code = '2'; |
||
602 | } |
||
603 | } elseif (mb_strstr($column['True_Type'], 'set')) { |
||
604 | $nullify_code = '3'; |
||
605 | } elseif (!empty($foreigners) |
||
606 | && !empty($foreigner) |
||
607 | && $foreignData['foreign_link'] == false |
||
608 | ) { |
||
609 | // foreign key in a drop-down |
||
610 | $nullify_code = '4'; |
||
611 | } elseif (!empty($foreigners) |
||
612 | && !empty($foreigner) |
||
613 | && $foreignData['foreign_link'] == true |
||
614 | ) { |
||
615 | // foreign key with a browsing icon |
||
616 | $nullify_code = '6'; |
||
617 | } else { |
||
618 | $nullify_code = '5'; |
||
619 | } |
||
620 | return $nullify_code; |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * Get the HTML elements for value column in insert form |
||
625 | * (here, "column" is used in the sense of HTML column in HTML table) |
||
626 | * |
||
627 | * @param array $column description of column in given table |
||
628 | * @param string $backup_field hidden input field |
||
629 | * @param string $column_name_appendix the name attribute |
||
630 | * @param string $onChangeClause onchange clause for fields |
||
631 | * @param integer $tabindex tab index |
||
632 | * @param integer $tabindex_for_value offset for the values tabindex |
||
633 | * @param integer $idindex id index |
||
634 | * @param string $data description of the column field |
||
635 | * @param string $special_chars special characters |
||
636 | * @param array $foreignData data about the foreign keys |
||
637 | * @param array $paramTableDbArray array containing $table and $db |
||
638 | * @param integer $rownumber the row number |
||
639 | * @param array $titles An HTML IMG tag for a particular icon from |
||
640 | * a theme, which may be an actual file or |
||
641 | * an icon from a sprite |
||
642 | * @param string $text_dir text direction |
||
643 | * @param string $special_chars_encoded replaced char if the string starts |
||
644 | * with a \r\n pair (0x0d0a) add an extra \n |
||
645 | * @param string $vkey [multi_edit]['row_id'] |
||
646 | * @param boolean $is_upload is upload or not |
||
647 | * @param integer $biggest_max_file_size 0 integer |
||
648 | * @param string $default_char_editing default char editing mode which is stored |
||
649 | * in the config.inc.php script |
||
650 | * @param array $no_support_types list of datatypes that are not (yet) |
||
651 | * handled by PMA |
||
652 | * @param array $gis_data_types list of GIS data types |
||
653 | * @param array $extracted_columnspec associative array containing type, |
||
654 | * spec_in_brackets and possibly |
||
655 | * enum_set_values (another array) |
||
656 | * @param boolean $readOnly is column read only or not |
||
657 | * |
||
658 | * @return string an html snippet |
||
659 | */ |
||
660 | private function getValueColumn( |
||
661 | array $column, |
||
662 | $backup_field, |
||
663 | $column_name_appendix, |
||
664 | $onChangeClause, |
||
665 | $tabindex, |
||
666 | $tabindex_for_value, |
||
667 | $idindex, |
||
668 | $data, |
||
669 | $special_chars, |
||
670 | array $foreignData, |
||
671 | array $paramTableDbArray, |
||
672 | $rownumber, |
||
673 | array $titles, |
||
674 | $text_dir, |
||
675 | $special_chars_encoded, |
||
676 | $vkey, |
||
677 | $is_upload, |
||
678 | $biggest_max_file_size, |
||
679 | $default_char_editing, |
||
680 | array $no_support_types, |
||
681 | array $gis_data_types, |
||
682 | array $extracted_columnspec, |
||
683 | $readOnly |
||
684 | ) { |
||
685 | // HTML5 data-* attribute data-type |
||
686 | $data_type = $this->dbi->types->getTypeClass($column['True_Type']); |
||
687 | $html_output = ''; |
||
688 | |||
689 | if ($foreignData['foreign_link'] == true) { |
||
690 | $html_output .= $this->getForeignLink( |
||
691 | $column, |
||
692 | $backup_field, |
||
693 | $column_name_appendix, |
||
694 | $onChangeClause, |
||
695 | $tabindex, |
||
696 | $tabindex_for_value, |
||
697 | $idindex, |
||
698 | $data, |
||
699 | $paramTableDbArray, |
||
700 | $rownumber, |
||
701 | $titles, |
||
702 | $readOnly |
||
703 | ); |
||
704 | } elseif (is_array($foreignData['disp_row'])) { |
||
705 | $html_output .= $this->dispRowForeignData( |
||
706 | $column, |
||
707 | $backup_field, |
||
708 | $column_name_appendix, |
||
709 | $onChangeClause, |
||
710 | $tabindex, |
||
711 | $tabindex_for_value, |
||
712 | $idindex, |
||
713 | $data, |
||
714 | $foreignData, |
||
715 | $readOnly |
||
716 | ); |
||
717 | } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea'] |
||
718 | && mb_strstr($column['pma_type'], 'longtext') |
||
719 | ) { |
||
720 | $html_output .= $this->getTextarea( |
||
721 | $column, |
||
722 | $backup_field, |
||
723 | $column_name_appendix, |
||
724 | $onChangeClause, |
||
725 | $tabindex, |
||
726 | $tabindex_for_value, |
||
727 | $idindex, |
||
728 | $text_dir, |
||
729 | $special_chars_encoded, |
||
730 | $data_type, |
||
731 | $readOnly |
||
732 | ); |
||
733 | } elseif (mb_strstr($column['pma_type'], 'text')) { |
||
734 | $html_output .= $this->getTextarea( |
||
735 | $column, |
||
736 | $backup_field, |
||
737 | $column_name_appendix, |
||
738 | $onChangeClause, |
||
739 | $tabindex, |
||
740 | $tabindex_for_value, |
||
741 | $idindex, |
||
742 | $text_dir, |
||
743 | $special_chars_encoded, |
||
744 | $data_type, |
||
745 | $readOnly |
||
746 | ); |
||
747 | $html_output .= "\n"; |
||
748 | if (mb_strlen($special_chars) > 32000) { |
||
749 | $html_output .= "</td>\n"; |
||
750 | $html_output .= '<td>' . __( |
||
751 | 'Because of its length,<br /> this column might not be editable.' |
||
752 | ); |
||
753 | } |
||
754 | } elseif ($column['pma_type'] == 'enum') { |
||
755 | $html_output .= $this->getPmaTypeEnum( |
||
756 | $column, |
||
757 | $backup_field, |
||
758 | $column_name_appendix, |
||
759 | $extracted_columnspec, |
||
760 | $onChangeClause, |
||
761 | $tabindex, |
||
762 | $tabindex_for_value, |
||
763 | $idindex, |
||
764 | $data, |
||
765 | $readOnly |
||
766 | ); |
||
767 | } elseif ($column['pma_type'] == 'set') { |
||
768 | $html_output .= $this->getPmaTypeSet( |
||
769 | $column, |
||
770 | $extracted_columnspec, |
||
771 | $backup_field, |
||
772 | $column_name_appendix, |
||
773 | $onChangeClause, |
||
774 | $tabindex, |
||
775 | $tabindex_for_value, |
||
776 | $idindex, |
||
777 | $data, |
||
778 | $readOnly |
||
779 | ); |
||
780 | } elseif ($column['is_binary'] || $column['is_blob']) { |
||
781 | $html_output .= $this->getBinaryAndBlobColumn( |
||
782 | $column, |
||
783 | $data, |
||
784 | $special_chars, |
||
785 | $biggest_max_file_size, |
||
786 | $backup_field, |
||
787 | $column_name_appendix, |
||
788 | $onChangeClause, |
||
789 | $tabindex, |
||
790 | $tabindex_for_value, |
||
791 | $idindex, |
||
792 | $text_dir, |
||
793 | $special_chars_encoded, |
||
794 | $vkey, |
||
795 | $is_upload, |
||
796 | $readOnly |
||
797 | ); |
||
798 | } elseif (! in_array($column['pma_type'], $no_support_types)) { |
||
799 | $html_output .= $this->getValueColumnForOtherDatatypes( |
||
800 | $column, |
||
801 | $default_char_editing, |
||
802 | $backup_field, |
||
803 | $column_name_appendix, |
||
804 | $onChangeClause, |
||
805 | $tabindex, |
||
806 | $special_chars, |
||
807 | $tabindex_for_value, |
||
808 | $idindex, |
||
809 | $text_dir, |
||
810 | $special_chars_encoded, |
||
811 | $data, |
||
812 | $extracted_columnspec, |
||
813 | $readOnly |
||
814 | ); |
||
815 | } |
||
816 | |||
817 | if (in_array($column['pma_type'], $gis_data_types)) { |
||
818 | $html_output .= $this->getHtmlForGisDataTypes(); |
||
819 | } |
||
820 | |||
821 | return $html_output; |
||
822 | } |
||
823 | |||
824 | /** |
||
825 | * Get HTML for foreign link in insert form |
||
826 | * |
||
827 | * @param array $column description of column in given table |
||
828 | * @param string $backup_field hidden input field |
||
829 | * @param string $column_name_appendix the name attribute |
||
830 | * @param string $onChangeClause onchange clause for fields |
||
831 | * @param integer $tabindex tab index |
||
832 | * @param integer $tabindex_for_value offset for the values tabindex |
||
833 | * @param integer $idindex id index |
||
834 | * @param string $data data to edit |
||
835 | * @param array $paramTableDbArray array containing $table and $db |
||
836 | * @param integer $rownumber the row number |
||
837 | * @param array $titles An HTML IMG tag for a particular icon from |
||
838 | * a theme, which may be an actual file or |
||
839 | * an icon from a sprite |
||
840 | * @param boolean $readOnly is column read only or not |
||
841 | * |
||
842 | * @return string an html snippet |
||
843 | */ |
||
844 | private function getForeignLink( |
||
845 | array $column, |
||
846 | $backup_field, |
||
847 | $column_name_appendix, |
||
848 | $onChangeClause, |
||
849 | $tabindex, |
||
850 | $tabindex_for_value, |
||
851 | $idindex, |
||
852 | $data, |
||
853 | array $paramTableDbArray, |
||
854 | $rownumber, |
||
855 | array $titles, |
||
856 | $readOnly |
||
857 | ) { |
||
858 | list($table, $db) = $paramTableDbArray; |
||
859 | $html_output = ''; |
||
860 | $html_output .= $backup_field . "\n"; |
||
861 | |||
862 | $html_output .= '<input type="hidden" name="fields_type' |
||
863 | . $column_name_appendix . '" value="foreign" />'; |
||
864 | |||
865 | $html_output .= '<input type="text" name="fields' . $column_name_appendix . '" ' |
||
866 | . 'class="textfield" ' |
||
867 | . $onChangeClause . ' ' |
||
868 | . ($readOnly ? 'readonly="readonly" ' : '') |
||
869 | . 'tabindex="' . ($tabindex + $tabindex_for_value) . '" ' |
||
870 | . 'id="field_' . ($idindex) . '_3" ' |
||
871 | . 'value="' . htmlspecialchars($data) . '" />'; |
||
872 | |||
873 | $html_output .= '<a class="ajax browse_foreign" href="browse_foreigners.php' |
||
874 | . Url::getCommon( |
||
875 | [ |
||
876 | 'db' => $db, |
||
877 | 'table' => $table, |
||
878 | 'field' => $column['Field'], |
||
879 | 'rownumber' => $rownumber, |
||
880 | 'data' => $data |
||
881 | ] |
||
882 | ) . '">' |
||
883 | . str_replace("'", "\'", $titles['Browse']) . '</a>'; |
||
884 | return $html_output; |
||
885 | } |
||
886 | |||
887 | /** |
||
888 | * Get HTML to display foreign data |
||
889 | * |
||
890 | * @param array $column description of column in given table |
||
891 | * @param string $backup_field hidden input field |
||
892 | * @param string $column_name_appendix the name attribute |
||
893 | * @param string $onChangeClause onchange clause for fields |
||
894 | * @param integer $tabindex tab index |
||
895 | * @param integer $tabindex_for_value offset for the values tabindex |
||
896 | * @param integer $idindex id index |
||
897 | * @param string $data data to edit |
||
898 | * @param array $foreignData data about the foreign keys |
||
899 | * @param boolean $readOnly is display read only or not |
||
900 | * |
||
901 | * @return string an html snippet |
||
902 | */ |
||
903 | private function dispRowForeignData( |
||
904 | $column, |
||
905 | $backup_field, |
||
906 | $column_name_appendix, |
||
907 | $onChangeClause, |
||
908 | $tabindex, |
||
909 | $tabindex_for_value, |
||
910 | $idindex, |
||
911 | $data, |
||
912 | array $foreignData, |
||
913 | $readOnly |
||
914 | ) { |
||
915 | $html_output = ''; |
||
916 | $html_output .= $backup_field . "\n"; |
||
917 | $html_output .= '<input type="hidden"' |
||
918 | . ' name="fields_type' . $column_name_appendix . '"'; |
||
919 | if ($column['is_binary']) { |
||
920 | $html_output .= ' value="hex" />'; |
||
921 | } else { |
||
922 | $html_output .= ' value="foreign" />'; |
||
923 | } |
||
924 | |||
925 | $html_output .= '<select name="fields' . $column_name_appendix . '"' |
||
926 | . ' ' . $onChangeClause |
||
927 | . ' class="textfield"' |
||
928 | . ($readOnly ? ' disabled' : '') |
||
929 | . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"' |
||
930 | . ' id="field_' . $idindex . '_3">'; |
||
931 | $html_output .= $this->relation->foreignDropdown( |
||
932 | $foreignData['disp_row'], |
||
933 | $foreignData['foreign_field'], |
||
934 | $foreignData['foreign_display'], |
||
935 | $data, |
||
936 | $GLOBALS['cfg']['ForeignKeyMaxLimit'] |
||
937 | ); |
||
938 | $html_output .= '</select>'; |
||
939 | |||
940 | //Add hidden input, as disabled <select> input does not included in POST. |
||
941 | if ($readOnly) { |
||
942 | $html_output .= '<input name="fields' . $column_name_appendix . '"' |
||
943 | . ' type="hidden" value="' . htmlspecialchars($data) . '">'; |
||
944 | } |
||
945 | |||
946 | return $html_output; |
||
947 | } |
||
948 | |||
949 | /** |
||
950 | * Get HTML textarea for insert form |
||
951 | * |
||
952 | * @param array $column column information |
||
953 | * @param string $backup_field hidden input field |
||
954 | * @param string $column_name_appendix the name attribute |
||
955 | * @param string $onChangeClause onchange clause for fields |
||
956 | * @param integer $tabindex tab index |
||
957 | * @param integer $tabindex_for_value offset for the values tabindex |
||
958 | * @param integer $idindex id index |
||
959 | * @param string $text_dir text direction |
||
960 | * @param string $special_chars_encoded replaced char if the string starts |
||
961 | * with a \r\n pair (0x0d0a) add an extra \n |
||
962 | * @param string $data_type the html5 data-* attribute type |
||
963 | * @param boolean $readOnly is column read only or not |
||
964 | * |
||
965 | * @return string an html snippet |
||
966 | */ |
||
967 | private function getTextarea( |
||
968 | array $column, |
||
969 | $backup_field, |
||
970 | $column_name_appendix, |
||
971 | $onChangeClause, |
||
972 | $tabindex, |
||
973 | $tabindex_for_value, |
||
974 | $idindex, |
||
975 | $text_dir, |
||
976 | $special_chars_encoded, |
||
977 | $data_type, |
||
978 | $readOnly |
||
979 | ) { |
||
980 | $the_class = ''; |
||
981 | $textAreaRows = $GLOBALS['cfg']['TextareaRows']; |
||
982 | $textareaCols = $GLOBALS['cfg']['TextareaCols']; |
||
983 | |||
984 | if ($column['is_char']) { |
||
985 | /** |
||
986 | * @todo clarify the meaning of the "textfield" class and explain |
||
987 | * why character columns have the "char" class instead |
||
988 | */ |
||
989 | $the_class = 'char charField'; |
||
990 | $textAreaRows = max($GLOBALS['cfg']['CharTextareaRows'], 7); |
||
991 | $textareaCols = $GLOBALS['cfg']['CharTextareaCols']; |
||
992 | $extracted_columnspec = Util::extractColumnSpec( |
||
993 | $column['Type'] |
||
994 | ); |
||
995 | $maxlength = $extracted_columnspec['spec_in_brackets']; |
||
996 | } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea'] |
||
997 | && mb_strstr($column['pma_type'], 'longtext') |
||
998 | ) { |
||
999 | $textAreaRows = $GLOBALS['cfg']['TextareaRows'] * 2; |
||
1000 | $textareaCols = $GLOBALS['cfg']['TextareaCols'] * 2; |
||
1001 | } |
||
1002 | $html_output = $backup_field . "\n" |
||
1003 | . '<textarea name="fields' . $column_name_appendix . '"' |
||
1004 | . ' class="' . $the_class . '"' |
||
1005 | . ($readOnly ? ' readonly="readonly"' : '') |
||
1006 | . (isset($maxlength) ? ' data-maxlength="' . $maxlength . '"' : '') |
||
1007 | . ' rows="' . $textAreaRows . '"' |
||
1008 | . ' cols="' . $textareaCols . '"' |
||
1009 | . ' dir="' . $text_dir . '"' |
||
1010 | . ' id="field_' . ($idindex) . '_3"' |
||
1011 | . (! empty($onChangeClause) ? ' ' . $onChangeClause : '') |
||
1012 | . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"' |
||
1013 | . ' data-type="' . $data_type . '">' |
||
1014 | . $special_chars_encoded |
||
1015 | . '</textarea>'; |
||
1016 | |||
1017 | return $html_output; |
||
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * Get HTML for enum type |
||
1022 | * |
||
1023 | * @param array $column description of column in given table |
||
1024 | * @param string $backup_field hidden input field |
||
1025 | * @param string $column_name_appendix the name attribute |
||
1026 | * @param array $extracted_columnspec associative array containing type, |
||
1027 | * spec_in_brackets and possibly |
||
1028 | * enum_set_values (another array) |
||
1029 | * @param string $onChangeClause onchange clause for fields |
||
1030 | * @param integer $tabindex tab index |
||
1031 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1032 | * @param integer $idindex id index |
||
1033 | * @param mixed $data data to edit |
||
1034 | * @param boolean $readOnly is column read only or not |
||
1035 | * |
||
1036 | * @return string an html snippet |
||
1037 | */ |
||
1038 | private function getPmaTypeEnum( |
||
1039 | array $column, |
||
1040 | $backup_field, |
||
1041 | $column_name_appendix, |
||
1042 | array $extracted_columnspec, |
||
1043 | $onChangeClause, |
||
1044 | $tabindex, |
||
1045 | $tabindex_for_value, |
||
1046 | $idindex, |
||
1047 | $data, |
||
1048 | $readOnly |
||
1049 | ) { |
||
1050 | $html_output = ''; |
||
1051 | if (! isset($column['values'])) { |
||
1052 | $column['values'] = $this->getColumnEnumValues( |
||
1053 | $column, |
||
1054 | $extracted_columnspec |
||
1055 | ); |
||
1056 | } |
||
1057 | $column_enum_values = $column['values']; |
||
1058 | $html_output .= '<input type="hidden" name="fields_type' |
||
1059 | . $column_name_appendix . '" value="enum" />'; |
||
1060 | $html_output .= "\n" . ' ' . $backup_field . "\n"; |
||
1061 | if (mb_strlen($column['Type']) > 20) { |
||
1062 | $html_output .= $this->getDropDownDependingOnLength( |
||
1063 | $column, |
||
1064 | $column_name_appendix, |
||
1065 | $onChangeClause, |
||
1066 | $tabindex, |
||
1067 | $tabindex_for_value, |
||
1068 | $idindex, |
||
1069 | $data, |
||
1070 | $column_enum_values, |
||
1071 | $readOnly |
||
1072 | ); |
||
1073 | } else { |
||
1074 | $html_output .= $this->getRadioButtonDependingOnLength( |
||
1075 | $column_name_appendix, |
||
1076 | $onChangeClause, |
||
1077 | $tabindex, |
||
1078 | $column, |
||
1079 | $tabindex_for_value, |
||
1080 | $idindex, |
||
1081 | $data, |
||
1082 | $column_enum_values, |
||
1083 | $readOnly |
||
1084 | ); |
||
1085 | } |
||
1086 | return $html_output; |
||
1087 | } |
||
1088 | |||
1089 | /** |
||
1090 | * Get column values |
||
1091 | * |
||
1092 | * @param array $column description of column in given table |
||
1093 | * @param array $extracted_columnspec associative array containing type, |
||
1094 | * spec_in_brackets and possibly enum_set_values |
||
1095 | * (another array) |
||
1096 | * |
||
1097 | * @return array column values as an associative array |
||
1098 | */ |
||
1099 | private function getColumnEnumValues(array $column, array $extracted_columnspec) |
||
1100 | { |
||
1101 | $column['values'] = []; |
||
1102 | foreach ($extracted_columnspec['enum_set_values'] as $val) { |
||
1103 | $column['values'][] = [ |
||
1104 | 'plain' => $val, |
||
1105 | 'html' => htmlspecialchars($val), |
||
1106 | ]; |
||
1107 | } |
||
1108 | return $column['values']; |
||
1109 | } |
||
1110 | |||
1111 | /** |
||
1112 | * Get HTML drop down for more than 20 string length |
||
1113 | * |
||
1114 | * @param array $column description of column in given table |
||
1115 | * @param string $column_name_appendix the name attribute |
||
1116 | * @param string $onChangeClause onchange clause for fields |
||
1117 | * @param integer $tabindex tab index |
||
1118 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1119 | * @param integer $idindex id index |
||
1120 | * @param string $data data to edit |
||
1121 | * @param array $column_enum_values $column['values'] |
||
1122 | * @param boolean $readOnly is column read only or not |
||
1123 | * |
||
1124 | * @return string an html snippet |
||
1125 | */ |
||
1126 | private function getDropDownDependingOnLength( |
||
1127 | array $column, |
||
1128 | $column_name_appendix, |
||
1129 | $onChangeClause, |
||
1130 | $tabindex, |
||
1131 | $tabindex_for_value, |
||
1132 | $idindex, |
||
1133 | $data, |
||
1134 | array $column_enum_values, |
||
1135 | $readOnly |
||
1136 | ) { |
||
1137 | $html_output = '<select name="fields' . $column_name_appendix . '"' |
||
1138 | . ' ' . $onChangeClause |
||
1139 | . ' class="textfield"' |
||
1140 | . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"' |
||
1141 | . ($readOnly ? ' disabled' : '') |
||
1142 | . ' id="field_' . ($idindex) . '_3">'; |
||
1143 | $html_output .= '<option value=""> </option>' . "\n"; |
||
1144 | |||
1145 | $selected_html = ''; |
||
1146 | foreach ($column_enum_values as $enum_value) { |
||
1147 | $html_output .= '<option value="' . $enum_value['html'] . '"'; |
||
1148 | if ($data == $enum_value['plain'] |
||
1149 | || ($data == '' |
||
1150 | && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES') |
||
1151 | && isset($column['Default']) |
||
1152 | && $enum_value['plain'] == $column['Default']) |
||
1153 | ) { |
||
1154 | $html_output .= ' selected="selected"'; |
||
1155 | $selected_html = $enum_value['html']; |
||
1156 | } |
||
1157 | $html_output .= '>' . $enum_value['html'] . '</option>' . "\n"; |
||
1158 | } |
||
1159 | $html_output .= '</select>'; |
||
1160 | |||
1161 | //Add hidden input, as disabled <select> input does not included in POST. |
||
1162 | if ($readOnly) { |
||
1163 | $html_output .= '<input name="fields' . $column_name_appendix . '"' |
||
1164 | . ' type="hidden" value="' . $selected_html . '">'; |
||
1165 | } |
||
1166 | return $html_output; |
||
1167 | } |
||
1168 | |||
1169 | /** |
||
1170 | * Get HTML radio button for less than 20 string length |
||
1171 | * |
||
1172 | * @param string $column_name_appendix the name attribute |
||
1173 | * @param string $onChangeClause onchange clause for fields |
||
1174 | * @param integer $tabindex tab index |
||
1175 | * @param array $column description of column in given table |
||
1176 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1177 | * @param integer $idindex id index |
||
1178 | * @param string $data data to edit |
||
1179 | * @param array $column_enum_values $column['values'] |
||
1180 | * @param boolean $readOnly is column read only or not |
||
1181 | * |
||
1182 | * @return string an html snippet |
||
1183 | */ |
||
1184 | private function getRadioButtonDependingOnLength( |
||
1185 | $column_name_appendix, |
||
1186 | $onChangeClause, |
||
1187 | $tabindex, |
||
1188 | array $column, |
||
1189 | $tabindex_for_value, |
||
1190 | $idindex, |
||
1191 | $data, |
||
1192 | array $column_enum_values, |
||
1193 | $readOnly |
||
1194 | ) { |
||
1195 | $j = 0; |
||
1196 | $html_output = ''; |
||
1197 | foreach ($column_enum_values as $enum_value) { |
||
1198 | $html_output .= ' ' |
||
1199 | . '<input type="radio" name="fields' . $column_name_appendix . '"' |
||
1200 | . ' class="textfield"' |
||
1201 | . ' value="' . $enum_value['html'] . '"' |
||
1202 | . ' id="field_' . ($idindex) . '_3_' . $j . '"' |
||
1203 | . ' ' . $onChangeClause; |
||
1204 | if ($data == $enum_value['plain'] |
||
1205 | || ($data == '' |
||
1206 | && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES') |
||
1207 | && isset($column['Default']) |
||
1208 | && $enum_value['plain'] == $column['Default']) |
||
1209 | ) { |
||
1210 | $html_output .= ' checked="checked"'; |
||
1211 | } elseif ($readOnly) { |
||
1212 | $html_output .= ' disabled'; |
||
1213 | } |
||
1214 | $html_output .= ' tabindex="' . ($tabindex + $tabindex_for_value) . '" />'; |
||
1215 | $html_output .= '<label for="field_' . $idindex . '_3_' . $j . '">' |
||
1216 | . $enum_value['html'] . '</label>' . "\n"; |
||
1217 | $j++; |
||
1218 | } |
||
1219 | return $html_output; |
||
1220 | } |
||
1221 | |||
1222 | /** |
||
1223 | * Get the HTML for 'set' pma type |
||
1224 | * |
||
1225 | * @param array $column description of column in given table |
||
1226 | * @param array $extracted_columnspec associative array containing type, |
||
1227 | * spec_in_brackets and possibly |
||
1228 | * enum_set_values (another array) |
||
1229 | * @param string $backup_field hidden input field |
||
1230 | * @param string $column_name_appendix the name attribute |
||
1231 | * @param string $onChangeClause onchange clause for fields |
||
1232 | * @param integer $tabindex tab index |
||
1233 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1234 | * @param integer $idindex id index |
||
1235 | * @param string $data description of the column field |
||
1236 | * @param boolean $readOnly is column read only or not |
||
1237 | * |
||
1238 | * @return string an html snippet |
||
1239 | */ |
||
1240 | private function getPmaTypeSet( |
||
1241 | array $column, |
||
1242 | array $extracted_columnspec, |
||
1243 | $backup_field, |
||
1244 | $column_name_appendix, |
||
1245 | $onChangeClause, |
||
1246 | $tabindex, |
||
1247 | $tabindex_for_value, |
||
1248 | $idindex, |
||
1249 | $data, |
||
1250 | $readOnly |
||
1251 | ) { |
||
1252 | list($column_set_values, $select_size) = $this->getColumnSetValueAndSelectSize( |
||
1253 | $column, |
||
1254 | $extracted_columnspec |
||
1255 | ); |
||
1256 | $vset = array_flip(explode(',', $data)); |
||
1257 | $html_output = $backup_field . "\n"; |
||
1258 | $html_output .= '<input type="hidden" name="fields_type' |
||
1259 | . $column_name_appendix . '" value="set" />'; |
||
1260 | $html_output .= '<select name="fields' . $column_name_appendix . '[]' . '"' |
||
1261 | . ' class="textfield"' |
||
1262 | . ($readOnly ? ' disabled' : '') |
||
1263 | . ' size="' . $select_size . '"' |
||
1264 | . ' multiple="multiple"' |
||
1265 | . ' ' . $onChangeClause |
||
1266 | . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"' |
||
1267 | . ' id="field_' . ($idindex) . '_3">'; |
||
1268 | |||
1269 | $selected_html = ''; |
||
1270 | foreach ($column_set_values as $column_set_value) { |
||
1271 | $html_output .= '<option value="' . $column_set_value['html'] . '"'; |
||
1272 | if (isset($vset[$column_set_value['plain']])) { |
||
1273 | $html_output .= ' selected="selected"'; |
||
1274 | $selected_html = $column_set_value['html']; |
||
1275 | } |
||
1276 | $html_output .= '>' . $column_set_value['html'] . '</option>' . "\n"; |
||
1277 | } |
||
1278 | $html_output .= '</select>'; |
||
1279 | |||
1280 | //Add hidden input, as disabled <select> input does not included in POST. |
||
1281 | if ($readOnly) { |
||
1282 | $html_output .= '<input name="fields' . $column_name_appendix . '[]' . '"' |
||
1283 | . ' type="hidden" value="' . $selected_html . '">'; |
||
1284 | } |
||
1285 | return $html_output; |
||
1286 | } |
||
1287 | |||
1288 | /** |
||
1289 | * Retrieve column 'set' value and select size |
||
1290 | * |
||
1291 | * @param array $column description of column in given table |
||
1292 | * @param array $extracted_columnspec associative array containing type, |
||
1293 | * spec_in_brackets and possibly enum_set_values |
||
1294 | * (another array) |
||
1295 | * |
||
1296 | * @return array $column['values'], $column['select_size'] |
||
1297 | */ |
||
1298 | private function getColumnSetValueAndSelectSize( |
||
1299 | array $column, |
||
1300 | array $extracted_columnspec |
||
1301 | ) { |
||
1302 | if (! isset($column['values'])) { |
||
1303 | $column['values'] = []; |
||
1304 | foreach ($extracted_columnspec['enum_set_values'] as $val) { |
||
1305 | $column['values'][] = [ |
||
1306 | 'plain' => $val, |
||
1307 | 'html' => htmlspecialchars($val), |
||
1308 | ]; |
||
1309 | } |
||
1310 | $column['select_size'] = min(4, count($column['values'])); |
||
1311 | } |
||
1312 | return [$column['values'], $column['select_size']]; |
||
1313 | } |
||
1314 | |||
1315 | /** |
||
1316 | * Get HTML for binary and blob column |
||
1317 | * |
||
1318 | * @param array $column description of column in given table |
||
1319 | * @param string|null $data data to edit |
||
1320 | * @param string $special_chars special characters |
||
1321 | * @param integer $biggest_max_file_size biggest max file size for uploading |
||
1322 | * @param string $backup_field hidden input field |
||
1323 | * @param string $column_name_appendix the name attribute |
||
1324 | * @param string $onChangeClause onchange clause for fields |
||
1325 | * @param integer $tabindex tab index |
||
1326 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1327 | * @param integer $idindex id index |
||
1328 | * @param string $text_dir text direction |
||
1329 | * @param string $special_chars_encoded replaced char if the string starts |
||
1330 | * with a \r\n pair (0x0d0a) add an |
||
1331 | * extra \n |
||
1332 | * @param string $vkey [multi_edit]['row_id'] |
||
1333 | * @param boolean $is_upload is upload or not |
||
1334 | * @param boolean $readOnly is column read only or not |
||
1335 | * |
||
1336 | * @return string an html snippet |
||
1337 | */ |
||
1338 | private function getBinaryAndBlobColumn( |
||
1339 | array $column, |
||
1340 | ?string $data, |
||
1341 | $special_chars, |
||
1342 | $biggest_max_file_size, |
||
1343 | $backup_field, |
||
1344 | $column_name_appendix, |
||
1345 | $onChangeClause, |
||
1346 | $tabindex, |
||
1347 | $tabindex_for_value, |
||
1348 | $idindex, |
||
1349 | $text_dir, |
||
1350 | $special_chars_encoded, |
||
1351 | $vkey, |
||
1352 | $is_upload, |
||
1353 | $readOnly |
||
1354 | ) { |
||
1355 | $html_output = ''; |
||
1356 | // Add field type : Protected or Hexadecimal |
||
1357 | $fields_type_html = '<input type="hidden" name="fields_type' |
||
1358 | . $column_name_appendix . '" value="%s" />'; |
||
1359 | // Default value : hex |
||
1360 | $fields_type_val = 'hex'; |
||
1361 | if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob']) |
||
1362 | || ($GLOBALS['cfg']['ProtectBinary'] === 'all') |
||
1363 | || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && !$column['is_blob']) |
||
1364 | ) { |
||
1365 | $html_output .= __('Binary - do not edit'); |
||
1366 | if (isset($data)) { |
||
1367 | $data_size = Util::formatByteDown( |
||
1368 | mb_strlen(stripslashes($data)), |
||
1369 | 3, |
||
1370 | 1 |
||
1371 | ); |
||
1372 | $html_output .= ' (' . $data_size[0] . ' ' . $data_size[1] . ')'; |
||
1373 | unset($data_size); |
||
1374 | } |
||
1375 | $fields_type_val = 'protected'; |
||
1376 | $html_output .= '<input type="hidden" name="fields' |
||
1377 | . $column_name_appendix . '" value="" />'; |
||
1378 | } elseif ($column['is_blob'] |
||
1379 | || ($column['len'] > $GLOBALS['cfg']['LimitChars']) |
||
1380 | ) { |
||
1381 | $html_output .= "\n" . $this->getTextarea( |
||
1382 | $column, |
||
1383 | $backup_field, |
||
1384 | $column_name_appendix, |
||
1385 | $onChangeClause, |
||
1386 | $tabindex, |
||
1387 | $tabindex_for_value, |
||
1388 | $idindex, |
||
1389 | $text_dir, |
||
1390 | $special_chars_encoded, |
||
1391 | 'HEX', |
||
1392 | $readOnly |
||
1393 | ); |
||
1394 | } else { |
||
1395 | // field size should be at least 4 and max $GLOBALS['cfg']['LimitChars'] |
||
1396 | $fieldsize = min(max($column['len'], 4), $GLOBALS['cfg']['LimitChars']); |
||
1397 | $html_output .= "\n" . $backup_field . "\n" . $this->getHtmlInput( |
||
1398 | $column, |
||
1399 | $column_name_appendix, |
||
1400 | $special_chars, |
||
1401 | $fieldsize, |
||
1402 | $onChangeClause, |
||
1403 | $tabindex, |
||
1404 | $tabindex_for_value, |
||
1405 | $idindex, |
||
1406 | 'HEX', |
||
1407 | $readOnly |
||
1408 | ); |
||
1409 | } |
||
1410 | $html_output .= sprintf($fields_type_html, $fields_type_val); |
||
1411 | |||
1412 | if ($is_upload && $column['is_blob'] && !$readOnly) { |
||
1413 | // We don't want to prevent users from using |
||
1414 | // browser's default drag-drop feature on some page(s), |
||
1415 | // so we add noDragDrop class to the input |
||
1416 | $html_output .= '<br />' |
||
1417 | . '<input type="file"' |
||
1418 | . ' name="fields_upload' . $vkey . '[' . $column['Field_md5'] . ']"' |
||
1419 | . ' class="textfield noDragDrop" id="field_' . $idindex . '_3" size="10"' |
||
1420 | . ' ' . $onChangeClause . '/> '; |
||
1421 | list($html_out,) = $this->getMaxUploadSize( |
||
1422 | $column, |
||
1423 | $biggest_max_file_size |
||
1424 | ); |
||
1425 | $html_output .= $html_out; |
||
1426 | } |
||
1427 | |||
1428 | if (!empty($GLOBALS['cfg']['UploadDir']) && !$readOnly) { |
||
1429 | $html_output .= $this->getSelectOptionForUpload($vkey, $column); |
||
1430 | } |
||
1431 | |||
1432 | return $html_output; |
||
1433 | } |
||
1434 | |||
1435 | /** |
||
1436 | * Get HTML input type |
||
1437 | * |
||
1438 | * @param array $column description of column in given table |
||
1439 | * @param string $column_name_appendix the name attribute |
||
1440 | * @param string $special_chars special characters |
||
1441 | * @param integer $fieldsize html field size |
||
1442 | * @param string $onChangeClause onchange clause for fields |
||
1443 | * @param integer $tabindex tab index |
||
1444 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1445 | * @param integer $idindex id index |
||
1446 | * @param string $data_type the html5 data-* attribute type |
||
1447 | * @param boolean $readOnly is column read only or not |
||
1448 | * |
||
1449 | * @return string an html snippet |
||
1450 | */ |
||
1451 | private function getHtmlInput( |
||
1452 | array $column, |
||
1453 | $column_name_appendix, |
||
1454 | $special_chars, |
||
1455 | $fieldsize, |
||
1456 | $onChangeClause, |
||
1457 | $tabindex, |
||
1458 | $tabindex_for_value, |
||
1459 | $idindex, |
||
1460 | $data_type, |
||
1461 | $readOnly |
||
1462 | ) { |
||
1463 | $input_type = 'text'; |
||
1464 | // do not use the 'date' or 'time' types here; they have no effect on some |
||
1465 | // browsers and create side effects (see bug #4218) |
||
1466 | |||
1467 | $the_class = 'textfield'; |
||
1468 | // verify True_Type which does not contain the parentheses and length |
||
1469 | if ($readOnly) { |
||
1470 | //NOOP. Disable date/timepicker |
||
1471 | } elseif ($column['True_Type'] === 'date') { |
||
1472 | $the_class .= ' datefield'; |
||
1473 | } elseif ($column['True_Type'] === 'time') { |
||
1474 | $the_class .= ' timefield'; |
||
1475 | } elseif ($column['True_Type'] === 'datetime' |
||
1476 | || $column['True_Type'] === 'timestamp' |
||
1477 | ) { |
||
1478 | $the_class .= ' datetimefield'; |
||
1479 | } |
||
1480 | $input_min_max = false; |
||
1481 | if (in_array($column['True_Type'], $this->dbi->types->getIntegerTypes())) { |
||
1482 | $extracted_columnspec = Util::extractColumnSpec( |
||
1483 | $column['Type'] |
||
1484 | ); |
||
1485 | $is_unsigned = $extracted_columnspec['unsigned']; |
||
1486 | $min_max_values = $this->dbi->types->getIntegerRange( |
||
1487 | $column['True_Type'], |
||
1488 | ! $is_unsigned |
||
1489 | ); |
||
1490 | $input_min_max = 'min="' . $min_max_values[0] . '" ' |
||
1491 | . 'max="' . $min_max_values[1] . '"'; |
||
1492 | $data_type = 'INT'; |
||
1493 | } |
||
1494 | return '<input type="' . $input_type . '"' |
||
1495 | . ' name="fields' . $column_name_appendix . '"' |
||
1496 | . ' value="' . $special_chars . '" size="' . $fieldsize . '"' |
||
1497 | . ((isset($column['is_char']) && $column['is_char']) |
||
1498 | ? ' data-maxlength="' . $fieldsize . '"' |
||
1499 | : '') |
||
1500 | . ($readOnly ? ' readonly="readonly"' : '') |
||
1501 | . ($input_min_max !== false ? ' ' . $input_min_max : '') |
||
1502 | . ' data-type="' . $data_type . '"' |
||
1503 | . ($input_type === 'time' ? ' step="1"' : '') |
||
1504 | . ' class="' . $the_class . '" ' . $onChangeClause |
||
1505 | . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"' |
||
1506 | . ' id="field_' . ($idindex) . '_3" />'; |
||
1507 | } |
||
1508 | |||
1509 | /** |
||
1510 | * Get HTML select option for upload |
||
1511 | * |
||
1512 | * @param string $vkey [multi_edit]['row_id'] |
||
1513 | * @param array $column description of column in given table |
||
1514 | * |
||
1515 | * @return string|void an html snippet |
||
1516 | */ |
||
1517 | private function getSelectOptionForUpload($vkey, array $column) |
||
1518 | { |
||
1519 | $files = $this->fileListing->getFileSelectOptions( |
||
1520 | Util::userDir($GLOBALS['cfg']['UploadDir']) |
||
1521 | ); |
||
1522 | |||
1523 | if ($files === false) { |
||
1524 | return '<span style="color:red">' . __('Error') . '</span><br />' . "\n" |
||
1525 | . __('The directory you set for upload work cannot be reached.') . "\n"; |
||
1526 | } elseif (!empty($files)) { |
||
1527 | return "<br />\n" |
||
1528 | . '<i>' . __('Or') . '</i>' . ' ' |
||
1529 | . __('web server upload directory:') . '<br />' . "\n" |
||
1530 | . '<select size="1" name="fields_uploadlocal' |
||
1531 | . $vkey . '[' . $column['Field_md5'] . ']">' . "\n" |
||
1532 | . '<option value="" selected="selected"></option>' . "\n" |
||
1533 | . $files |
||
1534 | . '</select>' . "\n"; |
||
1535 | } |
||
1536 | |||
1537 | return null; |
||
1538 | } |
||
1539 | |||
1540 | /** |
||
1541 | * Retrieve the maximum upload file size |
||
1542 | * |
||
1543 | * @param array $column description of column in given table |
||
1544 | * @param integer $biggest_max_file_size biggest max file size for uploading |
||
1545 | * |
||
1546 | * @return array an html snippet and $biggest_max_file_size |
||
1547 | */ |
||
1548 | private function getMaxUploadSize(array $column, $biggest_max_file_size) |
||
1549 | { |
||
1550 | // find maximum upload size, based on field type |
||
1551 | /** |
||
1552 | * @todo with functions this is not so easy, as you can basically |
||
1553 | * process any data with function like MD5 |
||
1554 | */ |
||
1555 | global $max_upload_size; |
||
1556 | $max_field_sizes = [ |
||
1557 | 'tinyblob' => '256', |
||
1558 | 'blob' => '65536', |
||
1559 | 'mediumblob' => '16777216', |
||
1560 | 'longblob' => '4294967296' // yeah, really |
||
1561 | ]; |
||
1562 | |||
1563 | $this_field_max_size = $max_upload_size; // from PHP max |
||
1564 | if ($this_field_max_size > $max_field_sizes[$column['pma_type']]) { |
||
1565 | $this_field_max_size = $max_field_sizes[$column['pma_type']]; |
||
1566 | } |
||
1567 | $html_output |
||
1568 | = Util::getFormattedMaximumUploadSize( |
||
1569 | $this_field_max_size |
||
1570 | ) . "\n"; |
||
1571 | // do not generate here the MAX_FILE_SIZE, because we should |
||
1572 | // put only one in the form to accommodate the biggest field |
||
1573 | if ($this_field_max_size > $biggest_max_file_size) { |
||
1574 | $biggest_max_file_size = $this_field_max_size; |
||
1575 | } |
||
1576 | return [$html_output, $biggest_max_file_size]; |
||
1577 | } |
||
1578 | |||
1579 | /** |
||
1580 | * Get HTML for the Value column of other datatypes |
||
1581 | * (here, "column" is used in the sense of HTML column in HTML table) |
||
1582 | * |
||
1583 | * @param array $column description of column in given table |
||
1584 | * @param string $default_char_editing default char editing mode which is stored |
||
1585 | * in the config.inc.php script |
||
1586 | * @param string $backup_field hidden input field |
||
1587 | * @param string $column_name_appendix the name attribute |
||
1588 | * @param string $onChangeClause onchange clause for fields |
||
1589 | * @param integer $tabindex tab index |
||
1590 | * @param string $special_chars special characters |
||
1591 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1592 | * @param integer $idindex id index |
||
1593 | * @param string $text_dir text direction |
||
1594 | * @param string $special_chars_encoded replaced char if the string starts |
||
1595 | * with a \r\n pair (0x0d0a) add an extra \n |
||
1596 | * @param string $data data to edit |
||
1597 | * @param array $extracted_columnspec associative array containing type, |
||
1598 | * spec_in_brackets and possibly |
||
1599 | * enum_set_values (another array) |
||
1600 | * @param boolean $readOnly is column read only or not |
||
1601 | * |
||
1602 | * @return string an html snippet |
||
1603 | */ |
||
1604 | private function getValueColumnForOtherDatatypes( |
||
1605 | array $column, |
||
1606 | $default_char_editing, |
||
1607 | $backup_field, |
||
1608 | $column_name_appendix, |
||
1609 | $onChangeClause, |
||
1610 | $tabindex, |
||
1611 | $special_chars, |
||
1612 | $tabindex_for_value, |
||
1613 | $idindex, |
||
1614 | $text_dir, |
||
1615 | $special_chars_encoded, |
||
1616 | $data, |
||
1617 | array $extracted_columnspec, |
||
1618 | $readOnly |
||
1619 | ) { |
||
1620 | // HTML5 data-* attribute data-type |
||
1621 | $data_type = $this->dbi->types->getTypeClass($column['True_Type']); |
||
1622 | $fieldsize = $this->getColumnSize($column, $extracted_columnspec); |
||
1623 | $html_output = $backup_field . "\n"; |
||
1624 | if ($column['is_char'] |
||
1625 | && ($GLOBALS['cfg']['CharEditing'] == 'textarea' |
||
1626 | || mb_strpos($data, "\n") !== false) |
||
1627 | ) { |
||
1628 | $html_output .= "\n"; |
||
1629 | $GLOBALS['cfg']['CharEditing'] = $default_char_editing; |
||
1630 | $html_output .= $this->getTextarea( |
||
1631 | $column, |
||
1632 | $backup_field, |
||
1633 | $column_name_appendix, |
||
1634 | $onChangeClause, |
||
1635 | $tabindex, |
||
1636 | $tabindex_for_value, |
||
1637 | $idindex, |
||
1638 | $text_dir, |
||
1639 | $special_chars_encoded, |
||
1640 | $data_type, |
||
1641 | $readOnly |
||
1642 | ); |
||
1643 | } else { |
||
1644 | $html_output .= $this->getHtmlInput( |
||
1645 | $column, |
||
1646 | $column_name_appendix, |
||
1647 | $special_chars, |
||
1648 | $fieldsize, |
||
1649 | $onChangeClause, |
||
1650 | $tabindex, |
||
1651 | $tabindex_for_value, |
||
1652 | $idindex, |
||
1653 | $data_type, |
||
1654 | $readOnly |
||
1655 | ); |
||
1656 | |||
1657 | $virtual = [ |
||
1658 | 'VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED' |
||
1659 | ]; |
||
1660 | if (in_array($column['Extra'], $virtual)) { |
||
1661 | $html_output .= '<input type="hidden" name="virtual' |
||
1662 | . $column_name_appendix . '" value="1" />'; |
||
1663 | } |
||
1664 | if ($column['Extra'] == 'auto_increment') { |
||
1665 | $html_output .= '<input type="hidden" name="auto_increment' |
||
1666 | . $column_name_appendix . '" value="1" />'; |
||
1667 | } |
||
1668 | if (substr($column['pma_type'], 0, 9) == 'timestamp') { |
||
1669 | $html_output .= '<input type="hidden" name="fields_type' |
||
1670 | . $column_name_appendix . '" value="timestamp" />'; |
||
1671 | } |
||
1672 | if (substr($column['pma_type'], 0, 8) == 'datetime') { |
||
1673 | $html_output .= '<input type="hidden" name="fields_type' |
||
1674 | . $column_name_appendix . '" value="datetime" />'; |
||
1675 | } |
||
1676 | if ($column['True_Type'] == 'bit') { |
||
1677 | $html_output .= '<input type="hidden" name="fields_type' |
||
1678 | . $column_name_appendix . '" value="bit" />'; |
||
1679 | } |
||
1680 | if ($column['pma_type'] == 'date' |
||
1681 | || $column['pma_type'] == 'datetime' |
||
1682 | || substr($column['pma_type'], 0, 9) == 'timestamp' |
||
1683 | ) { |
||
1684 | // the _3 suffix points to the date field |
||
1685 | // the _2 suffix points to the corresponding NULL checkbox |
||
1686 | // in dateFormat, 'yy' means the year with 4 digits |
||
1687 | } |
||
1688 | } |
||
1689 | return $html_output; |
||
1690 | } |
||
1691 | |||
1692 | /** |
||
1693 | * Get the field size |
||
1694 | * |
||
1695 | * @param array $column description of column in given table |
||
1696 | * @param array $extracted_columnspec associative array containing type, |
||
1697 | * spec_in_brackets and possibly enum_set_values |
||
1698 | * (another array) |
||
1699 | * |
||
1700 | * @return integer field size |
||
1701 | */ |
||
1702 | private function getColumnSize(array $column, array $extracted_columnspec) |
||
1703 | { |
||
1704 | if ($column['is_char']) { |
||
1705 | $fieldsize = $extracted_columnspec['spec_in_brackets']; |
||
1706 | if ($fieldsize > $GLOBALS['cfg']['MaxSizeForInputField']) { |
||
1707 | /** |
||
1708 | * This case happens for CHAR or VARCHAR columns which have |
||
1709 | * a size larger than the maximum size for input field. |
||
1710 | */ |
||
1711 | $GLOBALS['cfg']['CharEditing'] = 'textarea'; |
||
1712 | } |
||
1713 | } else { |
||
1714 | /** |
||
1715 | * This case happens for example for INT or DATE columns; |
||
1716 | * in these situations, the value returned in $column['len'] |
||
1717 | * seems appropriate. |
||
1718 | */ |
||
1719 | $fieldsize = $column['len']; |
||
1720 | } |
||
1721 | return min( |
||
1722 | max($fieldsize, $GLOBALS['cfg']['MinSizeForInputField']), |
||
1723 | $GLOBALS['cfg']['MaxSizeForInputField'] |
||
1724 | ); |
||
1725 | } |
||
1726 | |||
1727 | /** |
||
1728 | * Get HTML for gis data types |
||
1729 | * |
||
1730 | * @return string an html snippet |
||
1731 | */ |
||
1732 | private function getHtmlForGisDataTypes() |
||
1733 | { |
||
1734 | $edit_str = Util::getIcon('b_edit', __('Edit/Insert')); |
||
1735 | return '<span class="open_gis_editor">' |
||
1736 | . Util::linkOrButton( |
||
1737 | '#', |
||
1738 | $edit_str, |
||
1739 | [], |
||
1740 | '_blank' |
||
1741 | ) |
||
1742 | . '</span>'; |
||
1743 | } |
||
1744 | |||
1745 | /** |
||
1746 | * get html for continue insertion form |
||
1747 | * |
||
1748 | * @param string $table name of the table |
||
1749 | * @param string $db name of the database |
||
1750 | * @param array $where_clause_array array of where clauses |
||
1751 | * @param string $err_url error url |
||
1752 | * |
||
1753 | * @return string an html snippet |
||
1754 | */ |
||
1755 | public function getContinueInsertionForm( |
||
1756 | $table, |
||
1757 | $db, |
||
1758 | array $where_clause_array, |
||
1759 | $err_url |
||
1760 | ) { |
||
1761 | return $this->template->render('table/insert/continue_insertion_form', [ |
||
1762 | 'db' => $db, |
||
1763 | 'table' => $table, |
||
1764 | 'where_clause_array' => $where_clause_array, |
||
1765 | 'err_url' => $err_url, |
||
1766 | 'goto' => $GLOBALS['goto'], |
||
1767 | 'sql_query' => isset($_POST['sql_query']) ? $_POST['sql_query'] : null, |
||
1768 | 'has_where_clause' => isset($_REQUEST['where_clause']), |
||
1769 | 'insert_rows_default' => $GLOBALS['cfg']['InsertRows'], |
||
1770 | ]); |
||
1771 | } |
||
1772 | |||
1773 | /** |
||
1774 | * Get action panel |
||
1775 | * |
||
1776 | * @param array|null $where_clause where clause |
||
1777 | * @param string $after_insert insert mode, e.g. new_insert, same_insert |
||
1778 | * @param integer $tabindex tab index |
||
1779 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1780 | * @param boolean $found_unique_key boolean variable for unique key |
||
1781 | * |
||
1782 | * @return string an html snippet |
||
1783 | */ |
||
1784 | public function getActionsPanel( |
||
1785 | $where_clause, |
||
1786 | $after_insert, |
||
1787 | $tabindex, |
||
1788 | $tabindex_for_value, |
||
1789 | $found_unique_key |
||
1790 | ) { |
||
1791 | $html_output = '<fieldset id="actions_panel">' |
||
1792 | . '<table cellpadding="5" cellspacing="0" class="tdblock width100">' |
||
1793 | . '<tr>' |
||
1794 | . '<td class="nowrap vmiddle">' |
||
1795 | . $this->getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value) |
||
1796 | . "\n"; |
||
1797 | |||
1798 | $html_output .= '</td>' |
||
1799 | . '<td class="vmiddle">' |
||
1800 | . ' <strong>' |
||
1801 | . __('and then') . '</strong> ' |
||
1802 | . '</td>' |
||
1803 | . '<td class="nowrap vmiddle">' |
||
1804 | . $this->getAfterInsertDropDown( |
||
1805 | $where_clause, |
||
1806 | $after_insert, |
||
1807 | $found_unique_key |
||
1808 | ) |
||
1809 | . '</td>' |
||
1810 | . '</tr>'; |
||
1811 | $html_output .= '<tr>' |
||
1812 | . $this->getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) |
||
1813 | . '</tr>' |
||
1814 | . '</table>' |
||
1815 | . '</fieldset>'; |
||
1816 | return $html_output; |
||
1817 | } |
||
1818 | |||
1819 | /** |
||
1820 | * Get a HTML drop down for submit types |
||
1821 | * |
||
1822 | * @param array|null $where_clause where clause |
||
1823 | * @param integer $tabindex tab index |
||
1824 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1825 | * |
||
1826 | * @return string an html snippet |
||
1827 | */ |
||
1828 | private function getSubmitTypeDropDown( |
||
1829 | $where_clause, |
||
1830 | $tabindex, |
||
1831 | $tabindex_for_value |
||
1832 | ) { |
||
1833 | $html_output = '<select name="submit_type" class="control_at_footer" tabindex="' |
||
1834 | . ($tabindex + $tabindex_for_value + 1) . '">'; |
||
1835 | if (isset($where_clause)) { |
||
1836 | $html_output .= '<option value="save">' . __('Save') . '</option>'; |
||
1837 | } |
||
1838 | $html_output .= '<option value="insert">' |
||
1839 | . __('Insert as new row') |
||
1840 | . '</option>' |
||
1841 | . '<option value="insertignore">' |
||
1842 | . __('Insert as new row and ignore errors') |
||
1843 | . '</option>' |
||
1844 | . '<option value="showinsert">' |
||
1845 | . __('Show insert query') |
||
1846 | . '</option>' |
||
1847 | . '</select>'; |
||
1848 | return $html_output; |
||
1849 | } |
||
1850 | |||
1851 | /** |
||
1852 | * Get HTML drop down for after insert |
||
1853 | * |
||
1854 | * @param array|null $where_clause where clause |
||
1855 | * @param string $after_insert insert mode, e.g. new_insert, same_insert |
||
1856 | * @param boolean $found_unique_key boolean variable for unique key |
||
1857 | * |
||
1858 | * @return string an html snippet |
||
1859 | */ |
||
1860 | private function getAfterInsertDropDown($where_clause, $after_insert, $found_unique_key) |
||
1861 | { |
||
1862 | $html_output = '<select name="after_insert" class="control_at_footer">' |
||
1863 | . '<option value="back" ' |
||
1864 | . ($after_insert == 'back' ? 'selected="selected"' : '') . '>' |
||
1865 | . __('Go back to previous page') . '</option>' |
||
1866 | . '<option value="new_insert" ' |
||
1867 | . ($after_insert == 'new_insert' ? 'selected="selected"' : '') . '>' |
||
1868 | . __('Insert another new row') . '</option>'; |
||
1869 | |||
1870 | if (isset($where_clause)) { |
||
1871 | $html_output .= '<option value="same_insert" ' |
||
1872 | . ($after_insert == 'same_insert' ? 'selected="selected"' : '') . '>' |
||
1873 | . __('Go back to this page') . '</option>'; |
||
1874 | |||
1875 | // If we have just numeric primary key, we can also edit next |
||
1876 | // in 2.8.2, we were looking for `field_name` = numeric_value |
||
1877 | //if (preg_match('@^[\s]*`[^`]*` = [0-9]+@', $where_clause)) { |
||
1878 | // in 2.9.0, we are looking for `table_name`.`field_name` = numeric_value |
||
1879 | $is_numeric = false; |
||
1880 | if (! is_array($where_clause)) { |
||
1881 | $where_clause = [$where_clause]; |
||
1882 | } |
||
1883 | for ($i = 0, $nb = count($where_clause); $i < $nb; $i++) { |
||
1884 | // preg_match() returns 1 if there is a match |
||
1885 | $is_numeric = (preg_match( |
||
1886 | '@^[\s]*`[^`]*`[\.]`[^`]*` = [0-9]+@', |
||
1887 | $where_clause[$i] |
||
1888 | ) == 1); |
||
1889 | if ($is_numeric === true) { |
||
1890 | break; |
||
1891 | } |
||
1892 | } |
||
1893 | if ($found_unique_key && $is_numeric) { |
||
1894 | $html_output .= '<option value="edit_next" ' |
||
1895 | . ($after_insert == 'edit_next' ? 'selected="selected"' : '') . '>' |
||
1896 | . __('Edit next row') . '</option>'; |
||
1897 | } |
||
1898 | } |
||
1899 | $html_output .= '</select>'; |
||
1900 | return $html_output; |
||
1901 | } |
||
1902 | |||
1903 | /** |
||
1904 | * get Submit button and Reset button for action panel |
||
1905 | * |
||
1906 | * @param integer $tabindex tab index |
||
1907 | * @param integer $tabindex_for_value offset for the values tabindex |
||
1908 | * |
||
1909 | * @return string an html snippet |
||
1910 | */ |
||
1911 | private function getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) |
||
1912 | { |
||
1913 | return '<td>' |
||
1914 | . Util::showHint( |
||
1915 | __( |
||
1916 | 'Use TAB key to move from value to value,' |
||
1917 | . ' or CTRL+arrows to move anywhere.' |
||
1918 | ) |
||
1919 | ) |
||
1920 | . '</td>' |
||
1921 | . '<td colspan="3" class="right vmiddle">' |
||
1922 | . '<input type="button" class="preview_sql" value="' . __('Preview SQL') . '"' |
||
1923 | . ' tabindex="' . ($tabindex + $tabindex_for_value + 6) . '" />' |
||
1924 | . '<input type="reset" class="control_at_footer" value="' . __('Reset') . '"' |
||
1925 | . ' tabindex="' . ($tabindex + $tabindex_for_value + 7) . '" />' |
||
1926 | . '<input type="submit" class="control_at_footer" value="' . __('Go') . '"' |
||
1927 | . ' tabindex="' . ($tabindex + $tabindex_for_value + 8) . '" id="buttonYes" />' |
||
1928 | . '</td>'; |
||
1929 | } |
||
1930 | |||
1931 | /** |
||
1932 | * Get table head and table foot for insert row table |
||
1933 | * |
||
1934 | * @param array $url_params url parameters |
||
1935 | * |
||
1936 | * @return string an html snippet |
||
1937 | */ |
||
1938 | private function getHeadAndFootOfInsertRowTable(array $url_params) |
||
1939 | { |
||
1940 | $html_output = '<div class="responsivetable">' |
||
1941 | . '<table class="insertRowTable topmargin">' |
||
1942 | . '<thead>' |
||
1943 | . '<tr>' |
||
1944 | . '<th>' . __('Column') . '</th>'; |
||
1945 | |||
1946 | if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { |
||
1947 | $html_output .= $this->showTypeOrFunction('type', $url_params, true); |
||
1948 | } |
||
1949 | if ($GLOBALS['cfg']['ShowFunctionFields']) { |
||
1950 | $html_output .= $this->showTypeOrFunction('function', $url_params, true); |
||
1951 | } |
||
1952 | |||
1953 | $html_output .= '<th>' . __('Null') . '</th>' |
||
1954 | . '<th class="fillPage">' . __('Value') . '</th>' |
||
1955 | . '</tr>' |
||
1956 | . '</thead>' |
||
1957 | . ' <tfoot>' |
||
1958 | . '<tr>' |
||
1959 | . '<th colspan="5" class="tblFooters right">' |
||
1960 | . '<input type="submit" value="' . __('Go') . '" />' |
||
1961 | . '</th>' |
||
1962 | . '</tr>' |
||
1963 | . '</tfoot>'; |
||
1964 | return $html_output; |
||
1965 | } |
||
1966 | |||
1967 | /** |
||
1968 | * Prepares the field value and retrieve special chars, backup field and data array |
||
1969 | * |
||
1970 | * @param array $current_row a row of the table |
||
1971 | * @param array $column description of column in given table |
||
1972 | * @param array $extracted_columnspec associative array containing type, |
||
1973 | * spec_in_brackets and possibly |
||
1974 | * enum_set_values (another array) |
||
1975 | * @param boolean $real_null_value whether column value null or not null |
||
1976 | * @param array $gis_data_types list of GIS data types |
||
1977 | * @param string $column_name_appendix string to append to column name in input |
||
1978 | * @param bool $as_is use the data as is, used in repopulating |
||
1979 | * |
||
1980 | * @return array $real_null_value, $data, $special_chars, $backup_field, |
||
1981 | * $special_chars_encoded |
||
1982 | */ |
||
1983 | private function getSpecialCharsAndBackupFieldForExistingRow( |
||
1984 | array $current_row, |
||
1985 | array $column, |
||
1986 | array $extracted_columnspec, |
||
1987 | $real_null_value, |
||
1988 | array $gis_data_types, |
||
1989 | $column_name_appendix, |
||
1990 | $as_is |
||
1991 | ) { |
||
1992 | $special_chars_encoded = ''; |
||
1993 | $data = null; |
||
1994 | // (we are editing) |
||
1995 | if (!isset($current_row[$column['Field']])) { |
||
1996 | $real_null_value = true; |
||
1997 | $current_row[$column['Field']] = ''; |
||
1998 | $special_chars = ''; |
||
1999 | $data = $current_row[$column['Field']]; |
||
2000 | } elseif ($column['True_Type'] == 'bit') { |
||
2001 | $special_chars = $as_is |
||
2002 | ? $current_row[$column['Field']] |
||
2003 | : Util::printableBitValue( |
||
2004 | (int) $current_row[$column['Field']], |
||
2005 | (int) $extracted_columnspec['spec_in_brackets'] |
||
2006 | ); |
||
2007 | } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp' |
||
2008 | || $column['True_Type'] == 'datetime' |
||
2009 | || $column['True_Type'] == 'time') |
||
2010 | && (mb_strpos($current_row[$column['Field']], ".") !== false) |
||
2011 | ) { |
||
2012 | $current_row[$column['Field']] = $as_is |
||
2013 | ? $current_row[$column['Field']] |
||
2014 | : Util::addMicroseconds( |
||
2015 | $current_row[$column['Field']] |
||
2016 | ); |
||
2017 | $special_chars = htmlspecialchars($current_row[$column['Field']]); |
||
2018 | } elseif (in_array($column['True_Type'], $gis_data_types)) { |
||
2019 | // Convert gis data to Well Know Text format |
||
2020 | $current_row[$column['Field']] = $as_is |
||
2021 | ? $current_row[$column['Field']] |
||
2022 | : Util::asWKT( |
||
2023 | $current_row[$column['Field']], |
||
2024 | true |
||
2025 | ); |
||
2026 | $special_chars = htmlspecialchars($current_row[$column['Field']]); |
||
2027 | } else { |
||
2028 | // special binary "characters" |
||
2029 | if ($column['is_binary'] |
||
2030 | || ($column['is_blob'] && $GLOBALS['cfg']['ProtectBinary'] !== 'all') |
||
2031 | ) { |
||
2032 | $current_row[$column['Field']] = $as_is |
||
2033 | ? $current_row[$column['Field']] |
||
2034 | : bin2hex( |
||
2035 | $current_row[$column['Field']] |
||
2036 | ); |
||
2037 | } // end if |
||
2038 | $special_chars = htmlspecialchars($current_row[$column['Field']]); |
||
2039 | |||
2040 | //We need to duplicate the first \n or otherwise we will lose |
||
2041 | //the first newline entered in a VARCHAR or TEXT column |
||
2042 | $special_chars_encoded |
||
2043 | = Util::duplicateFirstNewline($special_chars); |
||
2044 | |||
2045 | $data = $current_row[$column['Field']]; |
||
2046 | } // end if... else... |
||
2047 | |||
2048 | //when copying row, it is useful to empty auto-increment column |
||
2049 | // to prevent duplicate key error |
||
2050 | if (isset($_REQUEST['default_action']) |
||
2051 | && $_REQUEST['default_action'] === 'insert' |
||
2052 | ) { |
||
2053 | if ($column['Key'] === 'PRI' |
||
2054 | && mb_strpos($column['Extra'], 'auto_increment') !== false |
||
2055 | ) { |
||
2056 | $data = $special_chars_encoded = $special_chars = null; |
||
2057 | } |
||
2058 | } |
||
2059 | // If a timestamp field value is not included in an update |
||
2060 | // statement MySQL auto-update it to the current timestamp; |
||
2061 | // however, things have changed since MySQL 4.1, so |
||
2062 | // it's better to set a fields_prev in this situation |
||
2063 | $backup_field = '<input type="hidden" name="fields_prev' |
||
2064 | . $column_name_appendix . '" value="' |
||
2065 | . htmlspecialchars($current_row[$column['Field']]) . '" />'; |
||
2066 | |||
2067 | return [ |
||
2068 | $real_null_value, |
||
2069 | $special_chars_encoded, |
||
2070 | $special_chars, |
||
2071 | $data, |
||
2072 | $backup_field |
||
2073 | ]; |
||
2074 | } |
||
2075 | |||
2076 | /** |
||
2077 | * display default values |
||
2078 | * |
||
2079 | * @param array $column description of column in given table |
||
2080 | * @param boolean $real_null_value whether column value null or not null |
||
2081 | * |
||
2082 | * @return array $real_null_value, $data, $special_chars, |
||
2083 | * $backup_field, $special_chars_encoded |
||
2084 | */ |
||
2085 | private function getSpecialCharsAndBackupFieldForInsertingMode( |
||
2086 | array $column, |
||
2087 | $real_null_value |
||
2088 | ) { |
||
2089 | if (! isset($column['Default'])) { |
||
2090 | $column['Default'] = ''; |
||
2091 | $real_null_value = true; |
||
2092 | $data = ''; |
||
2093 | } else { |
||
2094 | $data = $column['Default']; |
||
2095 | } |
||
2096 | |||
2097 | $trueType = $column['True_Type']; |
||
2098 | |||
2099 | if ($trueType == 'bit') { |
||
2100 | $special_chars = Util::convertBitDefaultValue( |
||
2101 | $column['Default'] |
||
2102 | ); |
||
2103 | } elseif (substr($trueType, 0, 9) == 'timestamp' |
||
2104 | || $trueType == 'datetime' |
||
2105 | || $trueType == 'time' |
||
2106 | ) { |
||
2107 | $special_chars = Util::addMicroseconds($column['Default']); |
||
2108 | } elseif ($trueType == 'binary' || $trueType == 'varbinary') { |
||
2109 | $special_chars = bin2hex($column['Default']); |
||
2110 | } else { |
||
2111 | $special_chars = htmlspecialchars($column['Default']); |
||
2112 | } |
||
2113 | $backup_field = ''; |
||
2114 | $special_chars_encoded = Util::duplicateFirstNewline( |
||
2115 | $special_chars |
||
2116 | ); |
||
2117 | return [ |
||
2118 | $real_null_value, $data, $special_chars, |
||
2119 | $backup_field, $special_chars_encoded |
||
2120 | ]; |
||
2121 | } |
||
2122 | |||
2123 | /** |
||
2124 | * Prepares the update/insert of a row |
||
2125 | * |
||
2126 | * @return array $loop_array, $using_key, $is_insert, $is_insertignore |
||
2127 | */ |
||
2128 | public function getParamsForUpdateOrInsert() |
||
2129 | { |
||
2130 | if (isset($_REQUEST['where_clause'])) { |
||
2131 | // we were editing something => use the WHERE clause |
||
2132 | $loop_array = is_array($_REQUEST['where_clause']) |
||
2133 | ? $_REQUEST['where_clause'] |
||
2134 | : [$_REQUEST['where_clause']]; |
||
2135 | $using_key = true; |
||
2136 | $is_insert = isset($_REQUEST['submit_type']) |
||
2137 | && ($_REQUEST['submit_type'] == 'insert' |
||
2138 | || $_REQUEST['submit_type'] == 'showinsert' |
||
2139 | || $_REQUEST['submit_type'] == 'insertignore'); |
||
2140 | } else { |
||
2141 | // new row => use indexes |
||
2142 | $loop_array = []; |
||
2143 | if (! empty($_REQUEST['fields'])) { |
||
2144 | foreach ($_REQUEST['fields']['multi_edit'] as $key => $dummy) { |
||
2145 | $loop_array[] = $key; |
||
2146 | } |
||
2147 | } |
||
2148 | $using_key = false; |
||
2149 | $is_insert = true; |
||
2150 | } |
||
2151 | $is_insertignore = isset($_REQUEST['submit_type']) |
||
2152 | && $_REQUEST['submit_type'] == 'insertignore'; |
||
2153 | return [$loop_array, $using_key, $is_insert, $is_insertignore]; |
||
2154 | } |
||
2155 | |||
2156 | /** |
||
2157 | * Check wether insert row mode and if so include tbl_changen script and set |
||
2158 | * global variables. |
||
2159 | * |
||
2160 | * @return void |
||
2161 | */ |
||
2162 | public function isInsertRow() |
||
2163 | { |
||
2164 | if (isset($_REQUEST['insert_rows']) |
||
2165 | && is_numeric($_REQUEST['insert_rows']) |
||
2166 | && $_REQUEST['insert_rows'] != $GLOBALS['cfg']['InsertRows'] |
||
2167 | ) { |
||
2168 | $GLOBALS['cfg']['InsertRows'] = $_REQUEST['insert_rows']; |
||
2169 | $response = Response::getInstance(); |
||
2170 | $header = $response->getHeader(); |
||
2171 | $scripts = $header->getScripts(); |
||
2172 | $scripts->addFile('vendor/jquery/additional-methods.js'); |
||
2173 | $scripts->addFile('tbl_change.js'); |
||
2174 | if (!defined('TESTSUITE')) { |
||
2175 | include 'tbl_change.php'; |
||
2176 | exit; |
||
2177 | } |
||
2178 | } |
||
2179 | } |
||
2180 | |||
2181 | /** |
||
2182 | * set $_SESSION for edit_next |
||
2183 | * |
||
2184 | * @param string $one_where_clause one where clause from where clauses array |
||
2185 | * |
||
2186 | * @return void |
||
2187 | */ |
||
2188 | public function setSessionForEditNext($one_where_clause) |
||
2189 | { |
||
2190 | $local_query = 'SELECT * FROM ' . Util::backquote($GLOBALS['db']) |
||
2191 | . '.' . Util::backquote($GLOBALS['table']) . ' WHERE ' |
||
2192 | . str_replace('` =', '` >', $one_where_clause) . ' LIMIT 1;'; |
||
2193 | |||
2194 | $res = $this->dbi->query($local_query); |
||
2195 | $row = $this->dbi->fetchRow($res); |
||
2196 | $meta = $this->dbi->getFieldsMeta($res); |
||
2197 | // must find a unique condition based on unique key, |
||
2198 | // not a combination of all fields |
||
2199 | list($unique_condition, $clause_is_unique) |
||
2200 | = Util::getUniqueCondition( |
||
2201 | $res, // handle |
||
2202 | count($meta), // fields_cnt |
||
2203 | $meta, // fields_meta |
||
2204 | $row, // row |
||
2205 | true, // force_unique |
||
2206 | false, // restrict_to_table |
||
2207 | null // analyzed_sql_results |
||
2208 | ); |
||
2209 | if (! empty($unique_condition)) { |
||
2210 | $_SESSION['edit_next'] = $unique_condition; |
||
2211 | } |
||
2212 | unset($unique_condition, $clause_is_unique); |
||
2213 | } |
||
2214 | |||
2215 | /** |
||
2216 | * set $goto_include variable for different cases and retrieve like, |
||
2217 | * if $GLOBALS['goto'] empty, if $goto_include previously not defined |
||
2218 | * and new_insert, same_insert, edit_next |
||
2219 | * |
||
2220 | * @param string $goto_include store some script for include, otherwise it is |
||
2221 | * boolean false |
||
2222 | * |
||
2223 | * @return string |
||
2224 | */ |
||
2225 | public function getGotoInclude($goto_include) |
||
2226 | { |
||
2227 | $valid_options = ['new_insert', 'same_insert', 'edit_next']; |
||
2228 | if (isset($_REQUEST['after_insert']) |
||
2229 | && in_array($_REQUEST['after_insert'], $valid_options) |
||
2230 | ) { |
||
2231 | $goto_include = 'tbl_change.php'; |
||
2232 | } elseif (! empty($GLOBALS['goto'])) { |
||
2233 | if (! preg_match('@^[a-z_]+\.php$@', $GLOBALS['goto'])) { |
||
2234 | // this should NOT happen |
||
2235 | //$GLOBALS['goto'] = false; |
||
2236 | $goto_include = false; |
||
2237 | } else { |
||
2238 | $goto_include = $GLOBALS['goto']; |
||
2239 | } |
||
2240 | if ($GLOBALS['goto'] == 'db_sql.php' && strlen($GLOBALS['table']) > 0) { |
||
2241 | $GLOBALS['table'] = ''; |
||
2242 | } |
||
2243 | } |
||
2244 | if (! $goto_include) { |
||
2245 | if (strlen($GLOBALS['table']) === 0) { |
||
2246 | $goto_include = 'db_sql.php'; |
||
2247 | } else { |
||
2248 | $goto_include = 'tbl_sql.php'; |
||
2249 | } |
||
2250 | } |
||
2251 | return $goto_include; |
||
2252 | } |
||
2253 | |||
2254 | /** |
||
2255 | * Defines the url to return in case of failure of the query |
||
2256 | * |
||
2257 | * @param array $url_params url parameters |
||
2258 | * |
||
2259 | * @return string error url for query failure |
||
2260 | */ |
||
2261 | public function getErrorUrl(array $url_params) |
||
2262 | { |
||
2263 | if (isset($_REQUEST['err_url'])) { |
||
2264 | return $_REQUEST['err_url']; |
||
2265 | } |
||
2266 | |||
2267 | return 'tbl_change.php' . Url::getCommon($url_params); |
||
2268 | } |
||
2269 | |||
2270 | /** |
||
2271 | * Builds the sql query |
||
2272 | * |
||
2273 | * @param boolean $is_insertignore $_REQUEST['submit_type'] == 'insertignore' |
||
2274 | * @param array $query_fields column names array |
||
2275 | * @param array $value_sets array of query values |
||
2276 | * |
||
2277 | * @return array of query |
||
2278 | */ |
||
2279 | public function buildSqlQuery($is_insertignore, array $query_fields, array $value_sets) |
||
2280 | { |
||
2281 | if ($is_insertignore) { |
||
2282 | $insert_command = 'INSERT IGNORE '; |
||
2283 | } else { |
||
2284 | $insert_command = 'INSERT '; |
||
2285 | } |
||
2286 | $query = [ |
||
2287 | $insert_command . 'INTO ' |
||
2288 | . Util::backquote($GLOBALS['table']) |
||
2289 | . ' (' . implode(', ', $query_fields) . ') VALUES (' |
||
2290 | . implode('), (', $value_sets) . ')' |
||
2291 | ]; |
||
2292 | unset($insert_command, $query_fields); |
||
2293 | return $query; |
||
2294 | } |
||
2295 | |||
2296 | /** |
||
2297 | * Executes the sql query and get the result, then move back to the calling page |
||
2298 | * |
||
2299 | * @param array $url_params url parameters array |
||
2300 | * @param array $query built query from buildSqlQuery() |
||
2301 | * |
||
2302 | * @return array $url_params, $total_affected_rows, $last_messages |
||
2303 | * $warning_messages, $error_messages, $return_to_sql_query |
||
2304 | */ |
||
2305 | public function executeSqlQuery(array $url_params, array $query) |
||
2306 | { |
||
2307 | $return_to_sql_query = ''; |
||
2308 | if (! empty($GLOBALS['sql_query'])) { |
||
2309 | $url_params['sql_query'] = $GLOBALS['sql_query']; |
||
2310 | $return_to_sql_query = $GLOBALS['sql_query']; |
||
2311 | } |
||
2312 | $GLOBALS['sql_query'] = implode('; ', $query) . ';'; |
||
2313 | // to ensure that the query is displayed in case of |
||
2314 | // "insert as new row" and then "insert another new row" |
||
2315 | $GLOBALS['display_query'] = $GLOBALS['sql_query']; |
||
2316 | |||
2317 | $total_affected_rows = 0; |
||
2318 | $last_messages = []; |
||
2319 | $warning_messages = []; |
||
2320 | $error_messages = []; |
||
2321 | |||
2322 | foreach ($query as $single_query) { |
||
2323 | if ($_REQUEST['submit_type'] == 'showinsert') { |
||
2324 | $last_messages[] = Message::notice(__('Showing SQL query')); |
||
2325 | continue; |
||
2326 | } |
||
2327 | if ($GLOBALS['cfg']['IgnoreMultiSubmitErrors']) { |
||
2328 | $result = $this->dbi->tryQuery($single_query); |
||
2329 | } else { |
||
2330 | $result = $this->dbi->query($single_query); |
||
2331 | } |
||
2332 | if (! $result) { |
||
2333 | $error_messages[] = $this->dbi->getError(); |
||
2334 | } else { |
||
2335 | // The next line contains a real assignment, it's not a typo |
||
2336 | if ($tmp = @$this->dbi->affectedRows()) { |
||
2337 | $total_affected_rows += $tmp; |
||
2338 | } |
||
2339 | unset($tmp); |
||
2340 | |||
2341 | $insert_id = $this->dbi->insertId(); |
||
2342 | if ($insert_id != 0) { |
||
2343 | // insert_id is id of FIRST record inserted in one insert, so if we |
||
2344 | // inserted multiple rows, we had to increment this |
||
2345 | |||
2346 | if ($total_affected_rows > 0) { |
||
2347 | $insert_id = $insert_id + $total_affected_rows - 1; |
||
2348 | } |
||
2349 | $last_message = Message::notice(__('Inserted row id: %1$d')); |
||
2350 | $last_message->addParam($insert_id); |
||
2351 | $last_messages[] = $last_message; |
||
2352 | } |
||
2353 | $this->dbi->freeResult($result); |
||
2354 | } |
||
2355 | $warning_messages = $this->getWarningMessages(); |
||
2356 | } |
||
2357 | return [ |
||
2358 | $url_params, |
||
2359 | $total_affected_rows, |
||
2360 | $last_messages, |
||
2361 | $warning_messages, |
||
2362 | $error_messages, |
||
2363 | $return_to_sql_query |
||
2364 | ]; |
||
2365 | } |
||
2366 | |||
2367 | /** |
||
2368 | * get the warning messages array |
||
2369 | * |
||
2370 | * @return array |
||
2371 | */ |
||
2372 | private function getWarningMessages() |
||
2373 | { |
||
2374 | $warning_essages = []; |
||
2375 | foreach ($this->dbi->getWarnings() as $warning) { |
||
2376 | $warning_essages[] = Message::sanitize( |
||
2377 | $warning['Level'] . ': #' . $warning['Code'] . ' ' . $warning['Message'] |
||
2378 | ); |
||
2379 | } |
||
2380 | return $warning_essages; |
||
2381 | } |
||
2382 | |||
2383 | /** |
||
2384 | * Column to display from the foreign table? |
||
2385 | * |
||
2386 | * @param string $where_comparison string that contain relation field value |
||
2387 | * @param array $map all Relations to foreign tables for a given |
||
2388 | * table or optionally a given column in a table |
||
2389 | * @param string $relation_field relation field |
||
2390 | * |
||
2391 | * @return string display value from the foreign table |
||
2392 | */ |
||
2393 | public function getDisplayValueForForeignTableColumn( |
||
2394 | $where_comparison, |
||
2395 | array $map, |
||
2396 | $relation_field |
||
2397 | ) { |
||
2398 | $foreigner = $this->relation->searchColumnInForeigners($map, $relation_field); |
||
2399 | $display_field = $this->relation->getDisplayField( |
||
2400 | $foreigner['foreign_db'], |
||
2401 | $foreigner['foreign_table'] |
||
2402 | ); |
||
2403 | // Field to display from the foreign table? |
||
2404 | if (! is_null($display_field) && strlen($display_field) > 0) { |
||
2405 | $dispsql = 'SELECT ' . Util::backquote($display_field) |
||
2406 | . ' FROM ' . Util::backquote($foreigner['foreign_db']) |
||
2407 | . '.' . Util::backquote($foreigner['foreign_table']) |
||
2408 | . ' WHERE ' . Util::backquote($foreigner['foreign_field']) |
||
2409 | . $where_comparison; |
||
2410 | $dispresult = $this->dbi->tryQuery( |
||
2411 | $dispsql, |
||
2412 | DatabaseInterface::CONNECT_USER, |
||
2413 | DatabaseInterface::QUERY_STORE |
||
2414 | ); |
||
2415 | if ($dispresult && $this->dbi->numRows($dispresult) > 0) { |
||
2416 | list($dispval) = $this->dbi->fetchRow($dispresult); |
||
2417 | } else { |
||
2418 | $dispval = ''; |
||
2419 | } |
||
2420 | if ($dispresult) { |
||
2421 | $this->dbi->freeResult($dispresult); |
||
2422 | } |
||
2423 | return $dispval; |
||
2424 | } |
||
2425 | return ''; |
||
2426 | } |
||
2427 | |||
2428 | /** |
||
2429 | * Display option in the cell according to user choices |
||
2430 | * |
||
2431 | * @param array $map all Relations to foreign tables for a given |
||
2432 | * table or optionally a given column in a table |
||
2433 | * @param string $relation_field relation field |
||
2434 | * @param string $where_comparison string that contain relation field value |
||
2435 | * @param string $dispval display value from the foreign table |
||
2436 | * @param string $relation_field_value relation field value |
||
2437 | * |
||
2438 | * @return string HTML <a> tag |
||
2439 | */ |
||
2440 | public function getLinkForRelationalDisplayField( |
||
2441 | array $map, |
||
2442 | $relation_field, |
||
2443 | $where_comparison, |
||
2444 | $dispval, |
||
2445 | $relation_field_value |
||
2446 | ) { |
||
2447 | $foreigner = $this->relation->searchColumnInForeigners($map, $relation_field); |
||
2448 | if ('K' == $_SESSION['tmpval']['relational_display']) { |
||
2449 | // user chose "relational key" in the display options, so |
||
2450 | // the title contains the display field |
||
2451 | $title = (! empty($dispval)) |
||
2452 | ? ' title="' . htmlspecialchars($dispval) . '"' |
||
2453 | : ''; |
||
2454 | } else { |
||
2455 | $title = ' title="' . htmlspecialchars($relation_field_value) . '"'; |
||
2456 | } |
||
2457 | $_url_params = [ |
||
2458 | 'db' => $foreigner['foreign_db'], |
||
2459 | 'table' => $foreigner['foreign_table'], |
||
2460 | 'pos' => '0', |
||
2461 | 'sql_query' => 'SELECT * FROM ' |
||
2462 | . Util::backquote($foreigner['foreign_db']) |
||
2463 | . '.' . Util::backquote($foreigner['foreign_table']) |
||
2464 | . ' WHERE ' . Util::backquote($foreigner['foreign_field']) |
||
2465 | . $where_comparison |
||
2466 | ]; |
||
2467 | $output = '<a href="sql.php' |
||
2468 | . Url::getCommon($_url_params) . '"' . $title . '>'; |
||
2469 | |||
2470 | if ('D' == $_SESSION['tmpval']['relational_display']) { |
||
2471 | // user chose "relational display field" in the |
||
2472 | // display options, so show display field in the cell |
||
2473 | $output .= (!empty($dispval)) ? htmlspecialchars($dispval) : ''; |
||
2474 | } else { |
||
2475 | // otherwise display data in the cell |
||
2476 | $output .= htmlspecialchars($relation_field_value); |
||
2477 | } |
||
2478 | $output .= '</a>'; |
||
2479 | return $output; |
||
2480 | } |
||
2481 | |||
2482 | /** |
||
2483 | * Transform edited values |
||
2484 | * |
||
2485 | * @param string $db db name |
||
2486 | * @param string $table table name |
||
2487 | * @param array $transformation mimetypes for all columns of a table |
||
2488 | * [field_name][field_key] |
||
2489 | * @param array &$edited_values transform columns list and new values |
||
2490 | * @param string $file file containing the transformation plugin |
||
2491 | * @param string $column_name column name |
||
2492 | * @param array $extra_data extra data array |
||
2493 | * @param string $type the type of transformation |
||
2494 | * |
||
2495 | * @return array |
||
2496 | */ |
||
2497 | public function transformEditedValues( |
||
2498 | $db, |
||
2499 | $table, |
||
2500 | array $transformation, |
||
2501 | array &$edited_values, |
||
2502 | $file, |
||
2503 | $column_name, |
||
2504 | array $extra_data, |
||
2505 | $type |
||
2506 | ) { |
||
2507 | $include_file = 'libraries/classes/Plugins/Transformations/' . $file; |
||
2508 | if (is_file($include_file)) { |
||
2509 | include_once $include_file; |
||
2510 | $_url_params = [ |
||
2511 | 'db' => $db, |
||
2512 | 'table' => $table, |
||
2513 | 'where_clause' => $_REQUEST['where_clause'], |
||
2514 | 'transform_key' => $column_name |
||
2515 | ]; |
||
2516 | $transform_options = $this->transformations->getOptions( |
||
2517 | isset($transformation[$type . '_options']) |
||
2518 | ? $transformation[$type . '_options'] |
||
2519 | : '' |
||
2520 | ); |
||
2521 | $transform_options['wrapper_link'] = Url::getCommon($_url_params); |
||
2522 | $class_name = $this->transformations->getClassName($include_file); |
||
2523 | /** @var TransformationsPlugin $transformation_plugin */ |
||
2524 | $transformation_plugin = new $class_name(); |
||
2525 | |||
2526 | foreach ($edited_values as $cell_index => $curr_cell_edited_values) { |
||
2527 | if (isset($curr_cell_edited_values[$column_name])) { |
||
2528 | $edited_values[$cell_index][$column_name] |
||
2529 | = $extra_data['transformations'][$cell_index] |
||
2530 | = $transformation_plugin->applyTransformation( |
||
2531 | $curr_cell_edited_values[$column_name], |
||
2532 | $transform_options |
||
2533 | ); |
||
2534 | } |
||
2535 | } // end of loop for each transformation cell |
||
2536 | } |
||
2537 | return $extra_data; |
||
2538 | } |
||
2539 | |||
2540 | /** |
||
2541 | * Get current value in multi edit mode |
||
2542 | * |
||
2543 | * @param array $multi_edit_funcs multiple edit functions array |
||
2544 | * @param array $multi_edit_salt multiple edit array with encryption salt |
||
2545 | * @param array $gis_from_text_functions array that contains gis from text functions |
||
2546 | * @param string $current_value current value in the column |
||
2547 | * @param array $gis_from_wkb_functions initially $val is $multi_edit_columns[$key] |
||
2548 | * @param array $func_optional_param array('RAND','UNIX_TIMESTAMP') |
||
2549 | * @param array $func_no_param array of set of string |
||
2550 | * @param string $key an md5 of the column name |
||
2551 | * |
||
2552 | * @return array |
||
2553 | */ |
||
2554 | public function getCurrentValueAsAnArrayForMultipleEdit( |
||
2555 | $multi_edit_funcs, |
||
2556 | $multi_edit_salt, |
||
2557 | $gis_from_text_functions, |
||
2558 | $current_value, |
||
2559 | $gis_from_wkb_functions, |
||
2560 | $func_optional_param, |
||
2561 | $func_no_param, |
||
2562 | $key |
||
2563 | ) { |
||
2564 | if (empty($multi_edit_funcs[$key])) { |
||
2565 | return $current_value; |
||
2566 | } elseif ('UUID' === $multi_edit_funcs[$key]) { |
||
2567 | /* This way user will know what UUID new row has */ |
||
2568 | $uuid = $this->dbi->fetchValue('SELECT UUID()'); |
||
2569 | return "'" . $uuid . "'"; |
||
2570 | } elseif ((in_array($multi_edit_funcs[$key], $gis_from_text_functions) |
||
2571 | && substr($current_value, 0, 3) == "'''") |
||
2572 | || in_array($multi_edit_funcs[$key], $gis_from_wkb_functions) |
||
2573 | ) { |
||
2574 | // Remove enclosing apostrophes |
||
2575 | $current_value = mb_substr($current_value, 1, -1); |
||
2576 | // Remove escaping apostrophes |
||
2577 | $current_value = str_replace("''", "'", $current_value); |
||
2578 | return $multi_edit_funcs[$key] . '(' . $current_value . ')'; |
||
2579 | } elseif (! in_array($multi_edit_funcs[$key], $func_no_param) |
||
2580 | || ($current_value != "''" |
||
2581 | && in_array($multi_edit_funcs[$key], $func_optional_param)) |
||
2582 | ) { |
||
2583 | if ((isset($multi_edit_salt[$key]) |
||
2584 | && ($multi_edit_funcs[$key] == "AES_ENCRYPT" |
||
2585 | || $multi_edit_funcs[$key] == "AES_DECRYPT")) |
||
2586 | || (! empty($multi_edit_salt[$key]) |
||
2587 | && ($multi_edit_funcs[$key] == "DES_ENCRYPT" |
||
2588 | || $multi_edit_funcs[$key] == "DES_DECRYPT" |
||
2589 | || $multi_edit_funcs[$key] == "ENCRYPT")) |
||
2590 | ) { |
||
2591 | return $multi_edit_funcs[$key] . '(' . $current_value . ",'" |
||
2592 | . $this->dbi->escapeString($multi_edit_salt[$key]) . "')"; |
||
2593 | } |
||
2594 | |||
2595 | return $multi_edit_funcs[$key] . '(' . $current_value . ')'; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
2596 | } |
||
2597 | |||
2598 | return $multi_edit_funcs[$key] . '()'; |
||
0 ignored issues
–
show
|
|||
2599 | } |
||
2600 | |||
2601 | /** |
||
2602 | * Get query values array and query fields array for insert and update in multi edit |
||
2603 | * |
||
2604 | * @param array $multi_edit_columns_name multiple edit columns name array |
||
2605 | * @param array $multi_edit_columns_null multiple edit columns null array |
||
2606 | * @param string $current_value current value in the column in loop |
||
2607 | * @param array $multi_edit_columns_prev multiple edit previous columns array |
||
2608 | * @param array $multi_edit_funcs multiple edit functions array |
||
2609 | * @param boolean $is_insert boolean value whether insert or not |
||
2610 | * @param array $query_values SET part of the sql query |
||
2611 | * @param array $query_fields array of query fields |
||
2612 | * @param string $current_value_as_an_array current value in the column |
||
2613 | * as an array |
||
2614 | * @param array $value_sets array of valu sets |
||
2615 | * @param string $key an md5 of the column name |
||
2616 | * @param array $multi_edit_columns_null_prev array of multiple edit columns |
||
2617 | * null previous |
||
2618 | * |
||
2619 | * @return array ($query_values, $query_fields) |
||
2620 | */ |
||
2621 | public function getQueryValuesForInsertAndUpdateInMultipleEdit( |
||
2622 | $multi_edit_columns_name, |
||
2623 | $multi_edit_columns_null, |
||
2624 | $current_value, |
||
2625 | $multi_edit_columns_prev, |
||
2626 | $multi_edit_funcs, |
||
2627 | $is_insert, |
||
2628 | $query_values, |
||
2629 | $query_fields, |
||
2630 | $current_value_as_an_array, |
||
2631 | $value_sets, |
||
2632 | $key, |
||
2633 | $multi_edit_columns_null_prev |
||
2634 | ) { |
||
2635 | // i n s e r t |
||
2636 | if ($is_insert) { |
||
2637 | // no need to add column into the valuelist |
||
2638 | if (strlen($current_value_as_an_array) > 0) { |
||
2639 | $query_values[] = $current_value_as_an_array; |
||
2640 | // first inserted row so prepare the list of fields |
||
2641 | if (empty($value_sets)) { |
||
2642 | $query_fields[] = Util::backquote( |
||
2643 | $multi_edit_columns_name[$key] |
||
2644 | ); |
||
2645 | } |
||
2646 | } |
||
2647 | } elseif (! empty($multi_edit_columns_null_prev[$key]) |
||
2648 | && ! isset($multi_edit_columns_null[$key]) |
||
2649 | ) { |
||
2650 | // u p d a t e |
||
2651 | |||
2652 | // field had the null checkbox before the update |
||
2653 | // field no longer has the null checkbox |
||
2654 | $query_values[] |
||
2655 | = Util::backquote($multi_edit_columns_name[$key]) |
||
2656 | . ' = ' . $current_value_as_an_array; |
||
2657 | } elseif (empty($multi_edit_funcs[$key]) |
||
2658 | && isset($multi_edit_columns_prev[$key]) |
||
2659 | && (("'" . $this->dbi->escapeString($multi_edit_columns_prev[$key]) . "'" === $current_value) |
||
2660 | || ('0x' . $multi_edit_columns_prev[$key] === $current_value)) |
||
2661 | ) { |
||
2662 | // No change for this column and no MySQL function is used -> next column |
||
2663 | } elseif (! empty($current_value)) { |
||
2664 | // avoid setting a field to NULL when it's already NULL |
||
2665 | // (field had the null checkbox before the update |
||
2666 | // field still has the null checkbox) |
||
2667 | if (empty($multi_edit_columns_null_prev[$key]) |
||
2668 | || empty($multi_edit_columns_null[$key]) |
||
2669 | ) { |
||
2670 | $query_values[] |
||
2671 | = Util::backquote($multi_edit_columns_name[$key]) |
||
2672 | . ' = ' . $current_value_as_an_array; |
||
2673 | } |
||
2674 | } |
||
2675 | return [$query_values, $query_fields]; |
||
2676 | } |
||
2677 | |||
2678 | /** |
||
2679 | * Get the current column value in the form for different data types |
||
2680 | * |
||
2681 | * @param string|false $possibly_uploaded_val uploaded file content |
||
2682 | * @param string $key an md5 of the column name |
||
2683 | * @param array|null $multi_edit_columns_type array of multi edit column types |
||
2684 | * @param string $current_value current column value in the form |
||
2685 | * @param array|null $multi_edit_auto_increment multi edit auto increment |
||
2686 | * @param integer $rownumber index of where clause array |
||
2687 | * @param array $multi_edit_columns_name multi edit column names array |
||
2688 | * @param array $multi_edit_columns_null multi edit columns null array |
||
2689 | * @param array $multi_edit_columns_null_prev multi edit columns previous null |
||
2690 | * @param boolean $is_insert whether insert or not |
||
2691 | * @param boolean $using_key whether editing or new row |
||
2692 | * @param string $where_clause where clause |
||
2693 | * @param string $table table name |
||
2694 | * @param array $multi_edit_funcs multiple edit functions array |
||
2695 | * |
||
2696 | * @return string current column value in the form |
||
2697 | */ |
||
2698 | public function getCurrentValueForDifferentTypes( |
||
2699 | $possibly_uploaded_val, |
||
2700 | $key, |
||
2701 | ?array $multi_edit_columns_type, |
||
2702 | $current_value, |
||
2703 | ?array $multi_edit_auto_increment, |
||
2704 | $rownumber, |
||
2705 | $multi_edit_columns_name, |
||
2706 | $multi_edit_columns_null, |
||
2707 | $multi_edit_columns_null_prev, |
||
2708 | $is_insert, |
||
2709 | $using_key, |
||
2710 | $where_clause, |
||
2711 | $table, |
||
2712 | $multi_edit_funcs |
||
2713 | ) { |
||
2714 | // Fetch the current values of a row to use in case we have a protected field |
||
2715 | if ($is_insert |
||
2716 | && $using_key && isset($multi_edit_columns_type) |
||
2717 | && is_array($multi_edit_columns_type) && !empty($where_clause) |
||
2718 | ) { |
||
2719 | $protected_row = $this->dbi->fetchSingleRow( |
||
2720 | 'SELECT * FROM ' . Util::backquote($table) |
||
2721 | . ' WHERE ' . $where_clause . ';' |
||
2722 | ); |
||
2723 | } |
||
2724 | |||
2725 | if (false !== $possibly_uploaded_val) { |
||
2726 | $current_value = $possibly_uploaded_val; |
||
2727 | } elseif (! empty($multi_edit_funcs[$key])) { |
||
2728 | $current_value = "'" . $this->dbi->escapeString($current_value) |
||
2729 | . "'"; |
||
2730 | } else { |
||
2731 | // c o l u m n v a l u e i n t h e f o r m |
||
2732 | if (isset($multi_edit_columns_type[$key])) { |
||
2733 | $type = $multi_edit_columns_type[$key]; |
||
2734 | } else { |
||
2735 | $type = ''; |
||
2736 | } |
||
2737 | |||
2738 | if ($type != 'protected' && $type != 'set' && strlen($current_value) === 0) { |
||
2739 | // best way to avoid problems in strict mode |
||
2740 | // (works also in non-strict mode) |
||
2741 | if (isset($multi_edit_auto_increment) |
||
2742 | && isset($multi_edit_auto_increment[$key]) |
||
2743 | ) { |
||
2744 | $current_value = 'NULL'; |
||
2745 | } else { |
||
2746 | $current_value = "''"; |
||
2747 | } |
||
2748 | } elseif ($type == 'set') { |
||
2749 | if (! empty($_REQUEST['fields']['multi_edit'][$rownumber][$key])) { |
||
2750 | $current_value = implode( |
||
2751 | ',', |
||
2752 | $_REQUEST['fields']['multi_edit'][$rownumber][$key] |
||
2753 | ); |
||
2754 | $current_value = "'" |
||
2755 | . $this->dbi->escapeString($current_value) . "'"; |
||
2756 | } else { |
||
2757 | $current_value = "''"; |
||
2758 | } |
||
2759 | } elseif ($type == 'protected') { |
||
2760 | // here we are in protected mode (asked in the config) |
||
2761 | // so tbl_change has put this special value in the |
||
2762 | // columns array, so we do not change the column value |
||
2763 | // but we can still handle column upload |
||
2764 | |||
2765 | // when in UPDATE mode, do not alter field's contents. When in INSERT |
||
2766 | // mode, insert empty field because no values were submitted. |
||
2767 | // If protected blobs where set, insert original fields content. |
||
2768 | if (! empty($protected_row[$multi_edit_columns_name[$key]])) { |
||
2769 | $current_value = '0x' |
||
2770 | . bin2hex($protected_row[$multi_edit_columns_name[$key]]); |
||
2771 | } else { |
||
2772 | $current_value = ''; |
||
2773 | } |
||
2774 | } elseif ($type === 'hex') { |
||
2775 | if (substr($current_value, 0, 2) != '0x') { |
||
2776 | $current_value = '0x' . $current_value; |
||
2777 | } |
||
2778 | } elseif ($type == 'bit') { |
||
2779 | $current_value = preg_replace('/[^01]/', '0', $current_value); |
||
2780 | $current_value = "b'" . $this->dbi->escapeString($current_value) |
||
2781 | . "'"; |
||
2782 | } elseif (! ($type == 'datetime' || $type == 'timestamp') |
||
2783 | || ($current_value != 'CURRENT_TIMESTAMP' |
||
2784 | && $current_value != 'current_timestamp()') |
||
2785 | ) { |
||
2786 | $current_value = "'" . $this->dbi->escapeString($current_value) |
||
2787 | . "'"; |
||
2788 | } |
||
2789 | |||
2790 | // Was the Null checkbox checked for this field? |
||
2791 | // (if there is a value, we ignore the Null checkbox: this could |
||
2792 | // be possible if Javascript is disabled in the browser) |
||
2793 | if (! empty($multi_edit_columns_null[$key]) |
||
2794 | && ($current_value == "''" || $current_value == '') |
||
2795 | ) { |
||
2796 | $current_value = 'NULL'; |
||
2797 | } |
||
2798 | |||
2799 | // The Null checkbox was unchecked for this field |
||
2800 | if (empty($current_value) |
||
2801 | && ! empty($multi_edit_columns_null_prev[$key]) |
||
2802 | && ! isset($multi_edit_columns_null[$key]) |
||
2803 | ) { |
||
2804 | $current_value = "''"; |
||
2805 | } |
||
2806 | } // end else (column value in the form) |
||
2807 | return $current_value; |
||
2808 | } |
||
2809 | |||
2810 | /** |
||
2811 | * Check whether inline edited value can be truncated or not, |
||
2812 | * and add additional parameters for extra_data array if needed |
||
2813 | * |
||
2814 | * @param string $db Database name |
||
2815 | * @param string $table Table name |
||
2816 | * @param string $column_name Column name |
||
2817 | * @param array &$extra_data Extra data for ajax response |
||
2818 | * |
||
2819 | * @return void |
||
2820 | */ |
||
2821 | public function verifyWhetherValueCanBeTruncatedAndAppendExtraData( |
||
2822 | $db, |
||
2823 | $table, |
||
2824 | $column_name, |
||
2825 | array &$extra_data |
||
2826 | ) { |
||
2827 | $extra_data['isNeedToRecheck'] = false; |
||
2828 | |||
2829 | $sql_for_real_value = 'SELECT ' . Util::backquote($table) . '.' |
||
2830 | . Util::backquote($column_name) |
||
2831 | . ' FROM ' . Util::backquote($db) . '.' |
||
2832 | . Util::backquote($table) |
||
2833 | . ' WHERE ' . $_REQUEST['where_clause'][0]; |
||
2834 | |||
2835 | $result = $this->dbi->tryQuery($sql_for_real_value); |
||
2836 | $fields_meta = $this->dbi->getFieldsMeta($result); |
||
2837 | $meta = $fields_meta[0]; |
||
2838 | if ($row = $this->dbi->fetchRow($result)) { |
||
2839 | $new_value = $row[0]; |
||
2840 | if ((substr($meta->type, 0, 9) == 'timestamp') |
||
2841 | || ($meta->type == 'datetime') |
||
2842 | || ($meta->type == 'time') |
||
2843 | ) { |
||
2844 | $new_value = Util::addMicroseconds($new_value); |
||
2845 | } elseif (mb_strpos($meta->flags, 'binary') !== false) { |
||
2846 | $new_value = '0x' . bin2hex($new_value); |
||
2847 | } |
||
2848 | $extra_data['isNeedToRecheck'] = true; |
||
2849 | $extra_data['truncatableFieldValue'] = $new_value; |
||
2850 | } |
||
2851 | $this->dbi->freeResult($result); |
||
2852 | } |
||
2853 | |||
2854 | /** |
||
2855 | * Function to get the columns of a table |
||
2856 | * |
||
2857 | * @param string $db current db |
||
2858 | * @param string $table current table |
||
2859 | * |
||
2860 | * @return array |
||
2861 | */ |
||
2862 | public function getTableColumns($db, $table) |
||
2863 | { |
||
2864 | $this->dbi->selectDb($db); |
||
2865 | return array_values($this->dbi->getColumns($db, $table, null, true)); |
||
2866 | } |
||
2867 | |||
2868 | /** |
||
2869 | * Function to determine Insert/Edit rows |
||
2870 | * |
||
2871 | * @param string $where_clause where clause |
||
2872 | * @param string $db current database |
||
2873 | * @param string $table current table |
||
2874 | * |
||
2875 | * @return mixed |
||
2876 | */ |
||
2877 | public function determineInsertOrEdit($where_clause, $db, $table) |
||
2878 | { |
||
2879 | if (isset($_REQUEST['where_clause'])) { |
||
2880 | $where_clause = $_REQUEST['where_clause']; |
||
2881 | } |
||
2882 | if (isset($_SESSION['edit_next'])) { |
||
2883 | $where_clause = $_SESSION['edit_next']; |
||
2884 | unset($_SESSION['edit_next']); |
||
2885 | $after_insert = 'edit_next'; |
||
2886 | } |
||
2887 | if (isset($_REQUEST['ShowFunctionFields'])) { |
||
2888 | $GLOBALS['cfg']['ShowFunctionFields'] = $_REQUEST['ShowFunctionFields']; |
||
2889 | } |
||
2890 | if (isset($_REQUEST['ShowFieldTypesInDataEditView'])) { |
||
2891 | $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] |
||
2892 | = $_REQUEST['ShowFieldTypesInDataEditView']; |
||
2893 | } |
||
2894 | if (isset($_REQUEST['after_insert'])) { |
||
2895 | $after_insert = $_REQUEST['after_insert']; |
||
2896 | } |
||
2897 | |||
2898 | if (isset($where_clause)) { |
||
2899 | // we are editing |
||
2900 | $insert_mode = false; |
||
2901 | $where_clause_array = $this->getWhereClauseArray($where_clause); |
||
2902 | list($where_clauses, $result, $rows, $found_unique_key) |
||
2903 | = $this->analyzeWhereClauses( |
||
2904 | $where_clause_array, |
||
2905 | $table, |
||
2906 | $db |
||
2907 | ); |
||
2908 | } else { |
||
2909 | // we are inserting |
||
2910 | $insert_mode = true; |
||
2911 | $where_clause = null; |
||
2912 | list($result, $rows) = $this->loadFirstRow($table, $db); |
||
2913 | $where_clauses = null; |
||
2914 | $where_clause_array = []; |
||
2915 | $found_unique_key = false; |
||
2916 | } |
||
2917 | |||
2918 | // Copying a row - fetched data will be inserted as a new row, |
||
2919 | // therefore the where clause is needless. |
||
2920 | if (isset($_REQUEST['default_action']) |
||
2921 | && $_REQUEST['default_action'] === 'insert' |
||
2922 | ) { |
||
2923 | $where_clause = $where_clauses = null; |
||
2924 | } |
||
2925 | |||
2926 | return [ |
||
2927 | $insert_mode, $where_clause, $where_clause_array, $where_clauses, |
||
2928 | $result, $rows, $found_unique_key, |
||
2929 | isset($after_insert) ? $after_insert : null |
||
2930 | ]; |
||
2931 | } |
||
2932 | |||
2933 | /** |
||
2934 | * Function to get comments for the table columns |
||
2935 | * |
||
2936 | * @param string $db current database |
||
2937 | * @param string $table current table |
||
2938 | * |
||
2939 | * @return array comments for columns |
||
2940 | */ |
||
2941 | public function getCommentsMap($db, $table) |
||
2942 | { |
||
2943 | $comments_map = []; |
||
2944 | |||
2945 | if ($GLOBALS['cfg']['ShowPropertyComments']) { |
||
2946 | $comments_map = $this->relation->getComments($db, $table); |
||
2947 | } |
||
2948 | |||
2949 | return $comments_map; |
||
2950 | } |
||
2951 | |||
2952 | /** |
||
2953 | * Function to get URL parameters |
||
2954 | * |
||
2955 | * @param string $db current database |
||
2956 | * @param string $table current table |
||
2957 | * |
||
2958 | * @return array url parameters |
||
2959 | */ |
||
2960 | public function getUrlParameters($db, $table) |
||
2961 | { |
||
2962 | /** |
||
2963 | * @todo check if we could replace by "db_|tbl_" - please clarify!? |
||
2964 | */ |
||
2965 | $url_params = [ |
||
2966 | 'db' => $db, |
||
2967 | 'sql_query' => $_POST['sql_query'] |
||
2968 | ]; |
||
2969 | |||
2970 | if (preg_match('@^tbl_@', $GLOBALS['goto'])) { |
||
2971 | $url_params['table'] = $table; |
||
2972 | } |
||
2973 | |||
2974 | return $url_params; |
||
2975 | } |
||
2976 | |||
2977 | /** |
||
2978 | * Function to get html for the gis editor div |
||
2979 | * |
||
2980 | * @return string |
||
2981 | */ |
||
2982 | public function getHtmlForGisEditor() |
||
2983 | { |
||
2984 | return '<div id="gis_editor"></div>' |
||
2985 | . '<div id="popup_background"></div>' |
||
2986 | . '<br />'; |
||
2987 | } |
||
2988 | |||
2989 | /** |
||
2990 | * Function to get html for the ignore option in insert mode |
||
2991 | * |
||
2992 | * @param int $row_id row id |
||
2993 | * @param bool $checked ignore option is checked or not |
||
2994 | * |
||
2995 | * @return string |
||
2996 | */ |
||
2997 | public function getHtmlForIgnoreOption($row_id, $checked = true) |
||
2998 | { |
||
2999 | return '<input type="checkbox"' |
||
3000 | . ($checked ? ' checked="checked"' : '') |
||
3001 | . ' name="insert_ignore_' . $row_id . '"' |
||
3002 | . ' id="insert_ignore_' . $row_id . '" />' |
||
3003 | . '<label for="insert_ignore_' . $row_id . '">' |
||
3004 | . __('Ignore') |
||
3005 | . '</label><br />' . "\n"; |
||
3006 | } |
||
3007 | |||
3008 | /** |
||
3009 | * Function to get html for the function option |
||
3010 | * |
||
3011 | * @param array $column column |
||
3012 | * @param string $column_name_appendix column name appendix |
||
3013 | * |
||
3014 | * @return String |
||
3015 | */ |
||
3016 | private function getHtmlForFunctionOption(array $column, $column_name_appendix) |
||
3017 | { |
||
3018 | return '<tr class="noclick">' |
||
3019 | . '<td ' |
||
3020 | . 'class="center">' |
||
3021 | . $column['Field_title'] |
||
3022 | . '<input type="hidden" name="fields_name' . $column_name_appendix |
||
3023 | . '" value="' . $column['Field_html'] . '"/>' |
||
3024 | . '</td>'; |
||
3025 | } |
||
3026 | |||
3027 | /** |
||
3028 | * Function to get html for the column type |
||
3029 | * |
||
3030 | * @param array $column column |
||
3031 | * |
||
3032 | * @return string |
||
3033 | */ |
||
3034 | private function getHtmlForInsertEditColumnType(array $column) |
||
3035 | { |
||
3036 | return '<td class="center' . $column['wrap'] . '">' |
||
3037 | . '<span class="column_type" dir="ltr">' . $column['pma_type'] . '</span>' |
||
3038 | . '</td>'; |
||
3039 | } |
||
3040 | |||
3041 | /** |
||
3042 | * Function to get html for the insert edit form header |
||
3043 | * |
||
3044 | * @param bool $has_blob_field whether has blob field |
||
3045 | * @param bool $is_upload whether is upload |
||
3046 | * |
||
3047 | * @return string |
||
3048 | */ |
||
3049 | public function getHtmlForInsertEditFormHeader($has_blob_field, $is_upload) |
||
3050 | { |
||
3051 | $html_output = '<form id="insertForm" class="lock-page '; |
||
3052 | if ($has_blob_field && $is_upload) { |
||
3053 | $html_output .= 'disableAjax'; |
||
3054 | } |
||
3055 | $html_output .= '" method="post" action="tbl_replace.php" name="insertForm" '; |
||
3056 | if ($is_upload) { |
||
3057 | $html_output .= ' enctype="multipart/form-data"'; |
||
3058 | } |
||
3059 | $html_output .= '>'; |
||
3060 | |||
3061 | return $html_output; |
||
3062 | } |
||
3063 | |||
3064 | /** |
||
3065 | * Function to get html for each insert/edit column |
||
3066 | * |
||
3067 | * @param array $table_columns table columns |
||
3068 | * @param int $column_number column index in table_columns |
||
3069 | * @param array $comments_map comments map |
||
3070 | * @param bool $timestamp_seen whether timestamp seen |
||
3071 | * @param array $current_result current result |
||
3072 | * @param string $chg_evt_handler javascript change event handler |
||
3073 | * @param string $jsvkey javascript validation key |
||
3074 | * @param string $vkey validation key |
||
3075 | * @param bool $insert_mode whether insert mode |
||
3076 | * @param array $current_row current row |
||
3077 | * @param int &$o_rows row offset |
||
3078 | * @param int &$tabindex tab index |
||
3079 | * @param int $columns_cnt columns count |
||
3080 | * @param bool $is_upload whether upload |
||
3081 | * @param int $tabindex_for_function tab index offset for function |
||
3082 | * @param array $foreigners foreigners |
||
3083 | * @param int $tabindex_for_null tab index offset for null |
||
3084 | * @param int $tabindex_for_value tab index offset for value |
||
3085 | * @param string $table table |
||
3086 | * @param string $db database |
||
3087 | * @param int $row_id row id |
||
3088 | * @param array $titles titles |
||
3089 | * @param int $biggest_max_file_size biggest max file size |
||
3090 | * @param string $default_char_editing default char editing mode which is stored |
||
3091 | * in the config.inc.php script |
||
3092 | * @param string $text_dir text direction |
||
3093 | * @param array $repopulate the data to be repopulated |
||
3094 | * @param array $column_mime the mime information of column |
||
3095 | * @param string $where_clause the where clause |
||
3096 | * |
||
3097 | * @return string |
||
3098 | */ |
||
3099 | private function getHtmlForInsertEditFormColumn( |
||
3100 | array $table_columns, |
||
3101 | $column_number, |
||
3102 | array $comments_map, |
||
3103 | $timestamp_seen, |
||
3104 | $current_result, |
||
3105 | $chg_evt_handler, |
||
3106 | $jsvkey, |
||
3107 | $vkey, |
||
3108 | $insert_mode, |
||
3109 | array $current_row, |
||
3110 | &$o_rows, |
||
3111 | &$tabindex, |
||
3112 | $columns_cnt, |
||
3113 | $is_upload, |
||
3114 | $tabindex_for_function, |
||
3115 | array $foreigners, |
||
3116 | $tabindex_for_null, |
||
3117 | $tabindex_for_value, |
||
3118 | $table, |
||
3119 | $db, |
||
3120 | $row_id, |
||
3121 | array $titles, |
||
3122 | $biggest_max_file_size, |
||
3123 | $default_char_editing, |
||
3124 | $text_dir, |
||
3125 | array $repopulate, |
||
3126 | array $column_mime, |
||
3127 | $where_clause |
||
3128 | ) { |
||
3129 | $column = $table_columns[$column_number]; |
||
3130 | $readOnly = false; |
||
3131 | if (! $this->userHasColumnPrivileges($column, $insert_mode)) { |
||
3132 | $readOnly = true; |
||
3133 | } |
||
3134 | |||
3135 | if (! isset($column['processed'])) { |
||
3136 | $column = $this->analyzeTableColumnsArray( |
||
3137 | $column, |
||
3138 | $comments_map, |
||
3139 | $timestamp_seen |
||
3140 | ); |
||
3141 | } |
||
3142 | $as_is = false; |
||
3143 | if (!empty($repopulate) && !empty($current_row)) { |
||
3144 | $current_row[$column['Field']] = $repopulate[$column['Field_md5']]; |
||
3145 | $as_is = true; |
||
3146 | } |
||
3147 | |||
3148 | $extracted_columnspec |
||
3149 | = Util::extractColumnSpec($column['Type']); |
||
3150 | |||
3151 | if (-1 === $column['len']) { |
||
3152 | $column['len'] = $this->dbi->fieldLen( |
||
3153 | $current_result, |
||
3154 | $column_number |
||
3155 | ); |
||
3156 | // length is unknown for geometry fields, |
||
3157 | // make enough space to edit very simple WKTs |
||
3158 | if (-1 === $column['len']) { |
||
3159 | $column['len'] = 30; |
||
3160 | } |
||
3161 | } |
||
3162 | //Call validation when the form submitted... |
||
3163 | $onChangeClause = $chg_evt_handler |
||
3164 | . "=\"return verificationsAfterFieldChange('" |
||
3165 | . Sanitize::escapeJsString($column['Field_md5']) . "', '" |
||
3166 | . Sanitize::escapeJsString($jsvkey) . "','" . $column['pma_type'] . "')\""; |
||
3167 | |||
3168 | // Use an MD5 as an array index to avoid having special characters |
||
3169 | // in the name attribute (see bug #1746964 ) |
||
3170 | $column_name_appendix = $vkey . '[' . $column['Field_md5'] . ']'; |
||
3171 | |||
3172 | if ($column['Type'] === 'datetime' |
||
3173 | && ! isset($column['Default']) |
||
3174 | && ! is_null($column['Default']) |
||
3175 | && $insert_mode |
||
3176 | ) { |
||
3177 | $column['Default'] = date('Y-m-d H:i:s', time()); |
||
3178 | } |
||
3179 | |||
3180 | $html_output = $this->getHtmlForFunctionOption( |
||
3181 | $column, |
||
3182 | $column_name_appendix |
||
3183 | ); |
||
3184 | |||
3185 | if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { |
||
3186 | $html_output .= $this->getHtmlForInsertEditColumnType($column); |
||
3187 | } //End if |
||
3188 | |||
3189 | // Get a list of GIS data types. |
||
3190 | $gis_data_types = Util::getGISDatatypes(); |
||
3191 | |||
3192 | // Prepares the field value |
||
3193 | $real_null_value = false; |
||
3194 | $special_chars_encoded = ''; |
||
3195 | if (!empty($current_row)) { |
||
3196 | // (we are editing) |
||
3197 | list( |
||
3198 | $real_null_value, $special_chars_encoded, $special_chars, |
||
3199 | $data, $backup_field |
||
3200 | ) |
||
3201 | = $this->getSpecialCharsAndBackupFieldForExistingRow( |
||
3202 | $current_row, |
||
3203 | $column, |
||
3204 | $extracted_columnspec, |
||
3205 | $real_null_value, |
||
3206 | $gis_data_types, |
||
3207 | $column_name_appendix, |
||
3208 | $as_is |
||
3209 | ); |
||
3210 | } else { |
||
3211 | // (we are inserting) |
||
3212 | // display default values |
||
3213 | $tmp = $column; |
||
3214 | if (isset($repopulate[$column['Field_md5']])) { |
||
3215 | $tmp['Default'] = $repopulate[$column['Field_md5']]; |
||
3216 | } |
||
3217 | list($real_null_value, $data, $special_chars, $backup_field, |
||
3218 | $special_chars_encoded |
||
3219 | ) |
||
3220 | = $this->getSpecialCharsAndBackupFieldForInsertingMode( |
||
3221 | $tmp, |
||
3222 | $real_null_value |
||
3223 | ); |
||
3224 | unset($tmp); |
||
3225 | } |
||
3226 | |||
3227 | $idindex = ($o_rows * $columns_cnt) + $column_number + 1; |
||
3228 | $tabindex = $idindex; |
||
3229 | |||
3230 | // Get a list of data types that are not yet supported. |
||
3231 | $no_support_types = Util::unsupportedDatatypes(); |
||
3232 | |||
3233 | // The function column |
||
3234 | // ------------------- |
||
3235 | $foreignData = $this->relation->getForeignData( |
||
3236 | $foreigners, |
||
3237 | $column['Field'], |
||
3238 | false, |
||
3239 | '', |
||
3240 | '' |
||
3241 | ); |
||
3242 | if ($GLOBALS['cfg']['ShowFunctionFields']) { |
||
3243 | $html_output .= $this->getFunctionColumn( |
||
3244 | $column, |
||
3245 | $is_upload, |
||
3246 | $column_name_appendix, |
||
3247 | $onChangeClause, |
||
3248 | $no_support_types, |
||
3249 | $tabindex_for_function, |
||
3250 | $tabindex, |
||
3251 | $idindex, |
||
3252 | $insert_mode, |
||
3253 | $readOnly, |
||
3254 | $foreignData |
||
3255 | ); |
||
3256 | } |
||
3257 | |||
3258 | // The null column |
||
3259 | // --------------- |
||
3260 | $html_output .= $this->getNullColumn( |
||
3261 | $column, |
||
3262 | $column_name_appendix, |
||
3263 | $real_null_value, |
||
3264 | $tabindex, |
||
3265 | $tabindex_for_null, |
||
3266 | $idindex, |
||
3267 | $vkey, |
||
3268 | $foreigners, |
||
3269 | $foreignData, |
||
3270 | $readOnly |
||
3271 | ); |
||
3272 | |||
3273 | // The value column (depends on type) |
||
3274 | // ---------------- |
||
3275 | // See bug #1667887 for the reason why we don't use the maxlength |
||
3276 | // HTML attribute |
||
3277 | |||
3278 | //add data attributes "no of decimals" and "data type" |
||
3279 | $no_decimals = 0; |
||
3280 | $type = current(explode("(", $column['pma_type'])); |
||
3281 | if (preg_match('/\(([^()]+)\)/', $column['pma_type'], $match)) { |
||
3282 | $match[0] = trim($match[0], '()'); |
||
3283 | $no_decimals = $match[0]; |
||
3284 | } |
||
3285 | $html_output .= '<td' . ' data-type="' . $type . '"' . ' data-decimals="' |
||
3286 | . $no_decimals . '">' . "\n"; |
||
3287 | // Will be used by js/tbl_change.js to set the default value |
||
3288 | // for the "Continue insertion" feature |
||
3289 | $html_output .= '<span class="default_value hide">' |
||
3290 | . $special_chars . '</span>'; |
||
3291 | |||
3292 | // Check input transformation of column |
||
3293 | $transformed_html = ''; |
||
3294 | if (!empty($column_mime['input_transformation'])) { |
||
3295 | $file = $column_mime['input_transformation']; |
||
3296 | $include_file = 'libraries/classes/Plugins/Transformations/' . $file; |
||
3297 | if (is_file($include_file)) { |
||
3298 | include_once $include_file; |
||
3299 | $class_name = $this->transformations->getClassName($include_file); |
||
3300 | $transformation_plugin = new $class_name(); |
||
3301 | $transformation_options = $this->transformations->getOptions( |
||
3302 | $column_mime['input_transformation_options'] |
||
3303 | ); |
||
3304 | $_url_params = [ |
||
3305 | 'db' => $db, |
||
3306 | 'table' => $table, |
||
3307 | 'transform_key' => $column['Field'], |
||
3308 | 'where_clause' => $where_clause |
||
3309 | ]; |
||
3310 | $transformation_options['wrapper_link'] |
||
3311 | = Url::getCommon($_url_params); |
||
3312 | $current_value = ''; |
||
3313 | if (isset($current_row[$column['Field']])) { |
||
3314 | $current_value = $current_row[$column['Field']]; |
||
3315 | } |
||
3316 | if (method_exists($transformation_plugin, 'getInputHtml')) { |
||
3317 | $transformed_html = $transformation_plugin->getInputHtml( |
||
3318 | $column, |
||
3319 | $row_id, |
||
3320 | $column_name_appendix, |
||
3321 | $transformation_options, |
||
3322 | $current_value, |
||
3323 | $text_dir, |
||
3324 | $tabindex, |
||
3325 | $tabindex_for_value, |
||
3326 | $idindex |
||
3327 | ); |
||
3328 | } |
||
3329 | if (method_exists($transformation_plugin, 'getScripts')) { |
||
3330 | $GLOBALS['plugin_scripts'] = array_merge( |
||
3331 | $GLOBALS['plugin_scripts'], |
||
3332 | $transformation_plugin->getScripts() |
||
3333 | ); |
||
3334 | } |
||
3335 | } |
||
3336 | } |
||
3337 | if (!empty($transformed_html)) { |
||
3338 | $html_output .= $transformed_html; |
||
3339 | } else { |
||
3340 | $html_output .= $this->getValueColumn( |
||
3341 | $column, |
||
3342 | $backup_field, |
||
3343 | $column_name_appendix, |
||
3344 | $onChangeClause, |
||
3345 | $tabindex, |
||
3346 | $tabindex_for_value, |
||
3347 | $idindex, |
||
3348 | $data, |
||
3349 | $special_chars, |
||
3350 | $foreignData, |
||
3351 | [$table, $db], |
||
3352 | $row_id, |
||
3353 | $titles, |
||
3354 | $text_dir, |
||
3355 | $special_chars_encoded, |
||
3356 | $vkey, |
||
3357 | $is_upload, |
||
3358 | $biggest_max_file_size, |
||
3359 | $default_char_editing, |
||
3360 | $no_support_types, |
||
3361 | $gis_data_types, |
||
3362 | $extracted_columnspec, |
||
3363 | $readOnly |
||
3364 | ); |
||
3365 | } |
||
3366 | return $html_output; |
||
3367 | } |
||
3368 | |||
3369 | /** |
||
3370 | * Function to get html for each insert/edit row |
||
3371 | * |
||
3372 | * @param array $url_params url parameters |
||
3373 | * @param array $table_columns table columns |
||
3374 | * @param array $comments_map comments map |
||
3375 | * @param bool $timestamp_seen whether timestamp seen |
||
3376 | * @param array $current_result current result |
||
3377 | * @param string $chg_evt_handler javascript change event handler |
||
3378 | * @param string $jsvkey javascript validation key |
||
3379 | * @param string $vkey validation key |
||
3380 | * @param bool $insert_mode whether insert mode |
||
3381 | * @param array $current_row current row |
||
3382 | * @param int &$o_rows row offset |
||
3383 | * @param int &$tabindex tab index |
||
3384 | * @param int $columns_cnt columns count |
||
3385 | * @param bool $is_upload whether upload |
||
3386 | * @param int $tabindex_for_function tab index offset for function |
||
3387 | * @param array $foreigners foreigners |
||
3388 | * @param int $tabindex_for_null tab index offset for null |
||
3389 | * @param int $tabindex_for_value tab index offset for value |
||
3390 | * @param string $table table |
||
3391 | * @param string $db database |
||
3392 | * @param int $row_id row id |
||
3393 | * @param array $titles titles |
||
3394 | * @param int $biggest_max_file_size biggest max file size |
||
3395 | * @param string $text_dir text direction |
||
3396 | * @param array $repopulate the data to be repopulated |
||
3397 | * @param array $where_clause_array the array of where clauses |
||
3398 | * |
||
3399 | * @return string |
||
3400 | */ |
||
3401 | public function getHtmlForInsertEditRow( |
||
3402 | array $url_params, |
||
3403 | array $table_columns, |
||
3404 | array $comments_map, |
||
3405 | $timestamp_seen, |
||
3406 | $current_result, |
||
3407 | $chg_evt_handler, |
||
3408 | $jsvkey, |
||
3409 | $vkey, |
||
3410 | $insert_mode, |
||
3411 | array $current_row, |
||
3412 | &$o_rows, |
||
3413 | &$tabindex, |
||
3414 | $columns_cnt, |
||
3415 | $is_upload, |
||
3416 | $tabindex_for_function, |
||
3417 | array $foreigners, |
||
3418 | $tabindex_for_null, |
||
3419 | $tabindex_for_value, |
||
3420 | $table, |
||
3421 | $db, |
||
3422 | $row_id, |
||
3423 | array $titles, |
||
3424 | $biggest_max_file_size, |
||
3425 | $text_dir, |
||
3426 | array $repopulate, |
||
3427 | array $where_clause_array |
||
3428 | ) { |
||
3429 | $html_output = $this->getHeadAndFootOfInsertRowTable($url_params) |
||
3430 | . '<tbody>'; |
||
3431 | |||
3432 | //store the default value for CharEditing |
||
3433 | $default_char_editing = $GLOBALS['cfg']['CharEditing']; |
||
3434 | $mime_map = $this->transformations->getMime($db, $table); |
||
3435 | $where_clause = ''; |
||
3436 | if (isset($where_clause_array[$row_id])) { |
||
3437 | $where_clause = $where_clause_array[$row_id]; |
||
3438 | } |
||
3439 | for ($column_number = 0; $column_number < $columns_cnt; $column_number++) { |
||
3440 | $table_column = $table_columns[$column_number]; |
||
3441 | $column_mime = []; |
||
3442 | if (isset($mime_map[$table_column['Field']])) { |
||
3443 | $column_mime = $mime_map[$table_column['Field']]; |
||
3444 | } |
||
3445 | $html_output .= $this->getHtmlForInsertEditFormColumn( |
||
3446 | $table_columns, |
||
3447 | $column_number, |
||
3448 | $comments_map, |
||
3449 | $timestamp_seen, |
||
3450 | $current_result, |
||
3451 | $chg_evt_handler, |
||
3452 | $jsvkey, |
||
3453 | $vkey, |
||
3454 | $insert_mode, |
||
3455 | $current_row, |
||
3456 | $o_rows, |
||
3457 | $tabindex, |
||
3458 | $columns_cnt, |
||
3459 | $is_upload, |
||
3460 | $tabindex_for_function, |
||
3461 | $foreigners, |
||
3462 | $tabindex_for_null, |
||
3463 | $tabindex_for_value, |
||
3464 | $table, |
||
3465 | $db, |
||
3466 | $row_id, |
||
3467 | $titles, |
||
3468 | $biggest_max_file_size, |
||
3469 | $default_char_editing, |
||
3470 | $text_dir, |
||
3471 | $repopulate, |
||
3472 | $column_mime, |
||
3473 | $where_clause |
||
3474 | ); |
||
3475 | } // end for |
||
3476 | $o_rows++; |
||
3477 | $html_output .= ' </tbody>' |
||
3478 | . '</table></div><br />' |
||
3479 | . '<div class="clearfloat"></div>'; |
||
3480 | |||
3481 | return $html_output; |
||
3482 | } |
||
3483 | |||
3484 | /** |
||
3485 | * Returns whether the user has necessary insert/update privileges for the column |
||
3486 | * |
||
3487 | * @param array $table_column array of column details |
||
3488 | * @param bool $insert_mode whether on insert mode |
||
3489 | * |
||
3490 | * @return boolean whether user has necessary privileges |
||
3491 | */ |
||
3492 | private function userHasColumnPrivileges(array $table_column, $insert_mode) |
||
3493 | { |
||
3494 | $privileges = $table_column['Privileges']; |
||
3495 | return ($insert_mode && strstr($privileges, 'insert') !== false) |
||
3496 | || (! $insert_mode && strstr($privileges, 'update') !== false); |
||
3497 | } |
||
3498 | } |
||
3499 |