PHP7实现SFTP文件下载遇filesize报错问题求助
解决PHP ssh2扩展SFTP文件大小获取失败及下载问题
针对你遇到的PHP7使用ssh2扩展下载SFTP文件时,filesize()报错且ssh2_sftp_stat()返回size为0,但shell客户端能正常访问文件的问题,我整理了几个可行的解决思路:
1. 先验证SFTP路径与文件的存在性
首先确认你指定的远程路径和文件名完全正确——Linux服务器的SFTP路径区分大小写,且部分服务器的根目录并非你连接后的默认工作目录。可以先列出目标目录的文件来验证:
$dirHandle = opendir("ssh2.sftp://".intval($sftp)."/csv"); if (!$dirHandle) { die("Failed to open remote directory"); } echo "Remote directory files:\n"; while (($fileName = readdir($dirHandle)) !== false) { echo "- $fileName\n"; } closedir($dirHandle);
通过这个代码可以确认目标文件是否存在,以及文件名是否和你使用的完全一致(比如有没有多余的空格、大小写错误)。
2. 改用ssh2_sftp_lstat()获取文件信息
部分SFTP服务器上,ssh2_sftp_stat()可能因为符号链接、权限限制等原因返回错误的文件大小,而ssh2_sftp_lstat()会直接获取文件本身的元数据,试试替换成这个函数:
$stat = ssh2_sftp_lstat($sftp, $remotePath); print_r($stat);
如果这里能得到正确的size值,就可以用这个值来替代filesize()的结果进行后续的下载逻辑。
3. 跳过文件大小检查,直接流式下载
如果获取文件大小始终有问题,最可靠的方式是放弃预先获取文件大小,直接流式读取直到文件结束:
// 打开远程文件和本地文件 $remoteFile = fopen("ssh2.sftp://".intval($sftp).$remotePath, 'rb'); $localFile = fopen($file, 'wb'); if (!$remoteFile || !$localFile) { die("Failed to open remote or local file"); } // 分块读取并写入 while (!feof($remoteFile)) { // 使用8KB缓冲区,平衡性能和内存占用 $buffer = fread($remoteFile, 8192); if ($buffer === false) { break; } fwrite($localFile, $buffer); } // 关闭文件句柄 fclose($remoteFile); fclose($localFile);
这种方式不依赖文件大小的预获取,只要能打开文件就能完整下载,避免了stat失败的问题。
4. 替换为phpseclib库(推荐)
ssh2扩展本身存在不少兼容性和稳定性问题,如果你可以更换库,推荐使用纯PHP实现的phpseclib,它的SFTP功能更可靠,且不需要依赖系统的ssh2扩展:
首先通过Composer安装:
composer require phpseclib/phpseclib:^3.0
然后使用以下代码下载文件:
require 'vendor/autoload.php'; use phpseclib3\Net\SFTP; // 连接SFTP服务器 $sftp = new SFTP('your-sftp-host'); if (!$sftp->login('your-username', 'your-password')) { die("SFTP login failed"); } // 下载文件:远程路径 -> 本地路径 if (!$sftp->get($remotePath, $file)) { die("Failed to download file"); }
这个库的API更简洁,对各种SFTP服务器的兼容性更好,能避免很多ssh2扩展的坑。
内容的提问来源于stack exchange,提问作者Olga Pshenichnikova
相关产品推荐
相关产品推荐

