PluginProbe
Migrate to WordPress.com / 5.88
Migrate to WordPress.com v5.88
6.72 6.65 trunk 5.72 5.81 5.88
wpcom-migration / callback / wings / fs.php

fs.php in Migrate to WordPress.com 5.88, at callback/wings/fs.php

419 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit;
3 if (!class_exists('BVFSCallback')) :
4 require_once dirname( __FILE__ ) . '/../streams.php';
5
6 class BVFSCallback extends BVCallbackBase {
7 public $stream;
8 public $account;
9
10 public static $cwAllowedFiles = array(".htaccess", ".user.ini", "malcare-waf.php");
11 const FS_WING_VERSION = 1.3;
12
13 public function __construct($callback_handler) {
14 $this->account = $callback_handler->account;
15 }
16
17 function fileStat($relfile, $md5 = false) {
18 $absfile = ABSPATH.$relfile;
19 $fdata = array();
20 $fdata["filename"] = $relfile;
21 $stats = @stat($absfile);
22 if ($stats) {
23 foreach (preg_grep('#size|uid|gid|mode|mtime#i', array_keys($stats)) as $key ) {
24 $fdata[$key] = $stats[$key];
25 }
26 if (is_link($absfile)) {
27 $fdata["link"] = @readlink($absfile);
28 }
29 if ($md5 === true && !is_dir($absfile)) {
30 $fdata["md5"] = $this->calculateMd5($absfile, array(), 0, 0, 0);
31 }
32 } else {
33 $fdata["failed"] = true;
34 }
35 return $fdata;
36 }
37
38 function scanFilesUsingGlob($initdir = "./", $offset = 0, $limit = 0, $bsize = 512, $recurse = true, $regex = '{.??,}*') {
39 $i = 0;
40 $dirs = array();
41 $dirs[] = $initdir;
42 $bfc = 0;
43 $bfa = array();
44 $current = 0;
45 $abspath = realpath(ABSPATH).'/';
46 $abslen = strlen($abspath);
47 # XNOTE: $recurse cannot be used directly here
48 while ($i < count($dirs)) {
49 $dir = $dirs[$i];
50
51 foreach (glob($abspath.$dir.$regex, GLOB_NOSORT | GLOB_BRACE) as $absfile) {
52 $relfile = substr($absfile, $abslen);
53 if (is_dir($absfile) && !is_link($absfile)) {
54 $dirs[] = $relfile."/";
55 }
56 $current++;
57 if ($offset >= $current)
58 continue;
59 if (($limit != 0) && (($current - $offset) > $limit)) {
60 $i = count($dirs);
61 break;
62 }
63 $bfa[] = $this->fileStat($relfile);
64 $bfc++;
65 if ($bfc == $bsize) {
66 $str = serialize($bfa);
67 $this->stream->writeStream($str);
68 $bfc = 0;
69 $bfa = array();
70 }
71 }
72 $regex = '{.??,}*';
73 $i++;
74 if ($recurse == false)
75 break;
76 }
77 if ($bfc != 0) {
78 $str = serialize($bfa);
79 $this->stream->writeStream($str);
80 }
81 return array("status" => "done");
82 }
83
84 function scanFiles($initdir = "./", $offset = 0, $limit = 0, $bsize = 512, $recurse = true, $md5 = false) {
85 $i = 0;
86 $links = array();
87 $dirs = array();
88 $dirs[] = $initdir;
89 $bfc = 0;
90 $bfa = array();
91 $current = 0;
92 while ($i < count($dirs)) {
93 $dir = $dirs[$i];
94 $d = @opendir(ABSPATH.$dir);
95 if ($d) {
96 while (($file = readdir($d)) !== false) {
97 if ($file == '.' || $file == '..') { continue; }
98 $relfile = $dir.$file;
99 $absfile = ABSPATH.$relfile;
100 if (is_link($absfile)) {
101 $links[] = $relfile;
102 }
103 if (is_dir($absfile) && !is_link($absfile)) {
104 $dirs[] = $relfile."/";
105 }
106 $current++;
107 if ($offset >= $current)
108 continue;
109 if (($limit != 0) && (($current - $offset) > $limit)) {
110 $i = count($dirs);
111 break;
112 }
113 $bfa[] = $this->fileStat($relfile, $md5);
114 $bfc++;
115 if ($bfc == $bsize) {
116 $str = serialize($bfa);
117 $this->stream->writeStream($str);
118 $bfc = 0;
119 $bfa = array();
120 }
121 }
122 closedir($d);
123 }
124 $i++;
125 if ($recurse == false)
126 break;
127 }
128 if ($bfc != 0) {
129 $str = serialize($bfa);
130 $this->stream->writeStream($str);
131 }
132
133 return $links;
134 }
135
136 function calculateMd5($absfile, $fdata, $offset, $limit, $bsize) {
137 if ($offset == 0 && $limit == 0) {
138 $md5 = md5_file($absfile);
139 } else {
140 if ($limit == 0)
141 $limit = $fdata["size"];
142 if ($offset + $limit < $fdata["size"])
143 $limit = $fdata["size"] - $offset;
144 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
145 $handle = fopen($absfile, "rb");
146 $ctx = hash_init('md5');
147 fseek($handle, $offset, SEEK_SET);
148 $dlen = 1;
149 while (($limit > 0) && ($dlen > 0)) {
150 if ($bsize > $limit)
151 $bsize = $limit;
152 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread -- Required for handling partial file reads with offset and limit
153 $d = fread($handle, $bsize);
154 $dlen = strlen($d);
155 hash_update($ctx, $d);
156 $limit -= $dlen;
157 }
158 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
159 fclose($handle);
160 $md5 = hash_final($ctx);
161 }
162 return $md5;
163 }
164
165 function getFilesContent($files, $withContent = true) {
166 $result = array();
167 $filesystem = WPCOMHelper::get_direct_filesystem();
168
169 foreach ($files as $file) {
170 $fdata = $this->fileStat($file);
171 $absfile = ABSPATH . $file;
172
173 if ($filesystem->is_dir($absfile) && !is_link($absfile)) {
174 $fdata['is_dir'] = true;
175 } else {
176 if (!$filesystem->is_readable($absfile)) {
177 $fdata['error'] = 'file not readable';
178 } else {
179 if ($withContent === true) {
180 $content = $filesystem->get_contents($absfile);
181 if ($content !== false) {
182 $fdata['content'] = $content;
183 } else {
184 $fdata['error'] = 'unable to read file';
185 }
186 }
187 }
188 }
189
190 if (is_wp_error($filesystem->errors) && $filesystem->errors->has_errors()) {
191 $fdata['fs_error'] = $filesystem->errors->get_error_message();
192 }
193
194 $result[$file] = $fdata;
195 }
196
197 return $result;
198 }
199
200 function getFilesStats($files, $offset = 0, $limit = 0, $bsize = 102400, $md5 = false) {
201 $result = array();
202 foreach ($files as $file) {
203 $fdata = $this->fileStat($file);
204 $absfile = ABSPATH.$file;
205 if (!is_readable($absfile)) {
206 $result["missingfiles"][] = $file;
207 continue;
208 }
209 if ($md5 === true && !is_dir($absfile)) {
210 $fdata["md5"] = $this->calculateMd5($absfile, $fdata, $offset, $limit, $bsize);
211 }
212 $result["stats"][] = $fdata;
213 }
214 return $result;
215 }
216
217 function uploadFiles($files, $offset = 0, $limit = 0, $bsize = 102400) {
218 $result = array();
219 foreach ($files as $file) {
220 if (!is_readable(ABSPATH.$file)) {
221 $result["missingfiles"][] = $file;
222 continue;
223 }
224 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Required for binary-safe chunked reading
225 $handle = fopen(ABSPATH.$file, "rb");
226 if (($handle != null) && is_resource($handle)) {
227 $fdata = $this->fileStat($file);
228 $_limit = $limit;
229 $_bsize = $bsize;
230 if ($_limit == 0)
231 $_limit = $fdata["size"];
232 if ($offset + $_limit > $fdata["size"])
233 $_limit = $fdata["size"] - $offset;
234 $fdata["limit"] = $_limit;
235 $sfdata = serialize($fdata);
236 $this->stream->writeStream($sfdata);
237 fseek($handle, $offset, SEEK_SET);
238 $dlen = 1;
239 while (($_limit > 0) && ($dlen > 0)) {
240 if ($_bsize > $_limit)
241 $_bsize = $_limit;
242 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread -- Required for binary-safe chunked reading
243 $d = fread($handle, $_bsize);
244 $dlen = strlen($d);
245 $this->stream->writeStream($d);
246 $_limit -= $dlen;
247 }
248 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Required for cleanup
249 fclose($handle);
250 } else {
251 $result["unreadablefiles"][] = $file;
252 }
253 }
254 $result["status"] = "done";
255 return $result;
256 }
257
258 function process($request) {
259 $params = $request->params;
260 $stream_init_info = BVStream::startStream($this->account, $request);
261
262 if (array_key_exists('stream', $stream_init_info)) {
263 $this->stream = $stream_init_info['stream'];
264 switch ($request->method) {
265 case "scanfilesglob":
266 $initdir = $params['initdir'];
267 $offset = intval($params['offset']);
268 $limit = intval($params['limit']);
269 $bsize = intval($params['bsize']);
270 $regex = $params['regex'];
271 $recurse = true;
272 if (array_key_exists('recurse', $params) && $params["recurse"] == "false") {
273 $recurse = false;
274 }
275 $resp = $this->scanFilesUsingGlob($initdir, $offset, $limit, $bsize, $recurse, $regex);
276 break;
277 case "scanfiles":
278 $links = array();
279 $dir_options = array();
280 if (array_key_exists('dir_options', $params)) {
281 $dir_options = $params['dir_options'];
282 }
283 $bsize = intval($params['bsize']);
284 foreach($dir_options as $option) {
285 $dir = $option['dir'];
286 $offset = intval($option['offset']);
287 $limit = intval($option['limit']);
288 $recurse = true;
289 if (array_key_exists('recurse', $option) && $option["recurse"] == "false") {
290 $recurse = false;
291 }
292 $md5 = true;
293 if (array_key_exists('md5', $option) && $option["md5"] == "false") {
294 $md5 = false;
295 }
296
297 $_links = $this->scanFiles($dir, $offset, $limit, $bsize, $recurse, $md5);
298 $links = array_merge($links, $_links);
299 }
300 $resp = array("status" => "done", "links" => $links);
301 break;
302 case "getfilesstats":
303 $files = $params['files'];
304 $offset = intval($params['offset']);
305 $limit = intval($params['limit']);
306 $bsize = intval($params['bsize']);
307 $md5 = false;
308 if (array_key_exists('md5', $params)) {
309 $md5 = true;
310 }
311 $resp = $this->getFilesStats($files, $offset, $limit, $bsize, $md5);
312 break;
313 case "sendmanyfiles":
314 $files = $params['files'];
315 $offset = intval($params['offset']);
316 $limit = intval($params['limit']);
317 $bsize = intval($params['bsize']);
318 $resp = $this->uploadFiles($files, $offset, $limit, $bsize);
319 break;
320 case "filelist":
321 $dir_options = array();
322 if (array_key_exists('dir_options', $params)) {
323 $dir_options = $params['dir_options'];
324 }
325 if (array_key_exists('chdir', $params)) {
326 chdir(ABSPATH);
327 }
328 $resp = array();
329 foreach($dir_options as $options) {
330 $glob_option = 0;
331 if (array_key_exists('onlydir', $options)) {
332 $glob_option = GLOB_ONLYDIR;
333 }
334
335 $regexes = array("*", ".*");
336 if (array_key_exists('regex', $options)) {
337 $regexes = array($options['regex']);
338 }
339
340 $md5 = false;
341 if (array_key_exists('md5', $options)) {
342 $md5 = $options['md5'];
343 }
344
345 $directoryList = array();
346
347 foreach($regexes as $regex) {
348 $directoryList = array_merge($directoryList, glob($options['dir'].$regex, $glob_option));
349 }
350 $resp[$options['dir']] = $this->getFilesStats($directoryList, 0, 0, 0, $md5);
351 }
352 break;
353 case "dirsexists":
354 $resp = array();
355 $dirs = $params['dirs'];
356
357 foreach ($dirs as $dir) {
358 $path = ABSPATH.$dir;
359 if (file_exists($path) && is_dir($path) && !is_link($path)) {
360 $resp[$dir] = true;
361 } else {
362 $resp[$dir] = false;
363 }
364 }
365
366 $resp["status"] = "Done";
367 break;
368 case "gtfilescntent":
369 $files = $params['files'];
370 $withContent = array_key_exists('withcontent', $params) ? $params['withcontent'] : true;
371 $resp = array("files_content" => $this->getFilesContent($files, $withContent));
372 break;
373 case "gtfls":
374 $resp = array();
375
376 if (array_key_exists('get_files_content', $params)) {
377 $args = $params['get_files_content'];
378 $with_content = array_key_exists('withcontent', $args) ? $args['withcontent'] : true;
379 $resp['get_files_content'] = $this->getFilesContent($args['files'], $with_content);
380 }
381
382 if (array_key_exists('get_files_stats', $params)) {
383 $args = $params['get_files_stats'];
384 $md5 = array_key_exists('md5', $args) ? $args['md5'] : false;
385 $stats = $this->getFilesStats(
386 $args['files'], $args['offset'], $args['limit'], $args['bsize'], $md5
387 );
388
389 $result = array();
390
391 if (array_key_exists('stats', $stats)) {
392 $result['stats'] = array();
393 foreach ($stats['stats'] as $stat) {
394 $result['stats'][$stat['filename']] = $stat;
395 }
396 }
397
398 if (array_key_exists('missingfiles', $stats)) {
399 $result['missingfiles'] = $stats['missingfiles'];
400 }
401
402 $resp['get_files_stats'] = $result;
403 }
404
405 break;
406 default:
407 $resp = false;
408 }
409 $end_stream_info = $this->stream->endStream();
410 if (!empty($end_stream_info) && is_array($resp)) {
411 $resp = array_merge($resp, $end_stream_info);
412 }
413 } else {
414 $resp = $stream_init_info;
415 }
416 return $resp;
417 }
418 }
419 endif;