Всякая мелочь одним постом-9
В заметке в ЖЖ «Бред сивой кобылы» собраны фотографии и описания советских клонов IBM PC.
В конце
80-х в СССР началась перестройка с ускорением. Может, если только ускорение, или только перестройка, и обошлось бы, но перестраиваться и ускоряться редкий Боливар такое вынесет… На фоне этого могучая электронная промышленность СССР и стран СЭВа, следуя руководящим документам эпохи осчастливила нас автохтонными ПК.Итак сегодня маленький обзорчик советских клонов IBM PC — ПЭВМ.
На сайте «Мурмолка» есть интересная статья, вынесенная из закрытой «Лепры», про стажировку в Отделе Технического Контроля Управления Делами Президента.
Саша занимался Виброакустикой. Помните суперкрутые фильмы про шпионов, где звук снимали лазером с окна, либо направленным микрофоном с полукилометра, либо просто специальной штукой, прикладывающейся к стене?
Так вот, Саша был спецом по тому, как это делать или от этого защищаться. Нет, нам конечно же тоже рассказывали про побочные виброакустические возмущения, пьезоэффект и т. д. Но одно дело лекции, другое — слушать обсуждение вчерашнего футбольного матча, происходящее в здании напротив.
В ЖЖ Олега Лурье рассказ об расформированном в начале
Глубина-то совсем небольшая — 104 метра минус тридцать метров сама лодка, итого получается семьдесят четыре- семьдесят два метра. Это же элементарно для моих ребят. Вся операция вывода подводников занимает около трех часов. Итого получается, что мы бы затратили на спасение оставшихся в живых моряков «Курска» не более 5—6 часов, а значит,какая-то, и, я думаю, немалая, часть подводников была бы спасена.
«Зачем исследовать космос» — перевод письма 1970 года отправленного монахине из Замбии, Марие Юкуда, заместителем директора по научной части в Центре космических полетов NASA, в ответ на вопрос о текущих исследованиях Марса.
В своем письме Вы спросили как я могу предлагать расходовать миллиарды долларов на путешествие на Марс, в то время, когда многие дети на Земле умирают от голода. Я знаю, что вы не ожидаете такого ответа, как «О, я и не знал, что есть дети, умирающие от голода, но теперь я буду воздерживаться от любых космических исследований пока человечество не решит эту проблему!»
На самом деле, я знал о голодающих детях задолго до того, как я узнал, что путешествие на планету Марс технически возможно. Тем не менее, я считаю, как и многие мои друзья, что путешествие на Луну и, в конечном итоге, на Марсе и другие планеты, это рискованное начинание, которое мы должны предпринять, и я даже считаю, что этот проект, в конечном счете, будет способствовать решению более серьезных проблем, с которыми мы сталкиваемся здесь, на Земле, чем многие другие потенциальные проекты помощи, которые обсуждались и обсуждаются год за годом, и которые очень медленно приносят осязаемые результаты.
Многотарифные счётчики воды
Сжатие GIF через gzip
Эксперимент мой сжатию несжатых ГИФ, по сути, провалился — если статические изображения иногда оказываются меньше (или сравнимы) с PNG, то с анимированными изображениями, ради которых всё и затевалось, всё плохо, я не сумел подобрать условия, при которых новоявленный метод обгоняет обычные соптимизированные ГИФы.
Зато я попутно выяснил, что ГИФ, вопреки моим ожиданиям, иногда жмётся gzip, на первой попавшейся анимации я получил выигрыш порядка 9%. Так что вот он метод ещё больше утоптать файлы ГИФ:
#!/bin/sh
which -s defluff
if [ $? -eq 0 ]; then
gifsicle -O3 "$1" | gzip -9nc | defluff 2>&- > "$2".temp
else
gifsicle -O3 "$1" | gzip -9nc > "$2".temp
fi
size=( $(ls -l "$2".temp) )
# срезаем заголовок gzip и контрольную сумму
let 'size=size[4]-10-8'
dd if="$2".temp of="$2" bs=1 skip=10 count=$size 2>&-
rm -f "$2".tempВ настройки Апача надо добавить новое расширение файла:
AddEncoding deflate .gif-def
AddType image/gif .gif-defДля браузера вместо gzip я указываю метод deflate — по факту это тот же gzip, но без заголовка и контрольной суммы, что позволяет сэкономить 18 байт, не бог весть сколько, конечно, но почему бы их не убрать, спрашивается.
Утилита defluff , которая у меня упоминается — это оптимизатор кодов Хаффмана для gzip, PNG и zip, иногда даёт выигрыш в размере.
Конвертор в несжатый GIF
Сделал я конвертор из обычного ГИФа в несжатый формат сжатый gzip, выложил на ГитХабе. Основное (разбор ГИФа) написано на Пайтоне, утилита, которая всё запускает — на Шеле. Для работы требуются ImageMagick (предпочтительнее) или gifsicle, gitinter (из libungif) и интерпретатор Пайтона.
Кажется, эксперимент провалился, я ещё буду вертеть различные ГИФы, но вряд ли
Из плюсов для себя: детально для себя разобрал формат GIF, освежил знания Пайтона (которые уже начинают тускнеть), Шела, поработал над интересной идеей.
Прогресс по несжатому ГИФу
Написал половину требуемого, чтобы попробовать эффективно конвертировать анимированный ГИФ в несжатый формат — разбор ГИФа на Пайтоне. Сначала я раскладываю ГИФ на информационные блоки, потом дербаню на кадры при помощи gifsicle, прогоняю каждый через gifinter и вытаскиваю (той же программой на Пайтоне) бинарное содержимое картинки.
Работает медленно, но мне больше нужна наглядность, а не скорость, с тем рассчётом всё и писал — вынимаю почти максимум, большинство данных даже не использую. На анимации в 47КБ (23 кадра) работает 4 секунды на моём слабеньком ноуте. Львиную часть времени (≈75%) занимает выемка бинарного тела картинки.
Вечером буду писать штуку, которая упаковывает полученное обратно в ГИФ.
Ни один браузер, кстати, не умеет отображать всё, что написано в стандарте ГИФа.
Поддержи антитабачный закон!
Попросили опубликовать. Поскольку я поддерживаю эту инициативу, с удовольствием у себя публикую (ниже текст не мой).

