PageRenderTime 68ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/application/libraries/PEAR/Net/FTP/Socket.php

https://github.com/shopaholiccompany/shopaholic
PHP | 783 lines | 377 code | 104 blank | 302 comment | 93 complexity | aba24751162945285b560d419b90666f MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, LGPL-2.1
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Net_FTP socket implementation of FTP functions.
  5. *
  6. * The functions in this file emulate the ext/FTP functions through
  7. * ext/Socket.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * LICENSE: This source file is subject to version 3.0 of the PHP license
  12. * that is available through the world-wide-web at the following URI:
  13. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  14. * the PHP License and are unable to obtain it through the web, please
  15. * send a note to license@php.net so we can mail you a copy immediately.
  16. *
  17. * @category Networking
  18. * @package FTP
  19. * @author Tobias Schlitt <toby@php.net>
  20. * @copyright 1997-2008 The PHP Group
  21. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  22. * @version CVS: $Id: Socket.php,v 1.7 2008/04/22 19:47:46 jschippers Exp $
  23. * @link http://pear.php.net/package/Net_FTP
  24. * @since File available since Release 0.0.1
  25. */
  26. error_reporting(E_ALL);
  27. /**
  28. * Default FTP extension constants
  29. */
  30. define('FTP_ASCII', 0);
  31. define('FTP_TEXT', 0);
  32. define('FTP_BINARY', 1);
  33. define('FTP_IMAGE', 1);
  34. define('FTP_TIMEOUT_SEC', 0);
  35. /**
  36. * What needs to be done overall?
  37. * #1 Install the rest of these functions
  38. * #2 Document better
  39. * #3 Alot of other things I don't remember
  40. */
  41. /*
  42. * !!! NOTE !!!
  43. * Most of the comment's are "not working",
  44. * meaning they are not all up-to-date
  45. * !!! NOTE !!!
  46. */
  47. /**
  48. * &resource ftp_connect ( string host [, int port [, int timeout ] ] );
  49. *
  50. * Opens an FTP connection and return resource or false on failure.
  51. *
  52. * FTP Success respons code: 220
  53. *
  54. * @param string $host Host to connect to
  55. * @param int $port Optional, port to connect to
  56. * @param int $timeout Optional, seconds until function timeouts
  57. *
  58. * @todo The FTP extension has ftp_get_option() function which returns the
  59. * timeout variable. This function needs to be created and contain it as
  60. * static variable.
  61. * @todo The FTP extension has ftp_set_option() function which sets the
  62. * timeout variable. This function needs to be created and called here.
  63. * @access public
  64. * @return &resource
  65. */
  66. function &ftp_connect($host, $port = 21, $timeout = 90)
  67. {
  68. $false = false; // We are going to return refrence (E_STRICT)
  69. if (!is_string($host) || !is_integer($port) || !is_integer($timeout)) {
  70. return $false;
  71. }
  72. $control = @fsockopen($host, $port, $iError, $sError,
  73. $timeout);
  74. $GLOBALS['_NET_FTP']['timeout'] = $timeout;
  75. if (!is_resource($control)) {
  76. return $false;
  77. }
  78. stream_set_blocking($control, true);
  79. stream_set_timeout($control, $timeout);
  80. do {
  81. $content[] = fgets($control, 8129);
  82. $array = socket_get_status($control);
  83. } while ($array['unread_bytes'] > 0);
  84. if (substr($content[count($content)-1], 0, 3) == 220) {
  85. return $control;
  86. }
  87. return $false;
  88. }
  89. /**
  90. * boolean ftp_login ( resource stream, string username, string password );
  91. *
  92. * Logs in to an given FTP connection stream.
  93. * Returns TRUE on success or FALSE on failure.
  94. *
  95. * NOTE:
  96. * Username and password are *not* optional. Function will *not*
  97. * assume "anonymous" if username and/or password is empty
  98. *
  99. * FTP Success respons code: 230
  100. *
  101. * @param resource &$control FTP resource to login to
  102. * @param string $username FTP Username to be used
  103. * @param string $password FTP Password to be used
  104. *
  105. * @access public
  106. * @return boolean
  107. */
  108. function ftp_login(&$control, $username, $password)
  109. {
  110. if (!is_resource($control) || is_null($username)) {
  111. return false;
  112. }
  113. fputs($control, 'USER '.$username."\r\n");
  114. $contents = array();
  115. do {
  116. $contents[] = fgets($control, 8192);
  117. $array = socket_get_status($control);
  118. } while ($array['unread_bytes'] > 0);
  119. if (substr($contents[count($contents)-1], 0, 3) != 331) {
  120. return false;
  121. }
  122. fputs($control, 'PASS '.$password."\r\n");
  123. $contents = array();
  124. do {
  125. $contents[] = fgets($control, 8192);
  126. $array = socket_get_status($control);
  127. } while ($array['unread_bytes']);
  128. if (substr($contents[count($contents)-1], 0, 3) == 230) {
  129. return true;
  130. }
  131. trigger_error('ftp_login() [<a href="function.ftp-login">function.ftp-login'.
  132. '</a>]: '.$contents[count($contents)-1], E_USER_WARNING);
  133. return false;
  134. }
  135. /**
  136. * boolean ftp_quit ( resource stream );
  137. *
  138. * Closes FTP connection.
  139. * Returns TRUE or FALSE on error.
  140. *
  141. * NOTE: The PHP function ftp_quit is *alias* to ftp_close, here it is
  142. * the *other-way-around* ( ftp_close() is alias to ftp_quit() ).
  143. *
  144. * NOTE:
  145. * resource is set to null since unset() can't unset the variable.
  146. *
  147. * @param resource &$control FTP resource
  148. *
  149. * @access public
  150. * @return boolean
  151. */
  152. function ftp_quit(&$control)
  153. {
  154. if (!is_resource($control)) {
  155. return false;
  156. }
  157. fputs($control, 'QUIT'."\r\n");
  158. fclose($control);
  159. $control = null;
  160. return true;
  161. }
  162. /**
  163. * Alias to ftp_quit()
  164. *
  165. * @param resource &$control FTP resource
  166. *
  167. * @see ftp_quit()
  168. * @access public
  169. * @return boolean
  170. */
  171. function ftp_close(&$control)
  172. {
  173. return ftp_quit($control);
  174. }
  175. /**
  176. * string ftp_pwd ( resource stream );
  177. *
  178. * Gets the current directory name.
  179. * Returns the current directory.
  180. *
  181. * Needs data connection: NO
  182. * Success response code: 257
  183. *
  184. * @param resource &$control FTP resource
  185. *
  186. * @access public
  187. * @return string
  188. */
  189. function ftp_pwd(&$control)
  190. {
  191. if (!is_resource($control)) {
  192. return $control;
  193. }
  194. fputs($control, 'PWD'."\r\n");
  195. $content = array();
  196. do {
  197. $content[] = fgets($control, 8192);
  198. $array = socket_get_status($control);
  199. } while ($array['unread_bytes'] > 0);
  200. if (substr($cont = $content[count($content)-1], 0, 3) == 257) {
  201. $pos = strpos($cont, '"')+1;
  202. $pos2 = strrpos($cont, '"') - $pos;
  203. $path = substr($cont, $pos, $pos2);
  204. return $path;
  205. }
  206. return false;
  207. }
  208. /**
  209. * boolean ftp_chdir ( resource stream, string directory );
  210. *
  211. * Changes the current directory to the specified directory.
  212. * Returns TRUE on success or FALSE on failure.
  213. *
  214. * FTP success response code: 250
  215. * Needs data connection: NO
  216. *
  217. * @param resource &$control FTP stream
  218. * @param string $pwd Directory name
  219. *
  220. * @access public
  221. * @return boolean
  222. */
  223. function ftp_chdir(&$control, $pwd)
  224. {
  225. if (!is_resource($control) || !is_string($pwd)) {
  226. return false;
  227. }
  228. fputs($control, 'CWD '.$pwd."\r\n");
  229. $content = array();
  230. do {
  231. $content[] = fgets($control, 8192);
  232. $array = socket_get_status($control);
  233. } while ($array['unread_bytes'] > 0);
  234. if (substr($content[count($content)-1], 0, 3) == 250) {
  235. return true;
  236. }
  237. trigger_error('ftp_chdir() [<a
  238. href="function.ftp-chdir">function.ftp-chdir</a>]:
  239. ' .$content[count($content)-1], E_USER_WARNING);
  240. return false;
  241. }
  242. $_NET_FTP = array();
  243. $_NET_FTP['USE_PASSIVE'] = false;
  244. $_NET_FTP['DATA'] = null;
  245. /**
  246. * boolean ftp_pasv ( resource stream, boolean passive );
  247. *
  248. * Toggles passive mode ON/OFF.
  249. * Returns TRUE on success or FALSE on failure.
  250. *
  251. * Comment:
  252. * Although my lack of C knowlege I checked how the PHP FTP extension
  253. * do things here. Seems like they create the data connection and store
  254. * it in object for other functions to use.
  255. * This is now done here.
  256. *
  257. * FTP success response code: 227
  258. *
  259. * @param stream &$control FTP stream
  260. * @param boolean $pasv True to switch to passive, false for active mode
  261. *
  262. * @access public
  263. * @return boolean
  264. */
  265. function ftp_pasv(&$control, $pasv)
  266. {
  267. if (!is_resource($control) || !is_bool($pasv)) {
  268. return false;
  269. }
  270. // If data connection exists, destroy it
  271. if (isset($GLOBALS['_NET_FTP']['DATA'])) {
  272. fclose($GLOBALS['_NET_FTP']['DATA']);
  273. $GLOBALS['_NET_FTP']['DATA'] = null;
  274. do {
  275. fgets($control, 16);
  276. $array = socket_get_status($control);
  277. } while ($array['unread_bytes'] > 0);
  278. }
  279. // Are we suppost to create active or passive connection?
  280. if (!$pasv) {
  281. $GLOBALS['_NET_FTP']['USE_PASSIVE'] = false;
  282. // Pick random "low bit"
  283. $low = rand(39, 250);
  284. // Pick random "high bit"
  285. $high = rand(39, 250);
  286. // Lowest possible port would be; 10023
  287. // Highest possible port would be; 64246
  288. $port = ($low<<8)+$high;
  289. $ip = str_replace('.', ',', $_SERVER['SERVER_ADDR']);
  290. $s = $ip.','.$low.','.$high;
  291. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  292. if (is_resource($socket)) {
  293. if (socket_bind($socket, '0.0.0.0', $port)) {
  294. if (socket_listen($socket)) {
  295. $GLOBALS['_NET_FTP']['DATA'] = &$socket;
  296. fputs($control, 'PORT '.$s."\r\n");
  297. $line = fgets($control, 512);
  298. if (substr($line, 0, 3) == 200) {
  299. return true;
  300. }
  301. }
  302. }
  303. }
  304. return false;
  305. }
  306. // Since we are here, we are suppost to create passive data connection.
  307. $i = fputs($control, 'PASV' ."\r\n");
  308. $content = array();
  309. do {
  310. $content[] = fgets($control, 128);
  311. $array = socket_get_status($control);
  312. } while ($array['unread_bytes']);
  313. if (substr($cont = $content[count($content)-1], 0, 3) != 227) {
  314. return false;
  315. }
  316. $pos = strpos($cont, '(')+1;
  317. $pos2 = strrpos($cont, ')')-$pos;
  318. $string = substr($cont, $pos, $pos2);
  319. $array = split(',', $string);
  320. // IP we are connecting to
  321. $ip = $array[0]. '.' .$array[1]. '.' .$array[2]. '.' .$array[3];
  322. // Port ( 256*lowbit + highbit
  323. $port = ($array[4] << 8)+$array[5];
  324. // Our data connection
  325. $data = fsockopen($ip, $port, $iError, $sError,
  326. $GLOBALS['_NET_FTP']['timeout']);
  327. if (is_resource($data)) {
  328. $GLOBALS['_NET_FTP']['USE_PASSIVE'] = true;
  329. $GLOBALS['_NET_FTP']['DATA'] = &$data;
  330. stream_set_blocking($data, true);
  331. stream_set_timeout($data, $GLOBALS['_NET_FTP']['timeout']);
  332. return true;
  333. }
  334. return false;
  335. }
  336. /**
  337. * array ftp_rawlist ( resource stream, string directory [,bool recursive] );
  338. *
  339. * Returns a detailed list of files in the given directory.
  340. *
  341. * Needs data connection: YES
  342. *
  343. * @param integer &$control FTP resource
  344. * @param string $pwd Path to retrieve
  345. * @param boolean $recursive Optional, retrieve recursive listing
  346. *
  347. * @todo Enable the recursive feature.
  348. * @access public
  349. * @return array
  350. */
  351. function ftp_rawlist(&$control, $pwd, $recursive = false)
  352. {
  353. if (!is_resource($control) || !is_string($pwd)) {
  354. return false;
  355. }
  356. if (!isset($GLOBALS['_NET_FTP']['DATA']) ||
  357. !is_resource($GLOBALS['_NET_FTP']['DATA'])) {
  358. ftp_pasv($control, $GLOBALS['_NET_FTP']['USE_PASSIVE']);
  359. }
  360. fputs($control, 'LIST '.$pwd."\r\n");
  361. $msg = fgets($control, 512);
  362. if (substr($msg, 0, 3) == 425) {
  363. return false;
  364. }
  365. $data = &$GLOBALS['_NET_FTP']['DATA'];
  366. if (!$GLOBALS['_NET_FTP']['USE_PASSIVE']) {
  367. $data = &socket_accept($data);
  368. }
  369. $content = array();
  370. switch ($GLOBALS['_NET_FTP']['USE_PASSIVE']) {
  371. case true:
  372. while (true) {
  373. $string = rtrim(fgets($data, 1024));
  374. if ($string=='') {
  375. break;
  376. }
  377. $content[] = $string;
  378. }
  379. fclose($data);
  380. break;
  381. case false:
  382. $string = socket_read($data, 1024, PHP_BINARY_READ);
  383. $content = explode("\n", $string);
  384. unset($content[count($content)-1]);
  385. socket_close($GLOBALS['_NET_FTP']['DATA']);
  386. socket_close($data);
  387. break;
  388. }
  389. $data = $GLOBALS['_NET_FTP']['DATA'] = null;
  390. $f = fgets($control, 1024);
  391. return $content;
  392. }
  393. /**
  394. * string ftp_systype ( resource stream );
  395. *
  396. * Gets system type identifier of remote FTP server
  397. * Returns the remote system type
  398. *
  399. * @param resource &$control FTP resource
  400. *
  401. * @access public
  402. * @return string
  403. */
  404. function ftp_systype(&$control)
  405. {
  406. if (!is_resource($control)) {
  407. return false;
  408. }
  409. fputs($control, 'SYST'."\r\n");
  410. $line = fgets($control, 256);
  411. if (substr($line, 0, 3) != 215) {
  412. return false;
  413. }
  414. $os = substr($line, 4, strpos($line, ' ', 4)-4);
  415. return $os;
  416. }
  417. /**
  418. * boolean ftp_alloc ( resource stream, integer bytes [, string &message ] );
  419. *
  420. * Allocates space for a file to be uploaded
  421. * Return TRUE on success or FALSE on failure
  422. *
  423. * NOTE; Many FTP servers do not support this command and/or don't need it.
  424. *
  425. * FTP success respons key: Belive it's 200
  426. * Needs data connection: NO
  427. *
  428. * @param resource &$control FTP stream
  429. * @param integer $int Space to allocate
  430. * @param string &$msg Optional, textual representation of the servers response
  431. * will be returned by reference
  432. *
  433. * @access public
  434. * @return boolean
  435. */
  436. function ftp_alloc(&$control, $int, &$msg = null)
  437. {
  438. if (!is_resource($control) || !is_integer($int)) {
  439. return false;
  440. }
  441. fputs($control, 'ALLO '.$int.' R '.$int."\r\n");
  442. $msg = rtrim(fgets($control, 256));
  443. $code = substr($msg, 0, 3);
  444. if ($code == 200 || $code == 202) {
  445. return true;
  446. }
  447. return false;
  448. }
  449. /**
  450. * bool ftp_put ( resource stream, string remote_file, string local_file,
  451. * int mode [, int startpos ] );
  452. *
  453. * Uploads a file to the FTP server
  454. * Returns TRUE on success or FALSE on failure.
  455. *
  456. * NOTE:
  457. * The transfer mode specified must be either FTP_ASCII or FTP_BINARY.
  458. *
  459. * @param resource &$control FTP stream
  460. * @param string $remote Remote file to write
  461. * @param string $local Local file to upload
  462. * @param integer $mode Upload mode, FTP_ASCI || FTP_BINARY
  463. * @param integer $pos Optional, start upload at position
  464. *
  465. * @access public
  466. * @return boolean
  467. */
  468. function ftp_put(&$control, $remote, $local, $mode, $pos = 0)
  469. {
  470. if (!is_resource($control) || !is_readable($local) ||
  471. !is_integer($mode) || !is_integer($pos)) {
  472. return false;
  473. }
  474. $types = array (
  475. 0 => 'A',
  476. 1 => 'I'
  477. );
  478. $windows = array (
  479. 0 => 't',
  480. 1 => 'b'
  481. );
  482. /**
  483. * TYPE values:
  484. * A ( ASCII )
  485. * I ( BINARY )
  486. * E ( EBCDIC )
  487. * L ( BYTE )
  488. */
  489. if (!isset($GLOBALS['_NET_FTP']['DATA']) ||
  490. !is_resource($GLOBALS['_NET_FTP']['DATA'])) {
  491. ftp_pasv($control, $GLOBALS['_NET_FTP']['USE_PASSIVE']);
  492. }
  493. // Establish data connection variable
  494. $data = &$GLOBALS['_NET_FTP']['DATA'];
  495. // Decide TYPE to use
  496. fputs($control, 'TYPE '.$types[$mode]."\r\n");
  497. $line = fgets($control, 256); // "Type set to TYPE"
  498. if (substr($line, 0, 3) != 200) {
  499. return false;
  500. }
  501. fputs($control, 'STOR '.$remote."\r\n");
  502. sleep(1);
  503. $line = fgets($control, 256); // "Opening TYPE mode data connect."
  504. if (substr($line, 0, 3) != 150) {
  505. return false;
  506. }
  507. // Creating resource to $local file
  508. $fp = fopen($local, 'r'. $windows[$mode]);
  509. if (!is_resource($fp)) {
  510. $fp = null;
  511. return false;
  512. }
  513. // Loop throu that file and echo it to the data socket
  514. $i = 0;
  515. switch ($GLOBALS['_NET_FTP']['USE_PASSIVE']) {
  516. case false:
  517. $data = &socket_accept($data);
  518. while (!feof($fp)) {
  519. $i += socket_write($data, fread($fp, 10240), 10240);
  520. }
  521. socket_close($data);
  522. break;
  523. case true:
  524. while (!feof($fp)) {
  525. $i += fputs($data, fread($fp, 10240), 10240);
  526. }
  527. fclose($data);
  528. break;
  529. }
  530. $data = null;
  531. do {
  532. $line = fgets($control, 256);
  533. } while (substr($line, 0, 4) != "226 ");
  534. return true;
  535. }
  536. /**
  537. * Retrieve a remote file to a local file
  538. * Returns TRUE on success or FALSE on failure
  539. *
  540. * @param integer &$control Stream ID
  541. * @param string $local Local filename
  542. * @param string $remote Remote filename
  543. * @param integer $mode Transfer mode (FTP_ASCII or FTP_BINARY)
  544. * @param integer $resume Resume the file transfer or not
  545. *
  546. * @access public
  547. * @return boolean
  548. */
  549. function ftp_get(&$control, $local, $remote, $mode, $resume = 0)
  550. {
  551. if (!is_resource($control) || !is_writable(dirname($local)) ||
  552. !is_integer($mode) || !is_integer($resume)) {
  553. return false;
  554. }
  555. $types = array (
  556. 0 => 'A',
  557. 1 => 'I'
  558. );
  559. $windows = array (
  560. 0 => 't',
  561. 1 => 'b'
  562. );
  563. if (!isset($GLOBALS['_NET_FTP']['DATA']) ||
  564. !is_resource($GLOBALS['_NET_FTP'][ 'DATA'])) {
  565. ftp_pasv($control, $GLOBALS['_NET_FTP']['USE_PASSIVE']);
  566. }
  567. $data = &$GLOBALS['NET_FTP']['DATA'];
  568. fputs($control, 'TYPE '.$types[$mode]."\r\n");
  569. $line = fgets($control, 256);
  570. if (substr($line, 0, 3) != 200) {
  571. return false;
  572. }
  573. $fp = fopen($local, 'w'.$windows[$mode]);
  574. if (!is_resource($fp)) {
  575. $fp = null;
  576. return false;
  577. }
  578. }
  579. /**
  580. * Changes to the parent directory
  581. * Returns TRUE on success or FALSE on failure
  582. *
  583. * @param integer &$control Stream ID
  584. *
  585. * @access public
  586. * @return boolean
  587. */
  588. function ftp_cdup(&$control)
  589. {
  590. fputs($control, 'CDUP'."\r\n");
  591. $line = fgets($control, 256);
  592. if (substr($line, 0, 3) != 250) {
  593. return false;
  594. }
  595. return true;
  596. }
  597. /**
  598. * Set permissions on a file via FTP
  599. * Returns the new file permission on success or false on error
  600. *
  601. * NOTE: This command is *not* supported by the standard
  602. * NOTE: This command not ready!
  603. *
  604. * @param integer &$control Stream ID
  605. * @param integer $mode Octal value
  606. * @param string $file File to change permissions on
  607. *
  608. * @todo Figure out a way to chmod files via FTP
  609. * @access public
  610. * @return integer
  611. */
  612. function ftp_chmod(&$control, $mode, $file)
  613. {
  614. if (!is_resource($control) || !is_integer($mode) || !is_string($file)) {
  615. return false;
  616. }
  617. // chmod not in the standard, proftpd doesn't recognize it
  618. // use SITE CHMOD?
  619. fputs($control, 'SITE CHMOD '.$mode. ' ' .$file."\r\n");
  620. $line = fgets($control, 256);
  621. if (substr($line, 0, 3) == 200) {
  622. return $mode;
  623. }
  624. trigger_error('ftp_chmod() [<a
  625. href="function.ftp-chmod">function.ftp-chmod</a>]: ' .
  626. rtrim($line), E_USER_WARNING);
  627. return false;
  628. }
  629. /**
  630. * Deletes a file on the FTP server
  631. * Returns TRUE on success or FALSE on failure
  632. *
  633. * @param integer &$control Stream ID
  634. * @param string $path File to delete
  635. *
  636. * @access public
  637. * @return boolean
  638. */
  639. function ftp_delete(&$control, $path)
  640. {
  641. if (!is_resource($control) || !is_string($path)) {
  642. return false;
  643. }
  644. fputs($control, 'DELE '.$path."\r\n");
  645. $line = fgets($control, 256);
  646. if (substr($line, 0, 3) == 250) {
  647. return true;
  648. }
  649. return false;
  650. }
  651. /**
  652. * Requests execution of a program on the FTP server
  653. * NOTE; SITE EXEC is *not* supported by the standart
  654. * Returns TRUE on success or FALSE on error
  655. *
  656. * @param integer &$control Stream ID
  657. * @param string $cmd Command to send
  658. *
  659. * @access public
  660. * @todo Look a littlebit better into this
  661. * @return boolean
  662. */
  663. function ftp_exec(&$control, $cmd)
  664. {
  665. if (!is_resource($control) || !is_string($cmd)) {
  666. return false;
  667. }
  668. // Command not defined in the standart
  669. // proftpd doesn't recognize SITE EXEC (only help,chgrp,chmod and ratio)
  670. fputs($control, 'SITE EXEC '.$cmd."\r\n");
  671. $line = fgets($control, 256);
  672. // php.net/ftp_exec uses respons code 200 to verify if command was sent
  673. // successfully or not, so we'll just do the same
  674. if (substr($line, 0, 3) == 200) {
  675. return true;
  676. }
  677. return false;
  678. }
  679. ?>