программирование

Загадки PHP

Да что это я всё о себе, да о себе? Давайте я вам лучше о PHP расскажу! PHP, несмотря на кажущуюся простоту, язык уникальный своими загадками. Возникают, они, в основном из-за того, что какие-то вещи делались в PHP хаками, чаще — как бог на душу положит. Например, ссылки.

Ссылки в PHP — совершенно особая сущность. Небольшой ликбез. Ссылка — это способ «соединить» две переменные так, что меняя значение одной, меняется значение второй и наоборот. Записывается ссылка очень просто: $foo = &$bar. Кажущаяся простота ссылок обманчива. Я сейчас буду рассматривать PHP5, поскольку мне кажется, что четвёртая версия должна умереть как можно скорее. Все примеры были проверены под PHP 5.1.4 и PHP 5.2.0RC1 под Windows и Linux.

<?php
    $a = new stdClass();
    function Bar($bar)
    {
        $bar->val = 1;
    }
    Bar($a);
    print_r($a);

Проблема номер раз. Как вы думаете, что напечатает print_r? Отвечу сразу: он покажет свойство «val» со значением «один». Почему так произошло? Дело в том, что в PHP5 (как и во многих других языках) все объекты передаются по ссылке. Это значит, что переменная $bar в функции ссылается на переменную $a, которую мы указали в качестве параметра и все изменения $bar коснутся переменной $a. Если мы вызовем функцию «Bar» с другим параметром, то $bar будет ссылаться на этот новый параметр.

Ситуация, когда объект в функцию нужно передать по значению, на практике — почти невероятна, впрочем, если она и возникнет, объект всегда можно клонировать — в PHP5 есть специальные конструкции.

<?php
    $v = array(1);
    $b = &$v[0];
    $c = $v;
    $v[0] = 100;

    echo $c[0];

Проблема номер два. Что же будет внутри $c[0]? Странно, но — 100. Как же так? Всё просто. В PHP, если мы создали ссылку на переменную, то оба имени переменных становятся ссылками. Получается, что присваивая $c внутренность $v, я его присваиваю вместе с $v[0], которая стала ссылкой.

Странно? Совсем нет. Дело в том, что имя переменной — это тоже ссылка. Ссылка на область памяти, где записано её значение. Если ссылок на место, занимаемое переменной, больше чем одна, то все её имена ведут себя как «ссылка», если же удалить «лишние», то последнее имя теряет свою «ссылочность». Пример:

<?php
    $v = array(1);
    $b = &$v[0];

    var_dump($v);

    unset($b);

    var_dump($v);

Первый «var_dump» покажет нам ссылку, второй — нет.

<?php
    $bar = 1;

    function Foo()
    {
        global $bar;
        $test = 100;

        $bar = &$test;
    }

    Foo();
    echo $bar;

Проблема номер три. Кстати говоря, когда вы используете конструкцию «global», на деле вы используете ссылку. Дело в том, что «global $bar» полностью эквивалентна «$bar =& $GLOBALS[’bar’]». Если вы не знаете что такое $GLOBALS, самое время открыть руководство по PHP и узнать. Так вот. Проблема заключается в том, что «магическое» слово «global» прячет от нас всю эту операцию, поэтому кажется, что в глобальной переменной $bar должно быть значение 100. Это не так.

На деле, «$bar = &$test» вызовет переназначение ссылки. То есть, прежняя ссылка «$bar — это $GLOBALS[’bar’]» пропадёт и на её место встанет «$bar — это $test». Значение $GLOBALS[’bar’], естественно, не изменится.

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

<?php
    $v = array(1);
    foreach ($v as &$item) echo $item;

    function Bar($foo)
    {
        $foo[0] = 100;
    }

    Bar($v);
    var_dump($v);

Итак! Что выведет «var_dump»? Правильно — 100. Почему? Вполне логично — в цикле мы проходим по элементам массива, причём $item ссылается на текущий элемент как ссылка. После цикла остаётся ссылка «$item — это $v[0]», поэтому, когда я передал в «Bar» переменную $v, её нулевой элемент остался ссылкой. Остальное понять труда не составляет. Давайте пойдём дальше.

<?php
    $v = array(1, 2);
    foreach ($v as &$item) echo $item;

    function Bar($foo)
    {
        $foo[0] = 100;
        $foo[1] = 100;
    }

    Bar($v);
    var_dump($v);

