1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * This reader caches the files of another reader 6 * It allow fast access to files. This is usefull if the access to the reader 7 * is slow (HTTP, FTP...), but will need more IO if the file is only extracted 8 * 9 * PHP versions 4 and 5 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2.1 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA 24 * 25 * @category File Formats 26 * @package File_Archive 27 * @author Vincent Lascaux <vincentlascaux@php.net> 28 * @copyright 1997-2005 The PHP Group 29 * @license http://www.gnu.org/copyleft/lesser.html LGPL 30 * @version CVS: $Id: Cache.php,v 1.1 2005/07/07 12:24:58 vincentlascaux Exp $ 31 * @link http://pear.php.net/package/File_Archive 32 */ 33 34require_once "File/Archive/Reader.php"; 35 36/** 37 * This reader caches the files of another reader 38 * It allow fast access to files. This is usefull if the access to the reader 39 * is slow (HTTP, FTP...), but will need more IO if the file is only extracted 40 */ 41class File_Archive_Reader_Cache extends File_Archive_Reader 42{ 43 var $tmpFile; 44 var $files = array(); 45 var $pos = 0; 46 var $fromSource = true; 47 var $endOfSource = false; 48 var $source; 49 50 /** 51 * $source is the reader to filter 52 */ 53 function File_Archive_Reader_Cache(&$source) 54 { 55 $this->source =& $source; 56 $this->tmpFile = tmpfile(); 57 } 58 59 function _writeEndOfFile() 60 { 61 $bufferSize = File_Archive::getOption('blockSize'); 62 while (($data = $this->source->getData($bufferSize))!=null) { 63 fwrite($this->tmpFile, $data); 64 } 65 } 66 /** 67 * @see File_Archive_Reader::next() 68 */ 69 function next() 70 { 71 //Write the end of the current file to the temp file 72 if ($this->fromSource && !empty($this->files)) { 73 $this->_writeEndOfFile(); 74 } 75 76 if ($this->pos+1 < count($this->files) && !$this->fromSource) { 77 $this->pos++; 78 fseek($this->tmpFile, $this->files[$this->pos]['pos'], SEEK_SET); 79 return true; 80 } else { 81 $this->fromSource = true; 82 if ($this->endOfSource) { 83 return false; 84 } 85 86 $ret = $this->source->next(); 87 if ($ret !== true) { 88 $this->endOfSource = true; 89 $this->source->close(); 90 return $ret; 91 } 92 93 $this->endOfSource = false; 94 fseek($this->tmpFile, 0, SEEK_END); 95 $this->files[] = array( 96 'name' => $this->source->getFilename(), 97 'stat' => $this->source->getStat(), 98 'mime' => $this->source->getMime(), 99 'pos' => ftell($this->tmpFile) 100 ); 101 $this->pos = count($this->files)-1; 102 103 return true; 104 } 105 } 106 107 /** 108 * @see File_Archive_Reader::getFilename() 109 */ 110 function getFilename() { return $this->files[$this->pos]['name']; } 111 /** 112 * @see File_Archive_Reader::getStat() 113 */ 114 function getStat() { return $this->files[$this->pos]['stat']; } 115 /** 116 * @see File_Archive_Reader::getMime() 117 */ 118 function getMime() { return $this->files[$this->pos]['mime']; } 119 /** 120 * @see File_Archive_Reader::getDataFilename() 121 */ 122 function getDataFilename() { return null; } 123 /** 124 * @see File_Archive_Reader::getData() 125 */ 126 function getData($length = -1) 127 { 128 if ($this->fromSource) { 129 $data = $this->source->getData($length); 130 if (PEAR::isError($data)) { 131 return $data; 132 } 133 134 fwrite($this->tmpFile, $data); 135 return $data; 136 } else { 137 if ($length == 0) { 138 return ''; 139 } 140 141 if ($length > 0 && $this->pos+1 < count($this->files)) { 142 $maxSize = $this->files[$this->pos+1]['pos'] - ftell($this->tmpFile); 143 if ($maxSize == 0) { 144 return null; 145 } 146 if ($length > $maxSize) { 147 $length = $maxSize; 148 } 149 return fread($this->tmpFile, $length); 150 } else { 151 $contents = ''; 152 $blockSize = File_Archive::getOption('blockSize'); 153 while (!feof($this->tmpFile)) { 154 $contents .= fread($this->tmpFile, $blockSize); 155 } 156 return $contents == '' ? null : $contents; 157 } 158 } 159 } 160 /** 161 * @see File_Archive_Reader::skip() 162 */ 163 function skip($length = -1) 164 { 165 if ($this->fromSource) { 166 return strlen($this->getData($length)); 167 } else { 168 if ($length >= 0 && $this->pos+1 < count($this->files)) { 169 $maxSize = $this->files[$this->pos+1]['pos'] - ftell($this->tmpFile); 170 if ($maxSize == 0) { 171 return null; 172 } 173 if ($length > $maxSize) { 174 $length = $maxSize; 175 } 176 fseek($this->tmpFile, $length, SEEK_CUR); 177 return $length; 178 } else { 179 $before = ftell($this->tmpFile); 180 fseek($this->tmpFile, 0, SEEK_SET); 181 $after = fteel($this->tmpFile); 182 return $after - $before; 183 } 184 } 185 } 186 /** 187 * @see File_Archive_Reader::rewind() 188 */ 189 function rewind($length = -1) 190 { 191 if ($this->fromSource) { 192 $this->_writeEndOfFile(); 193 $this->fromSource = false; 194 } 195 $before = ftell($this->tmpFile); 196 $pos = $this->files[$this->pos]['pos']; 197 fseek($this->tmpFile, $pos, SEEK_SET); 198 return $pos - $before; 199 } 200 /** 201 * @see File_Archive_Reader::tell() 202 */ 203 function tell() 204 { 205 return ftell($this->tmpFile) - $this->files[$this->pos]['pos']; 206 } 207 /** 208 * @see File_Archive_Reader::close() 209 */ 210 function close() 211 { 212 $this->fromSource = false; 213 $this->pos = 0; 214 fseek($this->tmpFile, 0, SEEK_SET); 215 } 216 function _closeAndReset() 217 { 218 $this->close(); 219 220 fclose($this->tmpFile); 221 $this->tmpFile = tmpfile(); 222 $this->endOfSource = false; 223 $this->files = array(); 224 $this->source->close(); 225 } 226 /** 227 * @see File_Archive_Reader::makeAppendWriter() 228 */ 229 function makeAppendWriter() 230 { 231 $writer = $this->source->makeAppendWriter(); 232 if (!PEAR::isError($writer)) { 233 $this->_closeAndReset(); 234 } 235 236 return $writer; 237 } 238 /** 239 * @see File_Archive_Reader::makeWriterRemoveFiles() 240 */ 241 function makeWriterRemoveFiles($pred) 242 { 243 $writer = $this->source->makeWriterRemoveFiles($pred); 244 if (!PEAR::isError($writer)) { 245 $this->_closeAndReset(); 246 } 247 return $writer; 248 } 249 /** 250 * @see File_Archive_Reader::makeWriterRemoveBlocks() 251 */ 252 function makeWriterRemoveBlocks($blocks, $seek = 0) 253 { 254 $writer = $this->source->makeWriterRemoveBlocks($blocks, $seek); 255 if (!PEAR::isError($writer)) { 256 $this->_closeAndReset(); 257 } 258 return $writer; 259 } 260} 261 262?>