PHP - в фрагментированной копии файла (через FTP) отсутствуют байты?

Итак, я пишу фрагментированный сценарий передачи файлов, предназначенный для копирования файлов — маленьких и больших — на удаленный сервер. Это работает почти фантастически (и с 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

Кажется, это сработает, если я добавлю sleep(1) сразу после fwrite(). Однако из-за этого сценарий выполняется миллион лет. Возможно ли, что добавление PHP имеет какой-то врожденный недостаток?

РЕДАКТИРОВАТЬ 4

Хорошо, каким-то образом еще больше изолировал проблему от проблемы с FTP. Когда я запускаю эту копию файла локально, она работает нормально. Однако, когда я использую протокол передачи файлов (строка 9), байты отсутствуют. Это происходит, несмотря на то, что двоичный файл помечает два случая fopen(). Что может быть причиной этого?

РЕДАКТИРОВАТЬ 5

Я нашел исправление. Модифицированный код приведен выше - я опубликую ответ самостоятельно, как только смогу.


person Nathanael    schedule 02.07.2012    source источник
comment
Если вы открываете двоичный файл, вы должны использовать fopen(...,'rb')   -  person AlexDev    schedule 02.07.2012
comment
Замена fopen(..., 'r') на fopen(..., 'rb') дала тот же эффект. Спасибо хоть!   -  person Nathanael    schedule 02.07.2012
comment
Возможно, попробуйте также $destination_handle = fopen($destination, 'ab');   -  person AlexDev    schedule 02.07.2012
comment
это шатко перед отправкой на удаленный сервер?   -  person starbeamrainbowlabs    schedule 02.07.2012
comment
На самом деле я не уверен, как бы я это проверил. Похоже, это происходит только с очень большими файлами (такими как видео, как в приведенном выше коде), поэтому я действительно не знаю, как найти недостающие данные.   -  person Nathanael    schedule 02.07.2012
comment
Я (возможно) подтвердил, что скрипт каким-то образом умирает в конце, а не повреждает файлы. Я создал простой файл, в котором каждая строка соответствует номеру строки, вплоть до 10000, а затем запустил свой скрипт. Он остановился на строке 6253. Однако сценарий по-прежнему возвращает Done! в конце, поэтому я не могу представить, что это проблема тайм-аута. Странный!   -  person Nathanael    schedule 02.07.2012
comment
Я подтвердил, что проблема существует где-то в fwrite(). При повторении $chunk внутри цикла полный файл возвращается в обязательном порядке. Однако записанный файл все равно усекается.   -  person Nathanael    schedule 02.07.2012
comment
Вероятно, да, но просто для подтверждения, вы закрываете $destination_handle?   -  person AlexDev    schedule 02.07.2012
comment
Я не был, но это не имеет значения в любом случае. :/   -  person Nathanael    schedule 02.07.2012
comment
Кто-нибудь может воспроизвести эту проблему с большими файлами?   -  person Nathanael    schedule 03.07.2012
comment
Можете ли вы загрузить на ftp-сервер с помощью клиента? Является ли библиотека php ftp опцией? Я без проблем использовал это с файлами от 500K до 100M.   -  person Nick Maroulis    schedule 03.07.2012
comment
Я действительно могу загрузить на FTP-сервер с помощью клиента. И библиотека FTP, безусловно, вариант, но я не мог понять, как с ее помощью добавлять файлы к другим. Есть ли что-то очевидное, что я упускаю?   -  person Nathanael    schedule 03.07.2012


Ответы (1)


Я нашел исправление, хотя я точно не знаю, почему оно работает. Простой сон после записи каждого фрагмента решает проблему. Я немного увеличил размер блока, чтобы ускорить процесс. Хотя это, возможно, плохое решение, оно должно работать для моего использования. Все равно спасибо, ребята!

person Nathanael    schedule 03.07.2012