Мёртвые японские души

Расследование министерства юстиции Японии не смогло обнаружить 234,354 тысячи человек старше 100 лет, которые по бумагам числятся живыми, в действительности их местопребывание, по обнародованным в пятницу данным, неизвестно.

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

И это министерство проверило только список столетних, если взять возраст младше, неизвестно сколько там таких «зомби». Мне интересно — если отфильтровать умерших, насколько снизится средняя продолжительность жизни в Японии?

7 комментариев

Огромные пульты

Огромный пульт от телика (32.24КиБ)

В супермаркете сегодня увидел — универсальный пульт «Gal LM-X11». Интересен он размерами — 12,5×28×2,5 см (сантиметров!).

Как ни странно, но такого монстра я бы купил. Если бы у меня был телевизор. Во-первых, это забавно, во-вторых, он вряд ли потеряется. Даже если упадёт за диван, я это услышу (о, да! вес — почти 400 грамм). С миниатюрными пультами у меня в прошлом была вечная проблема «куда-же-я-его-дел».

19 комментариев

Хром → Опера

К сожалению, с «Хрома» (это браузер), к которому я уже привык и который обставил с любовью плагинами, мне придётся пересесть куда-то ещё. Особенно я привык к расширению, которое позволяет в моём «Андроиде» (это операционная система в телефоне) мгновенно открыть ту же страницу, что у меня в браузере и продолжить читать с того же места. Очень удобно.

Но. Недавняя неприятная история, когда в код «Хромиума» (это «Хром», но без «жучков») попал один из «шпионских» модулей, заставляет задуматься — что ещё, по небрежности или умышленно, могла забыть выключить корпорация «Гугл» в своём браузере? Тем более, что ещё на слуху история о том, что «Гугл» собирал данные WiFi-трафика при помощи автомобилей Street View.

Вообще-то, каких-то особых секретов персонально у меня нет, но они есть у «Яндекса» и мне очень не хочется, чтобы какие-то данные из интранета по моей вине попали в «Гугл». Так что, «Хром» и «Хромиум» я больше не использую. По крайней мере, в ближайшем будущем.

Перехожу обратно на «Оперу», других вариантов нет. «Сафари» под Windows — это какой-то чёрный юмор, FireFox похож на обросшую ракушками баржу, IE9 пока ещё сырой чуть более, чем полностью. Так что, при всё богатстве выбора, другой альтернативы нет.

30 комментариев

«Community»

Только что, в шестнадцатой серии сериала «Сообщество», Абед Надир произнёс, напиваясь, «будем здоровы» по-русски (!).

Отличный сериал, кстати. Спасибо всем тем, кто советовал.

16 комментариев

PHP и UTF-8: четыре и шесть десятых или ещё проблемные функции

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

Дальше
Для начала, у нас в проекте используются ord и chr — функции получения кода символа и получения символа по его коду. Понятно, что места, в которых эти функции используются жёстко завязаны на однобайтные кодировки. В некоторых случаях ничего страшного не случится, в других эти места придётся переписать. Я нашёл несколько случаев использования, переписать пришлось пока только одно место, ещё одно я отложил на будущее. Сами функции я переписал следующим образом:

static public function ord($character) {
        if (self::ON) {
            $codes = unpack('N', mb_convert_encoding($character, 'UCS-4BE', 'UTF-8'));
            return reset($codes);
        }

        return ord($character);
    }

    static public function chr($ascii) {
        if (self::ON) {
            return mb_convert_encoding(pack('N', $ascii), 'UTF-8', 'UCS-4BE');
        }

        return chr($ascii);
    }

Более простая, но тоже не самая очевидная функция — addcslashes. Она экранирует указанные символы слешем, представляя все символы с кодом большим 128 как восьмеричное число, например, буква «ф» (в кодировке cp1251), если указать её во втором параметре, будет представлена «\364». Вопрос в следующем — символы в UTF-8 могу занимать больше одного символа, как их заэкранировать?

