Файл: tools/ftp.php
Строк: 223
<?php
class UTIL_Ftp
{
const ERROR_FTP_FUNCTION_IS_NOT_AVAILABLE = 'error_ftp_function_is_not_available';
const ERROR_EMPTY_HOST_PROVIDED = 'error_empty_host_provided';
const ERROR_CANT_CONNECT_TO_HOST = 'error_cant_connect_to_host';
const ERROR_EMPTY_CREDENTIALS_PROVIDED = 'error_empty_credentials_provided';
const ERROR_INVALID_CREDENTIALS_PROVIDED = 'error_invalid_credentials_provided';
/**
* @var connection stream
*/
private $stream;
/**
* @var connection timeout
*/
private $timeout = 30;
/**
* @var boolean
*/
private $loggedIn = false;
/**
* FTP root dir.
*
* @var string
*/
private $ftpRootDir;
/**
* Constructor.
*
* @param array $options
*/
private function __construct()
{
}
public function init()
{
$dirRoot = PEEP_DIR_ROOT;
if ( substr($dirRoot, 0, 1) === DS )
{
$dirRoot = substr($dirRoot, 1);
}
if ( substr($dirRoot, -1) === DS )
{
$dirRoot = substr($dirRoot, 0, -1);
}
$pathList = array($dirRoot);
while ( true )
{
$dirRoot = substr($dirRoot, ( strpos($dirRoot, DS) + 1));
$pathList[] = $dirRoot;
if ( !strstr($dirRoot, DS) )
{
break;
}
}
foreach ( $pathList as $path )
{
if ( $this->isFtpRootDir($path) )
{
$this->ftpRootDir = substr(PEEP_DIR_ROOT, 0, strpos(PEEP_DIR_ROOT, $path));
break;
}
}
if ( $this->ftpRootDir === null )
{
$this->ftpRootDir = PEEP_DIR_ROOT;
}
$this->chdir('/');
$dirname = "temp" . rand(1, 1000000);
if ( ftp_mkdir($this->stream, $dirname) )
{
// hotfix, doesn't work with win servers
$rootPath = "";
$dirRootPathArr = array_filter(explode(DS, PEEP_DIR_ROOT));
array_unshift($dirRootPathArr, "");
foreach ( $dirRootPathArr as $pathItem )
{
$rootPath .= $pathItem . DS;
if ( file_exists($rootPath . $dirname) )
{
$this->ftpRootDir = $rootPath;
ftp_rmdir($this->stream, $dirname);
return;
}
}
}
}
/**
* @param array $params
* @return UTIL_Ftp
*/
public static function getConnection( array $params )
{
if ( !function_exists('ftp_connect') )
{
throw new LogicException(self::ERROR_FTP_FUNCTION_IS_NOT_AVAILABLE);
}
if ( empty($params['host']) )
{
throw new InvalidArgumentException(self::ERROR_EMPTY_HOST_PROVIDED);
}
if ( empty($params['login']) || empty($params['password']) )
{
throw new InvalidArgumentException(self::ERROR_EMPTY_CREDENTIALS_PROVIDED);
}
$connection = new self();
if ( !empty($params['timeout']) )
{
$connection->setTimeout((int) $params['timeout']);
}
if ( !$connection->connect(trim($params['host']), (!empty($params['port']) ? (int) $params['port'] : 21)) )
{
throw new LogicException(self::ERROR_CANT_CONNECT_TO_HOST);
}
if ( !$connection->login(trim($params['login']), trim($params['password'])) )
{
throw new LogicException(self::ERROR_INVALID_CREDENTIALS_PROVIDED);
}
$connection->init();
return $connection;
}
private function isFtpRootDir( $path )
{
$this->chdir('/');
$segments = array_filter(explode(DS, $path));
foreach ( $segments as $segment )
{
if ( !@$this->chdir($segment) )
{
return false;
}
}
return true;
}
/**
* @return resource
*/
public function getStream()
{
return $this->stream;
}
public function getTimeout()
{
return $this->timeout;
}
public function setTimeout( $timeout )
{
$this->timeout = (int) $timeout;
}
public function connect( $host, $port = 21 )
{
if ( is_resource($this->stream) )
{
return true;
}
$this->stream = ftp_connect($host, $port, $this->timeout);
return (!empty($this->stream) && is_resource($this->stream));
}
public function isConnected()
{
return is_resource($this->stream);
}
public function login( $username, $password )
{
if ( ftp_login($this->stream, $username, $password) )
{
$this->loggedIn = true;
}
return $this->loggedIn;
}
public function isLoggedIn()
{
return $this->loggedIn;
}
public function pwd()
{
return ftp_pwd($this->stream);
}
public function chdir( $path )
{
$path = $this->getPath($path);
return ftp_chdir($this->stream, $path);
}
public function rename( $fromPath, $toPath )
{
$fromPath = $this->getPath($fromPath);
$toPath = $this->getPath($toPath);
return ftp_rename($this->stream, $fromPath, $toPath);
}
public function delete( $filePath )
{
$filePath = $this->getPath($filePath);
return ftp_delete($this->stream, $filePath);
}
public function rmDir( $dirPath )
{
$dirPath = $this->getPath($dirPath);
$dirPath = UTIL_File::removeLastDS($dirPath);
$dirContent = $this->readDir($dirPath);
foreach ( $dirContent as $dirItem )
{
if ( $dirItem['type'] === 'file' )
{
$this->delete($dirPath . DS . $dirItem['name']);
}
else
{
$this->rmDir($dirPath . DS . $dirItem['name']);
}
}
ftp_rmdir($this->stream, $dirPath);
}
public function mkDir( $dirPath )
{
$dirPath = $this->getPath($dirPath);
$result = ftp_mkdir($this->stream, $dirPath);
if ( $result === false )
{
trigger_error("Can't create dir by FTP `" . $dirPath . "`", E_USER_WARNING);
}
}
public function readDir( $dirPath, $type = 'all' )
{
$dirPath = $this->getPath($dirPath);
if ( ftp_pasv($this->stream, true) === false )
{
trigger_error("Can't set passive mode for FTP connection", E_USER_WARNING);
}
$resultArray = array();
$list = ftp_rawlist($this->stream, $dirPath);
if ( $list === false )
{
trigger_error("Can't get dir contents `" . $dirPath . "`", E_USER_WARNING);
return array();
}
if ( empty($list[0]) )
{
return $resultArray;
}
if ( strtolower(substr($list[0], 0, 6)) === 'total ' )
{
array_shift($list);
if ( empty($list[0]) )
{
return $resultArray;
}
}
switch ( strtolower(ftp_systype($this->stream)) )
{
case 'unix':
$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}) (.+)/';
foreach ( $list as $item )
{
$tempRegs = array();
$tempArray = null;
if ( preg_match($pattern, $item, $tempRegs) )
{
$tempArray = array(
'type' => ( strpos("-dl", substr($tempRegs[1], 0, 1)) ? 'dir' : 'file' ),
'rights' => $tempRegs[1],
'user' => $tempRegs[3],
'group' => $tempRegs[4],
'size' => $tempRegs[5],
'date' => $tempRegs[6],
'time' => $tempRegs[7],
'name' => $tempRegs[9]
);
}
if ( !empty($tempArray) && $tempArray['name'] !== '.' && $tempArray['name'] !== '..' && ( $type === 'all' || $type === $tempArray['type'] ) )
{
$resultArray[] = $tempArray;
}
}
break;
case 'mac':
$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}) (.+)';
break;
case 'win':
$pattern = '([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)';
break;
}
return $resultArray;
}
public function chmod( $mode, $filePath )
{
$filePath = $this->getPath($filePath);
$result = ftp_chmod($this->stream, $mode, $filePath);
if ( $result === false )
{
throw new LogicException("Can't chmod by FTP `" . $filePath . "`");
}
}
public function upload( $localFile, $remoteFile )
{
$remoteFile = $this->getPath($remoteFile);
if ( !ftp_put($this->stream, $remoteFile, $localFile, FTP_BINARY) )
{
trigger_error("Can't upload file by FTP `" . $localFile . "`", E_USER_WARNING);
}
}
/**
* Uploads LOCAL DIR CONTENTS to remote dir.
*
* @param string $localDir
* @param string $remoteDir
*/
public function uploadDir( $localDir, $remoteDir )
{
$remoteDir = $this->getPath($remoteDir);
if ( !file_exists($localDir) )
{
trigger_error("Can't read dir `" . $localDir . "`!", E_USER_WARNING);
return;
}
if ( !file_exists($remoteDir) )
{
$this->mkDir($remoteDir);
}
$handle = opendir($localDir);
while ( ($item = readdir($handle)) !== false )
{
if ( $item === '.' || $item === '..' )
{
continue;
}
$localPath = $localDir . DS . $item;
$remotePath = $remoteDir . DS . $item;
if ( is_file($localPath) )
{
$this->upload($localPath, $remotePath);
}
else
{
$this->uploadDir($localPath, $remotePath);
}
}
closedir($handle);
}
public function download( $remoteFile, $localFile )
{
$remoteFile = $this->getPath($remoteFile);
if ( ftp_get($this->stream, $localFile, $remoteFile, FTP_BINARY) )
{
throw new LogicException("Can't download file by FTP `" . $remoteFile . "`");
}
}
public function __destruct()
{
ftp_close($this->stream);
}
private function getPath( $path )
{
if ( $this->ftpRootDir === null )
{
return $path;
}
if ( strpos($path, $this->ftpRootDir) !== 0 )
{
return $path;
}
$path = substr($path, strlen($this->ftpRootDir));
return $path;
}
}