Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет Misha Verbitsky ([info]tiphareth)
@ 2017-07-04 11:01:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
верхний пост - 2014
Архив верхнего поста.

Архивы:
[ 2013 | 2012 | 2011 | 2007-2010 | 2006 ]


(Читать комментарии) - (Добавить комментарий)


[info]weary
2015-11-09 00:28 (ссылка)
Миша, вот как-то так можно попробовать избавиться от юникодного ужаса, который постит известно кто:

$string =~ s/[\p{Mn}\p{Me}]{5,}//g;

В данном случае регэксп вырезает все символы, принадлежащие юникодным категориям Mn (Mark, Nonspacing) и Me (Mark, Enclosing), которые повторяются более, чем 5 раз. В таком варианте не будут портиться диакритики для абсолютного большинства языков, и при этом будут вырезаться явно злонамеренные комбинации. То, что останется, уже не будет заметно вылезать за края строки. Должно работать на старом перле, наверное.

Подробнее о методе тут: https://stackoverflow.com/questions/22277052/how-can-zalgo-text-be-prevented

Я не очень хорошо знаком с кодом ljr, потому предположу, что это надо будет вставить где-то в cleanhtml.pl на 1191-ю строку, где обрабатывается $newdata, но могу ошибаться.

(Ответить) (Ветвь дискуссии)


[info]tiphareth
2015-11-09 00:29 (ссылка)
спасибо, ага
попробую

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-09 00:51 (ссылка)
меня пугает $$data
это по идее значение переменной, название которой равно значению $data
http://perldoc.perl.org/perlref.html
что оно там делает?
по идее надо в начале вставить этото регексп
еще до того, как она его отпарсила на тэги
там уже вначале что-то такое есть
126 $$data =~ s/(see_request\.bml\S+?)auth=\w+/$1/ig;
вот туда же и вбить
$$data =~ s/[\p{Mn}\p{Me}]{5,}//g;

но я не хочу делать вещь, которую я в упор не понимаю

в конце (после того, как по ней прошлись парсингом
my $p = HTML::TokeParser->new($data);
) это делать наверное все-таки не нужно

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-09 01:07 (ссылка)
По идее, там вся функция набивает строку $newdata (изначально пустая) из $data (её передали в функцию), пропуская $data через парсер, а потом меняет $data на новое. Почему они делают это по ссылке, вместо того, чтобы вернуть $newdata return-ом - не знаю, может их волновал вопрос производительности, а может иначе там никак.

Если воткнуть этот регэксп в самое начало (где see_request\.bml), то парсер получит уже очищенные данные, если в конце (где 1 while $newdata =~) - данные очистятся перед обратным присваиванием, так что, наверное, разницы не будет. По идее этот регэксп не должен влиять на тэги никоим образом. По-хорошему, конечно, это всё вживую проверять надо, там уж больно страшный код. Я смог протестировать только на текстовом файле.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-09 01:13 (ссылка)
я протестировал всячески
чой-то никакого эффекта
ради смеха можно попробовать букву z убрать, сейчас шмякну

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-09 01:18 (ссылка)
буква z тоже не убирается
шмякнул там в начале
$$data =~ s/[z]//g;
и в конце то же с $newdata
эффекта не было

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-09 01:31 (ссылка)
Странно, конечно, с виду должно было работать. Надо будет дальше вчитываться в код.

Если говорить о самом регэкспе, то я сейчас его ради интереса на старом перле проверил (5.8) - работает.
Вот пример: http://pastebin.ca/3243719
Такой результат:
perl

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-09 01:38 (ссылка)
угу, но он даже букву z из текста убрать не может

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-09 04:21 (ссылка)
Нашел у себя полурабочий ljr в виртуалке, поднятый пару лет назад, потестировал. К сожалению, комменты у меня там не работают, так что не всё получилось проверить.

В общем, там всё хитрее. Во-первых, я ошибся, clean отрабатывает только тогда, когда в теле сообщения есть тэги. Где он конкретно это выясняет, не могу сказать, но срабатывает он строго при наличии чего-то, похожего на тэг. Поэтому он это не вариант. В результате код с регэкспом надо вписывать куда-то ещё, либо в те места, где данные достаются из базы (Entry.pm и так далее, их несколько), либо всё делать в самом конце вывода, в /cgi-bin/Apache/LiveJournal.pm, в конце journal_content.

Во-вторых, там строки не совсем юникодные оказались, регэксп с некоторыми классами символов просто не работает, пока строку не объявишь юникодом через Encode::_utf8_on($html). Подробнее тут и тут. В документации пишут, что dangerous, и Do not use this unless you know with absolute certainty that the STRING holds only well-formed UTF-8. Но вроде работает, хотя выглядит подозрительно.

