LINUX.ORG.RU
решено ФорумTalks

Я люблю тебя, PHP!

 ,


0

2

Написал серверное приложение на чистом С. Оно слушает порт, а PHP с ним соединяется и получает данные в json-формате.

Несколько часов убил на то, чтобы понять почему PHP не может сделать json_decode. Наконец, написал минимальный пример:

$ cat test.php 
<?php

$s1 = '["1", "2"]';
echo "1 ", var_dump(json_decode($s1)), "\n";

$s2 = $s1 . "\0";
echo "2 ", var_dump(json_decode($s2)), "\n";

$ php test.php
1 array(2) {
  [0]=>
  string(1) "1"
  [1]=>
  string(1) "2"
}

2 NULL

Да это же просто феерично! Я добавил нулевой символ в конец строки, а она перестала быть корректным json, твою мать! Я даже сравнил побайтово две строки, вывев их в файл: отличие только в \0 на конце.

Что за специалист писал такой парсер json-а в php?!

---

Отныне это тред о впечатлениях, оставшихся после встречи с неочевидными, глупыми и неграмотными решениями в разных ЯП. Делись своими впечатлениями, лоровец.

★★

Последнее исправление: CYB3R (всего исправлений: 1)

Несколько часов убил на то, чтобы понять почему PHP не может

Чего тут понимать? Не может, потому что PHP.

И да, PHP -> ТС ССЗБ.

Boba_Fett
()
Ответ на: комментарий от vahtu
$ php --version
PHP Deprecated:  Comments starting with '#' are deprecated in /etc/php5/cli/conf.d/ming.ini on line 1 in Unknown on line 0
PHP Deprecated:  Comments starting with '#' are deprecated in /etc/php5/cli/conf.d/ps.ini on line 1 in Unknown on line 0
PHP 5.3.3-7+squeeze13 with Suhosin-Patch (cli) (built: Jun 10 2012 09:35:18) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH

bk_ ★★
() автор топика

В ruby, кстати, популярный парсер также валится в ошибкой:

drakmail@thinkpad-x220:~$ ruby test.rb 
# SOURCE CODE START #

$><<IO.read($0)

require 'json'

s1 = '["1", "2"]'
puts "1: " + JSON.parse(s1).to_s

s2 = s1 + "\0"
puts "2: " + JSON.parse(s2).to_s