Ответ в парной функции — stripcslashes. Если последовательно заэкранировать все байты UTF-8-последовательности символа, то stripcslashes вернёт этот символ в первоначальное состояние. Код реализации я приводить не буду, слишком длинный. Что о нём нужно знать — последовательность экранируется только в том случае, если встречается целиком.

Моя задача — эмулировать поведение функции в точности, в этой связи str_pad содержит две загадки: если задана строка дополнения из двух символов и более, то как аргумент дополняется слева и какая сторона дополняется первой, когда дополнять надо обе стороны?

bolk@dev:~/daproject$ php -r 'var_dump(str_pad("..", 3, "12", STR_PAD_BOTH));'
string(3) "..1"
bolk@dev:~/daproject$ php -r 'var_dump(str_pad("..", 5, "12", STR_PAD_LEFT));'
string(3) "121.."

Как видим, сначала дополняется правая сторона, а при дополнении слева символы дополняют в указанном порядке (когда я программировал эту функцию, у меня был соблазн сделать дополнение с конца последовательности).

Вообще, в PHP функций с тонкостями поведения масса. Функция wordwrap (по-умолчанию) преобразовывает длинную строку в абзац заданной ширины, разрывая строку так, чтобы не разорвать слова. А вот какими символами, по мнению этой функции, разделяются слова? Мои эксперименты показывают, что это пробел и «\n». Интересно, что «\r\n» эта функция не разрывает! Так же нужно не забыть про то, что пробелы, вообще говоря, сохраняются, заменяется на символ переноса только необходимый минимум.

13 комментариев

PHP и UTF-8: четыре с половиной или некоторые функции

Я пока приостановил эпопею с UTF-8, так как сменились приоритеты, но обязательно ещё вернусь к этому вопросу. А пока, в паузах, потихоньку пишу для функций, для которых уже нет UTF-8-аналогов эти самые аналоги. Вот, например, очередной набор (это статические методы класса UTF, для краткости я убираю часть для работы с однобайтными строками):

public static function strcmp($str1, $str2) {
    // используется модуль intl
    return collator_compare(collator_create(''), $str1, $str2);
}

public static function strncmp($str1, $str2, $len) {
    return self::strcmp(self::substr($str1, 0, $len), self::substr($str2, 0, $len));
}

public static function strcasecmp($str1, $str2) {
    return self::strcmp(self::strtolower($str1), self::strtolower($str2));
}

static public function ctype_space($text) {
    return preg_match('/^\p{Zs}+$/us', $text);
}

Привожу в качестве иллюстрации того, что не всё так сложно как кажется. Стоит только сесть и начать.

Некоторые функции в PHP уже есть (mb_substr), какие-то требуют минимальных доделок (preg_replace), некоторые можно выразить через другие (trim через ltrim и rtrim), оставшиеся, конечно, придётся написать (strcmp, ltrim, addcslashes и так далее).

И, кстати, в ходе родился замечательный совет: если функцию трудно реализовать (например, str_ireplace), посмотрите, может проще переписать место, где она используется. У меня две функции были использованы ровно по одному разу.

Добавлено позднее: тщательно изучил вопрос сравнения Unicode, я выяснил, что производить сравнение так, как это сделал я нельзя, поэтому функцию strcmp я удалил, буду переписывать. Например, буква «ё» в Unicode стоит дальше «л», а должно быть наоборот.

Добавлено ещё позже: в PHP 5.3 появилось расширение Intl, основанное на известной библиотеке UCI, оказывается это расширение собирается и с PHP 5.2.4+, так что имеет смысл использовать именно его.

13 комментариев

Белоярская АЭС

Есть такое направление — технотуризм, это посещение всевозможных закрытых учреждений и объектов. Мне давно хотелось посетить настоящую атомную электростанцию и вот, в прошлые выходные, мы с женой съездили на Белоярскую АЭС (находится в городе Заречный Свердловской области).

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

