FtpDeployTask.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <?php
  2. /**
  3. * $Id: FtpDeployTask.php 905 2010-10-05 16:28:03Z mrook $
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information please see
  19. * <http://phing.info>.
  20. */
  21. require_once 'phing/Task.php';
  22. /**
  23. * FtpDeployTask
  24. *
  25. * Deploys a set of files to a remote FTP server.
  26. *
  27. *
  28. * Example usage:
  29. * <ftpdeploy host="host" port="21" username="user" password="password" dir="public_html" mode="ascii" clearfirst="true">
  30. * <fileset dir=".">
  31. * <include name="**"/>
  32. * <exclude name="phing"/>
  33. * <exclude name="build.xml"/>
  34. * <exclude name="images/**.png"/>
  35. * <exclude name="images/**.gif"/>
  36. * <exclude name="images/**.jpg"/>
  37. * </fileset>
  38. * </ftpdeploy>
  39. *
  40. * @author Jorrit Schippers <jorrit at ncode dot nl>
  41. * @version $Id: FtpDeployTask.php 905 2010-10-05 16:28:03Z mrook $
  42. * @since 2.3.1
  43. * @package phing.tasks.ext
  44. */
  45. class FtpDeployTask extends Task
  46. {
  47. private $host = null;
  48. private $port = 21;
  49. private $username = null;
  50. private $password = null;
  51. private $dir = null;
  52. private $filesets;
  53. private $completeDirMap;
  54. private $mode = FTP_BINARY;
  55. private $clearFirst = false;
  56. private $passive = false;
  57. public function __construct() {
  58. $this->filesets = array();
  59. $this->completeDirMap = array();
  60. }
  61. public function setHost($host) {
  62. $this->host = $host;
  63. }
  64. public function setPort($port) {
  65. $this->port = (int) $port;
  66. }
  67. public function setUsername($username) {
  68. $this->username = $username;
  69. }
  70. public function setPassword($password) {
  71. $this->password = $password;
  72. }
  73. public function setDir($dir) {
  74. $this->dir = $dir;
  75. }
  76. public function setMode($mode) {
  77. switch(strtolower($mode)) {
  78. case 'ascii':
  79. $this->mode = FTP_ASCII;
  80. break;
  81. case 'binary':
  82. case 'bin':
  83. $this->mode = FTP_BINARY;
  84. break;
  85. }
  86. }
  87. public function setPassive($passive)
  88. {
  89. $this->passive = (bool) $passive;
  90. }
  91. public function setClearFirst($clearFirst) {
  92. $this->clearFirst = (bool) $clearFirst;
  93. }
  94. function createFileSet() {
  95. $num = array_push($this->filesets, new FileSet());
  96. return $this->filesets[$num-1];
  97. }
  98. /**
  99. * The init method: check if Net_FTP is available
  100. */
  101. public function init() {
  102. require_once 'PEAR.php';
  103. $paths = explode(PATH_SEPARATOR, get_include_path());
  104. foreach($paths as $path) {
  105. if(file_exists($path.DIRECTORY_SEPARATOR.'Net'.DIRECTORY_SEPARATOR.'FTP.php')) {
  106. return true;
  107. }
  108. }
  109. throw new BuildException('The FTP Deploy task requires the Net_FTP PEAR package.');
  110. }
  111. /**
  112. * The main entry point method.
  113. */
  114. public function main() {
  115. $project = $this->getProject();
  116. require_once 'Net/FTP.php';
  117. $ftp = new Net_FTP($this->host, $this->port);
  118. $ret = $ftp->connect();
  119. if(@PEAR::isError($ret)) {
  120. throw new BuildException('Could not connect to FTP server '.$this->host.' on port '.$this->port.': '.$ret->getMessage());
  121. } else {
  122. $this->log('Connected to FTP server ' . $this->host . ' on port ' . $this->port, Project::MSG_VERBOSE);
  123. }
  124. $ret = $ftp->login($this->username, $this->password);
  125. if(@PEAR::isError($ret)) {
  126. throw new BuildException('Could not login to FTP server '.$this->host.' on port '.$this->port.' with username '.$this->username.': '.$ret->getMessage());
  127. } else {
  128. $this->log('Logged in to FTP server with username ' . $this->username, Project::MSG_VERBOSE);
  129. }
  130. if ($this->passive) {
  131. $this->log('Setting passive mode', Project::MSG_INFO);
  132. $ret = $ftp->setPassive();
  133. if(@PEAR::isError($ret)) {
  134. $ftp->disconnect();
  135. throw new BuildException('Could not set PASSIVE mode: '.$ret->getMessage());
  136. }
  137. }
  138. // append '/' to the end if necessary
  139. $dir = substr($this->dir, -1) == '/' ? $this->dir : $this->dir.'/';
  140. if($this->clearFirst) {
  141. // TODO change to a loop through all files and directories within current directory
  142. $this->log('Clearing directory '.$dir, Project::MSG_INFO);
  143. $ftp->rm($dir, true);
  144. }
  145. // Create directory just in case
  146. $ret = $ftp->mkdir($dir, true);
  147. if(@PEAR::isError($ret)) {
  148. $ftp->disconnect();
  149. throw new BuildException('Could not create directory '.$dir.': '.$ret->getMessage());
  150. }
  151. $ret = $ftp->cd($dir);
  152. if(@PEAR::isError($ret)) {
  153. $ftp->disconnect();
  154. throw new BuildException('Could not change to directory '.$dir.': '.$ret->getMessage());
  155. } else {
  156. $this->log('Changed directory ' . $dir, Project::MSG_VERBOSE);
  157. }
  158. $fs = FileSystem::getFileSystem();
  159. $convert = $fs->getSeparator() == '\\';
  160. foreach($this->filesets as $fs) {
  161. $ds = $fs->getDirectoryScanner($project);
  162. $fromDir = $fs->getDir($project);
  163. $srcFiles = $ds->getIncludedFiles();
  164. $srcDirs = $ds->getIncludedDirectories();
  165. foreach($srcDirs as $dirname) {
  166. if($convert)
  167. $dirname = str_replace('\\', '/', $dirname);
  168. $this->log('Will create directory '.$dirname, Project::MSG_VERBOSE);
  169. $ret = $ftp->mkdir($dirname, true);
  170. if(@PEAR::isError($ret)) {
  171. $ftp->disconnect();
  172. throw new BuildException('Could not create directory '.$dirname.': '.$ret->getMessage());
  173. }
  174. }
  175. foreach($srcFiles as $filename) {
  176. $file = new PhingFile($fromDir->getAbsolutePath(), $filename);
  177. if($convert)
  178. $filename = str_replace('\\', '/', $filename);
  179. $this->log('Will copy '.$file->getCanonicalPath().' to '.$filename, Project::MSG_VERBOSE);
  180. $ret = $ftp->put($file->getCanonicalPath(), $filename, true, $this->mode);
  181. if(@PEAR::isError($ret)) {
  182. $ftp->disconnect();
  183. throw new BuildException('Could not deploy file '.$filename.': '.$ret->getMessage());
  184. }
  185. }
  186. }
  187. $ftp->disconnect();
  188. $this->log('Disconnected from FTP server', Project::MSG_VERBOSE);
  189. }
  190. }
  191. ?>