Exclude test/doctum-config.php from Scrutinizer analysis
[phpmyadmin.git] / libraries / classes / Transformations.php
blobc02e94109a489c57e8d8d5b19475e6afafa569c5
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Set of functions used with the relation and pdf feature
6 * This file also provides basic functions to use in other plugins!
7 * These are declared in the 'GLOBAL Plugin functions' section
9 * Please use short and expressive names.
10 * For now, special characters which aren't allowed in
11 * filenames or functions should not be used.
13 * Please provide a comment for your function,
14 * what it does and what parameters are available.
16 * @package PhpMyAdmin
18 declare(strict_types=1);
20 namespace PhpMyAdmin;
22 use PhpMyAdmin\DatabaseInterface;
23 use PhpMyAdmin\Plugins\TransformationsInterface;
24 use PhpMyAdmin\Relation;
25 use PhpMyAdmin\Util;
27 /**
28 * Transformations class
30 * @package PhpMyAdmin
32 class Transformations
34 /**
35 * Returns array of options from string with options separated by comma,
36 * removes quotes
38 * <code>
39 * getOptions("'option ,, quoted',abd,'2,3',");
40 * // array {
41 * // 'option ,, quoted',
42 * // 'abc',
43 * // '2,3',
44 * // '',
45 * // }
46 * </code>
48 * @param string $option_string comma separated options
50 * @return array options
52 public function getOptions($option_string)
54 $result = [];
56 if (strlen($option_string) === 0
57 || ! $transform_options = explode(",", $option_string)
58 ) {
59 return $result;
62 while (($option = array_shift($transform_options)) !== null) {
63 $trimmed = trim($option);
64 if (strlen($trimmed) > 1
65 && $trimmed[0] == "'"
66 && $trimmed[strlen($trimmed) - 1] == "'"
67 ) {
68 // '...'
69 $option = mb_substr($trimmed, 1, -1);
70 } elseif (isset($trimmed[0]) && $trimmed[0] == "'") {
71 // '...,
72 $trimmed = ltrim($option);
73 $rtrimmed = null;
74 while (($option = array_shift($transform_options)) !== null) {
75 // ...,
76 $trimmed .= ',' . $option;
77 $rtrimmed = rtrim($trimmed);
78 if ($rtrimmed[strlen($rtrimmed) - 1] == "'") {
79 // ,...'
80 break;
83 $option = mb_substr($rtrimmed, 1, -1);
85 $result[] = stripslashes($option);
88 return $result;
91 /**
92 * Gets all available MIME-types
94 * @access public
95 * @staticvar array mimetypes
96 * @return array array[mimetype], array[transformation]
98 public function getAvailableMimeTypes()
100 static $stack = null;
102 if (null !== $stack) {
103 return $stack;
106 $stack = [];
107 $sub_dirs = [
108 'Input/' => 'input_',
109 'Output/' => '',
110 '' => '',
113 foreach ($sub_dirs as $sd => $prefix) {
114 $handle = opendir('libraries/classes/Plugins/Transformations/' . $sd);
116 if (! $handle) {
117 $stack[$prefix . 'transformation'] = [];
118 $stack[$prefix . 'transformation_file'] = [];
119 continue;
122 $filestack = [];
123 while ($file = readdir($handle)) {
124 // Ignore hidden files
125 if ($file[0] == '.') {
126 continue;
128 // Ignore old plugins (.class in filename)
129 if (strpos($file, '.class') !== false) {
130 continue;
132 $filestack[] = $file;
135 closedir($handle);
136 sort($filestack);
138 foreach ($filestack as $file) {
139 if (preg_match('|^[^.].*_.*_.*\.php$|', $file)) {
140 // File contains transformation functions.
141 $parts = explode('_', str_replace('.php', '', $file));
142 $mimetype = $parts[0] . "/" . $parts[1];
143 $stack['mimetype'][$mimetype] = $mimetype;
145 $stack[$prefix . 'transformation'][] = $mimetype . ': ' . $parts[2];
146 $stack[$prefix . 'transformation_file'][] = $sd . $file;
147 if ($sd === '') {
148 $stack['input_transformation'][] = $mimetype . ': ' . $parts[2];
149 $stack['input_transformation_file'][] = $sd . $file;
151 } elseif (preg_match('|^[^.].*\.php$|', $file)) {
152 // File is a plain mimetype, no functions.
153 $base = str_replace('.php', '', $file);
155 if ($base != 'global') {
156 $mimetype = str_replace('_', '/', $base);
157 $stack['mimetype'][$mimetype] = $mimetype;
158 $stack['empty_mimetype'][$mimetype] = $mimetype;
163 return $stack;
167 * Returns the class name of the transformation
169 * @param string $filename transformation file name
171 * @return string the class name of transformation
173 public function getClassName($filename)
175 // get the transformation class name
176 $class_name = explode(".php", $filename);
177 $class_name = 'PhpMyAdmin\\' . str_replace('/', '\\', mb_substr($class_name[0], 18));
179 return $class_name;
183 * Returns the description of the transformation
185 * @param string $file transformation file
187 * @return string the description of the transformation
189 public function getDescription($file)
191 $include_file = 'libraries/classes/Plugins/Transformations/' . $file;
192 /** @var TransformationsInterface $class_name */
193 $class_name = $this->getClassName($include_file);
194 if (class_exists($class_name)) {
195 return $class_name::getInfo();
197 return '';
201 * Returns the name of the transformation
203 * @param string $file transformation file
205 * @return string the name of the transformation
207 public function getName($file)
209 $include_file = 'libraries/classes/Plugins/Transformations/' . $file;
210 /** @var TransformationsInterface $class_name */
211 $class_name = $this->getClassName($include_file);
212 if (class_exists($class_name)) {
213 return $class_name::getName();
215 return '';
219 * Fixups old MIME or transformation name to new one
221 * - applies some hardcoded fixups
222 * - adds spaces after _ and numbers
223 * - capitalizes words
224 * - removes back spaces
226 * @param string $value Value to fixup
228 * @return string
230 public function fixUpMime($value)
232 $value = str_replace(
234 "jpeg",
235 "png",
238 "JPEG",
239 "PNG",
241 $value
243 return str_replace(
244 ' ',
246 ucwords(
247 preg_replace('/([0-9_]+)/', '$1 ', $value)
253 * Gets the mimetypes for all columns of a table
255 * @param string $db the name of the db to check for
256 * @param string $table the name of the table to check for
257 * @param boolean $strict whether to include only results having a mimetype set
258 * @param boolean $fullName whether to use full column names as the key
260 * @access public
262 * @return array|bool [field_name][field_key] = field_value
264 public function getMime($db, $table, $strict = false, $fullName = false)
266 $relation = new Relation($GLOBALS['dbi']);
267 $cfgRelation = $relation->getRelationsParam();
269 if (! $cfgRelation['mimework']) {
270 return false;
273 $com_qry = '';
274 if ($fullName) {
275 $com_qry .= "SELECT CONCAT("
276 . "`db_name`, '.', `table_name`, '.', `column_name`"
277 . ") AS column_name, ";
278 } else {
279 $com_qry = "SELECT `column_name`, ";
281 $com_qry .= '`mimetype`, '
282 . '`transformation`, '
283 . '`transformation_options`, '
284 . '`input_transformation`, '
285 . '`input_transformation_options`'
286 . ' FROM ' . Util::backquote($cfgRelation['db']) . '.'
287 . Util::backquote($cfgRelation['column_info'])
288 . ' WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\''
289 . ' AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\''
290 . ' AND ( `mimetype` != \'\'' . (! $strict ?
291 ' OR `transformation` != \'\''
292 . ' OR `transformation_options` != \'\''
293 . ' OR `input_transformation` != \'\''
294 . ' OR `input_transformation_options` != \'\'' : '') . ')';
295 $result = $GLOBALS['dbi']->fetchResult(
296 $com_qry,
297 'column_name',
298 null,
299 DatabaseInterface::CONNECT_CONTROL
302 foreach ($result as $column => $values) {
303 // convert mimetype to new format (f.e. Text_Plain, etc)
304 $values['mimetype'] = $this->fixUpMime($values['mimetype']);
306 // For transformation of form
307 // output/image_jpeg__inline.inc.php
308 // extract dir part.
309 $dir = explode('/', $values['transformation']);
310 $subdir = '';
311 if (count($dir) === 2) {
312 $subdir = ucfirst($dir[0]) . '/';
313 $values['transformation'] = $dir[1];
316 $values['transformation'] = $this->fixUpMime($values['transformation']);
317 $values['transformation'] = $subdir . $values['transformation'];
318 $result[$column] = $values;
321 return $result;
325 * Set a single mimetype to a certain value.
327 * @param string $db the name of the db
328 * @param string $table the name of the table
329 * @param string $key the name of the column
330 * @param string $mimetype the mimetype of the column
331 * @param string $transformation the transformation of the column
332 * @param string $transformationOpts the transformation options of the column
333 * @param string $inputTransform the input transformation of the column
334 * @param string $inputTransformOpts the input transformation options of the column
335 * @param boolean $forcedelete force delete, will erase any existing
336 * comments for this column
338 * @access public
340 * @return boolean true, if comment-query was made.
342 public function setMime(
343 $db,
344 $table,
345 $key,
346 $mimetype,
347 $transformation,
348 $transformationOpts,
349 $inputTransform,
350 $inputTransformOpts,
351 $forcedelete = false
353 $relation = new Relation($GLOBALS['dbi']);
354 $cfgRelation = $relation->getRelationsParam();
356 if (! $cfgRelation['mimework']) {
357 return false;
360 // lowercase mimetype & transformation
361 $mimetype = mb_strtolower($mimetype);
362 $transformation = mb_strtolower($transformation);
364 // Do we have any parameter to set?
365 $has_value = (
366 strlen($mimetype) > 0 ||
367 strlen($transformation) > 0 ||
368 strlen($transformationOpts) > 0 ||
369 strlen($inputTransform) > 0 ||
370 strlen($inputTransformOpts) > 0
373 $test_qry = '
374 SELECT `mimetype`,
375 `comment`
376 FROM ' . Util::backquote($cfgRelation['db']) . '.'
377 . Util::backquote($cfgRelation['column_info']) . '
378 WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\'
379 AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table) . '\'
380 AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key) . '\'';
382 $test_rs = $relation->queryAsControlUser(
383 $test_qry,
384 true,
385 DatabaseInterface::QUERY_STORE
388 if ($test_rs && $GLOBALS['dbi']->numRows($test_rs) > 0) {
389 $row = @$GLOBALS['dbi']->fetchAssoc($test_rs);
390 $GLOBALS['dbi']->freeResult($test_rs);
392 if (! $forcedelete && ($has_value || strlen($row['comment']) > 0)) {
393 $upd_query = 'UPDATE '
394 . Util::backquote($cfgRelation['db']) . '.'
395 . Util::backquote($cfgRelation['column_info'])
396 . ' SET '
397 . '`mimetype` = \''
398 . $GLOBALS['dbi']->escapeString($mimetype) . '\', '
399 . '`transformation` = \''
400 . $GLOBALS['dbi']->escapeString($transformation) . '\', '
401 . '`transformation_options` = \''
402 . $GLOBALS['dbi']->escapeString($transformationOpts) . '\', '
403 . '`input_transformation` = \''
404 . $GLOBALS['dbi']->escapeString($inputTransform) . '\', '
405 . '`input_transformation_options` = \''
406 . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\'';
407 } else {
408 $upd_query = 'DELETE FROM '
409 . Util::backquote($cfgRelation['db'])
410 . '.' . Util::backquote($cfgRelation['column_info']);
412 $upd_query .= '
413 WHERE `db_name` = \'' . $GLOBALS['dbi']->escapeString($db) . '\'
414 AND `table_name` = \'' . $GLOBALS['dbi']->escapeString($table)
415 . '\'
416 AND `column_name` = \'' . $GLOBALS['dbi']->escapeString($key)
417 . '\'';
418 } elseif ($has_value) {
419 $upd_query = 'INSERT INTO '
420 . Util::backquote($cfgRelation['db'])
421 . '.' . Util::backquote($cfgRelation['column_info'])
422 . ' (db_name, table_name, column_name, mimetype, '
423 . 'transformation, transformation_options, '
424 . 'input_transformation, input_transformation_options) '
425 . ' VALUES('
426 . '\'' . $GLOBALS['dbi']->escapeString($db) . '\','
427 . '\'' . $GLOBALS['dbi']->escapeString($table) . '\','
428 . '\'' . $GLOBALS['dbi']->escapeString($key) . '\','
429 . '\'' . $GLOBALS['dbi']->escapeString($mimetype) . '\','
430 . '\'' . $GLOBALS['dbi']->escapeString($transformation) . '\','
431 . '\'' . $GLOBALS['dbi']->escapeString($transformationOpts) . '\','
432 . '\'' . $GLOBALS['dbi']->escapeString($inputTransform) . '\','
433 . '\'' . $GLOBALS['dbi']->escapeString($inputTransformOpts) . '\')';
436 if (isset($upd_query)) {
437 return $relation->queryAsControlUser($upd_query);
440 return false;
445 * GLOBAL Plugin functions
449 * Delete related transformation details
450 * after deleting database. table or column
452 * @param string $db Database name
453 * @param string $table Table name
454 * @param string $column Column name
456 * @return boolean State of the query execution
458 public function clear($db, $table = '', $column = '')
460 $relation = new Relation($GLOBALS['dbi']);
461 $cfgRelation = $relation->getRelationsParam();
463 if (! isset($cfgRelation['column_info'])) {
464 return false;
467 $delete_sql = 'DELETE FROM '
468 . Util::backquote($cfgRelation['db']) . '.'
469 . Util::backquote($cfgRelation['column_info'])
470 . ' WHERE ';
472 if (($column != '') && ($table != '')) {
473 $delete_sql .= '`db_name` = \'' . $db . '\' AND '
474 . '`table_name` = \'' . $table . '\' AND '
475 . '`column_name` = \'' . $column . '\' ';
476 } elseif ($table != '') {
477 $delete_sql .= '`db_name` = \'' . $db . '\' AND '
478 . '`table_name` = \'' . $table . '\' ';
479 } else {
480 $delete_sql .= '`db_name` = \'' . $db . '\' ';
483 return $GLOBALS['dbi']->tryQuery($delete_sql);