StorageEngine.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. <?php
  2. /**
  3. * Library for extracting information about the available storage engines
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin;
  7. use PhpMyAdmin\Engines\Bdb;
  8. use PhpMyAdmin\Engines\Berkeleydb;
  9. use PhpMyAdmin\Engines\Binlog;
  10. use PhpMyAdmin\Engines\Innobase;
  11. use PhpMyAdmin\Engines\Innodb;
  12. use PhpMyAdmin\Engines\Memory;
  13. use PhpMyAdmin\Engines\Merge;
  14. use PhpMyAdmin\Engines\MrgMyisam;
  15. use PhpMyAdmin\Engines\Myisam;
  16. use PhpMyAdmin\Engines\Ndbcluster;
  17. use PhpMyAdmin\Engines\Pbxt;
  18. use PhpMyAdmin\Engines\PerformanceSchema;
  19. use PhpMyAdmin\Html\Generator;
  20. use PhpMyAdmin\Utils\SessionCache;
  21. use function array_key_exists;
  22. use function define;
  23. use function explode;
  24. use function htmlspecialchars;
  25. use function mb_stripos;
  26. use function mb_strtolower;
  27. use function sprintf;
  28. /**
  29. * defines
  30. */
  31. define('PMA_ENGINE_SUPPORT_NO', 0);
  32. define('PMA_ENGINE_SUPPORT_DISABLED', 1);
  33. define('PMA_ENGINE_SUPPORT_YES', 2);
  34. define('PMA_ENGINE_SUPPORT_DEFAULT', 3);
  35. define('PMA_ENGINE_DETAILS_TYPE_PLAINTEXT', 0);
  36. define('PMA_ENGINE_DETAILS_TYPE_SIZE', 1);
  37. define('PMA_ENGINE_DETAILS_TYPE_NUMERIC', 2); //Has no effect yet...
  38. define('PMA_ENGINE_DETAILS_TYPE_BOOLEAN', 3); // 'ON' or 'OFF'
  39. /**
  40. * Base Storage Engine Class
  41. */
  42. class StorageEngine
  43. {
  44. /** @var string engine name */
  45. public $engine = 'dummy';
  46. /** @var string engine title/description */
  47. public $title = 'PMA Dummy Engine Class';
  48. /** @var string engine lang description */
  49. public $comment
  50. = 'If you read this text inside phpMyAdmin, something went wrong...';
  51. /** @var int engine supported by current server */
  52. public $support = PMA_ENGINE_SUPPORT_NO;
  53. /**
  54. * @param string $engine The engine ID
  55. */
  56. public function __construct($engine)
  57. {
  58. $storage_engines = self::getStorageEngines();
  59. if (empty($storage_engines[$engine])) {
  60. return;
  61. }
  62. $this->engine = $engine;
  63. $this->title = $storage_engines[$engine]['Engine'];
  64. $this->comment = ($storage_engines[$engine]['Comment'] ?? '');
  65. switch ($storage_engines[$engine]['Support']) {
  66. case 'DEFAULT':
  67. $this->support = PMA_ENGINE_SUPPORT_DEFAULT;
  68. break;
  69. case 'YES':
  70. $this->support = PMA_ENGINE_SUPPORT_YES;
  71. break;
  72. case 'DISABLED':
  73. $this->support = PMA_ENGINE_SUPPORT_DISABLED;
  74. break;
  75. case 'NO':
  76. default:
  77. $this->support = PMA_ENGINE_SUPPORT_NO;
  78. }
  79. }
  80. /**
  81. * Returns array of storage engines
  82. *
  83. * @return array[] array of storage engines
  84. *
  85. * @static
  86. * @staticvar array $storage_engines storage engines
  87. * @access public
  88. */
  89. public static function getStorageEngines()
  90. {
  91. global $dbi;
  92. static $storage_engines = null;
  93. if ($storage_engines == null) {
  94. $storage_engines = $dbi->fetchResult('SHOW STORAGE ENGINES', 'Engine');
  95. if ($dbi->getVersion() >= 50708) {
  96. $disabled = (string) SessionCache::get(
  97. 'disabled_storage_engines',
  98. static function () use ($dbi) {
  99. return $dbi->fetchValue(
  100. 'SELECT @@disabled_storage_engines'
  101. );
  102. }
  103. );
  104. foreach (explode(',', $disabled) as $engine) {
  105. if (! isset($storage_engines[$engine])) {
  106. continue;
  107. }
  108. $storage_engines[$engine]['Support'] = 'DISABLED';
  109. }
  110. }
  111. }
  112. return $storage_engines;
  113. }
  114. /**
  115. * @return array<int|string, array<string, mixed>>
  116. */
  117. public static function getArray(): array
  118. {
  119. $engines = [];
  120. foreach (self::getStorageEngines() as $details) {
  121. // Don't show PERFORMANCE_SCHEMA engine (MySQL 5.5)
  122. if ($details['Support'] === 'NO'
  123. || $details['Support'] === 'DISABLED'
  124. || $details['Engine'] === 'PERFORMANCE_SCHEMA'
  125. ) {
  126. continue;
  127. }
  128. $engines[$details['Engine']] = [
  129. 'name' => $details['Engine'],
  130. 'comment' => $details['Comment'],
  131. 'is_default' => $details['Support'] === 'DEFAULT',
  132. ];
  133. }
  134. return $engines;
  135. }
  136. /**
  137. * Loads the corresponding engine plugin, if available.
  138. *
  139. * @param string $engine The engine ID
  140. *
  141. * @return StorageEngine The engine plugin
  142. *
  143. * @static
  144. */
  145. public static function getEngine($engine)
  146. {
  147. switch (mb_strtolower($engine)) {
  148. case 'bdb':
  149. return new Bdb($engine);
  150. case 'berkeleydb':
  151. return new Berkeleydb($engine);
  152. case 'binlog':
  153. return new Binlog($engine);
  154. case 'innobase':
  155. return new Innobase($engine);
  156. case 'innodb':
  157. return new Innodb($engine);
  158. case 'memory':
  159. return new Memory($engine);
  160. case 'merge':
  161. return new Merge($engine);
  162. case 'mrg_myisam':
  163. return new MrgMyisam($engine);
  164. case 'myisam':
  165. return new Myisam($engine);
  166. case 'ndbcluster':
  167. return new Ndbcluster($engine);
  168. case 'pbxt':
  169. return new Pbxt($engine);
  170. case 'performance_schema':
  171. return new PerformanceSchema($engine);
  172. default:
  173. return new StorageEngine($engine);
  174. }
  175. }
  176. /**
  177. * Returns true if given engine name is supported/valid, otherwise false
  178. *
  179. * @param string $engine name of engine
  180. *
  181. * @return bool whether $engine is valid or not
  182. *
  183. * @static
  184. */
  185. public static function isValid($engine)
  186. {
  187. if ($engine === 'PBMS') {
  188. return true;
  189. }
  190. $storage_engines = self::getStorageEngines();
  191. return isset($storage_engines[$engine]);
  192. }
  193. /**
  194. * Returns as HTML table of the engine's server variables
  195. *
  196. * @return string The table that was generated based on the retrieved
  197. * information
  198. */
  199. public function getHtmlVariables()
  200. {
  201. $ret = '';
  202. foreach ($this->getVariablesStatus() as $details) {
  203. $ret .= '<tr>' . "\n"
  204. . ' <td>' . "\n";
  205. if (! empty($details['desc'])) {
  206. $ret .= ' '
  207. . Generator::showHint($details['desc'])
  208. . "\n";
  209. }
  210. $ret .= ' </td>' . "\n"
  211. . ' <th scope="row">' . htmlspecialchars($details['title']) . '</th>'
  212. . "\n"
  213. . ' <td class="text-monospace text-right">';
  214. switch ($details['type']) {
  215. case PMA_ENGINE_DETAILS_TYPE_SIZE:
  216. $parsed_size = $this->resolveTypeSize($details['value']);
  217. $ret .= $parsed_size[0] . '&nbsp;' . $parsed_size[1];
  218. unset($parsed_size);
  219. break;
  220. case PMA_ENGINE_DETAILS_TYPE_NUMERIC:
  221. $ret .= Util::formatNumber($details['value']) . ' ';
  222. break;
  223. default:
  224. $ret .= htmlspecialchars($details['value']) . ' ';
  225. }
  226. $ret .= '</td>' . "\n"
  227. . '</tr>' . "\n";
  228. }
  229. if (! $ret) {
  230. $ret = '<p>' . "\n"
  231. . ' '
  232. . __(
  233. 'There is no detailed status information available for this '
  234. . 'storage engine.'
  235. )
  236. . "\n"
  237. . '</p>' . "\n";
  238. } else {
  239. $ret = '<table class="table table-light table-striped table-hover w-auto">'
  240. . "\n" . $ret . '</table>' . "\n";
  241. }
  242. return $ret;
  243. }
  244. /**
  245. * Returns the engine specific handling for
  246. * PMA_ENGINE_DETAILS_TYPE_SIZE type variables.
  247. *
  248. * This function should be overridden when
  249. * PMA_ENGINE_DETAILS_TYPE_SIZE type needs to be
  250. * handled differently for a particular engine.
  251. *
  252. * @param int $value Value to format
  253. *
  254. * @return array the formatted value and its unit
  255. */
  256. public function resolveTypeSize($value)
  257. {
  258. return Util::formatByteDown($value);
  259. }
  260. /**
  261. * Returns array with detailed info about engine specific server variables
  262. *
  263. * @return array array with detailed info about specific engine server variables
  264. */
  265. public function getVariablesStatus()
  266. {
  267. global $dbi;
  268. $variables = $this->getVariables();
  269. $like = $this->getVariablesLikePattern();
  270. if ($like) {
  271. $like = " LIKE '" . $like . "' ";
  272. } else {
  273. $like = '';
  274. }
  275. $mysql_vars = [];
  276. $sql_query = 'SHOW GLOBAL VARIABLES ' . $like . ';';
  277. $res = $dbi->query($sql_query);
  278. while ($row = $dbi->fetchAssoc($res)) {
  279. if (isset($variables[$row['Variable_name']])) {
  280. $mysql_vars[$row['Variable_name']]
  281. = $variables[$row['Variable_name']];
  282. } elseif (! $like
  283. && mb_stripos($row['Variable_name'], $this->engine) !== 0
  284. ) {
  285. continue;
  286. }
  287. $mysql_vars[$row['Variable_name']]['value'] = $row['Value'];
  288. if (empty($mysql_vars[$row['Variable_name']]['title'])) {
  289. $mysql_vars[$row['Variable_name']]['title'] = $row['Variable_name'];
  290. }
  291. if (isset($mysql_vars[$row['Variable_name']]['type'])) {
  292. continue;
  293. }
  294. $mysql_vars[$row['Variable_name']]['type']
  295. = PMA_ENGINE_DETAILS_TYPE_PLAINTEXT;
  296. }
  297. $dbi->freeResult($res);
  298. return $mysql_vars;
  299. }
  300. /**
  301. * Reveals the engine's title
  302. *
  303. * @return string The title
  304. */
  305. public function getTitle()
  306. {
  307. return $this->title;
  308. }
  309. /**
  310. * Fetches the server's comment about this engine
  311. *
  312. * @return string The comment
  313. */
  314. public function getComment()
  315. {
  316. return $this->comment;
  317. }
  318. /**
  319. * Information message on whether this storage engine is supported
  320. *
  321. * @return string The localized message.
  322. */
  323. public function getSupportInformationMessage()
  324. {
  325. switch ($this->support) {
  326. case PMA_ENGINE_SUPPORT_DEFAULT:
  327. $message = __('%s is the default storage engine on this MySQL server.');
  328. break;
  329. case PMA_ENGINE_SUPPORT_YES:
  330. $message = __('%s is available on this MySQL server.');
  331. break;
  332. case PMA_ENGINE_SUPPORT_DISABLED:
  333. $message = __('%s has been disabled for this MySQL server.');
  334. break;
  335. case PMA_ENGINE_SUPPORT_NO:
  336. default:
  337. $message = __(
  338. 'This MySQL server does not support the %s storage engine.'
  339. );
  340. }
  341. return sprintf($message, htmlspecialchars($this->title));
  342. }
  343. /**
  344. * Generates a list of MySQL variables that provide information about this
  345. * engine. This function should be overridden when extending this class
  346. * for a particular engine.
  347. *
  348. * @return array The list of variables.
  349. */
  350. public function getVariables()
  351. {
  352. return [];
  353. }
  354. /**
  355. * Returns string with filename for the MySQL helppage
  356. * about this storage engine
  357. *
  358. * @return string MySQL help page filename
  359. */
  360. public function getMysqlHelpPage()
  361. {
  362. return $this->engine . '-storage-engine';
  363. }
  364. /**
  365. * Returns the pattern to be used in the query for SQL variables
  366. * related to the storage engine
  367. *
  368. * @return string SQL query LIKE pattern
  369. */
  370. public function getVariablesLikePattern()
  371. {
  372. return '';
  373. }
  374. /**
  375. * Returns a list of available information pages with labels
  376. *
  377. * @return string[] The list
  378. */
  379. public function getInfoPages()
  380. {
  381. return [];
  382. }
  383. /**
  384. * Generates the requested information page
  385. *
  386. * @param string $id page id
  387. *
  388. * @return string html output
  389. */
  390. public function getPage($id)
  391. {
  392. if (! array_key_exists($id, $this->getInfoPages())) {
  393. return '';
  394. }
  395. $id = 'getPage' . $id;
  396. return $this->$id();
  397. }
  398. }