1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * Write the files as a TAR archive 6 * 7 * PHP versions 4 and 5 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA 22 * 23 * @category File Formats 24 * @package File_Archive 25 * @author Vincent Lascaux <vincentlascaux@php.net> 26 * @copyright 1997-2005 The PHP Group 27 * @license http://www.gnu.org/copyleft/lesser.html LGPL 28 * @version CVS: $Id: Tar.php,v 1.18 2005/06/02 12:24:43 vincentlascaux Exp $ 29 * @link http://pear.php.net/package/File_Archive 30 */ 31 32require_once "File/Archive/Writer/Archive.php"; 33 34/** 35 * Write the files as a TAR archive 36 */ 37class File_Archive_Writer_Tar extends File_Archive_Writer_Archive 38{ 39 var $buffer; 40 var $useBuffer; 41 42 var $filename = null; 43 var $stats = null; 44 45 46 /** 47 * Creates the TAR header for a file 48 * 49 * @param string $filename name of the file 50 * @param array $stat statistics of the file 51 * @return string A 512 byte header for the file 52 * @access private 53 */ 54 function tarHeader($filename, $stat) 55 { 56 $mode = isset($stat[2]) ? $stat[2] : 0x8000; 57 $uid = isset($stat[4]) ? $stat[4] : 0; 58 $gid = isset($stat[5]) ? $stat[5] : 0; 59 $size = $stat[7]; 60 $time = isset($stat[9]) ? $stat[9] : time(); 61 $link = ""; 62 63 if ($mode & 0x4000) { 64 $type = 5; // Directory 65 } else if ($mode & 0x8000) { 66 $type = 0; // Regular 67 } else if ($mode & 0xA000) { 68 $type = 1; // Link 69 $link = @readlink($current); 70 } else { 71 $type = 9; // Unknown 72 } 73 74 $filePrefix = ''; 75 if (strlen($filename) > 255) { 76 return PEAR::raiseError( 77 "$filename is too long to be put in a tar archive" 78 ); 79 } else if (strlen($filename) > 100) { 80 $filePrefix = substr($filename, 0, strlen($filename)-100); 81 $filename = substr($filename, -100); 82 } 83 84 $blockbeg = pack("a100a8a8a8a12a12", 85 $filename, 86 decoct($mode), 87 sprintf("%6s ",decoct($uid)), 88 sprintf("%6s ",decoct($gid)), 89 sprintf("%11s ",decoct($size)), 90 sprintf("%11s ",decoct($time)) 91 ); 92 93 $blockend = pack("a1a100a6a2a32a32a8a8a155a12", 94 $type, 95 $link, 96 "ustar", 97 "00", 98 "Unknown", 99 "Unknown", 100 "", 101 "", 102 $filePrefix, 103 ""); 104 105 $checksum = 8*ord(" "); 106 for ($i = 0; $i < 148; $i++) { 107 $checksum += ord($blockbeg{$i}); 108 } 109 for ($i = 0; $i < 356; $i++) { 110 $checksum += ord($blockend{$i}); 111 } 112 113 $checksum = pack("a8",sprintf("%6s ",decoct($checksum))); 114 115 return $blockbeg . $checksum . $blockend; 116 } 117 /** 118 * Creates the TAR footer for a file 119 * 120 * @param int $size the size of the data that has been written to the TAR 121 * @return string A string made of less than 512 characteres to fill the 122 * last 512 byte long block 123 * @access private 124 */ 125 function tarFooter($size) 126 { 127 if ($size % 512 > 0) { 128 return pack("a".(512 - $size%512), ""); 129 } else { 130 return ""; 131 } 132 } 133 134 function flush() 135 { 136 if ($this->filename !== null) { 137 if ($this->useBuffer) { 138 $this->stats[7] = strlen($this->buffer); 139 140 $this->innerWriter->writeData( 141 $this->tarHeader($this->filename, $this->stats) 142 ); 143 $this->innerWriter->writeData( 144 $this->buffer 145 ); 146 } 147 $this->innerWriter->writeData( 148 $this->tarFooter($this->stats[7]) 149 ); 150 } 151 $this->buffer = ""; 152 } 153 154 function newFile($filename, $stats = array(), 155 $mime = "application/octet-stream") 156 { 157 $this->flush(); 158 159 $this->useBuffer = !isset($stats[7]); 160 $this->filename = $filename; 161 $this->stats = $stats; 162 163 if (!$this->useBuffer) { 164 return $this->innerWriter->writeData( 165 $this->tarHeader($filename, $stats) 166 ); 167 } 168 } 169 170 /** 171 * @see File_Archive_Writer::close() 172 */ 173 function close() 174 { 175 $this->flush(); 176 $this->innerWriter->writeData(pack("a1024", "")); 177 parent::close(); 178 } 179 /** 180 * @see File_Archive_Writer::writeData() 181 */ 182 function writeData($data) 183 { 184 if ($this->useBuffer) { 185 $this->buffer .= $data; 186 } else { 187 $this->innerWriter->writeData($data); 188 } 189 190 } 191 /** 192 * @see File_Archive_Writer::writeFile() 193 */ 194 function writeFile($filename) 195 { 196 if ($this->useBuffer) { 197 $this->buffer .= file_get_contents($filename); 198 } else { 199 $this->innerWriter->writeFile($filename); 200 } 201 } 202 /** 203 * @see File_Archive_Writer::getMime() 204 */ 205 function getMime() { return "application/x-tar"; } 206} 207 208 209/** 210 * A tar archive cannot contain files with name of folders longer than 255 chars 211 * This filter removes them 212 * 213 * @see File_Archive_Predicate, File_Archive_Reader_Filter 214 */ 215require_once "File/Archive/Predicate.php"; 216class File_Archive_Predicate_TARCompatible extends File_Archive_Predicate 217{ 218 function isTrue($source) 219 { 220 return strlen($source->getFilename()) <= 255; 221 } 222} 223 224?>