web-dev-qa-db-ja.com

SFTPをPHPで動作させることができません

N個のリモートサーバーを介してプログラムでファイルを取得する必要があるため、PHP)で単純なSFTPクライアントを作成しています。PECLSSH2拡張機能を使用しています。

しかし、私は障害物にぶつかりました。 php.netのドキュメントは、これを実行できることを示唆しています。

$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');

しかし、私は似たようなことを試みるlsメソッドを持っています

public function ls($dir)
{
    $rd = "ssh2.sftp://{$this->sftp}/$dir";
    $handle = opendir($rd);
    if (!is_resource($handle)) {
        throw new SFTPException("Could not open directory.");
    }

    while (false !== ($file = readdir($handle))) {
        if (substr($file, 0, 1) != '.'){
            print $file . "\n";
        }
    }
    closedir($handle);
}

次のエラーが発生します。

PHP Warning:  opendir(): Unable to open ssh2.sftp://Resource id #5/outgoing on remote Host

リソースを文字列にキャストすると、これが発生するため、これは完全に理にかなっています。ドキュメントは間違っていますか?リソースをホスト、ユーザー名、およびホストに置き換えようとしましたが、それも機能しませんでした。コマンドラインからSFTPを実行でき、正常に機能するため、パスが正しいことがわかります。

他の誰かがSFTPでSSH2拡張を使用しようとしましたか?ここで明らかな何かが欠けていますか?

更新:

社内の別のマシンでsftpをセットアップしましたが、問題なく動作します。だから、私が接続しようとしているサーバーについて何かが機能していないに違いありません。

17

SFTPサーバーに接続していて、ルートフォルダーに接続する必要がある場合(たとえば、フォルダーの内容を読み取るため)、パスとして「/」だけを使用すると、エラーが発生します。

私が見つけた解決策は、パス「/./」を使用することでした。これは、ルートフォルダーを参照する有効なパスです。これは、ログインしているユーザーが自分のルートフォルダーにのみアクセスでき、フルパスが利用できない場合に役立ちます。

したがって、ルートフォルダの内容を読み取ろうとするときのサーバーへの要求は、次のようになります。

$rd = "ssh2.sftp://{$this->sftp}/./";

5.6.27を超えるphpバージョンの場合はintval()を使用します

$sftpConnection = ssh2_connect($Host);
$sftp = ssh2_sftp($sftpConnection);
$fp = fopen("ssh2.sftp://" . intval($sftp) . $remoteFile, "r");

https://bugs.php.net/bug.php?id=73597

18
Calin Blaga

同様の問題が発生しています。私はあなたがこれに似た何かをしていると思います:

    $dir = "ssh2.sftp://{$sftp}{$remote_dir}"; 
    $handle = opendir($dir);

$remote_dirがルートからのフルパスである場合、open_dirは機能します。 $remote_dirが「/」または「」の場合は、「開くことができません」というエラーが表示されます。

私の場合、sshはftpのように「ホーム」ディレクトリではなくルートフォルダに接続しているようです。別のサーバーで動作するとおっしゃっていたので、設定の問題なのかしら。

7
safoo

拡張機能などをインストールせずにPHP(Windowsでも)内でSFTPを機能させる最も簡単な方法はPHPSECLIBです: http://phpseclib.sourceforge.net/ 。 SSHのものは完全にPHPクラスに実装されています。

使用するものは次のとおりです。

<?php
include('Net/SFTP.php');

$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
    exit('Login Failed');
}

echo $sftp->pwd();
?>
7
Max

そのページのドキュメントにエラーが含まれています。代わりに、ここの例を見てください。 http://php.net/ssh2_sftp -実際に行う必要があるのは、fopen(で使用する前にssh2_sftp()を使用して特別なSFTPリソースを開くことです。 )。そして、はい、それはそのように見えます、例えば文字列に変換すると「リソース#24」...少し奇妙ですが、明らかに機能します。

もう1つの注意点は、SFTPはリモートユーザーのホームディレクトリではなくルートディレクトリで開始されるため、URIのリモートパスは常に絶対パスである必要があることです。

3
mojuba

私は同じ問題を抱えていましたが、問題を理解することができました。

私の場合、サーバーに接続するときに、アカウントのルートに移動していましたが、サーバーの構成が原因で、そこに書き込むことができませんでした。

FireFTPを使用してアカウントに接続したので、アカウントのルートがどこにあるかを確認できました...それはサーバーのルートでした。

書き込みが許可されているフォルダーまでのパス全体を含める必要があったため、問題を解決できました。

したがって、私のアドバイスは、グラフィックインターフェイス(私はfireFTPを使用しました)を使用してパスを取得し、パス全体をコードに追加することです。


$pathFromAccountRootFolderToMyDestinationFolder = '/Account/Root/Folder/To/My/Folder';
$stream = fopen("ssh2.sftp://".$sftp."/".$pathFromAccountRootFolderToMyDestinationFolder."/myFile.ext", 'r');

これがあなたと同じ問題を抱えている他の人々に役立つことを願っています!

乾杯!

1
vfn

最近、PHPでSFTPを機能させようとしましたが、phpseclibの方がはるかに使いやすいことがわかりました。

http://phpseclib.sourceforge.net/

共有ホスト上にいないという贅沢があり、必要な拡張機能をインストールできる場合は、PECL拡張機能の方が良いかもしれませんが、私たち全員がそれほど幸運であるとは限りません。さらに、phpseclibのAPIはもう少し直感的に見え、OOPなどすべてです。

0
user216741

私の問題は、関数で接続し、内部にリソースを含む文字列URLを返すことでした。残念ながら、リソースは関数コンテキストで作成され、ガベージコレクターは関数側でリソースを切断しています。解決策:参照によってリソースを返し、より複雑なコンテキストで手動で設定を解除します。

0
Radenko

これは、私が数年前に見つけてphp.netにパッチを投稿したssh2パッケージのバグです。この問題は修正されますが、ssh2peclパッケージの再構築が必要です。詳細については、こちらをご覧ください: https://bugs.php.net/bug.php?id=69981 。この問題を修正するために、パッケージのssh2_fopen_wrappers.cファイルにパッチを含めました。これが私が含めたコメントです:

このバグの原因となるssh2_fopen_wrappers.cのコード行を次に示します:(コメントを含む)

/*
       Find resource->path in the path string, then copy the entire string from the original path.
       This includes ?query#fragment in the path string
*/
    resource->path = estrdup(strstr(path, resource->path));

このコード行(したがってこのバグ)は、バグ#59794の修正として導入されました。そのコード行は、パス変数からパーツ、クエリ、フラグメントを含む文字列を取得しようとしています。パス変数の次の値を考慮してください。

ssh2.sftp://Resource id #5/topdir?a=something#heading1

Resource-> pathが "/ topdir"の場合、コメントのとおり、 "/ topdir?a = something#heading1"がresource-> pathに割り当てられます。

ここで、resource-> pathが "/"の場合を考えてみましょう。コード行が実行されると、resource-> pathは "// Resource id#5/topdir#heading1"になります。これは明らかにあなたが望むものではありません。これを行うコード行は次のとおりです。

 resource->path = estrdup( strstr( strstr( path, "//" ) + 2, "/" ) );

Php_url_parse()を呼び出す前に、パス文字列から「リソースID#」を削除するバグ#73597のパッチを適用する必要がある場合もあります。

0
Ken Pardiac

(Powershell)サーバーでsftpサポートを有効にすることで問題を解決しました

0
David Lefkon