1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Gaufrette\Adapter; |
4
|
|
|
|
5
|
|
|
use Gaufrette\Util; |
6
|
|
|
use Gaufrette\Adapter; |
7
|
|
|
use Gaufrette\Stream; |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Adapter for the local filesystem. |
12
|
|
|
* |
13
|
|
|
* @author Antoine Hérault <[email protected]> |
14
|
|
|
* @author Leszek Prabucki <[email protected]> |
15
|
|
|
*/ |
16
|
|
|
class Local implements Adapter, |
17
|
|
|
StreamFactory, |
18
|
|
|
ChecksumCalculator, |
19
|
|
|
SizeCalculator, |
20
|
|
|
MimeTypeProvider |
21
|
|
|
{ |
22
|
|
|
protected $directory; |
23
|
|
|
private $create; |
24
|
|
|
private $mode; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @param string $directory Directory where the filesystem is located |
28
|
|
|
* @param bool $create Whether to create the directory if it does not |
29
|
|
|
* exist (default FALSE) |
30
|
|
|
* @param int $mode Mode for mkdir |
31
|
|
|
* |
32
|
|
|
* @throws \RuntimeException if the specified directory does not exist and |
33
|
|
|
* could not be created |
34
|
|
|
*/ |
35
|
|
|
public function __construct($directory, $create = false, $mode = 0777) |
36
|
|
|
{ |
37
|
|
|
$this->directory = Util\Path::normalize($directory); |
38
|
|
|
|
39
|
|
|
if (is_link($this->directory)) { |
40
|
|
|
$this->directory = realpath($this->directory); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
$this->create = $create; |
44
|
|
|
$this->mode = $mode; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritdoc} |
49
|
|
|
* |
50
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
51
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
52
|
|
|
* @throws \RuntimeException if the directory could not be created |
53
|
|
|
*/ |
54
|
|
|
public function read($key) |
55
|
|
|
{ |
56
|
|
|
if ($this->isDirectory($key)) { |
57
|
|
|
return false; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
return file_get_contents($this->computePath($key)); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* {@inheritdoc} |
65
|
|
|
* |
66
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
67
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
68
|
|
|
* @throws \RuntimeException if the directory could not be created |
69
|
|
|
*/ |
70
|
|
View Code Duplication |
public function write($key, $content) |
|
|
|
|
71
|
|
|
{ |
72
|
|
|
$path = $this->computePath($key); |
73
|
|
|
$this->ensureDirectoryExists(\Gaufrette\Util\Path::dirname($path), true); |
74
|
|
|
|
75
|
|
|
return file_put_contents($path, $content); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* {@inheritdoc} |
80
|
|
|
* |
81
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
82
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
83
|
|
|
* @throws \RuntimeException if the directory could not be created |
84
|
|
|
*/ |
85
|
|
View Code Duplication |
public function rename($sourceKey, $targetKey) |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
$targetPath = $this->computePath($targetKey); |
88
|
|
|
$this->ensureDirectoryExists(\Gaufrette\Util\Path::dirname($targetPath), true); |
89
|
|
|
|
90
|
|
|
return rename($this->computePath($sourceKey), $targetPath); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* {@inheritdoc} |
95
|
|
|
*/ |
96
|
|
|
public function exists($key) |
97
|
|
|
{ |
98
|
|
|
return is_file($this->computePath($key)); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* {@inheritdoc} |
103
|
|
|
* |
104
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
105
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
106
|
|
|
* @throws \RuntimeException if the directory could not be created |
107
|
|
|
*/ |
108
|
|
|
public function keys() |
109
|
|
|
{ |
110
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
111
|
|
|
|
112
|
|
|
try { |
113
|
|
|
$files = new \RecursiveIteratorIterator( |
114
|
|
|
new \RecursiveDirectoryIterator( |
115
|
|
|
$this->directory, |
116
|
|
|
\FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS |
117
|
|
|
), |
118
|
|
|
\RecursiveIteratorIterator::CHILD_FIRST |
119
|
|
|
); |
120
|
|
|
} catch (\Exception $e) { |
121
|
|
|
$files = new \EmptyIterator(); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$keys = []; |
125
|
|
|
foreach ($files as $file) { |
126
|
|
|
$keys[] = $this->computeKey($file); |
127
|
|
|
} |
128
|
|
|
sort($keys); |
129
|
|
|
|
130
|
|
|
return $keys; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* {@inheritdoc} |
135
|
|
|
* |
136
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
137
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
138
|
|
|
* @throws \RuntimeException if the directory could not be created |
139
|
|
|
*/ |
140
|
|
|
public function mtime($key) |
141
|
|
|
{ |
142
|
|
|
return filemtime($this->computePath($key)); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* {@inheritdoc} |
147
|
|
|
* |
148
|
|
|
* Can also delete a directory recursively when the given $key matches a |
149
|
|
|
* directory. |
150
|
|
|
*/ |
151
|
|
|
public function delete($key) |
152
|
|
|
{ |
153
|
|
|
if ($this->isDirectory($key)) { |
154
|
|
|
return $this->deleteDirectory($this->computePath($key)); |
155
|
|
|
} elseif ($this->exists($key)) { |
156
|
|
|
return unlink($this->computePath($key)); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
return false; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @param string $key |
164
|
|
|
* |
165
|
|
|
* @return bool |
166
|
|
|
* |
167
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
168
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
169
|
|
|
* @throws \RuntimeException if the directory could not be created |
170
|
|
|
*/ |
171
|
|
|
public function isDirectory($key) |
172
|
|
|
{ |
173
|
|
|
return is_dir($this->computePath($key)); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* {@inheritdoc} |
178
|
|
|
* |
179
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
180
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
181
|
|
|
* @throws \RuntimeException if the directory could not be created |
182
|
|
|
*/ |
183
|
|
|
public function createStream($key) |
184
|
|
|
{ |
185
|
|
|
return new Stream\Local($this->computePath($key), $this->mode); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* {@inheritdoc} |
190
|
|
|
* |
191
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
192
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
193
|
|
|
* @throws \RuntimeException if the directory could not be created |
194
|
|
|
*/ |
195
|
|
|
public function checksum($key) |
196
|
|
|
{ |
197
|
|
|
return Util\Checksum::fromFile($this->computePath($key)); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* {@inheritdoc} |
202
|
|
|
* |
203
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
204
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
205
|
|
|
* @throws \RuntimeException if the directory could not be created |
206
|
|
|
*/ |
207
|
|
|
public function size($key) |
208
|
|
|
{ |
209
|
|
|
return Util\Size::fromFile($this->computePath($key)); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* {@inheritdoc} |
214
|
|
|
* |
215
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
216
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
217
|
|
|
* @throws \RuntimeException if the directory could not be created |
218
|
|
|
*/ |
219
|
|
|
public function mimeType($key) |
220
|
|
|
{ |
221
|
|
|
$fileInfo = new \finfo(FILEINFO_MIME_TYPE); |
222
|
|
|
|
223
|
|
|
return $fileInfo->file($this->computePath($key)); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Computes the key from the specified path. |
228
|
|
|
* |
229
|
|
|
* @param $path |
230
|
|
|
* @return string |
231
|
|
|
* |
232
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
233
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
234
|
|
|
* @throws \RuntimeException if the directory could not be created |
235
|
|
|
*/ |
236
|
|
|
public function computeKey($path) |
237
|
|
|
{ |
238
|
|
|
$path = $this->normalizePath($path); |
239
|
|
|
|
240
|
|
|
return ltrim(substr($path, strlen($this->directory)), '/'); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Computes the path from the specified key. |
245
|
|
|
* |
246
|
|
|
* @param string $key The key which for to compute the path |
247
|
|
|
* |
248
|
|
|
* @return string A path |
249
|
|
|
* |
250
|
|
|
* @throws \InvalidArgumentException If the directory already exists |
251
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the directory |
252
|
|
|
* @throws \RuntimeException If directory does not exists and cannot be created |
253
|
|
|
*/ |
254
|
|
|
protected function computePath($key) |
255
|
|
|
{ |
256
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
257
|
|
|
|
258
|
|
|
return $this->normalizePath($this->directory.'/'.$key); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Normalizes the given path. |
263
|
|
|
* |
264
|
|
|
* @param string $path |
265
|
|
|
* |
266
|
|
|
* @return string |
267
|
|
|
* @throws \OutOfBoundsException If the computed path is out of the |
268
|
|
|
* directory |
269
|
|
|
*/ |
270
|
|
|
protected function normalizePath($path) |
271
|
|
|
{ |
272
|
|
|
$path = Util\Path::normalize($path); |
273
|
|
|
|
274
|
|
|
if (0 !== strpos($path, $this->directory)) { |
275
|
|
|
throw new \OutOfBoundsException(sprintf('The path "%s" is out of the filesystem.', $path)); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
return $path; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Ensures the specified directory exists, creates it if it does not. |
283
|
|
|
* |
284
|
|
|
* @param string $directory Path of the directory to test |
285
|
|
|
* @param bool $create Whether to create the directory if it does |
286
|
|
|
* not exist |
287
|
|
|
* |
288
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
289
|
|
|
* @throws \RuntimeException if the directory does not exists and could not |
290
|
|
|
* be created |
291
|
|
|
*/ |
292
|
|
|
protected function ensureDirectoryExists($directory, $create = false) |
293
|
|
|
{ |
294
|
|
|
if (!is_dir($directory)) { |
295
|
|
|
if (!$create) { |
296
|
|
|
throw new \RuntimeException(sprintf('The directory "%s" does not exist.', $directory)); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
$this->createDirectory($directory); |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Creates the specified directory and its parents. |
305
|
|
|
* |
306
|
|
|
* @param string $directory Path of the directory to create |
307
|
|
|
* |
308
|
|
|
* @throws \InvalidArgumentException if the directory already exists |
309
|
|
|
* @throws \RuntimeException if the directory could not be created |
310
|
|
|
*/ |
311
|
|
|
protected function createDirectory($directory) |
312
|
|
|
{ |
313
|
|
|
if (!@mkdir($directory, $this->mode, true) && !is_dir($directory)) { |
314
|
|
|
throw new \RuntimeException(sprintf('The directory \'%s\' could not be created.', $directory)); |
315
|
|
|
} |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* @param string The directory's path to delete |
320
|
|
|
* |
321
|
|
|
* @throws \InvalidArgumentException When attempting to delete the root |
322
|
|
|
* directory of this adapter. |
323
|
|
|
* |
324
|
|
|
* @return bool Wheter the operation succeeded or not |
325
|
|
|
*/ |
326
|
|
|
private function deleteDirectory($directory) |
327
|
|
|
{ |
328
|
|
|
if ($this->directory === $directory) { |
329
|
|
|
throw new \InvalidArgumentException( |
330
|
|
|
sprintf('Impossible to delete the root directory of this Local adapter ("%s").', $directory) |
331
|
|
|
); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
$status = true; |
335
|
|
|
|
336
|
|
|
if (file_exists($directory)) { |
337
|
|
|
$iterator = new \RecursiveIteratorIterator( |
338
|
|
|
new \RecursiveDirectoryIterator( |
339
|
|
|
$directory, |
340
|
|
|
\FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS |
341
|
|
|
), |
342
|
|
|
\RecursiveIteratorIterator::CHILD_FIRST |
343
|
|
|
); |
344
|
|
|
|
345
|
|
|
foreach ($iterator as $item) { |
346
|
|
|
if ($item->isDir()) { |
347
|
|
|
$status = $status && rmdir(strval($item)); |
348
|
|
|
} else { |
349
|
|
|
$status = $status && unlink(strval($item)); |
350
|
|
|
} |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
$status = $status && rmdir($directory); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
return $status; |
357
|
|
|
} |
358
|
|
|
} |
359
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.