6

わかりましたので、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, $existingLocationToSendFrom, NET_SFTP_LOCAL_FILE );
                            break;

                            case 'libssh2':
                                    $put = ssh2_scp_send($this->connection, $targetLocationToSendTo, $existingLocationToSendFrom, 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を開始しました..誰かアイデアがあれば、とても感謝しています... phpseclibを接続できません - エラー10060

4

2 に答える 2

18

このコードの主な問題は、垂直方向にスケーリングすることです。$connection_typeたとえば、「ファイル」の3 番目の潜在的な値を導入して、ローカル ファイルシステムという別の実装を追加することにしたとします。case 'file':ここで、あらゆる場所に条件を追加するコードを実行する必要がftp_sftpあり、制御不能になります。現在、コードの 'sftp' ブランチ内で同じ問題が発生しており、$ssh_type.

元のコード

switch($connection_type) {
    case 'ftp'  : // ...
    case 'stfp' : // ...
}

なる

switch($connection_type) {
    case 'ftp'  : // ...
    case 'stfp' : // ...
    case 'file' : // ...
}

これは、スイッチをオンにするコード内のすべての switch ステートメント$connection_typeに適用されることに注意してください。ftp_sftpそれぞれの追加の動作を組み込むために、クラスに何行のコードを追加するか想像してみてください...

実際、現在ftpsftpsshの 3 つの戦略があるようです。

ここでやりたいことは、垂直方向ではなく水平方向に拡張するようにコードを設定することです。これを行う方法は、ストラテジー デザイン パターンを使用することです。

基本的に、あなたがしていることは、コード内の共通インターフェースを引き出してから、FTP と SFTP の個別の実装を作成することです。これを実際に実装するにはさまざまな方法がありますので、心ゆくまで微調整してください!

共通インターフェース

これは、あらゆる「ftp クラス」が実行できなければならないことの定義です。

interface PhpFtp
{
    public function __construct($host, $username, $password, $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 ステートメントが 1 つあります$connection_type。ケースを別の方法で処理することを決定する場合がありdefaultます。

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と呼ばれる別のデザイン パターンをこっそり取り入れています。 テンプレート メソッドであり、 pwdBaseFtp::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->username, $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 クラスができまし$ssh_typeたが、元のftp_sftpクラスが$connection_type. ストラテジー パターンのハンドルを取得し、Ftp&Sftpクラスが完成したら、戻って実装内にストラテジー パターンを実装し、たとえばSftp2 つのクラス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, 'username', 'secret');
                break;

            default:
                echo 'No ssh method defined, please define one in: $ftp_sftp->ssh_type';
                exit();
                break;
        }

        if(!$connection || !$login)
            return false;
    }
}

新しいコードを使用する

新しいシステムを導入すると、何が何であるかを 10 倍簡単に確認でき、各クラスは特定のドメインに焦点を当て、コードは水平方向に成長します。どういう意味ですか?元のパラダイムに3 番目$connection_type の「ファイル」を追加することを検討したときの上記のことを覚えていますか? 新しい配置では、ファクトリにある 1つの 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();
}
于 2013-01-15T19:10:27.683 に答える
0

Wordpress の SFTP 実装は、奇妙な方法で chdir と pwd を実行します。彼らは ssh2_exec() を実行します。それがファイルのダウンロード/アップロードで機能するかどうかはわかりません。それらの実装は次のとおりです。

http://core.svn.wordpress.org/trunk/wp-admin/includes/class-wp-filesystem-ssh2.php

phpseclibの方が優れていると思いますが、参考までに。

また、phpseclib の最新バージョンは 0.3.1 です。idk... 参考までに笑。

最後に、include() の代わりに include_once() を使用することはできますか? そうすれば、クラスを複数回インスタンス化できますか?

于 2013-01-15T17:55:19.393 に答える