Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_compress.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 21.17 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  /**
015  * @ignore
016  */
017  if (!defined('IN_PHPBB'))
018  {
019      exit;
020  }
021   
022  /**
023  * Class for handling archives (compression/decompression)
024  */
025  class compress
026  {
027      var $fp = 0;
028   
029      /**
030      * @var array
031      */
032      protected $filelist = array();
033   
034      /**
035      * Add file to archive
036      */
037      function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '')
038      {
039          global $phpbb_root_path;
040   
041          $skip_files = explode(',', $skip_files);
042   
043          // Remove rm prefix from src path
044          $src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src;
045          // Add src prefix
046          $src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path;
047          // Remove initial "/" if present
048          $src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path;
049   
050          if (is_file($phpbb_root_path . $src))
051          {
052              $this->data($src_path, file_get_contents("$phpbb_root_path$src"), stat("$phpbb_root_path$src"), false);
053          }
054          else if (is_dir($phpbb_root_path . $src))
055          {
056              // Clean up path, add closing / if not present
057              $src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path;
058   
059              $filelist = filelist("$phpbb_root_path$src", '', '*');
060              krsort($filelist);
061   
062              /**
063              * Commented out, as adding the folders produces corrupted archives
064              if ($src_path)
065              {
066                  $this->data($src_path, '', true, stat("$phpbb_root_path$src"));
067              }
068              */
069   
070              foreach ($filelist as $path => $file_ary)
071              {
072                  /**
073                  * Commented out, as adding the folders produces corrupted archives
074                  if ($path)
075                  {
076                      // Same as for src_path
077                      $path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path;
078                      $path = ($path && substr($path, -1) != '/') ? $path . '/' : $path;
079   
080                      $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path"));
081                  }
082                  */
083   
084                  foreach ($file_ary as $file)
085                  {
086                      if (in_array($path . $file, $skip_files))
087                      {
088                          continue;
089                      }
090   
091                      $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), stat("$phpbb_root_path$src$path$file"), false);
092                  }
093              }
094          }
095          else
096          {
097              // $src does not exist
098              return false;
099          }
100   
101          return true;
102      }
103   
104      /**
105      * Add custom file (the filepath will not be adjusted)
106      */
107      function add_custom_file($src, $filename)
108      {
109          if (!file_exists($src))
110          {
111              return false;
112          }
113   
114          $this->data($filename, file_get_contents($src), stat($src), false);
115          return true;
116      }
117   
118      /**
119      * Add file data
120      */
121      function add_data($src, $name)
122      {
123          $stat = array();
124          $stat[2] = 436; //384
125          $stat[4] = $stat[5] = 0;
126          $stat[7] = strlen($src);
127          $stat[9] = time();
128          $this->data($name, $src, $stat, false);
129          return true;
130      }
131   
132      /**
133      * Checks if a file by that name as already been added and, if it has,
134      * returns a new, unique name.
135      *
136      * @param string $name The filename
137      * @return string A unique filename
138      */
139      protected function unique_filename($name)
140      {
141          if (isset($this->filelist[$name]))
142          {
143              $start = $name;
144              $ext = '';
145              $this->filelist[$name]++;
146   
147              // Separate the extension off the end of the filename to preserve it
148              $pos = strrpos($name, '.');
149              if ($pos !== false)
150              {
151                  $start = substr($name, 0, $pos);
152                  $ext = substr($name, $pos);
153              }
154   
155              return $start . '_' . $this->filelist[$name] . $ext;
156          }
157   
158          $this->filelist[$name] = 0;
159          return $name;
160      }
161   
162      /**
163      * Return available methods
164      *
165      * @return array Array of strings of available compression methods (.tar, .tar.gz, .zip, etc.)
166      */
167      static public function methods()
168      {
169          $methods = array('.tar');
170          $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
171   
172          foreach ($available_methods as $type => $module)
173          {
174              if (!@extension_loaded($module))
175              {
176                  continue;
177              }
178              $methods[] = $type;
179          }
180   
181          return $methods;
182      }
183  }
184   
185  /**
186  * Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux,
187  * Marc Delisle, http://www.phpmyadmin.net/
188  *
189  * Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com
190  *
191  * Modified extensively by psoTFX and DavidMJ, (c) phpBB Limited, 2003
192  *
193  * Based on work by Eric Mueller and Denis125
194  * Official ZIP file format: http://www.pkware.com/appnote.txt
195  */
196  class compress_zip extends compress
197  {
198      var $datasec = array();
199      var $ctrl_dir = array();
200      var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00";
201   
202      var $old_offset = 0;
203      var $datasec_len = 0;
204   
205      /**
206       * @var \phpbb\filesystem\filesystem_interface
207       */
208      protected $filesystem;
209   
210      /**
211      * Constructor
212      */
213      function __construct($mode, $file)
214      {
215          global $phpbb_filesystem;
216   
217          $this->fp = @fopen($file, $mode . 'b');
218          $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
219   
220          if (!$this->fp)
221          {
222              trigger_error('Unable to open file ' . $file . ' [' . $mode . 'b]');
223          }
224      }
225   
226      /**
227      * Convert unix to dos time
228      */
229      function unix_to_dos_time($time)
230      {
231          $timearray = (!$time) ? getdate() : getdate($time);
232   
233          if ($timearray['year'] < 1980)
234          {
235              $timearray['year'] = 1980;
236              $timearray['mon'] = $timearray['mday'] = 1;
237              $timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0;
238          }
239   
240          return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
241      }
242   
243      /**
244      * Extract archive
245      */
246      function extract($dst)
247      {
248          // Loop the file, looking for files and folders
249          $dd_try = false;
250          rewind($this->fp);
251   
252          while (!feof($this->fp))
253          {
254              // Check if the signature is valid...
255              $signature = fread($this->fp, 4);
256   
257              switch ($signature)
258              {
259                  // 'Local File Header'
260                  case "\x50\x4b\x03\x04":
261                      // Lets get everything we need.
262                      // We don't store the version needed to extract, the general purpose bit flag or the date and time fields
263                      $data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26));
264                      $file_name = fread($this->fp, $data['name_len']); // filename
265   
266                      if ($data['extra_field'])
267                      {
268                          fread($this->fp, $data['extra_field']); // extra field
269                      }
270   
271                      $target_filename = "$dst$file_name";
272   
273                      if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/')
274                      {
275                          if (!is_dir($target_filename))
276                          {
277                              $str = '';
278                              $folders = explode('/', $target_filename);
279   
280                              // Create and folders and subfolders if they do not exist
281                              foreach ($folders as $folder)
282                              {
283                                  $folder = trim($folder);
284                                  if (!$folder)
285                                  {
286                                      continue;
287                                  }
288   
289                                  $str = (!empty($str)) ? $str . '/' . $folder : $folder;
290                                  if (!is_dir($str))
291                                  {
292                                      if (!@mkdir($str, 0777))
293                                      {
294                                          trigger_error("Could not create directory $folder");
295                                      }
296   
297                                      try
298                                      {
299                                          $this->filesystem->phpbb_chmod($str, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
300                                      }
301                                      catch (\phpbb\filesystem\exception\filesystem_exception $e)
302                                      {
303                                          // Do nothing
304                                      }
305                                  }
306                              }
307                          }
308                          // This is a directory, we are not writing files
309                          continue 2;
310                      }
311                      else
312                      {
313                          // Some archivers are punks, they don't include folders in their archives!
314                          $str = '';
315                          $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
316   
317                          // Create and folders and subfolders if they do not exist
318                          foreach ($folders as $folder)
319                          {
320                              $folder = trim($folder);
321                              if (!$folder)
322                              {
323                                  continue;
324                              }
325   
326                              $str = (!empty($str)) ? $str . '/' . $folder : $folder;
327                              if (!is_dir($str))
328                              {
329                                  if (!@mkdir($str, 0777))
330                                  {
331                                      trigger_error("Could not create directory $folder");
332                                  }
333   
334                                  try
335                                  {
336                                      $this->filesystem->phpbb_chmod($str, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
337                                  }
338                                  catch (\phpbb\filesystem\exception\filesystem_exception $e)
339                                  {
340                                      // Do nothing
341                                  }
342                              }
343                          }
344                      }
345   
346                      if (!$data['uc_size'])
347                      {
348                          $content = '';
349                      }
350                      else
351                      {
352                          $content = fread($this->fp, $data['c_size']);
353                      }
354   
355                      $fp = fopen($target_filename, "w");
356   
357                      switch ($data['c_method'])
358                      {
359                          case 0:
360                              // Not compressed
361                              fwrite($fp, $content);
362                          break;
363   
364                          case 8:
365                              // Deflate
366                              fwrite($fp, gzinflate($content, $data['uc_size']));
367                          break;
368   
369                          case 12:
370                              // Bzip2
371                              fwrite($fp, bzdecompress($content));
372                          break;
373                      }
374   
375                      fclose($fp);
376                  break;
377   
378                  // We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention
379                  // or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders
380                  case "\x50\x4b\x01\x02":
381                  // This case should simply never happen.. but it does exist..
382                  case "\x50\x4b\x05\x06":
383                  break 2;
384   
385                  // 'Packed to Removable Disk', ignore it and look for the next signature...
386                  case 'PK00':
387                  continue 2;
388   
389                  // We have encountered a header that is weird. Lets look for better data...
390                  default:
391                      if (!$dd_try)
392                      {
393                          // Unexpected header. Trying to detect wrong placed 'Data Descriptor';
394                          $dd_try = true;
395                          fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4)
396                          continue 2;
397                      }
398                      trigger_error("Unexpected header, ending loop");
399                  break 2;
400              }
401   
402              $dd_try = false;
403          }
404      }
405   
406      /**
407      * Close archive
408      */
409      function close()
410      {
411          // Write out central file directory and footer ... if it exists
412          if (count($this->ctrl_dir))
413          {
414              fwrite($this->fp, $this->file());
415          }
416          fclose($this->fp);
417      }
418   
419      /**
420      * Create the structures ... note we assume version made by is MSDOS
421      */
422      function data($name, $data, $stat, $is_dir = false)
423      {
424          $name = str_replace('\\', '/', $name);
425          $name = $this->unique_filename($name);
426   
427          $hexdtime = pack('V', $this->unix_to_dos_time($stat[9]));
428   
429          if ($is_dir)
430          {
431              $unc_len = $c_len = $crc = 0;
432              $zdata = '';
433              $var_ext = 10;
434          }
435          else
436          {
437              $unc_len = strlen($data);
438              $crc = crc32($data);
439              $zdata = gzdeflate($data);
440              $c_len = strlen($zdata);
441              $var_ext = 20;
442   
443              // Did we compress? No, then use data as is
444              if ($c_len >= $unc_len)
445              {
446                  $zdata = $data;
447                  $c_len = $unc_len;
448                  $var_ext = 10;
449              }
450          }
451          unset($data);
452   
453          // If we didn't compress set method to store, else deflate
454          $c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00";
455   
456          // Are we a file or a directory? Set archive for file
457          $attrib = ($is_dir) ? 16 : 32;
458   
459          // File Record Header
460          $fr = "\x50\x4b\x03\x04";        // Local file header 4bytes
461          $fr .= pack('v', $var_ext);        // ver needed to extract 2bytes
462          $fr .= "\x00\x00";                // gen purpose bit flag 2bytes
463          $fr .= $c_method;                // compression method 2bytes
464          $fr .= $hexdtime;                // last mod time and date 2+2bytes
465          $fr .= pack('V', $crc);            // crc32 4bytes
466          $fr .= pack('V', $c_len);        // compressed filesize 4bytes
467          $fr .= pack('V', $unc_len);        // uncompressed filesize 4bytes
468          $fr .= pack('v', strlen($name));// length of filename 2bytes
469   
470          $fr .= pack('v', 0);            // extra field length 2bytes
471          $fr .= $name;
472          $fr .= $zdata;
473          unset($zdata);
474   
475          $this->datasec_len += strlen($fr);
476   
477          // Add data to file ... by writing data out incrementally we save some memory
478          fwrite($this->fp, $fr);
479          unset($fr);
480   
481          // Central Directory Header
482          $cdrec = "\x50\x4b\x01\x02";        // header 4bytes
483          $cdrec .= "\x00\x00";                // version made by
484          $cdrec .= pack('v', $var_ext);        // version needed to extract
485          $cdrec .= "\x00\x00";                // gen purpose bit flag
486          $cdrec .= $c_method;                // compression method
487          $cdrec .= $hexdtime;                // last mod time & date
488          $cdrec .= pack('V', $crc);            // crc32
489          $cdrec .= pack('V', $c_len);        // compressed filesize
490          $cdrec .= pack('V', $unc_len);        // uncompressed filesize
491          $cdrec .= pack('v', strlen($name));    // length of filename
492          $cdrec .= pack('v', 0);                // extra field length
493          $cdrec .= pack('v', 0);                // file comment length
494          $cdrec .= pack('v', 0);                // disk number start
495          $cdrec .= pack('v', 0);                // internal file attributes
496          $cdrec .= pack('V', $attrib);        // external file attributes
497          $cdrec .= pack('V', $this->old_offset);    // relative offset of local header
498          $cdrec .= $name;
499   
500          // Save to central directory
501          $this->ctrl_dir[] = $cdrec;
502   
503          $this->old_offset = $this->datasec_len;
504      }
505   
506      /**
507      * file
508      */
509      function file()
510      {
511          $ctrldir = implode('', $this->ctrl_dir);
512   
513          return $ctrldir . $this->eof_cdh .
514              pack('v', count($this->ctrl_dir)) .    // total # of entries "on this disk"
515              pack('v', count($this->ctrl_dir)) .    // total # of entries overall
516              pack('V', strlen($ctrldir)) .            // size of central dir
517              pack('V', $this->datasec_len) .            // offset to start of central dir
518              "\x00\x00";                                // .zip file comment length
519      }
520   
521      /**
522      * Download archive
523      */
524      function download($filename, $download_name = false)
525      {
526          global $phpbb_root_path;
527   
528          if ($download_name === false)
529          {
530              $download_name = $filename;
531          }
532   
533          $mimetype = 'application/zip';
534   
535          header('Cache-Control: private, no-cache');
536          header("Content-Type: $mimetype; name=\"$download_name.zip\"");
537          header("Content-disposition: attachment; filename=$download_name.zip");
538   
539          $fp = @fopen("{$phpbb_root_path}store/$filename.zip", 'rb');
540          if ($fp)
541          {
542              while ($buffer = fread($fp, 1024))
543              {
544                  echo $buffer;
545              }
546              fclose($fp);
547          }
548      }
549  }
550   
551  /**
552  * Tar/tar.gz compression routine
553  * Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994
554  */
555  class compress_tar extends compress
556  {
557      var $isgz = false;
558      var $isbz = false;
559      var $filename = '';
560      var $mode = '';
561      var $type = '';
562      var $wrote = false;
563   
564      /**
565       * @var \phpbb\filesystem\filesystem_interface
566       */
567      protected $filesystem;
568   
569      /**
570      * Constructor
571      */
572      function __construct($mode, $file, $type = '')
573      {
574          global $phpbb_filesystem;
575   
576          $type = (!$type) ? $file : $type;
577          $this->isgz = preg_match('#(\.tar\.gz|\.tgz)$#', $type);
578          $this->isbz = preg_match('#\.tar\.bz2$#', $type);
579   
580          $this->mode = &$mode;
581          $this->file = &$file;
582          $this->type = &$type;
583          $this->open();
584   
585          $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
586      }
587   
588      /**
589      * Extract archive
590      */
591      function extract($dst)
592      {
593          $fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread');
594   
595          // Run through the file and grab directory entries
596          while ($buffer = $fzread($this->fp, 512))
597          {
598              $tmp = unpack('A6magic', substr($buffer, 257, 6));
599   
600              if (trim($tmp['magic']) == 'ustar')
601              {
602                  $tmp = unpack('A100name', $buffer);
603                  $filename = trim($tmp['name']);
604   
605                  $tmp = unpack('Atype', substr($buffer, 156, 1));
606                  $filetype = (int) trim($tmp['type']);
607   
608                  $tmp = unpack('A12size', substr($buffer, 124, 12));
609                  $filesize = octdec((int) trim($tmp['size']));
610   
611                  $target_filename = "$dst$filename";
612   
613                  if ($filetype == 5)
614                  {
615                      if (!is_dir($target_filename))
616                      {
617                          $str = '';
618                          $folders = explode('/', $target_filename);
619   
620                          // Create and folders and subfolders if they do not exist
621                          foreach ($folders as $folder)
622                          {
623                              $folder = trim($folder);
624                              if (!$folder)
625                              {
626                                  continue;
627                              }
628   
629                              $str = (!empty($str)) ? $str . '/' . $folder : $folder;
630                              if (!is_dir($str))
631                              {
632                                  if (!@mkdir($str, 0777))
633                                  {
634                                      trigger_error("Could not create directory $folder");
635                                  }
636   
637                                  try
638                                  {
639                                      $this->filesystem->phpbb_chmod($str, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
640                                  }
641                                  catch (\phpbb\filesystem\exception\filesystem_exception $e)
642                                  {
643                                      // Do nothing
644                                  }
645                              }
646                          }
647                      }
648                  }
649                  else if ($filesize >= 0 && ($filetype == 0 || $filetype == "\0"))
650                  {
651                      // Some archivers are punks, they don't properly order the folders in their archives!
652                      $str = '';
653                      $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
654   
655                      // Create and folders and subfolders if they do not exist
656                      foreach ($folders as $folder)
657                      {
658                          $folder = trim($folder);
659                          if (!$folder)
660                          {
661                              continue;
662                          }
663   
664                          $str = (!empty($str)) ? $str . '/' . $folder : $folder;
665                          if (!is_dir($str))
666                          {
667                              if (!@mkdir($str, 0777))
668                              {
669                                  trigger_error("Could not create directory $folder");
670                              }
671   
672                              try
673                              {
674                                  $this->filesystem->phpbb_chmod($str, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
675                              }
676                              catch (\phpbb\filesystem\exception\filesystem_exception $e)
677                              {
678                                  // Do nothing
679                              }
680                          }
681                      }
682   
683                      // Write out the files
684                      if (!($fp = fopen($target_filename, 'wb')))
685                      {
686                          trigger_error("Couldn't create file $filename");
687                      }
688   
689                      try
690                      {
691                          $this->filesystem->phpbb_chmod($target_filename, \phpbb\filesystem\filesystem_interface::CHMOD_READ);
692                      }
693                      catch (\phpbb\filesystem\exception\filesystem_exception $e)
694                      {
695                          // Do nothing
696                      }
697   
698                      // Grab the file contents
699                      fwrite($fp, ($filesize) ? $fzread($this->fp, ($filesize + 511) &~ 511) : '', $filesize);
700                      fclose($fp);
701                  }
702              }
703          }
704      }
705   
706      /**
707      * Close archive
708      */
709      function close()
710      {
711          $fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose');
712   
713          if ($this->wrote)
714          {
715              $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
716   
717              // The end of a tar archive ends in two records of all NULLs (1024 bytes of \0)
718              $fzwrite($this->fp, str_repeat("\0", 1024));
719          }
720   
721          $fzclose($this->fp);
722      }
723   
724      /**
725      * Create the structures
726      */
727      function data($name, $data, $stat, $is_dir = false)
728      {
729          $name = $this->unique_filename($name);
730          $this->wrote = true;
731          $fzwrite =     ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
732   
733          $typeflag = ($is_dir) ? '5' : '';
734   
735          // This is the header data, it contains all the info we know about the file or folder that we are about to archive
736          $header = '';
737          $header .= pack('a100', $name);                        // file name
738          $header .= pack('a8', sprintf("%07o", $stat[2]));    // file mode
739          $header .= pack('a8', sprintf("%07o", $stat[4]));    // owner id
740          $header .= pack('a8', sprintf("%07o", $stat[5]));    // group id
741          $header .= pack('a12', sprintf("%011o", $stat[7]));    // file size
742          $header .= pack('a12', sprintf("%011o", $stat[9]));    // last mod time
743   
744          // Checksum
745          $checksum = 0;
746          for ($i = 0; $i < 148; $i++)
747          {
748              $checksum += ord($header[$i]);
749          }
750   
751          // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions
752          $checksum += 2415 + (($is_dir) ? 53 : 0);
753   
754          $header .= pack('a8', sprintf("%07o", $checksum));    // checksum
755          $header .= pack('a1', $typeflag);                    // link indicator
756          $header .= pack('a100', '');                        // name of linked file
757          $header .= pack('a6', 'ustar');                        // ustar indicator
758          $header .= pack('a2', '00');                        // ustar version
759          $header .= pack('a32', 'Unknown');                    // owner name
760          $header .= pack('a32', 'Unknown');                    // group name
761          $header .= pack('a8', '');                            // device major number
762          $header .= pack('a8', '');                            // device minor number
763          $header .= pack('a155', '');                        // filename prefix
764          $header .= pack('a12', '');                            // end
765   
766          // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512
767          $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : ''));
768          unset($data);
769      }
770   
771      /**
772      * Open archive
773      */
774      function open()
775      {
776          $fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen');
777          $this->fp = @$fzopen($this->file, $this->mode . (($fzopen == 'bzopen') ? '' : 'b') . (($fzopen == 'gzopen') ? '9' : ''));
778   
779          if (!$this->fp)
780          {
781              trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]');
782          }
783      }
784   
785      /**
786      * Download archive
787      */
788      function download($filename, $download_name = false)
789      {
790          global $phpbb_root_path;
791   
792          if ($download_name === false)
793          {
794              $download_name = $filename;
795          }
796   
797          switch ($this->type)
798          {
799              case '.tar':
800                  $mimetype = 'application/x-tar';
801              break;
802   
803              case '.tar.gz':
804                  $mimetype = 'application/x-gzip';
805              break;
806   
807              case '.tar.bz2':
808                  $mimetype = 'application/x-bzip2';
809              break;
810   
811              default:
812                  $mimetype = 'application/octet-stream';
813              break;
814          }
815   
816          header('Cache-Control: private, no-cache');
817          header("Content-Type: $mimetype; name=\"$download_name$this->type\"");
818          header("Content-disposition: attachment; filename=$download_name$this->type");
819   
820          $fp = @fopen("{$phpbb_root_path}store/$filename$this->type", 'rb');
821          if ($fp)
822          {
823              while ($buffer = fread($fp, 1024))
824              {
825                  echo $buffer;
826              }
827              fclose($fp);
828          }
829      }
830  }
831