PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/magento/framework/System/Ftp.php

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