<?php /* * AdminerDumpMarkdown - dump to MARKDOWN format v0.9 (March 12th, 2025) * * @link https://github.com/fthiella/adminer-plugin-dump-markdown * @author Federico Thiella, https://fthiella.github.io/ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) * */ class AdminerDumpMarkdown { private $type = 'markdown'; private $format = 'Markdown'; private $markdown_chr; private $rowSampleLimit; private $nullValue; private $specialChars; private $disableUTF8; private $mbStrAvailable; function __construct($config = []) { $this->rowSampleLimit = $config['rowSampleLimit'] ?? 100; $this->nullValue = $config['nullValue'] ?? "N/D"; $this->specialChars = $config['specialChars'] ?? '\\*_[](){}+-#.!|'; $this->markdown_chr = $config['markdown_chr'] ?? ['space' => ' ', 'table' => '|', 'header' => '-']; $this->disableUTF8 = $config['disableUTF8'] ?? False; if (extension_loaded('mbstring')) { $this->mbStrAvailable = true; } else { $this->mbStrAvailable = false; // also set disableUTF8 to true? } if (!$this->mbStrAvailable && !$this->disableUTF8) { echo "> WARNING: The PHP 'mbstring' extension is NOT enabled. Consider enabling 'mbstring' for better UTF-8 support.\n\n"; } } function _getAdminerConnection() { if (function_exists('Adminer\connection')) { return Adminer\connection(); } return Adminer\connection(); } function _getAdminerFields($table) { if (function_exists('Adminer\fields')) { return Adminer\fields($table); } return Adminer\fields($table); } function _getStringLength($value) { if ($this->disableUTF8 || !$this->mbStrAvailable) { return strlen($value); } return mb_strlen($value, 'UTF-8'); } function _getStrPos($special, $chr) { if ($this->disableUTF8 || !$this->mbStrAvailable) { return strpos($special, $chr); } return mb_strpos($special, $chr); } function _getSubString($value, $start, $length) { if ($this->disableUTF8 || !$this->mbStrAvailable) { return substr($value, $start, $length); } return mb_substr($value, $start, $length, 'UTF-8'); } function _escape_markdown($value) { $escaped_value = ""; $value = strval($value); if ($this->disableUTF8) { $value = utf8_decode($value); } for ($i = 0; $i < $this->_getStringLength($value); $i++) { $char = $this->_getSubString($value, $i, 1); if ($this->_getStrPos($this->specialChars, $char) !== false) { $escaped_value .= '\\' . $char; } else { $escaped_value .= $char; } } return $escaped_value; } function _process_value($value) { if($value === null) { return $this->nullValue; } return $this->_escape_markdown($value); } function _format_value($s, $l, $c) { return ($this->_getStringLength($s) > $l) ? $this->_getSubString($s, 0, $l) : $s.str_repeat($c, $l-$this->_getStringLength($s)); } function _map($array, $width, $c) { foreach ($array as $k => &$v) $v = $this->_format_value($v, $width[$k], $c); return $array; } function _map_header($array) { foreach ($array as $k => &$v) $v = $this->_process_value($k); return $array; } function _map_mtable($array) { foreach ($array as $k => &$v) $v = $this->markdown_chr['header']; return $array; } function _markdown_row($row, $column_width, $separator, $filler) { return implode($separator, $this->_map($row, $column_width, $filler)); } function _markdown_table($rows, $column_width) { $content = $this->_markdown_row($this->_map_header($rows[0]), $column_width, $this->markdown_chr['space'] . $this->markdown_chr['table'] . $this->markdown_chr['space'], $this->markdown_chr['space']) . "\n"; $content .= $this->_markdown_row($this->_map_mtable($rows[0]), $column_width, $this->markdown_chr['header'] . $this->markdown_chr['table'] . $this->markdown_chr['header'], $this->markdown_chr['header']) . "\n"; foreach ($rows as $row) { $content .= $this->_markdown_row($row, $column_width, $this->markdown_chr['space'] . $this->markdown_chr['table'] . $this->markdown_chr['space'], $this->markdown_chr['space']) . "\n"; } return $content; } function _bool($value) { return $value == 1 ? 'Yes' : 'No'; } function dumpFormat() { return array($this->type => $this->format); } function dumpDatabase($db) { if ($_POST["format"] == $this->format) { echo '# ' . $db . "\n\n"; return true; } } /* export table structure */ function dumpTable($table, $style, $is_view = false) { if ($_POST["format"] == $this->type) { echo '## ' . $this->_escape_markdown($table) . "\n\n"; if ($style) { echo "### table structure\n\n"; $field_rows = array(); $field_width = (['Column name' => 11, 'Type' => 4, 'Comment' => 7, 'Null' => 4, 'AI' => 2]); foreach ($this->_getAdminerFields($table) as $field) { $new_row = [ 'Column name' => $this->_process_value($field['field']), 'Type' => $field['full_type'], 'Comment' => $field['comment'], 'Null' => $this->_bool($field['null']), 'AI' => $this->_bool($field['auto_increment']) ]; array_push($field_rows, $new_row); foreach ($new_row as $key => $val) { $field_width[$key] = max($field_width[$key], $this->_getStringLength($new_row[$key])); } } echo $this->_markdown_table($field_rows, $field_width); echo "\n"; } return true; } } /* export table data */ function dumpData($table, $style, $query) { if ($_POST["format"] == $this->type) { echo "### table data\n\n"; $connection = $this->_getAdminerConnection(); $result = $connection->query($query, 1); if ($result) { $rn = 0; $sample_rows = array(); $column_width = array(); while ($raw_row = $result->fetch_assoc()) { // process row for output $row = []; foreach($raw_row as $key => $value) { $row[$key] = $this->_process_value($value); } // end process row switch(true) { case $rn==0: foreach ($row as $key => $val) { $column_width[$key] = $this->_getStringLength($this->_process_value($key)); // escape here? } case $rn<$this->rowSampleLimit: $sample_rows[$rn]=$row; foreach ($row as $key => $val) { $column_width[$key] = max($column_width[$key], $this->_getStringLength($row[$key])); } break; case $rn==$this->rowSampleLimit: echo $this->_markdown_table($sample_rows, $column_width); default: echo $this->_markdown_row($row, $column_width, $this->markdown_chr['space'] . $this->markdown_chr['table'] . $this->markdown_chr['space'], $this->markdown_chr['space']) . "\n"; } $rn++; } if ($rn<=$this->rowSampleLimit) { echo $this->_markdown_table($sample_rows, $column_width); } echo "\n"; } return true; } } function dumpHeaders($identifier, $multi_table = false) { if ($_POST["format"] == $this->type) { header("Content-Type: text/markdown; charset=utf-8"); return "md"; } } }