|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Gaufrette\Adapter; |
|
4
|
|
|
|
|
5
|
|
|
use Gaufrette\Adapter; |
|
6
|
|
|
use Gaufrette\File; |
|
7
|
|
|
use Gaufrette\Filesystem; |
|
8
|
|
|
use Gaufrette\Exception; |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* Ftp adapter |
|
12
|
|
|
* |
|
13
|
|
|
* @package Gaufrette |
|
14
|
|
|
* @author Antoine Hérault <[email protected]> |
|
15
|
|
|
*/ |
|
16
|
|
|
class Ftp implements Adapter, |
|
17
|
|
|
FileFactory, |
|
18
|
|
|
ListKeysAware |
|
19
|
|
|
{ |
|
20
|
|
|
protected $connection = null; |
|
21
|
|
|
protected $directory; |
|
22
|
|
|
protected $host; |
|
23
|
|
|
protected $port; |
|
24
|
|
|
protected $username; |
|
25
|
|
|
protected $password; |
|
26
|
|
|
protected $passive; |
|
27
|
|
|
protected $create; |
|
28
|
|
|
protected $mode; |
|
29
|
|
|
protected $ssl; |
|
30
|
|
|
protected $fileData = array(); |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* Constructor |
|
34
|
|
|
* |
|
35
|
|
|
* @param string $directory The directory to use in the ftp server |
|
36
|
|
|
* @param string $host The host of the ftp server |
|
37
|
|
|
* @param array $options The options like port, username, password, passive, create, mode |
|
38
|
|
|
*/ |
|
39
|
|
|
public function __construct($directory, $host, $options = array()) |
|
40
|
|
|
{ |
|
41
|
|
|
$this->directory = (string) $directory; |
|
42
|
|
|
$this->host = $host; |
|
43
|
|
|
$this->port = isset($options['port']) ? $options['port'] : 21; |
|
44
|
|
|
$this->username = isset($options['username']) ? $options['username'] : null; |
|
45
|
|
|
$this->password = isset($options['password']) ? $options['password'] : null; |
|
46
|
|
|
$this->passive = isset($options['passive']) ? $options['passive'] : false; |
|
47
|
|
|
$this->create = isset($options['create']) ? $options['create'] : false; |
|
48
|
|
|
$this->mode = isset($options['mode']) ? $options['mode'] : FTP_BINARY; |
|
49
|
|
|
$this->ssl = isset($options['ssl']) ? $options['ssl'] : false; |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* {@inheritDoc} |
|
54
|
|
|
*/ |
|
55
|
|
|
public function read($key) |
|
56
|
|
|
{ |
|
57
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
58
|
|
|
|
|
59
|
|
|
$temp = fopen('php://temp', 'r+'); |
|
60
|
|
|
|
|
61
|
|
|
if (!ftp_fget($this->getConnection(), $temp, $this->computePath($key), $this->mode)) { |
|
62
|
|
|
return false; |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
rewind($temp); |
|
66
|
|
|
$contents = stream_get_contents($temp); |
|
67
|
|
|
fclose($temp); |
|
68
|
|
|
|
|
69
|
|
|
return $contents; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* {@inheritDoc} |
|
74
|
|
|
*/ |
|
75
|
|
|
public function write($key, $content) |
|
76
|
|
|
{ |
|
77
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
78
|
|
|
|
|
79
|
|
|
$path = $this->computePath($key); |
|
80
|
|
|
$directory = dirname($path); |
|
81
|
|
|
|
|
82
|
|
|
$this->ensureDirectoryExists($directory, true); |
|
83
|
|
|
|
|
84
|
|
|
$temp = fopen('php://temp', 'r+'); |
|
85
|
|
|
$size = fwrite($temp, $content); |
|
86
|
|
|
rewind($temp); |
|
87
|
|
|
|
|
88
|
|
|
if (!ftp_fput($this->getConnection(), $path, $temp, $this->mode)) { |
|
89
|
|
|
fclose($temp); |
|
90
|
|
|
|
|
91
|
|
|
return false; |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
fclose($temp); |
|
95
|
|
|
|
|
96
|
|
|
return $size; |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* {@inheritDoc} |
|
101
|
|
|
*/ |
|
102
|
|
|
public function rename($sourceKey, $targetKey) |
|
103
|
|
|
{ |
|
104
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
105
|
|
|
|
|
106
|
|
|
$sourcePath = $this->computePath($sourceKey); |
|
107
|
|
|
$targetPath = $this->computePath($targetKey); |
|
108
|
|
|
|
|
109
|
|
|
$this->ensureDirectoryExists(dirname($targetPath), true); |
|
110
|
|
|
|
|
111
|
|
|
return ftp_rename($this->getConnection(), $sourcePath, $targetPath); |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* {@inheritDoc} |
|
116
|
|
|
*/ |
|
117
|
|
|
public function exists($key) |
|
118
|
|
|
{ |
|
119
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
120
|
|
|
|
|
121
|
|
|
$file = $this->computePath($key); |
|
122
|
|
|
$lines = ftp_rawlist($this->getConnection(), '-al ' . dirname($file)); |
|
123
|
|
|
|
|
124
|
|
|
if (false === $lines) { |
|
125
|
|
|
return false; |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
$pattern = '{(?<!->) '.preg_quote(basename($file)).'( -> |$)}m'; |
|
129
|
|
|
foreach ($lines as $line) { |
|
130
|
|
|
if (preg_match($pattern, $line)) { |
|
131
|
|
|
return true; |
|
132
|
|
|
} |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
return false; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* {@inheritDoc} |
|
140
|
|
|
*/ |
|
141
|
|
|
public function keys() |
|
142
|
|
|
{ |
|
143
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
144
|
|
|
|
|
145
|
|
|
$keys = $this->fetchKeys(); |
|
146
|
|
|
|
|
147
|
|
|
return $keys['keys']; |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
|
/** |
|
151
|
|
|
* {@inheritDoc} |
|
152
|
|
|
*/ |
|
153
|
|
|
public function listKeys($prefix = '') |
|
154
|
|
|
{ |
|
155
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
156
|
|
|
|
|
157
|
|
|
preg_match('/(.*?)[^\/]*$/', $prefix, $match); |
|
158
|
|
|
$directory = rtrim($match[1], '/'); |
|
159
|
|
|
|
|
160
|
|
|
$keys = $this->fetchKeys($directory, false); |
|
161
|
|
|
|
|
162
|
|
|
if ($directory === $prefix) { |
|
163
|
|
|
return $keys; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
$filteredKeys = array(); |
|
167
|
|
View Code Duplication |
foreach (array('keys', 'dirs') as $hash) { |
|
168
|
|
|
$filteredKeys[$hash] = array(); |
|
169
|
|
|
foreach ($keys[$hash] as $key) { |
|
170
|
|
|
if (0 === strpos($key, $prefix)) { |
|
171
|
|
|
$filteredKeys[$hash][] = $key; |
|
172
|
|
|
} |
|
173
|
|
|
} |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
return $filteredKeys; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
/** |
|
180
|
|
|
* {@inheritDoc} |
|
181
|
|
|
*/ |
|
182
|
|
|
public function mtime($key) |
|
183
|
|
|
{ |
|
184
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
185
|
|
|
|
|
186
|
|
|
$mtime = ftp_mdtm($this->getConnection(), $this->computePath($key)); |
|
187
|
|
|
|
|
188
|
|
|
// the server does not support this function |
|
189
|
|
|
if (-1 === $mtime) { |
|
190
|
|
|
throw new \RuntimeException('Server does not support ftp_mdtm function.'); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
return $mtime; |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
/** |
|
197
|
|
|
* {@inheritDoc} |
|
198
|
|
|
*/ |
|
199
|
|
|
public function delete($key) |
|
200
|
|
|
{ |
|
201
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
202
|
|
|
|
|
203
|
|
|
if ($this->isDirectory($key)) { |
|
204
|
|
|
return ftp_rmdir($this->getConnection(), $this->computePath($key)); |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
return ftp_delete($this->getConnection(), $this->computePath($key)); |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* {@inheritDoc} |
|
212
|
|
|
*/ |
|
213
|
|
|
public function isDirectory($key) |
|
214
|
|
|
{ |
|
215
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
216
|
|
|
|
|
217
|
|
|
return $this->isDir($this->computePath($key)); |
|
218
|
|
|
} |
|
219
|
|
|
|
|
220
|
|
|
/** |
|
221
|
|
|
* Lists files from the specified directory. If a pattern is |
|
222
|
|
|
* specified, it only returns files matching it. |
|
223
|
|
|
* |
|
224
|
|
|
* @param string $directory The path of the directory to list from |
|
225
|
|
|
* |
|
226
|
|
|
* @return array An array of keys and dirs |
|
227
|
|
|
*/ |
|
228
|
|
|
public function listDirectory($directory = '') |
|
229
|
|
|
{ |
|
230
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
231
|
|
|
|
|
232
|
|
|
$directory = preg_replace('/^[\/]*([^\/].*)$/', '/$1', $directory); |
|
233
|
|
|
|
|
234
|
|
|
$items = $this->parseRawlist( |
|
235
|
|
|
ftp_rawlist($this->getConnection(), '-al ' . $this->directory . $directory ) ? : array() |
|
236
|
|
|
); |
|
237
|
|
|
|
|
238
|
|
|
$fileData = $dirs = array(); |
|
239
|
|
|
foreach ($items as $itemData) { |
|
240
|
|
|
|
|
241
|
|
|
if ('..' === $itemData['name'] || '.' === $itemData['name']) { |
|
242
|
|
|
continue; |
|
243
|
|
|
} |
|
244
|
|
|
|
|
245
|
|
|
$item = array( |
|
246
|
|
|
'name' => $itemData['name'], |
|
247
|
|
|
'path' => trim(($directory ? $directory . '/' : '') . $itemData['name'], '/'), |
|
248
|
|
|
'time' => $itemData['time'], |
|
249
|
|
|
'size' => $itemData['size'], |
|
250
|
|
|
); |
|
251
|
|
|
|
|
252
|
|
|
if ('-' === substr($itemData['perms'], 0, 1)) { |
|
253
|
|
|
$fileData[$item['path']] = $item; |
|
254
|
|
|
} elseif ('d' === substr($itemData['perms'], 0, 1)) { |
|
255
|
|
|
$dirs[] = $item['path']; |
|
256
|
|
|
} |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
$this->fileData = array_merge($fileData, $this->fileData); |
|
260
|
|
|
|
|
261
|
|
|
return array( |
|
262
|
|
|
'keys' => array_keys($fileData), |
|
263
|
|
|
'dirs' => $dirs |
|
264
|
|
|
); |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
/** |
|
268
|
|
|
* {@inheritDoc} |
|
269
|
|
|
*/ |
|
270
|
|
|
public function createFile($key, Filesystem $filesystem) |
|
271
|
|
|
{ |
|
272
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
273
|
|
|
|
|
274
|
|
|
$file = new File($key, $filesystem); |
|
275
|
|
|
|
|
276
|
|
|
if (!array_key_exists($key, $this->fileData)) { |
|
277
|
|
|
$directory = dirname($key) == '.' ? '' : dirname($key); |
|
278
|
|
|
$this->listDirectory($directory); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
if (isset($this->fileData[$key])) { |
|
282
|
|
|
$fileData = $this->fileData[$key]; |
|
283
|
|
|
|
|
284
|
|
|
$file->setName($fileData['name']); |
|
285
|
|
|
$file->setSize($fileData['size']); |
|
286
|
|
|
} |
|
287
|
|
|
|
|
288
|
|
|
return $file; |
|
|
|
|
|
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
|
/** |
|
292
|
|
|
* Ensures the specified directory exists. If it does not, and the create |
|
293
|
|
|
* parameter is set to TRUE, it tries to create it |
|
294
|
|
|
* |
|
295
|
|
|
* @param string $directory |
|
296
|
|
|
* @param boolean $create Whether to create the directory if it does not |
|
297
|
|
|
* exist |
|
298
|
|
|
* |
|
299
|
|
|
* @throws RuntimeException if the directory does not exist and could not |
|
300
|
|
|
* be created |
|
301
|
|
|
*/ |
|
302
|
|
|
protected function ensureDirectoryExists($directory, $create = false) |
|
303
|
|
|
{ |
|
304
|
|
|
if (!$this->isDir($directory)) { |
|
305
|
|
|
if (!$create) { |
|
306
|
|
|
throw new \RuntimeException(sprintf('The directory \'%s\' does not exist.', $directory)); |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
$this->createDirectory($directory); |
|
310
|
|
|
} |
|
311
|
|
|
} |
|
312
|
|
|
|
|
313
|
|
|
/** |
|
314
|
|
|
* Creates the specified directory and its parent directories |
|
315
|
|
|
* |
|
316
|
|
|
* @param string $directory Directory to create |
|
317
|
|
|
* |
|
318
|
|
|
* @throws RuntimeException if the directory could not be created |
|
319
|
|
|
*/ |
|
320
|
|
|
protected function createDirectory($directory) |
|
321
|
|
|
{ |
|
322
|
|
|
// create parent directory if needed |
|
323
|
|
|
$parent = dirname($directory); |
|
324
|
|
|
if (!$this->isDir($parent)) { |
|
325
|
|
|
$this->createDirectory($parent); |
|
326
|
|
|
} |
|
327
|
|
|
|
|
328
|
|
|
// create the specified directory |
|
329
|
|
|
$created = ftp_mkdir($this->getConnection(), $directory); |
|
330
|
|
|
if (false === $created) { |
|
331
|
|
|
throw new \RuntimeException(sprintf('Could not create the \'%s\' directory.', $directory)); |
|
332
|
|
|
} |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* @param string $directory - full directory path |
|
337
|
|
|
* @return boolean |
|
338
|
|
|
*/ |
|
339
|
|
|
private function isDir($directory) |
|
340
|
|
|
{ |
|
341
|
|
|
if ('/' === $directory) { |
|
342
|
|
|
return true; |
|
343
|
|
|
} |
|
344
|
|
|
|
|
345
|
|
|
if (!@ftp_chdir($this->getConnection(), $directory)) { |
|
346
|
|
|
return false; |
|
347
|
|
|
} |
|
348
|
|
|
|
|
349
|
|
|
// change directory again to return in the base directory |
|
350
|
|
|
ftp_chdir($this->getConnection(), $this->directory); |
|
351
|
|
|
|
|
352
|
|
|
return true; |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
private function fetchKeys($directory = '', $onlyKeys = true) |
|
356
|
|
|
{ |
|
357
|
|
|
$directory = preg_replace('/^[\/]*([^\/].*)$/', '/$1', $directory); |
|
358
|
|
|
|
|
359
|
|
|
$lines = ftp_rawlist($this->getConnection(), '-alR '. $this->directory . $directory); |
|
360
|
|
|
|
|
361
|
|
|
if (false === $lines) { |
|
362
|
|
|
return array('keys' => array(), 'dirs' => array()); |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
$regexDir = '/'.preg_quote($this->directory . $directory, '/').'\/?(.+):$/u'; |
|
366
|
|
|
$regexItem = '/^(?:([d\-\d])\S+)\s+\S+(?:(?:\s+\S+){5})?\s+(\S+)\s+(.+?)$/'; |
|
367
|
|
|
|
|
368
|
|
|
$prevLine = null; |
|
369
|
|
|
$directories = array(); |
|
370
|
|
|
$keys = array('keys' => array(), 'dirs' => array()); |
|
371
|
|
|
|
|
372
|
|
|
foreach ((array) $lines as $line) { |
|
373
|
|
|
if ('' === $prevLine && preg_match($regexDir, $line, $match)) { |
|
374
|
|
|
$directory = $match[1]; |
|
375
|
|
|
unset($directories[$directory]); |
|
376
|
|
View Code Duplication |
if ($onlyKeys) { |
|
377
|
|
|
$keys = array( |
|
378
|
|
|
'keys' => array_merge($keys['keys'], $keys['dirs']), |
|
379
|
|
|
'dirs' => array() |
|
380
|
|
|
); |
|
381
|
|
|
} |
|
382
|
|
|
} elseif (preg_match($regexItem, $line, $tokens)) { |
|
383
|
|
|
$name = $tokens[3]; |
|
384
|
|
|
|
|
385
|
|
|
if ('.' === $name || '..' === $name) { |
|
386
|
|
|
continue; |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
$path = ltrim($directory . '/' . $name, '/'); |
|
390
|
|
|
|
|
391
|
|
|
if ('d' === $tokens[1] || '<dir>' === $tokens[2]) { |
|
392
|
|
|
$keys['dirs'][] = $path; |
|
393
|
|
|
$directories[$path] = true; |
|
394
|
|
|
} else { |
|
395
|
|
|
$keys['keys'][] = $path; |
|
396
|
|
|
} |
|
397
|
|
|
} |
|
398
|
|
|
$prevLine = $line; |
|
399
|
|
|
} |
|
400
|
|
|
|
|
401
|
|
View Code Duplication |
if ($onlyKeys) { |
|
402
|
|
|
$keys = array( |
|
403
|
|
|
'keys' => array_merge($keys['keys'], $keys['dirs']), |
|
404
|
|
|
'dirs' => array() |
|
405
|
|
|
); |
|
406
|
|
|
} |
|
407
|
|
|
|
|
408
|
|
|
foreach (array_keys($directories) as $directory) { |
|
409
|
|
|
$keys = array_merge_recursive($keys, $this->fetchKeys($directory, $onlyKeys)); |
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
return $keys; |
|
413
|
|
|
} |
|
414
|
|
|
|
|
415
|
|
|
/** |
|
416
|
|
|
* Parses the given raw list |
|
417
|
|
|
* |
|
418
|
|
|
* @param array $rawlist |
|
419
|
|
|
* |
|
420
|
|
|
* @return array |
|
421
|
|
|
*/ |
|
422
|
|
|
private function parseRawlist(array $rawlist) |
|
423
|
|
|
{ |
|
424
|
|
|
$parsed = array(); |
|
425
|
|
|
foreach ($rawlist as $line) { |
|
426
|
|
|
$infos = preg_split("/[\s]+/", $line, 9); |
|
427
|
|
|
|
|
428
|
|
|
if ($this->isLinuxListing($infos)) { |
|
429
|
|
|
$infos[7] = (strrpos($infos[7], ':') != 2 ) ? ($infos[7] . ' 00:00') : (date('Y') . ' ' . $infos[7]); |
|
430
|
|
|
if ('total' !== $infos[0]) { |
|
431
|
|
|
$parsed[] = array( |
|
432
|
|
|
'perms' => $infos[0], |
|
433
|
|
|
'num' => $infos[1], |
|
434
|
|
|
'size' => $infos[4], |
|
435
|
|
|
'time' => strtotime($infos[5] . ' ' . $infos[6] . '. ' . $infos[7]), |
|
436
|
|
|
'name' => $infos[8] |
|
437
|
|
|
); |
|
438
|
|
|
} |
|
439
|
|
|
} else { |
|
440
|
|
|
$isDir = (boolean) ('<dir>' === $infos[2]); |
|
441
|
|
|
$parsed[] = array( |
|
442
|
|
|
'perms' => $isDir ? 'd' : '-', |
|
443
|
|
|
'num' => '', |
|
444
|
|
|
'size' => $isDir ? '' : $infos[2], |
|
445
|
|
|
'time' => strtotime($infos[0] . ' ' . $infos[1]), |
|
446
|
|
|
'name' => $infos[3] |
|
447
|
|
|
); |
|
448
|
|
|
} |
|
449
|
|
|
} |
|
450
|
|
|
|
|
451
|
|
|
return $parsed; |
|
452
|
|
|
} |
|
453
|
|
|
|
|
454
|
|
|
/** |
|
455
|
|
|
* Computes the path for the given key |
|
456
|
|
|
* |
|
457
|
|
|
* @param string $key |
|
458
|
|
|
*/ |
|
459
|
|
|
private function computePath($key) |
|
460
|
|
|
{ |
|
461
|
|
|
return rtrim($this->directory, '/') . '/' . $key; |
|
462
|
|
|
} |
|
463
|
|
|
|
|
464
|
|
|
/** |
|
465
|
|
|
* Indicates whether the adapter has an open ftp connection |
|
466
|
|
|
* |
|
467
|
|
|
* @return boolean |
|
468
|
|
|
*/ |
|
469
|
|
|
private function isConnected() |
|
470
|
|
|
{ |
|
471
|
|
|
return is_resource($this->connection); |
|
472
|
|
|
} |
|
473
|
|
|
|
|
474
|
|
|
/** |
|
475
|
|
|
* Returns an opened ftp connection resource. If the connection is not |
|
476
|
|
|
* already opened, it open it before |
|
477
|
|
|
* |
|
478
|
|
|
* @return resource The ftp connection |
|
479
|
|
|
*/ |
|
480
|
|
|
private function getConnection() |
|
481
|
|
|
{ |
|
482
|
|
|
if (!$this->isConnected()) { |
|
483
|
|
|
$this->connect(); |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
return $this->connection; |
|
487
|
|
|
} |
|
488
|
|
|
|
|
489
|
|
|
/** |
|
490
|
|
|
* Opens the adapter's ftp connection |
|
491
|
|
|
* |
|
492
|
|
|
* @throws RuntimeException if could not connect |
|
493
|
|
|
*/ |
|
494
|
|
|
private function connect() |
|
495
|
|
|
{ |
|
496
|
|
|
// open ftp connection |
|
497
|
|
|
if (!$this->ssl) { |
|
498
|
|
|
$this->connection = ftp_connect($this->host, $this->port); |
|
499
|
|
|
} else { |
|
500
|
|
|
if(function_exists('ftp_ssl_connect')) { |
|
501
|
|
|
$this->connection = ftp_ssl_connect($this->host, $this->port); |
|
502
|
|
|
} else { |
|
503
|
|
|
throw new \RuntimeException('This Server Has No SSL-FTP Available.'); |
|
504
|
|
|
} |
|
505
|
|
|
} |
|
506
|
|
|
if (!$this->connection) { |
|
507
|
|
|
throw new \RuntimeException(sprintf('Could not connect to \'%s\' (port: %s).', $this->host, $this->port)); |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
|
$username = $this->username ? : 'anonymous'; |
|
511
|
|
|
$password = $this->password ? : ''; |
|
512
|
|
|
|
|
513
|
|
|
// login ftp user |
|
514
|
|
|
if (!@ftp_login($this->connection, $username, $password)) { |
|
515
|
|
|
$this->close(); |
|
516
|
|
|
throw new \RuntimeException(sprintf('Could not login as %s.', $username)); |
|
517
|
|
|
} |
|
518
|
|
|
|
|
519
|
|
|
// switch to passive mode if needed |
|
520
|
|
|
if ($this->passive && !ftp_pasv($this->connection, true)) { |
|
521
|
|
|
$this->close(); |
|
522
|
|
|
throw new \RuntimeException('Could not turn passive mode on.'); |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
// ensure the adapter's directory exists |
|
526
|
|
|
if ('/' !== $this->directory) { |
|
527
|
|
|
try { |
|
528
|
|
|
$this->ensureDirectoryExists($this->directory, $this->create); |
|
529
|
|
|
} catch (\RuntimeException $e) { |
|
530
|
|
|
$this->close(); |
|
531
|
|
|
throw $e; |
|
532
|
|
|
} |
|
533
|
|
|
|
|
534
|
|
|
// change the current directory for the adapter's directory |
|
535
|
|
|
if (!ftp_chdir($this->connection, $this->directory)) { |
|
536
|
|
|
$this->close(); |
|
537
|
|
|
throw new \RuntimeException(sprintf('Could not change current directory for the \'%s\' directory.', $this->directory)); |
|
538
|
|
|
} |
|
539
|
|
|
} |
|
540
|
|
|
} |
|
541
|
|
|
|
|
542
|
|
|
/** |
|
543
|
|
|
* Closes the adapter's ftp connection |
|
544
|
|
|
*/ |
|
545
|
|
|
private function close() |
|
546
|
|
|
{ |
|
547
|
|
|
if ($this->isConnected()) { |
|
548
|
|
|
ftp_close($this->connection); |
|
549
|
|
|
} |
|
550
|
|
|
} |
|
551
|
|
|
|
|
552
|
|
|
private function isLinuxListing($info) |
|
553
|
|
|
{ |
|
554
|
|
|
return count($info) >= 9; |
|
555
|
|
|
} |
|
556
|
|
|
} |
|
557
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.