run:R W Run
7.85 KB
2026-03-11 16:18:51
R W Run
3.54 KB
2026-03-11 16:18:51
R W Run
148.33 KB
2026-03-11 16:18:51
R W Run
11.45 KB
2026-03-11 16:18:51
R W Run
3.58 KB
2026-03-11 16:18:51
R W Run
2.53 KB
2026-03-11 16:18:51
R W Run
2.6 KB
2026-03-11 16:18:51
R W Run
6.59 KB
2026-03-11 16:18:51
R W Run
14.83 KB
2026-03-11 16:18:51
R W Run
21.18 KB
2026-03-11 16:18:51
R W Run
48.13 KB
2026-03-11 16:18:51
R W Run
4.07 KB
2026-03-11 16:18:51
R W Run
5.3 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
26.73 KB
2026-03-11 16:18:51
R W Run
2.8 KB
2026-03-11 16:18:51
R W Run
15.2 KB
2026-03-11 16:18:51
R W Run
192.08 KB
2026-03-11 16:18:51
R W Run
11.77 KB
2026-03-11 16:18:51
R W Run
3.2 KB
2026-03-11 16:18:51
R W Run
22.89 KB
2026-03-11 16:18:51
R W Run
12.77 KB
2026-03-11 16:18:51
R W Run
4.08 KB
2026-03-11 16:18:51
R W Run
26.27 KB
2026-03-11 16:18:51
R W Run
4.97 KB
2026-03-11 16:18:51
R W Run
5.57 KB
2026-03-11 16:18:51
R W Run
13.93 KB
2026-03-11 16:18:51
R W Run
4.09 KB
2026-03-11 16:18:51
R W Run
6.79 KB
2026-03-11 16:18:51
R W Run
60.45 KB
2026-03-11 16:18:51
R W Run
32.4 KB
2026-03-11 16:18:51
R W Run
18.24 KB
2026-03-11 16:18:51
R W Run
66.01 KB
2026-03-11 16:18:51
R W Run
23.84 KB
2026-03-11 16:18:51
R W Run
17.72 KB
2026-03-11 16:18:51
R W Run
22.71 KB
2026-03-11 16:18:51
R W Run
18.05 KB
2026-03-11 16:18:51
R W Run
22.76 KB
2026-03-11 16:18:51
R W Run
7.34 KB
2026-03-11 16:18:51
R W Run
4.51 KB
2026-03-11 16:18:51
R W Run
9.02 KB
2026-03-11 16:18:51
R W Run
1.46 KB
2026-03-11 16:18:51
R W Run
51.76 KB
2026-03-11 16:18:51
R W Run
25.29 KB
2026-03-11 16:18:51
R W Run
21.61 KB
2026-03-11 16:18:51
R W Run
27.77 KB
2026-03-11 16:18:51
R W Run
15.35 KB
2026-03-11 16:18:51
R W Run
24.54 KB
2026-03-11 16:18:51
R W Run
56.44 KB
2026-03-11 16:18:51
R W Run
1.42 KB
2026-03-11 16:18:51
R W Run
63.66 KB
2026-03-11 16:18:51
R W Run
31.9 KB
2026-03-11 16:18:51
R W Run
14.44 KB
2026-03-11 16:18:51
R W Run
36.47 KB
2026-03-11 16:18:51
R W Run
14 KB
2026-03-11 16:18:51
R W Run
121.89 KB
2026-03-11 16:18:51
R W Run
6.26 KB
2026-03-11 16:18:51
R W Run
20.73 KB
2026-03-11 16:18:51
R W Run
15.23 KB
2026-03-11 16:18:51
R W Run
10.14 KB
2026-03-11 16:18:51
R W Run
6.94 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
46.85 KB
2026-03-11 16:18:51
R W Run
18.61 KB
2026-03-11 16:18:51
R W Run
6.08 KB
2026-03-11 16:18:51
R W Run
20.06 KB
2026-03-11 16:18:51
R W Run
5.73 KB
2026-03-11 16:18:51
R W Run
68.18 KB
2026-03-11 16:18:51
R W Run
40.8 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
25.26 KB
2026-03-11 16:18:51
R W Run
95.94 KB
2026-03-11 16:18:51
R W Run
43.12 KB
2026-03-11 16:18:51
R W Run
41.73 KB
2026-03-11 16:18:51
R W Run
6.46 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
116.31 KB
2026-03-11 16:18:51
R W Run
9.39 KB
2026-03-11 16:18:51
R W Run
64.34 KB
2026-03-11 16:18:51
R W Run
44.73 KB
2026-03-11 16:18:51
R W Run
1.27 KB
2026-03-11 16:18:51
R W Run
3.68 KB
2026-03-11 16:18:51
R W Run
33.53 KB
2026-03-11 16:18:51
R W Run
48.84 KB
2026-03-11 16:18:51
R W Run
26.35 KB
2026-03-11 16:18:51
R W Run
1.12 KB
2026-03-11 16:18:51
R W Run
4.19 KB
2026-03-11 16:18:51
R W Run
38.19 KB
2026-03-11 16:18:51
R W Run
91.33 KB
2026-03-11 16:18:51
R W Run
80.39 KB
2026-03-11 16:18:51
R W Run
32.67 KB
2026-03-11 16:18:51
R W Run
16.18 KB
2026-03-11 16:18:51
R W Run
44.46 KB
2026-03-11 16:18:51
R W Run
6.23 KB
2026-03-11 16:18:51
R W Run
8.23 KB
2026-03-11 16:18:51
R W Run
96.96 KB
2026-03-11 16:18:51
R W Run
6.83 KB
2026-03-11 16:18:51
R W Run
46.62 KB
2026-03-11 16:18:51
R W Run
10.82 KB
2026-03-11 16:18:51
R W Run
68.86 KB
2026-03-11 16:18:51
R W Run
33.63 KB
2026-03-11 16:18:51
R W Run
113.3 KB
2026-03-11 16:18:51
R W Run
22.98 KB
2026-03-11 16:18:51
R W Run
10.66 KB
2026-03-11 16:18:51
R W Run
error_log
📄class-ftp.php
1<?php
2/**
3 * PemFTP - An Ftp implementation in pure PHP
4 *
5 * @package PemFTP
6 * @since 2.5.0
7 *
8 * @version 1.0
9 * @copyright Alexey Dotsenko
10 * @author Alexey Dotsenko
11 * @link https://www.phpclasses.org/package/1743-PHP-FTP-client-in-pure-PHP.html
12 * @license LGPL https://opensource.org/licenses/lgpl-license.html
13 */
14
15/**
16 * Defines the newline characters, if not defined already.
17 *
18 * This can be redefined.
19 *
20 * @since 2.5.0
21 * @var string
22 */
23if ( ! defined( 'CRLF' ) ) {
24 define( 'CRLF', "\r\n" );
25}
26
27/**
28 * Sets whatever to autodetect ASCII mode.
29 *
30 * This can be redefined.
31 *
32 * @since 2.5.0
33 * @var int
34 */
35if ( ! defined( 'FTP_AUTOASCII' ) ) {
36 define( 'FTP_AUTOASCII', -1 );
37}
38
39/**
40 *
41 * This can be redefined.
42 * @since 2.5.0
43 * @var int
44 */
45if ( ! defined( 'FTP_BINARY' ) ) {
46 define( 'FTP_BINARY', 1 );
47}
48
49/**
50 *
51 * This can be redefined.
52 * @since 2.5.0
53 * @var int
54 */
55if ( ! defined( 'FTP_ASCII' ) ) {
56 define( 'FTP_ASCII', 0 );
57}
58
59/**
60 * Whether to force FTP.
61 *
62 * This can be redefined.
63 *
64 * @since 2.5.0
65 * @var bool
66 */
67if ( ! defined( 'FTP_FORCE' ) ) {
68 define( 'FTP_FORCE', true );
69}
70
71/**
72 * @since 2.5.0
73 * @var string
74 */
75define('FTP_OS_Unix','u');
76
77/**
78 * @since 2.5.0
79 * @var string
80 */
81define('FTP_OS_Windows','w');
82
83/**
84 * @since 2.5.0
85 * @var string
86 */
87define('FTP_OS_Mac','m');
88
89/**
90 * PemFTP base class
91 *
92 */
93class ftp_base {
94 /* Public variables */
95 var $LocalEcho;
96 var $Verbose;
97 var $OS_local;
98 var $OS_remote;
99
100 /* Private variables */
101 var $_lastaction;
102 var $_errors;
103 var $_type;
104 var $_umask;
105 var $_timeout;
106 var $_passive;
107 var $_host;
108 var $_fullhost;
109 var $_port;
110 var $_datahost;
111 var $_dataport;
112 var $_ftp_control_sock;
113 var $_ftp_data_sock;
114 var $_ftp_temp_sock;
115 var $_ftp_buff_size;
116 var $_login;
117 var $_password;
118 var $_connected;
119 var $_ready;
120 var $_code;
121 var $_message;
122 var $_can_restore;
123 var $_port_available;
124 var $_curtype;
125 var $_features;
126
127 var $_error_array;
128 var $AuthorizedTransferMode;
129 var $OS_FullName;
130 var $_eol_code;
131 var $AutoAsciiExt;
132
133 /* Constructor */
134 function __construct($port_mode=FALSE, $verb=FALSE, $le=FALSE) {
135 $this->LocalEcho=$le;
136 $this->Verbose=$verb;
137 $this->_lastaction=NULL;
138 $this->_error_array=array();
139 $this->_eol_code=array(FTP_OS_Unix=>"\n", FTP_OS_Mac=>"\r", FTP_OS_Windows=>"\r\n");
140 $this->AuthorizedTransferMode=array(FTP_AUTOASCII, FTP_ASCII, FTP_BINARY);
141 $this->OS_FullName=array(FTP_OS_Unix => 'UNIX', FTP_OS_Windows => 'WINDOWS', FTP_OS_Mac => 'MACOS');
142 $this->AutoAsciiExt=array("ASP","BAT","C","CPP","CSS","CSV","JS","H","HTM","HTML","SHTML","INI","LOG","PHP3","PHTML","PL","PERL","SH","SQL","TXT");
143 $this->_port_available=($port_mode==TRUE);
144 $this->SendMSG("Staring FTP client class".($this->_port_available?"":" without PORT mode support"));
145 $this->_connected=FALSE;
146 $this->_ready=FALSE;
147 $this->_can_restore=FALSE;
148 $this->_code=0;
149 $this->_message="";
150 $this->_ftp_buff_size=4096;
151 $this->_curtype=NULL;
152 $this->SetUmask(0022);
153 $this->SetType(FTP_AUTOASCII);
154 $this->SetTimeout(30);
155 $this->Passive(!$this->_port_available);
156 $this->_login="anonymous";
157 $this->_password="anon@ftp.com";
158 $this->_features=array();
159 $this->OS_local=FTP_OS_Unix;
160 $this->OS_remote=FTP_OS_Unix;
161 $this->features=array();
162 if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $this->OS_local=FTP_OS_Windows;
163 elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') $this->OS_local=FTP_OS_Mac;
164 }
165
166 function ftp_base($port_mode=FALSE) {
167 $this->__construct($port_mode);
168 }
169
170// <!-- --------------------------------------------------------------------------------------- -->
171// <!-- Public functions -->
172// <!-- --------------------------------------------------------------------------------------- -->
173
174 function parselisting($line) {
175 $is_windows = ($this->OS_remote == FTP_OS_Windows);
176 if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/",$line,$lucifer)) {
177 $b = array();
178 if ($lucifer[3]<70) { $lucifer[3]+=2000; } else { $lucifer[3]+=1900; } // 4digit year fix
179 $b['isdir'] = ($lucifer[7]=="<DIR>");
180 if ( $b['isdir'] )
181 $b['type'] = 'd';
182 else
183 $b['type'] = 'f';
184 $b['size'] = $lucifer[7];
185 $b['month'] = $lucifer[1];
186 $b['day'] = $lucifer[2];
187 $b['year'] = $lucifer[3];
188 $b['hour'] = $lucifer[4];
189 $b['minute'] = $lucifer[5];
190 $b['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]);
191 $b['am/pm'] = $lucifer[6];
192 $b['name'] = $lucifer[8];
193 } else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) {
194 //echo $line."\n";
195 $lcount=count($lucifer);
196 if ($lcount<8) return '';
197 $b = array();
198 $b['isdir'] = $lucifer[0][0] === "d";
199 $b['islink'] = $lucifer[0][0] === "l";
200 if ( $b['isdir'] )
201 $b['type'] = 'd';
202 elseif ( $b['islink'] )
203 $b['type'] = 'l';
204 else
205 $b['type'] = 'f';
206 $b['perms'] = $lucifer[0];
207 $b['number'] = $lucifer[1];
208 $b['owner'] = $lucifer[2];
209 $b['group'] = $lucifer[3];
210 $b['size'] = $lucifer[4];
211 if ($lcount==8) {
212 sscanf($lucifer[5],"%d-%d-%d",$b['year'],$b['month'],$b['day']);
213 sscanf($lucifer[6],"%d:%d",$b['hour'],$b['minute']);
214 $b['time'] = @mktime($b['hour'],$b['minute'],0,$b['month'],$b['day'],$b['year']);
215 $b['name'] = $lucifer[7];
216 } else {
217 $b['month'] = $lucifer[5];
218 $b['day'] = $lucifer[6];
219 if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) {
220 $b['year'] = gmdate("Y");
221 $b['hour'] = $l2[1];
222 $b['minute'] = $l2[2];
223 } else {
224 $b['year'] = $lucifer[7];
225 $b['hour'] = 0;
226 $b['minute'] = 0;
227 }
228 $b['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b['day'],$b['month'],$b['year'],$b['hour'],$b['minute']));
229 $b['name'] = $lucifer[8];
230 }
231 }
232
233 return $b;
234 }
235
236 function SendMSG($message = "", $crlf=true) {
237 if ($this->Verbose) {
238 echo $message.($crlf?CRLF:"");
239 flush();
240 }
241 return TRUE;
242 }
243
244 function SetType($mode=FTP_AUTOASCII) {
245 if(!in_array($mode, $this->AuthorizedTransferMode)) {
246 $this->SendMSG("Wrong type");
247 return FALSE;
248 }
249 $this->_type=$mode;
250 $this->SendMSG("Transfer type: ".($this->_type==FTP_BINARY?"binary":($this->_type==FTP_ASCII?"ASCII":"auto ASCII") ) );
251 return TRUE;
252 }
253
254 function _settype($mode=FTP_ASCII) {
255 if($this->_ready) {
256 if($mode==FTP_BINARY) {
257 if($this->_curtype!=FTP_BINARY) {
258 if(!$this->_exec("TYPE I", "SetType")) return FALSE;
259 $this->_curtype=FTP_BINARY;
260 }
261 } elseif($this->_curtype!=FTP_ASCII) {
262 if(!$this->_exec("TYPE A", "SetType")) return FALSE;
263 $this->_curtype=FTP_ASCII;
264 }
265 } else return FALSE;
266 return TRUE;
267 }
268
269 function Passive($pasv=NULL) {
270 if(is_null($pasv)) $this->_passive=!$this->_passive;
271 else $this->_passive=$pasv;
272 if(!$this->_port_available and !$this->_passive) {
273 $this->SendMSG("Only passive connections available!");
274 $this->_passive=TRUE;
275 return FALSE;
276 }
277 $this->SendMSG("Passive mode ".($this->_passive?"on":"off"));
278 return TRUE;
279 }
280
281 function SetServer($host, $port=21, $reconnect=true) {
282 if(!is_long($port)) {
283 $this->verbose=true;
284 $this->SendMSG("Incorrect port syntax");
285 return FALSE;
286 } else {
287 $ip=@gethostbyname($host);
288 $dns=@gethostbyaddr($host);
289 if(!$ip) $ip=$host;
290 if(!$dns) $dns=$host;
291 // Validate the IPAddress PHP4 returns -1 for invalid, PHP5 false
292 // -1 === "255.255.255.255" which is the broadcast address which is also going to be invalid
293 $ipaslong = ip2long($ip);
294 if ( ($ipaslong == false) || ($ipaslong === -1) ) {
295 $this->SendMSG("Wrong host name/address \"".$host."\"");
296 return FALSE;
297 }
298 $this->_host=$ip;
299 $this->_fullhost=$dns;
300 $this->_port=$port;
301 $this->_dataport=$port-1;
302 }
303 $this->SendMSG("Host \"".$this->_fullhost."(".$this->_host."):".$this->_port."\"");
304 if($reconnect){
305 if($this->_connected) {
306 $this->SendMSG("Reconnecting");
307 if(!$this->quit(FTP_FORCE)) return FALSE;
308 if(!$this->connect()) return FALSE;
309 }
310 }
311 return TRUE;
312 }
313
314 function SetUmask($umask=0022) {
315 $this->_umask=$umask;
316 umask($this->_umask);
317 $this->SendMSG("UMASK 0".decoct($this->_umask));
318 return TRUE;
319 }
320
321 function SetTimeout($timeout=30) {
322 $this->_timeout=$timeout;
323 $this->SendMSG("Timeout ".$this->_timeout);
324 if($this->_connected)
325 if(!$this->_settimeout($this->_ftp_control_sock)) return FALSE;
326 return TRUE;
327 }
328
329 function connect($server=NULL) {
330 if(!empty($server)) {
331 if(!$this->SetServer($server)) return false;
332 }
333 if($this->_ready) return true;
334 $this->SendMsg('Local OS : '.$this->OS_FullName[$this->OS_local]);
335 if(!($this->_ftp_control_sock = $this->_connect($this->_host, $this->_port))) {
336 $this->SendMSG("Error : Cannot connect to remote host \"".$this->_fullhost." :".$this->_port."\"");
337 return FALSE;
338 }
339 $this->SendMSG("Connected to remote host \"".$this->_fullhost.":".$this->_port."\". Waiting for greeting.");
340 do {
341 if(!$this->_readmsg()) return FALSE;
342 if(!$this->_checkCode()) return FALSE;
343 $this->_lastaction=time();
344 } while($this->_code<200);
345 $this->_ready=true;
346 $syst=$this->systype();
347 if(!$syst) $this->SendMSG("Cannot detect remote OS");
348 else {
349 if(preg_match("/win|dos|novell/i", $syst[0])) $this->OS_remote=FTP_OS_Windows;
350 elseif(preg_match("/os/i", $syst[0])) $this->OS_remote=FTP_OS_Mac;
351 elseif(preg_match("/(li|u)nix/i", $syst[0])) $this->OS_remote=FTP_OS_Unix;
352 else $this->OS_remote=FTP_OS_Mac;
353 $this->SendMSG("Remote OS: ".$this->OS_FullName[$this->OS_remote]);
354 }
355 if(!$this->features()) $this->SendMSG("Cannot get features list. All supported - disabled");
356 else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
357 return TRUE;
358 }
359
360 function quit($force=false) {
361 if($this->_ready) {
362 if(!$this->_exec("QUIT") and !$force) return FALSE;
363 if(!$this->_checkCode() and !$force) return FALSE;
364 $this->_ready=false;
365 $this->SendMSG("Session finished");
366 }
367 $this->_quit();
368 return TRUE;
369 }
370
371 function login($user=NULL, $pass=NULL) {
372 if(!is_null($user)) $this->_login=$user;
373 else $this->_login="anonymous";
374 if(!is_null($pass)) $this->_password=$pass;
375 else $this->_password="anon@anon.com";
376 if(!$this->_exec("USER ".$this->_login, "login")) return FALSE;
377 if(!$this->_checkCode()) return FALSE;
378 if($this->_code!=230) {
379 if(!$this->_exec((($this->_code==331)?"PASS ":"ACCT ").$this->_password, "login")) return FALSE;
380 if(!$this->_checkCode()) return FALSE;
381 }
382 $this->SendMSG("Authentication succeeded");
383 if(empty($this->_features)) {
384 if(!$this->features()) $this->SendMSG("Cannot get features list. All supported - disabled");
385 else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
386 }
387 return TRUE;
388 }
389
390 function pwd() {
391 if(!$this->_exec("PWD", "pwd")) return FALSE;
392 if(!$this->_checkCode()) return FALSE;
393 return preg_replace("/^[0-9]{3} \"(.+)\".*$/s", "\\1", $this->_message);
394 }
395
396 function cdup() {
397 if(!$this->_exec("CDUP", "cdup")) return FALSE;
398 if(!$this->_checkCode()) return FALSE;
399 return true;
400 }
401
402 function chdir($pathname) {
403 if(!$this->_exec("CWD ".$pathname, "chdir")) return FALSE;
404 if(!$this->_checkCode()) return FALSE;
405 return TRUE;
406 }
407
408 function rmdir($pathname) {
409 if(!$this->_exec("RMD ".$pathname, "rmdir")) return FALSE;
410 if(!$this->_checkCode()) return FALSE;
411 return TRUE;
412 }
413
414 function mkdir($pathname) {
415 if(!$this->_exec("MKD ".$pathname, "mkdir")) return FALSE;
416 if(!$this->_checkCode()) return FALSE;
417 return TRUE;
418 }
419
420 function rename($from, $to) {
421 if(!$this->_exec("RNFR ".$from, "rename")) return FALSE;
422 if(!$this->_checkCode()) return FALSE;
423 if($this->_code==350) {
424 if(!$this->_exec("RNTO ".$to, "rename")) return FALSE;
425 if(!$this->_checkCode()) return FALSE;
426 } else return FALSE;
427 return TRUE;
428 }
429
430 function filesize($pathname) {
431 if(!isset($this->_features["SIZE"])) {
432 $this->PushError("filesize", "not supported by server");
433 return FALSE;
434 }
435 if(!$this->_exec("SIZE ".$pathname, "filesize")) return FALSE;
436 if(!$this->_checkCode()) return FALSE;
437 return preg_replace("/^[0-9]{3} ([0-9]+).*$/s", "\\1", $this->_message);
438 }
439
440 function abort() {
441 if(!$this->_exec("ABOR", "abort")) return FALSE;
442 if(!$this->_checkCode()) {
443 if($this->_code!=426) return FALSE;
444 if(!$this->_readmsg("abort")) return FALSE;
445 if(!$this->_checkCode()) return FALSE;
446 }
447 return true;
448 }
449
450 function mdtm($pathname) {
451 if(!isset($this->_features["MDTM"])) {
452 $this->PushError("mdtm", "not supported by server");
453 return FALSE;
454 }
455 if(!$this->_exec("MDTM ".$pathname, "mdtm")) return FALSE;
456 if(!$this->_checkCode()) return FALSE;
457 $mdtm = preg_replace("/^[0-9]{3} ([0-9]+).*$/s", "\\1", $this->_message);
458 $date = sscanf($mdtm, "%4d%2d%2d%2d%2d%2d");
459 $timestamp = mktime($date[3], $date[4], $date[5], $date[1], $date[2], $date[0]);
460 return $timestamp;
461 }
462
463 function systype() {
464 if(!$this->_exec("SYST", "systype")) return FALSE;
465 if(!$this->_checkCode()) return FALSE;
466 $DATA = explode(" ", $this->_message);
467 return array($DATA[1], $DATA[3]);
468 }
469
470 function delete($pathname) {
471 if(!$this->_exec("DELE ".$pathname, "delete")) return FALSE;
472 if(!$this->_checkCode()) return FALSE;
473 return TRUE;
474 }
475
476 function site($command, $fnction="site") {
477 if(!$this->_exec("SITE ".$command, $fnction)) return FALSE;
478 if(!$this->_checkCode()) return FALSE;
479 return TRUE;
480 }
481
482 function chmod($pathname, $mode) {
483 if(!$this->site( sprintf('CHMOD %o %s', $mode, $pathname), "chmod")) return FALSE;
484 return TRUE;
485 }
486
487 function restore($from) {
488 if(!isset($this->_features["REST"])) {
489 $this->PushError("restore", "not supported by server");
490 return FALSE;
491 }
492 if($this->_curtype!=FTP_BINARY) {
493 $this->PushError("restore", "cannot restore in ASCII mode");
494 return FALSE;
495 }
496 if(!$this->_exec("REST ".$from, "restore")) return FALSE;
497 if(!$this->_checkCode()) return FALSE;
498 return TRUE;
499 }
500
501 function features() {
502 if(!$this->_exec("FEAT", "features")) return FALSE;
503 if(!$this->_checkCode()) return FALSE;
504 $f=preg_split("/[".CRLF."]+/", preg_replace("/[0-9]{3}[ -].*[".CRLF."]+/", "", $this->_message), -1, PREG_SPLIT_NO_EMPTY);
505 $this->_features=array();
506 foreach($f as $k=>$v) {
507 $v=explode(" ", trim($v));
508 $this->_features[array_shift($v)]=$v;
509 }
510 return true;
511 }
512
513 function rawlist($pathname="", $arg="") {
514 return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "LIST", "rawlist");
515 }
516
517 function nlist($pathname="", $arg="") {
518 return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "NLST", "nlist");
519 }
520
521 function is_exists($pathname) {
522 return $this->file_exists($pathname);
523 }
524
525 function file_exists($pathname) {
526 $exists=true;
527 if(!$this->_exec("RNFR ".$pathname, "rename")) $exists=FALSE;
528 else {
529 if(!$this->_checkCode()) $exists=FALSE;
530 $this->abort();
531 }
532 if($exists) $this->SendMSG("Remote file ".$pathname." exists");
533 else $this->SendMSG("Remote file ".$pathname." does not exist");
534 return $exists;
535 }
536
537 function fget($fp, $remotefile, $rest=0) {
538 if($this->_can_restore and $rest!=0) fseek($fp, $rest);
539 $pi=pathinfo($remotefile);
540 if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
541 else $mode=FTP_BINARY;
542 if(!$this->_data_prepare($mode)) {
543 return FALSE;
544 }
545 if($this->_can_restore and $rest!=0) $this->restore($rest);
546 if(!$this->_exec("RETR ".$remotefile, "get")) {
547 $this->_data_close();
548 return FALSE;
549 }
550 if(!$this->_checkCode()) {
551 $this->_data_close();
552 return FALSE;
553 }
554 $out=$this->_data_read($mode, $fp);
555 $this->_data_close();
556 if(!$this->_readmsg()) return FALSE;
557 if(!$this->_checkCode()) return FALSE;
558 return $out;
559 }
560
561 function get($remotefile, $localfile=NULL, $rest=0) {
562 if(is_null($localfile)) $localfile=$remotefile;
563 if (@file_exists($localfile)) $this->SendMSG("Warning : local file will be overwritten");
564 $fp = @fopen($localfile, "w");
565 if (!$fp) {
566 $this->PushError("get","cannot open local file", "Cannot create \"".$localfile."\"");
567 return FALSE;
568 }
569 if($this->_can_restore and $rest!=0) fseek($fp, $rest);
570 $pi=pathinfo($remotefile);
571 if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
572 else $mode=FTP_BINARY;
573 if(!$this->_data_prepare($mode)) {
574 fclose($fp);
575 return FALSE;
576 }
577 if($this->_can_restore and $rest!=0) $this->restore($rest);
578 if(!$this->_exec("RETR ".$remotefile, "get")) {
579 $this->_data_close();
580 fclose($fp);
581 return FALSE;
582 }
583 if(!$this->_checkCode()) {
584 $this->_data_close();
585 fclose($fp);
586 return FALSE;
587 }
588 $out=$this->_data_read($mode, $fp);
589 fclose($fp);
590 $this->_data_close();
591 if(!$this->_readmsg()) return FALSE;
592 if(!$this->_checkCode()) return FALSE;
593 return $out;
594 }
595
596 function fput($remotefile, $fp, $rest=0) {
597 if($this->_can_restore and $rest!=0) fseek($fp, $rest);
598 $pi=pathinfo($remotefile);
599 if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
600 else $mode=FTP_BINARY;
601 if(!$this->_data_prepare($mode)) {
602 return FALSE;
603 }
604 if($this->_can_restore and $rest!=0) $this->restore($rest);
605 if(!$this->_exec("STOR ".$remotefile, "put")) {
606 $this->_data_close();
607 return FALSE;
608 }
609 if(!$this->_checkCode()) {
610 $this->_data_close();
611 return FALSE;
612 }
613 $ret=$this->_data_write($mode, $fp);
614 $this->_data_close();
615 if(!$this->_readmsg()) return FALSE;
616 if(!$this->_checkCode()) return FALSE;
617 return $ret;
618 }
619
620 function put($localfile, $remotefile=NULL, $rest=0) {
621 if(is_null($remotefile)) $remotefile=$localfile;
622 if (!file_exists($localfile)) {
623 $this->PushError("put","cannot open local file", "No such file or directory \"".$localfile."\"");
624 return FALSE;
625 }
626 $fp = @fopen($localfile, "r");
627
628 if (!$fp) {
629 $this->PushError("put","cannot open local file", "Cannot read file \"".$localfile."\"");
630 return FALSE;
631 }
632 if($this->_can_restore and $rest!=0) fseek($fp, $rest);
633 $pi=pathinfo($localfile);
634 if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
635 else $mode=FTP_BINARY;
636 if(!$this->_data_prepare($mode)) {
637 fclose($fp);
638 return FALSE;
639 }
640 if($this->_can_restore and $rest!=0) $this->restore($rest);
641 if(!$this->_exec("STOR ".$remotefile, "put")) {
642 $this->_data_close();
643 fclose($fp);
644 return FALSE;
645 }
646 if(!$this->_checkCode()) {
647 $this->_data_close();
648 fclose($fp);
649 return FALSE;
650 }
651 $ret=$this->_data_write($mode, $fp);
652 fclose($fp);
653 $this->_data_close();
654 if(!$this->_readmsg()) return FALSE;
655 if(!$this->_checkCode()) return FALSE;
656 return $ret;
657 }
658
659 function mput($local=".", $remote=NULL, $continious=false) {
660 $local=realpath($local);
661 if(!@file_exists($local)) {
662 $this->PushError("mput","cannot open local folder", "Cannot stat folder \"".$local."\"");
663 return FALSE;
664 }
665 if(!is_dir($local)) return $this->put($local, $remote);
666 if(empty($remote)) $remote=".";
667 elseif(!$this->file_exists($remote) and !$this->mkdir($remote)) return FALSE;
668 if($handle = opendir($local)) {
669 $list=array();
670 while (false !== ($file = readdir($handle))) {
671 if ($file != "." && $file != "..") $list[]=$file;
672 }
673 closedir($handle);
674 } else {
675 $this->PushError("mput","cannot open local folder", "Cannot read folder \"".$local."\"");
676 return FALSE;
677 }
678 if(empty($list)) return TRUE;
679 $ret=true;
680 foreach($list as $el) {
681 if(is_dir($local."/".$el)) $t=$this->mput($local."/".$el, $remote."/".$el);
682 else $t=$this->put($local."/".$el, $remote."/".$el);
683 if(!$t) {
684 $ret=FALSE;
685 if(!$continious) break;
686 }
687 }
688 return $ret;
689
690 }
691
692 function mget($remote, $local=".", $continious=false) {
693 $list=$this->rawlist($remote, "-lA");
694 if($list===false) {
695 $this->PushError("mget","cannot read remote folder list", "Cannot read remote folder \"".$remote."\" contents");
696 return FALSE;
697 }
698 if(empty($list)) return true;
699 if(!@file_exists($local)) {
700 if(!@mkdir($local)) {
701 $this->PushError("mget","cannot create local folder", "Cannot create folder \"".$local."\"");
702 return FALSE;
703 }
704 }
705 foreach($list as $k=>$v) {
706 $list[$k]=$this->parselisting($v);
707 if( ! $list[$k] or $list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
708 }
709 $ret=true;
710 foreach($list as $el) {
711 if($el["type"]=="d") {
712 if(!$this->mget($remote."/".$el["name"], $local."/".$el["name"], $continious)) {
713 $this->PushError("mget", "cannot copy folder", "Cannot copy remote folder \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
714 $ret=false;
715 if(!$continious) break;
716 }
717 } else {
718 if(!$this->get($remote."/".$el["name"], $local."/".$el["name"])) {
719 $this->PushError("mget", "cannot copy file", "Cannot copy remote file \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
720 $ret=false;
721 if(!$continious) break;
722 }
723 }
724 @chmod($local."/".$el["name"], $el["perms"]);
725 $t=strtotime($el["date"]);
726 if($t!==-1 and $t!==false) @touch($local."/".$el["name"], $t);
727 }
728 return $ret;
729 }
730
731 function mdel($remote, $continious=false) {
732 $list=$this->rawlist($remote, "-la");
733 if($list===false) {
734 $this->PushError("mdel","cannot read remote folder list", "Cannot read remote folder \"".$remote."\" contents");
735 return false;
736 }
737
738 foreach($list as $k=>$v) {
739 $list[$k]=$this->parselisting($v);
740 if( ! $list[$k] or $list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
741 }
742 $ret=true;
743
744 foreach($list as $el) {
745 if ( empty($el) )
746 continue;
747
748 if($el["type"]=="d") {
749 if(!$this->mdel($remote."/".$el["name"], $continious)) {
750 $ret=false;
751 if(!$continious) break;
752 }
753 } else {
754 if (!$this->delete($remote."/".$el["name"])) {
755 $this->PushError("mdel", "cannot delete file", "Cannot delete remote file \"".$remote."/".$el["name"]."\"");
756 $ret=false;
757 if(!$continious) break;
758 }
759 }
760 }
761
762 if(!$this->rmdir($remote)) {
763 $this->PushError("mdel", "cannot delete folder", "Cannot delete remote folder \"".$remote."/".$el["name"]."\"");
764 $ret=false;
765 }
766 return $ret;
767 }
768
769 function mmkdir($dir, $mode = 0777) {
770 if(empty($dir)) return FALSE;
771 if($this->is_exists($dir) or $dir == "/" ) return TRUE;
772 if(!$this->mmkdir(dirname($dir), $mode)) return false;
773 $r=$this->mkdir($dir, $mode);
774 $this->chmod($dir,$mode);
775 return $r;
776 }
777
778 function glob($pattern, $handle=NULL) {
779 $path=$output=null;
780 if(PHP_OS=='WIN32') $slash='\\';
781 else $slash='/';
782 $lastpos=strrpos($pattern,$slash);
783 if(!($lastpos===false)) {
784 $path=substr($pattern,0,-$lastpos-1);
785 $pattern=substr($pattern,$lastpos);
786 } else $path=getcwd();
787 if(is_array($handle) and !empty($handle)) {
788 foreach($handle as $dir) {
789 if($this->glob_pattern_match($pattern,$dir))
790 $output[]=$dir;
791 }
792 } else {
793 $handle=@opendir($path);
794 if($handle===false) return false;
795 while($dir=readdir($handle)) {
796 if($this->glob_pattern_match($pattern,$dir))
797 $output[]=$dir;
798 }
799 closedir($handle);
800 }
801 if(is_array($output)) return $output;
802 return false;
803 }
804
805 function glob_pattern_match($pattern,$subject) {
806 $out=null;
807 $chunks=explode(';',$pattern);
808 foreach($chunks as $pattern) {
809 $escape=array('$','^','.','{','}','(',')','[',']','|');
810 while(str_contains($pattern,'**'))
811 $pattern=str_replace('**','*',$pattern);
812 foreach($escape as $probe)
813 $pattern=str_replace($probe,"\\$probe",$pattern);
814 $pattern=str_replace('?*','*',
815 str_replace('*?','*',
816 str_replace('*',".*",
817 str_replace('?','.{1,1}',$pattern))));
818 $out[]=$pattern;
819 }
820 if(count($out)==1) return($this->glob_regexp("^$out[0]$",$subject));
821 else {
822 foreach($out as $tester)
823 // TODO: This should probably be glob_regexp(), but needs tests.
824 if($this->my_regexp("^$tester$",$subject)) return true;
825 }
826 return false;
827 }
828
829 function glob_regexp($pattern,$subject) {
830 $sensitive=(PHP_OS!='WIN32');
831 return ($sensitive?
832 preg_match( '/' . preg_quote( $pattern, '/' ) . '/', $subject ) :
833 preg_match( '/' . preg_quote( $pattern, '/' ) . '/i', $subject )
834 );
835 }
836
837 function dirlist($remote) {
838 $list=$this->rawlist($remote, "-la");
839 if($list===false) {
840 $this->PushError("dirlist","cannot read remote folder list", "Cannot read remote folder \"".$remote."\" contents");
841 return false;
842 }
843
844 $dirlist = array();
845 foreach($list as $k=>$v) {
846 $entry=$this->parselisting($v);
847 if ( empty($entry) )
848 continue;
849
850 if($entry["name"]=="." or $entry["name"]=="..")
851 continue;
852
853 $dirlist[$entry['name']] = $entry;
854 }
855
856 return $dirlist;
857 }
858// <!-- --------------------------------------------------------------------------------------- -->
859// <!-- Private functions -->
860// <!-- --------------------------------------------------------------------------------------- -->
861 function _checkCode() {
862 return ($this->_code<400 and $this->_code>0);
863 }
864
865 function _list($arg="", $cmd="LIST", $fnction="_list") {
866 if(!$this->_data_prepare()) return false;
867 if(!$this->_exec($cmd.$arg, $fnction)) {
868 $this->_data_close();
869 return FALSE;
870 }
871 if(!$this->_checkCode()) {
872 $this->_data_close();
873 return FALSE;
874 }
875 $out="";
876 if($this->_code<200) {
877 $out=$this->_data_read();
878 $this->_data_close();
879 if(!$this->_readmsg()) return FALSE;
880 if(!$this->_checkCode()) return FALSE;
881 if($out === FALSE ) return FALSE;
882 $out=preg_split("/[".CRLF."]+/", $out, -1, PREG_SPLIT_NO_EMPTY);
883// $this->SendMSG(implode($this->_eol_code[$this->OS_local], $out));
884 }
885 return $out;
886 }
887
888// <!-- --------------------------------------------------------------------------------------- -->
889// <!-- Partie : gestion des erreurs -->
890// <!-- --------------------------------------------------------------------------------------- -->
891// Gnre une erreur pour traitement externe la classe
892 function PushError($fctname,$msg,$desc=false){
893 $error=array();
894 $error['time']=time();
895 $error['fctname']=$fctname;
896 $error['msg']=$msg;
897 $error['desc']=$desc;
898 if($desc) $tmp=' ('.$desc.')'; else $tmp='';
899 $this->SendMSG($fctname.': '.$msg.$tmp);
900 return(array_push($this->_error_array,$error));
901 }
902
903// Rcupre une erreur externe
904 function PopError(){
905 if(count($this->_error_array)) return(array_pop($this->_error_array));
906 else return(false);
907 }
908}
909
910$mod_sockets = extension_loaded( 'sockets' );
911if ( ! $mod_sockets && function_exists( 'dl' ) && is_callable( 'dl' ) ) {
912 $prefix = ( PHP_SHLIB_SUFFIX == 'dll' ) ? 'php_' : '';
913 @dl( $prefix . 'sockets.' . PHP_SHLIB_SUFFIX ); // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.dlDeprecated
914 $mod_sockets = extension_loaded( 'sockets' );
915}
916
917require_once __DIR__ . "/class-ftp-" . ( $mod_sockets ? "sockets" : "pure" ) . ".php";
918
919if ( $mod_sockets ) {
920 class ftp extends ftp_sockets {}
921} else {
922 class ftp extends ftp_pure {}
923}
924