|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of SwiftMailer. |
|
5 * (c) 2004-2009 Chris Corbyn |
|
6 * |
|
7 * For the full copyright and license information, please view the LICENSE |
|
8 * file that was distributed with this source code. |
|
9 */ |
|
10 |
|
11 |
|
12 /** |
|
13 * A KeyCache which streams to and from disk. |
|
14 * @package Swift |
|
15 * @subpackage KeyCache |
|
16 * @author Chris Corbyn |
|
17 */ |
|
18 class Swift_KeyCache_DiskKeyCache implements Swift_KeyCache |
|
19 { |
|
20 |
|
21 /** Signal to place pointer at start of file */ |
|
22 const POSITION_START = 0; |
|
23 |
|
24 /** Signal to place pointer at end of file */ |
|
25 const POSITION_END = 1; |
|
26 |
|
27 /** Signal to leave pointer in whatever position it currently is */ |
|
28 const POSITION_CURRENT = 2; |
|
29 |
|
30 /** |
|
31 * An InputStream for cloning. |
|
32 * @var Swift_KeyCache_KeyCacheInputStream |
|
33 * @access private |
|
34 */ |
|
35 private $_stream; |
|
36 |
|
37 /** |
|
38 * A path to write to. |
|
39 * @var string |
|
40 * @access private |
|
41 */ |
|
42 private $_path; |
|
43 |
|
44 /** |
|
45 * Stored keys. |
|
46 * @var array |
|
47 * @access private |
|
48 */ |
|
49 private $_keys = array(); |
|
50 |
|
51 /** |
|
52 * Will be true if magic_quotes_runtime is turned on. |
|
53 * @var boolean |
|
54 * @access private |
|
55 */ |
|
56 private $_quotes = false; |
|
57 |
|
58 /** |
|
59 * Create a new DiskKeyCache with the given $stream for cloning to make |
|
60 * InputByteStreams, and the given $path to save to. |
|
61 * @param Swift_KeyCache_KeyCacheInputStream $stream |
|
62 * @param string $path to save to |
|
63 */ |
|
64 public function __construct(Swift_KeyCache_KeyCacheInputStream $stream, $path) |
|
65 { |
|
66 $this->_stream = $stream; |
|
67 $this->_path = $path; |
|
68 $this->_quotes = ini_get('magic_quotes_runtime'); |
|
69 } |
|
70 |
|
71 /** |
|
72 * Set a string into the cache under $itemKey for the namespace $nsKey. |
|
73 * @param string $nsKey |
|
74 * @param string $itemKey |
|
75 * @param string $string |
|
76 * @param int $mode |
|
77 * @throws Swift_IoException |
|
78 * @see MODE_WRITE, MODE_APPEND |
|
79 */ |
|
80 public function setString($nsKey, $itemKey, $string, $mode) |
|
81 { |
|
82 $this->_prepareCache($nsKey); |
|
83 switch ($mode) |
|
84 { |
|
85 case self::MODE_WRITE: |
|
86 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); |
|
87 break; |
|
88 case self::MODE_APPEND: |
|
89 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); |
|
90 break; |
|
91 default: |
|
92 throw new Swift_SwiftException( |
|
93 'Invalid mode [' . $mode . '] used to set nsKey='. |
|
94 $nsKey . ', itemKey=' . $itemKey |
|
95 ); |
|
96 break; |
|
97 } |
|
98 fwrite($fp, $string); |
|
99 $this->_freeHandle($nsKey, $itemKey); |
|
100 } |
|
101 |
|
102 /** |
|
103 * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. |
|
104 * @param string $nsKey |
|
105 * @param string $itemKey |
|
106 * @param Swift_OutputByteStream $os |
|
107 * @param int $mode |
|
108 * @see MODE_WRITE, MODE_APPEND |
|
109 * @throws Swift_IoException |
|
110 */ |
|
111 public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, |
|
112 $mode) |
|
113 { |
|
114 $this->_prepareCache($nsKey); |
|
115 switch ($mode) |
|
116 { |
|
117 case self::MODE_WRITE: |
|
118 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); |
|
119 break; |
|
120 case self::MODE_APPEND: |
|
121 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); |
|
122 break; |
|
123 default: |
|
124 throw new Swift_SwiftException( |
|
125 'Invalid mode [' . $mode . '] used to set nsKey='. |
|
126 $nsKey . ', itemKey=' . $itemKey |
|
127 ); |
|
128 break; |
|
129 } |
|
130 while (false !== $bytes = $os->read(8192)) |
|
131 { |
|
132 fwrite($fp, $bytes); |
|
133 } |
|
134 $this->_freeHandle($nsKey, $itemKey); |
|
135 } |
|
136 |
|
137 /** |
|
138 * Provides a ByteStream which when written to, writes data to $itemKey. |
|
139 * NOTE: The stream will always write in append mode. |
|
140 * @param string $nsKey |
|
141 * @param string $itemKey |
|
142 * @return Swift_InputByteStream |
|
143 */ |
|
144 public function getInputByteStream($nsKey, $itemKey, |
|
145 Swift_InputByteStream $writeThrough = null) |
|
146 { |
|
147 $is = clone $this->_stream; |
|
148 $is->setKeyCache($this); |
|
149 $is->setNsKey($nsKey); |
|
150 $is->setItemKey($itemKey); |
|
151 if (isset($writeThrough)) |
|
152 { |
|
153 $is->setWriteThroughStream($writeThrough); |
|
154 } |
|
155 return $is; |
|
156 } |
|
157 |
|
158 /** |
|
159 * Get data back out of the cache as a string. |
|
160 * @param string $nsKey |
|
161 * @param string $itemKey |
|
162 * @return string |
|
163 * @throws Swift_IoException |
|
164 */ |
|
165 public function getString($nsKey, $itemKey) |
|
166 { |
|
167 $this->_prepareCache($nsKey); |
|
168 if ($this->hasKey($nsKey, $itemKey)) |
|
169 { |
|
170 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); |
|
171 if ($this->_quotes) |
|
172 { |
|
173 ini_set('magic_quotes_runtime', 0); |
|
174 } |
|
175 $str = ''; |
|
176 while (!feof($fp) && false !== $bytes = fread($fp, 8192)) |
|
177 { |
|
178 $str .= $bytes; |
|
179 } |
|
180 if ($this->_quotes) |
|
181 { |
|
182 ini_set('magic_quotes_runtime', 1); |
|
183 } |
|
184 $this->_freeHandle($nsKey, $itemKey); |
|
185 return $str; |
|
186 } |
|
187 } |
|
188 |
|
189 /** |
|
190 * Get data back out of the cache as a ByteStream. |
|
191 * @param string $nsKey |
|
192 * @param string $itemKey |
|
193 * @param Swift_InputByteStream $is to write the data to |
|
194 */ |
|
195 public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) |
|
196 { |
|
197 if ($this->hasKey($nsKey, $itemKey)) |
|
198 { |
|
199 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); |
|
200 if ($this->_quotes) |
|
201 { |
|
202 ini_set('magic_quotes_runtime', 0); |
|
203 } |
|
204 while (!feof($fp) && false !== $bytes = fread($fp, 8192)) |
|
205 { |
|
206 $is->write($bytes); |
|
207 } |
|
208 if ($this->_quotes) |
|
209 { |
|
210 ini_set('magic_quotes_runtime', 1); |
|
211 } |
|
212 $this->_freeHandle($nsKey, $itemKey); |
|
213 } |
|
214 } |
|
215 |
|
216 /** |
|
217 * Check if the given $itemKey exists in the namespace $nsKey. |
|
218 * @param string $nsKey |
|
219 * @param string $itemKey |
|
220 * @return boolean |
|
221 */ |
|
222 public function hasKey($nsKey, $itemKey) |
|
223 { |
|
224 return is_file($this->_path . '/' . $nsKey . '/' . $itemKey); |
|
225 } |
|
226 |
|
227 /** |
|
228 * Clear data for $itemKey in the namespace $nsKey if it exists. |
|
229 * @param string $nsKey |
|
230 * @param string $itemKey |
|
231 */ |
|
232 public function clearKey($nsKey, $itemKey) |
|
233 { |
|
234 if ($this->hasKey($nsKey, $itemKey)) |
|
235 { |
|
236 $this->_freeHandle($nsKey, $itemKey); |
|
237 unlink($this->_path . '/' . $nsKey . '/' . $itemKey); |
|
238 } |
|
239 } |
|
240 |
|
241 /** |
|
242 * Clear all data in the namespace $nsKey if it exists. |
|
243 * @param string $nsKey |
|
244 */ |
|
245 public function clearAll($nsKey) |
|
246 { |
|
247 if (array_key_exists($nsKey, $this->_keys)) |
|
248 { |
|
249 foreach ($this->_keys[$nsKey] as $itemKey=>$null) |
|
250 { |
|
251 $this->clearKey($nsKey, $itemKey); |
|
252 } |
|
253 rmdir($this->_path . '/' . $nsKey); |
|
254 unset($this->_keys[$nsKey]); |
|
255 } |
|
256 } |
|
257 |
|
258 // -- Private methods |
|
259 |
|
260 /** |
|
261 * Initialize the namespace of $nsKey if needed. |
|
262 * @param string $nsKey |
|
263 * @access private |
|
264 */ |
|
265 private function _prepareCache($nsKey) |
|
266 { |
|
267 $cacheDir = $this->_path . '/' . $nsKey; |
|
268 if (!is_dir($cacheDir)) |
|
269 { |
|
270 if (!mkdir($cacheDir)) |
|
271 { |
|
272 throw new Swift_IoException('Failed to create cache directory ' . $cacheDir); |
|
273 } |
|
274 $this->_keys[$nsKey] = array(); |
|
275 } |
|
276 } |
|
277 |
|
278 /** |
|
279 * Get a file handle on the cache item. |
|
280 * @param string $nsKey |
|
281 * @param string $itemKey |
|
282 * @param int $position |
|
283 * @return resource |
|
284 * @access private |
|
285 */ |
|
286 private function _getHandle($nsKey, $itemKey, $position) |
|
287 { |
|
288 if (!isset($this->_keys[$nsKey][$itemKey])) |
|
289 { |
|
290 $openMode = $this->hasKey($nsKey, $itemKey) |
|
291 ? 'r+b' |
|
292 : 'w+b' |
|
293 ; |
|
294 $fp = fopen($this->_path . '/' . $nsKey . '/' . $itemKey, $openMode); |
|
295 $this->_keys[$nsKey][$itemKey] = $fp; |
|
296 } |
|
297 if (self::POSITION_START == $position) |
|
298 { |
|
299 fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET); |
|
300 } |
|
301 elseif (self::POSITION_END == $position) |
|
302 { |
|
303 fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END); |
|
304 } |
|
305 return $this->_keys[$nsKey][$itemKey]; |
|
306 } |
|
307 |
|
308 private function _freeHandle($nsKey, $itemKey) |
|
309 { |
|
310 $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT); |
|
311 fclose($fp); |
|
312 $this->_keys[$nsKey][$itemKey] = null; |
|
313 } |
|
314 |
|
315 /** |
|
316 * Destructor. |
|
317 */ |
|
318 public function __destruct() |
|
319 { |
|
320 foreach ($this->_keys as $nsKey=>$null) |
|
321 { |
|
322 $this->clearAll($nsKey); |
|
323 } |
|
324 } |
|
325 |
|
326 } |