некорректный результат substr и mb_substr для строк включающие бинарные данные

Acraft

Новичок
некорректный результат substr и mb_substr для строк включающие бинарные данные

Доброго времени суток.
Возникла следующая проблема

в PHP 5.2.6 функции mb_substr() и substr() некорректно вырезают часть данных, если эти данные имеют хоть один символ кириллицы, не закодированный в UTF8.
Из-за этого этими функциями невозможно вырезать нужный кусок из бинарных данных.
Этого бага нет в версии PHP 5.2.5 и 4.4.1

В чём может быть проблема?

p.s.: Видимо первый вариант поста был немного расплывчато сформулирован. Поэтому заменил содержимое.
 

dimagolov

Новичок
Acraft, а ты все сразу не читай file_get_contents-ом, ты делай fopen и читай фрагменты нужной длинны.
 

dimagolov

Новичок
объясни почему.
вообще-то нигде не сказало, что строковые ф-ии бинарно-безопастные. ну а от mb_ тем более глупо этого ожидать.
 

Acraft

Новичок
Cоединение инициирует удалённая сторона. Этот скрипт только слушает и выбрасывает в поток echo

В версиях PHP отличных (5.2.5, 4.4.1) от 5.2.6 обработка бинарных данных строковыми ф-ями проходит успешно.
 

Frog

Новичок
Автор оригинала: dimagolov
объясни почему.
вообще-то нигде не сказало, что строковые ф-ии бинарно-безопастные. ну а от mb_ тем более глупо этого ожидать.
Substr всегда использовался для вырезания части из бинарных данных.
Скажи, как еще можно вырезать кусок из бинарных данных?
Конечно, без fopen+ fseek+ fread.

http://bugs.php.net/bug.php?id=45311

-~{}~ 04.09.08 01:20:

Вот еще вариант вырезать-

http://ru.php.net/substr

If you need to divide a large string (binary data for example) into segments, a much quicker way to do it is to use streams and the php://memory stream wrapper.

For example, if you have a large string in memory, write it to a memory stream like
<?php
$segment_length = 8192; // this is how long our peice will be
$fp = fopen("php://memory", 'r+'); // create a handle to a memory stream resource
fputs($fp, $payload); // write data to the stream
$total_length=ftell($fp); // get the length of the stream
$payload_chunk = fread ( $fp, $segment_length );
?>

Working with large data sets, mine was 21MB, increased the speed several factors.

Но это подразумевается, что можно и substr() , но указанным способом- быстрее работает.
 

dimagolov

Новичок
Frog, присоединяюсь к разработчикам php. У меня баг не воспроизводится что на Win32 (дистрибут с php.net) что на FreeBSD amd64 (из портов, ясный пень), на i386 обломался уже проверять. Ты сам дал ссылку, а проверить не пробовал?

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

Frog

Новичок
Автор оригинала: dimagolov
Frog, присоединяюсь к разработчикам php. У меня баг не воспроизводится что на Win32 (дистрибут с php.net) что на FreeBSD amd64 (из портов, ясный пень), на i386 обломался уже проверять. Ты сам дал ссылку, а проверить не пробовал?
У Acraft баг есть- если он в здравом уме, то баг имеет место быть, проверять просто нет смысла (что, проверять врет Acraft или нет?).
Есть смысл пробовать повторить разработчикам, только для того, чтобы его исправить.

Главное условие для повторения бага- в бинарных данных, из которых вырезают substr(), должен быть хотя бы один символ кириллицы, т.е. хотя бы одна русская буква.

-~{}~ 04.09.08 17:41:

Автор оригинала: dimagolov
Acraft, учитывая вышеизложенное, вы совершенно зря не любите кошек, вы просто не умеете их готовить (с). протестируйте код из баг-репорта или предложите свой вариант. я вообще не удивлюсь, если у вас какой-то русский апач или сухосин, которые бьют данные до попадания их в пхп и я бы начинал проверки с этого.
На сколько я знаю- он проверял- данные в скрипт приходят не измененные.
 

tony2001

TeaM PHPClub
>Есть смысл пробовать повторить разработчикам, только для того, чтобы его исправить.
сделайте нормальный reproduce case для начала.
его наличие - гарантия, что баг-репорт воспримут серьезно.
а пока его нет, это всё из серии "уважаемые ученые, у меня в подвале раздается подземный стук".
 

Frog

Новичок
Автор оригинала: tony2001
>Есть смысл пробовать повторить разработчикам, только для того, чтобы его исправить.
сделайте нормальный reproduce case для начала.
его наличие - гарантия, что баг-репорт воспримут серьезно.
а пока его нет, это всё из серии "уважаемые ученые, у меня в подвале раздается подземный стук".
Ок, понятно.
А подсказать можете где прочитать что это такое и как его правильно создать?
 

tony2001

TeaM PHPClub
хм. может быть, просто название неясное, но тут ничего сложного нет.
нужна информация в таком виде:
я выполняю <скрипт> и получаю <неправильный результат>, а ожидаю получить <правильный результат>. непорядок!