# SOURCE CODE END #
1: ["1", "2"]
/usr/lib64/ruby/1.9.1/json/common.rb:146:in `parse': 706: unexpected token at '' (JSON::ParserError)
        from /usr/lib64/ruby/1.9.1/json/common.rb:146:in `parse'
        from test.rb:11:in `<main>'
drakmail ★★★★
()
Ответ на: комментарий от drakmail

unexpected token at "

Информативно :)

bk_ ★★
() автор топика
#!/usr/bin/perl

use Mojo::JSON;

my $json = Mojo::JSON->new();

# Malformed JSON: Unexpected data after array at line 1, offset 10.
$json->decode( qq{["1", "2"]\0} ) or die $json->error;
outtaspace ★★★
()

Пайтоновское:

>>> import json
>>> s1 = '["1", "2"]'
>>> s1 += "\0"
>>> s1
'["1", "2"]\x00'
>>> json.loads(s1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 368, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 1 column 10 - line 1 column 11 (char 10 - 11)
>>> 

Breton
()
$cat test.pl
#!/usr/bin/perl

use 5.010;
use strict;
use warnings;
use JSON::XS;
use Data::Dumper;

my $s1 = '["1", "2"]';
say "1:".Dumper(decode_json($s1));

my $s2 = $s1 . "\0";
say "2:". Dumper(decode_json($s2));
$./test.pl
1:$VAR1 = [
          '1',
          '2'
        ];

2:$VAR1 = [
          '1',
          '2'
        ];

:)

joy4eg ★★★★★
()

Правильно делает, JavaScript тоже сломается и все нормальные языки должны отказать.

А с чего вы в JSON вмешиваетесь функциями обработки строк? По сути, написали кривой энкодер и чему-то удивляетесь?

BaBL ★★★★★
()
Ответ на: комментарий от outtaspace

Хаха :)

 $ cat /tmp/a.pl 
#!/usr/bin/perl
use JSON;
use Data::Dumper;

my $obj = decode_json( qq{["1", "2"]\0\0\0} ) or die "Alala";
print Dumper($obj);


$ perl /tmp/a.pl
$VAR1 = [
          '1',
          '2'
        ];

$ perl --version

This is perl, v5.10.1 (*) built for i486-linux-gnu-thread-multi
(with 56 registered patches, see perl -V for more detail)
bk_ ★★
() автор топика

Ибо документацию читать надо.

wiki

Небольшой список основных элементов YAML:

  • потоки YAML используют печатаемые Unicode-символы, как UTF-8, так и UTF-16
tiandrey ★★★★★
()
Ответ на: комментарий от tiandrey

Да ты что? А если я к парсеру json на С к строке сконкатенирую «\0», то он заикнется про невалидный json?

bk_ ★★
() автор топика
Ответ на: комментарий от bk_

«\0» - печатный символ? Нет? Тогда поведение неопределено как минимум. И JSON - подмножество YAML с некоторых времён.

tiandrey ★★★★★
()
Ответ на: комментарий от KRoN73

Спасибо, я читал документацию. Что я инициировал добавлением \0: сделал слишком большую рекурсию или сделал невалидный json?

bk_ ★★
() автор топика
Ответ на: комментарий от bk_

Что я инициировал добавлением \0: сделал слишком большую рекурсию или сделал невалидный json?

Сообщил принимающей стороне, что у посылающей стороны есть какие-то проблемы. Принимающая сторона отказалась обрабатывать кусок данных, сопровождаемый ошибкой. Нормальное транзакционное поведение.

Slavaz ★★★★★
()
Последнее исправление: Slavaz (всего исправлений: 1)
Ответ на: комментарий от tiandrey

Нет? Тогда поведение неопределено как минимум.

Во-первых, где это сказано?

Во-вторых, C-style strings.

bk_ ★★
() автор топика

Нехватает только js

>>> JSON.parse( '["1", "2"]' )
Array ["1", "2"]

>>> JSON.parse( '["1", "2"]' + '\0' )
Unhandled Error: JSON.parse: Parsed string contains more than single value:  
Kalashnikov ★★★
()
Ответ на: Нехватает только js от Kalashnikov

От себя добавлю, что добавление к строковому буферу символа «\0» в языке С на корректность JSON-а не влияет :)

Вывод: json нормально умеют парсить только Perl да С.

bk_ ★★
() автор топика
Ответ на: комментарий от bk_

Вывод: json нормально умеют парсить только Perl да С.

Вывод: Perl и C имеют какие-то велосипедные парсеры, что ведет к возникновению сложноотлавливаемых ошибок при использованию в проекте нескольких языков.

BaBL ★★★★★
()
Ответ на: комментарий от Kalashnikov

Вариант outtaspace валится.

Потому что он использует вместо нормального JSON.pm какой-то бложиковый парсер, который копипастили разработчики всех быдлоязыков (тех, в которых вываливается парсер, судя по тексту топика).

bk_ ★★
() автор топика
Ответ на: комментарий от BaBL

что ведет к возникновению сложноотлавливаемых ошибок при использованию в проекте нескольких языков.

$out .= «\0»;

сложноотлавливаемых

\0

Хахаха.

bk_ ★★
() автор топика
Ответ на: комментарий от BaBL

Для Си '\0' это вообще признак конца строки. Так что ничего некорректного в этом нет.

KivApple ★★★★★
()

А с какого перепугу это должно быть валидным JSON?

vasily_pupkin ★★★★★
()
Ответ на: комментарий от bk_

В Module::CoreList отсутствует модуль которым я воспользовался и отсутствует модуль из вашего примера. Вы путаете язык программирования + его батарейку, с языком как платформой. Самый корректный пример - модули из батарейки.

outtaspace ★★★
()

Я добавил нулевой символ в конец строки, а она перестала быть корректным json

Давай по честному, ты просто накосячил и забыл срезать терминирующий ноль.

iBliss
()
Ответ на: комментарий от bk_

От себя добавлю, что добавление к строковому буферу символа «\0» в языке С на корректность JSON-а не влияет :)

Ты так говоришь, будто это что-то хорошее

vasily_pupkin ★★★★★
()
Ответ на: комментарий от bk_

Во-первых, это не описано в стандарте, значит, такие данные некорректные, значит, поведение не определено.

Во-вторых, там явно описана последовательность, в которой должны встречаться символы. Если ты не нашёл/не понял, вот вольный перевод той части стандарта.

RFC4267

JSON-текст - последовательность знаков. Знаки включают в себя шесть структурирующих символов, строки, числа и три константы.
JSON-текст содержит в себя массив или объект.
Структурирующие символы таковы:

  • начало массива - '['
  • начало объекта - '{'
  • конец массива - ']'
  • конец объекта - '}'
  • разделитель имени - ':'
  • разделитель значений - ','
  • до и после структурирующих символов может быть любое количество пробельных символов, а именно пробела, символа табуляции, символа перевода строки и символа возврата каретки.


Значениями должны быть только объект, массив, число, строка, или одна из трёх констант: 'true', 'false', 'null'.
Объект - структура, представляющая из себя неупорядоченный набор из ноля и более пар вида 'имя' - 'значение'.
объект = '{' [ член-объекта *( разделитель-значений член-объекта ) ] '}' член-объекта = строка разделитель-имени значение
Массив - структура, представляющая из себя упорядоченный набор из ноля и более значений.
массив = '[' [ значение *( разделитель-значений значение ) ] ']'
Число состоит из целой части, возможно, со знаком '-' в начале, за которой может следовать дробная и/или экспоненциальная часть. Восьмеричная и шестнадцатеричная формы запрещены. Нули в начале запрещены.
Дробная часть - знак '.' и одна и более цифра.
Экспоненциальная часть - символ 'E' или 'e', за которой может следовать '+' или '-', и одна и более цифр.
Строка - последовательность из ноля и более символов юникода, окружённая символами '«'.

Итого, вне кавычек разрешены только пробельные символы, символы '[]{},:+-.eE' и цифры.

tiandrey ★★★★★
()
Ответ на: комментарий от bk_

нормальные языки

перл

/0

Кстати, стандарт-то что говорит?

buddhist ★★★★★
()
Ответ на: комментарий от iBliss

по честному

По-честному, '\0' останавливать парсер. А-то набИжали защитнички и утверждают, что нулевой символ влечет за собой неопределенное поведение.

bk_ ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.