Translated using Weblate (Portuguese)
[phpmyadmin.git] / src / Transformations.php
blob168a37db4c0a3e9bf3c30a73b5a101154f5b6c43
1 <?php
2 /**
3 * Set of functions used with the relation and pdf feature
5 * This file also provides basic functions to use in other plugins!
6 * These are declared in the 'GLOBAL Plugin functions' section
8 * Please use short and expressive names.
9 * For now, special characters which aren't allowed in
10 * filenames or functions should not be used.
12 * Please provide a comment for your function,
13 * what it does and what parameters are available.
16 declare(strict_types=1);
18 namespace PhpMyAdmin;
20 use PhpMyAdmin\ConfigStorage\Relation;
21 use PhpMyAdmin\Dbal\ConnectionType;
22 use PhpMyAdmin\Plugins\TransformationsInterface;
24 use function array_shift;
25 use function class_exists;
26 use function closedir;
27 use function count;
28 use function explode;
29 use function ltrim;
30 use function mb_strtolower;
31 use function mb_substr;
32 use function opendir;
33 use function preg_match;
34 use function preg_replace;
35 use function readdir;
36 use function rtrim;
37 use function sort;
38 use function str_contains;
39 use function str_replace;
40 use function stripslashes;
41 use function strlen;
42 use function trim;
43 use function ucfirst;
44 use function ucwords;
46 /**
47 * Transformations class
49 class Transformations
51 /**
52 * Returns array of options from string with options separated by comma,
53 * removes quotes
55 * <code>
56 * getOptions("'option ,, quoted',abd,'2,3',");
57 * // array {
58 * // 'option ,, quoted',
59 * // 'abc',
60 * // '2,3',
61 * // '',
62 * // }
63 * </code>
65 * @param string $optionString comma separated options
67 * @return string[]
69 public function getOptions(string $optionString): array
71 if ($optionString === '') {
72 return [];
75 $transformOptions = explode(',', $optionString);
77 $result = [];
79 while (($option = array_shift($transformOptions)) !== null) {
80 $trimmed = trim($option);
81 if (strlen($trimmed) > 1 && $trimmed[0] == "'" && $trimmed[strlen($trimmed) - 1] == "'") {
82 // '...'
83 $option = mb_substr($trimmed, 1, -1);
84 } elseif (isset($trimmed[0]) && $trimmed[0] == "'") {
85 // '...,
86 $trimmed = ltrim($option);
87 $rtrimmed = '';
88 /** @infection-ignore-all */
89 while (($option = array_shift($transformOptions)) !== null) {
90 // ...,
91 $trimmed .= ',' . $option;
92 $rtrimmed = rtrim($trimmed);
93 if ($rtrimmed[strlen($rtrimmed) - 1] == "'") {
94 // ,...'
95 break;
99 $option = mb_substr($rtrimmed, 1, -1);
102 $result[] = stripslashes($option);
105 return $result;
109 * Gets all available MIME-types
111 * @return string[][] array[mimetype], array[transformation]
113 * @staticvar array $stack
115 public function getAvailableMimeTypes(): array
117 static $stack = null;
119 if ($stack !== null) {
120 return $stack;
123 $stack = [];
124 $subDirs = ['Input/' => 'input_', 'Output/' => '', '' => ''];
126 foreach ($subDirs as $sd => $prefix) {
127 $handle = opendir(ROOT_PATH . 'src/Plugins/Transformations/' . $sd);
129 if (! $handle) {
130 $stack[$prefix . 'transformation'] = [];
131 $stack[$prefix . 'transformation_file'] = [];
132 continue;
135 $filestack = [];
136 while ($file = readdir($handle)) {
137 // Ignore hidden files
138 if ($file[0] === '.') {
139 continue;
142 // Ignore old plugins (.class in filename)
143 if (str_contains($file, '.class')) {
144 continue;
147 $filestack[] = $file;
150 closedir($handle);
151 sort($filestack);
153 foreach ($filestack as $file) {
154 if (preg_match('|^[^.].*_.*_.*\.php$|', $file)) {
155 // File contains transformation functions.
156 $parts = explode('_', str_replace('.php', '', $file));
157 $mimetype = $parts[0] . '/' . $parts[1];
158 $stack['mimetype'][$mimetype] = $mimetype;
160 $stack[$prefix . 'transformation'][] = $mimetype . ': ' . $parts[2];
161 $stack[$prefix . 'transformation_file'][] = $sd . $file;
162 if ($sd === '') {
163 $stack['input_transformation'][] = $mimetype . ': ' . $parts[2];
164 $stack['input_transformation_file'][] = $sd . $file;
166 } elseif (preg_match('|^[^.].*\.php$|', $file)) {
167 // File is a plain mimetype, no functions.
168 $base = str_replace('.php', '', $file);
170 if ($base !== 'global') {
171 $mimetype = str_replace('_', '/', $base);
172 $stack['mimetype'][$mimetype] = $mimetype;
173 $stack['empty_mimetype'][$mimetype] = $mimetype;
179 return $stack;
183 * Returns the class name of the transformation
185 * @param string $filename transformation file name
187 * @return class-string<TransformationsInterface> the class name of transformation
189 private function getClassName(string $filename): string
191 return 'PhpMyAdmin\\Plugins\\Transformations\\' . str_replace('/', '\\', explode('.php', $filename)[0]);
194 public function getPluginInstance(string $filename): TransformationsInterface|null
196 $className = $this->getClassName($filename);
197 if (class_exists($className)) {
198 return new $className();
201 return null;
205 * Returns the description of the transformation
207 * @param string $file transformation file
209 * @return string the description of the transformation
211 public function getDescription(string $file): string
213 $className = $this->getClassName($file);
214 if (class_exists($className)) {
215 return $className::getInfo();
218 return '';
222 * Returns the name of the transformation
224 * @param string $file transformation file
226 * @return string the name of the transformation
228 public function getName(string $file): string
230 $className = $this->getClassName($file);
231 if (class_exists($className)) {
232 return $className::getName();
235 return '';
239 * Fixups old MIME or transformation name to new one
241 * - applies some hardcoded fixups
242 * - adds spaces after _ and numbers
243 * - capitalizes words
244 * - removes back spaces
246 * @param string $value Value to fixup
248 public function fixUpMime(string $value): string
250 $value = str_replace(
251 ['jpeg', 'png'],
252 ['JPEG', 'PNG'],
253 $value,
256 return str_replace(
257 ' ',
259 ucwords(
260 (string) preg_replace('/([0-9_]+)/', '$1 ', $value),
266 * Gets the mimetypes for all columns of a table
268 * @param string $db the name of the db to check for
269 * @param string $table the name of the table to check for
270 * @param bool $strict whether to include only results having a mimetype set
271 * @param bool $fullName whether to use full column names as the key
273 * @psalm-return array<string, array{
274 * column_name: string,
275 * mimetype: string,
276 * transformation: string,
277 * transformation_options: string,
278 * input_transformation: string,
279 * input_transformation_options: string
280 * }>|null
282 public function getMime(string $db, string $table, bool $strict = false, bool $fullName = false): array|null
284 $dbi = DatabaseInterface::getInstance();
285 $relation = new Relation($dbi);
286 $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature;
287 if ($browserTransformationFeature === null) {
288 return null;
291 $comQry = '';
292 if ($fullName) {
293 $comQry .= 'SELECT CONCAT(`db_name`, \'.\', `table_name`, \'.\', `column_name`) AS column_name, ';
294 } else {
295 $comQry = 'SELECT `column_name`, ';
298 $comQry .= '`mimetype`, '
299 . '`transformation`, '
300 . '`transformation_options`, '
301 . '`input_transformation`, '
302 . '`input_transformation_options`'
303 . ' FROM ' . Util::backquote($browserTransformationFeature->database) . '.'
304 . Util::backquote($browserTransformationFeature->columnInfo)
305 . ' WHERE `db_name` = ' . $dbi->quoteString($db, ConnectionType::ControlUser)
306 . ' AND `table_name` = ' . $dbi->quoteString($table, ConnectionType::ControlUser)
307 . ' AND ( `mimetype` != \'\'' . (! $strict ?
308 ' OR `transformation` != \'\''
309 . ' OR `transformation_options` != \'\''
310 . ' OR `input_transformation` != \'\''
311 . ' OR `input_transformation_options` != \'\'' : '') . ')';
314 * @psalm-var array<string, array{
315 * column_name: string,
316 * mimetype: string,
317 * transformation: string,
318 * transformation_options: string,
319 * input_transformation: string,
320 * input_transformation_options: string
321 * }> $result
323 $result = $dbi->fetchResult($comQry, 'column_name', null, ConnectionType::ControlUser);
325 foreach ($result as $column => $values) {
326 // convert mimetype to new format (f.e. Text_Plain, etc)
327 $values['mimetype'] = $this->fixUpMime($values['mimetype']);
329 // For transformation of form
330 // output/image_jpeg__inline.inc.php
331 // extract dir part.
332 $dir = explode('/', $values['transformation']);
333 $subdir = '';
334 if (count($dir) === 2) {
335 $subdir = ucfirst($dir[0]) . '/';
336 $values['transformation'] = $dir[1];
339 $values['transformation'] = $this->fixUpMime($values['transformation']);
340 $values['transformation'] = $subdir . $values['transformation'];
341 $result[$column] = $values;
344 return $result;
348 * Set a single mimetype to a certain value.
350 * @param string $db the name of the db
351 * @param string $table the name of the table
352 * @param string $key the name of the column
353 * @param string $mimetype the mimetype of the column
354 * @param string $transformation the transformation of the column
355 * @param string $transformationOpts the transformation options of the column
356 * @param string $inputTransform the input transformation of the column
357 * @param string $inputTransformOpts the input transformation options of the column
358 * @param bool $forcedelete force delete, will erase any existing
359 * comments for this column
361 public function setMime(
362 string $db,
363 string $table,
364 string $key,
365 string $mimetype,
366 string $transformation,
367 string $transformationOpts,
368 string $inputTransform,
369 string $inputTransformOpts,
370 bool $forcedelete = false,
371 ): bool {
372 $dbi = DatabaseInterface::getInstance();
373 $relation = new Relation($dbi);
374 $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature;
375 if ($browserTransformationFeature === null) {
376 return false;
379 // lowercase mimetype & transformation
380 $mimetype = mb_strtolower($mimetype);
381 $transformation = mb_strtolower($transformation);
383 // Do we have any parameter to set?
384 $hasValue =
385 $mimetype != '' ||
386 $transformation != '' ||
387 $transformationOpts !== '' ||
388 $inputTransform !== '' ||
389 $inputTransformOpts !== '';
391 $testQry = '
392 SELECT `mimetype`,
393 `comment`
394 FROM ' . Util::backquote($browserTransformationFeature->database) . '.'
395 . Util::backquote($browserTransformationFeature->columnInfo) . '
396 WHERE `db_name` = ' . $dbi->quoteString($db, ConnectionType::ControlUser) . '
397 AND `table_name` = ' . $dbi->quoteString($table, ConnectionType::ControlUser) . '
398 AND `column_name` = ' . $dbi->quoteString($key, ConnectionType::ControlUser);
400 $testRs = $dbi->queryAsControlUser($testQry);
402 if ($testRs->numRows() > 0) {
403 $row = $testRs->fetchAssoc();
405 if (! $forcedelete && ($hasValue || $row['comment'] != '')) {
406 $updQuery = 'UPDATE '
407 . Util::backquote($browserTransformationFeature->database) . '.'
408 . Util::backquote($browserTransformationFeature->columnInfo)
409 . ' SET '
410 . '`mimetype` = '
411 . $dbi->quoteString($mimetype, ConnectionType::ControlUser) . ', '
412 . '`transformation` = '
413 . $dbi->quoteString($transformation, ConnectionType::ControlUser) . ', '
414 . '`transformation_options` = '
415 . $dbi->quoteString($transformationOpts, ConnectionType::ControlUser) . ', '
416 . '`input_transformation` = '
417 . $dbi->quoteString($inputTransform, ConnectionType::ControlUser) . ', '
418 . '`input_transformation_options` = '
419 . $dbi->quoteString($inputTransformOpts, ConnectionType::ControlUser);
420 } else {
421 $updQuery = 'DELETE FROM '
422 . Util::backquote($browserTransformationFeature->database)
423 . '.' . Util::backquote($browserTransformationFeature->columnInfo);
426 $updQuery .= '
427 WHERE `db_name` = ' . $dbi->quoteString($db, ConnectionType::ControlUser) . '
428 AND `table_name` = ' . $dbi->quoteString($table, ConnectionType::ControlUser) . '
429 AND `column_name` = ' . $dbi->quoteString($key, ConnectionType::ControlUser);
430 } elseif ($hasValue) {
431 $updQuery = 'INSERT INTO '
432 . Util::backquote($browserTransformationFeature->database)
433 . '.' . Util::backquote($browserTransformationFeature->columnInfo)
434 . ' (db_name, table_name, column_name, mimetype, '
435 . 'transformation, transformation_options, '
436 . 'input_transformation, input_transformation_options) '
437 . ' VALUES('
438 . $dbi->quoteString($db, ConnectionType::ControlUser) . ','
439 . $dbi->quoteString($table, ConnectionType::ControlUser) . ','
440 . $dbi->quoteString($key, ConnectionType::ControlUser) . ','
441 . $dbi->quoteString($mimetype, ConnectionType::ControlUser) . ','
442 . $dbi->quoteString($transformation, ConnectionType::ControlUser) . ','
443 . $dbi->quoteString($transformationOpts, ConnectionType::ControlUser) . ','
444 . $dbi->quoteString($inputTransform, ConnectionType::ControlUser) . ','
445 . $dbi->quoteString($inputTransformOpts, ConnectionType::ControlUser) . ')';
448 if (isset($updQuery)) {
449 return (bool) $dbi->queryAsControlUser($updQuery);
452 return false;
456 * GLOBAL Plugin functions
460 * Delete related transformation details
461 * after deleting database. table or column
463 * @param string $db Database name
464 * @param string $table Table name
465 * @param string $column Column name
467 public function clear(string $db, string $table = '', string $column = ''): bool
469 $dbi = DatabaseInterface::getInstance();
470 $relation = new Relation($dbi);
471 $browserTransformationFeature = $relation->getRelationParameters()->browserTransformationFeature;
472 if ($browserTransformationFeature === null) {
473 return false;
476 $deleteSql = 'DELETE FROM '
477 . Util::backquote($browserTransformationFeature->database) . '.'
478 . Util::backquote($browserTransformationFeature->columnInfo)
479 . ' WHERE ';
481 if ($column !== '' && $table !== '') {
482 $deleteSql .= '`db_name` = \'' . $db . '\' AND '
483 . '`table_name` = \'' . $table . '\' AND '
484 . '`column_name` = \'' . $column . '\' ';
485 } elseif ($table !== '') {
486 $deleteSql .= '`db_name` = \'' . $db . '\' AND '
487 . '`table_name` = \'' . $table . '\' ';
488 } else {
489 $deleteSql .= '`db_name` = \'' . $db . '\' ';
492 return (bool) $dbi->tryQuery($deleteSql);