если разработчик запускает <скрипт> и получает-таки <неправильный результат>, можно считать, что уже пол-дела сделано.
очень сильно желательно, чтобы <скрипт> не требовал экзотической конфигурации, доп. софта (Pear, ZF, ezC и др.), нужен именно короткий самодостаточный скрипт, демонстрирующий проблему.
 

dimagolov

Новичок
Frog, не знаю в каком уме Acraft, но после моего замечания потер весь свой код, который хоть как-то отражал то, что он делал и где у него была проблема. люди же в здравом уме (ну или хотя бы ознакомившиеся с правилами форума) поступают так, как сказал tony2001
 

Frog

Новичок
Автор оригинала: dimagolov
Frog, не знаю в каком уме Acraft, но после моего замечания потер весь свой код, который хоть как-то отражал то, что он делал и где у него была проблема. люди же в здравом уме (ну или хотя бы ознакомившиеся с правилами форума) поступают так, как сказал tony2001
Он потер код для того, чтобы коротко и внятно описать суть вопроса, не заставляя посетителей форума разгребать его сырой код для того, чтобы понять что ему надо.

-~{}~ 04.09.08 19:09:

Автор оригинала: tony2001
хм. может быть, просто название неясное, но тут ничего сложного нет.
нужна информация в таком виде:
я выполняю <скрипт> и получаю <неправильный результат>, а ожидаю получить <правильный результат>. непорядок!

если разработчик запускает <скрипт> и получает-таки <неправильный результат>, можно считать, что уже пол-дела сделано.
очень сильно желательно, чтобы <скрипт> не требовал экзотической конфигурации, доп. софта (Pear, ZF, ezC и др.), нужен именно короткий самодостаточный скрипт, демонстрирующий проблему.
Спасибо.

-~{}~ 04.09.08 19:21:

Вот конкретный код, который у Acraft -а показывает баг PHP 5.2.6:

Простое описание, ниже будет еще особенность:

$str="testабв"; //строка в Win1251
echo substr($str,0,5);
выводит: testабв, а должен testа

а вот это, естественно, работает:

$str=iconv("Win1251","UTF8","testабв"); //строка в UTF
echo substr($str,0,5);
выводит: testа

и

$str=iconv("Win1251","UTF8","testабв"); //строка в UTF
echo mb_substr($str,0,5);
выводит: testа

Проблема в том, что в его проекте $str содержит бинарные данные, например, тело JPG файла. И, если в этом теле есть хоть одна русская буква, то substr() из такой строки $str возвращает не то, что его просят.

И вот особенность- баг наблюдается только тогда, когда позиция, начиная с которой надо вернуть строку, находится после хотябы одной русской буквы, т.е.:

$str="testабв"; //строка в Win1251
echo substr($str,0,3);
выводит: tes

а вто это:

$str="testабвtest"; //строка в Win1251
echo substr($str,8,3);
выводит: строку из космоса, а должен: est

----

Еще раз напомню- в проверенных Acraft-ом версиях PHP 5.2.5, 5.1.6, 4.4.1 бага нет,
т.е. в указанных версиях

$str="testабв"; //строка в Win1251
echo substr($str,0,5);
выводит: testа

---
 

tony2001

TeaM PHPClub
давайте с самого начала.

>Вот конкретный код, который у Acraft -а показывает баг PHP 5.2.6:
>$str="testабв"; //строка в Win1251
>echo substr($str,0,5);
>выводит: testабв, а должен testа

substr() без mbstring работает с байтами и ему всё равно какие там буквы.
но mbstring - не всё равно.
я должен догадаться сам, что mbstring включен? ладно, допустим догадался.
но настройки и кодировки я его точно угадать не смогу, а они имеют значение.

>Проблема в том, что $str содержит бинарные данные, например, тело JPG файла.
>И, если в этом теле есть хоть одна русская буква, то substr() из такой строки $str
>возвращает не то, что его просят.

если включен mbstring overloading и надо работать с бинарными данными, то можно пользоваться mb_orig_* функциями, это оригинальные строковые функции, без mbstring.
 

Frog

Новичок
Настройки PHP надо спрашивать у Acraft -а.

Но я лично говорю о том, что такое поведение substr() встречается у него только в 5.2.6, в других версиях PHP все отлично работает.

-~{}~ 04.09.08 19:45:

Просто лично мое мнение- проще и быстрее установить версию PHP, в которой этих проблем нет.
Конечно, может быть, поигравшись с настройками и кодом, можно заcтавить работать скрипт и в 5.2.6.
Но лично мое мнение- зачем?
Если у тебя много времени, ты очень молод, полон сил, собираешься жить до 100 лет и при этом тебе приносят каждый месяц домой деньги на блюдечке, а скрипт ты делаешь только для своего удовольствия- конечно, можно, а если нет- надо написать баг репорт, переставить версию PHP на работающую и зарабатывать своим трудом дальше.
 

tony2001

TeaM PHPClub
>Настройки PHP надо спрашивать у Acraft -а.

