Initial commit: WordPress wp-content (themes, plugins, languages)

- Theme: momentry (custom theme with REST API routes)
- Plugins: code-snippets (contains all API proxies)
- Languages: zh_TW translations
- Excludes: cache, backups, uploads, logs
This commit is contained in:
OpenCode
2026-05-29 19:07:56 +08:00
commit 09ef1f000f
6521 changed files with 867163 additions and 0 deletions

View File

@@ -0,0 +1,432 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
abstract class Ai1wm_Archiver {
const HEADER_SIZE = 4377;
const READ_CHUNK_SIZE = 512000;
/**
* File name including path to the file
*
* @type string
*/
protected $file_name = null;
/**
* File password string
*
* @type string
*/
protected $file_password = null;
/**
* File compression type
*
* @type string
*/
protected $file_compression = null;
/**
* Handle to the file
*
* @type resource
*/
protected $file_handle = null;
/**
* Header block format of a file
*
* Field Name Offset Length Contents
* name 0 255 filename (no path, no slash)
* size 255 14 size of file contents
* mtime 269 12 last modification time
* prefix 281 4088 path name, no trailing slashes
* crc32 4369 8 CRC32 checksum (hex string, optional)
*
* @type array
*/
protected $block_format = array(
'a255', // filename
'a14', // size of file contents
'a12', // last time modified
'a4088', // path
'a8', // crc32
);
/**
* Archive CRC value from the v2 EOF block
*
* @type string
*/
protected $archive_crc_value = null;
/**
* Archive CRC size from the v2 EOF block
*
* @type string
*/
protected $archive_crc_size = null;
/**
* Default constructor
*
* Initializes filename and end of file block
*
* @param string $file_name File to use as archive
* @param string $file_password File password string
* @param string $file_compression File compression type
* @param bool $file_write File Read/write mode
*
* @throws Ai1wm_Not_Accessible_Exception
* @throws Ai1wm_Not_Seekable_Exception
*/
public function __construct( $file_name, $file_password = null, $file_compression = null, $file_write = false ) {
$this->file_name = $file_name;
$this->file_password = $file_password;
$this->file_compression = $file_compression;
// Open archive file
if ( $file_write ) {
// Open archive file for writing
if ( ( $this->file_handle = @fopen( $file_name, 'cb' ) ) === false ) {
throw new Ai1wm_Not_Accessible_Exception( sprintf( __( 'Could not open file for writing. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Seek to end of archive file
if ( @fseek( $this->file_handle, 0, SEEK_END ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to end of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
} else {
// Open archive file for reading
if ( ( $this->file_handle = @fopen( $file_name, 'rb' ) ) === false ) {
throw new Ai1wm_Not_Accessible_Exception( sprintf( __( 'Could not open file for reading. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
}
/**
* Set current file pointer
*
* @param int $offset Archive offset
*
* @throws \Ai1wm_Not_Seekable_Exception
*
* @return void
*/
public function set_file_pointer( $offset ) {
if ( @fseek( $this->file_handle, $offset, SEEK_SET ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $offset ) );
}
}
/**
* Get current file pointer
*
* @throws \Ai1wm_Not_Tellable_Exception
*
* @return int
*/
public function get_file_pointer() {
if ( ( $offset = @ftell( $this->file_handle ) ) === false ) {
throw new Ai1wm_Not_Tellable_Exception( sprintf( __( 'Could not tell offset of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
return $offset;
}
/**
* Appends end of file block to the archive file
*
* @param string|null $archive_crc_value Pre-calculated archive CRC32 (optional)
*
* @throws \Ai1wm_Not_Seekable_Exception
* @throws \Ai1wm_Not_Writable_Exception
* @throws \Ai1wm_Quota_Exceeded_Exception
*
* @return void
*/
protected function append_eof( $archive_crc_value = null ) {
// Seek to end of archive file
if ( @fseek( $this->file_handle, 0, SEEK_END ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to end of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Use pre-calculated CRC if provided, otherwise calculate (fallback)
if ( empty( $archive_crc_value ) ) {
$archive_crc_value = Ai1wm_Crc::calculate_file_crc32( $this->file_name );
}
// Get archive size (before EOF block)
if ( ( $archive_crc_size = @ftell( $this->file_handle ) ) === false ) {
throw new Ai1wm_Not_Tellable_Exception( sprintf( __( 'Could not tell offset of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Write end of file block
if ( ( $eof_block = $this->get_eof_block( $archive_crc_size, $archive_crc_value ) ) ) {
if ( ( $file_bytes = @fwrite( $this->file_handle, $eof_block ) ) !== false ) {
if ( strlen( $eof_block ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write end of block to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write end of block to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
}
/**
* Replace forward slash with current directory separator
*
* @param string $path Path
*
* @return string
*/
protected function replace_forward_slash_with_directory_separator( $path ) {
return str_replace( '/', DIRECTORY_SEPARATOR, $path );
}
/**
* Replace current directory separator with forward slash
*
* @param string $path Path
*
* @return string
*/
protected function replace_directory_separator_with_forward_slash( $path ) {
return str_replace( DIRECTORY_SEPARATOR, '/', $path );
}
/**
* Escape Windows directory separator
*
* @param string $path Path
*
* @return string
*/
protected function escape_windows_directory_separator( $path ) {
return preg_replace( '/[\\\\]+/', '\\\\\\\\', $path );
}
/**
* Validate archive file
*
* @return bool
*/
public function is_valid() {
// Failed detecting the current file pointer offset
if ( ( $offset = @ftell( $this->file_handle ) ) === false ) {
return false;
}
// Failed seeking the beginning of EOL block
if ( @fseek( $this->file_handle, -static::HEADER_SIZE, SEEK_END ) === -1 ) {
return false;
}
// Get end of file block
if ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) === false ) {
return false;
}
// Failed returning to original offset
if ( @fseek( $this->file_handle, $offset, SEEK_SET ) === -1 ) {
return false;
}
// Trailing block does not match EOL
if ( $this->is_eof_block( $block ) === false ) {
return false;
}
return true;
}
/**
* Truncates the archive file
*
* @return void
*/
public function truncate() {
if ( ( $offset = @ftell( $this->file_handle ) ) === false ) {
throw new Ai1wm_Not_Tellable_Exception( sprintf( __( 'Could not tell offset of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
if ( @filesize( $this->file_name ) > $offset ) {
if ( @ftruncate( $this->file_handle, $offset ) === false ) {
throw new Ai1wm_Not_Truncatable_Exception( sprintf( __( 'Could not truncate file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
}
/**
* Closes the archive file
*
* We either close the file or append the end of file block if complete argument is set to true
*
* @param bool $complete Flag to append end of file block
* @param string|null $archive_crc_value Pre-calculated archive CRC32 (optional)
*
* @return void
*/
public function close( $complete = false, $archive_crc_value = null ) {
// Are we done appending to the file?
if ( true === $complete ) {
$this->append_eof( $archive_crc_value );
}
if ( @fclose( $this->file_handle ) === false ) {
throw new Ai1wm_Not_Closable_Exception( sprintf( __( 'Could not close file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
/**
* Generate end of file block
*
* @param string $archive_crc_value Archive CRC
*
* @return string
*/
protected function get_eof_block( $archive_crc_size = null, $archive_crc_value = null ) {
return pack( 'a255a14a4100a8', '', $archive_crc_size, '', $archive_crc_value );
}
/**
* Check if a block is an end of file block (v1 or v2)
*
* @param string $block The block to check
*
* @return bool
*/
protected function is_eof_block( $block ) {
return $this->is_v1_eof( $block ) || $this->is_v2_eof( $block );
}
/**
* Check if a block is a v1 end of file block (all null bytes)
*
* @param string $block The block to check
*
* @return bool
*/
protected function is_v1_eof( $block ) {
return $this->get_eof_block() === $block;
}
/**
* Check if a block is a v2 end of file block
*
* @param string $block The block to check
*
* @return bool
*/
protected function is_v2_eof( $block ) {
// Unpack end of file data
if ( ( $data = unpack( 'a255/a14size/a4100/a8crc32', $block ) ) ) {
if ( isset( $data['size'], $data['crc32'] ) ) {
if ( preg_match( '/^[0-9a-f]{8}$/i', $data['crc32'] ) ) {
return $this->get_eof_block( $data['size'], $data['crc32'] ) === $block;
}
}
}
return false;
}
/**
* Get archive CRC from EOF block (v2 only)
*
* @return string|null CRC32 hex string or null if v1 archive
*/
public function get_archive_crc_value() {
if ( is_null( $this->archive_crc_value ) ) {
$this->set_archive_crc_data();
}
return $this->archive_crc_value;
}
/**
* Get archive CRC size from EOF block (v2 only)
*
* @return int|null Size hex string or null if v1 archive
*/
public function get_archive_crc_size() {
if ( is_null( $this->archive_crc_size ) ) {
$this->set_archive_crc_data();
}
return $this->archive_crc_size;
}
/**
* Set archive CRC value and size from the v2 EOF block
*
* @return void
*/
protected function set_archive_crc_data() {
// Failed detecting the current file pointer offset
if ( ( $offset = @ftell( $this->file_handle ) ) === false ) {
return;
}
// Failed seeking the beginning of EOL block
if ( @fseek( $this->file_handle, -static::HEADER_SIZE, SEEK_END ) === -1 ) {
return;
}
// Get end of file block
if ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) === false ) {
return;
}
// Failed returning to original offset
if ( @fseek( $this->file_handle, $offset, SEEK_SET ) === -1 ) {
return;
}
// Check if v2 EOF
if ( $this->is_v2_eof( $block ) === false ) {
return;
}
// Unpack end of file data
if ( ( $data = unpack( 'a255/a14size/a4100/a8crc32', $block ) ) ) {
if ( isset( $data['crc32'] ) ) {
$this->archive_crc_value = trim( $data['crc32'] );
}
if ( isset( $data['size'] ) ) {
$this->archive_crc_size = (int) trim( $data['size'] );
}
}
}
}

View File

@@ -0,0 +1,306 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Compressor extends Ai1wm_Archiver {
/**
* Overloaded constructor that opens the passed file for writing
*
* @param string $file_name File to use as archive
* @param string $file_password File password string
* @param string $file_compression File compression type
*/
public function __construct( $file_name, $file_password = null, $file_compression = null ) {
// Call parent, to initialize variables
parent::__construct( $file_name, $file_password, $file_compression, true );
}
/**
* Add a file to the archive
*
* @param string $file_name File to add to the archive
* @param string $new_file_name Write the file with a different name
* @param int $file_bytes_read Amount of the bytes we read
* @param int $file_bytes_offset File bytes offset
* @param int $file_bytes_written Amount of the bytes we wrote
* @param string|null $file_crc File CRC32 checksum (passed by reference, optional)
*
* @throws \Ai1wm_Not_Seekable_Exception
* @throws \Ai1wm_Not_Writable_Exception
* @throws \Ai1wm_Quota_Exceeded_Exception
*
* @return bool
*/
public function add_file( $file_name, $new_file_name = '', &$file_bytes_read = 0, &$file_bytes_offset = 0, &$file_bytes_written = 0, &$file_crc = null ) {
// Replace forward slash with current directory separator in file name
$file_name = ai1wm_replace_forward_slash_with_directory_separator( $file_name );
// Escape Windows directory separator in file name
$file_name = ai1wm_escape_windows_directory_separator( $file_name );
// Flag to hold if file data has been processed
$completed = true;
// Start time
$start = microtime( true );
// Open the file for reading in binary mode (fopen may return null for quarantined files)
if ( ( $file_handle = @fopen( $file_name, 'rb' ) ) ) {
// Start native hash for current chunk
$hash_ctx = Ai1wm_Crc::init_crc32();
// Get header block with empty CRC placeholder
if ( ( $block = $this->get_file_block( $file_name, $new_file_name, '' ) ) ) {
// Write header block
if ( $file_bytes_offset === 0 ) {
if ( ( $file_bytes = @fwrite( $this->file_handle, $block ) ) !== false ) {
if ( strlen( $block ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write header to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write header to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
// Set file offset
if ( @fseek( $file_handle, $file_bytes_offset, SEEK_SET ) !== -1 ) {
$file_bytes_read = 0;
// Cache config file check outside the loop
$should_process_file = ! in_array( $new_file_name, ai1wm_config_filters() );
// Read the file in 512KB chunks
while ( false === @feof( $file_handle ) ) {
if ( ( $file_content = @fread( $file_handle, static::READ_CHUNK_SIZE ) ) !== false ) {
// Empty read indicates EOF
if ( strlen( $file_content ) === 0 ) {
break;
}
// Add the amount of bytes we read
$file_bytes_read += strlen( $file_content );
// Update CRC with original content (BEFORE compression/encryption)
Ai1wm_Crc::update_crc32( $hash_ctx, $file_content );
// Do not encrypt or compress config files
if ( $should_process_file === true ) {
// Add chunk data compression
if ( ! empty( $this->file_compression ) ) {
switch ( $this->file_compression ) {
case 'gzip':
$file_content = gzcompress( $file_content, 9 );
break;
case 'bzip2':
$file_content = bzcompress( $file_content, 9 );
break;
}
}
// Add chunk data encryption
if ( ! empty( $this->file_password ) ) {
$file_content = ai1wm_encrypt_string( $file_content, $this->file_password );
}
// Add variable length chunk size before chunk data
if ( ! empty( $this->file_compression ) ) {
$file_content = pack( 'N', strlen( $file_content ) ) . $file_content;
}
}
if ( ( $file_bytes = @fwrite( $this->file_handle, $file_content ) ) !== false ) {
if ( strlen( $file_content ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write content to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write content to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Add the amount of bytes we wrote
$file_bytes_written += $file_bytes;
}
// Time elapsed
if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break;
}
}
}
// Add the amount of bytes we read
$file_bytes_offset += $file_bytes_read;
}
// Combine and finalize CRC
if ( empty( $file_crc ) ) {
$file_crc = Ai1wm_Crc::finalize_crc32( $hash_ctx );
} else {
$file_crc = Ai1wm_Crc::combine_crc32( $file_crc, Ai1wm_Crc::finalize_crc32( $hash_ctx ), $file_bytes_read );
}
// Write file size to file header
if ( ( $file_size_block = $this->get_file_size_block( $file_bytes_written ) ) ) {
// Seek to beginning of file size (back over: content + crc32(8) + path(4088) + mtime(12) + size(14))
if ( @fseek( $this->file_handle, - $file_bytes_written - 8 - 4088 - 12 - 14, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( __( 'Your PHP is 32-bit. In order to export your file, please change your PHP version to 64-bit and try again. <a href="https://help.servmask.com/knowledgebase/php-32bit/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ) );
}
// Write file size to file header
if ( ( $file_bytes = @fwrite( $this->file_handle, $file_size_block ) ) !== false ) {
if ( strlen( $file_size_block ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write size to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write size to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Seek to beginning of file CRC (forward over: mtime(12) + path(4088))
if ( @fseek( $this->file_handle, + 12 + 4088, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( __( 'Your PHP is 32-bit. In order to export your file, please change your PHP version to 64-bit and try again. <a href="https://help.servmask.com/knowledgebase/php-32bit/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ) );
}
// Write file CRC to file header
if ( ( $file_crc_block = $this->get_file_crc_block( $file_crc ) ) ) {
if ( ( $file_bytes = @fwrite( $this->file_handle, $file_crc_block ) ) !== false ) {
if ( strlen( $file_crc_block ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write CRC to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
}
}
// Seek to end of file content (forward over: content)
if ( @fseek( $this->file_handle, + $file_bytes_written, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( __( 'Your PHP is 32-bit. In order to export your file, please change your PHP version to 64-bit and try again. <a href="https://help.servmask.com/knowledgebase/php-32bit/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ) );
}
}
}
// Close the handle
@fclose( $file_handle );
}
return $completed;
}
/**
* Generate binary block header for a file
*
* @param string $file_name Filename to generate block header for
* @param string $new_file_name Write the file with a different name
* @param string|null $crc32 CRC32 checksum (optional)
*
* @return string
*/
private function get_file_block( $file_name, $new_file_name = '', $crc32 = null ) {
$block = '';
// Get stats about the file
if ( ( $stat = @stat( $file_name ) ) !== false ) {
// Filename of the file we are accessing
if ( empty( $new_file_name ) ) {
$name = ai1wm_basename( $file_name );
} else {
$name = ai1wm_basename( $new_file_name );
}
// Size in bytes of the file
$size = $stat['size'];
// Last time the file was modified
$date = $stat['mtime'];
// Replace current directory separator with backward slash in file path
if ( empty( $new_file_name ) ) {
$path = ai1wm_replace_directory_separator_with_forward_slash( ai1wm_dirname( $file_name ) );
} else {
$path = ai1wm_replace_directory_separator_with_forward_slash( ai1wm_dirname( $new_file_name ) );
}
// Only calculate CRC if not provided
if ( empty( $crc32 ) ) {
$crc32 = Ai1wm_Crc::calculate_file_crc32( $file_name );
}
// Concatenate block format parts
$format = implode( '', $this->block_format );
// Pack file data into binary string
$block = pack( $format, $name, $size, $date, $path, $crc32 );
}
return $block;
}
/**
* Generate file size binary block header for a file
*
* @param int $file_size File size
*
* @return string
*/
public function get_file_size_block( $file_size ) {
$block = '';
// Pack file data into binary string
if ( isset( $this->block_format[1] ) ) {
$block = pack( $this->block_format[1], $file_size );
}
return $block;
}
/**
* Generate file CRC binary block header for a file
*
* @param int $file_crc File CRC
*
* @return string
*/
public function get_file_crc_block( $file_crc ) {
$block = '';
// Pack file data into binary string
if ( isset( $this->block_format[4] ) ) {
$block = pack( $this->block_format[4], $file_crc );
}
return $block;
}
}

View File

@@ -0,0 +1,717 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Extractor extends Ai1wm_Archiver {
/**
* Total files count
*
* @type int
*/
protected $total_files_count = null;
/**
* Total files size
*
* @type int
*/
protected $total_files_size = null;
/**
* Overloaded constructor that opens the passed file for reading
*
* @param string $file_name File to use as archive
* @param string $file_password File password string
* @param string $file_compression File compression type
*/
public function __construct( $file_name, $file_password = null, $file_compression = null ) {
// Call parent, to initialize variables
parent::__construct( $file_name, $file_password, $file_compression, false );
}
/**
* List all files in the archive
*
* @return array
*/
public function list_files() {
$files = array();
// Seek to beginning of archive file
if ( @fseek( $this->file_handle, 0, SEEK_SET ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to beginning of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
$offset = 0;
// Loop over files
while ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) ) {
// End block has been reached
if ( $this->is_eof_block( $block ) ) {
continue;
}
// Get file data from the block
if ( ( $data = $this->get_data_from_block( $block ) ) ) {
// Store the position where the file begins - used for downloading from archive directly
$data['offset'] = $offset;
// Skip file content, so we can move forward to the next file
if ( @fseek( $this->file_handle, $data['size'], SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $data['size'] ) );
}
$files[] = $data;
}
$offset = @ftell( $this->file_handle );
}
return $files;
}
/**
* Get the total files count in an archive
*
* @return int
*/
public function get_total_files_count() {
if ( is_null( $this->total_files_count ) ) {
$this->set_files_totals();
}
return $this->total_files_count;
}
/**
* Get the total files size in an archive
*
* @return int
*/
public function get_total_files_size() {
if ( is_null( $this->total_files_size ) ) {
$this->set_files_totals();
}
return $this->total_files_size;
}
/**
* Set the total files count and size in the archive
*
* @return void
*/
protected function set_files_totals() {
// Total files count
$this->total_files_count = 0;
// Total files size
$this->total_files_size = 0;
// Seek to beginning of archive file
if ( @fseek( $this->file_handle, 0, SEEK_SET ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to beginning of file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Loop over files
while ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) ) {
// End block has been reached
if ( $this->is_eof_block( $block ) ) {
continue;
}
// Get file data from the block
if ( ( $data = $this->get_data_from_block( $block ) ) ) {
// We have a file, increment the count
$this->total_files_count += 1;
// We have a file, increment the size
$this->total_files_size += $data['size'];
// Skip file content so we can move forward to the next file
if ( @fseek( $this->file_handle, $data['size'], SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $data['size'] ) );
}
}
}
}
/**
* Extract one file to location
*
* @param string $location Destination path
* @param array $exclude_files Exclude files by name
* @param array $exclude_extensions Exclude files by extension
* @param array $old_paths Old replace paths
* @param array $new_paths New replace paths
* @param int $file_bytes_read Amount of the bytes we read
* @param int $file_bytes_offset File bytes offset
* @param int $file_bytes_written Amount of the bytes we wrote
*
* @throws \Ai1wm_Not_Directory_Exception
* @throws \Ai1wm_Not_Seekable_Exception
*
* @return bool
*/
public function extract_one_file_to( $location, $exclude_files = array(), $exclude_extensions = array(), $old_paths = array(), $new_paths = array(), &$file_bytes_read = 0, &$file_bytes_offset = 0, &$file_bytes_written = 0 ) {
if ( false === is_dir( $location ) ) {
throw new Ai1wm_Not_Directory_Exception( sprintf( __( 'Location is not a directory: %s', 'all-in-one-wp-migration' ), $location ) );
}
// Replace forward slash with current directory separator in location
$location = ai1wm_replace_forward_slash_with_directory_separator( $location );
// Flag to hold if file data has been processed
$completed = true;
// Seek to file offset to archive file
if ( $file_bytes_offset > 0 ) {
if ( @fseek( $this->file_handle, - $file_bytes_offset - static::HEADER_SIZE, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, - $file_bytes_offset - static::HEADER_SIZE ) );
}
}
// Read file header block
if ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) ) {
// We reached end of file, set the pointer to the end of the file so that feof returns true
if ( $this->is_eof_block( $block ) ) {
// Seek to end of archive file minus 1 byte
@fseek( $this->file_handle, 1, SEEK_END );
// Read 1 character
@fgetc( $this->file_handle );
} else {
// Get file header data from the block
if ( ( $data = $this->get_data_from_block( $block ) ) ) {
// Set file name
$file_name = $data['filename'];
// Set file size
$file_size = $data['size'];
// Set file mtime
$file_mtime = $data['mtime'];
// Set file path
$file_path = $data['path'];
// Set file crc
$file_crc32 = $data['crc32'];
// Should we skip this file by name?
$should_exclude_file = false;
for ( $i = 0; $i < count( $exclude_files ); $i++ ) {
if ( strpos( $file_name . DIRECTORY_SEPARATOR, ai1wm_replace_forward_slash_with_directory_separator( $exclude_files[ $i ] ) . DIRECTORY_SEPARATOR ) === 0 ) {
$should_exclude_file = true;
break;
}
}
// Should we skip this file by extension?
for ( $i = 0; $i < count( $exclude_extensions ); $i++ ) {
if ( strrpos( $file_name, $exclude_extensions[ $i ] ) === strlen( $file_name ) - strlen( $exclude_extensions[ $i ] ) ) {
$should_exclude_file = true;
break;
}
}
// Validate file name and file path for directory traversal
if ( path_is_absolute( $file_name ) || validate_file( $file_name ) !== 0 ) {
$should_exclude_file = true;
}
// Do we have a match?
if ( $should_exclude_file === false ) {
// Replace extract paths
for ( $i = 0; $i < count( $old_paths ); $i++ ) {
if ( strpos( $file_path . DIRECTORY_SEPARATOR, ai1wm_replace_forward_slash_with_directory_separator( $old_paths[ $i ] ) . DIRECTORY_SEPARATOR ) === 0 ) {
$file_name = substr_replace( $file_name, ai1wm_replace_forward_slash_with_directory_separator( $new_paths[ $i ] ), 0, strlen( ai1wm_replace_forward_slash_with_directory_separator( $old_paths[ $i ] ) ) );
$file_path = substr_replace( $file_path, ai1wm_replace_forward_slash_with_directory_separator( $new_paths[ $i ] ), 0, strlen( ai1wm_replace_forward_slash_with_directory_separator( $old_paths[ $i ] ) ) );
break;
}
}
// Escape Windows directory separator in file path
if ( path_is_absolute( $file_path ) ) {
$location_file_path = ai1wm_escape_windows_directory_separator( $file_path );
} else {
$location_file_path = ai1wm_escape_windows_directory_separator( $location . DIRECTORY_SEPARATOR . $file_path );
}
// Escape Windows directory separator in file name
if ( path_is_absolute( $file_name ) ) {
$location_file_name = ai1wm_escape_windows_directory_separator( $file_name );
} else {
$location_file_name = ai1wm_escape_windows_directory_separator( $location . DIRECTORY_SEPARATOR . $file_name );
}
// Check if location doesn't exist, then create it
if ( false === is_dir( $location_file_path ) ) {
@mkdir( $location_file_path, $this->get_permissions_for_directory(), true );
}
$file_bytes_read = 0;
// We have a match, let's extract the file
if ( ( $completed = $this->extract_to( $location_file_name, $file_name, $file_size, $file_mtime, $file_bytes_read, $file_bytes_offset, $file_bytes_written ) ) ) {
$file_bytes_offset = $file_bytes_written = 0;
// Verify CRC32 if present (not empty means version 2 archive with CRC32)
if ( ! empty( $file_crc32 ) ) {
do_action( 'ai1wm_check_file_integrity', $file_name, $file_crc32 );
}
}
} else {
// We don't have a match, skip file content
if ( @fseek( $this->file_handle, $file_size, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $file_size ) );
}
}
}
}
}
return $completed;
}
/**
* Extract specific files from archive
*
* @param string $location Location where to extract files
* @param array $include_files Include files by name
* @param array $exclude_files Exclude files by name
* @param array $exclude_extensions Exclude files by extension
* @param int $file_bytes_read Amount of the bytes we read
* @param int $file_bytes_offset File bytes offset
* @param int $file_bytes_written Amount of the bytes we wrote
*
* @throws \Ai1wm_Not_Directory_Exception
* @throws \Ai1wm_Not_Seekable_Exception
*
* @return bool
*/
public function extract_by_files_array( $location, $include_files = array(), $exclude_files = array(), $exclude_extensions = array(), &$file_bytes_read = 0, &$file_bytes_offset = 0, &$file_bytes_written = 0 ) {
if ( false === is_dir( $location ) ) {
throw new Ai1wm_Not_Directory_Exception( sprintf( __( 'Location is not a directory: %s', 'all-in-one-wp-migration' ), $location ) );
}
// Replace forward slash with current directory separator in location
$location = ai1wm_replace_forward_slash_with_directory_separator( $location );
// Flag to hold if file data has been processed
$completed = true;
// Start time
$start = microtime( true );
// Seek to file offset to archive file
if ( $file_bytes_offset > 0 ) {
if ( @fseek( $this->file_handle, - $file_bytes_offset - static::HEADER_SIZE, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, - $file_bytes_offset - static::HEADER_SIZE ) );
}
}
// We read until we reached the end of the file, or the files we were looking for were found
while ( ( $block = @fread( $this->file_handle, static::HEADER_SIZE ) ) ) {
// We reached end of file, set the pointer to the end of the file so that feof returns true
if ( $this->is_eof_block( $block ) ) {
// Seek to end of archive file minus 1 byte
@fseek( $this->file_handle, 1, SEEK_END );
// Read 1 character
@fgetc( $this->file_handle );
} else {
// Get file header data from the block
if ( ( $data = $this->get_data_from_block( $block ) ) ) {
// Set file name
$file_name = $data['filename'];
// Set file size
$file_size = $data['size'];
// Set file mtime
$file_mtime = $data['mtime'];
// Set file path
$file_path = $data['path'];
// Set file crc
$file_crc32 = $data['crc32'];
// Should we extract this file by name?
$should_include_file = false;
for ( $i = 0; $i < count( $include_files ); $i++ ) {
if ( strpos( $file_name . DIRECTORY_SEPARATOR, ai1wm_replace_forward_slash_with_directory_separator( $include_files[ $i ] ) . DIRECTORY_SEPARATOR ) === 0 ) {
$should_include_file = true;
break;
}
}
// Should we skip this file name?
for ( $i = 0; $i < count( $exclude_files ); $i++ ) {
if ( strpos( $file_name . DIRECTORY_SEPARATOR, ai1wm_replace_forward_slash_with_directory_separator( $exclude_files[ $i ] ) . DIRECTORY_SEPARATOR ) === 0 ) {
$should_include_file = false;
break;
}
}
// Should we skip this file by extension?
for ( $i = 0; $i < count( $exclude_extensions ); $i++ ) {
if ( strrpos( $file_name, $exclude_extensions[ $i ] ) === strlen( $file_name ) - strlen( $exclude_extensions[ $i ] ) ) {
$should_include_file = false;
break;
}
}
// Validate file name and file path for directory traversal
if ( path_is_absolute( $file_name ) || validate_file( $file_name ) !== 0 ) {
$should_include_file = false;
}
// Do we have a match?
if ( $should_include_file === true ) {
// Escape Windows directory separator in file path
$location_file_path = ai1wm_escape_windows_directory_separator( $location . DIRECTORY_SEPARATOR . $file_path );
// Escape Windows directory separator in file name
$location_file_name = ai1wm_escape_windows_directory_separator( $location . DIRECTORY_SEPARATOR . $file_name );
// Check if location doesn't exist, then create it
if ( false === is_dir( $location_file_path ) ) {
@mkdir( $location_file_path, $this->get_permissions_for_directory(), true );
}
$file_bytes_read = 0;
// We have a match, let's extract the file
if ( ( $completed = $this->extract_to( $location_file_name, $file_name, $file_size, $file_mtime, $file_bytes_read, $file_bytes_offset, $file_bytes_written ) ) ) {
$file_bytes_offset = $file_bytes_written = 0;
// Verify CRC32 if present (not empty means version 2 archive with CRC32)
if ( ! empty( $file_crc32 ) ) {
do_action( 'ai1wm_check_file_integrity', $file_name, $file_crc32 );
}
}
} else {
// We don't have a match, skip file content
if ( @fseek( $this->file_handle, $file_size, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $file_size ) );
}
}
// Time elapsed
if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break;
}
}
}
}
}
return $completed;
}
/**
* Extract file to
*
* @param string $location_file_name Location file name
* @param string $file_name File name
* @param array $file_size File size (in bytes)
* @param array $file_mtime File modified time (in seconds)
* @param int $file_bytes_read Amount of the bytes we read
* @param int $file_bytes_offset File bytes offset
* @param int $file_bytes_written Amount of the bytes we wrote
*
* @throws \Ai1wm_Not_Seekable_Exception
* @throws \Ai1wm_Not_Readable_Exception
* @throws \Ai1wm_Quota_Exceeded_Exception
*
* @return bool
*/
private function extract_to( $location_file_name, $file_name, $file_size, $file_mtime, &$file_bytes_read = 0, &$file_bytes_offset = 0, &$file_bytes_written = 0 ) {
// Flag to hold if file data has been processed
$completed = true;
// Start time
$start = microtime( true );
// Seek to file offset to archive file
if ( $file_bytes_offset > 0 ) {
if ( @fseek( $this->file_handle, $file_bytes_offset, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $file_size ) );
}
}
// Set file size
$file_size -= $file_bytes_offset;
// Should the extract overwrite the file if it exists? (fopen may return null for quarantined files)
if ( ( $file_handle = @fopen( $location_file_name, ( $file_bytes_offset === 0 ? 'wb' : 'cb' ) ) ) ) {
// Set file offset
if ( @fseek( $file_handle, $file_bytes_written, SEEK_SET ) !== -1 ) {
$file_bytes_read = 0;
// Cache config file check outside the loop
$should_process_file = ! in_array( $file_name, ai1wm_config_filters() );
// Is the filesize more than 0 bytes?
while ( $file_size > 0 ) {
// Read the file in chunks of 512KB
$chunk_size = min( $file_size, static::READ_CHUNK_SIZE );
// Do not decrypt or decompress config files
if ( $should_process_file === true ) {
// Get decryption chunk size
if ( ! empty( $this->file_password ) ) {
if ( $file_size > static::READ_CHUNK_SIZE ) {
$chunk_size += ai1wm_crypt_iv_length() * 2;
$chunk_size = min( $chunk_size, $file_size );
}
}
// Read chunk header data
if ( ! empty( $this->file_compression ) ) {
$chunk_header_size = 4;
// Get chunk header block
if ( ( $chunk_header_block = fread( $this->file_handle, $chunk_header_size ) ) === false ) {
throw new Ai1wm_Not_Readable_Exception( sprintf( __( 'Could not read content from file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Get chunk header data
if ( ( $chunk_header_data = unpack( 'Nsize', $chunk_header_block ) ) ) {
if ( isset( $chunk_header_data['size'] ) ) {
$chunk_size = $chunk_header_data['size'];
}
}
// Add the amount of bytes we read
$file_bytes_read += $chunk_header_size;
// Remove the amout of bytes we read
$file_size -= $chunk_header_size;
}
}
// Read data chunk by chunk from archive file
if ( $chunk_size > 0 ) {
// Read the file in chunks of 512KB from archiver
if ( ( $file_content = @fread( $this->file_handle, $chunk_size ) ) === false ) {
throw new Ai1wm_Not_Readable_Exception( sprintf( __( 'Could not read content from file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
}
// Add the amount of bytes we read
$file_bytes_read += $chunk_size;
// Remove the amout of bytes we read
$file_size -= $chunk_size;
// Do not decrypt or decompress config files
if ( $should_process_file === true ) {
// Add chunk data decryption
if ( ! empty( $this->file_password ) ) {
$file_content = ai1wm_decrypt_string( $file_content, $this->file_password );
}
// Add chunk data decompression
if ( ! empty( $this->file_compression ) ) {
switch ( $this->file_compression ) {
case 'gzip':
$file_content = gzuncompress( $file_content );
break;
case 'bzip2':
$file_content = bzdecompress( $file_content );
break;
}
}
}
// Write file contents
if ( ( $file_bytes = @fwrite( $file_handle, $file_content ) ) !== false ) {
if ( strlen( $file_content ) !== $file_bytes ) {
throw new Ai1wm_Quota_Exceeded_Exception( sprintf( __( 'Out of disk space. Could not write content to file. File: %s', 'all-in-one-wp-migration' ), $location_file_name ) );
}
}
// Add the amount of bytes we wrote
$file_bytes_written += $file_bytes;
}
// Time elapsed
if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break;
}
}
}
// Add the amount of bytes we read
$file_bytes_offset += $file_bytes_read;
}
// Close the handle
@fclose( $file_handle );
// Let's apply last modified date
@touch( $location_file_name, $file_mtime );
// All files should chmoded to 644
@chmod( $location_file_name, $this->get_permissions_for_file() );
} else {
// We don't have file permissions, skip file content
if ( @fseek( $this->file_handle, $file_size, SEEK_CUR ) === -1 ) {
throw new Ai1wm_Not_Seekable_Exception( sprintf( __( 'Could not seek to offset of file. File: %s Offset: %d', 'all-in-one-wp-migration' ), $this->file_name, $file_size ) );
}
}
return $completed;
}
/**
* Get file header data from the block
*
* @param string $block Binary file header
*
* @return array
*/
private function get_data_from_block( $block ) {
$data = false;
// Prepare our array keys to unpack
$format = array(
$this->block_format[0] . 'filename/',
$this->block_format[1] . 'size/',
$this->block_format[2] . 'mtime/',
$this->block_format[3] . 'path/',
$this->block_format[4] . 'crc32',
);
$format = implode( '', $format );
// Unpack file header data
if ( ( $data = unpack( $format, $block ) ) ) {
// Set file details
$data['filename'] = trim( $data['filename'] );
$data['size'] = (int) trim( $data['size'] );
$data['mtime'] = (int) trim( $data['mtime'] );
$data['path'] = trim( $data['path'] );
$data['crc32'] = trim( $data['crc32'] );
// Set file name
$data['filename'] = ( $data['path'] === '.' ? $data['filename'] : $data['path'] . DIRECTORY_SEPARATOR . $data['filename'] );
// Set file path
$data['path'] = ( $data['path'] === '.' ? '' : $data['path'] );
// Replace forward slash with current directory separator in file name
$data['filename'] = ai1wm_replace_forward_slash_with_directory_separator( $data['filename'] );
// Replace forward slash with current directory separator in file path
$data['path'] = ai1wm_replace_forward_slash_with_directory_separator( $data['path'] );
}
return $data;
}
/**
* Check if file has reached end of file
* Returns true if file has reached eof, false otherwise
*
* @return bool
*/
public function has_reached_eof() {
return @feof( $this->file_handle );
}
/**
* Check if file has reached end of file
* Returns true if file has NOT reached eof, false otherwise
*
* @return bool
*/
public function has_not_reached_eof() {
return ! @feof( $this->file_handle );
}
/**
* Get directory permissions
*
* @return int
*/
public function get_permissions_for_directory() {
if ( defined( 'FS_CHMOD_DIR' ) ) {
return FS_CHMOD_DIR;
}
return 0755;
}
/**
* Get file permissions
*
* @return int
*/
public function get_permissions_for_file() {
if ( defined( 'FS_CHMOD_FILE' ) ) {
return FS_CHMOD_FILE;
}
return 0644;
}
}

View File

@@ -0,0 +1,202 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Crc {
/**
* Calculate CRC32 checksum for a file
*
* @param string $file_path Path to the file
* @return string|null CRC32 checksum as hexadecimal string or null on error
*/
public static function calculate_file_crc32( $file_path ) {
if ( ! file_exists( $file_path ) || ! is_readable( $file_path ) ) {
return null;
}
// Use hash_file for CRC32b (CRC32 with reversed bit order, more standard)
$crc = hash_file( 'crc32b', $file_path );
return $crc;
}
/**
* Verify file CRC32 checksum
*
* @param string $file_path Path to the file
* @param string $expected_crc Expected CRC32 checksum
* @return bool True if CRC matches, false otherwise
*/
public static function verify_file_crc32( $file_path, $expected_crc ) {
$calculated_crc = self::calculate_file_crc32( $file_path );
if ( $calculated_crc === null ) {
return false;
}
return strcasecmp( $calculated_crc, $expected_crc ) === 0;
}
/**
* Initialize CRC32 hash context for incremental calculation
*
* @return resource|\HashContext Hash context
*/
public static function init_crc32() {
return hash_init( 'crc32b' );
}
/**
* Update CRC32 hash with a data chunk
*
* @param resource|\HashContext $context Hash context
* @param string $data Data chunk to add
* @return void
*/
public static function update_crc32( $context, $data ) {
hash_update( $context, $data );
}
/**
* Finalize CRC32 calculation and return result
*
* @param resource|\HashContext $context Hash context
* @return string CRC32 checksum as hexadecimal string
*/
public static function finalize_crc32( $context ) {
return hash_final( $context );
}
/**
* Combine two CRC32 checksums
*
* This method mathematically combines two CRC32 values, allowing resumable
* CRC calculation across multiple processing cycles (e.g., handling timeouts).
*
* Based on zlib's crc32_combine algorithm using GF(2) polynomial arithmetic.
*
* @param string $crc1_hex CRC32 of first data block (hex string)
* @param string $crc2_hex CRC32 of second data block (hex string)
* @param int $len2 Length of second data block in bytes
* @return string Combined CRC32 checksum as hexadecimal string
*/
public static function combine_crc32( $crc1_hex, $crc2_hex, $len2 ) {
// CRC32 polynomial (reversed)
$poly = 0xEDB88320;
// Convert hex strings to integers
$crc1 = hexdec( $crc1_hex );
$crc2 = hexdec( $crc2_hex );
// If second block is empty, return first CRC unchanged
if ( $len2 === 0 ) {
return sprintf( '%08x', $crc1 );
}
// Build operator matrix for x^n where n = len2 * 8
// This represents multiplication by x^(8*len2) mod poly
$even = array_fill( 0, 32, 0 );
$even[0] = $poly;
$row = 1;
for ( $n = 1; $n < 32; $n++ ) {
$even[ $n ] = $row;
$row = $row << 1;
}
// Square to get x^2, x^4, x^8, etc.
$odd = array_fill( 0, 32, 0 );
self::gf2_matrix_square( $odd, $even );
self::gf2_matrix_square( $even, $odd );
// Apply len2 zeros to crc1 by repeatedly squaring and applying
do {
// Apply zeros operator for this bit of len2
self::gf2_matrix_square( $odd, $even );
if ( $len2 & 1 ) {
$crc1 = self::gf2_matrix_times( $odd, $crc1 );
}
$len2 >>= 1;
// If no more bits, we're done
if ( $len2 === 0 ) {
break;
}
// Square again for next bit
self::gf2_matrix_square( $even, $odd );
if ( $len2 & 1 ) {
$crc1 = self::gf2_matrix_times( $even, $crc1 );
}
$len2 >>= 1;
} while ( $len2 !== 0 );
// Combine the two CRCs
$crc1 ^= $crc2;
return sprintf( '%08x', $crc1 );
}
/**
* Matrix multiplication in GF(2)
*
* @param array $mat Matrix
* @param int $vec Vector
* @return int Result
*/
private static function gf2_matrix_times( $mat, $vec ) {
$sum = 0;
$mat_index = 0;
while ( $vec ) {
if ( $vec & 1 ) {
$sum ^= $mat[ $mat_index ];
}
$vec = ( $vec >> 1 ) & 0x7FFFFFFF;
$mat_index++;
}
return $sum;
}
/**
* Square a matrix in GF(2)
*
* @param array $square Result matrix (passed by reference)
* @param array $mat Input matrix
* @return void
*/
private static function gf2_matrix_square( &$square, $mat ) {
for ( $n = 0; $n < 32; $n++ ) {
$square[ $n ] = self::gf2_matrix_times( $mat, $mat[ $n ] );
}
}
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
if ( defined( 'WP_CLI' ) ) {
class Ai1wm_WP_CLI_Command extends WP_CLI_Command {
/**
* Creates a new backup.
*
* ## EXAMPLES
*
* $ wp ai1wm export
*
* @subcommand export
*/
public function export( $args = array(), $assoc_args = array() ) {
$this->info();
}
/**
* Creates a new backup.
*
* ## EXAMPLES
*
* $ wp ai1wm backup
*
* @subcommand backup
*/
public function backup( $args = array(), $assoc_args = array() ) {
$this->info();
}
/**
* Imports a backup.
*
* ## EXAMPLES
*
* $ wp ai1wm import
*
* @subcommand import
*/
public function import( $args = array(), $assoc_args = array() ) {
$this->info();
}
/**
* Restores a backup.
*
* ## EXAMPLES
*
* $ wp ai1wm restore
*
* @subcommand restore
*/
public function restore( $args = array(), $assoc_args = array() ) {
$this->info();
}
/**
* Resets site to default WordPress installation.
*
* ## EXAMPLES
*
* $ wp ai1wm reset
*
* @subcommand reset
*/
public function reset( $args = array(), $assoc_args = array() ) {
$this->info();
}
protected function info() {
if ( is_multisite() ) {
WP_CLI::error_multi_line(
array(
__( 'This feature is available in Multisite Extension.', 'all-in-one-wp-migration' ),
__( 'You can purchase it from this address: https://servmask.com/products/multisite-extension', 'all-in-one-wp-migration' ),
)
);
exit;
}
WP_CLI::error_multi_line(
array(
__( 'This feature is available in Unlimited Extension.', 'all-in-one-wp-migration' ),
__( 'You can purchase it from this address: https://servmask.com/products/unlimited-extension', 'all-in-one-wp-migration' ),
)
);
}
}
}

View File

@@ -0,0 +1,142 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Cron {
/**
* Schedules a hook which will be executed by the WordPress
* actions core on a specific interval
*
* @param string $hook Event hook
* @param string $recurrence How often the event should reoccur
* @param integer $timestamp Preferred timestamp (when the event shall be run)
* @param array $args Arguments to pass to the hook function(s)
* @return mixed
*/
public static function add( $hook, $recurrence, $timestamp, $args = array() ) {
$schedules = wp_get_schedules();
// Schedule event
if ( isset( $schedules[ $recurrence ] ) && ( $current = $schedules[ $recurrence ] ) ) {
if ( $timestamp <= ( $current_timestamp = time() ) ) {
while ( $timestamp <= $current_timestamp ) {
$timestamp += $current['interval'];
}
}
return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
}
}
/**
* Un-schedules all previously-scheduled cron jobs using a particular
* hook name or a specific combination of hook name and arguments.
*
* @param string $hook Event hook
* @return boolean
*/
public static function clear( $hook ) {
$cron = get_option( AI1WM_CRON, array() );
if ( empty( $cron ) ) {
return false;
}
foreach ( $cron as $timestamp => $hooks ) {
if ( isset( $hooks[ $hook ] ) ) {
unset( $cron[ $timestamp ][ $hook ] );
// Unset empty timestamps
if ( empty( $cron[ $timestamp ] ) ) {
unset( $cron[ $timestamp ] );
}
}
}
return update_option( AI1WM_CRON, $cron );
}
/**
* Checks whether cronjob already exists
*
* @param string $hook Event hook
* @param array $args Event callback arguments
* @return boolean
*/
public static function exists( $hook, $args = array() ) {
$cron = get_option( AI1WM_CRON, array() );
if ( empty( $cron ) ) {
return false;
}
foreach ( $cron as $timestamp => $hooks ) {
if ( empty( $args ) ) {
if ( isset( $hooks[ $hook ] ) ) {
return true;
}
} else {
if ( isset( $hooks[ $hook ][ md5( serialize( $args ) ) ] ) ) {
return true;
}
}
}
return false;
}
/**
* Deletes cron event(s) if it exists
*
* @param string $hook Event hook
* @param array $args Event callback arguments
* @return boolean
*/
public static function delete( $hook, $args = array() ) {
$cron = get_option( AI1WM_CRON, array() );
if ( empty( $cron ) ) {
return false;
}
$key = md5( serialize( $args ) );
foreach ( $cron as $timestamp => $hooks ) {
if ( isset( $cron[ $timestamp ][ $hook ][ $key ] ) ) {
unset( $cron[ $timestamp ][ $hook ][ $key ] );
}
if ( isset( $cron[ $timestamp ][ $hook ] ) && empty( $cron[ $timestamp ][ $hook ] ) ) {
unset( $cron[ $timestamp ][ $hook ] );
}
if ( empty( $cron[ $timestamp ] ) ) {
unset( $cron[ $timestamp ] );
}
}
return update_option( AI1WM_CRON, $cron );
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Database_Mariadb extends Ai1wm_Database_Mysqli {
/**
* Replace column types
*
* @param string $input Column value
* @return string
*/
protected function replace_column_types( $input ) {
static $search = null;
static $replace = null;
// Cache column types on first call
if ( is_null( $search ) || is_null( $replace ) ) {
$search = array();
$replace = array();
// Convert INET4 column type (10.10.0)
if ( version_compare( $this->server_version(), '10.10.0', '<' ) ) {
$search[] = '/(?<!`)\bINET4\b(?!\s*\()/i';
$replace[] = 'VARCHAR(15)';
}
// Convert INET6 column type (10.5.0)
if ( version_compare( $this->server_version(), '10.5.0', '<' ) ) {
$search[] = '/(?<!`)\bINET6\b(?!\s*\()/i';
$replace[] = 'VARCHAR(45)';
}
// Convert UUID column type (10.7.0)
if ( version_compare( $this->server_version(), '10.7.0', '<' ) ) {
$search[] = '/(?<!`)\bUUID\b(?!\s*\()/i';
$replace[] = 'CHAR(36)';
}
// Convert XMLTYPE column type (12.3.0)
if ( version_compare( $this->server_version(), '12.3.0', '<' ) ) {
$search[] = '/(?<!`)\bXMLTYPE\b(?!\s*\()/i';
$replace[] = 'LONGTEXT';
}
// Convert VECTOR(N) column type (11.7.1)
if ( version_compare( $this->server_version(), '11.7.1', '<' ) ) {
$search[] = '/(?<!`)\bVECTOR\s*\(\s*\d+\s*\)/i';
$replace[] = 'BLOB';
}
}
return preg_replace( $search, $replace, $input );
}
}

View File

@@ -0,0 +1,159 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Database_Mysql extends Ai1wm_Database {
/**
* Check whether table has auto increment attribute
*
* @param string $table_name Table name
* @return boolean
*/
public function has_auto_increment( $table_name ) {
return stripos( $this->get_create_table( $table_name ), 'AUTO_INCREMENT' ) !== false;
}
/**
* Run MySQL query
*
* @param string $input SQL query
* @return mixed
*/
public function query( $input ) {
if ( ! ( $result = mysql_query( $input, $this->wpdb->dbh ) ) ) {
$mysql_errno = 0;
// Get MySQL error code
if ( ! empty( $this->wpdb->dbh ) ) {
if ( is_resource( $this->wpdb->dbh ) ) {
$mysql_errno = mysql_errno( $this->wpdb->dbh );
} else {
$mysql_errno = 2006;
}
}
// MySQL server has gone away, try to reconnect
if ( empty( $this->wpdb->dbh ) || 2006 === $mysql_errno ) {
if ( ! $this->wpdb->check_connection( false ) ) {
throw new Ai1wm_Database_Exception( __( 'Error reconnecting to the database. <a href="https://help.servmask.com/knowledgebase/mysql-error-reconnecting/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), 503 );
}
$result = mysql_query( $input, $this->wpdb->dbh );
}
}
return $result;
}
/**
* Escape string input for MySQL query
*
* @param string $input String to escape
* @return string
*/
public function escape( $input ) {
return mysql_real_escape_string( $input, $this->wpdb->dbh );
}
/**
* Return the error code for the most recent function call
*
* @return integer
*/
public function errno() {
return mysql_errno( $this->wpdb->dbh );
}
/**
* Return a string description of the last error
*
* @return string
*/
public function error() {
return mysql_error( $this->wpdb->dbh );
}
/**
* Return server info
*
* @return string
*/
public function server_info() {
static $cached_result = null;
// Cache server info on first call
if ( $cached_result === null ) {
$cached_result = mysql_get_server_info( $this->wpdb->dbh );
}
return $cached_result;
}
/**
* Return the result from MySQL query as associative array
*
* @param mixed $result MySQL resource
* @return array
*/
public function fetch_assoc( &$result ) {
return mysql_fetch_assoc( $result );
}
/**
* Return the result from MySQL query as row
*
* @param mixed $result MySQL resource
* @return array
*/
public function fetch_row( &$result ) {
return mysql_fetch_row( $result );
}
/**
* Return the number for rows from MySQL results
*
* @param mixed $result MySQL resource
* @return integer
*/
public function num_rows( &$result ) {
return mysql_num_rows( $result );
}
/**
* Free MySQL result memory
*
* @param mixed $result MySQL resource
* @return boolean
*/
public function free_result( &$result ) {
return mysql_free_result( $result );
}
}

View File

@@ -0,0 +1,181 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Database_Mysqli extends Ai1wm_Database {
/**
* Check whether table has auto increment attribute
*
* @param string $table_name Table name
* @return boolean
*/
public function has_auto_increment( $table_name ) {
return stripos( $this->get_create_table( $table_name ), 'AUTO_INCREMENT' ) !== false;
}
/**
* Run MySQL query
*
* @param string $input SQL query
* @return mixed
*/
public function query( $input ) {
if ( ! mysqli_real_query( $this->wpdb->dbh, $input ) ) {
$mysqli_errno = 0;
// Get MySQL error code
if ( ! empty( $this->wpdb->dbh ) ) {
if ( $this->wpdb->dbh instanceof mysqli ) {
$mysqli_errno = mysqli_errno( $this->wpdb->dbh );
} else {
$mysqli_errno = 2006;
}
}
// MySQL server has gone away, try to reconnect
if ( empty( $this->wpdb->dbh ) || 2006 === $mysqli_errno ) {
if ( ! $this->wpdb->check_connection( false ) ) {
throw new Ai1wm_Database_Exception( __( 'Error reconnecting to the database. <a href="https://help.servmask.com/knowledgebase/mysql-error-reconnecting/" target="_blank">Technical details</a>', 'all-in-one-wp-migration' ), 503 );
}
mysqli_real_query( $this->wpdb->dbh, $input );
}
}
// The parameter $mode has had no effect as of PHP 8.1.0.
if ( ( PHP_MAJOR_VERSION >= 8 && PHP_MINOR_VERSION >= 1 ) || ! defined( 'MYSQLI_STORE_RESULT_COPY_DATA' ) ) {
return mysqli_store_result( $this->wpdb->dbh );
}
// Copy results from the internal mysqlnd buffer into the PHP variables fetched
return mysqli_store_result( $this->wpdb->dbh, MYSQLI_STORE_RESULT_COPY_DATA );
}
/**
* Escape string input for MySQL query
*
* @param string $input String to escape
* @return string
*/
public function escape( $input ) {
return mysqli_real_escape_string( $this->wpdb->dbh, $input );
}
/**
* Return the error code for the most recent function call
*
* @return integer
*/
public function errno() {
return mysqli_errno( $this->wpdb->dbh );
}
/**
* Return a string description of the last error
*
* @return string
*/
public function error() {
return mysqli_error( $this->wpdb->dbh );
}
/**
* Return server info
*
* @return string
*/
public function server_info() {
static $cached_result = null;
// Cache server info on first call
if ( $cached_result === null ) {
$cached_result = mysqli_get_server_info( $this->wpdb->dbh );
}
return $cached_result;
}
/**
* Return the result from MySQL query as associative array
*
* @param mixed $result MySQL resource
* @return array
*/
public function fetch_assoc( &$result ) {
if ( $result === false ) {
return false;
}
return mysqli_fetch_assoc( $result );
}
/**
* Return the result from MySQL query as row
*
* @param mixed $result MySQL resource
* @return array
*/
public function fetch_row( &$result ) {
if ( $result === false ) {
return false;
}
return mysqli_fetch_row( $result );
}
/**
* Return the number for rows from MySQL results
*
* @param mixed $result MySQL resource
* @return integer
*/
public function num_rows( &$result ) {
if ( $result === false ) {
return 0;
}
return mysqli_num_rows( $result );
}
/**
* Free MySQL result memory
*
* @param mixed $result MySQL resource
* @return boolean
*/
public function free_result( &$result ) {
if ( $result === false ) {
return true;
}
return mysqli_free_result( $result );
}
}

View File

@@ -0,0 +1,377 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Database_Sqlite extends Ai1wm_Database {
/**
* Check whether table has auto increment attribute
*
* @param string $table_name Table name
* @return boolean
*/
public function has_auto_increment( $table_name ) {
return stripos( $this->get_create_table( $table_name ), 'AUTOINCREMENT' ) !== false;
}
/**
* Get views
*
* @return array
*/
protected function get_views() {
if ( is_null( $this->views ) ) {
$where_query = array();
// Loop over table prefixes
if ( $this->get_table_prefix_filters() ) {
foreach ( $this->get_table_prefix_filters() as $prefix_filter ) {
if ( isset( $prefix_filter[0], $prefix_filter[1] ) ) {
$where_query[] = sprintf( "(`name` REGEXP '^%s' AND `name` NOT REGEXP '^%s')", $prefix_filter[0], $prefix_filter[1] );
} else {
$where_query[] = sprintf( "`name` REGEXP '^%s'", $prefix_filter[0] );
}
}
} else {
$where_query[] = 1;
}
$this->views = array();
// Loop over views
$result = $this->query( sprintf( "SELECT `name` FROM `sqlite_master` WHERE `type`='view' AND (%s)", implode( ' OR ', $where_query ) ) );
while ( $row = $this->fetch_row( $result ) ) {
if ( isset( $row[0] ) ) {
$this->views[] = $row[0];
}
}
$this->free_result( $result );
}
return $this->views;
}
/**
* Get base tables
*
* @return array
*/
protected function get_base_tables() {
if ( is_null( $this->base_tables ) ) {
$where_query = array();
// Loop over table prefixes
if ( $this->get_table_prefix_filters() ) {
foreach ( $this->get_table_prefix_filters() as $prefix_filter ) {
if ( isset( $prefix_filter[0], $prefix_filter[1] ) ) {
$where_query[] = sprintf( "(`name` REGEXP '^%s' AND `name` NOT REGEXP '^%s')", $prefix_filter[0], $prefix_filter[1] );
} else {
$where_query[] = sprintf( "`name` REGEXP '^%s'", $prefix_filter[0] );
}
}
} else {
$where_query[] = 1;
}
$this->base_tables = array();
// Loop over base tables
$result = $this->query( sprintf( "SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND (%s)", implode( ' OR ', $where_query ) ) );
while ( $row = $this->fetch_row( $result ) ) {
if ( isset( $row[0] ) ) {
$this->base_tables[] = $row[0];
}
}
$this->free_result( $result );
}
return $this->base_tables;
}
/**
* Run SQLite query
*
* @param string $input SQL query
* @return mixed
*/
public function query( $input ) {
return $this->wpdb->get_results( $input, ARRAY_A );
}
/**
* Escape string input for SQLite query
*
* @param string $input String to escape
* @return string
*/
public function escape( $input ) {
return $this->wpdb->_real_escape( $input );
}
/**
* Return the error code for the most recent function call
*
* @return integer
*/
public function errno() {
return 0;
}
/**
* Return a string description of the last error
*
* @return string
*/
public function error() {
}
/**
* Return server info
*
* @return string
*/
public function server_info() {
return $this->wpdb->db_server_info();
}
/**
* Return result as associative array
*
* @param mixed $result SQLite resource
* @return array
*/
public function fetch_assoc( &$result ) {
if ( key( $result ) === null ) {
return false;
}
$current = current( $result );
next( $result );
return $current;
}
/**
* Return the result from SQLite query as row
*
* @param mixed $result SQLite resource
* @return array
*/
public function fetch_row( &$result ) {
$current = $this->fetch_assoc( $result );
if ( $current === false ) {
return false;
}
return array_values( $current );
}
/**
* Return the number for rows from SQLite results
*
* @param mixed $result SQLite resource
* @return integer
*/
public function num_rows( &$result ) {
return count( $result );
}
/**
* Stub for free SQLite result memory
*
* @param mixed $result SQLite resource
* @return void
*/
public function free_result( &$result ) {
unset( $result );
}
/**
* Get SQLite create view
*
* @param string $table_name View name
* @return string
*/
protected function get_create_view( $table_name ) {
$result = $this->query( "SELECT `sql` FROM `sqlite_master` WHERE `name` = '{$table_name}'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get create table
if ( isset( $row['sql'] ) ) {
return $row['sql'];
}
}
/**
* Get SQLite create table
*
* @param string $table_name Table name
* @return string
*/
protected function get_create_table( $table_name ) {
$result = $this->query( "SELECT `sql` FROM `sqlite_master` WHERE `name` = '{$table_name}'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get create table
if ( isset( $row['sql'] ) ) {
return $row['sql'];
}
}
/**
* Replace table defaults
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_defaults( $input ) {
$pattern = array(
'/DEFAULT(\s+)(\d+)/i',
"/DEFAULT(\s+)'(.*?)'/i",
);
return preg_replace( $pattern, '', $input );
}
/**
* Replace view quotes
*
* @param string $input View value
* @return string
*/
protected function replace_view_quotes( $input ) {
return str_replace( '"', '`', $input );
}
/**
* Replace table quotes
*
* @param string $input Table value
* @return string
*/
protected function replace_table_quotes( $input ) {
return str_replace( '"', '`', $input );
}
/**
* Get SQLite primary keys
*
* @param string $table_name Table name
* @return array
*/
protected function get_primary_keys( $table_name ) {
$primary_keys = array();
// Get primary keys
$result = $this->query( "SELECT `table_info`.`name` FROM PRAGMA_TABLE_INFO('{$table_name}') AS table_info WHERE `table_info`.`pk` != 0" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['name'] ) ) {
$primary_keys[] = $row['name'];
}
}
// Close result cursor
$this->free_result( $result );
return $primary_keys;
}
/**
* Get SQLite column types
*
* @param string $table_name Table name
* @return array
*/
protected function get_column_types( $table_name ) {
$column_types = array();
// Get column types
$result = $this->query( "SELECT `name`, `type` FROM PRAGMA_TABLE_INFO('{$table_name}')" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['name'] ) ) {
$column_types[ strtolower( $row['name'] ) ] = $row['type'];
}
}
// Close result cursor
$this->free_result( $result );
return $column_types;
}
/**
* Get SQLite column names
*
* @param string $table_name Table name
* @return array
*/
public function get_column_names( $table_name ) {
$column_names = array();
// Get column names
$result = $this->query( "SELECT `name` FROM PRAGMA_TABLE_INFO('{$table_name}')" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['name'] ) ) {
$column_names[ strtolower( $row['name'] ) ] = $row['name'];
}
}
// Close result cursor
$this->free_result( $result );
return $column_names;
}
/**
* Get SQLite max allowed packet
*
* @return integer
*/
protected function get_max_allowed_packet() {
return PHP_INT_MAX;
}
/**
* Use SQLite transactions
*
* @return boolean
*/
protected function use_transactions() {
return false;
}
}

View File

@@ -0,0 +1,457 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Database_Utility {
protected static $db_client = null;
/**
* Set the database client instance for injection
*
* @param Ai1wm_Database $db_client Database client instance.
* @return void
*/
public static function set_client( $db_client ) {
self::$db_client = $db_client;
}
/**
* Get the database client instance, creating it if not set
*
* @return Ai1wm_Database
*/
public static function get_client() {
if ( self::$db_client === null ) {
return self::create_client();
}
return self::$db_client;
}
/**
* Create DB client to be used for DB manipulation
*
* @return Ai1wm_Database
*/
private static function create_client() {
global $wpdb;
// SQLite
if ( $wpdb instanceof WP_SQLite_DB || $wpdb instanceof WP_SQLite_DB\wpsqlitedb ) {
return new Ai1wm_Database_Sqlite( $wpdb );
}
// MariaDB
if ( ( $server_version = $wpdb->get_var( 'SELECT VERSION()' ) ) ) {
if ( stripos( $server_version, 'MariaDB' ) !== false ) {
return new Ai1wm_Database_Mariadb( $wpdb );
}
}
// MySQLi
if ( PHP_MAJOR_VERSION >= 7 ) {
return new Ai1wm_Database_Mysqli( $wpdb );
}
// MySQL
if ( empty( $wpdb->use_mysqli ) ) {
return new Ai1wm_Database_Mysql( $wpdb );
}
return new Ai1wm_Database_Mysqli( $wpdb );
}
/**
* Replace all occurrences of the search string with the replacement string.
* This function is case-sensitive.
*
* @param string $data Data to replace
* @param array $search List of string we're looking to replace
* @param array $replace What we want it to be replaced with
* @return string The original string with all elements replaced as needed
*/
public static function replace_values( $data, $search = array(), $replace = array() ) {
return strtr( $data, array_combine( $search, $replace ) );
}
/**
* Replace serialized occurrences of the search string with the replacement string.
* This function is case-sensitive.
*
* @param string $data Data to replace
* @param array $search List of string we're looking to replace
* @param array $replace What we want it to be replaced with
* @return string The original array with all elements replaced as needed
*/
public static function replace_serialized_values( $data, $search = array(), $replace = array() ) {
$pos = 0;
$result = self::parse_serialized_values( $data, $pos, $search, $replace );
if ( $pos !== strlen( $data ) ) {
// Failed to parse entire data
return strtr( $data, array_combine( $search, $replace ) );
}
return $result;
}
/**
* Parse serialized string and replace needed substitutions.
* This function is case-sensitive.
*
* @param string $data Serialized data
* @param integer $pos Character position
* @param array $search List of string we're looking to replace
* @param array $replace What we want it to be replaced with
* @return string The original string with all elements replaced as needed
*/
public static function parse_serialized_values( $data, &$pos, $search = array(), $replace = array() ) {
$length = strlen( $data );
if ( $pos >= $length ) {
return '';
}
$type = $data[ $pos ];
$pos++;
switch ( $type ) {
case 's':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$len_end = strpos( $data, ':', $pos );
if ( $len_end === false ) {
$pos--;
return '';
}
$str_length = (int) substr( $data, $pos, $len_end - $pos );
$pos = $len_end + 1;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '"' ) {
$pos--;
return '';
}
$pos++;
$str = substr( $data, $pos, $str_length );
$pos += $str_length;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '"' ) {
$pos--;
return '';
}
$pos++;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ';' ) {
$pos--;
return '';
}
$pos++;
// If the string is a single letter, skip any parsing or replacement.
if ( $str_length === 1 ) {
return 's:' . $str_length . ':"' . $str . '";';
}
// Attempt to parse the string as serialized data
$pos_inner = 0;
$parsed_str = self::parse_serialized_values( $str, $pos_inner, $search, $replace );
if ( $pos_inner === strlen( $str ) ) {
// The string is serialized data, use the parsed string
$new_str = $parsed_str;
} else {
// Regular string, perform replacement
$new_str = strtr( $str, array_combine( $search, $replace ) );
}
return 's:' . strlen( $new_str ) . ':"' . $new_str . '";';
case 'i':
case 'd':
case 'b':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$end = strpos( $data, ';', $pos );
if ( $end === false ) {
$pos--;
return '';
}
$value = substr( $data, $pos, $end - $pos );
$pos = $end + 1;
return $type . ':' . $value . ';';
case 'N':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ';' ) {
$pos--;
return '';
}
$pos++;
return 'N;';
case 'a':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$len_end = strpos( $data, ':', $pos );
if ( $len_end === false ) {
$pos--;
return '';
}
$array_length = (int) substr( $data, $pos, $len_end - $pos );
$pos = $len_end + 1;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '{' ) {
$pos--;
return '';
}
$pos++;
$result = 'a:' . $array_length . ':{';
for ( $i = 0; $i < $array_length * 2; $i++ ) {
$element = self::parse_serialized_values( $data, $pos, $search, $replace );
if ( $element === '' ) {
$pos--;
return '';
}
$result .= $element;
}
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '}' ) {
$pos--;
return '';
}
$pos++;
$result .= '}';
return $result;
case 'O':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$class_len_end = strpos( $data, ':', $pos );
if ( $class_len_end === false ) {
$pos--;
return '';
}
$class_length = (int) substr( $data, $pos, $class_len_end - $pos );
$pos = $class_len_end + 1;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '"' ) {
$pos--;
return '';
}
$pos++;
$class_name = substr( $data, $pos, $class_length );
$pos += $class_length;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '"' ) {
$pos--;
return '';
}
$pos++;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$prop_len_end = strpos( $data, ':', $pos );
if ( $prop_len_end === false ) {
$pos--;
return '';
}
$prop_count = (int) substr( $data, $pos, $prop_len_end - $pos );
$pos = $prop_len_end + 1;
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '{' ) {
$pos--;
return '';
}
$pos++;
$result = 'O:' . strlen( $class_name ) . ':"' . $class_name . '":' . $prop_count . ':{';
for ( $i = 0; $i < $prop_count * 2; $i++ ) {
$element = self::parse_serialized_values( $data, $pos, $search, $replace );
if ( $element === '' ) {
$pos--;
return '';
}
$result .= $element;
}
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== '}' ) {
$pos--;
return '';
}
$pos++;
$result .= '}';
return $result;
case 'R':
case 'r':
if ( ! isset( $data[ $pos ] ) || $data[ $pos ] !== ':' ) {
$pos--;
return '';
}
$pos++;
$end = strpos( $data, ';', $pos );
if ( $end === false ) {
$pos--;
return '';
}
$ref = substr( $data, $pos, $end - $pos );
$pos = $end + 1;
return $type . ':' . $ref . ';';
default:
$pos--;
return '';
}
}
/**
* Parse MySQL server version
*
* @param string $info Server info
* @return string
*/
public static function parse_server_version( $info ) {
$matches = array();
if ( preg_match( '/(\d+\.\d+\.\d+)-(\d+\.\d+\.\d+)/i', $info, $matches ) ) {
if ( isset( $matches[2] ) ) {
return $matches[2];
}
}
if ( preg_match( '/(\d+\.\d+\.\d+)/i', $info, $matches ) ) {
if ( isset( $matches[1] ) ) {
return $matches[1];
}
}
return '0.0.0';
}
/**
* Escape MySQL special characters
*
* @param string $data Data to escape
* @return string
*/
public static function escape_mysql( $data ) {
return strtr(
$data,
array_combine(
array( "\x00", "\n", "\r", '\\', "'", '"', "\x1a" ),
array( '\\0', '\\n', '\\r', '\\\\', "\\'", '\\"', '\\Z' )
)
);
}
/**
* Unescape MySQL special characters
*
* @param string $data Data to unescape
* @return string
*/
public static function unescape_mysql( $data ) {
return strtr(
$data,
array_combine(
array( '\\0', '\\n', '\\r', '\\\\', "\\'", '\\"', '\\Z' ),
array( "\x00", "\n", "\r", '\\', "'", '"', "\x1a" )
)
);
}
/**
* Encode base64 characters
*
* @param string $data Data to encode
* @return string
*/
public static function base64_encode( $data ) {
return base64_encode( $data );
}
/**
* Encode base64 characters
*
* @param string $data Data to decode
* @return string
*/
public static function base64_decode( $data ) {
return base64_decode( $data );
}
/**
* Validate base64 data
*
* @param string $data Data to validate
* @return boolean
*/
public static function base64_validate( $data ) {
return base64_encode( base64_decode( $data ) ) === $data;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Directory {
/**
* Create directory (recursively)
*
* @param string $path Path to the directory
* @return boolean
*/
public static function create( $path ) {
if ( @is_dir( $path ) ) {
return true;
}
return @mkdir( $path, 0777, true );
}
/**
* Delete directory (recursively)
*
* @param string $path Path to the directory
* @return boolean
*/
public static function delete( $path ) {
if ( @is_dir( $path ) ) {
try {
// Iterate over directory
$iterator = new Ai1wm_Recursive_Directory_Iterator( $path );
// Recursively iterate over directory
$iterator = new Ai1wm_Recursive_Iterator_Iterator( $iterator, RecursiveIteratorIterator::CHILD_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
// Remove files and directories
foreach ( $iterator as $item ) {
if ( $item->isDir() ) {
@rmdir( $item->getPathname() );
} else {
@unlink( $item->getPathname() );
}
}
} catch ( Exception $e ) {
}
return @rmdir( $path );
}
return false;
}
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_File_Htaccess {
/**
* Create backups .htaccess file
*
* @param string $path Path to file
* @return boolean
*/
public static function backups( $path ) {
return Ai1wm_File::create(
$path,
implode(
PHP_EOL,
array(
'<IfModule mod_mime.c>',
' AddType application/octet-stream .wpress',
'</IfModule>',
'<IfModule mod_dir.c>',
' DirectoryIndex index.php',
'</IfModule>',
'<IfModule mod_autoindex.c>',
' Options -Indexes',
'</IfModule>',
)
)
);
}
/**
* Create storage .htaccess file
*
* @param string $path Path to file
* @return boolean
*/
public static function storage( $path ) {
return Ai1wm_File::create(
$path,
implode(
PHP_EOL,
array(
'<IfModule mod_authz_core.c>',
' <FilesMatch ".*">',
' Require all denied',
' </FilesMatch>',
' <FilesMatch "\.log$">',
' Require all granted',
' </FilesMatch>',
'</IfModule>',
'<IfModule !mod_authz_core.c>',
' Order allow,deny',
' Deny from all',
' <FilesMatch "\.log$">',
' Order allow,deny',
' Allow from all',
' </FilesMatch>',
'</IfModule>',
'<IfModule mod_mime.c>',
' AddType text/plain .log',
'</IfModule>',
'<IfModule mod_dir.c>',
' DirectoryIndex index.php',
'</IfModule>',
'<IfModule mod_autoindex.c>',
' Options -Indexes',
'</IfModule>',
)
)
);
}
/**
* Create LiteSpeed .htaccess file
*
* @param string $path Path to file
* @return boolean
*/
public static function litespeed( $path ) {
return Ai1wm_File::insert_with_markers(
$path,
'LiteSpeed',
array(
'<IfModule Litespeed>',
' SetEnv noabort 1',
'</IfModule>',
)
);
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_File_Index {
/**
* Create index file
*
* @param string $path Path to file
* @return boolean
*/
public static function create( $path ) {
return Ai1wm_File::create( $path, 'Kangaroos cannot jump here' );
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_File_Robots {
/**
* Create robots.txt file
*
* @param string $path Path to file
* @return boolean
*/
public static function create( $path ) {
return Ai1wm_File::create(
$path,
implode(
PHP_EOL,
array(
'User-agent: *',
'Disallow: /ai1wm-backups/',
'Disallow: /wp-content/ai1wm-backups/',
)
)
);
}
}

View File

@@ -0,0 +1,105 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_File_Webconfig {
/**
* Create backups web.config file
*
* @param string $path Path to file
* @return boolean
*/
public static function backups( $path ) {
return Ai1wm_File::create(
$path,
implode(
PHP_EOL,
array(
'<?xml version="1.0" encoding="utf-8"?>',
'<configuration>',
' <system.webServer>',
' <staticContent>',
' <mimeMap fileExtension=".wpress" mimeType="application/octet-stream" />',
' </staticContent>',
' <defaultDocument>',
' <files>',
' <add value="index.php" />',
' </files>',
' </defaultDocument>',
' <directoryBrowse enabled="false" />',
' </system.webServer>',
'</configuration>',
)
)
);
}
/**
* Create storage web.config file
*
* @param string $path Path to file
* @return boolean
*/
public static function storage( $path ) {
return Ai1wm_File::create(
$path,
implode(
PHP_EOL,
array(
'<?xml version="1.0" encoding="utf-8"?>',
'<configuration>',
' <system.webServer>',
' <security>',
' <authorization>',
' <deny users="*" />',
' </authorization>',
' </security>',
' <requestFiltering>',
' <fileExtensions allowUnlisted="false">',
' <add fileExtension=".log" allowed="true" />',
' </fileExtensions>',
' </requestFiltering>',
' <staticContent>',
' <mimeMap fileExtension=".log" mimeType="text/plain" />',
' </staticContent>',
' <defaultDocument>',
' <files>',
' <add value="index.php" />',
' </files>',
' </defaultDocument>',
' <directoryBrowse enabled="false" />',
' </system.webServer>',
'</configuration>',
)
)
);
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_File {
/**
* Create a file with content
*
* @param string $path Path to the file
* @param string $content Content of the file
* @return boolean
*/
public static function create( $path, $content ) {
if ( ! @file_exists( $path ) ) {
if ( ! @is_writable( dirname( $path ) ) ) {
return false;
}
if ( ! @touch( $path ) ) {
return false;
}
} elseif ( ! @is_writable( $path ) ) {
return false;
}
// No changes were added
if ( function_exists( 'md5_file' ) ) {
if ( @md5_file( $path ) === md5( $content ) ) {
return true;
}
}
$is_written = false;
if ( ( $handle = @fopen( $path, 'w' ) ) !== false ) {
if ( @fwrite( $handle, $content ) !== false ) {
$is_written = true;
}
@fclose( $handle );
}
return $is_written;
}
/**
* Create a file with marker and content
*
* @param string $path Path to the file
* @param string $marker Name of the marker
* @param string $content Content of the file
* @return boolean
*/
public static function insert_with_markers( $path, $marker, $content ) {
return @insert_with_markers( $path, $marker, $content );
}
/**
* Delete a file by path
*
* @param string $path Path to the file
* @return boolean
*/
public static function delete( $path ) {
if ( ! @file_exists( $path ) ) {
return false;
}
return @unlink( $path );
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Recursive_Exclude_Filter extends RecursiveFilterIterator {
protected $exclude = array();
public function __construct( RecursiveIterator $iterator, $exclude = array() ) {
parent::__construct( $iterator );
if ( is_array( $exclude ) ) {
foreach ( $exclude as $path ) {
$this->exclude[] = ai1wm_replace_forward_slash_with_directory_separator( $path );
}
}
}
#[\ReturnTypeWillChange]
public function accept() {
if ( in_array( ai1wm_replace_forward_slash_with_directory_separator( $this->getInnerIterator()->getSubPathname() ), $this->exclude ) ) {
return false;
}
if ( in_array( ai1wm_replace_forward_slash_with_directory_separator( $this->getInnerIterator()->getPathname() ), $this->exclude ) ) {
return false;
}
if ( in_array( ai1wm_replace_forward_slash_with_directory_separator( $this->getInnerIterator()->getPath() ), $this->exclude ) ) {
return false;
}
if ( strpos( $this->getInnerIterator()->getSubPathname(), "\n" ) !== false ) {
return false;
}
if ( strpos( $this->getInnerIterator()->getSubPathname(), "\r" ) !== false ) {
return false;
}
return true;
}
#[\ReturnTypeWillChange]
public function getChildren() {
return new self( $this->getInnerIterator()->getChildren(), $this->exclude );
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Recursive_Extension_Filter extends RecursiveFilterIterator {
protected $include = array();
public function __construct( RecursiveIterator $iterator, $include = array() ) {
parent::__construct( $iterator );
if ( is_array( $include ) ) {
$this->include = $include;
}
}
#[\ReturnTypeWillChange]
public function accept() {
if ( $this->getInnerIterator()->isFile() ) {
if ( ! in_array( pathinfo( $this->getInnerIterator()->getFilename(), PATHINFO_EXTENSION ), $this->include ) ) {
return false;
}
}
return true;
}
#[\ReturnTypeWillChange]
public function getChildren() {
return new self( $this->getInnerIterator()->getChildren(), $this->include );
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Recursive_Directory_Iterator extends RecursiveDirectoryIterator {
public function __construct( $path ) {
parent::__construct( $path );
// Skip current and parent directory
$this->skipdots();
}
#[\ReturnTypeWillChange]
public function rewind() {
parent::rewind();
// Skip current and parent directory
$this->skipdots();
}
#[\ReturnTypeWillChange]
public function next() {
parent::next();
// Skip current and parent directory
$this->skipdots();
}
/**
* Returns whether current entry is a directory and not '.' or '..'
*
* Explicitly set allow links flag, because RecursiveDirectoryIterator::FOLLOW_SYMLINKS
* is not supported by <= PHP 5.3.0
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function hasChildren( $allow_links = true ) {
return parent::hasChildren( $allow_links );
}
protected function skipdots() {
while ( $this->isDot() ) {
parent::next();
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright (C) 2014-2025 ServMask Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution: This code is part of the All-in-One WP Migration plugin, developed by
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
class Ai1wm_Recursive_Iterator_Iterator extends RecursiveIteratorIterator {
}