/admin/libs/archive.php
PHP | 590 lines | 449 code | 107 blank | 34 comment | 147 complexity | c8e4ef7d734cceed3afcbd5f44c691d5 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, LGPL-2.1
- <?
- ////////////////////////////////////////////////////////////////////////////////
- // Copyright (C) ReloadCMS Development Team //
- // http://reloadcms.com //
- // This product released under GNU General Public License v2 //
- ////////////////////////////////////////////////////////////////////////////////
- class archiveTar
- {
- var $archive_name = '';
- var $tmp_file = 0;
- var $file_pos = 0;
- var $isGzipped = true;
- var $errors = array();
- var $files = array();
-
- function archiveTar(){
- if (!isset($this->errors)) $this->errors = array();
- }
-
- /*
- * Create archive from array filenames or directories, example:
- * $backup = new archiveTar();
- * $backup->archive_name = './content.tgz';
- * $backup->createArchive(array('./config','./content'));
- */
-
- function createArchive($file_list){
- $result = false;
-
- if (file_exists($this->archive_name) && is_file($this->archive_name)) $newArchive = false;
- else $newArchive = true;
- if ($newArchive){
- if (!$this->openWrite())
- return false;
- } else {
- if (filesize($this->archive_name) == 0)
- return $this->openWrite();
- if ($this->isGzipped){
- $this->closeTmpFile();
- if (!@rename($this->archive_name, $this->archive_name.'.tmp')){
- $this->errors[] = __('Cannot rename').' '.$this->archive_name.__(' to ').$this->archive_name.'.tmp';
- return false;
- }
- $tmpArchive = @gzopen($this->archive_name.'.tmp', 'rb');
- if (!$tmpArchive){
- $this->errors[] = $this->archive_name.'.tmp '.__('is not readable');
- @rename($this->archive_name.'.tmp', $this->archive_name);
- return false;
- }
- if (!$this->openWrite()){
- @rename($this->archive_name.'.tmp', $this->archive_name);
- return false;
- }
- $buffer = @gzread($tmpArchive, 512);
- if (!@gzeof($tmpArchive)){
- do {
- $binaryData = pack('a512', $buffer);
- $this->writeBlock($binaryData);
- $buffer = @gzread($tmpArchive, 512);
- }
- while (!@gzeof($tmpArchive));
- }
- @gzclose($tmpArchive);
- @unlink($this->archive_name.'.tmp');
- } else {
- $this->tmp_file = @fopen($this->archive_name, 'r+b');
- if (!$this->tmp_file) return false;
- }
- }
-
- if (isset($file_list) && is_array($file_list)) {
- if (count($file_list)>0)
- $result = $this->packFileArray($file_list);
- } else $this->errors[] = __('No file').__(' to ').__('Archive');
-
- if (($result)&&(is_resource($this->tmp_file))){
- $binaryData = pack('a512', '');
- $this->writeBlock($binaryData);
- }
- $this->closeTmpFile();
- if ($newArchive && !$result){
- $this->closeTmpFile();
- @unlink($this->archive_name);
- }
- return $result;
- }
- /*
- * Restore archive including the path, example:
- * $Archive = new archiveTar();
- * $Archive->archive_name = './content.tgz';
- * $Archive->restoreArchive('./');
- */
- function restoreArchive($path){
-
- $fileName = $this->archive_name;
-
- if (!$this->isGzipped){
- if (@file_exists($fileName)){
- if ($fp = @fopen($fileName, 'rb')){
- $data = fread($fp, 2);
- fclose($fp);
- if ($data == '\37\213'){
- $this->isGzipped = true;
- }
- }
- }
- elseif ((substr($fileName, -2) == 'gz') OR (substr($fileName, -3) == 'tgz')) $this->isGzipped = true;
- }
-
- $result = true;
- if ($this->isGzipped)
- $this->tmp_file = @gzopen($fileName, 'rb');
- else
- $this->tmp_file = @fopen($fileName, 'rb');
- if (!$this->tmp_file){
- $this->errors[] = $fileName.' '.__('is not readable');
- return false;
- }
-
- $result = $this->unpackFileArray($path);
- $this->closeTmpFile();
- return $result;
- }
- /* Show errors when pack/unpack
- * Example:
- * $Archive = new archiveTar();
- * //pack or unpack;
- * echo $Archive->showErrors($Archive->archive_name);
- */
- function showErrors ($message = '') {
- $Errors = $this->errors;
- if(count($Errors)>0) {
- if (!empty($message)) $message = ' ('.$message.')';
- $message = __('Error occurred').$message.': <br/>';
- foreach ($Errors as $value)
- $message .= $value.'<br/>';
- return $message;
- } else return '';
-
- }
-
- function packFileArray($file_array){
- $result = true;
- if (!$this->tmp_file){
- $this->errors[] = __('Invalid file descriptor');
- return false;
- }
- if (!is_array($file_array) || count($file_array)<=0)
- return true;
- for ($i = 0; $i<count($file_array); $i++){
- $filename = $file_array[$i];
- if ($filename == $this->archive_name)
- continue;
- if (strlen($filename)<=0)
- continue;
- if (!file_exists($filename)){
- $this->errors[] = __('No file').' '.$filename;
- continue;
- }
-
- if (!$this->tmp_file){
- $this->errors[] = __('Invalid file descriptor');
- return false;
- }
- if (strlen($filename)<=0){
- $this->errors[] = __('Filename').' '.__('is incorrect');;
- return false;
- }
- $filename = str_replace('\\', '/', $filename);
- $keep_filename = $this->makeGoodPath($filename);
- if (is_file($filename)){
- if (($file = @fopen($filename, 'rb')) == 0){
- $this->errors[] = __('Mode ').__('is incorrect');
- }
-
- if(($this->file_pos == 0)){
- if(!$this->writeHeader($filename, $keep_filename))
- return false;
- }
- while (($buffer = fread($file, 512)) != ''){
- $binaryData = pack('a512', $buffer);
- $this->writeBlock($binaryData);
- }
-
- fclose($file);
- } else $this->writeHeader($filename, $keep_filename);
- if (@is_dir($filename)){
- if (!($handle = opendir($filename))){
- $this->errors[] = __('Error').': '.__('Directory ').$filename.__('is not readable');
- continue;
- }
- while (false !== ($dir = readdir($handle))){
- if ($dir!='.' && $dir!='..'){
- $file_array_tmp = array();
- if ($filename != '.')
- $file_array_tmp[] = $filename.'/'.$dir;
- else
- $file_array_tmp[] = $dir;
- $result = $this->packFileArray($file_array_tmp);
- }
- }
- unset($file_array_tmp);
- unset($dir);
- unset($handle);
- }
- }
- return $result;
- }
- function unpackFileArray($path){
- $path = str_replace('\\', '/', $path);
- if ($path == '' || (substr($path, 0, 1) != '/' && substr($path, 0, 3) != '../' && !strpos($path, ':')))
- $path = './'.$path;
-
- clearstatcache();
- while (strlen($binaryData = $this->readBlock()) != 0){
- if (!$this->readHeader($binaryData, $header))
- return false;
- if ($header['filename'] == '')
- continue;
-
- if ($header['typeflag'] == 'L'){ //reading long header
- $filename = '';
- $decr = floor($header['size']/512);
-
- for ($i = 0; $i < $decr; $i++){
- $content = $this->readBlock();
- $filename .= $content;
- }
-
- if (($laspiece = $header['size'] % 512) != 0){
- $content = $this->readBlock();
- $filename .= substr($content, 0, $laspiece);
- }
- $binaryData = $this->readBlock();
- if (!$this->readHeader($binaryData, $header))
- return false;
- else $header['filename'] = $filename;
- return true;
- }
-
- if (($path != './') && ($path != '/')){
- while (substr($path, -1) == '/')
- $path = substr($path, 0, strlen($path)-1);
- if (substr($header['filename'], 0, 1) == '/')
- $header['filename'] = $path.$header['filename'];
- else
- $header['filename'] = $path.'/'.$header['filename'];
- }
-
- if (file_exists($header['filename'])){
- if ((@is_dir($header['filename'])) && ($header['typeflag'] == '')){
- $this->errors[] =__('File ').$header['filename'].__(' already exists').__(' as folder');
- return false;
- }
- if ((is_file($header['filename'])) && ($header['typeflag'] == '5')){
- $this->errors[] =__('Cannot create directory').'. '.__('File ').$header['filename'].__(' already exists');
- return false;
- }
- if (!is_writeable($header['filename'])){
- $this->errors[] = __('Cannot write to file').'. '.__('File ').$header['filename'].__(' already exists');
- return false;
- }
- }
-
- elseif (($this->dirCheck(($header['typeflag'] == '5' ? $header['filename'] : dirname($header['filename'])))) != 1){
- $this->errors[] = __('Cannot create directory').' '.__(' for ').$header['filename'];
- return false;
- }
- if ($header['typeflag'] == '5'){
- if (!@file_exists($header['filename'])) {
- if (!@mkdir($header['filename'], 0777)) {
-
- $this->errors[] = __('Cannot create directory').' '.$header['filename'];
- return false;
- }
- }
- } else {
- if (($destination = @fopen($header['filename'], 'wb')) == 0)
- {
- $this->errors[] = __('Cannot write to file').' '.$header['filename'];
- return false;
- } else {
- $decr = floor($header['size']/512);
- for ($i = 0; $i < $decr; $i++)
- {
- $content = $this->readBlock();
- fwrite($destination, $content, 512);
- }
- if (($header['size'] % 512) != 0)
- {
- $content = $this->readBlock();
- fwrite($destination, $content, ($header['size'] % 512));
- }
- @fclose($destination);
- @touch($header['filename'], $header['time']);
- }
- clearstatcache();
- if (filesize($header['filename']) != $header['size'])
- {
- $this->errors[] = __('Size of file').' '.$header['filename'].' '.__('is incorrect');
- return false;
- }
- }
- if (($file_dir = dirname($header['filename'])) == $header['filename'])
- $file_dir = '';
- if ((substr($header['filename'], 0, 1) == '/') && ($file_dir == ''))
- $file_dir = '/';
- $this->dirs[] = $file_dir;
- $this->files[] = $header['filename'];
-
- }
- return true;
- }
-
- /*
- * Check if a directory exists and create it (including parent dirs) if not.
- */
- function dirCheck($dir){
- $parent_dir = dirname($dir);
- if ((@is_dir($dir)) or ($dir == ''))
- return true;
- if (($parent_dir != $dir) and ($parent_dir != '') and (!$this->dirCheck($parent_dir)))
- return false;
- if (!@mkdir($dir, 0777)){
- $this->errors[] = __('Cannot create directory').' '.$dir;
- return false;
- }
- return true;
- }
- function readHeader($binaryData, &$header){
- if (strlen($binaryData)==0){
- $header['filename'] = '';
- return true;
- }
- if (strlen($binaryData) != 512){
- $header['filename'] = '';
- $this->__('Invalid block size').': '.strlen($binaryData);
- return false;
- }
- $checksum = 0;
- for ($i = 0; $i < 148; $i++)
- $checksum+=ord(substr($binaryData, $i, 1));
- for ($i = 148; $i < 156; $i++)
- $checksum += ord(' ');
- for ($i = 156; $i < 512; $i++)
- $checksum+=ord(substr($binaryData, $i, 1));
- $unpack_data = unpack('a100filename/a8mode/a8user_id/a8group_id/a12size/a12time/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor', $binaryData);
- $header['checksum'] = OctDec(trim($unpack_data['checksum']));
- if ($header['checksum'] != $checksum){
- $header['filename'] = '';
- if (($checksum == 256) && ($header['checksum'] == 0)) return true;
- $this->errors[] = __('Error checksum for file ').$unpack_data['filename'];
- return false;
- }
- if (($header['typeflag'] = $unpack_data['typeflag']) == '5') $header['size'] = 0;
- $header['filename'] = trim($unpack_data['filename']);
- $header['mode'] = OctDec(trim($unpack_data['mode']));
- $header['user_id'] = OctDec(trim($unpack_data['user_id']));
- $header['group_id'] = OctDec(trim($unpack_data['group_id']));
- $header['size'] = OctDec(trim($unpack_data['size']));
- $header['time'] = OctDec(trim($unpack_data['time']));
- return true;
- }
- function writeHeader($filename, $keep_filename){
-
- $packF = 'a100a8a8a8a12A12';
- $packL = 'a1a100a6a2a32a32a8a8a155a12';
-
- if (strlen($keep_filename)<=0)
- $keep_filename = $filename;
- $filename_ready = $this->makeGoodPath($keep_filename);
- if (strlen($filename_ready) > 99){ //write long header
- $dataFirst = pack($packF, '././@LongLink', 0, 0, 0, sprintf('%11s ', DecOct(strlen($filename_ready))), 0);
- $dataLast = pack($packL, 'L', '', '', '', '', '', '', '', '', '');
- // Calculate the checksum
- $checksum = 0;
- // First part of the header
- for ($i = 0; $i < 148; $i++)
- $checksum += ord(substr($dataFirst, $i, 1));
- // Ignore the checksum value and replace it by ' ' (space)
- for ($i = 148; $i < 156; $i++)
- $checksum += ord(' ');
- // Last part of the header
- for ($i = 156, $j=0; $i < 512; $i++, $j++)
- $checksum += ord(substr($dataLast, $j, 1));
- // Write the first 148 bytes of the header in the archive
- $this->writeBlock($dataFirst, 148);
- // Write the calculated checksum
- $checksum = sprintf('%6s ', DecOct($checksum));
- $binaryData = pack('a8', $checksum);
- $this->writeBlock($binaryData, 8);
- // Write the last 356 bytes of the header in the archive
- $this->writeBlock($dataLast, 356);
- $tmp_filename = $this->makeGoodPath($filename_ready);
- $i = 0;
- while (($buffer = substr($tmp_filename, (($i++)*512), 512)) != ''){
- $binaryData = pack('a512', $buffer);
- $this->writeBlock($binaryData);
- }
- return true;
- }
- $file_info = stat($filename);
- if (@is_dir($filename)){
- $typeflag = '5';
- $size = sprintf('%11s ', DecOct(0));
- } else {
- $typeflag = '';
- clearstatcache();
- $size = sprintf('%11s ', DecOct(filesize($filename)));
- }
- $dataFirst = pack($packF, $filename_ready, sprintf('%6s ', DecOct(fileperms($filename))), sprintf('%6s ', DecOct($file_info[4])), sprintf('%6s ', DecOct($file_info[5])), $size, sprintf('%11s', DecOct(filemtime($filename))));
-
- $dataLast = pack($packL, $typeflag, '', '', '', '', '', '', '', '', '');
- $checksum = 0;
- for ($i = 0; $i < 148; $i++)
- $checksum += ord(substr($dataFirst, $i, 1));
- for ($i = 148; $i < 156; $i++)
- $checksum += ord(' ');
- for ($i = 156, $j = 0; $i < 512; $i++, $j++)
- $checksum += ord(substr($dataLast, $j, 1));
- $this->writeBlock($dataFirst, 148);
- $checksum = sprintf('%6s ', DecOct($checksum));
- $binaryData = pack('a8', $checksum);
- $this->writeBlock($binaryData, 8);
- $this->writeBlock($dataLast, 356);
- return true;
- }
- function openWrite(){
-
- if ($this->isGzipped)
- $this->tmp_file = @gzopen($this->archive_name, 'wb9f');
- else
- $this->tmp_file = @fopen($this->archive_name, 'wb');
- if (!($this->tmp_file)){
- $this->errors[] = __('Cannot write to file').' '.$this->archive_name;
- return false;
- }
- return true;
- }
- function readBlock(){
- if (is_resource($this->tmp_file)){
- if ($this->isGzipped)
- $block = @gzread($this->tmp_file, 512);
- else
- $block = @fread($this->tmp_file, 512);
- } else $block = '';
- return $block;
- }
- function writeBlock($data, $length = 0){
- if (is_resource($this->tmp_file)){
-
- if ($length === 0){
- if ($this->isGzipped)
- @gzputs($this->tmp_file, $data);
- else
- @fputs($this->tmp_file, $data);
- } else {
- if ($this->isGzipped)
- @gzputs($this->tmp_file, $data, $length);
- else
- @fputs($this->tmp_file, $data, $length);
- }
- }
- }
- function closeTmpFile(){
-
- if (is_resource($this->tmp_file)){
- if ($this->isGzipped)
- @gzclose($this->tmp_file);
- else
- @fclose($this->tmp_file);
- $this->tmp_file = 0;
- }
- }
- function makeGoodPath($path){
- if (strlen($path)>0){
- $path = str_replace('\\', '/', $path);
- $partPath = explode('/', $path);
- $els = count($partPath)-1;
- // Study directories from last to first
- for ($i = $els; $i>=0; $i--){
- // Look for current path
- if ($partPath[$i] == '.'){
- // Ignore this directory
- // Should be the first $i=0, but no check is done
- }
- elseif ($partPath[$i] == '..'){
- // Ignore it and ignore the $i-1
- $i--;
- }
- elseif (($partPath[$i] == '') and ($i!=$els) and ($i!=0)){
- // Ignore only the double '//' in path,
- // but not the first and last /
- } else
- $result = $partPath[$i].($i!=$els ? '/'.$result : '');
- }
- } else $result = '';
-
- return $result;
- }
- }
- ?>