Согласно предвыборной программе Владимира Путина, законопроект, собравший 100 000 подписей в Интернете, будет рассмотрен властями. Подписи, собранные на сайте МК, будут переданы в Государственную Думу и Правительство РФ.
При нынешнем уровне потребления табака Россия теряет около 400 000 человек
По данным Всероссийского опроса взрослого населения об отношении к мерам борьбы с табакокурением, 95% россиян считают курение вредным (72%, включая курильщиков, говорят, что это очень вредно). 80% населения страны поддерживают национальную политику борьбы с табачной эпидемией. В том числе за запрет на рекламу табачных изделий высказались 86% опрошенных, за финансирование программ профилактики потребления табака выступают 85%. Более действенные предупреждения на пачках сигарет нужны 81% россиян. Полный запрет на курение в общественных местах и на рабочих местах, включая рестораны и бары, поддерживают 82% жителей страны.
Поддержи антитабачный законопроект Минздрава! Поставь свою подпись на сайте «МК» и расскажи об этой акции друзьям!
Сжатая несжатая ГИФ-анимация
В догонку к предыдущей статье: мне удалось сделать несжатый анимированный ГИФ c сжатием через DEFLATE, вот он ниже (анимация не закциклена):

Там шесть несжатых кадров (цифры «1», «2», «3», «3», «2» и «1») с небольшой задержкой, таблица из 16 цветов, в этом формате (несжатый ГИФ+DEFLATE) файл занял 619 байт:
bolk@Bolk ~ $ telnet bolknote.ru 80
Trying 91.230.61.15...
Connected to bolknote.ru.
Escape character is '^]'.
HEAD /imgs/2012.08.08.1.gif-gz HTTP/1.0
Host: bolknote.ru
Accept-encoding: gzip
HTTP/1.1 200 OK
Content-Type: image/gif
Content-Length: 619
Content-Encoding: gzipСобранная при помощи gifsicle анимация в формате «обычного» ГИФа занимает 1028 байт, разница в полтора раза. Права, я выключил в gifsicle оптимизацию — иначе gifsicle исключит из изображений повторящиеся части и эксперимент будет нечистым.
Сжатый несжатый GIF
Как многие знают, браузер нативно понимает сжатие gzip (алгоритм DEFLATE).
Графический файлы обычно так не сжимают — внутри у них свой алгоритм сжатия, например в ПНГ используется тот же DEFLATE. Но с ГИФом ситуация хуже — у него внутри более старый алгоритм LZW, к тому же нет никаких оптимизационных техник (например, ПНГ использует так называемые «фильтры», которые позволяют эффективно сжимать градиенты.
Вот я и подумал — нельзя ли
Смотрите, слева у вас на экране ГИФ, сжатый при помощи gzip (так и грузится с сервера), справа — ПНГ.
![]()
![]()
В каждом из них равное количество уникальных цветов, ПНГ пропущен через все оптимизаторы, которые я только нашёл. При этом ПНГ занимает 1374 байта, а гзипованный ГИФ — 1347, на 27 байт меньше. Дело тут конечно, не в паре десятков байт, а в принципе — если бы я выбрал картинку побольше, выигрыш, возможно, был бы существеннее.
Почему же LZW внутри ГИФа, плюс DEFLATE снаружи сделали файл меньше, чем оптимизирующие просто DEFLATE, плюс фильтры в случае ПНГ? Обычно наложение одного сжимающего алгоритма на другой делает файл больше сравнению с применением одного, более удачного алгоритам из двоих.
Дело в том, что в ГИФ я использовал несжатый, он подготовлен специальным образом, так, что его собственный алгоритм сжатия не работает, а gzip работает над несжатым потоком данных.
Самый простой, по моему мнению, способ получить такой файл — пропустить его через утилиту gifinter из набора libungif — библиотеки и набора утилит для работы с несжатыми файлами ГИФ.
Утилиты эти отлично скомпилировались под мой «Мак» и обрабатывал я ГИФ следующим образом: для начала оптимизировал его при помощи giflite (эта старая утилита под DOS, которую я запускаю
gifinter optimized.gif > non-compressed.gif
gzip -9n non-compressed.gifДальше я переименовал файл
AddEncoding gzip .gif-gz
AddType image/gif .gif-gzТеперь при запросе сервер будет выдавать все необходимые заголовки:
bolk@Bolk ~ $ telnet bolknote.ru 80
Trying 91.230.61.15...
Connected to bolknote.ru.
Escape character is '^]'.
HEAD /imgs/2012.08.08.gif-gz HTTP/1.0
Host: bolknote.ru
Accept-encoding: gzip
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 08 Aug 2012 06:12:14 GMT
Content-Type: image/gif
Content-Length: 1347
Connection: close
Accept-Ranges: bytes
Cache-Control: max-age=2592000
Expires: Fri, 07 Sep 2012 06:12:14 GMT
Content-Encoding: gzipЕсли интересно как устроен несжатый ГИФ, об этом можно прочитать в Википедии, откуда я взял картинку, там интересная уличная магия, перепечатывать «Википедию»
Готовой разгадки почему сжатый несжатый ГИФ обогнал ПНГ у меня нет, но есть одно возможное соображение — ГИФ
Динозавр в храме Ангкор-Ват
Храм
Причём окружающие животные нарисованы очень натурально, безо всяких фантазий, а тут — динозавр. У меня такой вопрос — не знает ли
Что ещё интересно, стегозавр нарисован ровно так, как будто художник его видел, т. е. без устрашающих излишеств, которыми снабжали чудовищ на старинных гравюрах.
Льняная свадьба
Думаю, зря мы забросили традицию отмечать годовщину свадьбы фотосессией, это интереснее, чем просто сходить в ресторан, как мы сделали в прошлом году. Льняную свадьбу (четыре года) мы отметили в стиле начала двадцатого века — революция ещё не случилась, но многие замечательные вещи — электрическое освещение, телефон уже вошли в нашу жизнь.
Съёмки проходили в
За фотографии традиционное спасибище великолепной Маше Зверевой, остальные фотографии можно посмотреть у неё в ЖЖ (из тех, что она сама выбрала).
Также спасибо за трость (видели бы вы как я её красил из балончика с краской) Индире Файзрахмановой, за часы Елене Козаковой и Мире Абраровой, Лилии Ясиной за букет и Инне Каражаковой за причёску жены.
Жена, ты такая молодец, что смогла это всё организовать!
Код для защиты GIF, PNG и JPEG (к предыдущей статье)
В коментариях к предыдущей заметке о моём предложении по защите графических форматов от внедрённого кода один из читателей попросил привести код, который показывал бы как моё предложение работает.
Для форматов GIF, JPEG и PNG я за полчаса написал следующее (язык — PHP 5.4 и выше):
<?
// //bolknote.ru август 2012
// Защищаем изображения, возращает false в случае неудачи
function ProtectPicture($inname, $outname)
{
// типы изображения, которые мы можем защитить и функции защиты
$enabled = [
IMAGETYPE_JPEG => 'Jpeg',
IMAGETYPE_PNG => 'Png',
IMAGETYPE_GIF => 'Gif',
];
if (list(,, $type) = @getimagesize($inname)) {
if (isset($enabled[$type])) {
if ($fi = @fopen($inname, 'rb')) {
flock($fi, LOCK_SH);
if ($fo = @fopen($outname, 'wb')) {
flock($fo, LOCK_EX);
// если все файлы удалось открыть, то вызываем функцию защиты
$ret = call_user_func('ProtectPicture'.$enabled[$type], $fi, $fo, filesize($inname));
fclose($fo);
fclose($fi);
if (!$ret) {
unlink($outname);
}
return $ret;
} else {
fclose($fi);
}
}
}
}
return false;
}
/* Private functions */
function ProtectPictureJpeg($fi, $fo, $controllen)
{
// заголовок JPEG
if (!@fwrite($fo, fread($fi, 2))) return false;
$protect = '<?php __halt_compiler();';
$length = pack('n', strlen($protect) + 2);
// дописываю секцию COM (comment)
if (!@fwrite($fo, "\xFF\xFE$length$protect")) return false;
// остаток файла
if (@stream_copy_to_stream($fi, $fo) != $controllen - 2) return false;
return true;
}
function ProtectPicturePng($fi, $fo, $controllen)
{
// заголовок PNG
if (!@fwrite($fo, fread($fi, 8))) return false;
// пропускаем кусок IHDR (он должен быть первым))
$len = unpack('N', $lenbin = fread($fi, 4))[1] + 8;
$ihdr = $lenbin . fread($fi, $len);
// Смотрим, не написал ли в этот кусок хакер свой код
if (($pos = strpos($ihdr, '<?')) !== false) {
// в стандарте перечислены поля, которые есть в этом куске — там должно быть 13 байт (+4 — длина)
if ($len != 17) return false;
// эта комбинация может встретиться только в первых восьми байтах заголовка — дальше поля не
// могут принимать такие большие значения
if ($pos > 11) return false;
// если разрешены короткие теги, нужно присмотреться к этому коду
// в столь ограниченном пространстве вред можно натворить только через запуск
// чего-то внешнего
if (ini_get('short_open_tag') && strpos($ihdr, '`', $pos + 2) !== false) {
return false;
}
}
if (!@fwrite($fo, $ihdr)) return false;
// кусок iTXt (text) с нашим кодом
$protect = "<?php __halt_compiler();";
$length = pack('N', strlen($protect));
$sum = pack('N', sprintf('%u', crc32($protect)));
if (!@fwrite($fo, "{$length}iTXt{$protect}{$sum}")) return false;
// остаток файла
if (@stream_copy_to_stream($fi, $fo) != $controllen - 8 - 4 - $len) return false;
return true;
}
function ProtectPictureGif($fi, $fo, $controllen)
{
$protect = "<?php __halt_compiler();";
// заголовок GIF
if (!@fwrite($fo, fread($fi, 6))) return false;
// поле Logical Screen Descriptor
$lsd = fread($fi, 7);
$flag = ord($lsd[4]);
// указана ли Global Color Table?
if ($flag & 128) {
$pixel = 1 + ($flag & 0b111);
$colors = pow(2, $pixel);
$gctlen = $colors * 3;
// читаем Global Color Table
$gct = fread($fi, $gctlen);
// не вставил ли уже туда злоумышленник „<?“?
// меняем у такой комбинации последний бит — это малозаметно,
// безопасность важнее!
if (strpos($gct, '<?') !== false) {
$gct = str_replace('<', '=', $gct);
}
if (!@fwrite($fo, $lsd . $gct)) return false;
} else {
$gctlen = 0;
if (!@fwrite($fo, $lsd)) return false;
}
// пишем комментарий с куском защиты
fwrite($fo, "!\xfe" . chr(strlen($protect)) . $protect . "\0");
if (@stream_copy_to_stream($fi, $fo) != $controllen - 6 - 7 - $gctlen) return false;
return true;
}В коде есть два места где я ищу не встретилась ли комбинация <? раньше, чем я вставляю защиту — это в заголовочном куске (IHDR) в ПНГ и в глобальной таблице цветов у ГИФа.
В случае ПНГ я анализирую заголовок, чтобы понять как там оказалась эта комбинация, она валидна только в первых восьми байтах (на зло остаётся всего 6 байт), кроме того, в этом случае я контролирую размер заголовка, в стандарте там указано 13 байт, хотя, кажется, размер не ограничивается. В общем, в шести байтах особо не разгуляешься, всё что я придумал туда засунуть — `rm *`, т. е. очистка текущего каталога. На этот случай, я контролирую появление символа `. На мой взгляд, вероятность встретить в нормальном ПНГ в заголовке <? после которого идёт ` ничтожно мала.
С ГИФом проще — меняю младший бит у цвета, это вряд ли будет заметно, а безопасность важнее.
Защита от внедрения PHP-кода в картинки (JPEG, GIF, PNG)
На «Хабре» всплыла тема атаки, старой как мир — заливаем на сайт картинку, у которой внутри (в поле комментариев) есть
Во всех форматах принятых в вебе, есть поле, позволяющее вставить такие данные. В JPEG есть специальные секции APPn и COM, в PNG — iTXt, tEXt и можно создавать произвольные секции, в GIF — блоки расширений, в SVG можно использовать обычный
В качестве абсолютного метода защиты на «Хабре» предлагается пропустить картинку через
Можно ещё попробовать вырезать все секции файла, куда можно запихнуть текстовую информацию, но это не спасёт от файлов, где ПХП вставлен прямо в графическую часть, так, чтобы детектор валидности картинки (в ПХП для этого обычно используют getimagesize) не спотыкался на файле.
Мне кажется, я придумал более удачный метод защиты.
В загруженный файл можно добавить первой секцией (сразу после заголовка) свой собственный кусок
# смотрим что внутри файла
bolk@Bolk ~ $ hexdump -Cn128 sample.jpg
00000000 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 |......JFIF......|
00000010 00 01 00 00 ff fe 00 1a 3c 3f 70 68 70 20 5f 5f |........<?php __|
00000020 68 61 6c 74 5f 63 6f 6d 70 69 6c 65 72 28 29 3b |halt_compiler();|
00000030 ff db 00 43 00 02 02 02 02 02 01 02 02 02 02 03 |...C............|
00000040 02 02 03 03 06 04 03 03 03 03 07 05 05 04 06 08 |................|
00000050 07 09 08 08 07 08 08 09 0a 0d 0b 09 0a 0c 0a 08 |................|
00000060 08 0b 0f 0b 0c 0d 0e 0e 0f 0e 09 0b 10 11 10 0e |................|
00000070 11 0d 0e 0e 0e ff db 00 43 01 02 03 03 03 03 03 |........C.......|
# запускаем
bolk@Bolk ~ $ php sample.jpg
????JFIF??Т. е. на экран выводится бинарный заголовок JPEG, первая секция, а потом интерпретатор дальше просто не идёт. Будет дальше ход хакера или нет, он не проинтерпретируется.
Яблокораздирающая история
«Макрадар» цитирует Джонатана Айва:
«Мы чуть не отказались выпуска iPhone, поскольку у нас возникли серьезные проблемы, которые казались неразрешимыми. В ранних прототипах нашего смартфона стоило лишь поднести устройство к уху, как, во время его касания к активному дисплею, набирались произвольные номера. Требовалось учитывать различные формы ушных раковин, прически и даже расовый тип пользователей. И это была лишь одна из многих сложнейших ситуаций, когда нам казалось, что у проекта нет будущего», — утверждает Айв.
Это насколько ранний
Приватный режим в Сафари под iOS
Честно сказать, не знаю для чего это может быть нужно, но это одна из вещей, которая если понадобится, то потом не найдёшь. Джаваскрипт, который позволяет определить запущен ли мобильный Сафари (под Айос) в приватном режиме:
function isPrivateMode() {
var s = window.sessionStorage, key = '';
try {
s.setItem(key, '');
s.removeItem(key);
} catch (e) {
if (e.code === DOMException.QUOTA_EXCEEDED_ERR && !s.length) {
return true;
} else {
throw e;
}
}
return false;
}
// приватный режим включен?
alert(isPrivateMode());Оригинальный код основан на следующем факте — в приватном режиме мобильный Сафари запрещает доступ к sessionStorage. Я только обернул скрипт в функцию и переименовал переменные.
Проблема с wifi-иконкой в «Montain Lion»
У меня с апгрейдом системы до «Горного Льва» возникла нестрашная, но раздражающая проблемка — несмотря на то, что соединение с вайфайем есть и сайты открываются, «Мак» утверждал, что подключение к интернету отсутствует и показывал иконку вайфая в верхнем меню с восклицательным знаком.
Меня это раздражало, потом и на ноуте жены возникла та же проблема. Поискал в интернете, все спрашивают совета, но никто не предлагает решение.
Решение нашёл случайно — надо удалить все лишние сетевые устройства (кнопкой с минусом в «Настройках сети»), у меня там была целая куча «свистков» МТС, «Мегафона» и «Билайна», у жены — то же.
Удалил устройства, восклицательный знак в иконке вайфая пропал. Потом устройства можно добавить обратно, это уже ни на что не влияет.
Хачик
Сегодня узнал, что Хачик — армянское христианское имя. Хачик — уменьшительное от «Хачатур» (Խաչատուր), которое переводится как «данный крестом» («хач» — крест, «тур» — дан, давать). Парадокс в том, что я знаю массу российских христиан, презрительно бросающих «хач» в сторону приезжих, тогда как всякое упоминание креста (т. е. распятия) для них священно.
Социальные сети и Джаббер

Некоторые ребята иногда удивляются, говорят, что постоянно видят меня онлайн в социальных сетях. И правда, что я там так много делаю?
Ответ — ничего. Можно сказать, я туда не захожу иногда неделями. На самом деле все социальные сети у меня подключены
Раньше «Одноклассники», «Вконтакте» и «Фейсбук» у меня были подключены к «Адиуму», теперь — к «Сообщениям»
Настраивается просто, нажимаем кнопку „+“ (см. на скриншоте выше), выбираем протокол Jabber и вписываем следующие данные.
Фейсбук В поле логин — ВашЛогинНаФейсбуке@chat.facebook.com, в поле пароль — пароль от «Фейсбука».
Одноклассники В поле логин — ВашIDвОдноклассниках@odnoklassniki.ru, в поле пароль — пароль от «Одноклассников». ID от «Одноклассников» можно найти на странице настроек, он там внизу написан.
Вконтакте В поле логин — ВашIDвоВконтакте@vk.com, в поле пароль — пароль от «Вконтакте». ID «Вконтакте» — это та часть после слеша, которая появляется в урле, когда вы переходите на страницу «Моя Страница».
Настройка «Сообщений» в «Горном Льве» на работу с «аськой»
В «Горном Льве» («Montain Lion» — это новая версия «Макоси», которая появилась сегодня) есть новая программа — «Сообщения» (Messages), это встроенный в операционную систему
ICQ в списке нет, но тем не менее, настроить «Сообщения» для работы с этим протоколом можно — в «аське» используется тот же протокол, что и в AIM — «Оскар», надо только поменять данные сервера, с которым надо соединяться и убрать галочку «Использовать SSL»:

Чтобы отключить HTML, который «Сообщения» отсылают по аське, нужно выполнить следующую последовательность действий:
# 1) в «Терминале» выполняем:
defaults read com.apple.iChat.AIM | sed "s/\(ForceICQPlainText\).*/\1 = 1;/" | xargs -0 defaults write com.apple.iChat.AIM
chflags uchg ~/Library/Preferences/com.apple.iChat.AIM.plist
# 2) !перезагружаемся!
# 3) в «Терминале» пишем:
chflags nouchg ~/Library/Preferences/com.apple.iChat.AIM.plistПатч модуля bcompiler для PHP 5.4
Мы тут по работе пытаемся закешировать
Я посидел над сообщениями при компиляции, посмотрел что другие ребята делали в модуле xcache для того, чтобы он заработал в 5.4, посмотрел внутренние структуры ПХП и родил патч, который позволяет успешно скомпилировать модуль. Модуль мои простенькие тесты проходит, но это правда не значит, что всё действительно работает.
Добавлено позднее: на более сложных тестах модуль Неудобно только то, что модуль не позволяет работать с объектами и анонимными функциями из ПХП 5.3 (которые тоже объекты), а так же компилирует всё в файл. Но второй недостаток легко обходится:Патч и немного кода.
diff -wrdu bcompiler-1.0.2/bcompiler_zend.c bcompiler-1.0.2.new/bcompiler_zend.c
--- bcompiler-1.0.2/bcompiler_zend.c 2011-06-09 15:58:42.000000000 +0400
+++ bcompiler-1.0.2.new/bcompiler_zend.c 2012-07-24 21:59:30.000000000 +0400
@@ -471,12 +471,6 @@
apc_serialize_zend_class_entry(zv->obj.ce, NULL, 0, NULL, 0 TSRMLS_CC);
#endif
break;
-#ifdef ZEND_ENGINE_2_4
- case IS_CLASS:
- case IS_SCALAR:
- case IS_NUMERIC:
- break;
-#endif
default:
/* The above list enumerates all types. If we get here,
* something very very bad has happened. */
@@ -551,12 +545,6 @@
apc_create_hashtable(&zv->obj.properties, apc_create_zval, NULL, sizeof(zval *) TSRMLS_CC);
#endif
break;
-#ifdef ZEND_ENGINE_2_4
- case IS_CLASS:
- case IS_SCALAR:
- case IS_NUMERIC:
- break;
-#endif
default:
/* The above list enumerates all types. If we get here,
* something very very bad has happened. */
@@ -636,8 +624,10 @@
}
SERIALIZE_SCALAR(arg_info->allow_null , zend_bool);
SERIALIZE_SCALAR(arg_info->pass_by_reference, zend_bool);
+#ifndef ZEND_ENGINE_2_4
SERIALIZE_SCALAR(arg_info->return_reference , zend_bool);
SERIALIZE_SCALAR(arg_info->required_num_args, int);
+#endif
#ifdef ZEND_ENGINE_2_1
if (BCOMPILERG(current_write) > 20) {
# ifdef ZEND_ENGINE_2_4
@@ -667,8 +657,10 @@
else ZS2SR(arg_info->class_name) = NULL;
DESERIALIZE_SCALAR(&arg_info->allow_null, zend_bool);
DESERIALIZE_SCALAR(&arg_info->pass_by_reference, zend_bool);
+#ifndef ZEND_ENGINE_2_4
DESERIALIZE_SCALAR(&arg_info->return_reference, zend_bool);
DESERIALIZE_SCALAR(&arg_info->required_num_args, int);
+#endif
#ifdef ZEND_ENGINE_2_1
if (BCOMPILERG(current_version) > 20) {
# ifdef ZEND_ENGINE_2_4
@@ -883,7 +875,9 @@
#else
SERIALIZE_SCALAR(*(zce->refcount) , int);
#endif
+#ifndef ZEND_ENGINE_2_4
SERIALIZE_SCALAR(zce->constants_updated, zend_bool);
+#endif
#ifdef ZEND_ENGINE_2
SERIALIZE_SCALAR(zce->ce_flags, zend_uint);
#endif
@@ -930,15 +924,15 @@
* and all the functions. */
BCOMPILER_DEBUG(("-----------------------------\nBUILTIN:\n"));
count = 0;
- if (zce->type == ZEND_INTERNAL_CLASS && zce->builtin_functions) {
- for (zfe = (zend_function_entry*)zce->builtin_functions; zfe->fname != NULL; zfe++) {
+ if (zce->type == ZEND_INTERNAL_CLASS && zce->info.internal.builtin_functions) {
+ for (zfe = (zend_function_entry*)zce->info.internal.builtin_functions; zfe->fname != NULL; zfe++) {
count++;
}
}
SERIALIZE_SCALAR(count, int);
for (i = 0; i < count; i++) {
- apc_serialize_zend_function_entry((zend_function_entry *)&zce->builtin_functions[i] TSRMLS_CC);
+ apc_serialize_zend_function_entry((zend_function_entry *)&zce->info.internal.builtin_functions[i] TSRMLS_CC);
}
#ifndef ZEND_ENGINE_2
/** old code: SERIALIZE_SCALAR(zce->handle_function_call, void*); */
@@ -974,12 +968,12 @@
/* do reflection info (file/start/end) !! TODO: check for PHP6 !! */
#ifdef ZEND_ENGINE_2
if (BCOMPILERG(current_write) >= 25) {
- char* fname = bcompiler_handle_filename(zce->filename TSRMLS_CC);
+ char* fname = bcompiler_handle_filename(zce->info.user.filename TSRMLS_CC);
apc_serialize_string(fname TSRMLS_CC);
- SERIALIZE_SCALAR(zce->line_start, int);
- SERIALIZE_SCALAR(zce->line_end, int);
- apc_serialize_zstring(zce->doc_comment, zce->doc_comment_len TSRMLS_CC);
- SERIALIZE_SCALAR(zce->doc_comment_len, int);
+ SERIALIZE_SCALAR(zce->info.user.line_start, int);
+ SERIALIZE_SCALAR(zce->info.user.line_end, int);
+ apc_serialize_zstring(zce->info.user.doc_comment, zce->info.user.doc_comment_len TSRMLS_CC);
+ SERIALIZE_SCALAR(zce->info.user.doc_comment_len, int);
}
#endif
@@ -1089,7 +1083,9 @@
*zce->refcount = 1; /* val: to avoid memort leaks */
}
#endif
+#ifndef ZEND_ENGINE_2_4
DESERIALIZE_SCALAR(&zce->constants_updated, zend_bool);
+#endif
#ifdef ZEND_ENGINE_2
DESERIALIZE_SCALAR(&zce->ce_flags, zend_uint);
#endif
@@ -1184,11 +1180,11 @@
zend_class_entry.builtin_functions member */
DESERIALIZE_SCALAR(&count, int);
- zce->builtin_functions = NULL;
+ zce->info.internal.builtin_functions = NULL;
if (count > 0) {
- zce->builtin_functions = (zend_function_entry*) ecalloc(count+1, sizeof(zend_function_entry));
+ zce->info.internal.builtin_functions = (zend_function_entry*) ecalloc(count+1, sizeof(zend_function_entry));
for (i = 0; i < count; i++) {
- apc_deserialize_zend_function_entry((zend_function_entry*)&zce->builtin_functions[i] TSRMLS_CC);
+ apc_deserialize_zend_function_entry((zend_function_entry*)&zce->info.internal.builtin_functions[i] TSRMLS_CC);
}
}
#ifndef ZEND_ENGINE_2
@@ -1237,11 +1233,11 @@
if (BCOMPILERG(current_version) >= 25) {
char* fname;
apc_create_string_u(&fname, -1 TSRMLS_CC);
- zce->filename = fname ? fname : estrdup(BCOMPILERG(current_filename));
- DESERIALIZE_SCALAR(&zce->line_start, int);
- DESERIALIZE_SCALAR(&zce->line_end, int);
- apc_create_string_u(ZS2SP(zce->doc_comment), -1 TSRMLS_CC);
- DESERIALIZE_SCALAR(&zce->doc_comment_len, int);
+ zce->info.user.filename = fname ? fname : estrdup(BCOMPILERG(current_filename));
+ DESERIALIZE_SCALAR(&zce->info.user.line_start, int);
+ DESERIALIZE_SCALAR(&zce->info.user.line_end, int);
+ apc_create_string_u(ZS2SP(zce->info.user.doc_comment), -1 TSRMLS_CC);
+ DESERIALIZE_SCALAR(&zce->info.user.doc_comment_len, int);
}
#endif
@@ -1564,7 +1560,7 @@
#ifdef ZEND_ENGINE_2_4
SERIALIZE_SCALAR(zoa->last_literal, zend_uint);
- SERIALIZE_SCALAR(zoa->size_literal, zend_uint);
+ //SERIALIZE_SCALAR(zoa->size_literal, zend_uint);
for (i = 0; i < (int) zoa->last_literal; i++) {
bc_serialize_zend_literal(&zoa->literals[i] TSRMLS_CC);
}
@@ -1572,7 +1568,7 @@
SERIALIZE_SCALAR(zoa->refcount[0], zend_uint);
SERIALIZE_SCALAR(zoa->last, zend_uint);
- SERIALIZE_SCALAR(zoa->size, zend_uint);
+ //SERIALIZE_SCALAR(zoa->size, zend_uint);
/* If a file 'A' is included twice in a single request, the following
* situation can occur: A is deserialized and its functions added to
@@ -1595,7 +1591,7 @@
SERIALIZE_SCALAR(zoa->T, zend_uint);
SERIALIZE_SCALAR(zoa->last_brk_cont, zend_uint);
- SERIALIZE_SCALAR(zoa->current_brk_cont, zend_uint);
+ //SERIALIZE_SCALAR(zoa->current_brk_cont, zend_uint);
#ifndef ZEND_ENGINE_2
SERIALIZE_SCALAR(zoa->uses_globals, zend_bool);
#endif
@@ -1608,8 +1604,8 @@
}
apc_serialize_hashtable(zoa->static_variables, apc_serialize_zval_ptr TSRMLS_CC);
assert(zoa->start_op == NULL);
- SERIALIZE_SCALAR(zoa->return_reference, zend_bool);
- SERIALIZE_SCALAR(zoa->done_pass_two, zend_bool);
+ //SERIALIZE_SCALAR(zoa->return_reference, zend_bool);
+ //SERIALIZE_SCALAR(zoa->done_pass_two, zend_bool);
fname = bcompiler_handle_filename(zoa->filename TSRMLS_CC);
apc_serialize_string(fname TSRMLS_CC);
if (fname) efree(fname);
@@ -1628,9 +1624,9 @@
#endif
SERIALIZE_SCALAR(zoa->fn_flags, zend_uint);
SERIALIZE_SCALAR(zoa->required_num_args, zend_uint);
- SERIALIZE_SCALAR(zoa->pass_rest_by_reference, zend_bool);
+ //SERIALIZE_SCALAR(zoa->pass_rest_by_reference, zend_bool);
- SERIALIZE_SCALAR(zoa->backpatch_count, int);
+ //SERIALIZE_SCALAR(zoa->backpatch_count, int);
#ifdef ZEND_ENGINE_2_3
SERIALIZE_SCALAR(zoa->this_var, zend_uint);
#else
@@ -1642,7 +1638,7 @@
#ifdef ZEND_ENGINE_2_1
if (BCOMPILERG(current_write) >= 0x0007) {
SERIALIZE_SCALAR(zoa->last_var, int);
- SERIALIZE_SCALAR(zoa->size_var, int);
+ //SERIALIZE_SCALAR(zoa->size_var, int);
for (i = 0; i < zoa->last_var; i++) {
SERIALIZE_SCALAR(zoa->vars[i].name_len, int);
apc_serialize_zstring(ZS2S(zoa->vars[i].name), ZLEN(zoa->vars[i].name_len) TSRMLS_CC);
@@ -1706,7 +1702,7 @@
#ifdef ZEND_ENGINE_2_4
DESERIALIZE_SCALAR(&zoa->last_literal, zend_uint);
- DESERIALIZE_SCALAR(&zoa->size_literal, zend_uint);
+ //DESERIALIZE_SCALAR(&zoa->size_literal, zend_uint);
zoa->literals = NULL;
if (zoa->last_literal) {
zoa->literals = (zend_literal*) ecalloc(zoa->last_literal, sizeof(zend_literal));
@@ -1722,7 +1718,7 @@
*zoa->refcount = 1; /* val: to avoid memort leaks */
}
DESERIALIZE_SCALAR(&zoa->last, zend_uint);
- DESERIALIZE_SCALAR(&zoa->size, zend_uint);
+ //DESERIALIZE_SCALAR(&zoa->size, zend_uint);
zoa->opcodes = NULL;
@@ -1736,7 +1732,7 @@
DESERIALIZE_SCALAR(&zoa->T, zend_uint);
DESERIALIZE_SCALAR(&zoa->last_brk_cont, zend_uint);
- DESERIALIZE_SCALAR(&zoa->current_brk_cont, zend_uint);
+ //DESERIALIZE_SCALAR(&zoa->current_brk_cont, zend_uint);
#ifndef ZEND_ENGINE_2
DESERIALIZE_SCALAR(&zoa->uses_globals, zend_bool);
#endif
@@ -1749,10 +1745,10 @@
}
apc_create_hashtable(&zoa->static_variables, apc_create_zval, NULL, sizeof(zval *) TSRMLS_CC);
- zoa->start_op = NULL;
+ //zoa->start_op = NULL;
- DESERIALIZE_SCALAR(&zoa->return_reference, zend_bool);
- DESERIALIZE_SCALAR(&zoa->done_pass_two, zend_bool);
+ //DESERIALIZE_SCALAR(&zoa->return_reference, zend_bool);
+ //DESERIALIZE_SCALAR(&zoa->done_pass_two, zend_bool);
apc_create_string_u(&fname, -1 TSRMLS_CC);
if (fname) {
zoa->filename = zend_set_compiled_filename(fname TSRMLS_CC);
@@ -1798,8 +1794,8 @@
zoa->fn_flags &= ~ZEND_ACC_IMPLEMENTED_ABSTRACT; /* this is set later by zend_do_inheritance() */
#endif
DESERIALIZE_SCALAR(&zoa->required_num_args, zend_uint);
- DESERIALIZE_SCALAR(&zoa->pass_rest_by_reference, zend_bool);
- DESERIALIZE_SCALAR(&zoa->backpatch_count, int);
+ //DESERIALIZE_SCALAR(&zoa->pass_rest_by_reference, zend_bool);
+ //DESERIALIZE_SCALAR(&zoa->backpatch_count, int);
#ifdef ZEND_ENGINE_2_3
DESERIALIZE_SCALAR(&zoa->this_var, zend_uint);
#else
@@ -1811,15 +1807,15 @@
#ifdef ZEND_ENGINE_2_1
if (BCOMPILERG(current_version) >= 0x0007) {
DESERIALIZE_SCALAR(&zoa->last_var, int);
- DESERIALIZE_SCALAR(&zoa->size_var, int);
- if (zoa->size_var > 0) {
+ //DESERIALIZE_SCALAR(&zoa->size_var, int);
+ /*if (zoa->size_var > 0) {
zoa->vars = ecalloc(zoa->size_var, sizeof(zoa->vars[0]));
for (i = 0; i < zoa->last_var; i++) {
DESERIALIZE_SCALAR(&(zoa->vars[i].name_len), int);
apc_create_string_u(ZS2SP(zoa->vars[i].name), -1 TSRMLS_CC);
DESERIALIZE_SCALAR(&(zoa->vars[i].hash_value), ulong);
}
- }
+ }*/
}
#endif
diff -wrdu bcompiler-1.0.2/php_bcompiler.c bcompiler-1.0.2.new/php_bcompiler.c
--- bcompiler-1.0.2/php_bcompiler.c 2011-06-09 15:58:42.000000000 +0400
+++ bcompiler-1.0.2.new/php_bcompiler.c 2012-07-24 21:27:31.000000000 +0400
@@ -571,7 +571,7 @@
#ifndef ZEND_ENGINE_2
if (i > n_old_class)
#else
- if (zc->filename && strcmp(zc->filename, real_path) == 0)
+ if (zc->info.user.filename && strcmp(zc->info.user.filename, real_path) == 0)
#endif
{
SERIALIZE_SCALAR(BCOMPILER_CLASS_ENTRY, char)
@@ -632,7 +632,7 @@
#ifndef ZEND_ENGINE_2
if (i > n_old_class)
#else
- if (zc->filename && strcmp(zc->filename, real_path) == 0)
+ if (zc->info.user.filename && strcmp(zc->info.user.filename, real_path) == 0)
#endif
{
#if PHP_MAJOR_VERSION >= 6
diff -wrdu bcompiler-1.0.2/php_bcompiler.h bcompiler-1.0.2.new/php_bcompiler.h
--- bcompiler-1.0.2/php_bcompiler.h 2011-06-09 15:58:42.000000000 +0400
+++ bcompiler-1.0.2.new/php_bcompiler.h 2012-07-24 22:13:31.000000000 +0400
@@ -22,7 +22,7 @@
#ifndef PHP_BCOMPILER_H
#define PHP_BCOMPILER_H
-#define PHP_BCOMPILER_VERSION "1.0.2"
+#define PHP_BCOMPILER_VERSION "1.0.2 (bolk) "
#ifdef HAVE_CONFIG_H
#include "config.h"$fp = fopen('php://memory', 'rw');
bcompiler_write_header($fp);
bcompiler_write_function($fp, 'тут имя вашей функции, которую надо скомпилировать');
bcompiler_write_footer($fp);
fseek($fp, 0);
$compiled = stream_get_contents($fp); // байт-код теперь в переменной $compiled
fclose($fp);
Замыкания и Джаваскрипт
Все знают, что зона видимости в JS создаётся только внутри функций (если не брать в расчёт конструкцию «let» из JS 1.7):
var v = 5;
!(function() {
var v = 6;
})();
alert(v); // будет 5Я тут подумал, что ведь есть и второй способ (я
var x = 1, y = 0;
// конструкция «let», JS 1.7+
let (x = x+10, y = 5) {
alert(x+y); // 16
}
alert(x+y); // 1
// конструкция «with»
with ({ x: x+10, y: 5 }) {
alert(x+y); // 16
}
alert(x+y); // 1Не так уж и много отличий, только выражением «with» быть не умеет, но можно было бы и научить.