ftp_nb_continue()
The ftp_nb_continue() function is a PHP built-in function that continues an asynchronous FTP operation. The function takes one parameter:
What is ftp_nb_continue()?
ftp_nb_continue() is a built-in PHP function that resumes — or continues — a non-blocking FTP file transfer that was started earlier. The nb in the name stands for non-blocking: instead of freezing your script until a whole file is uploaded or downloaded, the non-blocking FTP functions return control after each chunk so your script can do other work in between.
This page covers what the function returns, how the non-blocking transfer loop works, how to handle errors, and the common pitfalls.
How non-blocking transfers work
A normal transfer such as ftp_get() blocks: PHP waits for the entire file before the next line runs. The non-blocking family — ftp_nb_get(), ftp_nb_put(), ftp_nb_fget() and ftp_nb_fput() — starts the transfer and returns immediately. You then call ftp_nb_continue() repeatedly to move the transfer forward one chunk at a time, until it reports it is finished.
The function returns one of three constants:
| Constant | Meaning |
|---|---|
FTP_MOREDATA | The transfer is still in progress — call ftp_nb_continue() again. |
FTP_FINISHED | The transfer completed successfully — stop the loop. |
FTP_FAILED | The transfer failed — handle the error and stop. |
Note: the start function (
ftp_nb_get()etc.) returns the same set of constants, so your loop logic must account for the transfer finishing on the very first call.
Syntax of ftp_nb_continue()
ftp_nb_continue(resource $ftp): intIt takes a single parameter, $ftp: the connection identifier returned by ftp_connect() or ftp_ssl_connect().
PHP 8.1+: the connection is now an
FTP\Connectionobject instead of aresource, but your code does not need to change — you still just pass the value you got back fromftp_connect().
Using ftp_nb_continue()
You first start a non-blocking transfer, then drive it to completion with a loop:
<?php
// Open the connection and log in
$ftp = ftp_connect('ftp.example.com');
ftp_login($ftp, 'username', 'password');
ftp_pasv($ftp, true); // passive mode is usually required behind firewalls
// Start a non-blocking download: local_file <- remote_file
$state = ftp_nb_get($ftp, 'local_file.txt', 'remote_file.txt', FTP_BINARY);
// Drive the transfer forward until it finishes or fails
while ($state === FTP_MOREDATA) {
// You can do other work here while the file streams in
$state = ftp_nb_continue($ftp);
}
if ($state === FTP_FINISHED) {
echo "Download complete.\n";
} else {
echo "Download failed.\n";
}
ftp_close($ftp);Note the argument order of ftp_nb_get(): it is (connection, local_file, remote_file, mode) — the local destination comes before the remote source.
Error handling
Always check the return value on every iteration. If ftp_nb_continue() returns FTP_FAILED, the transfer broke and you should stop and report it rather than loop forever:
<?php
$state = ftp_nb_get($ftp, 'local_file.txt', 'remote_file.txt', FTP_BINARY);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
switch ($state) {
case FTP_FINISHED:
echo "Transfer succeeded.\n";
break;
case FTP_FAILED:
echo "Transfer failed.\n";
break;
}Because the loop condition is === FTP_MOREDATA, it exits automatically on both FTP_FINISHED and FTP_FAILED — the switch afterwards then tells you which one happened.
Common pitfalls
- Forgetting to check the start function's return value. A small file can finish during
ftp_nb_get()itself, returningFTP_FINISHEDbefore the loop ever runs. Assigning that return value to$state(as above) handles this correctly. - Calling
ftp_nb_continue()with no active transfer. It only works while a non-blocking operation is pending; otherwise it returnsFTP_FAILED. - A tight, empty loop. The whole point of non-blocking FTP is to do useful work between calls. An empty
whileloop just busy-waits and gives you no advantage over the blockingftp_get(). - Passive mode. Behind a firewall or NAT you usually need
ftp_pasv()set totruebefore starting the transfer.
Conclusion
ftp_nb_continue() resumes a non-blocking FTP transfer that was started with ftp_nb_get(), ftp_nb_put(), ftp_nb_fget() or ftp_nb_fput(). Call it in a loop while it returns FTP_MOREDATA, stop on FTP_FINISHED, and handle FTP_FAILED — and your script stays responsive while files move in the background.