This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Современные технологии эффективной разработки веб-приложений с использованием PHP PHP::SOAP и XForms на АвтоВАЗ-е MySQL: репликация и кластер издается с февраля 2004 года, www.phpinside.ru
PHP Inside №13
Содержание В фокусе Свой проект свободно распространяемого программного обеспечения.................................. 5 Две стороны документирования: phpDocumentor и DocBook..................................................14 Разработка современной CMS. Преимущества которые дает PHP 5.......................................24 MySQL – просто о сложном........................................................................................................ 37 Оптимизация PostgreSQL.............................................................................................................48 Построение поисковых систем. Принципы и реализация........................................................60 Доклад по целесообразности тестирования...............................................................................68 XML Sapiens как универсальная концепция сайтостроения в разрезе XML/PHP................. 77 XML в PHP 5................................................................................................................................. 88 Поддержка нескольких СУБД в проекте....................................................................................95 PHP::SOAP и Xforms.................................................................................................................. 104 Платежные системы – это не страшно..................................................................................... 133 Влияние TDD на дизайн кода....................................................................................................157 Введение TDD в существующий проект.................................................................................. 172
Человек с обложки. Как это было В этом номере мы совместно с организаторами конференции "Современные технологии эффективной разработки веб-приложений с использованием PHP" публикуем ее доклады и мастер-классы. На страницах журнала вы сможете найти не только материалы конференции, но и отзывы ее участников - почувствуете, так сказать, царившую там атмосферу. В дополнение к этому выпуску PHP Inside мы так же публикуем некоторые видео-материалы и презентации "as is". Теперь перейдем к вопросу, который записан в качестве заголовка этого раздела: кто же этот человек с обложки? Здесь, уважаемые коллеги, следует мысленно вернуться в тот весенний вечер 13-го Мая в Киев и, тем кто там был, вспомнить банкет после конференции (а тем кто не был - просто представить). А вспомнить нужно не то, что в заведении было выпито ВСЕ пиво, да и не то как все веселились, а аукцион, профессионально проведенный Александром Смирновым [admin], Еленой Теслей [Lenka], Александром Войцеховским [young] и некоторыми другими клубчанами. Одним из лотов была эксклюзивная кружка с логотипом PHP Inside и...! Замрите! Нет, не горшок, что в правой руке, а фото победителя торгов на обложку этого спецвыпуска (креативная идея исходила от admin'a)..
Команда номера
Авторы и переводчики Андрей Козак Борис Безруков Константин Погорелов Дмитрий Магунов Александр Войцеховский Алексей Борзов Юрий Логвинов Сергей Юдин Дмитрий Шейко Денис Жолудов Денис Соловьев Александр Анохин Владимир Булов Кирилл Литвинов Евгений Бондарев Павел Щеваев
Редакционная коллегия Александр Смирнов Александр Войцеховский Андрей Олищук [nw] Антон Чаплыгин Елена Тесля
2
PHP Inside №13
Победителем стал человек с сегодняшней обложки - Евгений Синица из украинского города Харькова (за фотосессию спасибо Lenke). Именно он увез эксклюзив. Евгению настолько полюбилась символика журнала и клуба, что он победил еще в нескольких торгах и вместе с кружкой "PHP Inside" получил пару других экспонатов, уже с атрибутикой PHPClub'а. Фотоотчеты с конференции, банкета, как и прочих событий PHPClub'а можно найти на сайте http://party.phpclub.net/search.php А состоялась конференция благодаря неисчерпаемому энтузиазму активистов из веб-сообщества и отеческой поддержке спонсоров и организаторов, чьи логотипы вы можете видеть справа. Внимание, еще остались раздаточные материалы в изначальном печатном виде. Приобрести их можно в Киеве: ул. Исаакяна, 18, офис 211, тел. +380 44 230 47 77, Андрей Зинченко.
Команда номера (продолжение)
Выпуск номера
Андрей Олищук [nw] Роман Толкачев [rammstein] Антон Чаплыгин Денис Зенькович
Если вам интересно узнать отзывы участников, то в полном объеме отзывы представлены на сайте PHPClub'а: http://phpclub.ru/talk/showthread.php?s=&threadid=67108&rand=59 а здесь мы приведем только некоторые из них. syfisher: Почти все понравилось! Плюсы: организация отличная, публика тоже очень хорошая. Мы думали по началу, что это будет некий официоз. Я на деле - очень дружеская атмосфера разработчиков. Очень понравилось место проживания активистов. Минусы: некоторые доклады были провальными или имели слишком рекламный характер. С этим нужно бороться или же выносить такие доклады в отдельные секции, идущие параллельно. Я бы посмотрел сколько бы человек пошло на AWWCMS, если бы мы начали рассказывать про LIMB (ладно, шучу :-)). На будущее: получать доклады в сокращенном виде (до 5 страниц) еще до голосования по темам. То есть ввести элемент диктатуры по этапе отбора докладчиков. Я думаю, что такого пренебрежительного отношения в конференции, как после 3-й, больше не будет. Мне как докладчику по TDD очень было приятно, что сообщество экстремалов развивается и достаточно резво. Это придает уверенности и является хорошим стимулом чтобы продолжать то, что мы начали. Конечно жаль, что не все активисты клубы выбрались на конференцию, а мы так рано уехали, но для первого раза (для меня лично) - очень доволен. Fiva: Конкретно разочаровали вопросы не по существу а с целью завалить докладчика, показать что весь его доклад - полная фуйня. Я думаю этого делать было не обязательно, плохие доклады от хороших можно было отличить не только невооруженным взглядом, но и сразу же после получения раздатки. kdk: Добавлю свои три капли. Уровень докладчиков несомненно стал выше. Если на прошлой конференции мне вспоминаются 2-3 интересных доклада, то на этой вспоминаются 2-3 плохих. Т.е. Ситуация в корне изменилась!!! Хороших докладов и грамотных докладчиков, умеющих общаться с аудиторией стало на порядок больше!!! 3
PHP Inside №13
voituk: Долго распыляться по поводу своих впечатлений не буду (хотя очень хотелось) скажу только что конференция прошла под лозунгом "TDD в массы!". Вторым (хотя скорее первым) ярким эпизодом конференции был отличный доклад Александра Анохина про XFroms+SOAP. P.S. конечно же очень приятно и познавательно было пообщаться с ребятами из Пензы и Анохиным в неформальной обстановке пивного бара. young: тема php не раскрыта :) mariroz: большое спасибо организаторам за хорошо подготовленную конференцию! Понравилась достаточно неформальная обстановка и свободный стиль изложения, разнообразность тем докладов. Хотя, действительно, были и рекламные выступления и слабые, но в целом время (надеюсь, не только для меня) потрачено недаром. Для того, чтобы были сильные, интересные доклады должны быть и слабые . И, кстати, глупые вопросы тоже. Мальчики из Пензы: вы просто молодцы ). Разочаровали конечно доклады о AWWCMS и siteMETA. Здесь не ругают, но мне не понравился также доклад о поддержке нескольких субд в проекте. Трудно, конечно, было выступать после доклада от автоваз, но мне показалось, что докладчик и сам чувствовал слабость своего доклада, отсюда и странноватый (имхо) стиль выступления. Из пожеланий: материалы конференции хорошо бы получить заранее; очень поддерживаю идею общего банкета . Да, и спасибо за отдельное внимание к женской части публики. Мелочь - но приятно. Yur@: Почитал отзывы, и немного удивился. Многие говорят, что конфы прогрессируют. Мне сравнивать не с чем, но осталось какой-то неприятный осадок... Если конкретно - организацию я бы оценил на 5, может с минусом. Т.к. никакого дискомфорта в этом плане не ощущал, а придирки к еде, бейджикам и указателям не столь серьезны (т.е. опять же, я не чувствовал по этому поводу дискомфорта). А вот по поводу докладов есть серьезное замечание. Не буду останавливаться на каком-то конкретном докладе, но 1й день мне не понравился абсолютно (окромя доклада по MySQL), второй день был куда интереснее (слабым звеном был разве что доклад по платежным системам). Но теперь о самом главном. Мне абсолютно неинтересно сидеть 45 минут и слушать, как люди сидят и пиарят свой программный продукт!!! Я НЕ ЖЕЛАЮ СЛУШАТЬ РЕКЛАМУ ЗА СВОИ ЖЕ ДЕНЬГИ. Самый яркий тому пример - Разработка современной CMS, отчасти сюда же можно отнести доклад по "Мете"... Я считаю, что такие доклады даже не должны допускаться на конфу. Я абсолютно ничего не услышал из доклада для себя полезного, а сам стиль доклада был пиарным, бездоказательственным, и необоснованным. screjet: Конфа прошла отлично! Есть предложение следующую провести в лесу с палатками, гитарами и фаейрволом.
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
В фокусе Свой проект свободно распространяемого программного обеспечения Каждый из вас слышал об операционных системах Linux. Автор: Андрей Козак Многие знают, что эти ОС в большинстве являются бесплатными и имеют открытые исходные коды. В настоящее время существуют десятки тысяч Open Source проектов. Эти проекты написаны на самых различных языках под самые различные платформы. Что же такое Open Source?
Вступление Open Source Software (ПО с открытым исходными текстами) представляет собой методологию разработки программного обеспечения, при котором исходный код программ либо является общественным достоянием (public domain), либо защищён с помощью одной или нескольких из многочисленных "открытых" лицензий - как, например, GNU General Public License (GPL). Такие лицензии, как правило, требуют, чтобы исходный код распространялся вместе с ПО, мог свободно модифицироваться и использоваться с минимальными ограничениями. Таким ограничением может быть требование о сохранении имен авторов, упоминание об их авторских правах. В некоторых случаях (напр., Apache или FreeBSD) эти ограничения очень малы. Заметьте, что это права пользователя, но не обязанность производителя - "открытая" лицензия не требует, чтобы само ПО предоставлялось бесплатно. Многие из наиболее успешных проектов "открытого" ПО, однако, доступны совершенно бесплатно. Подавляющее большинство открытых программ является одновременно свободным программным обеспечением и наоборот. Это вызвано тем, что определения открытого и свободного ПО очень близки, и большинство лицензий либо удовлетворяют обоим определениям сразу, либо не удовлетворяют ни одному из них.
Зачем нужен свой проект в Open Source? Причин, по которым люди начинают писать Open Source программы, существует несколько. Одна из них - с идеологической точки зрения. Такие люди часто используют Open Source ПО. Вторая из причин -поделиться с другими программистами какой-либо идеей (когда проект только зарождается), развивать её и соответственно реализовывать. Третья из возможных причин - это желание сделать что-то полезное, удобное. Четвертая - просто прославиться и стать народным героем. Пятая - поднять свой уровень программирования. Есть другие причины, но на них мы останавливаться не будем.
5
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Создание своего проекта Итак, по какой-то из причин вы решили все таки создать свой проект Open Source и разместить его в сети. Теперь придется решить несколько проблем: где разместить проект, под какой лицензией распространять, как лучше писать документацию и т.п.
Хостинг Возможно, первая проблема, с которой сталкивается разработчик Open Source, - как заявить о проекте, как сделать так, чтобы люди могли про него узнать, а возможно, и скачать. Самый простой способ -разместить сообщение на форуме, а затем интересующимся высылать информацию на e-mail. Но способ этот самый неудобный, т.к. существуют более гуманные средства для распространения Open Source. Начнем с различных каталогов скриптов. Довольно интересные сервисы, но малофункциональные. Полную документацию разместить в online некуда, дополнительные страницы создать невозможно и т.п. Поэтому сразу перейдем ко второму варианту. Вторым вариантом являются системы для размещения OpenSource проектов. На данный момент самые популярные - это Sourceforge и Freshmeat. В общем-то, они выполняют приблизительно одинаковые задачи, но Sourceforge является более популярным ресурсом. По последним данным там зарегистрировано около 1,1 миллиона пользователей и около 100 000 проектов, среди которых около 11 000 - проекты, написанные на PHP. Регистрация и размещение на этом сайте (как, впрочем, и на многих других) бесплатные. После создания своего проекта вы сможете пользоваться такими инструментами, как добавление на сервер файлов, логическое разделение их на релизы, ведется подробная статистика скачиваний по каждому из файлов, ведение своего Bug-track, CVS, форумов, возможность бесплатно разместить сайт проекта, что, несомненно, является большим плюсом, т.к. бесплатного хорошего хостинга не бывает. Есть еще один, но более специфический вариант для размещения проектов РНР Open Source - сайт PHPClasses. На этом сайте можно размещать РНР-проекты и просто библиотеки, которые написаны с использованием ООП. Сервис, если учесть специфику, довольно удобный. Кроме того, каждый месяц проходит конкурс на лучший проект месяца с призовым фондом (от спонсоров, например, книга либо лицензионная версия Zend Studio). Представим, что проблема, где размещать проект, решена, и вы выбрали для этого сервис, либо просто пользуетесь обычным платным/бесплатным хостингом. Теперь возникает другая проблема - как писать и оформлять документацию, чтобы другим было удобно ей пользоваться.
Документация Чаще всего документация появляется в относительно немаленьких проектах, т.к. реально появляется необходимость объяснить пользователям и, возможно, будущим разработчикам, что для чего служит. 6
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Документация обычно может состоять из двух основных частей: это описание пользовательской/администраторской части и описание для разработчиков (в отличие от обычных проектов, в библиотеках обычно одно описание - список и описание функций, классов и т.п.). Когда документируется пользовательская часть, не следует описывать все кропотливо и подробно, т.к. люди, которые интересуются проектом, уже имеют минимальный опыт для работы с такими вещами, но и просто перечислять кнопки тоже не стоит, т.к. это может затруднить понимание того, как работать с программой. При документировании самого кода я могу посоветовать программу под названием phpDocumentor. О ней подробно рассказано в докладе Бориса Безрукова "Две стороны документирования: PHPdocumentor и DocBook". Документация играет очень важную роль в поддержке проекта: лучше посидеть над документацией, чем потом отвечать на простые вопросы в форуме или по e-mail. Кроме того, будущим разработчикам все же удобнее читать документацию кода, чем разбирать чей-то код.
Выбор лицензии (GPL, LGPL, BSD) При создании своего проекта рано или поздно встает проблема лицензирования, т.к. необходимо как-то защитить свое право на интеллектуальную собственность, а также по другим причинам. Существует большое количество лицензий для программного обеспечения. Но чаще всего для проектов PHP Open Source пользуются тремя типами лицензий: GPL, LGPL и BSD. Для наглядности и более простого понимания лицензии GPL и BSD помещены в таблицу. Требования
GPL
BSD
Требуется указывать имя автора
Да
Да
Измененные файлы должны быть помечены
Да
Нет
Наименование производного ПО должно отличаться от наименования продукта создателей лицензии
Нет
Нет
Производные произведения должны распространяться на условиях первоначальной лицензии
Да
Нет
Указана территория, на которую предоставляется лицензия
Нет
Нет
Отсутствие гарантий на ПО
Да
Да
Предоставляется право применить другую лицензию
Нет
Не указано
Отдельно следует сказать о лицензии LGPL. Эта лицензия носит ограниченное применение: она может применяться только к библиотеке, и произведение, производное от первоначальной библиотеки, также должно быть библиотекой.
7
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Немного подробнее о лицензии BSD. Как известно, существует два варианта ее текста: с оговоркой о рекламе и без этой оговорки. Лицензия, которая одобрена для применения как Open Source, так и FreeSoftware, - это лицензия без оговорки о рекламе. Эта оговорка была официально отменена директором департамента технологического лицензирования Калифорнийского университета 22 июля 1999г. В 2001г. появился еще один вариант лицензии BSD - лицензия корпорации Intel "BSD+Patent License". Она специально разработана для того, чтобы позволить модифицировать и распространять ПО, которое может защищаться патентами на программное обеспечение корпорации Intel. Лицензии LGPL, BSD являются совместимыми с лицензией GPL. Совместимость с GPL означает, что разработчик вправе объединить модуль, который распространяется на условиях совместимой с GPL лицензии с модулем, распространяемым на условиях GPL, чтобы получить одну программу. Дальнейшее распространение полученной программы должно осуществляться в соответствии с условиями. Если создатель библиотеки решит заменить лицензию LGPL на GPL, то такая замена будет окончательной и повлечет за собой применение GPL ко всем последующим копиям данного экземпляра библиотеки и произведениям, производным от нее. LGPL содержит ряд специфических условий, в частности, в отношении произведений, возникающих в результате связывания ПО, использующего библиотеку, с библиотекой. Такие произведения могут распространяться на любых условиях с соблюдением определенных требований LGPL.
Контроль версий CVS (Concurrent Versions System) является системой контроля версий: она хранит историю изменений определённого набора файлов, как правило, исходного кода программного обеспечения, и позволяет нескольким (порой весьма удалённым друг от друга) разработчикам совместно работать над одним проектом. CVS популярна в мире Open Source. Система разрабатывается по лицензии GNU GPL. CVS использует архитектуру клиент-сервер: сервер хранит текущую версию (версии) проекта и историю изменений, а клиент соединяется с ним, чтобы получить рабочую копию (данная процедура называется check-out), затем проделать необходимые изменения и позже залить эти изменения (check-in). Обычно клиент и сервер соединяются через локальную сеть или через Интернет, но могут работать и на одной машине, если необходимо вести историю версий локального проекта. Серверное ПО обычно работает под управлением Unix (хотя существует CVS-сервер и для Windows NT), тогда как CVS клиенты доступны во всех популярных операционных системах.
8
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Клиенты также могут сравнить различные версии файлов, запросить полную историю изменений или получить исторический образ проекта на определённое число или по номеру ревизии. Многие Open Source проекты разрешают анонимный доступ на чтение, который впервые был применён OpenBSD. Это означает, что клиенты могут запрашивать и сравнивать версии файлов без пароля; только операции check-in, ведущие к изменению данных в репозитории, требуют пароль. CVS также может содержать различные ветки проекта. Например, стабильная версия проекта может составлять одну ветвь (branch), в которую вносятся только исправления ошибок, тогда как активная разработка может вестись в параллельной ветке, которая включает значительные улучшения или изменения с момента выхода стабильной версии. Для проектов, которые ведутся на сайте www.sourceforge.net, есть возможность использовать CVS (как анонимный доступ, так и доступ для разработчиков через SSH).
Стиль кода При создании и ведении своего проекта необходимо придерживаться определенных правил в написании программ, функций, классов, именования переменных и т.д. Эти правила вы должны утвердить сами. Если проект задумывается с учетом того, что разработчиков в будущем будет много (крупный, серьезный проект), то лучше писать код по общепринятым стандартам. Например, если идут какие-либо разветвления (операторы условий или циклов), то перед строками, находящихся между фигурными скобками этих операторов, следует ставить отступ (табуляция или пробелы). При написании классов их имена лучше составлять не из пары символов, а из слова (двух слов), которые будут приблизительно говорить о том, что этот класс делает. То же самое с функциями и переменными. Так код будет намного читабельнее для других программистов, которые захотят просмотреть исходники. И если какойлибо программист захочет помочь вам в разработке, то попросите его так же следовать этим правилам из этических соображений. Кроме того, было бы нелишним ставить комментарии, особенно перед объявлениями новых переменных и функций, где вкратце объяснять, для чего служит функция или переменная. Также при несинтаксических ошибках (скорее, пользовательских) следует выводить предупреждающее сообщение, а не просто завершать программу. Небольшой пример, демонстрирующий читабельность кода. Две программы, выполняющие абсолютно одинаковые задачи - вывод содержимого таблицы из СУБД MySQL. Пример 1. Нечитабельный код.
Пример 2. Более читабельный код.
Хотя код получается более "размашистым", но он становится более понятным для других. 10
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Основная теория для создания своего PHP Open Source проекта изложена. Программа написана, документирована и расположена в сети. Что же дальше?
Продвижение своего проекта Привлечение новых разработчиков В нескольких программистских форумах стоит дать объявления, что есть такой-то проект, посмотрите, оцените, покритикуйте и т.п. Сторонние программисты посмотрят проект, сразу скажут плюсы и минусы с их точки зрения. После небольшой дискуссии и исправления первых ошибок стоит дать объявления, что требуется помощь программистов и всех желающих помочь. Откликнется мало людей. Но скорее всего откликнутся действительно заинтересованные. Помощь принимать лучше всего любую (не только программистскую, но и, например, дизайнерскую), т.к., отказывая людям, вы тем самым будете обижать их. Теперь, когда собралась небольшая команда, проект можно развивать и представлять миру. Стоит разработать небольшой план, по которому про проект узнает больше людей. Оставляйте сообщения на различных форумах, в том числе и англоязычных. Для этого стоит перевести документацию на английский язык, а также сделать английскую версию сайта (все-таки англоязычных разработчиков намного больше, чем русскоязычных, да и понятие об Open Source у них лучше развито, чем у нас).
Реклама Говоря о рекламе, я не имею в виду массовые спам-рассылки, флуд в форумах и т.п. Я говорю в основном о различных каталогах и программистских сайтах. Сначала о каталогах. Каждый из вас был на подобных сайтах, где есть множество различных скриптов. Таких каталогов в Интернете много, например, http://www.hotscripts.com. Обычно добавление в каталог своего проекта - услуга бесплатная. После добавления можно будет контролировать, сколько человек пришли через этот каталог. Кроме этого, во многих каталогах посетители могут оставлять комментарии и выставлять оценку программе. Чем выше балл, тем выше рейтинг, тем, скорее всего, на более высокой ступеньке будет стоять проект в этом каталоге. Есть еще один способ поведать миру о проекте. Существует огромное множество сайтов программистской тематики, где кроме каталогов и форумов существует раздел "Статьи". Чаще всего в этот раздел пишут различные программисты. Свяжитесь с администратором ресурса, предложите ему разместить на его сайте статью про такой-то проект. Обязательно укажите, что проект Open Source и что денег за него никто не получает. Если статья будет хорошо написана и если проект действительно хороший, то администратор разместит вашу статью.
11
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Использование в других проектах Есть еще один вариант распространить информацию о вашем проекте. Предположим ваш проект - это полезная библиотека. Вы находите какой-либо проект, которому она может помочь. Предлагаете такой вариант администратору проекта, и если он согласится, это будет большой плюс: во-первых, вы поможете своему коллеге необходимыми наработками, во-вторых, вы обменяетесь постоянными аудиториями, и в-третьих, можно будет с гордостью заметить, что такой-то и такой-то проекты работают на базе вашего. Примеров такого симбиоза множество. Например: популярный комплекс для администрирования СУБД MySQL через веб-интерфейс phpMyAdmin включает в свой состав множество различных проектов, от OpenSource CMS до All-in-One веб-серверов (например, Denwer-2).
Проблемы существования и их решения Во время своего существования у любого проекта бывают не только хорошие времена. Бывают времена и смутные. Обусловлено это время проблемами, которые возникают. Вообще можно отделить два основных типа проблем. Первый тип - это когда нет разработчиков, которые хотели бы помогать в развитии проекта, а второй - это когда просто не хватает финансовых средств для каких-либо целей.
Отсутствие единомышленников Очень часто такая проблема возникает в самом начале жизненного пути проекта, когда никто не заинтересован в развитии проекта. Тогда стоит задуматься, а действительно ли нужен проект, или он является еще одним клоном? Потому как, если уже есть нечто готовое, то пользователям не понадобится что-то новое, но выполняющее те же функции. Если же все-таки вы решили, что проект действительно новаторский, то стоит еще раз попробовать поискать разработчиков, как описано выше. Если же разработчики-помощники были, но отказались от участия, то стоит призадуматься. Если проблема была не в отсутствии времени у разработчика, значит, ему либо надоело заниматься проектом, либо вы повели себя по отношению к нему некорректно. Все-таки не стоит забывать, что разрабатывать Open Source ПО дело добровольное. Если же человеку проект просто надоел, значит, ему перестало хватать воодушевления, новых идей, желания разрабатывать. В таких случаях стоит серьезно призадуматься о будущем проекта, обязательно составить небольшой TODO-list и поделиться идеями со всеми разработчиками. Если всех своих друзей-разработчиков постоянно воодушевлять (новые идеи, цифры скачанных копий проекта), то у них будет желание разрабатывать дальше. Но самое главное - чтобы желание было у вас.
Финансирование проекта После того, как проект просуществует некоторое время, захочется, чтобы он давал какую-либо отдачу (не только моральную, хотя письма с благодарностями тоже очень греют душу).
12
PHP Inside №13
Свой проект свободно распространяемого программного обеспечения
Это необходимо, если, например, вы хотите немного раскрутить проект с помощью баннерных сетей, купить новый домен для проекта, оплатить хостинг, либо же просто заплатить за Интернет. Здесь существует два пути: либо оставить сообщение на сайте проекта о том, что проект нуждается в финансовой поддержке, либо участвовать в баннерных сетях. Первый вариант в мире Open Source довольно распространен. На сайте Sourceforge.net для этого даже есть свой сервис, где каждый желающий может оставить свое пожертвование проекту через систему PayPal (т.н. Donations). На сайте можно оставить номера своих кошельков WebMoney и т.п. Второй вариант - размещение баннеров и другого типа рекламы на сайте проекта. Это менее прибыльный путь, но более стабильный + уже есть реклама для раскрутки. Реклама может быть в виде графических и текстовых баннеров, а также различных партнерских программ. Партнерские программы следует выбирать по тематике, которая будет интересна посетителям сайта, например, регистрация доменов или хостинг. Вообще, размещать сообщения о том, что проект не отказался бы от пожертвований, совсем не аморально. Ведь если проект популярный, реально помогает людям, экономя их время либо еще както, то его разработчик всегда заслуживает финансовой помощи. Источники: http://www.opensource.org/advocacy/faq.php http://www.libertarium.ru/libertarium/18586 http://www.sourceforge.net http://www.freshmeat.net http://ru.wikipedia.org
13
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Две стороны документирования: PHPdocumentor и DocBook Документирование исходного кода: стандарт PHPdocumentor. Одной из тем для споров в программировании всегда был и остаётся вопрос документирования кода: существует множество методик замены комментариев (к примеру, изучение API по коду тестов в XP). Тема необходимости написания комментариев останется вне обсуждения. Затронуты будут лишь способы документирования, а вернее, один способ, являющийся де-факто стандартом: PHPdocumentor – утилита авто-документирования (в дальнейшем – PHPdoc).
Автор: Борис Безруков [lovchy] Технический директор DeltaInform, OSS-энтузиаст, член группы документирования PHP
Вкратце о JavaDoc Идея PHPdoc не нова: концепт берёт своё начало в реализации JavaDoc [1.1]. JavaDoc – аналогичный продукт для документирования исходного кода Java. Суть систем автодокументирования сводится к извлечению структурных данных (схемы API) из исходного кода и представления их в удобном для чтения виде. JavaDoc очень быстро обрёл популярность, исключая необходимость ведения раздельных документов, облегчая этим процесс описания программного обеспечения.
PEAR::PHPdoc Было сказано: подход автодокументирования всегда был достаточно популярен (особенно для open source ПО), и PHPdocumentor является не единственной попыткой адаптации JavaDoc. Одним из альтернативных решений был PEAR::PHPdoc, так и не получивший ни одного стабильного выпуска и завершённый в пользу PHPdocumentor, который в свою очередь сам стал стандартом для PEAR. Существуют и ныне живущие аналоги, которые, тем не менее, не представляют собой ничего концептуально нового.
Суть подхода Говоря о PHPdoc (или JavaDoc) используются два слова: утилита и стандарт. Средства автодокументирования всегда включают в себя совершенно необходимую возможность дополнения данных, которые они могут извлечь из пустого кода: теги. Теги заключаются в комментарии особого вида (docblocks): /** * Description goes here * @author Борис `lovchy` Безруков * @version 1.0 stable */
где foo – имя тега
14
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Подобный способ написания также заимствован у JavaDoc. Именно набор тегов и является стандартом. Каждый тег начинается с символа “@” и может содержать как одну, так и несколько строк содержания. Стоит заметить, что все символы “@” в содержании тега рассматриваются как обычный символ. PHPdoc позволяет условно разделять документацию для внутреннего и внешнего пользования: здесь всегда стоит помнить, что в абсолютном большинстве случаев документацию обязательно надо писать для обоих случаев.
Обзор возможностей В случае PHP набор включает теги, специфичные как для процедурного кода, так и для ОО подхода. Кроме того, в него входят дополнительные теги, которые применяются к целому файлу, к целому разделу и т.д. Каждый блок содержит, кроме тегов, раздел описания. Он может рассматриваться как невидимый тег. Общее описание блока содержит общее описание элемента (класса, функции, метода, атрибута, …). Глобальные теги (описывающие файл) включают в себя следующие: •
@author – автор текущего файла. Тег может применяться как к файлу, так и к любому другому элементу.
•
@category, @package – используются для группировки и выделения отдельных пакетов. Широко используется PEAR, в целом – своеобразная замена пространств имён.
Документирование процедурного кода Сущность функции PHP в PHPdoc, кроме двух описаний, включает в себя основные дочерние: параметры функции и возвращаемое значение функции. Несмотря на то, что PHP – слабо типизированный язык, теги как параметров, так и возвращаемого значения включают возможность определить тип (включая имя объявленного класса). Объявление параметров: @param тип $имя описание
Для объявления неопределенного количества [типовых] параметров используется синтаксис: @param тип $имя,… описание
15
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Объявление возвращаемого значения @return тип описание
Безусловно, самой важной частью блока документации функции является её описание. PHPdoc позволяет давать функции два описания: соответственно короткое и длинное. Короткое описание всегда занимает одну строку и прерывается её окончанием, длинным описанием считается весь текст вплоть до первого тега. К длинному описанию в PHPdoc можно применять достаточно сложное форматирование – парсер умеет выстраивать списки из конструкций вида: -1 -2 - 3, подставляет параграфы в местах пропуска строки. Кроме того, PHPdoc понимает некоторые теги: , , , … Длинное описание – очень важный элемент составления общей картины о функции. Часто в длинное описание функции стоит включать пример её использования (заключенный в ). /** * Foobar * * This function does foobar this way: * $foo = foobar(true); * * @param bool $baz Baz * @return integer Foobar value */ function foobar($baz) { return rand(); }
Константы и включения Константы и включения сторонних файлов могут (и, как правило, должны) быть документированы аналогично остальным элементам. Каждая подобная сущность может иметь описание, длинное описание и набор общих тегов (@author, @since, …).
Документирование ОО кода. PHPdoc и PHP5 Условно разделим описание классов на описание атрибутов и описание методов. Фактически описание методов можно рассматривать как расширенное описание функций: расширенное дополнительными метаданными. В PHP4, не имеющем стандартных возможностей объектно-ориентированной среды, PHPdoc позволяет условно определять элементы как финальные (final) или абстрактные: теги @final и @abstract. Кроме того, модификатор доступа также может быть указан с помощью тега @access.
16
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Стоит заметить, что по умолчанию все элементы, имеющие @access private, не включаются в документацию (для этого есть специальный ключ при генерировании). Это позволяет внести то самое разделение на документацию для разработчиков кода и для людей сторонних – тех, кому может понадобиться API приложения. Фактически тег @access не имеет прямого отношения к модификатору доступа и может быть использован для любого элемента, дабы элемент был спрятан от “внешней документации”. Разумеется, его стоит использовать и в необъектном коде, и для описания внутренних констант. Атрибуты, в свою очередь, описываются с помощью тега @var, который, аналогично параметрам, может содержать тип переменной и описание. Если указано описание, но опущен тег @var, переменной присваивается тип mixed. Поддержка PHP5 в PHPdoc была включена в версию 1.3.0. С её выходом теги @final и @abstract считаются устаревшими: эти данные теперь также собираются из кода программы. На момент написания стабильной версии этой ветки ещё не было: последним выпуском был RC3. Говоря именно о документировании ОО кода, стоит рассказать о так называемых шаблонах блоков документации. Во избежание дублирования описания атрибутов или методов (как правило, дублируется тег @access и @var для атрибутов), в PHPdoc был введён механизм авто-дублирования по шаблону. Стоит просто обозначит начало блока как: /**#@+ * @access private */
и конец как: /**#@-*/
Теперь все элементы, находящиеся между приведёнными блоками, будут дополнены тегом @access со значением private. /** * Foobarer * @uses Bar */ class Foo { /** * @var bool Marks if life’s good */ public $LifesGood = true; }
Методы описываются аналогично функциям.
17
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Технология и сообщество PHPdocumentor облегчает задачу восприятия кода. Восприятия авторами и потенциальными авторам, а также разработчиками расширений – людьми, которые будут использовать API. Нигде проблема восприятия кода большим количеством людей не стоит так остро, как в разработках с использованием идеологии Open Source. В частности, разработок, распространяющихся по идеологии GPL, в которых способность быстро понять как отрезок кода, так и отдалённо схему работы всей системы – одно из требований. Требований, которые часто незаслуженно остаются без внимания. Тем не менее, с развитием PHP PHPdoc стал стандартом дефакто. В настоящее время PHPdoc поддерживается как официальным IDE от Zend, так и большинством других редакторов. В большинстве крупных разработок (большинство из которых, к сожалению, типовые CMS) технология уже используется. Хорошим примером использования PHPdoc на передовой может служить TE Smarty. Говоря об Open Source, стоит упомянуть и PEAR. PHPdoc, будучи одним из его пакетов, стал официальным требованием к оформлению кода библиотек. Более того, PHPdoc включает в себя средства, разработанные специально для этого репозитория.
Элементы разработки пользовательской документации. Разбор полётов Стандарт PHPdoc включает в себя возможность написания так называемых учебных пособий (tutorials). Если исключая необходимость в сторонних документах, мы побеждаем лень и повышаем производительность, то мешая код (пусть и аккуратно) с документацией, не имеющей к нему самого прямого отношения, мы вносим путаницу. Для написания же полной документации стандартом является DocBook. Использовать стоит именно его. Решение существует. PHPdoc (с версии 1.2.0) умеет работать с DocBook, подставляя в цельную документацию мета-данные из кода приложения. Подобная тесная интеграция позволяет разделить документацию кода и собственно код с внутренней документацией, оставляя возможность первому черпать из последнего. Для реализации подобной схемы используются inline tags.
Пользовательская документация: DocBook. При написании электронных документов с целью распространения информации одна из проблем, с которой сталкиваются писатели, – совместимость. Совместимость форматов, в которых они пишут с потребительскими системами. Подобная проблема стоит при передаче любой информации, и выходы были давно найдены. Суть технологии; использование XML; стандарт де-юре Одним из них является формат XML. DocBook, в свою очередь, представляет собой DTD, укомплектованный для написания технического текста. Ничего более. Разумеется, существует готовый набор утилит для преобразования XML DocBook-кода в различные форматы, и это ещё более облегчает задачу.
18
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Всё, что требуется для работы с DocBook – это понимание SGML. Существенная разница между DocBook и, к примеру, RTF или PDF заключается в том, что в XML мы не форматируем текст. Мы лишь указываем, как данный фрагмент должен быть выделен. В последствие для каждого формата, который будет сгенерирован из исходного кода, данный фрагмент может быть выделен по-разному. Стандарт DocBook существует очень долгое время и успел стать де-юре стандартом для написания пользовательской документации, а также статей и даже книг. Издательство O’Reilly, к примеру, принимает материал от авторов только в этом формате.
Краткий обзор DTD Работая с DocBook, всегда надо помнить, что перед вами просто подмножество XML. Все требования к XML предъявляются и к документу DocBook. Соответственно, все документы DocBook объявляются как XML-документы следующим образом:
где DTD – описание формата DocBook, а – один из возможных корневых элементов, который чаще всего используется в документации. Полный пример типовой книги (из документации): My First Book JaneDoe 1998Jane Doe Foreword ... ... ... ... ... ... ...
Другим корневыми элементом может быть . Далее каждая глава делится на разделы: тег . N может заменяться на число от 1 до 5, характеризуя уровень вложенности. Альтернативой подобному написанию может служить рекурсивный тег , автоматически учитывающий уровень вложенности. После идут параграфы – тег . DocBook, кроме уже описанных, содержит огромное количество тегов, имеющих отношение к технической литературе. Предусмотрено если не всё, то большая часть. Список тегов рассматриваться не будет. Для быстрого введения стоит обратиться к [2.2], а в процессе написания под рукой всегда стоит держать [2.1].
19
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
XML vs. SGML DocBook, представляющий собой стандарт написания, позволяет работать не только с XML, но и с более общей надстройкой – с SGML. Концептуальная разница заключается только в требованиях, которые накладывают оба эти языка. Впрочем, и она не столь велика. В действительности практически единственной разницей является процесс обработки документов. Здесь при необходимости написания своих утилит генерирования приходится выбирать между DSSSL и XSLT. В остальном, стоит повториться, разница крайне незначительна.
Entities: ввод терминов и разбиение на документы Кроме всех плюсов, которые уже были описаны выше, XML приносит с собой возможность объявлять entities (нечто вроде переменных). Содержание документации в абсолютном большинстве случаев не может быть размещено в одном файле уже из эстетических соображений, не говоря уже о практических. Здесь entities также находят применение. Сущности в XML являются константами, доступными по &foo;. За примером использования сущностей в качестве терминов стоит обратиться к следующему разделу. Ниже приведён пример использования сущностей для разбиения документа на составляющие файлы: ]> My First Book &second_chapter; &second_chapter; &conclusion;
Примеры физического и гораздо более важного – логического разбиения – великолепно раскрыты во второй главе [2.1].
Формирование документов: DSSSL и XSLT Как уже было сказано выше, одной из серьёзных разниц между DocBook XML-DTD и SGML-версией является способ получения из исходного кода документов. Используются разные обработчики и технологии. DSSSL [2.4] (Document Style Semantics and Specification Language) представляет собой язык преобразования SGML, похожий на LISP. В большинстве дистрибутивов DSSSL-преобразователем является Jade. XSLT [2.5] (Extensible Stylesheet Language Transformation) является аналогичным преобразователем для XSLT.
20
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Учитывая популярность DocBook, не удивительно, что существует готовое открытое решение. [2.3] содержит шаблоны как для DSSSL, так и для XSLT. Стоит заметить, что шаблоны для DSSSL вполне подходят и для XML-версий, что является хорошим аргументом в пользу выбора именно XML-DTD для работы.
Соавторство; Связка DocBook и CVS на примере документации PHP XML – текстовый формат, что, в частности, облегчает совместную работу над документами, давая возможность использовать CVS (и подобные системы).
Краткое введение в CVS CVS [2.6] представляет собой систему контроля версий для ведения истории файлов, которая, кроме того, содержит в себе средства предусмотрения параллельной работы. Суть подхода сводится к содержанию в отдельной копии файлов (репозитории) всех версий diff от начального. Каждый разработчик, получая отдельную копию, проводит операции коммита (записи на сервер), в процессе чего система предупреждает коллизии при параллельном доступе. Кроме этого, как правило, настраивают систему оповещения по e-mail, содержащую diff коммита.
Использование GNU-Autotools, организация мультиязычности Повторяющееся действие построения документов различных форматов из исходного XML можно сравнить с компиляцией. Для автоматизации построения ПО в UNIX стандартным средством является набор GNU-Autotools, которые находят применение в документации PHP. Документация крупного Open-Source проекта обязана быть доступной для большинства потенциальных технических писателей, причём необходимо минимизировать количество возможных проблем и упростить вопрос сборки и проверки правки исходного кода, позволяя авторам заняться делом: написанием документации. В случае инсталляции ПО, где мы встречаемся с аналогичными требованиями, GNU-Autotools используются давно и успешно. Три действия установки ПО совершенно аналогичны и в генерации документа по DocBook: •
configure – проверяющий доступность XSLTproc (либо Jade / других процессоров) и консистенцию поставки, а также позволяющий выбрать необходимый язык в случае мультиязычности;
•
make test – проверяющий исходный код по DTD, исключая “физические” ошибки;
•
make format – генерация запрошенного формата: format. Именно таким образом устроен репозиторий документации
PHP. При конфигурировании проверяется наличие всех необходимых утилит и собираются данные о несуществующих в выбранном переводе разделах: все они будут подставлены из исходной английской версии.
21
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Каждый перевод находится в своей папке и фактически является своим репозиторием. Это позволяет переводчикам работать отдельно от авторов исходной документации: все проблемы согласования отсутствующих разделов, как было описано выше, возьмёт на себя Autoconf. По окончанию конфигурирования генерируется корневой файл manual.xml. Пример начала для русской версии: %language-defs; %language-snippets; &GettingStarted; &chapters.intro; &chapters.tutorial; &InstallAndConfigure; &install.intro; &install.unix.index;
22
PHP Inside №13
Две стороны документирования: PHPdocumentor и DocBook
Отдельные теги DocBook, вроде , обрабатываются с подставлением ссылок на соответствующую функцию, если она существует, шаблоны документации PHP тоже заслуживают пристального внимания.
Livedocs С ростом размера документации и, соответственно, с увеличением времени компиляции её в HTML (любой другой формат) острее становится необходимость раздельной компиляции. Чаще в голову начинают приходить мысли о чём-то, аналогичном линковке. В процессе появления таких нужд у группы документирования PHP была создана утилита Livedocs, позволяющая просматривать части DocBook-документации, не генерируя полных документов на лету. При начальной установке создаётся индекс конкретного языка, после чего можно обращаться к любой части. Livedocs выпускается по лицензии PHP 3.0, а значит, может быть переписан и может использоваться в своих разработках.
Литература 1.1 JavaDoc Tool Homepage, Sun MS. http://java.sun.com/products/jdk/javadoc/ 1.2 PHPDocumentor http://phpdoc.org/
Manual,
http://manual.phpdoc.org/
1.3 PEAR::PHPdoc http://pear.php.net/package/PHPDoc 1.4 Документирование кода, или как сделать разработку удобнее? А. Сидоренко (PHPinside #8, 11.04) 2.1 DocBook: The definitive guide, N. Wellsh, L. Muellner (O’Reilly, 1999-05): http://www.docbook.org/tdg/en/html/docbook.html 2.2 DocBook PHPc Tutorial, A. Wormus, B. Bezrukov http://boris.bezrukov.info/Other/PHPconf.ru_4/DocBook.Tutorial. html 2.3 DocBook demystification HOW-TO, E. Raymond http://en.tldp.org/HOWTO/DocBook-Demystification-HOWTO/ 2.4 Complete XML+XSL DocBook Guide, B. Stayton (2002-05) http://www.sagehill.net/docbookxsl/index.html 2.5 Livedocs repository, http://cvs.php.net/livedocs/
23
PHP Inside №13
Разработка современной CMS.
Разработка современной CMS. Преимущества, которые дает PHP5 при разработке таких систем CMS можно условно разбить на две части: шаблонизатор низкоуровневая система, обеспечивающая единую систему обработки шаблонов и сборки страниц из отдельных фрагментов, и собственно CMS, которая пользуется шаблонизатором, снабжая его данными для формирования страниц, а также реализует интерфейс для управления сайтом.
Шаблонизатор
Авторы: Константин Погорелов, веб-программист, компания "AWWSOFT" Дмитрий Магунов, руководитель проекта компания "AWWSOFT" г.Одесса, Украина
На данный момент в мире имеется широкий спектр различных обработчиков шаблонов для PHP (далее шаблонизатор). Наиболее развитые из них довольно далеко развили язык шаблонов, открыв большие возможности для разработчиков. Интересно, что многие пришли к похожей схеме работы. Возможности вставки глобальных переменных или элементов массива по ключу, тривиальны и есть почти в каждом обработчике. Затем многие поддерживают вставку в шаблон вызова функции PHP. Следующий шаг - введение модификаторов и арифметических операций - упрощенный интерфейс вместо функций. И в конечном итоге, шаблонизатор дает доступ также к объектам, их полям и методам. В результате язык шаблонов превращается в дополнительный язык программирования, надстроенный над PHP. Примером такого средства может послужить Smarty. Здесь предлагается иная концепция шаблонизатора, не уступающая по возможностям описанной выше модели. В основу положена следующая идея: язык шаблонов - язык для доступа к данным и вывода их в некотором текстовом формате (HTML), а другие функции он выполнять не должен. Поэтому способ представления данных в программе должен быть скрыт от шаблонизатора, т.е. не имеет значения, хранится ли текст в поле объекта, в элементе массива или просто в глобальной переменной. Для этого создается виртуальное пространство переменных шаблонизатора, которое в реальности ссылается на необходимые источники данных. Само это пространство переменных представлено в виде дерева файловой системы системы UNIX. Вот примеры имен переменных: /var/group/petrov/math/mark /etc/tables/max_rows /usr/site1/templates/right_row
24
PHP Inside №13
Преимущества, которые дает PHP5 при разработке таких систем
В рамках проекта можно самостоятельно настроить, какие ветки на что будут ссылаться. Можно сказать, что системы доступа к данным "монтируются" в дерево данных. (Причем, монтировать можно в любую точку системы, а не только в корневую). В процессе программирования можно даже изменить представление переменных, однако шаблоны при этом останутся прежними. Кроме того, данный механизм позволяет тестировать шаблоны и дизайн, когда еще нет самой программы, т.к. все данные легко имитировать, например, в виде файлов. Функции также представляют собой особые точки в этом дереве. Например: /etc/current_date может быть настроена на самом деле не как переменная, а как функция, которая отрабатывает только в случае, если шаблонизатор встретил ее вызов. Уйти от модификаторов, пожалуй, невозможно. Особенно это важно во фрагментах подобно следующему: leftOuter для оператора LEFT JOIN и проверку IfNull, но, как мы видим, удовлетворительного решения, учитывающего особенности каждой СУБД, найти нельзя. В зависимости от начальной СУБД выбирается либо 1. Сделать LEFT JOIN, как в MySQL, хотя решение для MSSQL не лучшее. 2. Эмулировать подзапрос через IN(), пользуясь схемой MSSQL, хотя для MySQL есть своё эффективное решение.
Обычно
switch ($db->databaseType) { case 'mysql': $sql =$mysql_query; break; case 'mssql’: $sql = $mssql_query; break; default: die(‘Unsupported DB type’); } $db-> Execute($sql) $mysql_query и $mssql_query см. выше
Библиотеки абстрактного доступа не решают проблем поддержки нескольких СУБД. Неизбежно приходится сталкиваться с задачами, которые нельзя решить путём транслирования запроса Мета-СУБД в запрос конкретной СУБД. Тогда появляются “решения” через switch, case. Добавив ещё одну СУБД, мы получим блок switch … case, состоящий уже из 3-х пунктов. Это придётся делать в каждом месте, где пасует библиотека абстрактного доступа. Код приобретает множество конструкций вида: switch ($db->databaseType) { case '': {
Вынесем все разные операции в разные классы и дадим им одно имя switch ($db->databaseType) { case 'mysql': { $Handler = &new MySQLHandler($db); $results = $Handler -> do_operation($param1, $param2, $param3) } case 'mssql': { $Handler = &new MSSQLHandler($db); $results = $Handler -> do_operation($param1, $param2, $param3) } … default: die(‘Unsupported DB type’); } return ($results);
Вынесем повторяющиеся строки из switch case: switch ($db->databaseType) { case 'mysql': { $Handler = &new MySQLHandler($db); } case 'mssql': { $Handler = &new MSSQLHandler($db); }… default: die(‘Unsupported DB type’); } $results = $Hanlder-> do_operation($param1, $params2, $param3);
Т.к. данная конструкция встречается в нескольких местах, вынесем её в метод отдельного класса. function &create_handler($type) { switch ($type) { case 'mysql': { return new MySQLHandler($this-> db); } case 'mssql': { return new MSSQLHandler($this-> db); } …
Так как $db у нас уже имеется и так в классе Factory, то function &create_handler() { switch ($db->databaseType) { … } $Factory = new DBHandlerFactory($db); $Handler = &$Factory-> create_handler(); $results = $Hanlder-> do_operation($param1, $params2, $param3); $Factory = new DBHandlerFactory($db); $Handler = &$Factory-> get_db_handler(); $results = $Hanlder-> do_operation($param1, $params2, $param3);
Дизайн кода существенно упростился, разница в реализации инкапсулирована в классы «Операции с СУБД». Недостатки: при изменении требований к какой-либо функциональности можно изменить реализацию для одной СУБД и забыть сделать изменения для другой. При наличии 20-30 подобных конструкций/операций это выливается в (20-30)*N проверок и изменений. Но, по крайней мере, мы имеем решение, которое выглядит достаточно удобным для того, чтобы базировать на нём методику перевода проекта на поддержку нескольких СУБД. №
Шаг
Описание
1 Выделение операции
Прикидываем, какие выходными данными
параметры
являются
входными
и
2 Написание теста
Тестов не бывает много. Лучше иметь мало тестов, чем не иметь их вовсе
3 Вынесение операции
Переносим участок кода в метод класса и заменяем его (участок кода) вызовом метода
4 Тестирование
В процессе вынесения операции мы тестируем создаваемый метод. После замены тестируем клиентскую функциональность
Пункты 1-4 повторяются, пока все запросы и/или вызовы конструкторов запросов ADODB или PEAR::DB не будут вынесены в методы класса. 5 Рефакторинг
После того, как все операции вынесены в отдельный класс, производим рефакторинг. Устраняем дублирующийся код, разделяем классы, и т.д.
6 Создание копии
По технологии Cut&Paste создаём копию всех полученных в результате шагов 1-5 классов и меняем их названия. Создаём параллельный вызов тестов
100
PHP Inside №13
№
Поддержка нескольких СУБД в проекте
Шаг
Описание
7 Коррекция
Тесты показывают места, где необходимо внести изменения. Корректируем классы, всю подсистему общения с СУБД
8 Вынесение общих операций
Избавляемся от дублированного кода, выносим все общие операции в классы-предки
9 Рефакторинг тестов
Учитываем вновь появившиеся абстрактные классы
Выделение операции Под операцией подразумеваем логичную и обособленную последовательность действий. •
Выборка для формирования отчёта.
•
Внесение записи.
•
Изменение баланса на счету.
•
…
Если в проекте использованы транзакции, то можно ориентироваться на них. Или другой подход – ориентироваться на SQL-запросы и вызовы методов, которые конструируют запросы в библиотеке абстрактного доступа. Поиск мест, содержащий операции по работе с СУБД, может быть просто автоматизирован.
Написание теста Тест пишется для проверки клиентской функциональности, с одной стороны, и для создаваемой операции – с другой. Клиентской функциональностью является участок кода, содержащий выделенную операцию. Обычно достаточно написать один-два теста, которые доказывают, что всё работает хорошо. Это нужно сделать, чтобы не делать этого впоследствии вручную. Для вновь создаваемого метода тоже должны быть разработаны тесты. Это, с одной стороны, позволит разработать интерфейс обмена клиентской части с вновь создаваемым методом – параметры, ожидаемые значения, а с другой, позволит в дальнейшем проверить работу метода для другой СУБД. Написание теста экономит время на проверках, т.к. автоматизирует их. Также существенно уменьшает вероятность возникновения ошибок.
Вынесение операции Тут всё просто – копируем уже имеющуюся реализацию в метод класса. После копирования добиваемся срабатывания тестов. Тесты на метод можно написать и после переноса, но на клиентскую часть должны быть написаны до этого. После этого участок кода заменяем на вызов метода с параметрами. Все тесты должны после этого срабатывать. 101
PHP Inside №13
Поддержка нескольких СУБД в проекте
Рефакторинг После вынесения всех операций в отдельный класс можно заняться поиском дублирующихся частей. Весь код для работы с БД теперь находится в одном классе, а не разнесён по всему проекту. На данном этапе основная задача – убрать основные видимые дублирования и разнести операции по отдельным классам, которые отвечают за определённый набор функциональности. К примеру, управление записями клиентов – в один класс, а управление каталогом товаров – в другой. Также придётся изменить тесты классов для операций с БД. Заметим, что тесты клиентской функциональности менять скорее всего не придётся.
Создание копии Создаём копии всех получившихся классов. Меняем имена. К примеру, DBMySQLClients -> DBMSSQLClients Также нужно создать удобный путь для запуска тестов. Т.е., чтобы тестируемые классы можно было легко подменить. Для этого мы используем класс-фабрику: $DBFactory-> set_type(‘mysql’); $DBFactory-> get_clients(); Таким образом, мы легко получаем тесты для новой СУБД. В то же время получаем объект-фабрику, которую затем используем в проекте.
Коррекция Запускаем тесты и сразу же видим, где и что перестаёт срабатывать. Внесение изменений занимает минимум времени. Корректируем, смотрим на увеличивающуюся зелёную полоску тестов, радуемся. Во время этой стадии необходимо дописать все недостающие тесты клиентской функциональности. Т.е. на всё то, что начинает проверяться вручную «по-быстрому», нужно создать тесты. Тесты мы создадим один раз, а пользоваться потом будем очень долго.
Вынесение общих операций Теперь, после того, как весь код работает, можно действительно увидеть общие части, одинаковые для обеих СУБД. К серьёзным изменениям в коде это не приведет, т.к. нас защищает класс-фабрика. В целом достаточно будет: •
создать класс предок;
•
сделать имеющиеся 2 класса его потомками;
•
вынести все полностью одинаковые методы в класс-предок.
102
PHP Inside №13
Поддержка нескольких СУБД в проекте
Их мы выносим в класс-предок. Класс-фабрика будет возвращать во всех случаях экземпляр одного класса.
Рефакторинг тестов Создаём тесты для вновь появившихся классов. Переносим тесты методов и тестов для потомков в тесты для предков. Трудозатраты на добавление ещё одной СУБД будут минимальными, т.к. мы имеем •
Тесты для клиентской части;
•
Систему доступа к СУБД, учитывающую особенности каждой из СУБД;
•
Тесты на общие части и на особенности.
Чтобы добавить ещё одну СУБД, нужно будет произвести операции 5-9, в то время как объёмная, рутинная и «опасная» работа 1-4 в повторении не нуждается. В целом применение методики повлияет благотворно на дизайн кода проекта, позволит получить выгоды от наличия тестов (то, что вы никогда не решались сделать, но всегда хотели иметь) и увидеть новые перспективы улучшения кода.
103
PHP Inside №13
PHP::SOAP и Xforms
PHP::SOAP и Xforms Внедрение современных открытых стандартов на ОАО «АВАвтор: Анохин Александр, ТОВАЗ» начальник бюро экспертизы интернет-проектов ОАО «АВТОВАЗ» Соавторы: Булов Владимир Данный доклад подготовлен на основе опыта разработки Геннадьевич, начальник ряда модулей информационных систем ОАО «АВТОВАЗ» с исполь- центра развития зованием веб-служб (в реализации PHP5) и XForms (x-port информационных технологий FormsPlayer) и представляет собой краткое введение в данную тех- ОАО «АВТОВАЗ», Литвинов нологию. Кирилл Анатольевич, Предполагается, что аудитория знакома с базовыми XML- инженер-программист ОАО технологиями, такими как XML Namespaces, XPath. Акцент доволь- «АВТОВАЗ»
Введение
но сильно смещен автором в сторону XForms, поскольку литературы и онлайн-публикаций, посвященных SOA и веб-службам, накопилось уже достаточное количество, а в отношении XForms еще наблюдается некоторый дефицит информации на русском языке.
Предпосылки перехода на веб-службы и SOA Исторически ОАО “АВТОВАЗ” разрабатывает и внедряет информационные системы (ИС) для автоматизации своих бизнеспроцессов самостоятельно силами IT-подразделений, входящих в структуру предприятия. При постепенном развитии существующих и внедрении новых систем, ориентированных на веб, неизбежно возникает потребность в организации взаимодействия. Вопрос осложняется тем, что, хотя на данный момент основной связкой при построении систем является Intel-Linux-Apache-PHP-Oracle, все же стек языков и технологий, используемых (или использовавшихся) для построения приложений на предприятии чрезвычайно широк (ASP, Perl, Cobol, Delphi, C++, FoxPro,...). До недавнего времени решение было в организации обмена на уровне данных. Поскольку в качестве RDBMS преимущественно применялись продукты Oracle, то при необходимости доступа к данным соседней ИС требовалась организация db_link'а к удаленной БД, либо периодическая синхронизация хранилищ. Но, естественно, что доступность хранилища системы и доступность результатов ее работы – это совершенно разные вещи, и зачастую разработчикам одной ИС при такой “интеграции” требовалось заново реализовывать функциональность сторонней системы по работе с данными (вникать в структуру таблиц, повторять алгоритмы обработки данных), т.е., фактически делать частичный реинжиниринг. При появлении все большего количества систем, нуждающихся в одних и тех же данных (в основном нормативно-справочного характера – НСИ), решение с копированием порождало проблему поддержания актуальности в реальном времени, а организация большого количества db_link'ов отрицательно сказывалось на производительности сервера-хранилища НСИ.
104
PHP Inside №13
PHP::SOAP и Xforms
Проанализировав методы решения подобных проблем другими производителями ПО, подразделение ОАО “АВТОВАЗ”, отвечающее за стандартизацию веб-разработок, обращает внимание на стек спецификаций Web Services Activity от W3C. К тому же данные технологии уже довольно активно используются такими крупными вендорами, как, например, IBM, Oracle и Microsoft, и, следовательно, последующую интеграцию собственных разработок с готовыми покупными решениями, возможно, будет провести с минимальными финансовыми затратами. Таким образом, было принято решение о развитии направления развертывания веб-служб как основы для внутрикорпоративной информационной архитектуры. Появление в PHP5 расширения для обработки SOAP-сообщений кажется нам существенным шагом в развитии языка. К тому же появилась возможность, не переучивая разработчиков, разрабатывать интерфейсы систем в новом формате. Веб-службы, изначально являющиеся надстройками над основной бизнес-логикой систем, существенно облегчают машинное взаимодействие. Протокол SOAP (с помощью которого происходит общение) позволяет осуществлять взаимодействие с высоким уровнем абстракции в гетерогенных системах. Но, в отличие от «стандартных» веб-приложений, понимающих обычные POST- и GET-запросы, приходящие прямо от браузеров пользователей (в виде данных веб-форм, либо гиперссылок), бизнес-функция информационной системы оформленная в виде вебслужбы лишена такой возможности, поскольку в качестве входных и выходных сообщений в SOAP-запросах используются XML-документы. Поэтому общение конечного пользователя с таким приложением может осуществляться только через промежуточный модуль, осуществляющий трансформацию данных, пришедших, например, из формы в SOAP-сообщение и обратно. Технология XForms, предлагаемая в качестве рекомендации W3C, является новым поколением веб-форм и является одним из модулей XHTML – более строгого и гибкого приемника HTML. Одно из основных преимуществ Xorms – в том, что Xforms-клиент отправляет и получает данные как XML-документы. Эта функциональность исключительно полезна в связке с вебслужбами, где, как было отмечено выше, в качестве сообщений также используется XML. Таким образом можно исключить промежуточный модуль преобразования запросов, поскольку XForms-браузер уже является клиентом, способным общаться с веб-службой напрямую.
105
PHP Inside №13
PHP::SOAP и Xforms
Рис. Применение технологии XForms в схеме взаимодействия с веб-службами. Поставщик веб-службы (ИС1), предоставляя веб-сервис, опубликовывает его описание в виде WSDL-файла. Все потребители веб-службы могут получить данное описание, отправив GET-запрос. Целевой URL для подачи запроса может быть получен потребителем либо из реестра сервисов UDDI (для этого поставщик должен сначала зарегистрировать свой сервис в реестре), либо по прямой ссылке, предоставленной, скажем, службой поддержки системы-поставщика. SOAP-процессор способен преобразовывать сообщения из формата XML(SOAP) в объекты языка, поэтому разработчикам системы-потребителя (ИС2) нет необходимости знать правила преобразования данных в SOAP-сообщения и обратно и даже термин «XML» в целом (но, как правило, это не так). Основная особенность при взаимодействии в веб-службами с помощью XForms – это то, что в этом случае XML-документы отправляются «as is». XForms-процессор не умеет читать WSDLописание и формировать SOAP-конверты автоматически, поэтому автору формы необходимо самостоятельно составлять запросы и разбирать ответы веб-служб, что на самом деле не такая сложная задача, как будет показано далее на примере. Единственное, что XForms может «позаимствовать» у WSDL-описания, это типы данных входных и выходных сообщений веб-службы для валидации, а это не так мало.
106
PHP Inside №13
PHP::SOAP и Xforms
Но рассмотрим все по порядку. Формы – это важный механизм сбора информации. Поэтому онлайновые формы - основная часть, составляющая электронный бизнес и предоставление онлайн сервисов. Наиболее широко используемая технология веб-форм на сегодня – HTML-формы. Однако HTML-формы очень просты и не удовлетворяют всех потребностей, возникающих у авторов онлайн форм.
HTML-формы Преимущества HTML-форм: •
Малое время доставки данных и ответа через Интернет;
•
Легкость внесения изменений в содержание или макет формы;
•
Отсутствие необходимости повторно набирать данные формы;
•
Не требуется установка проприетарного ПО для поддержки форм, поскольку стандарт HTML очень широко поддерживается;
Легкость конструирования элементов формы внутри HTMLдокумента, используя стандартный набор тегов элементов управления.
Ограничения HTML-форм: •
Элемент управления формы может иметь лишь заранее заданное или введенное значение, из чего вытекает следующее:
- Отсутствие доступа к значениям элементов формы (такой, как чтение и запись, например), кроме отправки всей формы по назначенному адресу. - Проверка данных невозможна. - Вычисляемые результаты не могу быть сгенерированы формой. - Заранее заданные значения должны быть жестко прописаны в HTML-документе. •
Форма строго привязана к HTML-странице.
- Сложно повторно использовать форму на различных устройствах (иногда даже на различных веб-браузерах). - Содержание формы зависит от представления и макета страницы. •
Очень простая модель данных (параметр-значение). - Нет поддержки структурированных данных. - Маппинг из и в XML и системы может быть достаточно сло-
жен. Для преодоления этих ограничений в HTML-формах, применяются различные техники. Большинство подходов делятся на две группы: скриптинг на стороне клиента и серверные решения.
107
PHP Inside №13
PHP::SOAP и Xforms
Скриптинг на стороне клиента Со временем веб-браузеры обзавелись поддержкой скриптинга, используя такие языки, как JavaScript или VBScript. При таком подходе возможно включать функции языка непосредственно в HTML-страницу. Внедренный код будет работать в веб-браузере и с помощью интегрированной системы событий взаимодействовать с элементами управления форм. Это решение «в лоб» позволяет, однако, изменять значения, вычислять математические функции или режим представления элементов формы. Применение скриптинга не ограничивается только формами – можно менять структуру всего HTML-документа через его объектную модель (DOM: Document Object Model). Скриптинг расширяет функциональность и увеличивает способность документа взаимодействовать с пользователем, что делает его одним из самых часто используемых решений.
Преимущества скриптинга на стороне клиента: •
Повышает уровень взаимодействия между пользователем, формой и веб-браузером;
•
Пользователь и браузер порождают события, которые могут быть отслежены и обработаны;
•
Дает возможность проверки данных «на-лету»;
•
Возможность менять значения элементов формы извне.
Ограничения: •
Сложность HTML-форм многократно увеличивается;
•
Поддерживать HTML-документ становится сложнее;
•
Ограниченная переносимость, обусловленная различиями браузеров в части поддержки скриптовых языков;
•
Возможность выполнения встроенных программ может быть отключена пользователем;
•
Все-таки ограниченная функциональность (отсутствует, например, возможность сохранения данных на диск).
Решения на стороне сервера Другой путь преодоления ограничений HTML-форм – в использовании серверных приложений. Существует большое количество технологий, которые могут быть использованы: PHP, ASP, JSP, CGI… Эти приложения конструируют стандартные HTML-формы «на-лету». Они могут динамически формировать содержание, исходя из данных, полученных от пользователя (например, из предыдущей формы). Преимущества server-side решений: •
Способность динамической генерации HTML-документов.
•
Валидация пользовательских данных на сервере.
108
PHP Inside №13 •
PHP::SOAP и Xforms
Обработчиком данных формы может быть система управления или СУБД.
Ограничения: •
Пользователь должен быть онлайн. Реализация локальной формы невозможна.
•
Избыточное количество запросов на сервер, например, для валидации, данные сначала должны быть переданы на сервер.
•
Большие задержки, т.е. время задержки, зависящее от соединения и способностей сервера.
•
Повышенные требования к аппаратному обеспечению сервера.
•
Удар по производительности сервера.
Комбинация обоих решений Третий путь расширения способностей HTML-форм – в использовании комбинации серверных и клиентских техник. Хотя это не исключает вышеописанных помех серверных решений, но позволяет дополнительно расширить функциональность за счет скриптинга.
Проприетарные технологии и средства HTML-формы – не единственный способ представления формы в веб. Существует минимум еще две основных компании, которые предлагают свои средства разработки форм: •
Семейство продуктов Acrobat от Adobe – это широко используемая технология создания и обработки форм. Acrobat-форма сохраняется в файле формата PDF (Portable Document Format). Пользователь может загрузить такой файл, заполнить форму и отправить назад на сервер. В последних версиях Acrobat позволяет формировать данные формы как XML-структуры.
•
Майкрософт (Microsoft) выпустила новый продукт, названный InfoPath, который поставляется с новой версией офисного пакета Microsoft Office 2003. Он содержит средства для визуального создания форм, основанных на XML, которые могут быть опубликованы для просмотра веб-браузером.
Обзор преимущества Xforms Стандарт XForms адресован устранить недостатки серверных и клиентских решений, описанных выше. Он позволяет создавать динамичные и функциональные формы с использованием открытых стандартов, которые легко реализовать и поддерживать. XForms базируются на XML, что обеспечивает бесшовную интеграцию в другие XML-стандарты. Этот раздел описывает ключевые преимущества этого стандарта. •
Открытый и непроприетарный стандарт (стандартизован W3C):
109
PHP Inside №13
PHP::SOAP и Xforms
- Интероперабельности способствует тот факт, что основные вендоры участвуют в процессе на базе взаимного согласия. •
Полностью описывается с помощью XML:
- Природа Xforms позволяет использование расширяемого и ясного синтаксиса XML. Слияние со смежными технологиями, такими как XHTML, XPath или XML-Events, совершенно прозрачно; •
Разделяет содержание, называемое Моделью (XForms Model), пользовательские (входные и выходные) данные, называемые Экземплярами данных (Instanse data) и уровень представления, называемый Интерфейс пользователя (Xforms UI). - Модель содержит:
* XML-описание структуры, содержащей данные, управляемые элементами управления формы; * Инструкции отправки данных для взаимодействия с приложениями; * Функциональные компоненты, которые могут проверять данные, манипулировать ими и влиять на поведение формы в целом; - Элементы управления (XForms Controls) предназначены для отображения конечному пользователю; •
Модель XForms может быть многократно использована с различными вариантами пользовательских интерфейсов и устройств.
- Благодаря слабой связанности Модели и Пользовательского интерфейса, можно получить одинаковое поведение формы в различных средах отображения (например, в XHTML или SVG); •
Встроенная возможность валидации данных, использующая типизацию WXS и дополнительные условия пользователя (включая условные зависимости), сокращает потребность в скриптинге и дополнительных серверных компонентах;
- XForms может использовать Xpath для манипуляции булевыми, строковыми или числовыми значениями; •
Расширенный обмен информацией между клиентом (веб-браузером) и сервером.
- XForms определяет Протоколы передачи (Submission Protocols), которые позволяют клиенту отправлять и принимать экземпляры данных в фоновом режиме без перезагрузки всей формы. Для примера, возможна смена элементов выпадающего списка без перезагрузки всей страницы. •
Поддержка режима взаимодействия оффлайн;
•
Данные хранятся в XML-структуре: - Легко интегрируются с приложениями, поддерживающими
XML; - Данными можно обмениваться с другими non-XForms системами, например, Acrobat forms; •
- Элементы управления формы содержат встроенные метаданные, которые можно использовать для устройств с ограниченными характеристиками (голосовые и брайль-браузеры);
Техническое описание Xforms Как говорится в спецификации XForms: «XForms – это XML-приложение, которое представляет следующее поколение форм для веб. Разделяя традиционные формы HTML на три части: Модель, Экземпляры данных и Пользовательский интерфейс, – позволяет отделять контент от представления, повышает повторную используемость кода, дает строгую типизацию, сокращает количество обращений к серверу, снижает надобность в скриптинге и делает формы независимыми от устройств отображения».
Общие положения Для создания формы в HTML странице, стандарт HTML описывает синтаксис элементов формы, одновременно определяя внешний вид, т.е. в форме HTML это одновременно и структура данных, и слой пользовательского интерфейса с такими элементами, как таблицы, параграфы или переносы строк. В отличие от HTML, XForms – не одиночная технология, а базирующаяся на других (базовых) технологиях разметки, например, XHTML или SVG. Эти базовые технологии (или любая другая XML-технология) формируют базу для документа XForms. Благодаря XML-природе, они могут реализовать и использовать синтаксис, определенный в стандарте XForms. Для того, чтобы создать форму XForms, можно использовать в качестве базового, например, XHTML-документ, и определить пользовательский интерфейс путем встраивания элементов управления XForms в XHTML . Каждый используемый элемент управления может ссылаться на т.н. экземпляр данных, который является аккумулятором XMLэлементов. Элементы в экземпляре данных могут быть использованы для хранения как значений элементов управления, так и предопределенных заранее значений, например, для выпадающих списков либо результатов вычислений. Эта ссылка на элементе управления – всего лишь связь между пользовательским интерфейсом и контентом формы. В зависимости от конкретного назначения элемента управления он может отображать значение по ссылке и/или изменять его. Внешний вид элементов формы зависит от базовой (хост) разметки и XForms-процессора, который используется для отображения XForms-документа. XForms-процессор – это программа, понимающая синтаксис XForms и базовой разметки, которую он использует для отображения формы пользователю, т.е. соответственно клиентское ПО, веб-браузер, например.
111
PHP Inside №13
PHP::SOAP и Xforms
Экземпляр данных (instance elements) – это часть контента и функционального слоя Xforms-документа, также называемая Модель. Помимо экземпляров данных, Модель определяет характеристики и требования к элементам этих данных, т.е. типы, необходимость присутствия или диапазон значений. Все это описывается с помощью т.н. «привязок» (bind elements). Они также могут содержать инструкции вычисления выражений или определения отношений между двумя или более элементами экземпляра данных, т.е. назначения зависимостей. Для примера, элемент, хранящий номер кредитной карты только тогда требует значение, если другой элемент, определяющий тип оплаты, установлен в «credit card». Другая часть Модели XForms – элементы отправки данных (submission elements), которые определяют, данные какого экземпляра и куда отправляются, например, локальный файл на диске, веб-сервер или приложение. В зависимости от выбранного протокола, элемент отправки данных также может быть настроен на прием данных для экземпляра. Отправка может активироваться либо действиями пользователя, либо другими событиями, происходящими в фоном режиме (в момент, когда вводятся данные, например). Элементы отправки очень гибки и определяют взаимодействие между самой формой и ее окружением. XForms-модель также может также содержать элементы действий (action elements), которые способны отслеживать события, порождаемые пользователем, элементами управления, XForms-процессором или агентом, и обрабатывать их определенным образом. Например, если пользователь закрывает приложение, которое обслуживает форму, возникнет событие, которое может породить процесс сохранения введенных данных на диск перед закрытием, и в следующий раз, когда пользователь снова откроет документ с формой, другой обработчик событий загрузит сохраненные перед этим данные, тем самым восстановив состояние на момент закрытия.
Разделение контента и представления Для разделения содержания и представления стандарт XForms описывает 3 логические части: Модель, Экзепляр данных и Элементы управления. В следующих разделах поясняется, что они собой представляют и как взаимодействуют. Для описания всех частей используется синтаксис XML.
Модель Xforms Модель определяет функциональную часть формы, т.е. как форма будет себя вести и взаимодействовать с пользователем, описывается контейнером , который в свою очередь содержит различные вложенные элементы, такие как:
Instance Этот элемент ссылается на документ Экземпляра данных, как показано на листинге 2, или непосредственно содержит его XMLструктуру. Модель может содержать несколько элементов , каждому из которых присваивается уникальный ID.
112
PHP Inside №13
PHP::SOAP и Xforms
Bind Элементы создают связь между элементами экземпляров данных и функциями или событиями. Они также могут контролировать поведение формы путем определения требований для значений. Выражения привязки могут использовать предопределенные атрибуты и функции XForms, а также и другие XML-технологии, например, XPath или XML-events. XPath, кроме всего прочего, содержит функции, позволяющие манипулировать со строками, булевыми и числовыми значениями. События XML (XML-events) используются для доступа к информации о воздействиях пользователя на объектную модель документа (DOM), например, события мыши или клавиатуры.
Submission Элемент определяет, как форма взаимодействует с окружением. Целью может быть удаленная система, локальный файл или что-либо другое. В XForms описываются протоколы коммуникаций, которые позволяют обмениваться XML-данными; только экземпляры данных XForms могут использоваться для обмена. Элемент уточняет, какая часть экземпляра данных будет отправлена или получена. Модель XForms может содержать несколько элементов отправки данных, которые могут быть активированы множеством событий, например, когда пользователь нажал кнопку «отправить», или если форма уничтожается закрытием веббраузера.
Action. Элементы используются для перехвата событий и определения действий по их обработке. Они размещаются внутри элементов управления формы, отправки данных и элементов модели XForms. В последнем случае они применяются для обработки событий модели (примеры таких событий: "xforms-model-initialize", "xforms-model-destruct" и "xforms-reset"). Пример. Вышеописанные элементы могут быть оценены в листинге 1 с комментариями: •
элемент содержит атрибут, указывающий на XML Schema для экземпляра данных.
•
элемент ссылается на XML-документ, содержащий данные (приведен в листинге 2).
•
элемент назначен на элемент экземпляра данных "/data/sum/". Он (bind) вычисляет произведение значений элементов "/data/amount" и "/data/price/" и помещает результат в элемент "/data/sum".
•
элемент определяет, какой экземпляр данных будет отправлен на приложение "order.php", используя протокол POST.
113
PHP Inside №13 •
PHP::SOAP и Xforms
элемент перехватывает событие "xforms-model-destruct", которое возникает, если модель уничтожается, закрытием веббраузера, например. Вложенный элемент активизирует отправку данных, описанную в элементе с id="submit_1".
Пример Модели Xforms
Экземпляр данных Т.н. Экземпляр данных – это XML-структура, содержащая текущие значения элементов управления формы. Она также может описывать элементы, которые будут содержать вычисляемые или временные значения в процессе работы с формой. Как видно из листинга 2, экземпляр данных – это обыкновенный XML-документ. Для придания данным большей осмысленности можно использовать описание XML Schema, которое определяет природу отдельных элементов экземпляра данных, т.е. какой тип значения элемент может содержать (integer, string, date, и т.п.). Эта информация далее может использоваться для валидации данных, введенных пользователем.
XML-документ экземпляра данных Для использования экземпляра данных как хранилища значений элементов управления последние должны содержать ссылку на соответствующий элемент экземпляра данных. В листинге 3 элементы и содержат атрибут “ref”, предназначенный именно для этой цели, и в данном случае целью служит элемент "/data/amount". Значения, вводимые в поле ввода (), сохраняются в этом элементе и одновременно отображаются в поле вывода ().
114
PHP Inside №13
PHP::SOAP и Xforms
Элементы управления формы Спецификация XForms описывает набор элементов управления для построения пользовательского интерфейса формы. Примерами таких элементов служат поля ввода (input fields), поля вывода (output fields), кнопки (buttons) и опции (options). Для отображения элементов управления поддержка XForms может быть реализована в других XML-технологиях, которые нацелены на отображение документов (примерами такой базовой разметки могут служить XHTML или SVG). Следующий код показывает использование элементов XForms в XHTML-документе. Веб-браузер, поддерживающий XForms, отобразить элемент "" как поле для ввода, а на месте "" будет лишь значение.
Enter a number:
You entered:
Элементы управления XForms внутри XHTML-документа.
Полноценный XForms-документ. Три логические части: Модель, Экземпляр данных, Пользовательский интерфейс отделяют содержание от представления формы. Этот раздел объясняет, как эти три части работают вместе и образуют функциональную форму.
Изображение отношений в XForms-документе.
115
PHP Inside №13
PHP::SOAP и Xforms
Существующие средства Приложения, которые поддерживают XForms, становятся все более доступными. С тех пор, как спецификация стала официальной рекомендацией, это развитие заметно ускорилось. На данный момент можно разделить все их множество на процессоры и редакторы.
XForms процессоры Приложения, которые могут обрабатывать модель Xforms. Элементы управления представляются, используя соответствующую технологию отображения. Далее пользователь способен вводить информацию и отправить форму. В свою очередь процессоры могут быть нескольких различных типов: •
Клиентские приложения – полностью автономные, устанавливаются на стороне клиента. Фактически это веб-браузеры, обладающие полноценной поддержкой XForms на уровне ядра. К примеру, XSmiles или Nowell Technology Preview.
•
Плагины веб-браузеров. С минимальным процессом установки на клиенте плагин может обрабатывать Xforms посредством обычного веб-браузера, такого как Internet Explorer6.0. FormsPlayer, Xero или плагин IBM’s XML Forms Package – процессоры, работающие только на IE6.0. Более общий подход используется DENG-процессор, реализованный на Flash-технологии, и следовательно, может быть использован везде, где установлен Flash-плеер.
•
Серверные решения. Эти приложения обрабатывают XForms-документы на стороне сервера и предоставляют стандартный HTML+Javascript код, который может быть обработан любым обычным веб-браузером. Примерами могут служить IBM XML Forms Package, FormFaces.
Все три способа обработки Xforms-документов изображены ниже. Единственное, что хочется отметить, что сам документ составляется однажды независимо от выбранного подхода в обработке.
Различные типы приложений, поддерживающие XForms.
116
PHP Inside №13
PHP::SOAP и Xforms
Средства разработки Несмотря на то, что формат XForms-документа подчиняется синтаксису XML, создание полноценной формы может быть неэффективно в текстовом редакторе. На данный момент представлено не так много средств разработки, ниже перечислены основные из них: •
Xero – плагин к веб-браузеру, является частью «Web form development framework», где имеется также встроенный редактор.
•
Еще одно средство от компании «HoT Training and Consultancy Ltd».
•
В OpenOffice2.0 имеется возможность составлять документы XMLForm, используются стандартные теги XForms для разметки модели, но собственные для элементов интерфейса.
•
XFormation – коммерческая IDE от создателей FormsPlayer.
•
XML-редакторы общего назначения, но достаточно мощные, чтобы облегчить создание – XMLSpy и StylusStudio. Пример поисковой формы.
После освещения материальной части рассмотрим конкретный пример построения простейшей формы для работы с веб-службой поиска данных пользователя по имени.
Веб-служба Основной задачей нашей службы является трансляция сообщений клиента в DML-запросы хранилища. Бессмысленно описывать алгоритмы методов самого php-класса на который будут проецироваться операции веб-службы – они элементарны, поэтому ограничимся только описанием входного и выходного сообщений, которые будут приведены далее в примерах.
Форма Начнем с создания простейшей формы. Форма состоит из Модели и Пользовательского интерфейса. В простейшем случае Модель содержит Экземпляры данных и элементы для их отправки . Пример 1
117
PHP Inside №13
PHP::SOAP и Xforms
плагин FormsPlayer (http://www.formsplayer.com) не загружен (работает только с I E6.0_SP1+)
Встраивание Модели XForms в хост-документ.
В данном случае в качестве базового используется XHTMLдокумент. Декларируем пространства имен словарей, используемых в данном файле. Вторым этапом сообщаем Internet Explorer о необходимости загрузить объект FormsPlayer, в случае неудачи пользователю будет выведено содержимое элемента . Инструкция обработки (PI) также необходима для указания префикса, используемого элементами XForms. Далее мы описываем элементы и в Модели нашей формы. Здесь экземпляр данных “message” – это не только данные для отображения пользователю, но и для отправки на сервер, а так как принимающей стороной является веб-служба, то в этом экземпляре содержится точная копия ее входного SOAP-сообщения (которое после передачи данных заменится на ответ службы). Сам элемент submission мы рассмотрим позже, когда дойдем до отправки данных. Пользовательский интерфейс формы располагается в секции :
118
PHP Inside №13
PHP::SOAP и Xforms
... Логин: Имя пользователя системы, регистр не имеет значения ...
Стандартный элемент пользовательского интерфейса формы - поле ввода.
Элемент предоставляет поле для ввода параметра поискового запроса (имя пользователя). Введенное в это поле значение будет автоматически изменять содержимое элемента экземпляра данных, к которому оно привязано (в данном случае uname). Поэтому, если мы введем имя пользователя, к примеру, “vpupkin”, то содержащийся в памяти инстанс будет выглядеть следующим образом: vpupkin
SOAP-запрос с данными пользователя И именно такой документ будет отправлен в качестве запроса на веб-службу.
Смена состояния Когда пользователь отправляет данные, отправляемый экземпляр замещается ответом веб-службы, имеющим совершенно другую структуру, таким образом, чтобы отобразить эту новую информацию, нам нужен элемент управления, базирующийся на новой структуре ответа. Но размещение нового элемента на одном экране с уже существующим приведет к сообщениям об ошибках, потому что один и них будет постоянно ссылаться на несуществующий элемент в экземпляре данных. Для того чтобы избежать этого, нужно создать условия, в которых только один набор элементов управления присутствовал бы на странице, или/и чтобы элементы привязывались к различным экземплярам данных.
119
PHP Inside №13
PHP::SOAP и Xforms
Воспользуемся конструкцией switch/case для разделения пользовательского интерфейса на экраны, переключая их в момент отправки запроса. Заключим каждый набор элементов управления в отдельный и добавим триггеры для переключения: ... Логин: Регистр не имеет значения К результатам Здесь будут результаты К форме поиска ...
Организация многоэкранной формы Выше представлена двухэкранная форма. Только один элемент может быть активным в любой момент времени (при загрузке активным делается первый). Для переключения между экранами добавим кнопки . Когда происходит нажатие кнопки, выполняются все действия, находящиеся в элементе (в нашем случае это переключение на другой экран с помощью ). Но этого еще не достаточно, потому что до переключения к экрану с результатом нужно этот результат получить, т.е. инициировать отправку данных и получить ответ. ... К результатам ...
120
PHP Inside №13
PHP::SOAP и Xforms
Действие активизации отправки данных Эта инструкция говорит активировать отправку данных с @id=”real_ws” (который мы ранее уже описали). Рассмотрим некоторые свойства подробнее: ... ...
Элемент описания отправки данных Кроме описаний, какие данные (@ref), куда (@action) и каким методом (@method) отправлять, есть еще уточняющие атрибуты, как в нашем случае @replace=”instance”, говорящий, что нужно перегрузить лишь экземпляр данных, а не весь документ. Ответ веб-службы (замещающий данные запроса) в нашем случае будет выглядеть примерно так: 10090 vpupkin 2000 10091 vpupkin2 2010 10092 vpupkin_ftp 2020 resID1 1 3 25
121
PHP Inside №13
PHP::SOAP и Xforms
SOAP-ответ веб-службы В отличие от обычных форм, в спецификации XForms существует элемент управления , специально предназначенный для вывода повторяющихся фрагментов разметки. Так будет выглядеть разметка для вывода нашего ответа веб-службы в виде таблицы: Идентификатор Имя пользователя Группа
Текущая позиция
Вывод повторяющихся данных в виде таблицы Весь код, содержащийся в , будет выведен столько раз, сколько узлов выберет Xpath-выражение в атрибуте @nodeset (в данном примере выбираются все элементы row внутри экземпляра “message”). Причем каждый раз контекстным узлом для вложенных элементов является очередной элемент из набора, т.е. при каждой итерации элемент будет отображать содержимое вложенного элемента обрабатываемого узла . Хотелось бы обратить внимание, что информации о том, что результатам вывода будет именно таблица, нигде не наблюдается, обусловлено это тем, что одной из основных целей XForms является высокая доступность документа, поэтому внешний вид элементов интерфейса определяется исключительно реализацией стандарта на конкретном устройстве. Разработчику документа дозволено лишь рекомендовать внешний вид элемента управления назначением атрибуту @appearance одного из значений “minimal”, “compact” или “full” (хотя, естественно, даже это не предполагает четкого определения внешнего вида).
122
PHP Inside №13
PHP::SOAP и Xforms
Таким образом, в используемой нами имплементации (FormsPlayer) указание @appearance=”compact” в дает желаемый эффект – данные выводятся в виде таблицы. Причем кликом на какую-либо строку списка можно сделать ее контекстной, и специальная функция расширения index() вернет ее позицию, и все это без единой строчки скрипта!
. Форма уже вполне работоспособна и может сама отправить параметры поиска веб-службе, получить ответ и отобразить его на экране. Но что произойдет, если пользователь захочет осуществить повторный поиск? Переключение на экран с формой поиска приведет к ошибке, поскольку исходного экземпляра данных уже нет (помните? он замещен ответом веб-службы). Единственный выход – перезагрузка всего документа в первоначально состояние. Хотя этого можно избежать, используя привязку элементов управления поиска и отображения к различным экземплярам данных. Причем один из экземпляров («message») по-прежнему будет служить «контейнером-обменником» с веб-службой и хранилищем результата, а элементы формы поиска, содержащие данные, введенные пользователем, будут привязаны к другому экземпляру (назовем его «to_search»). Исходя из этого, нам потребуется “сконструировать” экземпляр данных «message» перед отправкой запроса для того, чтобы он содержал параметры поиска из экземпляра «to_search». Итак, начнем переделывать модель: ...
123
PHP Inside №13
PHP::SOAP и Xforms
Логин: Регистр не имеет значения
Декомпозиция экземпляров данных Заметьте, что, поскольку экземпляры данных больше не конфликтуют между собой, то необходимость в применении конструкции switch/case/toggle именно для устранения этой проблемы отпадает, и все элементы могут быть активны одновременно (вы, естественно, можете реализовывать многоэкранность в сложных формах, с целью повышения удобства использования). Теперь приступим к «конструированию». Модифицируем кнопку отправки данных, добавляя дополнительно необходимые действия: Искать
Конструирование SOAP-запроса Добавив действие перед отправкой данных, мы производим операцию присваивания: элементу из атрибута @ref присваивается значение атрибута @value (не сами значения атрибутов, а элементы, адресуемые выражениями XPath, причем адресовать можно не только скалярное значение, но и любой узел документа). Итак, имеем второй вариант поисковой формы:
124
PHP Inside №13
PHP::SOAP и Xforms
Но проблема повторного поиска без перезагрузки формы еще не решена, т.к. после первого же поиска в экземпляре «message» элемент будет отсутствовать как таковой (см. структуру ответа веб-службы), поэтому повторного копирования данных не произойдет. Для этого добавим в модель «эталонный» экземпляр данных для отправки (назовем его «USERS_soap_template»), который будем использовать в качестве “рыбы” при конструировании запроса к веб-службе и который является точной копией экземпляра «message» в первоначальном состоянии: ... ... Искать ...
Восстановление исходного SOAP-сообщения из шаблона Таким образом получаем сборку SOAP-запроса при каждом нажатии пользователем кнопки «Искать».
125
PHP Inside №13
PHP::SOAP и Xforms
В дополнение хочется отметить расширяемость такого решения – можно «заготовить» несколько шаблонов сообщений к различным веб-службам и дать возможность пользователю производить поиск данных по введенным параметрам одновременно в нескольких ресурсах.
Типизация Одним из недостатков веб-форм является отсутствие какойлибо типизации вводимых данных и невозможность накладывать дополнительные сценарии поведения формы (даже тривиальная потребность автора пометить одно из полей как «обязательное для заполнения» сразу же приведет к скриптингу). Спецификация XForms решает и эту задачу. Типы для элементов в экземплярах данных можно задавать, используя словарь W3C XML Schema (WXS). XForms поддерживает большинство основных WXS-типов и добавляет несколько собственных. Причем именно типизация влияет, прежде всего, на то, как будет выглядеть «виджет», связанный с данным элементом, так, например, , связанный с элементом типа xsd:boolean выглядит как «checkbox», с xsd:string – простое поле ввода, а на xsd:date многие имплементации выводят т.н. «datepicker». Более того, WXS позволяет автору схемы создавать собственные типы данных на основе уже существующих. Давайте попытаемся связать элемент нашего экземпляра “to_search” с неким типом данных (назовем его “myUnameType”). Итак, составляем схему: ...
Определение пользовательских типов данных Как видим, нашему типу соответствуют все строки, включающие только латинские буквы длиной от 4 до 8 символов. Вообще, WXS имеет мощный механизм работы с типами (это ее предназначение), но подробное описание этой технологии выходит за рамки данной статьи. Далее необходимо связать нашу схему с Xforms-документом – делается это указанием местоположения схемы в атрибуте @schema модели Xforms:
126
PHP Inside №13
PHP::SOAP и Xforms
Ассоциация модели XForms со схемой данных Связывание После того, как схема подключена, типы, определенные в ней, доступны для назначения элементам экземпляров данных. Существует несколько способов назначения типа, опишу наиболее, на мой взгляд, оптимальный – путем добавления элементов связывания (binding) в модель XForms: ... ... ... ... ... Логин: Регистр не имеет значения имя должно состоять только из латинских букв и иметь длину от 4 до 8 символов ...
Использование xforms:bind Введение связок позволяет создать промежуточный слой между элементами управления и экземплярами данных с добавлением дополнительных условий и типизацией. Как видим, при введении можно изменить адресацию поля ввода логина с абсолютной (непосредственно до элемента в экземпляре данных с помощью @ref или @nodeset) на относительную (по имени связки c помощью @bind). Сразу же появляется очевидная выгода – теряется зависимость интерфейса формы от структуры ее модели, потому что все элементы интерфейса не связываются с данными напрямую, и изменения структуры экземпляров данных повлечет лишь изменение адресации привязок и не затронет сам пользовательский интерфейс. Форма может реагировать на определенные действия пользователя порождением событий XML (спецификация XMLevents) и динамическим назначением CSS-псевдоклассов.
127
PHP Inside №13
PHP::SOAP и Xforms
После того, как Xforms-процессор обнаружит несоответствие вводимых данных заявленному типу, возникнет событие “xformsinvalid” (отловив которое, можно предпринять какие-либо действия, вывести сообщение, например), и элементу управления назначается псевдокласс :invalid (используя который, можно с помощью CSS оформлять “неправильные” элементы): /* подсвечиваем неправильные элементы */ *:invalid, *.invalid { background-color: red; } /* и управляем выводом сообщений alert в случае ошибки */ *:invalid>xforms|alert, *.invalid xforms\:alert { display:inline; } *:valid>xforms|alert, *.valid xforms\:alert { display:none; } /* раскраска repeat в реализации formsplayer */ .repeat-grid-header {background-color:black;color:white;text-align:center;} .repeat-item-odd {background-color:#EEEEEE;} .repeat-item-even {background-color:white;} .repeat-index {background-color:darkblue; color: white;} .repeat-grid-cell {font-style:normal;} .repeat-grid-header-cell {font-weight:bold;} .repeat-value {border:1px black solid;}
Визуальное оформление событий с помощью CSS-псевдоклассов
Сообщение об ошибке В приведенном выше фрагменте CSS на каждую группу определено по 2 селектора, что обусловлено нюансами реализации этой функциональности именно плагином FormsPlayer.
Автозапрос Введем небольшое дополнение, необходимое для того, чтобы пользователь при загрузке формы сразу увидел первую страницу результатов (иногда это удобно), а не пустую форму. Для этого нужно использовать механизм событий Xforms и конкретнее отследить и обработать событие “xforms-ready”, которое возникает после полной загрузки модели формы и отрисовки пользовательского интерфейса (ближайший аналог ). Добавляем обработчик события в модель формы (как дочерний элемент , поскольку именно она является целью данного события): ...
128
PHP Inside №13
PHP::SOAP и Xforms
...
Обработчик события xforms-ready Таким образом, после внедрения этого фрагмента в модель и перезагрузки формы произойдет выполнение всех действий из контейнера , связанных с событием «xforms-ready» (суть – эмуляция нажатия кнопки «отправить»).
Передача данных в «обычное» веб-приложение Хотя в этой статье технология XForms рассматривается именно в контексте взаимодействия с веб-службами, это не ограничивает ее применения. Данные можно посылать на уже существующие ресурсы, работающие, например, с методом GET. Для этого нужно лишь определить, какие параметры принимает внешнее приложение, и сформировать соответствующий запрос. Допустим «простой» скрипт «card.php» может быть вызван методом GET с параметром user, равным идентификатору пользователя, тогда дополним форму следующими элементами: … … Карточка пользователя …
Пример взаимодействия с веб-приложением Здесь идентификатор пользователя выбирается из контекстной записи в результате и копируется в макет запроса к card.php.
129
PHP Inside №13
PHP::SOAP и Xforms
Замечания по отладке При работе с XForms возникают некоторые специфические сложности, связанные с невозможностью без специального ПО просмотреть содержание того или иного экземпляра данных в любой момент времени, что несколько замедляет разработку. Поэтому далее приведены некоторые простейшие приемы, используемые авторами. Просмотр отправляемых данных может быть осуществлен путем отправки (тестовый элемент submission и триггер «тест») на скрипт, подобный приведенному ниже:
Скрипт, отображающий данные, пришедшие с XForms-формы методом POST
Просмотр ответа, который попадает в экземпляр, затруднен только в том случае, когда используется передача данных без перезагрузки всей страницы, поэтому для отладки бывает полезно временно убрать атрибут @replace=”instance” из того элемента submission, возвращенное содержимое которого мы хотим посмотреть. При этом, когда отправка данных будет инициирована, форма перезагрузится и результаты, посылаемые в экземпляр, отобразятся в браузере.
Ошибка веб-службы Если веб-служба не в состоянии обработать входной запрос по каким-либо причинам, то спецификация обязывает выдать SOAPFault, причем для передачи такого сообщения назначается код 500 (Internal Server Error). В этом случае браузер с поддержкой XForms реагирует стандартным образом, даже не принимая документ, следующий за заголовком на обработку. В веб-службах собственной разработки можно определять потребителя веб-службы путем чтения заголовков (HTTP_USER_AGENT, например) и не выдавать SOAPFault с кодом 500, если потребителем является браузер. Сам же SOAP-конверт с ошибкой может быть обработан формой стандартным образом, и если к элементу привязан какой-либо элемент управления, то сообщение об ошибке отобразится на экране пользователя.
Типы данных SOAP XForms не поддерживает типы данных, определяемые в спецификации SOAP, такие, например, как Struct и Array, поэтому, если в экземпляр данных попадет SOAP-сообщение с такими типами, XForms-процессор сообщит об ошибке данных. Выходом может служить отказ от использования SOAP-кодирования сообщений либо описание сложных типов всех структур запросов и ответов вебслужбы.
130
PHP Inside №13
PHP::SOAP и Xforms
Заключение Веб-службы предлагают хоть и не новую, но удачно выведенную на более высокий уровень идею за счет применения интернет-технологий для реализации и транспорта, а также практически неограниченную расширяемость благодаря использованию открытых стандартов из XML-стека в качестве базы. Утверждение вебслужб и SOA как основного направления развития информационной инфраструктуры такого предприятия, как ОАО «АВТОВАЗ», с полным циклом производства и множеством сложнейших бизнес процессов, обещает упростить связывание отдельных бизнес-функций в цепочки процессов; предоставить прозрачный доступ к любой корпоративной ИС для интеграции либо агрегации, например, в портальном решении. Хочется отметить также высокую повторную используемость разработок за счет очень слабой связанности компонентов (сервисов) SOA и их высокой интероперабельности. При использовании веб-сервисов у разработчиков не будет необходимости в непосредственном обращении к хранилищам данных, что снизит требования к уровню знаний предметной области разработчиками сторонних приложений и снизит зависимость логики программы от структуры данных хранилища. Обладая достаточно большим количеством php-разработчиков, с выходом php5 информационные службы завода не потеряли возможность развиваться в направлении мейнстрима и утвердились в мнении о стабильном и правильном курсе развития языка. XForms является наиболее влиятельной спецификацией на мир электронных форм и предназначена для того, чтобы устранить множество недостатков HTML-форм, а также предоставить возможности, далеко превосходящие их. Архитектура XForms позволяет с легкостью интегрироваться с веб-документами и системами управления на основе XML. Спецификация является открытым стандартом, обещает независимость от платформы либо вендора и уже набирает популярность у разработчиков и пользователей. Доказательством широкой заинтересованности разработчиков служит внушительный список уже существующих имплементаций (Oracle, например, на одном из «воркшопов» уже продемонстрировал пример переносимости формы, когда одна и та же форма обслуживалась на ПК, мобильном телефоне и войс-сервере посредством телефона без каких-либо изменений). Со своей способностью обмениваться XML-документами XForms удачно находит свое применение в связке с веб-службами, избавляя разработчиков от написания промежуточного ПО. XForms спроектирован с разделением процессов отображения данных и манипуляции ими, что может применяться для организации нескольких последовательных обращений на сервер по одному запросу пользователя.
131
PHP Inside №13
PHP::SOAP и Xforms
В этот процесс включается создание отдельного экземпляра данных для каждой веб-службы, содержащего необходимый SOAPзапрос. И когда пользователь порождает событие (например, нажатием кнопки), вы можете выполнить любое количество действий, и, так как каждый экземпляр может иметь свой элемент < submission>, возможно просто активировать их по очереди, перемещая данные между экземплярами с помощью элемента < setvalue>. В целом технология XForms представляется очень удобной для разработки веб-клиентов (или уже целых приложений) с расширенной функциональностью, которые могут работать вообще без перезагрузки. На фоне того, что ОАО «АВТОВАЗ» проводит активное внедрение бездисковых станций для рабочих мест с фиксированной функциональностью и с выходом полноценной поддержки XForms, в очередном релизе Gecko открываются широкие перспективы в построении функциональных пользовательских рабочих сред с минимальными требованиями – SOA-клиентов.
Полезные ссылки: 1. домашняя страница Xforms http://www.w3.org/MarkUp/Forms/ 2. FAQ - http://www.w3.org/MarkUp/Forms/2003/xforms-faq.html 3. домашняя страница Web Services Activity http://www.w3.org/2002/ws/ 4. XForms for HTML Authors - http://www.w3.org/MarkUp/Forms/2003/xforms-for-html-authors.html 5. XForms conversion guideline - http://xforms.dstc.edu.au/information/xforms-conversion-guideline.pdf 6. XForms Essentials - http://xformsinstitute.com/essentials/browse/ 7. XForms: XML Powered Web Forms http://safariexamples.informit.com/0321154991/book.html#bookpa2.html 8. сайт «технологии веб-сервисов» http://www.ubs.ru/ws/ 9. Ten Favorite XForms Engines (http://xml.com/pub/a/2003/09/10/xforms.html) 10. FormsPlayer - http://www.formsplayer.com/ XSmiles - http://www.x-smiles.org/ 11. DENG - http://claus.packts.net/ 12. xslt2Xforms - http://xforms.zeninteractif.com/xhtml/index.html 13. Oracle mobile browser - http://www.oracle.com/technology/tech/wireless/mobilebrowser.htm Novell - http://developer.novell.com/xforms/ Mozilla Firefox - http://www.mozilla.org/projects/xforms/ 14. Chiba - http://chiba.sourceforge.net/ Orbeon PresentationServer - http://www.orbeon.com/software/ IBM XML Forms Package - http://www.alphaworks.ibm.com/tech/xmlforms 15. OpenOffice 2.0beta - http://www.openoffice.org/ XFormation - http://www.xformation.com/ Stylus Studio XML Professional Edition - http://www.stylusstudio.com/ OnForm xPress - http://www.blackdog.co.uk/pages/onform_xpress.htm 16. Validator - http://xformsinstitute.com/validator/ XForms Buddy - http://www.beaufour.dk/index.php?sec=misc&pagename=xforms 17. XForms Wiki-1 - http://en.wikipedia.org/wiki/Xforms 18. XForms Wiki-2 - http://www.worldwidewiki.net/wiki/XForms
132
PHP Inside №13
Платежные системы - это не страшно
Платежные системы - это не страшно Поскольку речь идет о мастер-классе, а не об обзорном Автор: Евгений Бондарев докладе, то много внимания общим вопросам исторического характера уделяться не будет. Где, как, когда появились первые способы оплаты в сети, и какими путями продвигались в своем развитии эти направления электронной коммерции, можно прочесть в материалах прошлой конференции (или в интернете – Yandex по-прежнему не отменили). Данный материал ставит перед собой цель, в первую очередь, объяснить основные подходы к проведениям платежей и продемонстрировать их на конкретных показательных примерах. Например, несколько систем с абсолютно идентичным подходом, но несколько отличающимися (названиями или количеством передаваемых параметром) API подробно рассматривать нет смысла – это переливание из пустого в порожнее. Зато некоторые экзотические примеры, с которыми, возможно, и не придется сталкиваться в реальной жизни, смогут наглядно продемонстрировать то, что даже самое неожиданное на первый взгляд решение – это всего лишь одна из вариаций стандартных решений.
1. Основополагающие принципы При всем кажущемся многообразии платежных систем и, соответственно, API, существует 2 принципиально различных способа взаимодействия с платежной системой: •
передача управления серверу ПС;
•
прямое обращение к шлюзу ПС. Большего пока не дано.
Первый способ считается наиболее безопасным и корректным для проведения платежей. Второй обычно дает больше возможностей для взаимодействия с платежной системой, например, позволяет производить автоматическую оплату, контролировать статус оплаты определенного счета, проверять баланс и т.п. Хотя в большинстве случаев это не является необходимым для приема оплаты функционалом. Тут же следует оговориться, что данные функции автоматизации, предоставляемые ПС, применимы, в основном, для ЦПС, хотя не исключено, что некоторые ПС поддерживают вышеуказанный функционал. Кроме того, при процессинге кредитных карт серверу ПС передается критично важная информация типа номера карты, CVV, данных о кард-холдере. Соответственно, чем меньше вероятность того, что эта информация попадет в руки третьей стороне (например, магазину), тем охотнее будут пользоваться сервисом как веб-мастера, так и покупатели. Поэтому предоставление прямого доступа к шлюзу ПС для процессинга кредитных карт – достаточно редкое явление.
133
PHP Inside №13
Платежные системы - это не страшно
С процессингом КК вообще ситуация весьма щекотливая – современные средства антифродовых защит развиваются достаточно быстро, и реализация приема оплаты через merchant-panel гарантирует разработчику, что любые изменения регламента оплаты (например, введение дополнительных проверок по принципу 3D-secure от Visa) не потребуют доработки/переделки уже существующего и стабильного кода. Некоторые ПС предоставляют поддержку сразу двух способов, иногда все же распределяя между ними функционал, например, прием оплаты через merchant-panel, а управление аккаунтом – через прямое обращение (eGold). То же самое можно сказать и о способах контроля целостности (а также аутентификации) данных. Принципиально различных способов 2: использование механизмов хеширования и использование цифровой подписи. Наиболее простой вариант, используемый в некоторых системах, – ПС при возвращении результата транзакции серверу продавца передает также хеш-код, построенный из основных параметров, которые переданы при запросе на проведение транзакции, например, MD5 (номер заказа + сумма платежа + внутренний ключ продавца в ПС). Скрипт-получатель результата транзакции проверяет целостность данных совпадением вернувшегося хеша. Часто в ответ также добавляется «секретная фраза», известная только ПС и продавцу, что позволяет интерпретировать результат как однозначно полученный от ПС. Кстати, раз уж зашел разговор о «секретной фразе», стоит упомянуть, что многие системы, используют 2 пароля. Один из них на вход в систему (возможно, и на проведение элементарных операций типа проверки баланса, состояния оплаты счетов и т.п.), а второй – на финансовые операции (оплаты счетов, перевода денег и т.п.). Это относится как к онлайновым системам (e-Gold, RuPay), так и к оффлайновым (Privat24, например). Обычно в качестве «секретной фразы» используется или этот «пароль платежа», или же, что более удобно и надежно, данную фразу можно задать отдельно (для каждого сайта у RuPay или для каждого кошелька при приеме оплаты через WM Merchant системы WebMoney). Однако более надежным способом проверки целостности и, что важно, аутентификации, являются механизмы цифровой подписи. Чаще всего для создания используется тот же OpenSSL или PGP, с помощью которых формируется подпись при помощи одного из алгоритмов RSA (Ривест, Шамир и Адлеман). Некоторые ЦПС разрабатывают свои средства создания цифровой подписи (к примеру, WMSigner от WebMoney). Снабженные такой подписью данные однозначно позволяют как идентифицировать отправителя, так и быть уверенным в их целостности. Справедлива и обратная зависимость – поступившие в ПС данные о транзакции гарантированно не изменены при передаче процессинговому центру и поступили от владельца ключа (что при соблюдении мер предосторожности следует расценивать как «от магазина, от которого оно и должно было прийти»).
134
PHP Inside №13
Платежные системы - это не страшно
Число «2» для платежных систем можно считать кармическим. Достаточно вспомнить, что сами по себе ПС можно разделить на Цифровые (работающие со своими «виртуальными» денежными единицами) и Реальные (работающие с реальными счетами и вполне материальными дензнаками). И сами ЦПС отлично разделяются по способу доступа и управления счетом на два вида: через программу типа «Цифрового кошелька» или через интернет на сайте ЦПС. От себя добавлю еще одно наблюдение: если ваш сервер (сайт), который работает с ПС, сломали (а в некоторых случаях, например, обменного пункта, казино, и т.п. случаях, когда есть функционал по выводу средств, это будут делать с настойчивостью и упорством), его обязательно сломают и второй раз. Как говорят украинские буддисты: «Цэ карма».
2. WebMoney Из всех ЦПС (характерных как для наших широт, так и в мировом масштабе) WM являются одной из самых развитых (с технической точки зрения), распространенных и доступных. Хотя сразу же говорюсь, что для западного рынка WM не самое массовое решение – «буржуи» отдают предпочтение PayPal или e-Gold, но... Тут вступает в силу весьма существенное «но», которое позволяет говорить о WM, как о лидере по совокупности вышеупомянутых показателей. Распространенность и развитость PayPal (во многом благодаря тесному сотрудничеству и уникальному в своем роде симбиозу с интернет-аукционом eBay) перечеркивается показателем доступности – поддержка данной ЦПС ограничена набором из четырех десятков стран, автоматически причисляя остальных к странам «третьего сорта мира». E-Gold (о нем будет отдельный материал) доступен и не менее распространен, но остановился в развитии уже давно и, видимо, надолго (особых изменений, кроме появления новых металлов, за последние 4 года я не наблюдал). Кроме того, и PayPal, и e-Gold – это чисто «серверные» системы, в то время как WM управляется при помощи «Цифрового кошелька», что несколько разделяет их. Правда, в этой бочке меду есть изрядная доля дегтя: в последнее время WM постепенно превращается в такого себе «монстра» с приличной бюрократической машиной и атрофированной службой поддержки. Если бюрократию можно хоть как-то оправдать – получение сертификата весьма важный процесс, поскольку в системе цифровой наличности идентификация участника (особенно получающего деньги) не столь явна, как в реальных деньгах, где по реальному счету всегда можно вычислить владельца, то оправдать службу поддержки, которая официально «не поддерживает не-ASP технологии», весьма сложно. Особенно учитывая, что основная масса решений все же базируется на unix-платформах и проблемы в основном возникают именно у PHP-программистов (во всяком случае, об этом можно судить по темам в форуме поддержки).
135
PHP Inside №13
Платежные системы - это не страшно
WebMoney предоставляют 2 способа для взаимодействия с ЦПС: это прием оплаты через WM Merchant панель, расположенную на сервере платежной системы (самый простой, быстрый и надежный способ получить оплату), а также два интерфейса (HTTPS и XML) для «плотного» взаимодействия с системой (для того, чтобы с этими интерфейсами можно было работать, необходимо 2 вещи: аттестат уровня «Персональный» (или выше) и письмо в службу поддержки с просьбой активации интерфейсов для данного WMID.
2.1. WM Merchant Сервис позволяет задавать отдельные настройки панели приема платежа для каждого кошелька, на который будет производиться платеж. Эти настройки можно сконфигурировать на странице «Настройка» на сайте https://merchant.webmoney.ru. Основными параметрами являются адреса для оповещения и возвращения клиента на сайт, метод передачи результата (GET, POST, URL), режим работы (тестовый/реальный), метод формирования подписи (это может быть или MD5, или подпись, сформированная программой WMSigner). Реальный режим проведения платежа можно включить, только имея аттестат уровня не ниже «Персональный». Для обладателей «Начального» аттестата есть возможность работать только в тестовом режиме. Нас интересует в первую очередь Result URL, на который будет передано оповещение об успешном платеже. Интересно, что по данному адресу совершается 2 обращения: первое для проверки работоспособности сайта торговца, а второе – для передачи уже, собственно, всех реквизитов проведенного платежа. Также важны Success URL и Fail URL – адреса, на которые будет переброшен клиент в случае успешного или неуспешного платежей соответственно. Есть еще два маленьких, но существенных параметра, которые позволяют понизить риск мошенничества во время проведения платежа. Первый из них отвечает за то, можно ли изменять параметры Success, Fail и Result URL в форме перевода клиента на сайт Webmoney для оплаты (то есть, игнорировать ли приходящие из формы эти параметры). Второй отвечает за то, будут ли передаваться параметры готовящегося платежа при предварительном запросе (первом обращении на Result URL). Если в настройках Merchant-панели включена данная опция, то будет передан набор параметров, характеризующих происходящий платеж: кошелек торговца, сумма платежа, номер заказа, WM-идентификатор покупателя, флаг тестового режима и дополнительные поля, передаваемые торговцем в форме запроса платежа. В таком случае скрипт должен проверить все полученные данные и разрешить проведение платежа (вернуть строку YES) или отказать покупателю в платеже (вернуть любую другую строку, которая и будет показана покупателю системой). Эта проверка может быть полезна не только для контроля суммы готовящегося платежа, но и для того, чтобы исключить повторную оплату со стороны клиента. Пример формы для проведения платежа через WM Merchant:
136
PHP Inside №13
Платежные системы - это не страшно
... ...
«Любые другие поля» должны быть без префикса LMI_, и сюда хорошо «раскладывать» всевозможные хеши (которые удобнее использовать в качестве идентификатора, чем просто цифру, а именно цифра и должна передаваться в форме проведения платежа), а также сюда попадают идентификаторы сессий, viewstate и прочие удобства. Все эти поля никак не участвуют в подписи, которая формируется ПС. Типичная функция проверки целостности платежа выглядит примерно таким образом:
В случае, когда подпись формируется не при помощи MD5, а при помощи WMSigner, хеш будет так же формироваться при помощи данного программного обеспечения, о котором более подробно речь пойдет немного ниже.
Настоятельно рекомендуется тщательно проверять данные, пришедшие на Result URL, с оповещением о платеже. Проверять целостность полученных данных, сумму платежа, кошелек торговца и режим проведения платежа (тестовый или реальный). Списки и описания всех полей, а также подробные описания всех требуемых для проведения платежа действий (документировано все на высочайшем уровне) можно найти по адресу https://merchant.webmoney.ru/conf/guide.asp.
137
PHP Inside №13
Платежные системы - это не страшно
Парадоксальный в своем роде глюк был замечен при одновременной работе с двумя запущенными киперами и оплатой через WM Merchant одним из них на счет второго. Деньги зачислялись, но вызов Result URL с оповещением об оплате был пустым, хотя предварительный запрос при включении соответствующей опции передавал все положенные данные…
2.2. HTTPS и XML интерфейсы Данные интерфейсы позволяют полноценно управлять своими кошельками. Эти интерфейсы практически дублируют друг друга с точки зрения функциональности. Принципиальное отличие состоит в способе формирования и отправки запроса. Также некоторые функции, предоставляемые XML-интерфейсом, отсутствуют в HTTPS-интерфейсе (в частности, проведение оплаты). Любой запрос, вне зависимости от выбранного программистом интерфейса, должен быть подписан программой WMSigner. WebMoney предоставляют как ЕХЕ файл для Windows-платформ, так и исходники для сборки программы самостоятельно под управлением любой ОС. Установленная программа снабжается конфигурационным INI файлом, в котором указываются WMID, пароль и путь к файлу ключей. Формирование подписи из PHP сводится к вызову подобной функции: function _GetSign($inStr){ $fp = popen("./WMSigner", "r+"); $PlanStr = "$inStr\004\r\n"; fwrite($fp,$PlanStr); $s = fgets($fp, 133); pclose($fp); }
return $s;
Обычно подпись формируется из «склеенных» между собой ключевых переменных запроса. NB! Абсолютно неочевидная, недокументированная, но при этом проблемная особенность: для стабильной и корректной работы механизма подписи необходимо использовать файл ключей минимального размера (что противоречит самим WM, которые рекомендуют использовать файл как можно большего размера). Работа с неминимальным файлом ключей очень часто невозможна, и WMSigner возвращает ошибку. Зависимость от платформы требуемого размера файла и каких-либо других параметров обнаружить не удалось Это же касается и стандартных библиотек-примеров, которые с некоторого момента стали работать нестабильно. Что характерно, один и тот же код может работать или не работать на разных платформах. Особенно это касается XML-интерфейса, когда сервер ЦПС возвращает ответ о «невалидном XML» на ровном месте. Поскольку использование XML-интерфейса является более предпочтительным, это весьма досадно. Из общих рекомендаций могу посоветовать форматировать уровни xml при помощи табов.
138
PHP Inside №13
Платежные системы - это не страшно
Основные и наиболее используемые функции – это выставление счета, проверка оплаты счета, перевод средств на кошелек клиента и проверка баланса. Это обеспечивают интерфейсы Х1, Х4, Х2 и Х9 соответственно. Рассматривать каждый из них по отдельности смысла нет – принцип действия один и тот же. В качестве примера рассмотрим выписывание счета покупателю. Интерфейс Х1 выполняется путем отправки сформированного XML методом POST на URL https://w3s.webmoney.ru/asp/XMLInvoice.asp Формат отправляемого XML следующий: НОМЕР_ЗАПРОСА WMID_ПОДПИСАВШЕГО_ЗАПРОС ПОДПИСЬ_СФОРМИРОВАННАЯ_ИЗ_ПАРАМЕТРОВ_INVOICE+reqn НОМЕР_СЧЕТА_В_СИСТЕМЕ_ПРОДАВЦА WMID_ПОКУПАТЕЛЯ КОШЕЛЕК_ПРОДАВЦА СУММА ОПИСАНИЕ АДРЕС_ДОСТАВКИ МАКСИМАЛЬНЫЙ_СРОК_ПРОТЕКЦИИ МАКСИМАЛЬНЫЙ_СРОК_ОПЛАТЫ
Переменная НОМЕР_ЗАПРОСА – это целое число без знака, максимум 15 цифр (по спецификации, хотя на практике рекомендуется ограничиться 14-ю), которое при каждом новом запросе должно быть больше, чем при предыдущем. Такой себе автоинкремент. Очевидно, что для формирования данного числа больше всего подходит зависимость от текущей даты. В таком случае функция формирования данного номера приобретает примерно следующий вид:
Полный же цикл формирования и отправки запроса с использованием модуля CURL приобретет следующий вид: // номер счета в системе магазина $orderid = 18; // WMID клиента $customerwmid = 1818181818; // кошелек магазина на который будет производиться платеж $storepurse = "Z1869284749"; // сумма к оплате. разделитель точка, незначимые нули убраны $amount = "58.5"; // описание платежа $desc = "пример счета № 18"; // адрес доставки $address = "на деревню к дедушке"; // оплату принимаем без протекции $period = 0; // счет действителен 4 дня $expiration = 4; // получаем номер запроса $reqn = _GetReqN(); // формируем подпись $sign = _GetSign($orderid . $customerwmid . $storepurse . $amount . $desc . $address . $period . $expiration . $reqn); // формируем запрос $request = " $reqn 1231234321 $sign $orderid $customerwmid $storepurse $amount $desc $address $period $expiration "; // инициализируем CURL $cu = curl_init("https://w3s.webmoney.ru/asp/XMLInvoice.asp"); curl_setopt($cu, CURLOPT_HEADER, 0); $fp = tmpfile(); curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, 0); // настраиваем передачу методом POST curl_setopt ($cu, CURLOPT_POST, 1); curl_setopt ($cu, CURLOPT_POSTFIELDS, $request); // перенаправляем результат во временный файл curl_setopt ($cu, CURLOPT_FILE, $fp); // выполняем запрос curl_exec($cu); curl_close($cu); // получаем результат из временного файла fseek($fp,0,SEEK_SET); $result = ''; while ($str = fgets($fp,1024)) { $result .= $str; } fclose($fp);
140
PHP Inside №13
Платежные системы - это не страшно
Полученный в переменную $result XML можно разобрать или при помощи регулярных выражений, или воспользовавшись своим любимым парсером. В данном случае нам необходимо проверить, что поле retval хранит значение 0 (что означает «запрос выполнен»), а также получить значение атрибута id из invoice.
2.3. Merchant VS XML В каких случаях выписывание счета предпочтительней, чем оплата через WM Merchant. и наоборот? Какой из способов выбрать для приема оплаты? На самом деле наиболее удобным для покупателя будет предоставление обоих вариантов. Оплата через WM Merchant удобна и возможна только в том случае, когда клиент пользуется обозревателем Internet Explorer (хотя и это еще не гарантирует возможности оплаты – ActiveX ПС, используемый для аутентификации пользователей, может вешать браузер, если последний «обвешан» тулбарами, скинами, коллекциями смайлов и прочими троянами) и готов заплатить сразу и на месте. Если же покупатель использует для серфинга Мозиллу или Оперу, хочет заказать товар, но готов заплатить несколько позже или знает, что за товар заплатит его друг (подруга, брат, начальник, должник и т.п. – нужное подчеркнуть), и для этого достаточно, чтобы счет пришел другу, единственный способ – это выписка счета. Размещение на странице оплаты двух кнопок с вариантами решает данную проблему. Или можно предложить покупателю указать свой WMID для выставления счета, или оставить поле незаполненным для оплаты через WM Merchant. Или… В общем, количество вариантов ограничено только полетом фантазии разработчика…
3. RuPay Основным преимуществом ЦПС «RuPay» является то, что, кроме своей внутренней системы денежных единиц, сервис позволяет принимать платежи с десятков внешних источников, в которые включены как ЦПС (WebMoney, Яndex-деньги, Internet-money, EGold), так и денежные переводы (Western Union, банковские переводы, оплата наличными и по чеку). Также система сотрудничает с рядом банковских сервисов (например, «Приват-24» от ПриватБанка). Нацеливание на аудиторию стран бывшего союза для приема платежей из этих стран и из дальнего зарубежья весьма приятно. И что особенно радует, это темпы развития системы. Для уменьшения риска мошенничества и «отмывки денег» система ввела аттестацию (менее бюрократическую, чем у WebMoney). Без аттестата ограничиваются способы ввода денег на счет. Хотя вывод денег не ограничивается отсутствием аттестата. Особо интересными являются новые функции системы, такие как инвестирование (с ежедневным начислением процента и возможностью пополнить счет или снять с него деньги в любое время), а также совсем новая возможность «кредитование». Для приема платежей с сайта торговцу необходимо зарегистрировать сайт в системе и настроить его параметры: 141
PHP Inside №13
Платежные системы - это не страшно
Параметр
Формат
Описание
Название сайта
255 символов
Название осуществляющего платежей
сайта, прием
Адрес сайта
255 символов
URL сайта, осуществляющего прием платежей
Описание сайта
-
Описание осуществляющего платежей
URL оповещения о платеже
255 символов
URL (на веб-сайте продавца), на который система RuPay посылает HTTP POSTоповещение о совершении платежа с его реквизитами. Если продавец не определил этот URL, он не будет оповещаться системой о совершенных платежах. URL должен начинаться с префикса “http://” или “https://”
Секретный ключ
32 символа
Строка символов, добавляемая к реквизитам платежа, высылаемым продавцу вместе с оповещением. Эта строка используется для повышения надежности идентификации высылаемого оповещения. Содержание строки известно только системе RuPay и продавцу!
Способы оплаты
-
сайта, прием
Способы оплаты, которые будет использовать сайт продавца Сам платеж проходит в несколько этапов. Торговец формирует форму запроса проведения платежа с action=http://rupay.ru/rupay/pay/index.php, и покупатель переходит к оплате на сервере ЦПС. Эта форма будет выглядеть примерно так: ... ...
142
PHP Inside №13
Платежные системы - это не страшно
Далее система пытается авторизировать покупателя по его электронному адресу и предоставляет ему возможность выбрать способ оплаты товара из разрешенных торговцем при настройке ЦПС для сайта. Как и WebMoney, RuPay формирует предварительный запрос на проведение платежа, а также запрос оповещения о платеже. Для аутентификации источника запросов используется секретный ключ, указанный в настройках сайта. Если сервер торговца поддерживает защищенное соединение, то этот ключ будет просто передан в явном виде. Если HTTPS-соединение не поддерживается, ключ не передается, но он является неотъемлемой частью формируемой ЦПС цифровой подписи, которую как раз надо в таких случаях проверять для уверенности в целостности полученных сервером торговца данных. Для формирования контрольной подписи ЦПС «склеивает» параметры запроса в одну строку, используя разделитель “::”. Порядок следования параметров при формировании строки подписи следующий. Для предварительного запроса: rupay_action, rupay_site_id, rupay_order_id, rupay_name_service, rupay_id, rupay_sum, rupay_user, rupay_email, rupay_data, rupay_secret_key; для оповещения о платеже: rupay_action, rupay_site_id, rupay_order_id, rupay_sum, rupay_id, rupay_data, rupay_status, rupay_secret_key. После этого строка подписи обрабатывается MD5, и полученное значение передается параметром rupay_hash. Таким образом, примерный код проверки цифровой подписи оповещения о платеже будет следующим: function check_crc($responce_data) { $crc_data = array( "rupay_action" => $responce_data["rupay_action"], "rupay_site_id" => $responce_data["rupay_site_id"], "rupay_order_id" => $responce_data["rupay_order_id"], "rupay_sum" => $responce_data["rupay_sum"], "rupay_id" => $responce_data["rupay_id"], "rupay_data" => $responce_data["rupay_data"], "rupay_status" => $responce_data["rupay_status"], "rupay_secret_key" => "СЕКРЕТНАЯ_ФРАЗА", ); $crc_str = md5(implode("::", $crc_data)); return $crc_str==$responce_data["rupay_hash"]; }
4. E-gold Отличительной особенностью данной системы есть то, что средствами расчетов в ней являются ценные металлы (золото, серебро, платина, палладий), и средства хранятся не в долларах-евро, а в граммах-унциях. При расчете (переводе средств) сумма указывается или в массе цветного металла, или в денежном эквиваленте, хотя на счет будет все равно переведен металл. Например, можно перевести 18 долларов в эквиваленте золота. Будет произведен расчет массы, необходимой для перевода данной суммы (курсы всех металлов всегда самые актуальные), и масса, эквивалентная по стоимости 18-ти долларам, уйдет на счет адресата. Комиссия за переводы также берется из расчета массы и снимается с получателя.
143
PHP Inside №13
Платежные системы - это не страшно
В системе существуют 2 пароля: пароль на вход (доступ к аккаунту) и пароль на выполнение операций с содержимым счета.
4.1. Прием оплаты Прием оплаты производится на сайте ЦПС, куда покупатель переправляется при помощи подобной формы:
На сайте E-gold клиенту будет предложено ввести свой номер аккаунта, пароль, код, показанный на «картинке, защищающей от роботов», далее клиенту будет еще раз показана форма платежа со всеми реквизитами и предложено оплатить или отказаться. После оплаты будет выведен соответствующий текст и предложение вернуться на сайт торговца. Общая схема процесса оплаты приведена на картинке (взято из спецификации Shopping Cart интерфейса Egold):
144
PHP Inside №13
Платежные системы - это не страшно
Уведомление о платеже передает торговцу следующие поля: Название поля
Описание
PAYEE_ACCOUNT
Номер счета торговца в системе E-gold. То же значение, что и в форме на оплату
PAYMENT_ID
Номер оплаченного счета в системе учета на сайте торговца (то же значение, которое передавалось в форме на оплату, или текст NULL, если поле не было передано)
PAYMENT_AMOUNT
Сумма. То же значение, что и в форме на оплату
PAYMENT_UNITS
Валюта. То же значение, что и в форме на оплату
PAYMENT_METAL_ID
Вид металла. То же значение, что и в форме на оплату. Принимает значение от 1 до 4 для определения соответствующего металла (соответственно золота, серебра, платины и палладия)
PAYMENT_BATCH_NUM
Номер транзакции в системе E-gold
PAYER_ACCOUNT
Номер счета плательщика
HANDSHAKE_HASH
MD5 подпись
ACTUAL_PAYMENT_OUNCES
Реальная масса перевода средств в тройских унциях переведенного металла
USD_PER_OUNCE
Текущая стоимость одной унции данного металла в долларах
FEEWEIGHT
Масса металла, которая была взята в качестве комиссии
TIMESTAMPGMT
Дата и время транзакции
V2_HASH
MD5 подпись
145
PHP Inside №13
Платежные системы - это не страшно
Посчитать реально полученную сумму можно, высчитав полученный вес металла ( NET_WEIGHT = ACTUAL_PAYMENT_OUNCES – FEEWEIGHT) и умножив на стоимость металла в долларах (ACTUAL_AMOUNT = USD_PER_OUNCE * NET_WEIGHT). 2 хеша возвращается из соображений совместимости. До 2000 года возвращалось только значение HANDSHAKE_HASH, в котором фигурировал пароль платежа в явном виде. В октябре 2000 года был введен V2_HASH, в котором вместо пароля платежа используется его хеш. Таким образом, проверка целостности будет выглядеть примерно таким образом: function check_crc($responce_data) { $crc_data = array( "PAYMENT_ID" => $responce_data["PAYMENT_ID"], "PAYEE_ACCOUNT" => $responce_data["PAYEE_ACCOUNT"], "PAYMENT_AMOUNT" => $responce_data["PAYMENT_AMOUNT"], "PAYMENT_UNITS" => $responce_data["PAYMENT_UNITS"], "PAYMENT_METAL_ID" => $responce_data["PAYMENT_METAL_ID"], "PAYMENT_BATCH_NUM" => $responce_data["PAYMENT_BATCH_NUM"], "PAYER_ACCOUNT" => $responce_data["PAYER_ACCOUNT"], "ALT_PASS_HASH" => "РАСЧИТАННЫЙ_MD5_ПАРОЛЯ_ПЛАТЕЖА", "ACTUAL_PAYMENT_OUNCES" => $responce_data["ACTUAL_PAYMENT_OUNCES"], "USD_PER_OUNCE" => $responce_data["USD_PER_OUNCE"], "FEEWEIGHT" => $responce_data["FEEWEIGHT"], "TIMESTAMPGMT" => $responce_data["TIMESTAMPGMT"], ); $crc_str = strtoupper(md5(implode(":", $crc_data))); return $crc_str==$responce_data["V2_HASH"]; }
Есть как минимум один отрицательный момент в форме приема: STATUS_URL должен обязательно находиться на стандартных портах (80 для HTTP и 443 для HTTPS). Это не всегда удобно, поскольку часто бывает, что доступ к сайту по https-протоколу возможен только через нестандартный порт. Приходится жертвовать защищенным соединением.
4.2. Функции автоматизации Данный функционал представлен в виде HTTPS-интерфейса. Параметры могут передаваться как GET, так и POST методом. Выполнение функций сводится к обращению к определенному URL и разбору ответа. Для вызова используется CURL. Например, для получения текущего баланса необходимо сделать обращение по адресу https://www.e-gold.com/acct/balance.asp и передать туда параметры AccountID (с номером счета) и Passphrase (с паролем). // Задаем необходимые параметры $params = "AccountID=18181818&Passphrase=cheburashka"; // Собираем адрес $url = "https://www.e-gold.com/acct/balance.asp?".$params; // Инициализируем CURL $cu = curl_init($url); curl_setopt ($cu, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($cu, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($cu, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); curl_setopt($cu, CURLOPT_RETURNTRANSFER, 1); curl_setopt($cu, CURLOPT_HEADER, 0);
146
PHP Inside №13
Платежные системы - это не страшно
curl_setopt($cu, CURLOPT_TIMEOUT, 100); // Выполняем запрос и получаем результат $res = curl_exec($cu); // Закрываем ресурс curl_close($cu);
Полученный ответ необходимо разобрать, воспользовавшись немудреным регулярным выражением: $acc = preg_match("/]+>\s+
]+>(.*?)/", $result[1], $res); if ($acc) { // Первое значение в унциях, второе – в граммах $gold_ballance = array($res[1], $res[2]); }
Таким же образом можно получить стоимость любого из представленных в системе металлов по отношению к любой из двух десятков представленных валют на любую дату.
К примеру, запрос вида http://www.egold.com/unsecure/metaldata.asp?LATEST=1&GOLD=1 вернет актуальную стоимость одной унции золота в системе в следующем виде: 4/18/05 18:18:18 PM, 476.000
Сам же перевод денег может производиться в 2 этапа. Первый (не обязательный, но рекомендуемый) позволяет проверить, будет ли возможна транзакция, и получить конкретные данные об актуальной стоимости перевода в массе металла. Второй этап уже совершает окончательный перевод средств. В целом параметры платежа одинаковы для обоих этапов. Различны адреса, по которым происходит обращение, и ответы системы. Кстати, результатом является HTML, в котором есть набор hidden-полей с результирующими значениями (как и в случае с балансом). Для проверки готовящейся транзакции вызывается URL https://www.e-gold.com/acct/verify.asp, в который передаются следующие поля: Поле
Описание
ACCOUNTID
Номер аккаунта плательщика
PASSPHRASE
Пароль
PAYEE_ACCOUNT
Номер аккаунта получателя
AMOUNT
Сумма перевода. Не менее 0.000010 металла унции «по курсу»
PAY_IN
Код единиц перевода. Это могут быть как валюты, так и граммы или унции
WORTH_OF
Имя переводимого металла. Одно из “Gold”, “Silver”, “Platinum”, “Palladium”.
MEMO
Примечание до 50 символов. Будет доступно как плательщику, так и получателю
PAYMENT_ID
Номер перевода в системе пользователя. Опциональное поле.
147
PHP Inside №13
Платежные системы - это не страшно
Система вернет HTML, в котором будут поля Payee_Account, ACTUAL_PAYMENT_OUNCES, PAYMENT_AMOUNT, PAYMENT_UNITS, PAYMENT_METAL_ID, PAYER_ACCOUNT, USD_PER_OUNCE, PAYMENT_ID и ERROR. Все значения соответствуют входным данным, добавляется только стоимость унции металла в долларах США, количество переводимых унций металла и поле ERROR, которое содержит в себе текст ошибки в случае возникновения таковой (например, если указан несуществующий код металла или неверный аккаунт, или суммы на счету недостаточно для проведения перевода и т.п.). Повторный вызов с этими же параметрами, но по адресу https://www.e-gold.com/acct/confirm.asp инициирует перевод средств. Результат будет выражен такими же полями, как и при проверке, но к ним еще добавятся поля PAYMENT_FEE_OUNCES (размер комиссии в унциях) и PAYMENT_BATCH_NUM (внутренний номер транзакции в системе E-gold). Как мы можем увидеть из данных примеров, автоматизация в данной системе сделана весьма суррогатным образом. Фактически это просто отправка форм (или переходы по ссылкам), и так расположенных на сайте. Остается поблагодарить разработчиков за то, что они хотя бы документировали это (облачив в форму официальной спецификации).
5. Int-Commerce Данная система является одной из немногих Украинских систем, предоставляющих процессинг кредитных карт. Есть некоторые несущественные ограничения в выборе банка эквайера (банка, обслуживающего торговца) – это должен быть АККБ «Аваль». Этот же банк является и расчетным банком платежной системы. Для проведения оплаты с помощью системы интернет-коммерции (СИК) «Int-Commerce» клиент перенаправляется торговцем на адрес https://secure.intcommerce.com/servlets/SoftPOS_alias/SoftPOS.Pay (где alias - идентификатор торговца, согласованный при регистрации), куда методом GET передаются следующие параметры: Параметр
Описание
psum
Сумма оплаты в копейках
148
PHP Inside №13
Платежные системы - это не страшно
Параметр
Описание
pmode
Режим проведения транзакции. Может принимать значения: 1 – автоматический (после поступления данных авторизация происходит автоматически. В случае успешной авторизации автоматически происходит расчет по транзакции); 0 – ручной (то же, что предыдущее, но без автоматического расчета. То есть администратор сайта сам проводит расчет по транзакции либо ее откат); -1 - отложенный (после поступления данных от клиента администратору сайта высылается оповещение. Администратор сам принимает решение, проводить ли авторизацию карточки или нет).
poterm
Срок истинности заказа в часах
porder
Номер заказа
Plang
Язык интерфейса пользователя. Может принимать значения: 1 – украинский; 2 – русский;
3 – английский Результат транзакции торговец получает или на email, или вызовом ИПС-скрипта на сервере торговца. Во втором случае скрипту передаются следующие параметры методом GET: oderdID - номер заказа summ - сумма оплаты ordStat - статус заказа Код
Состояние
Описание
-20
Оплата отменена
После успешной авторизации транзакции администратором магазина была проведена операция отмены платежа
0
Заказ поступил, данных для авторизации недостаточно
На сервер были переданы данные заказа, но клиент еще не ввел данные карточки
10
Ожидание авторизации
Данные карточки были введены, транзакция ожидает авторизации администратором магазина
11
Авторизация отложена
Зарезервировано. Сейчас не используется
16
В авторизации отказано
В авторизации отказано
149
PHP Inside №13
Платежные системы - это не страшно
Код
Состояние
Описание
20
Заказ авторизован, ожидание расчета
Транзакция успешно авторизована и ожидает проведения расчета администратором магазина
30
Заказ оплачен Заказ оплачен Данные о результате транзакции поступают сразу же после изменения статуса заказа. Проверить, что данные поступили от ИПС, можно, только проверив IP-адрес вызывающей стороны. Подробности можно узнать на сайте www.int-commerce.com Я намеренно воздерживаюсь от своих комментариев в адрес данной системы. Достаточно сравнить ее с любой другой системой (показательным примером выступит процессинговый центр банка «Менатеп»), но, как писал бывший президент Л. Кучма: «Украина не Россия», так что «маемо тэ, що маемо».
6. Менатеп Для меня процессинговый центр банка «Менатеп» пока остается классическим примером грамотного и верного подхода к приему платежей. Речь идет в первую очередь о формировании корзины и передаче ее ПС. Во-первых, сама корзина представляет собой XML-файл, в котором есть место и для описания платежа, и для перечня покупок, и для служебной информации. Во-вторых, корзина подписывается магазином (для цифровой подписи используется алгоритм RSA-MD5), а файл с ключами можно получить только лично в банке. Подпись позволяет аутентифицировать продавца и гарантирует целостность переданных на сервер ПС данных, а то, что за ключами надо «тащиться» в банк лично, значительно снижает риск утечки ключей. В-третьих, хорош подход с передачей результата транзакции – в подписанном ПС XML-ответе (подпись, опять-таки, гарантирует целостность и источник данных) возвращается, кроме результата транзакции, еще и исходная корзина. Такое себе «быстрое решение» для обратной связи. Но этот маленький нюанс позволяет не спешить с хранением лишних данных в базе или где-то еще, а фиксировать, например, только завершенные транзакции. Схема проведения транзакции следующая: •
Сервер торговца формирует XML-файл корзины.
•
Клиент перебрасывается торговцем на адрес: https://www.menatepspb.com/ib/eps3/enter/?basket_url=http://www..., где параметр basket_url задает адрес, с которого сервис ИПС сможет считать файл корзины, закодированный BASE64.
•
ИПС раскодирует корзину и проверяет цифровую подпись торговца.
•
Если все в порядке, ИПС получает от покупателя данные по кредитной карте или реквизиты для банковского перевода и пытается провести транзакцию.
•
Результат транзакции возвращается торговцу на cmdAckUrl или cmdCancelUrl в зависимости от успешности.
•
Пользователь перенаправляется на returnUrl, указанный в корзине. 150
PHP Inside №13 •
Платежные системы - это не страшно
В зависимости от результатов, полученных торговцем на 5-м шаге, торговец выводит результат транзакции покупателю.
Особенно удобно то, что для механизмов подписи не нужно устанавливать стороннее ПО. Для работы можно использовать любые программные решения (большинство из которых есть на каждом сервере), поддерживающие RSA-MD5 (обычно это OpenSSL или GPG).
8. PayCash Семейство платежных систем PayCash достаточно велико. На самом деле это замечательная попытка объединить под одной крышей обработку платежей в разных странах и валютах. Создать универсальную ЦПС для всех. В России PayCash знакомы под маркой Yandex.Деньги, в Украине это Интернет.Деньги. Хотя принципиальное различие только в доменном имени (ну и еще кое в чем, iMoney опережают Yandex.Деньги, о чем я упомяну ниже). Данная ЦПС базируется на программном обеспечении типа «Интернет.Кошелек» (упрощенный аналог WM Keeper от WebMoney), который прост в установке, настройке и использовании, поскольку обладает минимально необходимым функционалом. Прием оплаты производится путем размещения на сайте формы такого вида:
При этом у покупателя ПО кошелька должно быть запущенно. Запрос попадает покупателю прямо в кошелек, покупатель оплачивает счет, и результат уходит на wbp_ShopAddress, указанный в форме. В качестве данного адреса могут выступать или email продавца, куда придут данные о результате транзакции, или IP-адрес компьютера продавца, на котором запущен кошелек. С автоматизацией дело обстоит очень плохо, поскольку обработать платеж «на лету» несколько проблематично (можно разбирать пришедший email, в котором для автоматизации все результирующие поля вынесены в отдельный раздел, но это полумера). Хотя в будущей версии ПО iWallet обещали это исправить и позволить передавать данные непосредственно серверному скрипту.
151
PHP Inside №13
Платежные системы - это не страшно
Долгие поиски возможности автоматизации процесса (читай – поиски документации) подарили весьма удивительные результаты: на сайте http://www.imoney.com.ua удалось обнаружить раздел, посвященный способам автоматизации (ни на сайте http://money.yandex.ru, ни на сайте http://www.paycash.com ничего подобного найдено не было), в котором описывается некий «HTTPудлинитель», с помощью которого можно добиться определенного прогресса в данной области. Данный «PayCash ShopAPI HTTP-wrapper» (AHW) по сути есть вспомогательное Windows-приложение (сервис), реализующее набор функций платежной системы PayCash ShopAPI: •
GetMoneyRequest,
•
GetIncomingPaymentApproval,
•
PaymentAuthorizationResult
посредством упаковки параметров вызываемой функции и передачи зашифрованного пакета на заданный сервер по протоколу HTTP, извлечения зашифрованного пакета с результатами работы функции из ответа сервера, распаковки и возврата их вызывающему. AHW предназначен для работы в качестве посредника между Кошельком-кассой и Магазином, функциональность которого реализована на заданном HTTP-сервере. Реализуются три основных функции, есть куча ASP-примеров, написанных на VB и JS, но становится очень грустно от того, что все это завязано под одну вполне определенную платформу. В комплект поставки входят примеры (точнее заготовки) ASP, CGI и COM серверных скриптов и объектов. Учитывая то, что в мире больше, чем одна операционная система, замечательную идею «единой ЦПС для всех» можно считать успешно проваленной… Примечание: на момент подготовки данного материала автор не имел возможности провести эксперименты со сборкой CGIпримеров под другие ОС, кроме Той Самой. Вероятно, что возможность таковой сборки все же есть. К моменту проведения конференции автор будет обладать более подробной информацией на этот счет.
9. ScanNet Данная датская ПС попала в обзор по причине несколько специфического способа взаимодействия с сайтом торговца. Это касается в равной степени как подготовки формы приема платежа, так и передачи результата транзакции. Характерной особенностью данной системы является фактическое отсутствие документации, хотя все основные вопросы подробно рассмотрены в FAQ. Вроде бы, это полбеды, но основным языком является датский, а с английским служба поддержки знакома только понаслышке (читали в газете, что есть такой язык, но не более).
152
PHP Inside №13
Платежные системы - это не страшно
Тем не менее, система весьма хороша с точки зрения торговца – оплата принимается во всех основных валютах мира, поддерживаются основные международные и датские карточные системы. Достаточно удобно контролировать поступления оплаты через панель управления и статистики. Там же, в панели управления, можно загрузить шаблоны для страниц формы оплаты и результата платежа. Сама загрузка выполнена не в виде UPLOAD файлов, а в форме указания URL, с которого данные шаблоны будут загружены. Относительный путь к шаблонам так же важен в силу того, что на сервере ПС создается как бы «зеркало» данных файлов и обращение к ним будет происходить именно с использованием данного относительного пути. К примеру, если для формы оплаты был загружен шаблон с адреса http://shop.com/payment/order.html, то оплата будет производиться по адресу https://pay.scannet.dk/ИДЕНТИФИКАТОР_МАГАЗИНА/payment/ord er.html. И вот тут-то и начинается красота простого и удобного решения. Шаблоны страниц формы оплаты и результата оплаты работают на шаблонном движке, что позволяет реализовывать практически все, что угодно душе. Во-первых, это позволяет даже в простой HTML-версии магазина получать выписки на email и сохранять все необходимые переменные при переходе с сервера на сервер. Пример шаблона результата платежа для HTML версии магазина: HTML DemoShop HTML DemoShop Во время проведения платежа произошли следующие ошибки: ${error} Результат оплаты: Во время оплаты обнаружены следующие ошибки:
${error}
Вернуться назад Уважаемый ${kunde_navn}, Вы оплатили заказ:
153
PHP Inside №13
Платежные системы - это не страшно
Данные заказа: ----------------------------------------------------------------- [Покупатель]: ${kunde_navn} ${kunde_adresse} ${kunde_postnr} ${kunde_by} ${kunde_email} [Продавец]: ${forhandler_Navn} ${forhandler_Attention} ${forhandler_Vej} ${forhandler_Land}-${forhandler_Postnummer} ${forhandler_By} Дата заказа: ${dato} Номер заказа: ${ordrenr} ${antal} шт. ${navn} по ${valutatxt.get(${valuta})} ${pris.talformat(',')} итого: ${valutatxt.get(${valuta})} ${liniepris.talformat(',')} Сумма без учета НДС: ${valutatxt.get(${valuta})} ${prisumoms.talformat(',')} Сумма с учетом НДС: ${valutatxt.get(${valuta})} ${prisialt.talformat(',')} ----------------------------------------------------------------- С Уважением, ${forhandler_Navn} Результат: Уважаемый ${kunde_navn}! На Ваш email (${email}) был выслан оплаченный Вами счет! С Уважением, ${forhandler_Navn}
Но всего лишь одна маленькая конструкция в шаблоне потребуется программисту на самом деле. Это конструкция
Следует отметить, что есть предопределенный набор обязательных переменных, передаваемых в форме оплаты. Сама форма будет передаваться скрипту /cgi-bin/auth3.pl, расположенному на сервере ЦПС. Примерный вид скрипта, вызываемого из шаблона формы оплаты заказа и формирующий форму, будет таким: