3 ноября 2012 г.

PHP. Как получить содержимое сгенерированной картинки

Если необходимо получить доступ к содержимому картинки, созданной в PHP с помощью функций GD, то можно сохранить её на диск и получить содержимое с помощью функций file_get_contents или fread.

Но можно и не сохранять. Можно вывести содержимое во внутренний буфер и скопировать его в строковую переменную с помощью функции ob_get_contents().
<?php
    ob_start();
    imagejpeg($image, null, 100);    
    $imageStringData = ob_get_contents();
    ob_end_clean();
    imagedestroy($image);
?>

Далее можно преобразовать полученные данные в шестнадцатеричное представление с помощью bin2hex() и произвести поиск с помощью strpos(). Например, чтобы найти маркер конца файла, надо передать функции strpos()  в качестве искомой строки код маркера в шестнадцатеричном представлении (в нашем случае -  'ffd9').

С помощью регулярных выражений можно искать прямо в двоичных данных. Маркер конца файла можно найти так:
<?php
    preg_match_all('/\xFF\xD9/', $image, $matches, PREG_OFFSET_CAPTURE);
?>

После того как все необходимые манипуляции с содержимым произведены, изображение можно привести к двоичному представлению и, например, отдать браузеру:
<?php
    $imageBin = pack('H*', $imageHex);
    header('Content-Type: image/jpeg');
    echo $imageBin;
?>

Для версии PHP 5.4.0 и выше можно вместо функции pack использовать hex2bin.

20 октября 2012 г.

Одна интересная особенность innerHTML в Internet Explorer

Была замечена интересная особенность работы innerHTML в IE. Ниже приведен код страницы с двумя блоками, каждый из которых содержит по таблице. Скрипт получает ссылки на таблицы. Теперь, если удалить таблицы из DOM, они останутся в памяти, поскольку в коде есть на них актуальные ссылки. Так и делаем. Только первую таблицу удаляем очисткой innerHTML родительского узла, а вторую - с помощью метода removeChild.

Проверяем. Со ссылками, естественно, все в порядке, только в IE первая таблица лишилась своего содержимого. Остался только элемент TABLE.

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

Это касается любых элементов, а не только таблиц. Эту особенность я наблюдал в 6, 7 и 9 версиях. Восьмой версии просто нет под рукой.

<div id="block_1">
    <table id="table_1">
        <tr>
            <td>Эту таблицу мы удалим, просто очистив innerHTML родительского объекта.</td>
        <tr>
    </table>
</div>
<div id="block_2">
    <table id="table_2">
        <tr>
            <td>Эту таблицу мы удалим с помощью метода removeChild.</td>
        <tr>
    </table>
</div>

<script type="text/javascript">
    var table_1 = document.getElementById('table_1');
    var table_2 = document.getElementById('table_2');
    var block_1 = document.getElementById('block_1');
    var block_2 = document.getElementById('block_2');
    
    
    block_1.innerHTML = '';
    block_2.removeChild(table_2);
    
    alert(table_1);
    alert(table_2);
    alert(table_1.innerHTML);
    alert(table_2.innerHTML);
</script>

11 октября 2012 г.

Почему не работает call_user_func_array

В документации по call_user_func_array есть два интересующих нас момента:
  •  "[call_user_func_array] Возвращает результат функции или FALSE в случае ошибки." 
  • "Передача параметра функции по значению при ожидаемой передаче по ссылке вызовет предупреждение и заставит call_user_func() вернуть FALSE..." 
На практике PHP (5.3.4) таки выдает предупреждение ("PHP Warning: Parameter 4 to JHTMLMenu::treerecurse() expected to be a reference, value given in /htdocs/libraries/joomla/html/html.php on line 87"), callback-функция действительно не выполняется, но call_user_func_array возвращает NULL, вместо обещанного FALSE. Ради справедливости отмечу, что тут мы получаем предупреждение, а не ошибку.

Пример из Joomla 1.5.7. Тут решается двумя разными способами: 1) делаем все элементы массива ссылками
<?php
if (strnatcmp(phpversion(),'5.3') >= 0)
{
    foreach($args as $key => $value)
    {
        $refs[$key] = &$args[$key];
    }
}
?>

или сам массив $args передаем по ссылке
<?php
call_user_func_array( array( $className, $func ), &$args );
?>

13 сентября 2012 г.

Простой шаблонизатор на JavaScript без компилирования шаблона

Шаблон:

var template = '\
    <div class="container">\
        <p>{{shortbio}}</p>\
        <ul>\
        {{foreach albums as album}}\
            <li {{if album.selected == true}} class="selected"{{endif}}>\
                {{album.name}} ({{album.year}})\
            </li>\
        {{endforeach}}\
        </ul>\
        \
        <select>\
        {{foreach albums as album}}\
            <option {{if album.selected == true}} selected{{endif}}>\
                {{album.name}} ({{album.year}})\
            </option>\
        {{endforeach}}\
        </select>\
    </div>\
';

Данные:

var data = {
    albums: [
        {name: 'Golden Heart',              year: '1996'},
        {name: 'A Night In London',         year: '1996'},
        {name: 'Sailing to Philadelphia',   year: '2000'},
        {name: 'The Ragpicker’s Dream',     year: '2002'},
        {name: 'Shangri-La',                year: '2004', selected: true},
        {name: 'One Take Radio Sessions',   year: '2005'},
        {name: 'Kill To Get Crimson',       year: '2007'},
        {name: 'Get Lucky',                 year: '2009'}
    ],
    
    shortbio: 'Марк Фро?йдер Но?пфлер OBE (англ. Mark Freuder Knopfler; 12 августа 1949, Глазго, Шотландия) — британский рок-музыкант, певец и композитор, один из сооснователей группы Dire Straits.'
};

Код:


Результат:


Скрипт шаблонизатора: github
Скрипт примера: templater_example.js

23 августа 2012 г.

Подсчет нажатий с 8-сегментным индикатором

Я доработал программу, которая считает количество нажатий кнопки. Теперь количество отображается с помощью 8-сегментного светодиодного индикатора. Для простоты я использовал один индикатор, соответственно отобразить можно только одну цифру. Поэтому программа считает до 9, а при следующем нажатии сбрасывает счетчик.

19 августа 2012 г.

Первый блин на Tiny26

Моя первая программа на МК. Каждые 2 секунды меняет уровень на первом контакте порта A на противоположный. Так сказать, программа типа "помигать диодом".