Что же тут покажет «var_dump»? Странно, но в обоих элементах массива будет… 100. Казалось бы — bug PHP (впрочем, я не настаиваю — может это и баг). Оказывается, не совсем. Дело в том, что ссылка в PHP уничтожается конструкцией unset и только ей. При переприсвоении ссылки прежняя ссылка не удаляется, точнее, PHP не трогает счётчик ссылок. В моём следующем примере все три переменные будут ссылкой (в чём легко убедиться, сделав «var_dump переменной $GLOBALS»):

<?php
    $v = 1;
    $k = 2;
    $b = &$v;
    $b = &$k;

Первый же unset «восстановит справедливость»:

<?php
    $v = 1;
    $b = &$v;
    $t = &$v;

    $k = 2;
    $b = &$k;

    unset($t);

Теперь переменные $k и $b — ссылочные, а $v — нет. Видимо, «пересчёт» ссылок при пересвоении вызывает какие-то трудности. Хотя эта особенность PHP вызывает целую кучу трудноуловимых багов. Спасибо моему братишке — Олегу Степанищеву за то, что обратил мой внимание на пример с foreach, после чего я и решил структурировать свои знания по этому поводу.

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

Explorer Canvas

IE не обновлялся очень давно и не поддерживает тег CANVAS, предоставляющий интересные возможности — рисование через JavaScript вектором. Интересно, что Microsoft когда-то давно предлагала к использованию свою разработку — язык VML, а ранее браузеры позволяли использовать VRML. Последний благополучно умер, а VML так и поддерживается современными версиями Internet Explorer.

Вероятно некоторая схожесть технологий VML и CANVAS вдохновила Emil A Eklund на создание Explorer Canvas — трансляцию вызовов CANVAS в теги VML. Поддержка пока ограниченная, но ведётся активная работа по расширению возможностей. На сайте есть небольшая демонстрация возможностей. Кстати, хорошо видно, что в браузерах Opera и FireFox canvas ведёт себя по-разному.

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

IE и HTTPS

Следующая проблема — некорректное поведение IE при использовании протокола HTTPS. Иногда (особенно на сайтах, где используются технологии изменения содержимого страницы без её перезагрузки), в странице используется тег iframe без содержимого или с указанием about:blank. IE считает, что такой IFRAME загружает содержимое не по протоколу HTTPS (формально он прав — конечно не загружает, но по сути-то содержимое пустое) и пишет предупреждение пользователю.

От этого раздражающего предупреждения можно избавиться следующим образом: указать в качестве src для iframe конструкцию

javascript:''

Т. е.

<iframe src="javascript:''></iframe>

javascript — это протокол, который позволяет выполнять JavaScript. Когда страница грузится по HTTPS этот скрипт выполняется в текущем протоколе — HTTPS, а указание пустой строки позволяет создать фрейм именно с пустым содержимым.

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

Панель на картинке

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

Вот в этих случаях не нужно, чтобы при наведении на картинку пользователь видел эту панель. Есть два способа избавиться от неё. Во-первых, можно запретить её появление на всей странице при помощи мета-тега: <meta http-equiv=«imagetoolbar» content=«no» />

Во-вторых, можно указать для какой картинки её показывать не нужно, используя нестандартный атрибут galleryimg

<img src="/img/image.jpg" width="100" height="100" alt="" galleryimg="no" >

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

Выполнение JS только в IE

Кстати говоря, есть два способа выполнения JavaScript-кода только в IE. Первый, который, правда, сработает и в Opera — указание в script language «JScript». JScript — это название диалекта JavaScript, реализованного в IE. Следующее:

<script language="JScript">alert('1')</script>

cработает только в Opera и Internet Explorer.

Второй способ — так называемая «условная компиляция». Был придуман Microsoft, чтобы прятать новые конструкции языка (например, try … catch) от предыдущих версий браузера. Следующий код выполнится только в Internet Explorer. Остальные браузеры посчитают его комментарием в коде JavaScript

/*@cc_on

alert(1)

@*/

В «условной компиляции» можно выполнять ещё ряд действий, например, проверять версию jscript и т.д, всё это легко найти в любом поисковике.

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

