ssh2_sftp

(PECL ssh2 >= 0.9.0)

ssh2_sftp初始化 SFTP 子系统

描述

ssh2_sftp(resource $session): resource|false

从已连接的 SSH2 服务器请求 SFTP 子系统。

参数

session

一个 SSH 连接链接标识符,从调用 ssh2_connect() 获得。

返回值

此方法返回一个 SSH2 SFTP 资源,用于所有其他 ssh2_sftp_*() 方法和 ssh2.sftp:// fopen 包装器,如果失败则返回 false

示例

示例 #1 通过 SFTP 打开文件

<?php
$connection
= ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');

$sftp = ssh2_sftp($connection);

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

参见

添加备注

用户贡献的备注 13 则

50
David Barnes
17 年前
以下是如何使用 SFTP 发送文件的示例

<?php

class SFTPConnection
{
private
$connection;
private
$sftp;

public function
__construct($host, $port=22)
{
$this->connection = @ssh2_connect($host, $port);
if (!
$this->connection)
throw new
Exception("无法连接到 $host 端口 $port.");
}

public function
login($username, $password)
{
if (! @
ssh2_auth_password($this->connection, $username, $password))
throw new
Exception("无法使用用户名 $username " .
"和密码 $password 进行身份验证.");

$this->sftp = @ssh2_sftp($this->connection);
if (!
$this->sftp)
throw new
Exception("无法初始化 SFTP 子系统.");
}

public function
uploadFile($local_file, $remote_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');

if (!
$stream)
throw new
Exception("无法打开文件: $remote_file");

$data_to_send = @file_get_contents($local_file);
if (
$data_to_send === false)
throw new
Exception("无法打开本地文件: $local_file.");

if (@
fwrite($stream, $data_to_send) === false)
throw new
Exception("无法从文件发送数据: $local_file.");

@
fclose($stream);
}
}

try
{
$sftp = new SFTPConnection("localhost", 22);
$sftp->login("username", "password");
$sftp->uploadFile("/tmp/to_be_sent", "/tmp/to_be_received");
}
catch (
Exception $e)
{
echo
$e->getMessage() . "\n";
}

?>
6
Josh
9 年前
请注意,您必须输入完整包装器 URI 顺序才能使接受这些参数的函数正常工作。例如,以下代码(在其他注释中被多次引用)不起作用

while (false !== ($file = readdir($handle))) if (is_dir($file)) { /* ... */ }

以下代码可以正常工作

$sc = ssh2_sftp(...);
while (false !== ($file = readdir($handle))) if (is_dir("ssh2.sftp://$sc/$file")) { /* ... */ }

您需要将“路径”作为 fopen() 包装器 URI 传递给这些函数。
9
bas weerman
16 年前
我添加了一些用于扫描文件系统、接收和删除文件的功能。

class SFTPConnection
{
private $connection;
private $sftp;

public function __construct($host, $port=22)
{
$this->connection = @ssh2_connect($host, $port);
if (! $this->connection)
throw new Exception("无法连接到 $host 端口 $port.");
}

public function login($username, $password)
{
if (! @ssh2_auth_password($this->connection, $username, $password))
throw new Exception("无法使用用户名 $username " . "和密码 $password 进行身份验证.");
$this->sftp = @ssh2_sftp($this->connection);
if (! $this->sftp)
throw new Exception("无法初始化 SFTP 子系统.");
}

public function uploadFile($local_file, $remote_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');
if (! $stream)
throw new Exception("无法打开文件: $remote_file");
$data_to_send = @file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("无法打开本地文件: $local_file.");
如果 (@fwrite($stream, $data_to_send) === false)
抛出新异常("无法从文件发送数据: $local_file.")
@fclose($stream);
}

函数 scanFilesystem($remote_file) {
$sftp = $this->sftp;
$dir = "ssh2.sftp://$sftp$remote_file";
$tempArray = 数组();
$handle = opendir($dir);
// 列出所有文件
当 (false !== ($file = readdir($handle))) {
如果 (substr("$file", 0, 1) != "."){
如果(is_dir($file)){
// $tempArray[$file] = $this->scanFilesystem("$dir/$file");
} 否则 {
$tempArray[]=$file;
}
}
}
closedir($handle);
返回 $tempArray;
}

公共函数 receiveFile($remote_file, $local_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'r');
if (! $stream)
throw new Exception("无法打开文件: $remote_file");
$contents = fread($stream, filesize("ssh2.sftp://$sftp$remote_file"));
file_put_contents ($local_file, $contents);
@fclose($stream);
}

