Сложный виджет

Сложный виджет представляет собой самостоятельное Web приложение произвольной структуры с поддержкой настроек на Desk.uz. Окно виджета представляет собой IFRAME с HTML документом внутри, определяемым самим разработчиком виджета, т.е. Desk.uz не имеет отношения к представлению (дизайн, вёрстка и т.п.) данных внутри окна виджета. Окно может изменять размеры по высоте и ширине, может перезагружаться и сворачиваться.

Загрузка содержимого виджета и все Ajax запросы проходят через проксирущий скрипт на Desk.uz. При этом источнику виджета передаются все необходимые POST (за исключением загружаемых файлов) и GET данные, а также Cookies. Cookies, пришедшие с ответом, устанавливаютя в браузер пользователя.

Основные требования

При разработке виджета необходимо соблюдать следующие условия:
  • Для всех CSS, JS файлов, ссылок, картинок и т.п. должны указываться абсолютные пути
  • Все внешние ссылки должны иметь параметр target=”_blank”
  • Элементы HTML документа не должны напрямую ссылаться на другие документы через теги A, FORM и др.
  • Все запросы должны отправляться через AJAX с использованием JavaScript API Desk.uz
  • При разработке внешнего вида (дизайна) содержимого виджета нужно учитывать, что минимальная ширина окна виджета может составлять 300 px
  • Всё содержимое виджета, включая ответы на Ajax запросы, должно передаваться в кодировке UTF-8

Настройки виджета

Настройки виджета пользователя передаются источнику виджета в строке запроса методом GET. При определении количества настроек и объёма данных для передачи необходимо учитывать, что в браузерах существуют ограничения на размер строки GET параметров.

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

Сруктура XML файла настроек виджета

<?xml version="1.0" encoding="UTF-8"?> <settings> <parameters>   <parameter>      <!-- Описание поля 1 -->   </parameter>   <parameter>      <!-- Описание поля 2 -->   </parameter> </parameters> </settings>

В Desk.uz доступны следующие виды полей настроек:

text – обычное текстовое поле <input type=”text”>

XML код:

<parameter>    <type>text</type>    <name>field_name</name> <!-- имя поля, параметр name в html аналоге, например, phone -->    <label>Field label</label> <!-- заголовок, например, «Ваш телефон» --> </parameter>

select – поле для выбора значений, аналог <select> в HTML

XML код:

<parameter>   <type>select</type>   <name>field_name</name>   <label>Field label</label>   <option value="1">Value 1</option>   <option value="2">Value 2</option>   <option value="3">Value 3</option>   <ondefault>1</ondefault> <!--значение, выбранное по умолчанию --> </parameter>

XML код для select с возможностью множественного выбора multiple:

<parameter>   <type>select</type>   <name>field_name[]</name> <!--передаётся массив значений -->   <label>Field label</label>   <multiple>1</multiple>   <option value="1">Value 1</option>   <option value="2">Value 2</option>   <option value="3">Value 3</option>   <ondefault>1</ondefault> <!--значения, выбранные по умолчанию -->   <ondefault>3</ondefault> </parameter>

XML код для select с поддержкой групп, аналог <optgroup> в HTML:

<parameter>   <type>select</type>   <name>field_name</name>   <label>Field label</label>   <optgroups>      <optgroup label="Label 1">       <option value="1">Value 1</option>       <option value="2">Value 2</option>      </optgroup>      <optgroup label="Label 2">       <option value="3">Value 3</option>       <option value="4">Value 4</option>      </optgroup>    </optgroups>   <ondefault>1</ondefault> <!--значение, выбранное по умолчанию --> </parameter>

radio – поле для выбора значений, аналог <input type=”radio”> в HTML

XML код:

<parameter>    <type>radio</type>    <name>field_name</name>    <label>Field label</label>    <value>Field value</value>    <ondefault>checked</ondefault> </parameter>

checkbox – поле для выбора значений, аналог <input type=”checkbox”> в HTML

XML код:

<parameter>    <type>checkbox</type>    <name>field_name</name>    <label>Field label</label>    <value>Field value</value>    <ondefault>0</ondefault> </parameter>

