.
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
class Ai1wm_Compressor extends Ai1wm_Archiver {
/**
* Overloaded constructor that opens the passed file for writing
*
* @param string $file_name File to use as archive
*/
public function __construct( $file_name ) {
// Call parent, to initialize variables
parent::__construct( $file_name, 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_written File written (in bytes)
* @param int $file_offset File offset (in bytes)
* @param int $timeout Process timeout (in seconds)
*
* @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_written = 0, &$file_offset = 0, $timeout = 0 ) {
$file_written = 0;
// Replace forward slash with current directory separator in file name
$file_name = $this->replace_forward_slash_with_directory_separator( $file_name );
// Escape Windows directory separator in file name
$file_name = $this->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
if ( ( $file_handle = @fopen( $file_name, 'rb' ) ) !== false ) {
$file_bytes = 0;
// Get header block
if ( ( $block = $this->get_file_block( $file_name, $new_file_name ) ) ) {
// Write header block
if ( $file_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. Unable to write header to file. File: %s', $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( 'Unable to write header to file. File: %s', $this->file_name ) );
}
}
// Set file offset
if ( @fseek( $file_handle, $file_offset, SEEK_SET ) !== -1 ) {
// Read the file in 512KB chunks
while ( false === @feof( $file_handle ) ) {
// Read the file in chunks of 512KB
if ( ( $file_content = @fread( $file_handle, 512000 ) ) !== false ) {
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. Unable to write content to file. File: %s', $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( 'Unable to write content to file. File: %s', $this->file_name ) );
}
// Set file written
$file_written += $file_bytes;
}
// Time elapsed
if ( $timeout ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break;
}
}
}
}
// Set file offset
$file_offset += $file_written;
// Write file size to file header
if ( ( $block = $this->get_file_size_block( $file_offset ) ) ) {
// Seek to beginning of file size
if ( @fseek( $this->file_handle, - $file_offset - 4096 - 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. ' .
'Technical details'
);
}
// Write file size to file header
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. Unable to write size to file. File: %s', $this->file_name ) );
}
} else {
throw new Ai1wm_Not_Writable_Exception( sprintf( 'Unable to write size to file. File: %s', $this->file_name ) );
}
// Seek to end of file content
if ( @fseek( $this->file_handle, + $file_offset + 4096 + 12, 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. ' .
'Technical details'
);
}
}
}
// 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
*
* @return mixed
*/
private function get_file_block( $file_name, $new_file_name = '' ) {
$block = false;
// Get stats about the file
if ( ( $stat = @stat( $file_name ) ) !== false ) {
// Get path details
if ( empty( $new_file_name ) ) {
$pathinfo = pathinfo( $file_name );
} else {
$pathinfo = pathinfo( $new_file_name );
}
// Filename of the file we are accessing
$name = $pathinfo['basename'];
// 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
$path = $this->replace_directory_separator_with_forward_slash( $pathinfo['dirname'] );
// Concatenate block format parts
$format = implode( '', $this->block_format );
// Pack file data into binary string
$block = pack( $format, $name, $size, $date, $path );
}
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 = false;
// Pack file data into binary string
if ( isset( $this->block_format[1] ) ) {
$block = pack( $this->block_format[1], $file_size );
}
return $block;
}
}