公共函数 deleteFile($remote_file){
$sftp = $this->sftp;
unlink("ssh2.sftp://$sftp$remote_file");
}
}
2
bas weerman
16 年前
我将读取函数改为

公共函数 receiveFile($remote_file, $local_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'r');
if (! $stream)
throw new Exception("无法打开文件: $remote_file");
$size = $this->getFileSize($remote_file);
$contents = '';
$read = 0;
$len = $size;
当 ($read < $len && ($buf = fread($stream, $len - $read))) {
$read += strlen($buf);
$contents .= $buf;
}
file_put_contents ($local_file, $contents);
@fclose($stream);
}

公共函数 getFileSize($file){
$sftp = $this->sftp;
返回 filesize("ssh2.sftp://$sftp$file");
}
2
Curtis Wyatt
16 年前
David Barnes提供的sftp类工作良好。但是,如果你收到关于fopen的错误,并且它无法打开流,请尝试远程服务器上的完全限定路径。

例如,如果你将文件上传到/Users/username/Sites/file.txt,这可能不起作用

<?php
尝试 {
$sftp = new SFTPConnection("localhost", 22);
$sftp->login("username", "password");
$sftp->uploadFile("/tmp/to_be_sent", "Sites/file.txt");
}
捕获 (
Exception $e) {
回显
$e->getMessage() . "\n";
}
?>

但是这将

<?php
尝试 {
$sftp = new SFTPConnection("localhost", 22);
$sftp->login("username", "password");
$sftp->uploadFile("/tmp/to_be_sent", "/Users/username/Sites/file.txt");
}
捕获 (
Exception $e) {
回显
$e->getMessage() . "\n";
}
?>

不要假设因为你是以该用户身份连接,所以你从其主目录空间开始。

另一个可能的选项是,你需要先使用 http://us.php.net/manual/en/function.ssh2-sftp-mkdir.php 创建目录(如果它尚不存在),然后将文件上传到其中。
1
Jaybee
10年前
上传(写入)文件时,必须使用绝对路径,而不是相对路径。

如果你像我一样,想使用相对路径,你可以使用以下代码

$fh=fopen("ssh2.sftp://$sftp".ssh2_sftp_realpath($sftp,".")."/fileinmyhomedir.txt");
2
webakiro at gmail dot com
8年前
如果你想存储一次使用的协议+资源("ssh2.sftp://$sftp";)
有一个小技巧需要知道...
这将不起作用

<?php
函数 connect(){
$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
返回
"ssh2.sftp://$sftp";
}
$remote = connect();
is_file( $remote."/path/to/file");
// 警告
// 消息: is_file(): ## 不是有效的 SSH2 SFTP 资源
?>

你必须在函数(is_file、filesize、fopen等)使用它时,让$sftp保持可用状态
否则,我猜GC会清理它并关闭ssh2_stfp连接
这就是为什么这有效

<?php
函数 connect(){
//...
全局 $sftp;
$sftp = ssh2_sftp($connection);
返回
"ssh2.sftp://$sftp";
}
$remote = connect();
is_file( $remote."/path/to/file");

// 或者更好的方法:

myClass {
公共函数
connect(){
//...
$this->sftp = ssh2_sftp($connection);
$this->remote = "ssh2.sftp://".$this->sftp;
}
公共函数
test(){
is_file( $this->remote."/path/to/file");
}
}
$obj = new myClass();
$obj->connect();
$obj->test();
?>
1
Jarrod Christman
7年前
David的代码运行良好,除了有一点,它不会上传文件,直到我在'$sftp'后面添加一个正斜杠

public function uploadFile($local_file, $remote_file)
{
$sftp = $this->sftp;
// 原始
// "ssh2.sftp://$sftp$remote_file"
$stream = @fopen("ssh2.sftp://$sftp/$remote_file", 'w');

if (! $stream)
throw new Exception("无法打开文件: $remote_file");

$data_to_send = @file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("无法打开本地文件: $local_file.");

如果 (@fwrite($stream, $data_to_send) === false)
抛出新异常("无法从文件发送数据: $local_file.")

@fclose($stream);
}
0
Youz
5年前
向之前的类添加一个函数,使用密钥而不是用户名/密码进行连接

<?php
公共函数 loginWithKey($username, $publicKey, $privateKey, $passphrase = null)
{
如果 (!@
ssh2_auth_pubkey_file($this->connection, $username, $publicKey, $privateKey, $passphrase)) {
抛出新异常 (
"无法使用给定的密钥或密码短语进行身份验证");
}

$this->sftp = @ssh2_sftp($this->connection);
如果 (!
$this->sftp) {
抛出新异常 (
"无法初始化 SFTP 子系统.");
}
}