Авторизация виджета

При добавлении виджета в каталог Desk.uz разработчик получает идентификационные параметры для виджета - DESK_API_KEY и DESK_API_SECRET, с помощью которых будет осуществляться обмен данными между Desk.uz и источником виджета.

DESK_API_KEY - это идентификационный ключ, своего рода логин виджета.
DESK_API_SECRET - это секретный код, известный только Desk.uz и источнику виджета.

На стороне Desk.uz секретный код прописывается в настройках виджета в базе данных. При отправке запроса источнику виджета методом POST передаётся параметр desk_key, представляющий собой строку вида SHA1(DESK_API_SECRET + desk_time) и сам параметр desk_time, который является текущей меткой времени Unix (количество секунд, прошедших с начала Эпохи Unix до текущего времени) с микросекундами. На стороне источника виджета скрипт "знает" секретный код и может воспроизвести операцию и сравнить ключи. Если строки совпадают, значит, запрос пришел действительно от Desk.uz. При этом нужно проверять метку времени, чтобы она превышала значение метки времени последнего обращения (desk_time > last_time), чтобы не дать возможность повторной передачи одной и той же строки. Если проверки прошли, нужно сохранить новую (присланную) метку, например, в какой-нибудь файл для последующего использования.

Примерно та же проверка осуществляется на стороне Desk.uz (для этого перед отправкой данных делается короткий запрос на получение только HTTP заголовков страницы без содержимого, при этом скрипт, обрабатывающий запросы на стороне источника виджета, отправляет заголовок Set-Cookie Deskuz_key со значением SHA1(DESK_API_SECRET + widget_time), где widget_time - метка времени, которая также присоединяется к получившемуся хешу символом «_».

Например, если

DESK_API_SECRET = adce48f99c504b62baa87007c4fb1e6422813cc0

widget_time = 1302179954.49

Hesh_sha1 = dc59ebe8b567cc59421bf53fd8a2876115c62698,

то значение

Cookie = dc59ebe8b567cc59421bf53fd8a2876115c62698_1302179954.49

Desk.uz сохраняет обновлённую метку времени в базе данных. Также заголовок Set-Cookie проверяется при получении ответа на запрос.

Помимо этого, при обмене данными используется своего рода «цифровая подпись», чтобы предотвратить подмену данных. Во время запроса отправляется параметр desk_signature в виде стоки SHA1(GET данные + POST данные + Cookie + DESK_API_SECRET). На стороне источника виджета эта строка проверяется. При ответе формируется строка SHA1(Содержимое ответа + DESK_API_SECRET) и отправляется в виде заголовка Set-Cookie Deskuz_signature, который также проверяется на стороне Desk.uz.

Если виджет написан с использованием языка PHP, то можно использовать готовый класс PHP API Desk.uz , который выполняет все выше описанные операции.

Пример использования PHP API Desk.uz:

<?php /** * Пример кода сложного виджета для Desk.uz с использованием PHP API Desk.uz */ require_once('Deskuz_api/config.php'); //подключаем config require_once('Deskuz_api/consumer.php'); //подключаем api //Создаём объект Deskuz_Consumer с параметрами из конфига $consumer = New Deskuz_Consumer(DESK_API_KEY,DESK_API_SECRET,DESK_TIME_STORAGE); /* Проводится начальная обработка запроса. До вызова методов ($consumer->begin,
$consumer->complete, $consumer->make_signature) вывод каких-либо данных делать не
следует, т.к. они посылают HTTP заголовки (Set-Cookie), если всё же требуется выводить
данные, используйте php функции для буферизации вывода ob_start(), ob_end_flush().
*/ if ($consumer->begin()) {   //Основная обработка запроса и проверка его параметров   $consumer->complete();   //Если все проверки прошли нормально, можно формировать и выводить содержимое виджета   if($consumer->status == 'SUCCESS') {     $main = 'Привет, пользователь';     /*     Если запрашивались персональные данные пользователя (desk_userid, desk_account),
и Desk.uz вернул их, то можно использовать их в дальнейшей логике виджета
    */     if (!empty($consumer->request_data['desk_account'])) {     /*     Здесь формируем содержимое для виджета. Тут возможны запросы к базе данных на получение
нужной информации.
    */       $main = 'Привет, '.$consumer->request_data['desk_account'];     }   }   else {     //Если возникли ошибки, можно вывести их в какой-нибудь лог-файл     foreach ($consumer->error as $err) {       file_put_contents('file.log',date('d.m.Y H:i:s').' '.$err.'\n ',FILE_APPEND);     }     $main = 'Извините, на данный момент нет данных';   }   //Шаблон содержимого виджета   $content = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> %s </body> </html>'
;   $content = sprintf($content,$main);   //Генерируем и посылаем подпись к содержимому   $consumer->make_signature($content);   //Выводим содержимое   print $content; } ?>

Использование Ajax

Для применения возможностей технологии Ajax нужно использовать JavaScript API Desk.uz, в состав которого также входит JavaScript фреймворк jQuery.
Для использования JavaScript API Desk.uz его необходимо подключить в HTML коде содержимого виджета:

<head> <script type="text/javascript" src="http://www.desk.uz/js/api/1.0/widgetapi.js"></script> </head>

На данный момент доступен следующий функционал:

  • Отправка Ajax запросов на сервер-источник виджета

Для этого можно использовать функцию

Deskuz.sendRequest(url, data, cookies, callback);

Где

url – это url, куда посылается запрос,

data – необходимые для передачи post данные, представляющие собой javascript объект,

cookies – одномерный массив имён cookie виджета, которые будут переданы прокси-скриптом серверу-источнику url,

callback – функция, куда будет передан результат выполнения запроса.

Пример использования:

<script type="text/javascript"> $(function() {   var params = new Object;   params.par1 = 'value';   params.par2 = new Object;   params.par2.item = 'value2'; //на сервер придут параметры $_POST[‘par1’] и $_POST[‘par2’][‘item’]   Deskuz.sendRequest('http://site.com/ajax.php?action=load', params, new Array('testcookie'),     function(data) {       $('#message').html(data); //Сюда будет передан результат     }); }); </script> <div id="message"></div>

Если виджет находится в режиме тестирования (который используется перед добавлением виджета в каталог), то перед вызовом метода Deskuz.sendRequest необходимо установить параметр Deskuz.debug в true. По умолчанию он установлен в false. Этот параметр (если true) говорит Desk.uz, что виджета ещё нет в каталоге, при этом также будут выводиться более подробные сообщения об ошибках. После отправки заявки на добавление виджета в каталог нужно убрать установку этого параметра.

Пример использования:

<script type="text/javascript"> $(function() {   Deskuz.debug = true;   var params = new Object;   params.par1 = 'value';   Deskuz.sendRequest('http://site.com/ajax.php?action=load', params, new Array('testcookie'),     function(data) {       $('#message').html(data); //Сюда будет передан результат     }); }); </script> <div id="message"></div>

  • Установка пользователю cookie

Deskuz.setCookie(name, value, seconds);

Где

name – имя cookie,

value – значение cookie,

seconds – время жизни в секундах

Пример использования:

<script type="text/javascript"> $(function() {   Deskuz.setCookie('testcookie','test',3600);   //Удаление cookie   Deskuz.setCookie('somecookie','', 0); }); </script>

  • Получение значения установленных cookie пользователя

Deskuz.getCookie(name);

Где

name – имя cookie.

Пример использования:

<script type="text/javascript"> $(function() {   var cookie = Deskuz.getCookie('testcookie'); }); </script>

  • Получение значения установленных настроек виджета пользователя

Deskuz.getSettingsValue(field);

Где

field – имя поля настроек.

Пример использования:

<script type="text/javascript"> function get() { var show = Deskuz.getSettingsValue('show'); Deskuz.sendRequest('http://site.com/ajax.php?action=get', show, '',   function(data) {     $('#message').html(data);   }); } </script> <div id="message"></div> <a href=”javascript:void(0);” onClick=”get();”>Показать</a>

Авторизация

Логин