Условные комментарии

Одна из проблем — как подключать какие-то части кода в зависимости от того является ли браузер Internet Explorer. Веб-мастера, обычно, пользуются CSS-хаками, а вот о том, что есть специальная конструкция, которая позволяется это сделать, мало кто знает.

Специальная конструкция

<--[if IE...] ... <![endif]-->

позволяет не только прятать какие-то части HTML от других браузеров (которые воспринимают их как обычный HTML-комментарий), но и выбирать HTML в зависимости от версии IE. Более подробно можно прочитать, например, в статье Manfred Staudinger Taming Your Multiple IE Standalones. Для тех, кто не знает английского, скажу — общий принцип легко понятен из примеров.

Кстати, от Internet Explorer так же можно прятать HTML-код — надо просто заключить его в теги

<comment> … </comment>

Этот нестандартный тег Internet Explorer считает комментарием и, соответственно, не показывает и не обрабатывает его содержимое.

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

Борьба с Activating ActiveX Controls

Одно из новшевств, которое появилось в последних обновлениях Internet Explorer — это «Activating ActiveX Controls» (KB912945). После обновления Internet Explorer позволяет управлять элементами, которые находятся на ActiveX (а к ним относится и Flash) только после клика на объект, сам объект до клика выделяется рамкой, если над ним провести мышкой. Само по себе это не так уж и мешает, только если этот ActiveX (Flash, например) не находится за каким-то контентом и если на нём находятся ссылки, то кликнуть по ним получается только со второго раза — первым активизируется ActiveX и только потом срабатывает ссылка.

Оказывается есть метод борьбы с этой проблемой. Всё что нужно сделать — обойти все теги object и присвоить их outerHTML самому себе. Например, так:

// When the page loads:
window.onload = function(){
  if (document.getElementsByTagName) {
    // Get all the tags of type object in the page.
      var objs = document.getElementsByTagName("object");
      for (i=0; i<objs.length; i++) {
        // Get the HTML content of each object tag
        // and replace it with itself.
        objs[i].outerHTML = objs[i].outerHTML;
      }
   }
}
// When the page unloads:
window.onunload = function() {
  if (document.getElementsByTagName) {
    //Get all the tags of type object in the page.
    var objs = document.getElementsByTagName("object");
    for (i=0; i<objs.length; i++) {
      // Clear out the HTML content of each object tag
      // to prevent an IE memory leak issue.
      objs[i].outerHTML = "";
    }
  }
}

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

Триграфы в Си

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

Вообще триграфы были придуманы для терминалов, в которых некоторых символов не хватает. В итоге вместо #define можно написать ??=define. Триграфы подменяются на нужные символы в самом начале, поэтому эти записи эквивалентны. Вместо { можно написать ??< , вместо } использовать ??>

Остальные триграфы можно найти в статье Елены Сагалаевой «Триграфы и альтернативные символы» на её персональном блоге. Кстати, очень рекомендую сам блог — отличное чтиво на темы связанные с программированием.

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

PHP для PocketPC

Одной из особенностей языка PHP является то, что существует ровно один интерпретатор этого языка. Это хорошо — никакого разночтения стандартов и прочих проблем наличия интерпретаторов от разных команд. Или, по крайней мере, другие мне не попадались. До сих пор.

Некие умельцы написали Pocket HPH — интерпретатор для PocketPC. Конечно, реализованы далеко не все функции, но и того набора, что есть, хватит, чтобы реализовать что-то приличное. Например, есть даже функции работы с SQLite и регулярными выражениями!

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

XSS

Одна из известных проблем безопасности на веб-сайта — так называемый XSS (Cross Site Scripting). Вкратце суть в том, что иногда удаётся внедрить на страницу некий код (на скриптовом языке), который может выполнить некоторые вредоностные действия. Например, украсть файлы cookie для этого сайта, если таковые имеются. В cookie часто в каком-то виде хранится информация, которая позволит хакеру залогиниться на этот сайт под вашим логином.

Похоже, фирма Microsoft первая, кто озаботился поиском принципиально новых возможностей решения этой проблемы. Microsoft добавила в свой браузер поддержку так называемых «HTTP-only cookie». Смысл в том, чтобы ставить cookie специальный флаг, который будет показывать, что данную cookie браузер должен сделать недоступной для скриптовых языков. Пример:

