home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / class-ftp.php < prev    next >
Encoding:
PHP Script  |  2016-08-31  |  26.5 KB  |  913 lines

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