Спасибо огромное агентству «Редкая марка» и  Бутяковой персонально за организованную экскурсию. Если кто-то захочет попасть на АЭС в ближайшем будущем, обращайтесь туда, можно написать лично.

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

Белоярская АЭС уникальна тем, что на её территории действует единственный в мире реактор на быстрых нейтронах БН-600 (мощность в настоящее время — 630 МВт), запущенный ещё в 1980 году — наследство СССР, инженерная школа страны была на таком уровне, что реактор этого типа (считается самым перспективным и современным) работает вот уже 30 лет без критических сбоев.

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

Дело не только в очень удачных инженерных решениях, но и в применённых материалах. Можно только гордиться промышленностью СССР, но вот такого же доверия к промышленности России у меня нет. Сейчас на территории АЭС возводится энергоблок БН-800 (на тех же быстрых нейтронах, как следует из названия), получится ли у нас ещё раз? Дирекцию настроена оптимистично, меня же гложут сомнения.

Что такое атомная электростанция изнутри? Моё воображение рисовало, довольно туманно, огромный реактор, вокруг куча обслуживающего персонала… На деле атомная электростанция — это трубы. Трубы, трубы, трубы, трубы и очень мало людей.

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

Самый совершенный атомный реактор, на настоящий момент, это обычная печка, энергия снимается через тепло. Кстати, в реакторе на быстрых нейтронах БАЭС в качестве теплоносителя используется жидкий натрий (это очень эффективно, но порождает массу технических трудностей, например, натрий при контакте с водяными парами взрывается).

Как и в моём воображении, на реальных АЭС всё управляется из больших комнат с кучей приборов, правда, люди не сидят сутками, напряжённо вглядываясь в их показания, а довольно расслабленно, даже вальяжно наблюдают за ситуацией. Такая расслабленность может моментально смениться слаженной активностью и умение мгновенно концентрироваться — главное качество, необходимое в этой работе.

Одна ошибка — курсы переквалификации, экзамены, вторая — прощай диспетчерская.

На фотографиях видно, что часть приборов современенная, часть, не иначе, осталась ещё с советских времён. Это закономерно — диспетчеры привыкают к определённым приборам и снимать показания с новых для них неоправданное неудобство. Тем не менее, приборы выходят из строя и обновления всё же производят, но дозированно.

Сам реакторный цех ещё более пустынный и огромный (десятки метров в любую сторону). Небольшая яркая бочка, окружённая «лепестками» — реактор. Не впечатляет, правда? Внутри реактора интересно до смерти, но в могилу мы не стремимся.

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

Общие впечатления — один раз съездить на такой объект интересно, в дальнейшем я бы посетил разве что музей в Обнинской АЭС (это первая гражданская АЭС в мире), не сомневаюсь, что остальные станции похожи между собой, на взгляд неспециалиста, как две капли воды.

14 комментариев

IE9 beta

Internet Explorer 9 beta (39.95КиБ)

Вышла первая бета-версия IE9. Идея разместить табы и адресную строку на одной прямой явно неудачная.

Сайты открываются через пень-колоду, явно хуже, чем в последней platform preview, мой сайт выглядит, как какашидзе, даром, что показывался одинаково во всех браузерах, включая самые старинные IE Mobile. Зато ACID3 — 95%, одно слово — синтетика.

Тьфу.

14 комментариев

QR-код в ASCII

 ▄▄▄▄▄▄▄  ▄▄ ▄▄    ▄▄▄▄▄▄▄ 
 █ ▄▄▄ █    ▄▄▄▀ ▄ █ ▄▄▄ █ 
 █ ███ █ ▀▄▀▄▀ ▄ ▀ █ ███ █ 
 █▄▄▄▄▄█ █▀█▀▄▀█ ▄ █▄▄▄▄▄█ 
  ▄▄   ▄ ▀██▀██ ▀█ ▄▄ ▄    
 ▄▄█▀ █▄▀█▀▀▀▀▄▄█  ▀▀ █▄▀█ 
 ▄███ ▀▄ ▀  ▄ ▄█▄█ ▄█▀▀  ▄ 
 ▀ ▀▄▀▄▄▀▄▄▄█▄ ▀██▄▀█ ▄▄▀█ 
 ▀▀▄▄▄▀▄ ▀▀█ █▄▀▄███▄▄  ▄  
 ▄▄▄▄▄▄▄ ▀▄▄▀▄▄ ▀█ ▄ █▄▀ █ 
 █ ▄▄▄ █  ▄█▀█ ███▄▄▄█▄ ▄█ 
 █ ███ █ ▄██▀▀▄▀▀▀█  █▀▀█▄ 
 █▄▄▄▄▄█ ▀ ▀ ███ ██▀▀▀▄  ▄ 
 

Интересная штука — QR-коды в ASCII-графике. Можно внутри текста помещать, в обычном текстовом файле. Profit.

14 комментариев

Пакетное скругление картинок v0̶.̶2̶.̶1 0.2.2

Ребята, качайте новую версию, я сделал antialiasing для углов. Ну и пришлось же помучиться! Я немного заболел, пока сидел дома, сделал.

Основная идея такова — рисуется красный круг на чёрном фоне, на него накладывается фильтр Гаусса (тут меня ждала засада — в PHP 4.4.4, который у меня, нет функций imagefilter и imageconvolution, зато последняя, написанная на чистом PHP есть в интернeтах).

Далее, я считаю красную компоненту круга альфа-каналом для указанного цвета фона и накладываю по точкам в четыре угла картинки четыре квадрата изображения с красным кругом. Формула пересчёта rgba → rgb очень простая.

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

Добавлено позже: обновил до 0.2.2 — теперь вся работа с временными файлами делается внутри временной папки (путь до неё берётся из переменных окружения).

25 комментариев

«Ты слишком правильный»

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

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

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

17 комментариев

Микроцефал

Фото из самолёта (32.21КиБ)

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

15 комментариев

Пакетное скругление картинок v0.2

Новая версия пакетного скруглителя картинок. Из нового: короткие имена ключей (их видно после запуска), ключи для сохранения EXIF из оригинального файла (-​-save-exif), рекурсивного обхода папок (-​-recursive) и сохранения оригинальных имён файлов (-​-keep-name).

19 комментариев

PHP и UTF-8: четвёртый этап

В прошлой части мы кое-что заменили в коде, в этой части неплохо было бы поискать не забыли ли мы что-то ещё заменить. А это значит — куча работы руками.

Какие у нас есть варианты?
Какие у нас есть варианты? Функцию preg_replace_callback мы рассмотрели ещё в прошлый раз (а я это сделал сегодня, ничего криминального не нашёл), но есть и другие callback-функции, а так же eval, регулярные выражения с ключом «e» (PREG_REPLACE_EVAL), call_user_func, call_user_func_array и create_function.

Начнём с eval, его проще всего найти:

bolk@dev:~/daproject$ find -type f ( -name '*.php' -or -name '*.tpl' -or -name '*.inc' ) | xargs -n1 egrep -li 'bevals*('
./php/lib/magpierss/extlib/Snoopy.class.inc
./php/lib/PEAR.php
./php/dir1/file1.php
./php/dir1/file2.php
./php/dir1/file3.php

К счастью, почти всё что я нашёл — это eval-вызовы в коде на JavaScript внутри PHP-скриптов, так что править мне ничего не пришлось. В вызовах call_user_func, call_user_func_array и create_function я так же ничего криминального не нашёл (проверяются точно так же).

Теперь я попробую найти вообще все callback-функции. Это чуть сложнее сделать — в руководстве по PHP раздела, где они были бы перечислены нет. В chm-версии руководства я просто поискал строку «callback».

