<?php
class tar_x {
function parseDirectory($dump_out, $rootPath, $exclude_dirs = array(), $seperator="/", $out_rel_path = ""){
foreach ($exclude_dirs as $excluded) {
if (realpath($rootPath) == realpath($excluded))
return array();
}
$fileArray=array();
$handle = opendir($rootPath);
while( ($file = @readdir($handle))!==false) {
if($file !='.' && $file !='..'){
$current_name = $rootPath.$seperator.$file;
$current_relname = $out_rel_path.$seperator.$file;
if (is_dir($current_name)){
$fileArray[$current_relname] = array_merge(stat($current_name), array('is_directory' => true));
$array = tar_x::parseDirectory($dump_out, $current_name, $exclude_dirs, $seperator, $current_relname);
$fileArray = array_merge($fileArray, $array);
} else {
if ($fp = fopen($current_name, "rb")) {
while ($temp = fread($fp, 1048576)) {
fwrite($dump_out, $temp);
}
$fileArray[$current_relname] = fstat($fp);
fclose($fp);
}
else
trigger_error("Could not open file {$current['name']} for reading. It was not added.");
}
}
}
closedir($handle);
return $fileArray;
}
/**
* Dumps directory contents into two files (*.dmp and *.tree). So that these files may be easily
* migrated to other place, for example to other web server, and extracted there. It does not
* use andy compression so it may result in huge output files depending on input directory size.
*
* Note: all contents of the parent directory of $out_name file is automatically excluded from the dump! See below.
*
* @param $src_dir
* path to input directory that shoul be dumped
*
* @param $exclude_dirs
* paths of directories that should be excluded from the dump.
* It must be paths inside $src_dir. If not, they will be ignored.
* Also a directory is excluded automatically if
* 1) it is inside $src_dir
* 2) and it is a parent directory of $out_name
* In that case there is not necessary to specify it in $exclude_dirs.
*
* @param $out_name
* path to output dump files. It should be a common part of name of these files.
* This function will create two separate files located in the same directory
* (this directory should have appropriate write permissions)
* that will have the same name but end with *.dmp and *.tree extensions.
* For example:
* If you specify as parameter value /www/home/_mydump/htdocs.tarx
* then it will create two files /www/home/_mydump/htdocs.tarx.dmp and
* /www/home/_mydump/htdocs.tarx.tree
*/
function dumpDirectory($src_dir, $exclude_dirs = array(), $out_name) {
if ($dump_out = fopen($out_name.'.dmp', "wb+")) {
$files = tar_x::parseDirectory($dump_out, $src_dir, array_merge(array(dirname($out_name)), $exclude_dirs));
fclose($dump_out);
if ($dump_tree = fopen($out_name.'.tree', "wb+")) {
fwrite($dump_tree, serialize($files));
fclose($dump_tree);
} else {
trigger_error("Could not open {$out_name} tree file for writing.");
}
} else {
trigger_error("Could not open {$out_name} dump file for writing.");
}
}
function setAttributes($file_path, $attributes) {
if (!touch($file_path, $attributes['mtime'], $attributes['atime']))
trigger_error('cannot change time attributes of '.$file_path);
$mode = $attributes['mode'] & 0x1ff;
if (!chmod($file_path, $mode))
trigger_error('cannot change mode '.$mode.' of '.$file_path);
}
/**
* Restores directory dump from *.dmp and *.tree files pair. It will overwrite existing files in $out_dir
* if they conflict with the same files in the dump.
* Input files pair MUST be previously created by dumpDirectory() function!
* If you are not sure about the input files, do not use them! because the results are unknown!
*
* Under Windows OS it may produce many warnings like 'touch() [function.touch]: Utime failed: Permission denied' (see http://php.net/manual/en/function.touch.php)
*
* @param $in_name
* path to the dump files previously created bu dumpDirectory() function.
* Note: this path should point to "both" files *.dmp and *.tree but not contain their extensions.
* Also the both files must locate in the same directory.
* For example:
* You have the following files pair: /www/home/_dump/tmp/mysite.tarx.dmp
* and /www/home/_dump/tmp/mysite.tarx.tree.
* Then you must specify this path: /www/home/_dump/tmp/mysite.tarx as parameter value
*
* @param $out_dir
* path to output directory where to extract the dump. No trailing slash! It must have appropriate write permissions.
*/
function restoreDirectory($in_name, $out_dir) {
if ($dump_in = fopen($in_name.'.dmp', "rb")) {
$files = unserialize(file_get_contents($in_name.'.tree'));
if (empty($files)) {
die("Could not read {$in_name} tree file.");
}
foreach($files as $rel_file => $stat) {
if (isset($stat['is_directory']) && $stat['is_directory']) {
mkdir($out_dir.$rel_file);
tar_x::setAttributes($out_dir.$rel_file, $stat);
} else {
if ($current_out_file = fopen($out_dir.$rel_file, "wb")) {
$bytes_read = 0;
$file_size = $stat['size'];
while ($bytes_read < $file_size && $temp = fread($dump_in, min($file_size - $bytes_read, 1048576))) {
$bytes_read += strlen($temp);
fwrite($current_out_file, $temp);
}
fclose($current_out_file);
tar_x::setAttributes($out_dir.$rel_file, $stat);
} else {
trigger_error("Could not open {$out_name} for writing.");
}
}
}
fclose($dump_in);
} else {
trigger_error("Could not open {$in_name} dump file for reading.");
}
}
}
?>