Set-Cookie: USER=123; expires=Wednesday, 09-Nov-99 23:12:40 GMT; HttpOnly

Предельно понятно и достаточно действенно. Пока в PHP, в setcookie нет поддержки этого флага, такую cookie можно ставить через вызов header.

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

Библиотека для работы с XBM и моно-BMP

Когда-то я делал библиотеку PEAR для графических форматов XBM и BMP (монохромного). Хотелось получить средство вывода графики в том случае, если на хостинге нет библиотеки GD, чтобы, хотя бы, какие-то простенькие диаграммы можно было строить. BMP — персонально для IE, в котором убрали поддержку формата BMP из-за ошибки в библиотеке отображения этого формата. Парням из Microsoft показалось, что проще ликвидировать поддержку, чем исправлять ошибку.

Одним словом, какое-то время назад у меня опять зачесались руки осчастливить человечество библиотекой, поддерживающей какой-нибудь умирающий формат.

Когда-то, когда сотовые телефоны ещё были большими, была такая штука — WAP, этакий урезанный WWW для сотовых телефонов. Собственно, WAP и сейчас пока живее всех живых, хотя сайтов в этом формате относительно немного. В WAP использовались картинки в специальном формате — WBMP (Wireless BMP, level 0). Если кому-нибудь ещё интересен этот формат — добро пожаловать, у меня теперь есть библиотека для работы с ним.

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

Тотализатор для «Электроники МК85»

Когда-то очень давно, когда гаджетомания во мне только-только поднимала голову, выпросил я у родителей советский карманный компьютер. «Электроника МК85», если не ошибаюсь. Это такой большой калькулятор, с небольшим графическим экраном и встроенным диалектом бейсика. Первый PDA, фактически.

Я из этой машинки выжимал всё что можно, а первым моим развлечением был тотализатор — по экрану ползли точки, которые обозначали лошадей, в конце выводился номер победившей «лошади». Неизбалованные «пентиумами» одногрупники (дело было, примерно, в году 1993-94), живо освоили тотализатор…

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

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

Регулярные выражения наглядно

RegExp Coach sample (12.55КиБ)

Увидел у Cooler’a ссылку на замечательную программу — The Regex Coach. Есть версия для Linux и Windows. Программа позволяет визуально проверять регулярные выражения — смотреть дерево, замены, совпадения и т. п. Очень рекомендую.

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

Разделяемая память и PHP

В основном на PHP пишут небольшие проекты, поэтому литература кишит примерами «как сделать сайт в три странички». Но, тем не менее, только простыми сайтами дело не ограничивается. Когда приходится делать производительные проекты, существует множество ухищрений и решений, одно из которых — использовать разделяемую память, там где кешировать данные в статические файлы не получается. Различных API для использования разделяемой памяти много, только в одном PHP есть shmop, shm_* и Memcache, что несколько осложняет дело.

Я сделал PEAR-класс System::SharedMemory для работы с разными видами разделяемой памяти, получить его можно у меня или на сайте PEAR.

В настоящий момент поддерживаются следующие API: 

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

Brainfuck

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

Дело давнее, но около месяца назад, поддавшись какому-то невнятному импульсу, я вернулся к идее оптимизирующего компилятора. Поскольку, в данный момент язык-фаворит для меня PHP, мне захотелось, руководствуясь теми же принципами, написать компилятор Brainfuck в PHP, что я и сделал.

Модуль к PHP написан в формате PEAR, т. е. его можно либо использовать непосредственно, либо исталлировать в составе PEAR.

Нельзя сказать, что я компилятор проводит глубокую оптимизацию, но, например, код «[->+>++<<][>+>[-]<<-][>+<[-]]" будет преобразован в

<?php
$in = array(0, $id = 0);
$d = array_fill(-65535, 65535, $di = 0);

$d[$di+1]+= $d[$di];
$d[$di+2]+= $d[$di]*2;
$d[$di] = 0;

$d[$di+1]+= $d[$di];
if ($d[$di]) $d[$di+2] = 0;
$d[$di] = 0;

$d[$di+1]+= $d[$di];
$d[$di] = 0;

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

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

Тег для календаря

WebForms-2 (8.91КиБ)

