fgets и utf-8

sokal32

Новичок
проблема в том что fgets($file, 4096) иногда портит некоторые символы (видимо 4095-й символ), т.к. fgets($file, 65535) какгбэ помогает, но я понимаю что гипотетически строка может иметь и большую длину, так может кто знает решение этой задачи, может какой-то mb_fgets =)
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
Никто не знает.
Ибо ты не объяснил что конкретно ты делаешь и зачем.
 

sokal32

Новичок
вот как только я задал вопрос так сразу и пришло прозрение, я просто читал 4096 байт и не проверял считалась ли вся строка до символа новой строки или я получил только часть строки, вобщем я так понял что просто не нужно указывать максимальное кол-во считываемых байт fgets($file)
 

Активист

Активист
Команда форума
Как бы интересно. А что Вы делаете?

Моя логика подсказывает что нужно проверить, отрезало ли двубайтный символ на два байта и если отрезало - то читать +1 / -1, но как проверить? Является ли последний символ двубайтный? (применимо не только к fgets, много где может быть проблема)

Кто не понял.
* Есть utf-8 строка: abcde1234йцуё, fgets($file, 12); возвратит битую строку UTF-8 (отрежет пол "ц") - решение проблемы? Мною везде по коду используется вилидация например по длине SQL поля, например - $input = substr($input, 0, 0xff), при этом iconv в cp1251 отработает с ошибкой.
 

Вурдалак

Продвинутый новичок
А кто тебе сказал, что символ двухбайтовый? Определить необходимое смещение можно по последнему байту строки
Код:
$t = strlen(rtrim(substr($s, -6), "\x80..\xBF"));
 

Активист

Активист
Команда форума
Надо будет проверить, исследовать так сказать этот вопрос.

Да, действительно, ошибся, до 6-ти байт.
 

sokal32

Новичок
я пока сделал так, не знаю оптимально ли:
PHP:
function fgetsd(&$file, $bpr = 4096, $delim = "\n")
{
	$buf = '';
	
	while(!feof($file))
	{
		$buf .= fgets($file, $bpr);
		
		if(mb_strpos($buf, "\n", 0, 'UTF-8') !== false)
		{
			break;
		}
	}
	
	return $buf;
}
 

Mamont

Новичок
Я бы использовал что-то в этом роде (не проверял):
PHP:
<?php
function mb_fgets( &$file, $buf_size=1024 ){
   $buf = fgets( $file, $buf_size );
   //Прочитали до конца файла - обрабатывать нечего
   if( fEoF($file) ) return $buf;

   $byte = ord(substr( $buf, -1, 1 ));
   //если меньше 0x7F - символ имеет однобайтовую кодировку,
   //дочитывать ничего не нужно
   if( $byte<=0x7F ) return $buf;

   //чтение прервалось на многобайтовом символе.
   //ищем стартовый байт, у него всегда включены 2 первых бита
   $count=1;
   while( $byte & 0xC0 != 0xC0 ){
      $count++;
      $byte = ord(substr( $buf, -$count, 1 ));
   }

   //считаем биты, до первого выключенного
   //первые 2 можно не считать ;)
   $mask = 0x40;
   $bits_count = 2;
   while( $byte & $mask ){
      $mask = $mask >> 1;
      $bits_count++;
   }

   //$count - сколько байт уже прочитано
   //$bits_count - сколько нужно прочитать
   return $buf . fgets( $file, $bits_count-$count );
}
 
Сверху