Запись в файл fwrite

e_moon

Новичок
Здравствуйте,

столкнулся с такой проблемой: необходимо записывать довольно большой объем данных полученный из SQL-запрпоса в текстовый файл. Итоговый размер файла ~15Мб.

Процедура такая:

PHP:
$fp=fopen('filename.txt','w'); //создать файл и открыть для записи с флагом w+
flock($fp, LOCK_EX); //блокировка LOCK_EX
fwrite($fp,'Заголовок'."\r\n"); //запись заголовка файла

while($Data=mysql_fetch_array($Result)) //до 50тыс. интераций
{
     if($Data['string'])
     fwrite($fp,$Data['string']."\r\n"); //построчная запись основных данных
}

fwrite($fp,'Подпись'); //запись подписи к файлу
flock($fp, LOCK_UN); //разблокировка LOCK_UN
fclose($fp); //закрыть
Все работает, но! Переодически получается такая лажа: в начале файла, вместо первых N записей, появляются непонятные символы. Komodo Edit обозначает их как NUL (очень много таких символов, вытянутых в одну строку). Что это может быть? В логе никаких ошибок или замечаний.
 

scorpion-ds

Новичок
По вашему коду проблема не видна, думаю стоит посмотреть на первые записи получаемые из $Data, возможно проблема в них.
 

radioheaded

PHP нуб
Вы уверены, что у вас работает именно этот код, который вы привели? На мой взгляд, он работать не может хотя бы из-за первой строки.
 

e_moon

Новичок
По вашему коду проблема не видна, думаю стоит посмотреть на первые записи получаемые из $Data, возможно проблема в них.
Ну вот, а как их можно проверить? В бд все записи - ок. По идее if($Data['String']) не должно веднуть True, если с данными что-либо не так. И вряд ли поможет is_string(), если там имеется какой-то набор символов.

Вы уверены, что у вас работает именно этот код, который вы привели? На мой взгляд, он работать не может хотя бы из-за первой строки.
Опечатался, уже подправил.
 

radioheaded

PHP нуб
Опечатался, уже подправил.
И все равно не будет работать. Но даже если учесть, что где-то у вас есть действительно работающий код, то почему вас смущают непечатаемые символы в строках? Вы уверены, что в бд их нет, и они появляются именно в результате работы кода?
 

e_moon

Новичок
И все равно не будет работать. Но даже если учесть, что где-то у вас есть действительно работающий код, то почему вас смущают непечатаемые символы в строках? Вы уверены, что в бд их нет, и они появляются именно в результате работы кода?
Уверен. Посудите сами, хотябы по тому, что к каждой строке из бд добавляется "\r\n". В этом случае NUL должны быть разделены переводом строки, а все они записываются в оду. Выходит, что fwrite($fp,$Data['string']."\r\n") записывает NUL (попробую в каком-нибуть Win HEx редакторе еще глянуть, что за символы).
 

Фанат

oncle terrible
Команда форума
приведите уже реальный код
без него разговаривать не о чем.
 

e_moon

Новичок
приведите уже реальный код
без него разговаривать не о чем.
Код большой, потому сократил его к сути.

Вот полностью цикл While:

PHP:
while($Data=mysql_fetch_array($Result))
{
    if($Data['String'])
    {
	if($Data['album']==1 AND isset($_POST['write_photos_info']))
	{
	    $imgRes=$this->MySQL->query('SELECT * FROM '._DBNAME_.'_img WHERE uid='.(int)$Data['id'].' GROUP BY filepath ORDER BY id ASC LIMIT 0,100');
  	    while($imgData=mysql_fetch_array($imgRes))
    	    {
            	$Images[$imgData['uid']][]=$imgData['filepath'];
     	    }
     	    unset($imgRes,$imgData);
     	}

	$URLimages=Null;

	if(isset($Images[$Data['id']]))
	{
	    for($p=0;$p<count($Images[$Data['id']]);$p++)
	    {
		if($Images[$Data['id']][$p])
		$URLimages.="<useralbum>\r\n\t<img>".$Images[$Data['id']][$p]."</img>\r\n</useralbum>\r\n";
	    }
	    unset($Images);
	}
	
        $Data['url']=preg_replace('/^http:\/\//i',Null,$Data['url']);

	$Buff="<userinfo>\r\n\t<pageurl>".$Data['url']."</pageurl>\r\n";
	$Buff.=$URLimages;
	$Buff.=(isset($_POST['last_l']) ? "\t<lastlogin>".($Data['lastinput'])."</lastlogin>\r\n" : Null);
	$Buff.=(isset($_POST['last_c']) ? "\t<lastedit>".($Data['lastchange'])."</lastedit>\r\n" : Null);
	$Buff.="</userinfo>\r\n";

	if($Buff)
	fwrite($this->XML,$Buff);
					
	unset($Data,$Buff,$p);
    }
}
unset($URLimages,$Result);
 

e_moon

Новичок
Вот собственно возник такой вопрос... А есть какое-либо ограничение на макс. длину строки для функции fwrite?! Не документированные баги/рекомендации так сказать? Пока ничего не нашел по этому поводу.
 

radioheaded

PHP нуб
Да нет никаких ограничений. Просто в базе у вас строки с нулевыми символами, так они и выводятся.
 

radioheaded

PHP нуб
А с чего вы решили, что переносы строк пропадают? На глазок? Покажите hex пары выводимых строк. И если сомневаетесь, это же просто проверить. Очистите таблицу, добавьте пару записей с простым текстом, не содержащим никаких спецсимволов, и запустите код.
 

e_moon

Новичок
А с чего вы решили, что переносы строк пропадают? На глазок? Покажите hex пары выводимых строк. И если сомневаетесь, это же просто проверить. Очистите таблицу, добавьте пару записей с простым текстом, не содержащим никаких спецсимволов, и запустите код.
Почему решил... Win Hex показывает нули 00 00 00... Да, кстати, первая строка fwrite($fp,'Заголовок'."\r\n"), которая записывается перед while также вылетает. В итоге файл начинается и до N-й строки заполняется просто нулями. Протестить и отловить проблему не получается. Попробую поюзать ftruncate().
 

radioheaded

PHP нуб
Ни print_r, ни var_dump не помогут, нулевой символ — непечатаемый. Поможет var_export

PHP:
php -r 'var_dump("\0\0\0abc");'
// string(6) "abc"
php -r 'var_export("\0\0\0abc");'
// '' . "\0" . '' . "\0" . '' . "\0" . 'abc'
 

e_moon

Новичок
В общем, разобрался. Оказывается, что при одновременном доступе к файлу различными процессами (данный скрипт работает по крону) уже записанное в него содержимое действительно заменяется нулями. Как оказалось, у меня вылазит такое в случае, когда запись файла занимает времени больше чем должно пройти его до очередного запуска срипта по крону.

Нашел интересную идею с flock($fp, LOCK_EX | LOCK_NB). Вроде работает.
 

fixxxer

К.О.
Партнер клуба
Нашел интересную идею с flock($fp, LOCK_EX | LOCK_NB). Вроде работает.
Какое-то странное магическое заклинание... :)

Тут на самом проблема в том, что при открытии с флагом w обрезка проходит до установки блокировки, и соответственно между fopen и flock параллельные процессы успевают что-то еще сделать. Чтобы этого избежать, обычно действуют так (для краткости пишу без проверок ошибок, которые в продакшен коде обязательны)
$f = fopen($file, 'a');
flock($f, LOCK_EX);
ftruncate($f, 0);
fseek($f, 0);
fwrite($f .......)
......
 
Сверху