Лично для меня событие недели — появление Opera 9.0 Technology Preview 1. Помимо поддержки XSLT, появления аналога настроек FireFox, только сделанных для человека, а не робота, поддержки Canvas, некоторых селекторов CSS3 и прочего, несомненный интерес представляет поддержка стандарта WebForms 2 — обратносовместимого расширения HTML для разработки различных интерфесов ввода. В частности, картинка на скриншоте делается одним-единственным тегом:

<input type="datetime" step="120" name="start">

и это далеко не самая впечататляющая демострация — просмотрите стандарт, хотя бы по диагонали. Жаль, что это всё удасться использовать не ранее чем лет через пять, прежде всего из-за абсолютного главенства Internet Explorer, уверен, что Gecko/Safari подтянутся, а вот от Microsoft такой резвости ожидать не приходится.

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

Блоки и локальные переменные в PHP

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

Рассуждал я как-то — чего же мне не хватает в PHP — языке, которому я посвящаю почти всё своё рабочее время, плюс немного свободного? Помимо всяких мелочей, жизнь без которых не так мила, но, в общем-то, вполне сносна. Не хватает мне вещи, которую я впервые увидел в Perl’e — языке, с такой близкой мне идеологией — который дарит программисту то, что он сам бы никогда не купил.

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

<?php
{
   var $i;
   echo $i = 1;
}
echo $i;

Пояснять нужно? Переменная, объявленная в фигурных скобках, перестаёт существовать за их пределами и не влияет на значения переменной с тем же именем, объявленной уровнем ниже. Я даже согласен на специальную конструкцию (хотя вот эта была бы предельно совместимой), чтобы это включили в PHP6, вместо пространств имён, которые, на мой взгляд, успешно подменяются объектами.

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

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

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

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

Формат графики XBM

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

Было время, меня увлёк графический формат XBM, единственное достоинство которого (впрочем, вполне достаточное, на мой взгляд) — безумная простота, позволяющая манипулировать графикой в этом формате из любого хоть чего-то стоящего языка программирования. Я даже разродился модулем ImageXBM и прочими вещами.

И вот я узнаю, что Internet Explorer 6.0SP1 и выше не поддерживает мой любимый формат! Причину цитирую:

A  change was made to Internet Explorer for Windows XP Service Pack 2 and Windows Server 2003 Service Pack 1 so that it does not render the XBM image file format. This update adds this change to all other supported versions of Internet Explorer. This change has been made to help prevent the Internet Explorer process from closing unexpectedly when users view invalidly-formed images. The XBM format is no longer supported by Internet Explorer.

Что переводится, примерно, так: «у нас что-то не работало, поэтому мы просто это отключили». Оплакал я смерть формата, которые за годы своей жизни так и не стал известен большинству разработчиков, да и сделал другой модуль.

Image_MonoBMP — модуля для работы с монохромными изображениями в формате BMP. А чтобы подтвердить, что я опять дарю вам то, что вы себе сами бы не купили, скажу, что этот формат, конечно, поддерживается Internet Explorer и Opera, но FireFox плевать на него хотел, да, в общем-то, и правильно.

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

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

Basic auth в Apache

Знаете ли вы, что в пароле при basic auth в Apache используются только первые восемь символов? Цитата с сайта Apache:

This is a feature of the crypt library on your system: in only looks at the first 8 characters of the password. To avoid it, use the -m option to htpasswd to create md5 passwords.

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

Maxthon

В качестве эксперимента попробовал браузер FireFox (основанный на Mozilla). Увы. Сразу же нашёл целых три бага. Кроме того, путанница с плагинами (extension), которые конфликтуют между собой и подходят только к той версии, для которой были созданы, радости не добавляет. Единственное, что порадовало — RSS reader (Sage), но недостатки, пожалуй, перевесили достоинства.

Решил попробовать новый Maxthon — надстройку на Internet Explorer, программу которую я использую очень давно, но уже не обновлял около года. С радостью узнал, что в новой версии появилось много нужных нововведений, в том числе — RSS reader. Вывод: остаюсь на Maxthon — движок IE меня вполне устраивает, поскольку на данный момент является стандартом de facto, а всё, что ему нехватает в плане дополнительных удобств, добавляет Maxthon.

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

← 1 62 63 64 65 66 67 →