PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/FTP-deployment/Deployment/libs/Ftp.php

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