?>
0
php at kanariepiet dot com
6年前
请记住,出于性能原因,在资源上使用stream_set_chunk_size(),特别是如果你在高延迟的链路上上传大文件。

SFTP 只能在一个数据包中发送 32K 数据,并且 libssh2 将在发送完每个数据包后等待响应。因此,如果默认块大小为 8K,则上传速度将非常慢。
如果你将块大小设置为例如 1Mb,libssh2 将在多个 32K 数据包中发送该块,然后等待响应,从而使上传速度更快。
(有关详细信息,请参阅 man libssh2_sftp_write)

<?php
$connection
= ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'w');

stream_set_chunk_size($stream, 1024*1024);
fwrite($stream, $data);
?>
0
btafoya at briantafoya dot com
7年前
这是一个修改后的 SFTPConnection 类,它之前发布过,并返回了一个递归目录扫描 scanFilesystem 方法。

<?php
class SFTPConnection
{
private
$connection;
private
$sftp;

public function
__construct($host, $port=22)
{
$this->connection = @ssh2_connect($host, $port);
if (!
$this->connection)
throw new
Exception("无法连接到 $host 端口 $port.");
}

public function
login($username, $password)
{
if (! @
ssh2_auth_password($this->connection, $username, $password))
throw new
Exception("无法使用用户名 $username 和密码 $password 进行身份验证.");
$this->sftp = @ssh2_sftp($this->connection);
if (!
$this->sftp)
throw new
Exception("无法初始化 SFTP 子系统.");
}

public function
uploadFile($local_file, $remote_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');
if (!
$stream)
throw new
Exception("无法打开文件: $remote_file");
$data_to_send = @file_get_contents($local_file);
if (
$data_to_send === false)
throw new
Exception("无法打开本地文件: $local_file.");
if (@
fwrite($stream, $data_to_send) === false)
throw new
Exception("无法从文件发送数据: $local_file.");
@
fclose($stream);
}

function
scanFilesystem($remote_file) {
$sftp = $this->sftp;
$dir = "ssh2.sftp://$sftp$remote_file";
$tempArray = array();

if (
is_dir($dir)) {
if (
$dh = opendir($dir)) {
while ((
$file = readdir($dh)) !== false) {
$filetype = filetype($dir . $file);
if(
$filetype == "dir") {
$tmp = $this->scanFilesystem($remote_file . $file . "/");
foreach(
$tmp as $t) {
$tempArray[] = $file . "/" . $t;
}
} else {
$tempArray[] = $file;
}
}
closedir($dh);
}
}

return
$tempArray;
}

public function
receiveFile($remote_file, $local_file)
{
$sftp = $this->sftp;
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'r');
if (!
$stream)
throw new
Exception("无法打开文件: $remote_file");
$contents = fread($stream, filesize("ssh2.sftp://$sftp$remote_file"));
file_put_contents ($local_file, $contents);
@
fclose($stream);
}

public function
deleteFile($remote_file){
$sftp = $this->sftp;
unlink("ssh2.sftp://$sftp$remote_file");
}
}
?>
0
sandipshah at vthrive dot com
14 年前


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

请确保您指定了文件的“绝对”路径。

如果没有,您将收到类似以下的错误消息

"无法打开文件 ..."

原因很简单 ... ssh2.sftp://$sftp 指向远程服务器上的“根”目录,在大多数情况下,您可能没有访问权限。

有必要将其指向您的“主目录”。例如,“ssh2.sftp://$sftp/home/username/filename”... 其中“/home/username” 是您的主目录所在的位置。
0
duke1 at drakkon dot net
16 年前
如果有人对如何获取目录列表感兴趣
$SSH_CONNECTION= ssh2_connect('shell.example.com', 22);
ssh2_auth_password($SSH_CONNECTION, 'username', 'password');
//-------------------------------------------------------------------
// 此函数查找给定目录中的所有文件并返回它们
function scanFilesystem($dir) {
$tempArray = 数组();
$handle = opendir($dir);
// 列出所有文件
当 (false !== ($file = readdir($handle))) {
如果 (substr("$file", 0, 1) != "."){
如果(is_dir($file)){
$tempArray[$file]=scanFilesystem("$dir/$file");
} 否则 {
$tempArray[]=$file;
}
}
}
closedir($handle);
返回 $tempArray;
}

//-------------------------------------------------------------------
$sftp = ssh2_sftp($SSH_CONNECTION);

// 获取所有传出文件的列表的代码
$dir = "ssh2.sftp://$sftp/outgoing";
$outgoing = scanFilesystem($dir);
sort($outgoing);
print_r($outgoing);
To Top