PluginProbe
Trinity Backup – Backup, Migrate, Restore, Clone & Schedule Backups / 2.0.5
Trinity Backup – Backup, Migrate, Restore, Clone & Schedule Backups v2.0.5
trunk 2.0.10 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9
trinity-backup / src / Database / Drivers / MysqliDriver.php

MysqliDriver.php in Trinity Backup – Backup, Migrate, Restore, Clone & Schedule Backups 2.0.5, at src/Database/Drivers/MysqliDriver.php

108 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4 namespace TrinityBackup\Database\Drivers;
5
6 if (!\defined('ABSPATH')) {
7 exit;
8 }
9
10 use RuntimeException;
11 use TrinityBackup\Database\DatabaseInterface;
12
13 /**
14 * WordPress.org Plugin Check forbids direct mysqli usage.
15 * This driver keeps the same interface but delegates to $wpdb.
16 */
17 final class MysqliDriver implements DatabaseInterface
18 {
19 public function connect(): void
20 {
21 // $wpdb is always available in WordPress runtime.
22 }
23
24 public function listTables(): array
25 {
26 global $wpdb;
27
28 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Listing tables for backup.
29 $tables = $wpdb->get_col('SHOW TABLES');
30
31 return array_map('strval', is_array($tables) ? $tables : []);
32 }
33
34 public function showCreateTable(string $table): string
35 {
36 global $wpdb;
37
38 $table = $this->validateIdentifier($table);
39
40 // Identifiers cannot be placeholders; validate strictly instead.
41 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table identifier validated via regex, SHOW CREATE TABLE requires literal identifier.
42 $row = $wpdb->get_row('SHOW CREATE TABLE `' . $table . '`', ARRAY_A);
43
44 if (!is_array($row) || !isset($row['Create Table'])) {
45 throw new RuntimeException('Create statement not found.');
46 }
47
48 return (string) $row['Create Table'];
49 }
50
51 public function select(string $sql): array
52 {
53 global $wpdb;
54
55 // Raw SQL is generated by the backup engine.
56 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Internal backup query, SQL built by exporter.
57 $rows = $wpdb->get_results($sql, ARRAY_A);
58
59 return is_array($rows) ? $rows : [];
60 }
61
62 public function execute(string $sql): void
63 {
64 global $wpdb;
65
66 if ($sql === '') {
67 return;
68 }
69
70 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Internal backup/restore query, SQL from backup file.
71 $result = $wpdb->query($sql);
72
73 if ($result === false) {
74 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Internal exception message, not output.
75 throw new RuntimeException('Query failed: ' . (string) $wpdb->last_error);
76 }
77 }
78
79 public function escape(string $value): string
80 {
81 // Do NOT use esc_sql() for SQL dump generation.
82 // WordPress applies placeholder escaping which turns "%" into "{hash}", corrupting content.
83 // Use a deterministic MySQL-style escape.
84 return strtr(
85 $value,
86 [
87 "\x00" => '\\0',
88 "\n" => '\\n',
89 "\r" => '\\r',
90 '\\' => '\\\\',
91 "'" => "\\'",
92 '"' => '\\"',
93 "\x1a" => '\\Z',
94 ]
95 );
96 }
97
98 private function validateIdentifier(string $identifier): string
99 {
100 // Allow common WordPress table identifiers: letters, digits, underscore.
101 if (!preg_match('/^[A-Za-z0-9_]+$/', $identifier)) {
102 throw new RuntimeException('Invalid table identifier.');
103 }
104
105 return $identifier;
106 }
107 }
108