|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Phossa Project |
|
4
|
|
|
* |
|
5
|
|
|
* PHP version 5.4 |
|
6
|
|
|
* |
|
7
|
|
|
* @category Library |
|
8
|
|
|
* @package Phossa2\Storage |
|
9
|
|
|
* @copyright Copyright (c) 2016 phossa.com |
|
10
|
|
|
* @license http://mit-license.org/ MIT License |
|
11
|
|
|
* @link http://www.phossa.com/ |
|
12
|
|
|
*/ |
|
13
|
|
|
/*# declare(strict_types=1); */ |
|
14
|
|
|
|
|
15
|
|
|
namespace Phossa2\Storage\Driver; |
|
16
|
|
|
|
|
17
|
|
|
use Phossa2\Storage\Message\Message; |
|
18
|
|
|
use Phossa2\Storage\Traits\LocalDirTrait; |
|
19
|
|
|
use Phossa2\Storage\Exception\LogicException; |
|
20
|
|
|
use Phossa2\Storage\Interfaces\PermissionAwareInterface; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* LocalDriver |
|
24
|
|
|
* |
|
25
|
|
|
* @package Phossa2\Storage |
|
26
|
|
|
* @author Hong Zhang <[email protected]> |
|
27
|
|
|
* @see DriverAbstract |
|
28
|
|
|
* @version 2.0.0 |
|
29
|
|
|
* @since 2.0.0 added |
|
30
|
|
|
*/ |
|
31
|
|
|
class LocalDriver extends DriverAbstract |
|
32
|
|
|
{ |
|
33
|
|
|
use LocalDirTrait; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* driver root |
|
37
|
|
|
* |
|
38
|
|
|
* @var string |
|
39
|
|
|
* @access protected |
|
40
|
|
|
*/ |
|
41
|
|
|
protected $root; |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* @param string $rootDir |
|
45
|
|
|
* @throws LogicException |
|
46
|
|
|
* @access public |
|
47
|
|
|
*/ |
|
48
|
|
|
public function __construct(/*# string */ $rootDir) |
|
49
|
|
|
{ |
|
50
|
|
|
if (!$this->makeDirectory($rootDir)) { |
|
51
|
|
|
throw new LogicException( |
|
52
|
|
|
$this->getError(), |
|
53
|
|
|
$this->getErrorCode() |
|
54
|
|
|
); |
|
55
|
|
|
} |
|
56
|
|
|
$this->root = rtrim($rootDir, "/\\") . \DIRECTORY_SEPARATOR; |
|
57
|
|
|
} |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* {@inheritDoc} |
|
61
|
|
|
*/ |
|
62
|
|
|
protected function realPath(/*# string */ $path)/*# : string */ |
|
63
|
|
|
{ |
|
64
|
|
|
return $this->root . ('/' !== \DIRECTORY_SEPARATOR ? |
|
65
|
|
|
str_replace('/', \DIRECTORY_SEPARATOR, $path) : $path); |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* {@inheritDoc} |
|
70
|
|
|
*/ |
|
71
|
|
|
protected function realExists(/*# string */ $realPath)/*# : bool */ |
|
72
|
|
|
{ |
|
73
|
|
|
return file_exists($realPath); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* {@inheritDoc} |
|
78
|
|
|
*/ |
|
79
|
|
|
protected function openReadStream(/*# string */ $realPath) |
|
80
|
|
|
{ |
|
81
|
|
|
$stream = fopen($realPath, 'r'); |
|
82
|
|
|
if (is_resource($stream)) { |
|
83
|
|
|
return $stream; |
|
84
|
|
|
} else { |
|
85
|
|
|
$this->setError( |
|
86
|
|
|
Message::get(Message::STR_OPENSTREAM_FAIL, $realPath), |
|
87
|
|
|
Message::STR_OPENSTREAM_FAIL |
|
88
|
|
|
); |
|
89
|
|
|
return null; |
|
90
|
|
|
} |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* {@inheritDoc} |
|
95
|
|
|
*/ |
|
96
|
|
View Code Duplication |
protected function readFile(/*# string */ $realPath) |
|
|
|
|
|
|
97
|
|
|
{ |
|
98
|
|
|
$str = file_get_contents($realPath); |
|
99
|
|
|
|
|
100
|
|
|
if (false === $str) { |
|
101
|
|
|
$this->setError( |
|
102
|
|
|
Message::get(Message::STR_OPENSTREAM_FAIL, $realPath), |
|
103
|
|
|
Message::STR_OPENSTREAM_FAIL |
|
104
|
|
|
); |
|
105
|
|
|
return null; |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
return $str; |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* {@inheritDoc} |
|
113
|
|
|
*/ |
|
114
|
|
|
protected function getRealMeta(/*# string */ $realPath)/*# : array */ |
|
115
|
|
|
{ |
|
116
|
|
|
try { |
|
117
|
|
|
$info = new \SplFileInfo($realPath); |
|
118
|
|
|
return [ |
|
119
|
|
|
'size' => $info->getSize(), |
|
120
|
|
|
'perm' => $info->getPerms() & PermissionAwareInterface::PERM_ALL, |
|
121
|
|
|
'ctime' => $info->getCTime(), |
|
122
|
|
|
'mtime' => $info->getMTime(), |
|
123
|
|
|
]; |
|
124
|
|
|
} catch (\Exception $e) { |
|
125
|
|
|
$this->setError( |
|
126
|
|
|
Message::get(Message::STR_GETMETA_FAIL, $realPath), |
|
127
|
|
|
Message::STR_GETMETA_FAIL |
|
128
|
|
|
); |
|
129
|
|
|
return []; |
|
130
|
|
|
} |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
/** |
|
134
|
|
|
* {@inheritDoc} |
|
135
|
|
|
*/ |
|
136
|
|
|
protected function ensurePath(/*# string */ $realPath)/*# : bool */ |
|
137
|
|
|
{ |
|
138
|
|
|
$parent = dirname($realPath); |
|
139
|
|
|
if (!$this->makeDirectory($parent)) { |
|
140
|
|
|
return false; |
|
141
|
|
|
} |
|
142
|
|
|
return true; |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
/** |
|
146
|
|
|
* {@inheritDoc} |
|
147
|
|
|
*/ |
|
148
|
|
View Code Duplication |
protected function writeStream( |
|
|
|
|
|
|
149
|
|
|
/*# string */ $realPath, |
|
150
|
|
|
$resource |
|
151
|
|
|
)/*# : bool */ { |
|
152
|
|
|
$tmpfname = tempnam(dirname($realPath), 'FOO'); |
|
153
|
|
|
if (false !== $tmpfname) { |
|
154
|
|
|
$stream = fopen($tmpfname, 'w+b'); |
|
155
|
|
|
if (is_resource($stream)) { |
|
156
|
|
|
stream_copy_to_stream($resource, $stream); |
|
157
|
|
|
fclose($stream); |
|
158
|
|
|
return $this->renameTempFile($tmpfname, $realPath); |
|
159
|
|
|
} |
|
160
|
|
|
} |
|
161
|
|
|
return false; |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* {@inheritDoc} |
|
166
|
|
|
*/ |
|
167
|
|
View Code Duplication |
protected function writeFile( |
|
|
|
|
|
|
168
|
|
|
/*# string */ $realPath, |
|
169
|
|
|
/*# string */ $content |
|
170
|
|
|
)/*# : bool */ { |
|
171
|
|
|
// write to a temp file |
|
172
|
|
|
$tmpfname = tempnam(dirname($realPath), 'FOO'); |
|
173
|
|
|
if (false !== $tmpfname) { |
|
174
|
|
|
$handle = fopen($tmpfname, 'w'); |
|
175
|
|
|
fwrite($handle, $content); |
|
176
|
|
|
fclose($handle); |
|
177
|
|
|
|
|
178
|
|
|
return $this->renameTempFile($tmpfname, $realPath); |
|
179
|
|
|
} |
|
180
|
|
|
return false; |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* {@inheritDoc} |
|
185
|
|
|
*/ |
|
186
|
|
|
protected function setRealMeta( |
|
187
|
|
|
/*# string */ $realPath, |
|
188
|
|
|
array $meta |
|
189
|
|
|
)/*# : bool */ { |
|
190
|
|
|
clearstatcache(true, $realPath); |
|
191
|
|
|
|
|
192
|
|
|
if (isset($meta['mtime'])) { |
|
193
|
|
|
touch($realPath, $meta['mtime']); |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
if (isset($meta['perm'])) { |
|
197
|
|
|
chmod($realPath, (int) $meta['perm']); |
|
198
|
|
|
} |
|
199
|
|
|
return true; |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
/** |
|
203
|
|
|
* {@inheritDoc} |
|
204
|
|
|
*/ |
|
205
|
|
|
protected function renameFile( |
|
206
|
|
|
/*# string */ $from, |
|
207
|
|
|
/*# string */ $to |
|
208
|
|
|
)/*# : bool */ { |
|
209
|
|
|
return @rename($from, $to); |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
/** |
|
213
|
|
|
* {@inheritDoc} |
|
214
|
|
|
*/ |
|
215
|
|
|
protected function copyFile( |
|
216
|
|
|
/*# string */ $from, |
|
217
|
|
|
/*# string */ $to |
|
218
|
|
|
)/*# : bool */ { |
|
219
|
|
|
return @copy($from, $to); |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
/** |
|
223
|
|
|
* {@inheritDoc} |
|
224
|
|
|
*/ |
|
225
|
|
|
protected function deleteFile(/*# string */ $realPath)/*# : bool */ |
|
226
|
|
|
{ |
|
227
|
|
|
return unlink($realPath); |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
/** |
|
231
|
|
|
* Rename tmpfile |
|
232
|
|
|
* |
|
233
|
|
|
* @param string $tmpFile |
|
234
|
|
|
* @param string $realPath |
|
235
|
|
|
* @return bool |
|
236
|
|
|
* @access protected |
|
237
|
|
|
*/ |
|
238
|
|
|
protected function renameTempFile( |
|
239
|
|
|
/*# string */ $tmpFile, |
|
240
|
|
|
/*# string */ $realPath |
|
241
|
|
|
)/*# : bool */ { |
|
242
|
|
|
if (@rename($tmpFile, $realPath) && |
|
243
|
|
|
@chmod($realPath, PermissionAwareInterface::PERM_ALL)) { |
|
244
|
|
|
return true; |
|
245
|
|
|
} |
|
246
|
|
|
$err = error_get_last(); |
|
247
|
|
|
$this->setError($err['message'], Message::STR_WRITEFILE_FAIL); |
|
248
|
|
|
@unlink($tmpFile); |
|
|
|
|
|
|
249
|
|
|
return false; |
|
250
|
|
|
} |
|
251
|
|
|
} |
|
252
|
|
|
|
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.