1: <?php
2:
3: 4: 5: 6: 7: 8: 9:
10:
11: 12: 13: 14: 15: 16:
17: class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_FileStream
18: {
19:
20: private $_offset = 0;
21:
22:
23: private $_path;
24:
25:
26: private $_mode;
27:
28:
29: private $_reader;
30:
31:
32: private $_writer;
33:
34:
35: private $_quotes = false;
36:
37:
38: private $_seekable = null;
39:
40: 41: 42: 43: 44:
45: public function __construct($path, $writable = false)
46: {
47: $this->_path = $path;
48: $this->_mode = $writable ? 'w+b' : 'rb';
49:
50: if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
51: $this->_quotes = true;
52: }
53: }
54:
55: 56: 57: 58:
59: public function getPath()
60: {
61: return $this->_path;
62: }
63:
64: 65: 66: 67: 68: 69: 70: 71: 72:
73: public function read($length)
74: {
75: $fp = $this->_getReadHandle();
76: if (!feof($fp)) {
77: if ($this->_quotes) {
78: ini_set('magic_quotes_runtime', 0);
79: }
80: $bytes = fread($fp, $length);
81: if ($this->_quotes) {
82: ini_set('magic_quotes_runtime', 1);
83: }
84: $this->_offset = ftell($fp);
85:
86: return $bytes;
87: } else {
88: $this->_resetReadHandle();
89:
90: return false;
91: }
92: }
93:
94: 95: 96: 97: 98:
99: public function setReadPointer($byteOffset)
100: {
101: if (isset($this->_reader)) {
102: $this->_seekReadStreamToPosition($byteOffset);
103: }
104: $this->_offset = $byteOffset;
105: }
106:
107:
108:
109:
110: protected function _commit($bytes)
111: {
112: fwrite($this->_getWriteHandle(), $bytes);
113: $this->_resetReadHandle();
114: }
115:
116:
117: protected function _flush()
118: {
119: }
120:
121:
122: private function _getReadHandle()
123: {
124: if (!isset($this->_reader)) {
125: if (!$this->_reader = fopen($this->_path, 'rb')) {
126: throw new Swift_IoException(
127: 'Unable to open file for reading [' . $this->_path . ']'
128: );
129: }
130: if ($this->_offset <> 0) {
131: $this->_getReadStreamSeekableStatus();
132: $this->_seekReadStreamToPosition($this->_offset);
133: }
134: }
135:
136: return $this->_reader;
137: }
138:
139:
140: private function _getWriteHandle()
141: {
142: if (!isset($this->_writer)) {
143: if (!$this->_writer = fopen($this->_path, $this->_mode)) {
144: throw new Swift_IoException(
145: 'Unable to open file for writing [' . $this->_path . ']'
146: );
147: }
148: }
149:
150: return $this->_writer;
151: }
152:
153:
154: private function _resetReadHandle()
155: {
156: if (isset($this->_reader)) {
157: fclose($this->_reader);
158: $this->_reader = null;
159: }
160: }
161:
162:
163: private function _getReadStreamSeekableStatus()
164: {
165: $metas = stream_get_meta_data($this->_reader);
166: $this->_seekable = $metas['seekable'];
167: }
168:
169:
170: private function _seekReadStreamToPosition($offset)
171: {
172: if ($this->_seekable===null) {
173: $this->_getReadStreamSeekableStatus();
174: }
175: if ($this->_seekable === false) {
176: $currentPos = ftell($this->_reader);
177: if ($currentPos<$offset) {
178: $toDiscard = $offset-$currentPos;
179: fread($this->_reader, $toDiscard);
180:
181: return;
182: }
183: $this->_copyReadStream();
184: }
185: fseek($this->_reader, $offset, SEEK_SET);
186: }
187:
188:
189: private function _copyReadStream()
190: {
191: if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
192:
193: } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
194:
195: } else {
196: throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
197: }
198: $currentPos = ftell($this->_reader);
199: fclose($this->_reader);
200: $source = fopen($this->_path, 'rb');
201: if (!$source) {
202: throw new Swift_IoException('Unable to open file for copying [' . $this->_path . ']');
203: }
204: fseek($tmpFile, 0, SEEK_SET);
205: while (!feof($source)) {
206: fwrite($tmpFile, fread($source, 4096));
207: }
208: fseek($tmpFile, $currentPos, SEEK_SET);
209: fclose($source);
210: $this->_reader = $tmpFile;
211: }
212: }
213: