«Кремниевая долина»

Пока отхожу от операции, смотрю сериал «Кремниевая долина» и дабы не заржавел мозг, сделал расшифровку надписи на футболке Эрлиха — одного из героев сериала, на трёх языках: Перле, Пайтоне и Тикле. Листинг один для трёх языков:
#\
"@{[$\=qq{\n},\
print map {chr $_} (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110)]}";#\
__END__ = 1;\
print(''.join(chr(b) for b in (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110))); #\
"""
foreach name {01000010 01101001 01110100 01100011 01101111 01101001 01101110} {
    puts -nonewline [binary format B* $name]
}
puts {} ;#"""
Дольше всего с Перлом возился, пока не вспомнил, что у него есть вычисление выражений внутри строк через конструкцию @{[…]}. Нужно рассказать как всё работает?
Комментировать
10 июля 2015 18:29

«Taint» в Перле

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

Например, хорошей вещью, на мой взгляд, является «taint» («загрязнение») — это специальная метка на переменной, что в ней лежат недоверенные данные, смешивание доверенных и недоверенных данных приводит к «загрязнению» результата. Недоверенными данными является весь ввод — то, что пришло со входного потока, прочитано из файлов и так далее, доверенными — то, что произвела сама программа. Например:
my $a = "hello"; # доверенные данные
my $b = <>; # «загрязённые» (строка, прочитанная из входного потока)

$a .= $b; # данные в переменной $a стали «грязными»
«Грязные» данные (если включен соответствующий режим), при попадании в операции, где они могут представлять угрозу для безопасности (например, пользовательский ввод напрямую попадает в функцию языка для удаления файла), генерируют специальное сообщение.

Вот, например, что будет если я добавлю в конец предыдущего кода вызов unlink (эта функция удаляет файл в Перле) с переменной «a», в качестве аргумента:
Insecure dependency in unlink while running with -T switch at sample.pl line 6, <> line 1
Причём выполнение программы прервётся в этом месте.

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

Было бы полезно иметь такой же механизм в ПХП — это помогло бы свести многие уязвимости к нулю, например, внедрение скриптов в код ХТМЛ или СКуЭл-уязвимости.

Справедливости ради, «taint» есть не только в Перле, насколько я знаю, этот же механизм используется в Руби и одно время был реализован в ДжаваСкрипте.
47 комментариев
10 января 2014 12:44

Локальные переменные

В прошлом я несколько лет программировал на Перле, очень любил этот язык и неплохо знал, до сих пор могу без особых проблем читать программы на нём. Прошло немало лет, наиболее часто я теперь использую ПХП и Джаваскрипт, на Перле не пишу вовсе (хотя в «Яндексе» был краткий эпизод — написал небольшой пример для документации к какому-то сервису).

Вообще я сейчас считаю, что будущее скорее за языками с лаконичным синтаксисом (Пайтон), чем за тем, у кого он сверхнасыщен (Перл, Руби).

Тем не менее, некоторых вещей из Перла мне до сих пор нехвает в других языках. Я научился без этого обходиться, но много лет меня не отпускает чувство, что у меня чего-то нет, что было раньше — как будто трогаешь языком ямку, где раньше был зуб.

Например, локальные переменные. В ПХП часто приходится смотреть (особенно, если достаётся код-лапша), не определяется ли выше и не используется ли ниже переменная с каким-нибудь глубокомысленным названием — «temp», «i» или что-то в подобном роде. Ну мне тоже хочется что-то временное сохранить и в цикле какой-то счётчик использовать, причём посредь чужого кода.

В Перле такой проблемы нет — там локальную переменную можно создать почти в любом месте, произвольном месте кода, просто поставив фигурные скобки — так создаётся новый лексический блок, у которого могут быть свои локальные переменные:
my @a = (1, 2, 3);
my @b = ('a', 'b', 'c');

for my $i (@a) { # первая переменная $i
     for my $i (@b) { # вторая переменная $i, перекроет первую только внутри цикла
         print $i . "\n";
    }

    {
         my $i = 'end'; # третья переменная $i, перекроет первую только в этом блоке
         print $i . "\n";
    }

    print $i . "\n"; # выводится первая переменная $i
}
Конечно, я не призываю именно так писать код — во вложенных циклах с одной и той же переменной легко запутаться, просто иллюстрирую принцип.

В Джаваскрипте ситуация меняется, появилась конструкция «let» (впрочем, раньше её можно было эмулировать), а ПХП ничего похожего так и нет. Я переписывался с разработчиками много лет назад на эту тему, но воз и ныне там.

Сейчас есть возможность опубликовать предложение, описав его в виде RFC — эта новая процедура появилась недавно, если предложение понравится, то синтаксис имеет все шансы попасть в язык. Надо будет как-нибудь заняться.
Комментировать
30 ноября 2013 12:12

Оператор goatse в Перле

Внезапно вспомним Перл. Когда-то я на нём много и в удовольствием программировал, причём этот навык не утерян мною до сих пор. Хотя попрограммировать на этом девиантном языке мне удаётся редко, я по-прежнему им восхищён. Немного жаль, что он умирает, но право же, чаще программы на нём можно слать в передачу «А вам слабо?», чем в продакшн.

Есть такая шутка, что Перл единственный язык, программа на котором до и после RSA-шифрования выглядит одинаково. Честно сказать, я не уверен, что это шутка, так как вот это, например, вполне разумная программа на Перле:
not exp log srand xor s qq qx xor
s x x length uc ord and print chr
ord for qw q join use sub tied qx
xor eval xor print qq q q xor int
eval lc q m cos and print chr ord
for qw y abs ne open tied hex exp
ref y m xor scalar srand print qq
q q xor int eval lc qq y sqrt cos
and print chr ord for qw x printf
each return local x y or print qq
s s and eval q s undef or oct xor
time xor ref print chr int ord lc
foreach qw y hex alarm chdir kill
exec return y s gt sin sort split
Если не верите, попробуйте запустить, ничего страшного не произойдёт. Очень много шуток есть по поводу того, каким ненатуралом надо быть, чтобы программировать на этом языке и в этом тоже есть доля правды.

Я постараюсь пропустить неаппетитные подробности, но есть такой мем «goatse» — это картинки мужичка, в деталях показывающего свою тёмную неизвестность, а так же пародии на неё. Не гуглите пожалуйста это, прошу, нет, даже умоляю, не надо. Та картинка, как любой шок-контент, используется в троллинге.

Для нас важно, что после того как картинка стала мемом, появился смайлик „=()=“, довольно точно отражающий её суть. Я знаю эту преамбулу, потому что однажды какой-то экспериментатор нашёл в Перле то, что назвали goatse operator — тот самый „=()=“, который, что интересно, позволяет делать довольно разумную вещь.

Например, вам нужно подсчитать сколько цифр содержится в строке. На помощь вам придёт goatse operator!
my $s = "Hello, world! This is a Perl! 123456";
my $c =()= $s =~ /\d/g;
print $c;
В результате будет напечатано число шесть.

Как это работает и почему нельзя как-то иначе?

Сначала отвечу на первую часть.

Самое правое выражение в рассматриваемой строчке — регулярное выражение, которое ищет одну цифру, оператором «=~» мы применяем его к конкретной переменной, а ключ «g» в конце регулярки говорит, что искать надо все вхождения.

В Перле есть понятие скалярного и списочного контекста. Результат может сильно отличаться в зависимости от того ожидается ли в каком-то месте кода скаляр или список (массив). Программист даже может проверить в каком контексте вызвана его функция при помощи специальной функции «wantarray».

Например, если я попробую напрямую присвоить результат выполнения регулярного выражения на переменной „s“ в скалярную переменную (начинается с доллара), то я получу флаг, показывающий встретились ли вообще цифры в рассматриваемой переменной. Если же присвоить тот же результат массиву (имя переменной начинается с «@»), то я получу массив совпадений.

С goatse operator происходит следующее.

На деле «() = что-то ещё» — это обычное присваивание массиву чего-то ещё. Пустые скобки — пустой анонимный массив, ему тоже можно что-то присвоить, синтаксис это позволяет. Таким образом контекст не скалярный и мы всего-то присваиваем одному массиву другой. Дальше чуть интереснее. По правилам Перла присваивание первого массива второму в скалярном контексте возвращает количество элементов первого.

