<?php
include_once($TOOLS_PATH.'\func.php');

class Archive {
	var $path_tar = '';
	//Required files source path for archiving. Archive file source path for extracting.
	var $path_src = '';
	//Created archive's destination path for archiving. Destination path for extracting.
	var $path_dest = '';
	//File name of archive that will be created or extracted.
	var $archive_file_name = '';
	//Array of files (or/and folders) (with/without path) that will be archived or array of files that will be delete before extracting.
	var $files_names = array ();
	//Array of folders' names that will not be included into archive or array of folders' names that will not be deleted before extracting.
	var $ignored_folders_names = array ();
	//Array of files' names that will not be included into archive or array of files' names that will not be deleted before extracting.
	var $ignored_files_names = array ();
	//Array of file types that will be included into archive or array of file types that will be deleted before extracting.
	var $unignored_file_types = array ();
	//Pattern (use in ereg()) of files' names that will be included into archive or pattern of files' names that will be deleted before extracting.
	var $unignored_file_name_pattern = '';
	//Flag that specify operation: archiving or extracting.
	var $extract = false;
	var $extract_files = array();
	//Flag that specify operation of deleting archive after its extracting.
	var $remove_archive = false;
	//Flag that specify operation of deleting files after its archiving from source path or deleting required files from destination folder before extracting there.
	var $remove_files = false;
	//Flag that specify including/excluding directory structure into archive.
	var $archive_with_path = false;
	//Specify path from which directory structure will be included into archive.
	var $root_path = '';
	//Flag that specify including only files into archive and no directories.
	var $only_files = false;
	//Flag that specify including only directories into archive and no files.
	var $only_folders = false;
	//Array of all errors.
	var $errors = array ();
	//Last error.
	var $last_error = '';
	
	//Constructor
	function Archive($path_src, $path_dest, $arc_filename, $extract){
		$this->path_src = $path_src;
		$this->path_dest = $path_dest;
		$this->archive_file_name = $arc_filename;
		$this->extract = $extract;
	}
	
	function setSourcePath($path){
		if (file_exists($path)){
			$this->path_src = $path;
			return true;
		}
		else
			return $this->setError("Source Path '$path' doesn't exist.");
	}
	
	function setDestinationPath($path){
		if (file_exists ($path)){
			$this->path_dest = $path;
			return true;
		}
		else
			return $this->setError("Destination Path '$path' doesn't exist.");
	}
	
	function setTarPath($path){
		//if (file_exists($path)){
			$this->path_tar = $path;
			return true;
		//}
		//else
		//	return $this->setError("Tar Path '$path' doesn't exist.");
	}
	
	function setArchiveFileName($file_name){
		if (is_string($file_name) && ereg('([0-z])', $file_name)){
			$this->archive_file_name = $file_name;
			return true;
		}
		else
			return $this->setError("File name '$file_name' for archive is not invalid.");
	}
	
	function setFilesNames($files_names){
		if (is_array($files_names)){
			$this->files_names = $files_names;
			return true;
		}
		else
			return $this->setError("Specify the array of files' names that should be included into the archive.");
	}
	
	function setExtractFiles($files_paths){
		if (is_array($files_paths)){
			$this->extract_files = $files_paths;
			return true;
		}
		else return $this->setError("Specify the array of files' paths that should be extracted from the archive.");
	}
	
	function setIgnoredFoldersNames($folders_names){
		if (is_array($folders_names)){
			$this->ignored_folders_names = $folders_names;
			return true;
		}
		else
			return $this->setError("Specify the array of folders' names that should not be included into the archive.");
	}
	
	function setIgnoredFilesNames($files_names){
		if (is_array($files_names)){
			$this->ignored_files_names = $files_names;
			return true;
		}
		else
			return $this->setError("Specify the array of files' names that should not be included in the archive.");
	}
	
	function setUnignoredFileTypes($file_types){
		if (is_array($file_types)){
			$this->unignored_file_types = $file_types;
			return true;
		}
		else
			return $this->setError("Specify the array of file types that should be included in the archive.");
	}
	
	function setUnignoredFileNamePattern($pattern){
		$this->unignored_file_name_pattern = $pattern;
		return true;
	}
	
	function setExtractFlag($flag){
		$this->extract = $flag;
		return true;
	}
	
