PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/ftp.class.php

http://github.com/dg/ftp-php
PHP | 233 lines | 137 code | 44 blank | 52 comment | 21 complexity | 9138370928894280b3b2668fb032bdbc MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * FTP - access to an FTP server.
  4. *
  5. * @author David Grudl
  6. * @copyright Copyright (c) 2008 David Grudl
  7. * @license New BSD License
  8. * @link http://phpfashion.com/
  9. * @version 1.0
  10. */
  11. class Ftp
  12. {
  13. /**#@+ FTP constant alias */
  14. const ASCII = FTP_ASCII;
  15. const TEXT = FTP_TEXT;
  16. const BINARY = FTP_BINARY;
  17. const IMAGE = FTP_IMAGE;
  18. const TIMEOUT_SEC = FTP_TIMEOUT_SEC;
  19. const AUTOSEEK = FTP_AUTOSEEK;
  20. const AUTORESUME = FTP_AUTORESUME;
  21. const FAILED = FTP_FAILED;
  22. const FINISHED = FTP_FINISHED;
  23. const MOREDATA = FTP_MOREDATA;
  24. /**#@-*/
  25. private static $aliases = array(
  26. 'sslconnect' => 'ssl_connect',
  27. 'getoption' => 'get_option',
  28. 'setoption' => 'set_option',
  29. 'nbcontinue' => 'nb_continue',
  30. 'nbfget' => 'nb_fget',
  31. 'nbfput' => 'nb_fput',
  32. 'nbget' => 'nb_get',
  33. 'nbput' => 'nb_put',
  34. );
  35. /** @var resource */
  36. private $resource;
  37. /** @var array */
  38. private $state;
  39. /** @var string */
  40. private $errorMsg;
  41. /**
  42. * @param string URL ftp://...
  43. */
  44. public function __construct($url = NULL)
  45. {
  46. if (!extension_loaded('ftp')) {
  47. throw new /*\*/Exception("PHP extension FTP is not loaded.");
  48. }
  49. if ($url) {
  50. $parts = parse_url($url);
  51. $this->connect($parts['host'], empty($parts['port']) ? NULL : (int) $parts['port']);
  52. $this->login($parts['user'], $parts['pass']);
  53. $this->pasv(TRUE);
  54. if (isset($parts['path'])) {
  55. $this->chdir($parts['path']);
  56. }
  57. }
  58. }
  59. /**
  60. * Magic method (do not call directly).
  61. * @param string method name
  62. * @param array arguments
  63. * @return mixed
  64. * @throws Exception
  65. * @throws FtpException
  66. */
  67. public function __call($name, $args)
  68. {
  69. $name = strtolower($name);
  70. $silent = strncmp($name, 'try', 3) === 0;
  71. $func = $silent ? substr($name, 3) : $name;
  72. $func = 'ftp_' . (isset(self::$aliases[$func]) ? self::$aliases[$func] : $func);
  73. if (!function_exists($func)) {
  74. throw new Exception("Call to undefined method Ftp::$name().");
  75. }
  76. $this->errorMsg = NULL;
  77. set_error_handler(array($this, '_errorHandler'));
  78. if ($func === 'ftp_connect' || $func === 'ftp_ssl_connect') {
  79. $this->state = array($name => $args);
  80. $this->resource = call_user_func_array($func, $args);
  81. $res = NULL;
  82. } elseif (!is_resource($this->resource)) {
  83. restore_error_handler();
  84. throw new FtpException("Not connected to FTP server. Call connect() or ssl_connect() first.");
  85. } else {
  86. if ($func === 'ftp_login' || $func === 'ftp_pasv') {
  87. $this->state[$name] = $args;
  88. }
  89. array_unshift($args, $this->resource);
  90. $res = call_user_func_array($func, $args);
  91. if ($func === 'ftp_chdir' || $func === 'ftp_cdup') {
  92. $this->state['chdir'] = array(ftp_pwd($this->resource));
  93. }
  94. }
  95. restore_error_handler();
  96. if (!$silent && $this->errorMsg !== NULL) {
  97. if (ini_get('html_errors')) {
  98. $this->errorMsg = html_entity_decode(strip_tags($this->errorMsg));
  99. }
  100. if (($a = strpos($this->errorMsg, ': ')) !== FALSE) {
  101. $this->errorMsg = substr($this->errorMsg, $a + 2);
  102. }
  103. throw new FtpException($this->errorMsg);
  104. }
  105. return $res;
  106. }
  107. /**
  108. * Internal error handler. Do not call directly.
  109. */
  110. public function _errorHandler($code, $message)
  111. {
  112. $this->errorMsg = $message;
  113. }
  114. /**
  115. * Reconnects to FTP server.
  116. * @return void
  117. */
  118. public function reconnect()
  119. {
  120. @ftp_close($this->resource); // intentionally @
  121. foreach ($this->state as $name => $args) {
  122. call_user_func_array(array($this, $name), $args);
  123. }
  124. }
  125. /**
  126. * Checks if file or directory exists.
  127. * @param string
  128. * @return bool
  129. */
  130. public function fileExists($file)
  131. {
  132. return is_array($this->nlist($file));
  133. }
  134. /**
  135. * Checks if directory exists.
  136. * @param string
  137. * @return bool
  138. */
  139. public function isDir($dir)
  140. {
  141. $current = $this->pwd();
  142. try {
  143. $this->chdir($dir);
  144. } catch (FtpException $e) {
  145. }
  146. $this->chdir($current);
  147. return empty($e);
  148. }
  149. /**
  150. * Recursive creates directories.
  151. * @param string
  152. * @return void
  153. */
  154. public function mkDirRecursive($dir)
  155. {
  156. $parts = explode('/', $dir);
  157. $path = '';
  158. while (!empty($parts)) {
  159. $path .= array_shift($parts);
  160. try {
  161. if ($path !== '') $this->mkdir($path);
  162. } catch (FtpException $e) {
  163. if (!$this->isDir($path)) {
  164. throw new FtpException("Cannot create directory '$path'.");
  165. }
  166. }
  167. $path .= '/';
  168. }
  169. }
  170. /**
  171. * Recursive deletes path.
  172. * @param string
  173. * @return void
  174. */
  175. public function deleteRecursive($path)
  176. {
  177. if (!$this->tryDelete($path)) {
  178. foreach ((array) $this->nlist($path) as $file) {
  179. if ($file !== '.' && $file !== '..') {
  180. $this->deleteRecursive(strpos($file, '/') === FALSE ? "$path/$file" : $file);
  181. }
  182. }
  183. $this->rmdir($path);
  184. }
  185. }
  186. }
  187. class FtpException extends Exception
  188. {
  189. }