Не все callback-функции нас интересуют, нужны только те, которые возвращают строковый результат. Кроме того, нужно поискать использование констант, которые задают в некоторых вызовах callback-функции.

Вот что у меня получилось: readline_callback_handler_install, readline_callback_read_char, ob_start, session_set_save_handler, CURLOPT_HEADERFUNCTION, CURLOPT_PASSWDFUNCTION, CURLOPT_PROGRESSFUNCTION, CURLOPT_READFUNCTION, CURLOPT_WRITEFUNCTION, FILTER_CALLBACK, iterator_apply, set_exception_handler, pcntl_signal, array_map, array_filter, array_walk, array_walk_recursive, array_udiff_uassoc, array_diff_uassoc, array_udiff_assoc, array_diff_ukey, array_udiff , array_intersect_ukey, array_uintersect_uassoc, array_uintersect_assoc, array_intersect_uassoc, array_intersect_assoc , array_uintersect, array_reduce, uksort, usort, uasort.

Или для командной строки (регулярное выражение я тут подсократил):

bolk@dev:~/daproject$ find -type f ( -name '*.php' -or -name '*.tpl' -or -name '*.inc' ) |
> xargs -n1 egrep -H 'array_map|array_filter|array_walk|…|uasort' | less

В выводе нужно высматривать только вызовы строковых функций и статических методов, которые стоят на месте callback-параметров или переменные на тех же местах, в последнем случае нужно будет детально разобрать что находится в этих переменных. У меня на это ушло две минуты, это в проекте с 50000 строк кода.

Всё, что осталось найти — вызовы preg_replace с модификатором «e». Я, было, подумал как-то автоматизировать это дело, но просмотрел сколько у меня вхождений этой функции — оказалось около 200, быстрее просмотреть глазами. Мои старания были вознаграждены — я сделал несколько замен.

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

2 комментария

33

Ну вот мне и 33. В этой связи часто вспоминают выражение «возраст Христа», сделайте мне одолжение не надо в мой день рождения вспоминать во сколько Христос помер, мне не будет приятно.

Я как-то незаметно завёл традицию — каждый год в этот день я вспоминаю что я успел сделать с прошедшего дня рождения. Сегодняшний день не исключение, но в этом году будет ещё и фотоnew.

Мужчина в коричневой куртке и джинсах стоит в лесу, держа лопату рядом с вырытой ямой и молодым деревцем, готовясь к посадке.
Сажаю дерево

Согласно расхожей поговорке, настоящий мужчина должен посадить дерево, построить дом и вырастить сына. В этом году я начал претворение этого плана в жизнь. Итак, с предыдущего дня рождения я успел следующее:

33 комментария

Веб-сервис оптимизации SVG

Веб-сервис оптимизации SVG (11.36КиБ)

Евгений Рыжков изготовил из моего скрипта оптимизации SVG веб-сервис. Скрипт я когда-то писал для книги и он появился после существенного развития идей Джоша Хирта, который показал принципиальную возможность автоматической оптимизации этого формата.

6 комментариев

Ограничение сна: FAIL

Всё, хватит, заканчиваю свой эксперимент по ограничению количества сна. Мне, чтобы выспаться, нужно около 9…10 часов, я ограничивал время сна до 5…8 часов в день. Появились все признаки усталости: сонливость, рассеянность. Правда, сегодня всё будет ещё хуже — у нас вылет в Екатеринбург в половину первого, а в 8:15 уже подъём.

Не знаю, буду ли читать комментарии. Как получится.

Оставить комментарий

PHP и UTF-8: третий этап (давайте уже что-нибудь заменим)

Ну что ж, всё готово для того, чтобы наконец-то что-то заменить в нашем проекте. С прошлого этапа у нас должен появиться поправленный руками класс Utf, который нужно подключить так, чтобы он был доступен из любого файла нашего проекта. Например, для этой цели можно воспользоваться настройкой PHP «auto_prepend_file».

