options = array('basedir' => ".", 'name' => $name, 'prepend' => "", 'inmemory' => 0, 'overwrite' => 0, 'recurse' => 1, 'storepaths' => 1, 'followlinks' => 0, 'level' => 3, 'method' => 1, 'sfx' => "", 'type' => "", 'comment' => "" ); $this->files = array(); $this->exclude = array(); $this->storeonly = array(); $this->error = array(); } /** * This function gives options to a archive * * @param array $options * @return void */ public function set_options($options) { foreach ($options as $key => $value) { $this->options[$key] = $value; } if (!empty($this->options['basedir'])) { $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']); $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']); $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']); } if (!empty($this->options['name'])) { $this->options['name'] = str_replace("\\", "/", $this->options['name']); $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']); } if (!empty($this->options['prepend'])) { $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']); $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']); $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']); $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/"; } } /** * This function is used to create a archive. * * @return boolean */ public function create_archive() { $this->make_list(); if ($this->options['inmemory'] == 0) { $pwd = getcwd(); chdir($this->options['basedir']); if ($this->options['overwrite'] == 0 && file_exists($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""))) { $this->error[] = "File {$this->options['name']} already exist."; chdir($pwd); return 0; } elseif ($this->archive = @fopen($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""), "wb+")) { chdir($pwd); } else { $this->error[] = "Could not open {$this->options['name']} for writing."; chdir($pwd); return 0; } } else { $this->archive = ""; } switch ($this->options['type']) { case "zip": if (!$this->create_zip()) { $this->error[] = "Could not create zip file."; return 0; } break; case "bzip": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } if (!$this->create_bzip()) { $this->error[] = "Could not create bzip2 file."; return 0; } break; case "gzip": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } if (!$this->create_gzip()) { $this->error[] = "Could not create gzip file."; return 0; } break; case "tar": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } } if ($this->options['inmemory'] == 0) { fclose($this->archive); if ($this->options['type'] == "gzip" || $this->options['type'] == "bzip") { unlink($this->options['basedir'] . "/" . $this->options['name'] . ".tmp"); } } } /** * This function is used for add data to a archive * * @param string $data * @return void */ public function add_data($data) { if ($this->options['inmemory'] == 0) { fwrite($this->archive, $data); } else { $this->archive .= $data; } } /** * This function make a list * * @return void */ public function make_list() { if (!empty($this->exclude)) { foreach ($this->files as $key => $value) { foreach ($this->exclude as $current) { if ($value['name'] == $current['name']) { unset($this->files[$key]); } } } } if (!empty($this->storeonly)) { foreach ($this->files as $key => $value) { foreach ($this->storeonly as $current) { if ($value['name'] == $current['name']) { $this->files[$key]['method'] = 0; } } } } unset($this->exclude, $this->storeonly); } /** * Add files a list * * @param array $list * @return void */ public function add_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) { $this->files[] = $current; } } /** * This function exclude files of a list * * @param array $list * @return void */ public function exclude_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) { $this->exclude[] = $current; } } /** * This function store files * * @param array $list */ public function store_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) { $this->storeonly[] = $current; } } /** * List files gives a List * * @param array $list * @return array */ public function list_files($list) { if (!is_array($list)) { $temp = $list; $list = array($temp ); unset($temp); } $files = array(); $pwd = getcwd(); chdir($this->options['basedir']); foreach ($list as $current) { $current = str_replace("\\", "/", $current); $current = preg_replace("/\/+/", "/", $current); $current = preg_replace("/\/$/", "", $current); if (strstr($current, "*")) { $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current); $regex = str_replace("*", ".*", $regex); $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : "."; $temp = $this->parse_dir($dir); foreach ($temp as $current2) { if (preg_match("/^{$regex}$/i", $current2['name'])) { $files[] = $current2; } } unset($regex, $dir, $temp, $current); } elseif (@is_dir($current)) { $temp = $this->parse_dir($current); foreach ($temp as $file) { $files[] = $file; } unset($temp, $file); } elseif (@file_exists($current)) { $files[] = array('name' => $current, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ? substr($current, strrpos($current, "/") + 1) : $current), 'type' => @is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0, 'ext' => substr($current, strrpos($current, ".")), 'stat' => stat($current) ); } } chdir($pwd); unset($current, $pwd); usort($files, array("archive", "sort_files" )); return $files; } /** * This function is for parse a directory name * * @param string $dirname * @return array */ public function parse_dir($dirname) { if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname)) { $files = array(array('name' => $dirname, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ? substr($dirname, strrpos($dirname, "/") + 1) : $dirname), 'type' => 5, 'stat' => stat($dirname) ) ); } else { $files = array(); } $dir = @opendir($dirname); while ($file = @readdir($dir)) { $fullname = $dirname . "/" . $file; if ($file == "." || $file == "..") { continue; } elseif (@is_dir($fullname)) { if (empty($this->options['recurse'])) { continue; } $temp = $this->parse_dir($fullname); foreach ($temp as $file2) { $files[] = $file2; } } elseif (@file_exists($fullname)) { $files[] = array('name' => $fullname, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ? substr($fullname, strrpos($fullname, "/") + 1) : $fullname), 'type' => @is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0, 'ext' => substr($file, strrpos($file, ".")), 'stat' => stat($fullname) ); } } @closedir($dir); return $files; } /** * This function sort two files * * @param array $a * @param array $b * @return boolean */ public function sort_files($a, $b) { if ($a['type'] != $b['type']) { if ($a['type'] == 5 || $b['type'] == 2) { return -1; } elseif ($a['type'] == 2 || $b['type'] == 5) { return 1; } elseif ($a['type'] == 5) { return strcmp(strtolower($a['name']), strtolower($b['name'])); } elseif ($a['ext'] != $b['ext']) { return strcmp($a['ext'], $b['ext']); } elseif ($a['stat'][7] != $b['stat'][7]) { return $a['stat'][7] > $b['stat'][7] ? -1 : 1; } else { return strcmp(strtolower($a['name']), strtolower($b['name'])); } } return 0; } /** * This function download a file * * @return void */ public function download_file() { if ($this->options['inmemory'] == 0) { $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster."; return; } switch ($this->options['type']) { case "zip": header("Content-Type: application/zip"); break; case "bzip": header("Content-Type: application/x-bzip2"); break; case "gzip": header("Content-Type: application/x-gzip"); break; case "tar": header("Content-Type: application/x-tar"); } $header = "Content-Disposition: attachment; filename=\""; $header .= strstr($this->options['name'], "/") ? substr($this->options['name'], strrpos($this->options['name'], "/") + 1) : $this->options['name']; $header .= "\""; header($header); header("Content-Length: " . strlen($this->archive)); header("Content-Transfer-Encoding: binary"); header("Cache-Control: no-cache, must-revalidate, max-age=60"); header("Expires: Sat, 01 Jan 2000 12:00:00 GMT"); print ($this->archive); } }