| Viewing file:  file.php (12.97 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
<?php/**
 * File containing the ezcArchiveFile class.
 *
 * @package Archive
 * @version 1.4.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 * @access private
 */
 
 /**
 * The ezcArchiveFile should implement the common interface between the
 * ezcArchiveBlockFile and ezcArchiveCharacterFile.
 *
 * @package Archive
 * @version 1.4.1
 * @access private
 */
 abstract class ezcArchiveFile implements Iterator
 {
 /**
 * The file is read-only.
 * The file permissions can be set to read-only or file is compressed with a
 * stream that can only be read. E.g. bzip2.
 */
 const READ_ONLY   = 1;
 
 /**
 * The file is write-only.
 * The file permissions can be set to write-only or file should be compressed with a
 * stream that can only write. E.g. bzip2.
 */
 const WRITE_ONLY  = 2;
 
 /**
 * The file is either read or append mode.
 * Some compressed streams (zlib) do not support reading and writing. But seperate reading
 * and appending does work.
 */
 const READ_APPEND = 3;
 
 /**
 * The file is opened in a read and write mode.
 */
 const READ_WRITE  = 4;
 
 /**
 * The mode the file is opened in. It has one of the following constant values:
 * READ_ONLY, WRITE_ONLY, READ_APPEND, or READ_WRITE.
 *
 * @var int
 */
 protected $fileAccess = null;
 
 /**
 * The current resource of the opened file.
 * If the file is closed, this resource should point to NULL.
 *
 * @var resource
 */
 protected $fp = null;
 
 /**
 * The name of the file.
 *
 * @var string
 */
 protected $fileName;
 
 /**
 * True when the current file does not have any blocks, otherwise false.
 *
 * @var boolean
 */
 protected $isEmpty;
 
 /**
 * True if the file-pointer supports seeking, otherwise false.
 * For example, files that use the bzip2 stream cannot seek.
 *
 * @var boolean
 */
 protected $fileMetaData;
 
 /**
 * True when the current block is valid, otherwise false.
 *
 * @var boolean
 */
 protected $isValid = false;
 
 /**
 * Read-mode for the archive file.
 */
 const SWITCH_READ = 0;
 
 /**
 * Append-mode for the archive file.
 */
 const SWITCH_APPEND = 1;
 
 /**
 * Switch for read-mode and append-mode.
 *
 * @var int
 */
 protected $readAppendSwitch;
 
 /**
 * Is the file new.
 *
 * @var bool
 */
 protected $isNew;
 
 /**
 * Is the file modified.
 *
 * @var bool
 */
 protected $isModified;
 
 /**
 * Opens the specified archive.
 *
 * If $createIfNotExist is true, then the file will be created if it does
 * not exist.
 *
 * @param string $fileName
 * @param bool $createIfNotExist
 * @param bool $readOnly
 * @return bool
 */
 protected function openFile( $fileName, $createIfNotExist, $readOnly = false )
 {
 if ( !$readOnly && $createIfNotExist && !self::fileExists( $fileName ) )
 {
 $this->isNew = true;
 $this->isEmpty = true;
 if ( !self::touch( $fileName ) )
 {
 throw new ezcBaseFilePermissionException( self::getPureFileName( $fileName ), ezcBaseFilePermissionException::WRITE );
 }
 }
 else
 {
 $this->isNew = false;
 }
 
 // Try to open it in read and write mode.
 $opened = false;
 if ( !$readOnly )
 {
 $this->fp = @fopen( $fileName, "r+b" );
 if ( $this->fp )
 {
 $this->fileAccess = self::READ_WRITE;
 $opened = true;
 }
 }
 
 if ( !$opened )
 {
 // Try to open it in read-only mode.
 $this->fp = @fopen( $fileName, "rb" );
 $this->fileAccess = self::READ_ONLY;
 
 // Check if we opened the file.
 if ( !$this->fp )
 {
 if ( !self::fileExists( $fileName ) )
 {
 throw new ezcBaseFileNotFoundException( $fileName );
 }
 
 // Cannot read the file.
 throw new ezcBaseFilePermissionException( $fileName, ezcBaseFilePermissionException::READ );
 }
 }
 
 $this->fileMetaData = stream_get_meta_data( $this->fp );
 
 // Hardcode BZip2 to read-only.
 // For some reason we can open the file in read-write mode, but we cannot rewind the fp. Strange..
 if ( $this->fileMetaData["wrapper_type"] == "BZip2" )
 {
 $this->fileAccess = self::READ_ONLY;
 }
 
 // Why is it read only?
 if ( !$readOnly && $this->fileAccess == self::READ_ONLY )
 {
 if ( $this->fileMetaData["wrapper_type"] == "ZLIB" || $this->fileMetaData["wrapper_type"] == "BZip2" )
 {
 // Append mode available?
 $b = @fopen( $fileName, "ab" );
 if ( $b !== false )
 {
 // We have also a write-only mode.
 fclose( $b );
 
 // The file is either read-only or write-only.
 $this->fileAccess = self::READ_APPEND;
 $this->readAppendSwitch = self::SWITCH_READ;
 }
 else
 {
 // Maybe we should write only to the archive.
 // Test this only, when the archive is new.
 
 if ( $this->isNew )
 {
 $b = @fopen( $fileName, "wb" );
 if ( $b !== false )
 {
 // XXX Clean up.
 $this->fp = $b;
 
 $this->isEmpty = true;
 $this->fileAccess = self::WRITE_ONLY;
 
 $this->fileName = $fileName;
 $this->isModified = false;
 
 return true;
 }
 }
 }
 }
 }
 
 // Check if the archive is empty.
 if ( fgetc( $this->fp ) === false )
 {
 $this->isEmpty = true;
 }
 else
 {
 $this->rewind();
 $this->isEmpty = false;
 }
 
 $this->fileName = $fileName;
 $this->isModified = false;
 }
 
 /**
 * Returns the file name or file path.
 *
 * @return string
 */
 public function getFileName()
 {
 return $this->fileName;
 }
 
 /**
 * Switch to write mode.
 */
 public function switchWriteMode()
 {
 // Switch only when we are in read (only) mode.
 if ( $this->fileAccess == self::READ_APPEND && $this->readAppendSwitch == self::SWITCH_READ )
 {
 fclose( $this->fp );
 $this->fp = @fopen( $this->fileName, "ab" );
 if ( $this->fp === false )
 {
 throw new ezcBaseFilePermissionException( self::getPureFileName( $this->fileName ), ezcBaseFilePermissionException::WRITE, "Cannot switch to write mode" );
 }
 $this->readAppendSwitch = self::SWITCH_APPEND;
 }
 }
 
 /**
 * Switch to read mode.
 *
 * @param int $pos Position to seek to; not used
 */
 public function switchReadMode( $pos = 0 )
 {
 // Switch only when we are in write (only) mode.
 if ( $this->fileAccess == self::READ_APPEND && $this->readAppendSwitch == self::SWITCH_APPEND )
 {
 fclose( $this->fp );
 
 $this->fp = fopen( $this->fileName, "rb" );
 
 if ( $this->fp === false )
 {
 throw new ezcBaseFilePermissionException( self::getPureFileName( $this->fileName ), ezcBaseFilePermissionException::READ, "Cannot switch back to read mode" );
 }
 $this->readAppendSwitch = self::SWITCH_READ;
 
 $this->positionSeek( 0, SEEK_END );
 
 // Doesn't Make sense, Seek-end should be at the end!
 while ( fgetc( $this->fp ) !== false );
 }
 }
 
 /**
 * Returns if the file access is in append mode.
 *
 * @return bool
 */
 public function isReadOnlyWriteOnlyStream()
 {
 return $this->fileAccess == self::READ_APPEND;
 }
 
 
 
 /**
 * Touches the specified file (sets the access and modification time).
 *
 * PHP system touch doesn't work correctly with the compress.zlib file.
 *
 * @param string $fileName
 * @return bool
 */
 public static function touch( $fileName )
 {
 return touch( self::getPureFileName( $fileName ) );
 }
 
 /**
 * Returns if the specified file exists.
 *
 * @param string $fileName
 * @return bool
 */
 public static function fileExists( $fileName )
 {
 return file_exists( self::getPureFileName( $fileName ) );
 }
 
 /**
 * Returns the specified file name without any filters or compression stream.
 *
 * @param string $fileName
 * @return string
 */
 private static function getPureFileName( $fileName )
 {
 // TODO: Multistream goes wrong.
 if ( strncmp( $fileName, "compress.zlib://", 16 ) == 0 )
 {
 return substr( $fileName, 16 );
 }
 
 if ( strncmp( $fileName, "compress.bzip2://", 17 ) == 0 )
 {
 return substr( $fileName, 17 );
 }
 
 return $fileName;
 }
 
 /**
 * Rewind the current file, and the current() method will return the
 * data from the first block, if available.
 */
 public function rewind()
 {
 if ( !is_null( $this->fp ) )
 {
 $this->isValid = true;
 
 if ( !$this->fileMetaData["seekable"] )
 {
 fclose( $this->fp );
 $this->fp = fopen( $this->fileMetaData["uri"], $this->fileMetaData["mode"] );
 }
 else
 {
 rewind( $this->fp );
 }
 
 $this->next();
 }
 else
 {
 $this->isValid = false;
 }
 }
 
 /**
 * Seeks in the file to/by the specified position.
 *
 * Ways of seeking ($whence):
 * - SEEK_SET - $pos is absolute, seek to that position in the file
 * - SEEK_CUR - $pos is relative, seek by $pos bytes from the current position
 *
 * @throws ezcArchiveException
 *         if trying to use SEEK_END for $whence
 * @param int $pos
 * @param int $whence
 * @return int If seek was successful or not
 */
 protected function positionSeek( $pos, $whence = SEEK_SET )
 {
 // Seek the end of the file in a write only file always succeeds.
 if ( $this->fileAccess == self::WRITE_ONLY && $pos == 0 && $whence == SEEK_END )
 {
 return true;
 }
 
 if ( $this->fileMetaData["seekable"] )
 {
 /**
 * Ugh, for some reason fseek starts throwing warnings for
 * zlib streams with SEEK_END. And there is no way to know this
 * upfront, so we need to use @ here. #fail.
 */
 return @fseek( $this->fp, $pos, $whence );
 }
 else
 {
 switch ( $whence )
 {
 case SEEK_SET:
 $transPos = $pos;
 break;
 
 case SEEK_CUR:
 $transPos = $pos + ftell( $this->fp );
 break;
 
 case SEEK_END:
 throw new ezcArchiveException( "SEEK_END in a non-seekable file is not supported (yet)." );
 }
 
 $cur = ftell( $this->fp );
 if ( $transPos <  $cur )
 {
 fclose( $this->fp );
 $this->fp = fopen( $this->fileMetaData["uri"], $this->fileMetaData["mode"] );
 
 $cur = 0;
 }
 
 for ( $i = $cur; $i < $transPos; $i++ )
 {
 $c = fgetc( $this->fp );
 if ( $c === false )
 {
 return -1;
 }
 }
 
 return 0;
 }
 }
 
 /**
 * Returns the current file access mode.
 *
 * @var int
 */
 public function getFileAccess()
 {
 return $this->fileAccess;
 }
 
 /**
 * Returns if the file is in read-only mode.
 *
 * @var bool
 */
 public function isReadOnly()
 {
 return $this->fileAccess == self::READ_ONLY;
 }
 
 /**
 * Returns if the file is new.
 *
 * @var bool
 */
 public function isNew()
 {
 return $this->isNew;
 }
 
 /**
 * Returns if the file is modified.
 *
 * @var bool
 */
 public function isModified()
 {
 return $this->isModified;
 }
 
 /**
 * Closes the file.
 */
 public function close()
 {
 if ( is_resource( $this->fp ) )
 {
 fclose( $this->fp );
 $this->fp = null;
 }
 }
 }
 ?>
 
 |