Просмотр файла engine/classes/ftp.php

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