Logo Search packages:      
Sourcecode: dacode version File versions  Download package

tar.php3

<?php
/**
 * Create and extract tar archives
 *
 * daCode http://www.dacode.org/
 * src/phplib/tar.php3
 * $Id: tar.php3,v 1.17.2.1 2002/05/15 17:27:04 jbcombes Exp $
 *
 *@author Denis Barbier <barbier@linuxfr.org>
 */
Class Tar {

      /**
       * Array describing tar format
       *@var array
       */
      var $format;

      /**
       * Unknown..
       *@var string
       */
      var $x_fmt;

      /**
       * Unknown
       *@var string
       */
      var $c_fmt;

      /**
       * When set to 1, file descriptor points to a header, otherwise it points to body file
       *@var boolean 
       */
      var $begin;

      /**
       * Controls whether we shall print debugung info
       *@var boolean
       */
      var  $debug;

      /**
       * When set, do not perform any action
       *@var boolean
       */
      var $noact;

      /**
       * Class constructor
       */
      Function tar() {
            global $config;

            $this->format = array(
                  'name'      => array(   0,   100,  "a99x") ,
                  'mode'      => array( 100,     8,   "A7x", "%07o\0") ,
                  'uid'       => array( 108,     8,   "A7x", "%07o\0") ,
                  'gid'       => array( 116,     8,   "A7x", "%07o\0") ,
                  'size'      => array( 124,    11,   "A11", "%011o") ,
                  'space1'    => array( 135,     1,   "A1") ,
                  'mtime'     => array( 136,    11,   "a11", "%011o") ,
                  'space2'    => array( 147,     1,   "A1") ,
                  'chksum'    => array( 148,     6,   "a6",  "%06o") ,
                  'space3'    => array( 154,     2,   "A2") ,
                  'typeflag'  => array( 156,     1,   "a1") ,
                  'linkname'  => array( 157,   100,   "a99x") ,
                  'magic'     => array( 257,     8,   "a8"),
                  'uname'     => array( 265,    32,   "a31x") ,
                  'gname'     => array( 297,    32,   "a31x") ,
                  'devmajor'  => array( 329,     8,   "a7x"),
                  'devminor'  => array( 337,     8,   "a7x"),
                  'prefix'    => array( 345,   155,   "a154x") ,
                  'space4'    => array( 500,    12,   "a12")
            );
            $s = '';
            reset($this->format);
            while (list($key, $val) = each($this->format)) {
                  if (ereg('x$', $val[2])) {
                        $s .= '/'.substr($val[2], 0, -1).$key.'/x';
                  } else {
                        $s .= '/'.$val[2].$key;
                  }
            }
            $this->x_fmt = substr($s, 1);
            $s = '';
            reset($this->format);
            while (list($key, $val) = each($this->format)) {
                  $s .= $val[2];
            }
            $this->c_fmt = $s;

            $this->olddir = '';

            //  When $this->begin is 1, file descriptor points to
            //  a header, otherwise it points to body file
            $this->begin = 1;

            //   When set, be verbose
            $this->debug = 0;
            //   When set, do not perform any action
            $this->noact = 0;
      }

      /**
       * Print a string if debuging is welcome
       * Calls echo in debuging mode. 
       *@param string the string to print 
       *@access private
       */
      Function verbose($string) {
            if ($this->debug) {
                  echo $string."\n";
            }
      }
      //Define functions to work with compressed and uncompressed files in a transparent 
      //manner
      /**
       * Opens a file, be it gzipped or not
       *@param string name of the file
       *@param string the mode (r or w)
       *@return integer file descriptor
       *@access private
       */
      Function fopen($filename,$mode) {
            if ($this->gz) {
                  $fd = gzopen($filename,$mode);
            } else {
                  $fd = fopen($filename,$mode);
            }
            return $fd;
      }

      /**
       * Closes a file
       *@param integer file descriptor
       *@access private
       */
      Function fclose($fd) {
            if ($this->gz) {
                  gzclose($fd);
            } else {
                  fclose($fd);
            }
      }

      /**
       * Reads from  file
       * Behaves as fread standard function.
       *@param integer file descriptor
       *@param integer number of bytes to read
       *@return string the value read
       *@access private
       */
      Function fread($fd,$size) {
            if ($this->gz) {
                  $str = gzread($fd,$size);
            } else {
                  $str = fread($fd,$size);
            }
            return $str;
      }


      /**
       * Writes to a file
       * see normal fwrite.
       *@param integer file descriptor
       *@param string data to write
       *@param integer size of data to write
       *@access private
       */
      Function fwrite($fd,$string,$size=0) {
            if ($this->gz) {
                  if ($size) {
                        gzwrite($fd,$string,$size);
                  } else {
                        gzwrite($fd,$string);
                  }
            } else {
                  if ($size) {
                        fwrite($fd,$string,$size);
                  } else {
                        fwrite($fd,$string);
                  }
            }
      }
      
      /**
       * Determines if EOF has been passed
       *@param integer file descriptor
       *@return boolean true if EOF reached or error, false otherwise
       *@access private
       */
      Function feof($fd) {
            if ($this->gz) {
                  $eof = gzeof($fd);
            } else {
                  $eof = feof($fd);
            }
            return $eof;
      }

      /**
       *  Open a tarfile, it may be at a different location
       * Calls echo on failure
       *@param string the name of the file
       *@param string directory where archive is to be unpacked
       *@return mixed integer file descriptor on success, void on failure
       *@access private
       */
      Function open_read($filename,$destdir="") {
            $this->destdir = $destdir;
            $fd = $this->fopen($filename, "rb");
            if (!$fd) {
                  echo lecho("Cannot read file")." $filename\n";
                  return;
            }
            if ($destdir) {
                  //   Store previous location
                  $this->olddir = chop(`pwd`);
                  chdir($destdir);
            }
            return $fd;
      }

      /**   
       * Read a 512-byte block containing file informations
       * Calls echo on failure
       *@param integer file descriptor
       *@param array subsitutions to perform on headers ????
       *@return array the headers of the tar file
       *@access private
       */
      Function read_header($fd,$subs) {
            $header = array();
            if (!$this->begin) {
                  echo lecho("File pointer misplaced: not at header position");
                  return;
            }
            $data = $this->fread($fd, 512);
            $header = unpack($this->x_fmt, $data);
            $this->begin = 0;
            reset($subs);
            while ($f = each($subs)) {
                  $g = current($subs);
                  $header["name"] = ereg_replace($f[1], $g, $header["name"]);
                  next($subs);
            }
            if ($this->debug) {
                  $this->display_header($header);
            }
            return $header;
      }

      /**
       * Read file contents
       * Calls echo on failure
       *@param integer file descriptor
       *@param integer type of the file to read in archive 
       *@param integer size of data to read
       *@return string data read, empty string on failure
       *@access private
       */
      Function read_body($fd,$type,$size) {
            if ($this->begin) {
                  echo lecho("File pointer misplaced: not at body position");
                  return;
            }
            $this->begin = 1;
            $body = '';

            if ($type == 5) {
                  //   Directory
                  return '';
            } elseif ($type == 0) {
                  //   Regular file
                  $size = octdec($size);
                  $res = $size % 512;
                  $body = $this->fread($fd, $size);
                  if ($res > 0) {
                        $this->fread($fd, 512 - $res);
                  }
            } else {
                  echo lecho("Error: file type not authorized")."<br />";
            }
            return $body;
      }

      /**
       * Display header informations
       *@param array hash name=> value of the header
       *@return HTML formatted list of header
       *@access private
       */
      Function display_header($header) {
            if (!$header || !is_array($header)) {
                  return;
            }
            reset($header);
            while (list($key, $val) = each($header)) {
                  if (!ereg('space', $key)) {
                        if ($key == 'uid' || $key == 'gid' || $key == 'size' ) {
                              $val = octdec($val);
                        } elseif ($key == 'mtime') {
                              $val = date("Y-M-d H:i:s", octdec($val));
                        }
                        echo '<br /><b>'.$key.'</b>:'.$val."\n";
                  }
            }
            echo "<br />\n";
      }

      /**
       * Extract a tar file
       * May call echo on error
       *@param string name of the file to extract
       *@param boolean true if file is zipped
       *@param mixed array substitutions to perform on headers or empty string
       *@param string destination directory
       *@param string mode for created files
       *@param string mode for the directories ro create
       *@return integer 0 if failure, file descriptor on success
       *@access public
       */
      Function extract($filename,$gz,$subs="",$destdir="",$filemode="0644",$dirmode="0755") {
            $this->gz = $gz;
            if (!is_array($subs)) {
                  $subs = array();
            }
            $fd = $this->open_read($filename,$destdir);
            if (!$fd) {
                  return 0;
            }
            $seen = 0;
            while (!$this->feof($fd)) {
                  $header = $this->read_header($fd,$subs);
                  if (empty($header["name"]) && $seen) {
                        //  EOF
                        break;
                  }
                  $seen = 1;
                  $body = $this->read_body($fd,$header["typeflag"],$header["size"]);
                  if ($header["typeflag"] == 5) {
                        $this->verbose(lecho("Create dir ").$header["name"].'<br />');
                        if (!$this->noact) {
                              mkdir($header["name"], octdec($dirmode));
                        }
                  } elseif ($header["typeflag"] == 0) {
                        $this->verbose(lecho("Create file ").$header["name"].
                              " size: ".octdec($header['size'])." bytes<br />\n");
                        if (!$this->noact) {
                              $out = fopen($header["name"], "wb");
                              if (!$out) {
                                    $this->verbose(lecho("Unable to write to ").$header["name"]);
                                    continue;
                              }
                              fwrite($out, $body);
                              fclose($out);
                        }
                  } else {
                        echo lecho("Error: file type not authorized")."<br />";
                  }
            }
            $this->fclose($fd);
            if ($this->olddir) {
                  chdir($this->olddir);
            }
            return $fd;
      }

      /**
       * Display contents of a tar file
       *@param string name of the file to extract
       *@param boolean true if file is zipped
       *@param mixed array substitutions to perform on headers or empty string
       *@param string destination directory
       *@return mixed array list of file on success, void on failure
       *@access public
       */
      Function files($filename,$gz,$subs="",$destdir="") {
            $this->gz = $gz;
            if (!is_array($subs)) {
                  $subs = array();
            }
            $list = array();
            $fd = $this->open_read($filename,$destdir);
            if (!$fd) {
                  return;
            }
            $seen = 0;
            while (!$this->feof($fd)) {
                  $header = $this->read_header($fd,$subs);
                  if (empty($header["name"]) && $seen) {
                        //  EOF
                        break;
                  }
                  $seen = 1;
                  $body = $this->read_body($fd,$header["typeflag"],$header["size"]);
                  if ($header["typeflag"] == 0) {
                        $list[] = $header["name"];
                  }
            }
            $this->fclose($fd);
            if ($this->olddir) {
                  chdir($this->olddir);
            }
            return $list;
      }

      /**
       * Show content of a file in the archive
       *@param string name of the file to extract
       *@param boolean true if file is zipped
       *@param string name of the file we wannna display
       *@param mixed array substitutions to perform on headers or empty string
       *@return mixed array list of file on success, void on failure
       *@access public
       */
      Function file_content($filename,$gz,$file,$subs="") {
            $this->gz = $gz;
            if (!is_array($subs)) {
                  $subs = array();
            }
            $fd = $this->open_read($filename);
            if (!$fd) {
                  return;
            }
            $seen = 0;
            while (!$this->feof($fd)) {
                  $header = $this->read_header($fd,$subs);
                  if (empty($header["name"]) && $seen) {
                        //  EOF
                        break;
                  }
                  $seen = 1;
                  $body = $this->read_body($fd,$header["typeflag"],$header["size"]);
                  if ($header["name"] == $file) {
                        $this->fclose($fd);
                        return $body;
                  }
            }
            $this->fclose($fd);
            if ($this->olddir) {
                  chdir($this->olddir);
            }
      }

      /**
       * Open a tarfile for writing
       *@param string name of the file
       *@param string directory where the file is to be created
       *@return integer file descriptor on success, vvoid on failure
       *@access private
       */
      Function open_write($filename,$fromdir="") {
            if ($fromdir) {
                  $this->olddir = chop(`pwd`);
                  chdir($fromdir);
            }
            umask(022);
            $fd = $this->fopen($filename, "wb");
            if (!$fd) {
                  echo lecho("Cannot write file")." $filename\n";
                  if ($fromdir) chdir($this->olddir);
                  return;
            }
            return $fd;
      }

      /**
       * Compute checksum
       *@param string data which we wnt the chacksum
       *@return string the checksum
       *@access private
       */
      Function compute_checksum($bindata) {
            $chksum = 0;
            $nbytes = $this->format["chksum"][1]+2;
            $hexstr = bin2hex(substr($bindata,0,$this->format["chksum"][0]).
                  pack("A".$nbytes, ' ').
                  substr($bindata,$this->format["chksum"][0]+$nbytes));
            for ($i = 0; $i < 512; $i++) {
                  $chksum += hexdec(substr($hexstr, 2*$i, 2));
            }
            $chksum = $chksum % 65535;
            $chksum = sprintf($this->format["chksum"][3], $chksum);
            return $chksum;
      }

      /**
       * Write a 512-byte block containing file informations
       * Calls echo on failure
       *@param integer file descriptor
       *@param array headers to write
       *@access private
       */
      Function write_header($fd,$header) {
            if (!$this->begin) {
                  echo lecho("File pointer misplaced: not at header position");
                  return;
            }
            $bindata = '';
            reset($header);
            while (list($key, $val) = each($header)) {
                  if (isset($this->format[$key][3])) {
                        $val = sprintf($this->format[$key][3], $val);
                  }
                  $bindata .= pack($this->format[$key][2], $val);
            }
            $chksum = $this->compute_checksum($bindata);
            $bindata = substr($bindata,0,$this->format["chksum"][0]).
                  pack($this->format["chksum"][2], $chksum).
                  substr($bindata,$this->format["chksum"][0]+$this->format["chksum"][1]);
            if (!$this->noact) {
                  $this->totalsize += 512;
                  $this->fwrite($fd, $bindata, 512);
            }
            $this->begin = 0;
      }

      /**
       * Write file contents
       * Calls echo on failure
       *@param integer file descriptor
       *@param integer type of file
       *@param integer size of file to write
       *@param integer name of file to write
       *@access private
       */

      Function write_body($fd,$type,$size,$name) {
            if ($this->begin) {
                  echo lecho("File pointer misplaced: not at body position");
                  return;
            }
            $this->begin = 1;
            if ($type == 5) {
                  //   Directory
                  return;
            } elseif ($type == 0) {
                  //   Regular file
                  $in = fopen($name, "rb");
                  if (!$in) {
                        echo lecho("Cannot read file")." $name <br />";
                        continue;
                  }
                  $body = fread($in, $size);
                  fclose($in);
                  if (!$this->noact) {
                        $this->totalsize += $size;
                        $this->fwrite($fd, $body, $size+0);
                        $res = $size % 512;
                        if ($res > 0) {
                              $this->totalsize += 512 - $res;
                              $this->fwrite($fd, pack("a".(512 - $res), ''));
                        }
                  }
            } else {
                  echo lecho("Error: file type not authorized")."<br />";
            }
      }

      /**
       * Add an entry to the tarfile
       *@param integer file descriptor
       *@param integer name of file to write
       *@param array files to exclude
       *@param array substitutions to performs
       *@access private
       */

      Function add_entry($fd,$name,$excludes,$subs) {
            reset($excludes);
            while ($f = each($excludes)) {
                  if (ereg($f[1], $name)) {
                        return;
                  }
            }
            $filename = $name;
            reset($subs);
            while ($f = each($subs)) {
                  $g = current($subs);
                  $filename = ereg_replace($f[1], $g, $filename);
                  next($subs);
            }

            $info = stat($name);
            $size = $info[7];
            if (!is_readable($name)) {
                  $this->verbose(lecho("Skipped non-existing ").$filename.'<br />');
                  return;
            } elseif (is_file($name)) {
                  $type = 0;
                  $this->verbose(lecho("Add file ").$filename.' size '.$size.' bytes <br />');
            } elseif (is_dir($name)) {
                  $type = 5;
                  $name .= '/';
                  $size = 0;
                  $this->verbose(lecho("Add dir ").$filename.'<br />');
            } else {
                  echo lecho("Error: file type not authorized").
                        lecho(" for file ").$filename." <br />";
                  return;
            }
            $header = array(
                  'name'      => $filename,
                  'mode'      => $info[2],
                  'uid'       => 0,
                  'gid'       => 0,
                  'size'      => $size,
                  'space1'    => "\0",
                  'mtime'     => $info[9],
                  'space2'    => "\0",
                  'chksum'    => '0',
                  'space3'    => "\0",
                  'typeflag'  => $type,
                  'linkname'  => '',
                  'magic'     => 'ustar  ',
                  'uname'     => 'root',
                  'gname'     => 'root',
                  'devmajor'  => '',
                  'devminor'  => '',
                  'prefix'    => '',
                  'space4'    => ''
            );
            $this->write_header($fd,$header);
            $this->write_body($fd,$type,$size,$name);
            if (is_dir($name)) {
                  //   Process directory recursively
                  $handle=opendir($name);
                  while ($file = readdir($handle)) {
                        if ($file == '.' || $file == '..') continue;
                        $this->add_entry($fd,$name.$file,$excludes,$subs);
                  }
            }
      }

      /**
       * Write an archive
       *@param string file name
       *@param string content of the file
       *@param boolean true if file is to be gzipped
       *@param mixed empty string or array of i=filenames to exclude
       *@param mixed subs empty string or array of substitutions to perform on archive headers
       *@param string directory where the files of the archive come from???
       *@access public
       */
      Function create($filename,$contents,$gz=false,$excludes="",
                                                      $subs="",$fromdir="") {
            $this->gz = $gz;
            if (!$this->noact) {
                  $fd = $this->open_write($filename,$fromdir);
                  if (!$fd) {
                        return 0;
                  }
            } else {
                  $fd = 0;
            }
            if (is_string($contents)) {
                  $contents = array($contents);
            }
            if (!is_array($excludes)) {
                  $excludes = array();
            }
            if (!is_array($subs)) {
                  $subs = array();
            }
            $this->totalsize = 0;
            while ($piece = each($contents)) {
                  $this->add_entry($fd, $piece[1],$excludes,$subs);
            }
            if (!$this->noact) {
                  $res = $this->totalsize % 10240;
                  if ($res > 0) {
                        $this->totalsize += 10240 - $res;
                        $this->fwrite($fd, pack("a".(10240 - $res), ''));
                  }
                  $this->fclose($fd);
            }
            if ($fromdir) {
                  chdir($this->olddir);
            }
            //   When noact is set, this function returns 0 because tarfile
            //   is not created
            return $fd;
      }
}

?>

Generated by  Doxygen 1.6.0   Back to index