How this extension can be used to append to existing files.
Closed this issue · 7 comments
I have a very slow process and HUGE CSV files.
The idea is whenever a reasonable sized piece of data is ready for it to be appended to a temporary FTP file. When the whole process finishes, the file is renamed to it's final position (name), so some 3rd party starts the processing with the whole data-set.
I know that this can be done with file_put_contents and some stream hacks, but it's ugly to have 2 ways of doing a single thing.
Any guidelines would be appreciated.
I think you can't because FTP protocol can't merge file.
So after some more research, the FTP protocol allows it to have append.
http://stackoverflow.com/questions/2536592/use-of-ftp-append-command it is documented also in the RFC search for APPEND (with create) (APPE)
.
The thing is that for some reason the PHP's ftp api has not implemented this.
Thugh you can achieve it through ftp:// stream and using the APPEND flags there.
The problem with that solution is that the authentication and all the network communication will be doubled for a single append of a file, even though a handle is already created.
I am pretty sure that this should be possible through exec or a raw command. I will be testing it tomorrow.
I've made it work with the proposal from the first comment but that's more of a hack than a solution, as it is not using the existing handle, but making a new connection on each append...
class FtpComponent extends \gftp\FtpComponent
{
public function __construct($config = array())
{
parent::__construct($config);
}
public function append($localFile, $remoteFile)
{
if (($contents = file_get_contents($localFile)) === false) {
throw new FtpException("Failed reading from local file: $localFile!");
}
$connection = rtrim($this->getConnectionString(), '/');
$path = "$connection/" . ltrim($remoteFile, '/');
($result = file_put_contents($path, $contents, FILE_APPEND));
if ($result === false) {
throw new FtpException("Failed writing to file: $remoteFile");
}
if (($expected = strlen($contents)) !== (int) $result) {
throw new FtpException("Written only $result out of $expected bytes to the remote file!");
}
return $result;
}
}
Is it an option to have a driver that will handle stream-based connections?
It will be based on the PHP primitives for file management and fallback to the streaming API underneath.
That way the communication will at least be consistent within the driver.
So I was not able to make this work with the ftp_* APIs so this propagated to PHP.
Hi, yes it is possible to implements such driver but I no time to develop it.
I just added support for resource in put and get method... I see ftp_fget / ftp_fput have an extra parameter resumePos (http://php.net/manual/en/function.ftp-fget.php) / startPos (http://php.net/manual/en/function.ftp-fput.php)
I think it can be use to append file.