├── tests ├── file │ └── test.txt ├── bootstrap.php ├── Sftp │ ├── ServerExceptionTest.php │ ├── AbstractTest.php │ ├── FileExceptionTest.php │ ├── DirectoryTest.php │ └── FileTest.php └── Ftp │ ├── AbstractTest.php │ ├── ServerExceptionTest.php │ ├── FileExceptionTest.php │ ├── DirectoryTest.php │ └── FileTest.php ├── .gitignore ├── .travis.yml ├── src ├── Exceptions │ ├── FileException.php │ ├── DirectoryException.php │ ├── ConnectionFailedException.php │ ├── ExtensionMissingException.php │ └── AuthenticationFailedException.php ├── Interfaces │ ├── FactoryInterface.php │ ├── ServerInterface.php │ ├── DirectoryInterface.php │ ├── ExceptionInterface.php │ ├── FileInterface.php │ └── FileDirectoryInterface.php ├── Servers │ ├── SslServer.php │ ├── AnonymousServer.php │ ├── SftpServer.php │ └── FtpServer.php ├── FtpTrait.php ├── FileFactory.php ├── DirectoryFactory.php ├── Abstracts │ ├── AbstractFtpException.php │ ├── AbstractFtp.php │ └── AbstractSftp.php ├── Helper │ └── Helper.php ├── Directories │ ├── SftpDirectory.php │ └── FtpDirectory.php └── Files │ ├── FtpFile.php │ └── SftpFile.php ├── phpunit.xml.dist ├── composer.json ├── LICENSE └── README.md /tests/file/test.txt: -------------------------------------------------------------------------------- 1 | demo file for test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ide 2 | nbproject 3 | # Composer 4 | vendor 5 | composer.lock 6 | # Test 7 | phpunit.xml 8 | # Php files 9 | example.php -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | 8 | before_script: 9 | - composer install --dev -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Exceptions 18 | */ 19 | class FileException extends AbstractFtpException 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Exceptions/DirectoryException.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Exceptions 18 | */ 19 | class DirectoryException extends AbstractFtpException 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Exceptions/ConnectionFailedException.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Exceptions 18 | */ 19 | class ConnectionFailedException extends AbstractFtpException 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Exceptions/ExtensionMissingException.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Exceptions 18 | */ 19 | class ExtensionMissingException extends AbstractFtpException 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Exceptions/AuthenticationFailedException.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Exceptions 18 | */ 19 | class AuthenticationFailedException extends AbstractFtpException 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /tests/Sftp/ServerExceptionTest.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ServerExceptionTest extends \PHPUnit_Framework_TestCase { 12 | 13 | /** 14 | * @expectedException \altayalp\FtpClient\Exceptions\ConnectionFailedException 15 | */ 16 | public function testConnectException() { 17 | @$server = new \altayalp\FtpClient\Servers\SftpServer('xx.xx.com'); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/Interfaces/FactoryInterface.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Interfaces 16 | */ 17 | interface FactoryInterface 18 | { 19 | 20 | /** 21 | * Create and return instance class 22 | */ 23 | public static function build(ServerInterface $server); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | ./tests/ 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "altayalp/ftp-client", 3 | "type": "library", 4 | "description": "FTP and SFTP client for Php", 5 | "keywords": ["ftp","php ftp","sftp","ssh ftp","ssh","ftp client"], 6 | "homepage": "https://github.com/altayalp/php-ftp-client", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "İzzet Ögetürk", 11 | "email": "altayalp@gmail.com", 12 | "homepage": "http://altayalp.com", 13 | "role": "Developer" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.4.0", 18 | "ext-ftp": "*" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "~4.8" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "altayalp\\FtpClient\\": "src/" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Sftp/AbstractTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | abstract class AbstractTest extends \PHPUnit_Framework_TestCase { 15 | 16 | protected static $session; 17 | 18 | 19 | public static function setUpBeforeClass() 20 | { 21 | $server = new SftpServer(getenv('FTP_HOST')); 22 | $server->login(getenv('FTP_USER'), getenv('FTP_PASS')); 23 | self::$session = $server; 24 | } 25 | 26 | /** 27 | * @return Connection 28 | */ 29 | protected static function getSession() 30 | { 31 | return self::$session; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/Ftp/AbstractTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | 14 | abstract class AbstractTest extends \PHPUnit_Framework_TestCase { 15 | 16 | protected static $session; 17 | 18 | 19 | public static function setUpBeforeClass() 20 | { 21 | $server = new FtpServer( getenv('FTP_HOST') ); 22 | $server->login(getenv('FTP_USER'), getenv('FTP_PASS')); 23 | $server->enablePassive(); 24 | self::$session = $server; 25 | } 26 | 27 | /** 28 | * @return Connection 29 | */ 30 | protected static function getSession() 31 | { 32 | return self::$session; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Servers/SslServer.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Servers 18 | */ 19 | class SslServer extends FtpServer 20 | { 21 | 22 | /** 23 | * {@inheritDoc} 24 | */ 25 | public function connect() 26 | { 27 | if (! $session = ftp_ssl_connect($this->server, $this->port, $this->timeout)) { 28 | throw new ConnectionFailedException('Could not connect to the ssl server'); 29 | } 30 | $this->setSession($session); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/Ftp/ServerExceptionTest.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ServerExceptionTest extends \PHPUnit_Framework_TestCase { 12 | 13 | /** 14 | * @expectedException \altayalp\FtpClient\Exceptions\ConnectionFailedException 15 | */ 16 | public function testConnectException() { 17 | @$server = new \altayalp\FtpClient\Servers\FtpServer('xx.xx.com'); 18 | } 19 | 20 | /** 21 | * @expectedException \altayalp\FtpClient\Exceptions\AuthenticationFailedException 22 | */ 23 | public function testAuthException() { 24 | $server = new \altayalp\FtpClient\Servers\FtpServer('ftp.linux.org.tr'); 25 | @$server->login('xxx','yyy'); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/Servers/AnonymousServer.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Servers 16 | */ 17 | class AnonymousServer extends FtpServer 18 | { 19 | /** 20 | * Constructor method 21 | * 22 | * @param String $server connect server address 23 | * @param integer $port connect server port 24 | * @param integer $timeOut server time out 25 | */ 26 | public function __construct($server, $port = 21, $timeOut = 90) 27 | { 28 | parent::__construct($server, $port, $timeOut); 29 | $this->connect(); 30 | $this->login('Anonymous', ''); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/FtpTrait.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | */ 16 | trait FtpTrait 17 | { 18 | /** 19 | * Ignore item to itemList 20 | * 21 | * @access private 22 | * @param string $type Type of item 23 | * @param string $name Name of item 24 | * @param array $ignore Names or extension item for ignore 25 | * @return boolean 26 | */ 27 | private function ignoreItem($type, $name, $ignore) 28 | { 29 | if ($type == 'file' && in_array(pathinfo($name, PATHINFO_EXTENSION), $ignore)) { 30 | return true; 31 | } elseif ($type == 'dir' && in_array($name, $ignore)) { 32 | return true; 33 | } 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 İzzet Ögetürk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Interfaces/ServerInterface.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Interfaces 16 | */ 17 | interface ServerInterface 18 | { 19 | 20 | /** 21 | * Connect to server 22 | * 23 | * @access public 24 | * @throws ConnectionFailedException 25 | */ 26 | public function connect(); 27 | 28 | /** 29 | * Log in to server 30 | * 31 | * @access public 32 | * @param string $userName user name 33 | * @param string $password password 34 | * @throws AuthenticationFailedException 35 | * 36 | */ 37 | public function login($userName, $password); 38 | 39 | /** 40 | * Get connection session 41 | * 42 | * @access public 43 | * @return resurce Connection session 44 | */ 45 | public function getSession(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/Ftp/FileExceptionTest.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class FileExceptionTest extends AbstractTest 20 | { 21 | 22 | protected static $file; 23 | 24 | public static function setUpBeforeClass() 25 | { 26 | parent::setUpBeforeClass(); 27 | self::$file = new FtpFile(self::getSession()); 28 | } 29 | 30 | /** 31 | * @expectedException \altayalp\FtpClient\Exceptions\FileException 32 | */ 33 | public function testUpload() 34 | { 35 | @self::$file->upload('noFile.file',''); 36 | } 37 | 38 | /** 39 | * @expectedException \altayalp\FtpClient\Exceptions\FileException 40 | */ 41 | public function testRm() 42 | { 43 | @self::$file->rm('noFile.file'); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tests/Sftp/FileExceptionTest.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class FileExceptionTest extends AbstractTest 20 | { 21 | 22 | protected static $file; 23 | 24 | public static function setUpBeforeClass() 25 | { 26 | parent::setUpBeforeClass(); 27 | self::$file = new SftpFile(self::getSession()); 28 | } 29 | 30 | /** 31 | * @expectedException \altayalp\FtpClient\Exceptions\FileException 32 | */ 33 | public function testUpload() 34 | { 35 | @self::$file->upload('noFile.file',''); 36 | } 37 | 38 | /** 39 | * @expectedException \altayalp\FtpClient\Exceptions\FileException 40 | */ 41 | public function testRm() 42 | { 43 | @self::$file->rm('noFile.file'); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/FileFactory.php: -------------------------------------------------------------------------------- 1 | 21 | * @package FtpClient 22 | */ 23 | class FileFactory implements FactoryInterface 24 | { 25 | 26 | /** 27 | * Build method for File classes 28 | */ 29 | public static function build(ServerInterface $server) 30 | { 31 | if ($server instanceof SftpServer) { 32 | return new SftpFile($server); 33 | } elseif ($server instanceof FtpServer || $server instanceof SslServer) { 34 | return new FtpFile($server); 35 | } else { 36 | throw new \InvalidArgumentException('The argument is must instance of server class'); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/DirectoryFactory.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Interfaces 16 | */ 17 | interface DirectoryInterface extends FileDirectoryInterface 18 | { 19 | 20 | /** 21 | * Change working directory to server 22 | * 23 | * @access public 24 | * @param string $dir directory name to switch 25 | * @return boolean true if success 26 | * @throws DirectoryException 27 | */ 28 | public function cd($dir); 29 | 30 | /** 31 | * Make new directory to ftp server 32 | * 33 | * @access public 34 | * @param string $dir directory name to create 35 | * @return boolean true if success 36 | * @throws DirectoryException 37 | */ 38 | public function mkdir($dir); 39 | 40 | /** 41 | * Get current working directory 42 | * 43 | * @access public 44 | * @return string current working directory 45 | */ 46 | public function pwd(); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/Interfaces/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Interfaces 16 | */ 17 | interface ExceptionInterface 18 | { 19 | /** 20 | * Exception message 21 | */ 22 | public function getMessage(); 23 | 24 | /** 25 | * User defined Exception code 26 | */ 27 | public function getCode(); 28 | 29 | /** 30 | * Source filename 31 | */ 32 | public function getFile(); 33 | 34 | /** 35 | * Source line 36 | */ 37 | public function getLine(); 38 | 39 | /** 40 | * An array of backtrace 41 | */ 42 | public function getTrace(); 43 | 44 | /** 45 | * Formated string of trace 46 | */ 47 | public function getTraceAsString(); 48 | 49 | /** 50 | * Formatted text to display exception message 51 | */ 52 | public function __toString(); 53 | 54 | /** 55 | * Constructer method 56 | */ 57 | public function __construct($message, $code = 0, \Exception $previous = null); 58 | } 59 | -------------------------------------------------------------------------------- /tests/Sftp/DirectoryTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class DirectoryTest extends AbstractTest { 14 | 15 | protected static $directory; 16 | 17 | public static function setUpBeforeClass() 18 | { 19 | parent::setUpBeforeClass(); 20 | self::$directory = new SftpDirectory(self::getSession()); 21 | } 22 | 23 | public function testListItem() 24 | { 25 | $dirList = self::$directory->ls('/.'); 26 | $this->assertTrue(is_array($dirList)); 27 | } 28 | 29 | public function testMkdir() 30 | { 31 | $mkdir = self::$directory->mkdir('ftp_test'); 32 | $this->assertTrue($mkdir); 33 | } 34 | 35 | public function testCd() 36 | { 37 | $cd = self::$directory->cd('ftp_test'); 38 | $this->assertEquals('ftp_test', $cd); 39 | $this->assertEquals('ftp_test', self::$directory->pwd()); 40 | } 41 | 42 | public function testPwd() 43 | { 44 | $this->assertEquals('ftp_test', self::$directory->pwd()); 45 | } 46 | 47 | public function testRm() 48 | { 49 | $rmTestDir = self::$directory->rm('/ftp_test'); 50 | $this->assertTrue($rmTestDir); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/Abstracts/AbstractFtpException.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Abstracts 18 | */ 19 | abstract class AbstractFtpException extends \Exception implements ExceptionInterface 20 | { 21 | /** 22 | * Exception message 23 | * 24 | * @access protected 25 | * @var string 26 | */ 27 | protected $message = 'Unknown error'; 28 | 29 | /** 30 | * Exception code 31 | * 32 | * @access protected 33 | * @var int 34 | */ 35 | protected $code = 0; 36 | 37 | /** 38 | * Source filename of exception 39 | * 40 | * @access protected 41 | * @var string 42 | */ 43 | protected $file; 44 | 45 | /** 46 | * Source line of exception 47 | * 48 | * @access protected 49 | * @var int 50 | */ 51 | protected $line; 52 | 53 | public function __construct($message = null, $code = 0, \Exception $previous = null) 54 | { 55 | if ($message === null) { 56 | $message = $this->message; 57 | } 58 | parent::__construct($message, $code, $previous); 59 | } 60 | 61 | public function __toString() 62 | { 63 | return get_class($this) . 64 | " '{$this->message}' in {$this->file} ({$this->line})\n" . 65 | "{$this->getTraceAsString()}"; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Ftp/DirectoryTest.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class DirectoryTest extends AbstractTest { 13 | 14 | protected static $directory; 15 | 16 | public static function setUpBeforeClass() 17 | { 18 | parent::setUpBeforeClass(); 19 | self::$directory = new FtpDirectory(self::getSession()); 20 | } 21 | 22 | public function testListItem() 23 | { 24 | $dirList = self::$directory->ls('.'); 25 | $this->assertTrue(is_array($dirList)); 26 | } 27 | 28 | public function testMkdir() 29 | { 30 | $mkdir = self::$directory->mkdir('ftp_test'); 31 | $this->assertTrue($mkdir); 32 | $this->assertEquals('dir', self::$directory->isDirOrFile('ftp_test')); 33 | } 34 | 35 | public function testCd() 36 | { 37 | $cd = self::$directory->cd('ftp_test'); 38 | $this->assertTrue($cd); 39 | $this->assertEquals('/ftp_test', self::$directory->pwd()); 40 | } 41 | 42 | public function testPwd() 43 | { 44 | $this->assertEquals('/ftp_test', self::$directory->pwd()); 45 | } 46 | 47 | public function testCdUp() 48 | { 49 | $cdUp = self::$directory->cdUp(); 50 | $this->assertTrue($cdUp); 51 | $this->assertEquals('/', self::$directory->pwd()); 52 | } 53 | 54 | public function testRm() 55 | { 56 | $rmTestDir = self::$directory->rm('ftp_test'); 57 | $this->assertTrue($rmTestDir); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/Interfaces/FileInterface.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | * @subpackage Interfaces 16 | */ 17 | interface FileInterface extends FileDirectoryInterface 18 | { 19 | 20 | /** 21 | * Download file from server 22 | * 23 | * @access public 24 | * @param string $remote remote file name 25 | * @param string $local new file name to save local disc 26 | * @return boolean return true if success 27 | * @throws FileException 28 | */ 29 | public function download($remote, $local); 30 | 31 | /** 32 | * Upload file to server from local disc 33 | * 34 | * @access public 35 | * @param string $local local file name 36 | * @param string $remote file name to upload ftp server 37 | * @return boolean true if success 38 | * @throws FileException 39 | */ 40 | public function upload($local, $remote); 41 | 42 | /** 43 | * Get the file last modified time to file 44 | * 45 | * @access public 46 | * @param string $file name of file to server 47 | * @return integer last modified time of file to Unix timestamp 48 | */ 49 | public function getLastMod($file); 50 | 51 | /** 52 | * Get file size 53 | * 54 | * @access public 55 | * @param string $file name of file to server 56 | * @return int file size 57 | */ 58 | public function getSize($file); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/Interfaces/FileDirectoryInterface.php: -------------------------------------------------------------------------------- 1 | 13 | * @package FtpClient 14 | * @subpackage Interfaces 15 | */ 16 | interface FileDirectoryInterface 17 | { 18 | 19 | /** 20 | * List items 21 | * 22 | * @access public 23 | * @param string $dir directory name 24 | * @param boolean $recursive Recursive directory (true or false) 25 | * @param array $ignore Ignored directory name or file extension 26 | * @return array item list 27 | */ 28 | public function ls($dir, $recursive, $ignore); 29 | 30 | /** 31 | * Remove item from server 32 | * 33 | * @access public 34 | * @param string $item item name to remove server 35 | * @return boolean Return true if success 36 | */ 37 | public function rm($item); 38 | 39 | /** 40 | * Rename file or directory to server 41 | * 42 | * @access public 43 | * @param string $oldName file or directory name to change new name 44 | * @param string $newName new file or directory name 45 | * @return boolean true if success 46 | */ 47 | public function rename($oldName, $newName); 48 | 49 | /** 50 | * Set chmod to file or directory 51 | * 52 | * @access public 53 | * @param int $permission chmod settings 54 | * @param string $item item name 55 | * @return boolean if success 56 | */ 57 | public function chmod($permission, $item); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /tests/Ftp/FileTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class FileTest extends AbstractTest { 14 | 15 | protected static $file; 16 | 17 | 18 | 19 | public static function setUpBeforeClass() 20 | { 21 | parent::setUpBeforeClass(); 22 | self::$file = new FtpFile(self::getSession()); 23 | } 24 | 25 | public function testListItem() 26 | { 27 | $fileList = self::$file->ls('.'); 28 | $this->assertTrue(is_array($fileList)); 29 | } 30 | 31 | public function testUpload() 32 | { 33 | $this->assertFileExists('tests/file/test.txt'); 34 | $upload = self::$file->upload('tests/file/test.txt','test.txt'); 35 | $this->assertTrue($upload); 36 | } 37 | 38 | public function testDownload() 39 | { 40 | $download = self::$file->download('test.txt', 'tests/file/test_download.txt'); 41 | $this->assertTrue($download); 42 | $this->assertFileExists('tests/file/test_download.txt'); 43 | } 44 | 45 | public function testRename() 46 | { 47 | $rename = self::$file->rename('test.txt', 'test_newname.txt'); 48 | $this->assertTrue($rename); 49 | } 50 | 51 | public function testChmod() 52 | { 53 | $chmod = self::$file->chmod(0777, 'test_newname.txt'); 54 | $this->assertTrue($chmod); 55 | } 56 | 57 | public function testGetLastMod() 58 | { 59 | $lastMod = self::$file->getLastMod('test_newname.txt'); 60 | $this->assertTrue(is_int($lastMod)); 61 | } 62 | 63 | public function testRm() 64 | { 65 | $rm = self::$file->rm('test_newname.txt'); 66 | $this->assertTrue($rm); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /tests/Sftp/FileTest.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class FileTest extends AbstractTest 14 | { 15 | 16 | protected static $file; 17 | 18 | public static function setUpBeforeClass() 19 | { 20 | parent::setUpBeforeClass(); 21 | self::$file = new SftpFile(self::getSession()); 22 | } 23 | 24 | public function testListItem() 25 | { 26 | $fileList = self::$file->ls('/.'); 27 | $this->assertTrue(is_array($fileList)); 28 | } 29 | 30 | public function testUpload() 31 | { 32 | $this->assertFileExists('tests/file/test.txt'); 33 | $upload = self::$file->upload('tests/file/test.txt','/test.txt'); 34 | $this->assertTrue($upload); 35 | } 36 | 37 | public function testDownload() 38 | { 39 | $download = self::$file->download('/test.txt', 'tests/file/test_download.txt'); 40 | $this->assertTrue($download); 41 | $this->assertFileExists('tests/file/test_download.txt'); 42 | } 43 | 44 | public function testRename() 45 | { 46 | $rename = self::$file->rename('/test.txt', '/test_newname.txt'); 47 | $this->assertTrue($rename); 48 | } 49 | 50 | public function testChmod() 51 | { 52 | $chmod = self::$file->chmod('/test_newname.txt', 0777); 53 | $this->assertTrue($chmod); 54 | } 55 | 56 | public function testGetLastMod() 57 | { 58 | $lastMod = self::$file->getLastMod('/test_newname.txt'); 59 | $this->assertTrue(is_int($lastMod)); 60 | } 61 | 62 | public function testRm() 63 | { 64 | $rm = self::$file->rm('/test_newname.txt'); 65 | $this->assertTrue($rm); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/Helper/Helper.php: -------------------------------------------------------------------------------- 1 | 14 | * @package FtpClient 15 | */ 16 | class Helper 17 | { 18 | 19 | /** 20 | * Format file size to human readable 21 | * 22 | * @access public 23 | * @param int $byte byte of file size 24 | * @return strıng formatted file size 25 | */ 26 | public static function formatByte($byte) 27 | { 28 | // ignore "Warning: Division by zero" 29 | if ($byte == 0) { 30 | return '0 B'; 31 | } 32 | $s = array('B', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb'); 33 | $e = floor(log($byte)/log(1024)); 34 | return sprintf('%.2f '.$s[$e], ($byte/pow(1024, floor($e)))); 35 | } 36 | 37 | /** 38 | * Format unix time 39 | * 40 | * @access public 41 | * @param int $date unix time 42 | * @return string Formatted date 43 | */ 44 | public static function formatDate($date, $format = 'd.m.Y H:i') 45 | { 46 | return date($format, $date); 47 | } 48 | 49 | /** 50 | * Get file extension 51 | * 52 | * @access public 53 | * @param type $file name of file 54 | * @return string file extension without dot 55 | */ 56 | public static function getFileExtension($file) 57 | { 58 | return pathinfo($file, PATHINFO_EXTENSION); 59 | } 60 | 61 | /* 62 | * if exist local file, rename file 63 | * demo.html renamed to demo_dae4c9057b2ea5c3c9e96e8352ac28f0c7d87f7d.html 64 | * 65 | * @access public 66 | * @param string $name file name 67 | * @return new file name 68 | */ 69 | public static function newName($name) 70 | { 71 | if (file_exists($name)) { 72 | $extension = self::getFileExtension($name); 73 | $name = substr($name,0,(-strlen($extension)-1)) . '_' . sha1(uniqid(rand(), true)) . ".$extension"; 74 | } 75 | return $name; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Directories/SftpDirectory.php: -------------------------------------------------------------------------------- 1 | 19 | * @package FtpClient 20 | * @subpackage Directories 21 | */ 22 | class SftpDirectory extends AbstractSftp implements DirectoryInterface 23 | { 24 | 25 | /** 26 | * Constructor method 27 | * 28 | * @param object $server instance of ServerInterface 29 | */ 30 | public function __construct(ServerInterface $server) 31 | { 32 | $this->session = $server->getSession(); 33 | $this->sFtp(); 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | * @throws DirectoryException 39 | */ 40 | public function ls($dir = null, $recursive = false, $ignore = array()) 41 | { 42 | return $this->listItem('dir', $dir, $recursive, $ignore); 43 | } 44 | 45 | /** 46 | * Remove a directory 47 | * 48 | * @link http://php.net/ssh2_sftp_rmdir Php manuel 49 | * @access public 50 | * @param string $dir dir name to remove ssh server 51 | * @return boolean true if success 52 | * @throws DirectoryException 53 | */ 54 | public function rm($dir) 55 | { 56 | $parseDir = $this->parseLastDirectory($dir); 57 | if (! ssh2_sftp_rmdir($this->getSFtp(), $parseDir)) { 58 | throw new DirectoryException('Directory not deleted'); 59 | } 60 | return true; 61 | } 62 | 63 | /** 64 | * {@inheritDoc} 65 | */ 66 | public function cd($dir) 67 | { 68 | $this->setLastDirectory($dir); 69 | return $dir; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | public function mkdir($dir) 76 | { 77 | $parseDir = $this->parseLastDirectory($dir); 78 | if (! ssh2_sftp_mkdir($this->getSFtp(), $parseDir)) { 79 | throw new DirectoryException('Directory can not be created'); 80 | } 81 | return true; 82 | } 83 | 84 | /** 85 | * {@inheritDoc} 86 | */ 87 | public function pwd() 88 | { 89 | return $this->getLastDirectory(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Servers/SftpServer.php: -------------------------------------------------------------------------------- 1 | server = $server; 60 | $this->port = $port; 61 | $this->connect(); 62 | } 63 | 64 | public function __destruct() 65 | { 66 | if (is_resource($this->session) === true) { 67 | unset($this->session); 68 | } 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | public function connect() 75 | { 76 | if (! $this->session = ssh2_connect($this->server, $this->port)) { 77 | throw new ConnectionFailedException('Could not connect to the server'); 78 | } 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | */ 84 | public function login($userName, $password) 85 | { 86 | if (! ssh2_auth_password($this->session, $userName, $password)) { 87 | throw new AuthenticationFailedException('Could not login server'); 88 | } 89 | } 90 | 91 | /** 92 | * {@inheritDoc} 93 | */ 94 | public function getSession() 95 | { 96 | return $this->session; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/Directories/FtpDirectory.php: -------------------------------------------------------------------------------- 1 | 19 | * @package FtpClient 20 | * @link https://github.com/altayalp/php-ftpclient 21 | */ 22 | class FtpDirectory extends AbstractFtp implements DirectoryInterface 23 | { 24 | 25 | /** 26 | * Constructor method 27 | * 28 | * @param resource $server instance of ServerInterface 29 | */ 30 | public function __construct(ServerInterface $server) 31 | { 32 | $this->session = $server->getSession(); 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | * @throws DirectoryException 38 | */ 39 | public function ls($dir = '.', $recursive = false, $ignore = array()) 40 | { 41 | return $this->listItem('dir', $dir, $recursive, $ignore); 42 | } 43 | 44 | /** 45 | * Remove a directory and files 46 | * 47 | * @link http://php.net/ftp_rmdir Php manuel 48 | * @access public 49 | * @param string $dir dir name to remove ftp server 50 | * @return boolean true if success 51 | * @throws DirectoryException 52 | */ 53 | public function rm($dir) 54 | { 55 | if (! ftp_rmdir($this->session, $dir)) { 56 | throw new DirectoryException('Directory not deleted'); 57 | } 58 | return true; 59 | } 60 | 61 | /** 62 | * {@inheritDoc} 63 | */ 64 | public function cd($dir) 65 | { 66 | if (! ftp_chdir($this->session, $dir)) { 67 | throw new DirectoryException('Work directory can not be change'); 68 | } 69 | return true; 70 | } 71 | 72 | /** 73 | * Changes to the parent directory 74 | * 75 | * @link http://php.net/ftp_cdup Php manuel address 76 | * @return boolean true if success 77 | * @throws DirectoryException 78 | */ 79 | public function cdUp() 80 | { 81 | if (! ftp_cdup($this->session)) { 82 | throw new DirectoryException('The parent directory can not changes'); 83 | } 84 | return true; 85 | } 86 | 87 | 88 | /** 89 | * {@inheritDoc} 90 | */ 91 | public function mkdir($dir) 92 | { 93 | if (! ftp_mkdir($this->session, $dir)) { 94 | throw new DirectoryException('Directory can not be created'); 95 | } 96 | return true; 97 | } 98 | 99 | /** 100 | * {@inheritDoc} 101 | * @throws DirectoryException 102 | */ 103 | public function pwd() 104 | { 105 | if (! $workDir = ftp_pwd($this->session)) { 106 | throw new DirectoryException('Can not get current directory'); 107 | } 108 | return $workDir; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/Servers/FtpServer.php: -------------------------------------------------------------------------------- 1 | 21 | * @link https://github.com/altayalp/php-ftpclient 22 | */ 23 | class FtpServer implements ServerInterface 24 | { 25 | 26 | /** 27 | * Connect session 28 | * 29 | * @access private 30 | * @var string 31 | */ 32 | private $session; 33 | 34 | /** 35 | * Connect server addres 36 | * 37 | * @access protected 38 | * @var string 39 | */ 40 | protected $server; 41 | 42 | /** 43 | * Connect port 44 | * 45 | * @access protected 46 | * @var boolean 47 | */ 48 | protected $port; 49 | 50 | /** 51 | * Connection timeout 52 | * 53 | * @access protected 54 | * @var integer 55 | */ 56 | protected $timeout; 57 | 58 | /** 59 | * Constructor method 60 | * 61 | * @param String $server connect server address 62 | * @param integer $port connect server port 63 | * @param integer $timeOut server time out 64 | * @throws ExtensionMissingException 65 | */ 66 | public function __construct($server, $port = 21, $timeOut = 90) 67 | { 68 | if (! extension_loaded('ftp')) { 69 | throw new ExtensionMissingException('Ftp extension must be loaded'); 70 | } 71 | $this->server = $server; 72 | $this->port = $port; 73 | $this->timeout = $timeOut; 74 | $this->connect(); 75 | } 76 | 77 | public function __destruct() 78 | { 79 | if (is_resource($this->session) === true) { 80 | ftp_close($this->session); 81 | } 82 | } 83 | 84 | /** 85 | * {@inheritDoc} 86 | */ 87 | public function connect() 88 | { 89 | if (! $this->session = ftp_connect($this->server, $this->port, $this->timeout)) { 90 | throw new ConnectionFailedException('Could not connect to the server'); 91 | } 92 | } 93 | 94 | /** 95 | * {@inheritDoc} 96 | */ 97 | public function login($userName, $password) 98 | { 99 | if (! ftp_login($this->session, $userName, $password)) { 100 | throw new AuthenticationFailedException('Could not login server'); 101 | } 102 | } 103 | 104 | /** 105 | * Turns passive mode on 106 | * 107 | * @access public 108 | */ 109 | public function turnPassive() 110 | { 111 | ftp_pasv($this->session, true); 112 | } 113 | 114 | /** 115 | * {@inheritDoc} 116 | */ 117 | public function getSession() 118 | { 119 | return $this->session; 120 | } 121 | 122 | /** 123 | * Set sesion 124 | * 125 | * @access protected 126 | * @param resource $session Connection session 127 | */ 128 | protected function setSession($session) 129 | { 130 | $this->session = $session; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/Files/FtpFile.php: -------------------------------------------------------------------------------- 1 | 19 | * @package FtpClient 20 | * @subpackage Files 21 | * @link https://github.com/altayalp/php-ftpclient 22 | */ 23 | class FtpFile extends AbstractFtp implements FileInterface 24 | { 25 | 26 | /** 27 | * Constructor method 28 | * 29 | * @param object $server instance of ServerInterface 30 | */ 31 | public function __construct(ServerInterface $server) 32 | { 33 | $this->session = $server->getSession(); 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | * @throws FileException 39 | */ 40 | public function ls($dir = '.', $recursive = false, $ignore = array()) 41 | { 42 | return $this->listItem('file', $dir, $recursive, $ignore); 43 | } 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | public function download($remote, $local, $mode = FTP_BINARY) 49 | { 50 | if (! ftp_get($this->session, $local, $remote, $mode)) { 51 | throw new FileException('File not downloaded'); 52 | } 53 | return true; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public function upload($local, $remote, $mode = FTP_BINARY) 60 | { 61 | if (! ftp_put($this->session, $remote, $local, $mode)) { 62 | throw new FileException('File don\'t uploaded'); 63 | } 64 | return true; 65 | } 66 | 67 | /** 68 | * Upload file to ftp server from http address 69 | * 70 | * @link http://php.net/ftp_fput Php manuel 71 | * @access public 72 | * @param string $httpFile http file name with address 73 | * @param string $remote file name to upload ftp server 74 | * @param string $mode Upload mode FTP_BINARY or FTP_ASCII 75 | * @return boolean true if success 76 | * @throws FileException|RuntimeException 77 | */ 78 | public function wget($httpFile, $remote, $mode = FTP_BINARY) 79 | { 80 | if (! ini_get('allow_url_fopen')) { 81 | throw new \RuntimeException('allow_url_fopen must enabled'); 82 | } 83 | if (! $handle = fopen($httpFile)) { 84 | throw new \RuntimeException('File can not opened'); 85 | } 86 | if (! ftp_fput($this->session, $remote, $handle, $mode) ) { 87 | throw new FileException('File not uploaded to ftp server'); 88 | } 89 | fclose($handle); 90 | return true; 91 | } 92 | 93 | /** 94 | * {@inheritDoc} 95 | * @throws FileException 96 | */ 97 | public function rm($file) 98 | { 99 | if (! ftp_delete($this->session, $file)) { 100 | throw new FileException('File not deleted'); 101 | } 102 | return true; 103 | } 104 | 105 | /** 106 | * {@inheritDoc} 107 | */ 108 | public function getLastMod($file) 109 | { 110 | return ftp_mdtm($this->session, $file); 111 | } 112 | 113 | /** 114 | * {@inheritDoc} 115 | */ 116 | public function getSize($file) 117 | { 118 | return ftp_size($this->session, $file); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/Abstracts/AbstractFtp.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Abstracts 18 | */ 19 | abstract class AbstractFtp 20 | { 21 | 22 | use FtpTrait; 23 | 24 | /** 25 | * Ftp connection session (instance of Server) 26 | * 27 | * @access protected 28 | * @var resource 29 | */ 30 | protected $session; 31 | 32 | /** 33 | * {@inheritDoc} 34 | * @throws RuntimeException 35 | */ 36 | public function rename($oldName, $newName) 37 | { 38 | if (! ftp_rename($this->session, $oldName, $newName)) { 39 | throw new \RuntimeException('Name can not be changed'); 40 | } 41 | return true; 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | * @throws RuntimeException 47 | */ 48 | public function chmod($permission,$file) 49 | { 50 | if (! ftp_chmod($this->session, $permission, $file)) { 51 | throw new \RuntimeException('Chmod can not be changed'); 52 | } 53 | return true; 54 | } 55 | 56 | /** 57 | * $name file or directory, its public for unittest 58 | * 59 | * @access public 60 | * @param string $name name of file or directory 61 | * @return strıng if is dir return dir else return file 62 | */ 63 | public function isDirOrFile($name) 64 | { 65 | if (ftp_size($this->session, $name) < 0) { 66 | return 'dir'; 67 | } else { 68 | return 'file'; 69 | } 70 | } 71 | 72 | /** 73 | * Returns a list of files in the given directory 74 | * 75 | * @link http://php.net/ftp_nlist 76 | * @param string $dir The directory to be listed 77 | * @throws RuntimeException 78 | * @return array File list 79 | */ 80 | private function nList($dir) 81 | { 82 | $dirList = ftp_nlist($this->session, $dir); 83 | if ($dirList === false) { 84 | throw new \RuntimeException('List error'); 85 | } 86 | return $dirList; 87 | } 88 | 89 | /** 90 | * List of file or directory 91 | * 92 | * @link http://php.net/ftp_nlist Php manuel 93 | * @access public 94 | * @param string $dir ftp directory name 95 | * @return array file list 96 | * @throws FileException 97 | */ 98 | public function listItem($type, $dir = '.', $recursive = false, $ignore = array()) 99 | { 100 | if ($type != 'dir' && $type != 'file') { 101 | throw new \InvalidArgumentException('$type must "file" or "dir"'); 102 | } 103 | $fileList = $this->nList($dir); 104 | $fileInfo = array(); 105 | foreach ($fileList as $file) { 106 | // remove directory and subdirectory name 107 | $file = str_replace("$dir/", '', $file); 108 | if ($this->ignoreItem($type, $file, $ignore) !== true && $this->isDirOrFile("$dir/$file") == $type) { 109 | $fileInfo[] = $file; 110 | } 111 | if ($recursive === true && $this->isDirOrFile("$dir/$file") == 'dir') { 112 | $fileInfo = array_merge($fileInfo, $this->listItem($type, "$dir/$file", $recursive, $ignore)); 113 | } 114 | } 115 | return $fileInfo; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/Files/SftpFile.php: -------------------------------------------------------------------------------- 1 | 19 | * @package FtpClient 20 | * @subpackage Files 21 | */ 22 | class SftpFile extends AbstractSftp implements FileInterface 23 | { 24 | 25 | /** 26 | * Constructor method 27 | * 28 | * @param object $server instance of ServerInterface 29 | */ 30 | public function __construct(ServerInterface $server) 31 | { 32 | $this->session = $server->getSession(); 33 | $this->sFtp(); 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | * @throws FileException 39 | */ 40 | public function ls($dir = '/.', $recursive = false, $ignore = array()) 41 | { 42 | return $this->listItem('file', $dir, $recursive, $ignore); 43 | } 44 | 45 | /** 46 | * @inheritDoc 47 | * @throws FileException 48 | */ 49 | public function download($remote, $local) 50 | { 51 | $parseFile = $this->parseLastDirectory($remote); 52 | $stream = @fopen($this->getWrapper($parseFile), 'r'); 53 | if (! $stream) { 54 | throw new FileException("Could not open file: $parseFile"); 55 | } 56 | 57 | $contents = ''; 58 | while (!feof($stream)) { 59 | $contents .= fread($stream, filesize($this->getWrapper("/$parseFile"))); 60 | } 61 | file_put_contents($local, $contents); 62 | 63 | @fclose($stream); 64 | 65 | return true; 66 | } 67 | 68 | /** 69 | * @inheritDoc 70 | * @throws FileException 71 | */ 72 | public function upload($local, $remote) 73 | { 74 | $parseFile = $this->parseLastDirectory($remote); 75 | $stream = @fopen($this->getWrapper($parseFile), 'w'); 76 | 77 | if (! $stream) { 78 | throw new FileException("Could not open file: $parseFile"); 79 | } 80 | $data_to_send = @file_get_contents($local); 81 | if ($data_to_send === false) { 82 | throw new FileException("Could not open local file: $local."); 83 | } 84 | 85 | if (fwrite($stream, $data_to_send) === false) 86 | throw new FileException("Could not send data from file: $local."); 87 | 88 | @fclose($stream); 89 | 90 | return true; 91 | } 92 | 93 | /** 94 | * Upload file to ssh server from http address 95 | * 96 | * @access public 97 | * @param string $httpFile http file name with address 98 | * @param string $remote file name to upload ssh server 99 | * @return boolean true if success 100 | * @throws FileException|RuntimeException 101 | */ 102 | public function wget($httpFile, $remote) 103 | { 104 | if (! ini_get('allow_url_fopen')) { 105 | throw new \RuntimeException('allow_url_fopen must enabled'); 106 | } 107 | if (! $fileData = file_get_contents($httpFile)) { 108 | throw new \RuntimeException('Can nat get file content'); 109 | } 110 | $parseFile = $this->parseLastDirectory($remote); 111 | if (! file_put_contents($this->getWrapper("/$parseFile"), $fileData)) { 112 | throw new FileException('File not uploaded to ftp server'); 113 | } 114 | return true; 115 | } 116 | 117 | /** 118 | * {@inheritDoc} 119 | * @throws FileException 120 | */ 121 | public function rm($file) 122 | { 123 | $parseFile = $this->parseLastDirectory($file); 124 | if (! ssh2_sftp_unlink($this->getSFtp(), $parseFile)) { 125 | throw new FileException('File can not deleted'); 126 | } 127 | return true; 128 | } 129 | 130 | /** 131 | * {@inheritDoc} 132 | */ 133 | public function getLastMod($file) 134 | { 135 | $parseFile = $this->parseLastDirectory($file); 136 | return filemtime($this->getWrapper("/$parseFile")); 137 | } 138 | 139 | /** 140 | * {@inheritDoc} 141 | */ 142 | public function getSize($file) 143 | { 144 | $parseFile = $this->parseLastDirectory($file); 145 | return filesize($this->getWrapper("/$parseFile")); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/Abstracts/AbstractSftp.php: -------------------------------------------------------------------------------- 1 | 16 | * @package FtpClient 17 | * @subpackage Abstracts 18 | */ 19 | abstract class AbstractSftp 20 | { 21 | 22 | use FtpTrait; 23 | 24 | /** 25 | * Ftp connection session (instance of Server) 26 | * 27 | * @access protected 28 | * @var resource 29 | */ 30 | protected $session; 31 | 32 | /** 33 | * Sftp resource 34 | * 35 | * @access protected 36 | * @var resource 37 | */ 38 | private $sFtp; 39 | 40 | /** 41 | * Working last directory 42 | * 43 | * @access private 44 | * @var string 45 | */ 46 | private static $lastDirectory; 47 | 48 | /** 49 | * Get $lastDirectory 50 | * 51 | * @return string $lastDirectory 52 | */ 53 | protected function getLastDirectory() 54 | { 55 | return self::$lastDirectory; 56 | } 57 | 58 | /** 59 | * Set $lastDirectory 60 | */ 61 | protected function setLastDirectory($dir) 62 | { 63 | self::$lastDirectory = $dir; 64 | } 65 | 66 | /** 67 | * Initialize SFTP subsystem 68 | * 69 | * @link http://php.net/ssh2_sftp Php manuel 70 | * @access protected 71 | * @throws RuntimeException 72 | */ 73 | protected function sFtp() 74 | { 75 | if (! $this->sFtp = ssh2_sftp($this->session)) { 76 | throw new \RuntimeException('Can not initialize SFTP'); 77 | } 78 | } 79 | 80 | /** 81 | * Get ssh2:// wrapper 82 | * 83 | * @link http://php.net/wrappers_ssh2 Php manuel 84 | * @access protected 85 | * @param string $file Remote file name 86 | * @return string url with sftp wrapper 87 | */ 88 | protected function getWrapper($file) 89 | { 90 | return sprintf('ssh2.sftp://%s%s', $this->sFtp, $file); 91 | } 92 | 93 | /** 94 | * Parse $lastDirectory 95 | * 96 | * @access protected 97 | * @param string $dir Directory name 98 | * @return string Parse dir name 99 | */ 100 | protected function parseLastDirectory($dir) 101 | { 102 | if (substr($dir,0,1) == '/') { 103 | return $dir; 104 | } else { 105 | return self::$lastDirectory . "/$dir"; 106 | } 107 | } 108 | 109 | /** 110 | * Get sFtp 111 | * 112 | * @access protected 113 | * @return resource sFtp source 114 | */ 115 | protected function getSFtp() 116 | { 117 | return $this->sFtp; 118 | } 119 | 120 | /** 121 | * {@inheritDoc} 122 | * @throws RuntimeException 123 | */ 124 | public function rename($oldName, $newName) 125 | { 126 | if (! ssh2_sftp_rename($this->sFtp, $oldName, $newName)) { 127 | throw new \RuntimeException('Name can not be changed'); 128 | } 129 | return true; 130 | } 131 | 132 | /** 133 | * {@inheritDoc} 134 | * @throws RuntimeException 135 | */ 136 | public function chmod($file, $permission) 137 | { 138 | if (! ssh2_sftp_chmod($this->sFtp, $file, $permission)) { 139 | throw new \RuntimeException('Chmod can not be changed'); 140 | } 141 | return true; 142 | } 143 | 144 | /** 145 | * List of file 146 | * 147 | * @link http://php.net/scandir Php manuel 148 | * @access public 149 | * @param string $dir ssh directory name 150 | * @return array file list 151 | * @throws FileException 152 | */ 153 | protected function listItem($type, $dir = '/.', $recursive = false, $ignore = array()) 154 | { 155 | if ($type == 'dir') { 156 | $bool = true; 157 | } elseif ($type == 'file') { 158 | $bool = false; 159 | } else { 160 | throw new \InvalidArgumentException('$type must "file" or "dir"'); 161 | } 162 | 163 | $parseDir = $this->parseLastDirectory($dir); 164 | $sDir = $this->getWrapper($parseDir); 165 | $fileList = array_diff(scandir($sDir), array('..', '.')); 166 | 167 | $fileInfo = array(); 168 | foreach ($fileList as $file) { 169 | if ($this->ignoreItem($type, $file, $ignore) !== true && is_dir("$sDir/$file") === $bool) { 170 | $fileInfo[] = $file; 171 | } 172 | if ($recursive === true && is_dir("$sDir/$file") === true) { 173 | $fileInfo = array_merge($fileInfo, $this->listItem($type, "$dir/$file", $recursive, $ignore)); 174 | } 175 | } 176 | 177 | return $fileInfo; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP FTP Client Library 2 | 3 | [![Build Status](https://travis-ci.org/altayalp/php-ftp-client.svg?branch=master)](https://travis-ci.org/altayalp/php-ftp-client) 4 | [![Latest Stable Version](https://poser.pugx.org/altayalp/ftp-client/version)](https://packagist.org/packages/altayalp/ftp-client) 5 | [![Latest Unstable Version](https://poser.pugx.org/altayalp/ftp-client/v/unstable)](//packagist.org/packages/altayalp/ftp-client) 6 | [![License](https://poser.pugx.org/altayalp/ftp-client/license)](https://packagist.org/packages/altayalp/ftp-client) 7 | 8 | Php 5.4+ object oriented and unit tested library for FTP and SFTP (ssh ftp) process. 9 | 10 | ### Installation 11 | 12 | Make sure the [PHP FTP](http://php.net/book_ftp) extension is installed or enabled. 13 | 14 | The recommended way to install the library is through [composer](https://getcomposer.org/). 15 | 16 | ```bash 17 | composer require altayalp/ftp-client 18 | ``` 19 | 20 | This command will install the library on current dir. 21 | 22 | ## Usage 23 | ### Connect and Log in to Server 24 | 25 | ```php 26 | // connect to ftp server 27 | use altayalp\FtpClient\Servers\FtpServer; 28 | 29 | $server = new FtpServer('ftp.example.com'); 30 | $server->login('user', 'password'); 31 | 32 | // or connect to ssh server 33 | use altayalp\FtpClient\Servers\SftpServer; 34 | 35 | $server = new SftpServer('ssh.example.com'); 36 | $server->login('user', 'password'); 37 | ``` 38 | 39 | You can call SftpServer class by port or FtpServer class by the port and timeout. The default port for SFTP is 22, for FTP is 21 and for timeout is 90 seconds. 40 | 41 | ```php 42 | // connect to ftp server 43 | use altayalp\FtpClient\Servers\FtpServer; 44 | 45 | $server = new FtpServer('ftp.example.com', 21, 90); 46 | $server->login('user', 'password'); 47 | 48 | // or connect to ssh server 49 | use altayalp\FtpClient\Servers\SftpServer; 50 | 51 | $server = new SftpServer('ssh.example.com', 22); 52 | $server->login('user', 'password'); 53 | ``` 54 | 55 | You can use same methods for FTP and SFTP after login server. The factory classes will return file or directory class instance. 56 | 57 | If you have a problem login to FTP server, turnPassive() method may useful after login method. It's not exist for SFTP. 58 | 59 | ```php 60 | $server->turnPassive(); 61 | ``` 62 | 63 | ### Fetching Files 64 | 65 | ```php 66 | use altayalp\FtpClient\FileFactory; 67 | 68 | $file = FileFactory::build($server); 69 | $list = $file->ls('public_html'); 70 | print_r($list); 71 | ``` 72 | 73 | Will output: 74 | 75 | ```php 76 | Array 77 | ( 78 | [0] => index.php 79 | [1] => .gitignore 80 | [2] => .htaccess 81 | [3] => composer.json 82 | [4] => phpunit.xml 83 | [5] => robots.txt 84 | [6] => server.php 85 | ) 86 | ``` 87 | 88 | This method takes two more optional parameters. $recursive also fetch subdirectories. $ignore parameter determine extension of the files which you don't want to see in list. 89 | 90 | ```php 91 | $list = $file->ls('public_html' false, array('php','html')); 92 | ``` 93 | 94 | Will output: 95 | 96 | ```php 97 | Array 98 | ( 99 | [0] => .gitignore 100 | [1] => .htaccess 101 | [2] => composer.json 102 | [3] => phpunit.xml 103 | [4] => robots.txt 104 | ) 105 | ``` 106 | 107 | ### Fetching Directories 108 | 109 | ```php 110 | use altayalp\FtpClient\DirectoryFactory; 111 | 112 | $dir = DirectoryFactory::build($server); 113 | $list = $dir->ls('public_html'); 114 | print_r($list); 115 | ``` 116 | 117 | Will output: 118 | 119 | ```php 120 | Array 121 | ( 122 | [0] => app 123 | [1] => bootstrap 124 | [2] => css 125 | [3] => packages 126 | [4] => vendor 127 | ) 128 | ``` 129 | 130 | This method takes two more optional parameters. $recursive also fetch subdirectories. $ignore parameter determine name of the directories which you don't want to see in list. 131 | 132 | ```php 133 | $list = $dir->ls('public_html' false, array('packages','vendor')); 134 | print_r($list); 135 | ``` 136 | 137 | Will output: 138 | 139 | ```php 140 | Array 141 | ( 142 | [0] => app 143 | [1] => bootstrap 144 | [2] => css 145 | ) 146 | ``` 147 | 148 | ### Other File Operations 149 | 150 | **Download file from server to local disc with rename** 151 | 152 | ```php 153 | $file->download('public_html/remote.html', 'local.html'); 154 | ``` 155 | 156 | **Upload file from local to server with rename** 157 | 158 | ```php 159 | $file->upload('local.zip', 'public_html/remote.zip'); 160 | ``` 161 | 162 | **Upload file from http server to server** 163 | 164 | ```php 165 | $file->wget('http://www.example.com/remote.zip', 'public_html/remote.zip'); 166 | ``` 167 | 168 | **Rename file to server** 169 | 170 | ```php 171 | $file->rename('public_html/oldname.zip', 'public_html/newname.zip'); 172 | ``` 173 | 174 | **Change chmod file to server** 175 | 176 | ```php 177 | $file->chmod(0777, 'public_html/file.zip'); 178 | ``` 179 | 180 | **Remove file to server** 181 | 182 | ```php 183 | $file->rm('public_html/remote.zip'); 184 | ``` 185 | 186 | **Get last modified time to file** 187 | 188 | ```php 189 | $file->getLastMod('public_html/remote.zip'); 190 | ``` 191 | 192 | **Get size to file** 193 | 194 | ```php 195 | $file->getSize('public_html/remote.zip'); 196 | ``` 197 | 198 | ### Other Directory Operations 199 | 200 | **Create new directory** 201 | 202 | ```php 203 | $dir->mkdir('public_html/new_directory'); 204 | ``` 205 | 206 | **Change current working directory** 207 | 208 | ```php 209 | $dir->cd('public_html/new_directory'); 210 | ``` 211 | 212 | **Changes to the parent directory (not exist Sftp)** 213 | 214 | ```php 215 | $dir->cdUp(); 216 | ``` 217 | 218 | **Get current working directory** 219 | 220 | ```php 221 | $dir->pwd(); 222 | ``` 223 | 224 | **Rename Directory** 225 | 226 | ```php 227 | $dir->rename('public_html/oldname', 'public_html/newname'); 228 | ``` 229 | 230 | **Change chmod directory to server** 231 | 232 | ```php 233 | $dir->chmod(0777, 'public_html/directory'); 234 | ``` 235 | 236 | **Remove Directory** 237 | 238 | The directory must be empty. 239 | 240 | ```php 241 | $dir->rm('public_html/directory'); 242 | ``` 243 | 244 | ### Usage Of Helper Class 245 | Helper Class contains some useful methods for actions: 246 | * Helper::formatByte: Format file size to human readable 247 | * Helper::formatDate: Format unix time 248 | * Helper::getFileExtension: Get given file extension 249 | * Helper::newName: If exist local file, rename the file 250 | 251 | ```php 252 | Helper::formatByte($file->getSize('public_html/dashboard.zip')); 253 | // Will output: 32.47 Mb 254 | Helper::formatDate($file->getLastMod('public_html/dashboard.zip')); 255 | // Will output: 14.06.2016 23:31 256 | // or 257 | Helper::formatDate($file->getLastMod('public_html/dashboard'), 'd.m.Y'); 258 | // Will output: 14.06.2016 259 | Helper::getFileExtension($fileName); 260 | // Will output: html 261 | $file->download('public_html/demo.html', Helper::newName('demo.html')); 262 | // if exist local file, rename file 263 | // demo.html renamed to demo_dae4c9057b2ea5c3c9e96e8352ac28f0c7d87f7d.html 264 | ``` 265 | 266 | ### Test 267 | Firstly rename phpunit.xml.dist to phpunit.xml and than open the file to edit ftp variables. After run the phpunit command. 268 | 269 | ```bash 270 | phpunit tests/Ftp 271 | # or 272 | phpunit tests/Sftp 273 | ``` 274 | 275 | ### License 276 | 277 | The MIT License (MIT). Please see [License File](https://github.com/altayalp/php-ftp-client/blob/master/LICENSE) for more information. 278 | --------------------------------------------------------------------------------