26 декабря 2012 г.

PayPal Standard Checkout в Sandbox. Часть 1.

Самый простой способ интеграции оплаты через PayPal - использовать Website Payments Standard. Это просто форма с данными о покупке и кнопка, например, "Buy Now". После нажатия на кнопку пользователь попадает на сайт PayPal, где и заканчивает процесс оплаты. Среди прочего, в форме можно указать URL, куда сервером PayPal будут отправляться сообщения (Instant Payment Notification) после каждого изменения статуса оплаты заказа.

В этой заметке я перевожу "private" как "секретный" и "public" как "открытый" применительно к ключам и сертификатам.

В Sandbox в меню "Test Account" нажимаем Preconfigured. Создаем два аккаунта: один для продавца, другой для покупателя. Покупателю в графе баланс указываем сумму, которую он будет тратить на покупки. Примеры заполнения формы ниже:

Создаем учетную запись покупателя
Создаем учетную запись продавца
Для защиты информации будем использовать Encrypted Website Payments. Это один из способов защиты передаваемой информации, рекомендованных PayPal. Данные в виде name-value pair (пара ключ-значение) шифруются и присваиваются полю с именем encrypt. Также cmd должно быть установлено в правильное значение.

Для шифрования нам понадобится создать  секретный ключ и открытый сертификат. Последний мы загрузим в свой аккаунт на PayPal. После загрузки ему будет присвоен CertID, который будет передаваться в форме вместе с информацией о покупке. Также надо будет скачать открытый сертификат PayPal.

О способах защиты, рекомендованных PayPal, можно почитать тут: Securing Your PayPal Payments Standard Buttons.

OpenSSL для Windows можно скачать тут (я использовал Win64 OpenSSL v1.0.1c). Это ссылка с официального сайта, с этой страницы. После запуска инсталлятор сообщил мне, что на компьютере не установлена Visual C++ 2008 Redistributables, которая необходима для работы программы. Скачиваем тут же.

Из командной строки переходим в директорию OpenSSL/bin.
Генерируем секретный ключ.
openssl genrsa -out my.sandbox-prvkey.pem 1024 -config openssl.cfg

На основе секретного ключа генерируем открытый сертификат.
openssl req -new -key my.sandbox-prvkey.pem -x509 -days 365 -out my.sandbox-pubcert.pem 
-config openssl.cfg

-x509 означает самоподписанный сертификат. С этой опцией используется опция -days.
После ввода команды в диалоговом режиме можно будет ввести информацию о владельце сертификата (название организации, страна, e-mail и т.д.). PayPal использует только сертификаты X.509.

Теперь нужно создать сертификат p12. Нужно будет придумать и ввести пароль, который будет использоваться позже для подписывания сообщения. Сам сертификат p12, похоже, в процессе шифрования не участвует.
openssl pkcs12 -export -in my.sandbox-pubcert.pem -inkey my.sandbox-prvkey.pem -out my.sandbox-cert.p12

Теперь нам надо загрузить наш сертификат и скачать сертификат PayPal. Чтобы зайти на тестовый PayPal, согласно документации, нужно выбрать аккаунт из списка в "Test Accounts" на developer.paypal.com и нажать кнопку "Enter Sandbox Test Site". Но какой бы я аккаунт не выбрал, я почему-то всегда заходил в первый в списке аккаунт, поэтому я просто заходил на  www.sandbox.paypal.com  из другого браузера.

Заходим в тестовый аккаунт продавца на sandbox.paypal.com, только в качестве логина используем не "Login Email", который мы задавали при регистрации тестового аккаунта, а фиктивный почтовый ящик, который был присвоен тестовому аккаунту автоматически (указан в списке тестовых пользователей, раздел Test Accounts в левом меню Sandbox).
E-mail тестовой учетной записи продавца,
который используется в качестве логина на  sandbox.paypal.com



Теперь My Account -> Profile -> My Settings, Encrypted Payment Settings.



В разделе Your Public Certificates добавляем наш сгенерированный открытый сертификат. После загрузки он появится в списке. На интересует присвоенный ему Cert ID. Его мы будем передавать в форме.



В разделе PayPal Public Certificate есть кнопка Download. Скачиваем открытый сертификат  PayPal. С нашей стороны он будет использоваться для шифрования данных формы.

PayPal предоставляет готовые решения для шифрования формы  на нескольких языках программирования. Их можно скачать на странице SDKs and Downloads в разделе "Website Payments Standard".

Продолжение следует.

7 декабря 2012 г.

CodeIgniter. Настройка хостинга GoDaddy

Чтобы работали ссылки типа http://yourdomain.com/controller/action/data надо настроить mod_rewrite так, чтобы путь передавался фронт-контроллеру index.php как строка запроса (/index.php?$1):
RewriteEngine on
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|gif)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?$1 [L,QSA]

Также нужно сообщить фреймворку, что информацию о пути нужно брать из строки запроса:
<?php
$config['uri_protocol']    = 'QUERY_STRING';
?>

Подстановка index.php в ссылки, естественно, должна быть отключена:
<?php
$config['index_page'] = "index.php?";
?>

3 ноября 2012 г.

PHP. Добавляем комментарий в JPEG

Ниже приведен пример скрипта, в котором я получаю содержимое картинки, хранящейся на диске, и преобразовываю его в шестнадцатеричное представление. Далее я создаю строку комментария. Она состоит из
  • маркера COM (комментарий), который в шестнадцатеричном представлении выглядит так: 'fffe',
  • двух байтов, указывающих длину комментария + 2 этих байта ('0008' строка содержит 6 байт),
  • собственно, строки комментария.
Хотя комментарий в файле JPEG может появляться где угодно, для простоты примера, я дописываю комментарий в начало файла, сразу после маркера начала изображения (SOI - 'ffd8'). В конец файла комментарий дописывать нельзя, потому что маркер конца изображения (EOI - 'ffd9') должен следовать сразу после сжатых данных. Потом я вывожу картинку в браузер.
<?php
    $image = file_get_contents('head1.jpg');
    $imageHex = bin2hex($image);
    
    $hexString = '636f6d6d656e';
    $commentBlock = 'fffe0008'.$hexString;
    $imageHex = str_replace('ffd8', 'ffd8'.$commentBlock, $imageHex);
    
    $imageBin = pack('H*', $imageHex);
    header('Content-Type: image/jpeg');
    echo $imageBin;
?>

Вместо функции pack можно использовать hex2bin, добавленную в PHP 5.4.0.

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 на противоположный. Так сказать, программа типа "помигать диодом".

Прерывание по уровню и фронту

Программа считает количество прерываний по линии INT0 и выводит его в порт А. Я отдельно рассматриваю случаи, когда прерывание вызывается низким уровнем сигнала, передним или задним фронтом и изменением уровня.

18 августа 2012 г.

Обработка прерываний. Регистр GIFR.

Чтобы вызвать прерывание от внешнего источника, на соответствующей ножке МК нужно создать необходимые электрические условия. Например, прерывание можно вызвать изменением потенциала с высокого на низкий. При этом, чтобы был вызван обработчик, прерывания в МК, необходимы следующие условия:
  • прерывания должны быть разрешены глобально (бит I в регистре SREG должен быть установлен);
  • конкретное прерывание должно быть разрешено (установлен соответствующий прерыванию бит в регистре GIMSK).