PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.4.9
Backup Migration v1.4.9
2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / database / search-replace.php
backup-backup / includes / database Last commit date
better-backup-v3.php 11 months ago better-backup.php 11 months ago better-restore.php 11 months ago even-better-restore-v3.php 11 months ago even-better-restore-v4.php 11 months ago manager.php 11 months ago search-replace.php 11 months ago smart-sort.php 11 months ago
search-replace.php
235 lines
1 <?php
2
3 /**
4 * Modifications by: Mikołaj `iClyde` Chodorowski
5 * Modified by e-mail contact: kontakt@iclyde.pl
6 * Package: Safe Search and Replace on Database with Serialized Data v2.0.1
7 *
8 * Please contact above e-mail if you see any credits problem.
9 */
10
11 // Namespace
12 namespace BMI\Plugin\Database;
13
14 // Use
15 use BMI\Plugin\BMI_Logger AS Logger;
16 use BMI\Plugin\Backup_Migration_Plugin as BMP;
17 use BMI\Plugin\Progress\BMI_ZipProgress AS Progress;
18
19 // Exit on direct access
20 if (!defined('ABSPATH')) exit;
21
22 /**
23 * Database Search and Replace for Enginge v3
24 */
25 class BMI_Search_Replace_Engine {
26
27 function __construct($tables, $currentPage = 0, $totalPages = 0, $isStaging = false) {
28
29 $this->totalPages = $totalPages;
30 $this->currentPage = $currentPage;
31 $this->all_tables = $tables;
32 $this->isStaging = $isStaging;
33
34 }
35
36 public function perform($search, $replace, $limitColumns = false) {
37
38 return $this->search_replace($search, $replace, $this->all_tables, $limitColumns);
39
40 }
41
42 private function recursive_unserialize_replace($from = '', $to = '', $data = '', $serialised = false, $visited = []) {
43
44 if (is_array($data) || is_object($data)) {
45 if (in_array($data, $visited, true)) {
46 return $data;
47 }
48 $visited[] = $data;
49 }
50 try {
51
52 if (is_string($data) && is_serialized($data) && ($unserialized = @unserialize($data, ['allowed_classes' => ['stdClass']])) !== false) {
53
54 $data = $this->recursive_unserialize_replace($from, $to, $unserialized, true);
55
56 } else if (is_array($data)) {
57
58 $_tmp = [];
59 foreach ($data as $key => $value) {
60 $_tmp[$key] = $this->recursive_unserialize_replace($from, $to, $value, false, $visited);
61 }
62
63 $data = $_tmp;
64 unset($_tmp);
65 } else if (is_object($data) && !is_a($data, '__PHP_Incomplete_Class')) {
66 $tmp = $data;
67 $props = get_object_vars($data);
68 foreach ($props as $key => $value) {
69 $tmp->$key = $this->recursive_unserialize_replace($from, $to, $value, false, $visited);
70 }
71 $data = $tmp;
72 unset($tmp);
73 } else if (is_string($data) && (null !== ($_tmp = json_decode($data, true))) && is_array($_tmp)) {
74 foreach ($_tmp as $key => $value) {
75 $_tmp[$key] = $this->recursive_unserialize_replace($from, $to, $value, false, $visited);
76 }
77 $data = json_encode($_tmp);
78 unset($_tmp);
79 } else if (is_string($data)) {
80 $data = str_replace($from, $to, $data);
81 }
82
83 if ($serialised) return serialize($data);
84
85 }
86 catch (\Exception $error) {}
87 catch (\Throwable $error) {}
88
89 return $data;
90
91 }
92
93 private function search_replace($search = '', $replace = '', $tables = [], $limitColumns = false) {
94
95 global $wpdb;
96
97 $excluded_columns = ['id', 'ID'];
98 $report = ['tables' => 0, 'rows' => 0, 'change' => 0, 'updates' => 0, 'currentPage' => 0, 'totalPages' => 0];
99
100 if ($this->currentPage !== 0 && is_numeric($this->currentPage)) {
101 $report['currentPage'] = $this->currentPage;
102 }
103
104 if ($this->totalPages !== 0 && is_numeric($this->totalPages)) {
105 $report['totalPages'] = $this->totalPages;
106 }
107
108 if (is_array($tables) && !empty($tables)) {
109
110 $wpdb->show_errors();
111
112 foreach($tables as $table) {
113
114 $report['tables']++;
115 $columns = [];
116
117 $fields = $wpdb->get_results('DESCRIBE ' . $table);
118 foreach ($fields as $index => $object) {
119 $columns[$object->Field] = $object->Key == 'PRI' ? true : false;
120 }
121
122 $fieldsForWhereStmt = [];
123
124 foreach ($fields as $index => $columnInfo) {
125 $type = strtolower($columnInfo->Type);
126 if (strpos($type, 'char') !== false || strpos($type, 'text') !== false) {
127 $column = mysqli_real_escape_string($wpdb->dbh, $columnInfo->Field);
128 if (!in_array($column, $fieldsForWhereStmt)) {
129 $fieldsForWhereStmt[] = $column;
130 }
131 }
132 }
133
134 $whereStmt = '';
135 $totalColumns = sizeof($fieldsForWhereStmt);
136 for ($i = 0; $i < $totalColumns; ++$i) {
137 $column = $fieldsForWhereStmt[$i];
138 if ($i == 0) $whereStmt .= ' WHERE ';
139 // if ($this->isStaging) {
140 $whereStmt .= '(`' . $column . '`' . ' LIKE ' . '"%' . mysqli_real_escape_string($wpdb->dbh, $search) . '%"';
141 $whereStmt .= ' AND `' . $column . '`' . ' NOT LIKE ' . '"%' . mysqli_real_escape_string($wpdb->dbh, $replace) . '%")';
142 // } else {
143 // $whereStmt .= '`' . $column . '`' . ' LIKE ' . '"%' . mysqli_real_escape_string($wpdb->dbh, $search) . '%"';
144 // }
145 if ($i != $totalColumns - 1) $whereStmt .= ' OR ';
146 }
147
148 if ($whereStmt === '') continue;
149 $row_count = $wpdb->get_results('SELECT COUNT(*) AS num FROM `' . $table . '`' . $whereStmt);
150 $row_count = $row_count[0]->num;
151 if ($row_count == 0) {
152 $report['currentPage'] = $report['currentPage'] + 1;
153 continue;
154 }
155
156 $page_size = BMI_MAX_SEARCH_REPLACE_PAGE;
157 $pages = ceil($row_count / $page_size);
158 $page = 0;
159
160 if ($report['totalPages'] === 0) {
161 $report['totalPages'] = $pages;
162 }
163
164 for ($page; $page < $pages; $page++) {
165
166 $report['currentPage'] = $report['currentPage'] + 1;
167
168 $current_row = 0;
169 $start = $page * $page_size;
170 $end = $start + $page_size;
171
172 $data = $wpdb->get_results(sprintf('SELECT * FROM %s%s LIMIT %d, %d', $table, $whereStmt, $start, $end));
173 for ($i = 0; $i < sizeof($data); ++$i) {
174
175 $row = $data[$i];
176 $report['rows']++;
177 $current_row++;
178
179 $update_sql = [];
180 $where_sql = [];
181 $upd = false;
182
183 foreach ($columns as $column => $primary_key) {
184
185 if ($limitColumns != false) {
186 if (!in_array($column, $limitColumns)) continue;
187 }
188 if (in_array($column, $excluded_columns)) continue;
189 if (!in_array($column, $fieldsForWhereStmt)) continue;
190
191 $edited_data = $data_to_fix = $row->$column;
192 $edited_data = $this->recursive_unserialize_replace($search, $replace, $data_to_fix);
193
194 if ($edited_data != $data_to_fix) {
195 $report['change']++;
196 $update_sql[] = '`' . $column . '`' . ' = "' . mysqli_real_escape_string($wpdb->dbh, $edited_data) . '"';
197 $upd = true;
198 $where_sql[] = '`' . $column . '`' . ' = "' . mysqli_real_escape_string($wpdb->dbh, $data_to_fix) . '"';
199 }
200
201 }
202
203 if ($upd && !empty($where_sql)) {
204 $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $update_sql) . ' WHERE ' . implode(' AND ', array_filter($where_sql));
205 $results = $wpdb->get_results($sql);
206
207 unset($sql);
208
209 $report['updates']++;
210
211 if ($wpdb->last_error !== '') {
212 // error_log(strval($wpdb->last_query));
213 // error_log(strval($wpdb->last_result));
214 // error_log(strval($wpdb->last_error));
215 }
216 }
217
218 unset($row);
219
220 }
221
222 unset($data);
223 return $report;
224
225 }
226
227 }
228
229 }
230
231 return $report;
232 }
233
234 }
235