PageRenderTime 25ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/ow_utilities/ftp.php

https://bitbucket.org/Noelfhim/no_ftp
PHP | 446 lines | 349 code | 48 blank | 49 comment | 21 complexity | 377e8d1d48b6e53d0e37d2ac7305ef20 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * EXHIBIT A. Common Public Attribution License Version 1.0
  4. * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the “License”);
  5. * you may not use this file except in compliance with the License. You may obtain a copy of the License at
  6. * http://www.oxwall.org/license. The License is based on the Mozilla Public License Version 1.1
  7. * but Sections 14 and 15 have been added to cover use of software over a computer network and provide for
  8. * limited attribution for the Original Developer. In addition, Exhibit A has been modified to be consistent
  9. * with Exhibit B. Software distributed under the License is distributed on an “AS IS” basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language
  11. * governing rights and limitations under the License. The Original Code is Oxwall software.
  12. * The Initial Developer of the Original Code is Oxwall Foundation (http://www.oxwall.org/foundation).
  13. * All portions of the code written by Oxwall Foundation are Copyright (c) 2011. All Rights Reserved.
  14. * EXHIBIT B. Attribution Information
  15. * Attribution Copyright Notice: Copyright 2011 Oxwall Foundation. All rights reserved.
  16. * Attribution Phrase (not exceeding 10 words): Powered by Oxwall community software
  17. * Attribution URL: http://www.oxwall.org/
  18. * Graphic Image as provided in the Covered Code.
  19. * Display of Attribution Information is required in Larger Works which are defined in the CPAL as a work
  20. * which combines Covered Code or portions thereof with code not governed by the terms of the CPAL.
  21. */
  22. /**
  23. * @author Sardar Madumarov <madumarov@gmail.com>
  24. * @package ow_utilities
  25. * @since 1.0
  26. */
  27. class UTIL_Ftp
  28. {
  29. /**
  30. * @var connection stream
  31. */
  32. private $stream;
  33. /**
  34. * @var connection timeout
  35. */
  36. private $timeout = 30;
  37. /**
  38. * @var boolean
  39. */
  40. private $loggedIn = false;
  41. /**
  42. * FTP root dir.
  43. *
  44. * @var <type>
  45. */
  46. private $ftpRootDir;
  47. /**
  48. * Constructor.
  49. *
  50. * @param array $options
  51. */
  52. private function __construct()
  53. {
  54. }
  55. public function init()
  56. {
  57. $dirRoot = OW_DIR_ROOT;
  58. if ( substr($dirRoot, 0, 1) === DS )
  59. {
  60. $dirRoot = substr($dirRoot, 1);
  61. }
  62. if ( substr($dirRoot, -1) === DS )
  63. {
  64. $dirRoot = substr($dirRoot, 0, -1);
  65. }
  66. $pathList = array($dirRoot);
  67. while ( true )
  68. {
  69. $dirRoot = substr($dirRoot, ( strpos($dirRoot, DS) + 1));
  70. $pathList[] = $dirRoot;
  71. if ( !strstr($dirRoot, DS) )
  72. {
  73. break;
  74. }
  75. }
  76. foreach ( $pathList as $path )
  77. {
  78. if ( $this->isFtpRootDir($path) )
  79. {
  80. $this->ftpRootDir = substr(OW_DIR_ROOT, 0, strpos(OW_DIR_ROOT, $path));
  81. break;
  82. }
  83. }
  84. if ( $this->ftpRootDir === null )
  85. {
  86. $this->ftpRootDir = OW_DIR_ROOT;
  87. }
  88. $this->chdir('/');
  89. }
  90. /**
  91. * @param array $params
  92. * @return UTIL_Ftp
  93. */
  94. public static function getConnection( array $params )
  95. {
  96. if ( empty($params['host']) )
  97. {
  98. throw new InvalidArgumentException('Empty host provided for connection');
  99. }
  100. $connection = new self();
  101. if ( !empty($params['timeout']) )
  102. {
  103. $connection->setTimeout((int) $params['timeout']);
  104. }
  105. $connected = $connection->connect(trim($params['host']), (!empty($params['port']) ? (int) $params['port'] : 21));
  106. if (!$connected)
  107. {
  108. throw new LogicException("Can't connect to host `" . trim($params['host']) . "` by FTP");
  109. }
  110. if ( !empty($params['login']) && !empty($params['password']) )
  111. {
  112. $connection->login(trim($params['login']), trim($params['password']));
  113. }
  114. $connection->init();
  115. return $connection;
  116. }
  117. private function isFtpRootDir( $path )
  118. {
  119. $this->chdir('/');
  120. $segments = array_filter(explode(DS, $path));
  121. foreach ( $segments as $segment )
  122. {
  123. if ( !@$this->chdir($segment) )
  124. {
  125. return false;
  126. }
  127. }
  128. return true;
  129. }
  130. /**
  131. * @return resource
  132. */
  133. public function getStream()
  134. {
  135. return $this->stream;
  136. }
  137. public function getTimeout()
  138. {
  139. return $this->timeout;
  140. }
  141. public function setTimeout( $timeout )
  142. {
  143. $this->timeout = (int) $timeout;
  144. }
  145. public function connect( $host, $port = 21 )
  146. {
  147. if ( is_resource($this->stream) )
  148. {
  149. return true;
  150. }
  151. $this->stream = ftp_connect($host, $port, $this->timeout);
  152. if ( $this->stream === false )
  153. {
  154. trigger_error("Can't connect to host `" . $host . "` by FTP", E_USER_WARNING);
  155. return false;
  156. }
  157. return true;
  158. }
  159. public function isConnected()
  160. {
  161. return is_resource($this->stream);
  162. }
  163. public function login( $username, $password )
  164. {
  165. if ( ftp_login($this->stream, $username, $password) )
  166. {
  167. $this->loggedIn = true;
  168. }
  169. }
  170. public function isLoggedIn()
  171. {
  172. return $this->loggedIn;
  173. }
  174. public function pwd()
  175. {
  176. return ftp_pwd($this->stream);
  177. }
  178. public function chdir( $path )
  179. {
  180. $path = $this->getPath($path);
  181. return ftp_chdir($this->stream, $path);
  182. }
  183. public function rename( $fromPath, $toPath )
  184. {
  185. $fromPath = $this->getPath($fromPath);
  186. $toPath = $this->getPath($toPath);
  187. return ftp_rename($this->stream, $fromPath, $toPath);
  188. }
  189. public function delete( $filePath )
  190. {
  191. $filePath = $this->getPath($filePath);
  192. return ftp_delete($this->stream, $filePath);
  193. }
  194. public function rmDir( $dirPath )
  195. {
  196. $dirPath = $this->getPath($dirPath);
  197. $dirPath = UTIL_File::removeLastDS($dirPath);
  198. $dirContent = $this->readDir($dirPath);
  199. foreach ( $dirContent as $dirItem )
  200. {
  201. if ( $dirItem['type'] === 'file' )
  202. {
  203. $this->delete($dirPath . DS . $dirItem['name']);
  204. }
  205. else
  206. {
  207. $this->rmDir($dirPath . DS . $dirItem['name']);
  208. }
  209. }
  210. ftp_rmdir($this->stream, $dirPath);
  211. }
  212. public function mkDir( $dirPath )
  213. {
  214. $dirPath = $this->getPath($dirPath);
  215. $result = ftp_mkdir($this->stream, $dirPath);
  216. if ( $result === false )
  217. {
  218. trigger_error("Can't create dir by FTP `" . $dirPath . "`", E_USER_WARNING);
  219. }
  220. }
  221. public function readDir( $dirPath, $type = 'all' )
  222. {
  223. $dirPath = $this->getPath($dirPath);
  224. if ( ftp_pasv($this->stream, true) === false )
  225. {
  226. trigger_error("Can't set passive mode for FTP connection", E_USER_WARNING);
  227. }
  228. $resultArray = array();
  229. $list = ftp_rawlist($this->stream, $dirPath);
  230. if ( $list === false )
  231. {
  232. trigger_error("Can't get dir contents `" . $dirPath . "`", E_USER_WARNING);
  233. return array();
  234. }
  235. if ( empty($list[0]) )
  236. {
  237. return $resultArray;
  238. }
  239. if ( strtolower(substr($list[0], 0, 6)) === 'total ' )
  240. {
  241. array_shift($list);
  242. if ( empty($list[0]) )
  243. {
  244. return $resultArray;
  245. }
  246. }
  247. switch ( strtolower(ftp_systype($this->stream)) )
  248. {
  249. case 'unix':
  250. $pattern = '/([-dl][rwxstST-]+).* ([0-9]*) ([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{1,2}:[0-9]{2})|[0-9]{4}) (.+)/';
  251. foreach ( $list as $item )
  252. {
  253. $tempRegs = array();
  254. $tempArray = null;
  255. if ( preg_match($pattern, $item, $tempRegs) )
  256. {
  257. $tempArray = array(
  258. 'type' => ( strpos("-dl", substr($tempRegs[1], 0, 1)) ? 'dir' : 'file' ),
  259. 'rights' => $tempRegs[1],
  260. 'user' => $tempRegs[3],
  261. 'group' => $tempRegs[4],
  262. 'size' => $tempRegs[5],
  263. 'date' => $tempRegs[6],
  264. 'time' => $tempRegs[7],
  265. 'name' => $tempRegs[9]
  266. );
  267. }
  268. if ( !empty($tempArray) && $tempArray['name'] !== '.' && $tempArray['name'] !== '..' && ( $type === 'all' || $type === $tempArray['type'] ) )
  269. {
  270. $resultArray[] = $tempArray;
  271. }
  272. }
  273. break;
  274. case 'mac':
  275. $pattern = '([-dl][rwxstST-]+).* ?([0-9 ]*)?([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{2}:[0-9]{2})|[0-9]{4}) (.+)';
  276. break;
  277. case 'win':
  278. $pattern = '([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)';
  279. break;
  280. }
  281. return $resultArray;
  282. }
  283. public function chmod( $mode, $filePath )
  284. {
  285. $filePath = $this->getPath($filePath);
  286. $result = ftp_chmod($this->stream, $mode, $filePath);
  287. if ( $result === false )
  288. {
  289. throw new LogicException("Can't chmod by FTP `" . $filePath . "`");
  290. }
  291. }
  292. public function upload( $localFile, $remoteFile )
  293. {
  294. $remoteFile = $this->getPath($remoteFile);
  295. if ( !ftp_put($this->stream, $remoteFile, $localFile, FTP_BINARY) )
  296. {
  297. trigger_error("Can't upload file by FTP `" . $localFile . "`", E_USER_WARNING);
  298. }
  299. }
  300. /**
  301. * Uploads LOCAL DIR CONTENTS to remote dir.
  302. *
  303. * @param string $localDir
  304. * @param string $remoteDir
  305. */
  306. public function uploadDir( $localDir, $remoteDir )
  307. {
  308. $remoteDir = $this->getPath($remoteDir);
  309. if ( !file_exists($localDir) )
  310. {
  311. trigger_error("Can't read dir `" . $localDir . "`!", E_USER_WARNING);
  312. return;
  313. }
  314. if ( !file_exists($remoteDir) )
  315. {
  316. $this->mkDir($remoteDir);
  317. }
  318. $handle = opendir($localDir);
  319. while ( ($item = readdir($handle)) !== false )
  320. {
  321. if ( $item === '.' || $item === '..' )
  322. {
  323. continue;
  324. }
  325. $localPath = $localDir . DS . $item;
  326. $remotePath = $remoteDir . DS . $item;
  327. if ( is_file($localPath) )
  328. {
  329. $this->upload($localPath, $remotePath);
  330. }
  331. else
  332. {
  333. $this->uploadDir($localPath, $remotePath);
  334. }
  335. }
  336. closedir($handle);
  337. }
  338. public function download( $remoteFile, $localFile )
  339. {
  340. $remoteFile = $this->getPath($remoteFile);
  341. if ( ftp_get($this->stream, $localFile, $remoteFile, FTP_BINARY) )
  342. {
  343. throw new LogicException("Can't download file by FTP `" . $remoteFile . "`");
  344. }
  345. }
  346. public function __destruct()
  347. {
  348. ftp_close($this->stream);
  349. }
  350. private function getPath( $path )
  351. {
  352. if ( $this->ftpRootDir === null )
  353. {
  354. return $path;
  355. }
  356. if ( strpos($path, $this->ftpRootDir) !== 0 )
  357. {
  358. return $path;
  359. }
  360. $path = substr($path, strlen($this->ftpRootDir));
  361. return $path;
  362. }
  363. }