php fwrite() не заканчивает запись строковых данных в файл, почему?

Я пытаюсь записать значительный кусок данных в файл, который открывается через fopen() в php. Оболочка протокола, которую я использую, — это ftp, поэтому файл удален от сервера, на котором запущен php-код. Файл, в который я пишу, находится на сервере Windows.

Я убедился, что файл на самом деле создается моим php-кодом, но проблема в том, что данные в файле либо не существуют (0 КБ), либо запись в файл останавливается преждевременно. Не уверен, почему это так.

Вот код, который я использую для обработки операции:

$file_handle = fopen($node['ftp'].$path_to_lut, "wb", 0, $node['ftp_context']);
include_once($file);

if ($file_handle)
{
     fwrite($file_handle, $string);  //$string is inside included $file
     fclose($file_handle);
} else {
     die('There was a problem opening the file.');
}

Этот код отлично работает, когда я размещаю его на своем локальном компьютере, но когда я загружаю его на свой веб-хост (Rackspace Cloud), он не работает. Это заставляет меня поверить, что это проблема, связанная с конфигурацией моего сервера в Rackspace, но я хочу знать, могу ли я что-нибудь сделать с моим php-кодом, чтобы сделать его более надежным.

Есть идеи, как убедиться, что fwrite действительно заканчивает запись строки на удаленную машину?

Спасибо!

Хорошо, я изменил код, который записывает в файл, вот так:

if ($file_handle)
{
    if ($bytesWritten = fwrite($file_handle, $string) ) {
        echo "There were " . $bytesWritten . " bytes written to the text file.";
    }

    if (!fflush($file_handle)) {
        die("There was a problem outputting all the data to the text file.");
    }

    if (!fclose($file_handle)) { 
        die("There was a problem closing the text file."); 
    }

} else {

    die("No file to write data to.  Sorry.");

}

Странно то, что инструкция echo показывает следующее:

В текстовый файл было записано 10330 байт.

И все же, когда я проверяю размер текстового файла через FTP, он показывает, что он равен 0 КБ, а данные внутри файла фактически усекаются. Я не могу представить, что это связано с самим FTP-сервером, потому что он работает, если PHP размещен на машине, отличной от той, что находится в Rackspace Cloud.

** ОБНОВЛЕНИЕ ** Я разговаривал с представителем Rackspace Cloud, который упомянул, что им требуется пассивный ftp, если вы собираетесь использовать ftp с их серверов. Я настроил удаленный сервер для обработки пассивных ftp-соединений и убедился, что пассивный ftp теперь работает на удаленном сервере через ftp-клиент OSX Transmit. Я добавил:

ftp_pasv($file_handle, true);

Сразу после оператора fopen() я получаю сообщение об ошибке от PHP, говорящее, что я не предоставил действительный ресурс для ftp_pasv(). Как я могу гарантировать, что соединение с ftp-сайтом, которое делает PHP, является PASV, а не ACTIVE, и по-прежнему использовать fwrite()? Между прочим, я заметил, что Windows-машина сообщает, что файл, записываемый моим PHP-кодом, имеет размер 4096 байт на диске. Больше этой суммы никогда не бывает. Это заставило меня изменить значение php output_buffering на 65536 только для устранения неполадок, но это также не решило проблему. . .

** ОБНОВЛЕНИЕ ЧАСТИ DUEX **

Устранение неполадок на моем виртуальном сервере в продукте Rackspace Cloud Sites оказалось слишком сложным, поскольку они не предлагают достаточных прав администратора. Я создал очень маленький облачный сервер на продукте Rackspace Cloud Server и настроил все так, что все еще вижу ту же ошибку с fwrite(). Чтобы убедиться, что я могу записать файл с этого сервера на удаленный сервер, я использовал основные команды ftp в моей оболочке bash на облачном сервере. Это работало нормально. Итак, я предполагаю, что в php-реализации fwrite() есть ошибка, и что это, вероятно, связано с какой-то проблемой регулирования данных. Когда я пишу на удаленный сервер из своей локальной среды, которая имеет медленную скорость по сравнению с тем, что предлагается на сервере Rackspace Cloud, все работает нормально. Есть ли способ эффективно снизить скорость записи? Просто спрашиваю :)

** ОБНОВЛЕНИЕ ЧАСТИ III *

Итак, я воспользовался предложением @a sad dude и реализовал функцию, которая может помочь кому-то, пытающемуся записать новый файл, и полностью отправить его по ftp:

function writeFileAndFTP($filename=null, $data=null, $node=null, $local_path=null, $remote_path=null)
{

    //  !Determin the path and the file to upload from the webserver
    $file = $local_path.'/'.$filename;


    //  !Open a new file to write to on the local machine
    if (!($file_handle = fopen($file, "wb", 0))) { 
        die("There was a problem opening ".$file." for writing!");
    }


    //  !Write the file to local disk
    if ($bytesWritten = fwrite($file_handle, $data) ) {
        //echo "There were " . $bytesWritten . " bytes written to " . $file;
    }

    //  !Close the file from writing
    if (!fclose($file_handle)) {
        die("There was a problem closing " . $file);
    }

    //  !Create connection to remote FTP server
    $ftp_cxn = ftp_connect($node['addr'], $node['ftp_port']) or die("Couldn't connect to the ftp server.");

    //  !Login to the remote server
    ftp_login($ftp_cxn, $node['user'], getPwd($node['ID'])) or die("Couldn't login to the ftp server.");

    //  !Set PASV or ACTIVE FTP
    ftp_pasv($ftp_cxn, true);


    //  !Upload the file
    if (!ftp_put($ftp_cxn, $remote_path.'/'.$filename, $file, FTP_ASCII)) {
        die("There was an issue ftp'ing the file to ".$node['addr'].$remote_path);  
    }

    //  !Close the ftp connection
    ftp_close($ftp_cxn);

}

