home *** CD-ROM | disk | FTP | other *** search
/ PC Basics 53 / PC Basics Issue 53.iso / Software / Internet / Invboard.exe / PC Basics 53 / Invboard / upload / sources / lib / tar.php < prev    next >
Encoding:
PHP Script  |  2002-06-12  |  22.5 KB  |  844 lines

  1. <?php
  2.  
  3. /*
  4. +--------------------------------------------------------------------------
  5. |   IBFORUMS v1
  6. |   ========================================
  7. |   by Matthew Mecham and David Baxter
  8. |   (c) 2001,2002 IBForums
  9. |   http://www.ibforums.com
  10. |   ========================================
  11. |   Web: http://www.ibforums.com
  12. |   Email: phpboards@ibforums.com
  13. |   Licence Info: phpib-licence@ibforums.com
  14. +---------------------------------------------------------------------------
  15. |
  16. |   > GNU Tar creation and extraction module
  17. |   > Module written by Matt Mecham
  18. |   > Usage style based on the C and Perl GNU modules
  19. |   > Will only work with PHP 4+
  20. |   
  21. |   > Date started: 15th Feb 2002
  22. |
  23. |    > Module Version Number: 1.0.0
  24. |   > Module Author: Matthew Mecham
  25. +--------------------------------------------------------------------------
  26. |
  27. | QUOTE OF THE MODULE:
  28. |  If you can't find a program the does what you want it to do, write your
  29. |  own.
  30. |
  31. +--------------------------------------------------------------------------
  32. */
  33.  
  34. /*************************************************************
  35. |
  36. | EXTRACTION USAGE:
  37. |
  38. | $tar = new tar();
  39. | $tar->new_tar("/foo/bar", "myTar.tar");
  40. | $files = $tar->list_files();
  41. | $tar->extract_files( "/extract/to/here/dir" );
  42. |
  43. | CREATION USAGE:
  44. |
  45. | $tar = new tar();
  46. | $tar->new_tar("/foo/bar" , "myNewTar.tar");
  47. | $tar->current_dir("/foo" );  //Optional - tells the script which dir we are in
  48. |                                to syncronise file creation from the tarball
  49. | $tar->add_files( $file_names_with_path_array );
  50. | (or $tar->add_directory( "/foo/bar/myDir" ); to archive a complete dir)
  51. | $tar->write_tar();
  52. |
  53. *************************************************************/
  54.  
  55.  
  56.  
  57. class tar {
  58.     
  59.     var $tar_header_length = '512';
  60.     var $tar_unpack_header = 'a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typeflag/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155/prefix';
  61.     var $tar_pack_header   = 'A100 A8 A8 A8 A12 A12 A8 A1 A100 A6 A2 A32 A32 A8 A8 A155';
  62.     var $current_dir       = "";
  63.     var $unpack_dir        = "";
  64.     var $pack_dir          = "";
  65.     var $error             = "";
  66.     var $work_dir          = array();
  67.     var $tar_in_mem        = array();
  68.     var $tar_filename      = "";
  69.     var $filehandle        = "";
  70.     var $warnings          = array();
  71.     var $attributes        = array();
  72.     var $tarfile_name      = "";
  73.     var $tarfile_path      = "";
  74.     var $tarfile_path_name = "";
  75.     var $workfiles         = array();
  76.     
  77.     //+--------------------------------------------------------------------------
  78.     // CONSTRUCTOR: Attempt to guess the current working dir.
  79.     //+--------------------------------------------------------------------------
  80.     
  81.     function tar() {
  82.         global $HTTP_SERVER_VARS;
  83.         
  84.         if ($this_dir = getcwd())
  85.         {
  86.             $this->current_dir = $this_dir;
  87.         }
  88.         else if (isset($HTTP_SERVER_VARS['DOCUMENT_ROOT']))
  89.         {
  90.             $this->current_dir = $HTTP_SERVER_VARS['DOCUMENT_ROOT'];
  91.         }
  92.         else
  93.         {
  94.             $this->current_dir = './';
  95.         }
  96.         
  97.         // Set some attributes, these can be overriden later
  98.         
  99.         $this->attributes = array(  'over_write_existing'   => 0,
  100.                                     'over_write_newer'      => 0,
  101.                                     'remove_tar_file'       => 0,
  102.                                     'remove_original_files' => 0,
  103.                                  );
  104.     }
  105.     
  106.     //+--------------------------------------------------------------------------
  107.     // Set the tarname. If we are extracting a tarball, then it must be the
  108.     // path to the tarball, and it's name (eg: $tar->new_tar("/foo/bar" ,'myTar.tar')
  109.     // or if we are creating a tar, then it must be the path and name of the tar file
  110.     // to create.
  111.     //+--------------------------------------------------------------------------
  112.     
  113.     function new_tar($tarpath, $tarname) {
  114.         
  115.         $this->tarfile_name = $tarname;
  116.         $this->tarfile_path = $tarpath;
  117.         
  118.         // Make sure there isn't a trailing slash on the path
  119.         
  120.         $this->tarfile_path = preg_replace( "#[/\\\]$#" , "" , $this->tarfile_path );
  121.         
  122.         $this->tarfile_path_name = $this->tarfile_path .'/'. $this->tarfile_name; 
  123.         
  124.     }
  125.     
  126.     
  127.     //+--------------------------------------------------------------------------
  128.     // Easy way to overwrite defaults
  129.     //+--------------------------------------------------------------------------
  130.     
  131.     function over_write_existing() {
  132.         $this->attributes['over_write_existing'] = 1;
  133.     }
  134.     function over_write_newer() {
  135.         $this->attributes['over_write_newer'] = 1;
  136.     }
  137.     function remove_tar_file() {
  138.         $this->attributes['remove_tar_file'] = 1;
  139.     }
  140.     function remove_original_files() {
  141.         $this->attributes['remove_original_files'] = 1;
  142.     }
  143.     
  144.     
  145.     
  146.     //+--------------------------------------------------------------------------
  147.     // User assigns the root directory for the tar ball creation/extraction
  148.     //+--------------------------------------------------------------------------
  149.     
  150.     function current_dir($dir = "") {
  151.         
  152.         $this->current_dir = $dir;
  153.         
  154.     }
  155.     
  156.     //+--------------------------------------------------------------------------
  157.     // list files: returns an array with all the filenames in the tar file
  158.     //+--------------------------------------------------------------------------
  159.     
  160.     function list_files($advanced="") {
  161.     
  162.         // $advanced == "" - return name only
  163.         // $advanced == 1  - return name, size, mtime, mode
  164.     
  165.         $data = $this->read_tar();
  166.         
  167.         $final = array();
  168.         
  169.         foreach($data as $d)
  170.         {
  171.             if ($advanced == 1)
  172.             {
  173.                 $final[] = array ( 'name'  => $d['name'],
  174.                                    'size'  => $d['size'],
  175.                                    'mtime' => $d['mtime'],
  176.                                    'mode'  => substr(decoct( $d['mode'] ), -4),
  177.                                  );
  178.             }
  179.             else
  180.             {
  181.                 $final[] = $d['name'];
  182.             }
  183.         }
  184.         
  185.         return $final;
  186.     }
  187.     
  188.     //+--------------------------------------------------------------------------
  189.     // Add a directory to the tar files.
  190.     // $tar->add_directory( str(TO DIRECTORY) )
  191.     //    Can be used in the following methods.
  192.     //      $tar->add_directory( "/foo/bar" );
  193.     //      $tar->write_tar( "/foo/bar" );
  194.     //+--------------------------------------------------------------------------
  195.     
  196.     function add_directory( $dir ) {
  197.     
  198.         $this->error = "";
  199.     
  200.         // Make sure the $to_dir is pointing to a valid dir, or we error
  201.         // and return
  202.         
  203.         if (! is_dir($dir) )
  204.         {
  205.             $this->error = "Extract files error: Destination directory ($to_dir) does not exist";
  206.             return FALSE;
  207.         }
  208.         
  209.         $cur_dir = getcwd();
  210.         chdir($dir);
  211.         
  212.         $this->get_dir_contents("./");
  213.         
  214.         $this->add_files($this->workfiles, $dir);
  215.         
  216.         chdir($cur_dir);
  217.         
  218.     }
  219.     
  220.     //-------------------------------------
  221.     
  222.     function get_dir_contents( $dir )
  223.     {
  224.     
  225.         $dir = preg_replace( "#/$#", "", $dir );
  226.         
  227.         if ( file_exists($dir) )
  228.         {
  229.             if ( is_dir($dir) )
  230.             {
  231.                 $handle = opendir($dir);
  232.                 
  233.                 while (($filename = readdir($handle)) !== false)
  234.                 {
  235.                     if (($filename != ".") && ($filename != ".."))
  236.                     {
  237.                         if (is_dir($dir."/".$filename))
  238.                         {
  239.                             $this->get_dir_contents($dir."/".$filename);
  240.                         }
  241.                         else
  242.                         {
  243.                             $this->workfiles[] = $dir."/".$filename;
  244.                         }
  245.                     }
  246.                 }
  247.                 
  248.                 closedir($handle);
  249.             }
  250.             else
  251.             {
  252.                 $this->error = "$dir is not a directory";
  253.                 return FALSE;
  254.             }
  255.         }
  256.         else
  257.         {
  258.             $this->error = "Could not locate $dir";
  259.             return;
  260.         }
  261.     }
  262.     
  263.     //+--------------------------------------------------------------------------
  264.     // Extract the tarball
  265.     // $tar->extract_files( str(TO DIRECTORY), [ array( FILENAMES )  ] )
  266.     //    Can be used in the following methods.
  267.     //      $tar->extract( "/foo/bar" , $files );
  268.     //       This will seek out the files in the user array and extract them
  269.     //    $tar->extract( "/foo/bar" );
  270.     //    Will extract the complete tar file into the user specified directory
  271.     //+--------------------------------------------------------------------------
  272.     
  273.     function extract_files( $to_dir, $files="" ) {
  274.     
  275.         $this->error = "";
  276.     
  277.         // Make sure the $to_dir is pointing to a valid dir, or we error
  278.         // and return
  279.         
  280.         if (! is_dir($to_dir) )
  281.         {
  282.             $this->error = "Extract files error: Destination directory ($to_dir) does not exist";
  283.             return;
  284.         }
  285.         
  286.         //---------------------------------------------
  287.         // change into the directory chosen by the user.
  288.         //---------------------------------------------
  289.         
  290.         chdir($to_dir);
  291.         $cur_dir = getcwd();
  292.         
  293.         $to_dir_slash = $to_dir . "/";
  294.         
  295.         //+------------------------------
  296.         // Get the file info from the tar
  297.         //+------------------------------
  298.         
  299.         $in_files = $this->read_tar();
  300.         
  301.         if ($this->error != "") {
  302.             return;
  303.         }
  304.         
  305.         foreach ($in_files as $k => $file) {
  306.         
  307.             //---------------------------------------------
  308.             // Are we choosing which files to extract?
  309.             //---------------------------------------------
  310.             
  311.             if (is_array($files))
  312.             {
  313.                 if (! in_array($file['name'], $files) )
  314.                 {
  315.                     continue;
  316.                 }
  317.             }
  318.             
  319.             chdir($cur_dir);
  320.             
  321.             //---------------------------------------------
  322.             // GNU TAR format dictates that all paths *must* be in the *nix
  323.             // format - if this is not the case, blame the tar vendor, not me!
  324.             //---------------------------------------------
  325.             
  326.             if ( preg_match("#/#", $file['name']) )
  327.             {
  328.                 $path_info = explode( "/" , $file['name'] );
  329.                 $file_name = array_pop($path_info);
  330.             } else
  331.             {
  332.                 $path_info = array();
  333.                 $file_name = $file['name'];
  334.             }
  335.             
  336.             //---------------------------------------------
  337.             // If we have a path, then we must build the directory tree
  338.             //---------------------------------------------
  339.             
  340.             
  341.             if (count($path_info) > 0)
  342.             {
  343.                 foreach($path_info as $dir_component)
  344.                 {
  345.                     if ($dir_component == "")
  346.                     {
  347.                         continue;
  348.                     }
  349.                     if ( (file_exists($dir_component)) && (! is_dir($dir_component)) )
  350.                     {
  351.                         $this->warnings[] = "WARNING: $dir_component exists, but is not a directory";
  352.                         continue;
  353.                     }
  354.                     if (! is_dir($dir_component))
  355.                     {
  356.                         mkdir( $dir_component, 0777);
  357.                         chmod( $dir_component, 0777);
  358.                     }
  359.                     
  360.                     if (! @chdir($dir_component))
  361.                     {
  362.                         $this->warnings[] = "ERROR: CHDIR to $dir_component FAILED!";
  363.                     }
  364.                 }
  365.             }
  366.             
  367.             //---------------------------------------------
  368.             // check the typeflags, and work accordingly
  369.             //---------------------------------------------
  370.             
  371.             if (($file['typeflag'] == 0) or (!$file['typeflag']) or ($file['typeflag'] == ""))
  372.             {
  373.                 if ( $FH = fopen($file_name, "wb") )
  374.                 {
  375.                     fputs( $FH, $file['data'], strlen($file['data']) );
  376.                     fclose($FH);
  377.                 }
  378.                 else
  379.                 {
  380.                     $this->warnings[] = "Could not write data to $file_name";
  381.                 }
  382.             }
  383.             else if ($file['typeflag'] == 5)
  384.             {
  385.                 if ( (file_exists($file_name)) && (! is_dir($file_name)) )
  386.                 {
  387.                     $this->warnings[] = "$file_name exists, but is not a directory";
  388.                     continue;
  389.                 }
  390.                 if (! is_dir($file_name))
  391.                 {
  392.                     mkdir( $file_name, 0777);
  393.                 }
  394.             }
  395.             else if ($file['typeflag'] == 6)
  396.             {
  397.                 $this->warnings[] = "Cannot handle named pipes";
  398.                 continue;
  399.             }
  400.             else if ($file['typeflag'] == 1)
  401.             {
  402.                 $this->warnings[] = "Cannot handle system links";
  403.             }
  404.             else if ($file['typeflag'] == 4)
  405.             {
  406.                 $this->warnings[] = "Cannot handle device files";
  407.             }    
  408.             else if ($file['typeflag'] == 3)
  409.             {
  410.                 $this->warnings[] = "Cannot handle device files";
  411.             }
  412.             else
  413.             {
  414.                 $this->warnings[] = "Unknown typeflag found";
  415.             }
  416.             
  417.             if (! @chmod( $file_name, $file['mode'] ) )
  418.             {
  419.                 $this->warnings[] = "ERROR: CHMOD $mode on $file_name FAILED!";
  420.             }
  421.             
  422.             @touch( $file_name, $file['mtime'] );
  423.             
  424.         }
  425.         
  426.         // Return to the "real" directory the scripts are in
  427.         
  428.         @chdir($this->current_dir);
  429.         
  430.     }
  431.         
  432.     //+--------------------------------------------------------------------------
  433.     // add files:
  434.     //  Takes an array of files, and adds them to the tar file
  435.     //  Optionally takes a path to use as root for the tar file - if omitted, it
  436.     //  assumes the current working directory is the tarball root. Be careful with
  437.     //  this, or you may get unexpected results -especially when attempting to read
  438.     //  and add files to the tarball.
  439.     //  EXAMPLE DIR STRUCTURE
  440.     //  /usr/home/somedir/forums/sources
  441.     //  BRIEF: To tar up the sources directory
  442.     // $files = array( 'sources/somescript.php', 'sources/anothersscript.php' );
  443.     //  If CWD is 'somedir', you'll need to use $tar->add_files( $files, "/usr/home/somedir/forums" );
  444.     //  or it'll attempt to open /usr/home/somedir/sources/somescript.php - which would result
  445.     //  in an error. Either that, or use:
  446.     //  chdir("/usr/home/somedir/forums");
  447.     //  $tar->add_files( $files );
  448.     //+--------------------------------------------------------------------------
  449.     
  450.     function add_files( $files, $root_path="" ) {
  451.     
  452.         // Do we a root path to change into?
  453.         
  454.         if ($root_path != "") {
  455.             chdir($root_path);
  456.         }
  457.         
  458.         $count    = 0;
  459.         
  460.         foreach ($files as $file) {
  461.         
  462.             // is it a Mac OS X work file?
  463.             
  464.             if ( preg_match("/\.ds_store/i", $file ) )
  465.             {
  466.                 continue;
  467.             }
  468.         
  469.             $typeflag = 0;
  470.             $data     = "";
  471.             $linkname = "";
  472.             
  473.             $stat = stat($file);
  474.             
  475.             // Did stat fail?
  476.             
  477.             if (! is_array($stat) ) {
  478.                 $this->warnings[] = "Error: Stat failed on $file";
  479.                 continue;
  480.             }
  481.             
  482.             $mode  = fileperms($file);
  483.             $uid   = $stat[4];
  484.             $gid   = $stat[5];
  485.             $rdev  = $stat[6];
  486.             $size  = filesize($file);
  487.             $mtime = filemtime($file);
  488.             
  489.             if (is_file($file)) {
  490.                 // It's a plain file, so lets suck it up
  491.                 $typeflag = 0;
  492.                 if ( $FH = fopen($file, 'rb') ) {
  493.                     $data = fread( $FH, filesize($file) );
  494.                     fclose($FH);
  495.                 } else {
  496.                     $this->warnings[] = "ERROR: Failed to open $file";
  497.                     continue;
  498.                 }
  499.             }
  500.             else if (is_link($file)) {
  501.                 $typeflag = 1;
  502.                 $linkname = @readlink($file);
  503.             }
  504.             else if (is_dir($file)) {
  505.                 $typeflag = 5;
  506.             }
  507.             else {
  508.                 // Sockets, Pipes and char/block specials are not
  509.                 // supported, so - lets use a silly value to keep the
  510.                 // tar ball legitimate.
  511.                 $typeflag = 9;
  512.             }
  513.             
  514.             // Add this data to our in memory tar file
  515.             
  516.             $this->tar_in_mem[] = array (
  517.                                           'name'     => $file,
  518.                                           'mode'     => $mode,
  519.                                           'uid'      => $uid,
  520.                                           'gid'      => $gid,
  521.                                           'size'     => strlen($data),
  522.                                           'mtime'    => $mtime,
  523.                                           'chksum'   => "      ",
  524.                                           'typeflag' => $typeflag,
  525.                                           'linkname' => $linkname,
  526.                                           'magic'    => "ustar\0",
  527.                                           'version'  => '00',
  528.                                           'uname'    => 'unknown',
  529.                                           'gname'    => 'unknown',
  530.                                           'devmajor' => "",
  531.                                           'devminor' => "",
  532.                                           'prefix'   => "",
  533.                                           'data'     => $data
  534.                                         );
  535.             // Clear the stat cache
  536.             
  537.             @clearstatcache();
  538.             
  539.             $count++;
  540.         }
  541.         
  542.         @chdir($this->current_dir);
  543.         
  544.         //Return the number of files to anyone who's interested
  545.         
  546.         return $count;
  547.     
  548.     }
  549.     
  550.     //+--------------------------------------------------------------------------
  551.     // write_tar:
  552.     // Writes the tarball into the directory specified in new_tar with a filename
  553.     // specified in new_tar
  554.     //+--------------------------------------------------------------------------
  555.     
  556.     function write_tar() {
  557.     
  558.         if ($this->tarfile_path_name == "") {
  559.             $this->error = 'No filename or path was specified to create a new tar file';
  560.             return;
  561.         }
  562.         
  563.         if ( count($this->tar_in_mem) < 1 ) {
  564.             $this->error = 'No data to write to the new tar file';
  565.             return;
  566.         }
  567.         
  568.         $tardata = "";
  569.         
  570.         foreach ($this->tar_in_mem as $file) {
  571.         
  572.             $prefix = "";
  573.             $tmp    = "";
  574.             $last   = "";
  575.         
  576.             // make sure the filename isn't longer than 99 characters.
  577.             
  578.             if (strlen($file['name']) > 99) {
  579.                 $pos = strrpos( $file['name'], "/" );
  580.                 if (is_string($pos) && !$pos) {
  581.                     // filename alone is longer than 99 characters!
  582.                     $this->error[] = "Filename {$file['name']} exceeds the length allowed by GNU Tape ARchives";
  583.                     continue;
  584.                 }
  585.                 $prefix = substr( $file['name'], 0 , $pos );  // Move the path to the prefix
  586.                 $file['name'] = substr( $file['name'], ($pos+1));
  587.                 if (strlen($prefix) > 154) {
  588.                     $this->error[] = "File path exceeds the length allowed by GNU Tape ARchives";
  589.                     continue;
  590.                 }
  591.             }
  592.             
  593.             // BEGIN FORMATTING (a8a1a100)
  594.             
  595.             $mode  = sprintf("%6s ", decoct($file['mode']));
  596.             $uid   = sprintf("%6s ", decoct($file['uid']));
  597.             $gid   = sprintf("%6s ", decoct($file['gid']));
  598.             $size  = sprintf("%11s ", decoct($file['size']));
  599.             $mtime = sprintf("%11s ", decoct($file['mtime']));
  600.             
  601.             $tmp  = pack("a100a8a8a8a12a12",$file['name'],$mode,$uid,$gid,$size,$mtime);
  602.                         
  603.             $last  = pack("a1"   , $file['typeflag']);
  604.             $last .= pack("a100" , $file['linkname']);
  605.                                 
  606.             $last .= pack("a6", "ustar"); // magic
  607.             $last .= pack("a2", "" ); // version
  608.             $last .= pack("a32", $file['uname']);
  609.             $last .= pack("a32", $file['gname']);
  610.             $last .= pack("a8", ""); // devmajor
  611.             $last .= pack("a8", ""); // devminor
  612.             $last .= pack("a155", $prefix);
  613.             //$last .= pack("a12", "");
  614.             $test_len = $tmp . $last . "12345678";
  615.             $last .= $this->internal_build_string( "\0" , ($this->tar_header_length - strlen($test_len)) );
  616.             
  617.             // Here comes the science bit, handling
  618.             // the checksum.
  619.             
  620.             $checksum = 0;
  621.             
  622.             for ($i = 0 ; $i < 148 ; $i++ ) {
  623.                 $checksum += ord( substr($tmp, $i, 1) );
  624.             }
  625.             
  626.             for ($i = 148 ; $i < 156 ; $i++) {
  627.                 $checksum += ord(' ');
  628.             }
  629.             
  630.             for ($i = 156, $j = 0 ; $i < 512 ; $i++, $j++) {
  631.                 $checksum += ord( substr($last, $j, 1) );
  632.             }
  633.             
  634.             $checksum = sprintf( "%6s ", decoct($checksum) );
  635.             
  636.             $tmp .= pack("a8", $checksum);
  637.             
  638.             $tmp .= $last;
  639.                
  640.                $tmp .= $file['data'];
  641.                
  642.                // Tidy up this chunk to the power of 512
  643.                
  644.                if ($file['size'] > 0)
  645.                {
  646.                    if ($file['size'] % 512 != 0)
  647.                    {
  648.                        $homer = $this->internal_build_string( "\0" , (512 - ($file['size'] % 512)) );
  649.                        $tmp .= $homer;
  650.                    }
  651.                }
  652.                
  653.                $tardata .= $tmp;
  654.         }
  655.         
  656.         // Add the footer
  657.         
  658.         $tardata .= pack( "a512", "" );
  659.         
  660.         // print it to the tar file
  661.         
  662.         $FH = fopen( $this->tarfile_path_name, 'wb' );
  663.         fputs( $FH, $tardata, strlen($tardata) );
  664.         fclose($FH);
  665.         
  666.         @chmod( $this->tarfile_path_name, 0777);
  667.         
  668.         // Done..
  669.     }
  670.            
  671.     //+--------------------------------------------------------------------------
  672.     // Read the tarball - builds an associative array
  673.     //+--------------------------------------------------------------------------
  674.     
  675.     function read_tar() {
  676.     
  677.         $filename = $this->tarfile_path_name;
  678.     
  679.         if ($filename == "") {
  680.             $this->error = 'No filename specified when attempting to read a tar file';
  681.             return array();
  682.         }
  683.         
  684.         if (! file_exists($filename) ) {
  685.             $this->error = 'Cannot locate the file '.$filename;
  686.             return array();
  687.         }
  688.         
  689.         $tar_info = array();
  690.         
  691.         $this->tar_filename = $filename;
  692.         
  693.         // Open up the tar file and start the loop
  694.  
  695.         if (! $FH = fopen( $filename , 'rb' ) ) {
  696.             $this->error = "Cannot open $filename for reading";
  697.             return array();
  698.         }
  699.         
  700.         // Grrr, perl allows spaces, PHP doesn't. Pack strings are hard to read without
  701.         // them, so to save my sanity, I'll create them with spaces and remove them here
  702.         
  703.         $this->tar_unpack_header = preg_replace( "/\s/", "" , $this->tar_unpack_header);
  704.         
  705.         while (!feof($FH)) {
  706.         
  707.             $buffer = fread( $FH , $this->tar_header_length );
  708.             
  709.             // check the block
  710.             
  711.             $checksum = 0;
  712.             
  713.             for ($i = 0 ; $i < 148 ; $i++) {
  714.                 $checksum += ord( substr($buffer, $i, 1) );
  715.             }
  716.             for ($i = 148 ; $i < 156 ; $i++) {
  717.                 $checksum += ord(' ');
  718.             }
  719.             for ($i = 156 ; $i < 512 ; $i++) {
  720.                 $checksum += ord( substr($buffer, $i, 1) );
  721.             }
  722.             
  723.             $fa = unpack( $this->tar_unpack_header, $buffer);
  724.  
  725.             $name     = trim($fa[filename]);
  726.             $mode     = OctDec(trim($fa[mode]));
  727.             $uid      = OctDec(trim($fa[uid]));
  728.             $gid      = OctDec(trim($fa[gid]));
  729.             $size     = OctDec(trim($fa[size]));
  730.             $mtime    = OctDec(trim($fa[mtime]));
  731.             $chksum   = OctDec(trim($fa[chksum]));
  732.             $typeflag = trim($fa[typeflag]);
  733.             $linkname = trim($fa[linkname]);
  734.             $magic    = trim($fa[magic]);
  735.             $version  = trim($fa[version]);
  736.             $uname    = trim($fa[uname]);
  737.             $gname    = trim($fa[gname]);
  738.             $devmajor = OctDec(trim($fa[devmajor]));
  739.             $devminor = OctDec(trim($fa[devminor]));
  740.             $prefix   = trim($fa[prefix]);
  741.             
  742.             if ( ($checksum == 256) && ($chksum == 0) ) {
  743.                 //EOF!
  744.                 break;
  745.             }
  746.             
  747.             if ($prefix) {
  748.                 $name = $prefix.'/'.$name;
  749.             }
  750.             
  751.             // Some broken tars don't set the type flag
  752.             // correctly for directories, so we assume that
  753.             // if it ends in / it's a directory...
  754.             
  755.             if ( (preg_match( "#/$#" , $name)) and (! $name) ) {
  756.                 $typeflag = 5;
  757.             }
  758.             
  759.             // If it's the end of the tarball...
  760.             $test = $this->internal_build_string( '\0' , 512 );
  761.             if ($buffer == $test) {
  762.                 break;
  763.             }
  764.             
  765.             // Read the next chunk
  766.             
  767.             $data = fread( $FH, $size );
  768.             
  769.             if (strlen($data) != $size) {
  770.                 $this->error = "Read error on tar file";
  771.                 fclose( $FH );
  772.                 return array();
  773.             }
  774.             
  775.             $diff = $size % 512;
  776.             
  777.             if ($diff != 0) {
  778.                 // Padding, throw away
  779.                 $crap = fread( $FH, (512-$diff) );
  780.             }
  781.             
  782.             // Protect against tarfiles with garbage at the end
  783.             
  784.             if ($name == "") {
  785.                 break;
  786.             }
  787.             
  788.             $tar_info[] = array (
  789.                                   'name'     => $name,
  790.                                   'mode'     => $mode,
  791.                                   'uid'      => $uid,
  792.                                   'gid'      => $gid,
  793.                                   'size'     => $size,
  794.                                   'mtime'    => $mtime,
  795.                                   'chksum'   => $chksum,
  796.                                   'typeflag' => $typeflag,
  797.                                   'linkname' => $linkname,
  798.                                   'magic'    => $magic,
  799.                                   'version'  => $version,
  800.                                   'uname'    => $uname,
  801.                                   'gname'    => $gname,
  802.                                   'devmajor' => $devmajor,
  803.                                   'devminor' => $devminor,
  804.                                   'prefix'   => $prefix,
  805.                                   'data'     => $data
  806.                                  );
  807.         }
  808.         
  809.         fclose($FH);
  810.         
  811.         return $tar_info;
  812.     }
  813.             
  814.  
  815.  
  816.  
  817.  
  818.  
  819. //+------------------------------------------------------------------------------
  820. // INTERNAL FUNCTIONS - These should NOT be called outside this module
  821. //+------------------------------------------------------------------------------
  822.     
  823.     //+--------------------------------------------------------------------------
  824.     // build_string: Builds a repititive string
  825.     //+--------------------------------------------------------------------------
  826.     
  827.     function internal_build_string($string="", $times=0) {
  828.     
  829.         $return = "";
  830.         for ($i=0 ; $i < $times ; ++$i ) {
  831.             $return .= $string;
  832.         }
  833.         
  834.         return $return;
  835.     }
  836.     
  837.     
  838.     
  839.     
  840.     
  841. }
  842.  
  843.  
  844. ?>