Что же дальше?
Следующая программа поможет нам заменить наши ущербные функции (их имена и статистика всё так же лежат в файле tool-func.log) на пока не менее ущербные обёртки.

<?
    if ($_SERVER['argc'] <> 3) die;
    if (realpath($_SERVER['argv'][2]) == realpath(__FILE__)) die; 

    $file = file_get_contents($_SERVER['argv'][2]);
    if (strpos($file, '<?') === false) die;

    $funcs = file($_SERVER['argv'][1], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($funcs as &$func) {
        list(,$func) = preg_split('/\s+/s', $func, 2, PREG_SPLIT_NO_EMPTY);
    }

    $skip   = false;
    $skipIf = array(T_PAAMAYIM_NEKUDOTAYIM, T_DOUBLE_COLON, T_OBJECT_OPERATOR);
    $fixed  = false;

    ob_start();

    foreach (token_get_all($file) as $token) {
        if (is_scalar($token)) {
            echo $token;
        } else {
            if (!$skip && $token[0] == T_STRING && in_array(strtolower($token[1]), $funcs)) {
                $fixed = print 'Utf::' . $token[1];
            } else {
                echo $token[1];
            }

            $skip = in_array($token[0], $skipIf); 
        }
    }

    file_put_contents($_SERVER['argv'][2], ob_get_clean());

    if ($fixed) {
        echo $_SERVER['argv'][2], "\n";
    }

Запустить её можно, например, так (напоминаю, что у меня PHP находится в файлах с расширениями php, tpl и inc):

bolk@dev:~/daproject$ find -type f \( -name '*.php' -or -name '*.tpl' -or -name '*.inc' \) | grep -vF '.svn' |
> xargs -n1 php tool4.php tool-func.log
./php/file.php
./php/dir1/file1.php
./php/dir1/file2.php
./php/dir1/dir2/file3.php
…

Программа напечатает имена файлов, где произошла замена. Своеобразная проверка — запустите её ещё раз, на втором проходе никаких имён файлов выведено быть не должно! Обязательно проследите, чтобы запуск не затронул ваш класс Utf!

Итак, мы заменили функции на вызовы класса Utf. Всё работает? У меня не заработало. Причины две — я ошибся в имени одной из функций в классе Utf и появились проблемы с preg_replace_callback. О последней проблеме поподробнее.

Пока preg_replace_callback была встроенной функцией всё было замечательно, как только она стала статическим методом класса, проблемы появились. Всё дело в указании в качестве callback метода статического класса. Во-первых, метод может оказаться private или protected, что мешает ему быть вызванным из другого, неродного класса, во-вторых, в качестве имени класса может быть указано «self», а «self» внутри класса Utf равно «Utf», что совсем не то, что ожидается.

Такие вещи придётся править вручную. Если нет возможности провести тестирование, то можно воспользоваться подсказками IDE — во многих случаях она укажет на такие ситуации, но, в любом случае, лучше все такие места просмотреть глазами.

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

Кстати, остаются ещё строковые функции, вызываемые как callback, внутри eval или в eval-выражениях preg_replace. Что-то с ними надо делать.

5 комментариев

PHP и UTF-8: третий этап (создание прототипов)

Этот сериал хорош тем, что я пишу его в реальном времени. Единственно, первая фаза — когда я собирал первоначальные данные и обдумывал как мне подступиться к этой задаче, заняла куда больше времени, чем может показаться. Итак, в предыдущей части мы выяснили какие модули используются в нашем проекте и узнали, что в нём кое-где указана кодировка прямым текстом. Так же держим в голове, что нам надо что-то будет делать с файловыми функциями и обращением к символу в строке по индексу ($str[$index]).

В этой части мы подготовимся к тому, чтобы заменить в проекте все упоминания небезопасных (с точки зрения работы с UTF-8) функций на статические методы класса Utf, где мы будем менять их на UTF-8-аналоги.

Что же дальше?
Вообще-то, я мог бы, конечно, вручную описать все 38 функций моего проекта, но мы же умеем программировать! Почему бы этим не воспользоваться? PHP даёт широкие (но, к сожалению, глючные) средства для исследования функций — это специальные классы расширения Reflection, которыми мы и воспользуемся.

<?
function U_makeproto($funcname)
{
    $func = new ReflectionFunction($funcname);

    $out = '    static public function ' . $funcname . '(';

    $counter = 0;
    $hasRefOptional = $hasOptional = false;
    $names = array();

    foreach ($func->getParameters() as $param) {
        $name = $param->getName();

        if ($name !== null && $name != '...') {
            $names[] = $name = '$' . $name;
        } else {
            $names[] = $name = '$param' . $counter++;
        }

        if ($param->isPassedByReference()) {
            $name = '&' . $name;
        }

        if ($param->isArray()) {
            $name = 'array ' . $name;
        }

        if ($param->isOptional()) {
            $name .= '=';
            $name .= $param->isDefaultValueAvailable() ? $param->getDefaultValue() : 'null';

            if ($param->isPassedByReference()) {
                $hasRefOptional = true;
            }

            $hasOptional = true;
        }

        $out .= $name . ', ';
    }

    $out = rtrim($out, ', ') . ') {';
    if ($counter || !$names) {
        $out .= "\n        // FIXME: Invalid proto ( https://www.php.net//$funcname )\n";
    }

    $out .= "\n        if (self::ON) {".
            "\n            // TODO: UTF version".
            "\n        }\n";

    if (!$hasRefOptional) {
        if ($hasOptional || !$counter && !$names) {
            $out .= "\n        " . '$params = func_get_args();'.
                    "\n        return call_user_func_array('$funcname', \$params);";
        } else {
            $hereNames = implode(', ', $names);

            $out .= "\n        return $funcname($hereNames);";
        }
    } else {
        $reqCounter = $func->getNumberOfRequiredParameters();
        $out .= "\n        switch (func_num_args()) {".
                "\n            case $reqCounter:".
                "\n                " . '$params = func_get_args();'.
                "\n                return call_user_func_array('$funcname', \$params);";

                for ($i = $reqCounter+1, $len = $func->getNumberOfParameters(); $i<=$len; $i++) {
                    $hereNames = implode(', ', array_slice($names, 0, $i));

                    $out .= "\n            case $i:".
                            "\n                return $funcname($hereNames);";
                }

                $out .= "\n            default:".
                        "\n                 trigger_error('Wrong parameter count for $funcname()', E_USER_WARNING);".
                        "\n                 return null;";

                $out .= "\n        }";
    }

    return $out . "\n    }";
}


echo "<?php\nclass UTF\n{\n    const ON = false;\n\n";
foreach (file('php://stdin', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $funcname) {
    echo U_makeproto($funcname), "\n\n";
}

echo "}";

Как я уже сказал, расширение Reflection работает в PHP с багами, именно поэтому я максимально подробно стараюсь обработать ошибочные ситуации. После запуска программы, можно подсчитать, какое количество функций (у меня их 10) не отобразилось правильно, ничего не поделаешь, придётся их править руками. Файл tool-func.log содержит частоты появления функций с их именами из первого этапа эпопеи.

bolk@dev:~/daproject$ sed -re 's/\s+\S+\s+//' tool-func.log | php tool-func-proto.php > utf.php
bolk@dev:~/daproject$ grep -c FIXME utf.php
10

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

P.S. В коде есть странное место — «blah» . ’\$var’, увы, у меня какие-то глюки с форматированием на сайте, пришлось сделать так.

Оставить комментарий

Пакетное скругление картинок: оболочка

Оболочка (8.03КиБ)

Пока у меня нет свободного вечера, чтобы заняться «скруглятором», но это не значит, что с проектом ничего не происходит. Читатель с ником oldTV изготовил отличную графическую оболочку «MCShell». Выглядит замечательно.

12 комментариев