Passed
Push — main ( d64c56...742ea5 )
by Thierry
03:47 queued 01:37
created

TableSelectAdmin::getEmailOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 2
rs 10
1
<?php
2
3
namespace Lagdo\DbAdmin\DbAdmin;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
6
use Lagdo\DbAdmin\Driver\Entity\TableSelectEntity;
7
8
use Exception;
9
10
/**
11
 * Admin table select functions
12
 */
13
class TableSelectAdmin extends AbstractAdmin
14
{
15
    /**
16
     * Print columns box in select
17
     * @param array $select Result of processSelectColumns()[0]
18
     * @param array $columns Selectable columns
19
     * @param array $options
20
     * @return array
21
     */
22
    private function getColumnsOptions(array $select, array $columns, array $options)
23
    {
24
        return [
25
            'select' => $select,
26
            'values' => (array)$options["columns"],
27
            'columns' => $columns,
28
            'functions' => $this->driver->functions(),
29
            'grouping' => $this->driver->grouping(),
30
        ];
31
    }
32
33
    /**
34
     * Print search box in select
35
     *
36
     * @param array selectable columns
0 ignored issues
show
Bug introduced by
The type Lagdo\DbAdmin\DbAdmin\selectable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
     * @param array $indexes
38
     * @param array $options
39
     *
40
     * @return array
41
     */
42
    private function getFiltersOptions(array $columns, array $indexes, array $options)
43
    {
44
        $fulltexts = [];
45
        foreach ($indexes as $i => $index) {
46
            $fulltexts[$i] = $index->type == "FULLTEXT" ? $this->util->html($options["fulltext"][$i]) : '';
47
        }
48
        return [
49
            // 'where' => $where,
50
            'values' => (array)$options["where"],
51
            'columns' => $columns,
52
            'indexes' => $indexes,
53
            'operators' => $this->driver->operators(),
54
            'fulltexts' => $fulltexts,
55
        ];
56
    }
57
58
    /**
59
     * Print order box in select
60
     *
61
     * @param array $columns Selectable columns
62
     * @param array $options
63
     *
64
     * @return array
65
     */
66
    private function getSortingOptions(array $columns, array $options)
67
    {
68
        $values = [];
69
        $descs = (array)$options["desc"];
70
        foreach ((array)$options["order"] as $key => $value) {
71
            $values[] = [
72
                'col' => $value,
73
                'desc' => $descs[$key] ?? 0,
74
            ];
75
        }
76
        return [
77
            // 'order' => $order,
78
            'values' => $values,
79
            'columns' => $columns,
80
        ];
81
    }
82
83
    /**
84
     * Print limit box in select
85
     *
86
     * @param string $limit Result of processSelectLimit()
87
     *
88
     * @return array
89
     */
90
    private function getLimitOptions(string $limit)
91
    {
92
        return ['value' => $this->util->html($limit)];
93
    }
94
95
    /**
96
     * Print text length box in select
97
     *
98
     * @param string|null $textLength Result of processSelectLength()
99
     *
100
     * @return array
101
     */
102
    private function getLengthOptions($textLength)
103
    {
104
        return [
105
            'value' => $textLength === null ? 0 : $this->util->html($textLength),
106
        ];
107
    }
108
109
    /**
110
     * Print action box in select
111
     *
112
     * @param array $indexes
113
     *
114
     * @return array
115
     */
116
    // private function getActionOptions(array $indexes)
117
    // {
118
    //     $columns = [];
119
    //     foreach ($indexes as $index) {
120
    //         $current_key = \reset($index->columns);
121
    //         if ($index->type != "FULLTEXT" && $current_key) {
122
    //             $columns[$current_key] = 1;
123
    //         }
124
    //     }
125
    //     $columns[""] = 1;
126
    //     return ['columns' => $columns];
127
    // }
128
129
    /**
130
     * Print command box in select
131
     *
132
     * @return bool whether to print default commands
133
     */
134
    // private function getCommandOptions()
135
    // {
136
    //     return !$this->driver->isInformationSchema($this->driver->database());
137
    // }
138
139
    /**
140
     * Print import box in select
141
     *
142
     * @return bool whether to print default import
143
     */
144
    // private function getImportOptions()
145
    // {
146
    //     return !$this->driver->isInformationSchema($this->driver->database());
147
    // }
148
149
    /**
150
     * Print extra text in the end of a select form
151
     *
152
     * @param array $emailFields Fields holding e-mails
153
     * @param array $columns Selectable columns
154
     *
155
     * @return array
156
     */
157
    // private function getEmailOptions(array $emailFields, array $columns)
158
    // {
159
    // }
160
161
    /**
162
     * Get required data for create/update on tables
163
     *
164
     * @param string $table         The table name
165
     * @param array  $queryOptions  The query options
166
     *
167
     * @return array
168
     */
169
    private function prepareSelect(string $table, array &$queryOptions = [])
170
    {
171
        $defaultOptions = [
172
            'columns' => [],
173
            'where' => [],
174
            'order' => [],
175
            'desc' => [],
176
            'fulltext' => [],
177
            'limit' => '50',
178
            'text_length' => '100',
179
            'page' => '1',
180
        ];
181
        foreach ($defaultOptions as $name => $value) {
182
            if (!isset($queryOptions[$name])) {
183
                $queryOptions[$name] = $value;
184
            }
185
        }
186
        $page = \intval($queryOptions['page']);
187
        if ($page > 0) {
188
            $page -= 1; // Page numbers start at 0 here, instead of 1.
189
        }
190
        $queryOptions['page'] = $page;
191
192
        $this->util->input()->values = $queryOptions;
193
194
        // From select.inc.php
195
        $indexes = $this->driver->indexes($table);
196
        $fields = $this->driver->fields($table);
197
        $foreignKeys = $this->admin->columnForeignKeys($table);
198
199
        $rights = []; // privilege => 0
200
        $columns = []; // selectable columns
201
        $textLength = null;
202
        foreach ($fields as $key => $field) {
203
            $name = $this->util->fieldName($field);
204
            if (isset($field->privileges["select"]) && $name != "") {
205
                $columns[$key] = \html_entity_decode(\strip_tags($name), ENT_QUOTES);
206
                if ($this->util->isShortable($field)) {
207
                    $textLength = $this->util->processSelectLength();
208
                }
209
            }
210
            $rights[] = $field->privileges;
211
        }
212
213
        list($select, $group) = $this->util->processSelectColumns($columns, $indexes);
214
        $isGroup = \count($group) < \count($select);
215
        $where = $this->util->processSelectSearch($fields, $indexes);
216
        $order = $this->util->processSelectOrder($fields, $indexes);
217
        $limit = intval($this->util->processSelectLimit());
218
219
        // if(isset($queryOptions["val"]) && is_ajax()) {
220
        //     header("Content-Type: text/plain; charset=utf-8");
221
        //     foreach($queryOptions["val"] as $unique_idf => $row) {
222
        //         $as = convertField($fields[key($row)]);
223
        //         $select = array($as ? $as : escapeId(key($row)));
224
        //         $where[] = where_check($unique_idf, $fields);
225
        //         $statement = $this->driver->select($table, $select, $where, $select);
226
        //         if($statement) {
227
        //             echo reset($statement->fetchRow());
228
        //         }
229
        //     }
230
        //     exit;
231
        // }
232
233
        $primary = $unselected = null;
234
        foreach ($indexes as $index) {
235
            if ($index->type == "PRIMARY") {
236
                $primary = \array_flip($index->columns);
237
                $unselected = ($select ? $primary : []);
238
                foreach ($unselected as $key => $val) {
239
                    if (\in_array($this->driver->escapeId($key), $select)) {
240
                        unset($unselected[$key]);
241
                    }
242
                }
243
                break;
244
            }
245
        }
246
247
        $tableStatus = $this->driver->tableStatusOrName($table);
248
        $oid = $tableStatus->oid;
249
        if ($oid && !$primary) {
250
            /*$primary = */$unselected = [$oid => 0];
251
            $indexes[] = ["type" => "PRIMARY", "columns" => [$oid]];
252
        }
253
254
        $tableName = $this->util->tableName($tableStatus);
255
256
        // $set = null;
257
        // if(isset($rights["insert"]) || !support("table")) {
258
        //     $set = "";
259
        //     foreach((array) $queryOptions["where"] as $val) {
260
        //         if($foreignKeys[$val["col"]] && count($foreignKeys[$val["col"]]) == 1 && ($val["op"] == "="
261
        //             || (!$val["op"] && !preg_match('~[_%]~', $val["val"])) // LIKE in Editor
262
        //         )) {
263
        //             $set .= "&set" . urlencode("[" . $this->util->bracketEscape($val["col"]) . "]") . "=" . urlencode($val["val"]);
264
        //         }
265
        //     }
266
        // }
267
        // $this->util->selectLinks($tableStatus, $set);
268
269
        if (!$columns && $this->driver->support("table")) {
270
            throw new Exception($this->trans->lang('Unable to select the table') .
271
                ($fields ? "." : ": " . $this->driver->error()));
272
        }
273
274
        // if($page == "last")
275
        // {
276
        //     $found_rows = $this->driver->result($this->driver->countRowsSql($table, $where, $isGroup, $group));
277
        //     $page = \floor(\max(0, $found_rows - 1) / $limit);
278
        // }
279
280
        $options = [
281
            'columns' => $this->getColumnsOptions($select, $columns, $queryOptions),
282
            'filters' => $this->getFiltersOptions($columns, $indexes, $queryOptions),
283
            'sorting' => $this->getSortingOptions($columns, $queryOptions),
284
            'limit' => $this->getLimitOptions($limit),
285
            'length' => $this->getLengthOptions($textLength),
286
            // 'action' => $this->getActionOptions($indexes),
287
        ];
288
289
        $select2 = $select;
290
        $group2 = $group;
291
        if (!$select2) {
292
            $select2[] = "*";
293
            $convert_fields = $this->driver->convertFields($columns, $fields, $select);
294
            if ($convert_fields) {
295
                $select2[] = \substr($convert_fields, 2);
296
            }
297
        }
298
        foreach ($select as $key => $val) {
299
            $field = $fields[$this->driver->unescapeId($val)] ?? null;
300
            if ($field && ($as = $this->driver->convertField($field))) {
301
                $select2[$key] = "$as AS $val";
302
            }
303
        }
304
        if (!$isGroup && $unselected) {
305
            foreach ($unselected as $key => $val) {
306
                $select2[] = $this->driver->escapeId($key);
307
                if ($group2) {
308
                    $group2[] = $this->driver->escapeId($key);
309
                }
310
            }
311
        }
312
313
        // From driver.inc.php
314
        $entity = new TableSelectEntity($table, $select2, $where, $group2, $order, $limit, $page);
315
        $query = $this->driver->buildSelectQuery($entity);
316
        // From adminer.inc.php
317
        $query = \str_replace("\n", " ", $query);
318
319
        return [$options, $query, $select, $fields, $foreignKeys, $columns, $indexes,
320
            $where, $group, $order, $limit, $page, $textLength, $isGroup, $tableName, $unselected];
321
    }
322
323
    /**
324
     * Get required data for create/update on tables
325
     *
326
     * @param string $table         The table name
327
     * @param array  $queryOptions  The query options
328
     *
329
     * @return array
330
     */
331
    public function getSelectData(string $table, array $queryOptions = [])
332
    {
333
        list($options, $query) = $this->prepareSelect($table, $queryOptions);
334
335
        $query = $this->util->html($query);
336
        $mainActions = [
337
            'select-exec' => $this->trans->lang('Execute'),
338
            'insert-table' => $this->trans->lang('New item'),
339
            'select-cancel' => $this->trans->lang('Cancel'),
340
        ];
341
342
        return \compact('mainActions', 'options', 'query');
343
    }
344
345
    /**
346
     * Get required data for create/update on tables
347
     *
348
     * @param string $table         The table name
349
     * @param array  $queryOptions  The query options
350
     *
351
     * @return array
352
     */
353
    public function execSelect(string $table, array $queryOptions)
354
    {
355
        list($options, $query, $select, $fields, $foreignKeys, $columns, $indexes,
356
            $where, $group, $order, $limit, $page, $textLength, $isGroup, $tableName,
357
            $unselected) = $this->prepareSelect($table, $queryOptions);
358
359
        $error = null;
360
        // From driver.inc.php
361
        $start = microtime(true);
362
        $statement = $this->driver->query($query);
363
        // From adminer.inc.php
364
        $duration = $this->trans->formatTime($start); // Compute and format the duration
365
366
        if (!$statement) {
367
            return ['error' => $this->driver->error()];
368
        }
369
        // From select.inc.php
370
        $rows = [];
371
        while (($row = $statement->fetchAssoc())) {
372
            if ($page && $this->driver->jush() == "oracle") {
373
                unset($row["RNUM"]);
374
            }
375
            $rows[] = $row;
376
        }
377
        if (!$rows) {
378
            return ['error' => $this->trans->lang('No rows.')];
379
        }
380
        // $backward_keys = $this->driver->backwardKeys($table, $tableName);
381
382
        // Results headers
383
        $headers = [
384
            '', // !$group && $select ? '' : lang('Modify');
385
        ];
386
        $names = [];
387
        $functions = [];
388
        reset($select);
389
        $rank = 1;
390
        foreach ($rows[0] as $key => $value) {
391
            $header = [];
392
            if (!isset($unselected[$key])) {
393
                $value = $queryOptions["columns"][key($select)] ?? [];
394
                $fun = $value["fun"] ?? '';
395
                $field = $fields[$select ? ($value ? $value["col"] : current($select)) : $key];
396
                $name = ($field ? $this->util->fieldName($field, $rank) : ($fun ? "*" : $key));
397
                $header = \compact('value', 'field', 'name');
398
                if ($name != "") {
399
                    $rank++;
400
                    $names[$key] = $name;
401
                    $column = $this->driver->escapeId($key);
402
                    // $href = remove_from_uri('(order|desc)[^=]*|page') . '&order%5B0%5D=' . urlencode($key);
403
                    // $desc = "&desc%5B0%5D=1";
404
                    $header['column'] = $column;
405
                    $header['key'] = $this->util->html($this->util->bracketEscape($key));
406
                    $header['sql'] = $this->admin->applySqlFunction($fun, $name); //! columns looking like functions
407
                }
408
                $functions[$key] = $fun;
409
                next($select);
410
            }
411
            $headers[] = $header;
412
        }
413
414
        // $lengths = [];
415
        // if($queryOptions["modify"])
416
        // {
417
        //     foreach($rows as $row)
418
        //     {
419
        //         foreach($row as $key => $value)
420
        //         {
421
        //             $lengths[$key] = \max($lengths[$key], \min(40, strlen(\utf8_decode($value))));
422
        //         }
423
        //     }
424
        // }
425
426
        $results = [];
427
        foreach ($rows as $n => $row) {
428
            $uniqueIds = $this->util->uniqueIds($rows[$n], $indexes);
429
            if (empty($uniqueIds)) {
430
                foreach ($rows[$n] as $key => $value) {
431
                    if (!\preg_match('~^(COUNT\((\*|(DISTINCT )?`(?:[^`]|``)+`)\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\(`(?:[^`]|``)+`\))$~', $key)) {
432
                        //! columns looking like functions
433
                        $uniqueIds[$key] = $value;
434
                    }
435
                }
436
            }
437
438
            // Unique identifier to edit returned data.
439
            // $unique_idf = "";
440
            $rowIds = [
441
                'where' => [],
442
                'null' => [],
443
            ];
444
            foreach ($uniqueIds as $key => $value) {
445
                $key = \trim($key);
446
                $type = '';
447
                $collation = '';
448
                if (isset($fields[$key])) {
449
                    $type = $fields[$key]->type;
450
                    $collation = $fields[$key]->collation;
451
                }
452
                if (($this->driver->jush() == "sql" || $this->driver->jush() == "pgsql") &&
453
                    \preg_match('~char|text|enum|set~', $type) && strlen($value) > 64) {
454
                    $key = (\strpos($key, '(') ? $key : $this->driver->escapeId($key)); //! columns looking like functions
455
                    $key = "MD5(" . ($this->driver->jush() != 'sql' || \preg_match("~^utf8~", $collation) ?
456
                        $key : "CONVERT($key USING " . $this->driver->charset() . ")") . ")";
457
                    $value = \md5($value);
458
                }
459
                if ($value !== null) {
460
                    $rowIds['where'][$this->util->bracketEscape($key)] = $value;
461
                } else {
462
                    $rowIds['null'][] = $this->util->bracketEscape($key);
463
                }
464
                // $unique_idf .= "&" . ($value !== null ? \urlencode("where[" . $this->util->bracketEscape($key) . "]") .
465
                //     "=" . \urlencode($value) : \urlencode("null[]") . "=" . \urlencode($key));
466
            }
467
468
            $cols = [];
469
            foreach ($row as $key => $value) {
470
                if (isset($names[$key])) {
471
                    $field = $fields[$key] ?? new TableFieldEntity();
472
                    $value = $this->driver->value($value, $field);
0 ignored issues
show
Bug introduced by
The method value() does not exist on Lagdo\DbAdmin\Driver\DriverInterface. Did you maybe mean values()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

472
                    /** @scrutinizer ignore-call */ 
473
                    $value = $this->driver->value($value, $field);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
473
                    if ($value != "" && (!isset($email_fields[$key]) || $email_fields[$key] != "")) {
474
                        //! filled e-mails can be contained on other pages
475
                        $email_fields[$key] = ($this->util->isMail($value) ? $names[$key] : "");
476
                    }
477
478
                    $link = "";
479
480
                    $value = $this->util->selectValue($value ?? '', $link, $field, $textLength);
481
                    $text = \preg_match('~text|lob~', $field->type);
482
483
                    $cols[] = \compact(/*'id', */'text', 'value'/*, 'editable'*/);
484
                }
485
            }
486
            $results[] = ['ids' => $rowIds, 'cols' => $cols];
487
        }
488
489
        $total = $this->driver->result($this->driver->countRowsSql($table, $where, $isGroup, $group));
490
491
        $rows = $results;
492
        return \compact('duration', 'headers', 'query', 'rows', 'limit', 'total', 'error');
493
    }
494
}
495