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

/downloader/lib/Mage/System/Ftp.php

https://bitbucket.org/dnejedly/eaparts
PHP | 509 lines | 374 code | 16 blank | 119 comment | 21 complexity | 70b8962d018790f05840c84e66ec3587 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_System
  23. * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Class to work with remote FTP server
  28. *
  29. * @category Mage
  30. * @package Mage_System
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_System_Ftp
  34. {
  35. /**
  36. * Connection object
  37. *
  38. * @var resource
  39. */
  40. protected $_conn = false;
  41. /**
  42. * Check connected, throw exception if not
  43. *
  44. * @throws Exception
  45. * @return void
  46. */
  47. protected function checkConnected()
  48. {
  49. if(!$this->_conn) {
  50. throw new Exception(__CLASS__." - no connection established with server");
  51. }
  52. }
  53. /**
  54. * ftp_mkdir wrapper
  55. *
  56. * @param sting $name
  57. * @return unknown_type
  58. */
  59. public function mdkir($name)
  60. {
  61. $this->checkConnected();
  62. return @ftp_mkdir($this->_conn, $name);
  63. }
  64. /**
  65. * Make dir recursive
  66. *
  67. * @param string $path
  68. * @param int $mode
  69. * @return bool
  70. */
  71. public function mkdirRecursive($path, $mode = 0777)
  72. {
  73. $this->checkConnected();
  74. $dir = explode("/", $path);
  75. $path= "";
  76. $ret = true;
  77. for ($i=0; $i < count($dir); $i++) {
  78. $path .= "/" .$dir[$i];
  79. if(!@ftp_chdir($this->_conn, $path)) {
  80. @ftp_chdir($this->_conn,"/");
  81. if(!@ftp_mkdir($this->_conn,$path)) {
  82. $ret=false;
  83. break;
  84. } else {
  85. @ftp_chmod($this->_conn, $mode, $path);
  86. }
  87. }
  88. }
  89. return $ret;
  90. }
  91. /**
  92. * Try to login to server
  93. *
  94. * @param string $login
  95. * @param string $password
  96. * @throws Exception on invalid login credentials
  97. * @return bool
  98. */
  99. public function login($login = "anonymous", $password = "")
  100. {
  101. $this->checkConnected();
  102. $res = @ftp_login($this->_conn, $login, $password);
  103. if(!$res) {
  104. throw new Exception("Invalid login credentials");
  105. }
  106. return $res;
  107. }
  108. /**
  109. * Validate connection string
  110. *
  111. * @param string $string
  112. * @throws Exception
  113. * @return string
  114. */
  115. public function validateConnectionString($string)
  116. {
  117. $data = @parse_url($string);
  118. if(false === $data) {
  119. throw new Exception("Connection string invalid: '{$string}'");
  120. }
  121. if($data['scheme'] != 'ftp') {
  122. throw new Exception("Support for scheme unsupported: '{$data['scheme']}'");
  123. }
  124. return $data;
  125. }
  126. /**
  127. * Connect to server using connect string
  128. * Connection string: ftp://user:pass@server:port/path
  129. * user,pass,port,path are optional parts
  130. *
  131. * @param string $string
  132. * @param int $timeout
  133. */
  134. public function connect($string, $timeout = 900)
  135. {
  136. $params = $this->validateConnectionString($string);
  137. $port = isset($params['port']) ? intval($params['port']) : 21;
  138. $this->_conn = ftp_connect($params['host'], $port, $timeout);
  139. if(!$this->_conn) {
  140. throw new Exception("Cannot connect to host: {$params['host']}");
  141. }
  142. if(isset($params['user']) && isset($params['pass'])) {
  143. $this->login($params['user'], $params['pass']);
  144. } else {
  145. $this->login();
  146. }
  147. if(isset($params['path'])) {
  148. if(!$this->chdir($params['path'])) {
  149. throw new Exception ("Cannot chdir after login to: {$params['path']}");
  150. }
  151. }
  152. }
  153. /**
  154. * ftp_fput wrapper
  155. *
  156. * @param string $remoteFile
  157. * @param resource $handle
  158. * @param int $mode FTP_BINARY | FTP_ASCII
  159. * @param int $startPos
  160. * @return bool
  161. */
  162. public function fput($remoteFile, $handle, $mode = FTP_BINARY, $startPos = 0)
  163. {
  164. $this->checkConnected();
  165. return @ftp_fput($this->_conn, $remoteFile, $handle, $mode, $startPos);
  166. }
  167. /**
  168. * ftp_put wrapper
  169. *
  170. * @param string $remoteFile
  171. * @param string $localFile
  172. * @param int $mode FTP_BINARY | FTP_ASCII
  173. * @param int $startPos
  174. * @return bool
  175. */
  176. public function put($remoteFile, $localFile, $mode = FTP_BINARY, $startPos = 0)
  177. {
  178. $this->checkConnected();
  179. return ftp_put($this->_conn, $remoteFile, $localFile, $mode, $startPos);
  180. }
  181. /**
  182. * Get current working directory
  183. *
  184. * @return mixed
  185. */
  186. public function getcwd()
  187. {
  188. $d = $this->raw("pwd");
  189. $data = explode(" ", $d[0], 3);
  190. if(empty($data[1])) {
  191. return false;
  192. }
  193. if(intval($data[0]) != 257) {
  194. return false;
  195. }
  196. $out = trim($data[1], '"');
  197. if($out !== "/") {
  198. $out = rtrim($out, "/");
  199. }
  200. return $out;
  201. }
  202. /**
  203. * ftp_raw wrapper
  204. *
  205. * @param string $cmd
  206. * @return mixed
  207. */
  208. public function raw($cmd)
  209. {
  210. $this->checkConnected();
  211. return @ftp_raw($this->_conn, $cmd);
  212. }
  213. /**
  214. * Upload local file to remote
  215. *
  216. * Can be used for relative and absoulte remote paths
  217. * Relative: use chdir before calling this
  218. *
  219. * @param srting $remote
  220. * @param string $local
  221. * @param int $dirMode
  222. * @param int $ftpMode
  223. * @return unknown_type
  224. */
  225. public function upload($remote, $local, $dirMode = 0777, $ftpMode = FTP_BINARY)
  226. {
  227. $this->checkConnected();
  228. if(!file_exists($local)) {
  229. throw new Exception("Local file doesn't exist: {$localFile}");
  230. }
  231. if(!is_readable($local)) {
  232. throw new Exception("Local file is not readable: {$localFile}");
  233. }
  234. if(is_dir($local)) {
  235. throw new Exception("Directory given instead of file: {$localFile}");
  236. }
  237. $globalPathMode = substr($remote, 0, 1) == "/";
  238. $dirname = dirname($remote);
  239. $cwd = $this->getcwd();
  240. if(false === $cwd) {
  241. throw new Exception("Server returns something awful on PWD command");
  242. }
  243. if(!$globalPathMode) {
  244. $dirname = $cwd."/".$dirname;
  245. $remote = $cwd."/".$remote;
  246. }
  247. $res = $this->mkdirRecursive($dirname, $dirMode);
  248. $this->chdir($cwd);
  249. if(!$res) {
  250. return false;
  251. }
  252. return $this->put($remote, $local, $ftpMode);
  253. }
  254. /**
  255. * Download remote file to local machine
  256. *
  257. * @param string $remote
  258. * @param string $local
  259. * @param int $ftpMode FTP_BINARY|FTP_ASCII
  260. * @return bool
  261. */
  262. public function download($remote, $local, $ftpMode = FTP_BINARY)
  263. {
  264. $this->checkConnected();
  265. return $this->get($local, $remote, $ftpMode);
  266. }
  267. /**
  268. * ftp_pasv wrapper
  269. *
  270. * @param bool $pasv
  271. * @return bool
  272. */
  273. public function pasv($pasv)
  274. {
  275. $this->checkConnected();
  276. return @ftp_pasv($this->_conn, (bool) $pasv);
  277. }
  278. /**
  279. * Close FTP connection
  280. *
  281. * @return void
  282. */
  283. public function close()
  284. {
  285. if($this->_conn) {
  286. @ftp_close($this->_conn);
  287. }
  288. }
  289. /**
  290. * ftp_chmod wrapper
  291. *
  292. * @param $mode
  293. * @param $remoteFile
  294. * @return bool
  295. */
  296. public function chmod($mode, $remoteFile)
  297. {
  298. $this->checkConnected();
  299. return @ftp_chmod($this->_conn, $mode, $remoteFile);
  300. }
  301. /**
  302. * ftp_chdir wrapper
  303. *
  304. * @param string $dir
  305. * @return bool
  306. */
  307. public function chdir($dir)
  308. {
  309. $this->checkConnected();
  310. return @ftp_chdir($this->_conn, $dir);
  311. }
  312. /**
  313. * ftp_cdup wrapper
  314. *
  315. * @return bool
  316. */
  317. public function cdup()
  318. {
  319. $this->checkConnected();
  320. return @ftp_cdup($this->_conn);
  321. }
  322. /**
  323. * ftp_get wrapper
  324. *
  325. * @param string $localFile
  326. * @param string $remoteFile
  327. * @param int $fileMode FTP_BINARY | FTP_ASCII
  328. * @param int $resumeOffset
  329. * @return bool
  330. */
  331. public function get($localFile, $remoteFile, $fileMode = FTP_BINARY, $resumeOffset = 0)
  332. {
  333. $remoteFile = $this->correctFilePath($remoteFile);
  334. $this->checkConnected();
  335. return @ftp_get($this->_conn, $localFile, $remoteFile, $fileMode, $resumeOffset);
  336. }
  337. /**
  338. * ftp_nlist wrapper
  339. *
  340. * @param string $dir
  341. * @return bool
  342. */
  343. public function nlist($dir = "/")
  344. {
  345. $this->checkConnected();
  346. $dir = $this->correctFilePath($dir);
  347. return @ftp_nlist($this->_conn, $dir);
  348. }
  349. /**
  350. * ftp_rawlist wrapper
  351. *
  352. * @param string $dir
  353. * @param bool $recursive
  354. * @return mixed
  355. */
  356. public function rawlist( $dir = "/", $recursive = false )
  357. {
  358. $this->checkConnected();
  359. $dir = $this->correctFilePath($dir);
  360. return @ftp_rawlist($this->_conn, $dir, $recursive);
  361. }
  362. /**
  363. * Convert byte count to float KB/MB format
  364. *
  365. * @param int $bytes
  366. * @return string
  367. */
  368. public static function byteconvert($bytes)
  369. {
  370. $symbol = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
  371. $exp = floor( log($bytes) / log(1024) );
  372. return sprintf( '%.2f ' . $symbol[ $exp ], ($bytes / pow(1024, floor($exp))) );
  373. }
  374. /**
  375. * Chmod string "-rwxrwxrwx" to "777" converter
  376. *
  377. * @param string $chmod
  378. * @return string
  379. */
  380. public static function chmodnum($chmod)
  381. {
  382. $trans = array('-' => '0', 'r' => '4', 'w' => '2', 'x' => '1');
  383. $chmod = substr(strtr($chmod, $trans), 1);
  384. $array = str_split($chmod, 3);
  385. return array_sum(str_split($array[0])) . array_sum(str_split($array[1])) . array_sum(str_split($array[2]));
  386. }
  387. /**
  388. * Check whether file exists
  389. *
  390. * @param string $path
  391. * @param bool $excludeIfIsDir
  392. * @return bool
  393. */
  394. public function fileExists($path, $excludeIfIsDir = true)
  395. {
  396. $path = $this->correctFilePath($path);
  397. $globalPathMode = substr($path, 0, 1) == "/";
  398. $file = basename($path);
  399. $dir = $globalPathMode ? dirname($path) : $this->getcwd()."/".$path;
  400. $data = $this->ls($dir);
  401. foreach($data as $row) {
  402. if($file == $row['name']) {
  403. if($excludeIfIsDir && $row['dir']) {
  404. continue;
  405. }
  406. return true;
  407. }
  408. }
  409. return false;
  410. }
  411. /**
  412. * Get directory contents in PHP array
  413. *
  414. * @param string $dir
  415. * @param bool $recursive
  416. * @return array
  417. */
  418. public function ls($dir = "/", $recursive = false)
  419. {
  420. $dir= $this->correctFilePath($dir);
  421. $rawfiles = (array) $this->rawlist($dir, $recursive);
  422. $structure = array();
  423. $arraypointer = &$structure;
  424. foreach ($rawfiles as $rawfile) {
  425. if ($rawfile[0] == '/') {
  426. $paths = array_slice(explode('/', str_replace(':', '', $rawfile)), 1);
  427. $arraypointer = &$structure;
  428. foreach ($paths as $path) {
  429. foreach ($arraypointer as $i => $file) {
  430. if ($file['name'] == $path) {
  431. $arraypointer = &$arraypointer[ $i ]['children'];
  432. break;
  433. }
  434. }
  435. }
  436. } elseif(!empty($rawfile)) {
  437. $info = preg_split("/[\s]+/", $rawfile, 9);
  438. $arraypointer[] = array(
  439. 'name' => $info[8],
  440. 'dir' => $info[0]{0} == 'd',
  441. 'size' => (int) $info[4],
  442. 'chmod' => self::chmodnum($info[0]),
  443. 'rawdata' => $info,
  444. 'raw' => $rawfile
  445. );
  446. }
  447. }
  448. return $structure;
  449. }
  450. /**
  451. * Correct file path
  452. *
  453. * @param string $str
  454. * @return string
  455. */
  456. public function correctFilePath($str)
  457. {
  458. $str = str_replace("\\", "/", $str);
  459. $str = preg_replace("/^.\//", "", $str);
  460. return $str;
  461. }
  462. /**
  463. * Delete file
  464. *
  465. * @param string $file
  466. * @return bool
  467. */
  468. public function delete($file)
  469. {
  470. $this->checkConnected();
  471. $file = $this->correctFilePath($file);
  472. return @ftp_delete($this->_conn, $file);
  473. }
  474. }