ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
SFTP.php
Go to the documentation of this file.
1 <?php
2 
38 namespace phpseclib\Net;
39 
41 
49 class SFTP extends SSH2
50 {
60  const CHANNEL = 0x100;
61 
69  const SOURCE_LOCAL_FILE = 1;
73  // this value isn't really used anymore but i'm keeping it reserved for historical reasons
74  const SOURCE_STRING = 2;
79  const SOURCE_CALLBACK = 16;
83  const RESUME = 4;
87  const RESUME_START = 8;
97  var $packet_types = array();
98 
106  var $status_codes = array();
107 
118  var $request_id = false;
119 
130  var $packet_type = -1;
131 
139  var $packet_buffer = '';
140 
148  var $extensions = array();
149 
157  var $version;
158 
167  var $pwd = false;
168 
176  var $packet_type_log = array();
177 
185  var $packet_log = array();
186 
195  var $sftp_errors = array();
196 
209  var $stat_cache = array();
210 
220 
229  var $use_stat_cache = true;
230 
239  var $sortOptions = array();
240 
252  function __construct($host, $port = 22, $timeout = 10)
253  {
254  parent::__construct($host, $port, $timeout);
255 
256  $this->max_sftp_packet = 1 << 15;
257 
258  $this->packet_types = array(
259  1 => 'NET_SFTP_INIT',
260  2 => 'NET_SFTP_VERSION',
261  /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
262  SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
263  pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
264  3 => 'NET_SFTP_OPEN',
265  4 => 'NET_SFTP_CLOSE',
266  5 => 'NET_SFTP_READ',
267  6 => 'NET_SFTP_WRITE',
268  7 => 'NET_SFTP_LSTAT',
269  9 => 'NET_SFTP_SETSTAT',
270  11 => 'NET_SFTP_OPENDIR',
271  12 => 'NET_SFTP_READDIR',
272  13 => 'NET_SFTP_REMOVE',
273  14 => 'NET_SFTP_MKDIR',
274  15 => 'NET_SFTP_RMDIR',
275  16 => 'NET_SFTP_REALPATH',
276  17 => 'NET_SFTP_STAT',
277  /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
278  SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
279  pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
280  18 => 'NET_SFTP_RENAME',
281  19 => 'NET_SFTP_READLINK',
282  20 => 'NET_SFTP_SYMLINK',
283 
284  101=> 'NET_SFTP_STATUS',
285  102=> 'NET_SFTP_HANDLE',
286  /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
287  SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
288  pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
289  103=> 'NET_SFTP_DATA',
290  104=> 'NET_SFTP_NAME',
291  105=> 'NET_SFTP_ATTRS',
292 
293  200=> 'NET_SFTP_EXTENDED'
294  );
295  $this->status_codes = array(
296  0 => 'NET_SFTP_STATUS_OK',
297  1 => 'NET_SFTP_STATUS_EOF',
298  2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
299  3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
300  4 => 'NET_SFTP_STATUS_FAILURE',
301  5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
302  6 => 'NET_SFTP_STATUS_NO_CONNECTION',
303  7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
304  8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
305  9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
306  10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
307  11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
308  12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
309  13 => 'NET_SFTP_STATUS_NO_MEDIA',
310  14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
311  15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
312  16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
313  17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
314  18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
315  19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
316  20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
317  21 => 'NET_SFTP_STATUS_LINK_LOOP',
318  22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
319  23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
320  24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
321  25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
322  26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
323  27 => 'NET_SFTP_STATUS_DELETE_PENDING',
324  28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
325  29 => 'NET_SFTP_STATUS_OWNER_INVALID',
326  30 => 'NET_SFTP_STATUS_GROUP_INVALID',
327  31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
328  );
329  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
330  // the order, in this case, matters quite a lot - see \phpseclib\Net\SFTP::_parseAttributes() to understand why
331  $this->attributes = array(
332  0x00000001 => 'NET_SFTP_ATTR_SIZE',
333  0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
334  0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
335  0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
336  // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
337  // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
338  // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
339  // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
340  -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
341  );
342  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
343  // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
344  // the array for that $this->open5_flags and similarily alter the constant names.
345  $this->open_flags = array(
346  0x00000001 => 'NET_SFTP_OPEN_READ',
347  0x00000002 => 'NET_SFTP_OPEN_WRITE',
348  0x00000004 => 'NET_SFTP_OPEN_APPEND',
349  0x00000008 => 'NET_SFTP_OPEN_CREATE',
350  0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
351  0x00000020 => 'NET_SFTP_OPEN_EXCL'
352  );
353  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
354  // see \phpseclib\Net\SFTP::_parseLongname() for an explanation
355  $this->file_types = array(
356  1 => 'NET_SFTP_TYPE_REGULAR',
357  2 => 'NET_SFTP_TYPE_DIRECTORY',
358  3 => 'NET_SFTP_TYPE_SYMLINK',
359  4 => 'NET_SFTP_TYPE_SPECIAL',
360  5 => 'NET_SFTP_TYPE_UNKNOWN',
361  // the followin types were first defined for use in SFTPv5+
362  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
363  6 => 'NET_SFTP_TYPE_SOCKET',
364  7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
365  8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
366  9 => 'NET_SFTP_TYPE_FIFO'
367  );
368  $this->_define_array(
369  $this->packet_types,
370  $this->status_codes,
371  $this->attributes,
372  $this->open_flags,
373  $this->file_types
374  );
375 
376  if (!defined('NET_SFTP_QUEUE_SIZE')) {
377  define('NET_SFTP_QUEUE_SIZE', 50);
378  }
379  }
380 
389  function login($username)
390  {
391  $args = func_get_args();
392  if (!call_user_func_array(array(&$this, '_login'), $args)) {
393  return false;
394  }
395 
396  $this->window_size_server_to_client[self::CHANNEL] = $this->window_size;
397 
398  $packet = pack(
399  'CNa*N3',
400  NET_SSH2_MSG_CHANNEL_OPEN,
401  strlen('session'),
402  'session',
403  self::CHANNEL,
404  $this->window_size,
405  0x4000
406  );
407 
408  if (!$this->_send_binary_packet($packet)) {
409  return false;
410  }
411 
412  $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
413 
414  $response = $this->_get_channel_packet(self::CHANNEL);
415  if ($response === false) {
416  return false;
417  }
418 
419  $packet = pack(
420  'CNNa*CNa*',
421  NET_SSH2_MSG_CHANNEL_REQUEST,
422  $this->server_channels[self::CHANNEL],
423  strlen('subsystem'),
424  'subsystem',
425  1,
426  strlen('sftp'),
427  'sftp'
428  );
429  if (!$this->_send_binary_packet($packet)) {
430  return false;
431  }
432 
433  $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
434 
435  $response = $this->_get_channel_packet(self::CHANNEL);
436  if ($response === false) {
437  // from PuTTY's psftp.exe
438  $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
439  "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
440  "exec sftp-server";
441  // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
442  // is redundant
443  $packet = pack(
444  'CNNa*CNa*',
445  NET_SSH2_MSG_CHANNEL_REQUEST,
446  $this->server_channels[self::CHANNEL],
447  strlen('exec'),
448  'exec',
449  1,
450  strlen($command),
451  $command
452  );
453  if (!$this->_send_binary_packet($packet)) {
454  return false;
455  }
456 
457  $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
458 
459  $response = $this->_get_channel_packet(self::CHANNEL);
460  if ($response === false) {
461  return false;
462  }
463  }
464 
465  $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
466 
467  if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
468  return false;
469  }
470 
471  $response = $this->_get_sftp_packet();
472  if ($this->packet_type != NET_SFTP_VERSION) {
473  user_error('Expected SSH_FXP_VERSION');
474  return false;
475  }
476 
477  extract(unpack('Nversion', $this->_string_shift($response, 4)));
478  $this->version = $version;
479  while (!empty($response)) {
480  extract(unpack('Nlength', $this->_string_shift($response, 4)));
481  $key = $this->_string_shift($response, $length);
482  extract(unpack('Nlength', $this->_string_shift($response, 4)));
483  $value = $this->_string_shift($response, $length);
484  $this->extensions[$key] = $value;
485  }
486 
487  /*
488  SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
489  however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
490  not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
491  one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
492  'newline@vandyke.com' would.
493  */
494  /*
495  if (isset($this->extensions['newline@vandyke.com'])) {
496  $this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
497  unset($this->extensions['newline@vandyke.com']);
498  }
499  */
500 
501  $this->request_id = 1;
502 
503  /*
504  A Note on SFTPv4/5/6 support:
505  <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
506 
507  "If the client wishes to interoperate with servers that support noncontiguous version
508  numbers it SHOULD send '3'"
509 
510  Given that the server only sends its version number after the client has already done so, the above
511  seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
512  most popular.
513 
514  <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
515 
516  "If the server did not send the "versions" extension, or the version-from-list was not included, the
517  server MAY send a status response describing the failure, but MUST then close the channel without
518  processing any further requests."
519 
520  So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
521  a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
522  v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
523  in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what \phpseclib\Net\SFTP would do is close the
524  channel and reopen it with a new and updated SSH_FXP_INIT packet.
525  */
526  switch ($this->version) {
527  case 2:
528  case 3:
529  break;
530  default:
531  return false;
532  }
533 
534  $this->pwd = $this->_realpath('.');
535 
536  $this->_update_stat_cache($this->pwd, array());
537 
538  return true;
539  }
540 
546  function disableStatCache()
547  {
548  $this->use_stat_cache = false;
549  }
550 
556  function enableStatCache()
557  {
558  $this->use_stat_cache = true;
559  }
560 
566  function clearStatCache()
567  {
568  $this->stat_cache = array();
569  }
570 
577  function pwd()
578  {
579  return $this->pwd;
580  }
581 
589  function _logError($response, $status = -1)
590  {
591  if ($status == -1) {
592  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
593  }
594 
595  $error = $this->status_codes[$status];
596 
597  if ($this->version > 2) {
598  extract(unpack('Nlength', $this->_string_shift($response, 4)));
599  $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
600  } else {
601  $this->sftp_errors[] = $error;
602  }
603  }
604 
616  function _realpath($path)
617  {
618  if ($this->pwd === false) {
619  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
620  if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
621  return false;
622  }
623 
624  $response = $this->_get_sftp_packet();
625  switch ($this->packet_type) {
626  case NET_SFTP_NAME:
627  // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
628  // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
629  // at is the first part and that part is defined the same in SFTP versions 3 through 6.
630  $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
631  extract(unpack('Nlength', $this->_string_shift($response, 4)));
632  return $this->_string_shift($response, $length);
633  case NET_SFTP_STATUS:
634  $this->_logError($response);
635  return false;
636  default:
637  user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
638  return false;
639  }
640  }
641 
642  if ($path[0] != '/') {
643  $path = $this->pwd . '/' . $path;
644  }
645 
646  $path = explode('/', $path);
647  $new = array();
648  foreach ($path as $dir) {
649  if (!strlen($dir)) {
650  continue;
651  }
652  switch ($dir) {
653  case '..':
654  array_pop($new);
655  case '.':
656  break;
657  default:
658  $new[] = $dir;
659  }
660  }
661 
662  return '/' . implode('/', $new);
663  }
664 
672  function chdir($dir)
673  {
674  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
675  return false;
676  }
677 
678  // assume current dir if $dir is empty
679  if ($dir === '') {
680  $dir = './';
681  // suffix a slash if needed
682  } elseif ($dir[strlen($dir) - 1] != '/') {
683  $dir.= '/';
684  }
685 
686  $dir = $this->_realpath($dir);
687 
688  // confirm that $dir is, in fact, a valid directory
689  if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
690  $this->pwd = $dir;
691  return true;
692  }
693 
694  // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
695  // the currently logged in user has the appropriate permissions or not. maybe you could see if
696  // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
697  // way to get those with SFTP
698 
699  if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
700  return false;
701  }
702 
703  // see \phpseclib\Net\SFTP::nlist() for a more thorough explanation of the following
704  $response = $this->_get_sftp_packet();
705  switch ($this->packet_type) {
706  case NET_SFTP_HANDLE:
707  $handle = substr($response, 4);
708  break;
709  case NET_SFTP_STATUS:
710  $this->_logError($response);
711  return false;
712  default:
713  user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
714  return false;
715  }
716 
717  if (!$this->_close_handle($handle)) {
718  return false;
719  }
720 
721  $this->_update_stat_cache($dir, array());
722 
723  $this->pwd = $dir;
724  return true;
725  }
726 
735  function nlist($dir = '.', $recursive = false)
736  {
737  return $this->_nlist_helper($dir, $recursive, '');
738  }
739 
749  function _nlist_helper($dir, $recursive, $relativeDir)
750  {
751  $files = $this->_list($dir, false);
752 
753  if (!$recursive) {
754  return $files;
755  }
756 
757  $result = array();
758  foreach ($files as $value) {
759  if ($value == '.' || $value == '..') {
760  if ($relativeDir == '') {
761  $result[] = $value;
762  }
763  continue;
764  }
765  if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
766  $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
767  $result = array_merge($result, $temp);
768  } else {
769  $result[] = $relativeDir . $value;
770  }
771  }
772 
773  return $result;
774  }
775 
784  function rawlist($dir = '.', $recursive = false)
785  {
786  $files = $this->_list($dir, true);
787  if (!$recursive || $files === false) {
788  return $files;
789  }
790 
791  static $depth = 0;
792 
793  foreach ($files as $key => $value) {
794  if ($depth != 0 && $key == '..') {
795  unset($files[$key]);
796  continue;
797  }
798  if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
799  $depth++;
800  $files[$key] = $this->rawlist($dir . '/' . $key, true);
801  $depth--;
802  } else {
803  $files[$key] = (object) $value;
804  }
805  }
806 
807  return $files;
808  }
809 
818  function _list($dir, $raw = true)
819  {
820  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
821  return false;
822  }
823 
824  $dir = $this->_realpath($dir . '/');
825  if ($dir === false) {
826  return false;
827  }
828 
829  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
830  if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
831  return false;
832  }
833 
834  $response = $this->_get_sftp_packet();
835  switch ($this->packet_type) {
836  case NET_SFTP_HANDLE:
837  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
838  // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
839  // represent the length of the string and leave it at that
840  $handle = substr($response, 4);
841  break;
842  case NET_SFTP_STATUS:
843  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
844  $this->_logError($response);
845  return false;
846  default:
847  user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
848  return false;
849  }
850 
851  $this->_update_stat_cache($dir, array());
852 
853  $contents = array();
854  while (true) {
855  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
856  // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
857  // SSH_MSG_CHANNEL_DATA messages is not known to me.
858  if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
859  return false;
860  }
861 
862  $response = $this->_get_sftp_packet();
863  switch ($this->packet_type) {
864  case NET_SFTP_NAME:
865  extract(unpack('Ncount', $this->_string_shift($response, 4)));
866  for ($i = 0; $i < $count; $i++) {
867  extract(unpack('Nlength', $this->_string_shift($response, 4)));
868  $shortname = $this->_string_shift($response, $length);
869  extract(unpack('Nlength', $this->_string_shift($response, 4)));
870  $longname = $this->_string_shift($response, $length);
872  if (!isset($attributes['type'])) {
873  $fileType = $this->_parseLongname($longname);
874  if ($fileType) {
875  $attributes['type'] = $fileType;
876  }
877  }
878  $contents[$shortname] = $attributes + array('filename' => $shortname);
879 
880  if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
881  $this->_update_stat_cache($dir . '/' . $shortname, array());
882  } else {
883  if ($shortname == '..') {
884  $temp = $this->_realpath($dir . '/..') . '/.';
885  } else {
886  $temp = $dir . '/' . $shortname;
887  }
888  $this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
889  }
890  // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
891  // final SSH_FXP_STATUS packet should tell us that, already.
892  }
893  break;
894  case NET_SFTP_STATUS:
895  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
896  if ($status != NET_SFTP_STATUS_EOF) {
897  $this->_logError($response, $status);
898  return false;
899  }
900  break 2;
901  default:
902  user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
903  return false;
904  }
905  }
906 
907  if (!$this->_close_handle($handle)) {
908  return false;
909  }
910 
911  if (count($this->sortOptions)) {
912  uasort($contents, array(&$this, '_comparator'));
913  }
914 
915  return $raw ? $contents : array_keys($contents);
916  }
917 
928  function _comparator($a, $b)
929  {
930  switch (true) {
931  case $a['filename'] === '.' || $b['filename'] === '.':
932  if ($a['filename'] === $b['filename']) {
933  return 0;
934  }
935  return $a['filename'] === '.' ? -1 : 1;
936  case $a['filename'] === '..' || $b['filename'] === '..':
937  if ($a['filename'] === $b['filename']) {
938  return 0;
939  }
940  return $a['filename'] === '..' ? -1 : 1;
941  case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
942  if (!isset($b['type'])) {
943  return 1;
944  }
945  if ($b['type'] !== $a['type']) {
946  return -1;
947  }
948  break;
949  case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
950  return 1;
951  }
952  foreach ($this->sortOptions as $sort => $order) {
953  if (!isset($a[$sort]) || !isset($b[$sort])) {
954  if (isset($a[$sort])) {
955  return -1;
956  }
957  if (isset($b[$sort])) {
958  return 1;
959  }
960  return 0;
961  }
962  switch ($sort) {
963  case 'filename':
964  $result = strcasecmp($a['filename'], $b['filename']);
965  if ($result) {
966  return $order === SORT_DESC ? -$result : $result;
967  }
968  break;
969  case 'permissions':
970  case 'mode':
971  $a[$sort]&= 07777;
972  $b[$sort]&= 07777;
973  default:
974  if ($a[$sort] === $b[$sort]) {
975  break;
976  }
977  return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
978  }
979  }
980  }
981 
1002  function setListOrder()
1003  {
1004  $this->sortOptions = array();
1005  $args = func_get_args();
1006  if (empty($args)) {
1007  return;
1008  }
1009  $len = count($args) & 0x7FFFFFFE;
1010  for ($i = 0; $i < $len; $i+=2) {
1011  $this->sortOptions[$args[$i]] = $args[$i + 1];
1012  }
1013  if (!count($this->sortOptions)) {
1014  $this->sortOptions = array('bogus' => true);
1015  }
1016  }
1017 
1027  function size($filename)
1028  {
1029  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1030  return false;
1031  }
1032 
1033  $result = $this->stat($filename);
1034  if ($result === false) {
1035  return false;
1036  }
1037  return isset($result['size']) ? $result['size'] : -1;
1038  }
1039 
1047  function _update_stat_cache($path, $value)
1048  {
1049  if ($this->use_stat_cache === false) {
1050  return;
1051  }
1052 
1053  // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
1054  $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1055 
1056  $temp = &$this->stat_cache;
1057  $max = count($dirs) - 1;
1058  foreach ($dirs as $i => $dir) {
1059  // if $temp is an object that means one of two things.
1060  // 1. a file was deleted and changed to a directory behind phpseclib's back
1061  // 2. it's a symlink. when lstat is done it's unclear what it's a symlink to
1062  if (is_object($temp)) {
1063  $temp = array();
1064  }
1065  if (!isset($temp[$dir])) {
1066  $temp[$dir] = array();
1067  }
1068  if ($i === $max) {
1069  if (is_object($temp[$dir])) {
1070  if (!isset($value->stat) && isset($temp[$dir]->stat)) {
1071  $value->stat = $temp[$dir]->stat;
1072  }
1073  if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
1074  $value->lstat = $temp[$dir]->lstat;
1075  }
1076  }
1077  $temp[$dir] = $value;
1078  break;
1079  }
1080  $temp = &$temp[$dir];
1081  }
1082  }
1083 
1092  {
1093  $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1094 
1095  $temp = &$this->stat_cache;
1096  $max = count($dirs) - 1;
1097  foreach ($dirs as $i => $dir) {
1098  if ($i === $max) {
1099  unset($temp[$dir]);
1100  return true;
1101  }
1102  if (!isset($temp[$dir])) {
1103  return false;
1104  }
1105  $temp = &$temp[$dir];
1106  }
1107  }
1108 
1119  {
1120  $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1121 
1122  $temp = &$this->stat_cache;
1123  foreach ($dirs as $dir) {
1124  if (!isset($temp[$dir])) {
1125  return null;
1126  }
1127  $temp = &$temp[$dir];
1128  }
1129  return $temp;
1130  }
1131 
1141  function stat($filename)
1142  {
1143  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1144  return false;
1145  }
1146 
1147  $filename = $this->_realpath($filename);
1148  if ($filename === false) {
1149  return false;
1150  }
1151 
1152  if ($this->use_stat_cache) {
1154  if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
1155  return $result['.']->stat;
1156  }
1157  if (is_object($result) && isset($result->stat)) {
1158  return $result->stat;
1159  }
1160  }
1161 
1162  $stat = $this->_stat($filename, NET_SFTP_STAT);
1163  if ($stat === false) {
1165  return false;
1166  }
1167  if (isset($stat['type'])) {
1168  if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1169  $filename.= '/.';
1170  }
1171  $this->_update_stat_cache($filename, (object) array('stat' => $stat));
1172  return $stat;
1173  }
1174 
1175  $pwd = $this->pwd;
1176  $stat['type'] = $this->chdir($filename) ?
1177  NET_SFTP_TYPE_DIRECTORY :
1178  NET_SFTP_TYPE_REGULAR;
1179  $this->pwd = $pwd;
1180 
1181  if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1182  $filename.= '/.';
1183  }
1184  $this->_update_stat_cache($filename, (object) array('stat' => $stat));
1185 
1186  return $stat;
1187  }
1188 
1198  function lstat($filename)
1199  {
1200  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1201  return false;
1202  }
1203 
1204  $filename = $this->_realpath($filename);
1205  if ($filename === false) {
1206  return false;
1207  }
1208 
1209  if ($this->use_stat_cache) {
1211  if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
1212  return $result['.']->lstat;
1213  }
1214  if (is_object($result) && isset($result->lstat)) {
1215  return $result->lstat;
1216  }
1217  }
1218 
1219  $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
1220  if ($lstat === false) {
1222  return false;
1223  }
1224  if (isset($lstat['type'])) {
1225  if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1226  $filename.= '/.';
1227  }
1228  $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1229  return $lstat;
1230  }
1231 
1232  $stat = $this->_stat($filename, NET_SFTP_STAT);
1233 
1234  if ($lstat != $stat) {
1235  $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
1236  $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1237  return $stat;
1238  }
1239 
1240  $pwd = $this->pwd;
1241  $lstat['type'] = $this->chdir($filename) ?
1242  NET_SFTP_TYPE_DIRECTORY :
1243  NET_SFTP_TYPE_REGULAR;
1244  $this->pwd = $pwd;
1245 
1246  if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1247  $filename.= '/.';
1248  }
1249  $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1250 
1251  return $lstat;
1252  }
1253 
1265  function _stat($filename, $type)
1266  {
1267  // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1268  $packet = pack('Na*', strlen($filename), $filename);
1269  if (!$this->_send_sftp_packet($type, $packet)) {
1270  return false;
1271  }
1272 
1273  $response = $this->_get_sftp_packet();
1274  switch ($this->packet_type) {
1275  case NET_SFTP_ATTRS:
1276  return $this->_parseAttributes($response);
1277  case NET_SFTP_STATUS:
1278  $this->_logError($response);
1279  return false;
1280  }
1281 
1282  user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1283  return false;
1284  }
1285 
1294  function truncate($filename, $new_size)
1295  {
1296  $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32
1297 
1298  return $this->_setstat($filename, $attr, false);
1299  }
1300 
1312  function touch($filename, $time = null, $atime = null)
1313  {
1314  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1315  return false;
1316  }
1317 
1318  $filename = $this->_realpath($filename);
1319  if ($filename === false) {
1320  return false;
1321  }
1322 
1323  if (!isset($time)) {
1324  $time = time();
1325  }
1326  if (!isset($atime)) {
1327  $atime = $time;
1328  }
1329 
1330  $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
1331  $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
1332  $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
1333  if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1334  return false;
1335  }
1336 
1337  $response = $this->_get_sftp_packet();
1338  switch ($this->packet_type) {
1339  case NET_SFTP_HANDLE:
1340  return $this->_close_handle(substr($response, 4));
1341  case NET_SFTP_STATUS:
1342  $this->_logError($response);
1343  break;
1344  default:
1345  user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1346  return false;
1347  }
1348 
1349  return $this->_setstat($filename, $attr, false);
1350  }
1351 
1363  function chown($filename, $uid, $recursive = false)
1364  {
1365  // quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
1366  // "if the owner or group is specified as -1, then that ID is not changed"
1367  $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
1368 
1369  return $this->_setstat($filename, $attr, $recursive);
1370  }
1371 
1383  function chgrp($filename, $gid, $recursive = false)
1384  {
1385  $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
1386 
1387  return $this->_setstat($filename, $attr, $recursive);
1388  }
1389 
1402  function chmod($mode, $filename, $recursive = false)
1403  {
1404  if (is_string($mode) && is_int($filename)) {
1405  $temp = $mode;
1406  $mode = $filename;
1407  $filename = $temp;
1408  }
1409 
1410  $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1411  if (!$this->_setstat($filename, $attr, $recursive)) {
1412  return false;
1413  }
1414  if ($recursive) {
1415  return true;
1416  }
1417 
1418  $filename = $this->_realPath($filename);
1419  // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1420  // tell us if the file actually exists.
1421  // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1422  $packet = pack('Na*', strlen($filename), $filename);
1423  if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
1424  return false;
1425  }
1426 
1427  $response = $this->_get_sftp_packet();
1428  switch ($this->packet_type) {
1429  case NET_SFTP_ATTRS:
1430  $attrs = $this->_parseAttributes($response);
1431  return $attrs['permissions'];
1432  case NET_SFTP_STATUS:
1433  $this->_logError($response);
1434  return false;
1435  }
1436 
1437  user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1438  return false;
1439  }
1440 
1450  function _setstat($filename, $attr, $recursive)
1451  {
1452  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1453  return false;
1454  }
1455 
1456  $filename = $this->_realpath($filename);
1457  if ($filename === false) {
1458  return false;
1459  }
1460 
1462 
1463  if ($recursive) {
1464  $i = 0;
1465  $result = $this->_setstat_recursive($filename, $attr, $i);
1466  $this->_read_put_responses($i);
1467  return $result;
1468  }
1469 
1470  // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
1471  // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
1472  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
1473  return false;
1474  }
1475 
1476  /*
1477  "Because some systems must use separate system calls to set various attributes, it is possible that a failure
1478  response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
1479  servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
1480 
1481  -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
1482  */
1483  $response = $this->_get_sftp_packet();
1484  if ($this->packet_type != NET_SFTP_STATUS) {
1485  user_error('Expected SSH_FXP_STATUS');
1486  return false;
1487  }
1488 
1489  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1490  if ($status != NET_SFTP_STATUS_OK) {
1491  $this->_logError($response, $status);
1492  return false;
1493  }
1494 
1495  return true;
1496  }
1497 
1509  function _setstat_recursive($path, $attr, &$i)
1510  {
1511  if (!$this->_read_put_responses($i)) {
1512  return false;
1513  }
1514  $i = 0;
1515  $entries = $this->_list($path, true);
1516 
1517  if ($entries === false) {
1518  return $this->_setstat($path, $attr, false);
1519  }
1520 
1521  // normally $entries would have at least . and .. but it might not if the directories
1522  // permissions didn't allow reading
1523  if (empty($entries)) {
1524  return false;
1525  }
1526 
1527  unset($entries['.'], $entries['..']);
1528  foreach ($entries as $filename => $props) {
1529  if (!isset($props['type'])) {
1530  return false;
1531  }
1532 
1533  $temp = $path . '/' . $filename;
1534  if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1535  if (!$this->_setstat_recursive($temp, $attr, $i)) {
1536  return false;
1537  }
1538  } else {
1539  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
1540  return false;
1541  }
1542 
1543  $i++;
1544 
1545  if ($i >= NET_SFTP_QUEUE_SIZE) {
1546  if (!$this->_read_put_responses($i)) {
1547  return false;
1548  }
1549  $i = 0;
1550  }
1551  }
1552  }
1553 
1554  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
1555  return false;
1556  }
1557 
1558  $i++;
1559 
1560  if ($i >= NET_SFTP_QUEUE_SIZE) {
1561  if (!$this->_read_put_responses($i)) {
1562  return false;
1563  }
1564  $i = 0;
1565  }
1566 
1567  return true;
1568  }
1569 
1577  function readlink($link)
1578  {
1579  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1580  return false;
1581  }
1582 
1583  $link = $this->_realpath($link);
1584 
1585  if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
1586  return false;
1587  }
1588 
1589  $response = $this->_get_sftp_packet();
1590  switch ($this->packet_type) {
1591  case NET_SFTP_NAME:
1592  break;
1593  case NET_SFTP_STATUS:
1594  $this->_logError($response);
1595  return false;
1596  default:
1597  user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
1598  return false;
1599  }
1600 
1601  extract(unpack('Ncount', $this->_string_shift($response, 4)));
1602  // the file isn't a symlink
1603  if (!$count) {
1604  return false;
1605  }
1606 
1607  extract(unpack('Nlength', $this->_string_shift($response, 4)));
1608  return $this->_string_shift($response, $length);
1609  }
1610 
1621  function symlink($target, $link)
1622  {
1623  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1624  return false;
1625  }
1626 
1627  $target = $this->_realpath($target);
1628  $link = $this->_realpath($link);
1629 
1630  $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
1631  if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) {
1632  return false;
1633  }
1634 
1635  $response = $this->_get_sftp_packet();
1636  if ($this->packet_type != NET_SFTP_STATUS) {
1637  user_error('Expected SSH_FXP_STATUS');
1638  return false;
1639  }
1640 
1641  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1642  if ($status != NET_SFTP_STATUS_OK) {
1643  $this->_logError($response, $status);
1644  return false;
1645  }
1646 
1647  return true;
1648  }
1649 
1657  function mkdir($dir, $mode = -1, $recursive = false)
1658  {
1659  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1660  return false;
1661  }
1662 
1663  $dir = $this->_realpath($dir);
1664  // by not providing any permissions, hopefully the server will use the logged in users umask - their
1665  // default permissions.
1666  $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1667 
1668  if ($recursive) {
1669  $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
1670  if (empty($dirs[0])) {
1671  array_shift($dirs);
1672  $dirs[0] = '/' . $dirs[0];
1673  }
1674  for ($i = 0; $i < count($dirs); $i++) {
1675  $temp = array_slice($dirs, 0, $i + 1);
1676  $temp = implode('/', $temp);
1677  $result = $this->_mkdir_helper($temp, $attr);
1678  }
1679  return $result;
1680  }
1681 
1682  return $this->_mkdir_helper($dir, $attr);
1683  }
1684 
1692  function _mkdir_helper($dir, $attr)
1693  {
1694  if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
1695  return false;
1696  }
1697 
1698  $response = $this->_get_sftp_packet();
1699  if ($this->packet_type != NET_SFTP_STATUS) {
1700  user_error('Expected SSH_FXP_STATUS');
1701  return false;
1702  }
1703 
1704  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1705  if ($status != NET_SFTP_STATUS_OK) {
1706  $this->_logError($response, $status);
1707  return false;
1708  }
1709 
1710  return true;
1711  }
1712 
1720  function rmdir($dir)
1721  {
1722  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1723  return false;
1724  }
1725 
1726  $dir = $this->_realpath($dir);
1727  if ($dir === false) {
1728  return false;
1729  }
1730 
1731  if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
1732  return false;
1733  }
1734 
1735  $response = $this->_get_sftp_packet();
1736  if ($this->packet_type != NET_SFTP_STATUS) {
1737  user_error('Expected SSH_FXP_STATUS');
1738  return false;
1739  }
1740 
1741  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1742  if ($status != NET_SFTP_STATUS_OK) {
1743  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
1744  $this->_logError($response, $status);
1745  return false;
1746  }
1747 
1748  $this->_remove_from_stat_cache($dir);
1749  // the following will do a soft delete, which would be useful if you deleted a file
1750  // and then tried to do a stat on the deleted file. the above, in contrast, does
1751  // a hard delete
1752  //$this->_update_stat_cache($dir, false);
1753 
1754  return true;
1755  }
1756 
1802  function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null)
1803  {
1804  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1805  return false;
1806  }
1807 
1808  $remote_file = $this->_realpath($remote_file);
1809  if ($remote_file === false) {
1810  return false;
1811  }
1812 
1813  $this->_remove_from_stat_cache($remote_file);
1814 
1815  $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
1816  // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
1817  // in practice, it doesn't seem to do that.
1818  //$flags|= ($mode & self::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
1819 
1820  if ($start >= 0) {
1821  $offset = $start;
1822  } elseif ($mode & self::RESUME) {
1823  // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called
1824  $size = $this->size($remote_file);
1825  $offset = $size !== false ? $size : 0;
1826  } else {
1827  $offset = 0;
1828  $flags|= NET_SFTP_OPEN_TRUNCATE;
1829  }
1830 
1831  $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
1832  if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1833  return false;
1834  }
1835 
1836  $response = $this->_get_sftp_packet();
1837  switch ($this->packet_type) {
1838  case NET_SFTP_HANDLE:
1839  $handle = substr($response, 4);
1840  break;
1841  case NET_SFTP_STATUS:
1842  $this->_logError($response);
1843  return false;
1844  default:
1845  user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1846  return false;
1847  }
1848 
1849  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
1850  $dataCallback = false;
1851  switch (true) {
1852  case $mode & self::SOURCE_CALLBACK:
1853  if (!is_callable($data)) {
1854  user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
1855  }
1856  $dataCallback = $data;
1857  // do nothing
1858  break;
1859  case is_resource($data):
1860  $mode = $mode & ~self::SOURCE_LOCAL_FILE;
1861  $fp = $data;
1862  break;
1863  case $mode & self::SOURCE_LOCAL_FILE:
1864  if (!is_file($data)) {
1865  user_error("$data is not a valid file");
1866  return false;
1867  }
1868  $fp = @fopen($data, 'rb');
1869  if (!$fp) {
1870  return false;
1871  }
1872  }
1873 
1874  if (isset($fp)) {
1875  $stat = fstat($fp);
1876  $size = $stat['size'];
1877 
1878  if ($local_start >= 0) {
1879  fseek($fp, $local_start);
1880  $size-= $local_start;
1881  }
1882  } elseif ($dataCallback) {
1883  $size = 0;
1884  } else {
1885  $size = strlen($data);
1886  }
1887 
1888  $sent = 0;
1889  $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
1890 
1891  $sftp_packet_size = 4096; // PuTTY uses 4096
1892  // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
1893  $sftp_packet_size-= strlen($handle) + 25;
1894  $i = 0;
1895  while ($dataCallback || $sent < $size) {
1896  if ($dataCallback) {
1897  $temp = call_user_func($dataCallback, $sftp_packet_size);
1898  if (is_null($temp)) {
1899  break;
1900  }
1901  } else {
1902  $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
1903  }
1904  $subtemp = $offset + $sent;
1905  $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
1906  if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
1907  if ($mode & self::SOURCE_LOCAL_FILE) {
1908  fclose($fp);
1909  }
1910  return false;
1911  }
1912  $sent+= strlen($temp);
1913  if (is_callable($progressCallback)) {
1914  call_user_func($progressCallback, $sent);
1915  }
1916 
1917  $i++;
1918 
1919  if ($i == NET_SFTP_QUEUE_SIZE) {
1920  if (!$this->_read_put_responses($i)) {
1921  $i = 0;
1922  break;
1923  }
1924  $i = 0;
1925  }
1926  }
1927 
1928  if (!$this->_read_put_responses($i)) {
1929  if ($mode & self::SOURCE_LOCAL_FILE) {
1930  fclose($fp);
1931  }
1932  $this->_close_handle($handle);
1933  return false;
1934  }
1935 
1936  if ($mode & self::SOURCE_LOCAL_FILE) {
1937  fclose($fp);
1938  }
1939 
1940  return $this->_close_handle($handle);
1941  }
1942 
1954  {
1955  while ($i--) {
1956  $response = $this->_get_sftp_packet();
1957  if ($this->packet_type != NET_SFTP_STATUS) {
1958  user_error('Expected SSH_FXP_STATUS');
1959  return false;
1960  }
1961 
1962  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1963  if ($status != NET_SFTP_STATUS_OK) {
1964  $this->_logError($response, $status);
1965  break;
1966  }
1967  }
1968 
1969  return $i < 0;
1970  }
1971 
1979  function _close_handle($handle)
1980  {
1981  if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
1982  return false;
1983  }
1984 
1985  // "The client MUST release all resources associated with the handle regardless of the status."
1986  // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
1987  $response = $this->_get_sftp_packet();
1988  if ($this->packet_type != NET_SFTP_STATUS) {
1989  user_error('Expected SSH_FXP_STATUS');
1990  return false;
1991  }
1992 
1993  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1994  if ($status != NET_SFTP_STATUS_OK) {
1995  $this->_logError($response, $status);
1996  return false;
1997  }
1998 
1999  return true;
2000  }
2001 
2018  function get($remote_file, $local_file = false, $offset = 0, $length = -1)
2019  {
2020  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
2021  return false;
2022  }
2023 
2024  $remote_file = $this->_realpath($remote_file);
2025  if ($remote_file === false) {
2026  return false;
2027  }
2028 
2029  $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
2030  if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
2031  return false;
2032  }
2033 
2034  $response = $this->_get_sftp_packet();
2035  switch ($this->packet_type) {
2036  case NET_SFTP_HANDLE:
2037  $handle = substr($response, 4);
2038  break;
2039  case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
2040  $this->_logError($response);
2041  return false;
2042  default:
2043  user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
2044  return false;
2045  }
2046 
2047  if (is_resource($local_file)) {
2048  $fp = $local_file;
2049  $stat = fstat($fp);
2050  $res_offset = $stat['size'];
2051  } else {
2052  $res_offset = 0;
2053  if ($local_file !== false) {
2054  $fp = fopen($local_file, 'wb');
2055  if (!$fp) {
2056  return false;
2057  }
2058  } else {
2059  $content = '';
2060  }
2061  }
2062 
2063  $fclose_check = $local_file !== false && !is_resource($local_file);
2064 
2065  $start = $offset;
2066  $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
2067  while (true) {
2068  $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
2069  if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
2070  if ($fclose_check) {
2071  fclose($fp);
2072  }
2073  return false;
2074  }
2075 
2076  $response = $this->_get_sftp_packet();
2077  switch ($this->packet_type) {
2078  case NET_SFTP_DATA:
2079  $temp = substr($response, 4);
2080  $offset+= strlen($temp);
2081  if ($local_file === false) {
2082  $content.= $temp;
2083  } else {
2084  fputs($fp, $temp);
2085  }
2086  break;
2087  case NET_SFTP_STATUS:
2088  // could, in theory, return false if !strlen($content) but we'll hold off for the time being
2089  $this->_logError($response);
2090  break 2;
2091  default:
2092  user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
2093  if ($fclose_check) {
2094  fclose($fp);
2095  }
2096  return false;
2097  }
2098 
2099  if ($length > 0 && $length <= $offset - $start) {
2100  break;
2101  }
2102  }
2103 
2104  if ($length > 0 && $length <= $offset - $start) {
2105  if ($local_file === false) {
2106  $content = substr($content, 0, $length);
2107  } else {
2108  ftruncate($fp, $length + $res_offset);
2109  }
2110  }
2111 
2112  if ($fclose_check) {
2113  fclose($fp);
2114  }
2115 
2116  if (!$this->_close_handle($handle)) {
2117  return false;
2118  }
2119 
2120  // if $content isn't set that means a file was written to
2121  return isset($content) ? $content : true;
2122  }
2123 
2132  function delete($path, $recursive = true)
2133  {
2134  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
2135  return false;
2136  }
2137 
2138  $path = $this->_realpath($path);
2139  if ($path === false) {
2140  return false;
2141  }
2142 
2143  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
2144  if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
2145  return false;
2146  }
2147 
2148  $response = $this->_get_sftp_packet();
2149  if ($this->packet_type != NET_SFTP_STATUS) {
2150  user_error('Expected SSH_FXP_STATUS');
2151  return false;
2152  }
2153 
2154  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
2155  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
2156  if ($status != NET_SFTP_STATUS_OK) {
2157  $this->_logError($response, $status);
2158  if (!$recursive) {
2159  return false;
2160  }
2161  $i = 0;
2162  $result = $this->_delete_recursive($path, $i);
2163  $this->_read_put_responses($i);
2164  return $result;
2165  }
2166 
2168 
2169  return true;
2170  }
2171 
2183  {
2184  if (!$this->_read_put_responses($i)) {
2185  return false;
2186  }
2187  $i = 0;
2188  $entries = $this->_list($path, true);
2189 
2190  // normally $entries would have at least . and .. but it might not if the directories
2191  // permissions didn't allow reading
2192  if (empty($entries)) {
2193  return false;
2194  }
2195 
2196  unset($entries['.'], $entries['..']);
2197  foreach ($entries as $filename => $props) {
2198  if (!isset($props['type'])) {
2199  return false;
2200  }
2201 
2202  $temp = $path . '/' . $filename;
2203  if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
2204  if (!$this->_delete_recursive($temp, $i)) {
2205  return false;
2206  }
2207  } else {
2208  if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
2209  return false;
2210  }
2211  $this->_remove_from_stat_cache($temp);
2212 
2213  $i++;
2214 
2215  if ($i >= NET_SFTP_QUEUE_SIZE) {
2216  if (!$this->_read_put_responses($i)) {
2217  return false;
2218  }
2219  $i = 0;
2220  }
2221  }
2222  }
2223 
2224  if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
2225  return false;
2226  }
2228 
2229  $i++;
2230 
2231  if ($i >= NET_SFTP_QUEUE_SIZE) {
2232  if (!$this->_read_put_responses($i)) {
2233  return false;
2234  }
2235  $i = 0;
2236  }
2237 
2238  return true;
2239  }
2240 
2248  function file_exists($path)
2249  {
2250  if ($this->use_stat_cache) {
2251  $path = $this->_realpath($path);
2252 
2253  $result = $this->_query_stat_cache($path);
2254 
2255  if (isset($result)) {
2256  // return true if $result is an array or if it's an stdClass object
2257  return $result !== false;
2258  }
2259  }
2260 
2261  return $this->stat($path) !== false;
2262  }
2263 
2271  function is_dir($path)
2272  {
2273  $result = $this->_get_stat_cache_prop($path, 'type');
2274  if ($result === false) {
2275  return false;
2276  }
2277  return $result === NET_SFTP_TYPE_DIRECTORY;
2278  }
2279 
2287  function is_file($path)
2288  {
2289  $result = $this->_get_stat_cache_prop($path, 'type');
2290  if ($result === false) {
2291  return false;
2292  }
2293  return $result === NET_SFTP_TYPE_REGULAR;
2294  }
2295 
2303  function is_link($path)
2304  {
2305  $result = $this->_get_lstat_cache_prop($path, 'type');
2306  if ($result === false) {
2307  return false;
2308  }
2309  return $result === NET_SFTP_TYPE_SYMLINK;
2310  }
2311 
2319  function fileatime($path)
2320  {
2321  return $this->_get_stat_cache_prop($path, 'atime');
2322  }
2323 
2331  function filemtime($path)
2332  {
2333  return $this->_get_stat_cache_prop($path, 'mtime');
2334  }
2335 
2343  function fileperms($path)
2344  {
2345  return $this->_get_stat_cache_prop($path, 'permissions');
2346  }
2347 
2355  function fileowner($path)
2356  {
2357  return $this->_get_stat_cache_prop($path, 'uid');
2358  }
2359 
2367  function filegroup($path)
2368  {
2369  return $this->_get_stat_cache_prop($path, 'gid');
2370  }
2371 
2379  function filesize($path)
2380  {
2381  return $this->_get_stat_cache_prop($path, 'size');
2382  }
2383 
2391  function filetype($path)
2392  {
2393  $type = $this->_get_stat_cache_prop($path, 'type');
2394  if ($type === false) {
2395  return false;
2396  }
2397 
2398  switch ($type) {
2399  case NET_SFTP_TYPE_BLOCK_DEVICE:
2400  return 'block';
2401  case NET_SFTP_TYPE_CHAR_DEVICE:
2402  return 'char';
2403  case NET_SFTP_TYPE_DIRECTORY:
2404  return 'dir';
2405  case NET_SFTP_TYPE_FIFO:
2406  return 'fifo';
2407  case NET_SFTP_TYPE_REGULAR:
2408  return 'file';
2409  case NET_SFTP_TYPE_SYMLINK:
2410  return 'link';
2411  default:
2412  return false;
2413  }
2414  }
2415 
2426  function _get_stat_cache_prop($path, $prop)
2427  {
2428  return $this->_get_xstat_cache_prop($path, $prop, 'stat');
2429  }
2430 
2441  function _get_lstat_cache_prop($path, $prop)
2442  {
2443  return $this->_get_xstat_cache_prop($path, $prop, 'lstat');
2444  }
2445 
2457  {
2458  if ($this->use_stat_cache) {
2459  $path = $this->_realpath($path);
2460 
2461  $result = $this->_query_stat_cache($path);
2462 
2463  if (is_object($result) && isset($result->$type)) {
2464  return $result->{$type}[$prop];
2465  }
2466  }
2467 
2468  $result = $this->$type($path);
2469 
2470  if ($result === false || !isset($result[$prop])) {
2471  return false;
2472  }
2473 
2474  return $result[$prop];
2475  }
2476 
2485  function rename($oldname, $newname)
2486  {
2487  if (!($this->bitmap & SSH2::MASK_LOGIN)) {
2488  return false;
2489  }
2490 
2491  $oldname = $this->_realpath($oldname);
2492  $newname = $this->_realpath($newname);
2493  if ($oldname === false || $newname === false) {
2494  return false;
2495  }
2496 
2497  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
2498  $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
2499  if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
2500  return false;
2501  }
2502 
2503  $response = $this->_get_sftp_packet();
2504  if ($this->packet_type != NET_SFTP_STATUS) {
2505  user_error('Expected SSH_FXP_STATUS');
2506  return false;
2507  }
2508 
2509  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
2510  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
2511  if ($status != NET_SFTP_STATUS_OK) {
2512  $this->_logError($response, $status);
2513  return false;
2514  }
2515 
2516  // don't move the stat cache entry over since this operation could very well change the
2517  // atime and mtime attributes
2518  //$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname));
2519  $this->_remove_from_stat_cache($oldname);
2520  $this->_remove_from_stat_cache($newname);
2521 
2522  return true;
2523  }
2524 
2535  {
2536  $attr = array();
2537  extract(unpack('Nflags', $this->_string_shift($response, 4)));
2538  // SFTPv4+ have a type field (a byte) that follows the above flag field
2539  foreach ($this->attributes as $key => $value) {
2540  switch ($flags & $key) {
2541  case NET_SFTP_ATTR_SIZE: // 0x00000001
2542  // The size attribute is defined as an unsigned 64-bit integer.
2543  // The following will use floats on 32-bit platforms, if necessary.
2544  // As can be seen in the BigInteger class, floats are generally
2545  // IEEE 754 binary64 "double precision" on such platforms and
2546  // as such can represent integers of at least 2^50 without loss
2547  // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
2548  $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
2549  break;
2550  case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
2551  $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
2552  break;
2553  case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
2554  $attr+= unpack('Npermissions', $this->_string_shift($response, 4));
2555  // mode == permissions; permissions was the original array key and is retained for bc purposes.
2556  // mode was added because that's the more industry standard terminology
2557  $attr+= array('mode' => $attr['permissions']);
2558  $fileType = $this->_parseMode($attr['permissions']);
2559  if ($fileType !== false) {
2560  $attr+= array('type' => $fileType);
2561  }
2562  break;
2563  case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
2564  $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
2565  break;
2566  case NET_SFTP_ATTR_EXTENDED: // 0x80000000
2567  extract(unpack('Ncount', $this->_string_shift($response, 4)));
2568  for ($i = 0; $i < $count; $i++) {
2569  extract(unpack('Nlength', $this->_string_shift($response, 4)));
2570  $key = $this->_string_shift($response, $length);
2571  extract(unpack('Nlength', $this->_string_shift($response, 4)));
2572  $attr[$key] = $this->_string_shift($response, $length);
2573  }
2574  }
2575  }
2576  return $attr;
2577  }
2578 
2588  function _parseMode($mode)
2589  {
2590  // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12
2591  // see, also, http://linux.die.net/man/2/stat
2592  switch ($mode & 0170000) {// ie. 1111 0000 0000 0000
2593  case 0000000: // no file type specified - figure out the file type using alternative means
2594  return false;
2595  case 0040000:
2596  return NET_SFTP_TYPE_DIRECTORY;
2597  case 0100000:
2598  return NET_SFTP_TYPE_REGULAR;
2599  case 0120000:
2600  return NET_SFTP_TYPE_SYMLINK;
2601  // new types introduced in SFTPv5+
2602  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
2603  case 0010000: // named pipe (fifo)
2604  return NET_SFTP_TYPE_FIFO;
2605  case 0020000: // character special
2606  return NET_SFTP_TYPE_CHAR_DEVICE;
2607  case 0060000: // block special
2608  return NET_SFTP_TYPE_BLOCK_DEVICE;
2609  case 0140000: // socket
2610  return NET_SFTP_TYPE_SOCKET;
2611  case 0160000: // whiteout
2612  // "SPECIAL should be used for files that are of
2613  // a known type which cannot be expressed in the protocol"
2614  return NET_SFTP_TYPE_SPECIAL;
2615  default:
2616  return NET_SFTP_TYPE_UNKNOWN;
2617  }
2618  }
2619 
2635  function _parseLongname($longname)
2636  {
2637  // http://en.wikipedia.org/wiki/Unix_file_types
2638  // http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions
2639  if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
2640  switch ($longname[0]) {
2641  case '-':
2642  return NET_SFTP_TYPE_REGULAR;
2643  case 'd':
2644  return NET_SFTP_TYPE_DIRECTORY;
2645  case 'l':
2646  return NET_SFTP_TYPE_SYMLINK;
2647  default:
2648  return NET_SFTP_TYPE_SPECIAL;
2649  }
2650  }
2651 
2652  return false;
2653  }
2654 
2668  {
2669  $packet = $this->request_id !== false ?
2670  pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
2671  pack('NCa*', strlen($data) + 1, $type, $data);
2672 
2673  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
2674  $result = $this->_send_channel_packet(self::CHANNEL, $packet);
2675  $stop = strtok(microtime(), ' ') + strtok('');
2676 
2677  if (defined('NET_SFTP_LOGGING')) {
2678  $packet_type = '-> ' . $this->packet_types[$type] .
2679  ' (' . round($stop - $start, 4) . 's)';
2680  if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
2681  echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
2682  flush();
2683  ob_flush();
2684  } else {
2685  $this->packet_type_log[] = $packet_type;
2686  if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
2687  $this->packet_log[] = $data;
2688  }
2689  }
2690  }
2691 
2692  return $result;
2693  }
2694 
2708  function _get_sftp_packet()
2709  {
2710  $this->curTimeout = false;
2711 
2712  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
2713 
2714  // SFTP packet length
2715  while (strlen($this->packet_buffer) < 4) {
2716  $temp = $this->_get_channel_packet(self::CHANNEL);
2717  if (is_bool($temp)) {
2718  $this->packet_type = false;
2719  $this->packet_buffer = '';
2720  return false;
2721  }
2722  $this->packet_buffer.= $temp;
2723  }
2724  extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
2725  $tempLength = $length;
2726  $tempLength-= strlen($this->packet_buffer);
2727 
2728  // SFTP packet type and data payload
2729  while ($tempLength > 0) {
2730  $temp = $this->_get_channel_packet(self::CHANNEL);
2731  if (is_bool($temp)) {
2732  $this->packet_type = false;
2733  $this->packet_buffer = '';
2734  return false;
2735  }
2736  $this->packet_buffer.= $temp;
2737  $tempLength-= strlen($temp);
2738  }
2739 
2740  $stop = strtok(microtime(), ' ') + strtok('');
2741 
2742  $this->packet_type = ord($this->_string_shift($this->packet_buffer));
2743 
2744  if ($this->request_id !== false) {
2745  $this->_string_shift($this->packet_buffer, 4); // remove the request id
2746  $length-= 5; // account for the request id and the packet type
2747  } else {
2748  $length-= 1; // account for the packet type
2749  }
2750 
2751  $packet = $this->_string_shift($this->packet_buffer, $length);
2752 
2753  if (defined('NET_SFTP_LOGGING')) {
2754  $packet_type = '<- ' . $this->packet_types[$this->packet_type] .
2755  ' (' . round($stop - $start, 4) . 's)';
2756  if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
2757  echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
2758  flush();
2759  ob_flush();
2760  } else {
2761  $this->packet_type_log[] = $packet_type;
2762  if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
2763  $this->packet_log[] = $packet;
2764  }
2765  }
2766  }
2767 
2768  return $packet;
2769  }
2770 
2779  function getSFTPLog()
2780  {
2781  if (!defined('NET_SFTP_LOGGING')) {
2782  return false;
2783  }
2784 
2785  switch (NET_SFTP_LOGGING) {
2786  case NET_SFTP_LOG_COMPLEX:
2787  return $this->_format_log($this->packet_log, $this->packet_type_log);
2788  break;
2789  //case NET_SFTP_LOG_SIMPLE:
2790  default:
2791  return $this->packet_type_log;
2792  }
2793  }
2794 
2801  function getSFTPErrors()
2802  {
2803  return $this->sftp_errors;
2804  }
2805 
2812  function getLastSFTPError()
2813  {
2814  return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
2815  }
2816 
2824  {
2825  $temp = array('version' => $this->version);
2826  if (isset($this->extensions['versions'])) {
2827  $temp['extensions'] = $this->extensions['versions'];
2828  }
2829  return $temp;
2830  }
2831 
2839  function _disconnect($reason)
2840  {
2841  $this->pwd = false;
2842  parent::_disconnect($reason);
2843  }
2844 }
clearStatCache()
Clear the stat cache.
Definition: SFTP.php:566
touch($filename, $time=null, $atime=null)
Sets access and modification time of file.
Definition: SFTP.php:1312
_get_xstat_cache_prop($path, $prop, $type)
Return a stat or lstat properity.
Definition: SFTP.php:2456
$path
Definition: aliased.php:25
readlink($link)
Return the target of a symbolic link.
Definition: SFTP.php:1577
_parseLongname($longname)
Parse Longname.
Definition: SFTP.php:2635
rawlist($dir='.', $recursive=false)
Returns a detailed list of files in the given directory.
Definition: SFTP.php:784
$size
Definition: RandomTest.php:84
_stat($filename, $type)
Returns general information about a file or symbolic link.
Definition: SFTP.php:1265
_realpath($path)
Canonicalize the Server-Side Path Name.
Definition: SFTP.php:616
_get_sftp_packet()
Receives SFTP Packets.
Definition: SFTP.php:2708
$files
Definition: metarefresh.php:49
nlist($dir='.', $recursive=false)
Returns a list of files in the given directory.
Definition: SFTP.php:735
_logError($response, $status=-1)
Logs errors.
Definition: SFTP.php:589
filesize($path)
Gets file size.
Definition: SFTP.php:2379
$result
setListOrder()
Defines how nlist() and rawlist() will be sorted - if at all.
Definition: SFTP.php:1002
_get_lstat_cache_prop($path, $prop)
Return an lstat properity.
Definition: SFTP.php:2441
_define_array()
Define Array.
Definition: SSH2.php:3648
$timeout
Timeout.
Definition: SSH2.php:640
$type
getSupportedVersions()
Get supported SFTP versions.
Definition: SFTP.php:2823
login($username)
Login.
Definition: SFTP.php:389
_get_stat_cache_prop($path, $prop)
Return a stat properity.
Definition: SFTP.php:2426
_query_stat_cache($path)
Checks cache for path.
Definition: SFTP.php:1118
_format_log($message_log, $message_number_log)
Formats a log for printing.
Definition: SSH2.php:3696
_comparator($a, $b)
Compares two rawlist entries using parameters set by setListOrder()
Definition: SFTP.php:928
disableStatCache()
Disable the stat cache.
Definition: SFTP.php:546
filemtime($path)
Gets file modification time.
Definition: SFTP.php:2331
__construct($host, $port=22, $timeout=10)
Default Constructor.
Definition: SFTP.php:252
_parseAttributes(&$response)
Parse Attributes.
Definition: SFTP.php:2534
chdir($dir)
Changes the current directory.
Definition: SFTP.php:672
_remove_from_stat_cache($path)
Remove files / directories from cache.
Definition: SFTP.php:1091
_send_sftp_packet($type, $data)
Sends SFTP Packets.
Definition: SFTP.php:2667
const MASK_LOGIN
Definition: SSH2.php:82
truncate($filename, $new_size)
Truncates a file to a given length.
Definition: SFTP.php:1294
getLastSFTPError()
Returns the last error.
Definition: SFTP.php:2812
const SOURCE_STRING
Reads data from a string.
Definition: SFTP.php:74
_disconnect($reason)
Disconnect.
Definition: SFTP.php:2839
symlink($target, $link)
Create a symlink.
Definition: SFTP.php:1621
_setstat($filename, $attr, $recursive)
Sets information about a file.
Definition: SFTP.php:1450
stat($filename)
Returns general information about a file.
Definition: SFTP.php:1141
size($filename)
Returns the file size, in bytes, or false, on failure.
Definition: SFTP.php:1027
is_file($path)
Tells whether the filename is a regular file.
Definition: SFTP.php:2287
$start
Definition: bench.php:8
$time
Definition: cron.php:21
const RESUME
Resumes an upload.
Definition: SFTP.php:83
getSFTPErrors()
Returns all errors.
Definition: SFTP.php:2801
Pure-PHP implementation of SSHv2.
rmdir($dir)
Removes a directory.
Definition: SFTP.php:1720
filegroup($path)
Gets file group.
Definition: SFTP.php:2367
_delete_recursive($path, &$i)
Recursively deletes directories on the SFTP server.
Definition: SFTP.php:2182
_update_stat_cache($path, $value)
Save files / directories to cache.
Definition: SFTP.php:1047
_parseMode($mode)
Attempt to identify the file type.
Definition: SFTP.php:2588
const CHANNEL
SFTP channel constant.
Definition: SFTP.php:60
SFTP Stream Wrapper.
enableStatCache()
Enable the stat cache.
Definition: SFTP.php:556
is_link($path)
Tells whether the filename is a symbolic link.
Definition: SFTP.php:2303
_close_handle($handle)
Close handle.
Definition: SFTP.php:1979
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
_setstat_recursive($path, $attr, &$i)
Recursively sets information on directories on the SFTP server.
Definition: SFTP.php:1509
$filename
Definition: buildRTE.php:89
is_dir($path)
Tells whether the filename is a directory.
Definition: SFTP.php:2271
_nlist_helper($dir, $recursive, $relativeDir)
Helper method for nlist.
Definition: SFTP.php:749
_string_shift(&$string, $index=1)
String Shift.
Definition: SSH2.php:3631
_send_binary_packet($data, $logged=null)
Sends Binary Packets.
Definition: SSH2.php:3393
chown($filename, $uid, $recursive=false)
Changes file or directory owner.
Definition: SFTP.php:1363
mkdir($dir, $mode=-1, $recursive=false)
Creates a directory.
Definition: SFTP.php:1657
put($remote_file, $data, $mode=self::SOURCE_STRING, $start=-1, $local_start=-1, $progressCallback=null)
Uploads a file to the SFTP server.
Definition: SFTP.php:1802
chgrp($filename, $gid, $recursive=false)
Changes file or directory group.
Definition: SFTP.php:1383
_mkdir_helper($dir, $attr)
Helper function for directory creation.
Definition: SFTP.php:1692
pwd()
Returns the current directory name.
Definition: SFTP.php:577
_list($dir, $raw=true)
Reads a list, be it detailed or not, of files in the given directory.
Definition: SFTP.php:818
chmod($mode, $filename, $recursive=false)
Set permissions on a file.
Definition: SFTP.php:1402
file_exists($path)
Checks whether a file or directory exists.
Definition: SFTP.php:2248
_get_channel_packet($client_channel, $skip_extended=false)
Gets channel data.
Definition: SSH2.php:3175
$i
Definition: disco.tpl.php:19
fileowner($path)
Gets file owner.
Definition: SFTP.php:2355
const SOURCE_LOCAL_FILE
#+ public
Definition: SFTP.php:69
const RESUME_START
Append a local file to an already existing remote file.
Definition: SFTP.php:87
_send_channel_packet($client_channel, $data)
Sends channel data.
Definition: SSH2.php:3529
_read_put_responses($i)
Reads multiple successive SSH_FXP_WRITE responses.
Definition: SFTP.php:1953
lstat($filename)
Returns general information about a file or symbolic link.
Definition: SFTP.php:1198
getSFTPLog()
Returns a log of the packets that have been sent and received.
Definition: SFTP.php:2779
fileatime($path)
Gets last access time of file.
Definition: SFTP.php:2319
$response
$target
Definition: test.php:19
const SOURCE_CALLBACK
Reads data from callback: function callback($length) returns string to proceed, null for EOF...
Definition: SFTP.php:79
rename($oldname, $newname)
Renames a file or a directory on the SFTP server.
Definition: SFTP.php:2485
$key
Definition: croninfo.php:18
filetype($path)
Gets file type.
Definition: SFTP.php:2391
fileperms($path)
Gets file permissions.
Definition: SFTP.php:2343
$data
Definition: bench.php:6