I'm trying to upload a file using SFTP. Recently upgraded from PHP 7.4. The same code I wrote in 7.4 no longer works. Every time I attempt to upload a file it stops at 15KB.
If I make a new file with no data, the function completes the call. I get a 0KB file. I'm also able to download files with no problem.
I am using PHP 8.1.26 on IISv10. The version of SSH2 I am using is 1.3.1 https://pecl.php.net/package/ssh2/1.3.1/windows
Here is a code chunk I'm using to test this out. I know the code is awful, but it's just a test. You can see that I've tried many things. I have already verified that I don't have SCP access.
function ssh2sendtest($sshHost, $sshPort, $sshUsername, $sshPassword, $localFilePath) {
// Encryption methods for SSH connection (unnecessary)
$cryptoMethods = [
"client_to_server" => [
"crypt" => "aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-ctr,3des-cbc"
],
"server_to_client" => [
"crypt" => "aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-ctr,3des-cbc"
]
];
// Define the callback functions (does nothing)
$callbacks = array(
'disconnect' => function ($reason, $message, $language) {
echo "Disconnected with reason code [$reason] and message: $message\n";
},
'debug' => function ($message, $language, $always_display) {
echo "Debug message: $message\n";
},
'ignore' => function ($message) {
echo "Ignore message: $message\n";
},
'macerror' => function ($packet) {
echo "MAC error on packet: " . bin2hex($packet) . "\n";
return false; // Return false to disconnect if there's a MAC error
}
);
// Establishing SSH connection
$connection = ssh2_connect($sshHost, $sshPort); //, $cryptoMethods, $callbacks);
if (!$connection) {
return 'Connection failed';
//exit;
}
// Authentication
if (!ssh2_auth_password($connection, $sshUsername, $sshPassword)) {
return 'Authentication failed';
//exit;
}
// Initializing SFTP session
$sftp = ssh2_sftp($connection);
if (!$sftp) {
return 'SFTP session failed';
//exit;
}
// Remote file path
$uniqueHash = md5(uniqid(rand(), true));
$remoteFilePath = "/KSDOA/Inbound/test{$uniqueHash}.txt";
$openFile = fopen($localFilePath, "r");
file_put_contents("ssh2.sftp://{$sshUsername}:{$sshPassword}@{$sshHost}:22/{$remoteFilePath}", $openFile);
/*
// Opening remote file in write mode
$remoteFile = fopen("ssh2.sftp://{$sftp}{$remoteFilePath}", 'w');
if (!$remoteFile) {
return 'Failed to open remote file';
}
$localData = file_get_contents($localFilePath);
$writeLength = strlen($localData);
// Writing to the remote file
fwrite($remoteFile, $localData, $writeLength);
fflush($remoteFile); // Flush the output buffer
fclose($remoteFile);
// Closing the connection
ssh2_disconnect($connection);
*/
return "File written and command executed successfully.";
}
The server I'm using is capable of sending a file as I've been sending files for a long time before this stack update. I'm able to manually upload files using CoreFTP also.
What am I doing wrong? I can't find anything wrong with my stack or code (aside from the fact that I have to support it on Windows).
Edit-- Although I don't understand why I need a buffer now, this works.
// Preparing to write to the remote file
$remoteStream = fopen("ssh2.sftp://{$sftp}{$remoteFilePath}", 'w');
if (!$remoteStream) {
fclose($localStream);
die('Cannot open remote file');
}
// Reading from the local file and writing to the remote file
while ($buffer = fread($localStream, 4096)) {
fwrite($remoteStream, $buffer);
}
fclose($localStream);
fclose($remoteStream);
ssh2_disconnect($connection);
Reading the entire file does not work. It's not a memory limit issue, the file is ~35k. This does not work.
// Preparing to write to the remote file
$remoteStream = fopen("ssh2.sftp://{$sftp}{$remoteFilePath}", 'w');
if (!$remoteStream) {
fclose($localStream);
die('Cannot open remote file');
}
$localData = file_get_contents($localFilePath);
fwrite($remoteStream, $localData);
fclose($remoteStream);
ssh2_disconnect($connection);
Answer posted in edit. Will try Olivier's suggestion also soon. Would love any input as to why I can't write the entire file at once and instead I have to buffer the data. As I said this wasn't an issue in PHP 7.4.
Here is the function I used. The remote stream file checking is done elsewhere.
function uploadViaSFTP($localFile, $remoteStream) {
// Check if the local file does not exist or is empty
if (!file_exists($localFile) || filesize($localFile) === 0) {
return false; // Local file does not exist or is empty
}
// Open the local file for reading
$localStream = fopen($localFile, 'rb');
if (!$localStream) {
return false; // Failed to open local file
}
// Initialize success flag
$success = true;
// Read from the local file and write to the remote file
while (!feof($localStream)) {
$buffer = fread($localStream, 4096);
if ($buffer === false || fwrite($remoteStream, $buffer) === false) {
$success = false;
break; // Exit the loop in case of read or write error
}
}
// Close file streams
fclose($localStream);
fclose($remoteStream);
return $success;
}