123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- <?php
-
- /*
- * This file is part of SwiftMailer.
- * (c) 2004-2009 Chris Corbyn
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-
- /**
- * Allows reading and writing of bytes to and from a file.
- * @package Swift
- * @subpackage ByteStream
- * @author Chris Corbyn
- */
- class Swift_ByteStream_FileByteStream
- extends Swift_ByteStream_AbstractFilterableInputStream
- implements Swift_FileStream
- {
-
- /** The internal pointer offset */
- private $_offset = 0;
-
- /** The path to the file */
- private $_path;
-
- /** The mode this file is opened in for writing */
- private $_mode;
-
- /** A lazy-loaded resource handle for reading the file */
- private $_reader;
-
- /** A lazy-loaded resource handle for writing the file */
- private $_writer;
-
- /** If magic_quotes_runtime is on, this will be true */
- private $_quotes = false;
-
- /** If stream is seekable true/false, or null if not known */
- private $_seekable = null;
-
- /**
- * Create a new FileByteStream for $path.
- * @param string $path
- * @param string $writable if true
- */
- public function __construct($path, $writable = false)
- {
- $this->_path = $path;
- $this->_mode = $writable ? 'w+b' : 'rb';
- $this->_quotes = ini_get('magic_quotes_runtime');
- }
-
- /**
- * Get the complete path to the file.
- * @return string
- */
- public function getPath()
- {
- return $this->_path;
- }
-
- /**
- * Reads $length bytes from the stream into a string and moves the pointer
- * through the stream by $length. If less bytes exist than are requested the
- * remaining bytes are given instead. If no bytes are remaining at all, boolean
- * false is returned.
- * @param int $length
- * @return string
- * @throws Swift_IoException
- */
- public function read($length)
- {
- $fp = $this->_getReadHandle();
- if (!feof($fp))
- {
- if ($this->_quotes)
- {
- ini_set('magic_quotes_runtime', 0);
- }
- $bytes = fread($fp, $length);
- if ($this->_quotes)
- {
- ini_set('magic_quotes_runtime', 1);
- }
- $this->_offset = ftell($fp);
- return $bytes;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Move the internal read pointer to $byteOffset in the stream.
- * @param int $byteOffset
- * @return boolean
- */
- public function setReadPointer($byteOffset)
- {
- if (isset($this->_reader))
- {
- $this->_seekReadStreamToPosition($byteOffset);
- }
- $this->_offset = $byteOffset;
- }
-
- // -- Private methods
-
- /** Just write the bytes to the file */
- protected function _commit($bytes)
- {
- fwrite($this->_getWriteHandle(), $bytes);
- $this->_resetReadHandle();
- }
-
- /** Not used */
- protected function _flush()
- {
- }
-
- /** Get the resource for reading */
- private function _getReadHandle()
- {
- if (!isset($this->_reader))
- {
- if (!$this->_reader = fopen($this->_path, 'rb'))
- {
- throw new Swift_IoException(
- 'Unable to open file for reading [' . $this->_path . ']'
- );
- }
- if ($this->_offset <> 0)
- {
- $this->_getReadStreamSeekableStatus();
- $this->_seekReadStreamToPosition($this->_offset);
- }
- }
- return $this->_reader;
- }
-
- /** Get the resource for writing */
- private function _getWriteHandle()
- {
- if (!isset($this->_writer))
- {
- if (!$this->_writer = fopen($this->_path, $this->_mode))
- {
- throw new Swift_IoException(
- 'Unable to open file for writing [' . $this->_path . ']'
- );
- }
- }
- return $this->_writer;
- }
-
- /** Force a reload of the resource for reading */
- private function _resetReadHandle()
- {
- if (isset($this->_reader))
- {
- fclose($this->_reader);
- $this->_reader = null;
- }
- }
-
- /** Check if ReadOnly Stream is seekable */
- private function _getReadStreamSeekableStatus()
- {
- $metas = stream_get_meta_data($this->_reader);
- $this->_seekable = $metas['seekable'];
- }
-
- /** Streams in a readOnly stream ensuring copy if needed */
- private function _seekReadStreamToPosition($offset)
- {
- if ($this->_seekable===null)
- {
- $this->_getReadStreamSeekableStatus();
- }
- if ($this->_seekable === false)
- {
- $currentPos = ftell($this->_reader);
- if ($currentPos<$offset)
- {
- $toDiscard = $offset-$currentPos;
- fread($this->_reader, $toDiscard);
- return;
- }
- $this->_copyReadStream();
- }
- fseek($this->_reader, $offset, SEEK_SET);
- }
-
- /** Copy a readOnly Stream to ensure seekability */
- private function _copyReadStream()
- {
- if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b'))
- {
- /* We have opened a php:// Stream Should work without problem */
- }
- elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile()))
- {
- /* We have opened a tmpfile */
- }
- else
- {
- throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
- }
- $currentPos = ftell($this->_reader);
- fclose($this->_reader);
- $source = fopen($this->_path, 'rb');
- if (!$source)
- {
- throw new Swift_IoException('Unable to open file for copying [' . $this->_path . ']');
- }
- fseek($tmpFile, 0, SEEK_SET);
- while (!feof($source))
- {
- fwrite($tmpFile, fread($source, 4096));
- }
- fseek($tmpFile, $currentPos, SEEK_SET);
- fclose($source);
- $this->_reader = $tmpFile;
- }
- }
|