Guest User

Archiv-Klasse in PHP

a guest
Jul 17th, 2012
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 17.94 KB | None | 0 0
  1. class archive {
  2.  
  3.     function archive($name) {
  4.         $this->options = array(
  5.             'basedir' => ".",
  6.             'name' => $name,
  7.             'prepend' => "",
  8.             'inmemory' => 0,
  9.             'overwrite' => 0,
  10.             'recurse' => 1,
  11.             'storepaths' => 1,
  12.             'followlinks' => 0,
  13.             'level' => 3,
  14.             'method' => 1,
  15.             'sfx' => "",
  16.             'type' => "",
  17.             'comment' => "",
  18.             'maxsize' => memory_get_usage()
  19.         );
  20.         $this->files = array();
  21.         $this->exclude = array();
  22.         $this->exclude_regexp = array();
  23.         $this->storeonly = array();
  24.         $this->error = array();
  25.     }
  26.  
  27.     function set_options($options) {
  28.         foreach ($options as $key => $value)
  29.             $this->options[$key] = $value;
  30.         if (!empty($this->options['basedir'])) {
  31.             $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']);
  32.             $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']);
  33.             $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']);
  34.         }
  35.         if (!empty($this->options['name'])) {
  36.             $this->options['name'] = str_replace("\\", "/", $this->options['name']);
  37.             $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']);
  38.         }
  39.         if (!empty($this->options['prepend'])) {
  40.             $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']);
  41.             $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']);
  42.             $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']);
  43.             $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/";
  44.         }
  45.     }
  46.  
  47.     function create_archive() {
  48.         $this->make_list();
  49.  
  50.         if ($this->options['inmemory'] == 0) {
  51.             $pwd = getcwd();
  52.             chdir($this->options['basedir']);
  53.             if ($this->options['overwrite'] == 0 && file_exists($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""))) {
  54.                 $this->error[] = "File {$this->options['name']} already exists.";
  55.                 chdir($pwd);
  56.                 return 0;
  57.             } else
  58.             if ($this->archive = @fopen($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""), "wb+"))
  59.                 chdir($pwd);
  60.             else {
  61.                 $this->error[] = "Could not open {$this->options['name']} for writing.";
  62.                 chdir($pwd);
  63.                 return 0;
  64.             }
  65.         } else
  66.             $this->archive = "";
  67.  
  68.         switch ($this->options['type']) {
  69.             case "zip" :
  70.                 if (!$this->create_zip()) {
  71.                     $this->error[] = "Could not create zip file.";
  72.                     return 0;
  73.                 }
  74.                 break;
  75.             case "bzip" :
  76.                 if (!$this->create_tar()) {
  77.                     $this->error[] = "Could not create tar file.";
  78.                     return 0;
  79.                 }
  80.                 if (!$this->create_bzip()) {
  81.                     $this->error[] = "Could not create bzip2 file.";
  82.                     return 0;
  83.                 }
  84.                 break;
  85.             case "gzip" :
  86.                 if (!$this->create_tar()) {
  87.                     $this->error[] = "Could not create tar file.";
  88.                     return 0;
  89.                 }
  90.                 if (!$this->create_gzip()) {
  91.                     $this->error[] = "Could not create gzip file.";
  92.                     return 0;
  93.                 }
  94.                 break;
  95.             case "tar" :
  96.                 if (!$this->create_tar()) {
  97.                     $this->error[] = "Could not create tar file.";
  98.                     return 0;
  99.                 }
  100.         }
  101.  
  102.         if ($this->options['inmemory'] == 0) {
  103.             fclose($this->archive);
  104.             if ($this->options['type'] == "gzip" || $this->options['type'] == "bzip")
  105.                 unlink($this->options['basedir'] . "/" . $this->options['name'] . ".tmp");
  106.         }
  107.     }
  108.  
  109.     function add_data($data) {
  110.         if ($this->options['inmemory'] == 0)
  111.             fwrite($this->archive, $data);
  112.         else
  113.             $this->archive .= $data;
  114.     }
  115.  
  116.     /**
  117.      * Checks if a file shall be excluded
  118.      */
  119.     function exclude_file($name) {
  120.         $ret = false;
  121.         // Check for exclusion regexps
  122.         if (!empty($this->exclude_regexp)) {
  123.             foreach ($this->exclude_regexp as $pattern) {
  124.                 if (preg_match('|^' . $pattern . '$|', $name)) {
  125.                     $ret = true;
  126.                 }
  127.             }
  128.         }
  129.         if ($this->options['maxsize'] > 0) {
  130.             if (filesize($this->options['basedir'] . "/" . $name) > $this->options['maxsize']) {
  131.                 $ret = true;
  132.             }
  133.         }
  134.         return $ret;
  135.     }
  136.  
  137.     function make_list() {
  138.         foreach ($this->files as $key => $value) {
  139.             if ($this->exclude_file($value['name'])) {
  140.                 unset($this->files[$key]);
  141.             }
  142.         }
  143.         if (!empty($this->exclude)) {
  144.             foreach ($this->files as $key => $value) {
  145.                 foreach ($this->exclude as $current) {
  146.                     if ($value['name'] == $current['name']) {
  147.                         unset($this->files[$key]);
  148.                     }
  149.                 }
  150.             }
  151.         }
  152.         if (!empty($this->storeonly))
  153.             foreach ($this->files as $key => $value)
  154.                 foreach ($this->storeonly as $current)
  155.                     if ($value['name'] == $current['name'])
  156.                         $this->files[$key]['method'] = 0;
  157.         unset($this->exclude, $this->storeonly);
  158.     }
  159.  
  160.     function add_files($list) {
  161.         $temp = $this->list_files($list);
  162.         foreach ($temp as $current)
  163.             $this->files[] = $current;
  164.     }
  165.  
  166.     function exclude_regexp_files($patterns) {
  167.         $this->exclude_regexp = explode("|", $patterns);
  168.     }
  169.  
  170.     function exclude_files($list) {
  171.         $temp = $this->list_files($list);
  172.         foreach ($temp as $current)
  173.             $this->exclude[] = $current;
  174.     }
  175.  
  176.     function store_files($list) {
  177.         $temp = $this->list_files($list);
  178.         foreach ($temp as $current)
  179.             $this->storeonly[] = $current;
  180.     }
  181.  
  182.     /**
  183.      * Creates a list of files with absolute pathes
  184.      */
  185.     function list_files($list) {
  186.         if (!is_array($list)) {
  187.             $temp = $list;
  188.             $list = array(
  189.                 $temp
  190.             );
  191.             unset($temp);
  192.         }
  193.  
  194.         $files = array();
  195.  
  196.         $pwd = getcwd();
  197.         chdir($this->options['basedir']);
  198.  
  199.         foreach ($list as $current) {
  200.             $current = str_replace("\\", "/", $current);
  201.             $current = preg_replace("/\/+/", "/", $current);
  202.             $current = preg_replace("/\/$/", "", $current);
  203.             if (strstr($current, "*")) {
  204.                 $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current);
  205.                 $regex = str_replace("*", ".*", $regex);
  206.                 $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : ".";
  207.                 $temp = $this->parse_dir($dir);
  208.                 //print "dir: ".$dir; print_r($temp);print "EOL<br>\n";
  209.                 foreach ($temp as $current2) {
  210.                     //print "$regex : ".$current2['name']." <br>\n";
  211.                     if (preg_match("/^{$regex}$/i", $current2['name']))
  212.                         $files[] = $current2;
  213.                 }
  214.                 unset($regex, $dir, $temp, $current);
  215.             } else
  216.             if (@ is_dir($current)) {
  217.                 $temp = $this->parse_dir($current);
  218.                 foreach ($temp as $file)
  219.                     $files[] = $file;
  220.                 unset($temp, $file);
  221.             } else
  222.             if (@ file_exists($current))
  223.                 $files[] = array(
  224.                     'name' => $current,
  225.                     'name2' => $this->options['prepend'] .
  226.                     preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ? substr($current, strrpos($current, "/") + 1) : $current),
  227.                     'type' => @ is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0,
  228.                     'ext' => substr($current, strrpos($current, ".")),
  229.                     'stat' => stat($current)
  230.                 );
  231.         }
  232.  
  233.         chdir($pwd);
  234.  
  235.         unset($current, $pwd);
  236.  
  237.         usort($files, array(
  238.             "archive",
  239.             "sort_files"
  240.         ));
  241.  
  242.         return $files;
  243.     }
  244.  
  245.     function parse_dir($dirname) {
  246.         if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname))
  247.             $files = array(
  248.                 array(
  249.                     'name' => $dirname,
  250.                     'name2' => $this->options['prepend'] .
  251.                     preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ? substr($dirname, strrpos($dirname, "/") + 1) : $dirname),
  252.                     'type' => 5,
  253.                     'stat' => stat($dirname)
  254.                 )
  255.             );
  256.         else
  257.             $files= array();
  258.         $dir = @ opendir($dirname);
  259.  
  260.         while ($file = @ readdir($dir)) {
  261.             $fullname = $dirname . "/" . $file;
  262.             if ($file == "." || $file == "..")
  263.                 continue;
  264.             else
  265.             if (@ is_dir($fullname)) {
  266.                 if (empty($this->options['recurse']))
  267.                     continue;
  268.                 $temp = $this->parse_dir($fullname);
  269.                 foreach ($temp as $file2)
  270.                     $files[] = $file2;
  271.             } else
  272.             if (@ file_exists($fullname))
  273.                 $files[] = array(
  274.                     'name' => $fullname,
  275.                     'name2' => $this->options['prepend'] .
  276.                     preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ? substr($fullname, strrpos($fullname, "/") + 1) : $fullname),
  277.                     'type' => @ is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0,
  278.                     'ext' => substr($file, strrpos($file, ".")),
  279.                     'stat' => stat($fullname)
  280.                 );
  281.         }
  282.  
  283.         @ closedir($dir);
  284.  
  285.         return $files;
  286.     }
  287.  
  288.     function sort_files($a, $b) {
  289.         if ($a['type'] != $b['type'])
  290.             if ($a['type'] == 5 || $b['type'] == 2)
  291.                 return -1;
  292.             else
  293.             if ($a['type'] == 2 || $b['type'] == 5)
  294.                 return 1;
  295.             else
  296.             if ($a['type'] == 5)
  297.                 return strcmp(strtolower($a['name']), strtolower($b['name']));
  298.             else
  299.             if ($a['ext'] != $b['ext'])
  300.                 return strcmp($a['ext'], $b['ext']);
  301.             else
  302.             if ($a['stat'][7] != $b['stat'][7])
  303.                 return $a['stat'][7] > $b['stat'][7] ? -1 : 1;
  304.             else
  305.                 return strcmp(strtolower($a['name']), strtolower($b['name']));
  306.         return 0;
  307.     }
  308.  
  309.     function download_file() {
  310.         if ($this->options['inmemory'] == 0) {
  311.             $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster.";
  312.             return;
  313.         }
  314.         switch ($this->options['type']) {
  315.             case "zip" :
  316.                 header("Content-Type: application/zip");
  317.                 break;
  318.             case "bzip" :
  319.                 header("Content-Type: application/x-bzip2");
  320.                 break;
  321.             case "gzip" :
  322.                 header("Content-Type: application/x-gzip");
  323.                 break;
  324.             case "tar" :
  325.                 header("Content-Type: application/x-tar");
  326.         }
  327.         $header = "Content-Disposition: attachment; filename=\"";
  328.         $header .= strstr($this->options['name'], "/") ? substr($this->options['name'], strrpos($this->options['name'], "/") + 1) : $this->options['name'];
  329.         $header .= "\"";
  330.         header($header);
  331.         header("Content-Length: " . strlen($this->archive));
  332.         header("Content-Transfer-Encoding: binary");
  333.         header("Cache-Control: no-cache, must-revalidate, max-age=60");
  334.         header("Expires: Sat, 01 Jan 2000 12:00:00 GMT");
  335.         print ($this->archive);
  336.     }
  337.  
  338.     /**
  339.      * This method saves the current archive-stream to the filesystem.
  340.      *
  341.      * @author PHPler
  342.      * @param string $filename
  343.      * @param string $path
  344.      * @return int success-/error-code
  345.      */
  346.     function save_file($filename, $path = '') {
  347.  
  348.         if ($this->options['inmemory'] == 0) {
  349.             $this->error[] = "Can only use save_file() if archive is in memory.";
  350.             return;
  351.         }
  352.  
  353.         if ($fhandle = @fopen($path . $filename, 'w')) {
  354.             if (@fwrite($fhandle, $this->archive)) {
  355.                 if (@fclose($fhandle))
  356.                     return 1;
  357.                 else
  358.                     return 0;
  359.             }else {
  360.                 return -2;
  361.             }
  362.         } else {
  363.             return -1;
  364.         }
  365.     }
  366.  
  367. }
  368.  
  369. class zip_file extends archive {
  370.  
  371.     function zip_file($name) {
  372.         $this->archive($name);
  373.         $this->options['type'] = "zip";
  374.     }
  375.  
  376.     function create_zip() {
  377.         $files = 0;
  378.         $offset = 0;
  379.         $central = "";
  380.  
  381.         if (!empty($this->options['sfx']))
  382.             if ($fp = @ fopen($this->options['sfx'], "rb")) {
  383.                 $temp = fread($fp, filesize($this->options['sfx']));
  384.                 fclose($fp);
  385.                 $this->add_data($temp);
  386.                 $offset += strlen($temp);
  387.                 unset($temp);
  388.             } else
  389.                 $this->error[] = "Could not open sfx module from {$this->options['sfx']}.";
  390.  
  391.         $pwd = getcwd();
  392.         chdir($this->options['basedir']);
  393.  
  394.         foreach ($this->files as $current) {
  395.             if ($current['name'] == $this->options['name'])
  396.                 continue;
  397.  
  398.             $timedate = explode(" ", date("Y n j G i s", $current['stat'][9]));
  399.             $timedate = ($timedate[0] - 1980 << 25) | ($timedate[1] << 21) | ($timedate[2] << 16) | ($timedate[3] << 11) | ($timedate[4] << 5) | ($timedate[5]);
  400.  
  401.             $block = pack("VvvvV", 0x04034b50, 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate);
  402.  
  403.             //if ($current['stat'][7] == 0 && $current['type'] == 5) {
  404.             if ($current['type'] == 5) {
  405.                 $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000);
  406.                 $block .= $current['name2'] . "/";
  407.                 $this->add_data($block);
  408.                 $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset);
  409.                 $central .= $current['name2'] . "/";
  410.                 $files++;
  411.                 $offset += ( 31 + strlen($current['name2']));
  412.             } else
  413.             if ($current['stat'][7] == 0) {
  414.                 $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000);
  415.                 $block .= $current['name2'];
  416.                 $this->add_data($block);
  417.                 $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset);
  418.                 $central .= $current['name2'];
  419.                 $files++;
  420.                 $offset += ( 30 + strlen($current['name2']));
  421.             } else
  422.             if ($fp = @ fopen($current['name'], "rb")) {
  423.                 $temp = fread($fp, $current['stat'][7]);
  424.                 fclose($fp);
  425.                 $crc32 = crc32($temp);
  426.                 if (!isset($current['method']) && $this->options['method'] == 1) {
  427.                     $temp = gzcompress($temp, $this->options['level']);
  428.                     $size = strlen($temp) - 6;
  429.                     $temp = substr($temp, 2, $size);
  430.                 } else
  431.                     $size= strlen($temp);
  432.                 $block .= pack("VVVvv", $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000);
  433.                 $block .= $current['name2'];
  434.                 $this->add_data($block);
  435.                 $this->add_data($temp);
  436.                 unset($temp);
  437.                 $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, 0x00000000, $offset);
  438.                 $central .= $current['name2'];
  439.                 $files++;
  440.                 $offset += ( 30 + strlen($current['name2']) + $size);
  441.             } else
  442.                 $this->error[] = "Could not open file {$current['name']} for reading. It was not added.";
  443.         }
  444.  
  445.         $this->add_data($central);
  446.  
  447.         $this->add_data(pack("VvvvvVVv", 0x06054b50, 0x0000, 0x0000, $files, $files, strlen($central), $offset, !empty($this->options['comment']) ? strlen($this->options['comment']) : 0x0000));
  448.  
  449.         if (!empty($this->options['comment']))
  450.             $this->add_data($this->options['comment']);
  451.  
  452.         chdir($pwd);
  453.  
  454.         return 1;
  455.     }
  456.  
  457. }
Advertisement
Add Comment
Please, Sign In to add comment