PluginProbe ʕ •ᴥ•ʔ
All-in-One WP Migration and Backup / 7.102
All-in-One WP Migration and Backup v7.102
7.106 trunk 7.100 7.101 7.102 7.103 7.104 7.105 7.97 7.98 7.99
all-in-one-wp-migration / lib / vendor / servmask / archiver / class-ai1wm-compressor.php
all-in-one-wp-migration / lib / vendor / servmask / archiver Last commit date
class-ai1wm-archiver.php 4 months ago class-ai1wm-compressor.php 4 months ago class-ai1wm-extractor.php 4 months ago
class-ai1wm-compressor.php
247 lines
1 <?php
2 /**
3 * Copyright (C) 2014-2025 ServMask Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Attribution: This code is part of the All-in-One WP Migration plugin, developed by
19 *
20 * ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
21 * ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
22 * ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
23 * ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
24 * ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
25 * ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
26 */
27
28 if ( ! defined( 'ABSPATH' ) ) {
29 die( 'Kangaroos cannot jump here' );
30 }
31
32 class Ai1wm_Compressor extends Ai1wm_Archiver {
33
34 /**
35 * Overloaded constructor that opens the passed file for writing
36 *
37 * @param string $file_name File to use as archive
38 * @param string $file_password File password string
39 * @param string $file_compression File compression type
40 */
41 public function __construct( $file_name, $file_password = null, $file_compression = null ) {
42 // Call parent, to initialize variables
43 parent::__construct( $file_name, $file_password, $file_compression, true );
44 }
45
46 /**
47 * Add a file to the archive
48 *
49 * @param string $file_name File to add to the archive
50 * @param string $new_file_name Write the file with a different name
51 * @param int $file_bytes_read Amount of the bytes we read
52 * @param int $file_bytes_offset File bytes offset
53 * @param int $file_bytes_written Amount of the bytes we wrote
54 *
55 * @throws \Ai1wm_Not_Seekable_Exception
56 * @throws \Ai1wm_Not_Writable_Exception
57 * @throws \Ai1wm_Quota_Exceeded_Exception
58 *
59 * @return bool
60 */
61 public function add_file( $file_name, $new_file_name = '', &$file_bytes_read = 0, &$file_bytes_offset = 0, &$file_bytes_written = 0 ) {
62 // Replace forward slash with current directory separator in file name
63 $file_name = ai1wm_replace_forward_slash_with_directory_separator( $file_name );
64
65 // Escape Windows directory separator in file name
66 $file_name = ai1wm_escape_windows_directory_separator( $file_name );
67
68 // Flag to hold if file data has been processed
69 $completed = true;
70
71 // Start time
72 $start = microtime( true );
73
74 // Open the file for reading in binary mode (fopen may return null for quarantined files)
75 if ( ( $file_handle = @fopen( $file_name, 'rb' ) ) ) {
76
77 // Get header block
78 if ( ( $block = $this->get_file_block( $file_name, $new_file_name ) ) ) {
79
80 // Write header block
81 if ( $file_bytes_offset === 0 ) {
82 if ( ( $file_bytes = @fwrite( $this->file_handle, $block ) ) !== false ) {
83 if ( strlen( $block ) !== $file_bytes ) {
84 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 ) );
85 }
86 } else {
87 throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write header to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
88 }
89 }
90
91 // Set file offset
92 if ( @fseek( $file_handle, $file_bytes_offset, SEEK_SET ) !== -1 ) {
93 $file_bytes_read = 0;
94
95 // Read the file in 512KB chunks
96 while ( false === @feof( $file_handle ) ) {
97 if ( ( $file_content = @fread( $file_handle, 512000 ) ) !== false ) {
98
99 // Add the amount of bytes we read
100 $file_bytes_read += strlen( $file_content );
101
102 // Do not encrypt or compress config files
103 if ( ! in_array( $new_file_name, ai1wm_config_filters() ) ) {
104
105 // Add chunk data compression
106 if ( ! empty( $this->file_compression ) ) {
107 switch ( $this->file_compression ) {
108 case 'gzip':
109 $file_content = gzcompress( $file_content, 9 );
110 break;
111
112 case 'bzip2':
113 $file_content = bzcompress( $file_content, 9 );
114 break;
115 }
116 }
117
118 // Add chunk data encryption
119 if ( ! empty( $this->file_password ) ) {
120 $file_content = ai1wm_encrypt_string( $file_content, $this->file_password );
121 }
122
123 // Add variable length chunk size before chunk data
124 if ( ! empty( $this->file_compression ) ) {
125 $file_content = pack( 'N', strlen( $file_content ) ) . $file_content;
126 }
127 }
128
129 if ( ( $file_bytes = @fwrite( $this->file_handle, $file_content ) ) !== false ) {
130 if ( strlen( $file_content ) !== $file_bytes ) {
131 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 ) );
132 }
133 } else {
134 throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write content to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
135 }
136
137 // Add the amount of bytes we wrote
138 $file_bytes_written += $file_bytes;
139 }
140
141 // Time elapsed
142 if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
143 if ( ( microtime( true ) - $start ) > $timeout ) {
144 $completed = false;
145 break;
146 }
147 }
148 }
149
150 // Add the amount of bytes we read
151 $file_bytes_offset += $file_bytes_read;
152 }
153
154 // Write file size to file header
155 if ( ( $block = $this->get_file_size_block( $file_bytes_written ) ) ) {
156
157 // Seek to beginning of file size
158 if ( @fseek( $this->file_handle, - $file_bytes_written - 4096 - 12 - 14, SEEK_CUR ) === -1 ) {
159 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' ) );
160 }
161
162 // Write file size to file header
163 if ( ( $file_bytes = @fwrite( $this->file_handle, $block ) ) !== false ) {
164 if ( strlen( $block ) !== $file_bytes ) {
165 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 ) );
166 }
167 } else {
168 throw new Ai1wm_Not_Writable_Exception( sprintf( __( 'Could not write size to file. File: %s', 'all-in-one-wp-migration' ), $this->file_name ) );
169 }
170
171 // Seek to end of file content
172 if ( @fseek( $this->file_handle, + $file_bytes_written + 4096 + 12, SEEK_CUR ) === -1 ) {
173 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' ) );
174 }
175 }
176 }
177
178 // Close the handle
179 @fclose( $file_handle );
180 }
181
182 return $completed;
183 }
184
185 /**
186 * Generate binary block header for a file
187 *
188 * @param string $file_name Filename to generate block header for
189 * @param string $new_file_name Write the file with a different name
190 *
191 * @return string
192 */
193 private function get_file_block( $file_name, $new_file_name = '' ) {
194 $block = '';
195
196 // Get stats about the file
197 if ( ( $stat = @stat( $file_name ) ) !== false ) {
198
199 // Filename of the file we are accessing
200 if ( empty( $new_file_name ) ) {
201 $name = ai1wm_basename( $file_name );
202 } else {
203 $name = ai1wm_basename( $new_file_name );
204 }
205
206 // Size in bytes of the file
207 $size = $stat['size'];
208
209 // Last time the file was modified
210 $date = $stat['mtime'];
211
212 // Replace current directory separator with backward slash in file path
213 if ( empty( $new_file_name ) ) {
214 $path = ai1wm_replace_directory_separator_with_forward_slash( ai1wm_dirname( $file_name ) );
215 } else {
216 $path = ai1wm_replace_directory_separator_with_forward_slash( ai1wm_dirname( $new_file_name ) );
217 }
218
219 // Concatenate block format parts
220 $format = implode( '', $this->block_format );
221
222 // Pack file data into binary string
223 $block = pack( $format, $name, $size, $date, $path );
224 }
225
226 return $block;
227 }
228
229 /**
230 * Generate file size binary block header for a file
231 *
232 * @param int $file_size File size
233 *
234 * @return string
235 */
236 public function get_file_size_block( $file_size ) {
237 $block = '';
238
239 // Pack file data into binary string
240 if ( isset( $this->block_format[1] ) ) {
241 $block = pack( $this->block_format[1], $file_size );
242 }
243
244 return $block;
245 }
246 }
247