Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
ftp.class.php
Go to the documentation of this file.
1 <?php
2 
3  define("FTP_TIMEOUT",90);
4 
5  // FTP Statuscodes
6  define("FTP_COMMAND_OK",200);
7  define("FTP_FILE_ACTION_OK",250);
8  define("FTP_FILE_TRANSFER_OK",226);
9  define("FTP_COMMAND_NOT_IMPLEMENTED",502);
10  define("FTP_FILE_STATUS",213);
11  define("FTP_NAME_SYSTEM_TYPE",215);
12  define("FTP_PASSIVE_MODE",227);
13  define("FTP_PATHNAME",257);
14  define("FTP_SERVICE_READY",220);
15  define("FTP_USER_LOGGED_IN",230);
16  define("FTP_PASSWORD_NEEDED",331);
17  define("FTP_USER_NOT_LOGGED_IN",530);
18 
19  if (!defined("FTP_ASCII")) define("FTP_ASCII",0);
20  if (!defined("FTP_BINARY")) define("FTP_BINARY",1);
21 
22  class FTP {
23 
24  var $passiveMode = TRUE;
25  var $lastLines = array();
26  var $lastLine = "";
27  var $controlSocket = NULL;
28  var $newResult = FALSE;
29  var $lastResult = -1;
30  var $pasvAddr = NULL;
31 
32  var $error_no = NULL;
33  var $error_msg = NULL;
34 
35  function FTP() {
36  }
37 
38  function connect($host, $port=21, $timeout=FTP_TIMEOUT) { //Opens an FTP connection
39  $this->_resetError();
40 
41  $err_no = 0;
42  $err_msg = "";
43  $this->controlSocket = @fsockopen($host, $port, $err_no, $err_msg, $timeout) or $this->_setError(-1,"fsockopen failed");
44  if ($err_no<>0) $this->setError($err_no,$err_msg);
45 
46  if ($this->_isError()) return false;
47 
48  @socket_set_timeout($this->controlSocket,$timeout) or $this->_setError(-1,"socket_set_timeout failed");
49  if ($this->_isError()) return false;
50 
51  $this->_waitForResult();
52  if ($this->_isError()) return false;
53 
54  return $this->getLastResult() == FTP_SERVICE_READY;
55  }
56 
57  function isConnected() {
58  return $this->controlSocket != NULL;
59  }
60 
61  function disconnect() {
62  if (!$this->isConnected()) return;
63  @fclose($this->controlSocket);
64  }
65 
66  function close() { //Closes an FTP connection
67  $this->disconnect();
68  }
69 
70  function login($user, $pass) { //Logs in to an FTP connection
71  $this->_resetError();
72 
73  $this->_printCommand("USER $user");
74  if ($this->_isError()) return false;
75 
76  $this->_waitForResult();
77  if ($this->_isError()) return false;
78 
79  if ($this->getLastResult() == FTP_PASSWORD_NEEDED){
80  $this->_printCommand("PASS $pass");
81  if ($this->_isError()) return FALSE;
82 
83  $this->_waitForResult();
84  if ($this->_isError()) return FALSE;
85  }
86 
88  return $result;
89  }
90 
91  function cdup() { //Changes to the parent directory
92  $this->_resetError();
93 
94  $this->_printCommand("CDUP");
95  $this->_waitForResult();
96  $lr = $this->getLastResult();
97  if ($this->_isError()) return FALSE;
98  return ($lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
99  }
100 
101  function cwd($path) {
102  $this->_resetError();
103 
104  $this->_printCommand("CWD $path");
105  $this->_waitForResult();
106  $lr = $this->getLastResult();
107  if ($this->_isError()) return FALSE;
108  return ($lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
109  }
110 
111  function cd($path) {
112  return $this->cwd($path);
113  }
114 
115  function chdir($path) { //Changes directories on a FTP server
116  return $this->cwd($path);
117  }
118 
119  function chmod($mode,$filename) { //Set permissions on a file via FTP
120  return $this->site("CHMOD $mode $filename");
121  }
122 
123  function delete($filename) { //Deletes a file on the FTP server
124  $this->_resetError();
125 
126  $this->_printCommand("DELE $filename");
127  $this->_waitForResult();
128  $lr = $this->getLastResult();
129  if ($this->_isError()) return FALSE;
130  return ($lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
131  }
132 
133  function exec($cmd) { //Requests execution of a program on the FTP server
134  return $this->site("EXEC $cmd");
135  }
136 
137  function fget($fp,$remote,$mode=FTP_BINARY,$resumepos=0) { //Downloads a file from the FTP server and saves to an open file
138  $this->_resetError();
139 
140  $type = "I";
141  if ($mode==FTP_ASCII) $type = "A";
142 
143  $this->_printCommand("TYPE $type");
144  $this->_waitForResult();
145  $lr = $this->getLastResult();
146  if ($this->_isError()) return FALSE;
147 
148  $result = $this->_download("RETR $remote");
149  if ($result) {
150  fwrite($fp,$result);
151  }
152  return $result;
153  }
154 
155  function fput($remote,$resource,$mode=FTP_BINARY,$startpos=0) { //Uploads from an open file to the FTP server
156  $this->_resetError();
157 
158  $type = "I";
159  if ($mode==FTP_ASCII) $type = "A";
160 
161  $this->_printCommand("TYPE $type");
162  $this->_waitForResult();
163  $lr = $this->getLastResult();
164  if ($this->_isError()) return FALSE;
165 
166  if ($startpos>0) fseek($resource,$startpos);
167  $result = $this->_uploadResource("STOR $remote",$resource);
168  return $result;
169  }
170 
171  function get_option($option) { //Retrieves various runtime behaviours of the current FTP stream
172  $this->_resetError();
173 
174  switch ($option) {
175  case "FTP_TIMEOUT_SEC" : return FTP_TIMEOUT;
176  case "PHP_FTP_OPT_AUTOSEEK" : return FALSE;
177  }
178  setError(-1,"Unknown option: $option");
179  return false;
180  }
181 
182  function get($locale,$remote,$mode=FTP_BINARY,$resumepos=0) { //Downloads a file from the FTP server
183  if (!($fp = @fopen($locale,"wb"))) return FALSE;
184  $result = $this->fget($fp,$remote,$mode,$resumepos);
185  @fclose($fp);
186  if (!$result) @unlink($locale);
187  return $result;
188  }
189  function mdtm($name) { //Returns the last modified time of the given file
190  $this->_resetError();
191 
192  $this->_printCommand("MDTM $name");
193  $this->_waitForResult();
194  $lr = $this->getLastResult();
195  if ($this->_isError()) return FALSE;
196  if ($lr!=FTP_FILE_STATUS) return FALSE;
197  $subject = trim(substr($this->lastLine,4));
198  $lucifer = array();
199  if (preg_match("/([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/",$subject,$lucifer)) return mktime($lucifer[4],$lucifer[5],$lucifer[6],$lucifer[2],$lucifer[3],$lucifer[1],0);
200  return FALSE;
201  }
202 
203  function mkdir($name) { //Creates a directory
204  $this->_resetError();
205 
206  $this->_printCommand("MKD $name");
207  $this->_waitForResult();
208  $lr = $this->getLastResult();
209  if ($this->_isError()) return FALSE;
210  return ($lr==FTP_PATHNAME || $lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
211  }
212 
213  function nb_continue() { //Continues retrieving/sending a file (non-blocking)
214  $this->_resetError();
215  // todo
216  }
217 
218  function nb_fget() { //Retrieves a file from the FTP server and writes it to an open file (non-blocking)
219  $this->_resetError();
220  // todo
221  }
222 
223  function nb_fput() { //Stores a file from an open file to the FTP server (non-blocking)
224  $this->_resetError();
225  // todo
226  }
227 
228  function nb_get() { //Retrieves a file from the FTP server and writes it to a local file (non-blocking)
229  $this->_resetError();
230  // todo
231  }
232 
233  function nb_put() { //Stores a file on the FTP server (non-blocking)
234  $this->_resetError();
235  // todo
236  }
237 
238  function nlist($remote_filespec="") { //Returns a list of files in the given directory
239  $this->_resetError();
240  $result = $this->_download(trim("NLST $remote_filespec"));
241  return ($result !== FALSE) ? explode("\n",str_replace("\r","",trim($result))) : $result;
242  }
243 
244  function pasv($pasv) { //Turns passive mode on or off
245  if (!$pasv) {
246  $this->_setError("Active (PORT) mode is not supported");
247  return false;
248  }
249  return true;
250  }
251 
252  function put($remote,$local,$mode=FTP_BINARY,$startpos=0) { //Uploads a file to the FTP server
253  if (!($fp = @fopen($local,"rb"))) return FALSE;
254  $result = $this->fput($remote,$fp,$mode,$startpos);
255  @fclose($fp);
256  return $result;
257  }
258 
259  function pwd() { //Returns the current directory name
260  $this->_resetError();
261 
262  $this->_printCommand("PWD");
263  $this->_waitForResult();
264  $lr = $this->getLastResult();
265  if ($this->_isError()) return FALSE;
266  if ($lr!=FTP_PATHNAME) return FALSE;
267  $subject = trim(substr($this->lastLine,4));
268  $lucifer = array();
269  if (preg_match("/\"(.*)\"/",$subject,$lucifer)) return $lucifer[1];
270  return FALSE;
271  }
272 
273  function quit() { //Alias of close
274  $this->close();
275  }
276 
277  function raw($cmd) { //Sends an arbitrary command to an FTP server
278  $this->_resetError();
279 
280  $this->_printCommand($cmd);
281  $this->_waitForResult();
282  $this->getLastResult();
283  return array($this->lastLine);
284  }
285 
286  function rawlist($remote_filespec="") { //Returns a detailed list of files in the given directory
287  $this->_resetError();
288  $result = $this->_download(trim("LIST $remote_filespec"));
289  return ($result !== FALSE) ? explode("\n",str_replace("\r","",trim($result))) : $result;
290  }
291 
292  function ls($remote_filespec="") { //Returns a parsed rawlist in an assoc array
293  $a = $this->rawlist($remote_filespec);
294  if (!$a) return $a;
295  $systype = $this->systype();
296  $is_windows = stristr($systype,"WIN")!==FALSE;
297  $b = array();
298  while (list($i,$line) = each($a)) {
299  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)) {
300  $b[$i] = array();
301  if ($lucifer[3]<70) { $lucifer[3]+=2000; } else { $lucifer[3]+=1900; } // 4digit year fix
302  $b[$i]['isdir'] = ($lucifer[7]=="<DIR>");
303  $b[$i]['size'] = $lucifer[7];
304  $b[$i]['month'] = $lucifer[1];
305  $b[$i]['day'] = $lucifer[2];
306  $b[$i]['year'] = $lucifer[3];
307  $b[$i]['hour'] = $lucifer[4];
308  $b[$i]['minute'] = $lucifer[5];
309  $b[$i]['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]);
310  $b[$i]['am/pm'] = $lucifer[6];
311  $b[$i]['name'] = $lucifer[8];
312  } else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) {
313  echo $line."\n";
314  $lcount=count($lucifer);
315  if ($lcount<8) continue;
316  $b[$i] = array();
317  $b[$i]['isdir'] = $lucifer[0]{0} === "d";
318  $b[$i]['islink'] = $lucifer[0]{0} === "l";
319  $b[$i]['perms'] = $lucifer[0];
320  $b[$i]['number'] = $lucifer[1];
321  $b[$i]['owner'] = $lucifer[2];
322  $b[$i]['group'] = $lucifer[3];
323  $b[$i]['size'] = $lucifer[4];
324  if ($lcount==8) {
325  sscanf($lucifer[5],"%d-%d-%d",$b[$i]['year'],$b[$i]['month'],$b[$i]['day']);
326  sscanf($lucifer[6],"%d:%d",$b[$i]['hour'],$b[$i]['minute']);
327  $b[$i]['time'] = @mktime($b[$i]['hour'],$b[$i]['minute'],0,$b[$i]['month'],$b[$i]['day'],$b[$i]['year']);
328  $b[$i]['name'] = $lucifer[7];
329  } else {
330  $b[$i]['month'] = $lucifer[5];
331  $b[$i]['day'] = $lucifer[6];
332  if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) {
333  $b[$i]['year'] = date("Y");
334  $b[$i]['hour'] = $l2[1];
335  $b[$i]['minute'] = $l2[2];
336  } else {
337  $b[$i]['year'] = $lucifer[7];
338  $b[$i]['hour'] = 0;
339  $b[$i]['minute'] = 0;
340  }
341  $b[$i]['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b[$i]['day'],$b[$i]['month'],$b[$i]['year'],$b[$i]['hour'],$b[$i]['minute']));
342  $b[$i]['name'] = $lucifer[8];
343  }
344  }
345  }
346  return $b;
347  }
348 
349  function rename($from,$to) { //Renames a file on the FTP server
350  $this->_resetError();
351 
352  $this->_printCommand("RNFR $from");
353  $this->_waitForResult();
354  $lr = $this->getLastResult();
355  if ($this->_isError()) return FALSE;
356  $this->_printCommand("RNTO $to");
357  $this->_waitForResult();
358  $lr = $this->getLastResult();
359  if ($this->_isError()) return FALSE;
360  return ($lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
361  }
362 
363  function rmdir($name) { //Removes a directory
364  $this->_resetError();
365 
366  $this->_printCommand("RMD $name");
367  $this->_waitForResult();
368  $lr = $this->getLastResult();
369  if ($this->_isError()) return FALSE;
370  return ($lr==FTP_FILE_ACTION_OK || $lr==FTP_COMMAND_OK);
371  }
372 
373  function set_option() { //Set miscellaneous runtime FTP options
374  $this->_resetError();
375  $this->_setError(-1,"set_option not supported");
376  return false;
377  }
378 
379  function site($cmd) { //Sends a SITE command to the server
380  $this->_resetError();
381 
382  $this->_printCommand("SITE $cmd");
383  $this->_waitForResult();
384  $lr = $this->getLastResult();
385  if ($this->_isError()) return FALSE;
386  return true;
387  }
388 
389  function size($name) { //Returns the size of the given file
390  $this->_resetError();
391 
392  $this->_printCommand("SIZE $name");
393  $this->_waitForResult();
394  $lr = $this->getLastResult();
395  if ($this->_isError()) return FALSE;
396  return $lr==FTP_FILE_STATUS ? trim(substr($this->lastLine,4)) : FALSE;
397  }
398 
399  function ssl_connect() { //Opens an Secure SSL-FTP connection
400  $this->_resetError();
401  $this->_setError(-1,"ssl_connect not supported");
402  return false;
403  }
404 
405  function systype() { // Returns the system type identifier of the remote FTP server
406  $this->_resetError();
407 
408  $this->_printCommand("SYST");
409  $this->_waitForResult();
410  $lr = $this->getLastResult();
411  if ($this->_isError()) return FALSE;
412  return $lr==FTP_NAME_SYSTEM_TYPE ? trim(substr($this->lastLine,4)) : FALSE;
413  }
414 
415  function getLastResult() {
416  $this->newResult = FALSE;
417  return $this->lastResult;
418  }
419 
420  /* private */
421  function _hasNewResult() {
422  return $this->newResult;
423  }
424 
425  /* private */
426  function _waitForResult() {
427  while(!$this->_hasNewResult() && $this->_readln()!==FALSE && !$this->_isError()) { /* noop */ }
428  }
429 
430  /* private */
431  function _readln() {
432  $line = fgets($this->controlSocket);
433  if ($line === FALSE) {
434  $this->_setError(-1,"fgets failed in _readln");
435  return FALSE;
436  }
437  if (strlen($line)==0) return $line;
438 
439  $lucifer = array();
440  if (preg_match("/^[0-9][0-9][0-9] /",$line,$lucifer)) {
441  //its a resultline
442  $this->lastResult = intval($lucifer[0]);
443  $this->newResult = TRUE;
444  if (substr($lucifer[0],0,1)=='5') {
445  $this->_setError($this->lastResult,trim(substr($line,4)));
446  }
447  }
448 
449  $this->lastLine = trim($line);
450  $this->lastLines[] = "< ".trim($line);
451  return $line;
452  }
453 
454  /* private */
455  function _printCommand($line) {
456  $this->lastLines[] = "> ".$line;
457  fwrite($this->controlSocket,$line."\r\n");
458  fflush($this->controlSocket);
459  }
460 
461  /* private */
462  function _pasv() {
463  $this->_resetError();
464  $this->_printCommand("PASV");
465  $this->_waitForResult();
466  $lr = $this->getLastResult();
467  if ($this->_isError()) return FALSE;
468  if ($lr!=FTP_PASSIVE_MODE) return FALSE;
469  $subject = trim(substr($this->lastLine,4));
470  $lucifer = array();
471  if (preg_match("/\\((\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3})\\)/",$subject,$lucifer)) {
472  $this->pasvAddr=$lucifer;
473 
474  $host = sprintf("%d.%d.%d.%d",$lucifer[1],$lucifer[2],$lucifer[3],$lucifer[4]);
475  $port = $lucifer[5]*256 + $lucifer[6];
476 
477  $err_no=0;
478  $err_msg="";
479  $passiveConnection = fsockopen($host,$port,$err_no,$err_msg, FTP_TIMEOUT);
480  if ($err_no!=0) {
481  $this->_setError($err_no,$err_msg);
482  return FALSE;
483  }
484 
485  return $passiveConnection;
486  }
487  return FALSE;
488  }
489 
490  /* private */
491  function _download($cmd) {
492  if (!($passiveConnection = $this->_pasv())) return FALSE;
493  $this->_printCommand($cmd);
494  $this->_waitForResult();
495  $lr = $this->getLastResult();
496  if (!$this->_isError()) {
497  $result = "";
498  while (!feof($passiveConnection)) {
499  $result .= fgets($passiveConnection);
500  }
501  fclose($passiveConnection);
502  $this->_waitForResult();
503  $lr = $this->getLastResult();
504  return ($lr==FTP_FILE_TRANSFER_OK) || ($lr==FTP_FILE_ACTION_OK) || ($lr==FTP_COMMAND_OK) ? $result : FALSE;
505  } else {
506  fclose($passiveConnection);
507  return FALSE;
508  }
509  }
510 
511  /* upload */
512  function _uploadResource($cmd,$resource) {
513  if (!($passiveConnection = $this->_pasv())) return FALSE;
514  $this->_printCommand($cmd);
515  $this->_waitForResult();
516  $lr = $this->getLastResult();
517  if (!$this->_isError()) {
518  $result = "";
519  while (!feof($resource)) {
520  $buf = fread($resource,1024);
521  fwrite($passiveConnection,$buf);
522  }
523  fclose($passiveConnection);
524  $this->_waitForResult();
525  $lr = $this->getLastResult();
526  return ($lr==FTP_FILE_TRANSFER_OK) || ($lr==FTP_FILE_ACTION_OK) || ($lr==FTP_COMMAND_OK) ? $result : FALSE;
527  } else {
528  fclose($passiveConnection);
529  return FALSE;
530  }
531  }
532 
533  /* private */
534  function _resetError() {
535  $this->error_no = NULL;
536  $this->error_msg = NULL;
537  }
538 
539  /* private */
540  function _setError($no,$msg) {
541  if (is_array($this->error_no)) {
542  $this->error_no[] = $no;
543  $this->error_msg[] = $msg;
544  } else if ($this->error_no!=NULL) {
545  $this->error_no = array($this->error_no,$no);
546  $this->error_msg = array($this->error_msg,$msg);
547  } else {
548  $this->error_no = $no;
549  $this->error_msg = $msg;
550  }
551  }
552 
553  /* private */
554  function _isError() {
555  return ($this->error_no != NULL) && ($this->error_no !== 0);
556  }
557 
558  }
559 ?>