_conn) {
throw new \Exception(__CLASS__ . " - no connection established with server");
}
}
/**
* ftp_mkdir wrapper
*
* @param string $name
* @return string the newly created directory name on success or FALSE on error.
*/
public function mdkir($name)
{
$this->checkConnected();
return @ftp_mkdir($this->_conn, $name);
}
/**
* Make dir recursive
*
* @param string $path
* @param int $mode
* @return bool
*/
public function mkdirRecursive($path, $mode = 0777)
{
$this->checkConnected();
$dir = explode("/", $path);
$path = "";
$ret = true;
for ($i = 0; $i < count($dir); $i++) {
$path .= "/" . $dir[$i];
if (!@ftp_chdir($this->_conn, $path)) {
@ftp_chdir($this->_conn, "/");
if (!@ftp_mkdir($this->_conn, $path)) {
$ret = false;
break;
} else {
@ftp_chmod($this->_conn, $mode, $path);
}
}
}
return $ret;
}
/**
* Try to login to server
*
* @param string $login
* @param string $password
* @return bool
* @throws \Exception on invalid login credentials
*/
public function login($login = "anonymous", $password = "test@gmail.com")
{
$this->checkConnected();
$res = @ftp_login($this->_conn, $login, $password);
if (!$res) {
throw new \Exception("Invalid login credentials");
}
return $res;
}
/**
* Validate connection string
*
* @param string $string
* @throws \Exception
* @return string
*/
public function validateConnectionString($string)
{
$data = parse_url($string);
if (false === $data) {
throw new \Exception("Connection string invalid: '{$string}'");
}
if ($data['scheme'] != 'ftp') {
throw new \Exception("Support for scheme unsupported: '{$data['scheme']}'");
}
return $data;
}
/**
* Connect to server using connect string
* Connection string: ftp://user:pass@server:port/path
* user,pass,port,path are optional parts
*
* @param string $string
* @param int $timeout
* @return void
* @throws \Exception
*/
public function connect($string, $timeout = 900)
{
$params = $this->validateConnectionString($string);
$port = isset($params['port']) ? intval($params['port']) : 21;
$this->_conn = ftp_connect($params['host'], $port, $timeout);
if (!$this->_conn) {
throw new \Exception("Cannot connect to host: {$params['host']}");
}
if (isset($params['user']) && isset($params['pass'])) {
$this->login($params['user'], $params['pass']);
} else {
$this->login();
}
if (isset($params['path'])) {
if (!$this->chdir($params['path'])) {
throw new \Exception("Cannot chdir after login to: {$params['path']}");
}
}
}
/**
* ftp_fput wrapper
*
* @param string $remoteFile
* @param resource $handle
* @param int $mode FTP_BINARY | FTP_ASCII
* @param int $startPos
* @return bool
*/
public function fput($remoteFile, $handle, $mode = FTP_BINARY, $startPos = 0)
{
$this->checkConnected();
return @ftp_fput($this->_conn, $remoteFile, $handle, $mode, $startPos);
}
/**
* ftp_put wrapper
*
* @param string $remoteFile
* @param string $localFile
* @param int $mode FTP_BINARY | FTP_ASCII
* @param int $startPos
* @return bool
*/
public function put($remoteFile, $localFile, $mode = FTP_BINARY, $startPos = 0)
{
$this->checkConnected();
return ftp_put($this->_conn, $remoteFile, $localFile, $mode, $startPos);
}
/**
* Get current working directory
*
* @return false|string
*/
public function getcwd()
{
$d = $this->raw("pwd");
$data = explode(" ", $d[0], 3);
if (empty($data[1])) {
return false;
}
if (intval($data[0]) != 257) {
return false;
}
$out = trim($data[1], '"');
if ($out !== "/") {
$out = rtrim($out, "/");
}
return $out;
}
/**
* ftp_raw wrapper
*
* @param string $cmd
* @return array The server's response as an array of strings.
*/
public function raw($cmd)
{
$this->checkConnected();
return @ftp_raw($this->_conn, $cmd);
}
/**
* Upload local file to remote
*
* Can be used for relative and absoulte remote paths
* Relative: use chdir before calling this
*
* @param string $remote
* @param string $local
* @param int $dirMode
* @param int $ftpMode
* @return bool
* @throws \Exception
*/
public function upload($remote, $local, $dirMode = 0777, $ftpMode = FTP_BINARY)
{
$this->checkConnected();
if (!file_exists($local)) {
throw new \Exception("Local file doesn't exist: {$local}");
}
if (!is_readable($local)) {
throw new \Exception("Local file is not readable: {$local}");
}
if (is_dir($local)) {
throw new \Exception("Directory given instead of file: {$local}");
}
$globalPathMode = substr($remote, 0, 1) == "/";
$dirname = dirname($remote);
$cwd = $this->getcwd();
if (false === $cwd) {
throw new \Exception("Server returns something awful on PWD command");
}
if (!$globalPathMode) {
$dirname = $cwd . "/" . $dirname;
$remote = $cwd . "/" . $remote;
}
$res = $this->mkdirRecursive($dirname, $dirMode);
$this->chdir($cwd);
if (!$res) {
return false;
}
return $this->put($remote, $local, $ftpMode);
}
/**
* Download remote file to local machine
*
* @param string $remote
* @param string $local
* @param int $ftpMode FTP_BINARY|FTP_ASCII
* @return bool
*/
public function download($remote, $local, $ftpMode = FTP_BINARY)
{
$this->checkConnected();
return $this->get($local, $remote, $ftpMode);
}
/**
* ftp_pasv wrapper
*
* @param bool $pasv
* @return bool
*/
public function pasv($pasv)
{
$this->checkConnected();
return @ftp_pasv($this->_conn, (bool)$pasv);
}
/**
* Close FTP connection
*
* @return void
*/
public function close()
{
if ($this->_conn) {
@ftp_close($this->_conn);
}
}
/**
* ftp_chmod wrapper
*
* @param int $mode
* @param string $remoteFile
* @return int The new file permissions on success or FALSE on error.
*/
public function chmod($mode, $remoteFile)
{
$this->checkConnected();
return @ftp_chmod($this->_conn, $mode, $remoteFile);
}
/**
* ftp_chdir wrapper
*
* @param string $dir
* @return bool
*/
public function chdir($dir)
{
$this->checkConnected();
return @ftp_chdir($this->_conn, $dir);
}
/**
* ftp_cdup wrapper
*
* @return bool
*/
public function cdup()
{
$this->checkConnected();
return @ftp_cdup($this->_conn);
}
/**
* ftp_get wrapper
*
* @param string $localFile
* @param string $remoteFile
* @param int $fileMode FTP_BINARY | FTP_ASCII
* @param int $resumeOffset
* @return bool
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
*/
public function get($localFile, $remoteFile, $fileMode = FTP_BINARY, $resumeOffset = 0)
{
$remoteFile = $this->correctFilePath($remoteFile);
$this->checkConnected();
return @ftp_get($this->_conn, $localFile, $remoteFile, $fileMode, $resumeOffset);
}
/**
* ftp_nlist wrapper
*
* @param string $dir
* @return bool
*/
public function nlist($dir = "/")
{
$this->checkConnected();
$dir = $this->correctFilePath($dir);
return @ftp_nlist($this->_conn, $dir);
}
/**
* ftp_rawlist wrapper
*
* @param string $dir
* @param bool $recursive
* @return array an array where each element corresponds to one line of text.
*/
public function rawlist($dir = "/", $recursive = false)
{
$this->checkConnected();
$dir = $this->correctFilePath($dir);
return @ftp_rawlist($this->_conn, $dir, $recursive);
}
/**
* Convert byte count to float KB/MB format
*
* @param int $bytes
* @return string
*/
public static function byteconvert($bytes)
{
$symbol = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
$exp = floor(log($bytes) / log(1024));
return sprintf('%.2f ' . $symbol[$exp], $bytes / pow(1024, floor($exp)));
}
/**
* Chmod string "-rwxrwxrwx" to "777" converter
*
* @param string $chmod
* @return string
*/
public static function chmodnum($chmod)
{
$trans = ['-' => '0', 'r' => '4', 'w' => '2', 'x' => '1'];
$chmod = substr(strtr($chmod, $trans), 1);
$array = str_split($chmod, 3);
return array_sum(str_split($array[0])) . array_sum(str_split($array[1])) . array_sum(str_split($array[2]));
}
/**
* Check whether file exists
*
* @param string $path
* @param bool $excludeIfIsDir
* @return bool
*/
public function fileExists($path, $excludeIfIsDir = true)
{
$path = $this->correctFilePath($path);
$globalPathMode = substr($path, 0, 1) == "/";
$file = basename($path);
$dir = $globalPathMode ? dirname($path) : $this->getcwd() . "/" . $path;
$data = $this->ls($dir);
foreach ($data as $row) {
if ($file == $row['name']) {
if ($excludeIfIsDir && $row['dir']) {
continue;
}
return true;
}
}
return false;
}
/**
* Get directory contents in PHP array
*
* @param string $dir
* @param bool $recursive
* @return array
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
public function ls($dir = "/", $recursive = false)
{
$dir = $this->correctFilePath($dir);
$rawfiles = (array)$this->rawlist($dir, $recursive);
$structure = [];
$arraypointer = & $structure;
foreach ($rawfiles as $rawfile) {
if ($rawfile[0] == '/') {
$paths = array_slice(explode('/', str_replace(':', '', $rawfile)), 1);
$arraypointer = & $structure;
foreach ($paths as $path) {
foreach ($arraypointer as $i => $file) {
if ($file['name'] == $path) {
$arraypointer = & $arraypointer[$i]['children'];
break;
}
}
}
} elseif (!empty($rawfile)) {
$info = preg_split("/[\s]+/", $rawfile, 9);
$arraypointer[] = [
'name' => $info[8],
'dir' => $info[0][0] == 'd',
'size' => (int)$info[4],
'chmod' => self::chmodnum($info[0]),
'rawdata' => $info,
'raw' => $rawfile,
];
}
}
return $structure;
}
/**
* Correct file path
*
* @param string $str
* @return string
*/
public function correctFilePath($str)
{
$str = str_replace("\\", "/", $str);
$str = preg_replace("/^.\//", "", $str);
return $str;
}
/**
* Delete file
*
* @param string $file
* @return bool
*/
public function delete($file)
{
$this->checkConnected();
$file = $this->correctFilePath($file);
return @ftp_delete($this->_conn, $file);
}
}