	function setRemoveArchiveFlag($flag){
		if ($flag){
			if ($this->extract){
				$this->remove_archive = $flag;
				return true;
			}
			else{
				return $this->setError("The 'extract' flag should be set to true to remove obsolete (superfluous) archive after extracting.");
			}
		}
		else{
			$this->remove_archive = $flag;
			return true;
		}
	}
	
	function setRemoveFilesFlag($flag){
		$this->remove_files = $flag;
		return true;
	}
	
	function setRootPath($path){
		if (strpos($this->path_src, $path) === 0 and strpos($this->path_dest, $path) === 0){
			$this->root_path = $path;
			return true;
		}
		else
			return $this->setError("Specify correct 'root path' value. Source path and destination path should start from root path (and include it). Example: root path = '/www/', source path = '/www/img/pic/', destination path = '/www/temp/'.");
	}
	
	function setArchiveWithPathFlag($flag){
		if ($flag){
			if ($this->extract)
				return $this->setError("The 'extract' flag should be set to false to create archive with path.");
			else{
				$this->archive_with_path = $flag;
				return true;
			}
		}
		else{
			$this->archive_with_path = $flag;
			return true;
		}
	}
	
	function setOnlyFilesFlag($flag){
		if ($flag){
			if ($this->only_folders)
				return $this->setError("The 'only folders' flag should be set to false to include into archive only files.");
			else{
				$this->only_files = $flag;
				return true;
			}
		}
		else{
			$this->only_files = $flag;
			return true;
		}
	}
	
	function setOnlyFoldersFlag($flag){
		if($flag){
			if ($this->only_files)
				return $this->setError("The 'only files' flag should be set to false to include into archive only folders.");
			else{
				$this->only_folders = $flag;
				return true;
			}
		}
		else{
			$this->only_folders = $flag;
			return true;
		}
	}
	
	function setError($error){
		$this->last_error = $error;
		$this->errors[] = $error;
		return false;
	}
	
