Version Description
- thinkovi references replace
- plugin pre auto update text changelog
- author name and uri change
- standalone library addon support
Download this release
Release Info
Developer | watchful |
Plugin | XCloner – Backup and Restore |
Version | 4.1.4 |
Comparing to | |
See all releases |
Code changes from version 4.1.4b to 4.1.4
- README.md +1 -1
- README.txt +277 -36
- admin/class-xcloner-admin.php +1 -1
- admin/partials/xcloner_generate_backups_page.php +2 -2
- admin/partials/xcloner_init_page.php +1 -1
- api/api_test.html +129 -0
- api/expose_api.php +50 -0
- api/index.html +0 -0
- api/standalone_config.json +55 -0
- composer.lock +12 -12
- examples/XCloner.postman_collection.json +288 -0
- examples/cli_encrypt_backup.php +64 -0
- examples/index.html +0 -0
- examples/standalone-backup-trigger.php +16 -0
- examples/standalone_backup_trigger_config.json +54 -0
- includes/class-xcloner-activator.php +95 -96
- includes/class-xcloner-api.php +1152 -1157
- includes/class-xcloner-archive.php +693 -583
- includes/class-xcloner-database.php +641 -614
- includes/class-xcloner-deactivator.php +1 -1
- includes/class-xcloner-encryption.php +357 -359
- includes/class-xcloner-file-system.php +193 -199
- includes/class-xcloner-loader.php +0 -40
- includes/class-xcloner-logger.php +116 -115
- includes/class-xcloner-remote-storage.php +109 -91
- includes/class-xcloner-sanitization.php +114 -54
- includes/class-xcloner-scheduler.php +450 -433
- includes/class-xcloner-settings.php +1010 -808
- includes/class-xcloner-standalone.php +100 -0
- includes/class-xcloner.php +660 -581
- lib/class-wp-error.php +226 -0
- lib/index.html +0 -0
- lib/mock_wp_functions.php +452 -0
- lib/wp-db.php +3555 -0
- public/class-xcloner-public.php +1 -1
- public/partials/xcloner-public-display.php +1 -1
- uninstall.php +1 -1
- vendor/composer/autoload_namespaces.php +1 -1
- vendor/composer/autoload_static.php +1 -1
- vendor/composer/installed.json +14 -14
- vendor/splitbrain/php-archive/.gitignore +8 -0
- vendor/splitbrain/php-archive/src/Archive.php +16 -13
- vendor/splitbrain/php-archive/src/ArchiveCorruptedException.php +10 -0
- vendor/splitbrain/php-archive/src/ArchiveIOException.php +10 -0
- vendor/splitbrain/php-archive/src/ArchiveIllegalCompressionException.php +10 -0
- vendor/splitbrain/php-archive/src/FileInfo.php +4 -19
- vendor/splitbrain/php-archive/src/FileInfoException.php +10 -0
- vendor/splitbrain/php-archive/src/Tar.php +65 -217
- vendor/splitbrain/php-archive/src/Zip.php +19 -3
- vendor/splitbrain/php-archive/tests/FileInfoTest.php +3 -4
- vendor/splitbrain/php-archive/tests/TarTestCase.php +42 -17
- vendor/splitbrain/php-archive/tests/ZipTestCase.php +87 -69
- vendor/splitbrain/php-archive/tests/tar.test.php +0 -617
- xcloner.php +5 -5
README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
# XCloner Wordpress Plugin - Backup and Restore
|
2 |
|
3 |
-
[![Author](http://img.shields.io/badge/author-@thinkovi-blue.svg?style=flat-square)](https://twitter.com/
|
4 |
[![Software License](https://img.shields.io/badge/license-GPL-brightgreen.svg?style=flat-square)](LICENSE.txt)
|
5 |
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/quality-score.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/?branch=master)
|
6 |
[![Build Status](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/build.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/build-status/master)
|
1 |
# XCloner Wordpress Plugin - Backup and Restore
|
2 |
|
3 |
+
[![Author](http://img.shields.io/badge/author-@thinkovi-blue.svg?style=flat-square)](https://twitter.com/WatchfulDashbrd)
|
4 |
[![Software License](https://img.shields.io/badge/license-GPL-brightgreen.svg?style=flat-square)](LICENSE.txt)
|
5 |
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/quality-score.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/?branch=master)
|
6 |
[![Build Status](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/build.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/build-status/master)
|
README.txt
CHANGED
@@ -1,55 +1,60 @@
|
|
1 |
-
===
|
2 |
-
Contributors:
|
3 |
-
Donate link:
|
4 |
-
Tags: backup
|
5 |
Requires at least: 3.0.1
|
6 |
-
Tested up to: 5.
|
7 |
-
Stable tag: 4.1.
|
8 |
|
9 |
-
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
XCloner is a
|
14 |
|
15 |
-
|
16 |
|
17 |
-
XCloner
|
18 |
|
19 |
-
XCloner
|
|
|
20 |
|
21 |
-
|
22 |
|
23 |
-
|
24 |
|
25 |
-
|
26 |
|
27 |
-
|
|
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
43 |
|
44 |
== Installation ==
|
45 |
|
46 |
-
1.
|
47 |
-
2.
|
48 |
-
3.
|
|
|
49 |
|
50 |
UPGRADE:
|
51 |
|
52 |
-
|
53 |
|
54 |
== Frequently Asked Questions ==
|
55 |
|
@@ -108,11 +113,16 @@ Of course, schedules can be adjusted accordingly to how often you update your si
|
|
108 |
10. Generate Backup Process
|
109 |
11. Generate Backup Screen
|
110 |
|
111 |
-
==
|
112 |
|
113 |
-
|
|
|
|
|
|
|
|
|
114 |
|
115 |
-
|
|
|
116 |
|
117 |
= 4.1.2 =
|
118 |
* improved default backup storage path security
|
@@ -271,3 +281,234 @@ Immigration Attorney Montana <a href="https://www.immigrationlawofmt.com" target
|
|
271 |
|
272 |
= 3.0.3 =
|
273 |
Please check changelog!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Backup, Restore and Migrate WordPress Sites With the XCloner Plugin ===
|
2 |
+
Contributors: watchful,ovidiul
|
3 |
+
Donate link: http://www.xcloner.com
|
4 |
+
Tags: backup, database backup, cloud backup, WordPress backup, WordPress migration
|
5 |
Requires at least: 3.0.1
|
6 |
+
Tested up to: 5.4
|
7 |
+
Stable tag: 4.1.4
|
8 |
|
9 |
+
XCloner is a backup plugin that allows you to safely back up and restore your WordPress sites. You can send site backups to SFTP, Dropbox, Amazon, Google Drive, Backblaze and other locations.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
[XCloner](https://www.xcloner.com) is a backup plugin that allows you to safely back up and restore your WordPress sites. You can send your site backups to SFTP, Dropbox, Amazon, Google Drive, Backblaze and other locations. You can create backups manually or automatically with XCloner’s built-in scheduler.
|
14 |
|
15 |
+
XCloner enables you to automatically generate backups with the built-in cron script. These cron jobs can run daily, weekly, monthly or even hourly.
|
16 |
|
17 |
+
XCloner allows you to generate custom backups of any WordPress site, and then restore the backup on any other location with the help of the automatic restore script we provide!
|
18 |
|
19 |
+
XCloner has many useful safety features. For example, XCloner will generate a core, plugins, themes or languages files backup before the automatic update of WordPress core, plugins, themes or languages files.
|
20 |
+
= Remote Storage for WordPress Backups =
|
21 |
|
22 |
+
XCloner allows you to send your backups to remote storage locations supporting FTP, SFTP, DropBox, Amazon S3, Google Drive, WebDAV, Backblaze, Azure and many more to come
|
23 |
|
24 |
+
You can generate “Differential Backups” so your backup will include only files modified after a certain date. This can decrease the space needed to store your backups.
|
25 |
|
26 |
+
XCloner also has safety features to make sure your backups are successful. One example: you have the ability to split backups into multiple smaller parts if a certain size limit is reached. Another example: XCloner can also store a local copy of the backup that it will then delete when the backup has been sent to the remote location.
|
27 |
|
28 |
+
= Secure, GDPR Compliant WordPress Backups =
|
29 |
+
XCloner is the best backup choice for people who care about security and privacy.
|
30 |
|
31 |
+
XCloner uses open source standards like TAR, MySQL and CSV formats so you can be sure that your backups can be restored in a variety of ways, giving you more flexibility and full control.
|
32 |
+
|
33 |
+
XCloner has a built-in security layer to protect your backups. You can create encrypted backup archives with AES-128-CBC algorithm. This encryption helps to ensure that your data is still GDPR compliant even if the backup fails.
|
34 |
+
|
35 |
+
= Restore Backups Anywhere =
|
36 |
+
|
37 |
+
You can restore backups on any location compatible with your website by using the XCloner restore feature. Your site clone can be restored on a totally different server, with new server and MySQL details.
|
38 |
+
|
39 |
+
XCloner will attempt to extract the backup archive files for you, as well as import the MySQL dump and update your WordPress configuration details.
|
40 |
+
|
41 |
+
The restore script is located inside the XCloner archive, in the /restore/ directory. XCloner can restore your original file and directory permissions. XCloner can also automatically update the new host settings to the configuration file.
|
42 |
+
|
43 |
+
XCloner has a variety of restoration options including: All Files, Only Plugins Files, Only Theme Files, Only Uploads Files, and Only Database Backup.
|
44 |
+
|
45 |
+
= XCloner works best with the Watchful dashboard =
|
46 |
+
[Watchful](https://watchful.net) is a web developers toolbox for remotely managing and monitoring multiple WordPress websites. Simply add all your production and staging sites into the Watchful Dashboard and use our tools to monitor uptime and site backups, plus updates to WordPress and core and plugins, and more. XCloner integrates smoothly with Watchful. You’ll be amazed at how much time and money you save managing your WordPress sites with [Watchful](https://wordpress.org/plugins/watchful/).
|
47 |
|
48 |
== Installation ==
|
49 |
|
50 |
+
1. In the WordPress backend, select Plugins > Add New.
|
51 |
+
2. In the search bar enter `xcloner`.
|
52 |
+
3. When the XCLoner listing is shown, click the 'Install` button.
|
53 |
+
4. Following installation, click the `Activate` button.
|
54 |
|
55 |
UPGRADE:
|
56 |
|
57 |
+
XLCloner can be updated from the plugins list in the WordPress backend.
|
58 |
|
59 |
== Frequently Asked Questions ==
|
60 |
|
113 |
10. Generate Backup Process
|
114 |
11. Generate Backup Screen
|
115 |
|
116 |
+
== Changelog ==
|
117 |
|
118 |
+
= 4.1.4 =
|
119 |
+
* thinkovi references replace
|
120 |
+
* plugin pre auto update text changelog
|
121 |
+
* author name and uri change
|
122 |
+
* standalone library addon support
|
123 |
|
124 |
+
= 4.1.3 =
|
125 |
+
* database include tables fix
|
126 |
|
127 |
= 4.1.2 =
|
128 |
* improved default backup storage path security
|
281 |
|
282 |
= 3.0.3 =
|
283 |
Please check changelog!
|
284 |
+
|
285 |
+
== Installation ==
|
286 |
+
|
287 |
+
1. In the WordPress backend, select Plugins > Add New.
|
288 |
+
2. In the search bar enter `xcloner`.
|
289 |
+
3. When the XCLoner listing is shown, click the 'Install` button.
|
290 |
+
4. Following installation, click the `Activate` button.
|
291 |
+
|
292 |
+
UPGRADE:
|
293 |
+
|
294 |
+
XLCloner can be updated from the plugins list in the WordPress backend.
|
295 |
+
|
296 |
+
== Frequently Asked Questions ==
|
297 |
+
|
298 |
+
= Where does XCloner keep it's Database Backups? =
|
299 |
+
|
300 |
+
XCloner stores them in separate mysql dump files, inside a folder called xcloner-XXXXX inside the backup archive root path, where XXXXX is a hash number that is identical with the last 5 characters of the backup name,
|
301 |
+
so if the backup name is backup_localhost-2017-02-16_15-36-sql-1c6c6.tgz , the mysql backup file will be stored in xcloner-1c6c6/ folder.
|
302 |
+
|
303 |
+
= How do I Restore my Backup? =
|
304 |
+
|
305 |
+
XCloner provide an easy to use restore script available in the Site Backup -> Restore Backups menu, the process is being described there as well.
|
306 |
+
|
307 |
+
If the XCloner Restore option fails, you can manually restore your backup as follows:
|
308 |
+
|
309 |
+
1. extract the backup archive files to your new location
|
310 |
+
2. locate the xcloner-XXXXX folder inside your backup root folder, and look for the mysql backup in database-sql and import it through phpmyadmin
|
311 |
+
3. update your wp-config.php file to reflect the new mysql details
|
312 |
+
|
313 |
+
= How do I know which Files were include in the Backup? =
|
314 |
+
|
315 |
+
The XCloner Manager Backups Panel provides an easy utility to view each backup content files list. It also stores a copy of the archived backup files inside the xcloner-XXXXX/backup_files.csv file in an easy to read CSV format.
|
316 |
+
|
317 |
+
= Do you have a Log for the created Backup? =
|
318 |
+
|
319 |
+
Yes, if XCloner Logger option is enabled, it will store a log file inside the xcloner-XXXXX folder inside the backup archive, file is named xcloner-xxxxx.log
|
320 |
+
|
321 |
+
= What are Differentials Backups? =
|
322 |
+
|
323 |
+
Differential Backups contain files modified after a certian period of time. So each time backup runs, modified files after that period of time are added to a new Backup archive.
|
324 |
+
Compared to Incremental Backups, which contain only modified files from the previous run, they use more space but are more reliable for files restore.
|
325 |
+
They will use considerably less space than a full backup however.
|
326 |
+
|
327 |
+
= Why Differential Backups and will you support Incremental Backups? =
|
328 |
+
|
329 |
+
The main difference comes from how reliable a backup set it. For instance, if something happens to one backup archive from the Incremental Backup set, then it is possible you will lose
|
330 |
+
the files changes in that period of time, however if the same case happens to a Differential Backup, then the files can easily be recovered from any of the other Differential Backups. The
|
331 |
+
storage difference between Incremental Backups and Differential Backups is not significant and considering the reliability of the Differential Set so we have decided, for now, to not implement
|
332 |
+
further Incremental Backups.
|
333 |
+
|
334 |
+
= What would a good Backup Procedure be with Differential Backups? =
|
335 |
+
|
336 |
+
As a general rule, I would recommend setting a weekly full site backup schedule and then a daily schedule for a differential backup. You can also include a daily backup of the database in the same Differential Backup.
|
337 |
+
Of course, schedules can be adjusted accordingly to how often you update your site, the size of it and the storage space available.
|
338 |
+
|
339 |
+
== Screenshots ==
|
340 |
+
|
341 |
+
1. XCloner Dashboard
|
342 |
+
2. General Backup Settings
|
343 |
+
3. List Backup Content
|
344 |
+
4. Cleanup Options for Local Storage
|
345 |
+
5. Remote Storage Panel supporting ftp, sftp, dropbox, amazon s3, azure blob and many more to come
|
346 |
+
6. Manage Scheduled Backups Panel
|
347 |
+
7. Edit Scheduled Backup
|
348 |
+
8. Generate Backup ->Files Options tab
|
349 |
+
9. Restore Backup Panel
|
350 |
+
10. Generate Backup Process
|
351 |
+
11. Generate Backup Screen
|
352 |
+
|
353 |
+
== Changelog ==
|
354 |
+
|
355 |
+
= 4.1.3 =
|
356 |
+
* database include tables fix
|
357 |
+
|
358 |
+
= 4.1.2 =
|
359 |
+
* improved default backup storage path security
|
360 |
+
* improved remote storage security
|
361 |
+
|
362 |
+
= 4.1.2 =
|
363 |
+
* vendor lib updates
|
364 |
+
* flysystem azure storage Upgrade
|
365 |
+
|
366 |
+
= 4.1.1 =
|
367 |
+
* log tmp directories fix, tracking only ERROR reports from php
|
368 |
+
* security improvement backup log name
|
369 |
+
* database restore resume fix
|
370 |
+
* memory limit fix
|
371 |
+
|
372 |
+
= 4.1.0 =
|
373 |
+
* added AES-128-CBC backup encryption and decryption option
|
374 |
+
* manage backup fixes
|
375 |
+
* scheduled backup screen fixes and addon backup encryption option
|
376 |
+
* automated backups encryption option addon
|
377 |
+
* generate backups encrypt option addon
|
378 |
+
|
379 |
+
= 4.0.9 =
|
380 |
+
* remote storage password encryption addon for database
|
381 |
+
* vendor cleanup packages
|
382 |
+
* database silent fail fix
|
383 |
+
* copyright changes
|
384 |
+
* jstree fix database display
|
385 |
+
* microtime float div fix
|
386 |
+
* manage backups data order fix
|
387 |
+
|
388 |
+
= 4.0.8 =
|
389 |
+
* updated vendor library dependencies, AWS, phpseclib
|
390 |
+
* TAR compression fix
|
391 |
+
* 7.2 compatibility checks and fixes
|
392 |
+
|
393 |
+
= 4.0.7 =
|
394 |
+
* added log fixes for Wordpress cron
|
395 |
+
* remove storage fixes
|
396 |
+
|
397 |
+
= 4.0.6 =
|
398 |
+
* S3 prefix addon for defining folders
|
399 |
+
* S3 custom endpoint addon to support minio.io
|
400 |
+
* code fixes
|
401 |
+
|
402 |
+
= 4.0.5 =
|
403 |
+
* Dropbox API update to V2
|
404 |
+
* Code fixes and text changes
|
405 |
+
|
406 |
+
= 4.0.4 =
|
407 |
+
* remote storage view fix
|
408 |
+
* added automatic backups option before WP automatic update
|
409 |
+
* deactivate exception handling fix
|
410 |
+
* restore pages improvements
|
411 |
+
* old XCloner backup format compatibility fixes
|
412 |
+
|
413 |
+
= 4.0.3 =
|
414 |
+
* added differential backups with the option to only backup files modified after a certain date
|
415 |
+
* added localhost restore option with direct access to the restore restore
|
416 |
+
* added schedule name fixes
|
417 |
+
* added restore filter All Files, Only Plugins Files, Only Theme Files, Only Uploads Files, Only Database Backup
|
418 |
+
* added remote backup list archive option on restore page
|
419 |
+
* tmp directory cleanup on deactivate
|
420 |
+
* sftp text fixes
|
421 |
+
|
422 |
+
= 4.0.2 =
|
423 |
+
* added WebDAV remote storage support
|
424 |
+
* added Google Drive Suppor through XCloner-Google-Drive plugin
|
425 |
+
* added depedency injection code refactoring
|
426 |
+
* added TAR PAX support on restore
|
427 |
+
* improving code quality scrutinizer
|
428 |
+
* fixing phpversion requirement
|
429 |
+
* adding Backblaze remote storage support
|
430 |
+
* added Remote Storage Manage Backups dropdown selection
|
431 |
+
* fixed windows opendir error
|
432 |
+
* added total archived files to notifications email
|
433 |
+
* timezone scheduler fix
|
434 |
+
* added default error sending to admin when no notification email is set
|
435 |
+
|
436 |
+
|
437 |
+
= 4.0.1 =
|
438 |
+
* Code rewritten from ground up to make use of latest code standards
|
439 |
+
* Added support for Dropbox, Amazon S3, Azure Blob and SFTP storage
|
440 |
+
* Added a new restore script
|
441 |
+
* Added an improved backup and system logger
|
442 |
+
* New Setting Panel
|
443 |
+
* New Manage Backups Panel with the options to Delete, Transfer to Remote Storage, Download and List Backup archive contents
|
444 |
+
* Added mail notifications for scheduled backups
|
445 |
+
* Added a new Cron Scheduler to make use of Wordpress System Cron option
|
446 |
+
* Improved user input sanitization
|
447 |
+
* Improved recursive file scanning and archiving
|
448 |
+
* Improved Mysql Backup dump
|
449 |
+
* Added Multiple Cleanup options both for local storage and remote
|
450 |
+
* Added Improved Backup Compressing option
|
451 |
+
|
452 |
+
= 3.1.5 =
|
453 |
+
* Config variables save sanitization addon
|
454 |
+
|
455 |
+
= 3.1.4 =
|
456 |
+
* DropPHP DropBox library update, upload fixes for files larger than 150MB
|
457 |
+
|
458 |
+
= 3.1.3 =
|
459 |
+
* XSS fix
|
460 |
+
|
461 |
+
= 3.1.2 =
|
462 |
+
* vulnerability fix
|
463 |
+
|
464 |
+
= 3.1.1 =
|
465 |
+
* added CSRF protection
|
466 |
+
|
467 |
+
= 3.1.0 =
|
468 |
+
* added Wordpress login-less integration
|
469 |
+
* plugin settings are now saved to database
|
470 |
+
* security audit and hardening
|
471 |
+
|
472 |
+
= 3.0.8 =
|
473 |
+
* added russian language support
|
474 |
+
|
475 |
+
= 3.0.7 =
|
476 |
+
* added sftp support for backup transfer, thanks Todd Bluhm - dynamicts.com
|
477 |
+
|
478 |
+
= 3.0.6 =
|
479 |
+
* added php 5.4 compatibility
|
480 |
+
|
481 |
+
= 3.0.4 =
|
482 |
+
* LFI vulnerability fix
|
483 |
+
|
484 |
+
= 3.0.3 =
|
485 |
+
* added amazon ssl option box
|
486 |
+
* moved the compress option to the System tab, don't use it unless you know what you are doing!
|
487 |
+
|
488 |
+
= 3.0.1 =
|
489 |
+
* several important security and bug fixes
|
490 |
+
|
491 |
+
= 3.0 =
|
492 |
+
* incremental database backup
|
493 |
+
* incremental file system scan
|
494 |
+
* backup size limit and option to split it into additional archives, default 2GB
|
495 |
+
* exclude files larger than a certain size option
|
496 |
+
* incremental files restore
|
497 |
+
* JQuery Start interface
|
498 |
+
|
499 |
+
= 2.2.1 =
|
500 |
+
* Added JSON AJAX interface to the Generate Backup process
|
501 |
+
* Added incremental filesystem scan
|
502 |
+
* several bug fixes
|
503 |
+
* php >=5.2.0 version check
|
504 |
+
|
505 |
+
= 2.1.2 =
|
506 |
+
* Added Amazon S3 cron storage support
|
507 |
+
|
508 |
+
= 2.1 =
|
509 |
+
* Initial release
|
510 |
+
|
511 |
+
== Upgrade Notice ==
|
512 |
+
|
513 |
+
= 3.0.3 =
|
514 |
+
Please check changelog!
|
admin/class-xcloner-admin.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
/**
|
4 |
* The admin-specific functionality of the plugin.
|
5 |
*
|
6 |
-
* @link
|
7 |
* @since 1.0.0
|
8 |
*
|
9 |
* @package Xcloner
|
3 |
/**
|
4 |
* The admin-specific functionality of the plugin.
|
5 |
*
|
6 |
+
* @link https://watchful.net
|
7 |
* @since 1.0.0
|
8 |
*
|
9 |
* @package Xcloner
|
admin/partials/xcloner_generate_backups_page.php
CHANGED
@@ -293,8 +293,8 @@ $tab = 1;
|
|
293 |
<div class="row">
|
294 |
<h5><?php echo __("Thank you for using XCloner.", 'xcloner-backup-and-restore') ?></h5>
|
295 |
<h6><?php echo sprintf(__("We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore'), '<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore/reviews/" target="_blank">Wordpress XCloner Reviews Section</a>') ?></h6>
|
296 |
-
<a class="twitter-follow-button" href="https://twitter.com/
|
297 |
-
data-show-count="false">Follow @
|
298 |
<script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
|
299 |
|
300 |
<br/>
|
293 |
<div class="row">
|
294 |
<h5><?php echo __("Thank you for using XCloner.", 'xcloner-backup-and-restore') ?></h5>
|
295 |
<h6><?php echo sprintf(__("We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore'), '<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore/reviews/" target="_blank">Wordpress XCloner Reviews Section</a>') ?></h6>
|
296 |
+
<a class="twitter-follow-button" href="https://twitter.com/WatchfulDashbrd"
|
297 |
+
data-show-count="false">Follow @WatchfulDashbrd</a>
|
298 |
<script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
|
299 |
|
300 |
<br/>
|
admin/partials/xcloner_init_page.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
*
|
6 |
* This file is used to markup the admin-facing aspects of the plugin.
|
7 |
*
|
8 |
-
* @link
|
9 |
* @since 1.0.0
|
10 |
*
|
11 |
* @package Xcloner
|
5 |
*
|
6 |
* This file is used to markup the admin-facing aspects of the plugin.
|
7 |
*
|
8 |
+
* @link https://watchful.net
|
9 |
* @since 1.0.0
|
10 |
*
|
11 |
* @package Xcloner
|
api/api_test.html
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<html>
|
2 |
+
<head>
|
3 |
+
<title>Incremental Backup Generator XCloner API</title>
|
4 |
+
|
5 |
+
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
6 |
+
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
7 |
+
<script>
|
8 |
+
var url = document.URL,
|
9 |
+
shortUrl = url.substring(0, url.lastIndexOf("/"));
|
10 |
+
|
11 |
+
var api_base_url = shortUrl + "/expose_api.php";
|
12 |
+
|
13 |
+
var scan_filesystem_url = api_base_url + "?action=scan_filesystem";
|
14 |
+
var backup_database_url = api_base_url + "?action=backup_database";
|
15 |
+
var backup_files_url = api_base_url + "?action=backup_files";
|
16 |
+
|
17 |
+
var global_backup_hash;
|
18 |
+
var backup_profile;
|
19 |
+
|
20 |
+
async function make_call(call, init, params) {
|
21 |
+
var data = new FormData();
|
22 |
+
data.append("init", init);
|
23 |
+
data.append("hash", global_backup_hash || "");
|
24 |
+
data.append("extra", JSON.stringify(params) || "");
|
25 |
+
data.append("standalone_api_key", jQuery('#standalone_api_key').val() || "");
|
26 |
+
data.append("backup_profile", JSON.stringify(backup_profile) || "");
|
27 |
+
return axios
|
28 |
+
.post(window[`${call}_url`], data, {
|
29 |
+
headers: {
|
30 |
+
"Content-Type": "application/json",
|
31 |
+
},
|
32 |
+
})
|
33 |
+
.then(function (response) {
|
34 |
+
// handle success
|
35 |
+
let data = response.data;
|
36 |
+
jQuery("#output").append(
|
37 |
+
`<b>${call}</b>: ${JSON.stringify(data)} <br />`
|
38 |
+
);
|
39 |
+
if (!Boolean(data.finished)) {
|
40 |
+
global_backup_hash = data.hash.substr(1, data.hash.length);
|
41 |
+
return make_call(call, 0, data.extra);
|
42 |
+
}
|
43 |
+
});
|
44 |
+
}
|
45 |
+
|
46 |
+
function start_backup() {
|
47 |
+
jQuery("#output").html("");
|
48 |
+
make_call("scan_filesystem", 1)
|
49 |
+
.then(function () {
|
50 |
+
return make_call("backup_database", 1);
|
51 |
+
})
|
52 |
+
.then(function () {
|
53 |
+
return make_call("backup_files", 1);
|
54 |
+
})
|
55 |
+
.then(function () {
|
56 |
+
jQuery("#loading").hide();
|
57 |
+
jQuery("#output").append(`<b>Backup Finished.</b>`);
|
58 |
+
}).catch(function(){
|
59 |
+
jQuery("#loading").hide();
|
60 |
+
});
|
61 |
+
}
|
62 |
+
|
63 |
+
jQuery(document).ready(function () {
|
64 |
+
jQuery("#button").on("click", function () {
|
65 |
+
try {
|
66 |
+
if (jQuery("#backup_profile").val()) {
|
67 |
+
backup_profile = JSON.parse(jQuery("#backup_profile").val());
|
68 |
+
}
|
69 |
+
} catch {
|
70 |
+
alert("Backup profile JSON data is invalid!");
|
71 |
+
return;
|
72 |
+
}
|
73 |
+
if ((api_url = jQuery("#api_url"))) {
|
74 |
+
api_base_url = api_url;
|
75 |
+
}
|
76 |
+
|
77 |
+
jQuery("#loading").show();
|
78 |
+
start_backup();
|
79 |
+
});
|
80 |
+
});
|
81 |
+
</script>
|
82 |
+
</head>
|
83 |
+
<body>
|
84 |
+
<input
|
85 |
+
type="text"
|
86 |
+
style="width: 350px;"
|
87 |
+
placeholder="XCloner Standalone API url"
|
88 |
+
id="api_url"
|
89 |
+
/>
|
90 |
+
<button id="button">Start Backup</button> <br />
|
91 |
+
<input
|
92 |
+
type="text"
|
93 |
+
style="width: 350px;"
|
94 |
+
placeholder="API KEY = config xcloner_standalone_api_key"
|
95 |
+
id="standalone_api_key"> <br />
|
96 |
+
<textarea
|
97 |
+
id="backup_profile"
|
98 |
+
style="width: 350px; height: 150px;"
|
99 |
+
placeholder="Backup Profile JSON Config"
|
100 |
+
>
|
101 |
+
{
|
102 |
+
"extra": [],
|
103 |
+
"backup_params": {
|
104 |
+
"backup_name": "backup_[domain]_8888-[time]-sql",
|
105 |
+
"email_notification": "your@email.com",
|
106 |
+
"diff_start_date": "",
|
107 |
+
"profile_name": "test2",
|
108 |
+
"backup_encrypt": false,
|
109 |
+
"target_storage": ""
|
110 |
+
},
|
111 |
+
"database": {
|
112 |
+
"#": [
|
113 |
+
"wordpress" ]
|
114 |
+
},
|
115 |
+
"excluded_files": [
|
116 |
+
"wp-content",
|
117 |
+
"wp-includes"
|
118 |
+
]
|
119 |
+
}</textarea
|
120 |
+
>
|
121 |
+
|
122 |
+
<div id="output"></div>
|
123 |
+
<img
|
124 |
+
src="https://i.gifer.com/4V0b.gif"
|
125 |
+
id="loading"
|
126 |
+
style="display: none;"
|
127 |
+
/>
|
128 |
+
</body>
|
129 |
+
</html>
|
api/expose_api.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
define('WP_DEBUG', false);
|
3 |
+
define('WP_DEBUG_DISPLAY', false);
|
4 |
+
|
5 |
+
require_once(dirname(__DIR__) . '/includes/class-xcloner-standalone.php');
|
6 |
+
|
7 |
+
if (!is_admin()) {
|
8 |
+
die('Access denied');
|
9 |
+
}
|
10 |
+
|
11 |
+
//loading the default xcloner settings in format [{'option_name':'value', {'option_value': 'value'}}]
|
12 |
+
$json_config = json_decode(file_get_contents(__DIR__ . '/standalone_config.json'));
|
13 |
+
|
14 |
+
if (!$json_config) {
|
15 |
+
die('Could not parse default JSON config, i will shutdown for now...');
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!is_localhost())
|
19 |
+
{
|
20 |
+
if (!isset($_REQUEST['standalone_api_key']) || !$_REQUEST['standalone_api_key'] || $config['xcloner_standalone_api_key'] != $_REQUEST['standalone_api_key']) {
|
21 |
+
die('Access denied, please check your standalone_api_key value');
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
$config = [];
|
26 |
+
|
27 |
+
foreach ($json_config as $item) {
|
28 |
+
$config[$item->option_name] = $item->option_value;
|
29 |
+
}
|
30 |
+
|
31 |
+
//we check to see if we have a backup_profile sent over post
|
32 |
+
if (isset($_POST['backup_profile']) && trim($_POST['backup_profile'])) {
|
33 |
+
$arr = json_decode(stripslashes($_POST['backup_profile']), true);
|
34 |
+
$config['profile'] = array_combine(array_keys($arr), $arr);
|
35 |
+
$config['profile']['processed'] = true;
|
36 |
+
$_POST['data'] = json_encode($config['profile']);
|
37 |
+
}
|
38 |
+
|
39 |
+
if (isset($_POST['extra'])) {
|
40 |
+
$_POST['data'] = json_decode(stripslashes($_POST['data']));
|
41 |
+
$_POST['data']->extra = json_decode(($_POST['extra']));
|
42 |
+
$_POST['data'] = json_encode($_POST['data']);
|
43 |
+
}
|
44 |
+
|
45 |
+
//pass json config to Xcloner_Standalone lib
|
46 |
+
$xcloner_backup = new Xcloner_Standalone($json_config);
|
47 |
+
ob_end_clean();
|
48 |
+
|
49 |
+
$xcloner_backup->define_ajax_hooks();
|
50 |
+
$xcloner_backup->run();
|
api/index.html
ADDED
File without changes
|
api/standalone_config.json
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{"option_name":"xcloner_cleanup_retention_limit_archives","option_value":"100"},
|
3 |
+
{"option_name":"xcloner_cleanup_retention_limit_days","option_value":"60"},
|
4 |
+
{"option_name":"xcloner_cleanup_settings_page","option_value":""},
|
5 |
+
{"option_name":"xcloner_cron_settings_page","option_value":""},
|
6 |
+
{"option_name":"xcloner_database_records_per_request","option_value":"1000"},
|
7 |
+
{"option_name":"xcloner_db_version","option_value":"1.1.7"},
|
8 |
+
{"option_name":"xcloner_directories_to_scan_per_request","option_value":"1000"},
|
9 |
+
{"option_name":"xcloner_disable_email_notification","option_value":"1"},
|
10 |
+
{"option_name":"xcloner_enable_log","option_value":"1"},
|
11 |
+
{"option_name":"xcloner_enable_mysql_backup","option_value":"1"},
|
12 |
+
{"option_name":"xcloner_enable_pre_update_backup","option_value":""},
|
13 |
+
{"option_name":"xcloner_encryption_key","option_value":"FMo5vh6NCTo8zcmTsrzV88nnHj6BdoHGOAK"},
|
14 |
+
{"option_name":"xcloner_standalone_api_key","option_value":""},
|
15 |
+
{"option_name":"xcloner_exclude_files_larger_than_mb","option_value":"0"},
|
16 |
+
{"option_name":"xcloner_files_to_process_per_request","option_value":"328"},
|
17 |
+
{"option_name":"xcloner_force_tmp_path_site_root","option_value":"1"},
|
18 |
+
{"option_name":"xcloner_mysql_database","option_value":"wordpress"},
|
19 |
+
{"option_name":"xcloner_mysql_hostname","option_value":"localhost"},
|
20 |
+
{"option_name":"xcloner_mysql_password","option_value":"root"},
|
21 |
+
{"option_name":"xcloner_mysql_prefix","option_value":"wp_"},
|
22 |
+
{"option_name":"xcloner_mysql_settings_page","option_value":""},
|
23 |
+
{"option_name":"xcloner_mysql_username","option_value":"root"},
|
24 |
+
{"option_name":"xcloner_size_limit_per_request","option_value":"50"},
|
25 |
+
{"option_name":"xcloner_split_backup_limit","option_value":"2048"},
|
26 |
+
{"option_name":"xcloner_start_path","option_value":"\/Applications\/MAMP\/htdocs\/wordpress/"},
|
27 |
+
{"option_name":"xcloner_store_path","option_value":"\/Applications\/MAMP\/htdocs\/wordpress\/wp-content\/backups\/"},
|
28 |
+
{"option_name":"xcloner_system_settings_page","option_value":"100"},
|
29 |
+
{"option_name":"xcloner_text","option_value":"0"},
|
30 |
+
{"option_name":"profile", "option_value":{
|
31 |
+
"extra": [],
|
32 |
+
"backup_params": {
|
33 |
+
"backup_name": "backup_[domain]_8888-[time]-sql",
|
34 |
+
"email_notification": "info@thinkovi.com",
|
35 |
+
"diff_start_date": "",
|
36 |
+
"schedule_name": "test2",
|
37 |
+
"backup_encrypt": false,
|
38 |
+
"start_at": false,
|
39 |
+
"schedule_frequency": "daily",
|
40 |
+
"schedule_storage": ""
|
41 |
+
},
|
42 |
+
"database": {
|
43 |
+
"#": [
|
44 |
+
"wordpress",
|
45 |
+
"joomla"
|
46 |
+
]
|
47 |
+
},
|
48 |
+
"excluded_files": [
|
49 |
+
"wp-content",
|
50 |
+
"wp-includes"
|
51 |
+
]
|
52 |
+
}}
|
53 |
+
]
|
54 |
+
|
55 |
+
|
composer.lock
CHANGED
@@ -776,24 +776,24 @@
|
|
776 |
"time": "2019-04-26T15:02:17+00:00"
|
777 |
},
|
778 |
{
|
779 |
-
"name": "mikey179/
|
780 |
-
"version": "v1.6.
|
781 |
"source": {
|
782 |
"type": "git",
|
783 |
"url": "https://github.com/bovigo/vfsStream.git",
|
784 |
-
"reference": "
|
785 |
},
|
786 |
"dist": {
|
787 |
"type": "zip",
|
788 |
-
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/
|
789 |
-
"reference": "
|
790 |
"shasum": ""
|
791 |
},
|
792 |
"require": {
|
793 |
"php": ">=5.3.0"
|
794 |
},
|
795 |
"require-dev": {
|
796 |
-
"phpunit/phpunit": "
|
797 |
},
|
798 |
"type": "library",
|
799 |
"extra": {
|
@@ -819,7 +819,7 @@
|
|
819 |
],
|
820 |
"description": "Virtual file system to mock the real file system in unit tests.",
|
821 |
"homepage": "http://vfs.bovigo.org/",
|
822 |
-
"time": "
|
823 |
},
|
824 |
{
|
825 |
"name": "monolog/monolog",
|
@@ -1591,16 +1591,16 @@
|
|
1591 |
},
|
1592 |
{
|
1593 |
"name": "splitbrain/php-archive",
|
1594 |
-
"version": "1.
|
1595 |
"source": {
|
1596 |
"type": "git",
|
1597 |
"url": "https://github.com/splitbrain/php-archive.git",
|
1598 |
-
"reference": "
|
1599 |
},
|
1600 |
"dist": {
|
1601 |
"type": "zip",
|
1602 |
-
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/
|
1603 |
-
"reference": "
|
1604 |
"shasum": ""
|
1605 |
},
|
1606 |
"require": {
|
@@ -1641,7 +1641,7 @@
|
|
1641 |
"unzip",
|
1642 |
"zip"
|
1643 |
],
|
1644 |
-
"time": "2018-
|
1645 |
},
|
1646 |
{
|
1647 |
"name": "srmklive/flysystem-dropbox-v2",
|
776 |
"time": "2019-04-26T15:02:17+00:00"
|
777 |
},
|
778 |
{
|
779 |
+
"name": "mikey179/vfsstream",
|
780 |
+
"version": "v1.6.8",
|
781 |
"source": {
|
782 |
"type": "git",
|
783 |
"url": "https://github.com/bovigo/vfsStream.git",
|
784 |
+
"reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe"
|
785 |
},
|
786 |
"dist": {
|
787 |
"type": "zip",
|
788 |
+
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/231c73783ebb7dd9ec77916c10037eff5a2b6efe",
|
789 |
+
"reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe",
|
790 |
"shasum": ""
|
791 |
},
|
792 |
"require": {
|
793 |
"php": ">=5.3.0"
|
794 |
},
|
795 |
"require-dev": {
|
796 |
+
"phpunit/phpunit": "^4.5|^5.0"
|
797 |
},
|
798 |
"type": "library",
|
799 |
"extra": {
|
819 |
],
|
820 |
"description": "Virtual file system to mock the real file system in unit tests.",
|
821 |
"homepage": "http://vfs.bovigo.org/",
|
822 |
+
"time": "2019-10-30T15:31:00+00:00"
|
823 |
},
|
824 |
{
|
825 |
"name": "monolog/monolog",
|
1591 |
},
|
1592 |
{
|
1593 |
"name": "splitbrain/php-archive",
|
1594 |
+
"version": "1.1.1",
|
1595 |
"source": {
|
1596 |
"type": "git",
|
1597 |
"url": "https://github.com/splitbrain/php-archive.git",
|
1598 |
+
"reference": "10d89013572ba1f4d4ad7fcb74860242f4c3860b"
|
1599 |
},
|
1600 |
"dist": {
|
1601 |
"type": "zip",
|
1602 |
+
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/10d89013572ba1f4d4ad7fcb74860242f4c3860b",
|
1603 |
+
"reference": "10d89013572ba1f4d4ad7fcb74860242f4c3860b",
|
1604 |
"shasum": ""
|
1605 |
},
|
1606 |
"require": {
|
1641 |
"unzip",
|
1642 |
"zip"
|
1643 |
],
|
1644 |
+
"time": "2018-09-09T12:13:53+00:00"
|
1645 |
},
|
1646 |
{
|
1647 |
"name": "srmklive/flysystem-dropbox-v2",
|
examples/XCloner.postman_collection.json
ADDED
@@ -0,0 +1,288 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"info": {
|
3 |
+
"_postman_id": "6cec0b62-e427-4d8c-a656-4ab81c389cd5",
|
4 |
+
"name": "XCloner",
|
5 |
+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
6 |
+
},
|
7 |
+
"item": [
|
8 |
+
{
|
9 |
+
"name": "Scan Filesystem Incremental",
|
10 |
+
"request": {
|
11 |
+
"method": "POST",
|
12 |
+
"header": [
|
13 |
+
{
|
14 |
+
"key": "da",
|
15 |
+
"value": "dada",
|
16 |
+
"type": "text",
|
17 |
+
"disabled": true
|
18 |
+
}
|
19 |
+
],
|
20 |
+
"body": {
|
21 |
+
"mode": "formdata",
|
22 |
+
"formdata": [
|
23 |
+
{
|
24 |
+
"key": "hash",
|
25 |
+
"value": "12345",
|
26 |
+
"description": "optional hash to set the backup UID",
|
27 |
+
"type": "text"
|
28 |
+
},
|
29 |
+
{
|
30 |
+
"key": "init",
|
31 |
+
"value": "1",
|
32 |
+
"description": "set to 1 on first request",
|
33 |
+
"type": "text",
|
34 |
+
"disabled": true
|
35 |
+
}
|
36 |
+
]
|
37 |
+
},
|
38 |
+
"url": {
|
39 |
+
"raw": "http://localhost:8888/wordpress/wp-content/plugins/XCloner-Wordpress/examples/expose_api.php?action=scan_filesystem",
|
40 |
+
"protocol": "http",
|
41 |
+
"host": [
|
42 |
+
"localhost"
|
43 |
+
],
|
44 |
+
"port": "8888",
|
45 |
+
"path": [
|
46 |
+
"wordpress",
|
47 |
+
"wp-content",
|
48 |
+
"plugins",
|
49 |
+
"XCloner-Wordpress",
|
50 |
+
"examples",
|
51 |
+
"expose_api.php"
|
52 |
+
],
|
53 |
+
"query": [
|
54 |
+
{
|
55 |
+
"key": "init",
|
56 |
+
"value": "1",
|
57 |
+
"disabled": true
|
58 |
+
},
|
59 |
+
{
|
60 |
+
"key": "hash",
|
61 |
+
"value": "12345",
|
62 |
+
"disabled": true
|
63 |
+
},
|
64 |
+
{
|
65 |
+
"key": "data",
|
66 |
+
"value": "{\"value\":\"te\"}",
|
67 |
+
"disabled": true
|
68 |
+
},
|
69 |
+
{
|
70 |
+
"key": "action",
|
71 |
+
"value": "scan_filesystem"
|
72 |
+
}
|
73 |
+
]
|
74 |
+
},
|
75 |
+
"description": "hash - optional parameter made of 5 chars to set the backup default hash\ninit = 1 - will trigger a backup initialization process"
|
76 |
+
},
|
77 |
+
"response": []
|
78 |
+
},
|
79 |
+
{
|
80 |
+
"name": "List Backup Files",
|
81 |
+
"request": {
|
82 |
+
"method": "POST",
|
83 |
+
"header": [],
|
84 |
+
"body": {
|
85 |
+
"mode": "formdata",
|
86 |
+
"formdata": [
|
87 |
+
{
|
88 |
+
"key": "file",
|
89 |
+
"value": "backup__8888-2020-04-01_13-59-sql-e506e.tar",
|
90 |
+
"description": "file name",
|
91 |
+
"type": "text"
|
92 |
+
},
|
93 |
+
{
|
94 |
+
"key": "start",
|
95 |
+
"value": "0",
|
96 |
+
"description": "position to start reading from",
|
97 |
+
"type": "text"
|
98 |
+
}
|
99 |
+
]
|
100 |
+
},
|
101 |
+
"url": {
|
102 |
+
"raw": "http://localhost:8888/wordpress/wp-content/plugins/XCloner-Wordpress/examples/expose_api.php?action=list_backup_files",
|
103 |
+
"protocol": "http",
|
104 |
+
"host": [
|
105 |
+
"localhost"
|
106 |
+
],
|
107 |
+
"port": "8888",
|
108 |
+
"path": [
|
109 |
+
"wordpress",
|
110 |
+
"wp-content",
|
111 |
+
"plugins",
|
112 |
+
"XCloner-Wordpress",
|
113 |
+
"examples",
|
114 |
+
"expose_api.php"
|
115 |
+
],
|
116 |
+
"query": [
|
117 |
+
{
|
118 |
+
"key": "action",
|
119 |
+
"value": "list_backup_files"
|
120 |
+
}
|
121 |
+
]
|
122 |
+
}
|
123 |
+
},
|
124 |
+
"response": []
|
125 |
+
},
|
126 |
+
{
|
127 |
+
"name": "Get Backup File List",
|
128 |
+
"request": {
|
129 |
+
"method": "GET",
|
130 |
+
"header": [],
|
131 |
+
"url": {
|
132 |
+
"raw": "http://localhost:8888/wordpress/wp-content/plugins/XCloner-Wordpress/examples/expose_api.php?action=get_manage_backups_list",
|
133 |
+
"protocol": "http",
|
134 |
+
"host": [
|
135 |
+
"localhost"
|
136 |
+
],
|
137 |
+
"port": "8888",
|
138 |
+
"path": [
|
139 |
+
"wordpress",
|
140 |
+
"wp-content",
|
141 |
+
"plugins",
|
142 |
+
"XCloner-Wordpress",
|
143 |
+
"examples",
|
144 |
+
"expose_api.php"
|
145 |
+
],
|
146 |
+
"query": [
|
147 |
+
{
|
148 |
+
"key": "action",
|
149 |
+
"value": "get_manage_backups_list"
|
150 |
+
},
|
151 |
+
{
|
152 |
+
"key": "storage_selection",
|
153 |
+
"value": "",
|
154 |
+
"disabled": true
|
155 |
+
}
|
156 |
+
]
|
157 |
+
}
|
158 |
+
},
|
159 |
+
"response": []
|
160 |
+
},
|
161 |
+
{
|
162 |
+
"name": "Backup Database",
|
163 |
+
"request": {
|
164 |
+
"method": "POST",
|
165 |
+
"header": [],
|
166 |
+
"body": {
|
167 |
+
"mode": "formdata",
|
168 |
+
"formdata": [
|
169 |
+
{
|
170 |
+
"key": "data",
|
171 |
+
"value": "{\"table_params\":[{\"id\":\"wordpress\",\"parent\":\"#\"}],\"files_params\":[{\"id\":\"/\",\"parent\":\"#\"},{\"id\":\"wp-admin\",\"parent\":\"/\"},{\"id\":\"wp-content\",\"parent\":\"/\"},{\"id\":\"wp-includes\",\"parent\":\"/\"},{\"id\":\".htaccess\",\"parent\":\"/\"},{\"id\":\"index.php\",\"parent\":\"/\"},{\"id\":\"info.php\",\"parent\":\"/\"},{\"id\":\"license.txt\",\"parent\":\"/\"},{\"id\":\"readme.html\",\"parent\":\"/\"},{\"id\":\"test.log\",\"parent\":\"/\"},{\"id\":\"test_exec.php\",\"parent\":\"/\"},{\"id\":\"wp-activate.php\",\"parent\":\"/\"},{\"id\":\"wp-blog-header.php\",\"parent\":\"/\"},{\"id\":\"wp-comments-post.php\",\"parent\":\"/\"},{\"id\":\"wp-config-sample.php\",\"parent\":\"/\"},{\"id\":\"wp-config.php\",\"parent\":\"/\"},{\"id\":\"wp-config.php-e\",\"parent\":\"/\"},{\"id\":\"wp-config.php.old\",\"parent\":\"/\"},{\"id\":\"wp-cron.php\",\"parent\":\"/\"},{\"id\":\"wp-links-opml.php\",\"parent\":\"/\"},{\"id\":\"wp-load.php\",\"parent\":\"/\"},{\"id\":\"wp-login.php\",\"parent\":\"/\"},{\"id\":\"wp-mail.php\",\"parent\":\"/\"},{\"id\":\"wp-settings.php\",\"parent\":\"/\"},{\"id\":\"wp-signup.php\",\"parent\":\"/\"},{\"id\":\"wp-trackback.php\",\"parent\":\"/\"},{\"id\":\"xcloner_main_8ad98-2019-03-04.log\",\"parent\":\"/\"},{\"id\":\"xmlrpc.php\",\"parent\":\"/\"}],\"backup_params\":[{\"name\":\"backup_name\",\"value\":\"backup_[domain]_8888-[time]-sql\"},{\"name\":\"email_notification\",\"value\":\"info@thinkovi.com\"},{\"name\":\"diff_start_date\",\"value\":\"\"},{\"name\":\"backup_comments\",\"value\":\"\"},{\"name\":\"schedule_name\",\"value\":\"\"},{\"name\":\"schedule_start_date\",\"value\":\"\"},{\"name\":\"schedule_start_time\",\"value\":\"\"},{\"name\":\"schedule_storage\",\"value\":\"\"}]}",
|
172 |
+
"description": "initial config data to send for backup",
|
173 |
+
"type": "text"
|
174 |
+
},
|
175 |
+
{
|
176 |
+
"key": "init",
|
177 |
+
"value": "1",
|
178 |
+
"description": "send 1 on first request",
|
179 |
+
"type": "text",
|
180 |
+
"disabled": true
|
181 |
+
},
|
182 |
+
{
|
183 |
+
"key": "hash",
|
184 |
+
"value": "12345",
|
185 |
+
"description": "unique backup hash UID",
|
186 |
+
"type": "text"
|
187 |
+
},
|
188 |
+
{
|
189 |
+
"key": "extra",
|
190 |
+
"value": "",
|
191 |
+
"description": "last action call response extra parameter",
|
192 |
+
"type": "text"
|
193 |
+
}
|
194 |
+
]
|
195 |
+
},
|
196 |
+
"url": {
|
197 |
+
"raw": "http://localhost:8888/wordpress/wp-content/plugins/XCloner-Wordpress/examples/expose_api.php?action=backup_database",
|
198 |
+
"protocol": "http",
|
199 |
+
"host": [
|
200 |
+
"localhost"
|
201 |
+
],
|
202 |
+
"port": "8888",
|
203 |
+
"path": [
|
204 |
+
"wordpress",
|
205 |
+
"wp-content",
|
206 |
+
"plugins",
|
207 |
+
"XCloner-Wordpress",
|
208 |
+
"examples",
|
209 |
+
"expose_api.php"
|
210 |
+
],
|
211 |
+
"query": [
|
212 |
+
{
|
213 |
+
"key": "action",
|
214 |
+
"value": "backup_database"
|
215 |
+
}
|
216 |
+
]
|
217 |
+
}
|
218 |
+
},
|
219 |
+
"response": []
|
220 |
+
},
|
221 |
+
{
|
222 |
+
"name": "Backup Files",
|
223 |
+
"request": {
|
224 |
+
"method": "POST",
|
225 |
+
"header": [],
|
226 |
+
"body": {
|
227 |
+
"mode": "formdata",
|
228 |
+
"formdata": [
|
229 |
+
{
|
230 |
+
"key": "data",
|
231 |
+
"value": "{\"table_params\":[{\"id\":\"wordpress\",\"parent\":\"#\"}],\"files_params\":[{\"id\":\"/\",\"parent\":\"#\"},{\"id\":\"wp-admin\",\"parent\":\"/\"},{\"id\":\"wp-content\",\"parent\":\"/\"},{\"id\":\"wp-includes\",\"parent\":\"/\"},{\"id\":\".htaccess\",\"parent\":\"/\"},{\"id\":\"index.php\",\"parent\":\"/\"},{\"id\":\"info.php\",\"parent\":\"/\"},{\"id\":\"license.txt\",\"parent\":\"/\"},{\"id\":\"readme.html\",\"parent\":\"/\"},{\"id\":\"test.log\",\"parent\":\"/\"},{\"id\":\"test_exec.php\",\"parent\":\"/\"},{\"id\":\"wp-activate.php\",\"parent\":\"/\"},{\"id\":\"wp-blog-header.php\",\"parent\":\"/\"},{\"id\":\"wp-comments-post.php\",\"parent\":\"/\"},{\"id\":\"wp-config-sample.php\",\"parent\":\"/\"},{\"id\":\"wp-config.php\",\"parent\":\"/\"},{\"id\":\"wp-config.php-e\",\"parent\":\"/\"},{\"id\":\"wp-config.php.old\",\"parent\":\"/\"},{\"id\":\"wp-cron.php\",\"parent\":\"/\"},{\"id\":\"wp-links-opml.php\",\"parent\":\"/\"},{\"id\":\"wp-load.php\",\"parent\":\"/\"},{\"id\":\"wp-login.php\",\"parent\":\"/\"},{\"id\":\"wp-mail.php\",\"parent\":\"/\"},{\"id\":\"wp-settings.php\",\"parent\":\"/\"},{\"id\":\"wp-signup.php\",\"parent\":\"/\"},{\"id\":\"wp-trackback.php\",\"parent\":\"/\"},{\"id\":\"xcloner_main_8ad98-2019-03-04.log\",\"parent\":\"/\"},{\"id\":\"xmlrpc.php\",\"parent\":\"/\"}],\"backup_params\":[{\"name\":\"backup_name\",\"value\":\"backup_[domain]_8888-[time]-sql\"},{\"name\":\"email_notification\",\"value\":\"info@thinkovi.com\"},{\"name\":\"diff_start_date\",\"value\":\"\"},{\"name\":\"backup_comments\",\"value\":\"\"},{\"name\":\"schedule_name\",\"value\":\"\"},{\"name\":\"schedule_start_date\",\"value\":\"\"},{\"name\":\"schedule_start_time\",\"value\":\"\"},{\"name\":\"schedule_storage\",\"value\":\"\"}]}\n",
|
232 |
+
"description": "config data to send to the backup",
|
233 |
+
"type": "text"
|
234 |
+
},
|
235 |
+
{
|
236 |
+
"key": "init",
|
237 |
+
"value": "1",
|
238 |
+
"description": "send 1 on first action call",
|
239 |
+
"type": "text",
|
240 |
+
"disabled": true
|
241 |
+
},
|
242 |
+
{
|
243 |
+
"key": "hash",
|
244 |
+
"value": "12345",
|
245 |
+
"description": "unique backup hash",
|
246 |
+
"type": "text"
|
247 |
+
},
|
248 |
+
{
|
249 |
+
"key": "extra",
|
250 |
+
"value": "{\"backup_part\":\"0\",\"backup_init\":0,\"backup_archive_name\":\"backup__8888-2020-04-13_14-53-sql\",\"backup_archive_name_full\":\"backup__8888-2020-04-13_14-53-sql-12345.tar\",\"lines_total\":1194,\"backup_size\":21102080,\"processed_file\":\"Requests\\/Exception\\/HTTP\\/401.php\",\"processed_file_size\":390,\"start_at_line\":987,\"start_at_byte\":0}",
|
251 |
+
"description": "last action call response extra parameter",
|
252 |
+
"type": "text"
|
253 |
+
},
|
254 |
+
{
|
255 |
+
"key": "",
|
256 |
+
"value": "",
|
257 |
+
"type": "text"
|
258 |
+
}
|
259 |
+
]
|
260 |
+
},
|
261 |
+
"url": {
|
262 |
+
"raw": "http://localhost:8888/wordpress/wp-content/plugins/XCloner-Wordpress/examples/expose_api.php?action=backup_files",
|
263 |
+
"protocol": "http",
|
264 |
+
"host": [
|
265 |
+
"localhost"
|
266 |
+
],
|
267 |
+
"port": "8888",
|
268 |
+
"path": [
|
269 |
+
"wordpress",
|
270 |
+
"wp-content",
|
271 |
+
"plugins",
|
272 |
+
"XCloner-Wordpress",
|
273 |
+
"examples",
|
274 |
+
"expose_api.php"
|
275 |
+
],
|
276 |
+
"query": [
|
277 |
+
{
|
278 |
+
"key": "action",
|
279 |
+
"value": "backup_files"
|
280 |
+
}
|
281 |
+
]
|
282 |
+
}
|
283 |
+
},
|
284 |
+
"response": []
|
285 |
+
}
|
286 |
+
],
|
287 |
+
"protocolProfileBehavior": {}
|
288 |
+
}
|
examples/cli_encrypt_backup.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* USAGE
|
4 |
+
* php cli_encrypt_backup.php BACKUP_NAME --encrypt(--decrypt) --key=ENCRYPTION_KEY_OPTIONAL
|
5 |
+
*/
|
6 |
+
|
7 |
+
define('WP_DEBUG', true);
|
8 |
+
define('WP_DEBUG_DISPLAY', true);
|
9 |
+
|
10 |
+
if (isset($argv[1])) {
|
11 |
+
$backup_name = $argv[1];
|
12 |
+
}
|
13 |
+
|
14 |
+
if (isset($argv[2]) && $argv[2] == '--encrypt') {
|
15 |
+
$cmd = "encrypt";
|
16 |
+
}
|
17 |
+
|
18 |
+
if (isset($argv[2]) && $argv[2] == '--decrypt') {
|
19 |
+
$cmd = "decrypt";
|
20 |
+
}
|
21 |
+
|
22 |
+
$key = "";
|
23 |
+
|
24 |
+
if (isset($argv[3]) && substr($argv[3], 0, 6) == '--key=') {
|
25 |
+
$key = substr($argv[3], 6, strlen($argv[3]));
|
26 |
+
}
|
27 |
+
|
28 |
+
require_once(dirname(__DIR__) . '/includes/class-xcloner-standalone.php');
|
29 |
+
|
30 |
+
//loading the default xcloner settings in format [{'option_name':'value', {'option_value': 'value'}}]
|
31 |
+
$json_config = json_decode(file_get_contents(__DIR__ . '/standalone_backup_trigger_config.json'));
|
32 |
+
|
33 |
+
if (!$json_config) {
|
34 |
+
die('Could not parse default JSON config, i will shutdown for now...');
|
35 |
+
}
|
36 |
+
|
37 |
+
//pass json config to Xcloner_Standalone lib
|
38 |
+
$xcloner = new Xcloner_Standalone($json_config);
|
39 |
+
|
40 |
+
if (!$backup_name) {
|
41 |
+
$return = $xcloner->start();
|
42 |
+
$backup_name = $return['extra']['backup_archive_name_full'];
|
43 |
+
}
|
44 |
+
|
45 |
+
$backup_path = $xcloner->get_xcloner_filesystem()->get_storage_path_file_info($backup_name)->getPathName();
|
46 |
+
if (!file_exists($backup_path)) {
|
47 |
+
die(sprintf("Backup file %s does not exists.\n", $backup_path));
|
48 |
+
}
|
49 |
+
|
50 |
+
if (isset($cmd) && $cmd == "encrypt") {
|
51 |
+
$xcloner->get_xcloner_encryption()->encrypt_file($backup_name, "encrypted_".$backup_name, $key);
|
52 |
+
} elseif (isset($cmd) && $cmd == "decrypt") {
|
53 |
+
$xcloner->get_xcloner_encryption()->decrypt_file($backup_name, "decrypted_".$backup_name, $key);
|
54 |
+
}
|
55 |
+
|
56 |
+
if (!isset($cmd)) {
|
57 |
+
if ($xcloner->get_xcloner_encryption()->is_encrypted_file($backup_name)) {
|
58 |
+
echo sprintf("Backup %s is encrypted, i will try to decrypt it \n", $backup_name);
|
59 |
+
$xcloner->get_xcloner_encryption()->decrypt_file($backup_name, "decrypted_".$backup_name, $key);
|
60 |
+
} else {
|
61 |
+
echo sprintf("Backup %s is not encrypted, i will try to encrypt it \n", $backup_name);
|
62 |
+
$xcloner->get_xcloner_encryption()->encrypt_file($backup_name, "encrypted_".$backup_name, $key);
|
63 |
+
}
|
64 |
+
}
|
examples/index.html
ADDED
File without changes
|
examples/standalone-backup-trigger.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
define('WP_DEBUG', true);
|
3 |
+
define('WP_DEBUG_DISPLAY', true);
|
4 |
+
|
5 |
+
require_once(dirname(__DIR__) . '/includes/class-xcloner-standalone.php');
|
6 |
+
|
7 |
+
//loading the default xcloner settings in format [{'option_name':'value', {'option_value': 'value'}}]
|
8 |
+
$json_config = json_decode(file_get_contents(__DIR__ . '/standalone_backup_trigger_config.json'));
|
9 |
+
|
10 |
+
if (!$json_config) {
|
11 |
+
die('Could not parse default JSON config, i will shutdown for now...');
|
12 |
+
}
|
13 |
+
|
14 |
+
//pass json config to Xcloner_Standalone lib
|
15 |
+
$xcloner_backup = new Xcloner_Standalone($json_config);
|
16 |
+
$xcloner_backup->start();
|
examples/standalone_backup_trigger_config.json
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{"option_name":"xcloner_cleanup_retention_limit_archives","option_value":"100"},
|
3 |
+
{"option_name":"xcloner_cleanup_retention_limit_days","option_value":"60"},
|
4 |
+
{"option_name":"xcloner_cleanup_settings_page","option_value":""},
|
5 |
+
{"option_name":"xcloner_cron_settings_page","option_value":""},
|
6 |
+
{"option_name":"xcloner_database_records_per_request","option_value":"1000"},
|
7 |
+
{"option_name":"xcloner_db_version","option_value":"1.1.7"},
|
8 |
+
{"option_name":"xcloner_directories_to_scan_per_request","option_value":"1000"},
|
9 |
+
{"option_name":"xcloner_disable_email_notification","option_value":"1"},
|
10 |
+
{"option_name":"xcloner_enable_log","option_value":"1"},
|
11 |
+
{"option_name":"xcloner_enable_mysql_backup","option_value":"1"},
|
12 |
+
{"option_name":"xcloner_enable_pre_update_backup","option_value":""},
|
13 |
+
{"option_name":"xcloner_encryption_key","option_value":"FMo5vh6NCTo8zcmTsrzV88nnHj6BdoHGOAK"},
|
14 |
+
{"option_name":"xcloner_standalone_api_key","option_value":""},
|
15 |
+
{"option_name":"xcloner_exclude_files_larger_than_mb","option_value":"0"},
|
16 |
+
{"option_name":"xcloner_files_to_process_per_request","option_value":"328"},
|
17 |
+
{"option_name":"xcloner_force_tmp_path_site_root","option_value":"1"},
|
18 |
+
{"option_name":"xcloner_mysql_database","option_value":"wordpress"},
|
19 |
+
{"option_name":"xcloner_mysql_hostname","option_value":"localhost"},
|
20 |
+
{"option_name":"xcloner_mysql_password","option_value":"root"},
|
21 |
+
{"option_name":"xcloner_mysql_prefix","option_value":"wp_"},
|
22 |
+
{"option_name":"xcloner_mysql_settings_page","option_value":""},
|
23 |
+
{"option_name":"xcloner_mysql_username","option_value":"root"},
|
24 |
+
{"option_name":"xcloner_size_limit_per_request","option_value":"50"},
|
25 |
+
{"option_name":"xcloner_split_backup_limit","option_value":"2048"},
|
26 |
+
{"option_name":"xcloner_start_path","option_value":"\/Applications\/MAMP\/htdocs\/wordpress/"},
|
27 |
+
{"option_name":"xcloner_store_path","option_value":"\/Applications\/MAMP\/htdocs\/wordpress\/wp-content\/backups\/"},
|
28 |
+
{"option_name":"xcloner_system_settings_page","option_value":"100"},
|
29 |
+
{"option_name":"xcloner_text","option_value":"0"},
|
30 |
+
{"option_name":"profile", "option_value":{
|
31 |
+
"extra": [],
|
32 |
+
"backup_params": {
|
33 |
+
"backup_name": "backup_[domain]_8888-[time]-sql",
|
34 |
+
"email_notification": "info@thinkovi.com",
|
35 |
+
"diff_start_date": "",
|
36 |
+
"schedule_name": "test2",
|
37 |
+
"backup_encrypt": false,
|
38 |
+
"start_at": false,
|
39 |
+
"schedule_frequency": "daily",
|
40 |
+
"schedule_storage": ""
|
41 |
+
},
|
42 |
+
"database": {
|
43 |
+
"#": [
|
44 |
+
"wordpress",
|
45 |
+
"joomla"
|
46 |
+
]
|
47 |
+
},
|
48 |
+
"excluded_files": [
|
49 |
+
"wp-content",
|
50 |
+
"wp-includes"
|
51 |
+
]
|
52 |
+
}}
|
53 |
+
]
|
54 |
+
|
includes/class-xcloner-activator.php
CHANGED
@@ -35,48 +35,49 @@
|
|
35 |
* @package Xcloner
|
36 |
* @subpackage Xcloner/includes
|
37 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
38 |
-
* @link
|
39 |
*/
|
40 |
-
class Xcloner_Activator
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
80 |
`id` int(11) NOT NULL AUTO_INCREMENT,
|
81 |
`name` varchar(255) NOT NULL,
|
82 |
`recurrence` varchar(25) NOT NULL,
|
@@ -90,76 +91,74 @@ class Xcloner_Activator {
|
|
90 |
) " . $charset_collate.";
|
91 |
";
|
92 |
|
93 |
-
|
94 |
-
|
95 |
|
96 |
-
|
97 |
-
|
98 |
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
if (!get_option('xcloner_regex_exclude')) {
|
160 |
-
update_option('xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup)(.*)$".PHP_EOL."(.*)\.(svn|git)(.*)$".PHP_EOL."wp-content\/cache(.*)$".PHP_EOL."(.*)error_log$");
|
161 |
-
}
|
162 |
-
|
163 |
-
}
|
164 |
|
|
|
|
|
|
|
|
|
165 |
}
|
35 |
* @package Xcloner
|
36 |
* @subpackage Xcloner/includes
|
37 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
38 |
+
* @link https://watchful.net
|
39 |
*/
|
40 |
+
class Xcloner_Activator
|
41 |
+
{
|
42 |
+
|
43 |
+
/**
|
44 |
+
* XCloner Database Version
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
const xcloner_db_version = '1.1.7';
|
48 |
+
/**
|
49 |
+
* Minimum required PHP version to run this plugin.
|
50 |
+
* @var string
|
51 |
+
*/
|
52 |
+
const xcloner_minimum_version = '5.6.0';
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Triggered when XCloner is activated.
|
56 |
+
*
|
57 |
+
* This method will get trigger once XCloner plugin is activated.
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*/
|
61 |
+
public static function activate()
|
62 |
+
{
|
63 |
+
global $wpdb;
|
64 |
+
|
65 |
+
if (version_compare(phpversion(), Xcloner_Activator::xcloner_minimum_version, '<')) {
|
66 |
+
wp_die('<p>'.sprintf(__("XCloner requires minimum PHP version %s in order to run correctly. We have detected your version as %s"), Xcloner_Activator::xcloner_minimum_version, phpversion()).'</p>', __("XCloner Activation Error"), array('response' => 500,
|
67 |
+
'back_link' => true
|
68 |
+
));
|
69 |
+
}
|
70 |
+
|
71 |
+
$charset_collate = $wpdb->get_charset_collate();
|
72 |
+
|
73 |
+
$installed_ver = get_option("xcloner_db_version");
|
74 |
+
|
75 |
+
$xcloner_db_version = Xcloner_Activator::xcloner_db_version;
|
76 |
+
|
77 |
+
$xcloner_scheduler_table = $wpdb->prefix."xcloner_scheduler";
|
78 |
+
|
79 |
+
if ($installed_ver != $xcloner_db_version) {
|
80 |
+
$xcloner_schedule_sql = "CREATE TABLE `".$xcloner_scheduler_table."` (
|
81 |
`id` int(11) NOT NULL AUTO_INCREMENT,
|
82 |
`name` varchar(255) NOT NULL,
|
83 |
`recurrence` varchar(25) NOT NULL,
|
91 |
) " . $charset_collate.";
|
92 |
";
|
93 |
|
94 |
+
require_once(ABSPATH.'wp-admin/includes/upgrade.php');
|
95 |
+
dbDelta($xcloner_schedule_sql);
|
96 |
|
97 |
+
update_option("xcloner_db_version", $xcloner_db_version);
|
98 |
+
}
|
99 |
|
100 |
+
if (get_option('xcloner_backup_compression_level') === false) {
|
101 |
+
update_option('xcloner_backup_compression_level', 0);
|
102 |
+
}
|
103 |
|
104 |
+
if (get_option('xcloner_enable_log') === false) {
|
105 |
+
update_option('xcloner_enable_log', 1);
|
106 |
+
}
|
107 |
|
108 |
+
if (get_option('xcloner_force_tmp_path_site_root') === false) {
|
109 |
+
update_option('xcloner_force_tmp_path_site_root', 1);
|
110 |
+
}
|
111 |
|
112 |
+
if (get_option('xcloner_enable_mysql_backup') === false) {
|
113 |
+
update_option('xcloner_enable_mysql_backup', 1);
|
114 |
+
}
|
115 |
|
116 |
+
if (get_option('xcloner_system_settings_page') === false) {
|
117 |
+
update_option('xcloner_system_settings_page', 100);
|
118 |
+
}
|
119 |
|
120 |
+
if (get_option('xcloner_files_to_process_per_request') === false) {
|
121 |
+
update_option('xcloner_files_to_process_per_request', 250);
|
122 |
+
}
|
123 |
|
124 |
+
if (get_option('xcloner_database_records_per_request') === false) {
|
125 |
+
update_option('xcloner_database_records_per_request', 10000);
|
126 |
+
}
|
127 |
|
128 |
+
if (get_option('xcloner_exclude_files_larger_than_mb') === false) {
|
129 |
+
update_option('xcloner_exclude_files_larger_than_mb', 0);
|
130 |
+
}
|
131 |
|
132 |
+
if (get_option('xcloner_split_backup_limit') === false) {
|
133 |
+
update_option('xcloner_split_backup_limit', 2048);
|
134 |
+
}
|
135 |
|
136 |
+
if (get_option('xcloner_size_limit_per_request') === false) {
|
137 |
+
update_option('xcloner_size_limit_per_request', 50);
|
138 |
+
}
|
139 |
|
140 |
+
if (get_option('xcloner_cleanup_retention_limit_days') === false) {
|
141 |
+
update_option('xcloner_cleanup_retention_limit_days', 60);
|
142 |
+
}
|
143 |
|
144 |
+
if (get_option('xcloner_cleanup_retention_limit_archives') === false) {
|
145 |
+
update_option('xcloner_cleanup_retention_limit_archives', 100);
|
146 |
+
}
|
147 |
|
148 |
+
if (get_option('xcloner_directories_to_scan_per_request') === false) {
|
149 |
+
update_option('xcloner_directories_to_scan_per_request', 25);
|
150 |
+
}
|
151 |
|
152 |
+
/*if(!get_option('xcloner_diff_backup_recreate_period'))
|
153 |
+
update_option('xcloner_diff_backup_recreate_period', 10);
|
154 |
+
* */
|
155 |
|
156 |
+
if (!get_option('xcloner_regex_exclude')) {
|
157 |
+
update_option('xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup)(.*)$".PHP_EOL."(.*)\.(svn|git)(.*)$".PHP_EOL."wp-content\/cache(.*)$".PHP_EOL."(.*)error_log$");
|
158 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
+
if (!get_option('xcloner_regex_exclude')) {
|
161 |
+
update_option('xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup)(.*)$".PHP_EOL."(.*)\.(svn|git)(.*)$".PHP_EOL."wp-content\/cache(.*)$".PHP_EOL."(.*)error_log$");
|
162 |
+
}
|
163 |
+
}
|
164 |
}
|
includes/class-xcloner-api.php
CHANGED
@@ -36,925 +36,925 @@ use splitbrain\PHPArchive\Zip;
|
|
36 |
use splitbrain\PHPArchive\Archive;
|
37 |
use splitbrain\PHPArchive\FileInfo;
|
38 |
|
39 |
-
|
40 |
/**
|
41 |
* XCloner Api Class
|
42 |
*/
|
43 |
class Xcloner_Api
|
44 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
-
|
47 |
-
private $xcloner_settings;
|
48 |
-
private $xcloner_file_system;
|
49 |
-
private $xcloner_scheduler;
|
50 |
-
private $xcloner_requirements;
|
51 |
-
private $xcloner_sanitization;
|
52 |
-
private $xcloner_encryption;
|
53 |
-
private $xcloner_remote_storage;
|
54 |
-
private $archive_system;
|
55 |
-
private $form_params;
|
56 |
-
private $logger;
|
57 |
-
private $xcloner_container;
|
58 |
-
|
59 |
-
/**
|
60 |
-
* XCloner_Api construct class
|
61 |
-
*
|
62 |
-
* @param Xcloner $xcloner_container [description]
|
63 |
-
*/
|
64 |
-
public function __construct(Xcloner $xcloner_container)
|
65 |
-
{
|
66 |
-
global $wpdb;
|
67 |
-
|
68 |
-
if (WP_DEBUG) {
|
69 |
-
error_reporting(0);
|
70 |
-
}
|
71 |
-
|
72 |
-
if (ob_get_length()) {
|
73 |
-
ob_end_clean();
|
74 |
-
}
|
75 |
-
ob_start();
|
76 |
-
|
77 |
-
$wpdb->show_errors = false;
|
78 |
-
|
79 |
-
$this->xcloner_container = $xcloner_container;
|
80 |
-
|
81 |
-
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
82 |
-
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_api");
|
83 |
-
$this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
|
84 |
-
$this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
|
85 |
-
$this->xcloner_requirements = $xcloner_container->get_xcloner_requirements();
|
86 |
-
$this->archive_system = $xcloner_container->get_archive_system();
|
87 |
-
$this->xcloner_database = $xcloner_container->get_xcloner_database();
|
88 |
-
$this->xcloner_scheduler = $xcloner_container->get_xcloner_scheduler();
|
89 |
-
$this->xcloner_encryption = $xcloner_container->get_xcloner_encryption();
|
90 |
-
$this->xcloner_remote_storage = $xcloner_container->get_xcloner_remote_storage();
|
91 |
-
|
92 |
-
if (isset($_POST['API_ID'])) {
|
93 |
-
$this->logger->info("Processing ajax request ID ".substr($this->xcloner_sanitization->sanitize_input_as_string($_POST['API_ID']),
|
94 |
-
0, 15));
|
95 |
-
}
|
96 |
-
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Get XCloner Container
|
101 |
-
* @return XCloner return the XCloner container
|
102 |
-
*/
|
103 |
-
public function get_xcloner_container()
|
104 |
-
{
|
105 |
-
return $this->xcloner_container;
|
106 |
-
}
|
107 |
-
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Checks API access
|
111 |
-
*/
|
112 |
-
private function check_access()
|
113 |
-
{
|
114 |
-
if (function_exists('current_user_can') && !current_user_can('manage_options')) {
|
115 |
-
$this->send_response(json_encode("Not allowed access here!"));
|
116 |
-
}
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Initialize the database connection
|
121 |
-
*/
|
122 |
-
public function init_db()
|
123 |
-
{
|
124 |
-
return;
|
125 |
-
|
126 |
-
|
127 |
-
$data['dbHostname'] = $this->xcloner_settings->get_db_hostname();
|
128 |
-
$data['dbUsername'] = $this->xcloner_settings->get_db_username();
|
129 |
-
$data['dbPassword'] = $this->xcloner_settings->get_db_password();
|
130 |
-
$data['dbDatabase'] = $this->xcloner_settings->get_db_database();
|
131 |
-
|
132 |
-
|
133 |
-
$data['recordsPerSession'] = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
|
134 |
-
$data['TEMP_DBPROCESS_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS.".database";
|
135 |
-
$data['TEMP_DUMP_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS."database-sql.sql";
|
136 |
-
|
137 |
-
try {
|
138 |
-
$this->xcloner_database->init($data);
|
139 |
-
|
140 |
-
}catch (Exception $e) {
|
141 |
-
|
142 |
-
$this->send_response($e->getMessage());
|
143 |
-
$this->logger->error($e->getMessage());
|
144 |
-
|
145 |
-
}
|
146 |
-
|
147 |
-
return $this->xcloner_database;
|
148 |
-
|
149 |
-
|
150 |
-
}
|
151 |
-
|
152 |
-
/*
|
153 |
* Save Schedule API
|
154 |
*/
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
/*
|
288 |
*
|
289 |
* Backup Files API
|
290 |
*
|
291 |
*/
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
*
|
354 |
* Backup Database API
|
355 |
*
|
356 |
*/
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
|
361 |
-
|
362 |
|
363 |
-
|
364 |
|
365 |
-
|
366 |
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
|
371 |
-
|
372 |
|
373 |
-
|
374 |
-
|
375 |
-
|
|
|
|
|
|
|
376 |
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
|
383 |
-
|
384 |
|
385 |
-
|
386 |
-
|
387 |
|
388 |
-
|
389 |
*
|
390 |
* Scan Filesystem API
|
391 |
*
|
392 |
*/
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
|
397 |
-
|
398 |
|
399 |
-
|
400 |
-
$init = (int)$_POST['init'];
|
401 |
|
402 |
-
|
403 |
-
$this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
|
404 |
-
}
|
405 |
|
406 |
-
|
|
|
|
|
407 |
|
408 |
-
|
409 |
|
410 |
-
|
411 |
|
412 |
-
|
413 |
-
$data["total_files_num"] = $this->xcloner_file_system->get_scanned_files_num();
|
414 |
-
$data["last_logged_file"] = $this->xcloner_file_system->last_logged_file();
|
415 |
-
$data["total_files_size"] = sprintf("%.2f",
|
416 |
-
$this->xcloner_file_system->get_scanned_files_total_size() / (1024 * 1024));
|
417 |
|
418 |
-
|
419 |
-
|
|
|
|
|
|
|
|
|
|
|
420 |
|
421 |
-
|
|
|
|
|
|
|
422 |
*
|
423 |
* Process params sent by the user
|
424 |
*
|
425 |
*/
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
|
|
|
|
|
|
498 |
*
|
499 |
* Get file list for tree view API
|
500 |
*
|
501 |
*/
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
|
|
572 |
*
|
573 |
* Get databases/tables list for frontend tree display API
|
574 |
*
|
575 |
*/
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
*
|
653 |
* Get schedule by id API
|
654 |
*
|
655 |
*/
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
|
|
|
|
674 |
*
|
675 |
* Get Schedule list API
|
676 |
*
|
677 |
*/
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
|
682 |
-
|
683 |
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
|
688 |
-
|
689 |
-
|
690 |
<a href=\"#" . $res->id."\" class=\"delete\" title='Delete'><i class=\"material-icons \">delete</i></a>";
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
|
|
|
|
|
|
|
|
758 |
*
|
759 |
* Delete Schedule by ID API
|
760 |
*
|
761 |
*/
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
|
766 |
-
|
767 |
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
|
772 |
-
|
773 |
-
|
774 |
|
775 |
-
|
776 |
*
|
777 |
* Delete backup by name from the storage path
|
778 |
*
|
779 |
*/
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
$this->check_access();
|
785 |
-
|
786 |
-
$backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_POST['name']);
|
787 |
-
$storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_selection']);
|
788 |
-
|
789 |
-
$data['finished'] = $this->xcloner_file_system->delete_backup_by_name($backup_name, $storage_selection);
|
790 |
-
|
791 |
-
return $this->send_response($data);
|
792 |
-
}
|
793 |
-
|
794 |
-
/**
|
795 |
-
* API Incremental Backup Encryption Method
|
796 |
-
*/
|
797 |
-
public function backup_encryption()
|
798 |
-
{
|
799 |
-
$this->check_access();
|
800 |
-
|
801 |
-
$backup_parts = array();
|
802 |
-
$return = array();
|
803 |
-
|
804 |
-
|
805 |
-
if (isset($_POST['data'])) {
|
806 |
-
$params = json_decode(stripslashes($_POST['data']));
|
807 |
-
|
808 |
-
$this->process_params($params);
|
809 |
-
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($this->form_params['extra']['backup_parent']);
|
810 |
-
|
811 |
-
if (isset($this->form_params['extra']['start'])) {
|
812 |
-
$start = $this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['start']);
|
813 |
-
} else {
|
814 |
-
$start = 0;
|
815 |
-
}
|
816 |
-
|
817 |
-
if (isset($this->form_params['extra']['iv'])) {
|
818 |
-
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($this->form_params['extra']['iv']);
|
819 |
-
} else {
|
820 |
-
$iv = "";
|
821 |
-
}
|
822 |
-
|
823 |
-
if (isset($this->form_params['extra']['part'])) {
|
824 |
-
$return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['part']);
|
825 |
-
} else {
|
826 |
-
$return['part'] = 0;
|
827 |
-
}
|
828 |
-
|
829 |
-
} else {
|
830 |
-
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
831 |
-
$start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
|
832 |
-
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
|
833 |
-
$return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
834 |
-
}
|
835 |
-
|
836 |
-
$backup_file = $source_backup_file;
|
837 |
-
|
838 |
-
if ($this->xcloner_file_system->is_multipart($backup_file)) {
|
839 |
-
$backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
|
840 |
-
$backup_file = $backup_parts[$return['part']];
|
841 |
-
}
|
842 |
-
|
843 |
-
$return['processing_file'] = $backup_file;
|
844 |
-
$return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
|
845 |
-
|
846 |
-
try {
|
847 |
-
$this->logger->info(json_encode($_POST));
|
848 |
-
$this->logger->info($iv);
|
849 |
-
$return = array_merge($return,
|
850 |
-
$this->xcloner_encryption->encrypt_file($backup_file, "", "", $start, base64_decode($iv)));
|
851 |
-
}catch (\Exception $e) {
|
852 |
-
$return['error'] = true;
|
853 |
-
$return['message'] = $e->getMessage();
|
854 |
-
$return['error_message'] = $e->getMessage();
|
855 |
-
}
|
856 |
-
|
857 |
-
//echo strlen($return['iv']);exit;
|
858 |
-
|
859 |
-
if (isset($return['finished']) && $return['finished']) {
|
860 |
-
if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
|
861 |
-
$return['start'] = 0;
|
862 |
-
|
863 |
-
++$return['part'];
|
864 |
-
|
865 |
-
if ($return['part'] < sizeof($backup_parts)) {
|
866 |
-
$return['finished'] = 0;
|
867 |
-
}
|
868 |
-
|
869 |
-
}
|
870 |
-
}
|
871 |
-
|
872 |
-
if (isset($_POST['data'])) {
|
873 |
-
$return['extra'] = array_merge($this->form_params['extra'], $return);
|
874 |
-
}
|
875 |
-
|
876 |
-
$this->send_response($return, 0);
|
877 |
-
}
|
878 |
|
879 |
-
|
880 |
-
* API Incremental Backup Decryption Method
|
881 |
-
*/
|
882 |
-
public function backup_decryption()
|
883 |
-
{
|
884 |
-
$this->check_access();
|
885 |
|
886 |
-
|
887 |
-
|
888 |
|
889 |
-
|
890 |
-
$start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
|
891 |
-
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
|
892 |
-
$decryption_key = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['decryption_key']); ;
|
893 |
-
$return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
894 |
|
895 |
-
|
|
|
896 |
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
945 |
<?php
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
?>
|
958 |
<?php if (!isset($file_info['parent'])): ?>
|
959 |
|
960 |
<?php ob_start(); ?>
|
@@ -964,21 +964,22 @@ class Xcloner_Api
|
|
964 |
<label for="checkbox_<?php echo $i ?>"> </label>
|
965 |
</p>
|
966 |
<?php
|
967 |
-
|
968 |
-
|
969 |
-
?>
|
970 |
|
971 |
<?php ob_start(); ?>
|
972 |
<span class=""><?php echo $file_info['path'] ?></span>
|
973 |
<?php if (!$file_exists_on_local_storage): ?>
|
974 |
<a href="#"
|
975 |
-
title="<?php echo __(
|
976 |
-
|
|
|
|
|
977 |
class="material-icons backup_warning">warning</i></a>
|
978 |
<?php endif ?>
|
979 |
<?php
|
980 |
-
|
981 |
-
|
982 |
<a href="#" title="expand" class="expand-multipart add"><i
|
983 |
class="material-icons">add</i></a>
|
984 |
<a href="#" title="collapse" class="expand-multipart remove"><i class="material-icons">remove</i></a>
|
@@ -987,17 +988,18 @@ class Xcloner_Api
|
|
987 |
<li>
|
988 |
<?php echo $child[0] ?> (<?php echo esc_html(size_format($child[2])) ?>)
|
989 |
<?php
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
?>
|
997 |
<?php if (!$child_exists_on_local_storage): ?>
|
998 |
<a href="#"
|
999 |
-
title="<?php echo __(
|
1000 |
-
|
|
|
|
|
1001 |
class="material-icons backup_warning">warning</i></a>
|
1002 |
<?php endif ?>
|
1003 |
<?php if (!$storage_selection) : ?>
|
@@ -1011,8 +1013,10 @@ class Xcloner_Api
|
|
1011 |
</a>
|
1012 |
<?php else: ?>
|
1013 |
<a href="#<?php echo $child[0] ?>" class="list-backup-content"
|
1014 |
-
title="<?php echo __(
|
1015 |
-
|
|
|
|
|
1016 |
class="material-icons">folder_open</i></a>
|
1017 |
|
1018 |
<a href="#<?php echo $child[0] ?>" class="backup-encryption"
|
@@ -1023,8 +1027,10 @@ class Xcloner_Api
|
|
1023 |
|
1024 |
<?php elseif ($storage_selection != "gdrive" && !$this->xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
|
1025 |
<a href="#<?php echo $child[0] ?>" class="copy-remote-to-local"
|
1026 |
-
title="<?php echo __(
|
1027 |
-
|
|
|
|
|
1028 |
class="material-icons">file_upload</i></a>
|
1029 |
<?php endif ?>
|
1030 |
</li>
|
@@ -1032,24 +1038,21 @@ class Xcloner_Api
|
|
1032 |
</ul>
|
1033 |
<?php endif; ?>
|
1034 |
<?php
|
1035 |
-
|
1036 |
-
|
1037 |
-
?>
|
1038 |
<?php ob_start(); ?>
|
1039 |
-
<?php if (isset($file_info['timestamp']))
|
1040 |
-
|
1041 |
-
|
1042 |
<?php
|
1043 |
-
|
1044 |
-
|
1045 |
-
?>
|
1046 |
|
1047 |
<?php ob_start(); ?>
|
1048 |
<?php echo esc_html(size_format($file_info['size'])) ?>
|
1049 |
<?php
|
1050 |
-
|
1051 |
-
|
1052 |
-
?>
|
1053 |
|
1054 |
<?php ob_start(); ?>
|
1055 |
<?php if (!$storage_selection): ?>
|
@@ -1059,15 +1062,17 @@ class Xcloner_Api
|
|
1059 |
|
1060 |
<?php if (sizeof($available_storages)): ?>
|
1061 |
<a href="#<?php echo $file_info['basename'] ?>" class="cloud-upload"
|
1062 |
-
title="<?php echo __(
|
1063 |
-
|
|
|
|
|
1064 |
class="material-icons">cloud_upload</i></a>
|
1065 |
<?php endif ?>
|
1066 |
<?php
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
<?php if ($this->xcloner_encryption->is_encrypted_file($basename)) :?>
|
1072 |
<a href="#<?php echo $file_info['basename'] ?>" class="backup-decryption"
|
1073 |
title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
|
@@ -1096,196 +1101,193 @@ class Xcloner_Api
|
|
1096 |
<?php endif ?>
|
1097 |
|
1098 |
<?php
|
1099 |
-
|
1100 |
-
|
1101 |
|
1102 |
<?php endif ?>
|
1103 |
<?php endforeach ?>
|
1104 |
<?php
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
|
|
|
|
1182 |
* Copy remote backup to local storage
|
1183 |
*/
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
$this->check_access();
|
1188 |
-
|
1189 |
-
$backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
1190 |
-
$storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
|
1191 |
-
|
1192 |
-
$xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
1193 |
|
1194 |
-
|
|
|
1195 |
|
1196 |
-
|
1197 |
-
if (method_exists($xcloner_remote_storage, "copy_backup_remote_to_local")) {
|
1198 |
-
$return = call_user_func_array(array(
|
1199 |
-
$xcloner_remote_storage,
|
1200 |
-
"copy_backup_remote_to_local"
|
1201 |
-
), array($backup_file, $storage_type));
|
1202 |
-
}
|
1203 |
-
}catch (Exception $e) {
|
1204 |
|
1205 |
-
|
1206 |
-
$return['message'] = $e->getMessage();
|
1207 |
-
}
|
1208 |
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1213 |
|
|
|
|
|
|
|
|
|
1214 |
|
1215 |
-
$this->send_response($return, 0);
|
1216 |
|
1217 |
-
|
|
|
1218 |
|
1219 |
-
|
1220 |
*
|
1221 |
* Upload backup to remote API
|
1222 |
*
|
1223 |
*/
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
|
1228 |
-
|
1229 |
|
1230 |
-
|
1231 |
-
|
1232 |
|
1233 |
-
|
1234 |
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
|
|
|
|
|
|
1243 |
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
|
|
1247 |
|
1248 |
-
if (!$return) {
|
1249 |
-
$return['error'] = 1;
|
1250 |
-
$return['message'] = "Upload failed, please check the error log for more information!";
|
1251 |
-
}
|
1252 |
|
|
|
|
|
1253 |
|
1254 |
-
|
1255 |
-
|
1256 |
-
}
|
1257 |
-
|
1258 |
-
/*
|
1259 |
*
|
1260 |
* Remote Storage Status Save
|
1261 |
*
|
1262 |
*/
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
|
1267 |
-
|
1268 |
|
1269 |
-
|
1270 |
|
1271 |
-
|
1272 |
|
1273 |
-
|
1274 |
-
|
1275 |
|
1276 |
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
|
1281 |
-
|
1282 |
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
|
1288 |
-
|
1289 |
$file = 'restore/vendor.built';
|
1290 |
|
1291 |
if(file_exists($file))
|
@@ -1301,185 +1303,178 @@ class Xcloner_Api
|
|
1301 |
$phar2->setStub($phar2->createDefaultStub('vendor/autoload.php', 'vendor/autoload.php'));
|
1302 |
* */
|
1303 |
|
1304 |
-
|
1305 |
|
1306 |
-
|
1307 |
-
|
1308 |
|
1309 |
-
|
1310 |
-
|
1311 |
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
|
1317 |
-
|
1318 |
-
|
1319 |
|
1320 |
-
|
1321 |
|
1322 |
-
|
1323 |
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
|
|
1333 |
|
1334 |
-
|
|
|
|
|
|
|
|
|
1335 |
|
1336 |
-
|
1337 |
-
|
1338 |
-
}catch (Exception $e) {
|
1339 |
-
//We are not interested in the error here
|
1340 |
-
}
|
1341 |
|
1342 |
-
|
1343 |
-
}
|
1344 |
-
|
1345 |
-
/*
|
1346 |
*
|
1347 |
* Download backup by Name from the Storage Path
|
1348 |
*
|
1349 |
*/
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
ob_end_clean();
|
1355 |
|
1356 |
-
|
1357 |
|
|
|
1358 |
|
1359 |
-
$metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($backup_name);
|
1360 |
-
$read_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($backup_name);
|
1361 |
|
|
|
|
|
1362 |
|
1363 |
-
header('Pragma: public');
|
1364 |
-
header('Expires: 0');
|
1365 |
-
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
1366 |
-
header('Cache-Control: private', false);
|
1367 |
-
header('Content-Transfer-Encoding: binary');
|
1368 |
-
header('Content-Disposition: attachment; filename="'.$metadata['path'].'";');
|
1369 |
-
header('Content-Type: application/octet-stream');
|
1370 |
-
header('Content-Length: '.$metadata['size']);
|
1371 |
|
1372 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1373 |
|
1374 |
-
|
1375 |
-
while (!feof($read_stream)) {
|
1376 |
-
$buffer = fread($read_stream, $chunkSize);
|
1377 |
-
echo $buffer;
|
1378 |
-
}
|
1379 |
-
fclose($read_stream);
|
1380 |
|
1381 |
-
|
|
|
|
|
|
|
|
|
|
|
1382 |
|
1383 |
-
|
|
|
1384 |
|
1385 |
-
|
1386 |
* Restore upload backup
|
1387 |
*/
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
|
1392 |
-
|
1393 |
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
|
1399 |
-
|
1400 |
-
|
1401 |
|
1402 |
-
|
1403 |
-
|
1404 |
-
|
1405 |
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
|
1410 |
-
|
1411 |
-
|
1412 |
|
1413 |
-
|
1414 |
|
1415 |
-
|
1416 |
-
|
1417 |
|
1418 |
-
|
1419 |
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
|
1424 |
-
|
1425 |
-
|
1426 |
|
1427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1428 |
|
1429 |
-
|
1430 |
-
$xcloner_file_transfer->set_target($target_url);
|
1431 |
-
$return['start'] = $xcloner_file_transfer->transfer_file($file, $start, $hash);
|
1432 |
|
1433 |
-
|
|
|
|
|
|
|
|
|
1434 |
|
1435 |
-
|
1436 |
-
|
1437 |
-
$return['status'] = 500;
|
1438 |
-
$return['message'] = "CURL communication error with the restore host. ".$e->getMessage();
|
1439 |
-
$this->send_response($return, 0);
|
1440 |
|
1441 |
-
|
1442 |
-
|
1443 |
-
$return['status'] = 200;
|
1444 |
-
|
1445 |
-
//we have finished the upload
|
1446 |
-
if (!$return['start'] and $is_multipart) {
|
1447 |
-
$return['part']++;
|
1448 |
-
$return['uploaded_size'] += $this->xcloner_file_system->get_storage_filesystem()->getSize($file);
|
1449 |
-
}
|
1450 |
-
|
1451 |
-
$this->send_response($return, 0);
|
1452 |
-
}
|
1453 |
-
|
1454 |
-
/*
|
1455 |
* Restore backup
|
1456 |
*/
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
|
1461 |
-
|
1462 |
-
|
1463 |
|
1464 |
-
|
1465 |
-
|
1466 |
|
1467 |
-
|
1468 |
*
|
1469 |
* Send the json response back
|
1470 |
*
|
1471 |
*/
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
|
1482 |
-
|
1483 |
-
|
1484 |
-
}
|
1485 |
}
|
36 |
use splitbrain\PHPArchive\Archive;
|
37 |
use splitbrain\PHPArchive\FileInfo;
|
38 |
|
|
|
39 |
/**
|
40 |
* XCloner Api Class
|
41 |
*/
|
42 |
class Xcloner_Api
|
43 |
{
|
44 |
+
private $xcloner_database;
|
45 |
+
private $xcloner_settings;
|
46 |
+
private $xcloner_file_system;
|
47 |
+
private $xcloner_scheduler;
|
48 |
+
private $xcloner_requirements;
|
49 |
+
private $xcloner_sanitization;
|
50 |
+
private $xcloner_encryption;
|
51 |
+
private $xcloner_remote_storage;
|
52 |
+
private $archive_system;
|
53 |
+
private $form_params;
|
54 |
+
private $logger;
|
55 |
+
private $xcloner_container;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* XCloner_Api construct class
|
59 |
+
*
|
60 |
+
* @param Xcloner $xcloner_container [description]
|
61 |
+
*/
|
62 |
+
public function __construct(Xcloner $xcloner_container)
|
63 |
+
{
|
64 |
+
//global $wpdb;
|
65 |
+
|
66 |
+
if (defined('WP_DEBUG') && WP_DEBUG) {
|
67 |
+
error_reporting(0);
|
68 |
+
}
|
69 |
+
|
70 |
+
if (ob_get_length()) {
|
71 |
+
ob_end_clean();
|
72 |
+
}
|
73 |
+
ob_start();
|
74 |
+
|
75 |
+
$this->xcloner_container = $xcloner_container;
|
76 |
+
|
77 |
+
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
78 |
+
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_api");
|
79 |
+
$this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
|
80 |
+
$this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
|
81 |
+
$this->xcloner_requirements = $xcloner_container->get_xcloner_requirements();
|
82 |
+
$this->archive_system = $xcloner_container->get_archive_system();
|
83 |
+
$this->xcloner_database = $xcloner_container->get_xcloner_database();
|
84 |
+
$this->xcloner_scheduler = $xcloner_container->get_xcloner_scheduler();
|
85 |
+
$this->xcloner_encryption = $xcloner_container->get_xcloner_encryption();
|
86 |
+
$this->xcloner_remote_storage = $xcloner_container->get_xcloner_remote_storage();
|
87 |
+
|
88 |
+
$this->xcloner_database->show_errors = false;
|
89 |
+
|
90 |
+
if (isset($_POST['API_ID'])) {
|
91 |
+
$this->logger->info("Processing ajax request ID ".substr(
|
92 |
+
$this->xcloner_sanitization->sanitize_input_as_string($_POST['API_ID']),
|
93 |
+
0,
|
94 |
+
15
|
95 |
+
));
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Get XCloner Container
|
101 |
+
* @return XCloner return the XCloner container
|
102 |
+
*/
|
103 |
+
public function get_xcloner_container()
|
104 |
+
{
|
105 |
+
return $this->xcloner_container;
|
106 |
+
}
|
107 |
+
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Checks API access
|
111 |
+
*/
|
112 |
+
private function check_access()
|
113 |
+
{
|
114 |
+
if (function_exists('current_user_can') && !current_user_can('manage_options')) {
|
115 |
+
$this->send_response(json_encode("Not allowed access here!"));
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Initialize the database connection
|
121 |
+
*/
|
122 |
+
public function init_db()
|
123 |
+
{
|
124 |
+
return;
|
125 |
+
}
|
126 |
|
127 |
+
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
* Save Schedule API
|
129 |
*/
|
130 |
+
public function save_schedule()
|
131 |
+
{
|
132 |
+
//global $wpdb;
|
133 |
+
|
134 |
+
$this->check_access();
|
135 |
+
|
136 |
+
$scheduler = $this->xcloner_scheduler;
|
137 |
+
$params = array();
|
138 |
+
$schedule = array();
|
139 |
+
$response = array();
|
140 |
+
|
141 |
+
if (isset($_POST['data'])) {
|
142 |
+
$params = json_decode(stripslashes($_POST['data']));
|
143 |
+
}
|
144 |
+
|
145 |
+
$this->process_params($params);
|
146 |
+
|
147 |
+
if (isset($_POST['id'])) {
|
148 |
+
$this->form_params['backup_params']['backup_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_name']);
|
149 |
+
$this->form_params['backup_params']['email_notification'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['email_notification']);
|
150 |
+
if ($_POST['diff_start_date']) {
|
151 |
+
$this->form_params['backup_params']['diff_start_date'] = strtotime($this->xcloner_sanitization->sanitize_input_as_string($_POST['diff_start_date']));
|
152 |
+
} else {
|
153 |
+
$this->form_params['backup_params']['diff_start_date'] = "";
|
154 |
+
}
|
155 |
+
$this->form_params['backup_params']['schedule_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_name']);
|
156 |
+
$this->form_params['backup_params']['backup_encrypt'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['backup_encrypt']);
|
157 |
+
$this->form_params['backup_params']['start_at'] = strtotime($_POST['schedule_start_date']);
|
158 |
+
$this->form_params['backup_params']['schedule_frequency'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_frequency']);
|
159 |
+
$this->form_params['backup_params']['schedule_storage'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_storage']);
|
160 |
+
$this->form_params['database'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['table_params'])));
|
161 |
+
$this->form_params['excluded_files'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['excluded_files'])));
|
162 |
+
|
163 |
+
//$this->form_params['backup_params']['backup_type'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_type']);
|
164 |
+
|
165 |
+
$tables = explode(PHP_EOL, $this->form_params['database']);
|
166 |
+
$return = array();
|
167 |
+
|
168 |
+
foreach ($tables as $table) {
|
169 |
+
$table = str_replace("\r", "", $table);
|
170 |
+
$data = explode(".", $table);
|
171 |
+
if (isset($data[1])) {
|
172 |
+
$return[$data[0]][] = $data[1];
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
$this->form_params['database'] = ($return);
|
177 |
+
|
178 |
+
$excluded_files = explode(PHP_EOL, $this->form_params['excluded_files']);
|
179 |
+
$return = array();
|
180 |
+
|
181 |
+
foreach ($excluded_files as $file) {
|
182 |
+
$file = str_replace("\r", "", $file);
|
183 |
+
if ($file) {
|
184 |
+
$return[] = $file;
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
$this->form_params['excluded_files'] = ($return);
|
189 |
+
|
190 |
+
$schedule['start_at'] = $this->form_params['backup_params']['start_at'];
|
191 |
+
|
192 |
+
if (!isset($_POST['status'])) {
|
193 |
+
$schedule['status'] = 0;
|
194 |
+
} else {
|
195 |
+
$schedule['status'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['status']);
|
196 |
+
}
|
197 |
+
} else {
|
198 |
+
$schedule['status'] = 1;
|
199 |
+
$schedule['start_at'] = strtotime($this->form_params['backup_params']['schedule_start_date'].
|
200 |
+
" ".$this->form_params['backup_params']['schedule_start_time']);
|
201 |
+
|
202 |
+
if ($schedule['start_at'] <= time()) {
|
203 |
+
$schedule['start_at'] = "";
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
if (!$schedule['start_at']) {
|
208 |
+
$schedule['start_at'] = date('Y-m-d H:i:s', time());
|
209 |
+
} else {
|
210 |
+
$schedule['start_at'] = date(
|
211 |
+
'Y-m-d H:i:s',
|
212 |
+
$schedule['start_at'] - ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS)
|
213 |
+
);
|
214 |
+
}
|
215 |
+
|
216 |
+
$schedule['name'] = $this->form_params['backup_params']['schedule_name'];
|
217 |
+
$schedule['recurrence'] = $this->form_params['backup_params']['schedule_frequency'];
|
218 |
+
if (!isset($this->form_params['backup_params']['schedule_storage'])) {
|
219 |
+
$this->form_params['backup_params']['schedule_storage'] = "";
|
220 |
+
}
|
221 |
+
$schedule['remote_storage'] = $this->form_params['backup_params']['schedule_storage'];
|
222 |
+
//$schedule['backup_type'] = $this->form_params['backup_params']['backup_type'];
|
223 |
+
$schedule['params'] = json_encode($this->form_params);
|
224 |
+
|
225 |
+
if (!isset($_POST['id'])) {
|
226 |
+
$this->xcloner_database->insert(
|
227 |
+
$this->xcloner_settings->get_table_prefix().'xcloner_scheduler',
|
228 |
+
$schedule,
|
229 |
+
array(
|
230 |
+
'%s',
|
231 |
+
'%s'
|
232 |
+
)
|
233 |
+
);
|
234 |
+
} else {
|
235 |
+
$this->xcloner_database->update(
|
236 |
+
$this->xcloner_settings->get_table_prefix().'xcloner_scheduler',
|
237 |
+
$schedule,
|
238 |
+
array('id' => $_POST['id']),
|
239 |
+
array(
|
240 |
+
'%s',
|
241 |
+
'%s'
|
242 |
+
)
|
243 |
+
);
|
244 |
+
}
|
245 |
+
if (isset($_POST['id'])) {
|
246 |
+
$scheduler->update_cron_hook($_POST['id']);
|
247 |
+
}
|
248 |
+
|
249 |
+
if ($this->xcloner_database->last_error) {
|
250 |
+
$response['error'] = 1;
|
251 |
+
$response['error_message'] = $this->xcloner_database->last_error/*."--".$this->xcloner_database->last_query*/
|
252 |
+
;
|
253 |
+
}
|
254 |
+
|
255 |
+
$scheduler->update_wp_cron_hooks();
|
256 |
+
$response['finished'] = 1;
|
257 |
+
|
258 |
+
$this->send_response($response);
|
259 |
+
}
|
260 |
+
|
261 |
+
/*
|
|
|
262 |
*
|
263 |
* Backup Files API
|
264 |
*
|
265 |
*/
|
266 |
+
public function backup_files()
|
267 |
+
{
|
268 |
+
$return = array();
|
269 |
+
$additional = array();
|
270 |
+
|
271 |
+
$this->check_access();
|
272 |
+
|
273 |
+
$params = json_decode(stripslashes($_POST['data']));
|
274 |
+
|
275 |
+
$init = (int)$_POST['init'];
|
276 |
+
|
277 |
+
if ($params === null) {
|
278 |
+
return $this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
|
279 |
+
}
|
280 |
+
|
281 |
+
$this->process_params($params);
|
282 |
+
|
283 |
+
$return['finished'] = 1;
|
284 |
+
|
285 |
+
//$return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'], $this->form_params['extra'], $init);
|
286 |
+
try {
|
287 |
+
$return = $this->archive_system->start_incremental_backup(
|
288 |
+
$this->form_params['backup_params'],
|
289 |
+
$this->form_params['extra'],
|
290 |
+
$init
|
291 |
+
);
|
292 |
+
} catch (Exception $e) {
|
293 |
+
$return = array();
|
294 |
+
$return['error'] = true;
|
295 |
+
$return['status'] = 500;
|
296 |
+
$return['error_message'] = $e->getMessage();
|
297 |
+
|
298 |
+
return $this->send_response($return, $hash = 1);
|
299 |
+
}
|
300 |
+
|
301 |
+
if ($return['finished']) {
|
302 |
+
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
|
303 |
+
if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
|
304 |
+
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
$data = $return;
|
309 |
+
|
310 |
+
//check if backup is finished
|
311 |
+
if ($return['finished']) {
|
312 |
+
if (isset($this->form_params['backup_params']['email_notification']) and $to = $this->form_params['backup_params']['email_notification']) {
|
313 |
+
try {
|
314 |
+
$from = "";
|
315 |
+
$subject = "";
|
316 |
+
$additional['lines_total'] = $return['extra']['lines_total'];
|
317 |
+
$this->archive_system->send_notification(
|
318 |
+
$to,
|
319 |
+
$from,
|
320 |
+
$subject,
|
321 |
+
$return['extra']['backup_parent'],
|
322 |
+
$this->form_params,
|
323 |
+
"",
|
324 |
+
$additional
|
325 |
+
);
|
326 |
+
} catch (Exception $e) {
|
327 |
+
$this->logger->error($e->getMessage());
|
328 |
+
}
|
329 |
+
}
|
330 |
+
$this->xcloner_file_system->remove_tmp_filesystem();
|
331 |
+
}
|
332 |
+
|
333 |
+
return $this->send_response($data, $hash = 1);
|
334 |
+
}
|
335 |
+
|
336 |
+
/*
|
337 |
*
|
338 |
* Backup Database API
|
339 |
*
|
340 |
*/
|
341 |
+
public function backup_database()
|
342 |
+
{
|
343 |
+
$data = array();
|
344 |
|
345 |
+
$this->check_access();
|
346 |
|
347 |
+
$params = json_decode(stripslashes($_POST['data']));
|
348 |
|
349 |
+
$init = (int)$_POST['init'];
|
350 |
|
351 |
+
if ($params === null) {
|
352 |
+
return $this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
|
353 |
+
}
|
354 |
|
355 |
+
$this->process_params($params);
|
356 |
|
357 |
+
//$xcloner_database = $this->init_db();
|
358 |
+
$return = $this->xcloner_database->start_database_recursion(
|
359 |
+
$this->form_params['database'],
|
360 |
+
$this->form_params['extra'],
|
361 |
+
$init
|
362 |
+
);
|
363 |
|
364 |
+
if (isset($return['error']) and $return['error']) {
|
365 |
+
$data['finished'] = 1;
|
366 |
+
} else {
|
367 |
+
$data['finished'] = $return['finished'];
|
368 |
+
}
|
369 |
|
370 |
+
$data['extra'] = $return;
|
371 |
|
372 |
+
return $this->send_response($data, $hash = 1);
|
373 |
+
}
|
374 |
|
375 |
+
/*
|
376 |
*
|
377 |
* Scan Filesystem API
|
378 |
*
|
379 |
*/
|
380 |
+
public function scan_filesystem()
|
381 |
+
{
|
382 |
+
$data = array();
|
383 |
|
384 |
+
$this->check_access();
|
385 |
|
386 |
+
$params = json_decode(stripslashes($_POST['data']));
|
|
|
387 |
|
388 |
+
$init = (int)$_POST['init'];
|
|
|
|
|
389 |
|
390 |
+
if ($params === null) {
|
391 |
+
$this->send_response('{"status":false,"msg":"The post_data profile parameter must be valid JSON"}');
|
392 |
+
}
|
393 |
|
394 |
+
$this->process_params($params);
|
395 |
|
396 |
+
$this->xcloner_file_system->set_excluded_files($this->form_params['excluded_files']);
|
397 |
|
398 |
+
$return = $this->xcloner_file_system->start_file_recursion($init);
|
|
|
|
|
|
|
|
|
399 |
|
400 |
+
$data["finished"] = !$return;
|
401 |
+
$data["total_files_num"] = $this->xcloner_file_system->get_scanned_files_num();
|
402 |
+
$data["last_logged_file"] = $this->xcloner_file_system->last_logged_file();
|
403 |
+
$data["total_files_size"] = sprintf(
|
404 |
+
"%.2f",
|
405 |
+
$this->xcloner_file_system->get_scanned_files_total_size() / (1024 * 1024)
|
406 |
+
);
|
407 |
|
408 |
+
return $this->send_response($data, $hash = 1);
|
409 |
+
}
|
410 |
+
|
411 |
+
/*
|
412 |
*
|
413 |
* Process params sent by the user
|
414 |
*
|
415 |
*/
|
416 |
+
private function process_params($params)
|
417 |
+
{
|
418 |
+
if($params->processed) {
|
419 |
+
$this->form_params = json_decode(json_encode((array)$params), true);
|
420 |
+
return;
|
421 |
+
}
|
422 |
+
if (isset($params->hash)) {
|
423 |
+
$this->xcloner_settings->set_hash($params->hash);
|
424 |
+
}
|
425 |
+
|
426 |
+
$this->form_params['extra'] = array();
|
427 |
+
$this->form_params['backup_params'] = array();
|
428 |
+
|
429 |
+
$this->form_params['database'] = array();
|
430 |
+
|
431 |
+
if (isset($params->backup_params)) {
|
432 |
+
foreach ($params->backup_params as $param) {
|
433 |
+
$this->form_params['backup_params'][$param->name] = $this->xcloner_sanitization->sanitize_input_as_string($param->value);
|
434 |
+
$this->logger->debug("Adding form parameter ".$param->name.".".$param->value."\n", array(
|
435 |
+
'POST',
|
436 |
+
'fields filter'
|
437 |
+
));
|
438 |
+
}
|
439 |
+
}
|
440 |
+
|
441 |
+
$this->form_params['database'] = array();
|
442 |
+
|
443 |
+
if (isset($params->table_params)) {
|
444 |
+
foreach ($params->table_params as $param) {
|
445 |
+
$this->form_params['database'][$param->parent][] = $this->xcloner_sanitization->sanitize_input_as_raw($param->id);
|
446 |
+
$this->logger->debug("Adding database filter ".$param->parent.".".$param->id."\n", array(
|
447 |
+
'POST',
|
448 |
+
'database filter'
|
449 |
+
));
|
450 |
+
}
|
451 |
+
}
|
452 |
+
|
453 |
+
$this->form_params['excluded_files'] = array();
|
454 |
+
if (isset($params->files_params)) {
|
455 |
+
foreach ($params->files_params as $param) {
|
456 |
+
$this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
|
457 |
+
}
|
458 |
+
|
459 |
+
$unique_exclude_files = array();
|
460 |
+
|
461 |
+
foreach ($params->files_params as $key => $param) {
|
462 |
+
if (!in_array($param->parent, $this->form_params['excluded_files'])) {
|
463 |
+
//$this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
|
464 |
+
$unique_exclude_files[] = $param->id;
|
465 |
+
$this->logger->debug("Adding file filter ".$param->id."\n", array(
|
466 |
+
'POST',
|
467 |
+
'exclude files filter'
|
468 |
+
));
|
469 |
+
}
|
470 |
+
}
|
471 |
+
$this->form_params['excluded_files'] = (array)$unique_exclude_files;
|
472 |
+
}
|
473 |
+
|
474 |
+
//$this->form_params['excluded_files'] = array_merge($this->form_params['excluded_files'], $this->exclude_files_by_default);
|
475 |
+
|
476 |
+
if (isset($params->extra)) {
|
477 |
+
foreach ($params->extra as $key => $value) {
|
478 |
+
$this->form_params['extra'][$key] = $this->xcloner_sanitization->sanitize_input_as_raw($value);
|
479 |
+
}
|
480 |
+
}
|
481 |
+
|
482 |
+
if (isset($this->form_params['backup_params']['diff_start_date']) and $this->form_params['backup_params']['diff_start_date']) {
|
483 |
+
$this->form_params['backup_params']['diff_start_date'] = strtotime($this->form_params['backup_params']['diff_start_date']);
|
484 |
+
$this->xcloner_file_system->set_diff_timestamp_start($this->form_params['backup_params']['diff_start_date']);
|
485 |
+
}
|
486 |
+
|
487 |
+
return $this->xcloner_settings->get_hash();
|
488 |
+
}
|
489 |
+
|
490 |
+
/*
|
491 |
*
|
492 |
* Get file list for tree view API
|
493 |
*
|
494 |
*/
|
495 |
+
public function get_file_system_action()
|
496 |
+
{
|
497 |
+
$this->check_access();
|
498 |
+
|
499 |
+
$folder = $this->xcloner_sanitization->sanitize_input_as_relative_path($_POST['id']);
|
500 |
+
|
501 |
+
$data = array();
|
502 |
+
|
503 |
+
if ($folder == "#") {
|
504 |
+
$folder = "/";
|
505 |
+
$data[] = array(
|
506 |
+
'id' => $folder,
|
507 |
+
'parent' => '#',
|
508 |
+
'text' => $this->xcloner_settings->get_xcloner_start_path(),
|
509 |
+
//'children' => true,
|
510 |
+
'state' => array('selected' => false, 'opened' => true),
|
511 |
+
'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-root.png"
|
512 |
+
);
|
513 |
+
}
|
514 |
+
|
515 |
+
try {
|
516 |
+
$files = $this->xcloner_file_system->list_directory($folder);
|
517 |
+
} catch (Exception $e) {
|
518 |
+
print $e->getMessage();
|
519 |
+
$this->logger->error($e->getMessage());
|
520 |
+
|
521 |
+
return;
|
522 |
+
}
|
523 |
+
|
524 |
+
$type = array();
|
525 |
+
foreach ($files as $key => $row) {
|
526 |
+
$type[$key] = $row['type'];
|
527 |
+
}
|
528 |
+
array_multisort($type, SORT_ASC, $files);
|
529 |
+
|
530 |
+
foreach ($files as $file) {
|
531 |
+
$children = false;
|
532 |
+
$text = $file['basename'];
|
533 |
+
|
534 |
+
if ($file['type'] == "dir") {
|
535 |
+
$children = true;
|
536 |
+
} else {
|
537 |
+
$text .= " (".$this->xcloner_requirements->file_format_size($file['size']).")";
|
538 |
+
}
|
539 |
+
|
540 |
+
if ($this->xcloner_file_system->is_excluded($file)) {
|
541 |
+
$selected = true;
|
542 |
+
} else {
|
543 |
+
$selected = false;
|
544 |
+
}
|
545 |
+
|
546 |
+
$data[] = array(
|
547 |
+
'id' => $file['path'],
|
548 |
+
'parent' => $folder,
|
549 |
+
'text' => $text,
|
550 |
+
//'title' => "test",
|
551 |
+
'children' => $children,
|
552 |
+
'state' => array('selected' => $selected, 'opened' => false, "checkbox_disabled" => $selected),
|
553 |
+
'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-".strtolower(substr(
|
554 |
+
$file['type'],
|
555 |
+
0,
|
556 |
+
1
|
557 |
+
)).".png"
|
558 |
+
);
|
559 |
+
}
|
560 |
+
|
561 |
+
|
562 |
+
return $this->send_response($data, 0);
|
563 |
+
}
|
564 |
+
|
565 |
+
/*
|
566 |
*
|
567 |
* Get databases/tables list for frontend tree display API
|
568 |
*
|
569 |
*/
|
570 |
+
public function get_database_tables_action()
|
571 |
+
{
|
572 |
+
$this->check_access();
|
573 |
+
|
574 |
+
$database = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['id']);
|
575 |
+
|
576 |
+
$data = array();
|
577 |
+
|
578 |
+
$xcloner_backup_only_wp_tables = $this->xcloner_settings->get_xcloner_option('xcloner_backup_only_wp_tables');
|
579 |
+
|
580 |
+
if ($database == "#") {
|
581 |
+
try {
|
582 |
+
$return = $this->xcloner_database->get_all_databases();
|
583 |
+
} catch (Exception $e) {
|
584 |
+
$this->logger->error($e->getMessage());
|
585 |
+
}
|
586 |
+
|
587 |
+
foreach ($return as $database) {
|
588 |
+
if ($xcloner_backup_only_wp_tables and $database['name'] != $this->xcloner_settings->get_db_database()) {
|
589 |
+
continue;
|
590 |
+
}
|
591 |
+
|
592 |
+
$state = array();
|
593 |
+
|
594 |
+
if ($database['name'] == $this->xcloner_settings->get_db_database()) {
|
595 |
+
$state['selected'] = true;
|
596 |
+
if ($database['num_tables'] < 25) {
|
597 |
+
$state['opened'] = false;
|
598 |
+
}
|
599 |
+
}
|
600 |
+
|
601 |
+
$data[] = array(
|
602 |
+
'id' => $database['name'],
|
603 |
+
'parent' => '#',
|
604 |
+
'text' => $database['name']." (".(int)$database['num_tables'].")",
|
605 |
+
'children' => true,
|
606 |
+
'state' => $state,
|
607 |
+
'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/database-icon.png"
|
608 |
+
);
|
609 |
+
}
|
610 |
+
} else {
|
611 |
+
try {
|
612 |
+
$return = $this->xcloner_database->list_tables($database, "", 1);
|
613 |
+
} catch (Exception $e) {
|
614 |
+
$this->logger->error($e->getMessage());
|
615 |
+
}
|
616 |
+
|
617 |
+
foreach ($return as $table) {
|
618 |
+
$state = array();
|
619 |
+
|
620 |
+
if ($xcloner_backup_only_wp_tables and !stristr(
|
621 |
+
$table['name'],
|
622 |
+
$this->xcloner_settings->get_table_prefix()
|
623 |
+
)) {
|
624 |
+
continue;
|
625 |
+
}
|
626 |
+
|
627 |
+
if (isset($database['name']) and $database['name'] == $this->xcloner_settings->get_db_database()) {
|
628 |
+
$state = array('selected' => true);
|
629 |
+
}
|
630 |
+
|
631 |
+
$data[] = array(
|
632 |
+
'id' => $database.".".$table['name'],
|
633 |
+
'parent' => $database,
|
634 |
+
'text' => $table['name']." (".(int)$table['records'].")",
|
635 |
+
'children' => false,
|
636 |
+
'state' => $state,
|
637 |
+
'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/table-icon.png"
|
638 |
+
);
|
639 |
+
}
|
640 |
+
}
|
641 |
+
|
642 |
+
return $this->send_response($data, 0);
|
643 |
+
}
|
644 |
+
|
645 |
+
/*
|
646 |
*
|
647 |
* Get schedule by id API
|
648 |
*
|
649 |
*/
|
650 |
+
public function get_schedule_by_id()
|
651 |
+
{
|
652 |
+
$this->check_access();
|
653 |
+
|
654 |
+
$schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
|
655 |
+
$scheduler = $this->xcloner_scheduler;
|
656 |
+
$data = $scheduler->get_schedule_by_id($schedule_id);
|
657 |
+
|
658 |
+
$data['start_at'] = date(
|
659 |
+
"Y-m-d H:i",
|
660 |
+
strtotime($data['start_at']) + ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS)
|
661 |
+
);
|
662 |
+
if (isset($data['backup_params']->diff_start_date) && $data['backup_params']->diff_start_date != "") {
|
663 |
+
$data['backup_params']->diff_start_date = date("Y-m-d", ($data['backup_params']->diff_start_date));
|
664 |
+
}
|
665 |
+
|
666 |
+
return $this->send_response($data);
|
667 |
+
}
|
668 |
+
|
669 |
+
/*
|
670 |
*
|
671 |
* Get Schedule list API
|
672 |
*
|
673 |
*/
|
674 |
+
public function get_scheduler_list()
|
675 |
+
{
|
676 |
+
$return = array();
|
677 |
|
678 |
+
$this->check_access();
|
679 |
|
680 |
+
$scheduler = $this->xcloner_scheduler;
|
681 |
+
$data = $scheduler->get_scheduler_list();
|
682 |
+
$return['data'] = array();
|
683 |
|
684 |
+
foreach ($data as $res) {
|
685 |
+
$action = "<a href=\"#".$res->id."\" class=\"edit\" title='Edit'> <i class=\"material-icons \">edit</i></a>
|
686 |
<a href=\"#" . $res->id."\" class=\"delete\" title='Delete'><i class=\"material-icons \">delete</i></a>";
|
687 |
+
if ($res->status) {
|
688 |
+
$status = '<i class="material-icons active status">timer</i>';
|
689 |
+
} else {
|
690 |
+
$status = '<i class="material-icons status inactive">timer_off</i>';
|
691 |
+
}
|
692 |
+
|
693 |
+
$next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id));
|
694 |
+
|
695 |
+
$next_run = date($this->xcloner_settings->get_xcloner_option('date_format')." ".$this->xcloner_settings->get_xcloner_option('time_format'), $next_run_time);
|
696 |
+
|
697 |
+
$remote_storage = $res->remote_storage;
|
698 |
+
|
699 |
+
if (!$next_run_time >= time()) {
|
700 |
+
$next_run = " ";
|
701 |
+
}
|
702 |
+
|
703 |
+
if (trim($next_run)) {
|
704 |
+
$date_text = date(
|
705 |
+
$this->xcloner_settings->get_xcloner_option('date_format')." ".$this->xcloner_settings->get_xcloner_option('time_format'),
|
706 |
+
$next_run_time + ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS)
|
707 |
+
);
|
708 |
+
|
709 |
+
if ($next_run_time >= time()) {
|
710 |
+
$next_run = "in ".human_time_diff($next_run_time, time());
|
711 |
+
} else {
|
712 |
+
$next_run = __("executed", 'xcloner-backup-and-restore');
|
713 |
+
}
|
714 |
+
|
715 |
+
$next_run = "<a href='#' title='".$date_text."'>".$next_run."</a>";
|
716 |
+
//$next_run .=" ($date_text)";
|
717 |
+
}
|
718 |
+
|
719 |
+
$backup_text = "";
|
720 |
+
$backup_size = "";
|
721 |
+
$backup_time = "";
|
722 |
+
|
723 |
+
if ($res->last_backup) {
|
724 |
+
if ($this->xcloner_file_system->get_storage_filesystem()->has($res->last_backup)) {
|
725 |
+
$metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($res->last_backup);
|
726 |
+
$backup_size = size_format($this->xcloner_file_system->get_backup_size($res->last_backup));
|
727 |
+
$backup_time = date(
|
728 |
+
$this->xcloner_settings->get_xcloner_option('date_format')." ".$this->xcloner_settings->get_xcloner_option('time_format'),
|
729 |
+
$metadata['timestamp'] + ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS)
|
730 |
+
);
|
731 |
+
}
|
732 |
+
|
733 |
+
$backup_text = "<span title='".$backup_time."' class='shorten_string'>".$res->last_backup." (".$backup_size.")</span>";
|
734 |
+
}
|
735 |
+
|
736 |
+
$schedules = wp_get_schedules();
|
737 |
+
|
738 |
+
if (isset($schedules[$res->recurrence])) {
|
739 |
+
$res->recurrence = $schedules[$res->recurrence]['display'];
|
740 |
+
}
|
741 |
+
|
742 |
+
$return['data'][] = array(
|
743 |
+
$res->id,
|
744 |
+
$res->name,
|
745 |
+
$res->recurrence, /*$res->start_at,*/
|
746 |
+
$next_run,
|
747 |
+
$remote_storage,
|
748 |
+
$backup_text,
|
749 |
+
$status,
|
750 |
+
$action
|
751 |
+
);
|
752 |
+
}
|
753 |
+
|
754 |
+
return $this->send_response($return, 0);
|
755 |
+
}
|
756 |
+
|
757 |
+
/*
|
758 |
*
|
759 |
* Delete Schedule by ID API
|
760 |
*
|
761 |
*/
|
762 |
+
public function delete_schedule_by_id()
|
763 |
+
{
|
764 |
+
$data = array();
|
765 |
|
766 |
+
$this->check_access();
|
767 |
|
768 |
+
$schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
|
769 |
+
$scheduler = $this->xcloner_scheduler;
|
770 |
+
$data['finished'] = $scheduler->delete_schedule_by_id($schedule_id);
|
771 |
|
772 |
+
return $this->send_response($data);
|
773 |
+
}
|
774 |
|
775 |
+
/*
|
776 |
*
|
777 |
* Delete backup by name from the storage path
|
778 |
*
|
779 |
*/
|
780 |
+
public function delete_backup_by_name()
|
781 |
+
{
|
782 |
+
$data = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
783 |
|
784 |
+
$this->check_access();
|
|
|
|
|
|
|
|
|
|
|
785 |
|
786 |
+
$backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_POST['name']);
|
787 |
+
$storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_selection']);
|
788 |
|
789 |
+
$data['finished'] = $this->xcloner_file_system->delete_backup_by_name($backup_name, $storage_selection);
|
|
|
|
|
|
|
|
|
790 |
|
791 |
+
return $this->send_response($data);
|
792 |
+
}
|
793 |
|
794 |
+
/**
|
795 |
+
* API Incremental Backup Encryption Method
|
796 |
+
*/
|
797 |
+
public function backup_encryption()
|
798 |
+
{
|
799 |
+
$this->check_access();
|
800 |
+
|
801 |
+
$backup_parts = array();
|
802 |
+
$return = array();
|
803 |
+
|
804 |
+
|
805 |
+
if (isset($_POST['data'])) {
|
806 |
+
$params = json_decode(stripslashes($_POST['data']));
|
807 |
+
|
808 |
+
$this->process_params($params);
|
809 |
+
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($this->form_params['extra']['backup_parent']);
|
810 |
+
|
811 |
+
if (isset($this->form_params['extra']['start'])) {
|
812 |
+
$start = $this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['start']);
|
813 |
+
} else {
|
814 |
+
$start = 0;
|
815 |
+
}
|
816 |
+
|
817 |
+
if (isset($this->form_params['extra']['iv'])) {
|
818 |
+
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($this->form_params['extra']['iv']);
|
819 |
+
} else {
|
820 |
+
$iv = "";
|
821 |
+
}
|
822 |
+
|
823 |
+
if (isset($this->form_params['extra']['part'])) {
|
824 |
+
$return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['part']);
|
825 |
+
} else {
|
826 |
+
$return['part'] = 0;
|
827 |
+
}
|
828 |
+
} else {
|
829 |
+
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
830 |
+
$start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
|
831 |
+
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
|
832 |
+
$return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
833 |
+
}
|
834 |
+
|
835 |
+
$backup_file = $source_backup_file;
|
836 |
+
|
837 |
+
if ($this->xcloner_file_system->is_multipart($backup_file)) {
|
838 |
+
$backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
|
839 |
+
$backup_file = $backup_parts[$return['part']];
|
840 |
+
}
|
841 |
+
|
842 |
+
$return['processing_file'] = $backup_file;
|
843 |
+
$return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
|
844 |
+
|
845 |
+
try {
|
846 |
+
$this->logger->info(json_encode($_POST));
|
847 |
+
$this->logger->info($iv);
|
848 |
+
$return = array_merge(
|
849 |
+
$return,
|
850 |
+
$this->xcloner_encryption->encrypt_file($backup_file, "", "", $start, base64_decode($iv))
|
851 |
+
);
|
852 |
+
} catch (\Exception $e) {
|
853 |
+
$return['error'] = true;
|
854 |
+
$return['message'] = $e->getMessage();
|
855 |
+
$return['error_message'] = $e->getMessage();
|
856 |
+
}
|
857 |
+
|
858 |
+
//echo strlen($return['iv']);exit;
|
859 |
+
|
860 |
+
if (isset($return['finished']) && $return['finished']) {
|
861 |
+
if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
|
862 |
+
$return['start'] = 0;
|
863 |
+
|
864 |
+
++$return['part'];
|
865 |
+
|
866 |
+
if ($return['part'] < sizeof($backup_parts)) {
|
867 |
+
$return['finished'] = 0;
|
868 |
+
}
|
869 |
+
}
|
870 |
+
}
|
871 |
+
|
872 |
+
if (isset($_POST['data'])) {
|
873 |
+
$return['extra'] = array_merge($this->form_params['extra'], $return);
|
874 |
+
}
|
875 |
+
|
876 |
+
$this->send_response($return, 0);
|
877 |
+
}
|
878 |
+
|
879 |
+
/**
|
880 |
+
* API Incremental Backup Decryption Method
|
881 |
+
*/
|
882 |
+
public function backup_decryption()
|
883 |
+
{
|
884 |
+
$this->check_access();
|
885 |
+
|
886 |
+
$backup_parts = array();
|
887 |
+
$return = array();
|
888 |
+
|
889 |
+
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
890 |
+
$start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
|
891 |
+
$iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
|
892 |
+
$decryption_key = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['decryption_key']);
|
893 |
+
;
|
894 |
+
$return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
895 |
+
|
896 |
+
$backup_file = $source_backup_file;
|
897 |
+
|
898 |
+
if ($this->xcloner_file_system->is_multipart($backup_file)) {
|
899 |
+
$backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
|
900 |
+
$backup_file = $backup_parts[$return['part']];
|
901 |
+
}
|
902 |
+
|
903 |
+
$return['processing_file'] = $backup_file;
|
904 |
+
$return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
|
905 |
+
|
906 |
+
try {
|
907 |
+
$return = array_merge(
|
908 |
+
$return,
|
909 |
+
$this->xcloner_encryption->decrypt_file($backup_file, "", $decryption_key, $start, base64_decode($iv))
|
910 |
+
);
|
911 |
+
} catch (\Exception $e) {
|
912 |
+
$return['error'] = true;
|
913 |
+
$return['message'] = $e->getMessage();
|
914 |
+
}
|
915 |
+
|
916 |
+
if ($return['finished']) {
|
917 |
+
if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
|
918 |
+
$return['start'] = 0;
|
919 |
+
|
920 |
+
++$return['part'];
|
921 |
+
|
922 |
+
if ($return['part'] < sizeof($backup_parts)) {
|
923 |
+
$return['finished'] = 0;
|
924 |
+
}
|
925 |
+
}
|
926 |
+
}
|
927 |
+
|
928 |
+
$this->send_response($return, 0);
|
929 |
+
}
|
930 |
+
|
931 |
+
public function get_manage_backups_list()
|
932 |
+
{
|
933 |
+
$this->check_access();
|
934 |
+
|
935 |
+
$return = array();
|
936 |
+
$storage_selection = "";
|
937 |
+
|
938 |
+
if (isset($_GET['storage_selection']) and $_GET['storage_selection']) {
|
939 |
+
$storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_GET['storage_selection']);
|
940 |
+
}
|
941 |
+
$available_storages = $this->xcloner_remote_storage->get_available_storages();
|
942 |
+
|
943 |
+
$backup_list = $this->xcloner_file_system->get_backup_archives_list($storage_selection);
|
944 |
+
|
945 |
+
$i = -1;
|
946 |
+
foreach ($backup_list as $file_info):?>
|
947 |
<?php
|
948 |
+
if ($storage_selection == "gdrive") {
|
949 |
+
$file_info['path'] = $file_info['filename'].".".$file_info['extension'];
|
950 |
+
}
|
951 |
+
$file_exists_on_local_storage = true;
|
952 |
+
|
953 |
+
if ($storage_selection) {
|
954 |
+
if (!$this->xcloner_file_system->get_storage_filesystem()->has($file_info['path'])) {
|
955 |
+
$file_exists_on_local_storage = false;
|
956 |
+
}
|
957 |
+
} ?>
|
|
|
|
|
958 |
<?php if (!isset($file_info['parent'])): ?>
|
959 |
|
960 |
<?php ob_start(); ?>
|
964 |
<label for="checkbox_<?php echo $i ?>"> </label>
|
965 |
</p>
|
966 |
<?php
|
967 |
+
$return['data'][$i][] = ob_get_contents();
|
968 |
+
ob_end_clean(); ?>
|
|
|
969 |
|
970 |
<?php ob_start(); ?>
|
971 |
<span class=""><?php echo $file_info['path'] ?></span>
|
972 |
<?php if (!$file_exists_on_local_storage): ?>
|
973 |
<a href="#"
|
974 |
+
title="<?php echo __(
|
975 |
+
"File does not exists on local storage",
|
976 |
+
"xcloner-backup-and-restore"
|
977 |
+
) ?>"><i
|
978 |
class="material-icons backup_warning">warning</i></a>
|
979 |
<?php endif ?>
|
980 |
<?php
|
981 |
+
if (isset($file_info['childs']) and is_array($file_info['childs'])):
|
982 |
+
?>
|
983 |
<a href="#" title="expand" class="expand-multipart add"><i
|
984 |
class="material-icons">add</i></a>
|
985 |
<a href="#" title="collapse" class="expand-multipart remove"><i class="material-icons">remove</i></a>
|
988 |
<li>
|
989 |
<?php echo $child[0] ?> (<?php echo esc_html(size_format($child[2])) ?>)
|
990 |
<?php
|
991 |
+
$child_exists_on_local_storage = true;
|
992 |
+
if ($storage_selection) {
|
993 |
+
if (!$this->xcloner_file_system->get_storage_filesystem()->has($child[0])) {
|
994 |
+
$child_exists_on_local_storage = false;
|
995 |
+
}
|
996 |
+
} ?>
|
|
|
997 |
<?php if (!$child_exists_on_local_storage): ?>
|
998 |
<a href="#"
|
999 |
+
title="<?php echo __(
|
1000 |
+
"File does not exists on local storage",
|
1001 |
+
"xcloner-backup-and-restore"
|
1002 |
+
) ?>"><i
|
1003 |
class="material-icons backup_warning">warning</i></a>
|
1004 |
<?php endif ?>
|
1005 |
<?php if (!$storage_selection) : ?>
|
1013 |
</a>
|
1014 |
<?php else: ?>
|
1015 |
<a href="#<?php echo $child[0] ?>" class="list-backup-content"
|
1016 |
+
title="<?php echo __(
|
1017 |
+
'List Backup Content',
|
1018 |
+
'xcloner-backup-and-restore'
|
1019 |
+
) ?>"><i
|
1020 |
class="material-icons">folder_open</i></a>
|
1021 |
|
1022 |
<a href="#<?php echo $child[0] ?>" class="backup-encryption"
|
1027 |
|
1028 |
<?php elseif ($storage_selection != "gdrive" && !$this->xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
|
1029 |
<a href="#<?php echo $child[0] ?>" class="copy-remote-to-local"
|
1030 |
+
title="<?php echo __(
|
1031 |
+
'Push Backup To Local Storage',
|
1032 |
+
'xcloner-backup-and-restore'
|
1033 |
+
) ?>"><i
|
1034 |
class="material-icons">file_upload</i></a>
|
1035 |
<?php endif ?>
|
1036 |
</li>
|
1038 |
</ul>
|
1039 |
<?php endif; ?>
|
1040 |
<?php
|
1041 |
+
$return['data'][$i][] = ob_get_contents();
|
1042 |
+
ob_end_clean(); ?>
|
|
|
1043 |
<?php ob_start(); ?>
|
1044 |
+
<?php if (isset($file_info['timestamp'])) {
|
1045 |
+
echo date("Y-m-d H:i", $file_info['timestamp']);
|
1046 |
+
} ?>
|
1047 |
<?php
|
1048 |
+
$return['data'][$i][] = ob_get_contents();
|
1049 |
+
ob_end_clean(); ?>
|
|
|
1050 |
|
1051 |
<?php ob_start(); ?>
|
1052 |
<?php echo esc_html(size_format($file_info['size'])) ?>
|
1053 |
<?php
|
1054 |
+
$return['data'][$i][] = ob_get_contents();
|
1055 |
+
ob_end_clean(); ?>
|
|
|
1056 |
|
1057 |
<?php ob_start(); ?>
|
1058 |
<?php if (!$storage_selection): ?>
|
1062 |
|
1063 |
<?php if (sizeof($available_storages)): ?>
|
1064 |
<a href="#<?php echo $file_info['basename'] ?>" class="cloud-upload"
|
1065 |
+
title="<?php echo __(
|
1066 |
+
'Send Backup To Remote Storage',
|
1067 |
+
'xcloner-backup-and-restore'
|
1068 |
+
) ?>"><i
|
1069 |
class="material-icons">cloud_upload</i></a>
|
1070 |
<?php endif ?>
|
1071 |
<?php
|
1072 |
+
$basename = $file_info['basename'];
|
1073 |
+
if (isset($file_info['childs']) and sizeof($file_info['childs'])) {
|
1074 |
+
$basename = $file_info['childs'][0][0];
|
1075 |
+
} ?>
|
1076 |
<?php if ($this->xcloner_encryption->is_encrypted_file($basename)) :?>
|
1077 |
<a href="#<?php echo $file_info['basename'] ?>" class="backup-decryption"
|
1078 |
title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
|
1101 |
<?php endif ?>
|
1102 |
|
1103 |
<?php
|
1104 |
+
$return['data'][$i][] = ob_get_contents();
|
1105 |
+
ob_end_clean(); ?>
|
1106 |
|
1107 |
<?php endif ?>
|
1108 |
<?php endforeach ?>
|
1109 |
<?php
|
1110 |
+
$this->send_response($return, 0);
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
/**
|
1114 |
+
* API method to list internal backup files
|
1115 |
+
*/
|
1116 |
+
public function list_backup_files()
|
1117 |
+
{
|
1118 |
+
$this->check_access();
|
1119 |
+
|
1120 |
+
$backup_parts = array();
|
1121 |
+
$return = array();
|
1122 |
+
|
1123 |
+
$source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
1124 |
+
|
1125 |
+
$start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
|
1126 |
+
$return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
1127 |
+
|
1128 |
+
$backup_file = $source_backup_file;
|
1129 |
+
|
1130 |
+
if ($this->xcloner_file_system->is_multipart($backup_file)) {
|
1131 |
+
$backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
|
1132 |
+
$backup_file = $backup_parts[$return['part']];
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
if ($this->xcloner_encryption->is_encrypted_file($backup_file)) {
|
1136 |
+
$return['error'] = true;
|
1137 |
+
$return['message'] = __("Backup archive is encrypted, please decrypt it first before you can list it's content.", "xcloner-backup-and-restore");
|
1138 |
+
$this->send_response($return, 0);
|
1139 |
+
}
|
1140 |
+
|
1141 |
+
try {
|
1142 |
+
$tar = $this->archive_system;
|
1143 |
+
$tar->open($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file, $start);
|
1144 |
+
|
1145 |
+
$data = $tar->contents($this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request'));
|
1146 |
+
} catch (Exception $e) {
|
1147 |
+
$return['error'] = true;
|
1148 |
+
$return['message'] = $e->getMessage();
|
1149 |
+
$this->send_response($return, 0);
|
1150 |
+
}
|
1151 |
+
|
1152 |
+
$return['files'] = array();
|
1153 |
+
$return['finished'] = 1;
|
1154 |
+
$return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
|
1155 |
+
$i = 0;
|
1156 |
+
|
1157 |
+
if (isset($data['extracted_files']) and is_array($data['extracted_files'])) {
|
1158 |
+
foreach ($data['extracted_files'] as $file) {
|
1159 |
+
$return['files'][$i]['path'] = $file->getPath();
|
1160 |
+
$return['files'][$i]['size'] = $file->getSize();
|
1161 |
+
$return['files'][$i]['mtime'] = date(
|
1162 |
+
$this->xcloner_settings->get_xcloner_option('date_format')." ".$this->xcloner_settings->get_xcloner_option('time_format'),
|
1163 |
+
$file->getMtime()
|
1164 |
+
);
|
1165 |
+
|
1166 |
+
$i++;
|
1167 |
+
}
|
1168 |
+
}
|
1169 |
+
|
1170 |
+
if (isset($data['start'])) {
|
1171 |
+
$return['start'] = $data['start'];
|
1172 |
+
$return['finished'] = 0;
|
1173 |
+
} else {
|
1174 |
+
if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
|
1175 |
+
$return['start'] = 0;
|
1176 |
+
|
1177 |
+
++$return['part'];
|
1178 |
+
|
1179 |
+
if ($return['part'] < sizeof($backup_parts)) {
|
1180 |
+
$return['finished'] = 0;
|
1181 |
+
}
|
1182 |
+
}
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
$this->send_response($return, 0);
|
1186 |
+
}
|
1187 |
+
|
1188 |
+
/*
|
1189 |
* Copy remote backup to local storage
|
1190 |
*/
|
1191 |
+
public function copy_backup_remote_to_local()
|
1192 |
+
{
|
1193 |
+
$this->check_access();
|
|
|
|
|
|
|
|
|
|
|
|
|
1194 |
|
1195 |
+
$backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
1196 |
+
$storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
|
1197 |
|
1198 |
+
$xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1199 |
|
1200 |
+
$return = array();
|
|
|
|
|
1201 |
|
1202 |
+
try {
|
1203 |
+
if (method_exists($xcloner_remote_storage, "copy_backup_remote_to_local")) {
|
1204 |
+
$return = call_user_func_array(array(
|
1205 |
+
$xcloner_remote_storage,
|
1206 |
+
"copy_backup_remote_to_local"
|
1207 |
+
), array($backup_file, $storage_type));
|
1208 |
+
}
|
1209 |
+
} catch (Exception $e) {
|
1210 |
+
$return['error'] = 1;
|
1211 |
+
$return['message'] = $e->getMessage();
|
1212 |
+
}
|
1213 |
|
1214 |
+
if (!$return) {
|
1215 |
+
$return['error'] = 1;
|
1216 |
+
$return['message'] = "Upload failed, please check the error log for more information!";
|
1217 |
+
}
|
1218 |
|
|
|
1219 |
|
1220 |
+
$this->send_response($return, 0);
|
1221 |
+
}
|
1222 |
|
1223 |
+
/*
|
1224 |
*
|
1225 |
* Upload backup to remote API
|
1226 |
*
|
1227 |
*/
|
1228 |
+
public function upload_backup_to_remote()
|
1229 |
+
{
|
1230 |
+
$this->check_access();
|
1231 |
|
1232 |
+
$return = array();
|
1233 |
|
1234 |
+
$backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
1235 |
+
$storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
|
1236 |
|
1237 |
+
$xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
1238 |
|
1239 |
+
try {
|
1240 |
+
if (method_exists($xcloner_remote_storage, "upload_backup_to_storage")) {
|
1241 |
+
$return = call_user_func_array(array(
|
1242 |
+
$xcloner_remote_storage,
|
1243 |
+
"upload_backup_to_storage"
|
1244 |
+
), array($backup_file, $storage_type));
|
1245 |
+
}
|
1246 |
+
} catch (Exception $e) {
|
1247 |
+
$return['error'] = 1;
|
1248 |
+
$return['message'] = $e->getMessage();
|
1249 |
+
}
|
1250 |
|
1251 |
+
if (!$return) {
|
1252 |
+
$return['error'] = 1;
|
1253 |
+
$return['message'] = "Upload failed, please check the error log for more information!";
|
1254 |
+
}
|
1255 |
|
|
|
|
|
|
|
|
|
1256 |
|
1257 |
+
$this->send_response($return, 0);
|
1258 |
+
}
|
1259 |
|
1260 |
+
/*
|
|
|
|
|
|
|
|
|
1261 |
*
|
1262 |
* Remote Storage Status Save
|
1263 |
*
|
1264 |
*/
|
1265 |
+
public function remote_storage_save_status()
|
1266 |
+
{
|
1267 |
+
$this->check_access();
|
1268 |
|
1269 |
+
$return = array();
|
1270 |
|
1271 |
+
$xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
1272 |
|
1273 |
+
$return['finished'] = $xcloner_remote_storage->change_storage_status($_POST['id'], $_POST['value']);
|
1274 |
|
1275 |
+
$this->send_response($return, 0);
|
1276 |
+
}
|
1277 |
|
1278 |
|
1279 |
+
public function download_restore_script()
|
1280 |
+
{
|
1281 |
+
$this->check_access();
|
1282 |
|
1283 |
+
ob_end_clean();
|
1284 |
|
1285 |
+
$adapter = new Local(dirname(__DIR__), LOCK_EX, '0001');
|
1286 |
+
$xcloner_plugin_filesystem = new Filesystem($adapter, new Config([
|
1287 |
+
'disable_asserts' => true,
|
1288 |
+
]));
|
1289 |
|
1290 |
+
/* Generate PHAR FILE
|
1291 |
$file = 'restore/vendor.built';
|
1292 |
|
1293 |
if(file_exists($file))
|
1303 |
$phar2->setStub($phar2->createDefaultStub('vendor/autoload.php', 'vendor/autoload.php'));
|
1304 |
* */
|
1305 |
|
1306 |
+
$tmp_file = $this->xcloner_settings->get_xcloner_tmp_path().DS."xcloner-restore.tgz";
|
1307 |
|
1308 |
+
$tar = $this->archive_system;
|
1309 |
+
$tar->create($tmp_file);
|
1310 |
|
1311 |
+
$tar->addFile(dirname(__DIR__)."/restore/vendor.build.txt", "vendor.phar");
|
1312 |
+
//$tar->addFile(dirname(__DIR__)."/restore/vendor.tgz", "vendor.tgz");
|
1313 |
|
1314 |
+
$files = $xcloner_plugin_filesystem->listContents("vendor/", true);
|
1315 |
+
foreach ($files as $file) {
|
1316 |
+
$tar->addFile(dirname(__DIR__).DS.$file['path'], $file['path']);
|
1317 |
+
}
|
1318 |
|
1319 |
+
$content = file_get_contents(dirname(__DIR__)."/restore/xcloner_restore.php");
|
1320 |
+
$content = str_replace("define('AUTH_KEY', '');", "define('AUTH_KEY', '".md5(AUTH_KEY)."');", $content);
|
1321 |
|
1322 |
+
$tar->addData("xcloner_restore.php", $content);
|
1323 |
|
1324 |
+
$tar->close();
|
1325 |
|
1326 |
+
if (file_exists($tmp_file)) {
|
1327 |
+
header('Content-Description: File Transfer');
|
1328 |
+
header('Content-Type: application/octet-stream');
|
1329 |
+
header('Content-Disposition: attachment; filename="'.basename($tmp_file).'"');
|
1330 |
+
header('Expires: 0');
|
1331 |
+
header('Cache-Control: must-revalidate');
|
1332 |
+
header('Pragma: public');
|
1333 |
+
header('Content-Length: '.filesize($tmp_file));
|
1334 |
+
readfile($tmp_file);
|
1335 |
+
}
|
1336 |
|
1337 |
+
try {
|
1338 |
+
unlink($tmp_file);
|
1339 |
+
} catch (Exception $e) {
|
1340 |
+
//We are not interested in the error here
|
1341 |
+
}
|
1342 |
|
1343 |
+
die();
|
1344 |
+
}
|
|
|
|
|
|
|
1345 |
|
1346 |
+
/*
|
|
|
|
|
|
|
1347 |
*
|
1348 |
* Download backup by Name from the Storage Path
|
1349 |
*
|
1350 |
*/
|
1351 |
+
public function download_backup_by_name()
|
1352 |
+
{
|
1353 |
+
$this->check_access();
|
|
|
|
|
1354 |
|
1355 |
+
ob_end_clean();
|
1356 |
|
1357 |
+
$backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_GET['name']);
|
1358 |
|
|
|
|
|
1359 |
|
1360 |
+
$metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($backup_name);
|
1361 |
+
$read_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($backup_name);
|
1362 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1363 |
|
1364 |
+
header('Pragma: public');
|
1365 |
+
header('Expires: 0');
|
1366 |
+
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
1367 |
+
header('Cache-Control: private', false);
|
1368 |
+
header('Content-Transfer-Encoding: binary');
|
1369 |
+
header('Content-Disposition: attachment; filename="'.$metadata['path'].'";');
|
1370 |
+
header('Content-Type: application/octet-stream');
|
1371 |
+
header('Content-Length: '.$metadata['size']);
|
1372 |
|
1373 |
+
ob_end_clean();
|
|
|
|
|
|
|
|
|
|
|
1374 |
|
1375 |
+
$chunkSize = 1024 * 1024;
|
1376 |
+
while (!feof($read_stream)) {
|
1377 |
+
$buffer = fread($read_stream, $chunkSize);
|
1378 |
+
echo $buffer;
|
1379 |
+
}
|
1380 |
+
fclose($read_stream);
|
1381 |
|
1382 |
+
wp_die();
|
1383 |
+
}
|
1384 |
|
1385 |
+
/*
|
1386 |
* Restore upload backup
|
1387 |
*/
|
1388 |
+
public function restore_upload_backup()
|
1389 |
+
{
|
1390 |
+
$this->check_access();
|
1391 |
|
1392 |
+
$return = array();
|
1393 |
|
1394 |
+
$return['part'] = 0;
|
1395 |
+
$return['total_parts'] = 0;
|
1396 |
+
$return['uploaded_size'] = 0;
|
1397 |
+
$is_multipart = 0;
|
1398 |
|
1399 |
+
$file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
|
1400 |
+
$hash = $this->xcloner_sanitization->sanitize_input_as_string($_POST['hash']);
|
1401 |
|
1402 |
+
if (isset($_POST['part'])) {
|
1403 |
+
$return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
|
1404 |
+
}
|
1405 |
|
1406 |
+
if (isset($_POST['uploaded_size'])) {
|
1407 |
+
$return['uploaded_size'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['uploaded_size']);
|
1408 |
+
}
|
1409 |
|
1410 |
+
$start = $this->xcloner_sanitization->sanitize_input_as_string($_POST['start']);
|
1411 |
+
$target_url = $this->xcloner_sanitization->sanitize_input_as_string($_POST['target_url']);
|
1412 |
|
1413 |
+
$return['total_size'] = $this->xcloner_file_system->get_backup_size($file);
|
1414 |
|
1415 |
+
if ($this->xcloner_file_system->is_multipart($file)) {
|
1416 |
+
$backup_parts = $this->xcloner_file_system->get_multipart_files($file);
|
1417 |
|
1418 |
+
$return['total_parts'] = sizeof($backup_parts) + 1;
|
1419 |
|
1420 |
+
if ($return['part'] and isset($backup_parts[$return['part'] - 1])) {
|
1421 |
+
$file = $backup_parts[$return['part'] - 1];
|
1422 |
+
}
|
1423 |
|
1424 |
+
$is_multipart = 1;
|
1425 |
+
}
|
1426 |
|
1427 |
+
try {
|
1428 |
+
$xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
|
1429 |
+
$xcloner_file_transfer->set_target($target_url);
|
1430 |
+
$return['start'] = $xcloner_file_transfer->transfer_file($file, $start, $hash);
|
1431 |
+
} catch (Exception $e) {
|
1432 |
+
$return = array();
|
1433 |
+
$return['error'] = true;
|
1434 |
+
$return['status'] = 500;
|
1435 |
+
$return['message'] = "CURL communication error with the restore host. ".$e->getMessage();
|
1436 |
+
$this->send_response($return, 0);
|
1437 |
+
}
|
1438 |
|
1439 |
+
$return['status'] = 200;
|
|
|
|
|
1440 |
|
1441 |
+
//we have finished the upload
|
1442 |
+
if (!$return['start'] and $is_multipart) {
|
1443 |
+
$return['part']++;
|
1444 |
+
$return['uploaded_size'] += $this->xcloner_file_system->get_storage_filesystem()->getSize($file);
|
1445 |
+
}
|
1446 |
|
1447 |
+
$this->send_response($return, 0);
|
1448 |
+
}
|
|
|
|
|
|
|
1449 |
|
1450 |
+
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1451 |
* Restore backup
|
1452 |
*/
|
1453 |
+
public function restore_backup()
|
1454 |
+
{
|
1455 |
+
$this->check_access();
|
1456 |
|
1457 |
+
define("XCLONER_PLUGIN_ACCESS", 1);
|
1458 |
+
include_once(dirname(__DIR__).DS."restore".DS."xcloner_restore.php");
|
1459 |
|
1460 |
+
return;
|
1461 |
+
}
|
1462 |
|
1463 |
+
/*
|
1464 |
*
|
1465 |
* Send the json response back
|
1466 |
*
|
1467 |
*/
|
1468 |
+
private function send_response($data, $attach_hash = 1)
|
1469 |
+
{
|
1470 |
+
if ($attach_hash and null !== $this->xcloner_settings->get_hash()) {
|
1471 |
+
$data['hash'] = $this->xcloner_settings->get_hash();
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
if (ob_get_length()) {
|
1475 |
+
//ob_clean();
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
return wp_send_json($data);
|
1479 |
+
}
|
|
|
1480 |
}
|
includes/class-xcloner-archive.php
CHANGED
@@ -36,181 +36,179 @@ use splitbrain\PHPArchive\FileInfo;
|
|
36 |
*/
|
37 |
class Xcloner_Archive extends Tar
|
38 |
{
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
|
66 |
/**
|
67 |
* The backup name encryption suffix
|
68 |
* @var string
|
69 |
*/
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
* Rename backup archive
|
130 |
*
|
131 |
* @param string $old_name
|
132 |
* @param string $new_name
|
133 |
*
|
134 |
*/
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
*
|
144 |
* Set the backup archive name
|
145 |
*
|
146 |
*/
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
$this->archive_name = $this->filesystem->process_backup_name($name);
|
151 |
|
152 |
-
|
153 |
-
|
154 |
}
|
155 |
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
if (!stristr($new_name, "-diff")) {
|
161 |
-
$new_name = $this->archive_name."-diff".date("Y-m-d_H-i", $diff_timestamp_start);
|
162 |
-
}
|
163 |
|
164 |
-
|
|
|
|
|
165 |
|
166 |
-
|
|
|
167 |
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
|
174 |
-
|
175 |
-
|
176 |
|
177 |
-
|
178 |
-
|
179 |
|
180 |
-
|
181 |
*
|
182 |
* Returns the backup archive name
|
183 |
*
|
184 |
* @return string archive name
|
185 |
*/
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
|
191 |
-
|
192 |
*
|
193 |
* Returns the multipart naming for the backup archive
|
194 |
*
|
195 |
* @return string multi-part backup name
|
196 |
*/
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
|
203 |
-
|
204 |
*
|
205 |
* Returns the full backup name including extension
|
206 |
*
|
207 |
*/
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
|
213 |
-
|
214 |
*
|
215 |
* Send notification error by E-Mail
|
216 |
*
|
@@ -224,34 +222,33 @@ class Xcloner_Archive extends Tar
|
|
224 |
* @return bool
|
225 |
*/
|
226 |
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
$body .= "<br /><>";
|
236 |
|
237 |
-
|
238 |
|
239 |
-
|
240 |
|
241 |
-
|
242 |
|
243 |
-
|
244 |
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
|
249 |
-
|
250 |
|
251 |
-
|
252 |
-
|
253 |
|
254 |
-
|
255 |
*
|
256 |
* Send backup archive notfication by E-Mail
|
257 |
*
|
@@ -265,546 +262,562 @@ class Xcloner_Archive extends Tar
|
|
265 |
*
|
266 |
* @return bool
|
267 |
*/
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
|
285 |
-
|
286 |
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
|
291 |
-
|
292 |
-
|
293 |
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
|
299 |
-
|
300 |
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
|
305 |
-
|
306 |
-
|
307 |
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
|
313 |
-
|
314 |
|
315 |
-
|
316 |
-
|
317 |
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
327 |
|
328 |
-
|
329 |
|
330 |
-
|
331 |
|
332 |
-
|
333 |
-
|
334 |
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
|
340 |
-
|
341 |
|
342 |
-
|
343 |
|
344 |
-
|
345 |
|
346 |
-
|
347 |
|
348 |
-
|
349 |
-
|
350 |
|
351 |
-
|
352 |
*
|
353 |
* Incremental Backup method
|
354 |
*
|
355 |
*/
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
|
364 |
-
|
365 |
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
if(isset($backup_params['backup_encrypt']) && $backup_params['backup_encrypt']) {
|
371 |
$encrypt = true;
|
372 |
}
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
if (!$this->get_archive_name()) {
|
377 |
-
$this->set_archive_name();
|
378 |
-
}
|
379 |
-
|
380 |
-
$this->backup_archive = new Tar();
|
381 |
-
$this->backup_archive->setCompression($this->compression_level);
|
382 |
-
|
383 |
-
$archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
|
384 |
-
|
385 |
-
if ($init) {
|
386 |
-
$this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name()));
|
387 |
|
388 |
-
|
|
|
|
|
389 |
|
390 |
-
|
|
|
391 |
|
392 |
-
|
393 |
-
$this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name()));
|
394 |
|
395 |
-
|
|
|
396 |
|
397 |
-
|
398 |
|
399 |
-
|
|
|
|
|
400 |
|
401 |
-
|
402 |
-
$return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension();
|
403 |
|
404 |
-
|
405 |
-
|
406 |
-
}
|
407 |
|
408 |
-
|
409 |
-
|
410 |
-
}
|
411 |
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
|
420 |
-
|
|
|
|
|
|
|
|
|
421 |
|
422 |
-
|
|
|
|
|
423 |
|
424 |
-
|
425 |
|
426 |
-
|
427 |
|
428 |
-
|
429 |
-
if (!$extra_params['start_at_line']) {
|
430 |
-
$file->seek(1);
|
431 |
-
} else {
|
432 |
-
$file->seek($extra_params['start_at_line'] + 1);
|
433 |
-
}
|
434 |
|
435 |
-
|
436 |
|
437 |
-
|
|
|
|
|
|
|
|
|
|
|
438 |
|
439 |
-
|
440 |
|
441 |
-
|
442 |
|
443 |
-
|
444 |
-
$current_line_str = $file->current();
|
445 |
|
446 |
-
|
447 |
|
448 |
-
|
|
|
449 |
|
450 |
-
|
451 |
|
452 |
-
|
453 |
-
$start_filesystem = $line[4];
|
454 |
-
}
|
455 |
|
456 |
-
|
457 |
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
$relative_path));
|
462 |
-
}
|
463 |
-
|
464 |
-
$extra_params['start_at_line']++;
|
465 |
-
$file->next();
|
466 |
-
continue;
|
467 |
-
}
|
468 |
|
469 |
-
|
470 |
|
471 |
-
|
472 |
-
|
473 |
-
|
|
|
|
|
|
|
|
|
474 |
|
475 |
-
|
476 |
-
|
477 |
-
|
|
|
478 |
|
479 |
-
|
480 |
|
481 |
-
|
|
|
|
|
482 |
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
|
487 |
-
|
488 |
-
$return['extra']['backup_size'] = 0;
|
489 |
-
}
|
490 |
|
491 |
-
|
492 |
|
493 |
-
|
|
|
|
|
494 |
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
$this->xcloner_split_backup_limit, $estimated_new_size));
|
499 |
-
list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']);
|
500 |
|
501 |
-
|
502 |
-
$this->logger->info(sprintf("Excluding %s file as it's size(%s) is bigger than the backup split limit of %s and it won't fit a single backup file",
|
503 |
-
$file_info['path'], $file_info['size'], $this->xcloner_split_backup_limit));
|
504 |
-
$extra_params['start_at_line']++;
|
505 |
-
}
|
506 |
|
507 |
-
|
508 |
-
$return['extra']['start_at_byte'] = 0;
|
509 |
|
510 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
511 |
|
512 |
-
|
513 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
|
515 |
-
|
516 |
-
|
517 |
-
$this->processed_size_bytes += $bytes_wrote;
|
518 |
-
|
519 |
-
//echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n";
|
520 |
-
$return['extra']['processed_file'] = $file_info['path'];
|
521 |
-
$return['extra']['processed_file_size'] = $file_info['size'];
|
522 |
-
$return['extra']['backup_size'] = $archive_info->getSize();
|
523 |
-
|
524 |
-
if ($last_position > 0) {
|
525 |
-
$start_byte = $last_position;
|
526 |
-
} else {
|
527 |
-
$extra_params['start_at_line']++;
|
528 |
-
$file->next();
|
529 |
-
$start_byte = 0;
|
530 |
-
$counter++;
|
531 |
-
}
|
532 |
|
533 |
-
|
534 |
-
clearstatcache();
|
535 |
-
$return['extra']['backup_size'] = $archive_info->getSize();
|
536 |
|
537 |
-
|
538 |
-
|
539 |
-
$return['extra']['start_at_byte'] = $last_position;
|
540 |
-
$this->logger->info(sprintf("Reached the maximum %s request data limit, returning response",
|
541 |
-
$this->file_size_per_request_limit));
|
542 |
-
return $return;
|
543 |
-
}
|
544 |
-
}
|
545 |
-
|
546 |
-
if (!$file->eof()) {
|
547 |
-
clearstatcache();
|
548 |
-
$return['extra']['backup_size'] = $archive_info->getSize();
|
549 |
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
555 |
|
556 |
-
|
557 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
558 |
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
$this->backup_archive->close();
|
563 |
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
|
|
570 |
|
571 |
-
|
572 |
-
|
573 |
|
574 |
-
|
575 |
-
|
576 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
577 |
|
578 |
-
|
579 |
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
|
585 |
-
|
586 |
-
|
587 |
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
|
592 |
-
|
593 |
*
|
594 |
* Write multipart file components
|
595 |
*
|
596 |
*/
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
|
607 |
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
|
612 |
-
|
613 |
*
|
614 |
* Create a new backup part
|
615 |
*
|
616 |
*/
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
} else {
|
636 |
-
$this->logger->info(sprintf("Creating new multipart info file %s",
|
637 |
-
$this->get_archive_name_with_extension()));
|
638 |
-
$this->write_multipart_file($this->get_archive_name_with_extension());
|
639 |
-
}
|
640 |
|
641 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
642 |
|
643 |
-
|
644 |
|
645 |
-
|
646 |
-
$this->backup_archive->setCompression($this->compression_level);
|
647 |
-
$archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
|
648 |
-
$this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
|
649 |
|
650 |
-
|
|
|
|
|
|
|
651 |
|
652 |
-
|
|
|
653 |
|
654 |
-
|
655 |
*
|
656 |
* Add file to archive
|
657 |
*
|
658 |
*/
|
659 |
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
$start_filesystem = $this->filesystem->get_adapter($filesystem);
|
668 |
-
|
669 |
-
if (!$file_info['path']) {
|
670 |
-
return;
|
671 |
-
}
|
672 |
-
|
673 |
-
if (isset($file_info['archive_prefix_path'])) {
|
674 |
-
$file_info['target_path'] = $file_info['archive_prefix_path']."/".$file_info['path'];
|
675 |
-
} else {
|
676 |
-
$file_info['target_path'] = $file_info['path'];
|
677 |
-
}
|
678 |
-
|
679 |
-
$last_position = $start_at_byte;
|
680 |
-
|
681 |
-
//$start_adapter = $this->filesystem->get_start_adapter();
|
682 |
-
|
683 |
-
if (!$append) {
|
684 |
-
$bytes_wrote = $file_info['size'];
|
685 |
-
$this->logger->info(sprintf("Adding %s bytes of file %s to archive %s ", $bytes_wrote,
|
686 |
-
$file_info['target_path'], $this->get_archive_name_with_extension()));
|
687 |
-
$this->backup_archive->addFile($start_adapter->applyPathPrefix($file_info['path']),
|
688 |
-
$file_info['target_path']);
|
689 |
-
} else {
|
690 |
-
$tmp_file = md5($file_info['path']);
|
691 |
-
|
692 |
-
//we isolate file to tmp if we are at byte 0, the starting point of file reading
|
693 |
-
if (!$start_at_byte) {
|
694 |
-
$this->logger->info(sprintf("Copying %s file to tmp filesystem file %s to prevent reading changes",
|
695 |
-
$file_info['path'], $tmp_file));
|
696 |
-
$file_stream = $start_filesystem->readStream($file_info['path']);
|
697 |
-
|
698 |
-
if (is_resource($file_stream['stream'])) {
|
699 |
-
$this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']);
|
700 |
-
}
|
701 |
-
}
|
702 |
-
|
703 |
-
if ($this->filesystem->get_tmp_filesystem()->has($tmp_file)) {
|
704 |
-
$is_tmp = 1;
|
705 |
-
$last_position = $this->backup_archive->appendFileData($this->filesystem->get_tmp_filesystem_adapter()
|
706 |
-
->applyPathPrefix($tmp_file),
|
707 |
-
$file_info['target_path'], $start_at_byte, $byte_limit);
|
708 |
-
} else {
|
709 |
-
$is_tmp = 0;
|
710 |
-
$last_position = $this->backup_archive->appendFileData($start_adapter->applyPathPrefix($file_info['path']),
|
711 |
-
$file_info['target_path'], $start_at_byte, $byte_limit);
|
712 |
-
}
|
713 |
-
|
714 |
-
|
715 |
-
if ($last_position == -1) {
|
716 |
-
$bytes_wrote = $file_info['size'] - $start_at_byte;
|
717 |
-
} else {
|
718 |
-
$bytes_wrote = $last_position - $start_at_byte;
|
719 |
-
}
|
720 |
|
|
|
|
|
|
|
721 |
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
$bytes_wrote, $start_at_byte, $file_info['target_path'], $tmp_file, $this->get_archive_name()));
|
728 |
-
}
|
729 |
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
737 |
|
738 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
739 |
|
740 |
-
return array($bytes_wrote, $last_position);
|
741 |
-
}
|
742 |
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
*
|
748 |
-
* @param string $file
|
749 |
-
* @throws ArchiveIOException
|
750 |
-
*/
|
751 |
-
/*
|
752 |
-
public function openForAppend($file = '')
|
753 |
-
{
|
754 |
-
$this->file = $file;
|
755 |
-
$this->memory = '';
|
756 |
-
$this->fh = 0;
|
757 |
-
|
758 |
-
if ($this->file) {
|
759 |
-
// determine compression
|
760 |
-
if ($this->comptype == Archive::COMPRESS_AUTO) {
|
761 |
-
$this->setCompression($this->complevel, $this->filetype($file));
|
762 |
}
|
763 |
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
768 |
} else {
|
769 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
770 |
}
|
771 |
|
772 |
-
|
773 |
-
|
|
|
|
|
|
|
|
|
774 |
}
|
775 |
}
|
776 |
-
|
777 |
-
$
|
778 |
}
|
779 |
-
*/
|
780 |
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
* public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
|
793 |
{
|
794 |
-
|
795 |
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
}
|
803 |
|
804 |
if ($this->closed) {
|
805 |
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
806 |
}
|
807 |
|
|
|
|
|
|
|
|
|
|
|
808 |
$fp = fopen($file, 'rb');
|
809 |
|
810 |
fseek($fp, $start);
|
@@ -814,12 +827,13 @@ class Xcloner_Archive extends Tar
|
|
814 |
}
|
815 |
|
816 |
// create file header
|
817 |
-
|
818 |
-
|
|
|
819 |
|
820 |
-
|
821 |
// write data
|
822 |
-
while ($end >=ftell($fp) and !feof($fp)
|
823 |
$data = fread($fp, 512);
|
824 |
if ($data === false) {
|
825 |
break;
|
@@ -828,35 +842,131 @@ class Xcloner_Archive extends Tar
|
|
828 |
break;
|
829 |
}
|
830 |
$packed = pack("a512", $data);
|
831 |
-
$bytes += $this->
|
832 |
}
|
833 |
|
834 |
|
835 |
|
836 |
//if we are not at the end of file, we return the current position for incremental writing
|
837 |
-
if(!feof($fp))
|
838 |
-
|
839 |
-
|
840 |
-
|
|
|
841 |
|
842 |
fclose($fp);
|
843 |
|
844 |
return $last_position;
|
845 |
-
}
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
856 |
{
|
857 |
$this->openForAppend($archive);
|
858 |
return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit);
|
859 |
}
|
860 |
*/
|
861 |
-
|
862 |
}
|
36 |
*/
|
37 |
class Xcloner_Archive extends Tar
|
38 |
{
|
39 |
+
/**
|
40 |
+
* Process file size per API request
|
41 |
+
* @var float|int
|
42 |
+
*/
|
43 |
+
private $file_size_per_request_limit = 52428800; //50MB = 52428800; 1MB = 1048576
|
44 |
+
/**
|
45 |
+
* Files count to process per API request
|
46 |
+
* @var int
|
47 |
+
*/
|
48 |
+
private $files_to_process_per_request = 250; //block of 512 bytes
|
49 |
+
/**
|
50 |
+
* Compression level, 0-uncompressed, 9-maximum compression
|
51 |
+
* @var int
|
52 |
+
*/
|
53 |
+
private $compression_level = 0; //0-9 , 0 uncompressed
|
54 |
+
/**
|
55 |
+
* Split backup size limit
|
56 |
+
* Create a new backup archive file once the set size is reached
|
57 |
+
* @var float|int
|
58 |
+
*/
|
59 |
+
private $xcloner_split_backup_limit = 2048; //2048MB
|
60 |
+
/**
|
61 |
+
* Number of processed bytes
|
62 |
+
* @var int
|
63 |
+
*/
|
64 |
+
private $processed_size_bytes = 0;
|
65 |
|
66 |
/**
|
67 |
* The backup name encryption suffix
|
68 |
* @var string
|
69 |
*/
|
70 |
+
private $encrypt_suffix = "-enc";
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Archive name
|
74 |
+
* @var string
|
75 |
+
*/
|
76 |
+
private $archive_name;
|
77 |
+
/**
|
78 |
+
* @var Tar
|
79 |
+
*/
|
80 |
+
private $backup_archive;
|
81 |
+
/**
|
82 |
+
* @var Xcloner_File_System
|
83 |
+
*/
|
84 |
+
private $filesystem;
|
85 |
+
/**
|
86 |
+
* @var Xcloner_Logger
|
87 |
+
*/
|
88 |
+
private $logger;
|
89 |
+
/**
|
90 |
+
* @var Xcloner_Settings
|
91 |
+
*/
|
92 |
+
private $xcloner_settings;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* [__construct description]
|
96 |
+
* @param Xcloner $xcloner_container XCloner Container
|
97 |
+
* @param string $archive_name Achive Name
|
98 |
+
*/
|
99 |
+
public function __construct(Xcloner $xcloner_container, $archive_name = "")
|
100 |
+
{
|
101 |
+
$this->filesystem = $xcloner_container->get_xcloner_filesystem();
|
102 |
+
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive");
|
103 |
+
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
104 |
+
|
105 |
+
if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request')) {
|
106 |
+
$this->file_size_per_request_limit = $value * 1024 * 1024;
|
107 |
+
} //MB
|
108 |
+
|
109 |
+
if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request')) {
|
110 |
+
$this->files_to_process_per_request = $value;
|
111 |
+
}
|
112 |
+
|
113 |
+
if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_backup_compression_level')) {
|
114 |
+
$this->compression_level = $value;
|
115 |
+
}
|
116 |
+
|
117 |
+
if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_split_backup_limit')) {
|
118 |
+
$this->xcloner_split_backup_limit = $value;
|
119 |
+
}
|
120 |
+
|
121 |
+
$this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024 * 1024; //transform to bytes
|
122 |
+
|
123 |
+
if (isset($archive_name) && $archive_name) {
|
124 |
+
$this->set_archive_name($archive_name);
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/*
|
129 |
* Rename backup archive
|
130 |
*
|
131 |
* @param string $old_name
|
132 |
* @param string $new_name
|
133 |
*
|
134 |
*/
|
135 |
+
public function rename_archive($old_name, $new_name)
|
136 |
+
{
|
137 |
+
$this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name));
|
138 |
+
$storage_filesystem = $this->filesystem->get_storage_filesystem();
|
139 |
+
$storage_filesystem->rename($old_name, $new_name);
|
140 |
+
}
|
141 |
+
|
142 |
+
/*
|
143 |
*
|
144 |
* Set the backup archive name
|
145 |
*
|
146 |
*/
|
147 |
+
public function set_archive_name($name = "", $part = 0, $encrypt_prefix = false)
|
148 |
+
{
|
149 |
+
$this->archive_name = $this->filesystem->process_backup_name($name);
|
|
|
150 |
|
151 |
+
if ($encrypt_prefix) {
|
152 |
+
$this->archive_name .= $this->encrypt_suffix;
|
153 |
}
|
154 |
|
155 |
+
if ($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start()) {
|
156 |
+
//$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start);
|
157 |
+
$new_name = $this->archive_name;
|
|
|
|
|
|
|
|
|
158 |
|
159 |
+
if (!stristr($new_name, "-diff")) {
|
160 |
+
$new_name = $this->archive_name."-diff".date("Y-m-d_H-i", $diff_timestamp_start);
|
161 |
+
}
|
162 |
|
163 |
+
$this->archive_name = $new_name;
|
164 |
+
}
|
165 |
|
166 |
+
if (isset($part) and $part) {
|
167 |
+
$new_name = preg_replace('/-part(\d*)/', "-part".$part, $this->archive_name);
|
168 |
+
if (!stristr($new_name, "-part")) {
|
169 |
+
$new_name = $this->archive_name."-part".$part;
|
170 |
+
}
|
171 |
|
172 |
+
$this->archive_name = $new_name;
|
173 |
+
}
|
174 |
|
175 |
+
return $this;
|
176 |
+
}
|
177 |
|
178 |
+
/*
|
179 |
*
|
180 |
* Returns the backup archive name
|
181 |
*
|
182 |
* @return string archive name
|
183 |
*/
|
184 |
+
public function get_archive_name()
|
185 |
+
{
|
186 |
+
return $this->archive_name;
|
187 |
+
}
|
188 |
|
189 |
+
/*
|
190 |
*
|
191 |
* Returns the multipart naming for the backup archive
|
192 |
*
|
193 |
* @return string multi-part backup name
|
194 |
*/
|
195 |
+
public function get_archive_name_multipart()
|
196 |
+
{
|
197 |
+
$new_name = preg_replace('/-part(\d*)/', "", $this->archive_name);
|
198 |
+
return $new_name."-multipart".$this->xcloner_settings->get_backup_extension_name(".csv");
|
199 |
+
}
|
200 |
|
201 |
+
/*
|
202 |
*
|
203 |
* Returns the full backup name including extension
|
204 |
*
|
205 |
*/
|
206 |
+
public function get_archive_name_with_extension()
|
207 |
+
{
|
208 |
+
return $this->archive_name.$this->xcloner_settings->get_backup_extension_name();
|
209 |
+
}
|
210 |
|
211 |
+
/*
|
212 |
*
|
213 |
* Send notification error by E-Mail
|
214 |
*
|
222 |
* @return bool
|
223 |
*/
|
224 |
|
225 |
+
/**
|
226 |
+
* @param string $error_message
|
227 |
+
*/
|
228 |
+
public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message)
|
229 |
+
{
|
230 |
+
$body = "";
|
231 |
+
$body .= sprintf(__("Backup Site Url: %s"), get_site_url());
|
232 |
+
$body .= "<br /><>";
|
|
|
233 |
|
234 |
+
$body .= sprintf(__("Error Message: %s"), $error_message);
|
235 |
|
236 |
+
$this->logger->info(sprintf("Sending backup error notification to %s", $to));
|
237 |
|
238 |
+
$admin_email = $this->xcloner_settings->get_xcloner_option("admin_email");
|
239 |
|
240 |
+
$headers = array('Content-Type: text/html; charset=UTF-8');
|
241 |
|
242 |
+
if ($admin_email and $from) {
|
243 |
+
$headers[] = 'From: '.$from.' <'.$admin_email.'>';
|
244 |
+
}
|
245 |
|
246 |
+
$return = wp_mail($to, $subject, $body, $headers);
|
247 |
|
248 |
+
return $return;
|
249 |
+
}
|
250 |
|
251 |
+
/*
|
252 |
*
|
253 |
* Send backup archive notfication by E-Mail
|
254 |
*
|
262 |
*
|
263 |
* @return bool
|
264 |
*/
|
265 |
+
public function send_notification(
|
266 |
+
$to,
|
267 |
+
$from,
|
268 |
+
$subject,
|
269 |
+
$backup_name,
|
270 |
+
$params,
|
271 |
+
$error_message = "",
|
272 |
+
$additional = array()
|
273 |
+
) {
|
274 |
+
if (!$from) {
|
275 |
+
$from = "XCloner Backup";
|
276 |
+
}
|
277 |
|
278 |
+
if (($error_message)) {
|
279 |
+
return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message);
|
280 |
+
}
|
281 |
|
282 |
+
$params = (array)$params;
|
283 |
|
284 |
+
if (!$subject) {
|
285 |
+
$subject = sprintf(__("New backup generated %s"), $backup_name);
|
286 |
+
}
|
287 |
|
288 |
+
$body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name)));
|
289 |
+
$body .= "<br /><br />";
|
290 |
|
291 |
+
if (isset($additional['lines_total'])) {
|
292 |
+
$body .= sprintf(__("Total files added: %s"), $additional['lines_total']);
|
293 |
+
$body .= "<br /><br />";
|
294 |
+
}
|
295 |
|
296 |
+
$backup_parts = $this->filesystem->get_multipart_files($backup_name);
|
297 |
|
298 |
+
if (!$backups_counter = sizeof($backup_parts)) {
|
299 |
+
$backups_counter = 1;
|
300 |
+
}
|
301 |
|
302 |
+
$body .= sprintf(__("Backup Parts: %s"), $backups_counter);
|
303 |
+
$body .= "<br />";
|
304 |
|
305 |
+
if (sizeof($backup_parts)) {
|
306 |
+
$body .= implode("<br />", $backup_parts);
|
307 |
+
$body .= "<br />";
|
308 |
+
}
|
309 |
|
310 |
+
$body .= "<br />";
|
311 |
|
312 |
+
$body .= sprintf(__("Backup Site Url: %s"), get_site_url());
|
313 |
+
$body .= "<br />";
|
314 |
|
315 |
+
if (isset($params['backup_params']->backup_comments)) {
|
316 |
+
$body .= __("Backup Comments: ").$params['backup_params']->backup_comments;
|
317 |
+
$body .= "<br /><br />";
|
318 |
+
}
|
319 |
|
320 |
+
if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
|
321 |
+
$body .= __("Latest 50 Log Lines: ")."<br />".implode(
|
322 |
+
"<br />\n",
|
323 |
+
$this->logger->getLastDebugLines(50)
|
324 |
+
);
|
325 |
+
}
|
326 |
|
327 |
+
$attachments = $this->filesystem->get_backup_attachments();
|
328 |
|
329 |
+
$attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path().DS."info.tgz";
|
330 |
|
331 |
+
$tar = $this;
|
332 |
+
$tar->create($attachments_archive);
|
333 |
|
334 |
+
foreach ($attachments as $key => $file) {
|
335 |
+
$tar->addFile($file, basename($file));
|
336 |
+
}
|
337 |
+
$tar->close();
|
338 |
|
339 |
+
$this->logger->info(sprintf("Sending backup notification to %s", $to));
|
340 |
|
341 |
+
$admin_email = $this->xcloner_settings->get_xcloner_option("admin_email");
|
342 |
|
343 |
+
$headers = array('Content-Type: text/html; charset=UTF-8', 'From: '.$from.' <'.$admin_email.'>');
|
344 |
|
345 |
+
$return = wp_mail($to, $subject, $body, $headers, array($attachments_archive));
|
346 |
|
347 |
+
return $return;
|
348 |
+
}
|
349 |
|
350 |
+
/*
|
351 |
*
|
352 |
* Incremental Backup method
|
353 |
*
|
354 |
*/
|
355 |
+
public function start_incremental_backup($backup_params, $extra_params, $init)
|
356 |
+
{
|
357 |
+
$return = array();
|
358 |
|
359 |
+
if (!isset($extra_params['backup_part'])) {
|
360 |
+
$extra_params['backup_part'] = 0;
|
361 |
+
}
|
362 |
|
363 |
+
$return['extra']['backup_part'] = $extra_params['backup_part'];
|
364 |
|
365 |
+
if (isset($extra_params['backup_archive_name'])) {
|
366 |
+
$this->set_archive_name($extra_params['backup_archive_name'], $return['extra']['backup_part']);
|
367 |
+
} else {
|
368 |
+
$encrypt = false;
|
369 |
+
if (isset($backup_params['backup_encrypt']) && $backup_params['backup_encrypt']) {
|
370 |
$encrypt = true;
|
371 |
}
|
372 |
+
$this->set_archive_name($backup_params['backup_name'], 0, $encrypt);
|
373 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
374 |
|
375 |
+
if (!$this->get_archive_name()) {
|
376 |
+
$this->set_archive_name();
|
377 |
+
}
|
378 |
|
379 |
+
$this->backup_archive = $this;
|
380 |
+
$this->backup_archive->setCompression($this->compression_level);
|
381 |
|
382 |
+
$archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
|
|
|
383 |
|
384 |
+
if ($init) {
|
385 |
+
$this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name()));
|
386 |
|
387 |
+
$this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
|
388 |
|
389 |
+
$return['extra']['backup_init'] = 1;
|
390 |
+
} else {
|
391 |
+
$this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name()));
|
392 |
|
393 |
+
$this->backup_archive->openForAppend($archive_info->getPath().DS.$archive_info->getFilename());
|
|
|
394 |
|
395 |
+
$return['extra']['backup_init'] = 0;
|
396 |
+
}
|
|
|
397 |
|
398 |
+
$return['extra']['backup_archive_name'] = $this->get_archive_name();
|
399 |
+
$return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension();
|
|
|
400 |
|
401 |
+
if (!isset($extra_params['start_at_line'])) {
|
402 |
+
$extra_params['start_at_line'] = 0;
|
403 |
+
}
|
404 |
|
405 |
+
if (!isset($extra_params['start_at_byte'])) {
|
406 |
+
$extra_params['start_at_byte'] = 0;
|
407 |
+
}
|
408 |
|
409 |
+
if (!$this->filesystem->get_tmp_filesystem()->has($this->filesystem->get_included_files_handler())) {
|
410 |
+
$this->logger->error(sprintf(
|
411 |
+
"Missing the includes file handler %s, aborting...",
|
412 |
+
$this->filesystem->get_included_files_handler()
|
413 |
+
));
|
414 |
|
415 |
+
$return['finished'] = 1;
|
416 |
+
return $return;
|
417 |
+
}
|
418 |
|
419 |
+
$included_files_handler = $this->filesystem->get_included_files_handler(1);
|
420 |
|
421 |
+
$file = new SplFileObject($included_files_handler);
|
422 |
|
423 |
+
$file->seek(PHP_INT_MAX);
|
|
|
|
|
|
|
|
|
|
|
424 |
|
425 |
+
$return['extra']['lines_total'] = ($file->key() - 1);
|
426 |
|
427 |
+
//we skip the first CSV line with headers
|
428 |
+
if (!$extra_params['start_at_line']) {
|
429 |
+
$file->seek(1);
|
430 |
+
} else {
|
431 |
+
$file->seek($extra_params['start_at_line'] + 1);
|
432 |
+
}
|
433 |
|
434 |
+
$this->processed_size_bytes = 0;
|
435 |
|
436 |
+
$counter = 0;
|
437 |
|
438 |
+
$start_byte = $extra_params['start_at_byte'];
|
|
|
439 |
|
440 |
+
$byte_limit = 0;
|
441 |
|
442 |
+
while (!$file->eof() and $counter <= $this->files_to_process_per_request) {
|
443 |
+
$current_line_str = $file->current();
|
444 |
|
445 |
+
$line = str_getcsv($current_line_str);
|
446 |
|
447 |
+
$relative_path = stripslashes($line[0]);
|
|
|
|
|
448 |
|
449 |
+
$start_filesystem = "start_filesystem";
|
450 |
|
451 |
+
if (isset($line[4])) {
|
452 |
+
$start_filesystem = $line[4];
|
453 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
|
455 |
+
//$adapter = $this->filesystem->get_adapter($start_filesystem);
|
456 |
|
457 |
+
if (!$relative_path || !$this->filesystem->get_filesystem($start_filesystem)->has($relative_path)) {
|
458 |
+
if ($relative_path != "") {
|
459 |
+
$this->logger->error(sprintf(
|
460 |
+
"Could not add file %b to backup archive, file not found",
|
461 |
+
$relative_path
|
462 |
+
));
|
463 |
+
}
|
464 |
|
465 |
+
$extra_params['start_at_line']++;
|
466 |
+
$file->next();
|
467 |
+
continue;
|
468 |
+
}
|
469 |
|
470 |
+
$file_info = $this->filesystem->get_filesystem($start_filesystem)->getMetadata($relative_path);
|
471 |
|
472 |
+
if (!isset($file_info['size'])) {
|
473 |
+
$file_info['size'] = 0;
|
474 |
+
}
|
475 |
|
476 |
+
if ($start_filesystem == "tmp_filesystem") {
|
477 |
+
$file_info['archive_prefix_path'] = $this->xcloner_settings->get_xcloner_tmp_path_suffix();
|
478 |
+
}
|
479 |
|
480 |
+
$byte_limit = (int)$this->file_size_per_request_limit / 512;
|
|
|
|
|
481 |
|
482 |
+
$append = 0;
|
483 |
|
484 |
+
if ($file_info['size'] > $byte_limit * 512 or $start_byte) {
|
485 |
+
$append = 1;
|
486 |
+
}
|
487 |
|
488 |
+
if (!isset($return['extra']['backup_size'])) {
|
489 |
+
$return['extra']['backup_size'] = 0;
|
490 |
+
}
|
|
|
|
|
491 |
|
492 |
+
$return['extra']['backup_size'] = $archive_info->getSize();
|
|
|
|
|
|
|
|
|
493 |
|
494 |
+
$estimated_new_size = $return['extra']['backup_size'] + $file_info['size'];
|
|
|
495 |
|
496 |
+
//we create a new backup part if we reach the Split Achive Limit
|
497 |
+
if ($this->xcloner_split_backup_limit and ($estimated_new_size > $this->xcloner_split_backup_limit) and (!$start_byte)) {
|
498 |
+
$this->logger->info(sprintf(
|
499 |
+
"Backup size limit %s bytes reached, file add estimate %s, attempt to create a new archive ",
|
500 |
+
$this->xcloner_split_backup_limit,
|
501 |
+
$estimated_new_size
|
502 |
+
));
|
503 |
+
list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']);
|
504 |
|
505 |
+
if ($file_info['size'] > $this->xcloner_split_backup_limit) {
|
506 |
+
$this->logger->info(sprintf(
|
507 |
+
"Excluding %s file as it's size(%s) is bigger than the backup split limit of %s and it won't fit a single backup file",
|
508 |
+
$file_info['path'],
|
509 |
+
$file_info['size'],
|
510 |
+
$this->xcloner_split_backup_limit
|
511 |
+
));
|
512 |
+
$extra_params['start_at_line']++;
|
513 |
+
}
|
514 |
|
515 |
+
$return['extra']['start_at_line'] = $extra_params['start_at_line'];
|
516 |
+
$return['extra']['start_at_byte'] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
517 |
|
518 |
+
$return['finished'] = 0;
|
|
|
|
|
519 |
|
520 |
+
return $return;
|
521 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
522 |
|
523 |
+
list($bytes_wrote, $last_position) = $this->add_file_to_archive(
|
524 |
+
$file_info,
|
525 |
+
$start_byte,
|
526 |
+
$byte_limit,
|
527 |
+
$append,
|
528 |
+
$start_filesystem
|
529 |
+
);
|
530 |
+
$this->processed_size_bytes += $bytes_wrote;
|
531 |
+
|
532 |
+
//echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n";
|
533 |
+
$return['extra']['processed_file'] = $file_info['path'];
|
534 |
+
$return['extra']['processed_file_size'] = $file_info['size'];
|
535 |
+
$return['extra']['backup_size'] = $archive_info->getSize();
|
536 |
+
|
537 |
+
if ($last_position > 0) {
|
538 |
+
$start_byte = $last_position;
|
539 |
+
} else {
|
540 |
+
$extra_params['start_at_line']++;
|
541 |
+
$file->next();
|
542 |
+
$start_byte = 0;
|
543 |
+
$counter++;
|
544 |
+
}
|
545 |
|
546 |
+
if ($this->processed_size_bytes >= $this->file_size_per_request_limit) {
|
547 |
+
clearstatcache();
|
548 |
+
$return['extra']['backup_size'] = $archive_info->getSize();
|
549 |
+
|
550 |
+
$return['finished'] = 0;
|
551 |
+
$return['extra']['start_at_line'] = $extra_params['start_at_line'];
|
552 |
+
$return['extra']['start_at_byte'] = $last_position;
|
553 |
+
$this->logger->info(sprintf(
|
554 |
+
"Reached the maximum %s request data limit, returning response",
|
555 |
+
$this->file_size_per_request_limit
|
556 |
+
));
|
557 |
+
return $return;
|
558 |
+
}
|
559 |
+
}
|
560 |
|
561 |
+
if (!$file->eof()) {
|
562 |
+
clearstatcache();
|
563 |
+
$return['extra']['backup_size'] = $archive_info->getSize();
|
|
|
564 |
|
565 |
+
$return['finished'] = 0;
|
566 |
+
$return['extra']['start_at_line'] = $extra_params['start_at_line'];
|
567 |
+
$return['extra']['start_at_byte'] = $last_position;
|
568 |
+
$this->logger->info(sprintf(
|
569 |
+
"We have reached the maximum files to process per request limit of %s, returning response",
|
570 |
+
$this->files_to_process_per_request
|
571 |
+
));
|
572 |
|
573 |
+
return $return;
|
574 |
+
}
|
575 |
|
576 |
+
//close the backup archive by adding 2*512 blocks of zero bytes
|
577 |
+
$this->logger->info(sprintf(
|
578 |
+
"Closing the backup archive %s with 2*512 zero bytes blocks.",
|
579 |
+
$this->get_archive_name_with_extension()
|
580 |
+
));
|
581 |
+
$this->backup_archive->close();
|
582 |
+
|
583 |
+
/**
|
584 |
+
* XCloner HOOK backup_archive_finished.
|
585 |
+
*
|
586 |
+
* This will get triggered when a backup archive is finished writing.
|
587 |
+
*/
|
588 |
+
//do_action('backup_archive_finished', $this->backup_archive, $this);
|
589 |
+
|
590 |
+
//updating archive_info
|
591 |
+
$archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
|
592 |
+
|
593 |
+
if ($return['extra']['backup_part']) {
|
594 |
+
$this->write_multipart_file($this->get_archive_name_with_extension());
|
595 |
+
}
|
596 |
|
597 |
+
$return['extra']['start_at_line'] = $extra_params['start_at_line'] - 1;
|
598 |
|
599 |
+
if (isset($file_info)) {
|
600 |
+
$return['extra']['processed_file'] = $file_info['path'];
|
601 |
+
$return['extra']['processed_file_size'] = $file_info['size'];
|
602 |
+
}
|
603 |
|
604 |
+
clearstatcache();
|
605 |
+
$return['extra']['backup_size'] = $archive_info->getSize();
|
606 |
|
607 |
+
$return['finished'] = 1;
|
608 |
+
return $return;
|
609 |
+
}
|
610 |
|
611 |
+
/*
|
612 |
*
|
613 |
* Write multipart file components
|
614 |
*
|
615 |
*/
|
616 |
+
private function write_multipart_file($path = "")
|
617 |
+
{
|
618 |
+
if (!$path) {
|
619 |
+
$path = $this->get_archive_name_with_extension();
|
620 |
+
}
|
621 |
|
622 |
+
$file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path);
|
623 |
+
//print_r($file_info);
|
624 |
+
$line = '"'.$file['path'].'","'.$file['timestamp'].'","'.$file['size'].'"'.PHP_EOL;
|
625 |
|
626 |
|
627 |
+
$this->filesystem->get_filesystem("storage_filesystem_append")
|
628 |
+
->write($this->get_archive_name_multipart(), $line);
|
629 |
+
}
|
630 |
|
631 |
+
/*
|
632 |
*
|
633 |
* Create a new backup part
|
634 |
*
|
635 |
*/
|
636 |
+
private function create_new_backup_part($part = 0)
|
637 |
+
{
|
638 |
+
//close the backup archive by adding 2*512 blocks of zero bytes
|
639 |
+
$this->logger->info(sprintf(
|
640 |
+
"Closing the backup archive %s with 2*512 zero bytes blocks.",
|
641 |
+
$this->get_archive_name_with_extension()
|
642 |
+
));
|
643 |
+
$this->backup_archive->close();
|
644 |
+
|
645 |
+
if (!$part) {
|
646 |
+
$old_name = $this->get_archive_name_with_extension();
|
647 |
+
$this->set_archive_name($this->get_archive_name(), ++$part);
|
648 |
+
$this->rename_archive($old_name, $this->get_archive_name_with_extension());
|
649 |
+
|
650 |
+
if ($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart())) {
|
651 |
+
$this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart());
|
652 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
653 |
|
654 |
+
$this->write_multipart_file($this->get_archive_name_with_extension());
|
655 |
+
} else {
|
656 |
+
$this->logger->info(sprintf(
|
657 |
+
"Creating new multipart info file %s",
|
658 |
+
$this->get_archive_name_with_extension()
|
659 |
+
));
|
660 |
+
$this->write_multipart_file($this->get_archive_name_with_extension());
|
661 |
+
}
|
662 |
|
663 |
+
$this->set_archive_name($this->get_archive_name(), ++$part);
|
664 |
|
665 |
+
$this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension()));
|
|
|
|
|
|
|
666 |
|
667 |
+
$this->backup_archive = $this;
|
668 |
+
$this->backup_archive->setCompression($this->compression_level);
|
669 |
+
$archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
|
670 |
+
$this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
|
671 |
|
672 |
+
return array($archive_info, $part);
|
673 |
+
}
|
674 |
|
675 |
+
/*
|
676 |
*
|
677 |
* Add file to archive
|
678 |
*
|
679 |
*/
|
680 |
|
681 |
+
/**
|
682 |
+
* @param integer $append
|
683 |
+
*/
|
684 |
+
public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem)
|
685 |
+
{
|
686 |
+
$start_adapter = $this->filesystem->get_adapter($filesystem);
|
687 |
+
$start_filesystem = $this->filesystem->get_adapter($filesystem);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
688 |
|
689 |
+
if (!$file_info['path']) {
|
690 |
+
return;
|
691 |
+
}
|
692 |
|
693 |
+
if (isset($file_info['archive_prefix_path'])) {
|
694 |
+
$file_info['target_path'] = $file_info['archive_prefix_path']."/".$file_info['path'];
|
695 |
+
} else {
|
696 |
+
$file_info['target_path'] = $file_info['path'];
|
697 |
+
}
|
|
|
|
|
698 |
|
699 |
+
$last_position = $start_at_byte;
|
700 |
+
|
701 |
+
//$start_adapter = $this->filesystem->get_start_adapter();
|
702 |
+
|
703 |
+
if (!$append) {
|
704 |
+
$bytes_wrote = $file_info['size'];
|
705 |
+
$this->logger->info(sprintf(
|
706 |
+
"Adding %s bytes of file %s to archive %s ",
|
707 |
+
$bytes_wrote,
|
708 |
+
$file_info['target_path'],
|
709 |
+
$this->get_archive_name_with_extension()
|
710 |
+
));
|
711 |
+
$this->backup_archive->addFile(
|
712 |
+
$start_adapter->applyPathPrefix($file_info['path']),
|
713 |
+
$file_info['target_path']
|
714 |
+
);
|
715 |
+
} else {
|
716 |
+
$tmp_file = md5($file_info['path']);
|
717 |
+
|
718 |
+
//we isolate file to tmp if we are at byte 0, the starting point of file reading
|
719 |
+
if (!$start_at_byte) {
|
720 |
+
$this->logger->info(sprintf(
|
721 |
+
"Copying %s file to tmp filesystem file %s to prevent reading changes",
|
722 |
+
$file_info['path'],
|
723 |
+
$tmp_file
|
724 |
+
));
|
725 |
+
$file_stream = $start_filesystem->readStream($file_info['path']);
|
726 |
+
|
727 |
+
if (is_resource($file_stream['stream'])) {
|
728 |
+
$this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']);
|
729 |
+
}
|
730 |
+
}
|
731 |
|
732 |
+
if ($this->filesystem->get_tmp_filesystem()->has($tmp_file)) {
|
733 |
+
$is_tmp = 1;
|
734 |
+
$last_position = $this->backup_archive->appendFileData(
|
735 |
+
$this->filesystem->get_tmp_filesystem_adapter()
|
736 |
+
->applyPathPrefix($tmp_file),
|
737 |
+
$file_info['target_path'],
|
738 |
+
$start_at_byte,
|
739 |
+
$byte_limit
|
740 |
+
);
|
741 |
+
} else {
|
742 |
+
$is_tmp = 0;
|
743 |
+
$last_position = $this->backup_archive->appendFileData(
|
744 |
+
$start_adapter->applyPathPrefix($file_info['path']),
|
745 |
+
$file_info['target_path'],
|
746 |
+
$start_at_byte,
|
747 |
+
$byte_limit
|
748 |
+
);
|
749 |
+
}
|
750 |
|
|
|
|
|
751 |
|
752 |
+
if ($last_position == -1) {
|
753 |
+
$bytes_wrote = $file_info['size'] - $start_at_byte;
|
754 |
+
} else {
|
755 |
+
$bytes_wrote = $last_position - $start_at_byte;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
756 |
}
|
757 |
|
758 |
+
|
759 |
+
if ($is_tmp) {
|
760 |
+
$this->logger->info(sprintf(
|
761 |
+
"Appended %s bytes, starting position %s, of tmp file %s (%s) to archive %s ",
|
762 |
+
$bytes_wrote,
|
763 |
+
$start_at_byte,
|
764 |
+
$tmp_file,
|
765 |
+
$file_info['target_path'],
|
766 |
+
$this->get_archive_name()
|
767 |
+
));
|
768 |
} else {
|
769 |
+
$this->logger->info(sprintf(
|
770 |
+
"Appended %s bytes, starting position %s, of original file %s to archive %s ",
|
771 |
+
$bytes_wrote,
|
772 |
+
$start_at_byte,
|
773 |
+
$file_info['target_path'],
|
774 |
+
$tmp_file,
|
775 |
+
$this->get_archive_name()
|
776 |
+
));
|
777 |
}
|
778 |
|
779 |
+
//we delete here the isolated tmp file
|
780 |
+
if ($last_position == -1) {
|
781 |
+
if ($this->filesystem->get_tmp_filesystem_adapter()->has($tmp_file)) {
|
782 |
+
$this->logger->info(sprintf("Deleting %s from the tmp filesystem", $tmp_file));
|
783 |
+
$this->filesystem->get_tmp_filesystem_adapter()->delete($tmp_file);
|
784 |
+
}
|
785 |
}
|
786 |
}
|
787 |
+
|
788 |
+
return array($bytes_wrote, $last_position);
|
789 |
}
|
|
|
790 |
|
791 |
+
/**
|
792 |
+
* Append data to a file to the current TAR archive using an existing file in the filesystem
|
793 |
+
*
|
794 |
+
* @param string $file path to the original file
|
795 |
+
* @param int $start starting reading position in file
|
796 |
+
* @param int $end end position in reading multiple with 512
|
797 |
+
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with
|
798 |
+
* all meta data, empty to take from original
|
799 |
+
* @throws ArchiveIOException
|
800 |
+
*/
|
801 |
+
public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
|
|
|
802 |
{
|
803 |
+
$end = $start+($limit*512);
|
804 |
|
805 |
+
//check to see if we are at the begining of writing the file
|
806 |
+
if (!$start) {
|
807 |
+
if (is_string($fileinfo)) {
|
808 |
+
$fileinfo = FileInfo::fromPath($file, $fileinfo);
|
809 |
+
}
|
810 |
+
}
|
|
|
811 |
|
812 |
if ($this->closed) {
|
813 |
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
814 |
}
|
815 |
|
816 |
+
if (is_dir($file)) {
|
817 |
+
$this->writeFileHeader($fileinfo);
|
818 |
+
return;
|
819 |
+
}
|
820 |
+
|
821 |
$fp = fopen($file, 'rb');
|
822 |
|
823 |
fseek($fp, $start);
|
827 |
}
|
828 |
|
829 |
// create file header
|
830 |
+
if (!$start) {
|
831 |
+
$this->writeFileHeader($fileinfo);
|
832 |
+
}
|
833 |
|
834 |
+
$bytes = 0;
|
835 |
// write data
|
836 |
+
while ($end >=ftell($fp) and !feof($fp)) {
|
837 |
$data = fread($fp, 512);
|
838 |
if ($data === false) {
|
839 |
break;
|
842 |
break;
|
843 |
}
|
844 |
$packed = pack("a512", $data);
|
845 |
+
$bytes += $this->writebytes($packed);
|
846 |
}
|
847 |
|
848 |
|
849 |
|
850 |
//if we are not at the end of file, we return the current position for incremental writing
|
851 |
+
if (!feof($fp)) {
|
852 |
+
$last_position = ftell($fp);
|
853 |
+
} else {
|
854 |
+
$last_position = -1;
|
855 |
+
}
|
856 |
|
857 |
fclose($fp);
|
858 |
|
859 |
return $last_position;
|
860 |
+
}
|
861 |
+
|
862 |
+
public function open($file, $start_byte = 0)
|
863 |
+
{
|
864 |
+
parent::open($file);
|
865 |
+
|
866 |
+
if ($start_byte) {
|
867 |
+
fseek($this->fh, $start_byte);
|
868 |
+
}
|
869 |
+
}
|
870 |
+
|
871 |
+
/**
|
872 |
+
* Open a TAR archive and put the file cursor at the end for data appending
|
873 |
+
*
|
874 |
+
* If $file is empty, the tar file will be created in memory
|
875 |
+
*
|
876 |
+
* @param string $file
|
877 |
+
* @throws ArchiveIOException
|
878 |
+
*/
|
879 |
+
public function openForAppend($file = '')
|
880 |
+
{
|
881 |
+
$this->file = $file;
|
882 |
+
$this->memory = '';
|
883 |
+
$this->fh = 0;
|
884 |
+
|
885 |
+
if ($this->file) {
|
886 |
+
// determine compression
|
887 |
+
if ($this->comptype == Archive::COMPRESS_AUTO) {
|
888 |
+
$this->setCompression($this->complevel, $this->filetype($file));
|
889 |
+
}
|
890 |
+
|
891 |
+
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
892 |
+
$this->fh = @gzopen($this->file, 'ab'.$this->complevel);
|
893 |
+
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
894 |
+
$this->fh = @bzopen($this->file, 'a');
|
895 |
+
} else {
|
896 |
+
$this->fh = @fopen($this->file, 'ab');
|
897 |
+
}
|
898 |
+
|
899 |
+
if (!$this->fh) {
|
900 |
+
throw new ArchiveIOException('Could not open file for writing: '.$this->file);
|
901 |
+
}
|
902 |
+
}
|
903 |
+
$this->writeaccess = true;
|
904 |
+
$this->closed = false;
|
905 |
+
}
|
906 |
+
|
907 |
+
/**
|
908 |
+
* Read the contents of a TAR archive
|
909 |
+
*
|
910 |
+
* This function lists the files stored in the archive
|
911 |
+
*
|
912 |
+
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
913 |
+
* Reopen the file with open() again if you want to do additional operations
|
914 |
+
*
|
915 |
+
* @throws ArchiveIOException
|
916 |
+
* @returns FileInfo[]
|
917 |
+
*/
|
918 |
+
public function contents($files_limit = 0)
|
919 |
+
{
|
920 |
+
if ($this->closed || !$this->file) {
|
921 |
+
throw new ArchiveIOException('Can not read from a closed archive');
|
922 |
+
}
|
923 |
+
|
924 |
+
$files_counter = 0;
|
925 |
+
$result = array();
|
926 |
+
|
927 |
+
while ($read = $this->readbytes(512)) {
|
928 |
+
$header = $this->parseHeader($read);
|
929 |
+
if (!is_array($header)) {
|
930 |
+
continue;
|
931 |
+
}
|
932 |
+
|
933 |
+
if($files_limit)
|
934 |
+
{
|
935 |
+
if(++$files_counter > $files_limit)
|
936 |
+
{
|
937 |
+
$return['extracted_files'] = $result;
|
938 |
+
$return['start'] = ftell($this->fh)-512;
|
939 |
+
return $return;
|
940 |
+
}
|
941 |
+
}
|
942 |
+
|
943 |
+
if($header['typeflag'] == 5)
|
944 |
+
$header['size'] = 0;
|
945 |
+
|
946 |
+
$this->skipbytes(ceil($header['size'] / 512) * 512);
|
947 |
+
$result[] = $this->header2fileinfo($header);
|
948 |
+
}
|
949 |
+
|
950 |
+
$return['extracted_files'] = $result;
|
951 |
+
|
952 |
+
$this->close();
|
953 |
+
return $return;
|
954 |
+
}
|
955 |
+
|
956 |
+
|
957 |
+
|
958 |
+
/**
|
959 |
+
* Adds a file to a TAR archive by appending it's data
|
960 |
+
*
|
961 |
+
* @param string $archive name of the archive file
|
962 |
+
* @param string $file name of the file to read data from
|
963 |
+
* @param string $start start position from where to start reading data
|
964 |
+
* @throws ArchiveIOException
|
965 |
+
*/
|
966 |
+
/*public function addFileToArchive($archive, $file, $start = 0)
|
967 |
{
|
968 |
$this->openForAppend($archive);
|
969 |
return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit);
|
970 |
}
|
971 |
*/
|
|
|
972 |
}
|
includes/class-xcloner-database.php
CHANGED
@@ -1,4 +1,6 @@
|
|
1 |
<?php
|
|
|
|
|
2 |
/*
|
3 |
* class-xcloner-database.php
|
4 |
*
|
@@ -20,628 +22,653 @@
|
|
20 |
* MA 02110-1301, USA.
|
21 |
*/
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
-
public function
|
43 |
-
|
44 |
-
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_database");
|
45 |
-
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
46 |
-
$this->fs = $xcloner_container->get_xcloner_filesystem();
|
47 |
-
|
48 |
-
if ($this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request'))
|
49 |
-
$this->recordsPerSession = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
|
50 |
-
|
51 |
-
if (!$this->recordsPerSession)
|
52 |
-
$this->recordsPerSession = 100;
|
53 |
-
|
54 |
-
if (!$wp_user && !$wp_pass && !$wp_host && !$wp_db)
|
55 |
-
{
|
56 |
-
$wp_host = $this->xcloner_settings->get_db_hostname();
|
57 |
-
$wp_user = $this->xcloner_settings->get_db_username();
|
58 |
-
$wp_pass = $this->xcloner_settings->get_db_password();
|
59 |
-
$wp_db = $this->xcloner_settings->get_db_database();
|
60 |
-
}
|
61 |
-
|
62 |
-
parent::__construct($wp_user, $wp_pass, $wp_db, $wp_host);
|
63 |
-
|
64 |
-
//$this->use_mysqli = true;
|
65 |
}
|
66 |
-
/*
|
67 |
-
* Initialize the database connection
|
68 |
-
*
|
69 |
-
* name: init
|
70 |
-
* @param array $data {'dbHostname', 'dbUsername', 'dbPassword', 'dbDatabase'}
|
71 |
-
* @return
|
72 |
-
*/
|
73 |
-
public function init($data, $start = 0)
|
74 |
-
{
|
75 |
-
if ($start and $this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)) {
|
76 |
-
$this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
|
77 |
-
}
|
78 |
-
|
79 |
-
$this->headers();
|
80 |
-
|
81 |
-
$this->suppress_errors = true;
|
82 |
-
}
|
83 |
-
|
84 |
-
public function start_database_recursion($params, $extra_params, $init = 0)
|
85 |
-
{
|
86 |
-
$tables = array();
|
87 |
-
$return['finished'] = 0;
|
88 |
-
$return['stats'] = array(
|
89 |
-
"total_records"=>0,
|
90 |
-
"tables_count"=>0,
|
91 |
-
"database_count"=>0,
|
92 |
-
);
|
93 |
-
|
94 |
-
if (!$this->xcloner_settings->get_enable_mysql_backup())
|
95 |
-
{
|
96 |
-
$return['finished'] = 1;
|
97 |
-
return $return;
|
98 |
-
}
|
99 |
-
|
100 |
-
$this->logger->debug(__("Starting database backup process"));
|
101 |
-
|
102 |
-
$this->init($params, $init);
|
103 |
-
|
104 |
-
if ($init)
|
105 |
-
{
|
106 |
-
$db_count = 0;
|
107 |
-
|
108 |
-
if (isset($params['#']))
|
109 |
-
{
|
110 |
-
foreach ($params['#'] as $database)
|
111 |
-
{
|
112 |
-
if (!isset($params[$database]) or !is_array($params[$database]))
|
113 |
-
$params[$database] = array();
|
114 |
-
}
|
115 |
-
$db_count = -1;
|
116 |
-
}
|
117 |
-
|
118 |
-
if (isset($params) and is_array($params))
|
119 |
-
foreach ($params as $database=>$tables)
|
120 |
-
{
|
121 |
-
if ($database != "#")
|
122 |
-
{
|
123 |
-
$stats = $this->write_backup_process_list($database, $tables);
|
124 |
-
$return['stats']['tables_count'] += $stats['tables_count'];
|
125 |
-
$return['stats']['total_records'] += $stats['total_records'];
|
126 |
-
}
|
127 |
-
}
|
128 |
-
|
129 |
-
if (sizeof($params))
|
130 |
-
$return['stats']['database_count'] = sizeof($params) + $db_count;
|
131 |
-
else
|
132 |
-
$return['stats']['database_count'] = 0;
|
133 |
-
|
134 |
-
return $return;
|
135 |
-
}
|
136 |
-
|
137 |
-
if (!isset($extra_params['startAtLine']))
|
138 |
-
$extra_params['startAtLine'] = 0;
|
139 |
-
if (!isset($extra_params['startAtRecord']))
|
140 |
-
$extra_params['startAtRecord'] = 0;
|
141 |
-
if (!isset($extra_params['dumpfile']))
|
142 |
-
$extra_params['dumpfile'] = "";
|
143 |
-
|
144 |
-
$return = $this->process_incremental($extra_params['startAtLine'], $extra_params['startAtRecord'], $extra_params['dumpfile']);
|
145 |
-
|
146 |
-
return $return;
|
147 |
-
}
|
148 |
-
|
149 |
-
public function log($message = "")
|
150 |
-
{
|
151 |
-
|
152 |
-
if ($message) {
|
153 |
-
$this->logger->info($message, array(""));
|
154 |
-
} else {
|
155 |
-
if ($this->last_query)
|
156 |
-
$this->logger->debug($this->last_query, array(""));
|
157 |
-
if ($this->last_error)
|
158 |
-
$this->logger->error($this->last_error, array(""));
|
159 |
-
}
|
160 |
-
|
161 |
-
return;
|
162 |
-
}
|
163 |
-
|
164 |
-
/*
|
165 |
-
*Return any error
|
166 |
-
*
|
167 |
-
* name: error
|
168 |
-
* @param string $message
|
169 |
-
* @return
|
170 |
-
*/
|
171 |
-
public function error($message)
|
172 |
-
{
|
173 |
-
$this->logger->error($message, array(""));
|
174 |
-
|
175 |
-
return;
|
176 |
-
}
|
177 |
-
|
178 |
-
/*
|
179 |
-
* Send some special headers after the connection is initialized
|
180 |
-
*
|
181 |
-
* name: headers
|
182 |
-
* @param
|
183 |
-
*/
|
184 |
-
private function headers()
|
185 |
-
{
|
186 |
-
$this->logger->debug(__("Setting mysql headers"));
|
187 |
-
|
188 |
-
$this->query("SET SQL_QUOTE_SHOW_CREATE=1;");
|
189 |
-
//$this->log();
|
190 |
-
$this->query("SET sql_mode = 0;");
|
191 |
-
//$this->log();
|
192 |
-
|
193 |
-
$this->set_charset($this->dbh, 'utf8');
|
194 |
-
//$this->log();
|
195 |
-
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
if (sizeof($included) and is_array($included)) {
|
281 |
$dbTable = $database.".".$table;
|
282 |
if (!in_array($table, $included) and !in_array($dbTable, $included)) {
|
283 |
$tablesList[$inc]['excluded'] = 1;
|
284 |
$this->log(sprintf(__("Excluding table %s.%s from backup"), $table, $database));
|
285 |
}
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
$return .= "#\n";
|
611 |
-
$return .= "# Powered by XCloner Site Backup\n";
|
612 |
-
$return .= "# http://www.xcloner.com\n";
|
613 |
-
$return .= "#\n";
|
614 |
-
$return .= "# Host: ".get_site_url()."\n";
|
615 |
-
$return .= "# Generation Time: ".date("M j, Y \a\\t H:i")."\n";
|
616 |
-
$return .= "# PHP Version: ".phpversion()."\n";
|
617 |
-
$return .= "# Database Charset: ".$this->charset."\n";
|
618 |
-
|
619 |
-
$results = $this->get_results("SHOW VARIABLES LIKE \"%version%\";", ARRAY_N);
|
620 |
-
if (isset($results)) {
|
621 |
-
foreach ($results as $result) {
|
622 |
-
|
623 |
-
$return .= "# MYSQL ".$result[0].": ".$result[1]."\n";
|
624 |
-
|
625 |
-
}
|
626 |
-
}
|
627 |
-
|
628 |
-
$results = $this->get_results("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
|
629 |
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '".$database."';");
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
}
|
645 |
-
|
646 |
-
|
647 |
}
|
1 |
<?php
|
2 |
+
|
3 |
+
|
4 |
/*
|
5 |
* class-xcloner-database.php
|
6 |
*
|
22 |
* MA 02110-1301, USA.
|
23 |
*/
|
24 |
|
25 |
+
if (!class_exists('wpdb')) {
|
26 |
+
require_once __DIR__ . "/../lib/wp-db.php";
|
27 |
+
}
|
28 |
+
|
29 |
+
class Xcloner_Database extends wpdb
|
30 |
+
{
|
31 |
+
public $debug = 0;
|
32 |
+
public $recordsPerSession = 10000;
|
33 |
+
public $dbCompatibility = "";
|
34 |
+
public $dbDropSyntax = 1;
|
35 |
+
public $countRecords = 0;
|
36 |
+
|
37 |
+
private $link;
|
38 |
+
private $db_selected;
|
39 |
+
private $logger;
|
40 |
+
private $xcloner_settings;
|
41 |
+
private $fs;
|
42 |
+
|
43 |
+
private $xcloner_dbhost;
|
44 |
+
private $xcloner_dbuser;
|
45 |
+
private $xcloner_dbpassword;
|
46 |
+
private $xcloner_dbname;
|
47 |
+
private $xcloner_prefix;
|
48 |
+
|
49 |
+
private $TEMP_DBPROCESS_FILE = ".database";
|
50 |
+
private $TEMP_DUMP_FILE = "database-backup.sql";
|
51 |
+
|
52 |
+
public function __construct(Xcloner $xcloner_container, $wp_user = "", $wp_pass = "", $wp_db = "", $wp_host = "")
|
53 |
+
{
|
54 |
+
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_database");
|
55 |
+
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
56 |
+
$this->fs = $xcloner_container->get_xcloner_filesystem();
|
57 |
+
|
58 |
+
if ($this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request')) {
|
59 |
+
$this->recordsPerSession = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
|
60 |
+
}
|
61 |
+
|
62 |
+
if (!$this->recordsPerSession) {
|
63 |
+
$this->recordsPerSession = 100;
|
64 |
+
}
|
65 |
+
|
66 |
+
$this->xcloner_dbhost = $this->xcloner_settings->get_db_hostname();
|
67 |
+
$this->xcloner_dbuser = $this->xcloner_settings->get_db_username();
|
68 |
+
$this->xcloner_dbpassword = $this->xcloner_settings->get_db_password();
|
69 |
+
$this->xcloner_dbname = $this->xcloner_settings->get_db_database();
|
70 |
+
$this->xcloner_prefix= "";
|
71 |
+
|
72 |
+
//fetch the default wordpress mysql credentials
|
73 |
+
if ( !$this->xcloner_dbuser || !$this->xcloner_dbhost || !$this->xcloner_dbname ) {
|
74 |
+
global $wpdb;
|
75 |
+
|
76 |
+
$this->xcloner_dbhost = $wpdb->dbhost;
|
77 |
+
update_option('xcloner_mysql_hostname', $this->xcloner_dbhost);
|
78 |
+
$this->xcloner_dbuser = $wpdb->dbuser;
|
79 |
+
update_option('xcloner_mysql_username', $this->xcloner_dbuser);
|
80 |
+
$this->xcloner_dbpassword = $wpdb->dbpassword;
|
81 |
+
update_option('xcloner_mysql_password', $this->xcloner_dbpassword);
|
82 |
+
$this->xcloner_dbname = $wpdb->dbname;
|
83 |
+
update_option('xcloner_mysql_database', $this->xcloner_dbname);
|
84 |
+
$this->xcloner_prefix = $wpdb->prefix;
|
85 |
+
update_option('xcloner_mysql_prefix', $this->xcloner_prefix);
|
86 |
+
|
87 |
+
}
|
88 |
+
|
89 |
+
parent::__construct($this->xcloner_dbuser, $this->xcloner_dbpassword, $this->xcloner_dbname, $this->xcloner_dbhost);
|
90 |
+
|
91 |
+
//$this->use_mysqli = true;
|
92 |
+
}
|
93 |
|
94 |
+
public function getPrefix() {
|
95 |
+
return $this->xcloner_prefix;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
+
public function getDbHost()
|
99 |
+
{
|
100 |
+
return $this->xcloner_dbhost;
|
101 |
+
}
|
102 |
+
|
103 |
+
public function getDbUser()
|
104 |
+
{
|
105 |
+
return $this->xcloner_dbuser;
|
106 |
+
}
|
107 |
+
|
108 |
+
public function getDbPassword()
|
109 |
+
{
|
110 |
+
return $this->xcloner_dbpassword;
|
111 |
+
}
|
112 |
+
|
113 |
+
public function getDbName()
|
114 |
+
{
|
115 |
+
return $this->xcloner_dbname;
|
116 |
+
}
|
117 |
+
|
118 |
+
/*
|
119 |
+
* Initialize the database connection
|
120 |
+
*
|
121 |
+
* name: init
|
122 |
+
* @param array $data {'dbHostname', 'dbUsername', 'dbPassword', 'dbDatabase'}
|
123 |
+
* @return
|
124 |
+
*/
|
125 |
+
public function init($data, $start = 0)
|
126 |
+
{
|
127 |
+
if ($start and $this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)) {
|
128 |
+
$this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
|
129 |
+
}
|
130 |
+
|
131 |
+
$this->headers();
|
132 |
+
|
133 |
+
$this->suppress_errors = true;
|
134 |
+
}
|
135 |
+
|
136 |
+
public function start_database_recursion($params, $extra_params, $init = 0)
|
137 |
+
{
|
138 |
+
$tables = array();
|
139 |
+
$return['finished'] = 0;
|
140 |
+
$return['stats'] = array(
|
141 |
+
"total_records"=>0,
|
142 |
+
"tables_count"=>0,
|
143 |
+
"database_count"=>0,
|
144 |
+
);
|
145 |
+
|
146 |
+
if (!$this->xcloner_settings->get_enable_mysql_backup()) {
|
147 |
+
$return['finished'] = 1;
|
148 |
+
return $return;
|
149 |
+
}
|
150 |
+
|
151 |
+
$this->logger->debug(__("Starting database backup process"));
|
152 |
+
|
153 |
+
$this->init($params, $init);
|
154 |
+
|
155 |
+
if ($init) {
|
156 |
+
$db_count = 0;
|
157 |
+
|
158 |
+
if (isset($params['#'])) {
|
159 |
+
foreach ($params['#'] as $database) {
|
160 |
+
if (!isset($params[$database]) or !is_array($params[$database])) {
|
161 |
+
$params[$database] = array();
|
162 |
+
}
|
163 |
+
}
|
164 |
+
$db_count = -1;
|
165 |
+
}
|
166 |
+
|
167 |
+
if (isset($params) and is_array($params)) {
|
168 |
+
foreach ($params as $database=>$tables) {
|
169 |
+
if ($database != "#") {
|
170 |
+
$stats = $this->write_backup_process_list($database, $tables);
|
171 |
+
$return['stats']['tables_count'] += $stats['tables_count'];
|
172 |
+
$return['stats']['total_records'] += $stats['total_records'];
|
173 |
+
}
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
if (sizeof($params)) {
|
178 |
+
$return['stats']['database_count'] = sizeof($params) + $db_count;
|
179 |
+
} else {
|
180 |
+
$return['stats']['database_count'] = 0;
|
181 |
+
}
|
182 |
+
|
183 |
+
return $return;
|
184 |
+
}
|
185 |
+
|
186 |
+
if (!isset($extra_params['startAtLine'])) {
|
187 |
+
$extra_params['startAtLine'] = 0;
|
188 |
+
}
|
189 |
+
if (!isset($extra_params['startAtRecord'])) {
|
190 |
+
$extra_params['startAtRecord'] = 0;
|
191 |
+
}
|
192 |
+
if (!isset($extra_params['dumpfile'])) {
|
193 |
+
$extra_params['dumpfile'] = "";
|
194 |
+
}
|
195 |
+
|
196 |
+
$return = $this->process_incremental($extra_params['startAtLine'], $extra_params['startAtRecord'], $extra_params['dumpfile']);
|
197 |
+
|
198 |
+
return $return;
|
199 |
+
}
|
200 |
+
|
201 |
+
public function log($message = "")
|
202 |
+
{
|
203 |
+
if ($message) {
|
204 |
+
$this->logger->info($message, array(""));
|
205 |
+
} else {
|
206 |
+
if ($this->last_query) {
|
207 |
+
$this->logger->debug($this->last_query, array(""));
|
208 |
+
}
|
209 |
+
if ($this->last_error) {
|
210 |
+
$this->logger->error($this->last_error, array(""));
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
return;
|
215 |
+
}
|
216 |
+
|
217 |
+
/*
|
218 |
+
*Return any error
|
219 |
+
*
|
220 |
+
* name: error
|
221 |
+
* @param string $message
|
222 |
+
* @return
|
223 |
+
*/
|
224 |
+
public function error($message)
|
225 |
+
{
|
226 |
+
$this->logger->error($message, array(""));
|
227 |
+
|
228 |
+
return;
|
229 |
+
}
|
230 |
+
|
231 |
+
/*
|
232 |
+
* Send some special headers after the connection is initialized
|
233 |
+
*
|
234 |
+
* name: headers
|
235 |
+
* @param
|
236 |
+
*/
|
237 |
+
private function headers()
|
238 |
+
{
|
239 |
+
$this->logger->debug(__("Setting mysql headers"));
|
240 |
+
|
241 |
+
$this->query("SET SQL_QUOTE_SHOW_CREATE=1;");
|
242 |
+
//$this->log();
|
243 |
+
$this->query("SET sql_mode = 0;");
|
244 |
+
//$this->log();
|
245 |
+
|
246 |
+
$this->set_charset($this->dbh, 'utf8');
|
247 |
+
//$this->log();
|
248 |
+
}
|
249 |
+
|
250 |
+
public function get_database_num_tables($database)
|
251 |
+
{
|
252 |
+
$this->logger->debug(sprintf(__("Getting number of tables in %s"), $database));
|
253 |
+
|
254 |
+
$query = "show tables in `".$database."`";
|
255 |
+
|
256 |
+
$res = $this->get_results($query);
|
257 |
+
$this->log();
|
258 |
+
|
259 |
+
return count($res);
|
260 |
+
}
|
261 |
+
|
262 |
+
public function get_all_databases()
|
263 |
+
{
|
264 |
+
$this->logger->debug(("Getting all databases"));
|
265 |
+
|
266 |
+
$query = "SHOW DATABASES;";
|
267 |
+
|
268 |
+
$databases = $this->get_results($query);
|
269 |
+
$this->log();
|
270 |
+
|
271 |
+
$databases_list = array();
|
272 |
+
|
273 |
+
$i = 0;
|
274 |
+
|
275 |
+
$databases_list[$i]['name'] = $this->dbname;
|
276 |
+
$databases_list[$i]['num_tables'] = $this->get_database_num_tables($this->dbname);
|
277 |
+
$i++;
|
278 |
+
|
279 |
+
if (is_array($databases)) {
|
280 |
+
foreach ($databases as $db) {
|
281 |
+
if ($db->Database != $this->dbname) {
|
282 |
+
$databases_list[$i]['name'] = $db->Database;
|
283 |
+
$databases_list[$i]['num_tables'] = $this->get_database_num_tables($db->Database);
|
284 |
+
$i++;
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
return $databases_list;
|
290 |
+
}
|
291 |
+
|
292 |
+
/*
|
293 |
+
* Returns an array of tables from a database and mark $excluded ones
|
294 |
+
*
|
295 |
+
* name: list_tables
|
296 |
+
* @param string $database
|
297 |
+
* @param array $included
|
298 |
+
* @param int $get_num_records
|
299 |
+
* @return array $tablesList
|
300 |
+
*/
|
301 |
+
public function list_tables($database = "", $included = array(), $get_num_records = 0)
|
302 |
+
{
|
303 |
+
$tablesList[0] = array( );
|
304 |
+
$inc = 0;
|
305 |
+
|
306 |
+
if (!$database) {
|
307 |
+
$database = $this->dbname;
|
308 |
+
}
|
309 |
+
|
310 |
+
$this->logger->debug(sprintf(("Listing tables in %s database"), $database));
|
311 |
+
|
312 |
+
$tables = $this->get_results("SHOW TABLES in `".$database."`");
|
313 |
+
$this->log();
|
314 |
+
|
315 |
+
foreach ($tables as $table) {
|
316 |
+
$table = array_values((array)$table)[0];
|
317 |
+
|
318 |
+
$tablesList[$inc]['name'] = $table;
|
319 |
+
$tablesList[$inc]['database'] = $database;
|
320 |
+
|
321 |
+
if ($get_num_records) {
|
322 |
+
$records_num_result = $this->get_var("SELECT count(*) FROM `".$database."`.`".$table."`");
|
323 |
+
$this->log();
|
324 |
+
|
325 |
+
$tablesList[$inc]['records'] = $records_num_result;
|
326 |
+
}
|
327 |
+
|
328 |
+
$tablesList[$inc]['excluded'] = 0;
|
329 |
+
|
330 |
if (sizeof($included) and is_array($included)) {
|
331 |
$dbTable = $database.".".$table;
|
332 |
if (!in_array($table, $included) and !in_array($dbTable, $included)) {
|
333 |
$tablesList[$inc]['excluded'] = 1;
|
334 |
$this->log(sprintf(__("Excluding table %s.%s from backup"), $table, $database));
|
335 |
}
|
336 |
+
}
|
337 |
+
|
338 |
+
$inc++;
|
339 |
+
}
|
340 |
+
|
341 |
+
return $tablesList;
|
342 |
+
}
|
343 |
+
|
344 |
+
public function write_backup_process_list($dbname, $incl_tables)
|
345 |
+
{
|
346 |
+
$return['total_records'] = 0;
|
347 |
+
$return['tables_count'] = 0;
|
348 |
+
|
349 |
+
$this->log(__("Preparing the database recursion file"));
|
350 |
+
|
351 |
+
$tables = $this->list_tables($dbname, $incl_tables, 1);
|
352 |
+
|
353 |
+
if ($this->dbname != $dbname) {
|
354 |
+
$dumpfile = $dbname."-backup.sql";
|
355 |
+
} else {
|
356 |
+
$dumpfile = $this->TEMP_DUMP_FILE;
|
357 |
+
}
|
358 |
+
|
359 |
+
$line = sprintf("###newdump###\t%s\t%s\n", $dbname, $dumpfile);
|
360 |
+
$this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
|
361 |
+
|
362 |
+
// write this to the class and write to $TEMP_DBPROCESS_FILE file as database.table records
|
363 |
+
foreach ($tables as $key=>$table) {
|
364 |
+
if ($table != "" and !$tables[$key]['excluded']) {
|
365 |
+
$line = sprintf("`%s`.`%s`\t%s\t%s\n", $dbname, $tables[$key]['name'], $tables[$key]['records'], $tables[$key]['excluded']);
|
366 |
+
$this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
|
367 |
+
$return['tables_count']++;
|
368 |
+
$return['total_records'] += $tables[$key]['records'];
|
369 |
+
}
|
370 |
+
}
|
371 |
+
|
372 |
+
$line = sprintf("###enddump###\t%s\t%s\n", $dbname, $dumpfile);
|
373 |
+
$this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
|
374 |
+
|
375 |
+
return $return;
|
376 |
+
}
|
377 |
+
|
378 |
+
/*
|
379 |
+
* Returns the number of records from a table
|
380 |
+
*
|
381 |
+
* name: countRecords
|
382 |
+
* @param string $table - the source table
|
383 |
+
* @return int $count
|
384 |
+
*/
|
385 |
+
public function countRecords($table)
|
386 |
+
{
|
387 |
+
$table = "`".$this->dbname."`.`$table`";
|
388 |
+
|
389 |
+
$result = $this->get_var("SELECT count(*) FROM $table;");
|
390 |
+
|
391 |
+
return intval($result) ;// not max limit on 32 bit systems 2147483647; on 64 bit 9223372036854775807
|
392 |
+
}
|
393 |
+
|
394 |
+
/*
|
395 |
+
* Processing the mysql backup incrementally
|
396 |
+
*
|
397 |
+
* name: processIncremental
|
398 |
+
* @param
|
399 |
+
* int $startAtLine - at which line from the perm.txt file to start reading
|
400 |
+
* int startAtRecord - at which record to start from the table found at $startAtLine
|
401 |
+
* string $dumpfie - where to save the data
|
402 |
+
* string $dbCompatibility - MYSQL40, MYSQ32, none=default
|
403 |
+
* int $dbDropSyntax - check if the DROP TABLE syntax should be added
|
404 |
+
* @return array $return
|
405 |
+
*/
|
406 |
+
public function process_incremental($startAtLine = 0, $startAtRecord = 0, $dumpfile = "", $dbCompatibility = "")
|
407 |
+
{
|
408 |
+
$count = 0;
|
409 |
+
$return['finished'] = 0;
|
410 |
+
$lines = array();
|
411 |
+
|
412 |
+
if ($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)) {
|
413 |
+
$lines = array_filter(explode("\n", $this->fs->get_tmp_filesystem()->read($this->TEMP_DBPROCESS_FILE)));
|
414 |
+
}
|
415 |
+
|
416 |
+
foreach ($lines as $buffer) {
|
417 |
+
if ($count == $startAtLine) {
|
418 |
+
$tableInfo = explode("\t", $buffer);
|
419 |
+
|
420 |
+
if ($tableInfo[0] == "###newdump###") {
|
421 |
+
// we create a new mysql dump file
|
422 |
+
if ($dumpfile != "") {
|
423 |
+
// we finished a previous one and write the footers
|
424 |
+
$return['dumpsize'] = $this->data_footers($dumpfile);
|
425 |
+
}
|
426 |
+
|
427 |
+
$dumpfile = $tableInfo[2];
|
428 |
+
|
429 |
+
$this->log(sprintf(__("Starting new backup dump to file %s"), $dumpfile));
|
430 |
+
|
431 |
+
$this->data_headers($dumpfile, $tableInfo[1]);
|
432 |
+
$dumpfile = $tableInfo[2];
|
433 |
+
$startAtLine++;
|
434 |
+
$return['new_dump'] = 1;
|
435 |
+
//break;
|
436 |
+
} else {
|
437 |
+
//we export the table
|
438 |
+
if ($tableInfo[0] == "###enddump###") {
|
439 |
+
$return['endDump'] = 1;
|
440 |
+
}
|
441 |
+
|
442 |
+
//table is excluded
|
443 |
+
if ($tableInfo[2]) {
|
444 |
+
continue;
|
445 |
+
}
|
446 |
+
|
447 |
+
$next = $startAtRecord + $this->recordsPerSession;
|
448 |
+
|
449 |
+
// $tableInfo[1] number of records in the table
|
450 |
+
$table = explode("`.`", $tableInfo[0]);
|
451 |
+
$tableName = str_replace("`", "", $table[1]);
|
452 |
+
$databaseName = str_replace("`", "", $table[0]);
|
453 |
+
|
454 |
+
//return something to the browser
|
455 |
+
$return['databaseName'] = $databaseName;
|
456 |
+
$return['tableName'] = $tableName;
|
457 |
+
$return['totalRecords'] = $tableInfo[1];
|
458 |
+
|
459 |
+
$processed_records = 0;
|
460 |
+
|
461 |
+
if (trim($tableName) != "" and !$tableInfo[2]) {
|
462 |
+
$processed_records = $this->export_table($databaseName, $tableName, $startAtRecord, $this->recordsPerSession, $dumpfile);
|
463 |
+
}
|
464 |
+
|
465 |
+
$return['processedRecords'] = $startAtRecord + $processed_records;
|
466 |
+
|
467 |
+
if ($next >= $tableInfo[1]) { //we finished loading the records for next sessions, will go to the new record
|
468 |
+
$startAtLine++;
|
469 |
+
$startAtRecord = 0;
|
470 |
+
} else {
|
471 |
+
$startAtRecord = $startAtRecord + $this->recordsPerSession;
|
472 |
+
}
|
473 |
+
|
474 |
+
//$return['dbCompatibility'] = self::$dbCompatibility;
|
475 |
+
|
476 |
+
$return['startAtLine'] = $startAtLine;
|
477 |
+
$return['startAtRecord'] = $startAtRecord;
|
478 |
+
$return['dumpfile'] = $dumpfile;
|
479 |
+
$return['dumpsize'] = $this->fs->get_tmp_filesystem_append()->getSize($dumpfile);
|
480 |
+
|
481 |
+
return $return;
|
482 |
+
break;
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
$count++;
|
487 |
+
}
|
488 |
+
|
489 |
+
//while is finished, lets go home...
|
490 |
+
if ($dumpfile != "") {
|
491 |
+
// we finished a previous one and write the footers
|
492 |
+
$return['dumpsize'] = $this->data_footers($dumpfile);
|
493 |
+
$return['dumpfile'] = ($dumpfile);
|
494 |
+
}
|
495 |
+
$return['finished'] = 1;
|
496 |
+
$return['startAtLine'] = $startAtLine;
|
497 |
+
|
498 |
+
if ($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)) {
|
499 |
+
$this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
|
500 |
+
}
|
501 |
+
|
502 |
+
$this->logger->debug(sprintf(("Database backup finished!")));
|
503 |
+
|
504 |
+
return $return;
|
505 |
+
}
|
506 |
+
|
507 |
+
|
508 |
+
/*
|
509 |
+
* Exporting the table records
|
510 |
+
*
|
511 |
+
* name: exportTable
|
512 |
+
* @param
|
513 |
+
* string $databaseName - database name of the table
|
514 |
+
* string tableName - table name
|
515 |
+
* int $start - where to start from
|
516 |
+
* int $limit - how many records
|
517 |
+
* handler $fd - file handler where to write the records
|
518 |
+
* @return
|
519 |
+
*/
|
520 |
+
|
521 |
+
/**
|
522 |
+
* @param integer $start
|
523 |
+
* @param integer $limit
|
524 |
+
*/
|
525 |
+
public function export_table($databaseName, $tableName, $start, $limit, $dumpfile)
|
526 |
+
{
|
527 |
+
$this->logger->debug(sprintf(("Exporting table %s.%s data"), $databaseName, $tableName));
|
528 |
+
|
529 |
+
$records = 0;
|
530 |
+
|
531 |
+
if ($start == 0) {
|
532 |
+
$this->dump_structure($databaseName, $tableName, $dumpfile);
|
533 |
+
}
|
534 |
+
|
535 |
+
$start = intval($start);
|
536 |
+
$limit = intval($limit);
|
537 |
+
//exporting the table content now
|
538 |
+
|
539 |
+
$query = "SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;";
|
540 |
+
if ($this->use_mysqli) {
|
541 |
+
$result = mysqli_query($this->dbh, $query);
|
542 |
+
$mysql_fetch_function = "mysqli_fetch_array";
|
543 |
+
} else {
|
544 |
+
$result = mysql_query($query, $this->dbh);
|
545 |
+
$mysql_fetch_function = "mysqli_fetch_array";
|
546 |
+
}
|
547 |
+
//$result = $this->get_results($query, ARRAY_N);
|
548 |
+
//print_r($result); exit;
|
549 |
+
|
550 |
+
if ($result) {
|
551 |
+
while ($row = $mysql_fetch_function($result, MYSQLI_ASSOC)) {
|
552 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, "INSERT INTO `$tableName` VALUES (");
|
553 |
+
$arr = $row;
|
554 |
+
$buffer = "";
|
555 |
+
$this->countRecords++;
|
556 |
+
|
557 |
+
foreach ($arr as $key => $value) {
|
558 |
+
if (!is_null($value)) {
|
559 |
+
$value = $this->_real_escape($value);
|
560 |
+
|
561 |
+
if (method_exists($this, 'remove_placeholder_escape')) {
|
562 |
+
$value = $this->remove_placeholder_escape($value);
|
563 |
+
}
|
564 |
+
$buffer .= "'" . $value . "', ";
|
565 |
+
} else {
|
566 |
+
$buffer .= "null, ";
|
567 |
+
}
|
568 |
+
}
|
569 |
+
$buffer = rtrim($buffer, ', ').");\n";
|
570 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, $buffer);
|
571 |
+
unset($buffer);
|
572 |
+
|
573 |
+
$records++;
|
574 |
+
}
|
575 |
+
}
|
576 |
+
|
577 |
+
$this->log(sprintf(__("Dumping %s records starting position %s from %s.%s table"), $records, $start, $databaseName, $tableName));
|
578 |
+
|
579 |
+
return $records;
|
580 |
+
}
|
581 |
+
|
582 |
+
public function dump_structure($databaseName, $tableName, $dumpfile)
|
583 |
+
{
|
584 |
+
$this->log(sprintf(__("Dumping the structure for %s.%s table"), $databaseName, $tableName));
|
585 |
+
|
586 |
+
$line = ("\n#\n# Table structure for table `$tableName`\n#\n\n");
|
587 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
|
588 |
+
|
589 |
+
if ($this->dbDropSyntax) {
|
590 |
+
$line = ("\nDROP table IF EXISTS `$tableName`;\n");
|
591 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
|
592 |
+
}
|
593 |
+
|
594 |
+
//$result = mysqli_query($this->dbh,"SHOW CREATE table `$databaseName`.`$tableName`;");
|
595 |
+
$result = $this->get_row("SHOW CREATE table `$databaseName`.`$tableName`;", ARRAY_N);
|
596 |
+
if ($result) {
|
597 |
+
//$row = mysqli_fetch_row( $result);
|
598 |
+
$line = ($result[1].";\n");
|
599 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
|
600 |
+
}
|
601 |
+
|
602 |
+
$line = ("\n#\n# End Structure for table `$tableName`\n#\n\n");
|
603 |
+
$line .= ("#\n# Dumping data for table `$tableName`\n#\n\n");
|
604 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
|
605 |
+
|
606 |
+
return;
|
607 |
+
}
|
608 |
+
|
609 |
+
public function data_footers($dumpfile)
|
610 |
+
{
|
611 |
+
$this->logger->debug(sprintf(("Writing dump footers in file"), $dumpfile));
|
612 |
+
// we finished the dump file, not return the size of it
|
613 |
+
$this->fs->get_tmp_filesystem_append()->write($dumpfile, "\n#\n# Finished at: ".date("M j, Y \a\\t H:i")."\n#");
|
614 |
+
$size = $this->fs->get_tmp_filesystem_append()->getSize($dumpfile);
|
615 |
+
|
616 |
+
$metadata_dumpfile = $this->fs->get_tmp_filesystem()->getMetadata($dumpfile);
|
617 |
+
|
618 |
+
//adding dump file to the included files list
|
619 |
+
$this->fs->store_file($metadata_dumpfile, 'tmp_filesystem');
|
620 |
+
|
621 |
+
return $size;
|
622 |
+
}
|
623 |
+
|
624 |
+
public function resetcountRecords()
|
625 |
+
{
|
626 |
+
$this->countRecords = 0;
|
627 |
+
|
628 |
+
return $this->countRecords;
|
629 |
+
}
|
630 |
+
|
631 |
+
public function getcountRecords()
|
632 |
+
{
|
633 |
+
return $this->countRecords;
|
634 |
+
}
|
635 |
+
|
636 |
+
|
637 |
+
public function data_headers($file, $database)
|
638 |
+
{
|
639 |
+
$this->logger->debug(sprintf(("Writing dump header for %s database in file"), $database, $file));
|
640 |
+
|
641 |
+
$return = "";
|
642 |
+
|
643 |
+
$return .= "#\n";
|
644 |
+
$return .= "# Powered by XCloner Site Backup\n";
|
645 |
+
$return .= "# http://www.xcloner.com\n";
|
646 |
+
$return .= "#\n";
|
647 |
+
$return .= "# Host: ".get_site_url()."\n";
|
648 |
+
$return .= "# Generation Time: ".date("M j, Y \a\\t H:i")."\n";
|
649 |
+
$return .= "# PHP Version: ".phpversion()."\n";
|
650 |
+
$return .= "# Database Charset: ".$this->charset."\n";
|
651 |
+
|
652 |
+
$results = $this->get_results("SHOW VARIABLES LIKE \"%version%\";", ARRAY_N);
|
653 |
+
if (isset($results)) {
|
654 |
+
foreach ($results as $result) {
|
655 |
+
$return .= "# MYSQL ".$result[0].": ".$result[1]."\n";
|
656 |
+
}
|
657 |
+
}
|
658 |
+
|
659 |
+
$results = $this->get_results("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
660 |
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '".$database."';");
|
661 |
+
|
662 |
+
if (isset($results[0])) {
|
663 |
+
$return .= "# MYSQL DEFAULT_CHARACTER_SET_NAME: ".$results[0]->DEFAULT_CHARACTER_SET_NAME."\n";
|
664 |
+
$return .= "# MYSQL SCHEMA_NAME: ".$results[0]->DEFAULT_COLLATION_NAME."\n";
|
665 |
+
}
|
666 |
+
|
667 |
+
$return .= "#\n# Database : `".$database."`\n# --------------------------------------------------------\n\n";
|
668 |
+
|
669 |
+
$this->log(sprintf(__("Writing %s database dump headers"), $database));
|
670 |
+
|
671 |
+
$return = $this->fs->get_tmp_filesystem()->write($file, $return);
|
672 |
+
return $return['size'];
|
673 |
+
}
|
|
|
|
|
|
|
|
|
674 |
}
|
includes/class-xcloner-deactivator.php
CHANGED
@@ -35,7 +35,7 @@
|
|
35 |
* @package Xcloner
|
36 |
* @subpackage Xcloner/includes
|
37 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
38 |
-
* @link
|
39 |
*/
|
40 |
|
41 |
class Xcloner_Deactivator {
|
35 |
* @package Xcloner
|
36 |
* @subpackage Xcloner/includes
|
37 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
38 |
+
* @link https://watchful.net
|
39 |
*/
|
40 |
|
41 |
class Xcloner_Deactivator {
|
includes/class-xcloner-encryption.php
CHANGED
@@ -8,390 +8,388 @@
|
|
8 |
|
9 |
//namespace XCloner;
|
10 |
|
|
|
|
|
|
|
11 |
class Xcloner_Encryption
|
12 |
{
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
* @return array|false Returns array or FALSE if an error occured
|
109 |
* @throws Exception
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
//$key = substr(sha1($key, true), 0, 16);
|
118 |
-
if (!$key) {
|
119 |
-
$key = $this->get_backup_encryption_key();
|
120 |
-
}
|
121 |
-
$key_digest = openssl_digest($key, "md5", true);
|
122 |
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
|
|
133 |
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
}
|
139 |
|
140 |
-
|
|
|
|
|
|
|
|
|
141 |
|
142 |
-
|
143 |
-
if (!$start) {
|
144 |
-
fwrite($fpOut, $iv);
|
145 |
-
}
|
146 |
|
147 |
-
|
148 |
-
|
|
|
|
|
149 |
|
150 |
-
|
|
|
|
|
151 |
|
152 |
-
|
|
|
|
|
153 |
|
154 |
-
|
155 |
-
|
|
|
156 |
|
157 |
-
|
158 |
-
$iv = substr($ciphertext, 0, 16);
|
159 |
-
//$iv = openssl_random_pseudo_bytes(16);
|
160 |
|
161 |
-
|
162 |
|
163 |
-
|
164 |
-
|
165 |
-
fclose($fpOut);
|
166 |
|
167 |
unset($ciphertext);
|
168 |
unset($plaintext);
|
169 |
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
* @throws Exception
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
return array("target_file" => $dest, "finished" => 1);
|
362 |
}
|
363 |
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
return null;
|
370 |
-
}
|
371 |
|
|
|
|
|
372 |
}
|
373 |
|
374 |
|
375 |
try {
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
echo "CAUGHT: ".$e->getMessage();
|
397 |
}
|
8 |
|
9 |
//namespace XCloner;
|
10 |
|
11 |
+
/**
|
12 |
+
* Xcloner_Encryption class
|
13 |
+
*/
|
14 |
class Xcloner_Encryption
|
15 |
{
|
16 |
+
const FILE_ENCRYPTION_BLOCKS = 1024 * 1024;
|
17 |
+
const FILE_ENCRYPTION_SUFFIX = ".encrypted";
|
18 |
+
const FILE_DECRYPTION_SUFFIX = ".decrypted";
|
19 |
+
|
20 |
+
private $xcloner_settings;
|
21 |
+
private $logger;
|
22 |
+
private $xcloner_container;
|
23 |
+
private $verification = false;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Xcloner_Encryption constructor.
|
27 |
+
* @param Xcloner $xcloner_container
|
28 |
+
*/
|
29 |
+
public function __construct(Xcloner $xcloner_container)
|
30 |
+
{
|
31 |
+
$this->xcloner_container = $xcloner_container;
|
32 |
+
if (property_exists($xcloner_container, 'xcloner_settings')) {
|
33 |
+
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
34 |
+
} else {
|
35 |
+
$this->xcloner_settings = "";
|
36 |
+
}
|
37 |
+
|
38 |
+
if (property_exists($xcloner_container, 'xcloner_logger')) {
|
39 |
+
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_encryption");
|
40 |
+
} else {
|
41 |
+
$this->logger = "";
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Returns the backup encryption key
|
47 |
+
*
|
48 |
+
* @return string|null
|
49 |
+
*/
|
50 |
+
public function get_backup_encryption_key()
|
51 |
+
{
|
52 |
+
if (is_object($this->xcloner_settings)) {
|
53 |
+
return $this->xcloner_settings->get_xcloner_encryption_key();
|
54 |
+
}
|
55 |
+
|
56 |
+
return null;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Check if provided filename has encrypted suffix
|
61 |
+
*
|
62 |
+
* @param $filename
|
63 |
+
* @return bool
|
64 |
+
*/
|
65 |
+
public function is_encrypted_file($filename)
|
66 |
+
{
|
67 |
+
$fp = fopen($this->get_xcloner_path().$filename, 'r');
|
68 |
+
if (is_resource($fp)) {
|
69 |
+
$encryption_length = fread($fp, 16);
|
70 |
+
fclose($fp);
|
71 |
+
if (is_numeric($encryption_length)) {
|
72 |
+
return true;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
return false;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Returns the filename with encrypted suffix
|
81 |
+
*
|
82 |
+
* @param string $filename
|
83 |
+
* @return string
|
84 |
+
*/
|
85 |
+
public function get_encrypted_target_backup_file_name($filename)
|
86 |
+
{
|
87 |
+
return str_replace(self::FILE_DECRYPTION_SUFFIX, "", $filename).self::FILE_ENCRYPTION_SUFFIX;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Returns the filename without encrypted suffix
|
92 |
+
*
|
93 |
+
* @param string $filename
|
94 |
+
* @return string
|
95 |
+
*/
|
96 |
+
public function get_decrypted_target_backup_file_name($filename)
|
97 |
+
{
|
98 |
+
return str_replace(self::FILE_ENCRYPTION_SUFFIX, "", $filename).self::FILE_DECRYPTION_SUFFIX;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Encrypt the passed file and saves the result in a new file with ".enc" as suffix.
|
103 |
+
*
|
104 |
+
* @param string $source Path to file that should be encrypted
|
105 |
+
* @param string $dest File name where the encryped file should be written to.
|
106 |
+
* @param string $key The key used for the encryption
|
107 |
+
* @param int $start Start position for reading when doing incremental mode.
|
108 |
+
* @param string $iv The IV key to use.
|
109 |
+
* @param bool $verification Weather we should we try to verify the decryption.
|
110 |
+
* @return array|false Returns array or FALSE if an error occured
|
|
|
111 |
* @throws Exception
|
112 |
+
*/
|
113 |
+
public function encrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $verification = true, $recursive = false)
|
114 |
+
{
|
115 |
+
if (is_object($this->logger)) {
|
116 |
+
$this->logger->info(sprintf('Encrypting file %s at position %d IV %s', $source, $start, base64_encode($iv)));
|
117 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
|
119 |
+
//$key = substr(sha1($key, true), 0, 16);
|
120 |
+
if (!$key) {
|
121 |
+
$key = $this->get_backup_encryption_key();
|
122 |
+
}
|
123 |
+
$key_digest = openssl_digest($key, "md5", true);
|
124 |
|
125 |
+
$keep_local = 1;
|
126 |
+
if (!$dest) {
|
127 |
+
$dest = $this->get_encrypted_target_backup_file_name($source);
|
128 |
+
$keep_local = 0;
|
129 |
+
}
|
130 |
|
131 |
+
if (!$iv || !$start) {
|
132 |
+
//$iv = openssl_random_pseudo_bytes(16);
|
133 |
+
$iv = str_pad(self::FILE_ENCRYPTION_BLOCKS, 16, "0000000000000000", STR_PAD_LEFT);
|
134 |
+
}
|
|
|
135 |
|
136 |
+
if (!$start) {
|
137 |
+
$fpOut = fopen($this->get_xcloner_path().$dest, 'w');
|
138 |
+
} else {
|
139 |
+
$fpOut = fopen($this->get_xcloner_path().$dest, 'a');
|
140 |
+
}
|
141 |
|
142 |
+
if (is_resource($fpOut)) {
|
|
|
|
|
|
|
143 |
|
144 |
+
// Put the initialization vector to the beginning of the file
|
145 |
+
if (!$start) {
|
146 |
+
fwrite($fpOut, $iv);
|
147 |
+
}
|
148 |
|
149 |
+
if (file_exists($this->get_xcloner_path().$source) &&
|
150 |
+
$fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
|
151 |
+
fseek($fpIn, (int)$start);
|
152 |
|
153 |
+
if (!feof($fpIn)) {
|
154 |
+
$plaintext = fread($fpIn, 16 * self::FILE_ENCRYPTION_BLOCKS);
|
155 |
+
$ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
|
156 |
|
157 |
+
// Use the first 16 bytes of the ciphertext as the next initialization vector
|
158 |
+
$iv = substr($ciphertext, 0, 16);
|
159 |
+
//$iv = openssl_random_pseudo_bytes(16);
|
160 |
|
161 |
+
fwrite($fpOut, $ciphertext);
|
|
|
|
|
162 |
|
163 |
+
$start = ftell($fpIn);
|
164 |
|
165 |
+
fclose($fpOut);
|
|
|
|
|
166 |
|
167 |
unset($ciphertext);
|
168 |
unset($plaintext);
|
169 |
|
170 |
+
if (!feof($fpIn)) {
|
171 |
+
fclose($fpIn);
|
172 |
+
//echo "\n NEW:".$key.md5($iv);
|
173 |
+
//self::encryptFile($source, $dest, $key, $start, $iv);
|
174 |
+
if ($recursive) {
|
175 |
+
$this->encrypt_file($source, $dest, $key, $start, ($iv), $verification, $recursive);
|
176 |
+
} else {
|
177 |
+
if (($iv) != base64_decode(base64_encode($iv))) {
|
178 |
+
throw new \Exception('Could not encode IV for transport');
|
179 |
+
}
|
180 |
+
|
181 |
+
return array(
|
182 |
+
"start" => $start,
|
183 |
+
"iv" => base64_encode($iv),
|
184 |
+
"target_file" => $dest,
|
185 |
+
"finished" => 0
|
186 |
+
);
|
187 |
+
}
|
188 |
+
}
|
189 |
+
}
|
190 |
+
} else {
|
191 |
+
if (is_object($this->logger)) {
|
192 |
+
$this->logger->error('Unable to read source file for encryption.');
|
193 |
+
}
|
194 |
+
throw new \Exception("Unable to read source file for encryption.");
|
195 |
+
}
|
196 |
+
} else {
|
197 |
+
if (is_object($this->logger)) {
|
198 |
+
$this->logger->error('Unable to write destination file for encryption.');
|
199 |
+
}
|
200 |
+
throw new \Exception("Unable to write destination file for encryption.");
|
201 |
+
}
|
202 |
+
|
203 |
+
if ($verification) {
|
204 |
+
$this->verify_encrypted_file($dest);
|
205 |
+
}
|
206 |
+
|
207 |
+
//we replace the original backup with the encrypted one
|
208 |
+
if (!$keep_local && copy(
|
209 |
+
$this->get_xcloner_path().$dest,
|
210 |
+
$this->get_xcloner_path().$source
|
211 |
+
)) {
|
212 |
+
unlink($this->get_xcloner_path().$dest);
|
213 |
+
}
|
214 |
+
|
215 |
+
|
216 |
+
return array("target_file" => $dest, "finished" => 1);
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* @param string $file
|
221 |
+
*/
|
222 |
+
public function verify_encrypted_file($file)
|
223 |
+
{
|
224 |
+
if (is_object($this->logger)) {
|
225 |
+
$this->logger->info(sprintf('Verifying encrypted file %s', $file));
|
226 |
+
}
|
227 |
+
|
228 |
+
$this->verification = true;
|
229 |
+
$this->decrypt_file($file);
|
230 |
+
$this->verification = false;
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Dencrypt the passed file and saves the result in a new file, removing the
|
235 |
+
* last 4 characters from file name.
|
236 |
+
*
|
237 |
+
* @param string $source Path to file that should be decrypted
|
238 |
+
* @param string $dest File name where the decryped file should be written to.
|
239 |
+
* @param string $key The key used for the decryption (must be the same as for encryption)
|
240 |
+
* @param int $start Start position for reading when doing incremental mode.
|
241 |
+
* @param string $iv The IV key to use.
|
242 |
+
* @return array|false Returns array or FALSE if an error occured
|
243 |
* @throws Exception
|
244 |
+
*/
|
245 |
+
public function decrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $recursive = false)
|
246 |
+
{
|
247 |
+
if (is_object($this->logger)) {
|
248 |
+
$this->logger->info(sprintf('Decrypting file %s at position %d with IV %s', $source, $start, base64_encode($iv)));
|
249 |
+
}
|
250 |
+
|
251 |
+
//$key = substr(sha1($key, true), 0, 16);
|
252 |
+
if (!$key) {
|
253 |
+
$key = $this->get_backup_encryption_key();
|
254 |
+
}
|
255 |
+
|
256 |
+
$key_digest = openssl_digest($key, "md5", true);
|
257 |
+
|
258 |
+
$keep_local = 1;
|
259 |
+
if (!$dest) {
|
260 |
+
$dest = $this->get_decrypted_target_backup_file_name($source);
|
261 |
+
$keep_local = 0;
|
262 |
+
}
|
263 |
+
|
264 |
+
if (!$start) {
|
265 |
+
if ($this->verification) {
|
266 |
+
$fpOut = fopen("php://stdout", 'w');
|
267 |
+
} else {
|
268 |
+
$fpOut = fopen($this->get_xcloner_path().$dest, 'w');
|
269 |
+
}
|
270 |
+
} else {
|
271 |
+
if ($this->verification) {
|
272 |
+
$fpOut = fopen("php://stdout", 'a');
|
273 |
+
} else {
|
274 |
+
$fpOut = fopen($this->get_xcloner_path().$dest, 'a');
|
275 |
+
}
|
276 |
+
}
|
277 |
+
|
278 |
+
if (is_resource($fpOut)) {
|
279 |
+
if (file_exists($this->get_xcloner_path().$source) &&
|
280 |
+
$fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
|
281 |
+
$encryption_length = (int)fread($fpIn, 16);
|
282 |
+
if (!$encryption_length) {
|
283 |
+
$encryption_length = self::FILE_ENCRYPTION_BLOCKS;
|
284 |
+
}
|
285 |
+
|
286 |
+
fseek($fpIn, (int)$start);
|
287 |
+
|
288 |
+
// Get the initialzation vector from the beginning of the file
|
289 |
+
if (!$iv) {
|
290 |
+
$iv = fread($fpIn, 16);
|
291 |
+
}
|
292 |
+
|
293 |
+
if (!feof($fpIn)) {
|
294 |
+
|
295 |
+
// we have to read one block more for decrypting than for encrypting
|
296 |
+
$ciphertext = fread($fpIn, 16 * ($encryption_length + 1));
|
297 |
+
$plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
|
298 |
+
|
299 |
+
if (!$plaintext) {
|
300 |
+
unlink($this->get_xcloner_path().$dest);
|
301 |
+
if (is_object($this->logger)) {
|
302 |
+
$this->logger->error('Backup decryption failed, please check your provided Encryption Key.');
|
303 |
+
}
|
304 |
+
throw new \Exception("Backup decryption failed, please check your provided Encryption Key.");
|
305 |
+
}
|
306 |
+
|
307 |
+
// Use the first 16 bytes of the ciphertext as the next initialization vector
|
308 |
+
$iv = substr($ciphertext, 0, 16);
|
309 |
+
|
310 |
+
if (!$this->verification) {
|
311 |
+
fwrite($fpOut, $plaintext);
|
312 |
+
}
|
313 |
+
|
314 |
+
$start = ftell($fpIn);
|
315 |
+
|
316 |
+
fclose($fpOut);
|
317 |
+
|
318 |
+
if (!feof($fpIn)) {
|
319 |
+
fclose($fpIn);
|
320 |
+
if ($this->verification || $recursive) {
|
321 |
+
unset($ciphertext);
|
322 |
+
unset($plaintext);
|
323 |
+
$this->decrypt_file($source, $dest, $key, $start, $iv, $recursive);
|
324 |
+
} else {
|
325 |
+
if (($iv) != base64_decode(base64_encode($iv))) {
|
326 |
+
throw new \Exception('Could not encode IV for transport');
|
327 |
+
}
|
328 |
+
|
329 |
+
return array(
|
330 |
+
"start" => $start,
|
331 |
+
"encryption_length" => $encryption_length,
|
332 |
+
"iv" => base64_encode($iv),
|
333 |
+
"target_file" => $dest,
|
334 |
+
"finished" => 0
|
335 |
+
);
|
336 |
+
}
|
337 |
+
}
|
338 |
+
}
|
339 |
+
} else {
|
340 |
+
if (is_object($this->logger)) {
|
341 |
+
$this->logger->error('Unable to read source file for decryption');
|
342 |
+
}
|
343 |
+
throw new \Exception("Unable to read source file for decryption");
|
344 |
+
}
|
345 |
+
} else {
|
346 |
+
if (is_object($this->logger)) {
|
347 |
+
$this->logger->error('Unable to write destination file for decryption');
|
348 |
+
}
|
349 |
+
throw new \Exception("Unable to write destination file for decryption");
|
350 |
+
}
|
351 |
+
|
352 |
+
//we replace the original backup with the encrypted one
|
353 |
+
if (!$keep_local && !$this->verification && copy(
|
354 |
+
$this->get_xcloner_path().$dest,
|
355 |
+
$this->get_xcloner_path().$source
|
356 |
+
)) {
|
357 |
+
unlink($this->get_xcloner_path().$dest);
|
358 |
+
}
|
359 |
+
|
360 |
+
return array("target_file" => $dest, "finished" => 1);
|
|
|
361 |
}
|
362 |
|
363 |
+
public function get_xcloner_path()
|
364 |
+
{
|
365 |
+
if (is_object($this->xcloner_settings)) {
|
366 |
+
return $this->xcloner_settings->get_xcloner_store_path().DS;
|
367 |
+
}
|
|
|
|
|
368 |
|
369 |
+
return null;
|
370 |
+
}
|
371 |
}
|
372 |
|
373 |
|
374 |
try {
|
375 |
+
if (isset($argv[1])) {
|
376 |
+
class Xcloner
|
377 |
+
{
|
378 |
+
/**
|
379 |
+
* Xcloner constructor.
|
380 |
+
*/
|
381 |
+
public function __construct()
|
382 |
+
{
|
383 |
+
}
|
384 |
+
}
|
385 |
+
$xcloner_encryption = new Xcloner_Encryption(new Xcloner());
|
386 |
+
|
387 |
+
if ($argv[1] == "-e") {
|
388 |
+
$xcloner_encryption->encrypt_file($argv[2], $argv[2].".enc", $argv[4], 0, 0, false, true);
|
389 |
+
} elseif ($argv[1] == "-d") {
|
390 |
+
$xcloner_encryption->decrypt_file($argv[2], $argv[2].".dec", $argv[4], 0, 0, true);
|
391 |
+
}
|
392 |
+
}
|
393 |
+
} catch (\Exception $e) {
|
394 |
+
echo "CAUGHT: ".$e->getMessage();
|
|
|
395 |
}
|
includes/class-xcloner-file-system.php
CHANGED
@@ -36,7 +36,6 @@ use League\Flysystem\Adapter\Local;
|
|
36 |
*/
|
37 |
class Xcloner_File_System
|
38 |
{
|
39 |
-
|
40 |
private $excluded_files = "";
|
41 |
private $additional_regex_patterns = array();
|
42 |
private $excluded_files_by_default = array("administrator/backups", "wp-content/backups");
|
@@ -77,7 +76,6 @@ class Xcloner_File_System
|
|
77 |
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
78 |
|
79 |
try {
|
80 |
-
|
81 |
$this->start_adapter = new Local($this->xcloner_settings->get_xcloner_start_path(), LOCK_EX, '0001');
|
82 |
$this->start_filesystem = new Filesystem($this->start_adapter, new Config([
|
83 |
'disable_asserts' => true,
|
@@ -97,20 +95,22 @@ class Xcloner_File_System
|
|
97 |
'disable_asserts' => true,
|
98 |
]));
|
99 |
|
100 |
-
$this->storage_adapter = new Local(
|
101 |
-
|
|
|
|
|
|
|
102 |
$this->storage_filesystem_append = new Filesystem($this->storage_adapter, new Config([
|
103 |
'disable_asserts' => true,
|
104 |
]));
|
105 |
-
}catch (Exception $e) {
|
106 |
$this->logger->error("Filesystem Initialization Error: ".$e->getMessage());
|
107 |
}
|
108 |
|
109 |
|
110 |
-
if ($value =
|
111 |
$this->folders_to_process_per_session = $value;
|
112 |
}
|
113 |
-
|
114 |
}
|
115 |
|
116 |
/**
|
@@ -225,7 +225,6 @@ class Xcloner_File_System
|
|
225 |
$spl_info = $this->getMetadataFull('tmp_adapter', $path);
|
226 |
|
227 |
return $spl_info;
|
228 |
-
|
229 |
}
|
230 |
|
231 |
public function get_temp_dir_handler()
|
@@ -392,11 +391,12 @@ class Xcloner_File_System
|
|
392 |
}
|
393 |
}
|
394 |
}
|
395 |
-
|
396 |
}
|
397 |
|
398 |
-
if ($file_info['type'] == 'file' and isset($file_info['extension']) and in_array(
|
399 |
-
|
|
|
|
|
400 |
$backup_files[$file_info['path']] = $file_info;
|
401 |
}
|
402 |
}
|
@@ -417,8 +417,10 @@ class Xcloner_File_System
|
|
417 |
public function start_file_recursion($init = 0)
|
418 |
{
|
419 |
if ($init) {
|
420 |
-
$this->logger->info(sprintf(
|
421 |
-
|
|
|
|
|
422 |
$this->do_system_init();
|
423 |
}
|
424 |
|
@@ -497,8 +499,10 @@ class Xcloner_File_System
|
|
497 |
public function remove_tmp_filesystem()
|
498 |
{
|
499 |
//delete the temporary folder
|
500 |
-
$this->logger->debug(sprintf(
|
501 |
-
|
|
|
|
|
502 |
|
503 |
$contents = $this->get_tmp_filesystem()->listContents();
|
504 |
|
@@ -510,7 +514,7 @@ class Xcloner_File_System
|
|
510 |
|
511 |
try {
|
512 |
rmdir($this->xcloner_settings->get_xcloner_tmp_path());
|
513 |
-
}catch (Exception $e) {
|
514 |
//silent continue
|
515 |
}
|
516 |
|
@@ -529,7 +533,6 @@ class Xcloner_File_System
|
|
529 |
$contents = $tmp_filesystem->listContents();
|
530 |
|
531 |
foreach ($contents as $file) {
|
532 |
-
|
533 |
if (preg_match("/.xcloner-(.*)/", $file['path'])) {
|
534 |
if ($file['timestamp'] < strtotime("-1days")) {
|
535 |
$tmp_filesystem->deleteDir($file['path']);
|
@@ -589,7 +592,6 @@ class Xcloner_File_System
|
|
589 |
}
|
590 |
|
591 |
foreach ($excluded_files as $excl) {
|
592 |
-
|
593 |
if ($this->is_regex($excl)) {
|
594 |
$this->additional_regex_patterns[] = $excl;
|
595 |
}
|
@@ -616,16 +618,16 @@ class Xcloner_File_System
|
|
616 |
|
617 |
//if we start with the root folder(empty value), we initializa the file system
|
618 |
if (!$folder) {
|
619 |
-
|
620 |
}
|
621 |
|
622 |
try {
|
623 |
-
|
624 |
$files = $this->start_filesystem->listContents($folder);
|
625 |
foreach ($files as $file) {
|
626 |
if (!is_readable($this->xcloner_settings->get_xcloner_start_path().DS.$file['path'])) {
|
627 |
-
$this->logger->info(sprintf(
|
628 |
-
|
|
|
|
|
629 |
"FILESYSTEM SCAN",
|
630 |
"NOT READABLE"
|
631 |
));
|
@@ -641,22 +643,20 @@ class Xcloner_File_System
|
|
641 |
if (isset($file['size'])) {
|
642 |
$this->files_size += $file['size'];
|
643 |
}
|
644 |
-
|
645 |
} else {
|
646 |
-
$this->logger->info(sprintf(
|
647 |
-
|
|
|
|
|
|
|
648 |
"FILESYSTEM SCAN",
|
649 |
"EXCLUDE"
|
650 |
));
|
651 |
}
|
652 |
}
|
653 |
-
|
654 |
-
}catch (Exception $e) {
|
655 |
-
|
656 |
$this->logger->error($e->getMessage());
|
657 |
-
|
658 |
}
|
659 |
-
|
660 |
}
|
661 |
|
662 |
public function estimate_read_write_time()
|
@@ -677,11 +677,8 @@ class Xcloner_File_System
|
|
677 |
$return['reading_time'] = $this->estimate_reading_time($tmp_file);
|
678 |
|
679 |
$this->tmp_filesystem->delete($tmp_file);
|
680 |
-
|
681 |
-
}catch (Exception $e) {
|
682 |
-
|
683 |
$this->logger->error($e->getMessage());
|
684 |
-
|
685 |
}
|
686 |
|
687 |
return $return;
|
@@ -716,8 +713,7 @@ class Xcloner_File_System
|
|
716 |
foreach ($_backup_files_list as $file) {
|
717 |
//processing rule folder capacity
|
718 |
if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit') &&
|
719 |
-
$_storage_size >= ($set_storage_limit = 1024 * 1024 * $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit'))) //bytes
|
720 |
-
{
|
721 |
$this->storage_filesystem->delete($file['path']);
|
722 |
$_storage_size -= $file['size'];
|
723 |
$this->logger->info("Deleting backup ".$file['path']." matching rule", array(
|
@@ -744,10 +740,7 @@ class Xcloner_File_System
|
|
744 |
$_backups_counter." >= ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')
|
745 |
));
|
746 |
}
|
747 |
-
|
748 |
-
|
749 |
}
|
750 |
-
|
751 |
}
|
752 |
|
753 |
/**
|
@@ -766,7 +759,6 @@ class Xcloner_File_System
|
|
766 |
$end_time = microtime(true) - $start_time;
|
767 |
|
768 |
return $end_time;
|
769 |
-
|
770 |
}
|
771 |
|
772 |
public function process_backup_name($name = "", $max_length = 100)
|
@@ -780,7 +772,7 @@ class Xcloner_File_System
|
|
780 |
$name = str_replace($tag, date("Y-m-d_H-i"), $name);
|
781 |
} elseif ($tag == '[hostname]') {
|
782 |
$name = str_replace($tag, gethostname(), $name);
|
783 |
-
}elseif ($tag == '[hash]') {
|
784 |
$name = str_replace($tag, $this->xcloner_container->randomString(5), $name);
|
785 |
} elseif ($tag == '[domain]') {
|
786 |
$domain = parse_url(admin_url(), PHP_URL_HOST);
|
@@ -927,163 +919,165 @@ class Xcloner_File_System
|
|
927 |
* exclude the backup folders
|
928 |
* PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
|
929 |
*/
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
//print_r($regex_patterns);exit;
|
941 |
-
|
942 |
-
if (is_array($regex_patterns)) {
|
943 |
-
//$this->excluded_files = array();
|
944 |
-
//$this->excluded_files[] ="(.*)\.(git)(.*)$";
|
945 |
-
//$this->excluded_files[] ="wp-content\/backups(.*)$";
|
946 |
-
|
947 |
-
foreach ($regex_patterns as $excluded_file_pattern) {
|
948 |
-
|
949 |
-
if (substr($excluded_file_pattern, strlen($excluded_file_pattern) - 1,
|
950 |
-
strlen($excluded_file_pattern)) == "\r") {
|
951 |
-
$excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern) - 1);
|
952 |
-
}
|
953 |
-
|
954 |
-
if ($file['path'] == "/") {
|
955 |
-
$needle = "/";
|
956 |
-
} else {
|
957 |
-
$needle = "/".$file['path'];
|
958 |
-
}
|
959 |
-
//echo $needle."---".$excluded_file_pattern."---\n";
|
960 |
-
|
961 |
-
if (@preg_match("/(^|^\/)".$excluded_file_pattern."/i", $needle)) {
|
962 |
-
return $excluded_file_pattern;
|
963 |
-
}
|
964 |
-
}
|
965 |
-
}
|
966 |
-
|
967 |
-
return false;
|
968 |
-
}
|
969 |
-
|
970 |
-
public function store_file($file, $storage = 'start_filesystem')
|
971 |
-
{
|
972 |
-
$this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
|
973 |
-
|
974 |
-
if (!isset($file['size'])) {
|
975 |
-
$file['size'] = 0;
|
976 |
-
}
|
977 |
-
if (!isset($file['visibility'])) {
|
978 |
-
$file['visibility'] = "private";
|
979 |
-
}
|
980 |
-
|
981 |
-
$csv_filename = str_replace('"', '""', $file['path']);
|
982 |
-
|
983 |
-
$line = '"'.($csv_filename).'","'.$file['timestamp'].'","'.$file['size'].'","'.$file['visibility'].'","'.$storage.'"'.PHP_EOL;
|
984 |
-
|
985 |
-
$this->last_logged_file = $file['path'];
|
986 |
-
|
987 |
-
if ($file['type'] == "dir") {
|
988 |
-
try {
|
989 |
-
$this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path']."\n");
|
990 |
-
}catch (Exception $e) {
|
991 |
-
$this->logger->error($e->getMessage());
|
992 |
-
}
|
993 |
-
}
|
994 |
-
|
995 |
-
if ($this->get_diff_timestamp_start()) {
|
996 |
-
if ($file['type'] != "file" && $response = $this->check_file_diff_time($file)) {
|
997 |
-
$this->logger->info(sprintf("Directory %s archiving skipped on differential backup %s", $file['path'],
|
998 |
-
$response), array(
|
999 |
-
"FILESYSTEM SCAN",
|
1000 |
-
"DIR DIFF"
|
1001 |
-
));
|
1002 |
-
|
1003 |
-
return false;
|
1004 |
-
}
|
1005 |
-
}
|
1006 |
-
|
1007 |
-
try {
|
1008 |
-
if (!$this->tmp_filesystem_append->has($this->get_included_files_handler())) {
|
1009 |
-
//adding fix for UTF-8 CSV preview
|
1010 |
-
$start_line = "\xEF\xBB\xBF".'"Filename","Timestamp","Size","Visibility","Storage"'.PHP_EOL;
|
1011 |
-
$this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
|
1012 |
-
}
|
1013 |
-
|
1014 |
-
$this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
|
1015 |
-
|
1016 |
-
}catch (Exception $e) {
|
1017 |
-
|
1018 |
-
$this->logger->error($e->getMessage());
|
1019 |
-
}
|
1020 |
-
|
1021 |
-
return true;
|
1022 |
-
}
|
1023 |
-
|
1024 |
-
public function get_fileystem_handler()
|
1025 |
-
{
|
1026 |
-
return $this;
|
1027 |
-
}
|
1028 |
-
|
1029 |
-
public function get_filesystem($system = "")
|
1030 |
-
{
|
1031 |
-
if ($system == "storage_filesystem_append") {
|
1032 |
-
return $this->storage_filesystem_append;
|
1033 |
-
} elseif ($system == "tmp_filesystem_append") {
|
1034 |
-
return $this->tmp_filesystem_append;
|
1035 |
-
} elseif ($system == "tmp_filesystem") {
|
1036 |
-
return $this->tmp_filesystem;
|
1037 |
-
} elseif ($system == "storage_filesystem") {
|
1038 |
-
return $this->storage_filesystem;
|
1039 |
-
} else {
|
1040 |
-
return $this->start_filesystem;
|
1041 |
-
}
|
1042 |
-
}
|
1043 |
-
|
1044 |
-
public function get_adapter($system)
|
1045 |
-
{
|
1046 |
-
if ($system == "tmp_filesystem") {
|
1047 |
-
return $this->tmp_adapter;
|
1048 |
-
} elseif ($system == "storage_filesystem") {
|
1049 |
-
return $this->storage_adapter;
|
1050 |
-
} else {
|
1051 |
-
return $this->start_adapter;
|
1052 |
-
}
|
1053 |
-
}
|
1054 |
-
|
1055 |
-
/**
|
1056 |
-
* File scan finished
|
1057 |
-
* Method called when file scan is finished
|
1058 |
-
*
|
1059 |
-
* @return bool
|
1060 |
-
*/
|
1061 |
-
private function scan_finished()
|
1062 |
-
{
|
1063 |
-
if ($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) &&
|
1064 |
-
$this->tmp_filesystem_append->getSize($this->get_temp_dir_handler())) {
|
1065 |
-
return false;
|
1066 |
-
}
|
1067 |
-
|
1068 |
-
if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
|
1069 |
-
$this->tmp_filesystem->delete($this->get_temp_dir_handler());
|
1070 |
-
}
|
1071 |
-
|
1072 |
-
$this->logger->debug(sprintf(("File scan finished")));
|
1073 |
-
|
1074 |
-
return true;
|
1075 |
-
}
|
1076 |
-
|
1077 |
-
/**
|
1078 |
-
* Calculate bytes from MB value
|
1079 |
-
*
|
1080 |
-
* @param int $mb_size
|
1081 |
-
*
|
1082 |
-
* @return float|int
|
1083 |
-
*/
|
1084 |
-
private function calc_to_bytes($mb_size)
|
1085 |
-
{
|
1086 |
-
return $mb_size * (1024 * 1024);
|
1087 |
-
}
|
1088 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1089 |
}
|
36 |
*/
|
37 |
class Xcloner_File_System
|
38 |
{
|
|
|
39 |
private $excluded_files = "";
|
40 |
private $additional_regex_patterns = array();
|
41 |
private $excluded_files_by_default = array("administrator/backups", "wp-content/backups");
|
76 |
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
77 |
|
78 |
try {
|
|
|
79 |
$this->start_adapter = new Local($this->xcloner_settings->get_xcloner_start_path(), LOCK_EX, '0001');
|
80 |
$this->start_filesystem = new Filesystem($this->start_adapter, new Config([
|
81 |
'disable_asserts' => true,
|
95 |
'disable_asserts' => true,
|
96 |
]));
|
97 |
|
98 |
+
$this->storage_adapter = new Local(
|
99 |
+
$this->xcloner_settings->get_xcloner_store_path(),
|
100 |
+
FILE_APPEND,
|
101 |
+
'0001'
|
102 |
+
);
|
103 |
$this->storage_filesystem_append = new Filesystem($this->storage_adapter, new Config([
|
104 |
'disable_asserts' => true,
|
105 |
]));
|
106 |
+
} catch (Exception $e) {
|
107 |
$this->logger->error("Filesystem Initialization Error: ".$e->getMessage());
|
108 |
}
|
109 |
|
110 |
|
111 |
+
if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_directories_to_scan_per_request')) {
|
112 |
$this->folders_to_process_per_session = $value;
|
113 |
}
|
|
|
114 |
}
|
115 |
|
116 |
/**
|
225 |
$spl_info = $this->getMetadataFull('tmp_adapter', $path);
|
226 |
|
227 |
return $spl_info;
|
|
|
228 |
}
|
229 |
|
230 |
public function get_temp_dir_handler()
|
391 |
}
|
392 |
}
|
393 |
}
|
|
|
394 |
}
|
395 |
|
396 |
+
if ($file_info['type'] == 'file' and isset($file_info['extension']) and in_array(
|
397 |
+
$file_info['extension'],
|
398 |
+
$this->backup_archive_extensions
|
399 |
+
)) {
|
400 |
$backup_files[$file_info['path']] = $file_info;
|
401 |
}
|
402 |
}
|
417 |
public function start_file_recursion($init = 0)
|
418 |
{
|
419 |
if ($init) {
|
420 |
+
$this->logger->info(sprintf(
|
421 |
+
__("Starting the filesystem scanner on root folder %s"),
|
422 |
+
$this->xcloner_settings->get_xcloner_start_path()
|
423 |
+
));
|
424 |
$this->do_system_init();
|
425 |
}
|
426 |
|
499 |
public function remove_tmp_filesystem()
|
500 |
{
|
501 |
//delete the temporary folder
|
502 |
+
$this->logger->debug(sprintf(
|
503 |
+
"Deleting the temporary storage folder %s",
|
504 |
+
$this->xcloner_settings->get_xcloner_tmp_path()
|
505 |
+
));
|
506 |
|
507 |
$contents = $this->get_tmp_filesystem()->listContents();
|
508 |
|
514 |
|
515 |
try {
|
516 |
rmdir($this->xcloner_settings->get_xcloner_tmp_path());
|
517 |
+
} catch (Exception $e) {
|
518 |
//silent continue
|
519 |
}
|
520 |
|
533 |
$contents = $tmp_filesystem->listContents();
|
534 |
|
535 |
foreach ($contents as $file) {
|
|
|
536 |
if (preg_match("/.xcloner-(.*)/", $file['path'])) {
|
537 |
if ($file['timestamp'] < strtotime("-1days")) {
|
538 |
$tmp_filesystem->deleteDir($file['path']);
|
592 |
}
|
593 |
|
594 |
foreach ($excluded_files as $excl) {
|
|
|
595 |
if ($this->is_regex($excl)) {
|
596 |
$this->additional_regex_patterns[] = $excl;
|
597 |
}
|
618 |
|
619 |
//if we start with the root folder(empty value), we initializa the file system
|
620 |
if (!$folder) {
|
|
|
621 |
}
|
622 |
|
623 |
try {
|
|
|
624 |
$files = $this->start_filesystem->listContents($folder);
|
625 |
foreach ($files as $file) {
|
626 |
if (!is_readable($this->xcloner_settings->get_xcloner_start_path().DS.$file['path'])) {
|
627 |
+
$this->logger->info(sprintf(
|
628 |
+
__("Excluding %s from the filesystem list, file not readable"),
|
629 |
+
$file['path']
|
630 |
+
), array(
|
631 |
"FILESYSTEM SCAN",
|
632 |
"NOT READABLE"
|
633 |
));
|
643 |
if (isset($file['size'])) {
|
644 |
$this->files_size += $file['size'];
|
645 |
}
|
|
|
646 |
} else {
|
647 |
+
$this->logger->info(sprintf(
|
648 |
+
__("Excluding %s from the filesystem list, matching pattern %s"),
|
649 |
+
$file['path'],
|
650 |
+
$matching_pattern
|
651 |
+
), array(
|
652 |
"FILESYSTEM SCAN",
|
653 |
"EXCLUDE"
|
654 |
));
|
655 |
}
|
656 |
}
|
657 |
+
} catch (Exception $e) {
|
|
|
|
|
658 |
$this->logger->error($e->getMessage());
|
|
|
659 |
}
|
|
|
660 |
}
|
661 |
|
662 |
public function estimate_read_write_time()
|
677 |
$return['reading_time'] = $this->estimate_reading_time($tmp_file);
|
678 |
|
679 |
$this->tmp_filesystem->delete($tmp_file);
|
680 |
+
} catch (Exception $e) {
|
|
|
|
|
681 |
$this->logger->error($e->getMessage());
|
|
|
682 |
}
|
683 |
|
684 |
return $return;
|
713 |
foreach ($_backup_files_list as $file) {
|
714 |
//processing rule folder capacity
|
715 |
if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit') &&
|
716 |
+
$_storage_size >= ($set_storage_limit = 1024 * 1024 * $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit'))) { //bytes
|
|
|
717 |
$this->storage_filesystem->delete($file['path']);
|
718 |
$_storage_size -= $file['size'];
|
719 |
$this->logger->info("Deleting backup ".$file['path']." matching rule", array(
|
740 |
$_backups_counter." >= ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')
|
741 |
));
|
742 |
}
|
|
|
|
|
743 |
}
|
|
|
744 |
}
|
745 |
|
746 |
/**
|
759 |
$end_time = microtime(true) - $start_time;
|
760 |
|
761 |
return $end_time;
|
|
|
762 |
}
|
763 |
|
764 |
public function process_backup_name($name = "", $max_length = 100)
|
772 |
$name = str_replace($tag, date("Y-m-d_H-i"), $name);
|
773 |
} elseif ($tag == '[hostname]') {
|
774 |
$name = str_replace($tag, gethostname(), $name);
|
775 |
+
} elseif ($tag == '[hash]') {
|
776 |
$name = str_replace($tag, $this->xcloner_container->randomString(5), $name);
|
777 |
} elseif ($tag == '[domain]') {
|
778 |
$domain = parse_url(admin_url(), PHP_URL_HOST);
|
919 |
* exclude the backup folders
|
920 |
* PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
|
921 |
*/
|
922 |
+
private function is_excluded_regex($file)
|
923 |
+
{
|
924 |
+
//$this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
|
925 |
+
|
926 |
+
$regex_patterns = explode(PHP_EOL, $this->xcloner_settings->get_xcloner_option('xcloner_regex_exclude'));
|
927 |
+
|
928 |
+
if (is_array($this->additional_regex_patterns)) {
|
929 |
+
$regex_patterns = array_merge($regex_patterns, $this->additional_regex_patterns);
|
930 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
931 |
|
932 |
+
//print_r($regex_patterns);exit;
|
933 |
+
|
934 |
+
if (is_array($regex_patterns)) {
|
935 |
+
//$this->excluded_files = array();
|
936 |
+
//$this->excluded_files[] ="(.*)\.(git)(.*)$";
|
937 |
+
//$this->excluded_files[] ="wp-content\/backups(.*)$";
|
938 |
+
|
939 |
+
foreach ($regex_patterns as $excluded_file_pattern) {
|
940 |
+
if (substr(
|
941 |
+
$excluded_file_pattern,
|
942 |
+
strlen($excluded_file_pattern) - 1,
|
943 |
+
strlen($excluded_file_pattern)
|
944 |
+
) == "\r") {
|
945 |
+
$excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern) - 1);
|
946 |
+
}
|
947 |
+
|
948 |
+
if ($file['path'] == "/") {
|
949 |
+
$needle = "/";
|
950 |
+
} else {
|
951 |
+
$needle = "/".$file['path'];
|
952 |
+
}
|
953 |
+
//echo $needle."---".$excluded_file_pattern."---\n";
|
954 |
+
|
955 |
+
if (@preg_match("/(^|^\/)".$excluded_file_pattern."/i", $needle)) {
|
956 |
+
return $excluded_file_pattern;
|
957 |
+
}
|
958 |
+
}
|
959 |
+
}
|
960 |
+
|
961 |
+
return false;
|
962 |
+
}
|
963 |
+
|
964 |
+
public function store_file($file, $storage = 'start_filesystem')
|
965 |
+
{
|
966 |
+
$this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
|
967 |
+
|
968 |
+
if (!isset($file['size'])) {
|
969 |
+
$file['size'] = 0;
|
970 |
+
}
|
971 |
+
if (!isset($file['visibility'])) {
|
972 |
+
$file['visibility'] = "private";
|
973 |
+
}
|
974 |
+
|
975 |
+
$csv_filename = str_replace('"', '""', $file['path']);
|
976 |
+
|
977 |
+
$line = '"'.($csv_filename).'","'.$file['timestamp'].'","'.$file['size'].'","'.$file['visibility'].'","'.$storage.'"'.PHP_EOL;
|
978 |
+
|
979 |
+
$this->last_logged_file = $file['path'];
|
980 |
+
|
981 |
+
if ($file['type'] == "dir") {
|
982 |
+
try {
|
983 |
+
$this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path']."\n");
|
984 |
+
} catch (Exception $e) {
|
985 |
+
$this->logger->error($e->getMessage());
|
986 |
+
}
|
987 |
+
}
|
988 |
+
|
989 |
+
if ($this->get_diff_timestamp_start()) {
|
990 |
+
if ($file['type'] != "file" && $response = $this->check_file_diff_time($file)) {
|
991 |
+
$this->logger->info(sprintf(
|
992 |
+
"Directory %s archiving skipped on differential backup %s",
|
993 |
+
$file['path'],
|
994 |
+
$response
|
995 |
+
), array(
|
996 |
+
"FILESYSTEM SCAN",
|
997 |
+
"DIR DIFF"
|
998 |
+
));
|
999 |
+
|
1000 |
+
return false;
|
1001 |
+
}
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
try {
|
1005 |
+
if (!$this->tmp_filesystem_append->has($this->get_included_files_handler())) {
|
1006 |
+
//adding fix for UTF-8 CSV preview
|
1007 |
+
$start_line = "\xEF\xBB\xBF".'"Filename","Timestamp","Size","Visibility","Storage"'.PHP_EOL;
|
1008 |
+
$this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
$this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
|
1012 |
+
} catch (Exception $e) {
|
1013 |
+
$this->logger->error($e->getMessage());
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
return true;
|
1017 |
+
}
|
1018 |
+
|
1019 |
+
public function get_fileystem_handler()
|
1020 |
+
{
|
1021 |
+
return $this;
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
public function get_filesystem($system = "")
|
1025 |
+
{
|
1026 |
+
if ($system == "storage_filesystem_append") {
|
1027 |
+
return $this->storage_filesystem_append;
|
1028 |
+
} elseif ($system == "tmp_filesystem_append") {
|
1029 |
+
return $this->tmp_filesystem_append;
|
1030 |
+
} elseif ($system == "tmp_filesystem") {
|
1031 |
+
return $this->tmp_filesystem;
|
1032 |
+
} elseif ($system == "storage_filesystem") {
|
1033 |
+
return $this->storage_filesystem;
|
1034 |
+
} else {
|
1035 |
+
return $this->start_filesystem;
|
1036 |
+
}
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
public function get_adapter($system)
|
1040 |
+
{
|
1041 |
+
if ($system == "tmp_filesystem") {
|
1042 |
+
return $this->tmp_adapter;
|
1043 |
+
} elseif ($system == "storage_filesystem") {
|
1044 |
+
return $this->storage_adapter;
|
1045 |
+
} else {
|
1046 |
+
return $this->start_adapter;
|
1047 |
+
}
|
1048 |
+
}
|
1049 |
+
|
1050 |
+
/**
|
1051 |
+
* File scan finished
|
1052 |
+
* Method called when file scan is finished
|
1053 |
+
*
|
1054 |
+
* @return bool
|
1055 |
+
*/
|
1056 |
+
private function scan_finished()
|
1057 |
+
{
|
1058 |
+
if ($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) &&
|
1059 |
+
$this->tmp_filesystem_append->getSize($this->get_temp_dir_handler())) {
|
1060 |
+
return false;
|
1061 |
+
}
|
1062 |
+
|
1063 |
+
if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
|
1064 |
+
$this->tmp_filesystem->delete($this->get_temp_dir_handler());
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
$this->logger->debug(sprintf(("File scan finished")));
|
1068 |
+
|
1069 |
+
return true;
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
/**
|
1073 |
+
* Calculate bytes from MB value
|
1074 |
+
*
|
1075 |
+
* @param int $mb_size
|
1076 |
+
*
|
1077 |
+
* @return float|int
|
1078 |
+
*/
|
1079 |
+
private function calc_to_bytes($mb_size)
|
1080 |
+
{
|
1081 |
+
return $mb_size * (1024 * 1024);
|
1082 |
+
}
|
1083 |
}
|
includes/class-xcloner-loader.php
CHANGED
@@ -86,45 +86,6 @@ class Xcloner_Loader
|
|
86 |
|
87 |
}
|
88 |
|
89 |
-
/**
|
90 |
-
* Add XCloner to Admin Menu
|
91 |
-
*/
|
92 |
-
public function xcloner_backup_add_admin_menu()
|
93 |
-
{
|
94 |
-
if (function_exists('add_menu_page')) {
|
95 |
-
add_menu_page(__('Site Backup', 'xcloner-backup-and-restore'),
|
96 |
-
__('Site Backup', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
|
97 |
-
array($this->xcloner_container, 'xcloner_display'), 'dashicons-backup');
|
98 |
-
}
|
99 |
-
|
100 |
-
if (function_exists('add_submenu_page')) {
|
101 |
-
|
102 |
-
add_submenu_page('xcloner_init_page', __('XCloner Dashboard', 'xcloner-backup-and-restore'),
|
103 |
-
__('Dashboard', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
|
104 |
-
array($this->xcloner_container, 'xcloner_display'));
|
105 |
-
add_submenu_page('xcloner_init_page', __('XCloner Backup Settings', 'xcloner-backup-and-restore'),
|
106 |
-
__('Settings', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_settings_page',
|
107 |
-
array($this->xcloner_container, 'xcloner_display'));
|
108 |
-
add_submenu_page('xcloner_init_page', __('Remote Storage Settings', 'xcloner-backup-and-restore'),
|
109 |
-
__('Remote Storage', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_remote_storage_page',
|
110 |
-
array($this->xcloner_container, 'xcloner_display'));
|
111 |
-
add_submenu_page('xcloner_init_page', __('Manage Backups', 'xcloner-backup-and-restore'),
|
112 |
-
__('Manage Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_manage_backups_page',
|
113 |
-
array($this->xcloner_container, 'xcloner_display'));
|
114 |
-
add_submenu_page('xcloner_init_page', __('Scheduled Backups', 'xcloner-backup-and-restore'),
|
115 |
-
__('Scheduled Backups', 'xcloner-backup-and-restore'), 'manage_options',
|
116 |
-
'xcloner_scheduled_backups_page', array($this->xcloner_container, 'xcloner_display'));
|
117 |
-
add_submenu_page('xcloner_init_page', __('Generate Backups', 'xcloner-backup-and-restore'),
|
118 |
-
__('Generate Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_generate_backups_page',
|
119 |
-
array($this->xcloner_container, 'xcloner_display'));
|
120 |
-
add_submenu_page('xcloner_init_page', __('Restore Backups', 'xcloner-backup-and-restore'),
|
121 |
-
__('Restore Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_restore_page',
|
122 |
-
array($this->xcloner_container, 'xcloner_display'));
|
123 |
-
}
|
124 |
-
|
125 |
-
}
|
126 |
-
|
127 |
-
|
128 |
/**
|
129 |
* Add a new action to the collection to be registered with WordPress.
|
130 |
*
|
@@ -191,7 +152,6 @@ class Xcloner_Loader
|
|
191 |
*/
|
192 |
public function run()
|
193 |
{
|
194 |
-
|
195 |
foreach ($this->filters as $hook) {
|
196 |
add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
|
197 |
$hook['accepted_args']);
|
86 |
|
87 |
}
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
/**
|
90 |
* Add a new action to the collection to be registered with WordPress.
|
91 |
*
|
152 |
*/
|
153 |
public function run()
|
154 |
{
|
|
|
155 |
foreach ($this->filters as $hook) {
|
156 |
add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
|
157 |
$hook['accepted_args']);
|
includes/class-xcloner-logger.php
CHANGED
@@ -4,119 +4,120 @@ use Monolog\Logger;
|
|
4 |
use Monolog\Handler\StreamHandler;
|
5 |
use Monolog\Handler\RotatingFileHandler;
|
6 |
|
7 |
-
class Xcloner_Logger extends Logger
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
|
|
122 |
}
|
4 |
use Monolog\Handler\StreamHandler;
|
5 |
use Monolog\Handler\RotatingFileHandler;
|
6 |
|
7 |
+
class Xcloner_Logger extends Logger
|
8 |
+
{
|
9 |
+
private $logger_path;
|
10 |
+
private $max_logger_files = 7;
|
11 |
+
private $main_logger_url;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Xcloner_Logger constructor.
|
15 |
+
* @param Xcloner $xcloner_container
|
16 |
+
* @param string $logger_name
|
17 |
+
* @throws Exception
|
18 |
+
*/
|
19 |
+
public function __construct(Xcloner $xcloner_container, $logger_name = "xcloner_logger")
|
20 |
+
{
|
21 |
+
if (!$xcloner_container->get_xcloner_settings()) {
|
22 |
+
$xcloner_settings = new Xcloner_Settings($xcloner_container);
|
23 |
+
} else {
|
24 |
+
$xcloner_settings = $xcloner_container->get_xcloner_settings();
|
25 |
+
}
|
26 |
+
|
27 |
+
$hash = $xcloner_settings->get_hash();
|
28 |
+
if ($hash == "-".$xcloner_settings->get_server_unique_hash(5)) {
|
29 |
+
$hash = "";
|
30 |
+
}
|
31 |
+
|
32 |
+
$logger_path = $xcloner_settings->get_xcloner_store_path().DS.$xcloner_settings->get_logger_filename();
|
33 |
+
$logger_path_tmp = "";
|
34 |
+
|
35 |
+
if ($hash) {
|
36 |
+
$logger_path_tmp = $xcloner_settings->get_xcloner_tmp_path().DS.$xcloner_settings->get_logger_filename(1);
|
37 |
+
}
|
38 |
+
|
39 |
+
$this->logger_path = $logger_path;
|
40 |
+
|
41 |
+
if (!is_dir($xcloner_settings->get_xcloner_store_path()) or !is_writable($xcloner_settings->get_xcloner_store_path())) {
|
42 |
+
$logger_path = 'php://stderr';
|
43 |
+
$logger_path_tmp = "";
|
44 |
+
}
|
45 |
+
|
46 |
+
if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
|
47 |
+
$logger_path = 'php://stderr';
|
48 |
+
$logger_path_tmp = "";
|
49 |
+
}
|
50 |
+
|
51 |
+
// create a log channel
|
52 |
+
parent::__construct($logger_name);
|
53 |
+
|
54 |
+
$debug_level = Logger::INFO;
|
55 |
+
|
56 |
+
if (defined('WP_DEBUG') && WP_DEBUG) {
|
57 |
+
$debug_level = Logger::DEBUG;
|
58 |
+
}
|
59 |
+
|
60 |
+
if ($logger_path) {
|
61 |
+
if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
|
62 |
+
$stream = new StreamHandler($logger_path, $debug_level);
|
63 |
+
} else {
|
64 |
+
$stream = new RotatingFileHandler($logger_path, $this->max_logger_files, $debug_level);
|
65 |
+
}
|
66 |
+
|
67 |
+
$this->pushHandler($stream);
|
68 |
+
|
69 |
+
$this->main_logger_url = $stream->getUrl();
|
70 |
+
}
|
71 |
+
|
72 |
+
if ($hash and $logger_path_tmp) {
|
73 |
+
$this->pushHandler(new StreamHandler($logger_path_tmp, $debug_level));
|
74 |
+
}
|
75 |
+
|
76 |
+
//return $this;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @return string|null
|
81 |
+
*/
|
82 |
+
public function get_main_logger_url()
|
83 |
+
{
|
84 |
+
return $this->main_logger_url;
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param int $totalLines
|
89 |
+
* @return array|bool
|
90 |
+
*/
|
91 |
+
public function getLastDebugLines($totalLines = 200)
|
92 |
+
{
|
93 |
+
$lines = array();
|
94 |
+
|
95 |
+
if (!file_exists($this->main_logger_url) or !is_readable($this->main_logger_url)) {
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
|
99 |
+
$fp = fopen($this->main_logger_url, 'r');
|
100 |
+
fseek($fp, - 1, SEEK_END);
|
101 |
+
$pos = ftell($fp);
|
102 |
+
$lastLine = "";
|
103 |
+
|
104 |
+
// Loop backword until we have our lines or we reach the start
|
105 |
+
while ($pos > 0 && count($lines) < $totalLines) {
|
106 |
+
$C = fgetc($fp);
|
107 |
+
if ($C == "\n") {
|
108 |
+
// skip empty lines
|
109 |
+
if (trim($lastLine) != "") {
|
110 |
+
$lines[] = $lastLine;
|
111 |
+
}
|
112 |
+
$lastLine = '';
|
113 |
+
} else {
|
114 |
+
$lastLine = $C.$lastLine;
|
115 |
+
}
|
116 |
+
fseek($fp, $pos--);
|
117 |
+
}
|
118 |
+
|
119 |
+
$lines = array_reverse($lines);
|
120 |
+
|
121 |
+
return $lines;
|
122 |
+
}
|
123 |
}
|
includes/class-xcloner-remote-storage.php
CHANGED
@@ -53,7 +53,6 @@ use League\Flysystem\WebDAV\WebDAVAdapter;
|
|
53 |
*/
|
54 |
class Xcloner_Remote_Storage
|
55 |
{
|
56 |
-
|
57 |
private $gdrive_app_name = "XCloner Backup and Restore";
|
58 |
|
59 |
private $storage_fields = array(
|
@@ -160,6 +159,7 @@ class Xcloner_Remote_Storage
|
|
160 |
|
161 |
private $xcloner_sanitization;
|
162 |
private $xcloner_file_system;
|
|
|
163 |
private $logger;
|
164 |
private $xcloner;
|
165 |
|
@@ -171,33 +171,30 @@ class Xcloner_Remote_Storage
|
|
171 |
{
|
172 |
$this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
|
173 |
$this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
|
|
|
174 |
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_remote_storage");
|
175 |
$this->xcloner = $xcloner_container;
|
176 |
|
177 |
foreach ($this->storage_fields as $main_key => $array) {
|
178 |
-
|
179 |
if (is_array($array)) {
|
180 |
foreach ($array as $key => $type) {
|
181 |
-
|
182 |
if ($type == "raw") {
|
183 |
-
add_filter(
|
|
|
184 |
function ($value) {
|
185 |
-
|
186 |
return $this->simple_crypt($value, 'e');
|
187 |
-
|
188 |
-
|
|
|
|
|
189 |
|
190 |
add_filter("option_" . $this->storage_fields['option_prefix'] . $key, function ($value) {
|
191 |
-
|
192 |
return $this->simple_crypt($value, 'd');
|
193 |
-
|
194 |
}, 10, 1);
|
195 |
}
|
196 |
-
|
197 |
}
|
198 |
}
|
199 |
}
|
200 |
-
|
201 |
}
|
202 |
|
203 |
/**
|
@@ -248,7 +245,7 @@ class Xcloner_Remote_Storage
|
|
248 |
$return = array();
|
249 |
foreach ($this->storage_fields as $storage => $data) {
|
250 |
$check_field = $this->storage_fields["option_prefix"] . $storage . "_enable";
|
251 |
-
if (
|
252 |
$return[$storage] = $data['text'];
|
253 |
}
|
254 |
}
|
@@ -267,13 +264,12 @@ class Xcloner_Remote_Storage
|
|
267 |
|
268 |
if (is_array($this->storage_fields[$storage])) {
|
269 |
foreach ($this->storage_fields[$storage] as $field => $validation) {
|
270 |
-
|
271 |
$check_field = $this->storage_fields["option_prefix"] . $field;
|
272 |
$sanitize_method = "sanitize_input_as_" . $validation;
|
273 |
|
274 |
|
275 |
//we do not save empty encrypted credentials
|
276 |
-
if($validation == "raw" && str_repeat('*', strlen($_POST[$check_field])) == $_POST[$check_field]
|
277 |
continue;
|
278 |
}
|
279 |
|
@@ -289,22 +285,30 @@ class Xcloner_Remote_Storage
|
|
289 |
update_option($check_field, $sanitized_value);
|
290 |
}
|
291 |
|
292 |
-
$this->xcloner->trigger_message(
|
293 |
-
|
|
|
|
|
|
|
294 |
}
|
295 |
-
|
296 |
}
|
297 |
|
298 |
public function check($action = "ftp")
|
299 |
{
|
300 |
try {
|
301 |
$this->verify_filesystem($action);
|
302 |
-
$this->xcloner->trigger_message(
|
303 |
-
|
|
|
|
|
|
|
304 |
$this->logger->debug(sprintf("Connection to remote storage %s is valid", strtoupper($action)));
|
305 |
} catch (Exception $e) {
|
306 |
-
$this->xcloner->trigger_message(
|
307 |
-
$
|
|
|
|
|
|
|
308 |
}
|
309 |
}
|
310 |
|
@@ -315,8 +319,10 @@ class Xcloner_Remote_Storage
|
|
315 |
{
|
316 |
$method = "get_" . $storage_type . "_filesystem";
|
317 |
|
318 |
-
$this->logger->info(sprintf(
|
319 |
-
|
|
|
|
|
320 |
|
321 |
if (!method_exists($this, $method)) {
|
322 |
return false;
|
@@ -375,8 +381,10 @@ class Xcloner_Remote_Storage
|
|
375 |
//doing remote storage cleaning here
|
376 |
$this->clean_remote_storage($storage, $remote_storage_filesystem);
|
377 |
|
378 |
-
$this->logger->info(
|
379 |
-
|
|
|
|
|
380 |
|
381 |
/*if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
|
382 |
{
|
@@ -396,8 +404,11 @@ class Xcloner_Remote_Storage
|
|
396 |
$parts = $this->xcloner_file_system->get_multipart_files($file);
|
397 |
if (is_array($parts)) {
|
398 |
foreach ($parts as $part_file) {
|
399 |
-
$this->logger->info(sprintf(
|
400 |
-
|
|
|
|
|
|
|
401 |
|
402 |
$backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($part_file);
|
403 |
if (!$remote_storage_filesystem->writeStream($part_file, $backup_file_stream)) {
|
@@ -410,7 +421,6 @@ class Xcloner_Remote_Storage
|
|
410 |
$this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
|
411 |
|
412 |
return true;
|
413 |
-
|
414 |
}
|
415 |
|
416 |
public function copy_backup_remote_to_local($file, $storage)
|
@@ -436,8 +446,11 @@ class Xcloner_Remote_Storage
|
|
436 |
$target_filename = $metadata['filename'] . "." . $metadata['extension'];
|
437 |
}
|
438 |
|
439 |
-
$this->logger->info(sprintf(
|
440 |
-
|
|
|
|
|
|
|
441 |
|
442 |
$backup_file_stream = $remote_storage_filesystem->readStream($file);
|
443 |
|
@@ -451,12 +464,17 @@ class Xcloner_Remote_Storage
|
|
451 |
$parts = $this->xcloner_file_system->get_multipart_files($file, $storage);
|
452 |
if (is_array($parts)) {
|
453 |
foreach ($parts as $part_file) {
|
454 |
-
$this->logger->info(sprintf(
|
455 |
-
|
|
|
|
|
|
|
456 |
|
457 |
$backup_file_stream = $remote_storage_filesystem->readStream($part_file);
|
458 |
-
if (!$this->xcloner_file_system->get_storage_filesystem()->writeStream(
|
459 |
-
$
|
|
|
|
|
460 |
return false;
|
461 |
}
|
462 |
}
|
@@ -466,15 +484,17 @@ class Xcloner_Remote_Storage
|
|
466 |
$this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
|
467 |
|
468 |
return true;
|
469 |
-
|
470 |
}
|
471 |
|
472 |
public function clean_remote_storage($storage, $remote_storage_filesystem)
|
473 |
{
|
474 |
$check_field = $this->storage_fields["option_prefix"] . $storage . "_cleanup_days";
|
475 |
-
if ($expire_days =
|
476 |
-
$this->logger->info(sprintf(
|
477 |
-
|
|
|
|
|
|
|
478 |
$files = $remote_storage_filesystem->listContents();
|
479 |
|
480 |
$current_timestamp = strtotime("-" . $expire_days . " days");
|
@@ -490,7 +510,6 @@ class Xcloner_Remote_Storage
|
|
490 |
$file['timestamp'] . " =< " . $expire_days
|
491 |
));
|
492 |
}
|
493 |
-
|
494 |
}
|
495 |
}
|
496 |
}
|
@@ -510,13 +529,13 @@ class Xcloner_Remote_Storage
|
|
510 |
|
511 |
$endpoint = sprintf(
|
512 |
'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
|
513 |
-
|
514 |
-
|
515 |
);
|
516 |
|
517 |
$blobRestProxy = BlobRestProxy::createBlobService($endpoint);
|
518 |
|
519 |
-
$adapter = new AzureBlobStorageAdapter($blobRestProxy,
|
520 |
|
521 |
$filesystem = new Filesystem($adapter, new Config([
|
522 |
'disable_asserts' => true,
|
@@ -533,8 +552,8 @@ class Xcloner_Remote_Storage
|
|
533 |
throw new Exception("DROPBOX requires PHP 5.6 to be installed!");
|
534 |
}
|
535 |
|
536 |
-
$client = new DropboxClient(
|
537 |
-
$adapter = new DropboxAdapter($client,
|
538 |
|
539 |
$filesystem = new Filesystem($adapter, new Config([
|
540 |
'disable_asserts' => true,
|
@@ -558,25 +577,22 @@ class Xcloner_Remote_Storage
|
|
558 |
|
559 |
$credentials = array(
|
560 |
'credentials' => array(
|
561 |
-
'key' =>
|
562 |
-
'secret' =>
|
563 |
),
|
564 |
-
'region' =>
|
565 |
'version' => 'latest',
|
566 |
);
|
567 |
|
568 |
-
if (
|
569 |
-
|
570 |
-
$credentials['endpoint'] = get_option('xcloner_aws_endpoint');
|
571 |
#$credentials['use_path_style_endpoint'] = true;
|
572 |
#$credentials['bucket_endpoint'] = false;
|
573 |
-
|
574 |
-
|
575 |
}
|
576 |
|
577 |
$client = new S3Client($credentials);
|
578 |
|
579 |
-
$adapter = new AwsS3Adapter($client,
|
580 |
$filesystem = new Filesystem($adapter, new Config([
|
581 |
'disable_asserts' => true,
|
582 |
]));
|
@@ -593,9 +609,11 @@ class Xcloner_Remote_Storage
|
|
593 |
}
|
594 |
|
595 |
|
596 |
-
$client = new B2Client(
|
597 |
-
|
598 |
-
|
|
|
|
|
599 |
|
600 |
$filesystem = new Filesystem($adapter, new Config([
|
601 |
'disable_asserts' => true,
|
@@ -613,14 +631,14 @@ class Xcloner_Remote_Storage
|
|
613 |
}
|
614 |
|
615 |
$settings = array(
|
616 |
-
'baseUri' =>
|
617 |
-
'userName' =>
|
618 |
-
'password' =>
|
619 |
//'proxy' => 'locahost:8888',
|
620 |
);
|
621 |
|
622 |
$client = new SabreClient($settings);
|
623 |
-
$adapter = new WebDAVAdapter($client,
|
624 |
$filesystem = new Filesystem($adapter, new Config([
|
625 |
'disable_asserts' => true,
|
626 |
]));
|
@@ -641,8 +659,8 @@ class Xcloner_Remote_Storage
|
|
641 |
|
642 |
$client = new \Google_Client();
|
643 |
$client->setApplicationName($this->gdrive_app_name);
|
644 |
-
$client->setClientId(
|
645 |
-
$client->setClientSecret(
|
646 |
|
647 |
//$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page&action=set_gdrive_code";
|
648 |
$redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
|
@@ -682,14 +700,11 @@ class Xcloner_Remote_Storage
|
|
682 |
update_option("xcloner_gdrive_access_token", $token['access_token']);
|
683 |
update_option("xcloner_gdrive_refresh_token", $token['refresh_token']);
|
684 |
|
685 |
-
$redirect_url = ('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?page=xcloner_remote_storage_page#gdrive");
|
686 |
-
|
687 |
-
?>
|
688 |
<script>
|
689 |
window.location = '<?php echo $redirect_url?>';
|
690 |
</script>
|
691 |
<?php
|
692 |
-
|
693 |
}
|
694 |
|
695 |
/*
|
@@ -698,7 +713,6 @@ class Xcloner_Remote_Storage
|
|
698 |
*/
|
699 |
public function get_gdrive_filesystem()
|
700 |
{
|
701 |
-
|
702 |
if (version_compare(phpversion(), '5.6.0', '<')) {
|
703 |
throw new Exception("Google Drive API requires PHP 5.6 to be installed!");
|
704 |
}
|
@@ -713,19 +727,19 @@ class Xcloner_Remote_Storage
|
|
713 |
throw new Exception($error_msg);
|
714 |
}
|
715 |
|
716 |
-
$client->refreshToken(
|
717 |
|
718 |
$service = new \Google_Service_Drive($client);
|
719 |
|
720 |
-
if (
|
721 |
$this->logger->info(sprintf("Doing a Google Drive emptyTrash call"), array(""));
|
722 |
$service->files->emptyTrash();
|
723 |
}
|
724 |
|
725 |
$parent = 'root';
|
726 |
-
$dir = basename(
|
727 |
|
728 |
-
$folderID =
|
729 |
|
730 |
$tmp = parse_url($folderID);
|
731 |
|
@@ -734,8 +748,11 @@ class Xcloner_Remote_Storage
|
|
734 |
}
|
735 |
|
736 |
if (stristr($folderID, "/")) {
|
737 |
-
$query = sprintf(
|
738 |
-
|
|
|
|
|
|
|
739 |
$response = $service->files->listFiles([
|
740 |
'pageSize' => 1,
|
741 |
'q' => $query
|
@@ -746,8 +763,10 @@ class Xcloner_Remote_Storage
|
|
746 |
$folderID = $obj->getId();
|
747 |
}
|
748 |
} else {
|
749 |
-
$this->xcloner->trigger_message(sprintf(__(
|
750 |
-
|
|
|
|
|
751 |
}
|
752 |
}
|
753 |
|
@@ -772,16 +791,16 @@ class Xcloner_Remote_Storage
|
|
772 |
$this->logger->info(sprintf("Creating the FTP remote storage connection"), array(""));
|
773 |
|
774 |
$adapter = new Adapter([
|
775 |
-
'host' =>
|
776 |
-
'username' =>
|
777 |
-
'password' =>
|
778 |
|
779 |
/** optional config settings */
|
780 |
-
'port' =>
|
781 |
-
'root' =>
|
782 |
-
'passive' =>
|
783 |
-
'ssl' =>
|
784 |
-
'timeout' =>
|
785 |
]);
|
786 |
|
787 |
$adapter->connect();
|
@@ -798,15 +817,15 @@ class Xcloner_Remote_Storage
|
|
798 |
$this->logger->info(sprintf("Creating the SFTP remote storage connection"), array(""));
|
799 |
|
800 |
$adapter = new SftpAdapter([
|
801 |
-
'host' =>
|
802 |
-
'username' =>
|
803 |
-
'password' =>
|
804 |
|
805 |
/** optional config settings */
|
806 |
-
'port' =>
|
807 |
-
'root' => (
|
808 |
-
'privateKey' =>
|
809 |
-
'timeout' =>
|
810 |
]);
|
811 |
|
812 |
$adapter->connect();
|
@@ -830,5 +849,4 @@ class Xcloner_Remote_Storage
|
|
830 |
{
|
831 |
return $this->aws_regions;
|
832 |
}
|
833 |
-
|
834 |
}
|
53 |
*/
|
54 |
class Xcloner_Remote_Storage
|
55 |
{
|
|
|
56 |
private $gdrive_app_name = "XCloner Backup and Restore";
|
57 |
|
58 |
private $storage_fields = array(
|
159 |
|
160 |
private $xcloner_sanitization;
|
161 |
private $xcloner_file_system;
|
162 |
+
private $xcloner_settings;
|
163 |
private $logger;
|
164 |
private $xcloner;
|
165 |
|
171 |
{
|
172 |
$this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
|
173 |
$this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
|
174 |
+
$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
|
175 |
$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_remote_storage");
|
176 |
$this->xcloner = $xcloner_container;
|
177 |
|
178 |
foreach ($this->storage_fields as $main_key => $array) {
|
|
|
179 |
if (is_array($array)) {
|
180 |
foreach ($array as $key => $type) {
|
|
|
181 |
if ($type == "raw") {
|
182 |
+
add_filter(
|
183 |
+
"pre_update_option_" . $this->storage_fields['option_prefix'] . $key,
|
184 |
function ($value) {
|
|
|
185 |
return $this->simple_crypt($value, 'e');
|
186 |
+
},
|
187 |
+
10,
|
188 |
+
1
|
189 |
+
);
|
190 |
|
191 |
add_filter("option_" . $this->storage_fields['option_prefix'] . $key, function ($value) {
|
|
|
192 |
return $this->simple_crypt($value, 'd');
|
|
|
193 |
}, 10, 1);
|
194 |
}
|
|
|
195 |
}
|
196 |
}
|
197 |
}
|
|
|
198 |
}
|
199 |
|
200 |
/**
|
245 |
$return = array();
|
246 |
foreach ($this->storage_fields as $storage => $data) {
|
247 |
$check_field = $this->storage_fields["option_prefix"] . $storage . "_enable";
|
248 |
+
if ($this->xcloner_settings->get_xcloner_option($check_field)) {
|
249 |
$return[$storage] = $data['text'];
|
250 |
}
|
251 |
}
|
264 |
|
265 |
if (is_array($this->storage_fields[$storage])) {
|
266 |
foreach ($this->storage_fields[$storage] as $field => $validation) {
|
|
|
267 |
$check_field = $this->storage_fields["option_prefix"] . $field;
|
268 |
$sanitize_method = "sanitize_input_as_" . $validation;
|
269 |
|
270 |
|
271 |
//we do not save empty encrypted credentials
|
272 |
+
if ($validation == "raw" && str_repeat('*', strlen($_POST[$check_field])) == $_POST[$check_field]) {
|
273 |
continue;
|
274 |
}
|
275 |
|
285 |
update_option($check_field, $sanitized_value);
|
286 |
}
|
287 |
|
288 |
+
$this->xcloner->trigger_message(
|
289 |
+
__("%s storage settings saved.", 'xcloner-backup-and-restore'),
|
290 |
+
"success",
|
291 |
+
$this->storage_fields[$action]['text']
|
292 |
+
);
|
293 |
}
|
|
|
294 |
}
|
295 |
|
296 |
public function check($action = "ftp")
|
297 |
{
|
298 |
try {
|
299 |
$this->verify_filesystem($action);
|
300 |
+
$this->xcloner->trigger_message(
|
301 |
+
__("%s connection is valid.", 'xcloner-backup-and-restore'),
|
302 |
+
"success",
|
303 |
+
$this->storage_fields[$action]['text']
|
304 |
+
);
|
305 |
$this->logger->debug(sprintf("Connection to remote storage %s is valid", strtoupper($action)));
|
306 |
} catch (Exception $e) {
|
307 |
+
$this->xcloner->trigger_message(
|
308 |
+
"%s connection error: " . $e->getMessage(),
|
309 |
+
"error",
|
310 |
+
$this->storage_fields[$action]['text']
|
311 |
+
);
|
312 |
}
|
313 |
}
|
314 |
|
319 |
{
|
320 |
$method = "get_" . $storage_type . "_filesystem";
|
321 |
|
322 |
+
$this->logger->info(sprintf(
|
323 |
+
"Checking validity of the remote storage %s filesystem",
|
324 |
+
strtoupper($storage_type)
|
325 |
+
));
|
326 |
|
327 |
if (!method_exists($this, $method)) {
|
328 |
return false;
|
381 |
//doing remote storage cleaning here
|
382 |
$this->clean_remote_storage($storage, $remote_storage_filesystem);
|
383 |
|
384 |
+
$this->logger->info(
|
385 |
+
sprintf("Transferring backup %s to remote storage %s", $file, strtoupper($storage)),
|
386 |
+
array("")
|
387 |
+
);
|
388 |
|
389 |
/*if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
|
390 |
{
|
404 |
$parts = $this->xcloner_file_system->get_multipart_files($file);
|
405 |
if (is_array($parts)) {
|
406 |
foreach ($parts as $part_file) {
|
407 |
+
$this->logger->info(sprintf(
|
408 |
+
"Transferring backup %s to remote storage %s",
|
409 |
+
$part_file,
|
410 |
+
strtoupper($storage)
|
411 |
+
), array(""));
|
412 |
|
413 |
$backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($part_file);
|
414 |
if (!$remote_storage_filesystem->writeStream($part_file, $backup_file_stream)) {
|
421 |
$this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
|
422 |
|
423 |
return true;
|
|
|
424 |
}
|
425 |
|
426 |
public function copy_backup_remote_to_local($file, $storage)
|
446 |
$target_filename = $metadata['filename'] . "." . $metadata['extension'];
|
447 |
}
|
448 |
|
449 |
+
$this->logger->info(sprintf(
|
450 |
+
"Transferring backup %s to local storage from %s storage",
|
451 |
+
$file,
|
452 |
+
strtoupper($storage)
|
453 |
+
), array(""));
|
454 |
|
455 |
$backup_file_stream = $remote_storage_filesystem->readStream($file);
|
456 |
|
464 |
$parts = $this->xcloner_file_system->get_multipart_files($file, $storage);
|
465 |
if (is_array($parts)) {
|
466 |
foreach ($parts as $part_file) {
|
467 |
+
$this->logger->info(sprintf(
|
468 |
+
"Transferring backup %s to local storage from %s storage",
|
469 |
+
$part_file,
|
470 |
+
strtoupper($storage)
|
471 |
+
), array(""));
|
472 |
|
473 |
$backup_file_stream = $remote_storage_filesystem->readStream($part_file);
|
474 |
+
if (!$this->xcloner_file_system->get_storage_filesystem()->writeStream(
|
475 |
+
$part_file,
|
476 |
+
$backup_file_stream
|
477 |
+
)) {
|
478 |
return false;
|
479 |
}
|
480 |
}
|
484 |
$this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
|
485 |
|
486 |
return true;
|
|
|
487 |
}
|
488 |
|
489 |
public function clean_remote_storage($storage, $remote_storage_filesystem)
|
490 |
{
|
491 |
$check_field = $this->storage_fields["option_prefix"] . $storage . "_cleanup_days";
|
492 |
+
if ($expire_days = $this->xcloner_settings->get_xcloner_option($check_field)) {
|
493 |
+
$this->logger->info(sprintf(
|
494 |
+
"Doing %s remote storage cleanup for %s days limit",
|
495 |
+
strtoupper($storage),
|
496 |
+
$expire_days
|
497 |
+
));
|
498 |
$files = $remote_storage_filesystem->listContents();
|
499 |
|
500 |
$current_timestamp = strtotime("-" . $expire_days . " days");
|
510 |
$file['timestamp'] . " =< " . $expire_days
|
511 |
));
|
512 |
}
|
|
|
513 |
}
|
514 |
}
|
515 |
}
|
529 |
|
530 |
$endpoint = sprintf(
|
531 |
'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
|
532 |
+
$this->xcloner_settings->get_xcloner_option("xcloner_azure_account_name"),
|
533 |
+
$this->xcloner_settings->get_xcloner_option("xcloner_azure_api_key")
|
534 |
);
|
535 |
|
536 |
$blobRestProxy = BlobRestProxy::createBlobService($endpoint);
|
537 |
|
538 |
+
$adapter = new AzureBlobStorageAdapter($blobRestProxy, $this->xcloner_settings->get_xcloner_option("xcloner_azure_container"));
|
539 |
|
540 |
$filesystem = new Filesystem($adapter, new Config([
|
541 |
'disable_asserts' => true,
|
552 |
throw new Exception("DROPBOX requires PHP 5.6 to be installed!");
|
553 |
}
|
554 |
|
555 |
+
$client = new DropboxClient($this->xcloner_settings->get_xcloner_option("xcloner_dropbox_access_token"));
|
556 |
+
$adapter = new DropboxAdapter($client, $this->xcloner_settings->get_xcloner_option("xcloner_dropbox_prefix"));
|
557 |
|
558 |
$filesystem = new Filesystem($adapter, new Config([
|
559 |
'disable_asserts' => true,
|
577 |
|
578 |
$credentials = array(
|
579 |
'credentials' => array(
|
580 |
+
'key' => $this->xcloner_settings->get_xcloner_option("xcloner_aws_key"),
|
581 |
+
'secret' => $this->xcloner_settings->get_xcloner_option("xcloner_aws_secret")
|
582 |
),
|
583 |
+
'region' => $this->xcloner_settings->get_xcloner_option("xcloner_aws_region"),
|
584 |
'version' => 'latest',
|
585 |
);
|
586 |
|
587 |
+
if ($this->xcloner_settings->get_xcloner_option('xcloner_aws_endpoint') != "" && !$this->xcloner_settings->get_xcloner_option("xcloner_aws_region")) {
|
588 |
+
$credentials['endpoint'] = $this->xcloner_settings->get_xcloner_option('xcloner_aws_endpoint');
|
|
|
589 |
#$credentials['use_path_style_endpoint'] = true;
|
590 |
#$credentials['bucket_endpoint'] = false;
|
|
|
|
|
591 |
}
|
592 |
|
593 |
$client = new S3Client($credentials);
|
594 |
|
595 |
+
$adapter = new AwsS3Adapter($client, $this->xcloner_settings->get_xcloner_option("xcloner_aws_bucket_name"), $this->xcloner_settings->get_xcloner_option("xcloner_aws_prefix"));
|
596 |
$filesystem = new Filesystem($adapter, new Config([
|
597 |
'disable_asserts' => true,
|
598 |
]));
|
609 |
}
|
610 |
|
611 |
|
612 |
+
$client = new B2Client(
|
613 |
+
$this->xcloner_settings->get_xcloner_option("xcloner_backblaze_account_id"),
|
614 |
+
$this->xcloner_settings->get_xcloner_option("xcloner_backblaze_application_key")
|
615 |
+
);
|
616 |
+
$adapter = new BackblazeAdapter($client, $this->xcloner_settings->get_xcloner_option("xcloner_backblaze_bucket_name"));
|
617 |
|
618 |
$filesystem = new Filesystem($adapter, new Config([
|
619 |
'disable_asserts' => true,
|
631 |
}
|
632 |
|
633 |
$settings = array(
|
634 |
+
'baseUri' => $this->xcloner_settings->get_xcloner_option("xcloner_webdav_url"),
|
635 |
+
'userName' => $this->xcloner_settings->get_xcloner_option("xcloner_webdav_username"),
|
636 |
+
'password' => $this->xcloner_settings->get_xcloner_option("xcloner_webdav_password"),
|
637 |
//'proxy' => 'locahost:8888',
|
638 |
);
|
639 |
|
640 |
$client = new SabreClient($settings);
|
641 |
+
$adapter = new WebDAVAdapter($client, $this->xcloner_settings->get_xcloner_option("xcloner_webdav_target_folder"));
|
642 |
$filesystem = new Filesystem($adapter, new Config([
|
643 |
'disable_asserts' => true,
|
644 |
]));
|
659 |
|
660 |
$client = new \Google_Client();
|
661 |
$client->setApplicationName($this->gdrive_app_name);
|
662 |
+
$client->setClientId($this->xcloner_settings->get_xcloner_option("xcloner_gdrive_client_id"));
|
663 |
+
$client->setClientSecret($this->xcloner_settings->get_xcloner_option("xcloner_gdrive_client_secret"));
|
664 |
|
665 |
//$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page&action=set_gdrive_code";
|
666 |
$redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
|
700 |
update_option("xcloner_gdrive_access_token", $token['access_token']);
|
701 |
update_option("xcloner_gdrive_refresh_token", $token['refresh_token']);
|
702 |
|
703 |
+
$redirect_url = ('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?page=xcloner_remote_storage_page#gdrive"); ?>
|
|
|
|
|
704 |
<script>
|
705 |
window.location = '<?php echo $redirect_url?>';
|
706 |
</script>
|
707 |
<?php
|
|
|
708 |
}
|
709 |
|
710 |
/*
|
713 |
*/
|
714 |
public function get_gdrive_filesystem()
|
715 |
{
|
|
|
716 |
if (version_compare(phpversion(), '5.6.0', '<')) {
|
717 |
throw new Exception("Google Drive API requires PHP 5.6 to be installed!");
|
718 |
}
|
727 |
throw new Exception($error_msg);
|
728 |
}
|
729 |
|
730 |
+
$client->refreshToken($this->xcloner_settings->get_xcloner_option("xcloner_gdrive_refresh_token"));
|
731 |
|
732 |
$service = new \Google_Service_Drive($client);
|
733 |
|
734 |
+
if ($this->xcloner_settings->get_xcloner_option("xcloner_gdrive_empty_trash", 0)) {
|
735 |
$this->logger->info(sprintf("Doing a Google Drive emptyTrash call"), array(""));
|
736 |
$service->files->emptyTrash();
|
737 |
}
|
738 |
|
739 |
$parent = 'root';
|
740 |
+
$dir = basename($this->xcloner_settings->get_xcloner_option("xcloner_gdrive_target_folder"));
|
741 |
|
742 |
+
$folderID = $this->xcloner_settings->get_xcloner_option("xcloner_gdrive_target_folder");
|
743 |
|
744 |
$tmp = parse_url($folderID);
|
745 |
|
748 |
}
|
749 |
|
750 |
if (stristr($folderID, "/")) {
|
751 |
+
$query = sprintf(
|
752 |
+
'mimeType = \'application/vnd.google-apps.folder\' and \'%s\' in parents and name contains \'%s\'',
|
753 |
+
$parent,
|
754 |
+
$dir
|
755 |
+
);
|
756 |
$response = $service->files->listFiles([
|
757 |
'pageSize' => 1,
|
758 |
'q' => $query
|
763 |
$folderID = $obj->getId();
|
764 |
}
|
765 |
} else {
|
766 |
+
$this->xcloner->trigger_message(sprintf(__(
|
767 |
+
"Could not find folder ID by name %s",
|
768 |
+
'xcloner-backup-and-restore'
|
769 |
+
), $folderID), "error");
|
770 |
}
|
771 |
}
|
772 |
|
791 |
$this->logger->info(sprintf("Creating the FTP remote storage connection"), array(""));
|
792 |
|
793 |
$adapter = new Adapter([
|
794 |
+
'host' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_hostname"),
|
795 |
+
'username' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_username"),
|
796 |
+
'password' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_password"),
|
797 |
|
798 |
/** optional config settings */
|
799 |
+
'port' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_port", 21),
|
800 |
+
'root' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_path"),
|
801 |
+
'passive' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_transfer_mode"),
|
802 |
+
'ssl' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_ssl_mode"),
|
803 |
+
'timeout' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_timeout", 30),
|
804 |
]);
|
805 |
|
806 |
$adapter->connect();
|
817 |
$this->logger->info(sprintf("Creating the SFTP remote storage connection"), array(""));
|
818 |
|
819 |
$adapter = new SftpAdapter([
|
820 |
+
'host' => $this->xcloner_settings->get_xcloner_option("xcloner_sftp_hostname"),
|
821 |
+
'username' => $this->xcloner_settings->get_xcloner_option("xcloner_sftp_username"),
|
822 |
+
'password' => $this->xcloner_settings->get_xcloner_option("xcloner_sftp_password"),
|
823 |
|
824 |
/** optional config settings */
|
825 |
+
'port' => $this->xcloner_settings->get_xcloner_option("xcloner_sftp_port", 22),
|
826 |
+
'root' => ($this->xcloner_settings->get_xcloner_option("xcloner_sftp_path")?$this->xcloner_settings->get_xcloner_option("xcloner_sftp_path"):'./'),
|
827 |
+
'privateKey' => $this->xcloner_settings->get_xcloner_option("xcloner_sftp_private_key"),
|
828 |
+
'timeout' => $this->xcloner_settings->get_xcloner_option("xcloner_ftp_timeout", 30),
|
829 |
]);
|
830 |
|
831 |
$adapter->connect();
|
849 |
{
|
850 |
return $this->aws_regions;
|
851 |
}
|
|
|
852 |
}
|
includes/class-xcloner-sanitization.php
CHANGED
@@ -2,58 +2,118 @@
|
|
2 |
|
3 |
use League\Flysystem\Util;
|
4 |
|
5 |
-
class Xcloner_Sanitization
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
2 |
|
3 |
use League\Flysystem\Util;
|
4 |
|
5 |
+
class Xcloner_Sanitization
|
6 |
+
{
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Construct method
|
10 |
+
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Sanitize input as INT
|
17 |
+
*
|
18 |
+
* @param [type] $option
|
19 |
+
* @return void
|
20 |
+
*/
|
21 |
+
public function sanitize_input_as_int($option)
|
22 |
+
{
|
23 |
+
return filter_var($option, FILTER_SANITIZE_NUMBER_INT);
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Sanitize input as FLOAT
|
28 |
+
*
|
29 |
+
* @param [type] $option
|
30 |
+
* @return void
|
31 |
+
*/
|
32 |
+
public function sanitize_input_as_float($option)
|
33 |
+
{
|
34 |
+
return filter_var($option, FILTER_VALIDATE_FLOAT);
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Sanitize input as STRING
|
39 |
+
*
|
40 |
+
* @param [type] $option
|
41 |
+
* @return void
|
42 |
+
*/
|
43 |
+
public function sanitize_input_as_string($option)
|
44 |
+
{
|
45 |
+
return filter_var($option, FILTER_SANITIZE_STRING);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Sanitize input as ABSOLUTE PATH
|
50 |
+
*
|
51 |
+
* @param [type] $option
|
52 |
+
* @return void
|
53 |
+
*/
|
54 |
+
public function sanitize_input_as_absolute_path($option)
|
55 |
+
{
|
56 |
+
$path = filter_var($option, FILTER_SANITIZE_URL);
|
57 |
+
|
58 |
+
try {
|
59 |
+
$option = Util::normalizePath($path);
|
60 |
+
} catch (Exception $e) {
|
61 |
+
add_settings_error('xcloner_error_message', '', __($e->getMessage()), 'error');
|
62 |
+
}
|
63 |
+
|
64 |
+
if ($path and !is_dir($path)) {
|
65 |
+
add_settings_error('xcloner_error_message', '', __(sprintf('Invalid Server Path %s', $option)), 'error');
|
66 |
+
|
67 |
+
return false;
|
68 |
+
}
|
69 |
+
|
70 |
+
return $path;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Sanitize input as PATH
|
75 |
+
*
|
76 |
+
* @param [type] $option
|
77 |
+
* @return void
|
78 |
+
*/
|
79 |
+
public function sanitize_input_as_path($option)
|
80 |
+
{
|
81 |
+
return filter_var($option, FILTER_SANITIZE_URL);
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Sanitize input as RELATIVE PATH
|
86 |
+
*
|
87 |
+
* @param [type] $option
|
88 |
+
* @return void
|
89 |
+
*/
|
90 |
+
public function sanitize_input_as_relative_path($option)
|
91 |
+
{
|
92 |
+
$option = filter_var($option, FILTER_SANITIZE_URL);
|
93 |
+
$option = str_replace("..", "", $option);
|
94 |
+
|
95 |
+
return $option;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Sanitize input as EMAIL
|
100 |
+
*
|
101 |
+
* @param [type] $option
|
102 |
+
* @return void
|
103 |
+
*/
|
104 |
+
public function sanitize_input_as_email($option)
|
105 |
+
{
|
106 |
+
return filter_var($option, FILTER_SANITIZE_EMAIL);
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Undocumented function as RAW
|
111 |
+
*
|
112 |
+
* @param [type] $option
|
113 |
+
* @return void
|
114 |
+
*/
|
115 |
+
public function sanitize_input_as_raw($option)
|
116 |
+
{
|
117 |
+
return filter_var($option, FILTER_UNSAFE_RAW);
|
118 |
+
}
|
119 |
}
|
includes/class-xcloner-scheduler.php
CHANGED
@@ -1,438 +1,455 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class Xcloner_Scheduler
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
|
18 |
-
|
19 |
-
/*public function __call($method, $args) {
|
20 |
-
echo "$method is not defined";
|
21 |
-
}*/
|
22 |
-
|
23 |
-
public function __construct(Xcloner $xcloner_container) {
|
24 |
-
global $wpdb;
|
25 |
-
|
26 |
-
$this->db = $wpdb;
|
27 |
-
$wpdb->show_errors = false;
|
28 |
-
|
29 |
-
$this->xcloner_container = $xcloner_container;
|
30 |
-
$this->xcloner_settings = $this->xcloner_container->get_xcloner_settings();
|
31 |
-
|
32 |
-
$this->scheduler_table = $this->db->prefix.$this->scheduler_table;
|
33 |
-
}
|
34 |
-
|
35 |
-
private function get_xcloner_container() {
|
36 |
-
return $this->xcloner_container;
|
37 |
-
}
|
38 |
-
|
39 |
-
private function set_xcloner_container(Xcloner $container) {
|
40 |
-
$this->xcloner_container = $container;
|
41 |
-
}
|
42 |
-
|
43 |
-
public function get_scheduler_list($return_only_enabled = 0) {
|
44 |
-
$list = $this->db->get_results("SELECT * FROM ".$this->scheduler_table);
|
45 |
-
|
46 |
-
if ($return_only_enabled) {
|
47 |
-
$new_list = array();
|
48 |
-
|
49 |
-
foreach ($list as $res) {
|
50 |
-
if ($res->status) {
|
51 |
-
$res->next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id)) + (get_option('gmt_offset') * HOUR_IN_SECONDS);
|
52 |
-
$new_list[] = $res;
|
53 |
-
}
|
54 |
-
}
|
55 |
-
$list = $new_list;
|
56 |
-
}
|
57 |
-
|
58 |
-
return $list;
|
59 |
-
}
|
60 |
-
|
61 |
-
public function get_next_run_schedule( ) {
|
62 |
-
$list = $this->get_scheduler_list($return_only_enabled = 1);
|
63 |
-
|
64 |
-
return $list;
|
65 |
-
}
|
66 |
-
|
67 |
-
public function get_schedule_by_id_object($id) {
|
68 |
-
$data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id);
|
69 |
-
|
70 |
-
return $data;
|
71 |
-
}
|
72 |
-
|
73 |
-
public function get_schedule_by_id($id) {
|
74 |
-
$data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id, ARRAY_A);
|
75 |
-
|
76 |
-
if (!$data) {
|
77 |
-
return false;
|
78 |
-
}
|
79 |
-
|
80 |
-
$params = json_decode($data['params']);
|
81 |
-
|
82 |
-
//print_r($params);
|
83 |
-
$data['params'] = "";
|
84 |
-
$data['backup_params'] = $params->backup_params;
|
85 |
-
$data['table_params'] = json_encode($params->database);
|
86 |
-
$data['excluded_files'] = json_encode($params->excluded_files);
|
87 |
-
|
88 |
-
return $data;
|
89 |
-
}
|
90 |
-
|
91 |
-
public function delete_schedule_by_id($id) {
|
92 |
-
$hook = 'xcloner_scheduler_'.$id;
|
93 |
-
wp_clear_scheduled_hook($hook, array($id));
|
94 |
-
|
95 |
-
$data = $this->db->delete($this->scheduler_table, array('id' => $id));
|
96 |
-
|
97 |
-
return $data;
|
98 |
-
}
|
99 |
-
|
100 |
-
public function deactivate_wp_cron_hooks() {
|
101 |
-
$list = $this->get_scheduler_list();
|
102 |
-
|
103 |
-
foreach ($list as $schedule) {
|
104 |
-
$hook = 'xcloner_scheduler_'.$schedule->id;
|
105 |
-
|
106 |
-
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
107 |
-
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
108 |
-
}
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
public function update_wp_cron_hooks() {
|
113 |
-
$list = $this->get_scheduler_list();
|
114 |
-
|
115 |
-
foreach ($list as $schedule) {
|
116 |
-
$hook = 'xcloner_scheduler_'.$schedule->id;
|
117 |
-
|
118 |
-
//adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
|
119 |
-
add_action($hook, array($this, 'xcloner_scheduler_callback'), 10, 1);
|
120 |
-
|
121 |
-
if (!wp_next_scheduled($hook, array($schedule->id)) and $schedule->status) {
|
122 |
-
|
123 |
-
if ($schedule->recurrence == "single") {
|
124 |
-
wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
|
125 |
-
} else {
|
126 |
-
wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
|
127 |
-
}
|
128 |
-
|
129 |
-
} elseif (!$schedule->status) {
|
130 |
-
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
131 |
-
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
132 |
-
}
|
133 |
-
}
|
134 |
-
}
|
135 |
-
|
136 |
-
}
|
137 |
-
|
138 |
-
public function update_cron_hook($id) {
|
139 |
-
$schedule = $this->get_schedule_by_id_object($id);
|
140 |
-
$hook = 'xcloner_scheduler_'.$schedule->id;
|
141 |
-
|
142 |
-
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
143 |
-
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
144 |
-
}
|
145 |
-
|
146 |
-
if ($schedule->status) {
|
147 |
-
|
148 |
-
if ($schedule->recurrence == "single") {
|
149 |
-
wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
|
150 |
-
} else {
|
151 |
-
wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
|
152 |
-
}
|
153 |
-
|
154 |
-
}
|
155 |
-
}
|
156 |
-
|
157 |
-
public function disable_single_cron($schedule_id) {
|
158 |
-
$schedule = array();
|
159 |
-
$hook = 'xcloner_scheduler_'.$schedule_id;
|
160 |
-
|
161 |
-
if ($timestamp = wp_next_scheduled($hook, array($schedule_id))) {
|
162 |
-
wp_unschedule_event($timestamp, $hook, array($schedule_id));
|
163 |
-
}
|
164 |
-
|
165 |
-
$schedule['status'] = 0;
|
166 |
-
|
167 |
-
$update = $this->db->update(
|
168 |
-
$this->scheduler_table,
|
169 |
-
$schedule,
|
170 |
-
array('id' => $schedule_id),
|
171 |
-
array(
|
172 |
-
'%s',
|
173 |
-
'%s'
|
174 |
-
)
|
175 |
-
);
|
176 |
-
|
177 |
-
return $update;
|
178 |
-
}
|
179 |
-
|
180 |
-
public function update_hash($schedule_id, $hash) {
|
181 |
-
$schedule = array();
|
182 |
-
|
183 |
-
$schedule['hash'] = $hash;
|
184 |
-
|
185 |
-
$update = $this->db->update(
|
186 |
-
$this->scheduler_table,
|
187 |
-
$schedule,
|
188 |
-
array('id' => $schedule_id),
|
189 |
-
array(
|
190 |
-
'%s',
|
191 |
-
'%s'
|
192 |
-
)
|
193 |
-
);
|
194 |
-
|
195 |
-
return $update;
|
196 |
-
}
|
197 |
-
|
198 |
-
public function update_last_backup($schedule_id, $last_backup) {
|
199 |
-
$schedule = array();
|
200 |
-
|
201 |
-
$this->logger->info(sprintf('Updating last backup %s for schedule id #%s', $last_backup, $schedule_id));
|
202 |
-
|
203 |
-
$schedule['last_backup'] = $last_backup;
|
204 |
-
|
205 |
-
$update = $this->db->update(
|
206 |
-
$this->scheduler_table,
|
207 |
-
$schedule,
|
208 |
-
array('id' => $schedule_id),
|
209 |
-
array(
|
210 |
-
'%s',
|
211 |
-
'%s'
|
212 |
-
)
|
213 |
-
);
|
214 |
-
|
215 |
-
return $update;
|
216 |
-
}
|
217 |
-
|
218 |
-
private function _xcloner_scheduler_callback($id, $schedule) {
|
219 |
-
set_time_limit(0);
|
220 |
-
|
221 |
-
|
222 |
-
$xcloner = new XCloner();
|
223 |
-
$xcloner->init();
|
224 |
-
$this->set_xcloner_container($xcloner);
|
225 |
-
$return_encrypted = array();
|
226 |
-
$return = array();
|
227 |
-
$additional = array();
|
228 |
-
|
229 |
-
#$hash = $this->xcloner_settings->get_hash();
|
230 |
-
#$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
|
231 |
-
|
232 |
-
//$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
|
233 |
-
$this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
|
234 |
-
$this->xcloner_encryption = $this->get_xcloner_container()->get_xcloner_encryption();
|
235 |
-
$this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
|
236 |
-
$this->archive_system = $this->get_xcloner_container()->get_archive_system();
|
237 |
-
$this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName("xcloner_scheduler");
|
238 |
-
$this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
239 |
-
|
240 |
-
$this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_settings->get_hash()));
|
241 |
-
|
242 |
-
if (isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date) {
|
243 |
-
$this->xcloner_file_system->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
|
244 |
-
}
|
245 |
-
|
246 |
-
if ($schedule['recurrence'] == "single") {
|
247 |
-
$this->disable_single_cron($schedule['id']);
|
248 |
-
}
|
249 |
-
|
250 |
-
if (!$schedule) {
|
251 |
-
$this->logger->info(sprintf("Could not load schedule with id'%s'", $id), array("CRON"));
|
252 |
-
|
253 |
-
return;
|
254 |
-
}
|
255 |
-
|
256 |
-
//echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
|
257 |
-
|
258 |
-
$this->update_hash($schedule['id'], $this->xcloner_settings->get_hash());
|
259 |
-
|
260 |
-
$this->logger->info(sprintf("Starting cron schedule '%s'", $schedule['name']), array("CRON"));
|
261 |
-
|
262 |
-
$this->xcloner_file_system->set_excluded_files(json_decode($schedule['excluded_files']));
|
263 |
-
|
264 |
-
$init = 1;
|
265 |
-
$continue = 1;
|
266 |
-
|
267 |
-
while ($continue) {
|
268 |
-
$continue = $this->xcloner_file_system->start_file_recursion($init);
|
269 |
-
|
270 |
-
$init = 0;
|
271 |
-
}
|
272 |
-
|
273 |
-
$this->logger->info(sprintf("File scan finished"), array("CRON"));
|
274 |
-
|
275 |
-
$this->logger->info(sprintf("Starting the database backup"), array("CRON"));
|
276 |
-
|
277 |
-
$init = 1;
|
278 |
-
$return['finished'] = 0;
|
279 |
-
|
280 |
-
while (!$return['finished']) {
|
281 |
-
$return = $this->xcloner_database->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
|
282 |
-
$init = 0;
|
283 |
-
}
|
284 |
-
|
285 |
-
$this->logger->info(sprintf("Database backup done"), array("CRON"));
|
286 |
-
|
287 |
-
$this->logger->info(sprintf("Starting file archive process"), array("CRON"));
|
288 |
-
|
289 |
-
$init = 0;
|
290 |
-
$return['finished'] = 0;
|
291 |
-
$return['extra'] = array();
|
292 |
-
|
293 |
-
while (!$return['finished']) {
|
294 |
-
$return = $this->archive_system->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
|
295 |
-
$init = 0;
|
296 |
-
}
|
297 |
-
$this->logger->info(sprintf("File archive process FINISHED."), array("CRON"));
|
298 |
-
|
299 |
-
//getting the last backup archive file
|
300 |
-
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
|
301 |
-
if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
|
302 |
-
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
|
303 |
-
}
|
304 |
-
|
305 |
-
//Updating schedule last backup archive
|
306 |
-
$this->update_last_backup($schedule['id'], $return['extra']['backup_parent']);
|
307 |
-
|
308 |
-
//Encrypting the backup archive
|
309 |
-
$return_encrypted['finished'] = 0;
|
310 |
-
$return_encrypted['start'] = 0;
|
311 |
-
$return_encrypted['iv'] = '';
|
312 |
-
$return_encrypted['target_file'] = '';
|
313 |
-
$part = 0;
|
314 |
-
$backup_parts = array();
|
315 |
-
|
316 |
-
if (isset($schedule['backup_params']->backup_encrypt) && $schedule['backup_params']->backup_encrypt) {
|
317 |
-
$this->logger->info(sprintf("Encrypting backup archive %s.", $return['extra']['backup_parent']), array("CRON"));
|
318 |
-
|
319 |
-
$backup_file = $return['extra']['backup_parent'];
|
320 |
-
|
321 |
-
if ($this->xcloner_file_system->is_multipart($return['extra']['backup_parent'])) {
|
322 |
-
$backup_parts = $this->xcloner_file_system->get_multipart_files($return['extra']['backup_parent']);
|
323 |
-
$backup_file = $backup_parts[$part];
|
324 |
-
}
|
325 |
-
|
326 |
-
while (!$return_encrypted['finished']) {
|
327 |
-
$return_encrypted = $this->xcloner_encryption->encrypt_file(
|
328 |
-
$backup_file,
|
329 |
-
"",
|
330 |
-
"",
|
331 |
-
"",
|
332 |
-
"",
|
333 |
-
true,
|
334 |
-
true
|
335 |
-
);
|
336 |
-
|
337 |
-
if ($return_encrypted['finished']) {
|
338 |
-
++$part;
|
339 |
-
|
340 |
-
if ($part < sizeof($backup_parts)) {
|
341 |
-
$return_encrypted['finished'] = 0;
|
342 |
-
$backup_file = $backup_parts[$part];
|
343 |
-
}
|
344 |
-
}
|
345 |
-
}
|
346 |
-
}
|
347 |
-
|
348 |
-
//Sending backup to remote storage
|
349 |
-
if (isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages())) {
|
350 |
-
$backup_file = $return['extra']['backup_parent'];
|
351 |
-
|
352 |
-
$this->logger->info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
|
353 |
-
|
354 |
-
if (method_exists($this->xcloner_remote_storage, "upload_backup_to_storage")) {
|
355 |
-
call_user_func_array(array(
|
356 |
-
$this->xcloner_remote_storage,
|
357 |
-
"upload_backup_to_storage"
|
358 |
-
), array($backup_file, $schedule['remote_storage']));
|
359 |
-
}
|
360 |
-
}
|
361 |
-
|
362 |
-
//Sending email notification
|
363 |
-
if (isset($schedule['backup_params']->email_notification) and $to = $schedule['backup_params']->email_notification) {
|
364 |
-
try {
|
365 |
-
$from = "";
|
366 |
-
$additional['lines_total'] = $return['extra']['lines_total'];
|
367 |
-
$subject = sprintf(__("%s - new backup generated %s"), $schedule['name'], $return['extra']['backup_parent']);
|
368 |
-
|
369 |
-
$this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
|
370 |
-
|
371 |
-
}catch (Exception $e) {
|
372 |
-
$this->logger->error($e->getMessage());
|
373 |
-
}
|
374 |
-
}
|
375 |
-
|
376 |
-
//CHECK IF WE SHOULD DELETE BACKUP AFTER REMOTE TRANSFER IS DONE
|
377 |
-
if ($schedule['remote_storage'] && $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_delete_after_remote_transfer')) {
|
378 |
-
$this->logger->info(sprintf("Deleting %s from local storage matching rule xcloner_cleanup_delete_after_remote_transfer", $return['extra']['backup_parent']));
|
379 |
-
$this->xcloner_file_system->delete_backup_by_name($return['extra']['backup_parent']);
|
380 |
-
|
381 |
-
}
|
382 |
-
|
383 |
-
//Removing the tmp filesystem used for backup
|
384 |
-
$this->xcloner_file_system->remove_tmp_filesystem();
|
385 |
-
|
386 |
-
//Backup Storage Cleanup
|
387 |
-
$this->xcloner_file_system->backup_storage_cleanup();
|
388 |
-
|
389 |
-
//Filesystem Cleanup
|
390 |
-
$this->xcloner_file_system->cleanup_tmp_directories();
|
391 |
-
}
|
392 |
-
|
393 |
-
public function xcloner_scheduler_callback($id, $schedule = "") {
|
394 |
-
if ($id) {
|
395 |
-
$schedule = $this->get_schedule_by_id($id);
|
396 |
-
}
|
397 |
-
|
398 |
-
try {
|
399 |
-
if (get_option('xcloner_disable_email_notification')) {
|
400 |
-
//we disable email notifications
|
401 |
-
$schedule['backup_params']->email_notification = "";
|
402 |
-
}
|
403 |
-
$this->_xcloner_scheduler_callback($id, $schedule);
|
404 |
-
|
405 |
-
}catch (Exception $e) {
|
406 |
-
|
407 |
-
//send email to site admin if email notification is not set in the scheduler
|
408 |
-
if (!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification) {
|
409 |
-
$schedule['backup_params']->email_notification = get_option('admin_email');
|
410 |
-
}
|
411 |
-
|
412 |
-
if (isset($schedule['backup_params']->email_notification) && $to = $schedule['backup_params']->email_notification) {
|
413 |
-
$from = "";
|
414 |
-
$this->archive_system->send_notification($to, $from, $schedule['name']." - backup error", "", "", $e->getMessage());
|
415 |
-
}
|
416 |
-
|
417 |
-
}
|
418 |
-
|
419 |
-
}
|
420 |
-
|
421 |
-
public function get_available_intervals() {
|
422 |
-
$schedules = wp_get_schedules();
|
423 |
-
$new_schedules = array();
|
424 |
-
|
425 |
-
foreach ($schedules as $key => $row) {
|
426 |
-
if (in_array($key, $this->allowed_schedules)) {
|
427 |
-
$new_schedules[$key] = $row;
|
428 |
-
$intervals[$key] = $row['interval'];
|
429 |
-
}
|
430 |
-
}
|
431 |
-
|
432 |
-
array_multisort($intervals, SORT_ASC, $new_schedules);
|
433 |
-
|
434 |
-
return $new_schedules;
|
435 |
-
}
|
436 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
438 |
}
|
1 |
<?php
|
2 |
|
3 |
+
class Xcloner_Scheduler
|
4 |
+
{
|
5 |
+
private $db;
|
6 |
+
private $scheduler_table = "xcloner_scheduler";
|
7 |
+
|
8 |
+
private $xcloner_remote_storage;
|
9 |
+
private $archive_system;
|
10 |
+
private $xcloner_database;
|
11 |
+
private $xcloner_settings;
|
12 |
+
private $logger;
|
13 |
+
private $xcloner_file_system;
|
14 |
+
private $xcloner_encryption;
|
15 |
+
private $xcloner_container;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
+
private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
|
18 |
+
|
19 |
+
/*public function __call($method, $args) {
|
20 |
+
echo "$method is not defined";
|
21 |
+
}*/
|
22 |
+
|
23 |
+
public function __construct(Xcloner $xcloner_container)
|
24 |
+
{
|
25 |
+
//global $wpdb;
|
26 |
+
|
27 |
+
$this->xcloner_container = $xcloner_container;
|
28 |
+
$this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
|
29 |
+
$this->xcloner_settings = $this->xcloner_container->get_xcloner_settings();
|
30 |
+
|
31 |
+
$this->db = $this->xcloner_database;
|
32 |
+
$this->db->show_errors = false;
|
33 |
|
34 |
+
$this->scheduler_table = $this->xcloner_settings->get_table_prefix().$this->scheduler_table;
|
35 |
+
}
|
36 |
+
|
37 |
+
private function get_xcloner_container()
|
38 |
+
{
|
39 |
+
return $this->xcloner_container;
|
40 |
+
}
|
41 |
+
|
42 |
+
private function set_xcloner_container(Xcloner $container)
|
43 |
+
{
|
44 |
+
$this->xcloner_container = $container;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function get_scheduler_list($return_only_enabled = 0)
|
48 |
+
{
|
49 |
+
$list = $this->db->get_results("SELECT * FROM ".$this->scheduler_table);
|
50 |
+
|
51 |
+
if ($return_only_enabled) {
|
52 |
+
$new_list = array();
|
53 |
+
|
54 |
+
foreach ($list as $res) {
|
55 |
+
if ($res->status) {
|
56 |
+
$res->next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id)) + ($this->xcloner_settings->get_xcloner_option('gmt_offset') * HOUR_IN_SECONDS);
|
57 |
+
$new_list[] = $res;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
$list = $new_list;
|
61 |
+
}
|
62 |
+
|
63 |
+
return $list;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function get_next_run_schedule()
|
67 |
+
{
|
68 |
+
$list = $this->get_scheduler_list($return_only_enabled = 1);
|
69 |
+
|
70 |
+
return $list;
|
71 |
+
}
|
72 |
+
|
73 |
+
public function get_schedule_by_id_object($id)
|
74 |
+
{
|
75 |
+
$data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id);
|
76 |
+
|
77 |
+
return $data;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function get_schedule_by_id($id)
|
81 |
+
{
|
82 |
+
$data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id, ARRAY_A);
|
83 |
+
|
84 |
+
if (!$data) {
|
85 |
+
return false;
|
86 |
+
}
|
87 |
+
|
88 |
+
$params = json_decode($data['params']);
|
89 |
+
|
90 |
+
//print_r($params);
|
91 |
+
$data['params'] = "";
|
92 |
+
$data['backup_params'] = $params->backup_params;
|
93 |
+
$data['table_params'] = json_encode($params->database);
|
94 |
+
$data['excluded_files'] = json_encode($params->excluded_files);
|
95 |
+
|
96 |
+
return $data;
|
97 |
+
}
|
98 |
+
|
99 |
+
public function delete_schedule_by_id($id)
|
100 |
+
{
|
101 |
+
$hook = 'xcloner_scheduler_'.$id;
|
102 |
+
wp_clear_scheduled_hook($hook, array($id));
|
103 |
+
|
104 |
+
$data = $this->db->delete($this->scheduler_table, array('id' => $id));
|
105 |
+
|
106 |
+
return $data;
|
107 |
+
}
|
108 |
+
|
109 |
+
public function deactivate_wp_cron_hooks()
|
110 |
+
{
|
111 |
+
$list = $this->get_scheduler_list();
|
112 |
+
|
113 |
+
foreach ($list as $schedule) {
|
114 |
+
$hook = 'xcloner_scheduler_'.$schedule->id;
|
115 |
+
|
116 |
+
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
117 |
+
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
public function update_wp_cron_hooks()
|
123 |
+
{
|
124 |
+
$list = $this->get_scheduler_list();
|
125 |
+
|
126 |
+
foreach ($list as $schedule) {
|
127 |
+
$hook = 'xcloner_scheduler_'.$schedule->id;
|
128 |
+
|
129 |
+
//adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
|
130 |
+
$this->xcloner_container->get_loader()->add_action($hook, $this, 'xcloner_scheduler_callback', 10, 1);
|
131 |
+
|
132 |
+
if (!wp_next_scheduled($hook, array($schedule->id)) and $schedule->status) {
|
133 |
+
if ($schedule->recurrence == "single") {
|
134 |
+
wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
|
135 |
+
} else {
|
136 |
+
wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
|
137 |
+
}
|
138 |
+
} elseif (!$schedule->status) {
|
139 |
+
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
140 |
+
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
141 |
+
}
|
142 |
+
}
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
public function update_cron_hook($id)
|
147 |
+
{
|
148 |
+
$schedule = $this->get_schedule_by_id_object($id);
|
149 |
+
$hook = 'xcloner_scheduler_'.$schedule->id;
|
150 |
+
|
151 |
+
if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
|
152 |
+
wp_unschedule_event($timestamp, $hook, array($schedule->id));
|
153 |
+
}
|
154 |
+
|
155 |
+
if ($schedule->status) {
|
156 |
+
if ($schedule->recurrence == "single") {
|
157 |
+
wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
|
158 |
+
} else {
|
159 |
+
wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
|
164 |
+
public function disable_single_cron($schedule_id)
|
165 |
+
{
|
166 |
+
$schedule = array();
|
167 |
+
$hook = 'xcloner_scheduler_'.$schedule_id;
|
168 |
+
|
169 |
+
if ($timestamp = wp_next_scheduled($hook, array($schedule_id))) {
|
170 |
+
wp_unschedule_event($timestamp, $hook, array($schedule_id));
|
171 |
+
}
|
172 |
+
|
173 |
+
$schedule['status'] = 0;
|
174 |
+
|
175 |
+
$update = $this->db->update(
|
176 |
+
$this->scheduler_table,
|
177 |
+
$schedule,
|
178 |
+
array('id' => $schedule_id),
|
179 |
+
array(
|
180 |
+
'%s',
|
181 |
+
'%s'
|
182 |
+
)
|
183 |
+
);
|
184 |
+
|
185 |
+
return $update;
|
186 |
+
}
|
187 |
+
|
188 |
+
public function update_hash($schedule_id, $hash)
|
189 |
+
{
|
190 |
+
$schedule = array();
|
191 |
+
|
192 |
+
$schedule['hash'] = $hash;
|
193 |
+
|
194 |
+
$update = $this->db->update(
|
195 |
+
$this->scheduler_table,
|
196 |
+
$schedule,
|
197 |
+
array('id' => $schedule_id),
|
198 |
+
array(
|
199 |
+
'%s',
|
200 |
+
'%s'
|
201 |
+
)
|
202 |
+
);
|
203 |
+
|
204 |
+
return $update;
|
205 |
+
}
|
206 |
+
|
207 |
+
public function update_last_backup($schedule_id, $last_backup)
|
208 |
+
{
|
209 |
+
$schedule = array();
|
210 |
+
|
211 |
+
$this->logger->info(sprintf('Updating last backup %s for schedule id #%s', $last_backup, $schedule_id));
|
212 |
+
|
213 |
+
$schedule['last_backup'] = $last_backup;
|
214 |
+
|
215 |
+
$update = $this->db->update(
|
216 |
+
$this->scheduler_table,
|
217 |
+
$schedule,
|
218 |
+
array('id' => $schedule_id),
|
219 |
+
array(
|
220 |
+
'%s',
|
221 |
+
'%s'
|
222 |
+
)
|
223 |
+
);
|
224 |
+
|
225 |
+
return $update;
|
226 |
+
}
|
227 |
+
|
228 |
+
private function _xcloner_scheduler_callback($id, $schedule, $xcloner = "")
|
229 |
+
{
|
230 |
+
set_time_limit(0);
|
231 |
+
|
232 |
+
if (!$xcloner) {
|
233 |
+
$xcloner = new XCloner();
|
234 |
+
$xcloner->init();
|
235 |
+
}
|
236 |
+
$this->set_xcloner_container($xcloner);
|
237 |
+
$return_encrypted = array();
|
238 |
+
$return = array();
|
239 |
+
$additional = array();
|
240 |
+
|
241 |
+
#$hash = $this->xcloner_settings->get_hash();
|
242 |
+
#$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
|
243 |
+
|
244 |
+
//$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
|
245 |
+
$this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
|
246 |
+
$this->xcloner_encryption = $this->get_xcloner_container()->get_xcloner_encryption();
|
247 |
+
$this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
|
248 |
+
$this->archive_system = $this->get_xcloner_container()->get_archive_system();
|
249 |
+
$this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName("xcloner_scheduler");
|
250 |
+
$this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
|
251 |
+
|
252 |
+
|
253 |
+
$this->db = $this->xcloner_database;
|
254 |
+
$this->db->show_errors = false;
|
255 |
+
|
256 |
+
$this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_settings->get_hash()));
|
257 |
+
|
258 |
+
if (isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date) {
|
259 |
+
$this->xcloner_file_system->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
|
260 |
+
}
|
261 |
+
|
262 |
+
|
263 |
+
if ($schedule['recurrence'] == "single") {
|
264 |
+
$this->disable_single_cron($schedule['id']);
|
265 |
+
}
|
266 |
+
|
267 |
+
if (!$schedule) {
|
268 |
+
$this->logger->info(sprintf("Could not load schedule with id'%s'", $id), array("CRON"));
|
269 |
+
|
270 |
+
return;
|
271 |
+
}
|
272 |
+
|
273 |
+
//echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
|
274 |
+
if (!$xcloner) {
|
275 |
+
//we update this only in WP mode
|
276 |
+
$this->update_hash($schedule['id'], $this->xcloner_settings->get_hash());
|
277 |
+
}
|
278 |
+
|
279 |
+
$this->logger->info(sprintf("Starting cron schedule '%s'", $schedule['name']), array("CRON"));
|
280 |
+
|
281 |
+
$this->xcloner_file_system->set_excluded_files(json_decode($schedule['excluded_files']));
|
282 |
+
|
283 |
+
$init = 1;
|
284 |
+
$continue = 1;
|
285 |
+
|
286 |
+
while ($continue) {
|
287 |
+
$continue = $this->xcloner_file_system->start_file_recursion($init);
|
288 |
+
|
289 |
+
$init = 0;
|
290 |
+
}
|
291 |
+
|
292 |
+
$this->logger->info(sprintf("File scan finished"), array("CRON"));
|
293 |
+
|
294 |
+
$this->logger->info(sprintf("Starting the database backup"), array("CRON"));
|
295 |
+
|
296 |
+
$init = 1;
|
297 |
+
$return['finished'] = 0;
|
298 |
+
|
299 |
+
while (!$return['finished']) {
|
300 |
+
$return = $this->xcloner_database->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
|
301 |
+
$init = 0;
|
302 |
+
}
|
303 |
+
|
304 |
+
$this->logger->info(sprintf("Database backup done"), array("CRON"));
|
305 |
+
|
306 |
+
$this->logger->info(sprintf("Starting file archive process"), array("CRON"));
|
307 |
+
|
308 |
+
$init = 0;
|
309 |
+
$return['finished'] = 0;
|
310 |
+
$return['extra'] = array();
|
311 |
+
|
312 |
+
while (!$return['finished']) {
|
313 |
+
$return = $this->archive_system->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
|
314 |
+
$init = 0;
|
315 |
+
}
|
316 |
+
$this->logger->info(sprintf("File archive process FINISHED."), array("CRON"));
|
317 |
+
|
318 |
+
//getting the last backup archive file
|
319 |
+
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
|
320 |
+
if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
|
321 |
+
$return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
|
322 |
+
}
|
323 |
+
|
324 |
+
//Updating schedule last backup archive
|
325 |
+
$this->update_last_backup($schedule['id'], $return['extra']['backup_parent']);
|
326 |
+
|
327 |
+
//Encrypting the backup archive
|
328 |
+
$return_encrypted['finished'] = 0;
|
329 |
+
$return_encrypted['start'] = 0;
|
330 |
+
$return_encrypted['iv'] = '';
|
331 |
+
$return_encrypted['target_file'] = '';
|
332 |
+
$part = 0;
|
333 |
+
$backup_parts = array();
|
334 |
+
|
335 |
+
if (isset($schedule['backup_params']->backup_encrypt) && $schedule['backup_params']->backup_encrypt) {
|
336 |
+
$this->logger->info(sprintf("Encrypting backup archive %s.", $return['extra']['backup_parent']), array("CRON"));
|
337 |
+
|
338 |
+
$backup_file = $return['extra']['backup_parent'];
|
339 |
+
|
340 |
+
if ($this->xcloner_file_system->is_multipart($return['extra']['backup_parent'])) {
|
341 |
+
$backup_parts = $this->xcloner_file_system->get_multipart_files($return['extra']['backup_parent']);
|
342 |
+
$backup_file = $backup_parts[$part];
|
343 |
+
}
|
344 |
+
|
345 |
+
while (!$return_encrypted['finished']) {
|
346 |
+
$return_encrypted = $this->xcloner_encryption->encrypt_file(
|
347 |
+
$backup_file,
|
348 |
+
"",
|
349 |
+
"",
|
350 |
+
"",
|
351 |
+
"",
|
352 |
+
true,
|
353 |
+
true
|
354 |
+
);
|
355 |
+
|
356 |
+
if ($return_encrypted['finished']) {
|
357 |
+
++$part;
|
358 |
+
|
359 |
+
if ($part < sizeof($backup_parts)) {
|
360 |
+
$return_encrypted['finished'] = 0;
|
361 |
+
$backup_file = $backup_parts[$part];
|
362 |
+
}
|
363 |
+
}
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
//Sending backup to remote storage
|
368 |
+
if (isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages())) {
|
369 |
+
$backup_file = $return['extra']['backup_parent'];
|
370 |
+
|
371 |
+
$this->logger->info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
|
372 |
+
|
373 |
+
if (method_exists($this->xcloner_remote_storage, "upload_backup_to_storage")) {
|
374 |
+
call_user_func_array(array(
|
375 |
+
$this->xcloner_remote_storage,
|
376 |
+
"upload_backup_to_storage"
|
377 |
+
), array($backup_file, $schedule['remote_storage']));
|
378 |
+
}
|
379 |
+
}
|
380 |
+
|
381 |
+
//Sending email notification
|
382 |
+
if (isset($schedule['backup_params']->email_notification) and $to = $schedule['backup_params']->email_notification) {
|
383 |
+
try {
|
384 |
+
$from = "";
|
385 |
+
$additional['lines_total'] = $return['extra']['lines_total'];
|
386 |
+
$subject = sprintf(__("%s - new backup generated %s"), $schedule['name'], $return['extra']['backup_parent']);
|
387 |
+
|
388 |
+
$this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
|
389 |
+
} catch (Exception $e) {
|
390 |
+
$this->logger->error($e->getMessage());
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
//CHECK IF WE SHOULD DELETE BACKUP AFTER REMOTE TRANSFER IS DONE
|
395 |
+
if ($schedule['remote_storage'] && $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_delete_after_remote_transfer')) {
|
396 |
+
$this->logger->info(sprintf("Deleting %s from local storage matching rule xcloner_cleanup_delete_after_remote_transfer", $return['extra']['backup_parent']));
|
397 |
+
$this->xcloner_file_system->delete_backup_by_name($return['extra']['backup_parent']);
|
398 |
+
}
|
399 |
+
|
400 |
+
//Backup Storage Cleanup
|
401 |
+
$this->xcloner_file_system->backup_storage_cleanup();
|
402 |
+
|
403 |
+
//Filesystem Cleanup
|
404 |
+
$this->xcloner_file_system->cleanup_tmp_directories();
|
405 |
+
|
406 |
+
//Removing the tmp filesystem used for backup
|
407 |
+
$this->xcloner_file_system->remove_tmp_filesystem();
|
408 |
+
|
409 |
+
return $return;
|
410 |
+
}
|
411 |
+
|
412 |
+
public function xcloner_scheduler_callback($id, $schedule = "", $xcloner = "")
|
413 |
+
{
|
414 |
+
if ($id) {
|
415 |
+
$schedule = $this->get_schedule_by_id($id);
|
416 |
+
}
|
417 |
+
|
418 |
+
try {
|
419 |
+
if ($this->xcloner_settings->get_xcloner_option('xcloner_disable_email_notification')) {
|
420 |
+
//we disable email notifications
|
421 |
+
$schedule['backup_params']->email_notification = "";
|
422 |
+
}
|
423 |
+
|
424 |
+
return $this->_xcloner_scheduler_callback($id, $schedule, $xcloner);
|
425 |
+
} catch (Exception $e) {
|
426 |
+
|
427 |
+
//send email to site admin if email notification is not set in the scheduler
|
428 |
+
if (!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification) {
|
429 |
+
$schedule['backup_params']->email_notification = $this->xcloner_settings->get_xcloner_option('admin_email');
|
430 |
+
}
|
431 |
+
|
432 |
+
if (isset($schedule['backup_params']->email_notification) && $to = $schedule['backup_params']->email_notification) {
|
433 |
+
$from = "";
|
434 |
+
$this->archive_system->send_notification($to, $from, $schedule['name']." - backup error", "", "", $e->getMessage());
|
435 |
+
}
|
436 |
+
}
|
437 |
+
}
|
438 |
+
|
439 |
+
public function get_available_intervals()
|
440 |
+
{
|
441 |
+
$schedules = wp_get_schedules();
|
442 |
+
$new_schedules = array();
|
443 |
+
|
444 |
+
foreach ($schedules as $key => $row) {
|
445 |
+
if (in_array($key, $this->allowed_schedules)) {
|
446 |
+
$new_schedules[$key] = $row;
|
447 |
+
$intervals[$key] = $row['interval'];
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
array_multisort($intervals, SORT_ASC, $new_schedules);
|
452 |
+
|
453 |
+
return $new_schedules;
|
454 |
+
}
|
455 |
}
|
includes/class-xcloner-settings.php
CHANGED
@@ -1,765 +1,967 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class Xcloner_Settings
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
|
202 |
-
public function get_db_database() {
|
203 |
-
global $wpdb;
|
204 |
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
if ($strlen) {
|
231 |
-
$hash = substr($hash, 0, $strlen);
|
232 |
-
}
|
233 |
-
|
234 |
-
return $hash;
|
235 |
-
}
|
236 |
-
|
237 |
-
public function settings_init() {
|
238 |
-
global $wpdb;
|
239 |
-
$this->xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
|
240 |
-
|
241 |
-
//ADDING MISSING OPTIONS
|
242 |
-
if (false == get_option('xcloner_mysql_settings_page')) {
|
243 |
-
add_option('xcloner_mysql_settings_page');
|
244 |
-
} // end if
|
245 |
-
|
246 |
-
if (false == get_option('xcloner_cron_settings_page')) {
|
247 |
-
add_option('xcloner_cron_settings_page');
|
248 |
-
} // end if
|
249 |
-
|
250 |
-
if (false == get_option('xcloner_system_settings_page')) {
|
251 |
-
add_option('xcloner_system_settings_page');
|
252 |
-
} // end if
|
253 |
-
|
254 |
-
if (false == get_option('xcloner_cleanup_settings_page')) {
|
255 |
-
add_option('xcloner_cleanup_settings_page');
|
256 |
-
} // end if
|
257 |
-
|
258 |
-
|
259 |
-
//ADDING SETTING SECTIONS
|
260 |
-
//GENERAL section
|
261 |
-
add_settings_section(
|
262 |
-
'xcloner_general_settings_group',
|
263 |
-
__(' '),
|
264 |
-
array($this, 'xcloner_settings_section_cb'),
|
265 |
-
'xcloner_settings_page'
|
266 |
-
);
|
267 |
-
//MYSQL section
|
268 |
-
add_settings_section(
|
269 |
-
'xcloner_mysql_settings_group',
|
270 |
-
__(' '),
|
271 |
-
array($this, 'xcloner_settings_section_cb'),
|
272 |
-
'xcloner_mysql_settings_page'
|
273 |
-
);
|
274 |
-
|
275 |
-
//SYSTEM section
|
276 |
-
add_settings_section(
|
277 |
-
'xcloner_system_settings_group',
|
278 |
-
__('These are advanced options recommended for developers!', 'xcloner-backup-and-restore'),
|
279 |
-
array($this, 'xcloner_settings_section_cb'),
|
280 |
-
'xcloner_system_settings_page'
|
281 |
-
);
|
282 |
-
|
283 |
-
//CLEANUP section
|
284 |
-
add_settings_section(
|
285 |
-
'xcloner_cleanup_settings_group',
|
286 |
-
__(' '),
|
287 |
-
array($this, 'xcloner_settings_section_cb'),
|
288 |
-
'xcloner_cleanup_settings_page'
|
289 |
-
);
|
290 |
-
|
291 |
-
|
292 |
-
//CRON section
|
293 |
-
add_settings_section(
|
294 |
-
'xcloner_cron_settings_group',
|
295 |
-
__(' '),
|
296 |
-
array($this, 'xcloner_settings_section_cb'),
|
297 |
-
'xcloner_cron_settings_page'
|
298 |
-
);
|
299 |
-
|
300 |
-
|
301 |
-
//REGISTERING THE 'GENERAL SECTION' FIELDS
|
302 |
-
register_setting('xcloner_general_settings_group', 'xcloner_backup_compression_level', array(
|
303 |
-
$this->xcloner_sanitization,
|
304 |
-
"sanitize_input_as_int"
|
305 |
-
));
|
306 |
-
add_settings_field(
|
307 |
-
'xcloner_backup_compression_level',
|
308 |
-
__('Backup Compression Level', 'xcloner-backup-and-restore'),
|
309 |
-
array($this, 'do_form_range_field'),
|
310 |
-
'xcloner_settings_page',
|
311 |
-
'xcloner_general_settings_group',
|
312 |
-
array(
|
313 |
-
'xcloner_backup_compression_level',
|
314 |
-
__('Options between [0-9]. Value 0 means no compression, while 9 is maximum compression affecting cpu load', 'xcloner-backup-and-restore'),
|
315 |
-
0,
|
316 |
-
9
|
317 |
-
)
|
318 |
-
);
|
319 |
-
|
320 |
-
register_setting('xcloner_general_settings_group', 'xcloner_start_path', array(
|
321 |
-
$this->xcloner_sanitization,
|
322 |
-
"sanitize_input_as_absolute_path"
|
323 |
-
));
|
324 |
-
add_settings_field(
|
325 |
-
'xcloner_start_path',
|
326 |
-
__('Backup Start Location', 'xcloner-backup-and-restore'),
|
327 |
-
array($this, 'do_form_text_field'),
|
328 |
-
'xcloner_settings_page',
|
329 |
-
'xcloner_general_settings_group',
|
330 |
-
array(
|
331 |
-
'xcloner_start_path',
|
332 |
-
__('Base path location from where XCloner can start the Backup.', 'xcloner-backup-and-restore'),
|
333 |
-
$this->get_xcloner_start_path(),
|
334 |
-
//'disabled'
|
335 |
-
)
|
336 |
-
);
|
337 |
-
|
338 |
-
register_setting('xcloner_general_settings_group', 'xcloner_store_path', array(
|
339 |
-
$this->xcloner_sanitization,
|
340 |
-
"sanitize_input_as_absolute_path"
|
341 |
-
));
|
342 |
-
add_settings_field(
|
343 |
-
'xcloner_store_path',
|
344 |
-
__('Backup Storage Location', 'xcloner-backup-and-restore'),
|
345 |
-
array($this, 'do_form_text_field'),
|
346 |
-
'xcloner_settings_page',
|
347 |
-
'xcloner_general_settings_group',
|
348 |
-
array(
|
349 |
-
'xcloner_store_path',
|
350 |
-
__('Location where XCloner will store the Backup archives.', 'xcloner-backup-and-restore'),
|
351 |
-
$this->get_xcloner_store_path(),
|
352 |
-
//'disabled'
|
353 |
-
)
|
354 |
-
);
|
355 |
-
|
356 |
-
register_setting('xcloner_general_settings_group', 'xcloner_encryption_key', array(
|
357 |
-
$this->xcloner_sanitization,
|
358 |
-
"sanitize_input_as_string"
|
359 |
-
));
|
360 |
-
add_settings_field(
|
361 |
-
'xcloner_encryption_key',
|
362 |
-
__('Backup Encryption Key', 'xcloner-backup-and-restore'),
|
363 |
-
array($this, 'do_form_text_field'),
|
364 |
-
'xcloner_settings_page',
|
365 |
-
'xcloner_general_settings_group',
|
366 |
-
array(
|
367 |
-
'xcloner_encryption_key',
|
368 |
-
__('Backup Encryption Key used to Encrypt/Decrypt backups, you might want to save this somewhere else as well.', 'xcloner-backup-and-restore'),
|
369 |
-
$this->get_xcloner_encryption_key(),
|
370 |
-
//'disabled'
|
371 |
-
)
|
372 |
-
);
|
373 |
-
|
374 |
-
register_setting('xcloner_general_settings_group', 'xcloner_enable_log', array(
|
375 |
-
$this->xcloner_sanitization,
|
376 |
-
"sanitize_input_as_int"
|
377 |
-
));
|
378 |
-
add_settings_field(
|
379 |
-
'xcloner_enable_log',
|
380 |
-
__('Enable XCloner Backup Log', 'xcloner-backup-and-restore'),
|
381 |
-
array($this, 'do_form_switch_field'),
|
382 |
-
'xcloner_settings_page',
|
383 |
-
'xcloner_general_settings_group',
|
384 |
-
array(
|
385 |
-
'xcloner_enable_log',
|
386 |
-
sprintf(__('Enable the XCloner Backup log. You will find it stored unde the Backup Storage Location, file %s', 'xcloner-backup-and-restore'), $this->get_logger_filename())
|
387 |
-
)
|
388 |
-
);
|
389 |
-
|
390 |
-
register_setting('xcloner_general_settings_group', 'xcloner_enable_pre_update_backup', array(
|
391 |
-
$this->xcloner_sanitization,
|
392 |
-
"sanitize_input_as_int"
|
393 |
-
));
|
394 |
-
add_settings_field(
|
395 |
-
'xcloner_enable_pre_update_backup',
|
396 |
-
__('Generate Backups before Automatic WP Upgrades', 'xcloner-backup-and-restore'),
|
397 |
-
array($this, 'do_form_switch_field'),
|
398 |
-
'xcloner_settings_page',
|
399 |
-
'xcloner_general_settings_group',
|
400 |
-
array(
|
401 |
-
'xcloner_enable_pre_update_backup',
|
402 |
-
sprintf(__('Attempt to generate a core, plugins, themes or languages files backup before the automatic update of Wordpress core, plugins, themes or languages files.', 'xcloner-backup-and-restore'), $this->get_logger_filename())
|
403 |
-
)
|
404 |
-
);
|
405 |
-
|
406 |
-
register_setting('xcloner_general_settings_group', 'xcloner_regex_exclude', array(
|
407 |
-
$this->xcloner_sanitization,
|
408 |
-
"sanitize_input_as_raw"
|
409 |
-
));
|
410 |
-
add_settings_field(
|
411 |
-
'xcloner_regex_exclude',
|
412 |
-
__('Regex Exclude Files', 'xcloner-backup-and-restore'),
|
413 |
-
array($this, 'do_form_textarea_field'),
|
414 |
-
'xcloner_settings_page',
|
415 |
-
'xcloner_general_settings_group',
|
416 |
-
array(
|
417 |
-
'xcloner_regex_exclude',
|
418 |
-
__('Regular expression match to exclude files and folders, example patterns provided below, one pattern per line', 'xcloner-backup-and-restore'),
|
419 |
-
//$this->get_xcloner_store_path(),
|
420 |
-
//'disabled'
|
421 |
-
)
|
422 |
-
);
|
423 |
-
|
424 |
-
//REGISTERING THE 'MYSQL SECTION' FIELDS
|
425 |
-
register_setting('xcloner_mysql_settings_group', 'xcloner_enable_mysql_backup', array(
|
426 |
-
$this->xcloner_sanitization,
|
427 |
-
"sanitize_input_as_int"
|
428 |
-
));
|
429 |
-
add_settings_field(
|
430 |
-
'xcloner_enable_mysql_backup',
|
431 |
-
__('Enable Mysql Backup', 'xcloner-backup-and-restore'),
|
432 |
-
array($this, 'do_form_switch_field'),
|
433 |
-
'xcloner_mysql_settings_page',
|
434 |
-
'xcloner_mysql_settings_group',
|
435 |
-
array(
|
436 |
-
'xcloner_enable_mysql_backup',
|
437 |
-
__('Enable Mysql Backup Option. If you don\'t want to backup the database, you can disable this.', 'xcloner-backup-and-restore')
|
438 |
-
)
|
439 |
-
);
|
440 |
-
|
441 |
-
register_setting('xcloner_mysql_settings_group', 'xcloner_backup_only_wp_tables');
|
442 |
-
add_settings_field(
|
443 |
-
'xcloner_backup_only_wp_tables',
|
444 |
-
__('Backup only WP tables', 'xcloner-backup-and-restore'),
|
445 |
-
array($this, 'do_form_switch_field'),
|
446 |
-
'xcloner_mysql_settings_page',
|
447 |
-
'xcloner_mysql_settings_group',
|
448 |
-
array(
|
449 |
-
'xcloner_backup_only_wp_tables',
|
450 |
-
sprintf(__('Enable this if you only want to Backup only tables starting with \'%s\' prefix', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
451 |
-
)
|
452 |
-
);
|
453 |
-
|
454 |
-
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_hostname', array(
|
455 |
-
$this->xcloner_sanitization,
|
456 |
-
"sanitize_input_as_raw"
|
457 |
-
));
|
458 |
-
add_settings_field(
|
459 |
-
'xcloner_mysql_hostname',
|
460 |
-
__('Mysql Hostname', 'xcloner-backup-and-restore'),
|
461 |
-
array($this, 'do_form_text_field'),
|
462 |
-
'xcloner_mysql_settings_page',
|
463 |
-
'xcloner_mysql_settings_group',
|
464 |
-
array(
|
465 |
-
'xcloner_mysql_hostname',
|
466 |
-
__('Wordpress mysql hostname', 'xcloner-backup-and-restore'),
|
467 |
-
$this->get_db_hostname(),
|
468 |
-
'disabled'
|
469 |
-
)
|
470 |
-
);
|
471 |
-
|
472 |
-
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_username', array(
|
473 |
-
$this->xcloner_sanitization,
|
474 |
-
"sanitize_input_as_raw"
|
475 |
-
));
|
476 |
-
add_settings_field(
|
477 |
-
'xcloner_mysql_username',
|
478 |
-
__('Mysql Username', 'xcloner-backup-and-restore'),
|
479 |
-
array($this, 'do_form_text_field'),
|
480 |
-
'xcloner_mysql_settings_page',
|
481 |
-
'xcloner_mysql_settings_group',
|
482 |
-
array(
|
483 |
-
'xcloner_mysql_username',
|
484 |
-
__('Wordpress mysql username', 'xcloner-backup-and-restore'),
|
485 |
-
$this->get_db_username(),
|
486 |
-
'disabled'
|
487 |
-
)
|
488 |
-
);
|
489 |
-
|
490 |
-
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_database', array(
|
491 |
-
$this->xcloner_sanitization,
|
492 |
-
"sanitize_input_as_raw"
|
493 |
-
));
|
494 |
-
add_settings_field(
|
495 |
-
'xcloner_mysql_database',
|
496 |
-
__('Mysql Database', 'xcloner-backup-and-restore'),
|
497 |
-
array($this, 'do_form_text_field'),
|
498 |
-
'xcloner_mysql_settings_page',
|
499 |
-
'xcloner_mysql_settings_group',
|
500 |
-
array(
|
501 |
-
'xcloner_mysql_database',
|
502 |
-
__('Wordpress mysql database', 'xcloner-backup-and-restore'),
|
503 |
-
$this->get_db_database(),
|
504 |
-
'disabled'
|
505 |
-
)
|
506 |
-
);
|
507 |
-
|
508 |
-
//REGISTERING THE 'SYSTEM SECTION' FIELDS
|
509 |
-
register_setting('xcloner_system_settings_group', 'xcloner_size_limit_per_request', array(
|
510 |
-
$this->xcloner_sanitization,
|
511 |
-
"sanitize_input_as_int"
|
512 |
-
));
|
513 |
-
add_settings_field(
|
514 |
-
'xcloner_size_limit_per_request',
|
515 |
-
__('Data Size Limit Per Request', 'xcloner-backup-and-restore'),
|
516 |
-
array($this, 'do_form_range_field'),
|
517 |
-
'xcloner_system_settings_page',
|
518 |
-
'xcloner_system_settings_group',
|
519 |
-
array(
|
520 |
-
'xcloner_size_limit_per_request',
|
521 |
-
__('Use this option to set how much file data can XCloner backup in one AJAX request. Range 0-1024 MB', 'xcloner-backup-and-restore'),
|
522 |
-
0,
|
523 |
-
1024
|
524 |
-
)
|
525 |
-
);
|
526 |
-
|
527 |
-
register_setting('xcloner_system_settings_group', 'xcloner_files_to_process_per_request', array(
|
528 |
-
$this->xcloner_sanitization,
|
529 |
-
"sanitize_input_as_int"
|
530 |
-
));
|
531 |
-
add_settings_field(
|
532 |
-
'xcloner_files_to_process_per_request',
|
533 |
-
__('Files To Process Per Request', 'xcloner-backup-and-restore'),
|
534 |
-
array($this, 'do_form_range_field'),
|
535 |
-
'xcloner_system_settings_page',
|
536 |
-
'xcloner_system_settings_group',
|
537 |
-
array(
|
538 |
-
'xcloner_files_to_process_per_request',
|
539 |
-
__('Use this option to set how many files XCloner should process at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
|
540 |
-
0,
|
541 |
-
1000
|
542 |
-
)
|
543 |
-
);
|
544 |
-
|
545 |
-
register_setting('xcloner_system_settings_group', 'xcloner_directories_to_scan_per_request', array(
|
546 |
-
$this->xcloner_sanitization,
|
547 |
-
"sanitize_input_as_int"
|
548 |
-
));
|
549 |
-
add_settings_field(
|
550 |
-
'xcloner_directories_to_scan_per_request',
|
551 |
-
__('Directories To Scan Per Request', 'xcloner-backup-and-restore'),
|
552 |
-
array($this, 'do_form_range_field'),
|
553 |
-
'xcloner_system_settings_page',
|
554 |
-
'xcloner_system_settings_group',
|
555 |
-
array(
|
556 |
-
'xcloner_directories_to_scan_per_request',
|
557 |
-
__('Use this option to set how many directories XCloner should scan at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
|
558 |
-
0,
|
559 |
-
1000
|
560 |
-
)
|
561 |
-
);
|
562 |
-
|
563 |
-
register_setting('xcloner_system_settings_group', 'xcloner_database_records_per_request', array(
|
564 |
-
$this->xcloner_sanitization,
|
565 |
-
"sanitize_input_as_int"
|
566 |
-
));
|
567 |
-
add_settings_field(
|
568 |
-
'xcloner_database_records_per_request',
|
569 |
-
__('Database Records Per Request', 'xcloner-backup-and-restore'),
|
570 |
-
array($this, 'do_form_range_field'),
|
571 |
-
'xcloner_system_settings_page',
|
572 |
-
'xcloner_system_settings_group',
|
573 |
-
array(
|
574 |
-
'xcloner_database_records_per_request',
|
575 |
-
__('Use this option to set how many database table records should be fetched per AJAX request, or set to 0 to fetch all. Range 0-100000 records', 'xcloner-backup-and-restore'),
|
576 |
-
0,
|
577 |
-
100000
|
578 |
-
)
|
579 |
-
);
|
580 |
-
|
581 |
-
/*register_setting('xcloner_system_settings_group', 'xcloner_diff_backup_recreate_period', array($this->xcloner_sanitization, "sanitize_input_as_int"));
|
582 |
-
add_settings_field(
|
583 |
-
'xcloner_diff_backup_recreate_period',
|
584 |
-
__('Differetial Backups Max Days','xcloner-backup-and-restore'),
|
585 |
-
array($this, 'do_form_number_field'),
|
586 |
-
'xcloner_system_settings_page',
|
587 |
-
'xcloner_system_settings_group',
|
588 |
-
array('xcloner_diff_backup_recreate_period',
|
589 |
-
__('Use this option to set when a full backup should be recreated if the scheduled backup type is set to \'Full Backup+Differential Backups\' ','xcloner-backup-and-restore'),
|
590 |
-
)
|
591 |
-
);*/
|
592 |
-
|
593 |
-
register_setting('xcloner_system_settings_group', 'xcloner_exclude_files_larger_than_mb', array(
|
594 |
-
$this->xcloner_sanitization,
|
595 |
-
"sanitize_input_as_int"
|
596 |
-
));
|
597 |
-
add_settings_field(
|
598 |
-
'xcloner_exclude_files_larger_than_mb',
|
599 |
-
__('Exclude files larger than (MB)', 'xcloner-backup-and-restore'),
|
600 |
-
array($this, 'do_form_number_field'),
|
601 |
-
'xcloner_system_settings_page',
|
602 |
-
'xcloner_system_settings_group',
|
603 |
-
array(
|
604 |
-
'xcloner_exclude_files_larger_than_mb',
|
605 |
-
__('Use this option to automatically exclude files larger than a certain size in MB, or set to 0 to include all. Range 0-1000 MB', 'xcloner-backup-and-restore'),
|
606 |
-
)
|
607 |
-
);
|
608 |
-
|
609 |
-
register_setting('xcloner_system_settings_group', 'xcloner_split_backup_limit', array(
|
610 |
-
$this->xcloner_sanitization,
|
611 |
-
"sanitize_input_as_int"
|
612 |
-
));
|
613 |
-
add_settings_field(
|
614 |
-
'xcloner_split_backup_limit',
|
615 |
-
__('Split Backup Archive Limit (MB)', 'xcloner-backup-and-restore'),
|
616 |
-
array($this, 'do_form_number_field'),
|
617 |
-
'xcloner_system_settings_page',
|
618 |
-
'xcloner_system_settings_group',
|
619 |
-
array(
|
620 |
-
'xcloner_split_backup_limit',
|
621 |
-
__('Use this option to automatically split the backup archive into smaller parts. Range 0-10000 MB', 'xcloner-backup-and-restore'),
|
622 |
-
)
|
623 |
-
);
|
624 |
-
|
625 |
-
register_setting('xcloner_system_settings_group', 'xcloner_force_tmp_path_site_root');
|
626 |
-
add_settings_field(
|
627 |
-
'xcloner_force_tmp_path_site_root',
|
628 |
-
__('Force Temporary Path Within XCloner Storage', 'xcloner-backup-and-restore'),
|
629 |
-
array($this, 'do_form_switch_field'),
|
630 |
-
'xcloner_system_settings_page',
|
631 |
-
'xcloner_system_settings_group',
|
632 |
-
array(
|
633 |
-
'xcloner_force_tmp_path_site_root',
|
634 |
-
sprintf(__('Enable this option if you want the XCloner Temporary Path to be within your XCloner Storage Location', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
635 |
-
)
|
636 |
-
);
|
637 |
-
|
638 |
-
register_setting('xcloner_system_settings_group', 'xcloner_disable_email_notification');
|
639 |
-
add_settings_field(
|
640 |
-
'xcloner_disable_email_notification',
|
641 |
-
__('Disable Email Notifications', 'xcloner-backup-and-restore'),
|
642 |
-
array($this, 'do_form_switch_field'),
|
643 |
-
'xcloner_system_settings_page',
|
644 |
-
'xcloner_system_settings_group',
|
645 |
-
array(
|
646 |
-
'xcloner_disable_email_notification',
|
647 |
-
sprintf(__('Enable this option if you want the XCloner to NOT send email notifications on successful backups', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
648 |
-
)
|
649 |
-
);
|
650 |
-
|
651 |
-
//REGISTERING THE 'CLEANUP SECTION' FIELDS
|
652 |
-
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_days', array(
|
653 |
-
$this->xcloner_sanitization,
|
654 |
-
"sanitize_input_as_int"
|
655 |
-
));
|
656 |
-
add_settings_field(
|
657 |
-
'xcloner_cleanup_retention_limit_days',
|
658 |
-
__('Cleanup by Date(days)', 'xcloner-backup-and-restore'),
|
659 |
-
array($this, 'do_form_number_field'),
|
660 |
-
'xcloner_cleanup_settings_page',
|
661 |
-
'xcloner_cleanup_settings_group',
|
662 |
-
array(
|
663 |
-
'xcloner_cleanup_retention_limit_days',
|
664 |
-
__('Specify the maximum number of days a backup archive can be kept on the server. 0 disables this option', 'xcloner-backup-and-restore')
|
665 |
-
)
|
666 |
-
);
|
667 |
-
|
668 |
-
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_archives', array(
|
669 |
-
$this->xcloner_sanitization,
|
670 |
-
"sanitize_input_as_int"
|
671 |
-
));
|
672 |
-
add_settings_field(
|
673 |
-
'xcloner_cleanup_retention_limit_archives',
|
674 |
-
__('Cleanup by Quantity', 'xcloner-backup-and-restore'),
|
675 |
-
array($this, 'do_form_number_field'),
|
676 |
-
'xcloner_cleanup_settings_page',
|
677 |
-
'xcloner_cleanup_settings_group',
|
678 |
-
array(
|
679 |
-
'xcloner_cleanup_retention_limit_archives',
|
680 |
-
__('Specify the maximum number of backup archives to keep on the server. 0 disables this option', 'xcloner-backup-and-restore')
|
681 |
-
)
|
682 |
-
);
|
683 |
-
|
684 |
-
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_capacity_limit', array(
|
685 |
-
$this->xcloner_sanitization,
|
686 |
-
"sanitize_input_as_int"
|
687 |
-
));
|
688 |
-
add_settings_field(
|
689 |
-
'xcloner_cleanup_capacity_limit',
|
690 |
-
__('Cleanup by Capacity(MB)', 'xcloner-backup-and-restore'),
|
691 |
-
array($this, 'do_form_number_field'),
|
692 |
-
'xcloner_cleanup_settings_page',
|
693 |
-
'xcloner_cleanup_settings_group',
|
694 |
-
array(
|
695 |
-
'xcloner_cleanup_capacity_limit',
|
696 |
-
__('Remove oldest backups if all created backups exceed the configured limit in Megabytes. 0 disables this option', 'xcloner-backup-and-restore')
|
697 |
-
)
|
698 |
-
);
|
699 |
-
|
700 |
-
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_delete_after_remote_transfer', array(
|
701 |
-
$this->xcloner_sanitization,
|
702 |
-
"sanitize_input_as_int"
|
703 |
-
));
|
704 |
-
add_settings_field(
|
705 |
-
'xcloner_cleanup_delete_after_remote_transfer',
|
706 |
-
__('Delete Backup After Remote Storage Transfer', 'xcloner-backup-and-restore'),
|
707 |
-
array($this, 'do_form_switch_field'),
|
708 |
-
'xcloner_cleanup_settings_page',
|
709 |
-
'xcloner_cleanup_settings_group',
|
710 |
-
array(
|
711 |
-
'xcloner_cleanup_delete_after_remote_transfer',
|
712 |
-
__('Remove backup created automatically from local storage after sending the backup to Remote Storage', 'xcloner-backup-and-restore')
|
713 |
-
)
|
714 |
-
);
|
715 |
-
|
716 |
-
//REGISTERING THE 'CRON SECTION' FIELDS
|
717 |
-
register_setting('xcloner_cron_settings_group', 'xcloner_cron_frequency');
|
718 |
-
add_settings_field(
|
719 |
-
'xcloner_cron_frequency',
|
720 |
-
__('Cron frequency', 'xcloner-backup-and-restore'),
|
721 |
-
array($this, 'do_form_text_field'),
|
722 |
-
'xcloner_cron_settings_page',
|
723 |
-
'xcloner_cron_settings_group',
|
724 |
-
array(
|
725 |
-
'xcloner_cron_frequency',
|
726 |
-
__('Cron frequency')
|
727 |
-
)
|
728 |
-
);
|
729 |
-
}
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
/**
|
735 |
-
* callback functions
|
736 |
-
*/
|
737 |
-
|
738 |
-
// section content cb
|
739 |
-
public function xcloner_settings_section_cb() {
|
740 |
-
//echo '<p>WPOrg Section Introduction.</p>';
|
741 |
-
}
|
742 |
-
|
743 |
-
// text field content cb
|
744 |
-
public function do_form_text_field($params) {
|
745 |
-
if (!isset($params['3'])) {
|
746 |
-
$params[3] = 0;
|
747 |
-
}
|
748 |
-
if (!isset($params['2'])) {
|
749 |
-
$params[2] = 0;
|
750 |
-
}
|
751 |
-
|
752 |
-
list($fieldname, $label, $value, $disabled) = $params;
|
753 |
-
|
754 |
-
if (!$value) {
|
755 |
-
$value = get_option($fieldname);
|
756 |
-
}
|
757 |
-
// output the field
|
758 |
-
?>
|
759 |
<div class="row">
|
760 |
<div class="input-field col s10 m10 l8">
|
761 |
<input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
762 |
-
id="<?php echo $fieldname ?>" type="
|
763 |
value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
|
764 |
</div>
|
765 |
<div class="col s2 m2 ">
|
@@ -770,24 +972,24 @@ class Xcloner_Settings {
|
|
770 |
|
771 |
|
772 |
<?php
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
<div class="row">
|
792 |
<div class="input-field col s10 m10 l8">
|
793 |
<textarea class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
@@ -840,24 +1042,24 @@ class Xcloner_Settings {
|
|
840 |
|
841 |
|
842 |
<?php
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
<div class="row">
|
862 |
<div class="input-field col s10 m5 l3">
|
863 |
<input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
@@ -872,16 +1074,16 @@ class Xcloner_Settings {
|
|
872 |
|
873 |
|
874 |
<?php
|
875 |
-
|
876 |
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
|
|
881 |
|
882 |
-
|
883 |
-
|
884 |
-
?>
|
885 |
<div class="row">
|
886 |
<div class="input-field col s10 m10 l8">
|
887 |
<p class="range-field">
|
@@ -898,16 +1100,16 @@ class Xcloner_Settings {
|
|
898 |
</div>
|
899 |
</div>
|
900 |
<?php
|
901 |
-
|
902 |
|
903 |
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
<div class="row">
|
912 |
<div class="input-field col s10 m5 l3">
|
913 |
<div class="switch">
|
@@ -929,5 +1131,5 @@ class Xcloner_Settings {
|
|
929 |
</div>
|
930 |
</div>
|
931 |
<?php
|
932 |
-
|
933 |
}
|
1 |
<?php
|
2 |
|
3 |
+
class Xcloner_Settings
|
4 |
+
{
|
5 |
+
private $logger_file = "xcloner_main_%s.log";
|
6 |
+
private $logger_file_hash = "xcloner%s.log";
|
7 |
+
private $hash;
|
8 |
+
private $xcloner_sanitization;
|
9 |
+
private $xcloner_container;
|
10 |
+
private $xcloner_database;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* XCloner General Settings Class
|
14 |
+
*
|
15 |
+
* @param Xcloner $xcloner_container
|
16 |
+
* @param string $hash
|
17 |
+
*/
|
18 |
+
public function __construct(Xcloner $xcloner_container, $hash = "", $json_config = "")
|
19 |
+
{
|
20 |
+
if($json_config) {
|
21 |
+
foreach($json_config as $item) {
|
22 |
+
add_option($item->option_name, $item->option_value);
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
+
$this->xcloner_container = $xcloner_container;
|
27 |
+
|
28 |
+
$this->xcloner_database = $xcloner_container->get_xcloner_database();
|
29 |
+
|
30 |
+
if (isset($hash)) {
|
31 |
+
$this->set_hash($hash);
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Get XCloner Main Container
|
37 |
+
*
|
38 |
+
* @return void
|
39 |
+
*/
|
40 |
+
private function get_xcloner_container()
|
41 |
+
{
|
42 |
+
return $this->xcloner_container;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Get Logger Filename Setting
|
47 |
+
*
|
48 |
+
* @param integer $include_hash
|
49 |
+
* @return void
|
50 |
+
*/
|
51 |
+
public function get_logger_filename($include_hash = 0)
|
52 |
+
{
|
53 |
+
if ($include_hash) {
|
54 |
+
$filename = sprintf($this->logger_file_hash, $this->get_hash());
|
55 |
+
} else {
|
56 |
+
$filename = sprintf($this->logger_file, $this->get_server_unique_hash(5));
|
57 |
+
}
|
58 |
+
|
59 |
+
return $filename;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Get XCloner Backup Start Path Setting
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*/
|
67 |
+
public function get_xcloner_start_path()
|
68 |
+
{
|
69 |
+
if (!$this->get_xcloner_option('xcloner_start_path') or !is_dir(/** @scrutinizer ignore-type */$this->get_xcloner_option('xcloner_start_path'))) {
|
70 |
+
$path = realpath(ABSPATH);
|
71 |
+
} else {
|
72 |
+
$path = $this->get_xcloner_option('xcloner_start_path');
|
73 |
+
}
|
74 |
+
|
75 |
+
return $path;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Get XCloner Start Path Setting , function is in legacy mode
|
80 |
+
*
|
81 |
+
* @param [type] $dir
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
public function get_xcloner_dir_path($dir)
|
85 |
+
{
|
86 |
+
$path = $this->get_xcloner_start_path().DS.$dir;
|
87 |
+
|
88 |
+
return $path;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get XCloner Backup Store Path Setting
|
93 |
+
*
|
94 |
+
* @return void
|
95 |
+
*/
|
96 |
+
public function get_xcloner_store_path()
|
97 |
+
{
|
98 |
+
if (!$this->get_xcloner_option('xcloner_store_path') or !is_dir(/** @scrutinizer ignore-type */$this->get_xcloner_option('xcloner_store_path'))) {
|
99 |
+
return $this->xcloner_container->check_dependencies();
|
100 |
+
} else {
|
101 |
+
$path = $this->get_xcloner_option('xcloner_store_path');
|
102 |
+
}
|
103 |
+
|
104 |
+
return $path;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Get XCloner Encryption Key
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*/
|
112 |
+
public function get_xcloner_encryption_key()
|
113 |
+
{
|
114 |
+
if (!$key = $this->get_xcloner_option('xcloner_encryption_key')) {
|
115 |
+
$key = $this->xcloner_container->randomString(35);
|
116 |
+
update_option('xcloner_encryption_key', $key);
|
117 |
+
}
|
118 |
+
|
119 |
+
return $key;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Create a random string
|
124 |
+
* @author XEWeb <>
|
125 |
+
* @param $length the length of the string to create
|
126 |
+
* @return string
|
127 |
+
*/
|
128 |
+
/*public function randomString($length = 6) {
|
129 |
+
$str = "";
|
130 |
+
$characters = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
|
131 |
+
$max = count($characters) - 1;
|
132 |
+
for ($i = 0; $i < $length; $i++) {
|
133 |
+
$rand = mt_rand(0, $max);
|
134 |
+
$str .= $characters[$rand];
|
135 |
+
}
|
136 |
+
return $str;
|
137 |
+
}*/
|
138 |
+
|
139 |
+
public function get_xcloner_tmp_path_suffix()
|
140 |
+
{
|
141 |
+
return "xcloner".$this->get_hash();
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Get XCloner Temporary Path
|
146 |
+
*
|
147 |
+
* @param boolean $suffix
|
148 |
+
* @return void
|
149 |
+
*/
|
150 |
+
public function get_xcloner_tmp_path($suffix = true)
|
151 |
+
{
|
152 |
+
if ($this->get_xcloner_option('xcloner_force_tmp_path_site_root')) {
|
153 |
+
$path = $this->get_xcloner_store_path();
|
154 |
+
} else {
|
155 |
+
$path = sys_get_temp_dir();
|
156 |
+
if (!is_dir($path)) {
|
157 |
+
try {
|
158 |
+
mkdir($path);
|
159 |
+
chmod($path, 0777);
|
160 |
+
} catch (Exception $e) {
|
161 |
+
//silent catch
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
if (!is_dir($path) or !is_writeable($path)) {
|
166 |
+
$path = $this->get_xcloner_store_path();
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
if ($suffix) {
|
171 |
+
$path = $path.DS.".".$this->get_xcloner_tmp_path_suffix();
|
172 |
+
}
|
173 |
+
|
174 |
+
return $path;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Get Enable Mysql Backup Option
|
179 |
+
*
|
180 |
+
* @return void
|
181 |
+
*/
|
182 |
+
public function get_enable_mysql_backup()
|
183 |
+
{
|
184 |
+
if ($this->get_xcloner_option('xcloner_enable_mysql_backup')) {
|
185 |
+
return true;
|
186 |
+
}
|
187 |
+
|
188 |
+
return false;
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Get Backup Extension Name
|
193 |
+
*
|
194 |
+
* @param string $ext
|
195 |
+
* @return string ( hash.(tar|tgz) )
|
196 |
+
*/
|
197 |
+
public function get_backup_extension_name($ext = "")
|
198 |
+
{
|
199 |
+
if (!$ext) {
|
200 |
+
if ($this->get_xcloner_option('xcloner_backup_compression_level')) {
|
201 |
+
$ext = ".tgz";
|
202 |
+
} else {
|
203 |
+
$ext = ".tar";
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
return ($this->get_hash()).$ext;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Get Backup Hash
|
212 |
+
*
|
213 |
+
* @return void
|
214 |
+
*/
|
215 |
+
public function get_hash($readonly = false )
|
216 |
+
{
|
217 |
+
if (!$this->hash && !$readonly) {
|
218 |
+
$this->set_hash("-".$this->get_server_unique_hash(5));
|
219 |
+
}
|
220 |
+
|
221 |
+
//echo $this->hash;
|
222 |
+
return $this->hash;
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Generate New Hash
|
227 |
+
*
|
228 |
+
* @return void
|
229 |
+
*/
|
230 |
+
public function generate_new_hash()
|
231 |
+
{
|
232 |
+
$hash = "-".md5(rand());
|
233 |
+
|
234 |
+
$hash = substr($hash, 0, 6);
|
235 |
+
|
236 |
+
$this->set_hash($hash);
|
237 |
+
|
238 |
+
return $hash;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Set New Hash
|
243 |
+
*
|
244 |
+
* @param string $hash
|
245 |
+
* @return void
|
246 |
+
*/
|
247 |
+
public function set_hash($hash = "")
|
248 |
+
{
|
249 |
+
if (substr($hash, 0, 1) != "-" and strlen($hash)) {
|
250 |
+
$hash = "-".$hash;
|
251 |
+
}
|
252 |
+
|
253 |
+
$this->hash = substr($hash, 0, 6);
|
254 |
+
|
255 |
+
return $this;
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Get Default Backup Name
|
260 |
+
*
|
261 |
+
* @return void
|
262 |
+
*/
|
263 |
+
public function get_default_backup_name()
|
264 |
+
{
|
265 |
+
$data = parse_url(get_site_url());
|
266 |
+
|
267 |
+
$backup_name = "backup_[domain]".(isset($data['port']) ? "_".$data['port'] : "")."-[time]-".($this->get_enable_mysql_backup() ? "sql" : "nosql");
|
268 |
+
|
269 |
+
return $backup_name;
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Get Database Hostname
|
274 |
+
*
|
275 |
+
* @return void
|
276 |
+
*/
|
277 |
+
public function get_db_hostname()
|
278 |
+
{
|
279 |
+
if (!$data = $this->get_xcloner_option('xcloner_mysql_hostname')) {
|
280 |
+
// $data = $this->xcloner_database->getDbHost();
|
281 |
+
}
|
282 |
+
|
283 |
+
return $data;
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Get Database Username
|
288 |
+
*
|
289 |
+
* @return void
|
290 |
+
*/
|
291 |
+
public function get_db_username()
|
292 |
+
{
|
293 |
+
if (!$data = $this->get_xcloner_option('xcloner_mysql_username')) {
|
294 |
+
//$data = $this->xcloner_database->getDbUser();
|
295 |
+
}
|
296 |
+
|
297 |
+
return $data;
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Get Database Password
|
302 |
+
*
|
303 |
+
* @return void
|
304 |
+
*/
|
305 |
+
public function get_db_password()
|
306 |
+
{
|
307 |
+
if (!$data = $this->get_xcloner_option('xcloner_mysql_password')) {
|
308 |
+
//$data = $this->xcloner_database->getDbPassword();
|
309 |
+
}
|
310 |
+
|
311 |
+
return $data;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Get Database Name
|
316 |
+
*
|
317 |
+
* @return void
|
318 |
+
*/
|
319 |
+
public function get_db_database()
|
320 |
+
{
|
321 |
+
if (!$data = $this->get_xcloner_option('xcloner_mysql_database')) {
|
322 |
+
//$data = $this->xcloner_database->getDbName();
|
323 |
+
}
|
324 |
+
|
325 |
+
return $data;
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Get Database Tables Prefix
|
330 |
+
*
|
331 |
+
* @return void
|
332 |
+
*/
|
333 |
+
public function get_table_prefix()
|
334 |
+
{
|
335 |
+
return $this->get_xcloner_option('xcloner_mysql_prefix');
|
336 |
+
}
|
337 |
+
|
338 |
+
/**
|
339 |
+
* @param string $option
|
340 |
+
*/
|
341 |
+
public function get_xcloner_option($option = "")
|
342 |
+
{
|
343 |
+
$data = get_option($option);
|
344 |
+
|
345 |
+
return $data;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Get Server Unique Hash used to generate the unique backup name
|
350 |
+
*
|
351 |
+
* @param integer $strlen
|
352 |
+
* @return void
|
353 |
+
*/
|
354 |
+
public function get_server_unique_hash($strlen = 0)
|
355 |
+
{
|
356 |
+
$hash = md5(get_home_url().__DIR__.$this->get_xcloner_encryption_key());
|
357 |
+
|
358 |
+
if ($strlen) {
|
359 |
+
$hash = substr($hash, 0, $strlen);
|
360 |
+
}
|
361 |
+
|
362 |
+
return $hash;
|
363 |
+
}
|
364 |
+
|
365 |
+
public function settings_init()
|
366 |
+
{
|
367 |
+
$this->xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
|
368 |
+
|
369 |
+
//ADDING MISSING OPTIONS
|
370 |
+
if (false == $this->get_xcloner_option('xcloner_mysql_settings_page')) {
|
371 |
+
update_option('xcloner_mysql_settings_page', '');
|
372 |
+
} // end if
|
373 |
+
|
374 |
+
if (false == $this->get_xcloner_option('xcloner_cron_settings_page')) {
|
375 |
+
update_option('xcloner_cron_settings_page', '');
|
376 |
+
} // end if
|
377 |
+
|
378 |
+
if (false == $this->get_xcloner_option('xcloner_system_settings_page')) {
|
379 |
+
update_option('xcloner_system_settings_page', '');
|
380 |
+
} // end if
|
381 |
+
|
382 |
+
if (false == $this->get_xcloner_option('xcloner_cleanup_settings_page')) {
|
383 |
+
update_option('xcloner_cleanup_settings_page', '');
|
384 |
+
} // end if
|
385 |
+
|
386 |
+
|
387 |
+
//ADDING SETTING SECTIONS
|
388 |
+
//GENERAL section
|
389 |
+
add_settings_section(
|
390 |
+
'xcloner_general_settings_group',
|
391 |
+
__(' '),
|
392 |
+
array($this, 'xcloner_settings_section_cb'),
|
393 |
+
'xcloner_settings_page'
|
394 |
+
);
|
395 |
+
//MYSQL section
|
396 |
+
add_settings_section(
|
397 |
+
'xcloner_mysql_settings_group',
|
398 |
+
__(' '),
|
399 |
+
array($this, 'xcloner_settings_section_cb'),
|
400 |
+
'xcloner_mysql_settings_page'
|
401 |
+
);
|
402 |
+
|
403 |
+
//SYSTEM section
|
404 |
+
add_settings_section(
|
405 |
+
'xcloner_system_settings_group',
|
406 |
+
__('These are advanced options recommended for developers!', 'xcloner-backup-and-restore'),
|
407 |
+
array($this, 'xcloner_settings_section_cb'),
|
408 |
+
'xcloner_system_settings_page'
|
409 |
+
);
|
410 |
+
|
411 |
+
//CLEANUP section
|
412 |
+
add_settings_section(
|
413 |
+
'xcloner_cleanup_settings_group',
|
414 |
+
__(' '),
|
415 |
+
array($this, 'xcloner_settings_section_cb'),
|
416 |
+
'xcloner_cleanup_settings_page'
|
417 |
+
);
|
418 |
+
|
419 |
+
|
420 |
+
//CRON section
|
421 |
+
add_settings_section(
|
422 |
+
'xcloner_cron_settings_group',
|
423 |
+
__(' '),
|
424 |
+
array($this, 'xcloner_settings_section_cb'),
|
425 |
+
'xcloner_cron_settings_page'
|
426 |
+
);
|
427 |
+
|
428 |
+
|
429 |
+
//REGISTERING THE 'GENERAL SECTION' FIELDS
|
430 |
+
register_setting('xcloner_general_settings_group', 'xcloner_backup_compression_level', array(
|
431 |
+
$this->xcloner_sanitization,
|
432 |
+
"sanitize_input_as_int"
|
433 |
+
));
|
434 |
+
add_settings_field(
|
435 |
+
'xcloner_backup_compression_level',
|
436 |
+
__('Backup Compression Level', 'xcloner-backup-and-restore'),
|
437 |
+
array($this, 'do_form_range_field'),
|
438 |
+
'xcloner_settings_page',
|
439 |
+
'xcloner_general_settings_group',
|
440 |
+
array(
|
441 |
+
'xcloner_backup_compression_level',
|
442 |
+
__('Options between [0-9]. Value 0 means no compression, while 9 is maximum compression affecting cpu load', 'xcloner-backup-and-restore'),
|
443 |
+
0,
|
444 |
+
9
|
445 |
+
)
|
446 |
+
);
|
447 |
+
|
448 |
+
register_setting('xcloner_general_settings_group', 'xcloner_start_path', array(
|
449 |
+
$this->xcloner_sanitization,
|
450 |
+
"sanitize_input_as_absolute_path"
|
451 |
+
));
|
452 |
+
add_settings_field(
|
453 |
+
'xcloner_start_path',
|
454 |
+
__('Backup Start Location', 'xcloner-backup-and-restore'),
|
455 |
+
array($this, 'do_form_text_field'),
|
456 |
+
'xcloner_settings_page',
|
457 |
+
'xcloner_general_settings_group',
|
458 |
+
array(
|
459 |
+
'xcloner_start_path',
|
460 |
+
__('Base path location from where XCloner can start the Backup.', 'xcloner-backup-and-restore'),
|
461 |
+
$this->get_xcloner_start_path(),
|
462 |
+
//'disabled'
|
463 |
+
)
|
464 |
+
);
|
465 |
+
|
466 |
+
register_setting('xcloner_general_settings_group', 'xcloner_store_path', array(
|
467 |
+
$this->xcloner_sanitization,
|
468 |
+
"sanitize_input_as_absolute_path"
|
469 |
+
));
|
470 |
+
add_settings_field(
|
471 |
+
'xcloner_store_path',
|
472 |
+
__('Backup Storage Location', 'xcloner-backup-and-restore'),
|
473 |
+
array($this, 'do_form_text_field'),
|
474 |
+
'xcloner_settings_page',
|
475 |
+
'xcloner_general_settings_group',
|
476 |
+
array(
|
477 |
+
'xcloner_store_path',
|
478 |
+
__('Location where XCloner will store the Backup archives.', 'xcloner-backup-and-restore'),
|
479 |
+
$this->get_xcloner_store_path(),
|
480 |
+
//'disabled'
|
481 |
+
)
|
482 |
+
);
|
483 |
+
|
484 |
+
register_setting('xcloner_general_settings_group', 'xcloner_encryption_key', array(
|
485 |
+
$this->xcloner_sanitization,
|
486 |
+
"sanitize_input_as_string"
|
487 |
+
));
|
488 |
+
add_settings_field(
|
489 |
+
'xcloner_encryption_key',
|
490 |
+
__('Backup Encryption Key', 'xcloner-backup-and-restore'),
|
491 |
+
array($this, 'do_form_text_field'),
|
492 |
+
'xcloner_settings_page',
|
493 |
+
'xcloner_general_settings_group',
|
494 |
+
array(
|
495 |
+
'xcloner_encryption_key',
|
496 |
+
__('Backup Encryption Key used to Encrypt/Decrypt backups, you might want to save this somewhere else as well.', 'xcloner-backup-and-restore'),
|
497 |
+
$this->get_xcloner_encryption_key(),
|
498 |
+
//'disabled'
|
499 |
+
)
|
500 |
+
);
|
501 |
+
|
502 |
+
register_setting('xcloner_general_settings_group', 'xcloner_enable_log', array(
|
503 |
+
$this->xcloner_sanitization,
|
504 |
+
"sanitize_input_as_int"
|
505 |
+
));
|
506 |
+
add_settings_field(
|
507 |
+
'xcloner_enable_log',
|
508 |
+
__('Enable XCloner Backup Log', 'xcloner-backup-and-restore'),
|
509 |
+
array($this, 'do_form_switch_field'),
|
510 |
+
'xcloner_settings_page',
|
511 |
+
'xcloner_general_settings_group',
|
512 |
+
array(
|
513 |
+
'xcloner_enable_log',
|
514 |
+
sprintf(__('Enable the XCloner Backup log. You will find it stored unde the Backup Storage Location, file %s', 'xcloner-backup-and-restore'), $this->get_logger_filename())
|
515 |
+
)
|
516 |
+
);
|
517 |
+
|
518 |
+
register_setting('xcloner_general_settings_group', 'xcloner_enable_pre_update_backup', array(
|
519 |
+
$this->xcloner_sanitization,
|
520 |
+
"sanitize_input_as_int"
|
521 |
+
));
|
522 |
+
add_settings_field(
|
523 |
+
'xcloner_enable_pre_update_backup',
|
524 |
+
__('Generate Backups before Automatic WP Upgrades', 'xcloner-backup-and-restore'),
|
525 |
+
array($this, 'do_form_switch_field'),
|
526 |
+
'xcloner_settings_page',
|
527 |
+
'xcloner_general_settings_group',
|
528 |
+
array(
|
529 |
+
'xcloner_enable_pre_update_backup',
|
530 |
+
sprintf(__('Attempt to generate a full site backup before applying automatic core updates.', 'xcloner-backup-and-restore'), $this->get_logger_filename())
|
531 |
+
)
|
532 |
+
);
|
533 |
+
|
534 |
+
register_setting('xcloner_general_settings_group', 'xcloner_regex_exclude', array(
|
535 |
+
$this->xcloner_sanitization,
|
536 |
+
"sanitize_input_as_raw"
|
537 |
+
));
|
538 |
+
add_settings_field(
|
539 |
+
'xcloner_regex_exclude',
|
540 |
+
__('Regex Exclude Files', 'xcloner-backup-and-restore'),
|
541 |
+
array($this, 'do_form_textarea_field'),
|
542 |
+
'xcloner_settings_page',
|
543 |
+
'xcloner_general_settings_group',
|
544 |
+
array(
|
545 |
+
'xcloner_regex_exclude',
|
546 |
+
__('Regular expression match to exclude files and folders, example patterns provided below, one pattern per line', 'xcloner-backup-and-restore'),
|
547 |
+
//$this->get_xcloner_store_path(),
|
548 |
+
//'disabled'
|
549 |
+
)
|
550 |
+
);
|
551 |
+
|
552 |
+
//REGISTERING THE 'MYSQL SECTION' FIELDS
|
553 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_enable_mysql_backup', array(
|
554 |
+
$this->xcloner_sanitization,
|
555 |
+
"sanitize_input_as_int"
|
556 |
+
));
|
557 |
+
add_settings_field(
|
558 |
+
'xcloner_enable_mysql_backup',
|
559 |
+
__('Enable Mysql Backup', 'xcloner-backup-and-restore'),
|
560 |
+
array($this, 'do_form_switch_field'),
|
561 |
+
'xcloner_mysql_settings_page',
|
562 |
+
'xcloner_mysql_settings_group',
|
563 |
+
array(
|
564 |
+
'xcloner_enable_mysql_backup',
|
565 |
+
__('Enable Mysql Backup Option. If you don\'t want to backup the database, you can disable this.', 'xcloner-backup-and-restore')
|
566 |
+
)
|
567 |
+
);
|
568 |
+
|
569 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_backup_only_wp_tables');
|
570 |
+
add_settings_field(
|
571 |
+
'xcloner_backup_only_wp_tables',
|
572 |
+
__('Backup only WP tables', 'xcloner-backup-and-restore'),
|
573 |
+
array($this, 'do_form_switch_field'),
|
574 |
+
'xcloner_mysql_settings_page',
|
575 |
+
'xcloner_mysql_settings_group',
|
576 |
+
array(
|
577 |
+
'xcloner_backup_only_wp_tables',
|
578 |
+
sprintf(__('Enable this if you only want to Backup only tables starting with \'%s\' prefix', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
579 |
+
)
|
580 |
+
);
|
581 |
+
|
582 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_hostname', array(
|
583 |
+
$this->xcloner_sanitization,
|
584 |
+
"sanitize_input_as_raw"
|
585 |
+
));
|
586 |
+
add_settings_field(
|
587 |
+
'xcloner_mysql_hostname',
|
588 |
+
__('Mysql Hostname', 'xcloner-backup-and-restore'),
|
589 |
+
array($this, 'do_form_text_field'),
|
590 |
+
'xcloner_mysql_settings_page',
|
591 |
+
'xcloner_mysql_settings_group',
|
592 |
+
array(
|
593 |
+
'xcloner_mysql_hostname',
|
594 |
+
__('Wordpress mysql hostname', 'xcloner-backup-and-restore'),
|
595 |
+
$this->get_db_hostname(),
|
596 |
+
//'disabled'
|
597 |
+
)
|
598 |
+
);
|
599 |
+
|
600 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_username', array(
|
601 |
+
$this->xcloner_sanitization,
|
602 |
+
"sanitize_input_as_raw"
|
603 |
+
));
|
604 |
+
add_settings_field(
|
605 |
+
'xcloner_mysql_username',
|
606 |
+
__('Mysql Username', 'xcloner-backup-and-restore'),
|
607 |
+
array($this, 'do_form_text_field'),
|
608 |
+
'xcloner_mysql_settings_page',
|
609 |
+
'xcloner_mysql_settings_group',
|
610 |
+
array(
|
611 |
+
'xcloner_mysql_username',
|
612 |
+
__('Wordpress mysql username', 'xcloner-backup-and-restore'),
|
613 |
+
$this->get_db_username(),
|
614 |
+
//'disabled'
|
615 |
+
)
|
616 |
+
);
|
617 |
+
|
618 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_password', array(
|
619 |
+
$this->xcloner_sanitization,
|
620 |
+
"sanitize_input_as_raw"
|
621 |
+
));
|
622 |
+
add_settings_field(
|
623 |
+
'xcloner_mysql_password',
|
624 |
+
__('Mysql Password', 'xcloner-backup-and-restore'),
|
625 |
+
array($this, 'do_form_password_field'),
|
626 |
+
'xcloner_mysql_settings_page',
|
627 |
+
'xcloner_mysql_settings_group',
|
628 |
+
array(
|
629 |
+
'xcloner_mysql_password',
|
630 |
+
__('Wordpress mysql password', 'xcloner-backup-and-restore'),
|
631 |
+
$this->get_db_username(),
|
632 |
+
//'disabled'
|
633 |
+
)
|
634 |
+
);
|
635 |
+
|
636 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_database', array(
|
637 |
+
$this->xcloner_sanitization,
|
638 |
+
"sanitize_input_as_raw"
|
639 |
+
));
|
640 |
+
add_settings_field(
|
641 |
+
'xcloner_mysql_database',
|
642 |
+
__('Mysql Database', 'xcloner-backup-and-restore'),
|
643 |
+
array($this, 'do_form_text_field'),
|
644 |
+
'xcloner_mysql_settings_page',
|
645 |
+
'xcloner_mysql_settings_group',
|
646 |
+
array(
|
647 |
+
'xcloner_mysql_database',
|
648 |
+
__('Wordpress mysql database', 'xcloner-backup-and-restore'),
|
649 |
+
$this->get_db_database(),
|
650 |
+
//'disabled'
|
651 |
+
)
|
652 |
+
);
|
653 |
+
|
654 |
+
register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_prefix', array(
|
655 |
+
$this->xcloner_sanitization,
|
656 |
+
"sanitize_input_as_raw"
|
657 |
+
));
|
658 |
+
add_settings_field(
|
659 |
+
'xcloner_mysql_prefix',
|
660 |
+
__('Mysql Tables Prefix', 'xcloner-backup-and-restore'),
|
661 |
+
array($this, 'do_form_text_field'),
|
662 |
+
'xcloner_mysql_settings_page',
|
663 |
+
'xcloner_mysql_settings_group',
|
664 |
+
array(
|
665 |
+
'xcloner_mysql_prefix',
|
666 |
+
__('Wordpress mysql tables prefix', 'xcloner-backup-and-restore'),
|
667 |
+
$this->get_table_prefix(),
|
668 |
+
//'disabled'
|
669 |
+
)
|
670 |
+
);
|
671 |
+
|
672 |
+
//REGISTERING THE 'SYSTEM SECTION' FIELDS
|
673 |
+
register_setting('xcloner_system_settings_group', 'xcloner_size_limit_per_request', array(
|
674 |
+
$this->xcloner_sanitization,
|
675 |
+
"sanitize_input_as_int"
|
676 |
+
));
|
677 |
+
add_settings_field(
|
678 |
+
'xcloner_size_limit_per_request',
|
679 |
+
__('Data Size Limit Per Request', 'xcloner-backup-and-restore'),
|
680 |
+
array($this, 'do_form_range_field'),
|
681 |
+
'xcloner_system_settings_page',
|
682 |
+
'xcloner_system_settings_group',
|
683 |
+
array(
|
684 |
+
'xcloner_size_limit_per_request',
|
685 |
+
__('Use this option to set how much file data can XCloner backup in one AJAX request. Range 0-1024 MB', 'xcloner-backup-and-restore'),
|
686 |
+
0,
|
687 |
+
1024
|
688 |
+
)
|
689 |
+
);
|
690 |
+
|
691 |
+
register_setting('xcloner_system_settings_group', 'xcloner_files_to_process_per_request', array(
|
692 |
+
$this->xcloner_sanitization,
|
693 |
+
"sanitize_input_as_int"
|
694 |
+
));
|
695 |
+
add_settings_field(
|
696 |
+
'xcloner_files_to_process_per_request',
|
697 |
+
__('Files To Process Per Request', 'xcloner-backup-and-restore'),
|
698 |
+
array($this, 'do_form_range_field'),
|
699 |
+
'xcloner_system_settings_page',
|
700 |
+
'xcloner_system_settings_group',
|
701 |
+
array(
|
702 |
+
'xcloner_files_to_process_per_request',
|
703 |
+
__('Use this option to set how many files XCloner should process at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
|
704 |
+
0,
|
705 |
+
1000
|
706 |
+
)
|
707 |
+
);
|
708 |
+
|
709 |
+
register_setting('xcloner_system_settings_group', 'xcloner_directories_to_scan_per_request', array(
|
710 |
+
$this->xcloner_sanitization,
|
711 |
+
"sanitize_input_as_int"
|
712 |
+
));
|
713 |
+
add_settings_field(
|
714 |
+
'xcloner_directories_to_scan_per_request',
|
715 |
+
__('Directories To Scan Per Request', 'xcloner-backup-and-restore'),
|
716 |
+
array($this, 'do_form_range_field'),
|
717 |
+
'xcloner_system_settings_page',
|
718 |
+
'xcloner_system_settings_group',
|
719 |
+
array(
|
720 |
+
'xcloner_directories_to_scan_per_request',
|
721 |
+
__('Use this option to set how many directories XCloner should scan at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
|
722 |
+
0,
|
723 |
+
1000
|
724 |
+
)
|
725 |
+
);
|
726 |
+
|
727 |
+
register_setting('xcloner_system_settings_group', 'xcloner_database_records_per_request', array(
|
728 |
+
$this->xcloner_sanitization,
|
729 |
+
"sanitize_input_as_int"
|
730 |
+
));
|
731 |
+
add_settings_field(
|
732 |
+
'xcloner_database_records_per_request',
|
733 |
+
__('Database Records Per Request', 'xcloner-backup-and-restore'),
|
734 |
+
array($this, 'do_form_range_field'),
|
735 |
+
'xcloner_system_settings_page',
|
736 |
+
'xcloner_system_settings_group',
|
737 |
+
array(
|
738 |
+
'xcloner_database_records_per_request',
|
739 |
+
__('Use this option to set how many database table records should be fetched per AJAX request, or set to 0 to fetch all. Range 0-100000 records', 'xcloner-backup-and-restore'),
|
740 |
+
0,
|
741 |
+
100000
|
742 |
+
)
|
743 |
+
);
|
744 |
+
|
745 |
+
/*register_setting('xcloner_system_settings_group', 'xcloner_diff_backup_recreate_period', array($this->xcloner_sanitization, "sanitize_input_as_int"));
|
746 |
+
add_settings_field(
|
747 |
+
'xcloner_diff_backup_recreate_period',
|
748 |
+
__('Differetial Backups Max Days','xcloner-backup-and-restore'),
|
749 |
+
array($this, 'do_form_number_field'),
|
750 |
+
'xcloner_system_settings_page',
|
751 |
+
'xcloner_system_settings_group',
|
752 |
+
array('xcloner_diff_backup_recreate_period',
|
753 |
+
__('Use this option to set when a full backup should be recreated if the scheduled backup type is set to \'Full Backup+Differential Backups\' ','xcloner-backup-and-restore'),
|
754 |
+
)
|
755 |
+
);*/
|
756 |
+
|
757 |
+
register_setting('xcloner_system_settings_group', 'xcloner_exclude_files_larger_than_mb', array(
|
758 |
+
$this->xcloner_sanitization,
|
759 |
+
"sanitize_input_as_int"
|
760 |
+
));
|
761 |
+
add_settings_field(
|
762 |
+
'xcloner_exclude_files_larger_than_mb',
|
763 |
+
__('Exclude files larger than (MB)', 'xcloner-backup-and-restore'),
|
764 |
+
array($this, 'do_form_number_field'),
|
765 |
+
'xcloner_system_settings_page',
|
766 |
+
'xcloner_system_settings_group',
|
767 |
+
array(
|
768 |
+
'xcloner_exclude_files_larger_than_mb',
|
769 |
+
__('Use this option to automatically exclude files larger than a certain size in MB, or set to 0 to include all. Range 0-1000 MB', 'xcloner-backup-and-restore'),
|
770 |
+
)
|
771 |
+
);
|
772 |
+
|
773 |
+
register_setting('xcloner_system_settings_group', 'xcloner_split_backup_limit', array(
|
774 |
+
$this->xcloner_sanitization,
|
775 |
+
"sanitize_input_as_int"
|
776 |
+
));
|
777 |
+
add_settings_field(
|
778 |
+
'xcloner_split_backup_limit',
|
779 |
+
__('Split Backup Archive Limit (MB)', 'xcloner-backup-and-restore'),
|
780 |
+
array($this, 'do_form_number_field'),
|
781 |
+
'xcloner_system_settings_page',
|
782 |
+
'xcloner_system_settings_group',
|
783 |
+
array(
|
784 |
+
'xcloner_split_backup_limit',
|
785 |
+
__('Use this option to automatically split the backup archive into smaller parts. Range 0-10000 MB', 'xcloner-backup-and-restore'),
|
786 |
+
)
|
787 |
+
);
|
788 |
+
|
789 |
+
register_setting('xcloner_system_settings_group', 'xcloner_force_tmp_path_site_root');
|
790 |
+
add_settings_field(
|
791 |
+
'xcloner_force_tmp_path_site_root',
|
792 |
+
__('Force Temporary Path Within XCloner Storage', 'xcloner-backup-and-restore'),
|
793 |
+
array($this, 'do_form_switch_field'),
|
794 |
+
'xcloner_system_settings_page',
|
795 |
+
'xcloner_system_settings_group',
|
796 |
+
array(
|
797 |
+
'xcloner_force_tmp_path_site_root',
|
798 |
+
sprintf(__('Enable this option if you want the XCloner Temporary Path to be within your XCloner Storage Location', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
799 |
+
)
|
800 |
+
);
|
801 |
+
|
802 |
+
register_setting('xcloner_system_settings_group', 'xcloner_disable_email_notification');
|
803 |
+
add_settings_field(
|
804 |
+
'xcloner_disable_email_notification',
|
805 |
+
__('Disable Email Notifications', 'xcloner-backup-and-restore'),
|
806 |
+
array($this, 'do_form_switch_field'),
|
807 |
+
'xcloner_system_settings_page',
|
808 |
+
'xcloner_system_settings_group',
|
809 |
+
array(
|
810 |
+
'xcloner_disable_email_notification',
|
811 |
+
sprintf(__('Enable this option if you want the XCloner to NOT send email notifications on successful backups', 'xcloner-backup-and-restore'), $this->get_table_prefix())
|
812 |
+
)
|
813 |
+
);
|
814 |
+
|
815 |
+
//REGISTERING THE 'CLEANUP SECTION' FIELDS
|
816 |
+
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_days', array(
|
817 |
+
$this->xcloner_sanitization,
|
818 |
+
"sanitize_input_as_int"
|
819 |
+
));
|
820 |
+
add_settings_field(
|
821 |
+
'xcloner_cleanup_retention_limit_days',
|
822 |
+
__('Cleanup by Date(days)', 'xcloner-backup-and-restore'),
|
823 |
+
array($this, 'do_form_number_field'),
|
824 |
+
'xcloner_cleanup_settings_page',
|
825 |
+
'xcloner_cleanup_settings_group',
|
826 |
+
array(
|
827 |
+
'xcloner_cleanup_retention_limit_days',
|
828 |
+
__('Specify the maximum number of days a backup archive can be kept on the server. 0 disables this option', 'xcloner-backup-and-restore')
|
829 |
+
)
|
830 |
+
);
|
831 |
+
|
832 |
+
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_archives', array(
|
833 |
+
$this->xcloner_sanitization,
|
834 |
+
"sanitize_input_as_int"
|
835 |
+
));
|
836 |
+
add_settings_field(
|
837 |
+
'xcloner_cleanup_retention_limit_archives',
|
838 |
+
__('Cleanup by Quantity', 'xcloner-backup-and-restore'),
|
839 |
+
array($this, 'do_form_number_field'),
|
840 |
+
'xcloner_cleanup_settings_page',
|
841 |
+
'xcloner_cleanup_settings_group',
|
842 |
+
array(
|
843 |
+
'xcloner_cleanup_retention_limit_archives',
|
844 |
+
__('Specify the maximum number of backup archives to keep on the server. 0 disables this option', 'xcloner-backup-and-restore')
|
845 |
+
)
|
846 |
+
);
|
847 |
+
|
848 |
+
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_capacity_limit', array(
|
849 |
+
$this->xcloner_sanitization,
|
850 |
+
"sanitize_input_as_int"
|
851 |
+
));
|
852 |
+
add_settings_field(
|
853 |
+
'xcloner_cleanup_capacity_limit',
|
854 |
+
__('Cleanup by Capacity(MB)', 'xcloner-backup-and-restore'),
|
855 |
+
array($this, 'do_form_number_field'),
|
856 |
+
'xcloner_cleanup_settings_page',
|
857 |
+
'xcloner_cleanup_settings_group',
|
858 |
+
array(
|
859 |
+
'xcloner_cleanup_capacity_limit',
|
860 |
+
__('Remove oldest backups if all created backups exceed the configured limit in Megabytes. 0 disables this option', 'xcloner-backup-and-restore')
|
861 |
+
)
|
862 |
+
);
|
863 |
+
|
864 |
+
register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_delete_after_remote_transfer', array(
|
865 |
+
$this->xcloner_sanitization,
|
866 |
+
"sanitize_input_as_int"
|
867 |
+
));
|
868 |
+
add_settings_field(
|
869 |
+
'xcloner_cleanup_delete_after_remote_transfer',
|
870 |
+
__('Delete Backup After Remote Storage Transfer', 'xcloner-backup-and-restore'),
|
871 |
+
array($this, 'do_form_switch_field'),
|
872 |
+
'xcloner_cleanup_settings_page',
|
873 |
+
'xcloner_cleanup_settings_group',
|
874 |
+
array(
|
875 |
+
'xcloner_cleanup_delete_after_remote_transfer',
|
876 |
+
__('Remove backup created automatically from local storage after sending the backup to Remote Storage', 'xcloner-backup-and-restore')
|
877 |
+
)
|
878 |
+
);
|
879 |
+
|
880 |
+
//REGISTERING THE 'CRON SECTION' FIELDS
|
881 |
+
register_setting('xcloner_cron_settings_group', 'xcloner_cron_frequency');
|
882 |
+
add_settings_field(
|
883 |
+
'xcloner_cron_frequency',
|
884 |
+
__('Cron frequency', 'xcloner-backup-and-restore'),
|
885 |
+
array($this, 'do_form_text_field'),
|
886 |
+
'xcloner_cron_settings_page',
|
887 |
+
'xcloner_cron_settings_group',
|
888 |
+
array(
|
889 |
+
'xcloner_cron_frequency',
|
890 |
+
__('Cron frequency')
|
891 |
+
)
|
892 |
+
);
|
893 |
+
}
|
894 |
+
|
895 |
+
|
896 |
+
|
897 |
+
|
898 |
+
/**
|
899 |
+
* callback functions
|
900 |
+
*/
|
901 |
+
|
902 |
+
// section content cb
|
903 |
+
public function xcloner_settings_section_cb()
|
904 |
+
{
|
905 |
+
//echo '<p>WPOrg Section Introduction.</p>';
|
906 |
+
}
|
907 |
+
|
908 |
+
// text field content cb
|
909 |
+
public function do_form_text_field($params)
|
910 |
+
{
|
911 |
+
if (!isset($params['3'])) {
|
912 |
+
$params[3] = 0;
|
913 |
+
}
|
914 |
+
if (!isset($params['2'])) {
|
915 |
+
$params[2] = 0;
|
916 |
+
}
|
917 |
+
|
918 |
+
list($fieldname, $label, $value, $disabled) = $params;
|
919 |
+
|
920 |
+
if (!$value) {
|
921 |
+
$value = $this->get_xcloner_option($fieldname);
|
922 |
+
}
|
923 |
+
// output the field?>
|
924 |
+
<div class="row">
|
925 |
+
<div class="input-field col s10 m10 l8">
|
926 |
+
<input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
927 |
+
id="<?php echo $fieldname ?>" type="text" class="validate"
|
928 |
+
value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
|
929 |
+
</div>
|
930 |
+
<div class="col s2 m2 ">
|
931 |
+
<a class="btn-floating tooltipped btn-small" data-position="left" data-delay="50"
|
932 |
+
data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
|
933 |
+
</div>
|
934 |
+
</div>
|
935 |
|
|
|
|
|
936 |
|
937 |
+
<?php
|
938 |
+
}
|
939 |
+
|
940 |
+
/**
|
941 |
+
* Password field UI
|
942 |
+
*
|
943 |
+
* @param [type] $params
|
944 |
+
* @return void
|
945 |
+
*/
|
946 |
+
public function do_form_password_field($params)
|
947 |
+
{
|
948 |
+
if (!isset($params['3'])) {
|
949 |
+
$params[3] = 0;
|
950 |
+
}
|
951 |
+
if (!isset($params['2'])) {
|
952 |
+
$params[2] = 0;
|
953 |
+
}
|
954 |
+
|
955 |
+
list($fieldname, $label, $value, $disabled) = $params;
|
956 |
+
|
957 |
+
if (!$value) {
|
958 |
+
$value = $this->get_xcloner_option($fieldname);
|
959 |
+
}
|
960 |
+
// output the field?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
961 |
<div class="row">
|
962 |
<div class="input-field col s10 m10 l8">
|
963 |
<input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
964 |
+
id="<?php echo $fieldname ?>" type="password" class="validate"
|
965 |
value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
|
966 |
</div>
|
967 |
<div class="col s2 m2 ">
|
972 |
|
973 |
|
974 |
<?php
|
975 |
+
}
|
976 |
+
|
977 |
+
// textarea field content cb
|
978 |
+
public function do_form_textarea_field($params)
|
979 |
+
{
|
980 |
+
if (!isset($params['3'])) {
|
981 |
+
$params[3] = 0;
|
982 |
+
}
|
983 |
+
if (!isset($params['2'])) {
|
984 |
+
$params[2] = 0;
|
985 |
+
}
|
986 |
+
|
987 |
+
list($fieldname, $label, $value, $disabled) = $params;
|
988 |
+
|
989 |
+
if (!$value) {
|
990 |
+
$value = $this->get_xcloner_option($fieldname);
|
991 |
+
}
|
992 |
+
// output the field?>
|
993 |
<div class="row">
|
994 |
<div class="input-field col s10 m10 l8">
|
995 |
<textarea class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
1042 |
|
1043 |
|
1044 |
<?php
|
1045 |
+
}
|
1046 |
+
|
1047 |
+
// number field content cb
|
1048 |
+
public function do_form_number_field($params)
|
1049 |
+
{
|
1050 |
+
if (!isset($params['3'])) {
|
1051 |
+
$params[3] = 0;
|
1052 |
+
}
|
1053 |
+
if (!isset($params['2'])) {
|
1054 |
+
$params[2] = 0;
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
list($fieldname, $label, $value, $disabled) = $params;
|
1058 |
+
|
1059 |
+
if (!$value) {
|
1060 |
+
$value = $this->get_xcloner_option($fieldname);
|
1061 |
+
}
|
1062 |
+
// output the field?>
|
1063 |
<div class="row">
|
1064 |
<div class="input-field col s10 m5 l3">
|
1065 |
<input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
|
1074 |
|
1075 |
|
1076 |
<?php
|
1077 |
+
}
|
1078 |
|
1079 |
+
public function do_form_range_field($params)
|
1080 |
+
{
|
1081 |
+
if (!isset($params['4'])) {
|
1082 |
+
$params[4] = 0;
|
1083 |
+
}
|
1084 |
|
1085 |
+
list($fieldname, $label, $range_start, $range_end, $disabled) = $params;
|
1086 |
+
$value = $this->get_xcloner_option($fieldname); ?>
|
|
|
1087 |
<div class="row">
|
1088 |
<div class="input-field col s10 m10 l8">
|
1089 |
<p class="range-field">
|
1100 |
</div>
|
1101 |
</div>
|
1102 |
<?php
|
1103 |
+
}
|
1104 |
|
1105 |
|
1106 |
+
public function do_form_switch_field($params)
|
1107 |
+
{
|
1108 |
+
if (!isset($params['2'])) {
|
1109 |
+
$params[2] = 0;
|
1110 |
+
}
|
1111 |
+
list($fieldname, $label, $disabled) = $params;
|
1112 |
+
$value = $this->get_xcloner_option($fieldname); ?>
|
1113 |
<div class="row">
|
1114 |
<div class="input-field col s10 m5 l3">
|
1115 |
<div class="switch">
|
1131 |
</div>
|
1132 |
</div>
|
1133 |
<?php
|
1134 |
+
}
|
1135 |
}
|
includes/class-xcloner-standalone.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
define('XCLONER_STANDALONE_MODE', true);
|
4 |
+
|
5 |
+
require_once(__DIR__.'/../vendor/autoload.php');
|
6 |
+
|
7 |
+
use Monolog\Logger;
|
8 |
+
use Monolog\Handler\StreamHandler;
|
9 |
+
use Monolog\Handler\RotatingFileHandler;
|
10 |
+
|
11 |
+
include_once(__DIR__ ."/../lib/mock_wp_functions.php");
|
12 |
+
require_once(__DIR__ . '/../includes/class-xcloner.php');
|
13 |
+
|
14 |
+
|
15 |
+
class Xcloner_Standalone extends Xcloner
|
16 |
+
{
|
17 |
+
public function __construct($json_config)
|
18 |
+
{
|
19 |
+
if (WP_DEBUG && WP_DEBUG_DISPLAY) {
|
20 |
+
$this->log_php_errors();
|
21 |
+
}
|
22 |
+
|
23 |
+
$this->load_dependencies();
|
24 |
+
|
25 |
+
$this->define_plugin_settings($json_config);
|
26 |
+
|
27 |
+
if(!isset($_POST['hash']) || !$_POST['hash']){
|
28 |
+
$_POST['hash'] = "";
|
29 |
+
}
|
30 |
+
$this->xcloner_settings = new XCloner_Settings($this, $_POST['hash'], $json_config);
|
31 |
+
|
32 |
+
|
33 |
+
if( !$this->xcloner_settings->get_hash(true) ){
|
34 |
+
$this->xcloner_settings->generate_new_hash();
|
35 |
+
}
|
36 |
+
|
37 |
+
|
38 |
+
$this->define_plugin_settings();
|
39 |
+
|
40 |
+
$this->xcloner_logger = new XCloner_Logger($this, "xcloner_standalone");
|
41 |
+
|
42 |
+
if (WP_DEBUG && WP_DEBUG_DISPLAY) {
|
43 |
+
$this->xcloner_logger->pushHandler(new StreamHandler('php://stdout', Logger::INFO));
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->xcloner_filesystem = new Xcloner_File_System($this);
|
47 |
+
$this->archive_system = new Xcloner_Archive($this);
|
48 |
+
$this->xcloner_database = new Xcloner_Database($this);
|
49 |
+
$this->xcloner_scheduler = new Xcloner_Scheduler($this);
|
50 |
+
$this->xcloner_remote_storage = new Xcloner_Remote_Storage($this);
|
51 |
+
$this->xcloner_file_transfer = new Xcloner_File_Transfer($this);
|
52 |
+
$this->xcloner_encryption = new Xcloner_Encryption($this);
|
53 |
+
$this->xcloner_sanitization = new Xcloner_Sanitization();
|
54 |
+
|
55 |
+
//$this->start();
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Start backup process trigger method
|
60 |
+
*
|
61 |
+
* @return void
|
62 |
+
*/
|
63 |
+
public function start()
|
64 |
+
{
|
65 |
+
$profile_config = ($this->xcloner_settings->get_xcloner_option('profile'));
|
66 |
+
|
67 |
+
$data['params'] = "";
|
68 |
+
$data['backup_params'] = $profile_config->backup_params;
|
69 |
+
$data['table_params'] = json_encode($profile_config->database);
|
70 |
+
$data['excluded_files'] = json_encode($profile_config->excluded_files);
|
71 |
+
|
72 |
+
return $this->xcloner_scheduler->xcloner_scheduler_callback(null, $data, $this);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Overwrite parent __call method
|
77 |
+
*
|
78 |
+
* @param [type] $property
|
79 |
+
* @param [type] $args
|
80 |
+
* @return void
|
81 |
+
*/
|
82 |
+
public function __call($property, $args)
|
83 |
+
{
|
84 |
+
$property = str_replace("get_", "", $property);
|
85 |
+
|
86 |
+
if (property_exists($this, $property)) {
|
87 |
+
return $this->$property;
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get Xcloner Main Class Container
|
93 |
+
*
|
94 |
+
* @return void
|
95 |
+
*/
|
96 |
+
private function get_xcloner_container()
|
97 |
+
{
|
98 |
+
return $this;
|
99 |
+
}
|
100 |
+
}
|
includes/class-xcloner.php
CHANGED
@@ -39,80 +39,84 @@
|
|
39 |
* @package Xcloner
|
40 |
* @subpackage Xcloner/includes
|
41 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
42 |
-
* @link
|
43 |
*/
|
44 |
-
class Xcloner
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
|
|
|
|
|
|
116 |
|
117 |
/**
|
118 |
* Dynamic get of class methods get_
|
@@ -120,11 +124,11 @@ class Xcloner {
|
|
120 |
* @param $args
|
121 |
* @return mixed
|
122 |
*/
|
123 |
-
public function __call($property, $args)
|
124 |
-
|
125 |
$property = str_replace("get_", "", $property);
|
126 |
|
127 |
-
if(property_exists($this, $property)){
|
128 |
return $this->$property;
|
129 |
}
|
130 |
}
|
@@ -135,7 +139,8 @@ class Xcloner {
|
|
135 |
* @param int $length
|
136 |
* @return string
|
137 |
*/
|
138 |
-
public function randomString($length = 6)
|
|
|
139 |
$str = "";
|
140 |
$characters = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
|
141 |
$max = count($characters) - 1;
|
@@ -146,551 +151,625 @@ class Xcloner {
|
|
146 |
return $str;
|
147 |
}
|
148 |
|
149 |
-
|
150 |
-
|
151 |
-
$backup_storage_path = (
|
152 |
-
|
153 |
-
if(!$backup_storage_path) {
|
154 |
|
|
|
155 |
$backup_storage_path = realpath(__DIR__ . DS . ".." . DS . ".." . DS . "..") . DS . "backups-" . $this->randomString('5') . DS;
|
|
|
156 |
|
157 |
-
|
158 |
-
|
159 |
-
$status = "error";
|
160 |
-
$message = sprintf(__("Unable to create the Backup Storage Location Folder %s . Please fix this before starting the backup process."),
|
161 |
-
$backup_storage_path);
|
162 |
-
$this->trigger_message($message, $status, $backup_storage_path);
|
163 |
-
return;
|
164 |
-
}
|
165 |
-
}
|
166 |
-
if (!is_writable($backup_storage_path)) {
|
167 |
$status = "error";
|
168 |
-
$message = sprintf(
|
169 |
-
|
|
|
|
|
170 |
$this->trigger_message($message, $status, $backup_storage_path);
|
171 |
-
|
172 |
return;
|
173 |
}
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
}
|
177 |
|
|
|
|
|
178 |
|
|
|
|
|
|
|
|
|
|
|
179 |
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
$message = sprintf(__($message), $message_param1, $message_param2, $message_param3);
|
185 |
-
add_action('xcloner_admin_notices', array($this, "trigger_message_notice"), 10, 2);
|
186 |
-
do_action('xcloner_admin_notices', $message, $status);
|
187 |
-
}
|
188 |
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
<div class="notice notice-<?php echo $status?> is-dismissible">
|
193 |
<p><?php _e($message, 'xcloner-backup-and-restore'); ?></p>
|
194 |
</div>
|
195 |
<?php
|
196 |
-
|
197 |
-
|
198 |
-
/**
|
199 |
-
* Load the required dependencies for this plugin.
|
200 |
-
*
|
201 |
-
* Include the following files that make up the plugin:
|
202 |
-
*
|
203 |
-
* - Xcloner_Loader. Orchestrates the hooks of the plugin.
|
204 |
-
* - Xcloner_i18n. Defines internationalization functionality.
|
205 |
-
* - Xcloner_Admin. Defines all hooks for the admin area.
|
206 |
-
* - Xcloner_Public. Defines all hooks for the public side of the site.
|
207 |
-
*
|
208 |
-
* Create an instance of the loader which will be used to register the hooks
|
209 |
-
* with WordPress.
|
210 |
-
*
|
211 |
-
* @since 1.0.0
|
212 |
-
* @access private
|
213 |
-
*/
|
214 |
-
private function load_dependencies() {
|
215 |
-
|
216 |
-
/**
|
217 |
-
* The class responsible for orchestrating the actions and filters of the
|
218 |
-
* core plugin.
|
219 |
-
*/
|
220 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-loader.php';
|
221 |
-
|
222 |
-
/**
|
223 |
-
* The class responsible for defining internationalization functionality
|
224 |
-
* of the plugin.
|
225 |
-
*/
|
226 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-i18n.php';
|
227 |
-
|
228 |
-
/**
|
229 |
-
* The class responsible for defining all actions that occur in the admin area.
|
230 |
-
*/
|
231 |
-
require_once plugin_dir_path(dirname(__FILE__)).'admin/class-xcloner-admin.php';
|
232 |
-
|
233 |
-
/**
|
234 |
-
* The class responsible for debugging XCloner.
|
235 |
-
*/
|
236 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-logger.php';
|
237 |
-
|
238 |
-
/**
|
239 |
-
* The class responsible for defining the admin settings area.
|
240 |
-
*/
|
241 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-settings.php';
|
242 |
-
|
243 |
-
/**
|
244 |
-
* The class responsible for defining the Remote Storage settings area.
|
245 |
-
*/
|
246 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-remote-storage.php';
|
247 |
-
|
248 |
-
/**
|
249 |
-
* The class responsible for implementing the database backup methods.
|
250 |
-
*/
|
251 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-database.php';
|
252 |
-
|
253 |
-
/**
|
254 |
-
* The class responsible for sanitization of users input.
|
255 |
-
*/
|
256 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-sanitization.php';
|
257 |
-
|
258 |
-
/**
|
259 |
-
* The class responsible for XCloner system requirements validation.
|
260 |
-
*/
|
261 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-requirements.php';
|
262 |
-
|
263 |
-
/**
|
264 |
-
* The class responsible for XCloner backup archive creation.
|
265 |
-
*/
|
266 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-archive.php';
|
267 |
-
|
268 |
-
/**
|
269 |
-
* The class responsible for XCloner API requests.
|
270 |
-
*/
|
271 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-api.php';
|
272 |
-
|
273 |
-
/**
|
274 |
-
* The class responsible for the XCloner File System methods.
|
275 |
-
*/
|
276 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-system.php';
|
277 |
-
|
278 |
-
/**
|
279 |
-
* The class responsible for the XCloner File Transfer methods.
|
280 |
-
*/
|
281 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-transfer.php';
|
282 |
-
|
283 |
-
/**
|
284 |
-
* The class responsible for the XCloner Scheduler methods.
|
285 |
-
*/
|
286 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-scheduler.php';
|
287 |
-
|
288 |
-
/**
|
289 |
-
* The class responsible for the XCloner Encryption methods.
|
290 |
-
*/
|
291 |
-
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-encryption.php';
|
292 |
-
|
293 |
-
/**
|
294 |
-
* The class responsible for defining all actions that occur in the public-facing
|
295 |
-
* side of the site.
|
296 |
-
*/
|
297 |
-
require_once plugin_dir_path(dirname(__FILE__)).'public/class-xcloner-public.php';
|
298 |
-
|
299 |
-
$this->loader = new Xcloner_Loader($this);
|
300 |
-
|
301 |
-
}
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Define the locale for this plugin for internationalization.
|
305 |
-
*
|
306 |
-
* Uses the Xcloner_i18n class in order to set the domain and to register the hook
|
307 |
-
* with WordPress.
|
308 |
-
*
|
309 |
-
* @since 1.0.0
|
310 |
-
* @access private
|
311 |
-
*/
|
312 |
-
private function set_locale() {
|
313 |
-
|
314 |
-
$plugin_i18n = new Xcloner_i18n();
|
315 |
-
|
316 |
-
$this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
|
317 |
-
|
318 |
-
//wp_localize_script( 'ajax-script', 'my_ajax_object',
|
319 |
-
// array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
|
320 |
-
|
321 |
-
}
|
322 |
-
|
323 |
-
/**
|
324 |
-
* Register all of the hooks related to the admin area functionality
|
325 |
-
* of the plugin.
|
326 |
-
*
|
327 |
-
* @since 1.0.0
|
328 |
-
* @access private
|
329 |
-
*/
|
330 |
-
private function define_admin_hooks() {
|
331 |
-
|
332 |
-
$plugin_admin = new Xcloner_Admin($this);
|
333 |
-
$this->plugin_admin = $plugin_admin;
|
334 |
-
|
335 |
-
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
|
336 |
-
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
|
337 |
-
|
338 |
-
add_action('backup_archive_finished', array($this, 'do_action_after_backup_finished'), 10, 2);
|
339 |
-
}
|
340 |
-
|
341 |
-
/**
|
342 |
-
* Register the Admin Sidebar menu
|
343 |
-
*
|
344 |
-
* @access private
|
345 |
-
*
|
346 |
-
*/
|
347 |
-
private function define_admin_menu() {
|
348 |
-
|
349 |
-
add_action('admin_menu', array($this->loader, 'xcloner_backup_add_admin_menu'));
|
350 |
-
|
351 |
-
}
|
352 |
-
|
353 |
-
private function define_plugin_settings() {
|
354 |
-
/**
|
355 |
-
* register wporg_settings_init to the admin_init action hook
|
356 |
-
*/
|
357 |
-
|
358 |
-
$this->xcloner_settings = new XCloner_Settings($this);
|
359 |
-
|
360 |
-
if (defined('DOING_CRON') || isset($_POST['hash'])) {
|
361 |
-
|
362 |
-
if (defined('DOING_CRON') || $_POST['hash'] == "generate_hash") {
|
363 |
-
$this->xcloner_settings->generate_new_hash();
|
364 |
-
} else {
|
365 |
-
$this->xcloner_settings->set_hash($_POST['hash']);
|
366 |
-
}
|
367 |
-
}
|
368 |
-
|
369 |
-
if (defined('DOING_CRON') || !isset($_POST['hash']))
|
370 |
-
{
|
371 |
-
add_action('shutdown', function() {
|
372 |
-
$this->xcloner_filesystem = new Xcloner_File_System($this);
|
373 |
-
$this->xcloner_filesystem->remove_tmp_filesystem();
|
374 |
-
});
|
375 |
-
}
|
376 |
-
|
377 |
-
$this->xcloner_sanitization = new Xcloner_Sanitization();
|
378 |
-
$this->xcloner_requirements = new Xcloner_Requirements($this);
|
379 |
-
|
380 |
-
add_action('admin_init', array($this->xcloner_settings, 'settings_init'));
|
381 |
-
|
382 |
-
//adding links to the Manage Plugins Wordpress page for XCloner
|
383 |
-
add_filter('plugin_action_links', array($this, 'add_plugin_action_links'), 10, 2);
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
}
|
388 |
-
|
389 |
-
/*
|
390 |
-
* @method static $this get_xcloner_logger()
|
391 |
-
* @method static $this get_xcloner_settings()
|
392 |
-
* type = core|plugin|theme|translation
|
393 |
-
*/
|
394 |
-
public function pre_auto_update($type, $item, $context)
|
395 |
-
{
|
396 |
-
if (!$type)
|
397 |
-
{
|
398 |
-
return false;
|
399 |
-
}
|
400 |
-
|
401 |
-
$exclude_files = array();
|
402 |
-
$regex = "";
|
403 |
-
$data = "";
|
404 |
-
|
405 |
-
$this->get_xcloner_logger()->info(sprintf("Doing automatic backup before %s upgrade, pre_auto_update hook.", $type));
|
406 |
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
|
|
|
|
|
|
|
|
|
|
419 |
|
420 |
-
|
421 |
-
|
422 |
-
foreach ($dir_array as $dir)
|
423 |
-
{
|
424 |
-
$data .= "\/".$dir;
|
425 |
-
$regex .= $data."$|";
|
426 |
-
}
|
427 |
|
428 |
-
|
|
|
|
|
429 |
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
-
|
|
|
437 |
|
438 |
-
|
439 |
-
|
440 |
-
$data .= "\/".$dir;
|
441 |
-
$regex .= $data."$|";
|
442 |
-
}
|
443 |
|
444 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
445 |
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
{
|
456 |
-
$data .= "\/".$dir;
|
457 |
-
$regex .= $data."$|";
|
458 |
-
}
|
459 |
|
460 |
-
|
461 |
-
|
462 |
-
$exclude_files = array(
|
463 |
-
"^(?!(".$regex."))(.*)$",
|
464 |
-
);
|
465 |
-
break;
|
466 |
-
}
|
467 |
|
468 |
-
|
469 |
-
|
470 |
-
$schedule['id'] = 0;
|
471 |
-
$schedule['name'] = "pre_auto_update";
|
472 |
-
$schedule['recurrence'] = "single";
|
473 |
-
$schedule['excluded_files'] = json_encode($exclude_files);
|
474 |
-
$schedule['table_params'] = json_encode(array("#" => array($this->get_xcloner_settings()->get_db_database())));
|
475 |
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
* of the plugin.
|
491 |
-
*
|
492 |
-
* @since 1.0.0
|
493 |
-
* @access private
|
494 |
-
*/
|
495 |
-
private function define_public_hooks() {
|
496 |
-
|
497 |
-
$plugin_public = new Xcloner_Public($this);
|
498 |
-
|
499 |
-
$this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
|
500 |
-
$this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
|
501 |
-
|
502 |
-
}
|
503 |
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
{
|
514 |
-
$logger->debug($this->friendly_error_type($error['type']).": ".var_export($error, true));
|
515 |
}
|
516 |
|
517 |
-
|
|
|
|
|
518 |
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
530 |
|
531 |
/**
|
532 |
* @method get_xcloner_settings()
|
533 |
* @throws Exception
|
534 |
*/
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
}
|
600 |
|
601 |
/**
|
602 |
* @method get_xcloner_scheduler()
|
603 |
*/
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
696 |
}
|
39 |
* @package Xcloner
|
40 |
* @subpackage Xcloner/includes
|
41 |
* @author Liuta Ovidiu <info@thinkovi.com>
|
42 |
+
* @link https://watchful.net
|
43 |
*/
|
44 |
+
class Xcloner
|
45 |
+
{
|
46 |
+
|
47 |
+
/**
|
48 |
+
* The loader that's responsible for maintaining and registering all hooks that power
|
49 |
+
* the plugin.
|
50 |
+
*
|
51 |
+
* @since 1.0.0
|
52 |
+
* @access protected
|
53 |
+
* @var Xcloner_Loader $loader Maintains and registers all hooks for the plugin.
|
54 |
+
*/
|
55 |
+
protected $loader;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* The unique identifier of this plugin.
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
* @access protected
|
62 |
+
* @var string $plugin_name The string used to uniquely identify this plugin.
|
63 |
+
*/
|
64 |
+
protected $plugin_name;
|
65 |
+
|
66 |
+
protected $plugin_admin;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* The current version of the plugin.
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
* @access protected
|
73 |
+
* @var string $version The current version of the plugin.
|
74 |
+
*/
|
75 |
+
protected $version;
|
76 |
+
|
77 |
+
private $xcloner_settings;
|
78 |
+
private $xcloner_logger;
|
79 |
+
private $xcloner_sanitization;
|
80 |
+
private $xcloner_requirements;
|
81 |
+
private $xcloner_filesystem;
|
82 |
+
private $archive_system;
|
83 |
+
private $xcloner_database;
|
84 |
+
private $xcloner_scheduler;
|
85 |
+
private $xcloner_remote_storage;
|
86 |
+
private $xcloner_file_transfer;
|
87 |
+
private $xcloner_encryption;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Define the core functionality of the plugin.
|
91 |
+
*
|
92 |
+
* Set the plugin name and the plugin version that can be used throughout the plugin.
|
93 |
+
* Load the dependencies, define the locale, and set the hooks for the admin area and
|
94 |
+
* the public-facing side of the site.
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*/
|
98 |
+
public function init()
|
99 |
+
{
|
100 |
+
$this->log_php_errors();
|
101 |
+
|
102 |
+
$this->plugin_name = 'xcloner';
|
103 |
+
$this->version = '4.0.4';
|
104 |
+
|
105 |
+
$this->load_dependencies();
|
106 |
+
$this->set_locale();
|
107 |
+
$this->define_admin_hooks();
|
108 |
+
$this->define_public_hooks();
|
109 |
+
|
110 |
+
$this->define_admin_menu();
|
111 |
+
$this->define_plugin_settings();
|
112 |
+
|
113 |
+
$this->define_ajax_hooks();
|
114 |
+
$this->define_cron_hooks();
|
115 |
+
}
|
116 |
+
|
117 |
+
public function log_php_errors(){
|
118 |
+
register_shutdown_function(array($this, 'exception_handler'));
|
119 |
+
}
|
120 |
|
121 |
/**
|
122 |
* Dynamic get of class methods get_
|
124 |
* @param $args
|
125 |
* @return mixed
|
126 |
*/
|
127 |
+
public function __call($property, $args)
|
128 |
+
{
|
129 |
$property = str_replace("get_", "", $property);
|
130 |
|
131 |
+
if (property_exists($this, $property)) {
|
132 |
return $this->$property;
|
133 |
}
|
134 |
}
|
139 |
* @param int $length
|
140 |
* @return string
|
141 |
*/
|
142 |
+
public function randomString($length = 6)
|
143 |
+
{
|
144 |
$str = "";
|
145 |
$characters = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
|
146 |
$max = count($characters) - 1;
|
151 |
return $str;
|
152 |
}
|
153 |
|
154 |
+
public function check_dependencies()
|
155 |
+
{
|
156 |
+
$backup_storage_path = (get_option('xcloner_store_path'));
|
|
|
|
|
157 |
|
158 |
+
if (!$backup_storage_path) {
|
159 |
$backup_storage_path = realpath(__DIR__ . DS . ".." . DS . ".." . DS . "..") . DS . "backups-" . $this->randomString('5') . DS;
|
160 |
+
}
|
161 |
|
162 |
+
if (!is_dir($backup_storage_path)) {
|
163 |
+
if (!@mkdir($backup_storage_path)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
$status = "error";
|
165 |
+
$message = sprintf(
|
166 |
+
__("Unable to create the Backup Storage Location Folder %s . Please fix this before starting the backup process."),
|
167 |
+
$backup_storage_path
|
168 |
+
);
|
169 |
$this->trigger_message($message, $status, $backup_storage_path);
|
|
|
170 |
return;
|
171 |
}
|
172 |
+
}
|
173 |
+
|
174 |
+
if (!is_writable($backup_storage_path)) {
|
175 |
+
$status = "error";
|
176 |
+
$message = sprintf(
|
177 |
+
__("Unable to write to the Backup Storage Location Folder %s . Please fix this before starting the backup process."),
|
178 |
+
$backup_storage_path
|
179 |
+
);
|
180 |
+
$this->trigger_message($message, $status, $backup_storage_path);
|
181 |
+
|
182 |
+
return;
|
183 |
}
|
184 |
|
185 |
+
update_option("xcloner_store_path", $backup_storage_path);
|
186 |
+
}
|
187 |
|
188 |
+
public function trigger_message($message, $status = "error", $message_param1 = "", $message_param2 = "", $message_param3 = "")
|
189 |
+
{
|
190 |
+
$message = sprintf(__($message), $message_param1, $message_param2, $message_param3);
|
191 |
+
add_action('xcloner_admin_notices', array($this, "trigger_message_notice"), 10, 2);
|
192 |
+
do_action('xcloner_admin_notices', $message, $status);
|
193 |
|
194 |
+
if (defined(XCLONER_STANDALONE_MODE) && XCLONER_STANDALONE_MODE) {
|
195 |
+
throw new Error($message);
|
196 |
+
}
|
197 |
+
}
|
|
|
|
|
|
|
|
|
198 |
|
199 |
+
public function trigger_message_notice($message, $status = "success")
|
200 |
+
{
|
201 |
+
?>
|
202 |
<div class="notice notice-<?php echo $status?> is-dismissible">
|
203 |
<p><?php _e($message, 'xcloner-backup-and-restore'); ?></p>
|
204 |
</div>
|
205 |
<?php
|
206 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
|
208 |
+
/**
|
209 |
+
* Load the required dependencies for this plugin.
|
210 |
+
*
|
211 |
+
* Include the following files that make up the plugin:
|
212 |
+
*
|
213 |
+
* - Xcloner_Loader. Orchestrates the hooks of the plugin.
|
214 |
+
* - Xcloner_i18n. Defines internationalization functionality.
|
215 |
+
* - Xcloner_Admin. Defines all hooks for the admin area.
|
216 |
+
* - Xcloner_Public. Defines all hooks for the public side of the site.
|
217 |
+
*
|
218 |
+
* Create an instance of the loader which will be used to register the hooks
|
219 |
+
* with WordPress.
|
220 |
+
*
|
221 |
+
* @since 1.0.0
|
222 |
+
* @access private
|
223 |
+
*/
|
224 |
+
public function load_dependencies()
|
225 |
+
{
|
226 |
+
|
227 |
+
/**
|
228 |
+
* The class responsible for orchestrating the actions and filters of the
|
229 |
+
* core plugin.
|
230 |
+
*/
|
231 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-loader.php';
|
232 |
+
|
233 |
+
/**
|
234 |
+
* The class responsible for defining internationalization functionality
|
235 |
+
* of the plugin.
|
236 |
+
*/
|
237 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-i18n.php';
|
238 |
+
|
239 |
+
/**
|
240 |
+
* The class responsible for defining all actions that occur in the admin area.
|
241 |
+
*/
|
242 |
+
require_once plugin_dir_path(dirname(__FILE__)).'admin/class-xcloner-admin.php';
|
243 |
+
|
244 |
+
/**
|
245 |
+
* The class responsible for debugging XCloner.
|
246 |
+
*/
|
247 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-logger.php';
|
248 |
+
|
249 |
+
/**
|
250 |
+
* The class responsible for defining the admin settings area.
|
251 |
+
*/
|
252 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-settings.php';
|
253 |
+
|
254 |
+
/**
|
255 |
+
* The class responsible for defining the Remote Storage settings area.
|
256 |
+
*/
|
257 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-remote-storage.php';
|
258 |
+
|
259 |
+
/**
|
260 |
+
* The class responsible for implementing the database backup methods.
|
261 |
+
*/
|
262 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-database.php';
|
263 |
+
|
264 |
+
/**
|
265 |
+
* The class responsible for sanitization of users input.
|
266 |
+
*/
|
267 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-sanitization.php';
|
268 |
+
|
269 |
+
/**
|
270 |
+
* The class responsible for XCloner system requirements validation.
|
271 |
+
*/
|
272 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-requirements.php';
|
273 |
+
|
274 |
+
/**
|
275 |
+
* The class responsible for XCloner backup archive creation.
|
276 |
+
*/
|
277 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-archive.php';
|
278 |
+
|
279 |
+
/**
|
280 |
+
* The class responsible for XCloner API requests.
|
281 |
+
*/
|
282 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-api.php';
|
283 |
+
|
284 |
+
/**
|
285 |
+
* The class responsible for the XCloner File System methods.
|
286 |
+
*/
|
287 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-system.php';
|
288 |
+
|
289 |
+
/**
|
290 |
+
* The class responsible for the XCloner File Transfer methods.
|
291 |
+
*/
|
292 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-transfer.php';
|
293 |
+
|
294 |
+
/**
|
295 |
+
* The class responsible for the XCloner Scheduler methods.
|
296 |
+
*/
|
297 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-scheduler.php';
|
298 |
+
|
299 |
+
/**
|
300 |
+
* The class responsible for the XCloner Encryption methods.
|
301 |
+
*/
|
302 |
+
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-encryption.php';
|
303 |
+
|
304 |
+
/**
|
305 |
+
* The class responsible for defining all actions that occur in the public-facing
|
306 |
+
* side of the site.
|
307 |
+
*/
|
308 |
+
require_once plugin_dir_path(dirname(__FILE__)).'public/class-xcloner-public.php';
|
309 |
+
|
310 |
+
$this->loader = new Xcloner_Loader($this);
|
311 |
+
}
|
312 |
|
313 |
+
/**
|
314 |
+
* Define the locale for this plugin for internationalization.
|
315 |
+
*
|
316 |
+
* Uses the Xcloner_i18n class in order to set the domain and to register the hook
|
317 |
+
* with WordPress.
|
318 |
+
*
|
319 |
+
* @since 1.0.0
|
320 |
+
* @access private
|
321 |
+
*/
|
322 |
+
private function set_locale()
|
323 |
+
{
|
324 |
+
$plugin_i18n = new Xcloner_i18n();
|
325 |
|
326 |
+
$this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
|
328 |
+
//wp_localize_script( 'ajax-script', 'my_ajax_object',
|
329 |
+
// array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
|
330 |
+
}
|
331 |
|
332 |
+
/**
|
333 |
+
* Register all of the hooks related to the admin area functionality
|
334 |
+
* of the plugin.
|
335 |
+
*
|
336 |
+
* @since 1.0.0
|
337 |
+
* @access private
|
338 |
+
*/
|
339 |
+
private function define_admin_hooks()
|
340 |
+
{
|
341 |
+
$plugin_admin = new Xcloner_Admin($this);
|
342 |
+
$this->plugin_admin = $plugin_admin;
|
343 |
|
344 |
+
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
|
345 |
+
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
|
346 |
|
347 |
+
$this->loader->add_action('backup_archive_finished', $this, 'do_action_after_backup_finished', 10, 2);
|
348 |
+
}
|
|
|
|
|
|
|
349 |
|
350 |
+
/**
|
351 |
+
* Register the Admin Sidebar menu
|
352 |
+
*
|
353 |
+
* @access private
|
354 |
+
*
|
355 |
+
*/
|
356 |
+
private function define_admin_menu()
|
357 |
+
{
|
358 |
+
$this->loader->add_action('admin_menu', $this, 'xcloner_backup_add_admin_menu');
|
359 |
+
}
|
360 |
|
361 |
+
public function define_plugin_settings()
|
362 |
+
{
|
363 |
+
/**
|
364 |
+
* register wporg_settings_init to the admin_init action hook
|
365 |
+
*/
|
366 |
+
$this->xcloner_settings = new XCloner_Settings($this);
|
367 |
+
|
368 |
+
if (defined('DOING_CRON') || isset($_POST['hash'])) {
|
369 |
+
if (defined('DOING_CRON') || $_POST['hash'] == "generate_hash") {
|
370 |
+
$this->xcloner_settings->generate_new_hash();
|
371 |
+
} else {
|
372 |
+
$this->xcloner_settings->set_hash($_POST['hash']);
|
373 |
+
}
|
374 |
+
}
|
375 |
|
376 |
+
if (defined('DOING_CRON') || !isset($_POST['hash'])) {
|
377 |
+
$this->loader->add_action('shutdown', $this, 'do_shutdown');
|
378 |
+
}
|
|
|
|
|
|
|
|
|
379 |
|
380 |
+
$this->xcloner_sanitization = new Xcloner_Sanitization();
|
381 |
+
$this->xcloner_requirements = new Xcloner_Requirements($this);
|
|
|
|
|
|
|
|
|
|
|
382 |
|
383 |
+
$this->loader->add_action('admin_init', $this->xcloner_settings, 'settings_init');
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
|
385 |
+
//adding links to the Manage Plugins Wordpress page for XCloner
|
386 |
+
$this->loader->add_filter('plugin_action_links', $this, 'add_plugin_action_links', 10, 2);
|
387 |
+
}
|
388 |
|
389 |
+
/**
|
390 |
+
* Shutdown actions
|
391 |
+
*
|
392 |
+
* @return void
|
393 |
+
*/
|
394 |
+
public function do_shutdown()
|
395 |
+
{
|
396 |
+
$this->xcloner_filesystem = new Xcloner_File_System($this);
|
397 |
+
$this->xcloner_filesystem->remove_tmp_filesystem();
|
398 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
|
400 |
+
/*
|
401 |
+
* @method static $this get_xcloner_logger()
|
402 |
+
* @method static $this get_xcloner_settings()
|
403 |
+
* type = core|plugin|theme|translation
|
404 |
+
*/
|
405 |
+
public function pre_auto_update($type, $item, $context)
|
406 |
+
{
|
407 |
+
if (!$type) {
|
408 |
+
return false;
|
|
|
|
|
409 |
}
|
410 |
|
411 |
+
$exclude_files = array();
|
412 |
+
$regex = "";
|
413 |
+
$data = "";
|
414 |
|
415 |
+
$this->get_xcloner_logger()->info(sprintf("Doing automatic backup before %s upgrade, pre_auto_update hook.", $type));
|
416 |
+
|
417 |
+
$content_dir = str_replace(ABSPATH, "", WP_CONTENT_DIR);
|
418 |
+
$plugins_dir = str_replace(ABSPATH, "", WP_PLUGIN_DIR);
|
419 |
+
$langs_dir = $content_dir.DS."languages";
|
420 |
+
$themes_dir = $content_dir.DS."themes";
|
421 |
+
|
422 |
+
switch ($type) {
|
423 |
+
case 'core':
|
424 |
+
$exclude_files = array(
|
425 |
+
"^(?!(wp-admin|wp-includes|(?!.*\/.*.php)))(.*)$",
|
426 |
+
);
|
427 |
+
break;
|
428 |
+
case 'plugin':
|
429 |
+
|
430 |
+
$dir_array = explode(DS, $plugins_dir);
|
431 |
+
|
432 |
+
foreach ($dir_array as $dir) {
|
433 |
+
$data .= "\/".$dir;
|
434 |
+
$regex .= $data."$|";
|
435 |
+
}
|
436 |
+
|
437 |
+
$regex .= "\/".implode("\/", $dir_array);
|
438 |
+
|
439 |
+
$exclude_files = array(
|
440 |
+
"^(?!(".$regex."))(.*)$",
|
441 |
+
);
|
442 |
+
break;
|
443 |
+
case 'theme':
|
444 |
+
|
445 |
+
$dir_array = explode(DS, $themes_dir);
|
446 |
+
|
447 |
+
foreach ($dir_array as $dir) {
|
448 |
+
$data .= "\/".$dir;
|
449 |
+
$regex .= $data."$|";
|
450 |
+
}
|
451 |
+
|
452 |
+
$regex .= "\/".implode("\/", $dir_array);
|
453 |
+
|
454 |
+
$exclude_files = array(
|
455 |
+
"^(?!(".$regex."))(.*)$",
|
456 |
+
);
|
457 |
+
break;
|
458 |
+
case 'translation':
|
459 |
+
|
460 |
+
$dir_array = explode(DS, $langs_dir);
|
461 |
+
|
462 |
+
foreach ($dir_array as $dir) {
|
463 |
+
$data .= "\/".$dir;
|
464 |
+
$regex .= $data."$|";
|
465 |
+
}
|
466 |
+
|
467 |
+
$regex .= "\/".implode("\/", $dir_array);
|
468 |
+
|
469 |
+
$exclude_files = array(
|
470 |
+
"^(?!(".$regex."))(.*)$",
|
471 |
+
);
|
472 |
+
break;
|
473 |
+
}
|
474 |
+
|
475 |
+
$schedule = array();
|
476 |
+
|
477 |
+
$schedule['id'] = 0;
|
478 |
+
$schedule['name'] = "pre_auto_update";
|
479 |
+
$schedule['recurrence'] = "single";
|
480 |
+
$schedule['excluded_files'] = json_encode($exclude_files);
|
481 |
+
$schedule['table_params'] = json_encode(array("#" => array($this->get_xcloner_settings()->get_db_database())));
|
482 |
+
|
483 |
+
$schedule['backup_params'] = new stdClass();
|
484 |
+
$schedule['backup_params']->email_notification = get_option('admin_email');
|
485 |
+
$schedule['backup_params']->backup_name = "backup_pre_auto_update_".$type."_[domain]-[time]-sql";
|
486 |
+
|
487 |
+
try {
|
488 |
+
$this->xcloner_scheduler->xcloner_scheduler_callback(0, $schedule);
|
489 |
+
} catch (Exception $e) {
|
490 |
+
$this->get_xcloner_logger()->error($e->getMessage());
|
491 |
+
}
|
492 |
+
}
|
493 |
+
|
494 |
+
/**
|
495 |
+
* Register all of the hooks related to the public-facing functionality
|
496 |
+
* of the plugin.
|
497 |
+
*
|
498 |
+
* @since 1.0.0
|
499 |
+
* @access private
|
500 |
+
*/
|
501 |
+
private function define_public_hooks()
|
502 |
+
{
|
503 |
+
$plugin_public = new Xcloner_Public($this);
|
504 |
+
|
505 |
+
$this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
|
506 |
+
$this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
|
507 |
+
}
|
508 |
+
|
509 |
+
public function exception_handler()
|
510 |
+
{
|
511 |
+
$logger = new XCloner_Logger($this, "php_system");
|
512 |
+
$error = error_get_last();
|
513 |
+
|
514 |
+
if ($error['type'] and $error['type'] === E_ERROR and $logger) {
|
515 |
+
$logger->error($this->friendly_error_type($error['type']).": ".var_export($error, true));
|
516 |
+
} elseif ($error['type'] and $logger) {
|
517 |
+
$logger->debug($this->friendly_error_type($error['type']).": ".var_export($error, true));
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
public function friendly_error_type($type)
|
522 |
+
{
|
523 |
+
static $levels = null;
|
524 |
+
if ($levels === null) {
|
525 |
+
$levels = [];
|
526 |
+
foreach (get_defined_constants() as $key=>$value) {
|
527 |
+
if (strpos($key, 'E_') !== 0) {
|
528 |
+
continue;
|
529 |
+
}
|
530 |
+
$levels[$value] = $key; //substr($key,2);
|
531 |
+
}
|
532 |
+
}
|
533 |
+
return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
|
534 |
+
}
|
535 |
|
536 |
/**
|
537 |
* @method get_xcloner_settings()
|
538 |
* @throws Exception
|
539 |
*/
|
540 |
+
public function define_ajax_hooks()
|
541 |
+
{
|
542 |
+
//adding the pre-update hook
|
543 |
+
|
544 |
+
if (is_admin() || defined('DOING_CRON')) {
|
545 |
+
$this->xcloner_logger = new XCloner_Logger($this, "xcloner_api");
|
546 |
+
$this->xcloner_filesystem = new Xcloner_File_System($this);
|
547 |
+
|
548 |
+
//$this->xcloner_filesystem->set_diff_timestamp_start (strtotime("-15 days"));
|
549 |
+
|
550 |
+
$this->archive_system = new Xcloner_Archive($this);
|
551 |
+
$this->xcloner_database = new Xcloner_Database($this);
|
552 |
+
$this->xcloner_scheduler = new Xcloner_Scheduler($this);
|
553 |
+
$this->xcloner_remote_storage = new Xcloner_Remote_Storage($this);
|
554 |
+
$this->xcloner_file_transfer = new Xcloner_File_Transfer($this);
|
555 |
+
$this->xcloner_encryption = new Xcloner_Encryption($this);
|
556 |
+
|
557 |
+
$xcloner_api = new Xcloner_Api($this);
|
558 |
+
|
559 |
+
|
560 |
+
$this->loader->add_action('wp_ajax_get_database_tables_action', $xcloner_api, 'get_database_tables_action');
|
561 |
+
$this->loader->add_action('wp_ajax_get_file_system_action', $xcloner_api, 'get_file_system_action');
|
562 |
+
$this->loader->add_action('wp_ajax_scan_filesystem', $xcloner_api, 'scan_filesystem');
|
563 |
+
$this->loader->add_action('wp_ajax_backup_database', $xcloner_api, 'backup_database');
|
564 |
+
$this->loader->add_action('wp_ajax_backup_files', $xcloner_api, 'backup_files');
|
565 |
+
$this->loader->add_action('wp_ajax_save_schedule', $xcloner_api, 'save_schedule');
|
566 |
+
$this->loader->add_action('wp_ajax_get_schedule_by_id', $xcloner_api, 'get_schedule_by_id');
|
567 |
+
$this->loader->add_action('wp_ajax_get_scheduler_list', $xcloner_api, 'get_scheduler_list');
|
568 |
+
$this->loader->add_action('wp_ajax_delete_schedule_by_id', $xcloner_api, 'delete_schedule_by_id');
|
569 |
+
$this->loader->add_action('wp_ajax_delete_backup_by_name', $xcloner_api, 'delete_backup_by_name');
|
570 |
+
$this->loader->add_action('wp_ajax_download_backup_by_name', $xcloner_api, 'download_backup_by_name');
|
571 |
+
$this->loader->add_action('wp_ajax_remote_storage_save_status', $xcloner_api, 'remote_storage_save_status');
|
572 |
+
$this->loader->add_action('wp_ajax_upload_backup_to_remote', $xcloner_api, 'upload_backup_to_remote');
|
573 |
+
$this->loader->add_action('wp_ajax_list_backup_files', $xcloner_api, 'list_backup_files');
|
574 |
+
$this->loader->add_action('wp_ajax_restore_upload_backup', $xcloner_api, 'restore_upload_backup');
|
575 |
+
$this->loader->add_action('wp_ajax_download_restore_script', $xcloner_api, 'download_restore_script');
|
576 |
+
$this->loader->add_action('wp_ajax_copy_backup_remote_to_local', $xcloner_api, 'copy_backup_remote_to_local');
|
577 |
+
$this->loader->add_action('wp_ajax_restore_backup', $xcloner_api, 'restore_backup');
|
578 |
+
$this->loader->add_action('wp_ajax_backup_encryption', $xcloner_api, 'backup_encryption');
|
579 |
+
$this->loader->add_action('wp_ajax_backup_decryption', $xcloner_api, 'backup_decryption');
|
580 |
+
$this->loader->add_action('wp_ajax_get_manage_backups_list', $xcloner_api, 'get_manage_backups_list');
|
581 |
+
$this->loader->add_action('admin_notices', $this, 'xcloner_error_admin_notices');
|
582 |
+
}
|
583 |
+
|
584 |
+
//Do a pre-update backup of targeted files
|
585 |
+
if ($this->get_xcloner_settings()->get_xcloner_option('xcloner_enable_pre_update_backup')) {
|
586 |
+
$this->loader->add_action("pre_auto_update", $this, "pre_auto_update", 1, 3);
|
587 |
+
}
|
588 |
+
}
|
589 |
+
|
590 |
+
public function add_plugin_action_links($links, $file)
|
591 |
+
{
|
592 |
+
if ($file == plugin_basename(dirname(dirname(__FILE__)).'/xcloner.php')) {
|
593 |
+
$links[] = '<a href="admin.php?page=xcloner_settings_page">'.__('Settings', 'xcloner-backup-and-restore').'</a>';
|
594 |
+
$links[] = '<a href="admin.php?page=xcloner_generate_backups_page">'.__('Generate Backup', 'xcloner-backup-and-restore').'</a>';
|
595 |
+
}
|
596 |
+
|
597 |
+
return $links;
|
598 |
+
}
|
599 |
+
|
600 |
+
public function xcloner_error_admin_notices()
|
601 |
+
{
|
602 |
+
settings_errors('xcloner_error_message');
|
603 |
+
}
|
|
|
604 |
|
605 |
/**
|
606 |
* @method get_xcloner_scheduler()
|
607 |
*/
|
608 |
+
public function define_cron_hooks()
|
609 |
+
{
|
610 |
+
//registering new schedule intervals
|
611 |
+
add_filter('cron_schedules', array($this, 'add_new_intervals'));
|
612 |
+
|
613 |
+
|
614 |
+
$xcloner_scheduler = $this->get_xcloner_scheduler();
|
615 |
+
$xcloner_scheduler->update_wp_cron_hooks();
|
616 |
+
}
|
617 |
+
|
618 |
+
/**
|
619 |
+
* @param $schedules
|
620 |
+
* @return mixed
|
621 |
+
*/
|
622 |
+
public function add_new_intervals($schedules)
|
623 |
+
{
|
624 |
+
//weekly scheduler interval
|
625 |
+
$schedules['weekly'] = array(
|
626 |
+
'interval' => 604800,
|
627 |
+
'display' => __('Once Weekly', 'xcloner-backup-and-restore')
|
628 |
+
);
|
629 |
+
|
630 |
+
//monthly scheduler interval
|
631 |
+
$schedules['monthly'] = array(
|
632 |
+
'interval' => 2635200,
|
633 |
+
'display' => __('Once Monthly', 'xcloner-backup-and-restore')
|
634 |
+
);
|
635 |
+
|
636 |
+
//monthly scheduler interval
|
637 |
+
$schedules['twicedaily'] = array(
|
638 |
+
'interval' => 43200,
|
639 |
+
'display' => __('Twice Daily', 'xcloner-backup-and-restore')
|
640 |
+
);
|
641 |
+
|
642 |
+
return $schedules;
|
643 |
+
}
|
644 |
+
|
645 |
+
/**
|
646 |
+
* Add XCloner to Admin Menu
|
647 |
+
*/
|
648 |
+
public function xcloner_backup_add_admin_menu()
|
649 |
+
{
|
650 |
+
if (function_exists('add_menu_page')) {
|
651 |
+
add_menu_page(
|
652 |
+
__('Site Backup', 'xcloner-backup-and-restore'),
|
653 |
+
__('Site Backup', 'xcloner-backup-and-restore'),
|
654 |
+
'manage_options',
|
655 |
+
'xcloner_init_page',
|
656 |
+
array($this, 'xcloner_display'),
|
657 |
+
'dashicons-backup'
|
658 |
+
);
|
659 |
+
}
|
660 |
+
|
661 |
+
if (function_exists('add_submenu_page')) {
|
662 |
+
add_submenu_page(
|
663 |
+
'xcloner_init_page',
|
664 |
+
__('XCloner Dashboard', 'xcloner-backup-and-restore'),
|
665 |
+
__('Dashboard', 'xcloner-backup-and-restore'),
|
666 |
+
'manage_options',
|
667 |
+
'xcloner_init_page',
|
668 |
+
array($this, 'xcloner_display')
|
669 |
+
);
|
670 |
+
add_submenu_page(
|
671 |
+
'xcloner_init_page',
|
672 |
+
__('XCloner Backup Settings', 'xcloner-backup-and-restore'),
|
673 |
+
__('Settings', 'xcloner-backup-and-restore'),
|
674 |
+
'manage_options',
|
675 |
+
'xcloner_settings_page',
|
676 |
+
array($this, 'xcloner_display')
|
677 |
+
);
|
678 |
+
add_submenu_page(
|
679 |
+
'xcloner_init_page',
|
680 |
+
__('Remote Storage Settings', 'xcloner-backup-and-restore'),
|
681 |
+
__('Remote Storage', 'xcloner-backup-and-restore'),
|
682 |
+
'manage_options',
|
683 |
+
'xcloner_remote_storage_page',
|
684 |
+
array($this, 'xcloner_display')
|
685 |
+
);
|
686 |
+
add_submenu_page(
|
687 |
+
'xcloner_init_page',
|
688 |
+
__('Manage Backups', 'xcloner-backup-and-restore'),
|
689 |
+
__('Manage Backups', 'xcloner-backup-and-restore'),
|
690 |
+
'manage_options',
|
691 |
+
'xcloner_manage_backups_page',
|
692 |
+
array($this, 'xcloner_display')
|
693 |
+
);
|
694 |
+
add_submenu_page(
|
695 |
+
'xcloner_init_page',
|
696 |
+
__('Scheduled Backups', 'xcloner-backup-and-restore'),
|
697 |
+
__('Scheduled Backups', 'xcloner-backup-and-restore'),
|
698 |
+
'manage_options',
|
699 |
+
'xcloner_scheduled_backups_page',
|
700 |
+
array($this, 'xcloner_display')
|
701 |
+
);
|
702 |
+
add_submenu_page(
|
703 |
+
'xcloner_init_page',
|
704 |
+
__('Generate Backups', 'xcloner-backup-and-restore'),
|
705 |
+
__('Generate Backups', 'xcloner-backup-and-restore'),
|
706 |
+
'manage_options',
|
707 |
+
'xcloner_generate_backups_page',
|
708 |
+
array($this, 'xcloner_display')
|
709 |
+
);
|
710 |
+
add_submenu_page(
|
711 |
+
'xcloner_init_page',
|
712 |
+
__('Restore Backups', 'xcloner-backup-and-restore'),
|
713 |
+
__('Restore Backups', 'xcloner-backup-and-restore'),
|
714 |
+
'manage_options',
|
715 |
+
'xcloner_restore_page',
|
716 |
+
array($this, 'xcloner_display')
|
717 |
+
);
|
718 |
+
}
|
719 |
+
}
|
720 |
+
|
721 |
+
/**
|
722 |
+
* Run the loader to execute all of the hooks with WordPress.
|
723 |
+
*
|
724 |
+
* @since 1.0.0
|
725 |
+
*/
|
726 |
+
public function run()
|
727 |
+
{
|
728 |
+
$this->loader->run();
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* The name of the plugin used to uniquely identify it within the context of
|
733 |
+
* WordPress and to define internationalization functionality.
|
734 |
+
*
|
735 |
+
* @since 1.0.0
|
736 |
+
* @return string The name of the plugin.
|
737 |
+
*/
|
738 |
+
public function get_plugin_name()
|
739 |
+
{
|
740 |
+
return $this->plugin_name;
|
741 |
+
}
|
742 |
+
|
743 |
+
/**
|
744 |
+
* The reference to the class that orchestrates the hooks with the plugin.
|
745 |
+
*
|
746 |
+
* @since 1.0.0
|
747 |
+
* @return Xcloner_Loader Orchestrates the hooks of the plugin.
|
748 |
+
*/
|
749 |
+
public function get_loader()
|
750 |
+
{
|
751 |
+
return $this->loader;
|
752 |
+
}
|
753 |
+
|
754 |
+
public function xcloner_display()
|
755 |
+
{
|
756 |
+
// check user capabilities
|
757 |
+
if (!current_user_can('manage_options')) {
|
758 |
+
return;
|
759 |
+
}
|
760 |
+
|
761 |
+
$page = sanitize_key($_GET['page']);
|
762 |
+
|
763 |
+
if ($page) {
|
764 |
+
$this->display($page);
|
765 |
+
}
|
766 |
+
}
|
767 |
+
|
768 |
+
public function display($page)
|
769 |
+
{
|
770 |
+
$plugin_admin = new Xcloner_Admin($this);
|
771 |
+
$this->plugin_admin = $plugin_admin;
|
772 |
+
|
773 |
+
call_user_func_array(array($this->plugin_admin, $page), array());
|
774 |
+
}
|
775 |
}
|
lib/class-wp-error.php
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WordPress Error API.
|
4 |
+
*
|
5 |
+
* Contains the WP_Error class and the is_wp_error() function.
|
6 |
+
*
|
7 |
+
* @package WordPress
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* WordPress Error class.
|
12 |
+
*
|
13 |
+
* Container for checking for WordPress errors and error messages. Return
|
14 |
+
* WP_Error and use is_wp_error() to check if this class is returned. Many
|
15 |
+
* core WordPress functions pass this class in the event of an error and
|
16 |
+
* if not handled properly will result in code errors.
|
17 |
+
*
|
18 |
+
* @since 2.1.0
|
19 |
+
*/
|
20 |
+
class WP_Error {
|
21 |
+
/**
|
22 |
+
* Stores the list of errors.
|
23 |
+
*
|
24 |
+
* @since 2.1.0
|
25 |
+
* @var array
|
26 |
+
*/
|
27 |
+
public $errors = array();
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Stores the list of data for error codes.
|
31 |
+
*
|
32 |
+
* @since 2.1.0
|
33 |
+
* @var array
|
34 |
+
*/
|
35 |
+
public $error_data = array();
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Initialize the error.
|
39 |
+
*
|
40 |
+
* If `$code` is empty, the other parameters will be ignored.
|
41 |
+
* When `$code` is not empty, `$message` will be used even if
|
42 |
+
* it is empty. The `$data` parameter will be used only if it
|
43 |
+
* is not empty.
|
44 |
+
*
|
45 |
+
* Though the class is constructed with a single error code and
|
46 |
+
* message, multiple codes can be added using the `add()` method.
|
47 |
+
*
|
48 |
+
* @since 2.1.0
|
49 |
+
*
|
50 |
+
* @param string|int $code Error code
|
51 |
+
* @param string $message Error message
|
52 |
+
* @param mixed $data Optional. Error data.
|
53 |
+
*/
|
54 |
+
public function __construct( $code = '', $message = '', $data = '' ) {
|
55 |
+
if ( empty( $code ) ) {
|
56 |
+
return;
|
57 |
+
}
|
58 |
+
|
59 |
+
$this->errors[ $code ][] = $message;
|
60 |
+
|
61 |
+
if ( ! empty( $data ) ) {
|
62 |
+
$this->error_data[ $code ] = $data;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Retrieve all error codes.
|
68 |
+
*
|
69 |
+
* @since 2.1.0
|
70 |
+
*
|
71 |
+
* @return array List of error codes, if available.
|
72 |
+
*/
|
73 |
+
public function get_error_codes() {
|
74 |
+
if ( ! $this->has_errors() ) {
|
75 |
+
return array();
|
76 |
+
}
|
77 |
+
|
78 |
+
return array_keys( $this->errors );
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Retrieve first error code available.
|
83 |
+
*
|
84 |
+
* @since 2.1.0
|
85 |
+
*
|
86 |
+
* @return string|int Empty string, if no error codes.
|
87 |
+
*/
|
88 |
+
public function get_error_code() {
|
89 |
+
$codes = $this->get_error_codes();
|
90 |
+
|
91 |
+
if ( empty( $codes ) ) {
|
92 |
+
return '';
|
93 |
+
}
|
94 |
+
|
95 |
+
return $codes[0];
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Retrieve all error messages or error messages matching code.
|
100 |
+
*
|
101 |
+
* @since 2.1.0
|
102 |
+
*
|
103 |
+
* @param string|int $code Optional. Retrieve messages matching code, if exists.
|
104 |
+
* @return array Error strings on success, or empty array on failure (if using code parameter).
|
105 |
+
*/
|
106 |
+
public function get_error_messages( $code = '' ) {
|
107 |
+
// Return all messages if no code specified.
|
108 |
+
if ( empty( $code ) ) {
|
109 |
+
$all_messages = array();
|
110 |
+
foreach ( (array) $this->errors as $code => $messages ) {
|
111 |
+
$all_messages = array_merge( $all_messages, $messages );
|
112 |
+
}
|
113 |
+
|
114 |
+
return $all_messages;
|
115 |
+
}
|
116 |
+
|
117 |
+
if ( isset( $this->errors[ $code ] ) ) {
|
118 |
+
return $this->errors[ $code ];
|
119 |
+
} else {
|
120 |
+
return array();
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Get single error message.
|
126 |
+
*
|
127 |
+
* This will get the first message available for the code. If no code is
|
128 |
+
* given then the first code available will be used.
|
129 |
+
*
|
130 |
+
* @since 2.1.0
|
131 |
+
*
|
132 |
+
* @param string|int $code Optional. Error code to retrieve message.
|
133 |
+
* @return string
|
134 |
+
*/
|
135 |
+
public function get_error_message( $code = '' ) {
|
136 |
+
if ( empty( $code ) ) {
|
137 |
+
$code = $this->get_error_code();
|
138 |
+
}
|
139 |
+
$messages = $this->get_error_messages( $code );
|
140 |
+
if ( empty( $messages ) ) {
|
141 |
+
return '';
|
142 |
+
}
|
143 |
+
return $messages[0];
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Retrieve error data for error code.
|
148 |
+
*
|
149 |
+
* @since 2.1.0
|
150 |
+
*
|
151 |
+
* @param string|int $code Optional. Error code.
|
152 |
+
* @return mixed Error data, if it exists.
|
153 |
+
*/
|
154 |
+
public function get_error_data( $code = '' ) {
|
155 |
+
if ( empty( $code ) ) {
|
156 |
+
$code = $this->get_error_code();
|
157 |
+
}
|
158 |
+
|
159 |
+
if ( isset( $this->error_data[ $code ] ) ) {
|
160 |
+
return $this->error_data[ $code ];
|
161 |
+
}
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Verify if the instance contains errors.
|
166 |
+
*
|
167 |
+
* @since 5.1.0
|
168 |
+
*
|
169 |
+
* @return bool
|
170 |
+
*/
|
171 |
+
public function has_errors() {
|
172 |
+
if ( ! empty( $this->errors ) ) {
|
173 |
+
return true;
|
174 |
+
}
|
175 |
+
return false;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Add an error or append additional message to an existing error.
|
180 |
+
*
|
181 |
+
* @since 2.1.0
|
182 |
+
*
|
183 |
+
* @param string|int $code Error code.
|
184 |
+
* @param string $message Error message.
|
185 |
+
* @param mixed $data Optional. Error data.
|
186 |
+
*/
|
187 |
+
public function add( $code, $message, $data = '' ) {
|
188 |
+
$this->errors[ $code ][] = $message;
|
189 |
+
if ( ! empty( $data ) ) {
|
190 |
+
$this->error_data[ $code ] = $data;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Add data for error code.
|
196 |
+
*
|
197 |
+
* The error code can only contain one error data.
|
198 |
+
*
|
199 |
+
* @since 2.1.0
|
200 |
+
*
|
201 |
+
* @param mixed $data Error data.
|
202 |
+
* @param string|int $code Error code.
|
203 |
+
*/
|
204 |
+
public function add_data( $data, $code = '' ) {
|
205 |
+
if ( empty( $code ) ) {
|
206 |
+
$code = $this->get_error_code();
|
207 |
+
}
|
208 |
+
|
209 |
+
$this->error_data[ $code ] = $data;
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Removes the specified error.
|
214 |
+
*
|
215 |
+
* This function removes all error messages associated with the specified
|
216 |
+
* error code, along with any error data for that code.
|
217 |
+
*
|
218 |
+
* @since 4.1.0
|
219 |
+
*
|
220 |
+
* @param string|int $code Error code.
|
221 |
+
*/
|
222 |
+
public function remove( $code ) {
|
223 |
+
unset( $this->errors[ $code ] );
|
224 |
+
unset( $this->error_data[ $code ] );
|
225 |
+
}
|
226 |
+
}
|
lib/index.html
ADDED
File without changes
|
lib/mock_wp_functions.php
ADDED
@@ -0,0 +1,452 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$wp_settings_errors = "";
|
3 |
+
|
4 |
+
//NONCE_KEY
|
5 |
+
//NONCE_SALT
|
6 |
+
//ABSPATH
|
7 |
+
|
8 |
+
if (!defined('WP_DEBUG')) {
|
9 |
+
define('WP_DEBUG', false);
|
10 |
+
}
|
11 |
+
|
12 |
+
if (!defined('WPINC')) {
|
13 |
+
define('WPINC', false);
|
14 |
+
}
|
15 |
+
|
16 |
+
if (!defined('DOING_CRON')) {
|
17 |
+
define('DOING_CRON', false);
|
18 |
+
}
|
19 |
+
|
20 |
+
if (!defined('WP_DEBUG_DISPLAY')) {
|
21 |
+
define('WP_DEBUG_DISPLAY', false);
|
22 |
+
}
|
23 |
+
|
24 |
+
if (!defined('WP_CONTENT_DIR')) {
|
25 |
+
define('WP_CONTENT_DIR', __DIR__);
|
26 |
+
}
|
27 |
+
|
28 |
+
if (!defined('DS')) {
|
29 |
+
define('DS', DIRECTORY_SEPARATOR);
|
30 |
+
}
|
31 |
+
|
32 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
33 |
+
define('MINUTE_IN_SECONDS', 60);
|
34 |
+
}
|
35 |
+
|
36 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
37 |
+
define('HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS);
|
38 |
+
}
|
39 |
+
|
40 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
41 |
+
define('DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS);
|
42 |
+
}
|
43 |
+
|
44 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
45 |
+
define('WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS);
|
46 |
+
}
|
47 |
+
|
48 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
49 |
+
define('MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS);
|
50 |
+
}
|
51 |
+
|
52 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
53 |
+
define('YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS);
|
54 |
+
}
|
55 |
+
|
56 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
57 |
+
define('WPINC', true);
|
58 |
+
}
|
59 |
+
|
60 |
+
if(!class_exists('WP_Error')) {
|
61 |
+
require_once(__DIR__ . '/class-wp-error.php');
|
62 |
+
}
|
63 |
+
|
64 |
+
if (!function_exists('is_wp_error')) {
|
65 |
+
function is_wp_error($thing)
|
66 |
+
{
|
67 |
+
return ($thing instanceof WP_Error);
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
if (!function_exists('get_site_url')) {
|
72 |
+
function get_site_url()
|
73 |
+
{
|
74 |
+
return __DIR__;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
if (!function_exists('admin_url')) {
|
79 |
+
function admin_url()
|
80 |
+
{
|
81 |
+
return __DIR__;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Sanitize plugin dir path
|
87 |
+
*
|
88 |
+
* @param [type] $path
|
89 |
+
* @return void
|
90 |
+
*/
|
91 |
+
if (!function_exists('plugin_dir_path')) {
|
92 |
+
function plugin_dir_path($path)
|
93 |
+
{
|
94 |
+
return dirname($path).DS;
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Undocumented function
|
100 |
+
*
|
101 |
+
* @param [type] $setting
|
102 |
+
* @param [type] $code
|
103 |
+
* @param [type] $message
|
104 |
+
* @param string $type
|
105 |
+
* @return void
|
106 |
+
*/
|
107 |
+
if (!function_exists('add_settings_error')) {
|
108 |
+
function add_settings_error($setting, $code, $message, $type = 'error')
|
109 |
+
{
|
110 |
+
global $wp_settings_errors;
|
111 |
+
|
112 |
+
$wp_settings_errors[] = array(
|
113 |
+
'setting' => $setting,
|
114 |
+
'code' => $code,
|
115 |
+
'message' => $message,
|
116 |
+
'type' => $type,
|
117 |
+
);
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
if (!function_exists('has_filter')) {
|
122 |
+
function has_filter($tag, $function_to_check = false)
|
123 |
+
{
|
124 |
+
return false;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
if (!function_exists('mbstring_binary_safe_encoding')) {
|
129 |
+
function mbstring_binary_safe_encoding($reset = false)
|
130 |
+
{
|
131 |
+
static $encodings = array();
|
132 |
+
static $overloaded = null;
|
133 |
+
|
134 |
+
if (is_null($overloaded)) {
|
135 |
+
$overloaded = function_exists('mb_internal_encoding') && (ini_get('mbstring.func_overload') & 2);
|
136 |
+
}
|
137 |
+
|
138 |
+
if (false === $overloaded) {
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
if (! $reset) {
|
143 |
+
$encoding = mb_internal_encoding();
|
144 |
+
array_push($encodings, $encoding);
|
145 |
+
mb_internal_encoding('ISO-8859-1');
|
146 |
+
}
|
147 |
+
|
148 |
+
if ($reset && $encodings) {
|
149 |
+
$encoding = array_pop($encodings);
|
150 |
+
mb_internal_encoding($encoding);
|
151 |
+
}
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
if (!function_exists('reset_mbstring_encoding')) {
|
156 |
+
function reset_mbstring_encoding()
|
157 |
+
{
|
158 |
+
mbstring_binary_safe_encoding(true);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Get option
|
164 |
+
*
|
165 |
+
* @param [type] $option_name
|
166 |
+
* @return void
|
167 |
+
*/
|
168 |
+
if (!function_exists('get_option')) {
|
169 |
+
function get_option($option_name = "")
|
170 |
+
{
|
171 |
+
if (!$option_name) {
|
172 |
+
return $GLOBALS['xcloner_settings'];
|
173 |
+
}
|
174 |
+
|
175 |
+
if(!isset($GLOBALS['xcloner_settings'][$option_name])){
|
176 |
+
return null;
|
177 |
+
}
|
178 |
+
|
179 |
+
return $GLOBALS['xcloner_settings'][$option_name];
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Add option
|
185 |
+
*
|
186 |
+
* @param [type] $option_name
|
187 |
+
* @param string $value
|
188 |
+
* @return void
|
189 |
+
*/
|
190 |
+
if (!function_exists('add_option')) {
|
191 |
+
function add_option($option_name, $value="")
|
192 |
+
{
|
193 |
+
return $GLOBALS['xcloner_settings'][$option_name] = $value;
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Update option or create if it doesn't exist
|
199 |
+
*
|
200 |
+
* @param [type] $option_name
|
201 |
+
* @param string $value
|
202 |
+
* @return void
|
203 |
+
*/
|
204 |
+
if (!function_exists('update_option')) {
|
205 |
+
function update_option($option_name, $value="")
|
206 |
+
{
|
207 |
+
return add_option($option_name, $value);
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Die script
|
213 |
+
*/
|
214 |
+
if (!function_exists('wp_die')) {
|
215 |
+
function wp_die($msg)
|
216 |
+
{
|
217 |
+
die($msg);
|
218 |
+
}
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
*
|
223 |
+
*/
|
224 |
+
if (!function_exists('dbDelta')) {
|
225 |
+
function dbDelta($sql)
|
226 |
+
{
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Custom Watchfull backend check
|
232 |
+
*/
|
233 |
+
if (!function_exists('is_admin')) {
|
234 |
+
function is_admin()
|
235 |
+
{
|
236 |
+
return true;
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
*
|
242 |
+
*/
|
243 |
+
if (!function_exists('register_activation_hook')) {
|
244 |
+
function register_activation_hook($path, $hook)
|
245 |
+
{
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
*
|
251 |
+
*/
|
252 |
+
if (!function_exists('register_deactivation_hook')) {
|
253 |
+
function register_deactivation_hook($path, $hook)
|
254 |
+
{
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
*
|
260 |
+
*/
|
261 |
+
if (!function_exists('deactivate_plugins')) {
|
262 |
+
function deactivate_plugins($path)
|
263 |
+
{
|
264 |
+
}
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
*
|
269 |
+
*/
|
270 |
+
if (!function_exists('wp_deregister_script')) {
|
271 |
+
function wp_deregister_script($path)
|
272 |
+
{
|
273 |
+
}
|
274 |
+
}
|
275 |
+
|
276 |
+
|
277 |
+
/**
|
278 |
+
*
|
279 |
+
*/
|
280 |
+
if (!function_exists('add_action')) {
|
281 |
+
function add_action($hook, $callback)
|
282 |
+
{
|
283 |
+
if(substr($hook, 0, 8) == "wp_ajax_") {
|
284 |
+
$request = "wp_ajax_".$_REQUEST['action'];
|
285 |
+
if($request === $hook){
|
286 |
+
//print_r($callback[1]);
|
287 |
+
//exit;
|
288 |
+
return call_user_func($callback);
|
289 |
+
}
|
290 |
+
}
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
*
|
296 |
+
*/
|
297 |
+
if (!function_exists('do_action')) {
|
298 |
+
function do_action($hook)
|
299 |
+
{
|
300 |
+
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
*
|
306 |
+
*/
|
307 |
+
if (!function_exists('add_filter')) {
|
308 |
+
function add_filter($hook)
|
309 |
+
{
|
310 |
+
//echo $hook;
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
*
|
316 |
+
*/
|
317 |
+
if (!function_exists('apply_filters')) {
|
318 |
+
function apply_filters($tag, $value)
|
319 |
+
{
|
320 |
+
return $value;
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
*
|
326 |
+
*/
|
327 |
+
if (!function_exists('do_filter')) {
|
328 |
+
function do_filter2($hook)
|
329 |
+
{
|
330 |
+
}
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
*
|
335 |
+
*/
|
336 |
+
if (!function_exists('_e')) {
|
337 |
+
function _e($str)
|
338 |
+
{
|
339 |
+
return $str;
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
*
|
345 |
+
*/
|
346 |
+
if (!function_exists('plugin_basename')) {
|
347 |
+
function plugin_basename($path)
|
348 |
+
{
|
349 |
+
return $path;
|
350 |
+
}
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
*
|
355 |
+
*/
|
356 |
+
if (!function_exists('settings_error')) {
|
357 |
+
function settings_error($error)
|
358 |
+
{
|
359 |
+
return $error;
|
360 |
+
}
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
*
|
365 |
+
*/
|
366 |
+
if (!function_exists('add_menu_page')) {
|
367 |
+
function add_menu_page()
|
368 |
+
{
|
369 |
+
}
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Get Home Url
|
374 |
+
*
|
375 |
+
* @return path
|
376 |
+
*/
|
377 |
+
if (!function_exists('get_home_url')) {
|
378 |
+
function get_home_url()
|
379 |
+
{
|
380 |
+
return __DIR__;
|
381 |
+
}
|
382 |
+
}
|
383 |
+
|
384 |
+
if (!function_exists('wp_load_translations_early')) {
|
385 |
+
function wp_load_translations_early()
|
386 |
+
{
|
387 |
+
return null;
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Translate string if available
|
393 |
+
*
|
394 |
+
* @return string
|
395 |
+
*/
|
396 |
+
if (!function_exists('__')) {
|
397 |
+
function __($string)
|
398 |
+
{
|
399 |
+
return $string;
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
if (!function_exists('wp_send_json')) {
|
404 |
+
function wp_send_json( $response, $status_code = null ) {
|
405 |
+
//return $response;
|
406 |
+
die(json_encode($response));
|
407 |
+
}
|
408 |
+
}
|
409 |
+
|
410 |
+
if (!function_exists('is_localhost')) {
|
411 |
+
function is_localhost($whitelist = ['127.0.0.1', '::1']) {
|
412 |
+
return in_array($_SERVER['REMOTE_ADDR'], $whitelist);
|
413 |
+
}
|
414 |
+
}
|
415 |
+
|
416 |
+
if (!function_exists('esc_html')) {
|
417 |
+
function esc_html( $text ) {
|
418 |
+
return $text;
|
419 |
+
}
|
420 |
+
}
|
421 |
+
|
422 |
+
if (!function_exists('size_format')) {
|
423 |
+
function size_format( $bytes, $decimals = 0 ) {
|
424 |
+
return $bytes;
|
425 |
+
}
|
426 |
+
}
|
427 |
+
if (!function_exists('wp_mail')) {
|
428 |
+
function wp_mail(){
|
429 |
+
|
430 |
+
}
|
431 |
+
}
|
432 |
+
|
433 |
+
// function current_user_can(){}
|
434 |
+
// function sanitize_key(){}
|
435 |
+
// function plugin_dir_url() {}
|
436 |
+
// function human_time_diff() {}
|
437 |
+
// function size_format(){}
|
438 |
+
// function wp_get_schedules() {}
|
439 |
+
// function wp_send_json() {}
|
440 |
+
// function get_site_url() {}
|
441 |
+
// function get_home_url() {}
|
442 |
+
// function wp_mail() {}
|
443 |
+
// function __(){}
|
444 |
+
// function admin_url(){}
|
445 |
+
// function load_plugin_textdomain() {}
|
446 |
+
// function wp_clear_scheduled_hook() {}
|
447 |
+
// function wp_unschedule_event() {}
|
448 |
+
// function wp_schedule_event() {}
|
449 |
+
// function wp_next_scheduled() {}
|
450 |
+
// function wp_schedule_single_event() {}
|
451 |
+
// function add_settings_section() {}
|
452 |
+
// function register_setting() {}
|
lib/wp-db.php
ADDED
@@ -0,0 +1,3555 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WordPress DB Class
|
4 |
+
*
|
5 |
+
* Original code from {@link http://php.justinvincent.com Justin Vincent (justin@visunet.ie)}
|
6 |
+
*
|
7 |
+
* @package WordPress
|
8 |
+
* @subpackage Database
|
9 |
+
* @since 0.71
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @since 0.71
|
14 |
+
*/
|
15 |
+
define( 'EZSQL_VERSION', 'WP1.25' );
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @since 0.71
|
19 |
+
*/
|
20 |
+
define( 'OBJECT', 'OBJECT' );
|
21 |
+
// phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ConstantNotUpperCase
|
22 |
+
define( 'object', 'OBJECT' ); // Back compat.
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @since 2.5.0
|
26 |
+
*/
|
27 |
+
define( 'OBJECT_K', 'OBJECT_K' );
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @since 0.71
|
31 |
+
*/
|
32 |
+
define( 'ARRAY_A', 'ARRAY_A' );
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @since 0.71
|
36 |
+
*/
|
37 |
+
define( 'ARRAY_N', 'ARRAY_N' );
|
38 |
+
|
39 |
+
/**
|
40 |
+
* WordPress Database Access Abstraction Object
|
41 |
+
*
|
42 |
+
* It is possible to replace this class with your own
|
43 |
+
* by setting the $wpdb global variable in wp-content/db.php
|
44 |
+
* file to your class. The wpdb class will still be included,
|
45 |
+
* so you can extend it or simply use your own.
|
46 |
+
*
|
47 |
+
* @link https://codex.wordpress.org/Function_Reference/wpdb_Class
|
48 |
+
*
|
49 |
+
* @since 0.71
|
50 |
+
*/
|
51 |
+
class wpdb {
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Whether to show SQL/DB errors.
|
55 |
+
*
|
56 |
+
* Default behavior is to show errors if both WP_DEBUG and WP_DEBUG_DISPLAY
|
57 |
+
* evaluated to true.
|
58 |
+
*
|
59 |
+
* @since 0.71
|
60 |
+
* @var bool
|
61 |
+
*/
|
62 |
+
var $show_errors = false;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Whether to suppress errors during the DB bootstrapping.
|
66 |
+
*
|
67 |
+
* @since 2.5.0
|
68 |
+
* @var bool
|
69 |
+
*/
|
70 |
+
var $suppress_errors = false;
|
71 |
+
|
72 |
+
/**
|
73 |
+
* The last error during query.
|
74 |
+
*
|
75 |
+
* @since 2.5.0
|
76 |
+
* @var string
|
77 |
+
*/
|
78 |
+
public $last_error = '';
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Amount of queries made
|
82 |
+
*
|
83 |
+
* @since 1.2.0
|
84 |
+
* @var int
|
85 |
+
*/
|
86 |
+
public $num_queries = 0;
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Count of rows returned by previous query
|
90 |
+
*
|
91 |
+
* @since 0.71
|
92 |
+
* @var int
|
93 |
+
*/
|
94 |
+
public $num_rows = 0;
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Count of affected rows by previous query
|
98 |
+
*
|
99 |
+
* @since 0.71
|
100 |
+
* @var int
|
101 |
+
*/
|
102 |
+
var $rows_affected = 0;
|
103 |
+
|
104 |
+
/**
|
105 |
+
* The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
|
106 |
+
*
|
107 |
+
* @since 0.71
|
108 |
+
* @var int
|
109 |
+
*/
|
110 |
+
public $insert_id = 0;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Last query made
|
114 |
+
*
|
115 |
+
* @since 0.71
|
116 |
+
* @var array
|
117 |
+
*/
|
118 |
+
var $last_query;
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Results of the last query made
|
122 |
+
*
|
123 |
+
* @since 0.71
|
124 |
+
* @var array|null
|
125 |
+
*/
|
126 |
+
var $last_result;
|
127 |
+
|
128 |
+
/**
|
129 |
+
* MySQL result, which is either a resource or boolean.
|
130 |
+
*
|
131 |
+
* @since 0.71
|
132 |
+
* @var mixed
|
133 |
+
*/
|
134 |
+
protected $result;
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Cached column info, for sanity checking data before inserting
|
138 |
+
*
|
139 |
+
* @since 4.2.0
|
140 |
+
* @var array
|
141 |
+
*/
|
142 |
+
protected $col_meta = array();
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Calculated character sets on tables
|
146 |
+
*
|
147 |
+
* @since 4.2.0
|
148 |
+
* @var array
|
149 |
+
*/
|
150 |
+
protected $table_charset = array();
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Whether text fields in the current query need to be sanity checked.
|
154 |
+
*
|
155 |
+
* @since 4.2.0
|
156 |
+
* @var bool
|
157 |
+
*/
|
158 |
+
protected $check_current_query = true;
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Flag to ensure we don't run into recursion problems when checking the collation.
|
162 |
+
*
|
163 |
+
* @since 4.2.0
|
164 |
+
* @see wpdb::check_safe_collation()
|
165 |
+
* @var bool
|
166 |
+
*/
|
167 |
+
private $checking_collation = false;
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Saved info on the table column
|
171 |
+
*
|
172 |
+
* @since 0.71
|
173 |
+
* @var array
|
174 |
+
*/
|
175 |
+
protected $col_info;
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Log of queries that were executed, for debugging purposes.
|
179 |
+
*
|
180 |
+
* @since 1.5.0
|
181 |
+
* @since 2.5.0 The third element in each query log was added to record the calling functions.
|
182 |
+
* @since 5.1.0 The fourth element in each query log was added to record the start time.
|
183 |
+
*
|
184 |
+
* @var array[] {
|
185 |
+
* Array of queries that were executed.
|
186 |
+
*
|
187 |
+
* @type array ...$0 {
|
188 |
+
* Data for each query.
|
189 |
+
*
|
190 |
+
* @type string $0 The query's SQL.
|
191 |
+
* @type float $1 Total time spent on the query, in seconds.
|
192 |
+
* @type string $2 Comma separated list of the calling functions.
|
193 |
+
* @type float $3 Unix timestamp of the time at the start of the query.
|
194 |
+
* }
|
195 |
+
* }
|
196 |
+
*/
|
197 |
+
var $queries;
|
198 |
+
|
199 |
+
/**
|
200 |
+
* The number of times to retry reconnecting before dying.
|
201 |
+
*
|
202 |
+
* @since 3.9.0
|
203 |
+
* @see wpdb::check_connection()
|
204 |
+
* @var int
|
205 |
+
*/
|
206 |
+
protected $reconnect_retries = 5;
|
207 |
+
|
208 |
+
/**
|
209 |
+
* WordPress table prefix
|
210 |
+
*
|
211 |
+
* You can set this to have multiple WordPress installations
|
212 |
+
* in a single database. The second reason is for possible
|
213 |
+
* security precautions.
|
214 |
+
*
|
215 |
+
* @since 2.5.0
|
216 |
+
* @var string
|
217 |
+
*/
|
218 |
+
public $prefix = '';
|
219 |
+
|
220 |
+
/**
|
221 |
+
* WordPress base table prefix.
|
222 |
+
*
|
223 |
+
* @since 3.0.0
|
224 |
+
* @var string
|
225 |
+
*/
|
226 |
+
public $base_prefix;
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Whether the database queries are ready to start executing.
|
230 |
+
*
|
231 |
+
* @since 2.3.2
|
232 |
+
* @var bool
|
233 |
+
*/
|
234 |
+
var $ready = false;
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Blog ID.
|
238 |
+
*
|
239 |
+
* @since 3.0.0
|
240 |
+
* @var int
|
241 |
+
*/
|
242 |
+
public $blogid = 0;
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Site ID.
|
246 |
+
*
|
247 |
+
* @since 3.0.0
|
248 |
+
* @var int
|
249 |
+
*/
|
250 |
+
public $siteid = 0;
|
251 |
+
|
252 |
+
/**
|
253 |
+
* List of WordPress per-blog tables
|
254 |
+
*
|
255 |
+
* @since 2.5.0
|
256 |
+
* @see wpdb::tables()
|
257 |
+
* @var array
|
258 |
+
*/
|
259 |
+
var $tables = array(
|
260 |
+
'posts',
|
261 |
+
'comments',
|
262 |
+
'links',
|
263 |
+
'options',
|
264 |
+
'postmeta',
|
265 |
+
'terms',
|
266 |
+
'term_taxonomy',
|
267 |
+
'term_relationships',
|
268 |
+
'termmeta',
|
269 |
+
'commentmeta',
|
270 |
+
);
|
271 |
+
|
272 |
+
/**
|
273 |
+
* List of deprecated WordPress tables
|
274 |
+
*
|
275 |
+
* categories, post2cat, and link2cat were deprecated in 2.3.0, db version 5539
|
276 |
+
*
|
277 |
+
* @since 2.9.0
|
278 |
+
* @see wpdb::tables()
|
279 |
+
* @var array
|
280 |
+
*/
|
281 |
+
var $old_tables = array( 'categories', 'post2cat', 'link2cat' );
|
282 |
+
|
283 |
+
/**
|
284 |
+
* List of WordPress global tables
|
285 |
+
*
|
286 |
+
* @since 3.0.0
|
287 |
+
* @see wpdb::tables()
|
288 |
+
* @var array
|
289 |
+
*/
|
290 |
+
var $global_tables = array( 'users', 'usermeta' );
|
291 |
+
|
292 |
+
/**
|
293 |
+
* List of Multisite global tables
|
294 |
+
*
|
295 |
+
* @since 3.0.0
|
296 |
+
* @see wpdb::tables()
|
297 |
+
* @var array
|
298 |
+
*/
|
299 |
+
var $ms_global_tables = array(
|
300 |
+
'blogs',
|
301 |
+
'blogmeta',
|
302 |
+
'signups',
|
303 |
+
'site',
|
304 |
+
'sitemeta',
|
305 |
+
'sitecategories',
|
306 |
+
'registration_log',
|
307 |
+
'blog_versions',
|
308 |
+
);
|
309 |
+
|
310 |
+
/**
|
311 |
+
* WordPress Comments table
|
312 |
+
*
|
313 |
+
* @since 1.5.0
|
314 |
+
* @var string
|
315 |
+
*/
|
316 |
+
public $comments;
|
317 |
+
|
318 |
+
/**
|
319 |
+
* WordPress Comment Metadata table
|
320 |
+
*
|
321 |
+
* @since 2.9.0
|
322 |
+
* @var string
|
323 |
+
*/
|
324 |
+
public $commentmeta;
|
325 |
+
|
326 |
+
/**
|
327 |
+
* WordPress Links table
|
328 |
+
*
|
329 |
+
* @since 1.5.0
|
330 |
+
* @var string
|
331 |
+
*/
|
332 |
+
public $links;
|
333 |
+
|
334 |
+
/**
|
335 |
+
* WordPress Options table
|
336 |
+
*
|
337 |
+
* @since 1.5.0
|
338 |
+
* @var string
|
339 |
+
*/
|
340 |
+
public $options;
|
341 |
+
|
342 |
+
/**
|
343 |
+
* WordPress Post Metadata table
|
344 |
+
*
|
345 |
+
* @since 1.5.0
|
346 |
+
* @var string
|
347 |
+
*/
|
348 |
+
public $postmeta;
|
349 |
+
|
350 |
+
/**
|
351 |
+
* WordPress Posts table
|
352 |
+
*
|
353 |
+
* @since 1.5.0
|
354 |
+
* @var string
|
355 |
+
*/
|
356 |
+
public $posts;
|
357 |
+
|
358 |
+
/**
|
359 |
+
* WordPress Terms table
|
360 |
+
*
|
361 |
+
* @since 2.3.0
|
362 |
+
* @var string
|
363 |
+
*/
|
364 |
+
public $terms;
|
365 |
+
|
366 |
+
/**
|
367 |
+
* WordPress Term Relationships table
|
368 |
+
*
|
369 |
+
* @since 2.3.0
|
370 |
+
* @var string
|
371 |
+
*/
|
372 |
+
public $term_relationships;
|
373 |
+
|
374 |
+
/**
|
375 |
+
* WordPress Term Taxonomy table
|
376 |
+
*
|
377 |
+
* @since 2.3.0
|
378 |
+
* @var string
|
379 |
+
*/
|
380 |
+
public $term_taxonomy;
|
381 |
+
|
382 |
+
/**
|
383 |
+
* WordPress Term Meta table.
|
384 |
+
*
|
385 |
+
* @since 4.4.0
|
386 |
+
* @var string
|
387 |
+
*/
|
388 |
+
public $termmeta;
|
389 |
+
|
390 |
+
//
|
391 |
+
// Global and Multisite tables
|
392 |
+
//
|
393 |
+
|
394 |
+
/**
|
395 |
+
* WordPress User Metadata table
|
396 |
+
*
|
397 |
+
* @since 2.3.0
|
398 |
+
* @var string
|
399 |
+
*/
|
400 |
+
public $usermeta;
|
401 |
+
|
402 |
+
/**
|
403 |
+
* WordPress Users table
|
404 |
+
*
|
405 |
+
* @since 1.5.0
|
406 |
+
* @var string
|
407 |
+
*/
|
408 |
+
public $users;
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Multisite Blogs table
|
412 |
+
*
|
413 |
+
* @since 3.0.0
|
414 |
+
* @var string
|
415 |
+
*/
|
416 |
+
public $blogs;
|
417 |
+
|
418 |
+
/**
|
419 |
+
* Multisite Blog Metadata table
|
420 |
+
*
|
421 |
+
* @since 5.1.0
|
422 |
+
* @var string
|
423 |
+
*/
|
424 |
+
public $blogmeta;
|
425 |
+
|
426 |
+
/**
|
427 |
+
* Multisite Blog Versions table
|
428 |
+
*
|
429 |
+
* @since 3.0.0
|
430 |
+
* @var string
|
431 |
+
*/
|
432 |
+
public $blog_versions;
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Multisite Registration Log table
|
436 |
+
*
|
437 |
+
* @since 3.0.0
|
438 |
+
* @var string
|
439 |
+
*/
|
440 |
+
public $registration_log;
|
441 |
+
|
442 |
+
/**
|
443 |
+
* Multisite Signups table
|
444 |
+
*
|
445 |
+
* @since 3.0.0
|
446 |
+
* @var string
|
447 |
+
*/
|
448 |
+
public $signups;
|
449 |
+
|
450 |
+
/**
|
451 |
+
* Multisite Sites table
|
452 |
+
*
|
453 |
+
* @since 3.0.0
|
454 |
+
* @var string
|
455 |
+
*/
|
456 |
+
public $site;
|
457 |
+
|
458 |
+
/**
|
459 |
+
* Multisite Sitewide Terms table
|
460 |
+
*
|
461 |
+
* @since 3.0.0
|
462 |
+
* @var string
|
463 |
+
*/
|
464 |
+
public $sitecategories;
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Multisite Site Metadata table
|
468 |
+
*
|
469 |
+
* @since 3.0.0
|
470 |
+
* @var string
|
471 |
+
*/
|
472 |
+
public $sitemeta;
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Format specifiers for DB columns. Columns not listed here default to %s. Initialized during WP load.
|
476 |
+
*
|
477 |
+
* Keys are column names, values are format types: 'ID' => '%d'
|
478 |
+
*
|
479 |
+
* @since 2.8.0
|
480 |
+
* @see wpdb::prepare()
|
481 |
+
* @see wpdb::insert()
|
482 |
+
* @see wpdb::update()
|
483 |
+
* @see wpdb::delete()
|
484 |
+
* @see wp_set_wpdb_vars()
|
485 |
+
* @var array
|
486 |
+
*/
|
487 |
+
public $field_types = array();
|
488 |
+
|
489 |
+
/**
|
490 |
+
* Database table columns charset
|
491 |
+
*
|
492 |
+
* @since 2.2.0
|
493 |
+
* @var string
|
494 |
+
*/
|
495 |
+
public $charset;
|
496 |
+
|
497 |
+
/**
|
498 |
+
* Database table columns collate
|
499 |
+
*
|
500 |
+
* @since 2.2.0
|
501 |
+
* @var string
|
502 |
+
*/
|
503 |
+
public $collate;
|
504 |
+
|
505 |
+
/**
|
506 |
+
* Database Username
|
507 |
+
*
|
508 |
+
* @since 2.9.0
|
509 |
+
* @var string
|
510 |
+
*/
|
511 |
+
protected $dbuser;
|
512 |
+
|
513 |
+
/**
|
514 |
+
* Database Password
|
515 |
+
*
|
516 |
+
* @since 3.1.0
|
517 |
+
* @var string
|
518 |
+
*/
|
519 |
+
protected $dbpassword;
|
520 |
+
|
521 |
+
/**
|
522 |
+
* Database Name
|
523 |
+
*
|
524 |
+
* @since 3.1.0
|
525 |
+
* @var string
|
526 |
+
*/
|
527 |
+
protected $dbname;
|
528 |
+
|
529 |
+
/**
|
530 |
+
* Database Host
|
531 |
+
*
|
532 |
+
* @since 3.1.0
|
533 |
+
* @var string
|
534 |
+
*/
|
535 |
+
protected $dbhost;
|
536 |
+
|
537 |
+
/**
|
538 |
+
* Database Handle
|
539 |
+
*
|
540 |
+
* @since 0.71
|
541 |
+
* @var string
|
542 |
+
*/
|
543 |
+
protected $dbh;
|
544 |
+
|
545 |
+
/**
|
546 |
+
* A textual description of the last query/get_row/get_var call
|
547 |
+
*
|
548 |
+
* @since 3.0.0
|
549 |
+
* @var string
|
550 |
+
*/
|
551 |
+
public $func_call;
|
552 |
+
|
553 |
+
/**
|
554 |
+
* Whether MySQL is used as the database engine.
|
555 |
+
*
|
556 |
+
* Set in WPDB::db_connect() to true, by default. This is used when checking
|
557 |
+
* against the required MySQL version for WordPress. Normally, a replacement
|
558 |
+
* database drop-in (db.php) will skip these checks, but setting this to true
|
559 |
+
* will force the checks to occur.
|
560 |
+
*
|
561 |
+
* @since 3.3.0
|
562 |
+
* @var bool
|
563 |
+
*/
|
564 |
+
public $is_mysql = null;
|
565 |
+
|
566 |
+
/**
|
567 |
+
* A list of incompatible SQL modes.
|
568 |
+
*
|
569 |
+
* @since 3.9.0
|
570 |
+
* @var array
|
571 |
+
*/
|
572 |
+
protected $incompatible_modes = array(
|
573 |
+
'NO_ZERO_DATE',
|
574 |
+
'ONLY_FULL_GROUP_BY',
|
575 |
+
'STRICT_TRANS_TABLES',
|
576 |
+
'STRICT_ALL_TABLES',
|
577 |
+
'TRADITIONAL',
|
578 |
+
);
|
579 |
+
|
580 |
+
/**
|
581 |
+
* Whether to use mysqli over mysql.
|
582 |
+
*
|
583 |
+
* @since 3.9.0
|
584 |
+
* @var bool
|
585 |
+
*/
|
586 |
+
private $use_mysqli = false;
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Whether we've managed to successfully connect at some point
|
590 |
+
*
|
591 |
+
* @since 3.9.0
|
592 |
+
* @var bool
|
593 |
+
*/
|
594 |
+
private $has_connected = false;
|
595 |
+
|
596 |
+
/**
|
597 |
+
* Connects to the database server and selects a database
|
598 |
+
*
|
599 |
+
* PHP5 style constructor for compatibility with PHP5. Does
|
600 |
+
* the actual setting up of the class properties and connection
|
601 |
+
* to the database.
|
602 |
+
*
|
603 |
+
* @link https://core.trac.wordpress.org/ticket/3354
|
604 |
+
* @since 2.0.8
|
605 |
+
*
|
606 |
+
* @global string $wp_version
|
607 |
+
*
|
608 |
+
* @param string $dbuser MySQL database user
|
609 |
+
* @param string $dbpassword MySQL database password
|
610 |
+
* @param string $dbname MySQL database name
|
611 |
+
* @param string $dbhost MySQL database host
|
612 |
+
*/
|
613 |
+
public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
|
614 |
+
register_shutdown_function( array( $this, '__destruct' ) );
|
615 |
+
|
616 |
+
if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
|
617 |
+
$this->show_errors();
|
618 |
+
}
|
619 |
+
|
620 |
+
// Use ext/mysqli if it exists unless WP_USE_EXT_MYSQL is defined as true
|
621 |
+
if ( function_exists( 'mysqli_connect' ) ) {
|
622 |
+
$this->use_mysqli = true;
|
623 |
+
|
624 |
+
if ( defined( 'WP_USE_EXT_MYSQL' ) ) {
|
625 |
+
$this->use_mysqli = ! WP_USE_EXT_MYSQL;
|
626 |
+
}
|
627 |
+
}
|
628 |
+
|
629 |
+
$this->dbuser = $dbuser;
|
630 |
+
$this->dbpassword = $dbpassword;
|
631 |
+
$this->dbname = $dbname;
|
632 |
+
$this->dbhost = $dbhost;
|
633 |
+
|
634 |
+
// wp-config.php creation will manually connect when ready.
|
635 |
+
if ( defined( 'WP_SETUP_CONFIG' ) ) {
|
636 |
+
return;
|
637 |
+
}
|
638 |
+
|
639 |
+
$this->db_connect();
|
640 |
+
}
|
641 |
+
|
642 |
+
/**
|
643 |
+
* PHP5 style destructor and will run when database object is destroyed.
|
644 |
+
*
|
645 |
+
* @see wpdb::__construct()
|
646 |
+
* @since 2.0.8
|
647 |
+
* @return true
|
648 |
+
*/
|
649 |
+
public function __destruct() {
|
650 |
+
return true;
|
651 |
+
}
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Makes private properties readable for backward compatibility.
|
655 |
+
*
|
656 |
+
* @since 3.5.0
|
657 |
+
*
|
658 |
+
* @param string $name The private member to get, and optionally process
|
659 |
+
* @return mixed The private member
|
660 |
+
*/
|
661 |
+
public function __get( $name ) {
|
662 |
+
if ( 'col_info' === $name ) {
|
663 |
+
$this->load_col_info();
|
664 |
+
}
|
665 |
+
|
666 |
+
return $this->$name;
|
667 |
+
}
|
668 |
+
|
669 |
+
/**
|
670 |
+
* Makes private properties settable for backward compatibility.
|
671 |
+
*
|
672 |
+
* @since 3.5.0
|
673 |
+
*
|
674 |
+
* @param string $name The private member to set
|
675 |
+
* @param mixed $value The value to set
|
676 |
+
*/
|
677 |
+
public function __set( $name, $value ) {
|
678 |
+
$protected_members = array(
|
679 |
+
'col_meta',
|
680 |
+
'table_charset',
|
681 |
+
'check_current_query',
|
682 |
+
);
|
683 |
+
if ( in_array( $name, $protected_members, true ) ) {
|
684 |
+
return;
|
685 |
+
}
|
686 |
+
$this->$name = $value;
|
687 |
+
}
|
688 |
+
|
689 |
+
/**
|
690 |
+
* Makes private properties check-able for backward compatibility.
|
691 |
+
*
|
692 |
+
* @since 3.5.0
|
693 |
+
*
|
694 |
+
* @param string $name The private member to check
|
695 |
+
*
|
696 |
+
* @return bool If the member is set or not
|
697 |
+
*/
|
698 |
+
public function __isset( $name ) {
|
699 |
+
return isset( $this->$name );
|
700 |
+
}
|
701 |
+
|
702 |
+
/**
|
703 |
+
* Makes private properties un-settable for backward compatibility.
|
704 |
+
*
|
705 |
+
* @since 3.5.0
|
706 |
+
*
|
707 |
+
* @param string $name The private member to unset
|
708 |
+
*/
|
709 |
+
public function __unset( $name ) {
|
710 |
+
unset( $this->$name );
|
711 |
+
}
|
712 |
+
|
713 |
+
/**
|
714 |
+
* Set $this->charset and $this->collate
|
715 |
+
*
|
716 |
+
* @since 3.1.0
|
717 |
+
*/
|
718 |
+
public function init_charset() {
|
719 |
+
$charset = '';
|
720 |
+
$collate = '';
|
721 |
+
|
722 |
+
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
|
723 |
+
$charset = 'utf8';
|
724 |
+
if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
|
725 |
+
$collate = DB_COLLATE;
|
726 |
+
} else {
|
727 |
+
$collate = 'utf8_general_ci';
|
728 |
+
}
|
729 |
+
} elseif ( defined( 'DB_COLLATE' ) ) {
|
730 |
+
$collate = DB_COLLATE;
|
731 |
+
}
|
732 |
+
|
733 |
+
if ( defined( 'DB_CHARSET' ) ) {
|
734 |
+
$charset = DB_CHARSET;
|
735 |
+
}
|
736 |
+
|
737 |
+
$charset_collate = $this->determine_charset( $charset, $collate );
|
738 |
+
|
739 |
+
$this->charset = $charset_collate['charset'];
|
740 |
+
$this->collate = $charset_collate['collate'];
|
741 |
+
}
|
742 |
+
|
743 |
+
/**
|
744 |
+
* Determines the best charset and collation to use given a charset and collation.
|
745 |
+
*
|
746 |
+
* For example, when able, utf8mb4 should be used instead of utf8.
|
747 |
+
*
|
748 |
+
* @since 4.6.0
|
749 |
+
*
|
750 |
+
* @param string $charset The character set to check.
|
751 |
+
* @param string $collate The collation to check.
|
752 |
+
* @return array The most appropriate character set and collation to use.
|
753 |
+
*/
|
754 |
+
public function determine_charset( $charset, $collate ) {
|
755 |
+
if ( ( $this->use_mysqli && ! ( $this->dbh instanceof mysqli ) ) || empty( $this->dbh ) ) {
|
756 |
+
return compact( 'charset', 'collate' );
|
757 |
+
}
|
758 |
+
|
759 |
+
if ( 'utf8' === $charset && $this->has_cap( 'utf8mb4' ) ) {
|
760 |
+
$charset = 'utf8mb4';
|
761 |
+
}
|
762 |
+
|
763 |
+
if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
|
764 |
+
$charset = 'utf8';
|
765 |
+
$collate = str_replace( 'utf8mb4_', 'utf8_', $collate );
|
766 |
+
}
|
767 |
+
|
768 |
+
if ( 'utf8mb4' === $charset ) {
|
769 |
+
// _general_ is outdated, so we can upgrade it to _unicode_, instead.
|
770 |
+
if ( ! $collate || 'utf8_general_ci' === $collate ) {
|
771 |
+
$collate = 'utf8mb4_unicode_ci';
|
772 |
+
} else {
|
773 |
+
$collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
|
774 |
+
}
|
775 |
+
}
|
776 |
+
|
777 |
+
// _unicode_520_ is a better collation, we should use that when it's available.
|
778 |
+
if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
|
779 |
+
$collate = 'utf8mb4_unicode_520_ci';
|
780 |
+
}
|
781 |
+
|
782 |
+
return compact( 'charset', 'collate' );
|
783 |
+
}
|
784 |
+
|
785 |
+
/**
|
786 |
+
* Sets the connection's character set.
|
787 |
+
*
|
788 |
+
* @since 3.1.0
|
789 |
+
*
|
790 |
+
* @param resource $dbh The resource given by mysql_connect
|
791 |
+
* @param string $charset Optional. The character set. Default null.
|
792 |
+
* @param string $collate Optional. The collation. Default null.
|
793 |
+
*/
|
794 |
+
public function set_charset( $dbh, $charset = null, $collate = null ) {
|
795 |
+
if ( ! isset( $charset ) ) {
|
796 |
+
$charset = $this->charset;
|
797 |
+
}
|
798 |
+
if ( ! isset( $collate ) ) {
|
799 |
+
$collate = $this->collate;
|
800 |
+
}
|
801 |
+
if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
|
802 |
+
$set_charset_succeeded = true;
|
803 |
+
|
804 |
+
if ( $this->use_mysqli ) {
|
805 |
+
if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
|
806 |
+
$set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
|
807 |
+
}
|
808 |
+
|
809 |
+
if ( $set_charset_succeeded ) {
|
810 |
+
$query = $this->prepare( 'SET NAMES %s', $charset );
|
811 |
+
if ( ! empty( $collate ) ) {
|
812 |
+
$query .= $this->prepare( ' COLLATE %s', $collate );
|
813 |
+
}
|
814 |
+
mysqli_query( $dbh, $query );
|
815 |
+
}
|
816 |
+
} else {
|
817 |
+
if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
|
818 |
+
$set_charset_succeeded = mysql_set_charset( $charset, $dbh );
|
819 |
+
}
|
820 |
+
if ( $set_charset_succeeded ) {
|
821 |
+
$query = $this->prepare( 'SET NAMES %s', $charset );
|
822 |
+
if ( ! empty( $collate ) ) {
|
823 |
+
$query .= $this->prepare( ' COLLATE %s', $collate );
|
824 |
+
}
|
825 |
+
mysql_query( $query, $dbh );
|
826 |
+
}
|
827 |
+
}
|
828 |
+
}
|
829 |
+
}
|
830 |
+
|
831 |
+
/**
|
832 |
+
* Change the current SQL mode, and ensure its WordPress compatibility.
|
833 |
+
*
|
834 |
+
* If no modes are passed, it will ensure the current MySQL server
|
835 |
+
* modes are compatible.
|
836 |
+
*
|
837 |
+
* @since 3.9.0
|
838 |
+
*
|
839 |
+
* @param array $modes Optional. A list of SQL modes to set.
|
840 |
+
*/
|
841 |
+
public function set_sql_mode( $modes = array() ) {
|
842 |
+
if ( empty( $modes ) ) {
|
843 |
+
if ( $this->use_mysqli ) {
|
844 |
+
$res = mysqli_query( $this->dbh, 'SELECT @@SESSION.sql_mode' );
|
845 |
+
} else {
|
846 |
+
$res = mysql_query( 'SELECT @@SESSION.sql_mode', $this->dbh );
|
847 |
+
}
|
848 |
+
|
849 |
+
if ( empty( $res ) ) {
|
850 |
+
return;
|
851 |
+
}
|
852 |
+
|
853 |
+
if ( $this->use_mysqli ) {
|
854 |
+
$modes_array = mysqli_fetch_array( $res );
|
855 |
+
if ( empty( $modes_array[0] ) ) {
|
856 |
+
return;
|
857 |
+
}
|
858 |
+
$modes_str = $modes_array[0];
|
859 |
+
} else {
|
860 |
+
$modes_str = mysql_result( $res, 0 );
|
861 |
+
}
|
862 |
+
|
863 |
+
if ( empty( $modes_str ) ) {
|
864 |
+
return;
|
865 |
+
}
|
866 |
+
|
867 |
+
$modes = explode( ',', $modes_str );
|
868 |
+
}
|
869 |
+
|
870 |
+
$modes = array_change_key_case( $modes, CASE_UPPER );
|
871 |
+
|
872 |
+
/**
|
873 |
+
* Filters the list of incompatible SQL modes to exclude.
|
874 |
+
*
|
875 |
+
* @since 3.9.0
|
876 |
+
*
|
877 |
+
* @param array $incompatible_modes An array of incompatible modes.
|
878 |
+
*/
|
879 |
+
$incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes );
|
880 |
+
|
881 |
+
foreach ( $modes as $i => $mode ) {
|
882 |
+
if ( in_array( $mode, $incompatible_modes ) ) {
|
883 |
+
unset( $modes[ $i ] );
|
884 |
+
}
|
885 |
+
}
|
886 |
+
|
887 |
+
$modes_str = implode( ',', $modes );
|
888 |
+
|
889 |
+
if ( $this->use_mysqli ) {
|
890 |
+
mysqli_query( $this->dbh, "SET SESSION sql_mode='$modes_str'" );
|
891 |
+
} else {
|
892 |
+
mysql_query( "SET SESSION sql_mode='$modes_str'", $this->dbh );
|
893 |
+
}
|
894 |
+
}
|
895 |
+
|
896 |
+
/**
|
897 |
+
* Sets the table prefix for the WordPress tables.
|
898 |
+
*
|
899 |
+
* @since 2.5.0
|
900 |
+
*
|
901 |
+
* @param string $prefix Alphanumeric name for the new prefix.
|
902 |
+
* @param bool $set_table_names Optional. Whether the table names, e.g. wpdb::$posts, should be updated or not.
|
903 |
+
* @return string|WP_Error Old prefix or WP_Error on error
|
904 |
+
*/
|
905 |
+
public function set_prefix( $prefix, $set_table_names = true ) {
|
906 |
+
|
907 |
+
if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) {
|
908 |
+
return new WP_Error( 'invalid_db_prefix', 'Invalid database prefix' );
|
909 |
+
}
|
910 |
+
|
911 |
+
$old_prefix = is_multisite() ? '' : $prefix;
|
912 |
+
|
913 |
+
if ( isset( $this->base_prefix ) ) {
|
914 |
+
$old_prefix = $this->base_prefix;
|
915 |
+
}
|
916 |
+
|
917 |
+
$this->base_prefix = $prefix;
|
918 |
+
|
919 |
+
if ( $set_table_names ) {
|
920 |
+
foreach ( $this->tables( 'global' ) as $table => $prefixed_table ) {
|
921 |
+
$this->$table = $prefixed_table;
|
922 |
+
}
|
923 |
+
|
924 |
+
if ( is_multisite() && empty( $this->blogid ) ) {
|
925 |
+
return $old_prefix;
|
926 |
+
}
|
927 |
+
|
928 |
+
$this->prefix = $this->get_blog_prefix();
|
929 |
+
|
930 |
+
foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
|
931 |
+
$this->$table = $prefixed_table;
|
932 |
+
}
|
933 |
+
|
934 |
+
foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
|
935 |
+
$this->$table = $prefixed_table;
|
936 |
+
}
|
937 |
+
}
|
938 |
+
return $old_prefix;
|
939 |
+
}
|
940 |
+
|
941 |
+
/**
|
942 |
+
* Sets blog id.
|
943 |
+
*
|
944 |
+
* @since 3.0.0
|
945 |
+
*
|
946 |
+
* @param int $blog_id
|
947 |
+
* @param int $network_id Optional.
|
948 |
+
* @return int previous blog id
|
949 |
+
*/
|
950 |
+
public function set_blog_id( $blog_id, $network_id = 0 ) {
|
951 |
+
if ( ! empty( $network_id ) ) {
|
952 |
+
$this->siteid = $network_id;
|
953 |
+
}
|
954 |
+
|
955 |
+
$old_blog_id = $this->blogid;
|
956 |
+
$this->blogid = $blog_id;
|
957 |
+
|
958 |
+
$this->prefix = $this->get_blog_prefix();
|
959 |
+
|
960 |
+
foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
|
961 |
+
$this->$table = $prefixed_table;
|
962 |
+
}
|
963 |
+
|
964 |
+
foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
|
965 |
+
$this->$table = $prefixed_table;
|
966 |
+
}
|
967 |
+
|
968 |
+
return $old_blog_id;
|
969 |
+
}
|
970 |
+
|
971 |
+
/**
|
972 |
+
* Gets blog prefix.
|
973 |
+
*
|
974 |
+
* @since 3.0.0
|
975 |
+
* @param int $blog_id Optional.
|
976 |
+
* @return string Blog prefix.
|
977 |
+
*/
|
978 |
+
public function get_blog_prefix( $blog_id = null ) {
|
979 |
+
if ( is_multisite() ) {
|
980 |
+
if ( null === $blog_id ) {
|
981 |
+
$blog_id = $this->blogid;
|
982 |
+
}
|
983 |
+
$blog_id = (int) $blog_id;
|
984 |
+
if ( defined( 'MULTISITE' ) && ( 0 == $blog_id || 1 == $blog_id ) ) {
|
985 |
+
return $this->base_prefix;
|
986 |
+
} else {
|
987 |
+
return $this->base_prefix . $blog_id . '_';
|
988 |
+
}
|
989 |
+
} else {
|
990 |
+
return $this->base_prefix;
|
991 |
+
}
|
992 |
+
}
|
993 |
+
|
994 |
+
/**
|
995 |
+
* Returns an array of WordPress tables.
|
996 |
+
*
|
997 |
+
* Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to
|
998 |
+
* override the WordPress users and usermeta tables that would otherwise
|
999 |
+
* be determined by the prefix.
|
1000 |
+
*
|
1001 |
+
* The scope argument can take one of the following:
|
1002 |
+
*
|
1003 |
+
* 'all' - returns 'all' and 'global' tables. No old tables are returned.
|
1004 |
+
* 'blog' - returns the blog-level tables for the queried blog.
|
1005 |
+
* 'global' - returns the global tables for the installation, returning multisite tables only if running multisite.
|
1006 |
+
* 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
|
1007 |
+
* 'old' - returns tables which are deprecated.
|
1008 |
+
*
|
1009 |
+
* @since 3.0.0
|
1010 |
+
* @uses wpdb::$tables
|
1011 |
+
* @uses wpdb::$old_tables
|
1012 |
+
* @uses wpdb::$global_tables
|
1013 |
+
* @uses wpdb::$ms_global_tables
|
1014 |
+
*
|
1015 |
+
* @param string $scope Optional. Can be all, global, ms_global, blog, or old tables. Defaults to all.
|
1016 |
+
* @param bool $prefix Optional. Whether to include table prefixes. Default true. If blog
|
1017 |
+
* prefix is requested, then the custom users and usermeta tables will be mapped.
|
1018 |
+
* @param int $blog_id Optional. The blog_id to prefix. Defaults to wpdb::$blogid. Used only when prefix is requested.
|
1019 |
+
* @return array Table names. When a prefix is requested, the key is the unprefixed table name.
|
1020 |
+
*/
|
1021 |
+
public function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
|
1022 |
+
switch ( $scope ) {
|
1023 |
+
case 'all':
|
1024 |
+
$tables = array_merge( $this->global_tables, $this->tables );
|
1025 |
+
if ( is_multisite() ) {
|
1026 |
+
$tables = array_merge( $tables, $this->ms_global_tables );
|
1027 |
+
}
|
1028 |
+
break;
|
1029 |
+
case 'blog':
|
1030 |
+
$tables = $this->tables;
|
1031 |
+
break;
|
1032 |
+
case 'global':
|
1033 |
+
$tables = $this->global_tables;
|
1034 |
+
if ( is_multisite() ) {
|
1035 |
+
$tables = array_merge( $tables, $this->ms_global_tables );
|
1036 |
+
}
|
1037 |
+
break;
|
1038 |
+
case 'ms_global':
|
1039 |
+
$tables = $this->ms_global_tables;
|
1040 |
+
break;
|
1041 |
+
case 'old':
|
1042 |
+
$tables = $this->old_tables;
|
1043 |
+
break;
|
1044 |
+
default:
|
1045 |
+
return array();
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
if ( $prefix ) {
|
1049 |
+
if ( ! $blog_id ) {
|
1050 |
+
$blog_id = $this->blogid;
|
1051 |
+
}
|
1052 |
+
$blog_prefix = $this->get_blog_prefix( $blog_id );
|
1053 |
+
$base_prefix = $this->base_prefix;
|
1054 |
+
$global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
|
1055 |
+
foreach ( $tables as $k => $table ) {
|
1056 |
+
if ( in_array( $table, $global_tables ) ) {
|
1057 |
+
$tables[ $table ] = $base_prefix . $table;
|
1058 |
+
} else {
|
1059 |
+
$tables[ $table ] = $blog_prefix . $table;
|
1060 |
+
}
|
1061 |
+
unset( $tables[ $k ] );
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) ) {
|
1065 |
+
$tables['users'] = CUSTOM_USER_TABLE;
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) ) {
|
1069 |
+
$tables['usermeta'] = CUSTOM_USER_META_TABLE;
|
1070 |
+
}
|
1071 |
+
}
|
1072 |
+
|
1073 |
+
return $tables;
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
/**
|
1077 |
+
* Selects a database using the current database connection.
|
1078 |
+
*
|
1079 |
+
* The database name will be changed based on the current database
|
1080 |
+
* connection. On failure, the execution will bail and display an DB error.
|
1081 |
+
*
|
1082 |
+
* @since 0.71
|
1083 |
+
*
|
1084 |
+
* @param string $db MySQL database name
|
1085 |
+
* @param resource|null $dbh Optional link identifier.
|
1086 |
+
*/
|
1087 |
+
public function select( $db, $dbh = null ) {
|
1088 |
+
if ( is_null( $dbh ) ) {
|
1089 |
+
$dbh = $this->dbh;
|
1090 |
+
}
|
1091 |
+
|
1092 |
+
if ( $this->use_mysqli ) {
|
1093 |
+
$success = mysqli_select_db( $dbh, $db );
|
1094 |
+
} else {
|
1095 |
+
$success = mysql_select_db( $db, $dbh );
|
1096 |
+
}
|
1097 |
+
if ( ! $success ) {
|
1098 |
+
$this->ready = false;
|
1099 |
+
if ( ! did_action( 'template_redirect' ) ) {
|
1100 |
+
wp_load_translations_early();
|
1101 |
+
|
1102 |
+
$message = '<h1>' . __( 'Can’t select database' ) . "</h1>\n";
|
1103 |
+
|
1104 |
+
$message .= '<p>' . sprintf(
|
1105 |
+
/* translators: %s: database name */
|
1106 |
+
__( 'We were able to connect to the database server (which means your username and password is okay) but not able to select the %s database.' ),
|
1107 |
+
'<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
|
1108 |
+
) . "</p>\n";
|
1109 |
+
|
1110 |
+
$message .= "<ul>\n";
|
1111 |
+
$message .= '<li>' . __( 'Are you sure it exists?' ) . "</li>\n";
|
1112 |
+
|
1113 |
+
$message .= '<li>' . sprintf(
|
1114 |
+
/* translators: 1: database user, 2: database name */
|
1115 |
+
__( 'Does the user %1$s have permission to use the %2$s database?' ),
|
1116 |
+
'<code>' . htmlspecialchars( $this->dbuser, ENT_QUOTES ) . '</code>',
|
1117 |
+
'<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
|
1118 |
+
) . "</li>\n";
|
1119 |
+
|
1120 |
+
$message .= '<li>' . sprintf(
|
1121 |
+
/* translators: %s: database name */
|
1122 |
+
__( 'On some systems the name of your database is prefixed with your username, so it would be like <code>username_%1$s</code>. Could that be the problem?' ),
|
1123 |
+
htmlspecialchars( $db, ENT_QUOTES )
|
1124 |
+
) . "</li>\n";
|
1125 |
+
|
1126 |
+
$message .= "</ul>\n";
|
1127 |
+
|
1128 |
+
$message .= '<p>' . sprintf(
|
1129 |
+
/* translators: %s: support forums URL */
|
1130 |
+
__( 'If you don’t know how to set up a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href="%s">WordPress Support Forums</a>.' ),
|
1131 |
+
__( 'https://wordpress.org/support/forums/' )
|
1132 |
+
) . "</p>\n";
|
1133 |
+
|
1134 |
+
$this->bail( $message, 'db_select_fail' );
|
1135 |
+
}
|
1136 |
+
}
|
1137 |
+
}
|
1138 |
+
|
1139 |
+
/**
|
1140 |
+
* Do not use, deprecated.
|
1141 |
+
*
|
1142 |
+
* Use esc_sql() or wpdb::prepare() instead.
|
1143 |
+
*
|
1144 |
+
* @since 2.8.0
|
1145 |
+
* @deprecated 3.6.0 Use wpdb::prepare()
|
1146 |
+
* @see wpdb::prepare
|
1147 |
+
* @see esc_sql()
|
1148 |
+
*
|
1149 |
+
* @param string $string
|
1150 |
+
* @return string
|
1151 |
+
*/
|
1152 |
+
function _weak_escape( $string ) {
|
1153 |
+
if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) {
|
1154 |
+
_deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
|
1155 |
+
}
|
1156 |
+
return addslashes( $string );
|
1157 |
+
}
|
1158 |
+
|
1159 |
+
/**
|
1160 |
+
* Real escape, using mysqli_real_escape_string() or mysql_real_escape_string()
|
1161 |
+
*
|
1162 |
+
* @see mysqli_real_escape_string()
|
1163 |
+
* @see mysql_real_escape_string()
|
1164 |
+
* @since 2.8.0
|
1165 |
+
*
|
1166 |
+
* @param string $string to escape
|
1167 |
+
* @return string escaped
|
1168 |
+
*/
|
1169 |
+
function _real_escape( $string ) {
|
1170 |
+
if ( $this->dbh ) {
|
1171 |
+
if ( $this->use_mysqli ) {
|
1172 |
+
$escaped = mysqli_real_escape_string( $this->dbh, $string );
|
1173 |
+
} else {
|
1174 |
+
$escaped = mysql_real_escape_string( $string, $this->dbh );
|
1175 |
+
}
|
1176 |
+
} else {
|
1177 |
+
$class = get_class( $this );
|
1178 |
+
if ( function_exists( '__' ) ) {
|
1179 |
+
/* translators: %s: database access abstraction class, usually wpdb or a class extending wpdb */
|
1180 |
+
_doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' );
|
1181 |
+
} else {
|
1182 |
+
_doing_it_wrong( $class, sprintf( '%s must set a database connection for use with escaping.', $class ), '3.6.0' );
|
1183 |
+
}
|
1184 |
+
$escaped = addslashes( $string );
|
1185 |
+
}
|
1186 |
+
|
1187 |
+
return $this->add_placeholder_escape( $escaped );
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
/**
|
1191 |
+
* Escape data. Works on arrays.
|
1192 |
+
*
|
1193 |
+
* @uses wpdb::_real_escape()
|
1194 |
+
* @since 2.8.0
|
1195 |
+
*
|
1196 |
+
* @param string|array $data
|
1197 |
+
* @return string|array escaped
|
1198 |
+
*/
|
1199 |
+
public function _escape( $data ) {
|
1200 |
+
if ( is_array( $data ) ) {
|
1201 |
+
foreach ( $data as $k => $v ) {
|
1202 |
+
if ( is_array( $v ) ) {
|
1203 |
+
$data[ $k ] = $this->_escape( $v );
|
1204 |
+
} else {
|
1205 |
+
$data[ $k ] = $this->_real_escape( $v );
|
1206 |
+
}
|
1207 |
+
}
|
1208 |
+
} else {
|
1209 |
+
$data = $this->_real_escape( $data );
|
1210 |
+
}
|
1211 |
+
|
1212 |
+
return $data;
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
/**
|
1216 |
+
* Do not use, deprecated.
|
1217 |
+
*
|
1218 |
+
* Use esc_sql() or wpdb::prepare() instead.
|
1219 |
+
*
|
1220 |
+
* @since 0.71
|
1221 |
+
* @deprecated 3.6.0 Use wpdb::prepare()
|
1222 |
+
* @see wpdb::prepare()
|
1223 |
+
* @see esc_sql()
|
1224 |
+
*
|
1225 |
+
* @param mixed $data
|
1226 |
+
* @return mixed
|
1227 |
+
*/
|
1228 |
+
public function escape( $data ) {
|
1229 |
+
if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) {
|
1230 |
+
_deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
|
1231 |
+
}
|
1232 |
+
if ( is_array( $data ) ) {
|
1233 |
+
foreach ( $data as $k => $v ) {
|
1234 |
+
if ( is_array( $v ) ) {
|
1235 |
+
$data[ $k ] = $this->escape( $v, 'recursive' );
|
1236 |
+
} else {
|
1237 |
+
$data[ $k ] = $this->_weak_escape( $v, 'internal' );
|
1238 |
+
}
|
1239 |
+
}
|
1240 |
+
} else {
|
1241 |
+
$data = $this->_weak_escape( $data, 'internal' );
|
1242 |
+
}
|
1243 |
+
|
1244 |
+
return $data;
|
1245 |
+
}
|
1246 |
+
|
1247 |
+
/**
|
1248 |
+
* Escapes content by reference for insertion into the database, for security
|
1249 |
+
*
|
1250 |
+
* @uses wpdb::_real_escape()
|
1251 |
+
*
|
1252 |
+
* @since 2.3.0
|
1253 |
+
*
|
1254 |
+
* @param string $string to escape
|
1255 |
+
*/
|
1256 |
+
public function escape_by_ref( &$string ) {
|
1257 |
+
if ( ! is_float( $string ) ) {
|
1258 |
+
$string = $this->_real_escape( $string );
|
1259 |
+
}
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
/**
|
1263 |
+
* Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
|
1264 |
+
*
|
1265 |
+
* The following placeholders can be used in the query string:
|
1266 |
+
* %d (integer)
|
1267 |
+
* %f (float)
|
1268 |
+
* %s (string)
|
1269 |
+
*
|
1270 |
+
* All placeholders MUST be left unquoted in the query string. A corresponding argument MUST be passed for each placeholder.
|
1271 |
+
*
|
1272 |
+
* For compatibility with old behavior, numbered or formatted string placeholders (eg, %1$s, %5s) will not have quotes
|
1273 |
+
* added by this function, so should be passed with appropriate quotes around them for your usage.
|
1274 |
+
*
|
1275 |
+
* Literal percentage signs (%) in the query string must be written as %%. Percentage wildcards (for example,
|
1276 |
+
* to use in LIKE syntax) must be passed via a substitution argument containing the complete LIKE string, these
|
1277 |
+
* cannot be inserted directly in the query string. Also see wpdb::esc_like().
|
1278 |
+
*
|
1279 |
+
* Arguments may be passed as individual arguments to the method, or as a single array containing all arguments. A combination
|
1280 |
+
* of the two is not supported.
|
1281 |
+
*
|
1282 |
+
* Examples:
|
1283 |
+
* $wpdb->prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s", array( 'foo', 1337, '%bar' ) );
|
1284 |
+
* $wpdb->prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
|
1285 |
+
*
|
1286 |
+
* @link https://secure.php.net/sprintf Description of syntax.
|
1287 |
+
* @since 2.3.0
|
1288 |
+
*
|
1289 |
+
* @param string $query Query statement with sprintf()-like placeholders
|
1290 |
+
* @param array|mixed $args The array of variables to substitute into the query's placeholders if being called with an array of arguments,
|
1291 |
+
* or the first variable to substitute into the query's placeholders if being called with individual arguments.
|
1292 |
+
* @param mixed $args,... further variables to substitute into the query's placeholders if being called wih individual arguments.
|
1293 |
+
* @return string|void Sanitized query string, if there is a query to prepare.
|
1294 |
+
*/
|
1295 |
+
public function prepare( $query, $args ) {
|
1296 |
+
if ( is_null( $query ) ) {
|
1297 |
+
return;
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
// This is not meant to be foolproof -- but it will catch obviously incorrect usage.
|
1301 |
+
if ( strpos( $query, '%' ) === false ) {
|
1302 |
+
wp_load_translations_early();
|
1303 |
+
_doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9.0' );
|
1304 |
+
}
|
1305 |
+
|
1306 |
+
$args = func_get_args();
|
1307 |
+
array_shift( $args );
|
1308 |
+
|
1309 |
+
// If args were passed as an array (as in vsprintf), move them up.
|
1310 |
+
$passed_as_array = false;
|
1311 |
+
if ( is_array( $args[0] ) && count( $args ) == 1 ) {
|
1312 |
+
$passed_as_array = true;
|
1313 |
+
$args = $args[0];
|
1314 |
+
}
|
1315 |
+
|
1316 |
+
foreach ( $args as $arg ) {
|
1317 |
+
if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
|
1318 |
+
wp_load_translations_early();
|
1319 |
+
_doing_it_wrong( 'wpdb::prepare', sprintf( __( 'Unsupported value type (%s).' ), gettype( $arg ) ), '4.8.2' );
|
1320 |
+
}
|
1321 |
+
}
|
1322 |
+
|
1323 |
+
/*
|
1324 |
+
* Specify the formatting allowed in a placeholder. The following are allowed:
|
1325 |
+
*
|
1326 |
+
* - Sign specifier. eg, $+d
|
1327 |
+
* - Numbered placeholders. eg, %1$s
|
1328 |
+
* - Padding specifier, including custom padding characters. eg, %05s, %'#5s
|
1329 |
+
* - Alignment specifier. eg, %05-s
|
1330 |
+
* - Precision specifier. eg, %.2f
|
1331 |
+
*/
|
1332 |
+
$allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|\'.)?[-+0-9]*(?:\.[0-9]+)?';
|
1333 |
+
|
1334 |
+
/*
|
1335 |
+
* If a %s placeholder already has quotes around it, removing the existing quotes and re-inserting them
|
1336 |
+
* ensures the quotes are consistent.
|
1337 |
+
*
|
1338 |
+
* For backward compatibility, this is only applied to %s, and not to placeholders like %1$s, which are frequently
|
1339 |
+
* used in the middle of longer strings, or as table name placeholders.
|
1340 |
+
*/
|
1341 |
+
$query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes.
|
1342 |
+
$query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes.
|
1343 |
+
$query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings like %%s.
|
1344 |
+
|
1345 |
+
$query = preg_replace( "/(?<!%)(%($allowed_format)?f)/", '%\\2F', $query ); // Force floats to be locale unaware.
|
1346 |
+
|
1347 |
+
$query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF]))/", '%%\\1', $query ); // Escape any unescaped percents.
|
1348 |
+
|
1349 |
+
// Count the number of valid placeholders in the query.
|
1350 |
+
$placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );
|
1351 |
+
|
1352 |
+
if ( count( $args ) !== $placeholders ) {
|
1353 |
+
if ( 1 === $placeholders && $passed_as_array ) {
|
1354 |
+
// If the passed query only expected one argument, but the wrong number of arguments were sent as an array, bail.
|
1355 |
+
wp_load_translations_early();
|
1356 |
+
_doing_it_wrong( 'wpdb::prepare', __( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ), '4.9.0' );
|
1357 |
+
|
1358 |
+
return;
|
1359 |
+
} else {
|
1360 |
+
/*
|
1361 |
+
* If we don't have the right number of placeholders, but they were passed as individual arguments,
|
1362 |
+
* or we were expecting multiple arguments in an array, throw a warning.
|
1363 |
+
*/
|
1364 |
+
wp_load_translations_early();
|
1365 |
+
_doing_it_wrong(
|
1366 |
+
'wpdb::prepare',
|
1367 |
+
/* translators: 1: number of placeholders, 2: number of arguments passed */
|
1368 |
+
sprintf(
|
1369 |
+
__( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
|
1370 |
+
$placeholders,
|
1371 |
+
count( $args )
|
1372 |
+
),
|
1373 |
+
'4.8.3'
|
1374 |
+
);
|
1375 |
+
}
|
1376 |
+
}
|
1377 |
+
|
1378 |
+
array_walk( $args, array( $this, 'escape_by_ref' ) );
|
1379 |
+
$query = @vsprintf( $query, $args );
|
1380 |
+
|
1381 |
+
return $this->add_placeholder_escape( $query );
|
1382 |
+
}
|
1383 |
+
|
1384 |
+
/**
|
1385 |
+
* First half of escaping for LIKE special characters % and _ before preparing for MySQL.
|
1386 |
+
*
|
1387 |
+
* Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security.
|
1388 |
+
*
|
1389 |
+
* Example Prepared Statement:
|
1390 |
+
*
|
1391 |
+
* $wild = '%';
|
1392 |
+
* $find = 'only 43% of planets';
|
1393 |
+
* $like = $wild . $wpdb->esc_like( $find ) . $wild;
|
1394 |
+
* $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );
|
1395 |
+
*
|
1396 |
+
* Example Escape Chain:
|
1397 |
+
*
|
1398 |
+
* $sql = esc_sql( $wpdb->esc_like( $input ) );
|
1399 |
+
*
|
1400 |
+
* @since 4.0.0
|
1401 |
+
*
|
1402 |
+
* @param string $text The raw text to be escaped. The input typed by the user should have no
|
1403 |
+
* extra or deleted slashes.
|
1404 |
+
* @return string Text in the form of a LIKE phrase. The output is not SQL safe. Call $wpdb::prepare()
|
1405 |
+
* or real_escape next.
|
1406 |
+
*/
|
1407 |
+
public function esc_like( $text ) {
|
1408 |
+
return addcslashes( $text, '_%\\' );
|
1409 |
+
}
|
1410 |
+
|
1411 |
+
/**
|
1412 |
+
* Print SQL/DB error.
|
1413 |
+
*
|
1414 |
+
* @since 0.71
|
1415 |
+
* @global array $EZSQL_ERROR Stores error information of query and error string
|
1416 |
+
*
|
1417 |
+
* @param string $str The error to display
|
1418 |
+
* @return false|void False if the showing of errors is disabled.
|
1419 |
+
*/
|
1420 |
+
public function print_error( $str = '' ) {
|
1421 |
+
global $EZSQL_ERROR;
|
1422 |
+
|
1423 |
+
if ( ! $str ) {
|
1424 |
+
if ( $this->use_mysqli ) {
|
1425 |
+
$str = mysqli_error( $this->dbh );
|
1426 |
+
} else {
|
1427 |
+
$str = mysql_error( $this->dbh );
|
1428 |
+
}
|
1429 |
+
}
|
1430 |
+
$EZSQL_ERROR[] = array(
|
1431 |
+
'query' => $this->last_query,
|
1432 |
+
'error_str' => $str,
|
1433 |
+
);
|
1434 |
+
|
1435 |
+
if ( $this->suppress_errors ) {
|
1436 |
+
return false;
|
1437 |
+
}
|
1438 |
+
|
1439 |
+
wp_load_translations_early();
|
1440 |
+
|
1441 |
+
if ( $caller = $this->get_caller() ) {
|
1442 |
+
/* translators: 1: Database error message, 2: SQL query, 3: Name of the calling function */
|
1443 |
+
$error_str = sprintf( __( 'WordPress database error %1$s for query %2$s made by %3$s' ), $str, $this->last_query, $caller );
|
1444 |
+
} else {
|
1445 |
+
/* translators: 1: Database error message, 2: SQL query */
|
1446 |
+
$error_str = sprintf( __( 'WordPress database error %1$s for query %2$s' ), $str, $this->last_query );
|
1447 |
+
}
|
1448 |
+
|
1449 |
+
error_log( $error_str );
|
1450 |
+
|
1451 |
+
// Are we showing errors?
|
1452 |
+
if ( ! $this->show_errors ) {
|
1453 |
+
return false;
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
// If there is an error then take note of it
|
1457 |
+
if ( is_multisite() ) {
|
1458 |
+
$msg = sprintf(
|
1459 |
+
"%s [%s]\n%s\n",
|
1460 |
+
__( 'WordPress database error:' ),
|
1461 |
+
$str,
|
1462 |
+
$this->last_query
|
1463 |
+
);
|
1464 |
+
|
1465 |
+
if ( defined( 'ERRORLOGFILE' ) ) {
|
1466 |
+
error_log( $msg, 3, ERRORLOGFILE );
|
1467 |
+
}
|
1468 |
+
if ( defined( 'DIEONDBERROR' ) ) {
|
1469 |
+
wp_die( $msg );
|
1470 |
+
}
|
1471 |
+
} else {
|
1472 |
+
$str = htmlspecialchars( $str, ENT_QUOTES );
|
1473 |
+
$query = htmlspecialchars( $this->last_query, ENT_QUOTES );
|
1474 |
+
|
1475 |
+
printf(
|
1476 |
+
'<div id="error"><p class="wpdberror"><strong>%s</strong> [%s]<br /><code>%s</code></p></div>',
|
1477 |
+
__( 'WordPress database error:' ),
|
1478 |
+
$str,
|
1479 |
+
$query
|
1480 |
+
);
|
1481 |
+
}
|
1482 |
+
}
|
1483 |
+
|
1484 |
+
/**
|
1485 |
+
* Enables showing of database errors.
|
1486 |
+
*
|
1487 |
+
* This function should be used only to enable showing of errors.
|
1488 |
+
* wpdb::hide_errors() should be used instead for hiding of errors. However,
|
1489 |
+
* this function can be used to enable and disable showing of database
|
1490 |
+
* errors.
|
1491 |
+
*
|
1492 |
+
* @since 0.71
|
1493 |
+
* @see wpdb::hide_errors()
|
1494 |
+
*
|
1495 |
+
* @param bool $show Whether to show or hide errors
|
1496 |
+
* @return bool Old value for showing errors.
|
1497 |
+
*/
|
1498 |
+
public function show_errors( $show = true ) {
|
1499 |
+
$errors = $this->show_errors;
|
1500 |
+
$this->show_errors = $show;
|
1501 |
+
return $errors;
|
1502 |
+
}
|
1503 |
+
|
1504 |
+
/**
|
1505 |
+
* Disables showing of database errors.
|
1506 |
+
*
|
1507 |
+
* By default database errors are not shown.
|
1508 |
+
*
|
1509 |
+
* @since 0.71
|
1510 |
+
* @see wpdb::show_errors()
|
1511 |
+
*
|
1512 |
+
* @return bool Whether showing of errors was active
|
1513 |
+
*/
|
1514 |
+
public function hide_errors() {
|
1515 |
+
$show = $this->show_errors;
|
1516 |
+
$this->show_errors = false;
|
1517 |
+
return $show;
|
1518 |
+
}
|
1519 |
+
|
1520 |
+
/**
|
1521 |
+
* Whether to suppress database errors.
|
1522 |
+
*
|
1523 |
+
* By default database errors are suppressed, with a simple
|
1524 |
+
* call to this function they can be enabled.
|
1525 |
+
*
|
1526 |
+
* @since 2.5.0
|
1527 |
+
* @see wpdb::hide_errors()
|
1528 |
+
* @param bool $suppress Optional. New value. Defaults to true.
|
1529 |
+
* @return bool Old value
|
1530 |
+
*/
|
1531 |
+
public function suppress_errors( $suppress = true ) {
|
1532 |
+
$errors = $this->suppress_errors;
|
1533 |
+
$this->suppress_errors = (bool) $suppress;
|
1534 |
+
return $errors;
|
1535 |
+
}
|
1536 |
+
|
1537 |
+
/**
|
1538 |
+
* Kill cached query results.
|
1539 |
+
*
|
1540 |
+
* @since 0.71
|
1541 |
+
*/
|
1542 |
+
public function flush() {
|
1543 |
+
$this->last_result = array();
|
1544 |
+
$this->col_info = null;
|
1545 |
+
$this->last_query = null;
|
1546 |
+
$this->rows_affected = $this->num_rows = 0;
|
1547 |
+
$this->last_error = '';
|
1548 |
+
|
1549 |
+
if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
|
1550 |
+
mysqli_free_result( $this->result );
|
1551 |
+
$this->result = null;
|
1552 |
+
|
1553 |
+
// Sanity check before using the handle
|
1554 |
+
if ( empty( $this->dbh ) || ! ( $this->dbh instanceof mysqli ) ) {
|
1555 |
+
return;
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
// Clear out any results from a multi-query
|
1559 |
+
while ( mysqli_more_results( $this->dbh ) ) {
|
1560 |
+
mysqli_next_result( $this->dbh );
|
1561 |
+
}
|
1562 |
+
} elseif ( is_resource( $this->result ) ) {
|
1563 |
+
mysql_free_result( $this->result );
|
1564 |
+
}
|
1565 |
+
}
|
1566 |
+
|
1567 |
+
/**
|
1568 |
+
* Connect to and select database.
|
1569 |
+
*
|
1570 |
+
* If $allow_bail is false, the lack of database connection will need
|
1571 |
+
* to be handled manually.
|
1572 |
+
*
|
1573 |
+
* @since 3.0.0
|
1574 |
+
* @since 3.9.0 $allow_bail parameter added.
|
1575 |
+
*
|
1576 |
+
* @param bool $allow_bail Optional. Allows the function to bail. Default true.
|
1577 |
+
* @return bool True with a successful connection, false on failure.
|
1578 |
+
*/
|
1579 |
+
public function db_connect( $allow_bail = true ) {
|
1580 |
+
$this->is_mysql = true;
|
1581 |
+
|
1582 |
+
/*
|
1583 |
+
* Deprecated in 3.9+ when using MySQLi. No equivalent
|
1584 |
+
* $new_link parameter exists for mysqli_* functions.
|
1585 |
+
*/
|
1586 |
+
$new_link = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
|
1587 |
+
$client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;
|
1588 |
+
|
1589 |
+
if ( $this->use_mysqli ) {
|
1590 |
+
$this->dbh = mysqli_init();
|
1591 |
+
|
1592 |
+
$host = $this->dbhost;
|
1593 |
+
$port = null;
|
1594 |
+
$socket = null;
|
1595 |
+
$is_ipv6 = false;
|
1596 |
+
|
1597 |
+
if ( $host_data = $this->parse_db_host( $this->dbhost ) ) {
|
1598 |
+
list( $host, $port, $socket, $is_ipv6 ) = $host_data;
|
1599 |
+
}
|
1600 |
+
|
1601 |
+
/*
|
1602 |
+
* If using the `mysqlnd` library, the IPv6 address needs to be
|
1603 |
+
* enclosed in square brackets, whereas it doesn't while using the
|
1604 |
+
* `libmysqlclient` library.
|
1605 |
+
* @see https://bugs.php.net/bug.php?id=67563
|
1606 |
+
*/
|
1607 |
+
if ( $is_ipv6 && extension_loaded( 'mysqlnd' ) ) {
|
1608 |
+
$host = "[$host]";
|
1609 |
+
}
|
1610 |
+
|
1611 |
+
if ( WP_DEBUG ) {
|
1612 |
+
mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
|
1613 |
+
} else {
|
1614 |
+
@mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
|
1615 |
+
}
|
1616 |
+
|
1617 |
+
if ( $this->dbh->connect_errno ) {
|
1618 |
+
$this->dbh = null;
|
1619 |
+
|
1620 |
+
/*
|
1621 |
+
* It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if:
|
1622 |
+
* - We haven't previously connected, and
|
1623 |
+
* - WP_USE_EXT_MYSQL isn't set to false, and
|
1624 |
+
* - ext/mysql is loaded.
|
1625 |
+
*/
|
1626 |
+
$attempt_fallback = true;
|
1627 |
+
|
1628 |
+
if ( $this->has_connected ) {
|
1629 |
+
$attempt_fallback = false;
|
1630 |
+
} elseif ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL ) {
|
1631 |
+
$attempt_fallback = false;
|
1632 |
+
} elseif ( ! function_exists( 'mysql_connect' ) ) {
|
1633 |
+
$attempt_fallback = false;
|
1634 |
+
}
|
1635 |
+
|
1636 |
+
if ( $attempt_fallback ) {
|
1637 |
+
$this->use_mysqli = false;
|
1638 |
+
return $this->db_connect( $allow_bail );
|
1639 |
+
}
|
1640 |
+
}
|
1641 |
+
} else {
|
1642 |
+
if ( WP_DEBUG ) {
|
1643 |
+
$this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
|
1644 |
+
} else {
|
1645 |
+
$this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
|
1646 |
+
}
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
if ( ! $this->dbh && $allow_bail ) {
|
1650 |
+
wp_load_translations_early();
|
1651 |
+
|
1652 |
+
// Load custom DB error template, if present.
|
1653 |
+
if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
|
1654 |
+
require_once( WP_CONTENT_DIR . '/db-error.php' );
|
1655 |
+
die();
|
1656 |
+
}
|
1657 |
+
|
1658 |
+
$message = '<h1>' . __( 'Error establishing a database connection' ) . "</h1>\n";
|
1659 |
+
|
1660 |
+
$message .= '<p>' . sprintf(
|
1661 |
+
/* translators: 1: wp-config.php, 2: database host */
|
1662 |
+
__( 'This either means that the username and password information in your %1$s file is incorrect or we can’t contact the database server at %2$s. This could mean your host’s database server is down.' ),
|
1663 |
+
'<code>wp-config.php</code>',
|
1664 |
+
'<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
|
1665 |
+
) . "</p>\n";
|
1666 |
+
|
1667 |
+
$message .= "<ul>\n";
|
1668 |
+
$message .= '<li>' . __( 'Are you sure you have the correct username and password?' ) . "</li>\n";
|
1669 |
+
$message .= '<li>' . __( 'Are you sure that you have typed the correct hostname?' ) . "</li>\n";
|
1670 |
+
$message .= '<li>' . __( 'Are you sure that the database server is running?' ) . "</li>\n";
|
1671 |
+
$message .= "</ul>\n";
|
1672 |
+
|
1673 |
+
$message .= '<p>' . sprintf(
|
1674 |
+
/* translators: %s: support forums URL */
|
1675 |
+
__( 'If you’re unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
|
1676 |
+
__( 'https://wordpress.org/support/forums/' )
|
1677 |
+
) . "</p>\n";
|
1678 |
+
|
1679 |
+
$this->bail( $message, 'db_connect_fail' );
|
1680 |
+
|
1681 |
+
return false;
|
1682 |
+
} elseif ( $this->dbh ) {
|
1683 |
+
if ( ! $this->has_connected ) {
|
1684 |
+
$this->init_charset();
|
1685 |
+
}
|
1686 |
+
|
1687 |
+
$this->has_connected = true;
|
1688 |
+
|
1689 |
+
$this->set_charset( $this->dbh );
|
1690 |
+
|
1691 |
+
$this->ready = true;
|
1692 |
+
$this->set_sql_mode();
|
1693 |
+
$this->select( $this->dbname, $this->dbh );
|
1694 |
+
|
1695 |
+
return true;
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
return false;
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
/**
|
1702 |
+
* Parse the DB_HOST setting to interpret it for mysqli_real_connect.
|
1703 |
+
*
|
1704 |
+
* mysqli_real_connect doesn't support the host param including a port or
|
1705 |
+
* socket like mysql_connect does. This duplicates how mysql_connect detects
|
1706 |
+
* a port and/or socket file.
|
1707 |
+
*
|
1708 |
+
* @since 4.9.0
|
1709 |
+
*
|
1710 |
+
* @param string $host The DB_HOST setting to parse.
|
1711 |
+
* @return array|bool Array containing the host, the port, the socket and whether
|
1712 |
+
* it is an IPv6 address, in that order. If $host couldn't be parsed,
|
1713 |
+
* returns false.
|
1714 |
+
*/
|
1715 |
+
public function parse_db_host( $host ) {
|
1716 |
+
$port = null;
|
1717 |
+
$socket = null;
|
1718 |
+
$is_ipv6 = false;
|
1719 |
+
|
1720 |
+
// First peel off the socket parameter from the right, if it exists.
|
1721 |
+
$socket_pos = strpos( $host, ':/' );
|
1722 |
+
if ( $socket_pos !== false ) {
|
1723 |
+
$socket = substr( $host, $socket_pos + 1 );
|
1724 |
+
$host = substr( $host, 0, $socket_pos );
|
1725 |
+
}
|
1726 |
+
|
1727 |
+
// We need to check for an IPv6 address first.
|
1728 |
+
// An IPv6 address will always contain at least two colons.
|
1729 |
+
if ( substr_count( $host, ':' ) > 1 ) {
|
1730 |
+
$pattern = '#^(?:\[)?(?P<host>[0-9a-fA-F:]+)(?:\]:(?P<port>[\d]+))?#';
|
1731 |
+
$is_ipv6 = true;
|
1732 |
+
} else {
|
1733 |
+
// We seem to be dealing with an IPv4 address.
|
1734 |
+
$pattern = '#^(?P<host>[^:/]*)(?::(?P<port>[\d]+))?#';
|
1735 |
+
}
|
1736 |
+
|
1737 |
+
$matches = array();
|
1738 |
+
$result = preg_match( $pattern, $host, $matches );
|
1739 |
+
|
1740 |
+
if ( 1 !== $result ) {
|
1741 |
+
// Couldn't parse the address, bail.
|
1742 |
+
return false;
|
1743 |
+
}
|
1744 |
+
|
1745 |
+
$host = '';
|
1746 |
+
foreach ( array( 'host', 'port' ) as $component ) {
|
1747 |
+
if ( ! empty( $matches[ $component ] ) ) {
|
1748 |
+
$$component = $matches[ $component ];
|
1749 |
+
}
|
1750 |
+
}
|
1751 |
+
|
1752 |
+
return array( $host, $port, $socket, $is_ipv6 );
|
1753 |
+
}
|
1754 |
+
|
1755 |
+
/**
|
1756 |
+
* Checks that the connection to the database is still up. If not, try to reconnect.
|
1757 |
+
*
|
1758 |
+
* If this function is unable to reconnect, it will forcibly die, or if after the
|
1759 |
+
* the {@see 'template_redirect'} hook has been fired, return false instead.
|
1760 |
+
*
|
1761 |
+
* If $allow_bail is false, the lack of database connection will need
|
1762 |
+
* to be handled manually.
|
1763 |
+
*
|
1764 |
+
* @since 3.9.0
|
1765 |
+
*
|
1766 |
+
* @param bool $allow_bail Optional. Allows the function to bail. Default true.
|
1767 |
+
* @return bool|void True if the connection is up.
|
1768 |
+
*/
|
1769 |
+
public function check_connection( $allow_bail = true ) {
|
1770 |
+
if ( $this->use_mysqli ) {
|
1771 |
+
if ( ! empty( $this->dbh ) && mysqli_ping( $this->dbh ) ) {
|
1772 |
+
return true;
|
1773 |
+
}
|
1774 |
+
} else {
|
1775 |
+
if ( ! empty( $this->dbh ) && mysql_ping( $this->dbh ) ) {
|
1776 |
+
return true;
|
1777 |
+
}
|
1778 |
+
}
|
1779 |
+
|
1780 |
+
$error_reporting = false;
|
1781 |
+
|
1782 |
+
// Disable warnings, as we don't want to see a multitude of "unable to connect" messages
|
1783 |
+
if ( WP_DEBUG ) {
|
1784 |
+
$error_reporting = error_reporting();
|
1785 |
+
error_reporting( $error_reporting & ~E_WARNING );
|
1786 |
+
}
|
1787 |
+
|
1788 |
+
for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
|
1789 |
+
// On the last try, re-enable warnings. We want to see a single instance of the
|
1790 |
+
// "unable to connect" message on the bail() screen, if it appears.
|
1791 |
+
if ( $this->reconnect_retries === $tries && WP_DEBUG ) {
|
1792 |
+
error_reporting( $error_reporting );
|
1793 |
+
}
|
1794 |
+
|
1795 |
+
if ( $this->db_connect( false ) ) {
|
1796 |
+
if ( $error_reporting ) {
|
1797 |
+
error_reporting( $error_reporting );
|
1798 |
+
}
|
1799 |
+
|
1800 |
+
return true;
|
1801 |
+
}
|
1802 |
+
|
1803 |
+
sleep( 1 );
|
1804 |
+
}
|
1805 |
+
|
1806 |
+
// If template_redirect has already happened, it's too late for wp_die()/dead_db().
|
1807 |
+
// Let's just return and hope for the best.
|
1808 |
+
if ( did_action( 'template_redirect' ) ) {
|
1809 |
+
return false;
|
1810 |
+
}
|
1811 |
+
|
1812 |
+
if ( ! $allow_bail ) {
|
1813 |
+
return false;
|
1814 |
+
}
|
1815 |
+
|
1816 |
+
wp_load_translations_early();
|
1817 |
+
|
1818 |
+
$message = '<h1>' . __( 'Error reconnecting to the database' ) . "</h1>\n";
|
1819 |
+
|
1820 |
+
$message .= '<p>' . sprintf(
|
1821 |
+
/* translators: %s: database host */
|
1822 |
+
__( 'This means that we lost contact with the database server at %s. This could mean your host’s database server is down.' ),
|
1823 |
+
'<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
|
1824 |
+
) . "</p>\n";
|
1825 |
+
|
1826 |
+
$message .= "<ul>\n";
|
1827 |
+
$message .= '<li>' . __( 'Are you sure that the database server is running?' ) . "</li>\n";
|
1828 |
+
$message .= '<li>' . __( 'Are you sure that the database server is not under particularly heavy load?' ) . "</li>\n";
|
1829 |
+
$message .= "</ul>\n";
|
1830 |
+
|
1831 |
+
$message .= '<p>' . sprintf(
|
1832 |
+
/* translators: %s: support forums URL */
|
1833 |
+
__( 'If you’re unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
|
1834 |
+
__( 'https://wordpress.org/support/forums/' )
|
1835 |
+
) . "</p>\n";
|
1836 |
+
|
1837 |
+
// We weren't able to reconnect, so we better bail.
|
1838 |
+
$this->bail( $message, 'db_connect_fail' );
|
1839 |
+
|
1840 |
+
// Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily).
|
1841 |
+
dead_db();
|
1842 |
+
}
|
1843 |
+
|
1844 |
+
/**
|
1845 |
+
* Perform a MySQL database query, using current database connection.
|
1846 |
+
*
|
1847 |
+
* More information can be found on the codex page.
|
1848 |
+
*
|
1849 |
+
* @since 0.71
|
1850 |
+
*
|
1851 |
+
* @param string $query Database query
|
1852 |
+
* @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
|
1853 |
+
* affected/selected for all other queries. Boolean false on error.
|
1854 |
+
*/
|
1855 |
+
public function query( $query ) {
|
1856 |
+
if ( ! $this->ready ) {
|
1857 |
+
$this->check_current_query = true;
|
1858 |
+
return false;
|
1859 |
+
}
|
1860 |
+
|
1861 |
+
/**
|
1862 |
+
* Filters the database query.
|
1863 |
+
*
|
1864 |
+
* Some queries are made before the plugins have been loaded,
|
1865 |
+
* and thus cannot be filtered with this method.
|
1866 |
+
*
|
1867 |
+
* @since 2.1.0
|
1868 |
+
*
|
1869 |
+
* @param string $query Database query.
|
1870 |
+
*/
|
1871 |
+
$query = apply_filters( 'query', $query );
|
1872 |
+
|
1873 |
+
$this->flush();
|
1874 |
+
|
1875 |
+
// Log how the function was called
|
1876 |
+
$this->func_call = "\$db->query(\"$query\")";
|
1877 |
+
|
1878 |
+
// If we're writing to the database, make sure the query will write safely.
|
1879 |
+
if ( $this->check_current_query && ! $this->check_ascii( $query ) ) {
|
1880 |
+
$stripped_query = $this->strip_invalid_text_from_query( $query );
|
1881 |
+
// strip_invalid_text_from_query() can perform queries, so we need
|
1882 |
+
// to flush again, just to make sure everything is clear.
|
1883 |
+
$this->flush();
|
1884 |
+
if ( $stripped_query !== $query ) {
|
1885 |
+
$this->insert_id = 0;
|
1886 |
+
return false;
|
1887 |
+
}
|
1888 |
+
}
|
1889 |
+
|
1890 |
+
$this->check_current_query = true;
|
1891 |
+
|
1892 |
+
// Keep track of the last query for debug.
|
1893 |
+
$this->last_query = $query;
|
1894 |
+
|
1895 |
+
$this->_do_query( $query );
|
1896 |
+
|
1897 |
+
// MySQL server has gone away, try to reconnect.
|
1898 |
+
$mysql_errno = 0;
|
1899 |
+
if ( ! empty( $this->dbh ) ) {
|
1900 |
+
if ( $this->use_mysqli ) {
|
1901 |
+
if ( $this->dbh instanceof mysqli ) {
|
1902 |
+
$mysql_errno = mysqli_errno( $this->dbh );
|
1903 |
+
} else {
|
1904 |
+
// $dbh is defined, but isn't a real connection.
|
1905 |
+
// Something has gone horribly wrong, let's try a reconnect.
|
1906 |
+
$mysql_errno = 2006;
|
1907 |
+
}
|
1908 |
+
} else {
|
1909 |
+
if ( is_resource( $this->dbh ) ) {
|
1910 |
+
$mysql_errno = mysql_errno( $this->dbh );
|
1911 |
+
} else {
|
1912 |
+
$mysql_errno = 2006;
|
1913 |
+
}
|
1914 |
+
}
|
1915 |
+
}
|
1916 |
+
|
1917 |
+
if ( empty( $this->dbh ) || 2006 == $mysql_errno ) {
|
1918 |
+
if ( $this->check_connection() ) {
|
1919 |
+
$this->_do_query( $query );
|
1920 |
+
} else {
|
1921 |
+
$this->insert_id = 0;
|
1922 |
+
return false;
|
1923 |
+
}
|
1924 |
+
}
|
1925 |
+
|
1926 |
+
// If there is an error then take note of it.
|
1927 |
+
if ( $this->use_mysqli ) {
|
1928 |
+
if ( $this->dbh instanceof mysqli ) {
|
1929 |
+
$this->last_error = mysqli_error( $this->dbh );
|
1930 |
+
} else {
|
1931 |
+
$this->last_error = __( 'Unable to retrieve the error message from MySQL' );
|
1932 |
+
}
|
1933 |
+
} else {
|
1934 |
+
if ( is_resource( $this->dbh ) ) {
|
1935 |
+
$this->last_error = mysql_error( $this->dbh );
|
1936 |
+
} else {
|
1937 |
+
$this->last_error = __( 'Unable to retrieve the error message from MySQL' );
|
1938 |
+
}
|
1939 |
+
}
|
1940 |
+
|
1941 |
+
if ( $this->last_error ) {
|
1942 |
+
// Clear insert_id on a subsequent failed insert.
|
1943 |
+
if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
1944 |
+
$this->insert_id = 0;
|
1945 |
+
}
|
1946 |
+
|
1947 |
+
$this->print_error();
|
1948 |
+
return false;
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
|
1952 |
+
$return_val = $this->result;
|
1953 |
+
} elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
|
1954 |
+
if ( $this->use_mysqli ) {
|
1955 |
+
$this->rows_affected = mysqli_affected_rows( $this->dbh );
|
1956 |
+
} else {
|
1957 |
+
$this->rows_affected = mysql_affected_rows( $this->dbh );
|
1958 |
+
}
|
1959 |
+
// Take note of the insert_id
|
1960 |
+
if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
1961 |
+
if ( $this->use_mysqli ) {
|
1962 |
+
$this->insert_id = mysqli_insert_id( $this->dbh );
|
1963 |
+
} else {
|
1964 |
+
$this->insert_id = mysql_insert_id( $this->dbh );
|
1965 |
+
}
|
1966 |
+
}
|
1967 |
+
// Return number of rows affected
|
1968 |
+
$return_val = $this->rows_affected;
|
1969 |
+
} else {
|
1970 |
+
$num_rows = 0;
|
1971 |
+
if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
|
1972 |
+
while ( $row = mysqli_fetch_object( $this->result ) ) {
|
1973 |
+
$this->last_result[ $num_rows ] = $row;
|
1974 |
+
$num_rows++;
|
1975 |
+
}
|
1976 |
+
} elseif ( is_resource( $this->result ) ) {
|
1977 |
+
while ( $row = mysql_fetch_object( $this->result ) ) {
|
1978 |
+
$this->last_result[ $num_rows ] = $row;
|
1979 |
+
$num_rows++;
|
1980 |
+
}
|
1981 |
+
}
|
1982 |
+
|
1983 |
+
// Log number of rows the query returned
|
1984 |
+
// and return number of rows selected
|
1985 |
+
$this->num_rows = $num_rows;
|
1986 |
+
$return_val = $num_rows;
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
return $return_val;
|
1990 |
+
}
|
1991 |
+
|
1992 |
+
/**
|
1993 |
+
* Internal function to perform the mysql_query() call.
|
1994 |
+
*
|
1995 |
+
* @since 3.9.0
|
1996 |
+
*
|
1997 |
+
* @see wpdb::query()
|
1998 |
+
*
|
1999 |
+
* @param string $query The query to run.
|
2000 |
+
*/
|
2001 |
+
private function _do_query( $query ) {
|
2002 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
2003 |
+
$this->timer_start();
|
2004 |
+
}
|
2005 |
+
|
2006 |
+
if ( ! empty( $this->dbh ) && $this->use_mysqli ) {
|
2007 |
+
$this->result = mysqli_query( $this->dbh, $query );
|
2008 |
+
} elseif ( ! empty( $this->dbh ) ) {
|
2009 |
+
$this->result = mysql_query( $query, $this->dbh );
|
2010 |
+
}
|
2011 |
+
$this->num_queries++;
|
2012 |
+
|
2013 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
2014 |
+
$this->queries[] = array(
|
2015 |
+
$query,
|
2016 |
+
$this->timer_stop(),
|
2017 |
+
$this->get_caller(),
|
2018 |
+
$this->time_start,
|
2019 |
+
);
|
2020 |
+
}
|
2021 |
+
}
|
2022 |
+
|
2023 |
+
/**
|
2024 |
+
* Generates and returns a placeholder escape string for use in queries returned by ::prepare().
|
2025 |
+
*
|
2026 |
+
* @since 4.8.3
|
2027 |
+
*
|
2028 |
+
* @return string String to escape placeholders.
|
2029 |
+
*/
|
2030 |
+
public function placeholder_escape() {
|
2031 |
+
static $placeholder;
|
2032 |
+
|
2033 |
+
if ( ! $placeholder ) {
|
2034 |
+
// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
|
2035 |
+
$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
|
2036 |
+
// Old WP installs may not have AUTH_SALT defined.
|
2037 |
+
$salt = defined( 'AUTH_SALT' ) && AUTH_SALT ? AUTH_SALT : (string) rand();
|
2038 |
+
|
2039 |
+
$placeholder = '{' . hash_hmac( $algo, uniqid( $salt, true ), $salt ) . '}';
|
2040 |
+
}
|
2041 |
+
|
2042 |
+
/*
|
2043 |
+
* Add the filter to remove the placeholder escaper. Uses priority 0, so that anything
|
2044 |
+
* else attached to this filter will receive the query with the placeholder string removed.
|
2045 |
+
*/
|
2046 |
+
if ( ! has_filter( 'query', array( $this, 'remove_placeholder_escape' ) ) ) {
|
2047 |
+
add_filter( 'query', array( $this, 'remove_placeholder_escape' ), 0 );
|
2048 |
+
}
|
2049 |
+
|
2050 |
+
return $placeholder;
|
2051 |
+
}
|
2052 |
+
|
2053 |
+
/**
|
2054 |
+
* Adds a placeholder escape string, to escape anything that resembles a printf() placeholder.
|
2055 |
+
*
|
2056 |
+
* @since 4.8.3
|
2057 |
+
*
|
2058 |
+
* @param string $query The query to escape.
|
2059 |
+
* @return string The query with the placeholder escape string inserted where necessary.
|
2060 |
+
*/
|
2061 |
+
public function add_placeholder_escape( $query ) {
|
2062 |
+
/*
|
2063 |
+
* To prevent returning anything that even vaguely resembles a placeholder,
|
2064 |
+
* we clobber every % we can find.
|
2065 |
+
*/
|
2066 |
+
return str_replace( '%', $this->placeholder_escape(), $query );
|
2067 |
+
}
|
2068 |
+
|
2069 |
+
/**
|
2070 |
+
* Removes the placeholder escape strings from a query.
|
2071 |
+
*
|
2072 |
+
* @since 4.8.3
|
2073 |
+
*
|
2074 |
+
* @param string $query The query from which the placeholder will be removed.
|
2075 |
+
* @return string The query with the placeholder removed.
|
2076 |
+
*/
|
2077 |
+
public function remove_placeholder_escape( $query ) {
|
2078 |
+
return str_replace( $this->placeholder_escape(), '%', $query );
|
2079 |
+
}
|
2080 |
+
|
2081 |
+
/**
|
2082 |
+
* Insert a row into a table.
|
2083 |
+
*
|
2084 |
+
* wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
|
2085 |
+
* wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
|
2086 |
+
*
|
2087 |
+
* @since 2.5.0
|
2088 |
+
* @see wpdb::prepare()
|
2089 |
+
* @see wpdb::$field_types
|
2090 |
+
* @see wp_set_wpdb_vars()
|
2091 |
+
*
|
2092 |
+
* @param string $table Table name
|
2093 |
+
* @param array $data Data to insert (in column => value pairs).
|
2094 |
+
* Both $data columns and $data values should be "raw" (neither should be SQL escaped).
|
2095 |
+
* Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
|
2096 |
+
* @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
|
2097 |
+
* If string, that format will be used for all of the values in $data.
|
2098 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2099 |
+
* If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
|
2100 |
+
* @return int|false The number of rows inserted, or false on error.
|
2101 |
+
*/
|
2102 |
+
public function insert( $table, $data, $format = null ) {
|
2103 |
+
return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
|
2104 |
+
}
|
2105 |
+
|
2106 |
+
/**
|
2107 |
+
* Replace a row into a table.
|
2108 |
+
*
|
2109 |
+
* wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
|
2110 |
+
* wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
|
2111 |
+
*
|
2112 |
+
* @since 3.0.0
|
2113 |
+
* @see wpdb::prepare()
|
2114 |
+
* @see wpdb::$field_types
|
2115 |
+
* @see wp_set_wpdb_vars()
|
2116 |
+
*
|
2117 |
+
* @param string $table Table name
|
2118 |
+
* @param array $data Data to insert (in column => value pairs).
|
2119 |
+
* Both $data columns and $data values should be "raw" (neither should be SQL escaped).
|
2120 |
+
* Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
|
2121 |
+
* @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
|
2122 |
+
* If string, that format will be used for all of the values in $data.
|
2123 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2124 |
+
* If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
|
2125 |
+
* @return int|false The number of rows affected, or false on error.
|
2126 |
+
*/
|
2127 |
+
public function replace( $table, $data, $format = null ) {
|
2128 |
+
return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
|
2129 |
+
}
|
2130 |
+
|
2131 |
+
/**
|
2132 |
+
* Helper function for insert and replace.
|
2133 |
+
*
|
2134 |
+
* Runs an insert or replace query based on $type argument.
|
2135 |
+
*
|
2136 |
+
* @since 3.0.0
|
2137 |
+
* @see wpdb::prepare()
|
2138 |
+
* @see wpdb::$field_types
|
2139 |
+
* @see wp_set_wpdb_vars()
|
2140 |
+
*
|
2141 |
+
* @param string $table Table name
|
2142 |
+
* @param array $data Data to insert (in column => value pairs).
|
2143 |
+
* Both $data columns and $data values should be "raw" (neither should be SQL escaped).
|
2144 |
+
* Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
|
2145 |
+
* @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
|
2146 |
+
* If string, that format will be used for all of the values in $data.
|
2147 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2148 |
+
* If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
|
2149 |
+
* @param string $type Optional. What type of operation is this? INSERT or REPLACE. Defaults to INSERT.
|
2150 |
+
* @return int|false The number of rows affected, or false on error.
|
2151 |
+
*/
|
2152 |
+
function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
|
2153 |
+
$this->insert_id = 0;
|
2154 |
+
|
2155 |
+
if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) {
|
2156 |
+
return false;
|
2157 |
+
}
|
2158 |
+
|
2159 |
+
$data = $this->process_fields( $table, $data, $format );
|
2160 |
+
if ( false === $data ) {
|
2161 |
+
return false;
|
2162 |
+
}
|
2163 |
+
|
2164 |
+
$formats = $values = array();
|
2165 |
+
foreach ( $data as $value ) {
|
2166 |
+
if ( is_null( $value['value'] ) ) {
|
2167 |
+
$formats[] = 'NULL';
|
2168 |
+
continue;
|
2169 |
+
}
|
2170 |
+
|
2171 |
+
$formats[] = $value['format'];
|
2172 |
+
$values[] = $value['value'];
|
2173 |
+
}
|
2174 |
+
|
2175 |
+
$fields = '`' . implode( '`, `', array_keys( $data ) ) . '`';
|
2176 |
+
$formats = implode( ', ', $formats );
|
2177 |
+
|
2178 |
+
$sql = "$type INTO `$table` ($fields) VALUES ($formats)";
|
2179 |
+
|
2180 |
+
$this->check_current_query = false;
|
2181 |
+
return $this->query( $this->prepare( $sql, $values ) );
|
2182 |
+
}
|
2183 |
+
|
2184 |
+
/**
|
2185 |
+
* Update a row in the table
|
2186 |
+
*
|
2187 |
+
* wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
|
2188 |
+
* wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
|
2189 |
+
*
|
2190 |
+
* @since 2.5.0
|
2191 |
+
* @see wpdb::prepare()
|
2192 |
+
* @see wpdb::$field_types
|
2193 |
+
* @see wp_set_wpdb_vars()
|
2194 |
+
*
|
2195 |
+
* @param string $table Table name
|
2196 |
+
* @param array $data Data to update (in column => value pairs).
|
2197 |
+
* Both $data columns and $data values should be "raw" (neither should be SQL escaped).
|
2198 |
+
* Sending a null value will cause the column to be set to NULL - the corresponding
|
2199 |
+
* format is ignored in this case.
|
2200 |
+
* @param array $where A named array of WHERE clauses (in column => value pairs).
|
2201 |
+
* Multiple clauses will be joined with ANDs.
|
2202 |
+
* Both $where columns and $where values should be "raw".
|
2203 |
+
* Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case.
|
2204 |
+
* @param array|string $format Optional. An array of formats to be mapped to each of the values in $data.
|
2205 |
+
* If string, that format will be used for all of the values in $data.
|
2206 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2207 |
+
* If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
|
2208 |
+
* @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
|
2209 |
+
* If string, that format will be used for all of the items in $where.
|
2210 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2211 |
+
* If omitted, all values in $where will be treated as strings.
|
2212 |
+
* @return int|false The number of rows updated, or false on error.
|
2213 |
+
*/
|
2214 |
+
public function update( $table, $data, $where, $format = null, $where_format = null ) {
|
2215 |
+
if ( ! is_array( $data ) || ! is_array( $where ) ) {
|
2216 |
+
return false;
|
2217 |
+
}
|
2218 |
+
|
2219 |
+
$data = $this->process_fields( $table, $data, $format );
|
2220 |
+
if ( false === $data ) {
|
2221 |
+
return false;
|
2222 |
+
}
|
2223 |
+
$where = $this->process_fields( $table, $where, $where_format );
|
2224 |
+
if ( false === $where ) {
|
2225 |
+
return false;
|
2226 |
+
}
|
2227 |
+
|
2228 |
+
$fields = $conditions = $values = array();
|
2229 |
+
foreach ( $data as $field => $value ) {
|
2230 |
+
if ( is_null( $value['value'] ) ) {
|
2231 |
+
$fields[] = "`$field` = NULL";
|
2232 |
+
continue;
|
2233 |
+
}
|
2234 |
+
|
2235 |
+
$fields[] = "`$field` = " . $value['format'];
|
2236 |
+
$values[] = $value['value'];
|
2237 |
+
}
|
2238 |
+
foreach ( $where as $field => $value ) {
|
2239 |
+
if ( is_null( $value['value'] ) ) {
|
2240 |
+
$conditions[] = "`$field` IS NULL";
|
2241 |
+
continue;
|
2242 |
+
}
|
2243 |
+
|
2244 |
+
$conditions[] = "`$field` = " . $value['format'];
|
2245 |
+
$values[] = $value['value'];
|
2246 |
+
}
|
2247 |
+
|
2248 |
+
$fields = implode( ', ', $fields );
|
2249 |
+
$conditions = implode( ' AND ', $conditions );
|
2250 |
+
|
2251 |
+
$sql = "UPDATE `$table` SET $fields WHERE $conditions";
|
2252 |
+
|
2253 |
+
$this->check_current_query = false;
|
2254 |
+
return $this->query( $this->prepare( $sql, $values ) );
|
2255 |
+
}
|
2256 |
+
|
2257 |
+
/**
|
2258 |
+
* Delete a row in the table
|
2259 |
+
*
|
2260 |
+
* wpdb::delete( 'table', array( 'ID' => 1 ) )
|
2261 |
+
* wpdb::delete( 'table', array( 'ID' => 1 ), array( '%d' ) )
|
2262 |
+
*
|
2263 |
+
* @since 3.4.0
|
2264 |
+
* @see wpdb::prepare()
|
2265 |
+
* @see wpdb::$field_types
|
2266 |
+
* @see wp_set_wpdb_vars()
|
2267 |
+
*
|
2268 |
+
* @param string $table Table name
|
2269 |
+
* @param array $where A named array of WHERE clauses (in column => value pairs).
|
2270 |
+
* Multiple clauses will be joined with ANDs.
|
2271 |
+
* Both $where columns and $where values should be "raw".
|
2272 |
+
* Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case.
|
2273 |
+
* @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
|
2274 |
+
* If string, that format will be used for all of the items in $where.
|
2275 |
+
* A format is one of '%d', '%f', '%s' (integer, float, string).
|
2276 |
+
* If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types.
|
2277 |
+
* @return int|false The number of rows updated, or false on error.
|
2278 |
+
*/
|
2279 |
+
public function delete( $table, $where, $where_format = null ) {
|
2280 |
+
if ( ! is_array( $where ) ) {
|
2281 |
+
return false;
|
2282 |
+
}
|
2283 |
+
|
2284 |
+
$where = $this->process_fields( $table, $where, $where_format );
|
2285 |
+
if ( false === $where ) {
|
2286 |
+
return false;
|
2287 |
+
}
|
2288 |
+
|
2289 |
+
$conditions = $values = array();
|
2290 |
+
foreach ( $where as $field => $value ) {
|
2291 |
+
if ( is_null( $value['value'] ) ) {
|
2292 |
+
$conditions[] = "`$field` IS NULL";
|
2293 |
+
continue;
|
2294 |
+
}
|
2295 |
+
|
2296 |
+
$conditions[] = "`$field` = " . $value['format'];
|
2297 |
+
$values[] = $value['value'];
|
2298 |
+
}
|
2299 |
+
|
2300 |
+
$conditions = implode( ' AND ', $conditions );
|
2301 |
+
|
2302 |
+
$sql = "DELETE FROM `$table` WHERE $conditions";
|
2303 |
+
|
2304 |
+
$this->check_current_query = false;
|
2305 |
+
return $this->query( $this->prepare( $sql, $values ) );
|
2306 |
+
}
|
2307 |
+
|
2308 |
+
/**
|
2309 |
+
* Processes arrays of field/value pairs and field formats.
|
2310 |
+
*
|
2311 |
+
* This is a helper method for wpdb's CRUD methods, which take field/value
|
2312 |
+
* pairs for inserts, updates, and where clauses. This method first pairs
|
2313 |
+
* each value with a format. Then it determines the charset of that field,
|
2314 |
+
* using that to determine if any invalid text would be stripped. If text is
|
2315 |
+
* stripped, then field processing is rejected and the query fails.
|
2316 |
+
*
|
2317 |
+
* @since 4.2.0
|
2318 |
+
*
|
2319 |
+
* @param string $table Table name.
|
2320 |
+
* @param array $data Field/value pair.
|
2321 |
+
* @param mixed $format Format for each field.
|
2322 |
+
* @return array|false Returns an array of fields that contain paired values
|
2323 |
+
* and formats. Returns false for invalid values.
|
2324 |
+
*/
|
2325 |
+
protected function process_fields( $table, $data, $format ) {
|
2326 |
+
$data = $this->process_field_formats( $data, $format );
|
2327 |
+
if ( false === $data ) {
|
2328 |
+
return false;
|
2329 |
+
}
|
2330 |
+
|
2331 |
+
$data = $this->process_field_charsets( $data, $table );
|
2332 |
+
if ( false === $data ) {
|
2333 |
+
return false;
|
2334 |
+
}
|
2335 |
+
|
2336 |
+
$data = $this->process_field_lengths( $data, $table );
|
2337 |
+
if ( false === $data ) {
|
2338 |
+
return false;
|
2339 |
+
}
|
2340 |
+
|
2341 |
+
$converted_data = $this->strip_invalid_text( $data );
|
2342 |
+
|
2343 |
+
if ( $data !== $converted_data ) {
|
2344 |
+
return false;
|
2345 |
+
}
|
2346 |
+
|
2347 |
+
return $data;
|
2348 |
+
}
|
2349 |
+
|
2350 |
+
/**
|
2351 |
+
* Prepares arrays of value/format pairs as passed to wpdb CRUD methods.
|
2352 |
+
*
|
2353 |
+
* @since 4.2.0
|
2354 |
+
*
|
2355 |
+
* @param array $data Array of fields to values.
|
2356 |
+
* @param mixed $format Formats to be mapped to the values in $data.
|
2357 |
+
* @return array Array, keyed by field names with values being an array
|
2358 |
+
* of 'value' and 'format' keys.
|
2359 |
+
*/
|
2360 |
+
protected function process_field_formats( $data, $format ) {
|
2361 |
+
$formats = $original_formats = (array) $format;
|
2362 |
+
|
2363 |
+
foreach ( $data as $field => $value ) {
|
2364 |
+
$value = array(
|
2365 |
+
'value' => $value,
|
2366 |
+
'format' => '%s',
|
2367 |
+
);
|
2368 |
+
|
2369 |
+
if ( ! empty( $format ) ) {
|
2370 |
+
$value['format'] = array_shift( $formats );
|
2371 |
+
if ( ! $value['format'] ) {
|
2372 |
+
$value['format'] = reset( $original_formats );
|
2373 |
+
}
|
2374 |
+
} elseif ( isset( $this->field_types[ $field ] ) ) {
|
2375 |
+
$value['format'] = $this->field_types[ $field ];
|
2376 |
+
}
|
2377 |
+
|
2378 |
+
$data[ $field ] = $value;
|
2379 |
+
}
|
2380 |
+
|
2381 |
+
return $data;
|
2382 |
+
}
|
2383 |
+
|
2384 |
+
/**
|
2385 |
+
* Adds field charsets to field/value/format arrays generated by
|
2386 |
+
* the wpdb::process_field_formats() method.
|
2387 |
+
*
|
2388 |
+
* @since 4.2.0
|
2389 |
+
*
|
2390 |
+
* @param array $data As it comes from the wpdb::process_field_formats() method.
|
2391 |
+
* @param string $table Table name.
|
2392 |
+
* @return array|false The same array as $data with additional 'charset' keys.
|
2393 |
+
*/
|
2394 |
+
protected function process_field_charsets( $data, $table ) {
|
2395 |
+
foreach ( $data as $field => $value ) {
|
2396 |
+
if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
|
2397 |
+
/*
|
2398 |
+
* We can skip this field if we know it isn't a string.
|
2399 |
+
* This checks %d/%f versus ! %s because its sprintf() could take more.
|
2400 |
+
*/
|
2401 |
+
$value['charset'] = false;
|
2402 |
+
} else {
|
2403 |
+
$value['charset'] = $this->get_col_charset( $table, $field );
|
2404 |
+
if ( is_wp_error( $value['charset'] ) ) {
|
2405 |
+
return false;
|
2406 |
+
}
|
2407 |
+
}
|
2408 |
+
|
2409 |
+
$data[ $field ] = $value;
|
2410 |
+
}
|
2411 |
+
|
2412 |
+
return $data;
|
2413 |
+
}
|
2414 |
+
|
2415 |
+
/**
|
2416 |
+
* For string fields, record the maximum string length that field can safely save.
|
2417 |
+
*
|
2418 |
+
* @since 4.2.1
|
2419 |
+
*
|
2420 |
+
* @param array $data As it comes from the wpdb::process_field_charsets() method.
|
2421 |
+
* @param string $table Table name.
|
2422 |
+
* @return array|false The same array as $data with additional 'length' keys, or false if
|
2423 |
+
* any of the values were too long for their corresponding field.
|
2424 |
+
*/
|
2425 |
+
protected function process_field_lengths( $data, $table ) {
|
2426 |
+
foreach ( $data as $field => $value ) {
|
2427 |
+
if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
|
2428 |
+
/*
|
2429 |
+
* We can skip this field if we know it isn't a string.
|
2430 |
+
* This checks %d/%f versus ! %s because its sprintf() could take more.
|
2431 |
+
*/
|
2432 |
+
$value['length'] = false;
|
2433 |
+
} else {
|
2434 |
+
$value['length'] = $this->get_col_length( $table, $field );
|
2435 |
+
if ( is_wp_error( $value['length'] ) ) {
|
2436 |
+
return false;
|
2437 |
+
}
|
2438 |
+
}
|
2439 |
+
|
2440 |
+
$data[ $field ] = $value;
|
2441 |
+
}
|
2442 |
+
|
2443 |
+
return $data;
|
2444 |
+
}
|
2445 |
+
|
2446 |
+
/**
|
2447 |
+
* Retrieve one variable from the database.
|
2448 |
+
*
|
2449 |
+
* Executes a SQL query and returns the value from the SQL result.
|
2450 |
+
* If the SQL result contains more than one column and/or more than one row, this function returns the value in the column and row specified.
|
2451 |
+
* If $query is null, this function returns the value in the specified column and row from the previous SQL result.
|
2452 |
+
*
|
2453 |
+
* @since 0.71
|
2454 |
+
*
|
2455 |
+
* @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
|
2456 |
+
* @param int $x Optional. Column of value to return. Indexed from 0.
|
2457 |
+
* @param int $y Optional. Row of value to return. Indexed from 0.
|
2458 |
+
* @return string|null Database query result (as string), or null on failure
|
2459 |
+
*/
|
2460 |
+
public function get_var( $query = null, $x = 0, $y = 0 ) {
|
2461 |
+
$this->func_call = "\$db->get_var(\"$query\", $x, $y)";
|
2462 |
+
|
2463 |
+
if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
|
2464 |
+
$this->check_current_query = false;
|
2465 |
+
}
|
2466 |
+
|
2467 |
+
if ( $query ) {
|
2468 |
+
$this->query( $query );
|
2469 |
+
}
|
2470 |
+
|
2471 |
+
// Extract var out of cached results based x,y vals
|
2472 |
+
if ( ! empty( $this->last_result[ $y ] ) ) {
|
2473 |
+
$values = array_values( get_object_vars( $this->last_result[ $y ] ) );
|
2474 |
+
}
|
2475 |
+
|
2476 |
+
// If there is a value return it else return null
|
2477 |
+
return ( isset( $values[ $x ] ) && $values[ $x ] !== '' ) ? $values[ $x ] : null;
|
2478 |
+
}
|
2479 |
+
|
2480 |
+
/**
|
2481 |
+
* Retrieve one row from the database.
|
2482 |
+
*
|
2483 |
+
* Executes a SQL query and returns the row from the SQL result.
|
2484 |
+
*
|
2485 |
+
* @since 0.71
|
2486 |
+
*
|
2487 |
+
* @param string|null $query SQL query.
|
2488 |
+
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
|
2489 |
+
* an stdClass object, an associative array, or a numeric array, respectively. Default OBJECT.
|
2490 |
+
* @param int $y Optional. Row to return. Indexed from 0.
|
2491 |
+
* @return array|object|null|void Database query result in format specified by $output or null on failure
|
2492 |
+
*/
|
2493 |
+
public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
|
2494 |
+
$this->func_call = "\$db->get_row(\"$query\",$output,$y)";
|
2495 |
+
|
2496 |
+
if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
|
2497 |
+
$this->check_current_query = false;
|
2498 |
+
}
|
2499 |
+
|
2500 |
+
if ( $query ) {
|
2501 |
+
$this->query( $query );
|
2502 |
+
} else {
|
2503 |
+
return null;
|
2504 |
+
}
|
2505 |
+
|
2506 |
+
if ( ! isset( $this->last_result[ $y ] ) ) {
|
2507 |
+
return null;
|
2508 |
+
}
|
2509 |
+
|
2510 |
+
if ( $output == OBJECT ) {
|
2511 |
+
return $this->last_result[ $y ] ? $this->last_result[ $y ] : null;
|
2512 |
+
} elseif ( $output == ARRAY_A ) {
|
2513 |
+
return $this->last_result[ $y ] ? get_object_vars( $this->last_result[ $y ] ) : null;
|
2514 |
+
} elseif ( $output == ARRAY_N ) {
|
2515 |
+
return $this->last_result[ $y ] ? array_values( get_object_vars( $this->last_result[ $y ] ) ) : null;
|
2516 |
+
} elseif ( strtoupper( $output ) === OBJECT ) {
|
2517 |
+
// Back compat for OBJECT being previously case insensitive.
|
2518 |
+
return $this->last_result[ $y ] ? $this->last_result[ $y ] : null;
|
2519 |
+
} else {
|
2520 |
+
$this->print_error( ' $db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N' );
|
2521 |
+
}
|
2522 |
+
}
|
2523 |
+
|
2524 |
+
/**
|
2525 |
+
* Retrieve one column from the database.
|
2526 |
+
*
|
2527 |
+
* Executes a SQL query and returns the column from the SQL result.
|
2528 |
+
* If the SQL result contains more than one column, this function returns the column specified.
|
2529 |
+
* If $query is null, this function returns the specified column from the previous SQL result.
|
2530 |
+
*
|
2531 |
+
* @since 0.71
|
2532 |
+
*
|
2533 |
+
* @param string|null $query Optional. SQL query. Defaults to previous query.
|
2534 |
+
* @param int $x Optional. Column to return. Indexed from 0.
|
2535 |
+
* @return array Database query result. Array indexed from 0 by SQL result row number.
|
2536 |
+
*/
|
2537 |
+
public function get_col( $query = null, $x = 0 ) {
|
2538 |
+
if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
|
2539 |
+
$this->check_current_query = false;
|
2540 |
+
}
|
2541 |
+
|
2542 |
+
if ( $query ) {
|
2543 |
+
$this->query( $query );
|
2544 |
+
}
|
2545 |
+
|
2546 |
+
$new_array = array();
|
2547 |
+
// Extract the column values
|
2548 |
+
if ( $this->last_result ) {
|
2549 |
+
for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
|
2550 |
+
$new_array[ $i ] = $this->get_var( null, $x, $i );
|
2551 |
+
}
|
2552 |
+
}
|
2553 |
+
return $new_array;
|
2554 |
+
}
|
2555 |
+
|
2556 |
+
/**
|
2557 |
+
* Retrieve an entire SQL result set from the database (i.e., many rows)
|
2558 |
+
*
|
2559 |
+
* Executes a SQL query and returns the entire SQL result.
|
2560 |
+
*
|
2561 |
+
* @since 0.71
|
2562 |
+
*
|
2563 |
+
* @param string $query SQL query.
|
2564 |
+
* @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
|
2565 |
+
* With one of the first three, return an array of rows indexed from 0 by SQL result row number.
|
2566 |
+
* Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively.
|
2567 |
+
* With OBJECT_K, return an associative array of row objects keyed by the value of each row's first column's value.
|
2568 |
+
* Duplicate keys are discarded.
|
2569 |
+
* @return array|object|null Database query results
|
2570 |
+
*/
|
2571 |
+
public function get_results( $query = null, $output = OBJECT ) {
|
2572 |
+
$this->func_call = "\$db->get_results(\"$query\", $output)";
|
2573 |
+
|
2574 |
+
if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
|
2575 |
+
$this->check_current_query = false;
|
2576 |
+
}
|
2577 |
+
|
2578 |
+
if ( $query ) {
|
2579 |
+
$this->query( $query );
|
2580 |
+
} else {
|
2581 |
+
return null;
|
2582 |
+
}
|
2583 |
+
|
2584 |
+
$new_array = array();
|
2585 |
+
if ( $output == OBJECT ) {
|
2586 |
+
// Return an integer-keyed array of row objects
|
2587 |
+
return $this->last_result;
|
2588 |
+
} elseif ( $output == OBJECT_K ) {
|
2589 |
+
// Return an array of row objects with keys from column 1
|
2590 |
+
// (Duplicates are discarded)
|
2591 |
+
if ( $this->last_result ) {
|
2592 |
+
foreach ( $this->last_result as $row ) {
|
2593 |
+
$var_by_ref = get_object_vars( $row );
|
2594 |
+
$key = array_shift( $var_by_ref );
|
2595 |
+
if ( ! isset( $new_array[ $key ] ) ) {
|
2596 |
+
$new_array[ $key ] = $row;
|
2597 |
+
}
|
2598 |
+
}
|
2599 |
+
}
|
2600 |
+
return $new_array;
|
2601 |
+
} elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
|
2602 |
+
// Return an integer-keyed array of...
|
2603 |
+
if ( $this->last_result ) {
|
2604 |
+
foreach ( (array) $this->last_result as $row ) {
|
2605 |
+
if ( $output == ARRAY_N ) {
|
2606 |
+
// ...integer-keyed row arrays
|
2607 |
+
$new_array[] = array_values( get_object_vars( $row ) );
|
2608 |
+
} else {
|
2609 |
+
// ...column name-keyed row arrays
|
2610 |
+
$new_array[] = get_object_vars( $row );
|
2611 |
+
}
|
2612 |
+
}
|
2613 |
+
}
|
2614 |
+
return $new_array;
|
2615 |
+
} elseif ( strtoupper( $output ) === OBJECT ) {
|
2616 |
+
// Back compat for OBJECT being previously case insensitive.
|
2617 |
+
return $this->last_result;
|
2618 |
+
}
|
2619 |
+
return null;
|
2620 |
+
}
|
2621 |
+
|
2622 |
+
/**
|
2623 |
+
* Retrieves the character set for the given table.
|
2624 |
+
*
|
2625 |
+
* @since 4.2.0
|
2626 |
+
*
|
2627 |
+
* @param string $table Table name.
|
2628 |
+
* @return string|WP_Error Table character set, WP_Error object if it couldn't be found.
|
2629 |
+
*/
|
2630 |
+
protected function get_table_charset( $table ) {
|
2631 |
+
$tablekey = strtolower( $table );
|
2632 |
+
|
2633 |
+
/**
|
2634 |
+
* Filters the table charset value before the DB is checked.
|
2635 |
+
*
|
2636 |
+
* Passing a non-null value to the filter will effectively short-circuit
|
2637 |
+
* checking the DB for the charset, returning that value instead.
|
2638 |
+
*
|
2639 |
+
* @since 4.2.0
|
2640 |
+
*
|
2641 |
+
* @param string $charset The character set to use. Default null.
|
2642 |
+
* @param string $table The name of the table being checked.
|
2643 |
+
*/
|
2644 |
+
$charset = apply_filters( 'pre_get_table_charset', null, $table );
|
2645 |
+
if ( null !== $charset ) {
|
2646 |
+
return $charset;
|
2647 |
+
}
|
2648 |
+
|
2649 |
+
if ( isset( $this->table_charset[ $tablekey ] ) ) {
|
2650 |
+
return $this->table_charset[ $tablekey ];
|
2651 |
+
}
|
2652 |
+
|
2653 |
+
$charsets = $columns = array();
|
2654 |
+
|
2655 |
+
$table_parts = explode( '.', $table );
|
2656 |
+
$table = '`' . implode( '`.`', $table_parts ) . '`';
|
2657 |
+
$results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
|
2658 |
+
if ( ! $results ) {
|
2659 |
+
return new WP_Error( 'wpdb_get_table_charset_failure' );
|
2660 |
+
}
|
2661 |
+
|
2662 |
+
foreach ( $results as $column ) {
|
2663 |
+
$columns[ strtolower( $column->Field ) ] = $column;
|
2664 |
+
}
|
2665 |
+
|
2666 |
+
$this->col_meta[ $tablekey ] = $columns;
|
2667 |
+
|
2668 |
+
foreach ( $columns as $column ) {
|
2669 |
+
if ( ! empty( $column->Collation ) ) {
|
2670 |
+
list( $charset ) = explode( '_', $column->Collation );
|
2671 |
+
|
2672 |
+
// If the current connection can't support utf8mb4 characters, let's only send 3-byte utf8 characters.
|
2673 |
+
if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
|
2674 |
+
$charset = 'utf8';
|
2675 |
+
}
|
2676 |
+
|
2677 |
+
$charsets[ strtolower( $charset ) ] = true;
|
2678 |
+
}
|
2679 |
+
|
2680 |
+
list( $type ) = explode( '(', $column->Type );
|
2681 |
+
|
2682 |
+
// A binary/blob means the whole query gets treated like this.
|
2683 |
+
if ( in_array( strtoupper( $type ), array( 'BINARY', 'VARBINARY', 'TINYBLOB', 'MEDIUMBLOB', 'BLOB', 'LONGBLOB' ) ) ) {
|
2684 |
+
$this->table_charset[ $tablekey ] = 'binary';
|
2685 |
+
return 'binary';
|
2686 |
+
}
|
2687 |
+
}
|
2688 |
+
|
2689 |
+
// utf8mb3 is an alias for utf8.
|
2690 |
+
if ( isset( $charsets['utf8mb3'] ) ) {
|
2691 |
+
$charsets['utf8'] = true;
|
2692 |
+
unset( $charsets['utf8mb3'] );
|
2693 |
+
}
|
2694 |
+
|
2695 |
+
// Check if we have more than one charset in play.
|
2696 |
+
$count = count( $charsets );
|
2697 |
+
if ( 1 === $count ) {
|
2698 |
+
$charset = key( $charsets );
|
2699 |
+
} elseif ( 0 === $count ) {
|
2700 |
+
// No charsets, assume this table can store whatever.
|
2701 |
+
$charset = false;
|
2702 |
+
} else {
|
2703 |
+
// More than one charset. Remove latin1 if present and recalculate.
|
2704 |
+
unset( $charsets['latin1'] );
|
2705 |
+
$count = count( $charsets );
|
2706 |
+
if ( 1 === $count ) {
|
2707 |
+
// Only one charset (besides latin1).
|
2708 |
+
$charset = key( $charsets );
|
2709 |
+
} elseif ( 2 === $count && isset( $charsets['utf8'], $charsets['utf8mb4'] ) ) {
|
2710 |
+
// Two charsets, but they're utf8 and utf8mb4, use utf8.
|
2711 |
+
$charset = 'utf8';
|
2712 |
+
} else {
|
2713 |
+
// Two mixed character sets. ascii.
|
2714 |
+
$charset = 'ascii';
|
2715 |
+
}
|
2716 |
+
}
|
2717 |
+
|
2718 |
+
$this->table_charset[ $tablekey ] = $charset;
|
2719 |
+
return $charset;
|
2720 |
+
}
|
2721 |
+
|
2722 |
+
/**
|
2723 |
+
* Retrieves the character set for the given column.
|
2724 |
+
*
|
2725 |
+
* @since 4.2.0
|
2726 |
+
*
|
2727 |
+
* @param string $table Table name.
|
2728 |
+
* @param string $column Column name.
|
2729 |
+
* @return string|false|WP_Error Column character set as a string. False if the column has no
|
2730 |
+
* character set. WP_Error object if there was an error.
|
2731 |
+
*/
|
2732 |
+
public function get_col_charset( $table, $column ) {
|
2733 |
+
$tablekey = strtolower( $table );
|
2734 |
+
$columnkey = strtolower( $column );
|
2735 |
+
|
2736 |
+
/**
|
2737 |
+
* Filters the column charset value before the DB is checked.
|
2738 |
+
*
|
2739 |
+
* Passing a non-null value to the filter will short-circuit
|
2740 |
+
* checking the DB for the charset, returning that value instead.
|
2741 |
+
*
|
2742 |
+
* @since 4.2.0
|
2743 |
+
*
|
2744 |
+
* @param string $charset The character set to use. Default null.
|
2745 |
+
* @param string $table The name of the table being checked.
|
2746 |
+
* @param string $column The name of the column being checked.
|
2747 |
+
*/
|
2748 |
+
$charset = apply_filters( 'pre_get_col_charset', null, $table, $column );
|
2749 |
+
if ( null !== $charset ) {
|
2750 |
+
return $charset;
|
2751 |
+
}
|
2752 |
+
|
2753 |
+
// Skip this entirely if this isn't a MySQL database.
|
2754 |
+
if ( empty( $this->is_mysql ) ) {
|
2755 |
+
return false;
|
2756 |
+
}
|
2757 |
+
|
2758 |
+
if ( empty( $this->table_charset[ $tablekey ] ) ) {
|
2759 |
+
// This primes column information for us.
|
2760 |
+
$table_charset = $this->get_table_charset( $table );
|
2761 |
+
if ( is_wp_error( $table_charset ) ) {
|
2762 |
+
return $table_charset;
|
2763 |
+
}
|
2764 |
+
}
|
2765 |
+
|
2766 |
+
// If still no column information, return the table charset.
|
2767 |
+
if ( empty( $this->col_meta[ $tablekey ] ) ) {
|
2768 |
+
return $this->table_charset[ $tablekey ];
|
2769 |
+
}
|
2770 |
+
|
2771 |
+
// If this column doesn't exist, return the table charset.
|
2772 |
+
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
|
2773 |
+
return $this->table_charset[ $tablekey ];
|
2774 |
+
}
|
2775 |
+
|
2776 |
+
// Return false when it's not a string column.
|
2777 |
+
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ]->Collation ) ) {
|
2778 |
+
return false;
|
2779 |
+
}
|
2780 |
+
|
2781 |
+
list( $charset ) = explode( '_', $this->col_meta[ $tablekey ][ $columnkey ]->Collation );
|
2782 |
+
return $charset;
|
2783 |
+
}
|
2784 |
+
|
2785 |
+
/**
|
2786 |
+
* Retrieve the maximum string length allowed in a given column.
|
2787 |
+
* The length may either be specified as a byte length or a character length.
|
2788 |
+
*
|
2789 |
+
* @since 4.2.1
|
2790 |
+
*
|
2791 |
+
* @param string $table Table name.
|
2792 |
+
* @param string $column Column name.
|
2793 |
+
* @return array|false|WP_Error array( 'length' => (int), 'type' => 'byte' | 'char' )
|
2794 |
+
* false if the column has no length (for example, numeric column)
|
2795 |
+
* WP_Error object if there was an error.
|
2796 |
+
*/
|
2797 |
+
public function get_col_length( $table, $column ) {
|
2798 |
+
$tablekey = strtolower( $table );
|
2799 |
+
$columnkey = strtolower( $column );
|
2800 |
+
|
2801 |
+
// Skip this entirely if this isn't a MySQL database.
|
2802 |
+
if ( empty( $this->is_mysql ) ) {
|
2803 |
+
return false;
|
2804 |
+
}
|
2805 |
+
|
2806 |
+
if ( empty( $this->col_meta[ $tablekey ] ) ) {
|
2807 |
+
// This primes column information for us.
|
2808 |
+
$table_charset = $this->get_table_charset( $table );
|
2809 |
+
if ( is_wp_error( $table_charset ) ) {
|
2810 |
+
return $table_charset;
|
2811 |
+
}
|
2812 |
+
}
|
2813 |
+
|
2814 |
+
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
|
2815 |
+
return false;
|
2816 |
+
}
|
2817 |
+
|
2818 |
+
$typeinfo = explode( '(', $this->col_meta[ $tablekey ][ $columnkey ]->Type );
|
2819 |
+
|
2820 |
+
$type = strtolower( $typeinfo[0] );
|
2821 |
+
if ( ! empty( $typeinfo[1] ) ) {
|
2822 |
+
$length = trim( $typeinfo[1], ')' );
|
2823 |
+
} else {
|
2824 |
+
$length = false;
|
2825 |
+
}
|
2826 |
+
|
2827 |
+
switch ( $type ) {
|
2828 |
+
case 'char':
|
2829 |
+
case 'varchar':
|
2830 |
+
return array(
|
2831 |
+
'type' => 'char',
|
2832 |
+
'length' => (int) $length,
|
2833 |
+
);
|
2834 |
+
|
2835 |
+
case 'binary':
|
2836 |
+
case 'varbinary':
|
2837 |
+
return array(
|
2838 |
+
'type' => 'byte',
|
2839 |
+
'length' => (int) $length,
|
2840 |
+
);
|
2841 |
+
|
2842 |
+
case 'tinyblob':
|
2843 |
+
case 'tinytext':
|
2844 |
+
return array(
|
2845 |
+
'type' => 'byte',
|
2846 |
+
'length' => 255, // 2^8 - 1
|
2847 |
+
);
|
2848 |
+
|
2849 |
+
case 'blob':
|
2850 |
+
case 'text':
|
2851 |
+
return array(
|
2852 |
+
'type' => 'byte',
|
2853 |
+
'length' => 65535, // 2^16 - 1
|
2854 |
+
);
|
2855 |
+
|
2856 |
+
case 'mediumblob':
|
2857 |
+
case 'mediumtext':
|
2858 |
+
return array(
|
2859 |
+
'type' => 'byte',
|
2860 |
+
'length' => 16777215, // 2^24 - 1
|
2861 |
+
);
|
2862 |
+
|
2863 |
+
case 'longblob':
|
2864 |
+
case 'longtext':
|
2865 |
+
return array(
|
2866 |
+
'type' => 'byte',
|
2867 |
+
'length' => 4294967295, // 2^32 - 1
|
2868 |
+
);
|
2869 |
+
|
2870 |
+
default:
|
2871 |
+
return false;
|
2872 |
+
}
|
2873 |
+
}
|
2874 |
+
|
2875 |
+
/**
|
2876 |
+
* Check if a string is ASCII.
|
2877 |
+
*
|
2878 |
+
* The negative regex is faster for non-ASCII strings, as it allows
|
2879 |
+
* the search to finish as soon as it encounters a non-ASCII character.
|
2880 |
+
*
|
2881 |
+
* @since 4.2.0
|
2882 |
+
*
|
2883 |
+
* @param string $string String to check.
|
2884 |
+
* @return bool True if ASCII, false if not.
|
2885 |
+
*/
|
2886 |
+
protected function check_ascii( $string ) {
|
2887 |
+
if ( function_exists( 'mb_check_encoding' ) ) {
|
2888 |
+
if ( mb_check_encoding( $string, 'ASCII' ) ) {
|
2889 |
+
return true;
|
2890 |
+
}
|
2891 |
+
} elseif ( ! preg_match( '/[^\x00-\x7F]/', $string ) ) {
|
2892 |
+
return true;
|
2893 |
+
}
|
2894 |
+
|
2895 |
+
return false;
|
2896 |
+
}
|
2897 |
+
|
2898 |
+
/**
|
2899 |
+
* Check if the query is accessing a collation considered safe on the current version of MySQL.
|
2900 |
+
*
|
2901 |
+
* @since 4.2.0
|
2902 |
+
*
|
2903 |
+
* @param string $query The query to check.
|
2904 |
+
* @return bool True if the collation is safe, false if it isn't.
|
2905 |
+
*/
|
2906 |
+
protected function check_safe_collation( $query ) {
|
2907 |
+
if ( $this->checking_collation ) {
|
2908 |
+
return true;
|
2909 |
+
}
|
2910 |
+
|
2911 |
+
// We don't need to check the collation for queries that don't read data.
|
2912 |
+
$query = ltrim( $query, "\r\n\t (" );
|
2913 |
+
if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $query ) ) {
|
2914 |
+
return true;
|
2915 |
+
}
|
2916 |
+
|
2917 |
+
// All-ASCII queries don't need extra checking.
|
2918 |
+
if ( $this->check_ascii( $query ) ) {
|
2919 |
+
return true;
|
2920 |
+
}
|
2921 |
+
|
2922 |
+
$table = $this->get_table_from_query( $query );
|
2923 |
+
if ( ! $table ) {
|
2924 |
+
return false;
|
2925 |
+
}
|
2926 |
+
|
2927 |
+
$this->checking_collation = true;
|
2928 |
+
$collation = $this->get_table_charset( $table );
|
2929 |
+
$this->checking_collation = false;
|
2930 |
+
|
2931 |
+
// Tables with no collation, or latin1 only, don't need extra checking.
|
2932 |
+
if ( false === $collation || 'latin1' === $collation ) {
|
2933 |
+
return true;
|
2934 |
+
}
|
2935 |
+
|
2936 |
+
$table = strtolower( $table );
|
2937 |
+
if ( empty( $this->col_meta[ $table ] ) ) {
|
2938 |
+
return false;
|
2939 |
+
}
|
2940 |
+
|
2941 |
+
// If any of the columns don't have one of these collations, it needs more sanity checking.
|
2942 |
+
foreach ( $this->col_meta[ $table ] as $col ) {
|
2943 |
+
if ( empty( $col->Collation ) ) {
|
2944 |
+
continue;
|
2945 |
+
}
|
2946 |
+
|
2947 |
+
if ( ! in_array( $col->Collation, array( 'utf8_general_ci', 'utf8_bin', 'utf8mb4_general_ci', 'utf8mb4_bin' ), true ) ) {
|
2948 |
+
return false;
|
2949 |
+
}
|
2950 |
+
}
|
2951 |
+
|
2952 |
+
return true;
|
2953 |
+
}
|
2954 |
+
|
2955 |
+
/**
|
2956 |
+
* Strips any invalid characters based on value/charset pairs.
|
2957 |
+
*
|
2958 |
+
* @since 4.2.0
|
2959 |
+
*
|
2960 |
+
* @param array $data Array of value arrays. Each value array has the keys
|
2961 |
+
* 'value' and 'charset'. An optional 'ascii' key can be
|
2962 |
+
* set to false to avoid redundant ASCII checks.
|
2963 |
+
* @return array|WP_Error The $data parameter, with invalid characters removed from
|
2964 |
+
* each value. This works as a passthrough: any additional keys
|
2965 |
+
* such as 'field' are retained in each value array. If we cannot
|
2966 |
+
* remove invalid characters, a WP_Error object is returned.
|
2967 |
+
*/
|
2968 |
+
protected function strip_invalid_text( $data ) {
|
2969 |
+
$db_check_string = false;
|
2970 |
+
|
2971 |
+
foreach ( $data as &$value ) {
|
2972 |
+
$charset = $value['charset'];
|
2973 |
+
|
2974 |
+
if ( is_array( $value['length'] ) ) {
|
2975 |
+
$length = $value['length']['length'];
|
2976 |
+
$truncate_by_byte_length = 'byte' === $value['length']['type'];
|
2977 |
+
} else {
|
2978 |
+
$length = false;
|
2979 |
+
// Since we have no length, we'll never truncate.
|
2980 |
+
// Initialize the variable to false. true would take us
|
2981 |
+
// through an unnecessary (for this case) codepath below.
|
2982 |
+
$truncate_by_byte_length = false;
|
2983 |
+
}
|
2984 |
+
|
2985 |
+
// There's no charset to work with.
|
2986 |
+
if ( false === $charset ) {
|
2987 |
+
continue;
|
2988 |
+
}
|
2989 |
+
|
2990 |
+
// Column isn't a string.
|
2991 |
+
if ( ! is_string( $value['value'] ) ) {
|
2992 |
+
continue;
|
2993 |
+
}
|
2994 |
+
|
2995 |
+
$needs_validation = true;
|
2996 |
+
if (
|
2997 |
+
// latin1 can store any byte sequence
|
2998 |
+
'latin1' === $charset
|
2999 |
+
||
|
3000 |
+
// ASCII is always OK.
|
3001 |
+
( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) )
|
3002 |
+
) {
|
3003 |
+
$truncate_by_byte_length = true;
|
3004 |
+
$needs_validation = false;
|
3005 |
+
}
|
3006 |
+
|
3007 |
+
if ( $truncate_by_byte_length ) {
|
3008 |
+
mbstring_binary_safe_encoding();
|
3009 |
+
if ( false !== $length && strlen( $value['value'] ) > $length ) {
|
3010 |
+
$value['value'] = substr( $value['value'], 0, $length );
|
3011 |
+
}
|
3012 |
+
reset_mbstring_encoding();
|
3013 |
+
|
3014 |
+
if ( ! $needs_validation ) {
|
3015 |
+
continue;
|
3016 |
+
}
|
3017 |
+
}
|
3018 |
+
|
3019 |
+
// utf8 can be handled by regex, which is a bunch faster than a DB lookup.
|
3020 |
+
if ( ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) && function_exists( 'mb_strlen' ) ) {
|
3021 |
+
$regex = '/
|
3022 |
+
(
|
3023 |
+
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
|
3024 |
+
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
|
3025 |
+
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
|
3026 |
+
| [\xE1-\xEC][\x80-\xBF]{2}
|
3027 |
+
| \xED[\x80-\x9F][\x80-\xBF]
|
3028 |
+
| [\xEE-\xEF][\x80-\xBF]{2}';
|
3029 |
+
|
3030 |
+
if ( 'utf8mb4' === $charset ) {
|
3031 |
+
$regex .= '
|
3032 |
+
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
|
3033 |
+
| [\xF1-\xF3][\x80-\xBF]{3}
|
3034 |
+
| \xF4[\x80-\x8F][\x80-\xBF]{2}
|
3035 |
+
';
|
3036 |
+
}
|
3037 |
+
|
3038 |
+
$regex .= '){1,40} # ...one or more times
|
3039 |
+
)
|
3040 |
+
| . # anything else
|
3041 |
+
/x';
|
3042 |
+
$value['value'] = preg_replace( $regex, '$1', $value['value'] );
|
3043 |
+
|
3044 |
+
if ( false !== $length && mb_strlen( $value['value'], 'UTF-8' ) > $length ) {
|
3045 |
+
$value['value'] = mb_substr( $value['value'], 0, $length, 'UTF-8' );
|
3046 |
+
}
|
3047 |
+
continue;
|
3048 |
+
}
|
3049 |
+
|
3050 |
+
// We couldn't use any local conversions, send it to the DB.
|
3051 |
+
$value['db'] = $db_check_string = true;
|
3052 |
+
}
|
3053 |
+
unset( $value ); // Remove by reference.
|
3054 |
+
|
3055 |
+
if ( $db_check_string ) {
|
3056 |
+
$queries = array();
|
3057 |
+
foreach ( $data as $col => $value ) {
|
3058 |
+
if ( ! empty( $value['db'] ) ) {
|
3059 |
+
// We're going to need to truncate by characters or bytes, depending on the length value we have.
|
3060 |
+
if ( 'byte' === $value['length']['type'] ) {
|
3061 |
+
// Using binary causes LEFT() to truncate by bytes.
|
3062 |
+
$charset = 'binary';
|
3063 |
+
} else {
|
3064 |
+
$charset = $value['charset'];
|
3065 |
+
}
|
3066 |
+
|
3067 |
+
if ( $this->charset ) {
|
3068 |
+
$connection_charset = $this->charset;
|
3069 |
+
} else {
|
3070 |
+
if ( $this->use_mysqli ) {
|
3071 |
+
$connection_charset = mysqli_character_set_name( $this->dbh );
|
3072 |
+
} else {
|
3073 |
+
$connection_charset = mysql_client_encoding();
|
3074 |
+
}
|
3075 |
+
}
|
3076 |
+
|
3077 |
+
if ( is_array( $value['length'] ) ) {
|
3078 |
+
$length = sprintf( '%.0f', $value['length']['length'] );
|
3079 |
+
$queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), $length ) USING $connection_charset )", $value['value'] );
|
3080 |
+
} elseif ( 'binary' !== $charset ) {
|
3081 |
+
// If we don't have a length, there's no need to convert binary - it will always return the same result.
|
3082 |
+
$queries[ $col ] = $this->prepare( "CONVERT( CONVERT( %s USING $charset ) USING $connection_charset )", $value['value'] );
|
3083 |
+
}
|
3084 |
+
|
3085 |
+
unset( $data[ $col ]['db'] );
|
3086 |
+
}
|
3087 |
+
}
|
3088 |
+
|
3089 |
+
$sql = array();
|
3090 |
+
foreach ( $queries as $column => $query ) {
|
3091 |
+
if ( ! $query ) {
|
3092 |
+
continue;
|
3093 |
+
}
|
3094 |
+
|
3095 |
+
$sql[] = $query . " AS x_$column";
|
3096 |
+
}
|
3097 |
+
|
3098 |
+
$this->check_current_query = false;
|
3099 |
+
$row = $this->get_row( 'SELECT ' . implode( ', ', $sql ), ARRAY_A );
|
3100 |
+
if ( ! $row ) {
|
3101 |
+
return new WP_Error( 'wpdb_strip_invalid_text_failure' );
|
3102 |
+
}
|
3103 |
+
|
3104 |
+
foreach ( array_keys( $data ) as $column ) {
|
3105 |
+
if ( isset( $row[ "x_$column" ] ) ) {
|
3106 |
+
$data[ $column ]['value'] = $row[ "x_$column" ];
|
3107 |
+
}
|
3108 |
+
}
|
3109 |
+
}
|
3110 |
+
|
3111 |
+
return $data;
|
3112 |
+
}
|
3113 |
+
|
3114 |
+
/**
|
3115 |
+
* Strips any invalid characters from the query.
|
3116 |
+
*
|
3117 |
+
* @since 4.2.0
|
3118 |
+
*
|
3119 |
+
* @param string $query Query to convert.
|
3120 |
+
* @return string|WP_Error The converted query, or a WP_Error object if the conversion fails.
|
3121 |
+
*/
|
3122 |
+
protected function strip_invalid_text_from_query( $query ) {
|
3123 |
+
// We don't need to check the collation for queries that don't read data.
|
3124 |
+
$trimmed_query = ltrim( $query, "\r\n\t (" );
|
3125 |
+
if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $trimmed_query ) ) {
|
3126 |
+
return $query;
|
3127 |
+
}
|
3128 |
+
|
3129 |
+
$table = $this->get_table_from_query( $query );
|
3130 |
+
if ( $table ) {
|
3131 |
+
$charset = $this->get_table_charset( $table );
|
3132 |
+
if ( is_wp_error( $charset ) ) {
|
3133 |
+
return $charset;
|
3134 |
+
}
|
3135 |
+
|
3136 |
+
// We can't reliably strip text from tables containing binary/blob columns
|
3137 |
+
if ( 'binary' === $charset ) {
|
3138 |
+
return $query;
|
3139 |
+
}
|
3140 |
+
} else {
|
3141 |
+
$charset = $this->charset;
|
3142 |
+
}
|
3143 |
+
|
3144 |
+
$data = array(
|
3145 |
+
'value' => $query,
|
3146 |
+
'charset' => $charset,
|
3147 |
+
'ascii' => false,
|
3148 |
+
'length' => false,
|
3149 |
+
);
|
3150 |
+
|
3151 |
+
$data = $this->strip_invalid_text( array( $data ) );
|
3152 |
+
if ( is_wp_error( $data ) ) {
|
3153 |
+
return $data;
|
3154 |
+
}
|
3155 |
+
|
3156 |
+
return $data[0]['value'];
|
3157 |
+
}
|
3158 |
+
|
3159 |
+
/**
|
3160 |
+
* Strips any invalid characters from the string for a given table and column.
|
3161 |
+
*
|
3162 |
+
* @since 4.2.0
|
3163 |
+
*
|
3164 |
+
* @param string $table Table name.
|
3165 |
+
* @param string $column Column name.
|
3166 |
+
* @param string $value The text to check.
|
3167 |
+
* @return string|WP_Error The converted string, or a WP_Error object if the conversion fails.
|
3168 |
+
*/
|
3169 |
+
public function strip_invalid_text_for_column( $table, $column, $value ) {
|
3170 |
+
if ( ! is_string( $value ) ) {
|
3171 |
+
return $value;
|
3172 |
+
}
|
3173 |
+
|
3174 |
+
$charset = $this->get_col_charset( $table, $column );
|
3175 |
+
if ( ! $charset ) {
|
3176 |
+
// Not a string column.
|
3177 |
+
return $value;
|
3178 |
+
} elseif ( is_wp_error( $charset ) ) {
|
3179 |
+
// Bail on real errors.
|
3180 |
+
return $charset;
|
3181 |
+
}
|
3182 |
+
|
3183 |
+
$data = array(
|
3184 |
+
$column => array(
|
3185 |
+
'value' => $value,
|
3186 |
+
'charset' => $charset,
|
3187 |
+
'length' => $this->get_col_length( $table, $column ),
|
3188 |
+
),
|
3189 |
+
);
|
3190 |
+
|
3191 |
+
$data = $this->strip_invalid_text( $data );
|
3192 |
+
if ( is_wp_error( $data ) ) {
|
3193 |
+
return $data;
|
3194 |
+
}
|
3195 |
+
|
3196 |
+
return $data[ $column ]['value'];
|
3197 |
+
}
|
3198 |
+
|
3199 |
+
/**
|
3200 |
+
* Find the first table name referenced in a query.
|
3201 |
+
*
|
3202 |
+
* @since 4.2.0
|
3203 |
+
*
|
3204 |
+
* @param string $query The query to search.
|
3205 |
+
* @return string|false $table The table name found, or false if a table couldn't be found.
|
3206 |
+
*/
|
3207 |
+
protected function get_table_from_query( $query ) {
|
3208 |
+
// Remove characters that can legally trail the table name.
|
3209 |
+
$query = rtrim( $query, ';/-#' );
|
3210 |
+
|
3211 |
+
// Allow (select...) union [...] style queries. Use the first query's table name.
|
3212 |
+
$query = ltrim( $query, "\r\n\t (" );
|
3213 |
+
|
3214 |
+
// Strip everything between parentheses except nested selects.
|
3215 |
+
$query = preg_replace( '/\((?!\s*select)[^(]*?\)/is', '()', $query );
|
3216 |
+
|
3217 |
+
// Quickly match most common queries.
|
3218 |
+
if ( preg_match(
|
3219 |
+
'/^\s*(?:'
|
3220 |
+
. 'SELECT.*?\s+FROM'
|
3221 |
+
. '|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?'
|
3222 |
+
. '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?'
|
3223 |
+
. '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?'
|
3224 |
+
. '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:.+?FROM)?'
|
3225 |
+
. ')\s+((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)/is',
|
3226 |
+
$query,
|
3227 |
+
$maybe
|
3228 |
+
) ) {
|
3229 |
+
return str_replace( '`', '', $maybe[1] );
|
3230 |
+
}
|
3231 |
+
|
3232 |
+
// SHOW TABLE STATUS and SHOW TABLES WHERE Name = 'wp_posts'
|
3233 |
+
if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES).+WHERE\s+Name\s*=\s*("|\')((?:[0-9a-zA-Z$_.-]|[\xC2-\xDF][\x80-\xBF])+)\\1/is', $query, $maybe ) ) {
|
3234 |
+
return $maybe[2];
|
3235 |
+
}
|
3236 |
+
|
3237 |
+
// SHOW TABLE STATUS LIKE and SHOW TABLES LIKE 'wp\_123\_%'
|
3238 |
+
// This quoted LIKE operand seldom holds a full table name.
|
3239 |
+
// It is usually a pattern for matching a prefix so we just
|
3240 |
+
// strip the trailing % and unescape the _ to get 'wp_123_'
|
3241 |
+
// which drop-ins can use for routing these SQL statements.
|
3242 |
+
if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES)\s+(?:WHERE\s+Name\s+)?LIKE\s*("|\')((?:[\\\\0-9a-zA-Z$_.-]|[\xC2-\xDF][\x80-\xBF])+)%?\\1/is', $query, $maybe ) ) {
|
3243 |
+
return str_replace( '\\_', '_', $maybe[2] );
|
3244 |
+
}
|
3245 |
+
|
3246 |
+
// Big pattern for the rest of the table-related queries.
|
3247 |
+
if ( preg_match(
|
3248 |
+
'/^\s*(?:'
|
3249 |
+
. '(?:EXPLAIN\s+(?:EXTENDED\s+)?)?SELECT.*?\s+FROM'
|
3250 |
+
. '|DESCRIBE|DESC|EXPLAIN|HANDLER'
|
3251 |
+
. '|(?:LOCK|UNLOCK)\s+TABLE(?:S)?'
|
3252 |
+
. '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|REPAIR).*\s+TABLE'
|
3253 |
+
. '|TRUNCATE(?:\s+TABLE)?'
|
3254 |
+
. '|CREATE(?:\s+TEMPORARY)?\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?'
|
3255 |
+
. '|ALTER(?:\s+IGNORE)?\s+TABLE'
|
3256 |
+
. '|DROP\s+TABLE(?:\s+IF\s+EXISTS)?'
|
3257 |
+
. '|CREATE(?:\s+\w+)?\s+INDEX.*\s+ON'
|
3258 |
+
. '|DROP\s+INDEX.*\s+ON'
|
3259 |
+
. '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE'
|
3260 |
+
. '|(?:GRANT|REVOKE).*ON\s+TABLE'
|
3261 |
+
. '|SHOW\s+(?:.*FROM|.*TABLE)'
|
3262 |
+
. ')\s+\(*\s*((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)\s*\)*/is',
|
3263 |
+
$query,
|
3264 |
+
$maybe
|
3265 |
+
) ) {
|
3266 |
+
return str_replace( '`', '', $maybe[1] );
|
3267 |
+
}
|
3268 |
+
|
3269 |
+
return false;
|
3270 |
+
}
|
3271 |
+
|
3272 |
+
/**
|
3273 |
+
* Load the column metadata from the last query.
|
3274 |
+
*
|
3275 |
+
* @since 3.5.0
|
3276 |
+
*/
|
3277 |
+
protected function load_col_info() {
|
3278 |
+
if ( $this->col_info ) {
|
3279 |
+
return;
|
3280 |
+
}
|
3281 |
+
|
3282 |
+
if ( $this->use_mysqli ) {
|
3283 |
+
$num_fields = mysqli_num_fields( $this->result );
|
3284 |
+
for ( $i = 0; $i < $num_fields; $i++ ) {
|
3285 |
+
$this->col_info[ $i ] = mysqli_fetch_field( $this->result );
|
3286 |
+
}
|
3287 |
+
} else {
|
3288 |
+
$num_fields = mysql_num_fields( $this->result );
|
3289 |
+
for ( $i = 0; $i < $num_fields; $i++ ) {
|
3290 |
+
$this->col_info[ $i ] = mysql_fetch_field( $this->result, $i );
|
3291 |
+
}
|
3292 |
+
}
|
3293 |
+
}
|
3294 |
+
|
3295 |
+
/**
|
3296 |
+
* Retrieve column metadata from the last query.
|
3297 |
+
*
|
3298 |
+
* @since 0.71
|
3299 |
+
*
|
3300 |
+
* @param string $info_type Optional. Type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
|
3301 |
+
* @param int $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
|
3302 |
+
* @return mixed Column Results
|
3303 |
+
*/
|
3304 |
+
public function get_col_info( $info_type = 'name', $col_offset = -1 ) {
|
3305 |
+
$this->load_col_info();
|
3306 |
+
|
3307 |
+
if ( $this->col_info ) {
|
3308 |
+
if ( $col_offset == -1 ) {
|
3309 |
+
$i = 0;
|
3310 |
+
$new_array = array();
|
3311 |
+
foreach ( (array) $this->col_info as $col ) {
|
3312 |
+
$new_array[ $i ] = $col->{$info_type};
|
3313 |
+
$i++;
|
3314 |
+
}
|
3315 |
+
return $new_array;
|
3316 |
+
} else {
|
3317 |
+
return $this->col_info[ $col_offset ]->{$info_type};
|
3318 |
+
}
|
3319 |
+
}
|
3320 |
+
}
|
3321 |
+
|
3322 |
+
/**
|
3323 |
+
* Starts the timer, for debugging purposes.
|
3324 |
+
*
|
3325 |
+
* @since 1.5.0
|
3326 |
+
*
|
3327 |
+
* @return true
|
3328 |
+
*/
|
3329 |
+
public function timer_start() {
|
3330 |
+
$this->time_start = microtime( true );
|
3331 |
+
return true;
|
3332 |
+
}
|
3333 |
+
|
3334 |
+
/**
|
3335 |
+
* Stops the debugging timer.
|
3336 |
+
*
|
3337 |
+
* @since 1.5.0
|
3338 |
+
*
|
3339 |
+
* @return float Total time spent on the query, in seconds
|
3340 |
+
*/
|
3341 |
+
public function timer_stop() {
|
3342 |
+
return ( microtime( true ) - $this->time_start );
|
3343 |
+
}
|
3344 |
+
|
3345 |
+
/**
|
3346 |
+
* Wraps errors in a nice header and footer and dies.
|
3347 |
+
*
|
3348 |
+
* Will not die if wpdb::$show_errors is false.
|
3349 |
+
*
|
3350 |
+
* @since 1.5.0
|
3351 |
+
*
|
3352 |
+
* @param string $message The Error message
|
3353 |
+
* @param string $error_code Optional. A Computer readable string to identify the error.
|
3354 |
+
* @return false|void
|
3355 |
+
*/
|
3356 |
+
public function bail( $message, $error_code = '500' ) {
|
3357 |
+
if ( $this->show_errors ) {
|
3358 |
+
$error = '';
|
3359 |
+
|
3360 |
+
if ( $this->use_mysqli ) {
|
3361 |
+
if ( $this->dbh instanceof mysqli ) {
|
3362 |
+
$error = mysqli_error( $this->dbh );
|
3363 |
+
} elseif ( mysqli_connect_errno() ) {
|
3364 |
+
$error = mysqli_connect_error();
|
3365 |
+
}
|
3366 |
+
} else {
|
3367 |
+
if ( is_resource( $this->dbh ) ) {
|
3368 |
+
$error = mysql_error( $this->dbh );
|
3369 |
+
} else {
|
3370 |
+
$error = mysql_error();
|
3371 |
+
}
|
3372 |
+
}
|
3373 |
+
|
3374 |
+
if ( $error ) {
|
3375 |
+
$message = '<p><code>' . $error . "</code></p>\n" . $message;
|
3376 |
+
}
|
3377 |
+
|
3378 |
+
wp_die( $message );
|
3379 |
+
} else {
|
3380 |
+
if ( class_exists( 'WP_Error', false ) ) {
|
3381 |
+
$this->error = new WP_Error( $error_code, $message );
|
3382 |
+
} else {
|
3383 |
+
$this->error = $message;
|
3384 |
+
}
|
3385 |
+
|
3386 |
+
return false;
|
3387 |
+
}
|
3388 |
+
}
|
3389 |
+
|
3390 |
+
|
3391 |
+
/**
|
3392 |
+
* Closes the current database connection.
|
3393 |
+
*
|
3394 |
+
* @since 4.5.0
|
3395 |
+
*
|
3396 |
+
* @return bool True if the connection was successfully closed, false if it wasn't,
|
3397 |
+
* or the connection doesn't exist.
|
3398 |
+
*/
|
3399 |
+
public function close() {
|
3400 |
+
if ( ! $this->dbh ) {
|
3401 |
+
return false;
|
3402 |
+
}
|
3403 |
+
|
3404 |
+
if ( $this->use_mysqli ) {
|
3405 |
+
$closed = mysqli_close( $this->dbh );
|
3406 |
+
} else {
|
3407 |
+
$closed = mysql_close( $this->dbh );
|
3408 |
+
}
|
3409 |
+
|
3410 |
+
if ( $closed ) {
|
3411 |
+
$this->dbh = null;
|
3412 |
+
$this->ready = false;
|
3413 |
+
$this->has_connected = false;
|
3414 |
+
}
|
3415 |
+
|
3416 |
+
return $closed;
|
3417 |
+
}
|
3418 |
+
|
3419 |
+
/**
|
3420 |
+
* Whether MySQL database is at least the required minimum version.
|
3421 |
+
*
|
3422 |
+
* @since 2.5.0
|
3423 |
+
*
|
3424 |
+
* @global string $wp_version
|
3425 |
+
* @global string $required_mysql_version
|
3426 |
+
*
|
3427 |
+
* @return WP_Error|void
|
3428 |
+
*/
|
3429 |
+
public function check_database_version() {
|
3430 |
+
global $wp_version, $required_mysql_version;
|
3431 |
+
// Make sure the server has the required MySQL version
|
3432 |
+
if ( version_compare( $this->db_version(), $required_mysql_version, '<' ) ) {
|
3433 |
+
/* translators: 1: WordPress version number, 2: Minimum required MySQL version number */
|
3434 |
+
return new WP_Error( 'database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version ) );
|
3435 |
+
}
|
3436 |
+
}
|
3437 |
+
|
3438 |
+
/**
|
3439 |
+
* Whether the database supports collation.
|
3440 |
+
*
|
3441 |
+
* Called when WordPress is generating the table scheme.
|
3442 |
+
*
|
3443 |
+
* Use `wpdb::has_cap( 'collation' )`.
|
3444 |
+
*
|
3445 |
+
* @since 2.5.0
|
3446 |
+
* @deprecated 3.5.0 Use wpdb::has_cap()
|
3447 |
+
*
|
3448 |
+
* @return bool True if collation is supported, false if version does not
|
3449 |
+
*/
|
3450 |
+
public function supports_collation() {
|
3451 |
+
_deprecated_function( __FUNCTION__, '3.5.0', 'wpdb::has_cap( \'collation\' )' );
|
3452 |
+
return $this->has_cap( 'collation' );
|
3453 |
+
}
|
3454 |
+
|
3455 |
+
/**
|
3456 |
+
* The database character collate.
|
3457 |
+
*
|
3458 |
+
* @since 3.5.0
|
3459 |
+
*
|
3460 |
+
* @return string The database character collate.
|
3461 |
+
*/
|
3462 |
+
public function get_charset_collate() {
|
3463 |
+
$charset_collate = '';
|
3464 |
+
|
3465 |
+
if ( ! empty( $this->charset ) ) {
|
3466 |
+
$charset_collate = "DEFAULT CHARACTER SET $this->charset";
|
3467 |
+
}
|
3468 |
+
if ( ! empty( $this->collate ) ) {
|
3469 |
+
$charset_collate .= " COLLATE $this->collate";
|
3470 |
+
}
|
3471 |
+
|
3472 |
+
return $charset_collate;
|
3473 |
+
}
|
3474 |
+
|
3475 |
+
/**
|
3476 |
+
* Determine if a database supports a particular feature.
|
3477 |
+
*
|
3478 |
+
* @since 2.7.0
|
3479 |
+
* @since 4.1.0 Added support for the 'utf8mb4' feature.
|
3480 |
+
* @since 4.6.0 Added support for the 'utf8mb4_520' feature.
|
3481 |
+
*
|
3482 |
+
* @see wpdb::db_version()
|
3483 |
+
*
|
3484 |
+
* @param string $db_cap The feature to check for. Accepts 'collation',
|
3485 |
+
* 'group_concat', 'subqueries', 'set_charset',
|
3486 |
+
* 'utf8mb4', or 'utf8mb4_520'.
|
3487 |
+
* @return int|false Whether the database feature is supported, false otherwise.
|
3488 |
+
*/
|
3489 |
+
public function has_cap( $db_cap ) {
|
3490 |
+
$version = $this->db_version();
|
3491 |
+
|
3492 |
+
switch ( strtolower( $db_cap ) ) {
|
3493 |
+
case 'collation': // @since 2.5.0
|
3494 |
+
case 'group_concat': // @since 2.7.0
|
3495 |
+
case 'subqueries': // @since 2.7.0
|
3496 |
+
return version_compare( $version, '4.1', '>=' );
|
3497 |
+
case 'set_charset':
|
3498 |
+
return version_compare( $version, '5.0.7', '>=' );
|
3499 |
+
case 'utf8mb4': // @since 4.1.0
|
3500 |
+
if ( version_compare( $version, '5.5.3', '<' ) ) {
|
3501 |
+
return false;
|
3502 |
+
}
|
3503 |
+
if ( $this->use_mysqli ) {
|
3504 |
+
$client_version = mysqli_get_client_info();
|
3505 |
+
} else {
|
3506 |
+
$client_version = mysql_get_client_info();
|
3507 |
+
}
|
3508 |
+
|
3509 |
+
/*
|
3510 |
+
* libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
|
3511 |
+
* mysqlnd has supported utf8mb4 since 5.0.9.
|
3512 |
+
*/
|
3513 |
+
if ( false !== strpos( $client_version, 'mysqlnd' ) ) {
|
3514 |
+
$client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $client_version );
|
3515 |
+
return version_compare( $client_version, '5.0.9', '>=' );
|
3516 |
+
} else {
|
3517 |
+
return version_compare( $client_version, '5.5.3', '>=' );
|
3518 |
+
}
|
3519 |
+
case 'utf8mb4_520': // @since 4.6.0
|
3520 |
+
return version_compare( $version, '5.6', '>=' );
|
3521 |
+
}
|
3522 |
+
|
3523 |
+
return false;
|
3524 |
+
}
|
3525 |
+
|
3526 |
+
/**
|
3527 |
+
* Retrieve the name of the function that called wpdb.
|
3528 |
+
*
|
3529 |
+
* Searches up the list of functions until it reaches
|
3530 |
+
* the one that would most logically had called this method.
|
3531 |
+
*
|
3532 |
+
* @since 2.5.0
|
3533 |
+
*
|
3534 |
+
* @return string Comma separated list of the calling functions.
|
3535 |
+
*/
|
3536 |
+
public function get_caller() {
|
3537 |
+
return wp_debug_backtrace_summary( __CLASS__ );
|
3538 |
+
}
|
3539 |
+
|
3540 |
+
/**
|
3541 |
+
* Retrieves the MySQL server version.
|
3542 |
+
*
|
3543 |
+
* @since 2.7.0
|
3544 |
+
*
|
3545 |
+
* @return null|string Null on failure, version number on success.
|
3546 |
+
*/
|
3547 |
+
public function db_version() {
|
3548 |
+
if ( $this->use_mysqli ) {
|
3549 |
+
$server_info = mysqli_get_server_info( $this->dbh );
|
3550 |
+
} else {
|
3551 |
+
$server_info = mysql_get_server_info( $this->dbh );
|
3552 |
+
}
|
3553 |
+
return preg_replace( '/[^0-9.].*/', '', $server_info );
|
3554 |
+
}
|
3555 |
+
}
|
public/class-xcloner-public.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
/**
|
4 |
* The public-facing functionality of the plugin.
|
5 |
*
|
6 |
-
* @link
|
7 |
* @since 1.0.0
|
8 |
*
|
9 |
* @package Xcloner
|
3 |
/**
|
4 |
* The public-facing functionality of the plugin.
|
5 |
*
|
6 |
+
* @link https://watchful.net
|
7 |
* @since 1.0.0
|
8 |
*
|
9 |
* @package Xcloner
|
public/partials/xcloner-public-display.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
*
|
6 |
* This file is used to markup the public-facing aspects of the plugin.
|
7 |
*
|
8 |
-
* @link
|
9 |
* @since 1.0.0
|
10 |
*
|
11 |
* @package Xcloner
|
5 |
*
|
6 |
* This file is used to markup the public-facing aspects of the plugin.
|
7 |
*
|
8 |
+
* @link https://watchful.net
|
9 |
* @since 1.0.0
|
10 |
*
|
11 |
* @package Xcloner
|
uninstall.php
CHANGED
@@ -19,7 +19,7 @@
|
|
19 |
* For more information, see the following discussion:
|
20 |
* https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate/pull/123#issuecomment-28541913
|
21 |
*
|
22 |
-
* @link
|
23 |
* @since 1.0.0
|
24 |
*
|
25 |
* @package Xcloner
|
19 |
* For more information, see the following discussion:
|
20 |
* https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate/pull/123#issuecomment-28541913
|
21 |
*
|
22 |
+
* @link https://watchful.net
|
23 |
* @since 1.0.0
|
24 |
*
|
25 |
* @package Xcloner
|
vendor/composer/autoload_namespaces.php
CHANGED
@@ -6,5 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
|
|
6 |
$baseDir = dirname($vendorDir);
|
7 |
|
8 |
return array(
|
9 |
-
'org\\bovigo\\vfs\\' => array($vendorDir . '/mikey179/
|
10 |
);
|
6 |
$baseDir = dirname($vendorDir);
|
7 |
|
8 |
return array(
|
9 |
+
'org\\bovigo\\vfs\\' => array($vendorDir . '/mikey179/vfsstream/src/main/php'),
|
10 |
);
|
vendor/composer/autoload_static.php
CHANGED
@@ -209,7 +209,7 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
|
|
209 |
array (
|
210 |
'org\\bovigo\\vfs\\' =>
|
211 |
array (
|
212 |
-
0 => __DIR__ . '/..' . '/mikey179/
|
213 |
),
|
214 |
),
|
215 |
);
|
209 |
array (
|
210 |
'org\\bovigo\\vfs\\' =>
|
211 |
array (
|
212 |
+
0 => __DIR__ . '/..' . '/mikey179/vfsstream/src/main/php',
|
213 |
),
|
214 |
),
|
215 |
);
|
vendor/composer/installed.json
CHANGED
@@ -797,27 +797,27 @@
|
|
797 |
]
|
798 |
},
|
799 |
{
|
800 |
-
"name": "mikey179/
|
801 |
-
"version": "v1.6.
|
802 |
-
"version_normalized": "1.6.
|
803 |
"source": {
|
804 |
"type": "git",
|
805 |
"url": "https://github.com/bovigo/vfsStream.git",
|
806 |
-
"reference": "
|
807 |
},
|
808 |
"dist": {
|
809 |
"type": "zip",
|
810 |
-
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/
|
811 |
-
"reference": "
|
812 |
"shasum": ""
|
813 |
},
|
814 |
"require": {
|
815 |
"php": ">=5.3.0"
|
816 |
},
|
817 |
"require-dev": {
|
818 |
-
"phpunit/phpunit": "
|
819 |
},
|
820 |
-
"time": "
|
821 |
"type": "library",
|
822 |
"extra": {
|
823 |
"branch-alias": {
|
@@ -1638,17 +1638,17 @@
|
|
1638 |
},
|
1639 |
{
|
1640 |
"name": "splitbrain/php-archive",
|
1641 |
-
"version": "1.
|
1642 |
-
"version_normalized": "1.
|
1643 |
"source": {
|
1644 |
"type": "git",
|
1645 |
"url": "https://github.com/splitbrain/php-archive.git",
|
1646 |
-
"reference": "
|
1647 |
},
|
1648 |
"dist": {
|
1649 |
"type": "zip",
|
1650 |
-
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/
|
1651 |
-
"reference": "
|
1652 |
"shasum": ""
|
1653 |
},
|
1654 |
"require": {
|
@@ -1664,7 +1664,7 @@
|
|
1664 |
"ext-iconv": "Used for proper filename encode handling",
|
1665 |
"ext-mbstring": "Can be used alternatively for handling filename encoding"
|
1666 |
},
|
1667 |
-
"time": "2018-
|
1668 |
"type": "library",
|
1669 |
"installation-source": "source",
|
1670 |
"autoload": {
|
797 |
]
|
798 |
},
|
799 |
{
|
800 |
+
"name": "mikey179/vfsstream",
|
801 |
+
"version": "v1.6.8",
|
802 |
+
"version_normalized": "1.6.8.0",
|
803 |
"source": {
|
804 |
"type": "git",
|
805 |
"url": "https://github.com/bovigo/vfsStream.git",
|
806 |
+
"reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe"
|
807 |
},
|
808 |
"dist": {
|
809 |
"type": "zip",
|
810 |
+
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/231c73783ebb7dd9ec77916c10037eff5a2b6efe",
|
811 |
+
"reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe",
|
812 |
"shasum": ""
|
813 |
},
|
814 |
"require": {
|
815 |
"php": ">=5.3.0"
|
816 |
},
|
817 |
"require-dev": {
|
818 |
+
"phpunit/phpunit": "^4.5|^5.0"
|
819 |
},
|
820 |
+
"time": "2019-10-30T15:31:00+00:00",
|
821 |
"type": "library",
|
822 |
"extra": {
|
823 |
"branch-alias": {
|
1638 |
},
|
1639 |
{
|
1640 |
"name": "splitbrain/php-archive",
|
1641 |
+
"version": "1.1.1",
|
1642 |
+
"version_normalized": "1.1.1.0",
|
1643 |
"source": {
|
1644 |
"type": "git",
|
1645 |
"url": "https://github.com/splitbrain/php-archive.git",
|
1646 |
+
"reference": "10d89013572ba1f4d4ad7fcb74860242f4c3860b"
|
1647 |
},
|
1648 |
"dist": {
|
1649 |
"type": "zip",
|
1650 |
+
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/10d89013572ba1f4d4ad7fcb74860242f4c3860b",
|
1651 |
+
"reference": "10d89013572ba1f4d4ad7fcb74860242f4c3860b",
|
1652 |
"shasum": ""
|
1653 |
},
|
1654 |
"require": {
|
1664 |
"ext-iconv": "Used for proper filename encode handling",
|
1665 |
"ext-mbstring": "Can be used alternatively for handling filename encoding"
|
1666 |
},
|
1667 |
+
"time": "2018-09-09T12:13:53+00:00",
|
1668 |
"type": "library",
|
1669 |
"installation-source": "source",
|
1670 |
"autoload": {
|
vendor/splitbrain/php-archive/.gitignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.iml
|
2 |
+
.idea/
|
3 |
+
composer.phar
|
4 |
+
vendor/
|
5 |
+
composer.lock
|
6 |
+
apigen.phar
|
7 |
+
docs/
|
8 |
+
nbproject/
|
vendor/splitbrain/php-archive/src/Archive.php
CHANGED
@@ -10,12 +10,15 @@ abstract class Archive
|
|
10 |
const COMPRESS_GZIP = 1;
|
11 |
const COMPRESS_BZIP = 2;
|
12 |
|
|
|
|
|
|
|
13 |
/**
|
14 |
* Set the compression level and type
|
15 |
*
|
16 |
* @param int $level Compression level (0 to 9)
|
17 |
* @param int $type Type of compression to use (use COMPRESS_* constants)
|
18 |
-
* @
|
19 |
*/
|
20 |
abstract public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO);
|
21 |
|
@@ -117,16 +120,16 @@ abstract class Archive
|
|
117 |
*/
|
118 |
abstract public function save($file);
|
119 |
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
}
|
10 |
const COMPRESS_GZIP = 1;
|
11 |
const COMPRESS_BZIP = 2;
|
12 |
|
13 |
+
/** @var callable */
|
14 |
+
protected $callback;
|
15 |
+
|
16 |
/**
|
17 |
* Set the compression level and type
|
18 |
*
|
19 |
* @param int $level Compression level (0 to 9)
|
20 |
* @param int $type Type of compression to use (use COMPRESS_* constants)
|
21 |
+
* @throws ArchiveIllegalCompressionException
|
22 |
*/
|
23 |
abstract public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO);
|
24 |
|
120 |
*/
|
121 |
abstract public function save($file);
|
122 |
|
123 |
+
/**
|
124 |
+
* Set a callback function to be called whenever a file is added or extracted.
|
125 |
+
*
|
126 |
+
* The callback is called with a FileInfo object as parameter. You can use this to show progress
|
127 |
+
* info during an operation.
|
128 |
+
*
|
129 |
+
* @param callable $callback
|
130 |
+
*/
|
131 |
+
public function setCallback($callback)
|
132 |
+
{
|
133 |
+
$this->callback = $callback;
|
134 |
+
}
|
135 |
}
|
vendor/splitbrain/php-archive/src/ArchiveCorruptedException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace splitbrain\PHPArchive;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* The archive is unreadable
|
7 |
+
*/
|
8 |
+
class ArchiveCorruptedException extends \Exception
|
9 |
+
{
|
10 |
+
}
|
vendor/splitbrain/php-archive/src/ArchiveIOException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace splitbrain\PHPArchive;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Read/Write Errors
|
7 |
+
*/
|
8 |
+
class ArchiveIOException extends \Exception
|
9 |
+
{
|
10 |
+
}
|
vendor/splitbrain/php-archive/src/ArchiveIllegalCompressionException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace splitbrain\PHPArchive;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Bad or unsupported compression settings requested
|
7 |
+
*/
|
8 |
+
class ArchiveIllegalCompressionException extends \Exception
|
9 |
+
{
|
10 |
+
}
|
vendor/splitbrain/php-archive/src/FileInfo.php
CHANGED
@@ -55,18 +55,13 @@ class FileInfo
|
|
55 |
|
56 |
$stat = stat($path);
|
57 |
$file = new FileInfo();
|
58 |
-
|
59 |
-
if(is_dir($path))
|
60 |
-
$size = 0;
|
61 |
-
else
|
62 |
-
$size = filesize($path);
|
63 |
|
64 |
$file->setPath($path);
|
65 |
$file->setIsdir(is_dir($path));
|
66 |
$file->setMode(fileperms($path));
|
67 |
$file->setOwner(fileowner($path));
|
68 |
$file->setGroup(filegroup($path));
|
69 |
-
$file->setSize($
|
70 |
$file->setUid($stat['uid']);
|
71 |
$file->setGid($stat['gid']);
|
72 |
$file->setMtime($stat['mtime']);
|
@@ -79,13 +74,11 @@ class FileInfo
|
|
79 |
}
|
80 |
|
81 |
/**
|
82 |
-
* @return int
|
83 |
*/
|
84 |
public function getSize()
|
85 |
{
|
86 |
-
|
87 |
-
return 0;
|
88 |
-
|
89 |
return $this->size;
|
90 |
}
|
91 |
|
@@ -295,7 +288,6 @@ class FileInfo
|
|
295 |
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
296 |
*
|
297 |
* @param int|string $strip
|
298 |
-
* @return FileInfo
|
299 |
*/
|
300 |
public function strip($strip)
|
301 |
{
|
@@ -334,22 +326,15 @@ class FileInfo
|
|
334 |
*/
|
335 |
public function match($include = '', $exclude = '')
|
336 |
{
|
337 |
-
//echo $include;
|
338 |
-
|
339 |
-
//echo $this->getPath()."--".preg_match($include, $this->getPath())."\n";
|
340 |
$extract = true;
|
341 |
if ($include && !preg_match($include, $this->getPath())) {
|
342 |
$extract = false;
|
343 |
-
|
344 |
}
|
345 |
if ($exclude && preg_match($exclude, $this->getPath())) {
|
346 |
$extract = false;
|
347 |
}
|
348 |
-
|
349 |
return $extract;
|
350 |
}
|
351 |
}
|
352 |
|
353 |
-
class FileInfoException extends \Exception
|
354 |
-
{
|
355 |
-
}
|
55 |
|
56 |
$stat = stat($path);
|
57 |
$file = new FileInfo();
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
$file->setPath($path);
|
60 |
$file->setIsdir(is_dir($path));
|
61 |
$file->setMode(fileperms($path));
|
62 |
$file->setOwner(fileowner($path));
|
63 |
$file->setGroup(filegroup($path));
|
64 |
+
$file->setSize(filesize($path));
|
65 |
$file->setUid($stat['uid']);
|
66 |
$file->setGid($stat['gid']);
|
67 |
$file->setMtime($stat['mtime']);
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
+
* @return int the filesize. always 0 for directories
|
78 |
*/
|
79 |
public function getSize()
|
80 |
{
|
81 |
+
if($this->isdir) return 0;
|
|
|
|
|
82 |
return $this->size;
|
83 |
}
|
84 |
|
288 |
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
289 |
*
|
290 |
* @param int|string $strip
|
|
|
291 |
*/
|
292 |
public function strip($strip)
|
293 |
{
|
326 |
*/
|
327 |
public function match($include = '', $exclude = '')
|
328 |
{
|
|
|
|
|
|
|
329 |
$extract = true;
|
330 |
if ($include && !preg_match($include, $this->getPath())) {
|
331 |
$extract = false;
|
|
|
332 |
}
|
333 |
if ($exclude && preg_match($exclude, $this->getPath())) {
|
334 |
$extract = false;
|
335 |
}
|
336 |
+
|
337 |
return $extract;
|
338 |
}
|
339 |
}
|
340 |
|
|
|
|
|
|
vendor/splitbrain/php-archive/src/FileInfoException.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace splitbrain\PHPArchive;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* File meta data problems
|
7 |
+
*/
|
8 |
+
class FileInfoException extends \Exception
|
9 |
+
{
|
10 |
+
}
|
vendor/splitbrain/php-archive/src/Tar.php
CHANGED
@@ -28,12 +28,15 @@ class Tar extends Archive
|
|
28 |
* Sets the compression to use
|
29 |
*
|
30 |
* @param int $level Compression level (0 to 9)
|
31 |
-
* @param int $type
|
32 |
-
* @
|
33 |
*/
|
34 |
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
35 |
{
|
36 |
$this->compressioncheck($type);
|
|
|
|
|
|
|
37 |
$this->comptype = $type;
|
38 |
$this->complevel = $level;
|
39 |
if($level == 0) $this->comptype = Archive::COMPRESS_NONE;
|
@@ -45,8 +48,9 @@ class Tar extends Archive
|
|
45 |
*
|
46 |
* @param string $file
|
47 |
* @throws ArchiveIOException
|
|
|
48 |
*/
|
49 |
-
public function open($file
|
50 |
{
|
51 |
$this->file = $file;
|
52 |
|
@@ -68,9 +72,6 @@ class Tar extends Archive
|
|
68 |
throw new ArchiveIOException('Could not open file for reading: '.$this->file);
|
69 |
}
|
70 |
$this->closed = false;
|
71 |
-
|
72 |
-
if($start_byte)
|
73 |
-
fseek($this->fh, $start_byte);
|
74 |
}
|
75 |
|
76 |
/**
|
@@ -82,44 +83,28 @@ class Tar extends Archive
|
|
82 |
* Reopen the file with open() again if you want to do additional operations
|
83 |
*
|
84 |
* @throws ArchiveIOException
|
|
|
85 |
* @returns FileInfo[]
|
86 |
*/
|
87 |
-
public function contents(
|
88 |
{
|
89 |
if ($this->closed || !$this->file) {
|
90 |
throw new ArchiveIOException('Can not read from a closed archive');
|
91 |
}
|
92 |
|
93 |
-
$files_counter = 0;
|
94 |
$result = array();
|
95 |
-
|
96 |
while ($read = $this->readbytes(512)) {
|
97 |
$header = $this->parseHeader($read);
|
98 |
if (!is_array($header)) {
|
99 |
continue;
|
100 |
}
|
101 |
|
102 |
-
if($files_limit)
|
103 |
-
{
|
104 |
-
if(++$files_counter > $files_limit)
|
105 |
-
{
|
106 |
-
$return['extracted_files'] = $result;
|
107 |
-
$return['start'] = ftell($this->fh)-512;
|
108 |
-
return $return;
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
if($header['typeflag'] == 5)
|
113 |
-
$header['size'] = 0;
|
114 |
-
|
115 |
$this->skipbytes(ceil($header['size'] / 512) * 512);
|
116 |
$result[] = $this->header2fileinfo($header);
|
117 |
}
|
118 |
|
119 |
-
$return['extracted_files'] = $result;
|
120 |
-
|
121 |
$this->close();
|
122 |
-
return $
|
123 |
}
|
124 |
|
125 |
/**
|
@@ -140,35 +125,26 @@ class Tar extends Archive
|
|
140 |
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
141 |
* Reopen the file with open() again if you want to do additional operations
|
142 |
*
|
143 |
-
* @param string
|
144 |
-
* @param int|string $strip
|
145 |
-
* @param string
|
146 |
-
* @param string
|
147 |
* @throws ArchiveIOException
|
|
|
148 |
* @return FileInfo[]
|
149 |
*/
|
150 |
-
public function extract($outdir, $strip = '', $exclude = '', $include = ''
|
151 |
{
|
152 |
-
|
153 |
if ($this->closed || !$this->file) {
|
154 |
throw new ArchiveIOException('Can not read from a closed archive');
|
155 |
}
|
156 |
|
157 |
$outdir = rtrim($outdir, '/');
|
158 |
-
|
159 |
-
@mkdir($outdir, 0755, true);
|
160 |
-
else
|
161 |
-
@chmod($outdir, 0777);
|
162 |
-
|
163 |
-
//@mkdir($outdir, 0777, true);
|
164 |
-
|
165 |
if (!is_dir($outdir)) {
|
166 |
throw new ArchiveIOException("Could not create directory '$outdir'");
|
167 |
}
|
168 |
|
169 |
-
$files_counter = 0;
|
170 |
-
$return = array();
|
171 |
-
|
172 |
$extracted = array();
|
173 |
while ($dat = $this->readbytes(512)) {
|
174 |
// read the file header
|
@@ -176,17 +152,6 @@ class Tar extends Archive
|
|
176 |
if (!is_array($header)) {
|
177 |
continue;
|
178 |
}
|
179 |
-
|
180 |
-
if($files_limit)
|
181 |
-
{
|
182 |
-
if(++$files_counter > $files_limit)
|
183 |
-
{
|
184 |
-
$return['extracted_files'] = $extracted;
|
185 |
-
$return['start'] = ftell($this->fh)-512;
|
186 |
-
return $return;
|
187 |
-
}
|
188 |
-
}
|
189 |
-
|
190 |
$fileinfo = $this->header2fileinfo($header);
|
191 |
|
192 |
// apply strip rules
|
@@ -201,17 +166,11 @@ class Tar extends Archive
|
|
201 |
// create output directory
|
202 |
$output = $outdir.'/'.$fileinfo->getPath();
|
203 |
$directory = ($fileinfo->getIsdir()) ? $output : dirname($output);
|
204 |
-
|
205 |
-
@mkdir($directory, 0755, true);
|
206 |
-
else
|
207 |
-
@chmod($directory, 0755);
|
208 |
|
209 |
// extract data
|
210 |
if (!$fileinfo->getIsdir()) {
|
211 |
-
|
212 |
-
unlink($output);
|
213 |
-
|
214 |
-
$fp = fopen($output, "wb");
|
215 |
if (!$fp) {
|
216 |
throw new ArchiveIOException('Could not open file for writing: '.$output);
|
217 |
}
|
@@ -225,21 +184,20 @@ class Tar extends Archive
|
|
225 |
}
|
226 |
|
227 |
fclose($fp);
|
228 |
-
touch($output, $fileinfo->getMtime());
|
229 |
-
chmod($output, $fileinfo->getMode());
|
230 |
} else {
|
231 |
-
|
232 |
-
$this->skipbytes(ceil(0 / 512) * 512); // the size is usually 0 for directories
|
233 |
}
|
234 |
|
|
|
|
|
|
|
235 |
$extracted[] = $fileinfo;
|
236 |
}
|
237 |
|
238 |
$this->close();
|
239 |
-
|
240 |
-
$return['extracted_files'] = $extracted;
|
241 |
-
|
242 |
-
return $return;
|
243 |
}
|
244 |
|
245 |
/**
|
@@ -249,6 +207,7 @@ class Tar extends Archive
|
|
249 |
*
|
250 |
* @param string $file
|
251 |
* @throws ArchiveIOException
|
|
|
252 |
*/
|
253 |
public function create($file = '')
|
254 |
{
|
@@ -281,9 +240,11 @@ class Tar extends Archive
|
|
281 |
/**
|
282 |
* Add a file to the current TAR archive using an existing file in the filesystem
|
283 |
*
|
284 |
-
* @param string
|
285 |
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
286 |
-
* @throws
|
|
|
|
|
287 |
*/
|
288 |
public function addFile($file, $fileinfo = '')
|
289 |
{
|
@@ -295,27 +256,19 @@ class Tar extends Archive
|
|
295 |
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
296 |
}
|
297 |
|
298 |
-
|
299 |
-
{
|
300 |
-
$this->writeFileHeader($fileinfo);
|
301 |
-
return;
|
302 |
-
}
|
303 |
-
|
304 |
-
$fp = fopen($file, 'rb');
|
305 |
if (!$fp) {
|
306 |
throw new ArchiveIOException('Could not open file for reading: '.$file);
|
307 |
}
|
308 |
|
309 |
// create file header
|
310 |
-
if(is_resource($this->fh))
|
311 |
-
{
|
312 |
-
$archive_header_position = ftell($this->fh);
|
313 |
-
}
|
314 |
$this->writeFileHeader($fileinfo);
|
315 |
|
316 |
// write data
|
|
|
317 |
while (!feof($fp)) {
|
318 |
$data = fread($fp, 512);
|
|
|
319 |
if ($data === false) {
|
320 |
break;
|
321 |
}
|
@@ -325,23 +278,16 @@ class Tar extends Archive
|
|
325 |
$packed = pack("a512", $data);
|
326 |
$this->writebytes($packed);
|
327 |
}
|
|
|
328 |
|
329 |
-
$
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
{
|
334 |
-
$archive_current_position = ftell($this->fh);
|
335 |
-
fseek($this->fh, $archive_header_position);
|
336 |
-
|
337 |
-
$fileinfo->setSize(ftell($fp));
|
338 |
-
$this->writeFileHeader($fileinfo);
|
339 |
-
|
340 |
-
fseek($this->fh, $archive_current_position);
|
341 |
-
|
342 |
-
}
|
343 |
|
344 |
-
|
|
|
|
|
345 |
}
|
346 |
|
347 |
/**
|
@@ -368,6 +314,10 @@ class Tar extends Archive
|
|
368 |
for ($s = 0; $s < $len; $s += 512) {
|
369 |
$this->writebytes(pack("a512", substr($data, $s, 512)));
|
370 |
}
|
|
|
|
|
|
|
|
|
371 |
}
|
372 |
|
373 |
/**
|
@@ -380,6 +330,7 @@ class Tar extends Archive
|
|
380 |
* consists of two 512 blocks of zero bytes"
|
381 |
*
|
382 |
* @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
|
|
|
383 |
*/
|
384 |
public function close()
|
385 |
{
|
@@ -415,6 +366,7 @@ class Tar extends Archive
|
|
415 |
* Returns the created in-memory archive data
|
416 |
*
|
417 |
* This implicitly calls close() on the Archive
|
|
|
418 |
*/
|
419 |
public function getArchive()
|
420 |
{
|
@@ -441,6 +393,7 @@ class Tar extends Archive
|
|
441 |
*
|
442 |
* @param string $file
|
443 |
* @throws ArchiveIOException
|
|
|
444 |
*/
|
445 |
public function save($file)
|
446 |
{
|
@@ -448,7 +401,7 @@ class Tar extends Archive
|
|
448 |
$this->setCompression($this->complevel, $this->filetype($file));
|
449 |
}
|
450 |
|
451 |
-
if (
|
452 |
throw new ArchiveIOException('Could not write to file: '.$file);
|
453 |
}
|
454 |
}
|
@@ -492,103 +445,9 @@ class Tar extends Archive
|
|
492 |
if ($written === false) {
|
493 |
throw new ArchiveIOException('Failed to write to archive stream');
|
494 |
}
|
495 |
-
|
496 |
return $written;
|
497 |
}
|
498 |
|
499 |
-
public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
|
500 |
-
{
|
501 |
-
$end = $start+($limit*512);
|
502 |
-
|
503 |
-
//check to see if we are at the begining of writing the file
|
504 |
-
if(!$start)
|
505 |
-
{
|
506 |
-
if (is_string($fileinfo)) {
|
507 |
-
$fileinfo = FileInfo::fromPath($file, $fileinfo);
|
508 |
-
}
|
509 |
-
}
|
510 |
-
|
511 |
-
if ($this->closed) {
|
512 |
-
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
513 |
-
}
|
514 |
-
|
515 |
-
if(is_dir($file))
|
516 |
-
{
|
517 |
-
$this->writeFileHeader($fileinfo);
|
518 |
-
return;
|
519 |
-
}
|
520 |
-
|
521 |
-
$fp = fopen($file, 'rb');
|
522 |
-
|
523 |
-
fseek($fp, $start);
|
524 |
-
|
525 |
-
if (!$fp) {
|
526 |
-
throw new ArchiveIOException('Could not open file for reading: '.$file);
|
527 |
-
}
|
528 |
-
|
529 |
-
// create file header
|
530 |
-
if(!$start)
|
531 |
-
{
|
532 |
-
$this->writeFileHeader($fileinfo);
|
533 |
-
}
|
534 |
-
|
535 |
-
$bytes = 0;
|
536 |
-
// write data
|
537 |
-
while ($end >=ftell($fp) and !feof($fp) ) {
|
538 |
-
$data = fread($fp, 512);
|
539 |
-
if ($data === false) {
|
540 |
-
break;
|
541 |
-
}
|
542 |
-
if ($data === '') {
|
543 |
-
break;
|
544 |
-
}
|
545 |
-
$packed = pack("a512", $data);
|
546 |
-
$bytes += $this->writebytes($packed);
|
547 |
-
}
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
//if we are not at the end of file, we return the current position for incremental writing
|
552 |
-
if(!feof($fp))
|
553 |
-
$last_position = ftell($fp);
|
554 |
-
else
|
555 |
-
$last_position = -1;
|
556 |
-
|
557 |
-
fclose($fp);
|
558 |
-
|
559 |
-
return $last_position;
|
560 |
-
}
|
561 |
-
|
562 |
-
public function openForAppend($file = '')
|
563 |
-
{
|
564 |
-
|
565 |
-
$this->file = $file;
|
566 |
-
$this->memory = '';
|
567 |
-
$this->fh = 0;
|
568 |
-
|
569 |
-
if ($this->file) {
|
570 |
-
// determine compression
|
571 |
-
if ($this->comptype == Archive::COMPRESS_AUTO) {
|
572 |
-
$this->setCompression($this->complevel, $this->filetype($file));
|
573 |
-
}
|
574 |
-
|
575 |
-
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
576 |
-
$this->fh = @gzopen($this->file, 'ab'.$this->complevel);
|
577 |
-
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
578 |
-
$this->fh = @bzopen($this->file, 'a');
|
579 |
-
} else {
|
580 |
-
$this->fh = @fopen($this->file, 'ab');
|
581 |
-
}
|
582 |
-
|
583 |
-
if (!$this->fh) {
|
584 |
-
throw new ArchiveIOException('Could not open file for writing: '.$this->file);
|
585 |
-
}
|
586 |
-
}
|
587 |
-
$this->writeaccess = true;
|
588 |
-
$this->closed = false;
|
589 |
-
|
590 |
-
}
|
591 |
-
|
592 |
/**
|
593 |
* Skip forward in the open file pointer
|
594 |
*
|
@@ -596,7 +455,7 @@ class Tar extends Archive
|
|
596 |
*
|
597 |
* @param int $bytes seek to this position
|
598 |
*/
|
599 |
-
function skipbytes($bytes)
|
600 |
{
|
601 |
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
602 |
@gzseek($this->fh, $bytes, SEEK_CUR);
|
@@ -614,9 +473,10 @@ class Tar extends Archive
|
|
614 |
}
|
615 |
|
616 |
/**
|
617 |
-
* Write the given file
|
618 |
*
|
619 |
* @param FileInfo $fileinfo
|
|
|
620 |
*/
|
621 |
protected function writeFileHeader(FileInfo $fileinfo)
|
622 |
{
|
@@ -635,12 +495,13 @@ class Tar extends Archive
|
|
635 |
* Write a file header to the stream
|
636 |
*
|
637 |
* @param string $name
|
638 |
-
* @param int
|
639 |
-
* @param int
|
640 |
-
* @param int
|
641 |
-
* @param int
|
642 |
-
* @param int
|
643 |
* @param string $typeflag Set to '5' for directories
|
|
|
644 |
*/
|
645 |
protected function writeRawFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '')
|
646 |
{
|
@@ -716,20 +577,13 @@ class Tar extends Archive
|
|
716 |
"a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix",
|
717 |
$block
|
718 |
);
|
719 |
-
|
720 |
-
if(DecOct($header['typeflag']) == DecOct(''))
|
721 |
-
{
|
722 |
-
$header['typeflag'] = (string)0;
|
723 |
-
}
|
724 |
-
|
725 |
if (!$header) {
|
726 |
throw new ArchiveCorruptedException('Failed to parse header');
|
727 |
}
|
728 |
-
$return['checksum'] = OctDec(trim($header['checksum']));
|
729 |
|
|
|
730 |
if ($return['checksum'] != $chks) {
|
731 |
-
|
732 |
-
throw new ArchiveCorruptedException('Header does not match it\'s checksum for ');
|
733 |
}
|
734 |
|
735 |
$return['filename'] = trim($header['filename']);
|
@@ -748,22 +602,15 @@ class Tar extends Archive
|
|
748 |
$return['filename'] = trim($header['prefix']).'/'.$return['filename'];
|
749 |
}
|
750 |
|
751 |
-
// Handle Long-Link
|
752 |
if ($return['typeflag'] == 'L') {
|
753 |
// following data block(s) is the filename
|
754 |
$filename = trim($this->readbytes(ceil($return['size'] / 512) * 512));
|
755 |
// next block is the real header
|
756 |
$block = $this->readbytes(512);
|
757 |
$return = $this->parseHeader($block);
|
758 |
-
|
759 |
// overwrite the filename
|
760 |
-
|
761 |
-
}elseif ($return['typeflag'] == 'x') {
|
762 |
-
// following data block(s) is the filename
|
763 |
-
$filename = trim($this->readbytes(ceil($return['size'] / 512) * 512));
|
764 |
-
// next block is the real header
|
765 |
-
$block = $this->readbytes(512);
|
766 |
-
$return = $this->parseHeader($block);
|
767 |
}
|
768 |
|
769 |
return $return;
|
@@ -822,7 +669,7 @@ class Tar extends Archive
|
|
822 |
{
|
823 |
// for existing files, try to read the magic bytes
|
824 |
if(file_exists($file) && is_readable($file) && filesize($file) > 5) {
|
825 |
-
$fh = fopen($file, 'rb');
|
826 |
if(!$fh) return false;
|
827 |
$magic = fread($fh, 5);
|
828 |
fclose($fh);
|
@@ -841,4 +688,5 @@ class Tar extends Archive
|
|
841 |
|
842 |
return Archive::COMPRESS_NONE;
|
843 |
}
|
|
|
844 |
}
|
28 |
* Sets the compression to use
|
29 |
*
|
30 |
* @param int $level Compression level (0 to 9)
|
31 |
+
* @param int $type Type of compression to use (use COMPRESS_* constants)
|
32 |
+
* @throws ArchiveIllegalCompressionException
|
33 |
*/
|
34 |
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
35 |
{
|
36 |
$this->compressioncheck($type);
|
37 |
+
if ($level < -1 || $level > 9) {
|
38 |
+
throw new ArchiveIllegalCompressionException('Compression level should be between -1 and 9');
|
39 |
+
}
|
40 |
$this->comptype = $type;
|
41 |
$this->complevel = $level;
|
42 |
if($level == 0) $this->comptype = Archive::COMPRESS_NONE;
|
48 |
*
|
49 |
* @param string $file
|
50 |
* @throws ArchiveIOException
|
51 |
+
* @throws ArchiveIllegalCompressionException
|
52 |
*/
|
53 |
+
public function open($file)
|
54 |
{
|
55 |
$this->file = $file;
|
56 |
|
72 |
throw new ArchiveIOException('Could not open file for reading: '.$this->file);
|
73 |
}
|
74 |
$this->closed = false;
|
|
|
|
|
|
|
75 |
}
|
76 |
|
77 |
/**
|
83 |
* Reopen the file with open() again if you want to do additional operations
|
84 |
*
|
85 |
* @throws ArchiveIOException
|
86 |
+
* @throws ArchiveCorruptedException
|
87 |
* @returns FileInfo[]
|
88 |
*/
|
89 |
+
public function contents()
|
90 |
{
|
91 |
if ($this->closed || !$this->file) {
|
92 |
throw new ArchiveIOException('Can not read from a closed archive');
|
93 |
}
|
94 |
|
|
|
95 |
$result = array();
|
|
|
96 |
while ($read = $this->readbytes(512)) {
|
97 |
$header = $this->parseHeader($read);
|
98 |
if (!is_array($header)) {
|
99 |
continue;
|
100 |
}
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
$this->skipbytes(ceil($header['size'] / 512) * 512);
|
103 |
$result[] = $this->header2fileinfo($header);
|
104 |
}
|
105 |
|
|
|
|
|
106 |
$this->close();
|
107 |
+
return $result;
|
108 |
}
|
109 |
|
110 |
/**
|
125 |
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
126 |
* Reopen the file with open() again if you want to do additional operations
|
127 |
*
|
128 |
+
* @param string $outdir the target directory for extracting
|
129 |
+
* @param int|string $strip either the number of path components or a fixed prefix to strip
|
130 |
+
* @param string $exclude a regular expression of files to exclude
|
131 |
+
* @param string $include a regular expression of files to include
|
132 |
* @throws ArchiveIOException
|
133 |
+
* @throws ArchiveCorruptedException
|
134 |
* @return FileInfo[]
|
135 |
*/
|
136 |
+
public function extract($outdir, $strip = '', $exclude = '', $include = '')
|
137 |
{
|
|
|
138 |
if ($this->closed || !$this->file) {
|
139 |
throw new ArchiveIOException('Can not read from a closed archive');
|
140 |
}
|
141 |
|
142 |
$outdir = rtrim($outdir, '/');
|
143 |
+
@mkdir($outdir, 0777, true);
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
if (!is_dir($outdir)) {
|
145 |
throw new ArchiveIOException("Could not create directory '$outdir'");
|
146 |
}
|
147 |
|
|
|
|
|
|
|
148 |
$extracted = array();
|
149 |
while ($dat = $this->readbytes(512)) {
|
150 |
// read the file header
|
152 |
if (!is_array($header)) {
|
153 |
continue;
|
154 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
$fileinfo = $this->header2fileinfo($header);
|
156 |
|
157 |
// apply strip rules
|
166 |
// create output directory
|
167 |
$output = $outdir.'/'.$fileinfo->getPath();
|
168 |
$directory = ($fileinfo->getIsdir()) ? $output : dirname($output);
|
169 |
+
@mkdir($directory, 0777, true);
|
|
|
|
|
|
|
170 |
|
171 |
// extract data
|
172 |
if (!$fileinfo->getIsdir()) {
|
173 |
+
$fp = @fopen($output, "wb");
|
|
|
|
|
|
|
174 |
if (!$fp) {
|
175 |
throw new ArchiveIOException('Could not open file for writing: '.$output);
|
176 |
}
|
184 |
}
|
185 |
|
186 |
fclose($fp);
|
187 |
+
@touch($output, $fileinfo->getMtime());
|
188 |
+
@chmod($output, $fileinfo->getMode());
|
189 |
} else {
|
190 |
+
$this->skipbytes(ceil($header['size'] / 512) * 512); // the size is usually 0 for directories
|
|
|
191 |
}
|
192 |
|
193 |
+
if(is_callable($this->callback)) {
|
194 |
+
call_user_func($this->callback, $fileinfo);
|
195 |
+
}
|
196 |
$extracted[] = $fileinfo;
|
197 |
}
|
198 |
|
199 |
$this->close();
|
200 |
+
return $extracted;
|
|
|
|
|
|
|
201 |
}
|
202 |
|
203 |
/**
|
207 |
*
|
208 |
* @param string $file
|
209 |
* @throws ArchiveIOException
|
210 |
+
* @throws ArchiveIllegalCompressionException
|
211 |
*/
|
212 |
public function create($file = '')
|
213 |
{
|
240 |
/**
|
241 |
* Add a file to the current TAR archive using an existing file in the filesystem
|
242 |
*
|
243 |
+
* @param string $file path to the original file
|
244 |
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
245 |
+
* @throws ArchiveCorruptedException when the file changes while reading it, the archive will be corrupt and should be deleted
|
246 |
+
* @throws ArchiveIOException there was trouble reading the given file, it was not added
|
247 |
+
* @throws FileInfoException trouble reading file info, it was not added
|
248 |
*/
|
249 |
public function addFile($file, $fileinfo = '')
|
250 |
{
|
256 |
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
257 |
}
|
258 |
|
259 |
+
$fp = @fopen($file, 'rb');
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
if (!$fp) {
|
261 |
throw new ArchiveIOException('Could not open file for reading: '.$file);
|
262 |
}
|
263 |
|
264 |
// create file header
|
|
|
|
|
|
|
|
|
265 |
$this->writeFileHeader($fileinfo);
|
266 |
|
267 |
// write data
|
268 |
+
$read = 0;
|
269 |
while (!feof($fp)) {
|
270 |
$data = fread($fp, 512);
|
271 |
+
$read += strlen($data);
|
272 |
if ($data === false) {
|
273 |
break;
|
274 |
}
|
278 |
$packed = pack("a512", $data);
|
279 |
$this->writebytes($packed);
|
280 |
}
|
281 |
+
fclose($fp);
|
282 |
|
283 |
+
if($read != $fileinfo->getSize()) {
|
284 |
+
$this->close();
|
285 |
+
throw new ArchiveCorruptedException("The size of $file changed while reading, archive corrupted. read $read expected ".$fileinfo->getSize());
|
286 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
|
288 |
+
if(is_callable($this->callback)) {
|
289 |
+
call_user_func($this->callback, $fileinfo);
|
290 |
+
}
|
291 |
}
|
292 |
|
293 |
/**
|
314 |
for ($s = 0; $s < $len; $s += 512) {
|
315 |
$this->writebytes(pack("a512", substr($data, $s, 512)));
|
316 |
}
|
317 |
+
|
318 |
+
if (is_callable($this->callback)) {
|
319 |
+
call_user_func($this->callback, $fileinfo);
|
320 |
+
}
|
321 |
}
|
322 |
|
323 |
/**
|
330 |
* consists of two 512 blocks of zero bytes"
|
331 |
*
|
332 |
* @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
|
333 |
+
* @throws ArchiveIOException
|
334 |
*/
|
335 |
public function close()
|
336 |
{
|
366 |
* Returns the created in-memory archive data
|
367 |
*
|
368 |
* This implicitly calls close() on the Archive
|
369 |
+
* @throws ArchiveIOException
|
370 |
*/
|
371 |
public function getArchive()
|
372 |
{
|
393 |
*
|
394 |
* @param string $file
|
395 |
* @throws ArchiveIOException
|
396 |
+
* @throws ArchiveIllegalCompressionException
|
397 |
*/
|
398 |
public function save($file)
|
399 |
{
|
401 |
$this->setCompression($this->complevel, $this->filetype($file));
|
402 |
}
|
403 |
|
404 |
+
if (!@file_put_contents($file, $this->getArchive())) {
|
405 |
throw new ArchiveIOException('Could not write to file: '.$file);
|
406 |
}
|
407 |
}
|
445 |
if ($written === false) {
|
446 |
throw new ArchiveIOException('Failed to write to archive stream');
|
447 |
}
|
|
|
448 |
return $written;
|
449 |
}
|
450 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
/**
|
452 |
* Skip forward in the open file pointer
|
453 |
*
|
455 |
*
|
456 |
* @param int $bytes seek to this position
|
457 |
*/
|
458 |
+
protected function skipbytes($bytes)
|
459 |
{
|
460 |
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
461 |
@gzseek($this->fh, $bytes, SEEK_CUR);
|
473 |
}
|
474 |
|
475 |
/**
|
476 |
+
* Write the given file meta data as header
|
477 |
*
|
478 |
* @param FileInfo $fileinfo
|
479 |
+
* @throws ArchiveIOException
|
480 |
*/
|
481 |
protected function writeFileHeader(FileInfo $fileinfo)
|
482 |
{
|
495 |
* Write a file header to the stream
|
496 |
*
|
497 |
* @param string $name
|
498 |
+
* @param int $uid
|
499 |
+
* @param int $gid
|
500 |
+
* @param int $perm
|
501 |
+
* @param int $size
|
502 |
+
* @param int $mtime
|
503 |
* @param string $typeflag Set to '5' for directories
|
504 |
+
* @throws ArchiveIOException
|
505 |
*/
|
506 |
protected function writeRawFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '')
|
507 |
{
|
577 |
"a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix",
|
578 |
$block
|
579 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
580 |
if (!$header) {
|
581 |
throw new ArchiveCorruptedException('Failed to parse header');
|
582 |
}
|
|
|
583 |
|
584 |
+
$return['checksum'] = OctDec(trim($header['checksum']));
|
585 |
if ($return['checksum'] != $chks) {
|
586 |
+
throw new ArchiveCorruptedException('Header does not match it\'s checksum');
|
|
|
587 |
}
|
588 |
|
589 |
$return['filename'] = trim($header['filename']);
|
602 |
$return['filename'] = trim($header['prefix']).'/'.$return['filename'];
|
603 |
}
|
604 |
|
605 |
+
// Handle Long-Link entries from GNU Tar
|
606 |
if ($return['typeflag'] == 'L') {
|
607 |
// following data block(s) is the filename
|
608 |
$filename = trim($this->readbytes(ceil($return['size'] / 512) * 512));
|
609 |
// next block is the real header
|
610 |
$block = $this->readbytes(512);
|
611 |
$return = $this->parseHeader($block);
|
|
|
612 |
// overwrite the filename
|
613 |
+
$return['filename'] = $filename;
|
|
|
|
|
|
|
|
|
|
|
|
|
614 |
}
|
615 |
|
616 |
return $return;
|
669 |
{
|
670 |
// for existing files, try to read the magic bytes
|
671 |
if(file_exists($file) && is_readable($file) && filesize($file) > 5) {
|
672 |
+
$fh = @fopen($file, 'rb');
|
673 |
if(!$fh) return false;
|
674 |
$magic = fread($fh, 5);
|
675 |
fclose($fh);
|
688 |
|
689 |
return Archive::COMPRESS_NONE;
|
690 |
}
|
691 |
+
|
692 |
}
|
vendor/splitbrain/php-archive/src/Zip.php
CHANGED
@@ -34,10 +34,13 @@ class Zip extends Archive
|
|
34 |
*
|
35 |
* @param int $level Compression level (0 to 9)
|
36 |
* @param int $type Type of compression to use ignored for ZIP
|
37 |
-
* @
|
38 |
*/
|
39 |
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
40 |
{
|
|
|
|
|
|
|
41 |
$this->complevel = $level;
|
42 |
}
|
43 |
|
@@ -152,6 +155,9 @@ class Zip extends Archive
|
|
152 |
|
153 |
// nothing more to do for directories
|
154 |
if ($fileinfo->getIsdir()) {
|
|
|
|
|
|
|
155 |
continue;
|
156 |
}
|
157 |
|
@@ -226,8 +232,11 @@ class Zip extends Archive
|
|
226 |
unlink($extractto); // remove temporary gz file
|
227 |
}
|
228 |
|
229 |
-
touch($output, $fileinfo->getMtime());
|
230 |
//FIXME what about permissions?
|
|
|
|
|
|
|
231 |
}
|
232 |
|
233 |
$this->close();
|
@@ -271,9 +280,10 @@ class Zip extends Archive
|
|
271 |
/**
|
272 |
* Add a file to the current archive using an existing file in the filesystem
|
273 |
*
|
274 |
-
* @param string
|
275 |
* @param string|FileInfo $fileinfo either the name to use in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
276 |
* @throws ArchiveIOException
|
|
|
277 |
*/
|
278 |
public function addFile($file, $fileinfo = '')
|
279 |
{
|
@@ -350,6 +360,10 @@ class Zip extends Archive
|
|
350 |
$name,
|
351 |
(bool) $this->complevel
|
352 |
);
|
|
|
|
|
|
|
|
|
353 |
}
|
354 |
|
355 |
/**
|
@@ -357,6 +371,7 @@ class Zip extends Archive
|
|
357 |
*
|
358 |
* After a call to this function no more data can be added to the archive, for
|
359 |
* read access no reading is allowed anymore
|
|
|
360 |
*/
|
361 |
public function close()
|
362 |
{
|
@@ -400,6 +415,7 @@ class Zip extends Archive
|
|
400 |
* Returns the created in-memory archive data
|
401 |
*
|
402 |
* This implicitly calls close() on the Archive
|
|
|
403 |
*/
|
404 |
public function getArchive()
|
405 |
{
|
34 |
*
|
35 |
* @param int $level Compression level (0 to 9)
|
36 |
* @param int $type Type of compression to use ignored for ZIP
|
37 |
+
* @throws ArchiveIllegalCompressionException
|
38 |
*/
|
39 |
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
40 |
{
|
41 |
+
if ($level < -1 || $level > 9) {
|
42 |
+
throw new ArchiveIllegalCompressionException('Compression level should be between -1 and 9');
|
43 |
+
}
|
44 |
$this->complevel = $level;
|
45 |
}
|
46 |
|
155 |
|
156 |
// nothing more to do for directories
|
157 |
if ($fileinfo->getIsdir()) {
|
158 |
+
if(is_callable($this->callback)) {
|
159 |
+
call_user_func($this->callback, $fileinfo);
|
160 |
+
}
|
161 |
continue;
|
162 |
}
|
163 |
|
232 |
unlink($extractto); // remove temporary gz file
|
233 |
}
|
234 |
|
235 |
+
@touch($output, $fileinfo->getMtime());
|
236 |
//FIXME what about permissions?
|
237 |
+
if(is_callable($this->callback)) {
|
238 |
+
call_user_func($this->callback, $fileinfo);
|
239 |
+
}
|
240 |
}
|
241 |
|
242 |
$this->close();
|
280 |
/**
|
281 |
* Add a file to the current archive using an existing file in the filesystem
|
282 |
*
|
283 |
+
* @param string $file path to the original file
|
284 |
* @param string|FileInfo $fileinfo either the name to use in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
285 |
* @throws ArchiveIOException
|
286 |
+
* @throws FileInfoException
|
287 |
*/
|
288 |
public function addFile($file, $fileinfo = '')
|
289 |
{
|
360 |
$name,
|
361 |
(bool) $this->complevel
|
362 |
);
|
363 |
+
|
364 |
+
if(is_callable($this->callback)) {
|
365 |
+
call_user_func($this->callback, $fileinfo);
|
366 |
+
}
|
367 |
}
|
368 |
|
369 |
/**
|
371 |
*
|
372 |
* After a call to this function no more data can be added to the archive, for
|
373 |
* read access no reading is allowed anymore
|
374 |
+
* @throws ArchiveIOException
|
375 |
*/
|
376 |
public function close()
|
377 |
{
|
415 |
* Returns the created in-memory archive data
|
416 |
*
|
417 |
* This implicitly calls close() on the Archive
|
418 |
+
* @throws ArchiveIOException
|
419 |
*/
|
420 |
public function getArchive()
|
421 |
{
|
vendor/splitbrain/php-archive/tests/FileInfoTest.php
CHANGED
@@ -1,8 +1,7 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
5 |
-
use splitbrain\PHPArchive\FileInfo;
|
6 |
use PHPUnit\Framework\TestCase;
|
7 |
|
8 |
class FileInfoTest extends TestCase
|
@@ -101,10 +100,10 @@ class FileInfoTest extends TestCase
|
|
101 |
}
|
102 |
|
103 |
/**
|
104 |
-
* @expectedException splitbrain\PHPArchive\FileInfoException
|
105 |
*/
|
106 |
public function testFromPathWithFileNotExisted()
|
107 |
{
|
108 |
-
|
109 |
}
|
110 |
}
|
1 |
+
<?php /** @noinspection PhpUnhandledExceptionInspection */
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
|
|
5 |
use PHPUnit\Framework\TestCase;
|
6 |
|
7 |
class FileInfoTest extends TestCase
|
100 |
}
|
101 |
|
102 |
/**
|
103 |
+
* @expectedException \splitbrain\PHPArchive\FileInfoException
|
104 |
*/
|
105 |
public function testFromPathWithFileNotExisted()
|
106 |
{
|
107 |
+
FileInfo::fromPath('invalid_file_path');
|
108 |
}
|
109 |
}
|
vendor/splitbrain/php-archive/tests/TarTestCase.php
CHANGED
@@ -1,18 +1,21 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
5 |
-
use splitbrain\PHPArchive\Tar;
|
6 |
-
use PHPUnit\Framework\TestCase;
|
7 |
use org\bovigo\vfs\vfsStream;
|
|
|
8 |
|
9 |
class TarTestCase extends TestCase
|
10 |
{
|
|
|
|
|
|
|
11 |
/**
|
12 |
* file extensions that several tests use
|
13 |
*/
|
14 |
protected $extensions = array('tar');
|
15 |
|
|
|
16 |
protected function setUp()
|
17 |
{
|
18 |
parent::setUp();
|
@@ -27,12 +30,22 @@ class TarTestCase extends TestCase
|
|
27 |
vfsStream::setup('home_root_path');
|
28 |
}
|
29 |
|
|
|
30 |
protected function tearDown()
|
31 |
{
|
32 |
parent::tearDown();
|
33 |
$this->extensions[] = null;
|
34 |
}
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
/*
|
37 |
* dependency for tests needing zlib extension to pass
|
38 |
*/
|
@@ -50,7 +63,7 @@ class TarTestCase extends TestCase
|
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
54 |
*/
|
55 |
public function testTarFileIsNotExisted()
|
56 |
{
|
@@ -149,6 +162,7 @@ class TarTestCase extends TestCase
|
|
149 |
$file = "$dir/test.$ext";
|
150 |
|
151 |
$tar->open($file);
|
|
|
152 |
$content = $tar->contents();
|
153 |
|
154 |
$this->assertCount(4, $content, "Contents of $file");
|
@@ -170,7 +184,9 @@ class TarTestCase extends TestCase
|
|
170 |
$archive = sys_get_temp_dir() . '/dwtartest' . md5(time()) . '.' . $ext;
|
171 |
$extract = sys_get_temp_dir() . '/dwtartest' . md5(time() + 1);
|
172 |
|
|
|
173 |
$tar = new Tar();
|
|
|
174 |
$tar->create($archive);
|
175 |
foreach ($input as $path) {
|
176 |
$file = basename($path);
|
@@ -178,8 +194,11 @@ class TarTestCase extends TestCase
|
|
178 |
}
|
179 |
$tar->close();
|
180 |
$this->assertFileExists($archive);
|
|
|
181 |
|
|
|
182 |
$tar = new Tar();
|
|
|
183 |
$tar->open($archive);
|
184 |
$tar->extract($extract, '', '/FileInfo\\.php/', '/.*\\.php/');
|
185 |
|
@@ -187,6 +206,8 @@ class TarTestCase extends TestCase
|
|
187 |
$this->assertFileExists("$extract/Zip.php");
|
188 |
$this->assertFileNotExists("$extract/FileInfo.php");
|
189 |
|
|
|
|
|
190 |
$this->nativeCheck($archive, $ext);
|
191 |
|
192 |
self::RDelete($extract);
|
@@ -575,7 +596,8 @@ class TarTestCase extends TestCase
|
|
575 |
try {
|
576 |
$phar = new \PharData($archive);
|
577 |
$phar->extractTo($extract);
|
578 |
-
} catch
|
|
|
579 |
|
580 |
$this->assertFileExists("$extract/Tar.php");
|
581 |
$this->assertFileExists("$extract/Zip.php");
|
@@ -588,7 +610,7 @@ class TarTestCase extends TestCase
|
|
588 |
}
|
589 |
|
590 |
/**
|
591 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
592 |
*/
|
593 |
public function testContentsWithInvalidArchiveStream()
|
594 |
{
|
@@ -597,7 +619,7 @@ class TarTestCase extends TestCase
|
|
597 |
}
|
598 |
|
599 |
/**
|
600 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
601 |
*/
|
602 |
public function testExtractWithInvalidOutDir()
|
603 |
{
|
@@ -611,7 +633,7 @@ class TarTestCase extends TestCase
|
|
611 |
}
|
612 |
|
613 |
/**
|
614 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
615 |
*/
|
616 |
public function testExtractWithArchiveStreamIsClosed()
|
617 |
{
|
@@ -626,7 +648,7 @@ class TarTestCase extends TestCase
|
|
626 |
}
|
627 |
|
628 |
/**
|
629 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
630 |
*/
|
631 |
public function testCreateWithInvalidFile()
|
632 |
{
|
@@ -638,7 +660,7 @@ class TarTestCase extends TestCase
|
|
638 |
}
|
639 |
|
640 |
/**
|
641 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
642 |
*/
|
643 |
public function testAddFileWithArchiveStreamIsClosed()
|
644 |
{
|
@@ -651,7 +673,7 @@ class TarTestCase extends TestCase
|
|
651 |
}
|
652 |
|
653 |
/**
|
654 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
655 |
*/
|
656 |
public function testAddFileWithInvalidFile()
|
657 |
{
|
@@ -663,7 +685,7 @@ class TarTestCase extends TestCase
|
|
663 |
}
|
664 |
|
665 |
/**
|
666 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
667 |
*/
|
668 |
public function testAddDataWithArchiveStreamIsClosed()
|
669 |
{
|
@@ -683,7 +705,8 @@ class TarTestCase extends TestCase
|
|
683 |
$tar->create($archive);
|
684 |
$tar->close();
|
685 |
|
686 |
-
$
|
|
|
687 |
}
|
688 |
|
689 |
/**
|
@@ -709,11 +732,12 @@ class TarTestCase extends TestCase
|
|
709 |
$tar->create();
|
710 |
$tar->addFile("$dir/zero.txt", 'zero.txt');
|
711 |
|
712 |
-
$
|
|
|
713 |
}
|
714 |
|
715 |
-
|
716 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
717 |
*/
|
718 |
public function testSaveWithInvalidDestinationFile()
|
719 |
{
|
@@ -723,7 +747,8 @@ class TarTestCase extends TestCase
|
|
723 |
$tar->create();
|
724 |
$tar->addFile("$dir/zero.txt", 'zero.txt');
|
725 |
|
726 |
-
$
|
|
|
727 |
}
|
728 |
|
729 |
/**
|
1 |
+
<?php /** @noinspection PhpUnhandledExceptionInspection */
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
|
|
|
|
5 |
use org\bovigo\vfs\vfsStream;
|
6 |
+
use PHPUnit\Framework\TestCase;
|
7 |
|
8 |
class TarTestCase extends TestCase
|
9 |
{
|
10 |
+
/** @var int callback counter */
|
11 |
+
protected $counter = 0;
|
12 |
+
|
13 |
/**
|
14 |
* file extensions that several tests use
|
15 |
*/
|
16 |
protected $extensions = array('tar');
|
17 |
|
18 |
+
/** @inheritdoc */
|
19 |
protected function setUp()
|
20 |
{
|
21 |
parent::setUp();
|
30 |
vfsStream::setup('home_root_path');
|
31 |
}
|
32 |
|
33 |
+
/** @inheritdoc */
|
34 |
protected function tearDown()
|
35 |
{
|
36 |
parent::tearDown();
|
37 |
$this->extensions[] = null;
|
38 |
}
|
39 |
|
40 |
+
/**
|
41 |
+
* Callback check function
|
42 |
+
* @param FileInfo $fileinfo
|
43 |
+
*/
|
44 |
+
public function increaseCounter($fileinfo) {
|
45 |
+
$this->assertInstanceOf('\\splitbrain\\PHPArchive\\FileInfo', $fileinfo);
|
46 |
+
$this->counter++;
|
47 |
+
}
|
48 |
+
|
49 |
/*
|
50 |
* dependency for tests needing zlib extension to pass
|
51 |
*/
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
67 |
*/
|
68 |
public function testTarFileIsNotExisted()
|
69 |
{
|
162 |
$file = "$dir/test.$ext";
|
163 |
|
164 |
$tar->open($file);
|
165 |
+
/** @var FileInfo[] $content */
|
166 |
$content = $tar->contents();
|
167 |
|
168 |
$this->assertCount(4, $content, "Contents of $file");
|
184 |
$archive = sys_get_temp_dir() . '/dwtartest' . md5(time()) . '.' . $ext;
|
185 |
$extract = sys_get_temp_dir() . '/dwtartest' . md5(time() + 1);
|
186 |
|
187 |
+
$this->counter = 0;
|
188 |
$tar = new Tar();
|
189 |
+
$tar->setCallback(array($this, 'increaseCounter'));
|
190 |
$tar->create($archive);
|
191 |
foreach ($input as $path) {
|
192 |
$file = basename($path);
|
194 |
}
|
195 |
$tar->close();
|
196 |
$this->assertFileExists($archive);
|
197 |
+
$this->assertEquals(count($input), $this->counter);
|
198 |
|
199 |
+
$this->counter = 0;
|
200 |
$tar = new Tar();
|
201 |
+
$tar->setCallback(array($this, 'increaseCounter'));
|
202 |
$tar->open($archive);
|
203 |
$tar->extract($extract, '', '/FileInfo\\.php/', '/.*\\.php/');
|
204 |
|
206 |
$this->assertFileExists("$extract/Zip.php");
|
207 |
$this->assertFileNotExists("$extract/FileInfo.php");
|
208 |
|
209 |
+
$this->assertEquals(count($input) - 1, $this->counter);
|
210 |
+
|
211 |
$this->nativeCheck($archive, $ext);
|
212 |
|
213 |
self::RDelete($extract);
|
596 |
try {
|
597 |
$phar = new \PharData($archive);
|
598 |
$phar->extractTo($extract);
|
599 |
+
} catch(\Exception $e) {
|
600 |
+
};
|
601 |
|
602 |
$this->assertFileExists("$extract/Tar.php");
|
603 |
$this->assertFileExists("$extract/Zip.php");
|
610 |
}
|
611 |
|
612 |
/**
|
613 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
614 |
*/
|
615 |
public function testContentsWithInvalidArchiveStream()
|
616 |
{
|
619 |
}
|
620 |
|
621 |
/**
|
622 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
623 |
*/
|
624 |
public function testExtractWithInvalidOutDir()
|
625 |
{
|
633 |
}
|
634 |
|
635 |
/**
|
636 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
637 |
*/
|
638 |
public function testExtractWithArchiveStreamIsClosed()
|
639 |
{
|
648 |
}
|
649 |
|
650 |
/**
|
651 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
652 |
*/
|
653 |
public function testCreateWithInvalidFile()
|
654 |
{
|
660 |
}
|
661 |
|
662 |
/**
|
663 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
664 |
*/
|
665 |
public function testAddFileWithArchiveStreamIsClosed()
|
666 |
{
|
673 |
}
|
674 |
|
675 |
/**
|
676 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
677 |
*/
|
678 |
public function testAddFileWithInvalidFile()
|
679 |
{
|
685 |
}
|
686 |
|
687 |
/**
|
688 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
689 |
*/
|
690 |
public function testAddDataWithArchiveStreamIsClosed()
|
691 |
{
|
705 |
$tar->create($archive);
|
706 |
$tar->close();
|
707 |
|
708 |
+
$tar->close();
|
709 |
+
$this->assertTrue(true); // succeed if no exception, yet
|
710 |
}
|
711 |
|
712 |
/**
|
732 |
$tar->create();
|
733 |
$tar->addFile("$dir/zero.txt", 'zero.txt');
|
734 |
|
735 |
+
$tar->save(vfsStream::url('home_root_path/archive_file'));
|
736 |
+
$this->assertTrue(true); // succeed if no exception, yet
|
737 |
}
|
738 |
|
739 |
+
/**
|
740 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
741 |
*/
|
742 |
public function testSaveWithInvalidDestinationFile()
|
743 |
{
|
747 |
$tar->create();
|
748 |
$tar->addFile("$dir/zero.txt", 'zero.txt');
|
749 |
|
750 |
+
$tar->save(vfsStream::url('archive_file'));
|
751 |
+
$this->assertTrue(true); // succeed if no exception, yet
|
752 |
}
|
753 |
|
754 |
/**
|
vendor/splitbrain/php-archive/tests/ZipTestCase.php
CHANGED
@@ -1,18 +1,30 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
5 |
-
use splitbrain\PHPArchive\Zip;
|
6 |
-
use PHPUnit\Framework\TestCase;
|
7 |
use org\bovigo\vfs\vfsStream;
|
|
|
8 |
|
9 |
class ZipTestCase extends TestCase
|
10 |
{
|
|
|
|
|
|
|
|
|
11 |
protected function setUp()
|
12 |
{
|
13 |
vfsStream::setup('home_root_path');
|
14 |
}
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
/*
|
17 |
* dependency for tests needing zip extension to pass
|
18 |
*/
|
@@ -22,7 +34,7 @@ class ZipTestCase extends TestCase
|
|
22 |
}
|
23 |
|
24 |
/**
|
25 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
26 |
*/
|
27 |
public function testMissing()
|
28 |
{
|
@@ -41,7 +53,7 @@ class ZipTestCase extends TestCase
|
|
41 |
{
|
42 |
$zip = new Zip();
|
43 |
|
44 |
-
$dir
|
45 |
$tdir = ltrim($dir, '/');
|
46 |
|
47 |
$zip->create();
|
@@ -81,9 +93,9 @@ class ZipTestCase extends TestCase
|
|
81 |
{
|
82 |
$zip = new Zip();
|
83 |
|
84 |
-
$dir
|
85 |
$tdir = ltrim($dir, '/');
|
86 |
-
$tmp
|
87 |
|
88 |
$zip->create($tmp);
|
89 |
$zip->setCompression(0);
|
@@ -114,27 +126,25 @@ class ZipTestCase extends TestCase
|
|
114 |
}
|
115 |
|
116 |
/**
|
117 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
118 |
*/
|
119 |
public function testCreateWithInvalidFilePath()
|
120 |
{
|
121 |
$zip = new Zip();
|
122 |
|
123 |
-
$
|
124 |
-
$tmp = vfsStream::url('invalid_root_path/test.zip');
|
125 |
|
126 |
$zip->create($tmp);
|
127 |
}
|
128 |
|
129 |
/**
|
130 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
131 |
*/
|
132 |
public function testAddFileWithArchiveStreamIsClosed()
|
133 |
{
|
134 |
$zip = new Zip();
|
135 |
|
136 |
-
$dir
|
137 |
-
$tmp = vfsStream::url('home_root_path/test.zip');
|
138 |
|
139 |
$zip->setCompression(0);
|
140 |
$zip->close();
|
@@ -142,13 +152,13 @@ class ZipTestCase extends TestCase
|
|
142 |
}
|
143 |
|
144 |
/**
|
145 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
146 |
*/
|
147 |
public function testAddFileWithInvalidFile()
|
148 |
{
|
149 |
$zip = new Zip();
|
150 |
|
151 |
-
$tmp
|
152 |
|
153 |
$zip->create($tmp);
|
154 |
$zip->setCompression(0);
|
@@ -162,9 +172,9 @@ class ZipTestCase extends TestCase
|
|
162 |
*/
|
163 |
public function testZipContent()
|
164 |
{
|
165 |
-
$dir = dirname(__FILE__).'/zip';
|
166 |
|
167 |
-
$zip
|
168 |
$file = "$dir/test.zip";
|
169 |
|
170 |
$zip->open($file);
|
@@ -179,18 +189,18 @@ class ZipTestCase extends TestCase
|
|
179 |
}
|
180 |
|
181 |
/**
|
182 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
183 |
*/
|
184 |
public function testZipContentWithArchiveStreamIsClosed()
|
185 |
{
|
186 |
-
$dir = dirname(__FILE__).'/zip';
|
187 |
|
188 |
-
$zip
|
189 |
$file = "$dir/test.zip";
|
190 |
|
191 |
$zip->open($file);
|
192 |
$zip->close();
|
193 |
-
$
|
194 |
}
|
195 |
|
196 |
/**
|
@@ -203,16 +213,21 @@ class ZipTestCase extends TestCase
|
|
203 |
$archive = sys_get_temp_dir() . '/dwziptest' . md5(time()) . '.zip';
|
204 |
$extract = sys_get_temp_dir() . '/dwziptest' . md5(time() + 1);
|
205 |
|
|
|
206 |
$zip = new Zip();
|
|
|
207 |
$zip->create($archive);
|
208 |
-
foreach($input as $path) {
|
209 |
$file = basename($path);
|
210 |
$zip->addFile($path, $file);
|
211 |
}
|
212 |
$zip->close();
|
213 |
$this->assertFileExists($archive);
|
|
|
214 |
|
|
|
215 |
$zip = new Zip();
|
|
|
216 |
$zip->open($archive);
|
217 |
$zip->extract($extract, '', '/FileInfo\\.php/', '/.*\\.php/');
|
218 |
|
@@ -220,6 +235,8 @@ class ZipTestCase extends TestCase
|
|
220 |
$this->assertFileExists("$extract/Zip.php");
|
221 |
$this->assertFileNotExists("$extract/FileInfo.php");
|
222 |
|
|
|
|
|
223 |
$this->nativeCheck($archive);
|
224 |
$this->native7ZipCheck($archive);
|
225 |
|
@@ -246,8 +263,8 @@ class ZipTestCase extends TestCase
|
|
246 |
$zip->open($archive);
|
247 |
$zip->extract($extract);
|
248 |
|
249 |
-
$this->assertFileExists($extract.'/tüst.txt');
|
250 |
-
$this->assertFileExists($extract.'/snowy☃.txt');
|
251 |
|
252 |
$this->nativeCheck($archive);
|
253 |
$this->native7ZipCheck($archive);
|
@@ -257,7 +274,7 @@ class ZipTestCase extends TestCase
|
|
257 |
}
|
258 |
|
259 |
/**
|
260 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
261 |
*/
|
262 |
public function testAddDataWithArchiveStreamIsClosed()
|
263 |
{
|
@@ -277,7 +294,8 @@ class ZipTestCase extends TestCase
|
|
277 |
$zip->create($archive);
|
278 |
$zip->close();
|
279 |
|
280 |
-
$
|
|
|
281 |
}
|
282 |
|
283 |
public function testSaveArchiveFile()
|
@@ -288,11 +306,12 @@ class ZipTestCase extends TestCase
|
|
288 |
$zip->create();
|
289 |
$zip->addFile("$dir/zero.txt", 'zero.txt');
|
290 |
|
291 |
-
$
|
|
|
292 |
}
|
293 |
|
294 |
/**
|
295 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
296 |
*/
|
297 |
public function testSaveWithInvalidFilePath()
|
298 |
{
|
@@ -353,10 +372,10 @@ class ZipTestCase extends TestCase
|
|
353 |
*/
|
354 |
public function testZipExtract()
|
355 |
{
|
356 |
-
$dir = dirname(__FILE__).'/zip';
|
357 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
358 |
|
359 |
-
$zip
|
360 |
$file = "$dir/test.zip";
|
361 |
|
362 |
$zip->open($file);
|
@@ -364,28 +383,28 @@ class ZipTestCase extends TestCase
|
|
364 |
|
365 |
clearstatcache();
|
366 |
|
367 |
-
$this->assertFileExists($out.'/zip/testdata1.txt', "Extracted $file");
|
368 |
-
$this->assertEquals(13, filesize($out.'/zip/testdata1.txt'), "Extracted $file");
|
369 |
|
370 |
-
$this->assertFileExists($out.'/zip/foobar/testdata2.txt', "Extracted $file");
|
371 |
-
$this->assertEquals(13, filesize($out.'/zip/foobar/testdata2.txt'), "Extracted $file");
|
372 |
|
373 |
-
$this->assertFileExists($out.'/zip/compressable.txt', "Extracted $file");
|
374 |
-
$this->assertEquals(1836, filesize($out.'/zip/compressable.txt'), "Extracted $file");
|
375 |
-
$this->assertFileNotExists($out.'/zip/compressable.txt.gz', "Extracted $file");
|
376 |
|
377 |
self::RDelete($out);
|
378 |
}
|
379 |
|
380 |
/**
|
381 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
382 |
*/
|
383 |
public function testZipExtractWithArchiveStreamIsClosed()
|
384 |
{
|
385 |
-
$dir = dirname(__FILE__).'/zip';
|
386 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
387 |
|
388 |
-
$zip
|
389 |
$file = "$dir/test.zip";
|
390 |
|
391 |
$zip->open($file);
|
@@ -399,10 +418,10 @@ class ZipTestCase extends TestCase
|
|
399 |
*/
|
400 |
public function testCompStripExtract()
|
401 |
{
|
402 |
-
$dir = dirname(__FILE__).'/zip';
|
403 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
404 |
|
405 |
-
$zip
|
406 |
$file = "$dir/test.zip";
|
407 |
|
408 |
$zip->open($file);
|
@@ -410,11 +429,11 @@ class ZipTestCase extends TestCase
|
|
410 |
|
411 |
clearstatcache();
|
412 |
|
413 |
-
$this->assertFileExists($out.'/testdata1.txt', "Extracted $file");
|
414 |
-
$this->assertEquals(13, filesize($out.'/testdata1.txt'), "Extracted $file");
|
415 |
|
416 |
-
$this->assertFileExists($out.'/foobar/testdata2.txt', "Extracted $file");
|
417 |
-
$this->assertEquals(13, filesize($out.'/foobar/testdata2.txt'), "Extracted $file");
|
418 |
|
419 |
self::RDelete($out);
|
420 |
}
|
@@ -425,10 +444,10 @@ class ZipTestCase extends TestCase
|
|
425 |
*/
|
426 |
public function testPrefixStripExtract()
|
427 |
{
|
428 |
-
$dir = dirname(__FILE__).'/zip';
|
429 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
430 |
|
431 |
-
$zip
|
432 |
$file = "$dir/test.zip";
|
433 |
|
434 |
$zip->open($file);
|
@@ -436,11 +455,11 @@ class ZipTestCase extends TestCase
|
|
436 |
|
437 |
clearstatcache();
|
438 |
|
439 |
-
$this->assertFileExists($out.'/zip/testdata1.txt', "Extracted $file");
|
440 |
-
$this->assertEquals(13, filesize($out.'/zip/testdata1.txt'), "Extracted $file");
|
441 |
|
442 |
-
$this->assertFileExists($out.'/testdata2.txt', "Extracted $file");
|
443 |
-
$this->assertEquals(13, filesize($out.'/testdata2.txt'), "Extracted $file");
|
444 |
|
445 |
self::RDelete($out);
|
446 |
}
|
@@ -451,10 +470,10 @@ class ZipTestCase extends TestCase
|
|
451 |
*/
|
452 |
public function testIncludeExtract()
|
453 |
{
|
454 |
-
$dir = dirname(__FILE__).'/zip';
|
455 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
456 |
|
457 |
-
$zip
|
458 |
$file = "$dir/test.zip";
|
459 |
|
460 |
$zip->open($file);
|
@@ -462,10 +481,10 @@ class ZipTestCase extends TestCase
|
|
462 |
|
463 |
clearstatcache();
|
464 |
|
465 |
-
$this->assertFileNotExists($out.'/zip/testdata1.txt', "Extracted $file");
|
466 |
|
467 |
-
$this->assertFileExists($out.'/zip/foobar/testdata2.txt', "Extracted $file");
|
468 |
-
$this->assertEquals(13, filesize($out.'/zip/foobar/testdata2.txt'), "Extracted $file");
|
469 |
|
470 |
self::RDelete($out);
|
471 |
}
|
@@ -476,10 +495,10 @@ class ZipTestCase extends TestCase
|
|
476 |
*/
|
477 |
public function testExcludeExtract()
|
478 |
{
|
479 |
-
$dir = dirname(__FILE__).'/zip';
|
480 |
-
$out = sys_get_temp_dir().'/dwziptest'.md5(time());
|
481 |
|
482 |
-
$zip
|
483 |
$file = "$dir/test.zip";
|
484 |
|
485 |
$zip->open($file);
|
@@ -487,10 +506,10 @@ class ZipTestCase extends TestCase
|
|
487 |
|
488 |
clearstatcache();
|
489 |
|
490 |
-
$this->assertFileExists($out.'/zip/testdata1.txt', "Extracted $file");
|
491 |
-
$this->assertEquals(13, filesize($out.'/zip/testdata1.txt'), "Extracted $file");
|
492 |
|
493 |
-
$this->assertFileNotExists($out.'/zip/foobar/testdata2.txt', "Extracted $file");
|
494 |
|
495 |
self::RDelete($out);
|
496 |
}
|
@@ -521,7 +540,6 @@ class ZipTestCase extends TestCase
|
|
521 |
$this->assertFileExists("$out/täst.txt");
|
522 |
}
|
523 |
|
524 |
-
|
525 |
/**
|
526 |
* recursive rmdir()/unlink()
|
527 |
*
|
1 |
+
<?php /** @noinspection PhpUnhandledExceptionInspection */
|
2 |
|
3 |
namespace splitbrain\PHPArchive;
|
4 |
|
|
|
|
|
5 |
use org\bovigo\vfs\vfsStream;
|
6 |
+
use PHPUnit\Framework\TestCase;
|
7 |
|
8 |
class ZipTestCase extends TestCase
|
9 |
{
|
10 |
+
/** @var int callback counter */
|
11 |
+
protected $counter = 0;
|
12 |
+
|
13 |
+
/** @inheritdoc */
|
14 |
protected function setUp()
|
15 |
{
|
16 |
vfsStream::setup('home_root_path');
|
17 |
}
|
18 |
|
19 |
+
/**
|
20 |
+
* Callback check function
|
21 |
+
* @param FileInfo $fileinfo
|
22 |
+
*/
|
23 |
+
public function increaseCounter($fileinfo) {
|
24 |
+
$this->assertInstanceOf('\\splitbrain\\PHPArchive\\FileInfo', $fileinfo);
|
25 |
+
$this->counter++;
|
26 |
+
}
|
27 |
+
|
28 |
/*
|
29 |
* dependency for tests needing zip extension to pass
|
30 |
*/
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
38 |
*/
|
39 |
public function testMissing()
|
40 |
{
|
53 |
{
|
54 |
$zip = new Zip();
|
55 |
|
56 |
+
$dir = dirname(__FILE__) . '/zip';
|
57 |
$tdir = ltrim($dir, '/');
|
58 |
|
59 |
$zip->create();
|
93 |
{
|
94 |
$zip = new Zip();
|
95 |
|
96 |
+
$dir = dirname(__FILE__) . '/zip';
|
97 |
$tdir = ltrim($dir, '/');
|
98 |
+
$tmp = vfsStream::url('home_root_path/test.zip');
|
99 |
|
100 |
$zip->create($tmp);
|
101 |
$zip->setCompression(0);
|
126 |
}
|
127 |
|
128 |
/**
|
129 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
130 |
*/
|
131 |
public function testCreateWithInvalidFilePath()
|
132 |
{
|
133 |
$zip = new Zip();
|
134 |
|
135 |
+
$tmp = vfsStream::url('invalid_root_path/test.zip');
|
|
|
136 |
|
137 |
$zip->create($tmp);
|
138 |
}
|
139 |
|
140 |
/**
|
141 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
142 |
*/
|
143 |
public function testAddFileWithArchiveStreamIsClosed()
|
144 |
{
|
145 |
$zip = new Zip();
|
146 |
|
147 |
+
$dir = dirname(__FILE__) . '/zip';
|
|
|
148 |
|
149 |
$zip->setCompression(0);
|
150 |
$zip->close();
|
152 |
}
|
153 |
|
154 |
/**
|
155 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
156 |
*/
|
157 |
public function testAddFileWithInvalidFile()
|
158 |
{
|
159 |
$zip = new Zip();
|
160 |
|
161 |
+
$tmp = vfsStream::url('home_root_path/test.zip');
|
162 |
|
163 |
$zip->create($tmp);
|
164 |
$zip->setCompression(0);
|
172 |
*/
|
173 |
public function testZipContent()
|
174 |
{
|
175 |
+
$dir = dirname(__FILE__) . '/zip';
|
176 |
|
177 |
+
$zip = new Zip();
|
178 |
$file = "$dir/test.zip";
|
179 |
|
180 |
$zip->open($file);
|
189 |
}
|
190 |
|
191 |
/**
|
192 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
193 |
*/
|
194 |
public function testZipContentWithArchiveStreamIsClosed()
|
195 |
{
|
196 |
+
$dir = dirname(__FILE__) . '/zip';
|
197 |
|
198 |
+
$zip = new Zip();
|
199 |
$file = "$dir/test.zip";
|
200 |
|
201 |
$zip->open($file);
|
202 |
$zip->close();
|
203 |
+
$zip->contents();
|
204 |
}
|
205 |
|
206 |
/**
|
213 |
$archive = sys_get_temp_dir() . '/dwziptest' . md5(time()) . '.zip';
|
214 |
$extract = sys_get_temp_dir() . '/dwziptest' . md5(time() + 1);
|
215 |
|
216 |
+
$this->counter = 0;
|
217 |
$zip = new Zip();
|
218 |
+
$zip->setCallback(array($this, 'increaseCounter'));
|
219 |
$zip->create($archive);
|
220 |
+
foreach ($input as $path) {
|
221 |
$file = basename($path);
|
222 |
$zip->addFile($path, $file);
|
223 |
}
|
224 |
$zip->close();
|
225 |
$this->assertFileExists($archive);
|
226 |
+
$this->assertEquals(count($input), $this->counter);
|
227 |
|
228 |
+
$this->counter = 0;
|
229 |
$zip = new Zip();
|
230 |
+
$zip->setCallback(array($this, 'increaseCounter'));
|
231 |
$zip->open($archive);
|
232 |
$zip->extract($extract, '', '/FileInfo\\.php/', '/.*\\.php/');
|
233 |
|
235 |
$this->assertFileExists("$extract/Zip.php");
|
236 |
$this->assertFileNotExists("$extract/FileInfo.php");
|
237 |
|
238 |
+
$this->assertEquals(count($input) - 1, $this->counter);
|
239 |
+
|
240 |
$this->nativeCheck($archive);
|
241 |
$this->native7ZipCheck($archive);
|
242 |
|
263 |
$zip->open($archive);
|
264 |
$zip->extract($extract);
|
265 |
|
266 |
+
$this->assertFileExists($extract . '/tüst.txt');
|
267 |
+
$this->assertFileExists($extract . '/snowy☃.txt');
|
268 |
|
269 |
$this->nativeCheck($archive);
|
270 |
$this->native7ZipCheck($archive);
|
274 |
}
|
275 |
|
276 |
/**
|
277 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
278 |
*/
|
279 |
public function testAddDataWithArchiveStreamIsClosed()
|
280 |
{
|
294 |
$zip->create($archive);
|
295 |
$zip->close();
|
296 |
|
297 |
+
$zip->close();
|
298 |
+
$this->assertTrue(true); // succeed if no exception, yet
|
299 |
}
|
300 |
|
301 |
public function testSaveArchiveFile()
|
306 |
$zip->create();
|
307 |
$zip->addFile("$dir/zero.txt", 'zero.txt');
|
308 |
|
309 |
+
$zip->save(vfsStream::url('home_root_path/archive_file'));
|
310 |
+
$this->assertTrue(true); // succeed if no exception, yet
|
311 |
}
|
312 |
|
313 |
/**
|
314 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
315 |
*/
|
316 |
public function testSaveWithInvalidFilePath()
|
317 |
{
|
372 |
*/
|
373 |
public function testZipExtract()
|
374 |
{
|
375 |
+
$dir = dirname(__FILE__) . '/zip';
|
376 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
377 |
|
378 |
+
$zip = new Zip();
|
379 |
$file = "$dir/test.zip";
|
380 |
|
381 |
$zip->open($file);
|
383 |
|
384 |
clearstatcache();
|
385 |
|
386 |
+
$this->assertFileExists($out . '/zip/testdata1.txt', "Extracted $file");
|
387 |
+
$this->assertEquals(13, filesize($out . '/zip/testdata1.txt'), "Extracted $file");
|
388 |
|
389 |
+
$this->assertFileExists($out . '/zip/foobar/testdata2.txt', "Extracted $file");
|
390 |
+
$this->assertEquals(13, filesize($out . '/zip/foobar/testdata2.txt'), "Extracted $file");
|
391 |
|
392 |
+
$this->assertFileExists($out . '/zip/compressable.txt', "Extracted $file");
|
393 |
+
$this->assertEquals(1836, filesize($out . '/zip/compressable.txt'), "Extracted $file");
|
394 |
+
$this->assertFileNotExists($out . '/zip/compressable.txt.gz', "Extracted $file");
|
395 |
|
396 |
self::RDelete($out);
|
397 |
}
|
398 |
|
399 |
/**
|
400 |
+
* @expectedException \splitbrain\PHPArchive\ArchiveIOException
|
401 |
*/
|
402 |
public function testZipExtractWithArchiveStreamIsClosed()
|
403 |
{
|
404 |
+
$dir = dirname(__FILE__) . '/zip';
|
405 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
406 |
|
407 |
+
$zip = new Zip();
|
408 |
$file = "$dir/test.zip";
|
409 |
|
410 |
$zip->open($file);
|
418 |
*/
|
419 |
public function testCompStripExtract()
|
420 |
{
|
421 |
+
$dir = dirname(__FILE__) . '/zip';
|
422 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
423 |
|
424 |
+
$zip = new Zip();
|
425 |
$file = "$dir/test.zip";
|
426 |
|
427 |
$zip->open($file);
|
429 |
|
430 |
clearstatcache();
|
431 |
|
432 |
+
$this->assertFileExists($out . '/testdata1.txt', "Extracted $file");
|
433 |
+
$this->assertEquals(13, filesize($out . '/testdata1.txt'), "Extracted $file");
|
434 |
|
435 |
+
$this->assertFileExists($out . '/foobar/testdata2.txt', "Extracted $file");
|
436 |
+
$this->assertEquals(13, filesize($out . '/foobar/testdata2.txt'), "Extracted $file");
|
437 |
|
438 |
self::RDelete($out);
|
439 |
}
|
444 |
*/
|
445 |
public function testPrefixStripExtract()
|
446 |
{
|
447 |
+
$dir = dirname(__FILE__) . '/zip';
|
448 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
449 |
|
450 |
+
$zip = new Zip();
|
451 |
$file = "$dir/test.zip";
|
452 |
|
453 |
$zip->open($file);
|
455 |
|
456 |
clearstatcache();
|
457 |
|
458 |
+
$this->assertFileExists($out . '/zip/testdata1.txt', "Extracted $file");
|
459 |
+
$this->assertEquals(13, filesize($out . '/zip/testdata1.txt'), "Extracted $file");
|
460 |
|
461 |
+
$this->assertFileExists($out . '/testdata2.txt', "Extracted $file");
|
462 |
+
$this->assertEquals(13, filesize($out . '/testdata2.txt'), "Extracted $file");
|
463 |
|
464 |
self::RDelete($out);
|
465 |
}
|
470 |
*/
|
471 |
public function testIncludeExtract()
|
472 |
{
|
473 |
+
$dir = dirname(__FILE__) . '/zip';
|
474 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
475 |
|
476 |
+
$zip = new Zip();
|
477 |
$file = "$dir/test.zip";
|
478 |
|
479 |
$zip->open($file);
|
481 |
|
482 |
clearstatcache();
|
483 |
|
484 |
+
$this->assertFileNotExists($out . '/zip/testdata1.txt', "Extracted $file");
|
485 |
|
486 |
+
$this->assertFileExists($out . '/zip/foobar/testdata2.txt', "Extracted $file");
|
487 |
+
$this->assertEquals(13, filesize($out . '/zip/foobar/testdata2.txt'), "Extracted $file");
|
488 |
|
489 |
self::RDelete($out);
|
490 |
}
|
495 |
*/
|
496 |
public function testExcludeExtract()
|
497 |
{
|
498 |
+
$dir = dirname(__FILE__) . '/zip';
|
499 |
+
$out = sys_get_temp_dir() . '/dwziptest' . md5(time());
|
500 |
|
501 |
+
$zip = new Zip();
|
502 |
$file = "$dir/test.zip";
|
503 |
|
504 |
$zip->open($file);
|
506 |
|
507 |
clearstatcache();
|
508 |
|
509 |
+
$this->assertFileExists($out . '/zip/testdata1.txt', "Extracted $file");
|
510 |
+
$this->assertEquals(13, filesize($out . '/zip/testdata1.txt'), "Extracted $file");
|
511 |
|
512 |
+
$this->assertFileNotExists($out . '/zip/foobar/testdata2.txt', "Extracted $file");
|
513 |
|
514 |
self::RDelete($out);
|
515 |
}
|
540 |
$this->assertFileExists("$out/täst.txt");
|
541 |
}
|
542 |
|
|
|
543 |
/**
|
544 |
* recursive rmdir()/unlink()
|
545 |
*
|
vendor/splitbrain/php-archive/tests/tar.test.php
DELETED
@@ -1,617 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
use splitbrain\PHPArchive\Tar;
|
4 |
-
|
5 |
-
class Tar_TestCase extends PHPUnit_Framework_TestCase
|
6 |
-
{
|
7 |
-
/**
|
8 |
-
* file extensions that several tests use
|
9 |
-
*/
|
10 |
-
protected $extensions = array('tar');
|
11 |
-
|
12 |
-
public function setUp()
|
13 |
-
{
|
14 |
-
parent::setUp();
|
15 |
-
if (extension_loaded('zlib')) {
|
16 |
-
$this->extensions[] = 'tgz';
|
17 |
-
$this->extensions[] = 'tar.gz';
|
18 |
-
}
|
19 |
-
if (extension_loaded('bz2')) {
|
20 |
-
$this->extensions[] = 'tbz';
|
21 |
-
$this->extensions[] = 'tar.bz2';
|
22 |
-
}
|
23 |
-
}
|
24 |
-
|
25 |
-
/*
|
26 |
-
* dependency for tests needing zlib extension to pass
|
27 |
-
*/
|
28 |
-
public function test_ext_zlib()
|
29 |
-
{
|
30 |
-
if (!extension_loaded('zlib')) {
|
31 |
-
$this->markTestSkipped('skipping all zlib tests. Need zlib extension');
|
32 |
-
}
|
33 |
-
}
|
34 |
-
|
35 |
-
/*
|
36 |
-
* dependency for tests needing zlib extension to pass
|
37 |
-
*/
|
38 |
-
public function test_ext_bz2()
|
39 |
-
{
|
40 |
-
if (!extension_loaded('bz2')) {
|
41 |
-
$this->markTestSkipped('skipping all bzip2 tests. Need bz2 extension');
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @expectedException splitbrain\PHPArchive\ArchiveIOException
|
47 |
-
*/
|
48 |
-
public function test_missing()
|
49 |
-
{
|
50 |
-
$tar = new Tar();
|
51 |
-
$tar->open('nope.tar');
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* simple test that checks that the given filenames and contents can be grepped from
|
56 |
-
* the uncompressed tar stream
|
57 |
-
*
|
58 |
-
* No check for format correctness
|
59 |
-
*/
|
60 |
-
public function test_createdynamic()
|
61 |
-
{
|
62 |
-
$tar = new Tar();
|
63 |
-
|
64 |
-
$dir = dirname(__FILE__) . '/tar';
|
65 |
-
$tdir = ltrim($dir, '/');
|
66 |
-
|
67 |
-
$tar->create();
|
68 |
-
$tar->AddFile("$dir/testdata1.txt");
|
69 |
-
$tar->AddFile("$dir/foobar/testdata2.txt", 'noway/testdata2.txt');
|
70 |
-
$tar->addData('another/testdata3.txt', 'testcontent3');
|
71 |
-
|
72 |
-
$data = $tar->getArchive();
|
73 |
-
|
74 |
-
$this->assertTrue(strpos($data, 'testcontent1') !== false, 'Content in TAR');
|
75 |
-
$this->assertTrue(strpos($data, 'testcontent2') !== false, 'Content in TAR');
|
76 |
-
$this->assertTrue(strpos($data, 'testcontent3') !== false, 'Content in TAR');
|
77 |
-
|
78 |
-
// fullpath might be too long to be stored as full path FS#2802
|
79 |
-
$this->assertTrue(strpos($data, "$tdir") !== false, 'Path in TAR');
|
80 |
-
$this->assertTrue(strpos($data, "testdata1.txt") !== false, 'File in TAR');
|
81 |
-
|
82 |
-
$this->assertTrue(strpos($data, 'noway/testdata2.txt') !== false, 'Path in TAR');
|
83 |
-
$this->assertTrue(strpos($data, 'another/testdata3.txt') !== false, 'Path in TAR');
|
84 |
-
|
85 |
-
// fullpath might be too long to be stored as full path FS#2802
|
86 |
-
$this->assertTrue(strpos($data, "$tdir/foobar") === false, 'Path not in TAR');
|
87 |
-
$this->assertTrue(strpos($data, "foobar.txt") === false, 'File not in TAR');
|
88 |
-
|
89 |
-
$this->assertTrue(strpos($data, "foobar") === false, 'Path not in TAR');
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* simple test that checks that the given filenames and contents can be grepped from the
|
94 |
-
* uncompressed tar file
|
95 |
-
*
|
96 |
-
* No check for format correctness
|
97 |
-
*/
|
98 |
-
public function test_createfile()
|
99 |
-
{
|
100 |
-
$tar = new Tar();
|
101 |
-
|
102 |
-
$dir = dirname(__FILE__) . '/tar';
|
103 |
-
$tdir = ltrim($dir, '/');
|
104 |
-
$tmp = tempnam(sys_get_temp_dir(), 'dwtartest');
|
105 |
-
|
106 |
-
$tar->create($tmp);
|
107 |
-
$tar->AddFile("$dir/testdata1.txt");
|
108 |
-
$tar->AddFile("$dir/foobar/testdata2.txt", 'noway/testdata2.txt');
|
109 |
-
$tar->addData('another/testdata3.txt', 'testcontent3');
|
110 |
-
$tar->close();
|
111 |
-
|
112 |
-
$this->assertTrue(filesize($tmp) > 30); //arbitrary non-zero number
|
113 |
-
$data = file_get_contents($tmp);
|
114 |
-
|
115 |
-
$this->assertTrue(strpos($data, 'testcontent1') !== false, 'Content in TAR');
|
116 |
-
$this->assertTrue(strpos($data, 'testcontent2') !== false, 'Content in TAR');
|
117 |
-
$this->assertTrue(strpos($data, 'testcontent3') !== false, 'Content in TAR');
|
118 |
-
|
119 |
-
// fullpath might be too long to be stored as full path FS#2802
|
120 |
-
$this->assertTrue(strpos($data, "$tdir") !== false, "Path in TAR '$tdir'");
|
121 |
-
$this->assertTrue(strpos($data, "testdata1.txt") !== false, 'File in TAR');
|
122 |
-
|
123 |
-
$this->assertTrue(strpos($data, 'noway/testdata2.txt') !== false, 'Path in TAR');
|
124 |
-
$this->assertTrue(strpos($data, 'another/testdata3.txt') !== false, 'Path in TAR');
|
125 |
-
|
126 |
-
// fullpath might be too long to be stored as full path FS#2802
|
127 |
-
$this->assertTrue(strpos($data, "$tdir/foobar") === false, 'Path not in TAR');
|
128 |
-
$this->assertTrue(strpos($data, "foobar.txt") === false, 'File not in TAR');
|
129 |
-
|
130 |
-
$this->assertTrue(strpos($data, "foobar") === false, 'Path not in TAR');
|
131 |
-
|
132 |
-
@unlink($tmp);
|
133 |
-
}
|
134 |
-
|
135 |
-
/**
|
136 |
-
* List the contents of the prebuilt TAR files
|
137 |
-
*/
|
138 |
-
public function test_tarcontent()
|
139 |
-
{
|
140 |
-
$dir = dirname(__FILE__) . '/tar';
|
141 |
-
|
142 |
-
foreach ($this->extensions as $ext) {
|
143 |
-
$tar = new Tar();
|
144 |
-
$file = "$dir/test.$ext";
|
145 |
-
|
146 |
-
$tar->open($file);
|
147 |
-
$content = $tar->contents();
|
148 |
-
|
149 |
-
$this->assertCount(4, $content, "Contents of $file");
|
150 |
-
$this->assertEquals('tar/testdata1.txt', $content[1]->getPath(), "Contents of $file");
|
151 |
-
$this->assertEquals(13, $content[1]->getSize(), "Contents of $file");
|
152 |
-
|
153 |
-
$this->assertEquals('tar/foobar/testdata2.txt', $content[3]->getPath(), "Contents of $file");
|
154 |
-
$this->assertEquals(13, $content[3]->getSize(), "Contents of $file");
|
155 |
-
}
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* Create an archive and unpack it again
|
160 |
-
*/
|
161 |
-
public function test_dogfood()
|
162 |
-
{
|
163 |
-
foreach ($this->extensions as $ext) {
|
164 |
-
$input = glob(dirname(__FILE__) . '/../src/*');
|
165 |
-
$archive = sys_get_temp_dir() . '/dwtartest' . md5(time()) . '.' . $ext;
|
166 |
-
$extract = sys_get_temp_dir() . '/dwtartest' . md5(time() + 1);
|
167 |
-
|
168 |
-
$tar = new Tar();
|
169 |
-
$tar->create($archive);
|
170 |
-
foreach ($input as $path) {
|
171 |
-
$file = basename($path);
|
172 |
-
$tar->addFile($path, $file);
|
173 |
-
}
|
174 |
-
$tar->close();
|
175 |
-
$this->assertFileExists($archive);
|
176 |
-
|
177 |
-
$tar = new Tar();
|
178 |
-
$tar->open($archive);
|
179 |
-
$tar->extract($extract, '', '/FileInfo\\.php/', '/.*\\.php/');
|
180 |
-
|
181 |
-
$this->assertFileExists("$extract/Tar.php");
|
182 |
-
$this->assertFileExists("$extract/Zip.php");
|
183 |
-
$this->assertFileNotExists("$extract/FileInfo.php");
|
184 |
-
|
185 |
-
$this->nativeCheck($archive, $ext);
|
186 |
-
|
187 |
-
self::rdelete($extract);
|
188 |
-
unlink($archive);
|
189 |
-
}
|
190 |
-
}
|
191 |
-
|
192 |
-
/**
|
193 |
-
* Test the given archive with a native tar installation (if available)
|
194 |
-
*
|
195 |
-
* @param $archive
|
196 |
-
* @param $ext
|
197 |
-
*/
|
198 |
-
protected function nativeCheck($archive, $ext)
|
199 |
-
{
|
200 |
-
if (!is_executable('/usr/bin/tar')) {
|
201 |
-
return;
|
202 |
-
}
|
203 |
-
|
204 |
-
$switch = array(
|
205 |
-
'tar' => '-tf',
|
206 |
-
'tgz' => '-tzf',
|
207 |
-
'tar.gz' => '-tzf',
|
208 |
-
'tbz' => '-tjf',
|
209 |
-
'tar.bz2' => '-tjf',
|
210 |
-
);
|
211 |
-
$arg = $switch[$ext];
|
212 |
-
$archive = escapeshellarg($archive);
|
213 |
-
|
214 |
-
$return = 0;
|
215 |
-
$output = array();
|
216 |
-
$ok = exec("/usr/bin/tar $arg $archive 2>&1 >/dev/null", $output, $return);
|
217 |
-
$output = join("\n", $output);
|
218 |
-
|
219 |
-
$this->assertNotFalse($ok, "native tar execution for $archive failed:\n$output");
|
220 |
-
$this->assertSame(0, $return, "native tar execution for $archive had non-zero exit code $return:\n$output");
|
221 |
-
$this->assertSame('', $output, "native tar execution for $archive had non-empty output:\n$output");
|
222 |
-
}
|
223 |
-
|
224 |
-
/**
|
225 |
-
* Extract the prebuilt tar files
|
226 |
-
*/
|
227 |
-
public function test_tarextract()
|
228 |
-
{
|
229 |
-
$dir = dirname(__FILE__) . '/tar';
|
230 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
231 |
-
|
232 |
-
foreach ($this->extensions as $ext) {
|
233 |
-
$tar = new Tar();
|
234 |
-
$file = "$dir/test.$ext";
|
235 |
-
|
236 |
-
$tar->open($file);
|
237 |
-
$tar->extract($out);
|
238 |
-
|
239 |
-
clearstatcache();
|
240 |
-
|
241 |
-
$this->assertFileExists($out . '/tar/testdata1.txt', "Extracted $file");
|
242 |
-
$this->assertEquals(13, filesize($out . '/tar/testdata1.txt'), "Extracted $file");
|
243 |
-
|
244 |
-
$this->assertFileExists($out . '/tar/foobar/testdata2.txt', "Extracted $file");
|
245 |
-
$this->assertEquals(13, filesize($out . '/tar/foobar/testdata2.txt'), "Extracted $file");
|
246 |
-
|
247 |
-
self::rdelete($out);
|
248 |
-
}
|
249 |
-
}
|
250 |
-
|
251 |
-
/**
|
252 |
-
* Extract the prebuilt tar files with component stripping
|
253 |
-
*/
|
254 |
-
public function test_compstripextract()
|
255 |
-
{
|
256 |
-
$dir = dirname(__FILE__) . '/tar';
|
257 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
258 |
-
|
259 |
-
foreach ($this->extensions as $ext) {
|
260 |
-
$tar = new Tar();
|
261 |
-
$file = "$dir/test.$ext";
|
262 |
-
|
263 |
-
$tar->open($file);
|
264 |
-
$tar->extract($out, 1);
|
265 |
-
|
266 |
-
clearstatcache();
|
267 |
-
|
268 |
-
$this->assertFileExists($out . '/testdata1.txt', "Extracted $file");
|
269 |
-
$this->assertEquals(13, filesize($out . '/testdata1.txt'), "Extracted $file");
|
270 |
-
|
271 |
-
$this->assertFileExists($out . '/foobar/testdata2.txt', "Extracted $file");
|
272 |
-
$this->assertEquals(13, filesize($out . '/foobar/testdata2.txt'), "Extracted $file");
|
273 |
-
|
274 |
-
self::rdelete($out);
|
275 |
-
}
|
276 |
-
}
|
277 |
-
|
278 |
-
/**
|
279 |
-
* Extract the prebuilt tar files with prefix stripping
|
280 |
-
*/
|
281 |
-
public function test_prefixstripextract()
|
282 |
-
{
|
283 |
-
$dir = dirname(__FILE__) . '/tar';
|
284 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
285 |
-
|
286 |
-
foreach ($this->extensions as $ext) {
|
287 |
-
$tar = new Tar();
|
288 |
-
$file = "$dir/test.$ext";
|
289 |
-
|
290 |
-
$tar->open($file);
|
291 |
-
$tar->extract($out, 'tar/foobar/');
|
292 |
-
|
293 |
-
clearstatcache();
|
294 |
-
|
295 |
-
$this->assertFileExists($out . '/tar/testdata1.txt', "Extracted $file");
|
296 |
-
$this->assertEquals(13, filesize($out . '/tar/testdata1.txt'), "Extracted $file");
|
297 |
-
|
298 |
-
$this->assertFileExists($out . '/testdata2.txt', "Extracted $file");
|
299 |
-
$this->assertEquals(13, filesize($out . '/testdata2.txt'), "Extracted $file");
|
300 |
-
|
301 |
-
self::rdelete($out);
|
302 |
-
}
|
303 |
-
}
|
304 |
-
|
305 |
-
/**
|
306 |
-
* Extract the prebuilt tar files with include regex
|
307 |
-
*/
|
308 |
-
public function test_includeextract()
|
309 |
-
{
|
310 |
-
$dir = dirname(__FILE__) . '/tar';
|
311 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
312 |
-
|
313 |
-
foreach ($this->extensions as $ext) {
|
314 |
-
$tar = new Tar();
|
315 |
-
$file = "$dir/test.$ext";
|
316 |
-
|
317 |
-
$tar->open($file);
|
318 |
-
$tar->extract($out, '', '', '/\/foobar\//');
|
319 |
-
|
320 |
-
clearstatcache();
|
321 |
-
|
322 |
-
$this->assertFileNotExists($out . '/tar/testdata1.txt', "Extracted $file");
|
323 |
-
|
324 |
-
$this->assertFileExists($out . '/tar/foobar/testdata2.txt', "Extracted $file");
|
325 |
-
$this->assertEquals(13, filesize($out . '/tar/foobar/testdata2.txt'), "Extracted $file");
|
326 |
-
|
327 |
-
self::rdelete($out);
|
328 |
-
}
|
329 |
-
}
|
330 |
-
|
331 |
-
/**
|
332 |
-
* Extract the prebuilt tar files with exclude regex
|
333 |
-
*/
|
334 |
-
public function test_excludeextract()
|
335 |
-
{
|
336 |
-
$dir = dirname(__FILE__) . '/tar';
|
337 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
338 |
-
|
339 |
-
foreach ($this->extensions as $ext) {
|
340 |
-
$tar = new Tar();
|
341 |
-
$file = "$dir/test.$ext";
|
342 |
-
|
343 |
-
$tar->open($file);
|
344 |
-
$tar->extract($out, '', '/\/foobar\//');
|
345 |
-
|
346 |
-
clearstatcache();
|
347 |
-
|
348 |
-
$this->assertFileExists($out . '/tar/testdata1.txt', "Extracted $file");
|
349 |
-
$this->assertEquals(13, filesize($out . '/tar/testdata1.txt'), "Extracted $file");
|
350 |
-
|
351 |
-
$this->assertFileNotExists($out . '/tar/foobar/testdata2.txt', "Extracted $file");
|
352 |
-
|
353 |
-
self::rdelete($out);
|
354 |
-
}
|
355 |
-
}
|
356 |
-
|
357 |
-
/**
|
358 |
-
* Check the extension to compression guesser
|
359 |
-
*/
|
360 |
-
public function test_filetype()
|
361 |
-
{
|
362 |
-
$tar = new Tar();
|
363 |
-
$this->assertEquals(Tar::COMPRESS_NONE, $tar->filetype('foo'));
|
364 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype('foo.tgz'));
|
365 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype('foo.tGZ'));
|
366 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype('foo.tar.GZ'));
|
367 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype('foo.tar.gz'));
|
368 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype('foo.tbz'));
|
369 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype('foo.tBZ'));
|
370 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype('foo.tar.BZ2'));
|
371 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype('foo.tar.bz2'));
|
372 |
-
|
373 |
-
$dir = dirname(__FILE__) . '/tar';
|
374 |
-
$this->assertEquals(Tar::COMPRESS_NONE, $tar->filetype("$dir/test.tar"));
|
375 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype("$dir/test.tgz"));
|
376 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype("$dir/test.tbz"));
|
377 |
-
$this->assertEquals(Tar::COMPRESS_NONE, $tar->filetype("$dir/test.tar.guess"));
|
378 |
-
$this->assertEquals(Tar::COMPRESS_GZIP, $tar->filetype("$dir/test.tgz.guess"));
|
379 |
-
$this->assertEquals(Tar::COMPRESS_BZIP, $tar->filetype("$dir/test.tbz.guess"));
|
380 |
-
}
|
381 |
-
|
382 |
-
/**
|
383 |
-
* @depends test_ext_zlib
|
384 |
-
*/
|
385 |
-
public function test_longpathextract()
|
386 |
-
{
|
387 |
-
$dir = dirname(__FILE__) . '/tar';
|
388 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
389 |
-
|
390 |
-
foreach (array('ustar', 'gnu') as $format) {
|
391 |
-
$tar = new Tar();
|
392 |
-
$tar->open("$dir/longpath-$format.tgz");
|
393 |
-
$tar->extract($out);
|
394 |
-
|
395 |
-
$this->assertFileExists(
|
396 |
-
$out . '/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/test.txt'
|
397 |
-
);
|
398 |
-
|
399 |
-
self::rdelete($out);
|
400 |
-
}
|
401 |
-
}
|
402 |
-
|
403 |
-
// FS#1442
|
404 |
-
public function test_createlongfile()
|
405 |
-
{
|
406 |
-
$tar = new Tar();
|
407 |
-
$tar->setCompression(0);
|
408 |
-
$tmp = tempnam(sys_get_temp_dir(), 'dwtartest');
|
409 |
-
|
410 |
-
$path = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt';
|
411 |
-
|
412 |
-
$tar->create($tmp);
|
413 |
-
$tar->addData($path, 'testcontent1');
|
414 |
-
$tar->close();
|
415 |
-
|
416 |
-
$this->assertTrue(filesize($tmp) > 30); //arbitrary non-zero number
|
417 |
-
$data = file_get_contents($tmp);
|
418 |
-
|
419 |
-
// We should find the complete path and a longlink entry
|
420 |
-
$this->assertTrue(strpos($data, 'testcontent1') !== false, 'content in TAR');
|
421 |
-
$this->assertTrue(strpos($data, $path) !== false, 'path in TAR');
|
422 |
-
$this->assertTrue(strpos($data, '@LongLink') !== false, '@LongLink in TAR');
|
423 |
-
|
424 |
-
@unlink($tmp);
|
425 |
-
}
|
426 |
-
|
427 |
-
public function test_createlongpathustar()
|
428 |
-
{
|
429 |
-
$tar = new Tar();
|
430 |
-
$tar->setCompression(0);
|
431 |
-
$tmp = tempnam(sys_get_temp_dir(), 'dwtartest');
|
432 |
-
|
433 |
-
$path = '';
|
434 |
-
for ($i = 0; $i < 11; $i++) {
|
435 |
-
$path .= '1234567890/';
|
436 |
-
}
|
437 |
-
$path = rtrim($path, '/');
|
438 |
-
|
439 |
-
$tar->create($tmp);
|
440 |
-
$tar->addData("$path/test.txt", 'testcontent1');
|
441 |
-
$tar->close();
|
442 |
-
|
443 |
-
$this->assertTrue(filesize($tmp) > 30); //arbitrary non-zero number
|
444 |
-
$data = file_get_contents($tmp);
|
445 |
-
|
446 |
-
// We should find the path and filename separated, no longlink entry
|
447 |
-
$this->assertTrue(strpos($data, 'testcontent1') !== false, 'content in TAR');
|
448 |
-
$this->assertTrue(strpos($data, 'test.txt') !== false, 'filename in TAR');
|
449 |
-
$this->assertTrue(strpos($data, $path) !== false, 'path in TAR');
|
450 |
-
$this->assertFalse(strpos($data, "$path/test.txt") !== false, 'full filename in TAR');
|
451 |
-
$this->assertFalse(strpos($data, '@LongLink') !== false, '@LongLink in TAR');
|
452 |
-
|
453 |
-
@unlink($tmp);
|
454 |
-
}
|
455 |
-
|
456 |
-
public function test_createlongpathgnu()
|
457 |
-
{
|
458 |
-
$tar = new Tar();
|
459 |
-
$tar->setCompression(0);
|
460 |
-
$tmp = tempnam(sys_get_temp_dir(), 'dwtartest');
|
461 |
-
|
462 |
-
$path = '';
|
463 |
-
for ($i = 0; $i < 20; $i++) {
|
464 |
-
$path .= '1234567890/';
|
465 |
-
}
|
466 |
-
$path = rtrim($path, '/');
|
467 |
-
|
468 |
-
$tar->create($tmp);
|
469 |
-
$tar->addData("$path/test.txt", 'testcontent1');
|
470 |
-
$tar->close();
|
471 |
-
|
472 |
-
$this->assertTrue(filesize($tmp) > 30); //arbitrary non-zero number
|
473 |
-
$data = file_get_contents($tmp);
|
474 |
-
|
475 |
-
// We should find the complete path/filename and a longlink entry
|
476 |
-
$this->assertTrue(strpos($data, 'testcontent1') !== false, 'content in TAR');
|
477 |
-
$this->assertTrue(strpos($data, 'test.txt') !== false, 'filename in TAR');
|
478 |
-
$this->assertTrue(strpos($data, $path) !== false, 'path in TAR');
|
479 |
-
$this->assertTrue(strpos($data, "$path/test.txt") !== false, 'full filename in TAR');
|
480 |
-
$this->assertTrue(strpos($data, '@LongLink') !== false, '@LongLink in TAR');
|
481 |
-
|
482 |
-
@unlink($tmp);
|
483 |
-
}
|
484 |
-
|
485 |
-
/**
|
486 |
-
* Extract a tarbomomb
|
487 |
-
* @depends test_ext_zlib
|
488 |
-
*/
|
489 |
-
public function test_tarbomb()
|
490 |
-
{
|
491 |
-
$dir = dirname(__FILE__) . '/tar';
|
492 |
-
$out = sys_get_temp_dir() . '/dwtartest' . md5(time());
|
493 |
-
|
494 |
-
$tar = new Tar();
|
495 |
-
|
496 |
-
$tar->open("$dir/tarbomb.tgz");
|
497 |
-
$tar->extract($out);
|
498 |
-
|
499 |
-
clearstatcache();
|
500 |
-
|
501 |
-
$this->assertFileExists(
|
502 |
-
$out . '/AAAAAAAAAAAAAAAAA/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.txt'
|
503 |
-
);
|
504 |
-
|
505 |
-
self::rdelete($out);
|
506 |
-
}
|
507 |
-
|
508 |
-
/**
|
509 |
-
* A single zero file should be just a header block + the footer
|
510 |
-
*/
|
511 |
-
public function test_zerofile()
|
512 |
-
{
|
513 |
-
$dir = dirname(__FILE__) . '/tar';
|
514 |
-
$tar = new Tar();
|
515 |
-
$tar->setCompression(0);
|
516 |
-
$tar->create();
|
517 |
-
$tar->addFile("$dir/zero.txt", 'zero.txt');
|
518 |
-
$file = $tar->getArchive();
|
519 |
-
|
520 |
-
$this->assertEquals(512 * 3, strlen($file)); // 1 header block + 2 footer blocks
|
521 |
-
}
|
522 |
-
|
523 |
-
public function test_zerodata()
|
524 |
-
{
|
525 |
-
$tar = new Tar();
|
526 |
-
$tar->setCompression(0);
|
527 |
-
$tar->create();
|
528 |
-
$tar->addData('zero.txt', '');
|
529 |
-
$file = $tar->getArchive();
|
530 |
-
|
531 |
-
$this->assertEquals(512 * 3, strlen($file)); // 1 header block + 2 footer blocks
|
532 |
-
}
|
533 |
-
|
534 |
-
/**
|
535 |
-
* A file of exactly one block should be just a header block + data block + the footer
|
536 |
-
*/
|
537 |
-
public function test_blockfile()
|
538 |
-
{
|
539 |
-
$dir = dirname(__FILE__) . '/tar';
|
540 |
-
$tar = new Tar();
|
541 |
-
$tar->setCompression(0);
|
542 |
-
$tar->create();
|
543 |
-
$tar->addFile("$dir/block.txt", 'block.txt');
|
544 |
-
$file = $tar->getArchive();
|
545 |
-
|
546 |
-
$this->assertEquals(512 * 4, strlen($file)); // 1 header block + data block + 2 footer blocks
|
547 |
-
}
|
548 |
-
|
549 |
-
public function test_blockdata()
|
550 |
-
{
|
551 |
-
$tar = new Tar();
|
552 |
-
$tar->setCompression(0);
|
553 |
-
$tar->create();
|
554 |
-
$tar->addData('block.txt', str_pad('', 512, 'x'));
|
555 |
-
$file = $tar->getArchive();
|
556 |
-
|
557 |
-
$this->assertEquals(512 * 4, strlen($file)); // 1 header block + data block + 2 footer blocks
|
558 |
-
}
|
559 |
-
|
560 |
-
/**
|
561 |
-
* @depends test_ext_zlib
|
562 |
-
*/
|
563 |
-
public function test_gzipisvalid()
|
564 |
-
{
|
565 |
-
foreach (['tgz', 'tar.gz'] as $ext) {
|
566 |
-
$input = glob(dirname(__FILE__) . '/../src/*');
|
567 |
-
$archive = sys_get_temp_dir() . '/dwtartest' . md5(time()) . '.' . $ext;
|
568 |
-
$extract = sys_get_temp_dir() . '/dwtartest' . md5(time() + 1);
|
569 |
-
|
570 |
-
$tar = new Tar();
|
571 |
-
$tar->setCompression(9, Tar::COMPRESS_GZIP);
|
572 |
-
$tar->create();
|
573 |
-
foreach ($input as $path) {
|
574 |
-
$file = basename($path);
|
575 |
-
$tar->addFile($path, $file);
|
576 |
-
}
|
577 |
-
$tar->save($archive);
|
578 |
-
$this->assertFileExists($archive);
|
579 |
-
|
580 |
-
try {
|
581 |
-
$phar = new PharData($archive);
|
582 |
-
$phar->extractTo($extract);
|
583 |
-
} catch (\Exception $e) {};
|
584 |
-
|
585 |
-
$this->assertFileExists("$extract/Tar.php");
|
586 |
-
$this->assertFileExists("$extract/Zip.php");
|
587 |
-
|
588 |
-
$this->nativeCheck($archive, $ext);
|
589 |
-
|
590 |
-
self::rdelete($extract);
|
591 |
-
unlink($archive);
|
592 |
-
}
|
593 |
-
}
|
594 |
-
|
595 |
-
/**
|
596 |
-
* recursive rmdir()/unlink()
|
597 |
-
*
|
598 |
-
* @static
|
599 |
-
* @param $target string
|
600 |
-
*/
|
601 |
-
public static function rdelete($target)
|
602 |
-
{
|
603 |
-
if (!is_dir($target)) {
|
604 |
-
unlink($target);
|
605 |
-
} else {
|
606 |
-
$dh = dir($target);
|
607 |
-
while (false !== ($entry = $dh->read())) {
|
608 |
-
if ($entry == '.' || $entry == '..') {
|
609 |
-
continue;
|
610 |
-
}
|
611 |
-
self::rdelete("$target/$entry");
|
612 |
-
}
|
613 |
-
$dh->close();
|
614 |
-
rmdir($target);
|
615 |
-
}
|
616 |
-
}
|
617 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xcloner.php
CHANGED
@@ -7,17 +7,17 @@
|
|
7 |
* registers the activation and deactivation functions, and defines a function
|
8 |
* that starts the plugin.
|
9 |
*
|
10 |
-
* @link
|
11 |
* @since 1.0.0
|
12 |
* @package Xcloner
|
13 |
*
|
14 |
* @wordpress-plugin
|
15 |
* Plugin Name: XCloner - Site Backup and Restore
|
16 |
-
* Plugin URI:
|
17 |
* Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks, as well as transfer the backup archives to remote FTP, SFTP, DropBox, Amazon S3, Google Drive, WebDAV, Backblaze, Azure accounts.
|
18 |
-
* Version: 4.1.
|
19 |
-
* Author:
|
20 |
-
* Author URI:
|
21 |
* License: GPL-2.0+
|
22 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
23 |
* Text Domain: xcloner-backup-and-restore
|
7 |
* registers the activation and deactivation functions, and defines a function
|
8 |
* that starts the plugin.
|
9 |
*
|
10 |
+
* @link https://watchful.net
|
11 |
* @since 1.0.0
|
12 |
* @package Xcloner
|
13 |
*
|
14 |
* @wordpress-plugin
|
15 |
* Plugin Name: XCloner - Site Backup and Restore
|
16 |
+
* Plugin URI: https://xcloner.com/
|
17 |
* Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks, as well as transfer the backup archives to remote FTP, SFTP, DropBox, Amazon S3, Google Drive, WebDAV, Backblaze, Azure accounts.
|
18 |
+
* Version: 4.1.4
|
19 |
+
* Author: watchful
|
20 |
+
* Author URI: https://watchful.net/
|
21 |
* License: GPL-2.0+
|
22 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
23 |
* Text Domain: xcloner-backup-and-restore
|