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)
Ответ на: комментарий от qnikst

что строка S+null в php мне совершенно не понятно.

Дык:

php -r '$s = "+\0+"; var_dump($s); echo ord($s[1]);'
string(3) "++"
0

\0 — вполне себе символ в PHP.

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

В utf-8 \0 вообще быть не может

Щито? Покажите мне null-terminated строку в utf-8, где \0 быть не может!

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

Си кстати тоже относится к legacy-языкам, на которых новый код надо писать разве что в рамках драйверов к ядру.

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

Почему ты считаешь, что строка S в С это тоже самое, что строка S+null в php мне совершенно не понятно.

Потому что мне непонятно, чем может служить символ \0 в php, кроме как символом конца строки. Причем, конкретно здесь виноват не пхп, а парсер json, который парсит \0 как управляющий символ и вылетает на этом ровном месте.

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

Си кстати тоже относится к legacy-языкам, на которых новый код надо писать разве что в рамках драйверов к ядру

Это ты на лурке прочитал, да?

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

Си кстати тоже относится к legacy-языкам, на которых новый код надо писать разве что в рамках драйверов к ядру.

библиотеки стоит писать исключительно на С, по вполне очевидным причинам - скорость + простое использование с разными ЯП

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

Щито? Покажите мне null-terminated строку в utf-8, где \0 быть не может!

Прошу прощения, но как \0 может быть _в_ null-terminated строке в любой кодировке? :)

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

Это ты на лурке прочитал, да?

Нет, это я посмотрел на go и разочаровался в си. В вебе си, кстати, уж точно не должно быть, как и php.

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

мне непонятно, чем может служить символ \0 в php, кроме как символом конца строки

Символом с кодом 0. Например, при работе с бинарными данными.

// Ваш к.о.

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

ты понял, что я про тоже, и что ты подтвердил моё недоразумение требованиями ТС?

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

А вот обработка ошибок в PHP действительно дерьмо.

В документации сказано, что оно вернет NULL. То, что обработка ошибок не универсальна - это да, плохо, но конкретно в этом случае виноват json_decode, а не пхп, и то, что эта функция не предусматривает \0.

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

Например, при работе с бинарными данными.

В нормальных языках есть отдельно типы []byte (или иной другой для представления данных в виде кучки байт) и String с юникодами и прочими няшками.

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

\0 будет в конце строки и только в конце строки. Товарищ выше невнятно написал, на что я и ответил.

Придираясь в ответ, \0 будет через символ для ASCII-символов в UTF-16 :)

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

Символом с кодом 0. Например, при работе с бинарными данными.

В строке? Для этого в нормальных высокоуровневых языках есть что-то типа class bytearray, но никак не строка.

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

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

В конец добавление не влияет? А если посредине поставить?

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

А если посредине поставить?

то очевидно середина станет концом

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

Ну и скорми стандартной сишной функции строку в UTF-16. Посмотрим на пустой вывод.

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

А зачем нужен тип с символом \0 как маркером конца строки?

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

тебе стыдно должно быть

php > $a = "\0\0\0";
php > $b = json_encode($a);
php > var_dump($b);
string(20) ""\u0000\u0000\u0000""
php > $c = json_decode($b,false);
php > var_dump($c);
string(3) ""
php > for($i=0;$i<3;$i++) echo ord($c[$i]);
000
qnikst ★★★★★
()
Ответ на: комментарий от bk_

сериализованный json это строка, в которой могут быть \u0000 точка, в какой там тип в языке ты это запихнёшь это твои личные проблемы, не относящиеся к стандарту языка сериализации.

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

\0 будет в конце строки и только в конце строки.

В юникоде (не в конкретных utf-8, а именно в юникоде) написано, что символ \0 означает Null Character и ничего не делает при выводе. Т.е. printf(«\0hello\0world») по идее должен вывести helloworld. То что его на этом глючит — СИШКАПРОБЛЕМЫ.

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

поскольку для языка С это *стандартный* универсальный формат строки

Вроде бы много языков знаешь, судя по сообщениям, а упираешься в одну парадигму, как только что прочитавший «С для чайников».

Нет, zero-terminated строки никто не использует, потому что это удобно. Это неудобно и опасно. Но просто.

note173 ★★★★★
()

Сипроблемы. Смирись, Си устарел.

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

Но *где* используются строки с \0 в середине?

Используются, чтобы взломать что-то написанное на С например)

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

В нормальных языках есть отдельно типы []byte

Как это связано с запретом _некоторых_ языков использовать в строках символ \0?

От того, что в каком-то «нормальном» языке появится тип byte, символ \0 автоматически не становится запретным.

$ java test
qwerty
0
$ cat test.java
class test
{
        public static void main(String[] args)
        {
                String s = "qwe\0rty";
                System.out.println(s);
                char c = s.charAt(3);
                System.out.println( (int)c );
        }
}

Не понимаю, как ограничения древней реализации можно принимать за какие-то общие правила :)

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

Про ваш пхп уже можно слагать легенды, как постулаты, державшиеся десятки лет, вдруг перестали поддерживаться. Далее к ним подкатили другие любители все упрощать, и понеслось.

