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