SFTP上传文件出现0字节错误,结合PHP代码寻求解决方案
SFTP上传文件出现0字节错误的排查与解决办法
我之前也碰到过一模一样的问题,结合你给出的代码片段,咱们一步步拆解可能的原因和对应的解决办法:
1. 核心问题:没正确读取本地上传的文件内容
你的代码里只拿到了上传文件的原始文件名$filename,但完全没处理PHP上传文件的临时存储路径。PHP会把上传的文件先存在服务器临时目录,路径存在$_FILES["fileToUpload"]["tmp_name"]里——如果直接创建远程文件但不把临时文件的内容写进去,远程文件自然就是0字节。
解决代码示例:
<?php if(isset($_POST["submit"])) { $filename = $_FILES["fileToUpload"]["name"]; $localTmpFile = $_FILES["fileToUpload"]["tmp_name"]; // 关键:获取本地临时文件路径 require_once('/home/Script_Server/login_server_ftp.php'); $resConnection = ssh2_connect($strServer, $strServerPort); if(ssh2_auth_password($resConnection, $strServerUsername, $strServerPassword)){ echo "connected"; $resSFTP = ssh2_sftp($resConnection); // 拼接远程文件完整路径 $remoteFilePath = "ssh2.sftp://{$resSFTP}/var/www/html/mysite.com/folder/" . $filename; $remoteFileHandle = fopen($remoteFilePath, 'w'); // 读取本地临时文件内容并写入远程 if ($remoteFileHandle) { fwrite($remoteFileHandle, file_get_contents($localTmpFile)); fflush($remoteFileHandle); // 强制刷新缓冲区 fclose($remoteFileHandle); echo "文件上传成功"; } else { echo "无法打开远程文件"; } ssh2_disconnect($resConnection); } else { echo "SFTP认证失败"; } }
2. 远程目录权限不足
如果远程目录/var/www/html/mysite.com/folder/没有给SFTP用户写入权限,系统可能允许你创建空文件,但无法写入内容,最终就是0字节。
排查与解决:
- 登录目标服务器,用
ls -l /var/www/html/mysite.com/查看目录权限,确保SFTP所属的用户/用户组有w(写入)权限。 - 可以先在代码里加个权限测试:
$testFile = "ssh2.sftp://{$resSFTP}/var/www/html/mysite.com/folder/test_perm.txt"; $testHandle = fopen($testFile, 'w'); if ($testHandle) { fwrite($testHandle, "权限测试内容"); fclose($testHandle); echo "目录权限正常"; unlink($testFile); // 测试完删除文件 } else { echo "远程目录无写入权限,请调整权限"; }
3. SSH2扩展缓冲区未刷新
有时候ssh2的fwrite不会立即把内容写入远程服务器,程序提前断开连接后,缓冲区的内容丢失,导致文件为空。
解决办法:
在fwrite之后调用fflush($remoteFileHandle)强制刷新缓冲区,再关闭文件句柄,最后断开SFTP连接(就像上面代码示例里那样)。
4. 大文件导致内存不足或超时
如果上传的文件很大,用file_get_contents一次性读取整个文件会占用大量内存,可能导致读取失败,进而写入空内容。
解决办法:分块读写
用循环分块读取本地文件,再写入远程,避免内存溢出:
$localHandle = fopen($localTmpFile, 'rb'); $remoteHandle = fopen($remoteFilePath, 'wb'); // 每次读取8KB分块写入 while (!feof($localHandle)) { fwrite($remoteHandle, fread($localHandle, 8192)); } fclose($localHandle); fclose($remoteHandle);
内容的提问来源于stack exchange,提问作者Th3Gh0st




