PHP - Chunked文件副本(通过FTP)丢失了字节?

时间:2012-07-02 16:15:31

标签: php ftp eof chunked

所以,我正在编写一个分块文件传输脚本,用于将文件(小型和大型)复制到远程服务器。它几乎可以很好地工作(并且我测试了26个字节的文件,哈哈)但是当我开始做更大的文件时,我注意到它不是很有效。例如,我上传了一个96,489,231字节的文件,但最终文件是95,504,152字节。我用928,670,754字节文件测试了它,复制的文件只有927,902,792字节。

有没有其他人经历过这个?我猜feof()可能会做一些不稳定的事情,但我不知道如何替换它,或者测试它。为方便起见,我对代码进行了评论。 :)

<?php

// FTP credentials
$server = CENSORED;
$username = CENSORED;
$password = CENSORED;

// Destination file (where the copied file should go)
$destination = "ftp://$username:$password@$server/ftp/final.mp4";

// The file on my server that we're copying (in chunks) to $destination.
$read = 'grr.mp4';

// If the file we're trying to copy exists...
if (file_exists($read))
{
    // Set a chunk size
    $chunk_size = 4194304;

    // For reading through the file we want to copy to the FTP server.
    $read_handle = fopen($read, 'rb');

    // For appending to the destination file.
    $destination_handle = fopen($destination, 'ab');

    echo '<span style="font-size:20px;">';
    echo 'Uploading.....';

    // Loop through $read until we reach the end of the file.
    while (!feof($read_handle))
    {
        // So Rackspace doesn't think nothing's happening.
        echo PHP_EOL;
        flush();

        // Read a chunk of the file we're copying.
        $chunk = fread($read_handle, $chunk_size);

        // Write the chunk to the destination file.
        fwrite($destination_handle, $chunk);

        sleep(1);
    }
    echo 'Done!';
    echo '</span>';
}

fclose($read_handle);
fclose($destination_handle);
?>

修改

我(可能已经)确认脚本最终会以某种方式死亡,而不是破坏文件。我创建了一个简单的文件,每行对应行号,最多10000个,然后运行我的脚本。它停在第6253行。但是,剧本仍在返回“完成!”最后,所以我无法想象这是一个超时问题。奇怪!

编辑2

我已确认问题存在于fwrite()中。通过在循环内回显$chunk,可以确保返回完整的文件。但是,写入的文件仍然不匹配。

编辑3

如果我在fwrite()之后立即添加sleep(1),它似乎有效。但是,这使脚本需要一百万年才能运行。 PHP的追加可能有一些固有的缺陷吗?

编辑4

好吧,不知何故,将问题进一步隔离成为FTP问题。当我在本地运行此文件副本时,它工作正常。但是,当我使用文件传输协议(第9行)时,字节丢失。尽管二元标记fopen()这两种情况,但仍在发生这种情况。可能导致这种情况的原因是什么?

编辑5

我找到了解决办法。修改后的代码在上面 - 我会尽快自己发布答案。

1 个答案:

答案 0 :(得分:1)

我找到了修复,但我不确定它为什么会起作用。在编写每个块之后简单地睡觉可以解决问题。为了加快速度,我大大提高了块大小。虽然这是一个可以说是糟糕的解决方案,但它应该适用于我的用途。不管怎样,谢谢你们!