├── .distignore ├── .env.example ├── .github ├── ISSUE_TEMPLATE │ └── pre-release-testing.md └── workflows │ ├── deploy-wp.sh │ ├── deploy.yml │ ├── update-tested-up-to.sh │ └── update-tested-up-to.yml ├── .gitignore ├── README.md ├── _config.yml ├── build.sh ├── docker-compose.yml ├── docker ├── Dockerfile └── entrypoint.sh ├── docs ├── local-dev.md ├── release-process.md ├── reporting-bugs.md ├── testing-cli-commands.md ├── testing-pull-requests.md └── workflows.md ├── package-lock.json ├── package.json ├── phpstan-baseline.neon ├── phpstan.neon ├── webpack.dev.js ├── webpack.prod.js └── xcloner-backup-and-restore ├── CHANGELOG.txt ├── LICENSE.txt ├── README.txt ├── admin ├── assets │ ├── btn_google_signin_dark_pressed_web.png │ ├── database-icon.png │ ├── file-icon-d.png │ ├── file-icon-f.png │ ├── file-icon-l.png │ ├── file-icon-root.png │ └── table-icon.png ├── class-xcloner-admin.php ├── css │ ├── jquery.dataTables.min.css │ ├── materialize.min.css │ ├── responsive.dataTables.css │ └── xcloner-admin.css ├── fonts │ └── roboto │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.eot │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Regular.woff │ │ ├── Roboto-Regular.woff2 │ │ ├── Roboto-Thin.eot │ │ ├── Roboto-Thin.ttf │ │ ├── Roboto-Thin.woff │ │ └── Roboto-Thin.woff2 ├── images │ ├── Sorting icons.psd │ ├── banners │ │ ├── CF Banner 728x90 blue.jpg │ │ └── CF Banner 728x90 red.jpg │ ├── favicon.ico │ ├── sort_asc.png │ ├── sort_asc_disabled.png │ ├── sort_both.png │ ├── sort_desc.png │ ├── sort_desc_disabled.png │ └── xcloner-logo.svg ├── index.php ├── js │ ├── dataTables.responsive.js │ ├── index.js │ ├── index.min.js │ ├── index.min.js.LICENSE.txt │ ├── index.min.js.map │ ├── jquery.dataTables.min.js │ ├── materialize.min.js │ ├── xcloner-admin.js │ ├── xcloner-backup-class.js │ ├── xcloner-manage-backups-class.js │ ├── xcloner-remote-storage-class.js │ ├── xcloner-restore-class.js │ └── xcloner-scheduler-class.js └── partials │ ├── remote_storage │ ├── aws.php │ ├── azure.php │ ├── backblaze.php │ ├── dropbox.php │ ├── ftp.php │ ├── gdrive.php │ ├── index.html │ ├── local.php │ ├── onedrive.php │ ├── sftp.php │ └── webdav.php │ ├── xcloner_console_page.php │ ├── xcloner_generate_backups_page.php │ ├── xcloner_header.php │ ├── xcloner_init_page.php │ ├── xcloner_manage_backups_page.php │ ├── xcloner_remote_storage_page.php │ ├── xcloner_restore_page.php │ └── xcloner_scheduled_backups_page.php ├── composer.json ├── composer.lock ├── index.php ├── languages ├── xcloner-backup-and-restore-de_DE.mo ├── xcloner-backup-and-restore-de_DE.po ├── xcloner-backup-and-restore-ro_RO.mo ├── xcloner-backup-and-restore-ro_RO.po ├── xcloner-backup-and-restore.mo └── xcloner-backup-and-restore.po ├── lib ├── Xcloner.php ├── Xcloner_Activator.php ├── Xcloner_Api.php ├── Xcloner_Archive.php ├── Xcloner_Archive_Restore.php ├── Xcloner_Composer_Actions.php ├── Xcloner_Database.php ├── Xcloner_Deactivator.php ├── Xcloner_Encryption.php ├── Xcloner_File_Transfer.php ├── Xcloner_Filesystem.php ├── Xcloner_Loader.php ├── Xcloner_Logger.php ├── Xcloner_Remote_Storage.php ├── Xcloner_Requirements.php ├── Xcloner_Restore.php ├── Xcloner_Sanitization.php ├── Xcloner_Scheduler.php ├── Xcloner_Settings.php ├── Xcloner_cli.php └── Xcloner_i18n.php ├── uninstall.php └── xcloner.php /.distignore: -------------------------------------------------------------------------------- 1 | /vendor/**.md 2 | /vendor/**tests/ 3 | /vendor/bin/ 4 | /admin/js/index.js 5 | /admin/js/xcloner* 6 | /admin/js/materialize.min.js 7 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | WORDPRESS_DEBUG=true 2 | WORDPRESS_PORT=8080 3 | WORDPRESS_DB_HOST=db 4 | WORDPRESS_DB_USER=wordpress 5 | WORDPRESS_DB_PASSWORD=wordpress 6 | WORDPRESS_DB_NAME=wordpress 7 | WORDPRESS_URL=https://wordpress.xcloner.local 8 | WORDPRESS_TITLE='XCloner Testing' 9 | WORDPRESS_ADMIN_USER=admin 10 | WORDPRESS_ADMIN_PASSWORD=admin 11 | WORDPRESS_ADMIN_EMAIL=hello@watchful.net 12 | 13 | XCLONER_GDRIVE_CLIENT_ID: 14 | XCLONER_GDRIVE_REDIRECT_URL: 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/pre-release-testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pre-release testing 3 | about: Use this template to test new versions before release. 4 | title: "[TESTING] Testing for version x.y.z" 5 | labels: testing 6 | assignees: jimiero 7 | 8 | --- 9 | 10 | # Settings 11 | - [ ] Basic Settings can be saved 12 | - [ ] Remote Storages settings show `VALID` message when saved. 13 | - [ ] Amazon S3 14 | - [ ] Azure Blob 15 | - [ ] Backblaze 16 | - [ ] BOX 17 | - [ ] Dropbox 18 | - [ ] Google Drive 19 | - [ ] SFTP 20 | - [ ] WebDav 21 | 22 | # Generate Local Backup 23 | - [ ] Full backup with default settings completes successfully. 24 | - [ ] Partial backup with some tables excluded completes successfully. 25 | - [ ] Partial backup with some files excludes completes successfully. 26 | - [ ] Partial backup with additional databases included completes successfully. 27 | - [ ] Backup options 28 | - [ ] Backup process completes successfully with encryption enabled 29 | - [ ] Backup process completes successfully when `transfer to Dropbox` enabled. 30 | - [ ] Check that backup archive successfuly uploaded in Dropbox account. 31 | - [ ] Backup process completes successfully when `transferr to Dropbox` enabled and `delete from local storage` selected. 32 | - [ ] Check that backup archive successfuly deleted from Dropbox account. 33 | 34 | # Send backups to remote storage 35 | 36 | In these tests, use a very a simple backup that will complete quickly and have a very small size. For example, do not include any databases and exclude all files except `index.php`. 37 | 38 | - [ ] Partial backup completes successfully and send file to SFTP location. 39 | - [ ] Partial backup completes successfully and send file to Dropbox location (likely tested above). 40 | - [ ] Partial backup completes successfully and send file to Azure Blob location. 41 | - [ ] Partial backup completes successfully and send file to Amazon S3 location. 42 | - [ ] Partial backup completes successfully and send file to Backblaze location. 43 | - [ ] Partial backup completes successfully and send file to BOX location. 44 | 45 | # Manage Local Backups 46 | - [ ] Make sure backups are listed. 47 | - [ ] Make sure backups can be deleted when the icon is clicked. 48 | - [ ] Make sure backups can be uploaded to DropBox when the icon is clicked. 49 | - [ ] Make sure backups can be downloaded when the icon is clicked. 50 | - [ ] Make sure backup contents can be listed when the icon is clicked. 51 | - [ ] Make sure an encrypted backup can be unencrypted when the icon is clicked. 52 | 53 | # Manage Remote Backups 54 | - [ ] Dropbox backups are listed. 55 | - [ ] Dropbox backups can be deleted when the icon is clicked. 56 | - [ ] Dropbox backups can be downloaded when the icon is clicked. 57 | - [ ] Dropbox backup contents can be listed when the icon is clicked. 58 | - [ ] Encrypted Dropbox backups can be unencrypted when the icon is clicked. 59 | 60 | # Scheduling Backups 61 | - [ ] Create a Scheduled Profile 62 | - [ ] Check the correct recurrence of a scheduled Profile based on the Wordpress cronjob execution 63 | 64 | # Restore Backups 65 | - [ ] Restore all files from a local backup. 66 | - [ ] Restore database from a local backup. 67 | - [ ] Migrate files from a backup to a different domain. 68 | - [ ] Migrate the database from a backup to a different domain. 69 | 70 | # Watchful Backups 71 | - [ ] Site connects/validates in Watchful (test `Refresh data` success). 72 | - [ ] XCloner backup works as expected in Watchful when using the `Start Backup` button. 73 | 74 | # Other tests 75 | - [ ] Trigger any backup profile from the XCloner CLI. 76 | - [ ] Trigger any backup profile from the WP CLI. 77 | - [ ] Check if enabling/disabling logs in XCloner settings works as expected. 78 | - [ ] Check if XCloner version has been incremented from previous release. 79 | - [ ] Check if release has changelog notes. 80 | -------------------------------------------------------------------------------- /.github/workflows/deploy-wp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ -z "$SVN_USERNAME" ]] && [[ -z "$BUILD_ONLY" ]]; then 4 | echo "x Missing SVN_USERNAME env variable" 5 | exit 1 6 | fi 7 | 8 | if [[ -z "$SVN_PASSWORD" ]] && [[ -z "$BUILD_ONLY" ]]; then 9 | echo "x Missing SVN_PASSWORD env variable" 10 | exit 1 11 | fi 12 | 13 | if [[ -z "$VERSION" ]]; then 14 | VERSION="${GITHUB_REF#refs/tags/}" 15 | VERSION="${VERSION#v}" 16 | fi 17 | 18 | rx='^([0-9]+\.){2}(\*|[0-9]+)(-.*)?$' 19 | if [[ $VERSION =~ $rx ]]; then 20 | echo "ℹ VERSION is $VERSION" 21 | elif [[ -z "$BUILD_ONLY" ]]; then 22 | echo "x Unable to validate version: '$VERSION'" 23 | exit 1 24 | fi 25 | 26 | CURRENT_DIR=$(pwd) 27 | SLUG="xcloner-backup-and-restore" 28 | 29 | SVN_URL="https://plugins.svn.wordpress.org/${SLUG}/" 30 | SVN_DIR="${CURRENT_DIR}/${SLUG}-svn" 31 | BUILD_DIR="${CURRENT_DIR}/${SLUG}-build" 32 | 33 | echo "➤ Building Webpack bundle" 34 | export NODE_OPTIONS=--openssl-legacy-provider 35 | npm install || exit 1 36 | npm run build-prod || exit 1 37 | 38 | echo "➤ Copying files to build directory" 39 | rsync -av --delete "${CURRENT_DIR}/${SLUG}/" "${BUILD_DIR}/" 40 | 41 | echo "➤ Install composer dependencies without dev dependencies" 42 | cd "${BUILD_DIR}" || exit 1 43 | composer install --no-dev --prefer-dist -o --no-interaction || exit 1 44 | cd "${CURRENT_DIR}" || exit 1 45 | 46 | if [[ -n "$BUILD_ONLY" ]]; then 47 | echo "✓ Plugin built!" 48 | exit 0 49 | fi 50 | 51 | echo "➤ Checking out SVN repository..." 52 | svn checkout "${SVN_URL}/trunk/" "${SVN_DIR}/trunk/" 53 | cd "${CURRENT_DIR}" || exit 1 54 | 55 | echo "➤ Coping files to SVN repository..." 56 | rsync -r --exclude-from=".distignore" "${BUILD_DIR}/" "${SVN_DIR}/trunk/" 57 | 58 | echo "➤ Adding files to SVN repository..." 59 | cd "${SVN_DIR}/trunk" || exit 1 60 | svn st | grep '^?' | awk '{print $2}' | xargs -r svn add 61 | svn st | grep '^!' | awk '{print $2}' | xargs -r svn rm 62 | 63 | echo "➤ Committing files to SVN repository..." 64 | svn commit -m "v${VERSION}" --no-auth-cache --non-interactive --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --config-option=servers:global:http-timeout=300 || exit 1 65 | 66 | echo "➤ Coping tag to SVN repository..." 67 | cd "${SVN_DIR}" || exit 1 68 | svn cp "${SVN_URL}/trunk" "${SVN_URL}/tags/${VERSION}" -m "Tagging v${VERSION}" --no-auth-cache --non-interactive --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --config-option=servers:global:http-timeout=300 || exit 1 69 | 70 | echo "✓ Plugin deployed!" 71 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to WordPress.org 2 | on: workflow_dispatch 3 | jobs: 4 | deploy: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout code 8 | uses: actions/checkout@master 9 | - name: Setup PHP 10 | uses: shivammathur/setup-php@v2 11 | with: 12 | php-version: '7.3' 13 | tools: composer 14 | - name: Execute script to deploy on WordPress.org 15 | run: ${{ github.workspace }}/.github/workflows/deploy-wp.sh 16 | env: 17 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 18 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} -------------------------------------------------------------------------------- /.github/workflows/update-tested-up-to.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ -z "$SVN_USERNAME" ]]; then 4 | echo "x Missing SVN_USERNAME env variable" 5 | exit 1 6 | fi 7 | 8 | if [[ -z "$SVN_PASSWORD" ]]; then 9 | echo "x Missing SVN_PASSWORD env variable" 10 | exit 1 11 | fi 12 | 13 | SLUG="xcloner-backup-and-restore" 14 | README_FILE_PATH="./xcloner-backup-and-restore/README.txt" 15 | SVN_URL="https://plugins.svn.wordpress.org/${SLUG}/" 16 | SVN_DIR="./svn-${SLUG}" 17 | 18 | echo "➤ Checking out SVN repository..." 19 | svn checkout "$SVN_URL" "$SVN_DIR" --depth immediates 20 | 21 | svn update --set-depth infinity "$SVN_DIR/trunk" 22 | 23 | echo "➤ Coping README file to SVN repository..." 24 | rsync -rc "$README_FILE_PATH" "${SVN_DIR}/trunk" --delete --delete-excluded 25 | 26 | echo "➤ Adding files to SVN repository..." 27 | cd "$SVN_DIR" 28 | svn add . --force > /dev/null 29 | 30 | echo "➤ Committing files to SVN repository..." 31 | svn commit -m "Update tested up to" --no-auth-cache --non-interactive --username "$SVN_USERNAME" --password "$SVN_PASSWORD" 32 | 33 | echo "✓ Updated WordPress tested up to version!" 34 | -------------------------------------------------------------------------------- /.github/workflows/update-tested-up-to.yml: -------------------------------------------------------------------------------- 1 | name: Update tested up to version 2 | on: workflow_dispatch 3 | jobs: 4 | deploy-wp: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - name: Update "tested up to version" to WordPress SVN 9 | run: | 10 | sudo apt-get update && sudo apt-get install -y subversion 11 | ${{ github.workspace }}/.github/workflows/update-tested-up-to.sh 12 | env: 13 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 14 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | xcloner-backup-and-restore/vendor/ 3 | .idea/ 4 | 5 | docker-compose.override.yml 6 | 7 | /xcloner-backup-and-restore-build/ 8 | /xcloner-backup-and-restore-svn/ 9 | /xcloner-backup-and-restore*.zip 10 | 11 | .env 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 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) 7 | 8 | Backup your WordPress site, restore to any web location, send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP and many others with XCloner backup plugin. 9 | 10 | 11 | XCloner is a Backup and Restore plugin that is perfectly integrated with WordPress. 12 | 13 | XCloner design was specifically created to Generate custom backups of any LAMP website through custom admin inputs, and to be able to Restore the clone on any other location with the help of the automatic Restore script we provide! 14 | 15 | XCloner Backup tool uses Open Source standards like TAR, Mysql and CSV formats so you can rest assured your backups can be restored in a variety of ways, giving you more flexibility and full control. 16 | 17 | ## Features 18 | 19 | * Backup and Restore your WordPress site easily 20 | * Create compressed and uncompressed backups using TAR open source format 21 | * Create encrypted backups archives with AES-128-CBC algorithm 22 | * Create automated backups from your Scheduled Backups Section 23 | * Received email notifications of created backups 24 | * Generate automatic backups based on cronjobs, it can run daily, weekly, monthly or even hourly 25 | * Restore your backups on any other location, XCloner will attempt to extract the backup archive files for you, as well as import the mysql dump and update the WordPress config details 26 | * Upload your backups to Remote Storage locations supporting FTP, SFTP, Dropbox, AWS, Azure Blob and many more to come 27 | * Watch every step of XCloner through it's built in debugger 28 | * Although we have optimized XCloner to run properly on most hosts, we give Developers options to customize its running speed and avoid backup timeouts, all from the XCloner Config-> System Options 29 | * Ability to split backups into multiple smaller parts if a certain size limit is reached 30 | 31 | ## Installation 32 | 33 | 1. Upload the plugin directory to wp-content/plugins directory 34 | 2. Activate the plugin 35 | 3. Access the plugin Dashboard from the Admin Sidebar -> Site Backup Menu 36 | 37 | ## UPGRADE 38 | 39 | You can do it easily from the WordPress backend. 40 | 41 | ## Frequently Asked Questions 42 | 43 | Where does XCloner keep it's database backups? 44 | 45 | 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, 46 | 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. 47 | 48 | How do I restore my backup? 49 | 50 | XCloner provide an easy-to-use restore script available in the Site Backup -> Restore Backups menu, the process is being described there as well. 51 | 52 | If the XCloner Restore option fails, you can manually restore your backup as follows: 53 | 54 | 1. extract the backup archive files to your new location 55 | 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 56 | 3. update your wp-config.php file to reflect the new mysql details 57 | 58 | How do I know which files were include in the backup? 59 | 60 | 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. 61 | 62 | Do you have a log for the created backup? 63 | 64 | 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 65 | 66 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | DATE=$(date +"%Y%m%d%H%M") 2 | SLUG="xcloner-backup-and-restore" 3 | BUILD_ONLY="true" 4 | BUILD_SCRIPT_PATH="./.github/workflows/deploy-wp.sh" 5 | BUILD_DIR="xcloner-backup-and-restore-build" 6 | 7 | export BUILD_ONLY 8 | 9 | echo "Building plugin" 10 | 11 | bash "${BUILD_SCRIPT_PATH}" 12 | 13 | echo "Creating archive" 14 | cd "${BUILD_DIR}" || exit 1 15 | mkdir "${SLUG}" 16 | mv ./* "${SLUG}" 17 | zip -r "xcloner-backup-and-restore-${DATE}.zip" "${SLUG}" || exit 1 18 | mv "xcloner-backup-and-restore-${DATE}.zip" ../ 19 | cd .. 20 | 21 | echo "Removing build directory" 22 | rm -rf "${BUILD_DIR}" 23 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: xcloner-testing 2 | 3 | services: 4 | wordpress: 5 | depends_on: 6 | - db 7 | build: 8 | context: . 9 | dockerfile: docker/Dockerfile 10 | volumes: 11 | - ./xcloner-backup-and-restore:/src/xcloner-backup-and-restore:ro 12 | ports: 13 | - "${WORDPRESS_PORT:-8080}:80" 14 | environment: 15 | WORDPRESS_DEBUG: "${WORDPRESS_DEBUG:-false}" 16 | WORDPRESS_DB_HOST: "${WORDPRESS_DB_HOST:-db}" 17 | WORDPRESS_DB_USER: "${WORDPRESS_DB_USER:-wordpress}" 18 | WORDPRESS_DB_PASSWORD: "${WORDPRESS_DB_PASSWORD:-wordpress}" 19 | WORDPRESS_DB_NAME: "${WORDPRESS_DB_NAME:-wordpress}" 20 | WORDPRESS_URL: "${WORDPRESS_URL:-http://localhost:8080}" 21 | WORDPRESS_TITLE: "${WORDPRESS_TITLE:-WordPress}" 22 | WORDPRESS_ADMIN_USER: "${WORDPRESS_ADMIN_USER:-admin}" 23 | WORDPRESS_ADMIN_PASSWORD: "${WORDPRESS_ADMIN_PASSWORD:-password}" 24 | WORDPRESS_ADMIN_EMAIL: "${WORDPRESS_ADMIN_EMAIL:-example@example.com}" 25 | XCLONER_GDRIVE_CLIENT_ID: "${XCLONER_GDRIVE_CLIENT_ID:-}" 26 | XCLONER_GDRIVE_REDIRECT_URL: "${XCLONER_GDRIVE_REDIRECT_URL:-}" 27 | 28 | db: 29 | image: mariadb:10.5.8 30 | volumes: 31 | - db_data:/var/lib/mysql 32 | environment: 33 | MYSQL_ROOT_PASSWORD: "${WORDPRESS_DB_PASSWORD:-wordpress}" 34 | MYSQL_DATABASE: "${WORDPRESS_DB_NAME:-wordpress}" 35 | MYSQL_USER: "${WORDPRESS_DB_USER:-wordpress}" 36 | MYSQL_PASSWORD: "${WORDPRESS_DB_PASSWORD:-wordpress}" 37 | healthcheck: 38 | test: "/usr/bin/mysql --user=wordpress --password=wordpress --execute \"SHOW DATABASES;\"" 39 | interval: 3s 40 | timeout: 1s 41 | retries: 10 42 | 43 | volumes: 44 | db_data: {} 45 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM wordpress:latest 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y inotify-tools rsync wait-for-it 5 | 6 | COPY docker/entrypoint.sh /usr/local/bin/ 7 | RUN chmod +x /usr/local/bin/entrypoint.sh 8 | 9 | RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 10 | RUN chmod +x wp-cli.phar 11 | RUN mv wp-cli.phar /usr/local/bin/wp 12 | 13 | ENTRYPOINT ["entrypoint.sh"] 14 | CMD ["apache2-foreground"] 15 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #!/usr/bin/env bash 3 | set -Eeuo pipefail 4 | 5 | if [[ "$1" == apache2* ]] || [ "$1" = 'php-fpm' ]; then 6 | uid="$(id -u)" 7 | gid="$(id -g)" 8 | if [ "$uid" = '0' ]; then 9 | case "$1" in 10 | apache2*) 11 | user="${APACHE_RUN_USER:-www-data}" 12 | group="${APACHE_RUN_GROUP:-www-data}" 13 | 14 | # strip off any '#' symbol ('#1000' is valid syntax for Apache) 15 | pound='#' 16 | user="${user#$pound}" 17 | group="${group#$pound}" 18 | ;; 19 | *) # php-fpm 20 | user='www-data' 21 | group='www-data' 22 | ;; 23 | esac 24 | else 25 | user="$uid" 26 | group="$gid" 27 | fi 28 | 29 | if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then 30 | # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) 31 | if [ "$uid" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then 32 | chown "$user:$group" . 33 | fi 34 | 35 | echo >&2 "WordPress not found in $PWD - copying now..." 36 | if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then 37 | echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" 38 | fi 39 | sourceTarArgs=( 40 | --create 41 | --file - 42 | --directory /usr/src/wordpress 43 | --owner "$user" --group "$group" 44 | ) 45 | targetTarArgs=( 46 | --extract 47 | --file - 48 | ) 49 | if [ "$uid" != '0' ]; then 50 | # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" 51 | targetTarArgs+=( --no-overwrite-dir ) 52 | fi 53 | # loop over "pluggable" content in the source, and if it already exists in the destination, skip it 54 | # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) 55 | for contentPath in \ 56 | /usr/src/wordpress/.htaccess \ 57 | /usr/src/wordpress/wp-content/*/*/ \ 58 | ; do 59 | contentPath="${contentPath%/}" 60 | [ -e "$contentPath" ] || continue 61 | contentPath="${contentPath#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. 62 | if [ -e "$PWD/$contentPath" ]; then 63 | echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" 64 | sourceTarArgs+=( --exclude "./$contentPath" ) 65 | fi 66 | done 67 | tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" 68 | echo >&2 "Complete! WordPress has been successfully copied to $PWD" 69 | fi 70 | 71 | wpEnvs=( "${!WORDPRESS_@}" ) 72 | if [ ! -s wp-config.php ] && [ "${#wpEnvs[@]}" -gt 0 ]; then 73 | for wpConfigDocker in \ 74 | wp-config-docker.php \ 75 | /usr/src/wordpress/wp-config-docker.php \ 76 | ; do 77 | if [ -s "$wpConfigDocker" ]; then 78 | echo >&2 "No 'wp-config.php' found in $PWD, but 'WORDPRESS_...' variables supplied; copying '$wpConfigDocker' (${wpEnvs[*]})" 79 | # using "awk" to replace all instances of "put your unique phrase here" with a properly unique string (for AUTH_KEY and friends to have safe defaults if they aren't specified with environment variables) 80 | awk ' 81 | /put your unique phrase here/ { 82 | cmd = "head -c1m /dev/urandom | sha1sum | cut -d\\ -f1" 83 | cmd | getline str 84 | close(cmd) 85 | gsub("put your unique phrase here", str) 86 | } 87 | { print } 88 | ' "$wpConfigDocker" > wp-config.php 89 | if [ "$uid" = '0' ]; then 90 | # attempt to ensure that wp-config.php is owned by the run user 91 | # could be on a filesystem that doesn't allow chown (like some NFS setups) 92 | chown "$user:$group" wp-config.php || true 93 | fi 94 | break 95 | fi 96 | done 97 | fi 98 | fi 99 | 100 | SRC_PATH="${SRC_PATH-/src/xcloner-backup-and-restore/}" 101 | DEST_PATH="${DEST_PATH-/var/www/html/wp-content/plugins/xcloner-backup-and-restore/}" 102 | 103 | sync() { 104 | rsync "${SRC_PATH}" "${DEST_PATH}" -r --delete || true 105 | chown www-data:www-data -R /var/www/html 106 | } 107 | 108 | watcher() { 109 | inotifywait -e modify,create,delete,move -r "${SRC_PATH}" -q --format '%w%f' | while read FILE; do 110 | sync 111 | watcher 112 | done 113 | } 114 | sync 115 | watcher & 116 | 117 | wait-for-it "${WORDPRESS_DB_HOST}:3306" --timeout=0 --strict -- echo "Database is up" 118 | 119 | wp core install --url="${WORDPRESS_URL}" --title="${WORDPRESS_TITLE}" --admin_user="${WORDPRESS_ADMIN_USER}" --admin_password="${WORDPRESS_ADMIN_PASSWORD}" --admin_email="${WORDPRESS_ADMIN_EMAIL}" --allow-root 120 | wp plugin activate xcloner-backup-and-restore --allow-root 121 | 122 | exec "$@" 123 | -------------------------------------------------------------------------------- /docs/local-dev.md: -------------------------------------------------------------------------------- 1 | # Local Development 2 | 3 | ## Install For Development 4 | 5 | - `git clone git@github.com:watchfulli/XCloner-Wordpress.git` 6 | - `npm install` 7 | - Install JavaScript Dependencies: 8 | - If testing: 9 | - `npm run build-prod` will build for production. 10 | - `npm run build` does not do anything. 11 | - If doing development: 12 | - `npm run start` Starts watcher 13 | - Install Composer Dependencies 14 | - If installing for testing: 15 | - `docker run --rm -it --volume "$(pwd)":/app prooph/composer:7.3 install --no-dev` 16 | - If installing for development: 17 | - `docker run --rm -it --volume "$(pwd)":/app prooph/composer:7.3 install` 18 | 19 | ## Local Development Environment 20 | A [docker-compose](https://docs.docker.com/samples/wordpress/)-based local development environment is provided. 21 | 22 | - Start server 23 | - `docker-compose up -d` 24 | - If you get errors about port already being allocated, you can either: 25 | - Kill all containers and try again: `docker kill $(docker ps -q) && docker-compose up -d` 26 | - Change the port in docker-compose.yml. 27 | - Access Site 28 | - [http://localhost:6123](http://localhost:6123) 29 | - Run WP CLI command: 30 | - `docker-compose run wordpress-cli wp user create admin admin@example.com --role=admin user_pass=pass` 31 | 32 | ## WordPress Tests 33 | 34 | There is a special phpunit container for running WordPress tests, with WordPress and MySQL configured. 35 | 36 | - Enter container 37 | - `docker-compose run phpunit` 38 | - Test 39 | - `composer test:wordpress` 40 | 41 | ## Debug Logging 42 | 43 | Because most of what xCloner does happens via asynchronous requests, logging PHP errors is important for identifying bugs. 44 | 45 | By default, xCloner registers its own error handlers. This will prevent WordPress default error logging with WP_DEBUG_LOG from working as expected. 46 | 47 | You can use that log, or you can disable it in xCloner's "Settings" screen. 48 | 49 | - @todo find or create documentation about the PHP logging feature in xCloner. 50 | - [Recent post about WordPress debug logging from Delicious Brains](https://deliciousbrains.com/why-use-wp-debug-log-wordpress-development/) 51 | - [Post about WordPress debug logging I wrote for Elegant Themes awhile ago](https://www.elegantthemes.com/blog/tips-tricks/using-the-wordpress-debug-log) 52 | -------------------------------------------------------------------------------- /docs/release-process.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | ## Starting Release 4 | 5 | ### Releases Tracking WordPress Version Updates 6 | 7 | The git workflow ".version.yml" runs once a day, using a [cron trigger](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule). This workflow checks if the current value of "Tested up to" is the less than the latest version of WordPress. If it is not, this workflow will do the following: 8 | 9 | - Create a new branch. 10 | - Increment the "Stable tag" by 1 patch version. 11 | - Set the "Tested up to" value to the latest version. 12 | - Create a pull request title "UPDATE For WordPress $VERSION" where $VERSION is the latest version of WordPress. 13 | 14 | The test and analysis pipelines will run on the pull request. If they pass, advance to manual testing of this version. If not, we will need to examine why those pipelines failed before moving forward. Work to fix this should be done in a branch based off of the PR's branch. 15 | 16 | ### Other Releases 17 | 18 | If a release is being done for other reasons, a pull request to update the - branch should be made. The rest of this workflow. 19 | 20 | ## Manual Testing 21 | 22 | To test the pull request for the new version: 23 | 24 | - Checkout the repo locally, at the same branch as the pull request. 25 | - Build plugin the same way as in "deploy.yml". 26 | - `npm install` 27 | - `npm run build-prod` 28 | - `composer install --no-dev --prefer-dist -o` 29 | 30 | ## Trigger Release To WordPress.org/plugins 31 | 32 | When the release is ready: 33 | 34 | - Merge the pull request to the master branch 35 | - Apply and push a tag to the latest commit of master branch 36 | - Tag must be the same as the value of "Stable tag". 37 | - `git tag 1.0.0 && git push --tags` 38 | - This will trigger the "deploy.yml" workflow. 39 | - This should create a new release in [WordPress plugin repo](https://wordpress.org/plugins/xcloner-backup-and-restore/). 40 | -------------------------------------------------------------------------------- /docs/reporting-bugs.md: -------------------------------------------------------------------------------- 1 | # Reporting Bugs 2 | 3 | Whenever you find a bug, [please open a GitHub issue for it](https://github.com/watchfulli/XCloner-Wordpress/issues/new). If you are opening an issue after reading a support thread on WordPress.org, please include a link to that thread. Also, indicate if you have reproduced the bug yourself, or if you are only passing on a report. 4 | 5 | ## What To Include 6 | 7 | Begin by stating what you were doing, what you expected to happen and what happened instead. Please include a list of steps to reproduce the error. 8 | 9 | In the issue, please note what versions of the following you are testing with: 10 | - WordPress 11 | - xCloner 12 | - PHP 13 | 14 | Please do not write "latest" version, use a version number always. If you are testing a branch from the Github repo, please note which branch, at which commit you have checked out. Also indicate if you installed using the process documented in [the local development documentation](./local-dev.md). 15 | 16 | 17 | ### Error Logging. 18 | 19 | Please always include what PHP errors happened with WP_DEBUG enabled and what JavaScript console errors happened. If they didn't, or you don't know, include that. The [local dev](./local-dev.md) documentation includes notes about setting up debug logging, which is probably neccasary for testing. 20 | 21 | For JavaScript console errors, please provide __the text of any errors__. Please do not include a screenshot of the terminal or all of the text in the JavaScript console. Please do not include warnings, or other text in the JavaScript console, unless you belive it is relevant. 22 | -------------------------------------------------------------------------------- /docs/testing-cli-commands.md: -------------------------------------------------------------------------------- 1 | # CLI Commands For Testing 2 | 3 | 4 | ## `latest-wordpress` 5 | 6 | Gets latest version of WordPress via API. Other commands will use same API lookup if this doesn't run first. 7 | 8 | Examples: 9 | - `docker-compose run wordpress-cli wp latest-wordpress` 10 | ## `is-tested-up-to` 11 | 12 | Checks if the plugin's tested up to version is greater than or equal to latest version of WordPress. 13 | 14 | Examples: 15 | - `docker-compose run wordpress-cli wp is-tested-up-to` 16 | 17 | ## `update-version` 18 | 19 | Gets latest version of WordPress. Sets the "Tested up to" value in README.txt to latest version of WordPress. Sets stable tag in README.txt and version in xcloner.php to one minor version higher. 20 | 21 | Examples: 22 | - `docker-compose run wordpress-cli wp update-version` 23 | 24 | Probably need to run this first: 25 | 26 | ```bash 27 | sudo chmod 777 xcloner.php 28 | sudo chmod 777 README.txt 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/testing-pull-requests.md: -------------------------------------------------------------------------------- 1 | # Testing Pull Requests 2 | 3 | This is documentation for testing pull requests (PRs) for xcloner. 4 | 5 | https://github.com/watchfulli/XCloner-Wordpress/pulls 6 | 7 | When testing, you must install the plugin using the process documented in [the local development documentation](./local-dev.md). If you do not run composer update, as instructed after checking out the branch, your testing will not be valid. It is OK to subsitute your own local environment for the one that is included. 8 | 9 | ## Setting Up To Test 10 | 11 | 1. Checkout the repo from [Github](https://github.com/watchfulli/XCloner-Wordpress) 12 | 2. If you've already cloned it, reset your current branch: 13 | - `git reset HEAD --hard` 14 | 3. Identify which branch the PR the branch is for. 15 | 4. Switch to that branch 16 | - `git fetch origin name-of-branch` 17 | - `git checkout name-of-branch` 18 | - Please not activate the plugin yet 19 | 5. Run the installation steps documented in [the local development documentation](./local-dev.md) to simulate a production build: 20 | - `npm install` 21 | - Ensure you have the latest JavaScript dependecies install. 22 | - `npm run build-prod` 23 | - Ensure the JavaScript and CSS assets are built. 24 | - `docker run --rm -it --volume "$(pwd)":/app prooph/composer:7.3 install --no-dev` 25 | - Ensures the PHP dependencies are installed correctly 26 | - Installation uses a Docker container so that we use a consistent PHP version (7.3) to install. 27 | - `docker-compose up -d` 28 | - Starts or restarts the server 29 | 6. In your test WordPress site, activate the plugin. 30 | 7. Attempt to reproduce the bug, using the steps listed in the original issue that the [bug was reported in](./reporting-bugs.md) 31 | 8. If the bug is no longer present, comment on the issue explaining how you tested. 32 | - Make sure to include your version of PHP and WordPress. 33 | 9. If the bug is still present, comment on the issue explaining how you tested and what PHP and JavaScript errors you encountered. 34 | - Make sure to include your version of PHP and WordPress. 35 | -------------------------------------------------------------------------------- /docs/workflows.md: -------------------------------------------------------------------------------- 1 | # Github Action Workflows 2 | 3 | There are several Github actions: 4 | 5 | 1. analysis.yml 6 | - This runs [phpstan](https://phpstan.org/) and [checks backwards compatibility with older versions of php](https://github.com/PHPCompatibility/PHPCompatibilityWP). 7 | - This runs on all pull requests. 8 | 2. test.yml 9 | - This runs [phpunit](https://phpunit.de/) tests. 10 | - These tests can run locally. See [WordPress Tests section of local dev docs](./local-dev.md) 11 | - This runs on all pull requests. 12 | 3. deploy.yml 13 | - This [releases updates to WordPress.org](https://github.com/10up/action-wordpress-plugin-deploy). 14 | - This runs when a new tag is added. 15 | 4. version.yml 16 | - This checks if the "Tested up to" value is older than latest version of WordPress. 17 | - See [release process docs](./release-process.md) 18 | - This runs once a day. 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xcloner-backup-and-restore", 3 | "version": "3.1.4", 4 | "description": "XCloner Backup and Restore plugin", 5 | "main": "xcloner.php", 6 | "directories": { 7 | "example": "examples", 8 | "lib": "lib" 9 | }, 10 | "scripts": { 11 | "build": "echo \"Error: no build specified\"", 12 | "build-prod": "webpack --config webpack.prod.js", 13 | "start": "webpack --config webpack.dev.js --watch --info-verbosity verbose", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/ovidiul/XCloner-Wordpress.git" 19 | }, 20 | "keywords": [ 21 | "backup" 22 | ], 23 | "author": "Watchful.net", 24 | "license": "GPL-3.0-or-later", 25 | "bugs": { 26 | "url": "https://github.com/ovidiul/XCloner-Wordpress/issues" 27 | }, 28 | "homepage": "https://github.com/ovidiul/XCloner-Wordpress#readme", 29 | "devDependencies": { 30 | "terser-webpack-plugin": "^4.1.0", 31 | "uglify-js": "^3.10.3", 32 | "webpack": "^4.44.1", 33 | "webpack-cli": "^3.3.12", 34 | "webpack-merge": "^5.1.3", 35 | "webpack-merge-and-include-globally": "^2.1.25" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /phpstan-baseline.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | ignoreErrors: 3 | - 4 | message: "#^Variable \\$remote_storage might not be defined\\.$#" 5 | count: 1 6 | path: xcloner-backup-and-restore/admin/partials/remote_storage/aws.php 7 | 8 | - 9 | message: "#^Variable \\$gdrive_auth_url might not be defined\\.$#" 10 | count: 1 11 | path: xcloner-backup-and-restore/admin/partials/remote_storage/gdrive.php 12 | 13 | - 14 | message: "#^Variable \\$gdrive_construct might not be defined\\.$#" 15 | count: 1 16 | path: xcloner-backup-and-restore/admin/partials/remote_storage/gdrive.php 17 | 18 | - 19 | message: "#^Variable \\$remote_storage might not be defined\\.$#" 20 | count: 1 21 | path: xcloner-backup-and-restore/admin/partials/remote_storage/gdrive.php 22 | 23 | - 24 | message: "#^Variable \\$this might not be defined\\.$#" 25 | count: 2 26 | path: xcloner-backup-and-restore/admin/partials/xcloner_console_page.php 27 | 28 | - 29 | message: "#^Variable \\$this might not be defined\\.$#" 30 | count: 3 31 | path: xcloner-backup-and-restore/admin/partials/xcloner_generate_backups_page.php 32 | 33 | - 34 | message: "#^Variable \\$this might not be defined\\.$#" 35 | count: 5 36 | path: xcloner-backup-and-restore/admin/partials/xcloner_init_page.php 37 | 38 | - 39 | message: "#^Variable \\$this might not be defined\\.$#" 40 | count: 4 41 | path: xcloner-backup-and-restore/admin/partials/xcloner_manage_backups_page.php 42 | 43 | - 44 | message: "#^Variable \\$this might not be defined\\.$#" 45 | count: 1 46 | path: xcloner-backup-and-restore/admin/partials/xcloner_remote_storage_page.php 47 | 48 | - 49 | message: "#^Constant AUTH_KEY not found\\.$#" 50 | count: 1 51 | path: xcloner-backup-and-restore/admin/partials/xcloner_restore_page.php 52 | 53 | - 54 | message: "#^Variable \\$this might not be defined\\.$#" 55 | count: 4 56 | path: xcloner-backup-and-restore/admin/partials/xcloner_restore_page.php 57 | 58 | - 59 | message: "#^Variable \\$this might not be defined\\.$#" 60 | count: 2 61 | path: xcloner-backup-and-restore/admin/partials/xcloner_scheduled_backups_page.php 62 | 63 | - 64 | message: "#^Call to an undefined method Xcloner\\:\\:get_xcloner_scheduler\\(\\)\\.$#" 65 | count: 1 66 | path: xcloner-backup-and-restore/includes/class-xcloner-deactivator.php 67 | 68 | - 69 | message: "#^Call to an undefined method Xcloner\\:\\:get_xcloner_filesystem\\(\\)\\.$#" 70 | count: 1 71 | path: xcloner-backup-and-restore/includes/class-xcloner-deactivator.php 72 | 73 | - 74 | message: "#^Call to an undefined method Xcloner\\:\\:get_xcloner_settings\\(\\)\\.$#" 75 | count: 2 76 | path: xcloner-backup-and-restore/includes/class-xcloner.php 77 | 78 | - 79 | message: "#^Constant WP_CONTENT_DIR not found\\.$#" 80 | count: 1 81 | path: xcloner-backup-and-restore/includes/class-xcloner.php 82 | 83 | - 84 | message: "#^Constant WP_PLUGIN_DIR not found\\.$#" 85 | count: 1 86 | path: xcloner-backup-and-restore/includes/class-xcloner.php 87 | 88 | - 89 | message: "#^Instantiated class Xcloner_Public not found\\.$#" 90 | count: 1 91 | path: xcloner-backup-and-restore/includes/class-xcloner.php 92 | 93 | - 94 | message: "#^Method Xcloner\\:\\:onedrive_auth_token\\(\\) with return type void returns false but should not return anything\\.$#" 95 | count: 1 96 | path: xcloner-backup-and-restore/includes/class-xcloner.php 97 | 98 | - 99 | message: "#^PHPDoc tag @param has invalid value \\(\\$args\\)\\: Unexpected token \"\\$args\", expected type at offset 83$#" 100 | count: 1 101 | path: xcloner-backup-and-restore/includes/class-xcloner.php 102 | 103 | - 104 | message: "#^PHPDoc tag @param has invalid value \\(\\$property\\)\\: Unexpected token \"\\$property\", expected type at offset 59$#" 105 | count: 1 106 | path: xcloner-backup-and-restore/includes/class-xcloner.php 107 | 108 | - 109 | message: "#^PHPDoc tag @param has invalid value \\(\\$schedules\\)\\: Unexpected token \"\\$schedules\", expected type at offset 18$#" 110 | count: 1 111 | path: xcloner-backup-and-restore/includes/class-xcloner.php 112 | 113 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - phpstan-baseline.neon 3 | 4 | parameters: 5 | level: 3 6 | paths: 7 | - xcloner-backup-and-restore/admin 8 | - xcloner-backup-and-restore/includes 9 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | // Webpack uses this to work with directories 2 | const path = require("path"); 3 | const TerserPlugin = require("terser-webpack-plugin"); 4 | 5 | // This is the main configuration object. 6 | // Here you write different options and tell Webpack what to do 7 | module.exports = { 8 | // Path to your entry point. From this file Webpack will begin his work 9 | entry: { 10 | index: "./xcloner-backup-and-restore/admin/js/index.js", 11 | }, 12 | 13 | // Path and filename of your result bundle. 14 | // Webpack will bundle all JavaScript into this file 15 | output: { 16 | path: path.resolve(__dirname, "xcloner-backup-and-restore/dist"), 17 | filename: "./admin/js/[name].min.js", 18 | }, 19 | 20 | optimization: { 21 | minimize: false, 22 | minimizer: [new TerserPlugin()], 23 | }, 24 | 25 | // Default mode for Webpack is production. 26 | // Depending on mode Webpack will apply different things 27 | // on final bundle. For now we don't need production's JavaScript 28 | // minifying and other thing so let's set mode to development 29 | //mode: 'development' 30 | mode: "development", 31 | devtool: 'inline-source-map', 32 | }; 33 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | // Webpack uses this to work with directories 2 | const path = require("path"); 3 | const TerserPlugin = require("terser-webpack-plugin"); 4 | const webpack = require('webpack'); 5 | 6 | // This is the main configuration object. 7 | // Here you write different options and tell Webpack what to do 8 | module.exports = { 9 | // Path to your entry point. From this file Webpack will begin his work 10 | entry: { 11 | index: "./xcloner-backup-and-restore/admin/js/index.js", 12 | }, 13 | 14 | // Path and filename of your result bundle. 15 | // Webpack will bundle all JavaScript into this file 16 | output: { 17 | path: path.resolve(__dirname, "xcloner-backup-and-restore"), 18 | filename: "./admin/js/[name].min.js", 19 | }, 20 | 21 | optimization: { 22 | minimize: true, 23 | minimizer: [new TerserPlugin( 24 | { 25 | extractComments: { 26 | banner: (licenseFile) => { 27 | return `\n 28 | For license information please see ${path.basename(licenseFile)}\n 29 | To view source code please see https://github.com/watchfulli/XCloner-Wordpress/\n`; 30 | }, 31 | } 32 | } 33 | )], 34 | }, 35 | 36 | plugins: [ 37 | new webpack.BannerPlugin('You can review the source code here: https://github.com/watchfulli/XCloner-Wordpress/') 38 | ], 39 | mode: "production", 40 | devtool: 'source-map', 41 | }; 42 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | = 4.7.6 = 2 | * Update "tested up to" version 3 | 4 | = 4.7.5 = 5 | * Move changelog to a separate file (https://github.com/watchfulli/XCloner-Wordpress/issues/315) 6 | 7 | = 4.7.4 = 8 | * Prevent direct access to Composer vendor files to avoid security issues 9 | 10 | = 4.7.3 = 11 | * Update "tested up to" version 12 | 13 | = 4.7.2 = 14 | * Update "tested up to" version 15 | 16 | = 4.7.1 = 17 | * Update "tested up to" version 18 | 19 | = 4.7.0 = 20 | * Fix typo on Google drive integration #288 21 | * Review authentication on Google drive integration to drop unsupported oob authentication #264 22 | * Update "tested up to" version 23 | 24 | = 4.6.5 = 25 | * Update "tested up to" version 26 | 27 | = 4.6.4 = 28 | * Update "tested up to" version 29 | 30 | = 4.6.3 = 31 | * Update "tested up to" version 32 | 33 | = 4.6.2 = 34 | * fix: Add CLI support for backup archive files listing: https://github.com/watchfulli/XCloner-Wordpress/issues/138 35 | * fix: PHP deprecated messages: https://github.com/watchfulli/XCloner-Wordpress/issues/170 36 | 37 | = 4.6.1 = 38 | * fix: Backup archives not containing all files: https://github.com/watchfulli/XCloner-Wordpress/issues/179 39 | * fix: File not found error while scanning for files: https://github.com/watchfulli/XCloner-Wordpress/issues/266 40 | 41 | = 4.6.0 = 42 | * Split UI of local restore and site cloning: https://github.com/watchfulli/XCloner-Wordpress/issues/258 43 | 44 | = 4.5.2 = 45 | * Removed duplicate code 46 | 47 | = 4.5.1 = 48 | * Removed unused dependencies 49 | 50 | = 4.5.0 = 51 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/166 52 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/167 53 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/173 54 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/237 55 | 56 | = 4.4.8 = 57 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/242 58 | 59 | = 4.4.7 = 60 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/239 61 | 62 | = 4.4.6 = 63 | * https://github.com/watchfulli/XCloner-Wordpress/issues/241 64 | 65 | = 4.4.5 = 66 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/240 67 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/234 68 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/225 69 | 70 | = 4.4.4 = 71 | * fix: missing escapes and sanitizations 72 | 73 | = 4.4.3 = 74 | * remove PHP Short Tags to be compliant with WordPress guidelines 75 | 76 | = 4.4.2 = 77 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/227 78 | * fix: https://github.com/watchfulli/XCloner-Wordpress/issues/231 79 | 80 | = 4.4.1 = 81 | * minor code review 82 | 83 | = 4.4.0 = 84 | * remove remote restore feature to be compliant with WordPress guidelines 85 | 86 | = 4.3.7 = 87 | * security fixes 88 | 89 | = 4.3.6 = 90 | * security fixes 91 | 92 | = 4.3.5 = 93 | * security fixes 94 | 95 | = 4.2.16 = 96 | * Backblaze remote storage UI text changes 97 | * Improved Google Drive integration 98 | * http(s) url email backup fix 99 | * design changes 100 | * security fixes 101 | 102 | = 4.2.15 = 103 | 104 | * frontend popup display conflict fix 105 | * design changes 106 | * remote storage direct download option addon 107 | * replace modal from generate backup screen with a new follow up tab 108 | * S3 uplaod fix 109 | * WP-CLI --quiet flag addon, --encrypt/--decrypt addon 110 | * CSRF nonces implementation API 111 | 112 | = 4.2.14 = 113 | 114 | * CSRF restore vulnerability fix 115 | 116 | = 4.2.13 = 117 | 118 | * conflict fix bootstrap modal display 119 | * WP 5.5 compatibility check and update 120 | 121 | = 4.2.12 = 122 | 123 | * Google Drive authorization fix 124 | 125 | = 4.2.11 = 126 | 127 | * OneDrive file upload size limit fix 128 | 129 | = 4.2.10 = 130 | 131 | * Add `Local Storage` to the `Remote Storage` area 132 | * Cleanup uploaded archive after restore 133 | * Add WP-CLI support 134 | * Add Microsoft OneDrive support to remote storage 135 | * BUG: Load webdav vendor lib only if webdav is activated 136 | * Add support for Backblaze application keys 137 | * BUG: Google Drive upload issue 138 | 139 | = 4.2.9 = 140 | 141 | * scheduler fix call init 142 | * google drive support fix 143 | * PHP 7.1 minimum requirement 144 | * PHP 7.x bug fix 145 | * PHP 7.x minimum support activation 146 | 147 | = 4.2.1 = 148 | 149 | ** Implemented enhancements: ** 150 | * Rename `Scheduled Backups` menu to `Schedules & Profiles` 151 | 152 | ** Fixed bugs: ** 153 | * Fixed `redeclare deactivate\_plugin` bug in CLI 154 | 155 | = 4.2.0 = 156 | 157 | ** Implemented enhancements: ** 158 | 159 | * Improve error when connecting to remote site using restore script from another site 160 | * Improve error message when accessing restore script directly 161 | * Encrypt database password during restore 162 | * Update default regex exclusions 163 | * Replace youtube links 164 | * Add additional cleanup & quota options for backup storage 165 | * Add standalone CLI for making backups 166 | * Move `send to remote destination` option to the `Backup Options` tab 167 | 168 | ** Fixed bugs: ** 169 | 170 | * Select All Backups delete does not work 171 | * JS Error during restoration 172 | * Ajax error when viewing empty storage area 173 | * Javascript error when running a backup, and clicking "Send Backup to remote storage" 174 | * SFTP bug 175 | * Live DB restore replaces WP Options table 176 | 177 | = 4.1.5 = 178 | * SFTP upoad fix 179 | 180 | = 4.1.4 = 181 | * thinkovi references replace 182 | * plugin pre auto update text changelog 183 | * author name and uri change 184 | * standalone library addon support 185 | 186 | = 4.1.3 = 187 | * database include tables fix 188 | 189 | = 4.1.2 = 190 | * improved default backup storage path security 191 | * improved remote storage security 192 | 193 | = 4.1.2 = 194 | * vendor lib updates 195 | * flysystem azure storage Upgrade 196 | 197 | = 4.1.1 = 198 | * log tmp directories fix, tracking only ERROR reports from php 199 | * security improvement backup log name 200 | * database restore resume fix 201 | * memory limit fix 202 | 203 | = 4.1.0 = 204 | * added AES-128-CBC backup encryption and decryption option 205 | * manage backup fixes 206 | * scheduled backup screen fixes and addon backup encryption option 207 | * automated backups encryption option addon 208 | * generate backups encrypt option addon 209 | 210 | = 4.0.9 = 211 | * remote storage password encryption addon for database 212 | * vendor cleanup packages 213 | * database silent fail fix 214 | * copyright changes 215 | * jstree fix database display 216 | * microtime float div fix 217 | * manage backups data order fix 218 | 219 | = 4.0.8 = 220 | * updated vendor library dependencies, AWS, phpseclib 221 | * TAR compression fix 222 | * 7.2 compatibility checks and fixes 223 | 224 | = 4.0.7 = 225 | * added log fixes for Wordpress cron 226 | * remove storage fixes 227 | 228 | = 4.0.6 = 229 | * S3 prefix addon for defining folders 230 | * S3 custom endpoint addon to support minio.io 231 | * code fixes 232 | 233 | = 4.0.5 = 234 | * Dropbox API update to V2 235 | * Code fixes and text changes 236 | 237 | = 4.0.4 = 238 | * remote storage view fix 239 | * added automatic backups option before WP automatic update 240 | * deactivate exception handling fix 241 | * restore pages improvements 242 | * old XCloner backup format compatibility fixes 243 | 244 | = 4.0.3 = 245 | * added differential backups with the option to only backup files modified after a certain date 246 | * added localhost restore option with direct access to the restore restore 247 | * added schedule name fixes 248 | * added restore filter All Files, Only Plugins Files, Only Theme Files, Only Uploads Files, Only Database Backup 249 | * added remote backup list archive option on restore page 250 | * tmp directory cleanup on deactivate 251 | * sftp text fixes 252 | 253 | = 4.0.2 = 254 | * added WebDAV remote storage support 255 | * added Google Drive Suppor through XCloner-Google-Drive plugin 256 | * added depedency injection code refactoring 257 | * added TAR PAX support on restore 258 | * improving code quality scrutinizer 259 | * fixing phpversion requirement 260 | * adding Backblaze remote storage support 261 | * added Remote Storage Manage Backups dropdown selection 262 | * fixed windows opendir error 263 | * added total archived files to notifications email 264 | * timezone scheduler fix 265 | * added default error sending to admin when no notification email is set 266 | 267 | 268 | = 4.0.1 = 269 | * Code rewritten from ground up to make use of latest code standards 270 | * Added support for Dropbox, Amazon S3, Azure Blob and SFTP storage 271 | * Added a new restore script 272 | * Added an improved backup and system logger 273 | * New Setting Panel 274 | * New Manage Backups Panel with the options to Delete, Transfer to Remote Storage, Download and List Backup archive contents 275 | * Added mail notifications for scheduled backups 276 | * Added a new Cron Scheduler to make use of Wordpress System Cron option 277 | * Improved user input sanitization 278 | * Improved recursive file scanning and archiving 279 | * Improved Mysql Backup dump 280 | * Added Multiple Cleanup options both for local storage and remote 281 | * Added Improved Backup Compressing option 282 | 283 | = 3.1.5 = 284 | * Config variables save sanitization addon 285 | 286 | = 3.1.4 = 287 | * DropPHP DropBox library update, upload fixes for files larger than 150MB 288 | 289 | = 3.1.3 = 290 | * XSS fix 291 | 292 | = 3.1.2 = 293 | * vulnerability fix 294 | 295 | = 3.1.1 = 296 | * added CSRF protection 297 | 298 | = 3.1.0 = 299 | * added Wordpress login-less integration 300 | * plugin settings are now saved to database 301 | * security audit and hardening 302 | 303 | = 3.0.8 = 304 | * added russian language support 305 | 306 | = 3.0.7 = 307 | * added sftp support for backup transfer, thanks Todd Bluhm - dynamicts.com 308 | 309 | = 3.0.6 = 310 | * added php 5.4 compatibility 311 | 312 | = 3.0.4 = 313 | * LFI vulnerability fix 314 | 315 | = 3.0.3 = 316 | * added amazon ssl option box 317 | * moved the compress option to the System tab, don't use it unless you know what you are doing! 318 | 319 | = 3.0.1 = 320 | * several important security and bug fixes 321 | 322 | = 3.0 = 323 | * incremental database backup 324 | * incremental file system scan 325 | * backup size limit and option to split it into additional archives, default 2GB 326 | * exclude files larger than a certain size option 327 | * incremental files restore 328 | * JQuery Start interface 329 | 330 | = 2.2.1 = 331 | * Added JSON AJAX interface to the Generate Backup process 332 | * Added incremental filesystem scan 333 | * several bug fixes 334 | * php >=5.2.0 version check 335 | 336 | = 2.1.2 = 337 | * Added Amazon S3 cron storage support 338 | 339 | = 2.1 = 340 | * Initial release -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/btn_google_signin_dark_pressed_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/btn_google_signin_dark_pressed_web.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/database-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/database-icon.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/file-icon-d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/file-icon-d.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/file-icon-f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/file-icon-f.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/file-icon-l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/file-icon-l.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/file-icon-root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/file-icon-root.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/assets/table-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/assets/table-icon.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/class-xcloner-admin.php: -------------------------------------------------------------------------------- 1 | 24 | */ 25 | class Xcloner_Admin 26 | { 27 | 28 | /** 29 | * The ID of this plugin. 30 | * 31 | * @since 1.0.0 32 | * @access private 33 | * @var string $plugin_name The ID of this plugin. 34 | */ 35 | private $plugin_name; 36 | 37 | /** 38 | * @var Xcloner 39 | */ 40 | private $xcloner_container; 41 | 42 | /** 43 | * Initialize the class and set its properties. 44 | * 45 | * Xcloner_Admin constructor. 46 | * @param Xcloner $xcloner_container 47 | */ 48 | public function __construct(Xcloner $xcloner_container) 49 | { 50 | $this->plugin_name = Xcloner::PLUGIN_NAME; 51 | $this->xcloner_container = $xcloner_container; 52 | } 53 | 54 | /** 55 | * @return Xcloner 56 | */ 57 | public function get_xcloner_container() 58 | { 59 | return $this->xcloner_container; 60 | } 61 | 62 | /** 63 | * Register the stylesheets for the admin area. 64 | * 65 | * @since 1.0.0 66 | */ 67 | public function enqueue_styles($hook) 68 | { 69 | 70 | if (!stristr($hook, "page_" . $this->plugin_name) || (isset($_GET['option']) && $_GET['option'] == "com_cloner")) { 71 | return; 72 | } 73 | 74 | /** 75 | * This function is provided for demonstration purposes only. 76 | * 77 | * An instance of this class should be passed to the run() function 78 | * defined in Xcloner_Loader as all of the hooks are defined 79 | * in that particular class. 80 | * 81 | * The Xcloner_Loader will then create the relationship 82 | * between the defined hooks and the functions defined in this 83 | * class. 84 | */ 85 | 86 | wp_enqueue_style($this->plugin_name . "_materialize", plugin_dir_url(__FILE__) . 'css/materialize.min.css', array()); 87 | wp_enqueue_style($this->plugin_name . "_materialize.icons", '//fonts.googleapis.com/icon?family=Material+Icons', array()); 88 | wp_enqueue_style($this->plugin_name . "_jquery.datatables", plugin_dir_url(__FILE__) . 'css/jquery.dataTables.min.css', array()); 89 | wp_enqueue_style($this->plugin_name . "_jquery.datatables.responsive", plugin_dir_url(__FILE__) . 'css/responsive.dataTables.css', array()); 90 | wp_enqueue_style($this->plugin_name . "_jstree", dirname(plugin_dir_url(__FILE__)) . '/vendor/vakata/jstree/dist/themes/default/style.min.css', array()); 91 | wp_enqueue_style($this->plugin_name, plugin_dir_url(__FILE__) . 'css/xcloner-admin.css', array()); 92 | } 93 | 94 | /** 95 | * Register the JavaScript for the admin area. 96 | * 97 | * @since 1.0.0 98 | */ 99 | public function enqueue_scripts($hook) 100 | { 101 | 102 | if (!stristr($hook, "page_" . $this->plugin_name)) { 103 | return; 104 | } 105 | 106 | /** 107 | * This function is provided for demonstration purposes only. 108 | * 109 | * An instance of this class should be passed to the run() function 110 | * defined in Xcloner_Loader as all of the hooks are defined 111 | * in that particular class. 112 | * 113 | * The Xcloner_Loader will then create the relationship 114 | * between the defined hooks and the functions defined in this 115 | * class. 116 | */ 117 | 118 | add_thickbox(); 119 | wp_enqueue_script('plugin-install'); 120 | wp_enqueue_script('updates'); 121 | wp_enqueue_script($this->plugin_name . "_jquery.datatables", plugin_dir_url(__FILE__) . 'js/jquery.dataTables.min.js', array('jquery')); 122 | wp_enqueue_script($this->plugin_name . "_jquery.datatables.respnsive", plugin_dir_url(__FILE__) . 'js/dataTables.responsive.js', array('jquery')); 123 | wp_enqueue_script($this->plugin_name . "_vakata", dirname(plugin_dir_url(__FILE__)) . '/vendor/vakata/jstree/dist/jstree.min.js', array('jquery')); 124 | 125 | wp_enqueue_script($this->plugin_name, dirname(plugin_dir_url(__FILE__)) . '/admin/js/index.min.js', array('jquery')); 126 | } 127 | 128 | public function xcloner_init_page() 129 | { 130 | require_once("partials/xcloner_init_page.php"); 131 | } 132 | 133 | /** 134 | * Returns the XCloner Storage Page 135 | */ 136 | public function xcloner_remote_storage_page() 137 | { 138 | $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization(); 139 | $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage(); 140 | 141 | if (isset($_POST['action'])) { 142 | $_POST['action'] = $xcloner_sanitization->sanitize_input_as_string($_POST['action']); 143 | $remote_storage->save($_POST['action']); 144 | } 145 | 146 | if (isset($_POST['authentification_code']) && $_POST['authentification_code'] != "") { 147 | $_POST['authentification_code'] = $xcloner_sanitization->sanitize_input_as_string($_POST['authentification_code']); 148 | 149 | $remote_storage->gdrive_set_access_token($_POST['authentification_code']); 150 | } 151 | 152 | if (isset($_POST['connection_check']) && $_POST['connection_check']) { 153 | $remote_storage->check($_POST['action']); 154 | } 155 | 156 | require_once("partials/xcloner_remote_storage_page.php"); 157 | 158 | } 159 | 160 | public function xcloner_scheduled_backups_page() 161 | { 162 | $requirements = $this->xcloner_container->get_xcloner_requirements(); 163 | 164 | if (!$requirements->check_backup_ready_status()) { 165 | require_once("partials/xcloner_init_page.php"); 166 | 167 | return false; 168 | } 169 | 170 | require_once("partials/xcloner_scheduled_backups_page.php"); 171 | 172 | return true; 173 | } 174 | 175 | public function xcloner_manage_backups_page() 176 | { 177 | require_once("partials/xcloner_manage_backups_page.php"); 178 | 179 | } 180 | 181 | public function xcloner_debugger_page() 182 | { 183 | require_once("partials/xcloner_console_page.php"); 184 | 185 | } 186 | 187 | public function xcloner_restore_site() 188 | { 189 | require_once("partials/xcloner_restore_page.php"); 190 | } 191 | 192 | public function xcloner_clone_site() 193 | { 194 | require_once("partials/xcloner_restore_page.php"); 195 | } 196 | 197 | public function xcloner_generate_backups_page() 198 | { 199 | $requirements = $this->xcloner_container->get_xcloner_requirements(); 200 | 201 | if (!$requirements->check_backup_ready_status()) { 202 | require_once("partials/xcloner_init_page.php"); 203 | 204 | return false; 205 | } 206 | 207 | require_once("partials/xcloner_generate_backups_page.php"); 208 | 209 | return true; 210 | } 211 | 212 | public function xcloner_settings_page() 213 | { 214 | // check user capabilities 215 | if (!current_user_can('manage_options')) { 216 | return; 217 | } 218 | 219 | // add error/update messages 220 | 221 | // check if the user have submitted the settings 222 | // wordpress will add the "settings-updated" $_GET parameter to the url 223 | if (isset($_GET['settings-updated'])) { 224 | // add settings saved message with the class of "updated" 225 | add_settings_error('wporg_messages', 'wporg_message', __('Settings Saved', 'wporg'), 'updated'); 226 | } 227 | 228 | // show error/update messages 229 | settings_errors('wporg_messages'); 230 | ?> 231 | 232 | get_xcloner_container()->get_xcloner_sanitization(); 234 | $active_tab = "general_options"; 235 | 236 | if (isset($_GET['tab'])) { 237 | $active_tab = $xcloner_sanitization->sanitize_input_as_string($_GET['tab']); 238 | } 239 | 240 | ?> 241 | 242 |
243 |
244 | 245 |
246 | 247 | 259 | 260 |
261 | 262 |
263 | 275 |
276 | 277 |
278 |
279 | tbody > tr > td.child, 2 | table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, 3 | table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { 4 | cursor: default !important; 5 | } 6 | table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, 7 | table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, 8 | table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { 9 | display: none !important; 10 | } 11 | table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child, 12 | table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child { 13 | position: relative; 14 | padding-left: 30px; 15 | cursor: pointer; 16 | } 17 | table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before, 18 | table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before { 19 | top: 9px; 20 | left: 4px; 21 | height: 14px; 22 | width: 14px; 23 | display: block; 24 | position: absolute; 25 | color: white; 26 | border: 2px solid white; 27 | border-radius: 14px; 28 | box-shadow: 0 0 3px #444; 29 | box-sizing: content-box; 30 | text-align: center; 31 | font-family: 'Courier New', Courier, monospace; 32 | line-height: 14px; 33 | content: '+'; 34 | background-color: #31b131; 35 | } 36 | table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before, 37 | table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before { 38 | content: '-'; 39 | background-color: #d33333; 40 | } 41 | table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before { 42 | display: none; 43 | } 44 | table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child, 45 | table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child { 46 | padding-left: 27px; 47 | } 48 | table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before, 49 | table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before { 50 | top: 5px; 51 | left: 4px; 52 | height: 14px; 53 | width: 14px; 54 | border-radius: 14px; 55 | line-height: 14px; 56 | text-indent: 3px; 57 | } 58 | table.dataTable.dtr-column > tbody > tr > td.control, 59 | table.dataTable.dtr-column > tbody > tr > th.control { 60 | position: relative; 61 | cursor: pointer; 62 | } 63 | table.dataTable.dtr-column > tbody > tr > td.control:before, 64 | table.dataTable.dtr-column > tbody > tr > th.control:before { 65 | top: 50%; 66 | left: 50%; 67 | height: 16px; 68 | width: 16px; 69 | margin-top: -10px; 70 | margin-left: -10px; 71 | display: block; 72 | position: absolute; 73 | color: white; 74 | border: 2px solid white; 75 | border-radius: 14px; 76 | box-shadow: 0 0 3px #444; 77 | box-sizing: content-box; 78 | text-align: center; 79 | font-family: 'Courier New', Courier, monospace; 80 | line-height: 14px; 81 | content: '+'; 82 | background-color: #31b131; 83 | } 84 | table.dataTable.dtr-column > tbody > tr.parent td.control:before, 85 | table.dataTable.dtr-column > tbody > tr.parent th.control:before { 86 | content: '-'; 87 | background-color: #d33333; 88 | } 89 | table.dataTable > tbody > tr.child { 90 | padding: 0.5em 1em; 91 | } 92 | table.dataTable > tbody > tr.child:hover { 93 | background: transparent !important; 94 | } 95 | table.dataTable > tbody > tr.child ul { 96 | display: inline-block; 97 | list-style-type: none; 98 | margin: 0; 99 | padding: 0; 100 | } 101 | table.dataTable > tbody > tr.child ul li { 102 | border-bottom: 1px solid #efefef; 103 | padding: 0.5em 0; 104 | } 105 | table.dataTable > tbody > tr.child ul li:first-child { 106 | padding-top: 0; 107 | } 108 | table.dataTable > tbody > tr.child ul li:last-child { 109 | border-bottom: none; 110 | } 111 | table.dataTable > tbody > tr.child span.dtr-title { 112 | display: inline-block; 113 | min-width: 75px; 114 | font-weight: bold; 115 | } 116 | 117 | div.dtr-modal { 118 | position: fixed; 119 | box-sizing: border-box; 120 | top: 0; 121 | left: 0; 122 | height: 100%; 123 | width: 100%; 124 | z-index: 100; 125 | padding: 10em 1em; 126 | } 127 | div.dtr-modal div.dtr-modal-display { 128 | position: absolute; 129 | top: 0; 130 | left: 0; 131 | bottom: 0; 132 | right: 0; 133 | width: 50%; 134 | height: 50%; 135 | overflow: auto; 136 | margin: auto; 137 | z-index: 102; 138 | overflow: auto; 139 | background-color: #f5f5f7; 140 | border: 1px solid black; 141 | border-radius: 0.5em; 142 | box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); 143 | } 144 | div.dtr-modal div.dtr-modal-content { 145 | position: relative; 146 | padding: 1em; 147 | } 148 | div.dtr-modal div.dtr-modal-close { 149 | position: absolute; 150 | top: 6px; 151 | right: 6px; 152 | width: 22px; 153 | height: 22px; 154 | border: 1px solid #eaeaea; 155 | background-color: #f9f9f9; 156 | text-align: center; 157 | border-radius: 3px; 158 | cursor: pointer; 159 | z-index: 12; 160 | } 161 | div.dtr-modal div.dtr-modal-close:hover { 162 | background-color: #eaeaea; 163 | } 164 | div.dtr-modal div.dtr-modal-background { 165 | position: fixed; 166 | top: 0; 167 | left: 0; 168 | right: 0; 169 | bottom: 0; 170 | z-index: 101; 171 | background: rgba(0, 0, 0, 0.6); 172 | } 173 | 174 | @media screen and (max-width: 767px) { 175 | div.dtr-modal div.dtr-modal-display { 176 | width: 95%; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/css/xcloner-admin.css: -------------------------------------------------------------------------------- 1 | /** 2 | * All of the CSS for your admin-specific functionality should be 3 | * included in this file. 4 | */ 5 | /* fallback */ 6 | 7 | html { 8 | font-family: GillSans, Calibri, Trebuchet, sans-serif; 9 | } 10 | 11 | /* 12 | @font-face { 13 | font-family: 'Material Icons'; 14 | font-style: normal; 15 | font-weight: 400; 16 | src: url(../fonts/MaterialIcons-Regular.eot); 17 | src: local('Material Icons'), 18 | local('MaterialIcons-Regular'), 19 | url(../fonts/MaterialIcons-Regular.woff2) format('woff2'), 20 | url(../fonts/MaterialIcons-Regular.woff) format('woff'), 21 | url(../fontsMaterialIcons-Regular.ttf) format('truetype'); 22 | }*/ 23 | 24 | h1 { 25 | font-size: 23px; 26 | } 27 | 28 | h2 { 29 | font-size: 18px; 30 | } 31 | 32 | .input-field { 33 | margin-top: 0px; 34 | } 35 | 36 | td, th { 37 | padding-top: 0px !important; 38 | } 39 | 40 | .form-table th { 41 | padding-top: 10px !important; 42 | } 43 | 44 | a.nav-tab.col { 45 | padding: 10px; 46 | } 47 | 48 | span.shorten_string { 49 | cursor: pointer; 50 | } 51 | 52 | .card-panel { 53 | min-height: 60px; 54 | } 55 | 56 | .dashboard .additional_system_info { 57 | display: none; 58 | } 59 | 60 | .nav-tab-wrapper li { 61 | margin-bottom: 0px; 62 | } 63 | 64 | .nav-tab-wrapper-content .tab-content { 65 | display: none; 66 | } 67 | 68 | .nav-tab-wrapper-content .tab-content.active { 69 | display: block; 70 | } 71 | 72 | .input-field label.active { 73 | font-size: 1rem; 74 | } 75 | 76 | .xcloner-debugger .console { 77 | height: 450px; 78 | min-height: 300px; 79 | overflow: auto; 80 | } 81 | 82 | #error_modal textarea { 83 | height: 150px; 84 | } 85 | 86 | #error_modal .msg { 87 | font-size: 14px; 88 | } 89 | 90 | #generate_backup .backup-status, #generate_backup ul.backup-status > li { 91 | display: none; 92 | } 93 | 94 | ul.backup-name { 95 | margin-top: 1.78rem; 96 | } 97 | 98 | #generate_backup .status-body ul.backup-name li, #generate_backup ul.logged-databases li { 99 | font-weight: bold; 100 | } 101 | 102 | #generate_backup .backup-done .collapsible-body { 103 | margin-top: 1.83rem; 104 | } 105 | 106 | #generate_backup .status-body > ul, #generate_backup .status-body ul.logged-tables { 107 | margin: 5px 10px; 108 | max-height: 200px; 109 | overflow-y: auto; 110 | margin-top: 1.78rem; 111 | } 112 | 113 | #generate_backup .action-buttons .cancel, 114 | #generate_backup .action-buttons .restart { 115 | display: none; 116 | } 117 | 118 | .modal-footer .modal-close.btn-flat { 119 | color: #fff; 120 | } 121 | 122 | .collapsible-body { 123 | padding: 0px 10px; 124 | } 125 | 126 | .select-wrapper + label { 127 | font-size: 1rem; 128 | } 129 | 130 | .input-field>label:not(.label-icon).active { 131 | -webkit-transform: translateY(-14px) scale(1); 132 | transform: translateY(-14px) scale(1); 133 | } 134 | 135 | #schedule_backup .server-time h2 { 136 | color: #fff; 137 | } 138 | 139 | #schedule_backup_success { 140 | display: none; 141 | } 142 | 143 | #scheduled_backups_wrapper .dataTables_length, 144 | #manage_backups_wrapper .dataTables_length { 145 | display: none; 146 | } 147 | 148 | table#scheduled_backups { 149 | font-size: 16px; 150 | } 151 | 152 | #scheduled_backups td, #scheduled_backups th { 153 | padding-top: 8px !important; 154 | } 155 | 156 | #scheduled_backups i.status { 157 | color: #fff; 158 | } 159 | 160 | .site-backup_page_xcloner_scheduled_backups_page #server_time h2 { 161 | color: #fff; 162 | margin: 9px 0px; 163 | padding: 10px 10px 5px 10px; 164 | } 165 | 166 | textarea.materialize-textarea { 167 | overflow: auto; 168 | resize: auto; 169 | } 170 | 171 | #scheduled_backups .edit, #scheduled_backups .status.active, #scheduled_backups .delete, 172 | #manage_backups .download, #manage_backups .cloud-upload, #manage_backups .delete, #manage_backups .list-backup-content, 173 | .backup-done .download, .backup-done .cloud-upload, .backup-done .delete, .backup-done .list-backup-content, 174 | #manage_backups .copy-remote-to-local, #manage_backups .expand-multipart, 175 | #manage_backups .backup-encryption, #manage_backups .backup-decryption { 176 | color: #4db6ac; 177 | } 178 | 179 | #scheduled_backups .status.inactive { 180 | color: #d32f2f; 181 | } 182 | 183 | table.dataTable thead th, table.dataTable tfoot th { 184 | padding-left: 10px; 185 | } 186 | 187 | table.dataTable tr.odd { 188 | background-color: #fff; 189 | } 190 | 191 | table.dataTable tr.even { 192 | background-color: #f3f3f3; 193 | } 194 | 195 | #manage_backups ul.multipart { 196 | margin-left: 20px; 197 | display: none; 198 | } 199 | 200 | #manage_backups ul.multipart li { 201 | padding: 5px; 202 | list-style-type: square; 203 | } 204 | 205 | a.expand-multipart.remove { 206 | display: none; 207 | } 208 | 209 | .remote-storage .label label { 210 | font-size: 16px; 211 | } 212 | 213 | .remote-storage .label { 214 | padding-top: 25px; 215 | } 216 | 217 | .remote-storage .collapsible-header { 218 | padding: 10px; 219 | display: block; 220 | line-height: 25px; 221 | } 222 | 223 | #generate_backup p { 224 | margin: 0px; 225 | } 226 | 227 | #generate_backup .collapsible-header, 228 | .xcloner-debugger .collapsible-header{ 229 | display: block; 230 | } 231 | 232 | #manage_backups td.checkbox { 233 | vertical-align: top; 234 | } 235 | 236 | #remote_storage_modal { 237 | min-height: 350px; 238 | } 239 | 240 | #remote_storage_modal .label label { 241 | font-size: 16px; 242 | } 243 | 244 | #remote_storage_modal .label { 245 | padding-top: 25px; 246 | } 247 | 248 | #remote_storage_modal .status { 249 | display: none; 250 | } 251 | 252 | #remote_storage_modal .status-text.error { 253 | color: red; 254 | } 255 | 256 | #remote_storage_modal .status-text { 257 | font-weight: bold; 258 | } 259 | 260 | #backup-status h5 { 261 | font-size: 18px; 262 | } 263 | 264 | #backup-status .row .item .title { 265 | width: 100px; 266 | display: inline-block; 267 | font-weight: bold; 268 | } 269 | 270 | .xcloner-restore li.steps { 271 | display: none; 272 | } 273 | 274 | .xcloner-restore .steps.show { 275 | display: block; 276 | } 277 | 278 | .xcloner-restore li .collapsible-body { 279 | padding: 25px 10px 15px 10px; 280 | } 281 | 282 | .xcloner-restore select.browser-default { 283 | height: 36px; 284 | font-size: 18px; 285 | } 286 | 287 | .xcloner-restore .steps .progress { 288 | display: none; 289 | } 290 | 291 | .xcloner-restore .status > div { 292 | margin: 10px 0px 0px 0px; 293 | } 294 | 295 | .xcloner-restore .toggler { 296 | display: inline-block; 297 | } 298 | 299 | .xcloner-restore .toggler .normal { 300 | display: block; 301 | } 302 | 303 | .xcloner-restore .toggler .cancel { 304 | display: none; 305 | } 306 | 307 | .xcloner-restore .toggler.cancel .normal { 308 | display: none; 309 | } 310 | 311 | .xcloner-restore .toggler.cancel .cancel { 312 | display: block; 313 | } 314 | 315 | .xcloner-restore ul.text-steps li { 316 | list-style-type: decimal; 317 | padding:5px 0px; 318 | } 319 | 320 | .xcloner-restore ul.text-steps li.warning { 321 | color: red; 322 | } 323 | 324 | .xcloner-restore ul.text-steps ul li { 325 | list-style-type: disc; 326 | } 327 | 328 | .xcloner-restore ul.text-steps ul { 329 | margin: 10px; 330 | } 331 | 332 | .xcloner-restore ul.text-steps { 333 | margin-left: 50px; 334 | } 335 | 336 | .xcloner-restore .restore-remote-backup-step .files-list { 337 | max-height: 250px; 338 | overflow: auto; 339 | margin: 10px 5px; 340 | } 341 | 342 | #backup_cotent_modal .modal-content .files-list span { 343 | cursor: pointer; 344 | } 345 | 346 | .xcloner-restore .query-box { 347 | display: none; 348 | } 349 | 350 | .xcloner-restore .query-box .query-list { 351 | height: 10rem; 352 | } 353 | 354 | .xcloner-restore .restore-remote-database-step h5 { 355 | margin-top: -10px; 356 | margin-bottom: 25px; 357 | } 358 | 359 | .regex_pattern { 360 | cursor: pointer; 361 | font-weight: bold; 362 | } 363 | 364 | .jstree-icon.jstree-checkbox.jstree-checkbox-disabled { 365 | opacity: 0.3; 366 | } 367 | 368 | #xcloner_regex_exclude { 369 | height: 5rem; 370 | } 371 | 372 | ul.xcloner_regex_exclude_limit li:nth-of-type(n+2) { 373 | display: none; 374 | } 375 | 376 | .xcloner-restore .btn.waves-effect.waves-light.grey { 377 | margin-top: -2px; 378 | } 379 | 380 | .xcloner-restore #xcloner_restore_finish { 381 | display: none; 382 | } 383 | 384 | ul.files-list li { 385 | padding: 0px; 386 | white-space: pre; 387 | } 388 | 389 | ul.files-list.error{ 390 | color: red; 391 | } 392 | 393 | #manage_backups_wrapper #manage_backups_filter { 394 | min-width: 277px; 395 | } 396 | 397 | #generate_backup_form .progress, .xcloner-restore .progress { 398 | width: 100% !important; 399 | height: 4px !important; 400 | } 401 | 402 | i.backup_warning { 403 | color: orange; 404 | } 405 | 406 | .col.remote-storage-selection { 407 | padding-top: 0px; 408 | margin-bottom: -54px; 409 | } 410 | 411 | .remote-storage #authentification_code { 412 | display: none; 413 | } 414 | 415 | .dataTables_wrapper .dataTables_filter input { 416 | margin-left: 0px; 417 | } 418 | 419 | #backup_options .row{ 420 | min-height: 30px; 421 | } 422 | 423 | .input-field .switch label { 424 | color: #000; 425 | } 426 | 427 | .wp-core-ui .select-wrapper select { 428 | border: 0px; 429 | } 430 | 431 | #save_schedule .switch { 432 | margin-top: 20px; 433 | } 434 | 435 | .collapsible-header i { 436 | vertical-align: middle; 437 | } 438 | 439 | #backup-status .title{ 440 | display: inline; 441 | } 442 | 443 | .wp-core-ui select { 444 | max-width: initial; 445 | } 446 | 447 | .xcloner-menu.dropdown-trigger i.material-icons{ 448 | vertical-align: middle; 449 | } 450 | 451 | .xcloner-menu.dropdown-content { 452 | min-width: 250px; 453 | } 454 | 455 | h1.xcloner-menu { 456 | margin: 1.68rem 0 1.68rem 0; 457 | } 458 | 459 | .xcloner-logo { 460 | max-height: 75px; 461 | max-width: 225px; 462 | float: right; 463 | margin-top: 15px; 464 | } 465 | 466 | .row.remote-storage .collapsible.popout>li { 467 | margin: 0px; 468 | } 469 | 470 | #generate_backup_form .nav-tab-wrapper-content { 471 | margin-top: 15px; 472 | } 473 | 474 | .row .nav-tab-wrapper{ 475 | border-bottom: 0px; 476 | } 477 | 478 | .form-table tr{ 479 | border-bottom: 0px; 480 | } 481 | 482 | #gdrive input#authentification_code::placeholder { 483 | color: red; 484 | } 485 | 486 | a:focus { 487 | box-shadow: none; 488 | } 489 | 490 | @media only screen and (min-width: 993px) { 491 | .dashboard .backup-ready { 492 | float: right; 493 | } 494 | } 495 | 496 | 497 | @media only screen and (max-width: 993px) { 498 | .xcloner-logo { 499 | display: none 500 | } 501 | 502 | .col.remote-storage-selection { 503 | padding-top: 0px; 504 | margin-bottom: 0px; 505 | } 506 | } -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/fonts/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/Sorting icons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/Sorting icons.psd -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/banners/CF Banner 728x90 blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/banners/CF Banner 728x90 blue.jpg -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/banners/CF Banner 728x90 red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/banners/CF Banner 728x90 red.jpg -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/favicon.ico -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/sort_asc.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/sort_asc_disabled.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/sort_both.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/sort_desc.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/images/sort_desc_disabled.png -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/images/xcloner-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/index.php: -------------------------------------------------------------------------------- 1 | option[value="' + response.recurrence + '"]') 83 | .prop("selected", true); 84 | this.edit_modal 85 | .find('#backup_type>option[value="' + response.backup_type + '"]') 86 | .prop("selected", true); 87 | this.edit_modal 88 | .find( 89 | '#schedule_storage>option[value="' + response.remote_storage + '"]' 90 | ) 91 | .prop("selected", true); 92 | //var date = new Date(response.start_at); 93 | this.edit_modal.find("#schedule_start_date").val(response.start_at); 94 | 95 | if ( 96 | response.backup_params.backup_encrypt !== undefined && 97 | response.backup_params.backup_encrypt == 1 98 | ) { 99 | this.edit_modal.find("#backup_encrypt").attr("checked", "checked"); 100 | } 101 | 102 | if ( 103 | response.backup_params.backup_delete_after_remote_transfer !== undefined && 104 | response.backup_params.backup_delete_after_remote_transfer == 1 105 | ) { 106 | this.edit_modal.find("#backup_delete_after_remote_transfer").attr("checked", "checked"); 107 | } 108 | 109 | var tables = jQuery.parseJSON(response.table_params); 110 | 111 | var tables_list = ""; 112 | 113 | for (var db in tables) { 114 | for (var i in tables[db]) 115 | tables_list += db + "." + tables[db][i] + "\n"; 116 | } 117 | 118 | this.edit_modal.find("#table_params").val(tables_list); 119 | 120 | var files = jQuery.parseJSON(response.excluded_files); 121 | var exclude_files_list = ""; 122 | for (var i in files) { 123 | exclude_files_list += files[i] + "\n"; 124 | } 125 | 126 | this.edit_modal.find("#excluded_files").val(exclude_files_list); 127 | 128 | jQuery(".col select").formSelect(); 129 | 130 | M.updateTextFields(); 131 | 132 | edit_schedule_modal_instance.open(); 133 | } 134 | 135 | save_schedule(form, dataTable) { 136 | var data = jQuery(form).serialize(); 137 | var $this = this; 138 | 139 | jQuery 140 | .ajax({ 141 | url: XCLONER_AJAXURL, 142 | dataType: "json", 143 | type: "POST", 144 | data: data, 145 | error: function (err) { 146 | //show_ajax_error("Communication Error", "", err) 147 | //console.log(err); 148 | alert("Error saving schedule!"); 149 | }, 150 | }) 151 | .done(function (json) { 152 | if (json.error !== undefined) { 153 | alert("Error saving schedule!" + json.error); 154 | return; 155 | } 156 | 157 | edit_schedule_modal_instance.close(); 158 | //location.reload(); 159 | dataTable.ajax.reload(); 160 | }); 161 | } 162 | 163 | IsJsonString(str) { 164 | try { 165 | JSON.parse(str); 166 | } catch (e) { 167 | return false; 168 | } 169 | return true; 170 | } 171 | 172 | //end class 173 | } 174 | 175 | var xcloner_scheduler = new Xcloner_Scheduler(); 176 | 177 | jQuery("select[required]").css({ 178 | display: "block", 179 | height: 0, 180 | padding: 0, 181 | width: 0, 182 | position: "absolute", 183 | }); 184 | 185 | let dataTable = jQuery("#scheduled_backups").DataTable({ 186 | responsive: true, 187 | bFilter: false, 188 | order: [[3, "desc"]], 189 | buttons: ["selectAll", "selectNone"], 190 | language: { 191 | emptyTable: "No schedules available", 192 | buttons: { 193 | selectAll: "Select all items", 194 | selectNone: "Select none", 195 | }, 196 | }, 197 | columnDefs: [ 198 | { targets: "no-sort", orderable: false }, 199 | { className: "hide-on-med-and-down", targets: [3, 5] }, 200 | ], 201 | ajax: XCLONER_AJAXURL + "&action=get_scheduler_list", 202 | fnDrawCallback: function (oSettings) { 203 | jQuery(this) 204 | .off("click", ".edit") 205 | .on("click", ".edit", function () { 206 | var hash = jQuery(this).attr("href"); 207 | var id = hash.substr(1); 208 | var data = xcloner_scheduler.get_schedule_by_id(id); 209 | }); 210 | 211 | jQuery(this) 212 | .off("click", ".delete") 213 | .on("click", ".delete", function () { 214 | var hash = jQuery(this).attr("href"); 215 | var id = hash.substr(1); 216 | if (confirm("Are you sure you want to delete it?")) { 217 | var data = xcloner_scheduler.delete_schedule_by_id( 218 | id, 219 | this, 220 | dataTable 221 | ); 222 | } 223 | }); 224 | 225 | jQuery("span.shorten_string").each(function () { 226 | doShortText(jQuery(this)); 227 | }); 228 | jQuery("span.shorten_string").click(function () { 229 | jQuery(this).toggleClass("full"); 230 | doShortText(jQuery(this)); 231 | }); 232 | }, 233 | }); 234 | 235 | jQuery("#save_schedule").on("submit", function () { 236 | xcloner_scheduler.save_schedule(jQuery(this), dataTable); 237 | 238 | return false; 239 | }); 240 | 241 | var date_picker; 242 | var date_picker_allowed; 243 | 244 | if (typeof jQuery(".timepicker").pickatime === "function") { 245 | jQuery(".timepicker").pickatime({ 246 | default: "now", 247 | min: [7, 30], 248 | twelvehour: false, // change to 12 hour AM/PM clock from 24 hour 249 | donetext: "OK", 250 | autoclose: false, 251 | vibrate: true, // vibrate the device when dragging clock hand 252 | }); 253 | } 254 | 255 | if (typeof jQuery(".timepicker").pickadate === "function") { 256 | date_picker = jQuery(".datepicker").pickadate({ 257 | format: "d mmmm yyyy", 258 | selectMonths: true, // Creates a dropdown to control month 259 | selectYears: 15, // Creates a dropdown of 15 years to control year 260 | min: +0.1, 261 | onSet: function () { 262 | //this.close(); 263 | }, 264 | }); 265 | 266 | date_picker_allowed = jQuery(".datepicker_max_today").pickadate({ 267 | format: "yyyy-mm-dd", 268 | selectMonths: true, // Creates a dropdown to control month 269 | selectYears: 15, // Creates a dropdown of 15 years to control year 270 | max: +0.1, 271 | onSet: function () { 272 | //this.close(); 273 | }, 274 | }); 275 | } 276 | }); 277 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/aws.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |   26 |
27 |
28 |

29 | Visit %s to install your own S3 like service.'), "https://aws.amazon.com/s3/", "https://minio.io/") ?> 30 |

31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | " id="aws_key" type="text" 40 | name="xcloner_aws_key" class="validate" value="" 41 | autocomplete="off"> 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 |
50 | " id="aws_secret" type="text" 51 | name="xcloner_aws_secret" class="validate" 52 | value="" 53 | autocomplete="off"> 54 |
55 |
56 | 57 |
58 |
59 | 60 |
61 |
62 | 77 |
78 |
79 | 80 |
81 |
82 |
83 | 84 |
85 |
86 | " 88 | id="aws_endpoint" type="text" name="xcloner_aws_endpoint" class="validate" 89 | value="" autocomplete="off"> 90 |
91 |
92 |
93 |
94 | 95 |
96 |
97 | " 98 | id="aws_region" type="text" name="xcloner_aws_region" class="validate" 99 | value="" autocomplete="off"> 100 |
101 |
102 |
103 | 104 |
105 |
106 | 107 |
108 |
109 | " id="aws_bucket_name" 110 | type="text" name="xcloner_aws_bucket_name" class="validate" 111 | value="" autocomplete="off"> 112 |
113 |
114 | 115 |
116 |
117 | 118 |
119 |
120 | " 122 | id="aws_prefix" type="text" name="xcloner_aws_prefix" class="validate" 123 | value="" autocomplete="off"> 124 |
125 |
126 | 127 | 128 | 129 |
130 |
131 | 135 |
136 |
137 | 141 |
142 |
143 | 144 |
145 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/azure.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 18 |
19 |
20 |
21 | 22 |
23 |
24 |   25 |
26 |
27 |

28 | https://azure.microsoft.com/en-us/services/storage/blobs/') ?> 29 |

30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 | " 39 | id="azure_account_name" type="text" name="xcloner_azure_account_name" class="validate" 40 | value="" autocomplete="off"> 41 |
42 |
43 | 44 | 45 |
46 |
47 | 48 |
49 |
50 | " id="azure_api_key" 51 | type="text" name="xcloner_azure_api_key" class="validate" 52 | value="" autocomplete="off"> 53 |
54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 | " id="azure_container" 62 | type="text" name="xcloner_azure_container" class="validate" 63 | value=""> 64 |
65 |
66 | 67 | 68 | 69 |
70 |
71 | 75 |
76 |
77 | 82 |
83 |
84 | 85 |
86 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/backblaze.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 | 10 |
11 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |   26 |
27 |
28 |

29 | https://secure.backblaze.com/b2_buckets.htm') ?> 30 |

31 |

32 | If you specify only the bucket name, you must use the master key.
33 | However, if you specify both bucket name and bucket id, you do not need the master key and can use a single-bucket key. 34 |

35 |
36 |
37 | 38 |
39 |
40 | 42 |
43 |
44 | " 45 | id="backblaze_account_id" type="text" name="xcloner_backblaze_account_id" class="validate" 46 | value="" autocomplete="off"> 47 |
48 |
49 | 50 | 51 |
52 |
53 | 55 |
56 |
57 | " 58 | id="backblaze_application_key" type="text" name="xcloner_backblaze_application_key" class="validate" 59 | value="" 60 | autocomplete="off"> 61 |
62 |
63 | 64 |
65 |
66 | 68 |
69 |
70 | " 71 | id="backblaze_bucket_name" type="text" name="xcloner_backblaze_bucket_name" class="validate" 72 | value="" autocomplete="off"> 73 |
74 |
75 | 76 |
77 |
78 | 80 |
81 |
82 | " 83 | id="backblaze_bucket_id" type="text" name="xcloner_backblaze_bucket_id" class="validate" 84 | value="" autocomplete="off"> 85 |
86 |
87 | 88 | 89 | 90 |
91 |
92 | 96 |
97 |
98 | 103 |
104 |
105 | 106 |
107 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/dropbox.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 18 |
19 |
20 |
21 | 22 |
23 |
24 |   25 |
26 |
27 |

28 | https://www.dropbox.com/developers/apps") ?> 29 |

30 |
31 |
32 | 33 |
34 |
35 | 37 |
38 |
39 | " 40 | id="dropbox_access_token" type="text" name="xcloner_dropbox_access_token" class="validate" 41 | value="" autocomplete="off"> 42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 |
50 |
51 | " 52 | id="dropbox_app_secret" type="text" name="xcloner_dropbox_app_secret" class="validate" 53 | value="" 54 | autocomplete="off"> 55 |
56 |
57 | 58 |
59 |
60 | 61 |
62 |
63 | " id="dropbox_prefix" 64 | type="text" name="xcloner_dropbox_prefix" class="validate" 65 | value=""> 66 |
67 |
68 | 69 | 70 | 71 |
72 |
73 | 77 |
78 |
79 | 83 |
84 |
85 | 86 |
87 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/ftp.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 24 |
25 |
26 |
27 |
28 |
29 | 30 |
31 |
32 | " 35 | type="text" name="xcloner_ftp_hostname" class="validate" 36 | value=""> 37 |
38 |
39 | " id="ftp_port" type="text" 40 | name="xcloner_ftp_port" class="validate" 41 | value=""> 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 |
50 | " id="ftp_username" 51 | type="text" name="xcloner_ftp_username" class="validate" 52 | value="" autocomplete="off"> 53 |
54 |
55 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | " id="ftp_password" 63 | type="text" name="xcloner_ftp_password" class="validate" 64 | value="" 65 | autocomplete="off"> 66 |
67 |
68 | 69 |
70 |
71 | 72 |
73 |
74 | " id="ftp_root" 75 | type="text" name="xcloner_ftp_path" class="validate" 76 | value=""> 77 |
78 |
79 | 80 |
81 |
82 | 83 |
84 |
85 |

86 | 93 |

94 |

95 | 102 |

103 |
104 |
105 | 106 |
107 |
108 | 109 |
110 |
111 |

112 |

119 |

120 |

127 |
128 |
129 | 130 |
131 |
132 | 133 |
134 |
135 | " id="ftp_timeout" 136 | type="text" name="xcloner_ftp_timeout" class="validate" 137 | value=""> 138 |
139 |
140 | 141 | 142 | 143 |
144 |
145 | 149 |
150 |
151 | 155 |
156 |
157 | 158 |
159 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/gdrive.php: -------------------------------------------------------------------------------- 1 | get_xcloner_container()->get_xcloner_remote_storage(); 8 | 9 | $gdrive_auth_url = ""; 10 | 11 | if (method_exists($remote_storage, "gdrive_get_auth_url")) { 12 | $gdrive_auth_url = $remote_storage->gdrive_get_auth_url(); 13 | } 14 | 15 | $gdrive_construct = $remote_storage->gdrive_construct(); 16 | ?> 17 |
18 | computer 19 | 20 |
21 | 29 |
30 | 31 |
32 |
33 | 34 | 35 | 36 |
37 |
38 |   39 |
40 |
41 |

42 | 43 |

44 |
45 |
46 | 47 |
48 |
49 |   50 |
51 |
52 | 55 | <?php echo sprintf(__('Authorize Google Drive', 'xcloner-backup-and-restore')) ?> 57 | 58 | "> 60 |
61 |
62 | 63 |
64 |
65 | 72 |
73 |
74 | " 75 | id="gdrive_target_folder" type="text" name="xcloner_gdrive_target_folder" class="validate" 76 | value="" autocomplete="off"> 77 |
78 |
79 | 80 | 81 | 82 |
83 |
84 | 86 |
87 |
88 |

89 | 95 |

96 |

97 | 103 |

104 |
105 |
106 | 107 |
108 |
109 | 113 |
114 |
115 | 119 |
120 |
121 | 122 | 123 |
124 | 148 |
149 | 150 | 151 | 152 |
153 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watchfulli/XCloner-Wordpress/ef00242abfee3a5734206d8a450c649ddc6e6536/xcloner-backup-and-restore/admin/partials/remote_storage/index.html -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/local.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | " id="aws_key" 26 | type="text" name="xcloner_start_path" class="validate" 27 | value="" autocomplete="off"> 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | " id="aws_key" 37 | type="text" name="xcloner_store_path" class="validate" 38 | value="" autocomplete="off"> 39 |
40 |
41 | 42 | 43 | 44 |
45 |
46 | 50 |
51 |
52 | 56 |
57 |
58 | 59 |
60 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/onedrive.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 18 |
19 |
20 |
21 | 22 |
23 |
24 |   25 |
26 |
27 |

28 | Microsoft Azure App Registrations and get your Client ID and Client Secret. More details on setting up the code flow authentication can be found here. 29 | Make sure to also add the %s to the Authentication->Redirect URIs area', 'xcloner-backup-and-restore'), 'https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade', 'https://docs.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth?view=odsp-graph-online#code-flow', get_admin_url()) ?> 30 |

31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | " 40 | id="onedrive_client_id" type="text" name="xcloner_onedrive_client_id" class="validate" 41 | value="" autocomplete="off"> 42 |
43 |
44 | 45 |
46 |
47 | 49 |
50 |
51 | " 52 | id="onedrive_client_secret" type="text" name="xcloner_onedrive_client_secret" class="validate" 53 | value="" 54 | autocomplete="off"> 55 |
56 |
57 | 58 |
59 |
60 |   61 |
62 |
63 | 66 | 67 |
68 |
69 | 70 |
71 |
72 | 73 |
74 |
75 | " 76 | id="onedrive_path" type="text" name="xcloner_onedrive_path" class="validate" 77 | value=""> 78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 89 |
90 |
91 | 95 |
96 |
97 | 98 |
99 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/sftp.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 21 |
22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 | " 30 | id="sftp_host" type="text" name="xcloner_sftp_hostname" class="validate" 31 | value=""> 32 |
33 |
34 | " 35 | id="sftp_port" type="text" name="xcloner_sftp_port" class="validate" 36 | value=""> 37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 |
45 | " 46 | id="sftp_username" type="text" name="xcloner_sftp_username" class="validate" 47 | value="" autocomplete="off"> 48 |
49 |
50 | 51 | 52 |
53 |
54 | 55 |
56 |
57 | " 58 | id="ftp_spassword" type="text" name="xcloner_sftp_password" class="validate" 59 | value="" 60 | autocomplete="off"> 61 |
62 |
63 | 64 |
65 |
66 | 67 |
68 |
69 | 74 |
75 |
76 | 77 |
78 |
79 | 80 |
81 |
82 | " 83 | id="sftp_root" type="text" name="xcloner_sftp_path" class="validate" 84 | value=""> 85 |
86 |
87 | 88 |
89 |
90 | 91 |
92 |
93 | " 94 | id="sftp_timeout" type="text" name="xcloner_sftp_timeout" class="validate" 95 | value=""> 96 |
97 |
98 | 99 | 100 | 101 |
102 |
103 | 107 |
108 |
109 | 114 |
115 |
116 | 117 |
118 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/remote_storage/webdav.php: -------------------------------------------------------------------------------- 1 | 7 |
8 | computer 9 |
10 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |   26 |
27 |
28 |

29 | https://secure.backblaze.com/b2_buckets.htm')?> 30 |

31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | " 40 | id="webdav_url" type="text" name="xcloner_webdav_url" class="validate" 41 | value="" autocomplete="off"> 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 |
50 | " 51 | id="webdav_username" type="text" name="xcloner_webdav_username" class="validate" 52 | value="" autocomplete="off"> 53 |
54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 | " 62 | id="webdav_password" type="text" name="xcloner_webdav_password" 63 | class="validate" 64 | value="" 65 | autocomplete="off"> 66 |
67 |
68 | 69 |
70 |
71 | 72 |
73 |
74 | " 75 | id="webdav_target_folder" type="text" name="xcloner_webdav_target_folder" 76 | class="validate" 77 | value="" 78 | autocomplete="off"> 79 |
80 |
81 | 82 | 83 | 84 |
85 |
86 | 90 |
91 |
92 | 97 |
98 |
99 | 100 |
101 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/xcloner_console_page.php: -------------------------------------------------------------------------------- 1 | get_xcloner_container()->get_xcloner_settings(); 4 | $logger = $this->get_xcloner_container()->get_xcloner_logger(); 5 | $logger_content = $logger->getLastDebugLines(); 6 | ?> 7 |
8 |
9 |
10 | 11 |
12 | 13 | get_xcloner_option('xcloner_enable_log')) : ?> 14 | 29 | 35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/xcloner_header.php: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 |

7 | expand_more 8 |

9 | 10 | 11 | 62 | 63 | 68 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/admin/partials/xcloner_remote_storage_page.php: -------------------------------------------------------------------------------- 1 | get_xcloner_container()->get_xcloner_remote_storage(); 3 | ?> 4 | 5 | 14 | 15 |
16 |
17 | 20 |
21 |
22 | " 23 | id="xcloner_{type}cleanup_retention_limit_days" type="text" 24 | name="xcloner_{type}cleanup_retention_limit_days" class="validate" 25 | value=""> 26 |
27 |
28 | 29 | 30 |
31 |
32 | 34 |
35 |
36 | " 37 | id="xcloner_{type}cleanup_retention_limit_archives" type="number" 38 | name="xcloner_{type}cleanup_retention_limit_archives" class="validate" 39 | value=""> 40 |
41 |
42 | 43 | 44 |
45 |
46 | 49 |
50 |
51 | " 52 | id="xcloner_{type}cleanup_capacity_limit" type="number" name="xcloner_{type}cleanup_capacity_limit" 53 | class="validate" value=""> 54 |
55 |
56 | 57 | 58 |
59 |
60 | 63 |
64 |
65 | " 66 | id="xcloner_{type}cleanup_exclude_days" type="text" name="xcloner_{type}cleanup_exclude_days" 67 | class="validate" value=""> 68 |
69 |
70 | 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 | 184 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "watchfulli/xcloner-wordpress", 3 | "license": "GPL-2.0-or-later", 4 | "description": "WordPress backup plugin for XCloner", 5 | "require": { 6 | "as247/flysystem-onedrive": "^1.0", 7 | "gliterd/backblaze-b2": "^1.5", 8 | "league/flysystem": "^1.0", 9 | "league/flysystem-aws-s3-v3": "^1.0", 10 | "league/flysystem-azure-blob-storage": "^0.1.6", 11 | "league/flysystem-sftp": "^1.0", 12 | "league/flysystem-webdav": "^1.0", 13 | "mhetreramesh/flysystem-backblaze": "^1.6", 14 | "monolog/monolog": "^1.22", 15 | "nao-pon/flysystem-google-drive": "^1.1", 16 | "splitbrain/php-archive": "^1.0", 17 | "srmklive/flysystem-dropbox-v2": "^1.0", 18 | "vakata/jstree": "^3.3" 19 | }, 20 | "prefer-stable": true, 21 | "require-dev": { 22 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7", 23 | "phpcompatibility/phpcompatibility-wp": "*", 24 | "phpstan/extension-installer": "^1.1", 25 | "phpstan/phpstan": "^1.0", 26 | "phpunit/phpunit": "^7.0", 27 | "squizlabs/php_codesniffer": "3.*", 28 | "symfony/process": "^5.4", 29 | "szepeviktor/phpstan-wordpress": "^1.0", 30 | "yoast/phpunit-polyfills": "^1.0" 31 | }, 32 | "scripts": { 33 | "test": "vendor/bin/phpunit --config=phpunit-integration.xml", 34 | "pre-autoload-dump": "Watchfulli\\XClonerCore\\Xcloner_Composer_Actions::cleanup", 35 | "post-autoload-dump": "Watchfulli\\XClonerCore\\Xcloner_Composer_Actions::prevent_vendor_direct_access" 36 | }, 37 | "config": { 38 | "preferred-install": "dist", 39 | "sort-packages": true, 40 | "optimize-autoloader": true, 41 | "allow-plugins": { 42 | "bamarni/composer-bin-plugin": true, 43 | "dealerdirect/phpcodesniffer-composer-installer": true, 44 | "phpstan/extension-installer": true 45 | } 46 | }, 47 | "extra": { 48 | "custom-commands": { 49 | "commands": [ 50 | "ImaginaryMachines\\IsStableTagLatestTag" 51 | ] 52 | }, 53 | "google/apiclient-services": [ 54 | "Drive" 55 | ], 56 | "aws/aws-sdk-php": [ 57 | "S3" 58 | ] 59 | }, 60 | "autoload": { 61 | "psr-4": { 62 | "Watchfulli\\XClonerCore\\": "lib/" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/index.php: -------------------------------------------------------------------------------- 1 | '.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()).'

', __("XCloner Activation Error"), array('response' => 500, 32 | 'back_link' => true 33 | )); 34 | } 35 | 36 | $charset_collate = $wpdb->get_charset_collate(); 37 | 38 | $installed_ver = get_option("xcloner_db_version"); 39 | 40 | $xcloner_db_version = Xcloner_Activator::xcloner_db_version; 41 | 42 | $xcloner_scheduler_table = $wpdb->prefix."xcloner_scheduler"; 43 | 44 | if ($installed_ver != $xcloner_db_version) { 45 | $xcloner_schedule_sql = "CREATE TABLE `".$xcloner_scheduler_table."` ( 46 | `id` int(11) NOT NULL AUTO_INCREMENT, 47 | `name` varchar(255) NOT NULL, 48 | `recurrence` varchar(25) NOT NULL, 49 | `params` text NOT NULL, 50 | `start_at` datetime, 51 | `remote_storage` varchar(10) DEFAULT NULL, 52 | `hash` varchar(10) DEFAULT NULL, 53 | `status` int(1) NOT NULL, 54 | `last_backup` varchar(100) DEFAULT NULL, 55 | PRIMARY KEY (`id`) 56 | ) " . $charset_collate."; 57 | "; 58 | 59 | require_once(ABSPATH.'wp-admin/includes/upgrade.php'); 60 | dbDelta($xcloner_schedule_sql); 61 | 62 | update_option("xcloner_db_version", $xcloner_db_version); 63 | } 64 | 65 | if (get_option('xcloner_backup_compression_level') === false) { 66 | update_option('xcloner_backup_compression_level', 0); 67 | } 68 | 69 | if (get_option('xcloner_enable_log') === false) { 70 | update_option('xcloner_enable_log', 1); 71 | } 72 | 73 | if (get_option('xcloner_force_tmp_path_site_root') === false) { 74 | update_option('xcloner_force_tmp_path_site_root', 1); 75 | } 76 | 77 | if (get_option('xcloner_system_settings_page') === false) { 78 | update_option('xcloner_system_settings_page', 100); 79 | } 80 | 81 | if (get_option('xcloner_files_to_process_per_request') === false) { 82 | update_option('xcloner_files_to_process_per_request', 250); 83 | } 84 | 85 | if (get_option('xcloner_database_records_per_request') === false) { 86 | update_option('xcloner_database_records_per_request', 10000); 87 | } 88 | 89 | if (get_option('xcloner_exclude_files_larger_than_mb') === false) { 90 | update_option('xcloner_exclude_files_larger_than_mb', 0); 91 | } 92 | 93 | if (get_option('xcloner_split_backup_limit') === false) { 94 | update_option('xcloner_split_backup_limit', 2048); 95 | } 96 | 97 | if (get_option('xcloner_size_limit_per_request') === false) { 98 | update_option('xcloner_size_limit_per_request', 50); 99 | } 100 | 101 | if (get_option('xcloner_cleanup_retention_limit_days') === false) { 102 | update_option('xcloner_cleanup_retention_limit_days', 60); 103 | } 104 | 105 | if (get_option('xcloner_cleanup_retention_limit_archives') === false) { 106 | update_option('xcloner_cleanup_retention_limit_archives', 100); 107 | } 108 | 109 | if (get_option('xcloner_directories_to_scan_per_request') === false) { 110 | update_option('xcloner_directories_to_scan_per_request', 25); 111 | } 112 | 113 | if (!get_option('xcloner_regex_exclude')) { 114 | update_option('xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup|wp-content\/ai1wm-backups|wp-content\/plugins\/akeebabackupwp\/app\/backups)(.*)\.(.*)$(?set_archive_name($archive_name); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Composer_Actions.php: -------------------------------------------------------------------------------- 1 | isFile() && $file->getExtension() == 'php') { 28 | $contents = file_get_contents($file->getPathname()); 29 | 30 | $check_to_add = "if (!defined('ABSPATH') && PHP_SAPI !== 'cli') { die(); }"; 31 | 32 | if (strpos($contents, $check_to_add) !== false) { 33 | continue; 34 | } 35 | 36 | $contents = preg_replace('/namespace\s+([a-zA-Z0-9_\\\\]+);/m', "namespace $1;\n\n$check_to_add\n", $contents, 1); 37 | 38 | if ( 39 | strpos($contents, $check_to_add) === false 40 | ) 41 | { 42 | $contents = preg_replace('/namespace\s+([a-zA-Z0-9_\\\\]+)\s*{/', "namespace $1\n{\n$check_to_add", $contents, 1); 43 | } 44 | 45 | if ( 46 | strpos($contents, 'declare(strict_types=1);') !== false && 47 | strpos($contents, $check_to_add) === false 48 | ) { 49 | $contents = str_replace( 50 | "declare(strict_types=1);", 51 | "declare(strict_types=1);\n\n$check_to_add\n", 52 | $contents 53 | ); 54 | } 55 | 56 | if (strpos($contents, $check_to_add) === false) { 57 | $contents = "" . $contents; 58 | } 59 | 60 | file_put_contents($file->getPathname(), $contents); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Deactivator.php: -------------------------------------------------------------------------------- 1 | get_xcloner_filesystem()->cleanup_tmp_directories(); 17 | } catch (Exception $e) { 18 | $xcloner_plugin->trigger_message_notice($e->getMessage()); 19 | } 20 | 21 | $xcloner_scheduler = $xcloner_plugin->get_xcloner_scheduler(); 22 | $xcloner_scheduler->deactivate_wp_cron_hooks(); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_File_Transfer.php: -------------------------------------------------------------------------------- 1 | 13 | * 14 | * This program is free software; you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation; either version 2 of the License, or 17 | * (at your option) any later version. 18 | * 19 | * This program is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | * GNU General Public License for more details. 23 | * 24 | * You should have received a copy of the GNU General Public License 25 | * along with this program; if not, write to the Free Software 26 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 27 | * MA 02110-1301, USA. 28 | * 29 | * @link https://github.com/ovidiul/XCloner-Wordpress 30 | * 31 | * @modified 7/25/18 1:46 PM 32 | * 33 | */ 34 | class Xcloner_File_Transfer extends Xcloner_Filesystem 35 | { 36 | 37 | /** 38 | * Target url web address of the restore script 39 | * 40 | * @var string 41 | */ 42 | private $target_url; 43 | /** 44 | * Transfer data limit in bytes 45 | * 46 | * @var int 47 | */ 48 | private $transfer_limit = 1048576; // Bytes 1MB= 1048576 300KB = 358400. 49 | 50 | 51 | /** 52 | * Set target method 53 | * 54 | * @param $target_url 55 | * 56 | * @return mixed 57 | */ 58 | public function set_target($target_url) 59 | { 60 | return $this->target_url = $target_url; 61 | } 62 | 63 | /** 64 | * @param $file 65 | * @param int $start 66 | * @param string $hash 67 | * 68 | * @return bool|int 69 | * @throws Exception 70 | */ 71 | public function transfer_file($file, $start = 0, $hash = "") 72 | { 73 | if (!$this->target_url) { 74 | throw new Exception("Please setup a target url for upload"); 75 | } 76 | 77 | 78 | $fp = $this->get_storage_filesystem()->readStream($file); 79 | 80 | fseek($fp, $start); 81 | 82 | $binary_data = fread($fp, $this->transfer_limit); 83 | 84 | $tmp_filename = "xcloner_upload_" . substr(md5(time()), 0, 5); 85 | 86 | $this->get_tmp_filesystem()->write($tmp_filename, $binary_data); 87 | 88 | $tmp_file_path = $this->get_tmp_filesystem_adapter()->applyPathPrefix($tmp_filename); 89 | 90 | $send_array = array(); 91 | 92 | $send_array['file'] = $file; 93 | $send_array['start'] = $start; 94 | $send_array['xcloner_action'] = "write_file"; 95 | $send_array['hash'] = $hash; 96 | #$send_array['blob'] = $binary_data; 97 | $send_array['blob'] = $this->curl_file_create($tmp_file_path, 'application/x-binary', $tmp_filename); 98 | 99 | //$data = http_build_query($send_array); 100 | 101 | $this->get_logger()->info(sprintf( 102 | "Sending curl request to %s with %s data of file %s starting position %s using temporary file %s", 103 | $this->target_url, 104 | $this->transfer_limit, 105 | $file, 106 | $start, 107 | $tmp_filename 108 | )); 109 | 110 | 111 | $ch = curl_init(); 112 | curl_setopt($ch, CURLOPT_URL, $this->target_url); 113 | 114 | curl_setopt($ch, CURLOPT_POST, 1); 115 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 116 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); 117 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); 118 | curl_setopt($ch, CURLOPT_TIMEOUT, 1200); 119 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 120 | 121 | curl_setopt($ch, CURLOPT_POSTFIELDS, $send_array); 122 | curl_setopt($ch, CURLOPT_VERBOSE, true); 123 | 124 | $original_result = curl_exec($ch); 125 | 126 | 127 | $this->get_tmp_filesystem()->delete($tmp_filename); 128 | 129 | $result = json_decode($original_result); 130 | 131 | if (!$result) { 132 | throw new Exception("We have received no valid response from the remote host, original message: " . $original_result); 133 | } 134 | 135 | if ($result->status != 200) { 136 | throw new Exception($result->response); 137 | } 138 | 139 | if (ftell($fp) >= $this->get_storage_filesystem()->getSize($file)) { 140 | $this->get_logger()->info(sprintf( 141 | "Upload done for file %s to target url %s, transferred a total of %s bytes", 142 | $file, 143 | $this->target_url, 144 | ftell($fp) 145 | )); 146 | $this->remove_tmp_filesystem(); 147 | 148 | return false; 149 | } 150 | 151 | return ftell($fp); 152 | } 153 | 154 | /** 155 | * @param string $filename 156 | * @param string $mimetype 157 | * @param string $postname 158 | * 159 | * @return CURLFile|string 160 | */ 161 | private function curl_file_create($filename, $mimetype = '', $postname = '') 162 | { 163 | if (!function_exists('curl_file_create')) { 164 | return "@$filename;filename=" 165 | . ($postname ?: basename($filename)) 166 | . ($mimetype ? ";type=$mimetype" : ''); 167 | } else { 168 | return curl_file_create($filename, $mimetype, $postname); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Loader.php: -------------------------------------------------------------------------------- 1 | 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 24 | * MA 02110-1301, USA. 25 | * 26 | * @link https://github.com/ovidiul/XCloner-Wordpress 27 | * 28 | * @modified 7/25/18 1:46 PM 29 | * 30 | */ 31 | 32 | 33 | /** 34 | * Register all actions and filters for the plugin. 35 | * 36 | * Maintain a list of all hooks that are registered throughout 37 | * the plugin, and register them with the WordPress API. Call the 38 | * run function to execute the list of actions and filters. 39 | * 40 | * @package Xcloner 41 | * @subpackage Xcloner/includes 42 | * @author Liuta Ovidiu 43 | */ 44 | class Xcloner_Loader 45 | { 46 | 47 | /** 48 | * The array of actions registered with WordPress. 49 | * 50 | * @since 1.0.0 51 | * @access protected 52 | * @var array $actions The actions registered with WordPress to fire when the plugin loads. 53 | */ 54 | protected $actions; 55 | 56 | /** 57 | * The array of filters registered with WordPress. 58 | * 59 | * @since 1.0.0 60 | * @access protected 61 | * @var array $filters The filters registered with WordPress to fire when the plugin loads. 62 | */ 63 | protected $filters; 64 | 65 | /** 66 | * @var Xcloner 67 | */ 68 | private $xcloner_container; 69 | 70 | 71 | /** 72 | * Initialize the collections used to maintain the actions and filters. 73 | * 74 | * Xcloner_Loader constructor. 75 | * @param Xcloner $xcloner_container 76 | */ 77 | public function __construct(Xcloner $xcloner_container) 78 | { 79 | 80 | $this->actions = array(); 81 | $this->filters = array(); 82 | 83 | $this->xcloner_container = $xcloner_container; 84 | 85 | } 86 | 87 | /** 88 | * Add a new action to the collection to be registered with WordPress. 89 | * 90 | * @param string $hook The name of the WordPress action that is being registered. 91 | * @param array $callback The name of the function definition on the $component. 92 | * @param int $priority Optional. he priority at which the function should be fired. Default is 10. 93 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. 94 | * @since 1.0.0 95 | */ 96 | public function add_action($hook, $callback, $priority = 10, $accepted_args = 1) 97 | { 98 | $this->actions = $this->add($this->actions, $hook, $callback[0], $callback[1], $priority, $accepted_args); 99 | } 100 | 101 | /** 102 | * Add a new filter to the collection to be registered with WordPress. 103 | * 104 | * @param string $hook The name of the WordPress filter that is being registered. 105 | * @param object $component A reference to the instance of the object on which the filter is defined. 106 | * @param string $callback The name of the function definition on the $component. 107 | * @param int $priority Optional. he priority at which the function should be fired. Default is 10. 108 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1 109 | * @since 1.0.0 110 | */ 111 | public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1) 112 | { 113 | $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args); 114 | } 115 | 116 | /** 117 | * A utility function that is used to register the actions and hooks into a single 118 | * collection. 119 | * 120 | * @param array $hooks The collection of hooks that is being registered (that is, actions or filters). 121 | * @param string $hook The name of the WordPress filter that is being registered. 122 | * @param object $component A reference to the instance of the object on which the filter is defined. 123 | * @param string $callback The name of the function definition on the $component. 124 | * @param int $priority The priority at which the function should be fired. 125 | * @param int $accepted_args The number of arguments that should be passed to the $callback. 126 | * @return array The collection of actions and filters registered with WordPress. 127 | * @since 1.0.0 128 | * @access private 129 | */ 130 | private function add($hooks, $hook, $component, $callback, $priority, $accepted_args) 131 | { 132 | 133 | $hooks[] = array( 134 | 'hook' => $hook, 135 | 'component' => $component, 136 | 'callback' => $callback, 137 | 'priority' => $priority, 138 | 'accepted_args' => $accepted_args 139 | ); 140 | 141 | return $hooks; 142 | 143 | } 144 | 145 | /** 146 | * Register the filters and actions with WordPress. 147 | * 148 | * @since 1.0.0 149 | */ 150 | public function run() 151 | { 152 | foreach ($this->filters as $hook) { 153 | add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']); 154 | } 155 | 156 | foreach ($this->actions as $hook) { 157 | add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']); 158 | } 159 | 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Logger.php: -------------------------------------------------------------------------------- 1 | get_xcloner_settings()) { 25 | $xcloner_settings = new Xcloner_Settings($xcloner_container); 26 | } else { 27 | $xcloner_settings = $xcloner_container->get_xcloner_settings(); 28 | } 29 | 30 | $hash = $xcloner_settings->get_hash(); 31 | if ($hash == "-" . $xcloner_settings->get_server_unique_hash(5)) { 32 | $hash = ""; 33 | } 34 | 35 | $logger_path = $xcloner_settings->get_xcloner_store_path() . DS . $xcloner_settings->get_logger_filename(); 36 | $logger_path_tmp = ""; 37 | 38 | if ($hash) { 39 | $logger_path_tmp = $xcloner_settings->get_xcloner_tmp_path() . DS . $xcloner_settings->get_logger_filename(1); 40 | } 41 | 42 | $this->logger_path = $logger_path; 43 | 44 | if (!is_dir($xcloner_settings->get_xcloner_store_path()) or !is_writable($xcloner_settings->get_xcloner_store_path())) { 45 | $logger_path = 'php://stderr'; 46 | $logger_path_tmp = ""; 47 | } 48 | 49 | if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) { 50 | $logger_path = 'php://stderr'; 51 | $logger_path_tmp = ""; 52 | } 53 | 54 | // create a log channel 55 | parent::__construct($logger_name); 56 | 57 | $debug_level = Logger::INFO; 58 | 59 | if (defined('WP_DEBUG') && WP_DEBUG) { 60 | $debug_level = Logger::DEBUG; 61 | } 62 | 63 | if ($logger_path) { 64 | if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) { 65 | $stream = new StreamHandler($logger_path, $debug_level); 66 | } else { 67 | $stream = new RotatingFileHandler($logger_path, $this->max_logger_files, $debug_level); 68 | } 69 | 70 | $this->pushHandler($stream); 71 | 72 | $this->main_logger_url = $stream->getUrl(); 73 | } 74 | 75 | if ($hash and $logger_path_tmp) { 76 | $this->pushHandler(new StreamHandler($logger_path_tmp, $debug_level)); 77 | } 78 | 79 | //return $this; 80 | } 81 | 82 | /** 83 | * @return string|null 84 | */ 85 | public function get_main_logger_url() 86 | { 87 | return $this->main_logger_url; 88 | } 89 | 90 | /** 91 | * @param int $totalLines 92 | * @return array|bool 93 | */ 94 | public function getLastDebugLines($totalLines = 200) 95 | { 96 | $lines = array(); 97 | 98 | if (!file_exists($this->main_logger_url) or !is_readable($this->main_logger_url)) { 99 | return false; 100 | } 101 | 102 | $fp = fopen($this->main_logger_url, 'r'); 103 | fseek($fp, -1, SEEK_END); 104 | $pos = ftell($fp); 105 | $lastLine = ""; 106 | 107 | // Loop backword until we have our lines or we reach the start 108 | while ($pos > 0 && count($lines) < $totalLines) { 109 | $C = fgetc($fp); 110 | if ($C == "\n") { 111 | // skip empty lines 112 | if (trim($lastLine) != "") { 113 | $lines[] = $lastLine; 114 | } 115 | $lastLine = ''; 116 | } else { 117 | $lastLine = $C . $lastLine; 118 | } 119 | fseek($fp, $pos--); 120 | } 121 | 122 | $lines = array_reverse($lines); 123 | 124 | return $lines; 125 | } 126 | 127 | /** 128 | * Info message logging 129 | * 130 | * @param [type] $msg 131 | * @param boolean $print 132 | * @return void 133 | */ 134 | public function print_info($message, $context = array()) 135 | { 136 | if (php_sapi_name() == "cli" && !WP_DEBUG && !defined('XCLONER_DISABLE_OUTPUT')) { 137 | echo sprintf("[%s] %s \n", date("Y-m-d H:i:s"), $message); 138 | } 139 | return parent::info($message, $context); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Requirements.php: -------------------------------------------------------------------------------- 1 | xcloner_container = $xcloner_container; 14 | $this->xcloner_settings = $xcloner_container->get_xcloner_settings(); 15 | } 16 | 17 | public function check_backup_ready_status() 18 | { 19 | if (!$this->check_min_php_version(1)) { 20 | return false; 21 | } 22 | 23 | if (!$this->check_xcloner_start_path(1)) { 24 | return false; 25 | } 26 | 27 | if (!$this->check_xcloner_store_path(1)) { 28 | return false; 29 | } 30 | 31 | if (!$this->check_xcloner_tmp_path(1)) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | public function check_min_php_version($return_bool = 0) 39 | { 40 | 41 | if ($return_bool == 1) { 42 | if (version_compare(phpversion(), self::MIN_PHP_VERSION, '<')) { 43 | return false; 44 | } else { 45 | return true; 46 | } 47 | } 48 | 49 | return phpversion(); 50 | } 51 | 52 | public function check_xcloner_start_path($return_bool = 0) 53 | { 54 | $path = $this->xcloner_settings->get_xcloner_start_path(); 55 | 56 | if ($return_bool) { 57 | if (!file_exists($path)) { 58 | return false; 59 | } 60 | 61 | return is_readable($path); 62 | } 63 | 64 | return $path; 65 | } 66 | 67 | public function check_xcloner_tmp_path($return_bool = 0) 68 | { 69 | $path = $this->xcloner_settings->get_xcloner_tmp_path(); 70 | 71 | if ($return_bool) { 72 | if (!file_exists($path)) { 73 | return false; 74 | } 75 | 76 | if (!is_writeable($path)) { 77 | @chmod($path, 0777); 78 | } 79 | 80 | return is_writeable($path); 81 | } 82 | 83 | return $path; 84 | } 85 | 86 | public function check_xcloner_store_path($return_bool = 0) 87 | { 88 | $path = $this->xcloner_settings->get_xcloner_store_path(); 89 | 90 | if ($return_bool) { 91 | if (!file_exists($path)) { 92 | return false; 93 | } 94 | 95 | if (!is_writeable($path)) { 96 | @chmod($path, 0777); 97 | } 98 | 99 | return is_writeable($path); 100 | } 101 | 102 | return $path; 103 | } 104 | 105 | public function get_max_execution_time() 106 | { 107 | return ini_get('max_execution_time'); 108 | } 109 | 110 | public function get_memory_limit() 111 | { 112 | return ini_get('memory_limit'); 113 | } 114 | 115 | public function get_open_basedir() 116 | { 117 | $open_basedir = ini_get('open_basedir'); 118 | 119 | if (!$open_basedir) { 120 | $open_basedir = "none"; 121 | } 122 | 123 | return $open_basedir; 124 | } 125 | 126 | public function get_free_disk_space() 127 | { 128 | return $this->file_format_size(disk_free_space($this->xcloner_settings->get_xcloner_store_path())); 129 | } 130 | 131 | public function file_format_size($bytes, $decimals = 2) 132 | { 133 | $unit_list = array('B', 'KB', 'MB', 'GB', 'PB'); 134 | 135 | if ($bytes == 0) { 136 | return $bytes . ' ' . $unit_list[0]; 137 | } 138 | 139 | $unit_count = count($unit_list); 140 | for ($i = $unit_count - 1; $i >= 0; $i--) { 141 | $power = $i * 10; 142 | if (($bytes >> $power) >= 1) { 143 | return round($bytes / (1 << $power), $decimals) . ' ' . $unit_list[$i]; 144 | } 145 | } 146 | 147 | return $bytes . ' ' . $unit_list[0]; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/lib/Xcloner_Sanitization.php: -------------------------------------------------------------------------------- 1 | 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 24 | * MA 02110-1301, USA. 25 | * 26 | * @link https://github.com/ovidiul/XCloner-Wordpress 27 | * 28 | * @modified 7/25/18 1:46 PM 29 | * 30 | */ 31 | 32 | 33 | /** 34 | * Define the internationalization functionality. 35 | * 36 | * Loads and defines the internationalization files for this plugin 37 | * so that it is ready for translation. 38 | * 39 | * @since 1.0.0 40 | * @package Xcloner 41 | * @subpackage Xcloner/includes 42 | * @author Liuta Ovidiu 43 | */ 44 | class Xcloner_i18n 45 | { 46 | 47 | /** 48 | * Load the plugin text domain for translation. 49 | * 50 | * @since 1.0.0 51 | */ 52 | public function load_plugin_textdomain() 53 | { 54 | 55 | load_plugin_textdomain( 56 | 'xcloner-backup-and-restore', 57 | false, 58 | dirname(dirname(plugin_basename(__FILE__))) . '/languages/' 59 | ); 60 | 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /xcloner-backup-and-restore/uninstall.php: -------------------------------------------------------------------------------- 1 | should_run()) { 43 | try { 44 | $xcloner_cli->run(); 45 | } catch (Exception $e) { 46 | echo $e->getMessage() . "\n"; 47 | } 48 | return; 49 | } 50 | 51 | // If this file is called directly, and we're not in CLI mode, then exit. 52 | if (!defined('WPINC')) { 53 | die; 54 | } 55 | 56 | 57 | if (function_exists('register_activation_hook')) { 58 | register_activation_hook(__FILE__, [new Xcloner_Activator(), 'activate']); 59 | } 60 | 61 | if (function_exists('register_deactivation_hook')) { 62 | register_deactivation_hook(__FILE__, [new Xcloner_Deactivator(), 'deactivate']); 63 | } 64 | 65 | if (version_compare(phpversion(), Xcloner_Activator::xcloner_minimum_version, '<')) { 66 | ?> 67 |
68 |

69 |
70 | check_dependencies(); 131 | 132 | $xcloner->init(); 133 | $xcloner->run(); 134 | } 135 | 136 | try { 137 | run_xcloner(); 138 | } catch (Exception $e) { 139 | echo $e->getMessage(); 140 | } 141 | --------------------------------------------------------------------------------