person ariestav    schedule 27.02.2012    source источник
comment
include_once($file); - где этот код?   -  person hakre    schedule 28.02.2012
comment
Это выглядит следующим образом: $string = "a string about 20 lines long";   -  person ariestav    schedule 28.02.2012
comment
Что выводит var_dump($node['ftp_context']);? (удалить логин/пароль).   -  person hakre    schedule 28.02.2012
comment
ресурс(32) типа (контекст потока)   -  person ariestav    schedule 28.02.2012
comment
Кроме того, код var_dump(stream_get_meta_data($file_handle)); выводит: array(10) { ["wrapper_data"]=> NULL ["wrapper_type"]=> string(3) "ftp" ["stream_type"]=> string(14) "tcp_socket/ssl" ["mode"]=> string(2) "r+" ["unread_bytes"]=> int(0) ["seekable"]=> bool(false) ["uri"]=> string(119) "ftp://user:[email protected]:21/vars.txt" ["timed_out"]=> bool(false) ["blocked"]=> bool(true) ["eof"]=> bool(false) }   -  person ariestav    schedule 28.02.2012
comment
можете ли вы убедиться, что папка и файл, в которые вы пишете, имеют действительное разрешение. chown до 777 попробуйте еще раз. если это сработает, вы, по крайней мере, будете знать, что с разрешениями что-то не так. Суть в том, что пользователь FTP должен иметь доступ на запись в папку, в которую вы пишете.   -  person Jaspreet Chahal    schedule 28.02.2012
comment
Я на 100% уверен, что у пользователя ftp есть права на запись в папку. Как я писал в посте, файл создается и записывается, но в некоторых случаях данные усекаются или файл оказывается пустым. Я очень сомневаюсь, что это проблема с разрешениями.   -  person ariestav    schedule 28.02.2012
comment
Поместите fflush($file_handle); над закрытием. Также вам нужно проверить возвращаемые параметры всех этих функций, потому что они сообщат вам, если они потерпели неудачу, например. если fclose не удалось успешно закрыть. См. руководство для каждой функции и их возвращаемых значений.   -  person hakre    schedule 28.02.2012
comment
Пожалуйста, обновите свой вопрос (добавьте его ниже) вместо того, чтобы вводить код в комментарий;) - И вы можете проверить размер файла через FTP после записи в файл для целей отладки.   -  person hakre    schedule 28.02.2012
comment
Прости за это. Я новичок в StackOverflow. Я обновил вопрос.   -  person ariestav    schedule 28.02.2012


Ответы (1)


Длина строки, которую fwrite может записать за один раз, ограничена на некоторых платформах (поэтому она возвращает количество записанных байтов). Вы можете попробовать запустить его в цикле, но лучше просто использовать file_put_contents, что гарантирует запись всей строки.

http://www.php.net/manual/en/function.file-put-contents.php

person a sad dude    schedule 27.02.2012
comment
Интересно, спасибо за наводку. Из любопытства, есть ли директива apache, которую я могу установить в файле .htaccess, чтобы изменить ограничение данных для fwrite()? - person ariestav; 28.02.2012
comment
Сомнительно ) плюс, если вы используете ftp, я думаю, это больше связано с сетью. Работал ли file_put_contents? - person a sad dude; 28.02.2012
comment
Нет, не работал. Файл создается, но данные в него не записываются. - person ariestav; 28.02.2012
comment
Через Apache вы можете изменить директивы PHP ini (при условии, что модуль PHP включен). Хотя это не очень хорошая практика. Однако вам придется проверить, есть ли в PHP такая возможность. - person Christian; 01.03.2012
comment
Вы можете проверить, включен ли модуль PHP на сервере - php.net /manual/en/book.ftp.php - и попробуйте вместо этого. Или, может быть, какая-то библиотека PHP. - person a sad dude; 01.03.2012
comment
Ой, извините, не увидел обновление. Вы уже пытаетесь использовать функцию из этого модуля, но, я полагаю, на дескрипторе, созданном с помощью fopen. Вместо этого вы должны использовать ftp_connect - person a sad dude; 01.03.2012
comment
@a sad dude: Что касается ftp_connect, вы предлагаете мне записать файл на локальный диск веб-сервера, а затем загрузить этот файл на удаленный сервер? Я не уверен, как я могу использовать ftp_connect без предварительной записи файла на диск. С fwrite() кажется, что меньше времени, так как данные записываются в место назначения. - person ariestav; 01.03.2012
comment
Предложение сначала записать файл на веб-сервер, а затем загрузить файл целиком на узел удаленного сервера сработало. Пожалуйста, смотрите мой код выше. - person ariestav; 02.03.2012