	function createArchive(){
		if($this->extract)
			return $this->setError("'extract' flag was set to true. Can't create archive.");
		if (!$this->setDestinationPath($this->path_dest) || !$this->setSourcePath($this->path_src) || !$this->setArchiveFileName($this->archive_file_name))
			return false;
		if($this->archive_with_path){
			if (empty($this->root_path))
				return $this->setError("Specify 'root path' value from which should begin archiving with path.");
			if (empty($this->files_names)){
				$dir = opendir($this->path_src);
				if ($this->only_files){
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if(is_file($this->path_src.$file)){
							$this->files_names[$file] = substr($this->path_src, strlen($this->root_path)).$file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
									unset($this->files_names[$file]);
									continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
							
						}
					}
					if ($count == 2)
						$this->files_names[] = substr($this->path_src, strlen($this->root_path));
				}
				else if ($this->only_folders){
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if(is_dir($this->path_src.$file)){
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = substr($this->path_src, strlen($this->root_path)).$file;
						}
					}
					if ($count == 2)
						$this->files_names[] = substr($this->path_src, strlen($this->root_path));
				}
				else {
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if(is_file($this->path_src.$file)){
							$this->files_names[$file] = substr($this->path_src, strlen($this->root_path)).$file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
									unset($this->files_names[$file]);
									continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
						}
						else{
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = substr($this->path_src, strlen($this->root_path)).$file;
						}
					}
					if ($count == 2)
						$this->files_names[] = substr($this->path_src, strlen($this->root_path));
				}
			}
			else{
				foreach($this->files_names as $key => $value){
					if(file_exists($this->path_src.$value)){
						$this->files_names[$key] = substr($this->path_src, strlen($this->root_path)).$value;
					}
					else
						return $this->setError("File/folder '".$this->path_src.$value."' that you want to include into archive doesn't exist. Can't create archive.");
				}
			}
			chdir($this->root_path);
			$result = mysystem($this->path_tar.'tar czf '.substr($this->path_dest, strlen($this->root_path)).$this->archive_file_name.' '.implode(' ', $this->files_names));
			if (!empty($result))
				return $this->setError("Creating archive failed. System answer: <pre>".$result.'</pre>');
			if($this->remove_files){
				$result = mysystem('rm -rf '.implode(' ', $this->files_names));
				if (!empty($result))
					return $this->setError("Deleting files that was included into archive after archiving failed. System answer: <pre>".$result.'</pre>');
			}
		}
		else{
			if (empty($this->files_names)){
				$dir = opendir($this->path_src);
				if ($this->only_files){
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if(is_file($this->path_src.$file)){
							$this->files_names[$file] = $file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
								unset($this->files_names[$file]);
								continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
							
						}
					}
					if ($count == 2)
						return $this->setError("There are no files that match your requirements.");
				}
				else if ($this->only_folders){
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if(is_dir($this->path_src.$file)){
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = $file;
						}
					}
					if ($count == 2)
						return $this->setError("There are no folders that match your requirements.");
				}
				else {
					$count = 0;
					while($file = readdir($dir)){
						$count++;
						if($file == '.' || $file == '..') continue;
						if(is_file($this->path_src.$file)){
							$this->files_names[$file] = $file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
								unset($this->files_names[$file]);
								continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
						}
						else{
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = $file;
						}
					}
					if ($count == 2)
						return $this->setError("There are no files/folders that match your requirements.");
				}
			}
			else{
				foreach($this->files_names as $key => $value){
					if(file_exists($this->path_src.$value))
						$this->files_names[$key] = $value;
					else
						return $this->setError("File/folder '".$this->path_src.$value."' that you want to include into archive doesn't exist. Can't create archive.");
				}
			}
			chdir($this->path_src);
			$result = mysystem($this->path_tar.'tar czf '.$this->path_dest.$this->archive_file_name.' '.implode(' ', $this->files_names));
			if (!empty($result))
				return $this->setError("Creating archive failed. System answer: <pre>".$result.'</pre>');
			if($this->remove_files){
				$result = mysystem('rm -r '.implode(' ', $this->files_names));
				if (!empty($result))
					return $this->setError("Deleting files that was included into archive after archiving failed. System answer: <pre>".$result.'</pre>');
			}
		}
		return true;
	}
	
	function extractArchive(){
		if(!$this->extract)
			return $this->setError("'extract' flag was set to false. Can't extract archive.");
		if (!$this->setDestinationPath($this->path_dest) || !$this->setSourcePath($this->path_src) || !$this->setArchiveFileName($this->archive_file_name))
			return false;
		chdir($this->path_dest);
		if($this->remove_files){
			if(empty($this->files_names)){
				$dir = opendir($this->path_dest);
				if ($this->only_files){
					while($file = readdir($dir)){
						if(is_file($file)){
							$this->files_names[$file] = $file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
								unset($this->files_names[$file]);
								continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
							
						}
					}
				}
				else if ($this->only_folders){
					while($file = readdir($dir)){
						if(is_dir($file)){
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = $file;
						}
					}
				}
				else {
					while($file = readdir($dir)){
						if(is_file($file)){
							$this->files_names[$file] = $file;
							if(!empty($this->unignored_file_name_pattern) && !ereg($this->unignored_file_name_pattern, $file)){
								unset($this->files_names[$file]);
								continue;
							}
							if(in_array($file, $this->ignored_files_names)){
								unset($this->files_names[$file]);
								continue;
							}
							if(!empty($this->unignored_file_types) && !in_array(".".pathinfo($file, PATHINFO_EXTENSION), $this->unignored_file_types)){
								unset($this->files_names[$file]);
								continue;
							}
						}
						else{
							if(!in_array($file, $this->ignored_folders_names))
								$this->files_names[$file] = $file;
						}
					}
				}
				if (!empty($this->files_names)){
					$result = mysystem('rm -r '.implode(' ', $this->files_names));
					if (!empty($result))
						return $this->setError("Can't delete files that required for deleting before extracting. System answer: <pre>".$result.'</pre>');
				}
			}
			else{
				foreach($this->files_names as $value){
					if(file_exists($value)){
						$result = mysystem('rm -r '.$value);
						if(!empty($result))
							return $this->setError("Deleting file '".$this->path_dest.$value."' before extaction failed. System answer: <pre>".$result.'</pre>');
					}
				}
			}
		}
		$result = mysystem($this->path_tar.'tar --recursive-unlink -zpxf '.$this->path_src.$this->archive_file_name.(empty($this->extract_files) ? '' : ' '.implode(' ', $this->extract_files)));
		if(!empty($result))
			return $this->setError("Extracting archive '".$this->path_src.$this->archive_file_name."' failed. System answer: <pre>".$result.'</pre>');
		if ($this->remove_archive){
			$result = mysystem('rm -r '.$this->path_src.$this->archive_file_name);
			if(!empty($result))
				return $this->setError("Deleting archive '".$this->path_src.$this->archive_file_name."' after extaction failed. System answer: <pre>".$result.'</pre>');
		}
		return true;
	}
}

?>