я попросил дать мне скрипт, чтобы я разбрался в проблеме и исправил её (или объяснил почему так - правильно).
если ты сам не можешь воспроизвести проблему и не знаешь как это сделать, какой смысл было вообще начинать всё это?

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

действительно, зачем исправлять проблемы? зачем фиксить баги? зачем?

>Если у тебя много времени, ты очень молод, полон сил, собираешься жить до 100
>лет и при этом тебе приносят каждый месяц домой деньги на блюдечке, а скрипт ты
>делаешь только для своего удовольствия- конечно, можно, а если нет- надо
>написать баг репорт, переставить версию PHP на работающую и зарабатывать
>своим трудом дальше.

меньше текста, плз.
вы вдвоём пока даже и баг-репорт не смогли составить.
 

Frog

Новичок
>я попросил дать мне скрипт, чтобы я разбрался в проблеме и исправил её (или объяснил почему так - правильно).
>если ты сам не можешь воспроизвести проблему и не знаешь как это сделать, какой смысл было вообще начинать всё это?

Топик начал Acraft, после чего я нашел за него описание бага в сети и вместе с ним локализовали проблему-
выше я написал код с описанием.

>действительно, зачем исправлять проблемы? зачем фиксить баги? зачем?

Исправлять проблемы- это два утверждения- исправлять баги и решать проблемы.
Я сказал- надо решать проблемы.
Фиксить баги- ни я ни Вы ни Acraft не пофиксят ни одного бага в PHP 5.2.6.

>меньше текста, плз.
>вы вдвоём пока даже и баг-репорт не смогли составить.

Лично мне это не нужно.
Acraft может и составит, если у него будет на это время.
Только для того, что бы баг, может быть, когда-то исправили.
Но на его работу это влиять не должно.

-~{}~ 04.09.08 20:50:

Да, Tony, с возрастом ты стал более нетерпимым к новичкам.. :)
 

tony2001

TeaM PHPClub
>Фиксить баги- ни я ни Вы ни Acraft не пофиксят ни одного бага в PHP 5.2.6.
я не смогу вернуться в прошлое, это правда.
но это не означает, что надо просто забыть и жить с 5.2.5, исправить 5.2.7 до его выхода лично мне вполне по силам.
если, конечно, мне объяснят нормально проблему, а не будут разводить демагогию.
это возможно или мне надо дальше тратить время на разговоры?

-~{}~ 04.09.08 20:53:

>Да, Tony, с возрастом ты стал более нетерпимым к новичкам..
всё это прекрасно, но нельзя ли перейти к делу?
 

Frog

Новичок
:)
Вобщемто, как я уже сказал, это не мой проект и не моя проблема.
Насколько я знаю, Acraft будет переставлять версию на 5.2.5, просто потому, что ему надо быстрее завершать проект.

Если это чему-то поможет, то код, показывающий баг, я написал, но про настройки PHP ничего не знаю.
Если Acraft захочет- он напишет, тогда, возможно, весь этот разговор и будет иметь и смысл и результаты.

Лично от меня- извинения за болтовню и недостаточность данных.

Думаю, надо только ждать ответа от Acraft о настройках PHP.
 

Acraft

Новичок
Основные настройки PHP 5.2.6 на котором наблюдается баг.

; Language Options ;
;;;;;;;;;;;;;;;;;;;;
engine = On
zend.ze1_compatibility_mode = Off
short_open_tag = On
asp_tags = Off
precision = 14
y2k_compliance = On
output_buffering = 4096
output_handler = ob_gzhandler
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func=
serialize_precision = 100
allow_call_time_pass_reference = On
safe_mode = Off
safe_mode_gid = Off
safe_mode_include_dir =
safe_mode_exec_dir =
safe_mode_allowed_env_vars = PHP_
expose_php = On

; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
max_execution_time = 60
max_input_time = 60
memory_limit = 60M

; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
error_reporting = E_ALL & ~E_NOTICE
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off

; Data Handling ;
;;;;;;;;;;;;;;;;;
variables_order = "EGPCS"
register_globals = On
register_long_arrays = Off
register_argc_argv = On
post_max_size = 8M
magic_quotes_gpc = On
magic_quotes_runtime = Off
magic_quotes_sybase = Off
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
always_populate_raw_post_data = On

[mbstring]
mbstring.internal_encoding = UTF-8

PHP:
// Прописывание в коде 
ini_set('mbstring.internal_encoding','');  
//положения вещей не меняет.
такой способ (попробовать в конце-концов стоило) тоже ничего дельного не принёс:

PHP:
$strData = file_get_contents("php://input");   // cкрипт ждёт обращения
$fp = fopen("php://memory", 'r+');
fwrite($fp, $strData);
rewind($fp);
var_dump(unpack('L', fgets($fp,4)));   // берёт первый dword
Сегодня из портов установили патч php5-5.2.6_2. Пока рано говорить на 100 процентов.
Но первые тесты показали отсутствие проблемы.
 
Сверху