Итого получилось так, вот тут на 1169-й строке сразу после $r->send_http_header(); можно вписать:

Encode::_utf8_on($html);
$html =~ s/[\p{Mn}\p{Me}]{5,}//g;

и, после рестарта сервера и десятка нажатий ctrl+f5 (какой-то у них упрямый кэш), оно начинает таки вырезать лишнее. На вид ничего не ломается, но у меня сам сайт и так работает лишь наполовину. Вот что-то вроде патча: http://pastebin.ca/3243979

При этом оно прогоняет весь контент через регэксп, что, по идее, не совсем прилично в плане производительности. Можно попробовать вставить такое только туда, где достаются посты и комменты. Или вообще только на комменты, что ещё лучше, но это надо намного глубже лезть в код.

Вообще это кривые хаки какие-то, я уже не знаю, стоит ли вообще всё это делать, или хрен с ним, пусть уж будет юникод, а владельцы журналов сами модерируют.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-09 05:07 (ссылка)
это стремно: она может начать плохо взаимодействовать с мемкэшем,
у которого семь пятниц на неделе (либо с неправильным энкодингом
от экзотического браузера). Надо бы, да, на комменты, причем строго
от анонимов


(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-09 14:26 (ссылка)
Можно и так попробовать, наверное.

В /cgi-bin/talklib.pl после 971-й строчки можно вставить такое:

if ($posts->{$talkid}->{'posterid'} == 0) {
Encode::_utf8_on($posts->{$talkid}->{'subject'});
Encode::_utf8_on($posts->{$talkid}->{'body'});
$posts->{$talkid}->{'subject'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
$posts->{$talkid}->{'body'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
}

По идее у анонов posterid == 0, про юзеров с openid не знаю.

http://pastebin.ca/3244577

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-09 15:16 (ссылка)
эффект очень странный: говно улетучилось, но сами посты (не комменты, а именно посты)
перекодировались в кракозябры. Протестировал и убрал.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-09 15:38 (ссылка)
Хм, и правда, я кое-как отловил такое, причем только на S1, с S2 всё нормально. Буду думать.

(Ответить) (Уровень выше)


[info]weary
2015-11-10 02:33 (ссылка)
В общем, стало ясно, что есть проблема с S1 и bml. Совершенно не понимаю, что они там внутри такое делают, но при наличии в выводе utf-строки, пропущенной через тот Encode (который ничего не меняет, а только ставит внутренний флаг), всё ломается к чертям. Видимо, видя юникодную строку они начинают делать ещё одну перекодировку, но где - не могу сказать. На S2, который выводится в другом месте, флаг юникода вроде бы отрицательно не влияет.

Пока что получилось обойти так: оставить то, что есть в load_comments (предыдущий коммент), и в файле /htdocs/talkread.bml на строке 448 перед my $cleansubject = LJ::ehtml($post->{'subject'}); воткнуть

if ($post->{'posterid'} == 0) {
Encode::_utf8_off($post->{'body'});
Encode::_utf8_off($post->{'subject'});
}

В данном случае флаг юникода снимается с того текста, что был ранее обработан в load_comments (subject и body для posterid == 0), и с контентом ничего плохого не происходит. После этого у меня вывод портиться перестал. Хотя, возможно, где-то, где в bml ещё выводятся комменты, проблема осталась. Вроде на вид в bml больше нигде load_comments не используется, но я ни в чём не уверен. В recent_comments.bml комменты есть, но достаются они иначе.

Но всё это похоже на большой хак в плохом смысле, конечно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]maxmornev
2015-11-10 02:55 (ссылка)
Как вариант, можно сразу после регекспов выше добавить Encode::_utf8_off.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-10 03:16 (ссылка)
Ох, действительно, что-то я совсем отупел к ночи.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-10 14:10 (ссылка)
поставил, спасибо
пока не помогло, ибо надо вбить проверку на OpenID, у них-то posterid ненулевой

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-10 14:23 (ссылка)
не уверен, что какой-то эффект был достигнут (даже с аноном):
http://lj.rossia.org/users/chaos_soyuz/2052.html
вбил я туда следующее
# anti-zalgo measure (makaka)
# https://lj.rossia.org/users/tiphareth/1761692.html?thread=97284764#t97284764
if ($posts->{$talkid}->{'posterid'} == 0) {
Encode::_utf8_on($posts->{$talkid}->{'subject'});
Encode::_utf8_on($posts->{$talkid}->{'body'});
$posts->{$talkid}->{'subject'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
$posts->{$talkid}->{'body'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
Encode::_utf8_off($posts->{$talkid}->{'subject'});
Encode::_utf8_off($posts->{$talkid}->{'body'});
}

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-10 14:29 (ссылка)
>не уверен, что какой-то эффект был достигнут (даже с аноном):

Я там с аноном попробовал - у меня эффект есть: https://lj.rossia.org/users/chaos_soyuz/2052.html?thread=100868

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-10 14:31 (ссылка)
у меня все те же вертикальные палочки
там надо вверх-вниз пару раз окно продернуть, иначе их не видно

(Ответить) (Уровень выше)


[info]weary
2015-11-10 14:31 (ссылка)
Вот как выглядит: https://i.imgur.com/6ZRXHUU.png

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-10 14:32 (ссылка)
так вертикальные палочки на картинке налицо, нет?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-10 14:33 (ссылка)
Так то от соседнего коммента под юзером, а в коде же проверяется posterid == 0. А в комменте анона всё чисто.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-10 14:34 (ссылка)
а, я осел, пардон
действительно

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-10 14:39 (ссылка)
осталось понять, как бы там резать openid, а не одних анонов

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-10 15:28 (ссылка)
Где-то здесь на 1014-й внутри цикла достаётся полное описание юзера из базы, и в том массиве ($post->{'upost'}) может лежать что-то, что показывает, что юзер пришел через openid. У меня локально openid вообще не работает почему-то, проверить не могу, потому предположу, что определить можно то ли по имени юзера (если там есть какой-нибудь ext_), то ли по какому-нибудь свойству из данного массива.

Если на том этапе получится определить openid, то можно будет воткнуть туда похожий код.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-10 16:50 (ссылка)
openid определяется такой проверкой
но это ад, конечно

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-10 23:35 (ссылка)
Похоже, что openid - это $user->{'journaltype'} == 'I', а у обычного юзера там 'P'. 'I' включает в себя всех, в том числе и ЖЖ, хотя в некоторых местах оно обрабатывается по-разному, например, в userinfo.bml.

Соответственно, если пользователя уже вытащили из базы, то достаточно проверять journaltype. В talklib.pl это можно сделать на 1017-й, где $up это тот юзер, а не-юзеры уже пропущены в next unless $up строчкой выше.

if ($up->{'journaltype'} == 'I') {
Encode::...
$post->{'body'} =~ ....
# etc
}

Либо, как вариант, чтобы не размазывать всё это по коду, можно воткнуть между my $up и next unless что-то вроде такого, что сработает и на анонимуса, и ликвидировать вставленный ранее блок:

if (($post->{'posterid'} == 0) || ($up && ($up->{'journaltype'} == 'I'))) {
#...
}

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

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]tiphareth
2015-11-11 00:48 (ссылка)
Спасибо! Сделаю

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-13 14:26 (ссылка)
туплю несколько
а чего писать в #... ?

Encode::_utf8_on($posts->{$talkid}->{'subject'});
Encode::_utf8_on($posts->{$talkid}->{'body'});
$posts->{$talkid}->{'subject'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
$posts->{$talkid}->{'body'} =~ s/[\p{Mn}\p{Me}]{5,}//g;
$posts->{$talkid}->{'body'} =~ s/\n{8,}//g;
Encode::_utf8_off($posts->{$talkid}->{'subject'});
Encode::_utf8_off($posts->{$talkid}->{'body'});

Или encode-decode на этом этапе ненужно?
опасаюсь засрать что-то постороннее, поэтому спрашиваю

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]weary
2015-11-13 15:03 (ссылка)
Да, вроде так.

Перед применением того юникодного регэкспа всегда нужно делать utf8_on, а после - utf8_off. По идее, даже если сделать это два раза, то ничего не сломается (не проверю сейчас, увы).

(Ответить) (Уровень выше)


[info]weary
2015-11-13 15:13 (ссылка)
И тут тоже в условии $up->{'journaltype'} eq 'I' вместо ==, иначе всегда срабатывать будет.

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-10 14:24 (ссылка)
все это было в талклиб.пл, после 448

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-10 14:27 (ссылка)
вроде бы, да, никакого эффекта: добил туда к этим регекспам
$posts->{$talkid}->{'body'} =~ s/z//g;
но никаких букв z ниоткуда убрать не удалось

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-09 00:52 (ссылка)
кажется, понял, да

(Ответить) (Уровень выше)


[info]tiphareth
2015-11-09 01:11 (ссылка)
в общем, она ни в начале, ни в конце ничего не делает
даже если написать
$newdata =~ s/[\p{Mn}\p{Me}]//g;
либо же
1 while $newdata =~ s/[\p{Mn}\p{Me}]//g;

возможно, с точки зрения перла эти юникодные буквы не соответствуют /[\p{Mn}\p{Me}]/
либо я не туда пишу, либо что-то еще

(Ответить) (Уровень выше)


(Читать комментарии) -