Такие, как вы, в упор не видите других точек зрения и других ЯП.

А самое интересное, все дружно глаголят о том, в *строках*, еще раз - В СТРОКАХ посредине может быть нулевой символ! Какой смысл в НУЛЕВОМ СИМВОЛЕ В СТРОКЕ, кроме как маркера ее конца? Здесь пользователи пхп теряются, пытаясь провести аналогию между бинарными данными и строкой.

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

zero-terminated строки никто не использует, потому что это удобно

4.2, разбить текст на слова, например, в С удобно, максимально быстро и не требует дополнительной памяти

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

\0 будет в конце строки и только в конце строки. Товарищ выше невнятно написал, на что я и ответил.

В этом случае \0 не принадлежит к этой строке.

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

Наверняка в System.out.println есть код вроде

println.c

... else if (c == '\0') {
    /* Do nothing. Skip this symbol to ensure that code monkeys that pushed here that symbol will think that all right. */
} else ...
bk_ ★★
() автор топика
Ответ на: комментарий от PolarFox

В языке с образцовой поддержкой юникода:

package main

import "fmt"

func main() {
  fmt.Printf("\x00hello\x00world\n")
}
$ go run test.go 
helloworld
PolarFox ★★★★★
()
Ответ на: комментарий от bk_

Про ваш пхп уже можно слагать легенды, как постулаты, державшиеся десятки лет, вдруг перестали поддерживаться.

Обрати внимание, в теме фигурировала уже МАССА других языков. Нет, только Си (и работающий на его библиотеках Perl) идут в ногу. Ага :)

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

В этом случае \0 не принадлежит к этой строке.

Щито? Не понял. Как \0 может не принадлежать той строке, которую он терминирует?

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

Наверняка в System.out.println есть код вроде

Я уже представляю уровень Вашего кода, ага :D

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

Не понимаю, как ограничения древней реализации можно принимать за какие-то общие правила :)

учитывая то, что даже в C эта проблема только у ТС, и если нужно поддерживать \0 в данных то никаких проблем нет.

qnikst ★★★★★
()

Сипроблемы&&быдлокодпроблемы.

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

Щито? Не понял. Как \0 может не принадлежать той строке, которую он терминирует?

«abc\0»

«abc» — строка с длиной 3. \0 — не строка. (Это я исключительно про Си, конечно).

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

И на этих старых ЯП все работает. А на остальных, которые писали молодые философы новой школы - это уже не работает. Жаль.

Тем паче, никто так не заметил, какую точку зрения я отстаиваю, несмотря на ее многократный перепост:

* добавить в стандарт опредение, что \0 равносильно EOF или концу строки, как угодно, которое «мягко» останавливает парсер.

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

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

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

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

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

В юникоде (не в конкретных utf-8, а именно в юникоде) написано, что символ \0 означает Null Character и ничего не делает при выводе.

Прошу ман.

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

Такие, как вы, в упор не видите других точек зрения и других ЯП.

я тебе объяснил свою точку зрения со стороны php, java, c и haskell. Будем продолжать сравнивать кто из нас не видит проблемы и кто предлагает костыль?

А самое интересное, все дружно глаголят о том, в *строках*, еще раз - В СТРОКАХ посредине может быть нулевой символ! Какой смысл в НУЛЕВОМ СИМВОЛЕ В СТРОКЕ, кроме как маркера ее конца?

ЛЮБОЙ нужный мне в данной конкретной задаче. Блиан json это сериализация данных, ЛЮБЫХ данных, ЛЮБЫХ, а не тех, которые не содержат \0. JSON должен работать в ЛЮБОЙ реализации языка, а не только в null-terminated, попробуй это понять.

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

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

Я не раз подчёркивал, что отвечаю обычно не человеку, а на сообщение. Я в споре часто вообще не обращаю внимания на то, кто какую позицию занимает по какому-то вопросу. Есть сообщение, я его комментирую, если есть что сказать.

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

добавить в стандарт опредение, что \0 равносильно EOF или концу строки, как угодно, которое «мягко» останавливает парсер.

Нужно добавить полноценное описание потокового парсинга, а не просто \0.

добавить возможность экранировать нулевой символ по аналогии и двойной кавычкой

Разумно.

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

JSON должен работать в ЛЮБОЙ реализации языка, а не только в null-terminated, попробуй это понять.

ВО! ВО! ТЫ наткнулся на мою мысль! А теперь я тебя поведу далее: почему тогда автор стандарта JSON, зная, что в С строки оканчиваются на \0, не прописал в стандарте соответствующее поведение?

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

Вот смотри, есть два нулевых байта. Если у нас кодировка утф8, то это строка с двумя символами \0, если utf-16, то строка с одним символом \0. На таком примере понятно, почему []byte != string даже с нормальной поддержкой \0 в этом самом string?

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

Какой смысл в НУЛЕВОМ СИМВОЛЕ В СТРОКЕ

Например, это может быть кодировка, где цифры имеют коды от 00 до 09. Видел такую в конце 1980-х, только название уже не помню.

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

нет, это тебе надо написать код на C, который не шлет мусор туда, куда не надо.

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