Получается «SCALAR = LIST0 = LISTREGEXP», что возвращает нам количество элементов массива LISTREGEXP при любом не константном LIST0. Двумя присваиваниями, идущими подряд, вряд ли кого-то удивишь, цепочки присваиваний можно использовать в Си, JavaScript, PHP и куче других языков.

Теперь ответ на второй вопрос. Нельзя ли как-то иначе. Можно. Если религия вам не позволяет использовать «оператор» с такими сомнительными ассоциациями, то можно, например, присвоить результат работы регулярного выражения переменной-массиву, а потом взять его в скалярном контексте. Как-то так:
my $s = "Hello, world! This is a Perl! 123456";
my @c =$s =~ /\d/g;
print scalar @c; # массив в скалярном контексте вернёт количество элементов
Но это скучно.
25 комментариев
14 июля 2011 00:55

Определение UTF-8 на чистом Perl

У нас сейчас смена админов: отдел переходит из ведомства одних админов к другим. Соотвественно, все задачи выполняются сильно медленее. Задача по установке модуля к Perl висит уже несколько дней. Вот и пришлось мне написать на чистом Perl функцию, определяющую UTF-8 это или нет.

На Perl'e не писал уже очень давно, так что было интересно что я помню. Функцию, в итоге, сохраню здесь, мало ли — понадобится кому.
sub detect_utf8($) {
    my $str = shift;
    my %exclude = map { $_ => undef } (0..191, 194..244);  # RFC 3629

    for (my $i = 0, $l, $len = length $str; $i < $len; $i++) {
        $code = ord substr($str, $i, 1);

        return 0 unless exists $exclude{$code};

        for ($l = 0; $code & 128; $l++, $code = 0xFF & ($code << 1)) {}

        $i += $l - 1 if $l;

        return 0 if $i > $len or $l > 4; # broken
    }

    1;
}
Что можно улучшить: проверять, чтобы дополнительные байты имели старшие биты «10».
5 комментариев
14 апреля 2009 16:20

PHP SOAP

Что-то одно PHP SOAP или Perl SOAP::Lite — делала ключница. Простая задача: общаются две программы, клиент на PHP, используется модуль SOAP и сервер на Perl, используется SOAP::Lite.

В режиме XML-RPC Perl отвечает «Неверная версия» (SOAP::Lite поддерживает только 1.1), попытки установить версию со стороны PHP (есть специальные константы SOAP_1_1 и SOAP_1_2) ни к чему не приводят, в режиме document ещё хуже — PHP начинает плеваться совершенно невразумительными сообщениями об ошибках из разряда «моя нога кефир валяться», т.е. все слова знакомые, но что бы это значило… Мануал ничего не проясняет, интернет молчит, примеры из руководства не работают. Шаманскими плясками (например, я нашёл в исходниках параметр soap_action) удалось заставить PHP замолчать, но тут уже возмущается Perl — говорит, что доступ к методу запрещён.

Есть ещё nuSOAP (написанный на чистом PHP), но этот монстр занимает более полуметра. В общем, выкинул всё, взял cURL и SimpleXML. Сам запрос — 40 строк, ещё примерно столько же — разбор ответа через SimpleXML, меньше сотни строк. Так и живём.
11 комментариев
23 июня 2008 12:57

Декоративная обфускация PERL-кода

Нашёл замечательную старую статью «Декоративная обфускация PERL-кода», в статье есть просто изумительные примеры, например, знаменитый «квадрат» из ключевых слов Perl:
not exp log srand xor s qq qx xor
s x x length uc ord and print chr
ord for qw q join use sub tied qx
xor eval xor print qq q q xor int
eval lc q m cos and print chr ord
for qw y abs ne open tied hex exp
ref y m xor scalar srand print qq
q q xor int eval lc qq y sqrt cos
and print chr ord for qw x printf
each return local x y or print qq
s s and eval q s undef or oct xor
time xor ref print chr int ord lc
foreach qw y hex alarm chdir kill
exec return y s gt sin sort split
Это работающая программа, выводящая строку «just another perl hacker».
3 комментария
18 марта 2008 16:31

Use only…

Столько лет программирую на Perl и всё время узнаю что-то новое. Главным образом потому, что недосуг внимательно прочитать полную документацию. Сегодня с удивлением узнал о существовании конструкции «use only» [ <<> ]
4 комментария
22 апреля 2003 18:22