PHP FTP / SFTP交换机类
好的,所以通过ftp或sftp从你自己访问其他服务器……我写了一个小类来处理它.它显然是新的,可以很容易地改进,所以我想把它扔出去看看其他人认为(stackoverflow得到了很多观点,所以希望这可以帮助其他人),以及他们如何改进它…所以我想问题是……如何改进?
class ftp_sftp{ //determine,if ssh,to use phpseclib or php's inbuilt ssh_sftp 'libssh' public $ssh_type = 'phpseclib'; //set ths path to the directory containing the entire phpseclib files public $phpseclib_path = 'scripts/phpseclib0.3.0'; //private vars generated by this class public $host; public $username; public $password; public $connection_type; public $port_number; public $connection = false; //contruct method which will attempt to set the connection details and automatically attempt to establisha connection to the server public function __construct( $host,$username,$password,$connection_type,$port_number = false ){ //add the webroot to the beginning of the $this->phpseclib_path (this is bespoke to my own configuration) $this->phpseclib_path = WEBROOT_PRIVATE.$this->phpseclib_path; //setting the classes vars $this->host = $host; $this->username = $username; $this->password = $password; $this->connection_type = $connection_type; //set the port number to defaults based on connection type if none passed if( $port_number === false ){ if( $connection_type == 'ftp' ){ $port_number = 21; } else { $port_number = 22; } } $this->port_number = $port_number; //now set the server connection into this classes connection var $this->connection = $this->connect(); } //tests the details passed and tries to establish a connection,returns false on fail. function connect(){ br($this->connection_type); switch( $this->connection_type ) { case 'ftp': $connection = ftp_connect($this->host); $login = ftp_login($connection,$this->username,$this->password); //if no connection was possible return false and leave $this-connection as false if(!$connection || !$login){ return false; } else { // enabling passive mode ftp_pasv( $connection,true ); return $connection; } break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': //inlcude the phpseclib path in the include array and include the ssh2 class set_include_path($this->phpseclib_path ); if(!include('Net/SSH2.php')){ echo 'Sorry failed to load SSH2 class'; br(); } if(!include('Net/SFTP.php')){ echo 'Sorry failed to load SFTP class'; br(); } $connection = new Net_SFTP($this->host,$this->port_number); $login = $connection->login($this->username,$this->password); break; case 'libssh2': $connection = ssh2_connect($this->host,$this->port_number); $login = ssh2_auth_password($connection,'username','secret'); break; default: echo 'No ssh method defined,please define one in: $ftp_sftp->ssh_type'; exit(); break; } //if no connection was possible return false and leave $this-connection as false if (!$connection || !$login) { return false; } else { return $connection; } break; default: echo 'No connection type set cannot choose a method to connect'; break; } } //acces the phpseclib errors public function errors(){ if($this->connection_type == 'sftp' && $this->ssh_type == 'phpseclib'){ print_r($this->connection->getErrors()); } else { echo 'no error logs available'; } } //function used by this class to check certain values are set public function connection_check(){ if( $this->connection === false){ echo 'Sorry there seems to be a connection problem please try again'; br(); } if( $this->connection_type === false){ echo 'Sorry there seems to be a no connection type set'; } if( $this->connection === false || $this->connection_type === false ){ exit(); } } //transfers a file to the connected server public function put($targetLocationToSendTo,$existingLocationToSendFrom){ //check the connection $this->connection_check(); switch( $this->connection_type ) { case 'ftp': //ftp_put the file across $put = ftp_put( $this->connection,$targetLocationToSendTo,$existingLocationToSendFrom,FTP_BINARY); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $put = $this->connection->put( $targetLocationToSendTo,NET_SFTP_LOCAL_FILE ); break; case 'libssh2': $put = ssh2_scp_send($this->connection,0755); break; } break; } return $put; } //list the contents of a remote directory public function dir_list( $dirToList ){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $list = $this->connection = ftp_nlist($this->connection,$dirToList); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $list = $this->connection->nlist( $dirToList ); break; case 'libssh2': echo 'Sorry there is no support for nlist with libssh2,however this link has a possible answer: http://randomdrake.com/2012/02/08/listing-and-downloading-files-over-sftp-with-php-and-ssh2/'; break; } break; } return $list; } //get the timestamp of the file on another server public function remote_filemtime( $pathToFile ){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $timeStamp = ftp_mdtm($this->connection,$pathToFile); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $statinfo = $this->connection->stat( $pathToFile ); break; case 'libssh2': $statinfo = ssh2_sftp_stat($this->connection,$pathToFile); break; } if($statinfo['mtime']){ $timeStamp = $statinfo['mtime']; } else { $timeStamp = false; } break; } return $timeStamp; } //make a directory on the remote server public function make_dir( $dirToMake ){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $dir_made = ftp_mkdir($this->connection,$dirToMake); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $statinfo = $this->connection->mkdir( $dirToMake ); break; case 'libssh2': $statinfo = ssh2_sftp_mkdir($this->connection,$dirToMake,0755); break; } break; } return $dir_made; } //change directory public function change_dir( $dirToMoveTo ){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $chdir = ftp_chdir($this->connection,$dirToMoveTo ); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $chdir = $this->connection->chdir( $dirToMoveTo ); break; case 'libssh2': echo 'Sorry this feature does exist yet for when using libssh2 with the ftp_sftp class'; exit(); break; } break; } return $chdir; } //curent directory we are looking in public function pwd(){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $pwd = ftp_pwd($this->connection); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $pwd = $this->connection->pwd(); break; case 'libssh2': echo 'Sorry this feature does exist yet for when using libssh2'; exit(); break; } break; } return $pwd; } //delete file public function delete_file($fileToDelete){ //check the connection $this->connection_check(); //run appropriate list switch( $this->connection_type ) { case 'ftp': $unlink = ftp_delete($this->connection,$fileToDelete); break; case 'sftp': //decide which ssh type to use switch( $this->ssh_type ){ case 'phpseclib': $unlink = $this->connection->delete( $fileToDelete ); break; case 'libssh2': $unlink = ssh2_sftp_unlink($this->connection,$fileToDelete); break; } break; } return $unlink; } }//end of class 使用课程: $ftp_sftp = new ftp_sftp( '92.21.627.163','ftpuser','yourpassword','','ftp','21' ); echo $ftp_sftp->pwd(); 我在使用easyPHP连接我的win7机器上的phpseclib时遇到了一些麻烦,并开始了Q ..如果有人有任何想法我会非常感激…
这段代码的主要问题是它垂直缩放.假设您决定添加另一个实现,一个本地文件系统,为$file_type的’file’引入第三个潜在值.现在你必须通过代码添加案例’文件’:各地的条件,使ftp_sftp失去控制.你现在在’sftp’代码分支中再次遇到同样的问题,处理$ssh_type.
原始代码 switch($connection_type) { case 'ftp' : // ... case 'stfp' : // ... } 变 switch($connection_type) { case 'ftp' : // ... case 'stfp' : // ... case 'file' : // ... } 请记住,这是针对切换$connection_type的代码中的每个switch语句.想象一下,我们将多少行代码添加到ftp_sftp类中以合并每个附加行为…… 事实上,你现在看起来实际上有三种策略,ftp,sftp& SSH. 你想要做的是将代码设置为水平扩展而不是垂直扩展,这样做的方法是通过Strategy design pattern. 基本上你正在做的是在代码中拉出公共接口,然后为FTP和&创建单独的实现. SFTP.有很多不同的方法可以对此进行实际实施,因此请调整您心中的内容! 一个通用的界面 这是任何’ftp类’必须能够做的定义. interface PhpFtp { public function __construct($host,$port_number = false); public function connect(); public function errors(); public function connection_check(); public function put($targetLocationToSendTo,$existingLocationToSendFrom); public function dir_list( $dirToList ); public function remote_filemtime( $pathToFile ); public function make_dir( $dirToMake ); public function change_dir( $dirToMoveTo ); public function pwd(); public function delete_file($fileToDelete); } 一个工厂 现在整个代码中都有一个switch语句来检查$connection_type.您可能决定以不同方式处理默认情况. class PhpFtpFactory { public static function create($connection_type) { switch($connection_type) { case 'ftp': $oFtp = new Ftp(); break; case 'sftp': $oFtp = new Sftp(); break; default: throw new UnexpectedValueExcpetion( 'No connection type set cannot choose a method to connect'); } // Potential follow-up construction steps return $oFtp; } } 基类 不是绝对必要,但非常有帮助.此外,我们在这里偷偷摸摸另一个设计模式,称为Template Method.BaseFtp :: pwd是一个模板方法,它控制整个pwd算法,但委托给具体的孩子一部分. abstract class BaseFtp implements PhpFtp { public function pwd() { $this->connection_check(); return $this->_pwd(); } abstract protected function _pwd(); } 具体的FTP实现 现在我们有一个简洁的FTP类,它只进行FTP操作,它对SFTP一无所知. class Ftp extends BaseFtp { protected function _pwd() { return ftp_pwd($this->connection); } public function connect() { $connection = ftp_connect($this->host); $login = ftp_login($connection,$this->password); // if no connection was possible return false and leave $this-connection as false if(!$connection || !$login) return false; // enabling passive mode ftp_pasv( $connection,true ); return $connection; } } 具体SFTP类 现在我们有一个独立的SFTP类,但是请注意它就像原始的ftp_sftp类为$connection_type做的那样切换$ssh_type.一旦你掌握了战略模式,并拥有Ftp&完成Sftp类后,您可以返回并在Sftp实现中实现策略模式,这样您就可以拥有2个类Phpseclib&例如,Libssh2. class Sftp extends BaseFtp { protected function _pwd() { // decide which ssh type to use switch($this->ssh_type) { case 'phpseclib': return $this->connection->pwd(); case 'libssh2': echo 'Sorry this feature does exist yet for when using libssh2'; return false; } } public function connect() { // decide which ssh type to use switch( $this->ssh_type ) { case 'phpseclib': // inlcude the phpseclib path in the include array // and include the ssh2 class set_include_path($this->phpseclib_path ); if(!include('Net/SSH2.php')){ echo 'Sorry failed to load SSH2 class'; br(); } if(!include('Net/SFTP.php')){ echo 'Sorry failed to load SFTP class'; br(); } $connection = new Net_SFTP($this->host,$this->port_number); $login = $connection->login($this->username,$this->password); break; case 'libssh2': $connection = ssh2_connect($this->host,$this->port_number); $login = ssh2_auth_password($connection,'secret'); break; default: echo 'No ssh method defined,please define one in: $ftp_sftp->ssh_type'; exit(); break; } if(!$connection || !$login) return false; } } 使用新代码 随着新系统的到位,它的10X更容易看出是什么,每个类都关注它的特定领域,代码水平增长.那是什么意思?记住上面,当我们考虑在原始范例中添加第三个$connection_type’文件’时?在新的安排中,我们更新了一个switch语句,即工厂中的一个: class PhpFtpFactory { public static function create($connection_type) { switch($connection_type) { case 'ftp': $oFtp = new Ftp(); break; case 'sftp': $oFtp = new Sftp(); break; case 'file': $oFtp = new File(); break; default: throw new UnexpectedValueExcpetion( 'No connection type set cannot choose a method to connect'); } // Potential follow-up construction steps return $oFtp; } } 然后你当然添加了新的具体实现 class File extends PhpFtp { // ... } 由于新的File类可以进入它自己的空间,我们不会扩展一个中心类,即原始的ftp_sftp类. 为了使用新系统,你可以在工厂找到一个实例并从那里开始 // get an instance of the Ftp class $ftp = PhpFtpFactory::create('ftp'); // get an instance of the Sftp class $sftp = PhpFtpFactory::create('sftp'); 这些实例中的任何一个都支持所有PhpFtp函数,因为它们实现了接口!这也使您能够编写多态代码.考虑一个对接口进行类型提示的函数 // This is polymorphic code function doFtpStuff(PhpFtp $oFtp) { // As mentioned above $oFtp can be an instance of any class that implements PhpFtp $oFtp->connect(); $oFtp->pwd(); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |