depage-fs
Loading...
Searching...
No Matches
FtpCurl.php
Go to the documentation of this file.
1<?php
2
4
7
8class FtpCurl
9{
10 public $context;
11
12 protected $path;
13 protected $mode;
14 protected $buffer;
15 protected $pos;
16 protected $dirPos;
17 protected $files;
18 protected $url;
19 protected $translation = ['dev', 'ino', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'size', 'atime', 'mtime', 'ctime', 'blksize', 'blocks'];
20
21 static protected $parameters;
22 static protected $handle;
23 public static function registerStream($protocol, array $parameters = [])
24 {
25 $class = get_called_class();
26 static::$parameters = $parameters;
27
28 if (in_array($protocol, stream_get_wrappers())) {
29 stream_wrapper_unregister($protocol);
30 }
31 stream_wrapper_register($protocol, $class);
32 }
33
34 protected function getParameter($parameter)
35 {
36 return isset(static::$parameters[$parameter]) ? static::$parameters[$parameter] : null;
37 }
38 protected function createHandle($url, $hostOnly = false)
39 {
40 $parsed = Fs::parseUrl($url);
41 $parsed['path'] = str_replace(" ", "%20", $parsed['path']);
42 $host = preg_replace('#' . preg_quote($parsed['path']) . '(/)?$#', '', $url);
43 $path = (isset($parsed['path'])) ? $parsed['path'] : '/';
44 $url = str_replace(" ", "%20", $url);
45
46 if (static::$handle) {
47 curl_reset(static::$handle);
48 $this->curlSet(CURLOPT_URL, ($hostOnly) ? $host : $url);
49 } else {
50 static::$handle = ($hostOnly) ? curl_init($host) : curl_init($url);
51 }
52
53 if (!static::$handle) {
54 throw new FsException('Could not initialize cURL.');
55 }
56
57 $username = $parsed['user'];
58 $password = (isset($parsed['pass'])) ? $parsed['pass'] : '';
59
60 $options = [
61 CURLOPT_USERNAME => rawurldecode($username),
62 CURLOPT_PASSWORD => rawurldecode($password),
63 CURLOPT_RETURNTRANSFER => true,
64 CURLOPT_PORT => (isset($parsed['port'])) ? $parsed['port'] : 21,
65 CURLOPT_FOLLOWLOCATION => true,
66 //CURLOPT_VERBOSE => true,
67 ];
68
69 if ($parsed['scheme'] == "ftps") {
70 $options += [
71 CURLOPT_FTP_SSL => CURLFTPSSL_TRY, // require SSL For both control and data connections
72 CURLOPT_FTPSSLAUTH => CURLFTPAUTH_DEFAULT, // let cURL choose the FTP authentication method (either SSL or TLS)
73 ];
74 }
75
76 if ($this->getParameter('timeout')) {
77 $options[CURLOPT_TIMEOUT] = $this->getParameter('timeout');
78 }
79
80 if ($this->getParameter('caCert')) {
81 $options += [
82 CURLOPT_SSL_VERIFYPEER => true,
83 CURLOPT_SSL_VERIFYHOST => 2,
84 CURLOPT_CAINFO => $this->getParameter('caCert'),
85 ];
86 }
87
88 // cURL FTP enables passive mode by default, so disable it by enabling the PORT command and allowing cURL to select the IP address for the data connection
89 if (!$this->getParameter('passive') === false) {
90 $options[CURLOPT_FTPPORT] = '-';
91 }
92
93 foreach ($options as $option => $value) {
94 $this->curlSet($option, $value);
95 }
96
97 return $path;
98 }
99 public static function disconnect()
100 {
101 static::$handle = null;
102 }
103 protected function curlSet($option, $value)
104 {
105 if (!curl_setopt(static::$handle, $option, $value)) {
106 throw new FsException(sprintf('Could not set cURL option: %s', $option));
107 }
108 }
109 protected function execute()
110 {
111 $result = curl_exec(static::$handle);
112
113 if (
114 $result === false
115 && $this->getParameter('ssl') === false
116 ) {
117 $this->curlSet(CURLOPT_SSL_VERIFYPEER, false);
118 $this->curlSet(CURLOPT_SSL_VERIFYHOST, false);
119
120 $result = curl_exec(static::$handle);
121 }
122
123 if (
124 $result === false
125 && curl_errno(static::$handle) !== 9
126 && curl_errno(static::$handle) !== 21
127 ) {
128 throw new FsException(curl_error(static::$handle) ?: 'cURL request failed.');
129 }
130
131 return $result;
132 }
133 protected function executeFtpCommand($command, $url)
134 {
135 $path = $this->createHandle($url, true);
136 $this->curlSet(CURLOPT_QUOTE, [$command . ' ' . $path]);
137 $this->curlSet(CURLOPT_NOBODY, true);
138
139 $result = $this->execute();
140
141 return ($result === false) ? false : true;
142 }
143
144 protected function isDir($url)
145 {
146 return $this->executeFtpCommand('CWD', $url);
147 }
148 protected function mkdirRecursive($url)
149 {
150 $result = true;
151
152 if (!$this->isDir($url)) {
153 $path = explode('/', $url);
154 array_pop($path);
155 $prev = implode('/', $path);
156 if (!$this->isDir($prev)) {
157 $result = $this->mkdirRecursive($prev);
158 }
159 $result = $result && $result = $this->executeFtpCommand('MKD', $url);
160 }
161
162 return $result;
163 }
164
165 public function stream_open($url, $mode, $options, &$openedPath)
166 {
167 $this->url = $url;
168 $this->mode = $mode;
169 $this->pos = 0;
170
171 $this->createHandle($url);
172
173 if ($this->mode == 'wb') {
174 $this->curlSet(CURLOPT_UPLOAD, true);
175 $this->buffer = fopen('php://temp' , 'w+b');
176 } else {
177 $this->buffer = $this->execute();
178 }
179
180 return true;
181 }
182 public function stream_close()
183 {
184 }
185 public function stream_read($count)
186 {
187 $read = false;
188
189 if (strlen($this->buffer) > 0) {
190 $read = substr($this->buffer, $this->pos, $count);
191 $this->pos += $count;
192 }
193
194 return $read;
195 }
196 public function stream_write($data)
197 {
198 $bytesWritten = fwrite($this->buffer, $data);
199 $this->pos += $bytesWritten;
200
201 return $bytesWritten;
202 }
203 public function stream_eof()
204 {
205 $eof = false;
206
207 if ($this->pos >= strlen($this->buffer)) {
208 $eof = true;
209 }
210
211 return $eof;
212 }
213 public function stream_tell()
214 {
215 return $this->pos;
216 }
217 public function stream_flush()
218 {
219 $result = true;
220
221 if ($this->mode == 'wb') {
222 rewind($this->buffer);
223
224 $this->curlSet(CURLOPT_INFILE, $this->buffer);
225 $this->curlSet(CURLOPT_INFILESIZE, $this->pos);
226
227 $result = ($this->execute() === false) ? false : true;
228 }
229
230 $this->buffer = null;
231 $this->pos = null;
232
233 return $result;
234 }
235 public function stream_stat()
236 {
237 $this->createHandle($this->url);
238
239 $stat = $this->createStat();
240 $this->setStat($stat, 'size', strlen($this->buffer));
241
242 return $stat;
243 }
244 public function url_stat($url, $flags)
245 {
246 $urlArray = explode('/', $url);
247 $nodeName = array_pop($urlArray);
248 $url = implode('/', $urlArray) . '/';
249
250 $stat = false;
251 $this->createHandle($url, false);
252 $this->curlSet(CURLOPT_CUSTOMREQUEST, 'LIST -a');
253 $result = $this->execute();
254
255 if ($result) {
256 $nodes = $this->parseLs($result);
257
258 if (isset($nodes[$nodeName])) {
259 $stat = $this->createStat();
260 $node = $nodes[$nodeName];
261
262 $this->setStat(
263 $stat,
264 'mode',
265 octdec($this->translateFileType($node['type']) . $this->translatePermissions($node['permissions']))
266 );
267 }
268 }
269
270 return $stat;
271 }
272 public function dir_opendir($url, $options)
273 {
274 $this->dirPos = 0;
275
276 $path = $this->createHandle($url, true);
277 $this->curlSet(CURLOPT_CUSTOMREQUEST, 'LIST -a ' . $path);
278 $result = $this->execute();
279
280 $this->files = ($result) ? array_keys($this->parseLs($result)) : [];
281
282 return (bool) $result;
283 }
284 public function dir_readdir()
285 {
286 $result = false;
287
288 if (isset($this->files[$this->dirPos])) {
289 $result = $this->files[$this->dirPos];
290 $this->dirPos++;
291 }
292
293 return $result;
294 }
295 public function mkdir($url, $mode, $options)
296 {
297 if ($options & STREAM_MKDIR_RECURSIVE) {
298 $result = $this->mkdirRecursive($url);
299 } else {
300 $result = $this->executeFtpCommand('MKD', $url);
301 }
302
303 return $result;
304 }
305 public function unlink($url)
306 {
307 return $this->executeFtpCommand('DELE', $url);
308 }
309 public function rmdir($url)
310 {
311 return $this->executeFtpCommand('RMD', $url);
312 }
313 public function rename($urlFrom, $urlTo)
314 {
315 $pathFrom = $this->createHandle($urlFrom, true);
316 $pathTo = $this->createHandle($urlTo, true);
317
318 $this->curlSet(CURLOPT_QUOTE, ['RNFR ' . $pathFrom, 'RNTO ' . $pathTo]);
319
320 return ($this->execute() === false) ? false : true;
321 }
322
323 protected function createStat()
324 {
325 $stat = [];
326
327 foreach($this->translation as $index => $name) {
328 $stat[$index] = 0;
329 $stat[$name] = 0;
330 }
331
332 return $stat;
333 }
334 protected function setStat(&$stat, $name, $value)
335 {
336 $stat[$name] = $value;
337 $stat[array_search($name, $this->translation)] = $value;
338 }
339 protected function parseLs($ls)
340 {
341 $list = explode(PHP_EOL, trim($ls));
342
343 $nodes = [];
344 foreach ($list as $line) {
345 if ($line) {
346 $split = preg_split('/\s+/', $line);
347
348 $info['type'] = $split[0][0];
349 $info['permissions'] = substr(array_shift($split),1);
350 $info['hardlinks'] = array_shift($split);
351 $info['user'] = array_shift($split);
352 $info['group'] = array_shift($split);
353 $info['size'] = array_shift($split);
354 $name = implode(' ', array_splice($split, 3));
355 $info['mtime'] = strtotime(implode(' ', $split));
356
357 $nodes[$name] = $info;
358 }
359 }
360
361 return $nodes;
362 }
363
364 protected function translateFileType($char)
365 {
366 $type = false;
367
368 switch ($char) {
369 case '-': $type = 100; break;
370 case 'd': $type = 40; break;
371 }
372
373 return $type;
374 }
375 protected function translatePermissions($permissions)
376 {
377 $result = '';
378
379 foreach (str_split($permissions, 3) as $operator) {
380 $numerical = 0;
381
382 for ($i = 0; $i < 2; $i++) {
383 if ($operator[$i] !== '-') {
384 $numerical += pow(2, (2 - $i));
385 }
386 }
387
388 $result .= $numerical;
389 }
390
391 return $result;
392 }
393}
394
395// vim:set ft=php sw=4 sts=4 fdm=marker :
static parseUrl($url)
Definition Fs.php:355
createHandle($url, $hostOnly=false)
Definition FtpCurl.php:38
url_stat($url, $flags)
Definition FtpCurl.php:244
mkdir($url, $mode, $options)
Definition FtpCurl.php:295
setStat(&$stat, $name, $value)
Definition FtpCurl.php:334
dir_opendir($url, $options)
Definition FtpCurl.php:272
translatePermissions($permissions)
Definition FtpCurl.php:375
rename($urlFrom, $urlTo)
Definition FtpCurl.php:313
executeFtpCommand($command, $url)
Definition FtpCurl.php:133
curlSet($option, $value)
Definition FtpCurl.php:103
getParameter($parameter)
Definition FtpCurl.php:34
stream_open($url, $mode, $options, &$openedPath)
Definition FtpCurl.php:165
static registerStream($protocol, array $parameters=[])
Definition FtpCurl.php:23