Совместное использование встроенной поддержки XML в DB2 и PHP

Используйте встроенную поддержку XML в DB2 совместно с PHP, чтобы облегчить прикладным системам использование XML- данных

Узнайте больше об эффективности использования встроенных средств для работы с XML, которые планируется включить в следующую версию универсальной базы данных DB2® Universal Database™ для Linux®, UNIX®и Windows® в целях упрощения программного кода приложений и реляционных схем. Наша статья рассматривает влияние развития схемы на приложение и проводит читателя через один из возможных сценариев использования, чтобы наглядно продемонстрировать, насколько просто настроить среду PHP, интегрировать встроенные средства DB2 для работы с XML в приложения на PHP, включая Web-сервисы, написанные на PHP и XQuery; показывает преимущество введения в базу данных бизнес-логики и преобразования данных при помощи языка запросов XQuery, хранимых процедур и представлений. Чтобы нагляднее выделить влияние использования встроенных в DB2 средств XML на код PHP-приложения и проект реляционной схемы, данный сценарий создает параллельную среду, в которой используется база данных, не имеющая никаких средств для работы с XML (например, MySQL). Мы покажем разницу между программными кодами, запросами к базе данных и реляционными схемами для данных двух сред.

Хардип Сингх (Hardeep Singh), разработчик инструментария XML для DB2, IBM

Photo: Хардип Сингх (Hardeep Singh)Хардип Сингх (Hardeep Singh) – член группы встроенной поддержки XML в DB2 и архитектор инструментария для XML DB2 (DB2 XQuery Builder). Он также отвечает за стратегию переноса XML-приложений для следующей версии универсальной базы данных DB2. Его опыт работы в промышленности насчитывает 21 год. .



Амир Малик (Amir Malik), студент-дипломник, IBM

Амир Малик (Amir Malik)Амир Малик (Amir Malik) в прошлом году стажировался в группе встроенной поддержки XML DB2 в исследовательской лаборатории IBM в Кремниевой долине. В настоящее время получает степень бакалавра наук в сфере проектирования компьютеров в Калифорнийском университете г. Санта-Круз.



27.10.2005

Введение

PHP предлагает простую среду разработки и развертывания Web-приложений - это одна из причин популярности данного языка программирования. Встроенные средства DB2 для работы с XML, включенные в следующую версию, которая называется DB2 Viper, еще более упрощают процесс разработки. Упрощение проявляется в следующих формах:

  • Уменьшение размера кода приложения и снижение его сложности;
  • Более простая реляционная схема;
  • Улучшенное управление развитием схемы при изменении бизнес-требований.

Чтобы разобраться в основах встроенной поддержки XML в DB2, мы рекомендуем начать с чтения статьи "Firing Up the Hybrid Engine" (Запуск гибридного механизма), автором которой является Анжул Бамбри (Anjul Bhambhri), менеджер отдела по разработке встроенных средств поддержки XML в DB2 (статья опубликована в журнале DB2 Magazine).

В нашей статье мы отталкиваемся от этих основ и демонстрируем эффективность использования встроенных средств работы с XML для снижения сложности кода приложений и реляционных схем. Мы также рассматриваем воздействие изменений бизнес-требований на данные (развитие схемы) и влияние таких изменений на код приложения и реляционную схему.

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

Вот некоторые положения, которые мы постараемся проиллюстрировать по ходу сценария:

  • Легкость настройки среды PHP;
  • Простая интеграция встроенных средств работы с XML DB2 в приложения PHP, в том числе, в Web-сервисы, написанные на PHP и языке запросов XQuery;
  • Введение в базу данных компонентов бизнес-логики и преобразований данных при помощи XQuery, хранимых процедур и представлений.

Средства DB2 для работы с XML, которые мы используем в данном сценарии, будут охватывать следующие области:

  • Хранение документа XML в столбце в качестве анализируемой структуры;
  • Использование языка запросов XQuery для поиска и публикации;
  • Поддержка XML хранимыми процедурами и представлениями DB2;
  • Использование индексов XML для повышения производительности.

Чтобы нагляднее выделить влияние использования встроенных средств DB2 для работы с XML на код PHP-приложения и проект реляционной схемы, данный сценарий создает параллельную среду, в которой используется база данных, не имеющая никаких средств для работы с XML (например, MySQL). Мы исследуем различие между кодами приложения, запросами к базе данных и реляционными схемами для данных двух сред и приведем обоснования сделанного нами выбора в пользу конкретного варианта кода, схемы или запроса, а также, по возможности, альтернативные варианты.


Сценарий

Модель сценария построена на примере интернет-магазина, занимающегося продажей антикварных изделий из серебра зарегистрированным покупателям. Поскольку одна из задач данного сценария –иллюстрация различных сред баз данных и их влияния на код приложения, мы попытаемся показать со всех сторон два приложения (одно из которых использует встроенные средства DB2 для работы с XML, а другое представляет собой реляционную СУБД с открытым исходным кодом, например, MySQL, которая имеет ограниченные средства для работы с XML или вообще не имеет таких средств).

По этой причине для представления покупателей, посещающих Web-сайт, будет использоваться страница, которая содержит две вертикально расположенные панели. Каждая панель предназначена для демонстрации версии одного и того же приложения с одной и той же функциональностью для пользователя, но использующего в качестве серверной части различные базы данных:

  • DB2 со встроенной поддержкой XML;
  • другую реляционную СУБД (в данном случае, DB2, в которой средства для работы с XML не используются).

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

Рисунок 1. Панели приложения (пример)
Панели приложения (пример)

Этим демонстрируется, что, хотя функциональность для пользователя не изменяется в любом из двух случаев, сложность кода варьируется в значительной степени. Контраст показывает преимущество использования встроенных средств XML в обычных прикладных программах для малого и среднего бизнеса, написанных на PHP.

Примечание: Мы предполагаем для этого сценария, что бизнес-данные хранятся в формате XML, даже если база данных не имеет никаких средств для работы с XML. В результате этого код приложения на PHP будет использовать доступные ему средства XML (такие как функция SimpleXML). В базе данных с ограниченными средствами XML или без таких средств XML-данные будут храниться в виде объекта CLOB/BLOB или распределенными по реляционным полям.

На Web-сайте покупателям будет предложен указатель, содержащий список категорий и производителей всех изделий из серебра, имеющихся в магазине. Если пользователь нажимает мышью на категории или торговой марке, отображается список товаров в этой категории или данной торговой марки. При выборе любого товара в списке на странице отображаются свойства товара. Пользователь имеет возможность добавить данный товар в корзину. Как только пользователь передает оформленный заказ, создается бланк заказа, а пользователю выписывается накладная на основании бланка заказа. Пользователь может в любое время проверить, какие товары находятся в корзине. Пользователь может также получить отчет обо всех товарах, которые он заказывал раньше.


Архитектура приложения

На рисунке 2 показана схема архитектуры для нашего учебного приложения.

Рисунок 2. Архитектура приложения
Архитектура приложения

Реляционная и XML схемы

Документы XML и схемы

Свойственная XML схема хранения не требует, чтобы столбец XML был связан с конкретной схемой XML. Любая проверка достоверности, необходимая для XML-документа, вставляемого в базу данных, делается исключительно в предложении insert при помощи функции SQL/XML XMLVALIDATE.

Реляционная схема

Реляционные схемы для хранения данных документов XML в этих двух базах данных будут различными.

Для XML DB2 это три таблицы по два столбца в каждой.

Рисунок 3. Схема XML DB2
Relational schema for native XML scenario

Для реляционной СУБД без поддержки XML необходимы 4 таблицы по несколько столбцов в каждой:

Рисунок 4. Реляционная схема для сценария без поддержки XML
Реляционная схема для сценария без поддержки XML

Обратите внимание, насколько проще схема отношений для DB2 с XML по сравнению с реляционной СУБД без поддержки XML.

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

Драйвер DB2 для PHP

Перед тем, как мы приступим к рассмотрению кода приложения PHP, давайте попробуем разобраться с драйвером DB2 для PHP. Драйвер ibm_db2 поддерживает два метода подключения к базе данных: каталогизированное и некаталогизированное подключение. Каталогизированное подключение может выполняться к локальной базе данных (если на локальном компьютере запущен сервер DB2) или к удаленному узлу сервера DB2. Второй метод обычно применяется для удаленных некаталогизированных подключений и требует от пользователя создания строки подключения (вроде JDBC URL). Следующий код выполняет подключение к каталогизированной базе данных (клиентскому приложению не нужно знать или заботиться о том, является ли каталогизированное подключение локальным или удаленным.)

$conn = db2_connect($dbname, $dbuser, $dbpass);
if(!$conn) {
echo db2_conn_errormsg();
die("Unable to connect to database!");
}

Можно также создать постоянное соединение с базой данных при помощи драйвера db2_pconnect. Постоянное соединение в действительности не закрывается при вызове db2_close, поскольку обработка подключения поддерживается через запросы. Более подробную информацию о драйвере IBM DB2 для PHP смотрите http://www.php.net/manual/en/ref.ibm-db2.php. В следующем фрагменте кода предполагается, что $conn соответствует корректной обработке соединения.

Заполнение базы данных

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

DB2 Viper

Поскольку каждый документ об изделии включает в качестве атрибута идентификатор изделия, мы должны извлечь его при помощи API PHP SimpleXml.

Примечание: гораздо проще использовать данное API, чем манипулировать DOM-объектами, которые были единственным вариантом до выхода 5 версии PHP.

  1. Создаем подключение к базе данных;
    $conn =db2_connect($dbname, $dbuser, $dbpass);
  2. Открываем документ из файла в переменную;
    $fileContents = file_get_contents("products/p1.xml");
  3. Создаем простой XML-объект из этой переменной;
    $dom = simplexml_load_string($fileContents);
  4. Извлекаем идентификатор продукта из документа;
    $prodID = (string) $dom["pid"];
  5. Создаем предварительное предложение для вставки XML-документа в базу данных;
    $stmt =db2_prepare($conn, "INSERT INTO xmlproduct VALUES (?, ?)");
  6. Передаем извлеченный из документа идентификатор продукта вместе с документом в качестве параметра запроса.
    db2_execute($stmt, array($prodID, $fileContents);

Обратите внимание, что вставка данных в столбец XML не отличается от вставки в любой столбец CLOB. Благодаря тому, что новая версия DB2 поддерживает неявный анализ XML-данных при вставке, нам не нужно явно вызывать функцию XMLPARSE на входном значении. Если нужно было бы сохранить сторонние пробелы вокруг тегов HTML, нам следовало воспользоваться функцией XMLPARSE с параметром PRESERVE WHITESPACE.

Примечание: Все запросы в этих фрагментах кода выделены полужирным шрифтом, чтобы их можно было отличить от кода PHP-приложения.

Реляционная СУБД без поддержки XML

Поскольку такая база данных не имеет никаких средств для работы с данными XML, документ изделия необходимо разбить на две реляционные таблицы. Распределение информации между реляционной схемой и схемой XML непосредственно встроено в код приложения PHP.

  1. Сначала загружаем документ в DOM:
    $fileContents = file_get_contents("$products/p1.xml");
    $dom = simplexml_load_string($fileContents);
  2. Теперь распределяем отдельные элементы изделия по локальным переменным:
    $prodID = (string) $dom["pid"];
    $prodName = (string) $dom->description->name;
    $prodDetails = (string) $dom->description->details;
    $prodPrice = (float) $dom->description->price;
  3. URL изображения для каждого изделия необходимо хранить в отдельной таблице изображений:
    $images = array();
    foreach($dom->description->images->image as $image) {
    switch((string) $image[type']) {
    case thumbnail':$prodImgThumb = (string) $image;
    $prodImgAlias = (string) $image[alias'];
    if(!$prodImgAlias) $prodImgAlias = NULL;
    $stmt = db2_prepare($conn, "INSERT INTO sqlimages(Pid,Type,Alias,Location)
     VALUES (?, ?, ?, ?)");
    db2_execute($stmt, array($prodID, thumbnail', $prodImgAlias, $prodImgThumb));
    case full':
    $prodImgFull = (string) $image;
    $prodImgAlias = (string) $image[alias'];
    if(!$prodImgAlias) $prodImgAlias = NULL;
    $stmt = db2_prepare($conn, "INSERT INTO sqlimages(Pid,Type,Alias,Location)
    VALUES (?, ?, ?, ?)");
    db2_execute($stmt, array($prodID, full', $prodImgAlias, $prodImgFull));
    }
    }
  4. Текущая версия, драйвер Ibm_db2, не поддерживает обработку переменной NULL в качестве аргумента исполняемой функции; значит, мы используем простой обходной маневр:
    if(!$prodBrand) $prodBrand = " ";
    if(!$prodCategory) $prodCategory = " ";
    if(!$prodImgFull) $prodImgFull = " ";
    Note: This issue has been fixed in the latest version of ibm_db2 driver. Вы можете получить исправление по следующему адресу: pecl.php.net/package/ibm_db2
  5. Теперь сохраняем информацию об изделиях в таблице изделий:
    $stmt = db2_prepare($conn, "
    	INSERT INTO sqlproduct (Pid, Name, Details, Brand,
    		Category, Price, Weight, Size, Description)
    		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
    db2_execute($stmt, array($prodID, $prodName,$prodDetails, $prodBrand, $prodCategory,
    	$prodPrice, $prodWeight, $prodSize, $fileContents));

Создание главной страницы

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

Рисунок 5. Главная страница
Главная страница

Создание списка категорий и торговых марок

Индекс создается путем запрашивания у базы данных списка уникальных категорий и торговых марок для всех изделий, имеющихся в базе. Список создается при запуске приложения.

DB2 Viper

  1. Сначала при помощи XQuery создаем представление DB2 для списка категорий, которое обходит все изделия и возвращает последовательность всех уникальных категорий:
    CREATE VIEW Categories(Category) AS SELECT DISTINCT(XMLCAST(
    XMLQUERY(for $i in $t/product/description/category return $i'
    PASSING BY REF T.DESCRIPTION AS "t" RETURNING SEQUENCE)
    AS VARCHAR(128))) FROM
    xmlproduct AS t
  2. Теперь вызываем представление из приложения:
    $stmt = db2_exec($conn, "SELECT * FROM Categories>");
    while(list($cat) = db2_fetch_array($stmt)) {
    echo "<a href=\"catalog.php?category=" . urlencode($cat) . "\">$cat</a><br/>"; }

Реляционная СУБД без поддержки XML

Создаем список неповторяющихся категорий из таблицы изделий:

$stmt = db2_exec($conn, "SELECT DISTINCT(category) FROM SQLPRODUCT");
while(list($cat) = db2_fetch_array($stmt)) {
echo "<a href=\"catalog.php?category=" . urlencode($cat) . 
     "\">$cat</a><br/>";}

Код приложения в обоих случаях аналогичен. Создание представления XML-данных помогает отделить XML-структуру данных об изделии от кода приложения, что позволит нам без сложностей сделать запрос к представлению. Для того чтобы найти элемент «торговая марка», потребовалось бы изменить запрос XQuery в представлении, и точно так же потребовалось бы вызвать SQL, чтобы проверить столбец Торговая марка.

Влияние развития схемы на списки указателя

По просьбе покупателей, нам нужно предоставить пользователям возможность просматривать на Web-сайте посеребренные или выполненные из серебра 925 пробы изделия. Давайте посмотрим, какой эффект даст добавление к указателю подкатегорий: XML Schema, реляционная схема, запросы и код приложения PHP.

Действие на схему XML и экземпляр документа

В категорию элемента в XML-схеме изделия добавляется новый атрибут (catx). Все новые документы XML для изделий теперь будут иметь этот атрибут, со значением, соответственно, 925 проба (sterling) или посеребренный (silverplated):

<category catx="silverplated">Miscellaneous</category>

Действие на реляционную схему

  • DB2 Viper
    Поскольку документ XML хранится в отдельном столбце, не требуется вносить изменения в реляционную схему.
  • Реляционная СУБД без поддержки XML
    В чисто реляционной базе данных вам потребуется изменить схему таблицы изделий, добавив еще один столбец (catx). Это может повлечь за собой потерю и необходимость повторной вставки всех документов на изделия.

Действие на запросы

  • DB2 Viper The XQuery needed to create the index would change to include this new attribute in the criteria. Аналогично, запросы XQuery, которые использовались для создания списка товаров на основании выбора в указателе, тоже должны быть изменены для включения в новые критерии.
  • Реляционная СУБД без поддержки XML
    Предложение Insert изменится, в него нужно включить новый столбец.

Изменение запроса, необходимого для создания индекса: новый столбец включается в предложение WHERE. Аналогично, запросы XQuery, которые использовались для создания списка товаров на основании выбора в указателе, тоже должны быть изменены для включения в новые критерии.

Действие на код приложения

  • DB2 Viper
    Без изменений.
  • Реляционная СУБД без поддержки XML
    • Требуется дописать программный код DOM, чтобы распределить информацию из подкатегории.
    • Необходимы дополнительные параметры в предложении INSERT.
    • Возможно, впоследствии потребуется повторная вставка всех данных, что вызовет замедление работы системы для конечного пользователя.

Отображение списка элементов при нажатии пользователя на категории или торговой марке

Если пользователь нажимает мышью на категории или марке, отображается список всех товаров в этой категории или список товаров данной торговой марки. Для каждого товара в списке имеется краткое описание и URL миниатюры изображения. Этот список форматируется и отображается на главной странице.

Рисунок 6. Список товаров в категории
Список товаров в категории

DB2 Viper

В DB2 запрос XQuery не только создает списки, но также преобразует их в вывод в формате HTML, который может быть непосредственно воспринят браузером. Эта функция XQuery позволяет поместить в стек не только компоненты бизнес-логики, но также компоненты публикации на сервере базы данных, что, в сущности, делает приложение среднего уровня очень простым и лаконичным. Это идеальная причина использовать РНР, а не Java ™ или VS .NET®.

$xquery =for $i in $t/product
let $thumb := $i/description/images/image[@type="thumbnail"]
where $i/description/category = " . htmlentities($category) . "
return
<div class="float">
<a href="product.php?pid={$i/@pid}">
<img border="0" src="data/images/{$thumb}.jpg" height="100" width="100"/>
</a>
<p> <a href="product.php?pid={$i/@pid}">{$i/description/name}
    </a> </p>
    </div>;>

    $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY(
    $xquery' PASSING BY REF T.DESCRIPTION AS \"t\"
    RETURNING SEQUENCE) AS CLOB(32K)) FROM xmlproduct AS t");

    db2_execute($stmt);
    while(list($product) = db2_fetch_array($stmt)){echo $product;}

Изучив приведенный выше программный код, мы увидим, что код РНР сократился до двух строк, в то время как запрос к базе данных содержит большую часть логической схемы.

Примечание: нам нужно экранировать любые входящие переменные CGI, использующие сущности HTML (например, категории), чтобы при включении в запрос XQuery они не содержали никаких недопустимых неэкранированных сущностей.

Хотя XQuery может выполнять преобразования для публикации, во многих случаях такие действия могут оказаться нежелательными. Было бы более правильным по соображениям проекта, производительности и стиля для создания окончательной Web-страницы использовать преобразования XSLT в среднем слое или в клиентском приложении. В большинстве ситуаций более удобным будет объединить эти два условия в одном запросе. Использование XQuery не создает разработчикам препятствий в применении XSLT для преобразований. Приведенный здесь пример – эта наша попытка показать, что XQuery способен не только на поиск данных, но и на выполнение сложной бизнес-логики и преобразований этих данных.

Реляционная СУБД без поддержки XML

Сначала мы делаем запрос к базе данных, чтобы получить набор записей для всех товаров, которые соответствуют выбранной категории:

<?php
$sql = "SELECT P.Pid, P.Name, I.Location FROM sqlproduct P, sqlimages I WHERE P.Category = ? AND I.Pid = P.Pid AND I.Type = ?"); $stmt = db2_prepare($conn, $sql);
db2_execute($stmt, array($category, "thumbnail"));

Затем мы просматриваем результирующее множество и создаем Web-страницу при помощи PHP:

while(list($prodPid, $prodName, $prodImg) = db2_fetch_array($stmt)) {
?>
<div class="float">
<a href="product.php?pid=<?php echo $prodPid ?>">
<img border="0" src="data/images/<?php echo $prodImg ?>.jpg" height="100" width="100"/>
</a>
<p> <a href="product.php?pid=<?php echo $prodPid ?>"><?php echo $prodName ?></a></p>
</div>
<?php
}
?>

Хотя код для публикации очень похож на запрос XQuery, существенное различие заключается в том, что код выполняется и управляется в среднем звене, а не на сервере базы данных. Поэтому, если запрос XQuery был зарегистрирован на сервере базы данных как хранимая процедура, он управляется как часть базы данных. На следующем этапе мы увидим, как это осуществить.

Свойства изделия

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

Рисунок 7. Свойства изделия
Свойства изделия

DB2 Viper

Запрос XQuery, который создает страницу свойств изделия, сохраняется как хранимая процедура.

Использование хранимых процедур для создания страницы свойств изделий

Хранимая процедура getProduct написана на SQL/PL и принимает в качестве аргумента идентификатор изделия; она возвращает курсор набора записей. Хранимая процедура обычно выполняет запрос XQuery, который генерирует раскладку, где свойства изделия показываются вместе с изображением, а дополнительные миниатюры - сбоку страницы.

CREATE PROCEDURE getProduct(IN id VARCHAR(10))
DYNAMIC RESULT SETS 1 LANGUAGE SQL BEGIN BEGIN DECLARE c_cur CURSOR WITH RETURN FOR SELECT XMLSERIALIZE(XMLQUERY(for $i in $t/product let $thumb := $i/description/images/image[@type="thumbnail"] let $name := $i/description/name/text() let $details := $i/description/details/text() let $price := $i/description/price let $size := $i/description/size return <div id="Product"> <h2>{$name}</h2> { for $j in $i/description/images/image[@type != "thumbnail"][1] return <div class="ProductImageMain"> <img name="mainPic" border="0" src="data/images/{$thumb}.jpg" width="200"/> </div> } <p id="ProductDetails"> <strong>Details: </strong> {$details}<br/> <br/> <strong>Price: </strong> ${$price/text()}<br/><br/> <strong>Size: </strong> {$size/text()} {$size/@units/text()} <br/><br/> <a href="cart.php? action=add&pid={$i/@pid}" >Click here to Buy</a><br/> </p> <div id="ProductImages"> { for $j in $i/description/images/image[@type != "thumbnail"] [position() != 1] return <div class="ProductImageExtra"> <a href="javascript:void()" onMouseover="document.mainPic.src= data/images/{$j/text()}.jpg''" onMouseout="document.mainPic.src=
data/images/{$i/description/images/image[@type != "thumbnail"][1]}.jpg''"> <img border="0" src="data/images/{$j/text()}.jpg" width="100"/> </a> </div> } </div> </div> PASSING T.DESCRIPTION AS "t" RETURNING SEQUENCE) AS CLOB(32K)) FROM xmlproduct T WHERE Pid = id;
OPEN c_cur; END; END

Примечание: в запросах XQuery не нужно экранировать символ амперсенда. Это касается всех специальных символов.

Важно: поскольку XQuery работает с типами XML, во всех возвращаемых данных специальные символы будут экранированы. Один из обходных способов - это привести возвращаемые данные запроса к типу VARCHAR при помощи функции приведения.

Код приложения

$stmt = db2_prepare($conn, "CALL getProduct(?)");
db2_execute($stmt, array($pid));
list($product) = db2_fetch_array($stmt);
echo $product;

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

Реляционная СУБД без поддержки XML

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

  1. Делаем выборку свойств изделия из таблицы изделий:
    $stmt = db2_prepare($conn, "SELECT P.Name, P.Details, P.Price, 
    	P.Size, I.Location, I.Alias FROM sqlproduct P, sqlimages I 
    	WHERE P.Pid = ? AND P.Pid = I.Pid AND I.Type = ? 
    	FETCH FIRST ROW ONLY");
    	
    db2_execute($stmt, array($pid, full'));
    list($prodName, $prodDetails, $prodPrice, $prodSize, $prodImgThumb,
    $prodImgAlias) = db2_fetch_array($stmt);
  2. Теперь создаем отображаемый вывод, для чего помещаем в данные теги HTML:
    <div id="Product">
    <h2><?php echo $prodName ?></h2>
    <div class="ProductImageMain">
    <img border="0" src="data/images/<?php echo $prodImgThumb ?
    >.jpg" width="200"/>
    </div>

    Здесь можно без труда отобразить смешанный код PHP и HTML, воспользовавшись конструкцией <?phpand?>:

    <p id="ProductDetails">
    <strong>Details: </strong> <?php echo $prodDetails ?><br/> <br/>
    <strong>Price: </strong> $<?php echo $prodPrice ?><br/> <br/>
    <strong>Size: </strong> <?php echo $prodSize ?><br/> <br/>
    <a href="cart.php?mode=sql&action=add&pid=<?php echo $pid ?>
    ">Click here to Buy</a><br/>
    </p>
    <div id="ProductImages">
  3. Запрашиваем изображения, связанные с данным изделием, и добавляем их URL к выводимой Web-странице:
    <?php
    $stmt = db2_prepare($conn, "SELECT DISTINCT(Location) FROM sqlimages WHERE Pid = ? AND Type = ? AND NOT Location = ?"); db2_execute($stmt, array($pid, full', $prodImgThumb)); while(list($prodImg) = db2_fetch_array($stmt)) {
    ?> <div class="ProductImageExtra"> <img border="0" src="data/images/<?php echo $prodImg ?>.jpg" width="100"/> </div> <?php } ?> </div> </div>

Поскольку данные об изделии были распределены по двум таблицам, и код PHP был смешан с кодом HTML, нам нужно выполнить два разных запроса, чтобы получить подробное описание изделия и данные о расположении изображений.

Корзина

Корзина – это неотъемлемый компонент любого интернет-магазина, поэтому данная утилита идеальна для существования в форме Web-сервиса. Web-сервис может быть настроен на расчет цены, налогов, пересчет валют, расходов на пересылку и так далее. В нашем учебном примере мы создали Web-сервер, воспользовавшись для расчета цен и налогов PHP и XQuery.

Товары, добавляемые в корзину покупателем, сохраняются как файлы cookie на стороне клиента. Файлы cookie считываются в PHP как ассоциативная матрица и присваиваются переменной $cart.

Рисунок 8. Корзина
Корзина

DB2 Viper

Источник для Web-сервиса и запрос

  1. Мы снова воспользовались XQuery, чтобы встроить средства компоновки вывода и бизнес-логики в один запрос. Web-сервис, наряду с информацией корзины, которая представляет собой XML-документ, содержащий идентификатор изделия и соответствующие количества, также принимает аргумент значения налога с продаж. Благодаря этому, можно передать «корзину» как значение XML непосредственно в запрос Xquery:
    <?php
    function getCart($cart, $taxrate) { global $conn; $result = ""; $xquery = for $dummy in (1)
  2. В запросе XQuery переменная $cart может итерироваться, точно так же, как любой другой XML-документ:
    let $items := for $i in $cart/items/item
    let $product := db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")
    /product[@pid = $i/@pid]/description
    let $name := $product/name/text()
    let $price := $product/price/text()
    let $itemPrice := if($price = 0 or empty($price)) then ("$0.00") 
    else (concat("$", $price))
    return
    <tr>
  3. Для каждого товара вычисляем итоговую цену товара, используя информацию о количестве, переданную из корзины, и информацию о цене, полученную из каталога изделий в базе данных:
    <noframes>{$price * $i/@quantity}</noframes>
    <td class="itemDetails">
    <a href="product.php?mode=xml&pid={$i/@pid}">{$name}</a>
    </td>
    <td class="itemQuantity">
    {xs:integer($i/@quantity)}
    <br/>
    <a href="cart.php?mode=xml&action=del&pid=
    {$i/@pid}">Remove</a>
    </td>
    <td class="itemPrice">
    {$itemPrice}
    </td>
    </tr>
    return
    <x>
  4. Возвращаем XML (XHTML)-структуру, содержащую расчет цены для каждого товара вместе с информацией о публикации:
    {$items}<tr><td class="itemDetails"> </td><td class="itemQuantity">
    <strong>Subtotal</strong></td><td class="itemPrice">
  5. Вычисляем итоговую цену для каждого товара в корзине из возвращаемой структуры: В действительности мы используем вывод части запроса в качестве входной переменной следующей части запроса:
    Total all
    <strong> ${ sum( $items/noframes/text() ) } </strong>
    </td></tr><tr>
    <td class="itemDetails"> </td>
    <td class="itemQuantity"><strong>Tax 
    ({$tax * 100}%)</strong></td>
    <td class="itemPrice">
  6. Воспользуемся переменной налога, переданной Web-сервису из клиентского приложения, для расчета платежа.

    Примечание: сумму всех товаров, которая была вычислена на предыдущих этапах, не следует присваивать переменной при помощи предложения let. Эта переменная может затем использоваться при расчете налогов и общей суммы платежа.

    <strong> ${ xs:decimal(sum($items/noframes/text())) 
    * $tax } </strong></td></tr><tr>
    <td class="itemDetails"> </td>
    <td class="itemQuantity"><strong>
    Grand Total</strong></td>
    <td class="itemPrice">
    <strong> ${ xs:decimal(sum($items/noframes/text())) * (1 + $tax) } <
    /strong></td></tr></x>;

    В качестве упражнения предлагаем читателям переписать внешнее выражение для цикла более элегантным образом;

  7. Хотя XQuery не поддерживает связывание параметра рабочего цикла, это можно обойти. Параметры рабочего цикла могут быть переданы в XQuery при помощи предложения функции XQuery PASSING BY:
    $stmt = db2_prepare($conn, "VALUES( XMLSERIALIZE( 
    XMLQUERY($xquery' PASSING BY
    REF CAST(? AS XML) AS \"cart\" , CAST(? AS DECIMAL
    (10,8)) AS \"tax\" RETURNING SEQUENCE) AS CLOB(32K)))");

    Обратите внимание, что информация корзины передается в запрос как строка XML. Строка преобразуется в тип XML при помощи функции CAST (? As XML);

  8. Если запрос регистрируется как хранимая процедура, то РНР-код, который требуется для запуска этого Web-сервиса, сокращается до следующих двух строк:
    if($stmt) {
    if(!db2_execute($stmt, array($cart, $taxrate))) {
    return db2_stmt_errormsg($stmt);
    }
    list($result) = db2_fetch_array($stmt);
    if(!$result) return db2_stmt_errormsg($stmt);
    } else {
    $result = db2_stmt_errormsg();
    }return $result;}
  9. Регистрируем Web-сервис:
     $server = new SoapServer(null, array(uri' =
       > http://ibm.com/db2/xml/php'));
    $server->addFunction(getCart');
    $server->handle(); ?>

Как вы можете видеть из приведенного выше примера кода, создать Web-сервис при помощи PHP и встроенной поддержки XML DB2 очень просто. Более того, нам не нужно определять документ WSDL (Web Services Description Language, язык описания Web-сервисов) именно благодаря простоте реализации нашей службы.

Клиент Web-сервиса

Теперь Web-сервис может быть вызван из кода приложения-клиента для отображения информации корзины на Web-сайте. Сама корзина представляет собой клиентское приложение, которое вызывает Web-сервис.

  1. Создаем строку XML для информации корзины, которая будет передана в качестве аргумента Web-сервису:
    <?php
    $cartXML = "<items>"; foreach($cart as $cpid => $quantity) { $cartXML .= "<item pid=\"$cpid\" quantity=\"$quantity\"/>"; } $cartXML .= "</items>";
  2. Подключаемся к Web-сервису:
    $client = new SoapClient(null, array(location' => 
        http://127.0.0.1/cartsvc.php',
    uri' => http://ibm.com/db2/xml/php'));
    $taxrate = 0.0;
  3. Вызываем Web-сервис и выводим возвращенную строку в браузер:
    echo $client->getCart($cartXML, $taxrate); ?>

Примечание: поскольку корзина реализована как Web-сервис, она может быть вызвана из приложения, написанного на любом языке.

Реляционная СУБД без поддержки XML

Реляционный вариант данного примера не содержит Web-сервис или расчет налога с продаж. Хотя запрос выглядит проще, чем запрос XQuery, мы должны запросить базу данных по каждому товару в корзине, в результате чего увеличивается трафик базы данных и несколько усложняется код приложения, связанный с циклом. Создание Web-сервиса из реляционного фрагмента не вызовет сложностей вследствие простоты, с которой Web-сервис может быть написан в PHP. Как и в версии XML, функция getCart принимает информацию корзины в качестве аргумента, формат которого нужно определить заранее. Если это будет значение XML, то для чтения информации корзины придется использовать DOM, или, возможно, ассоциативную матрицу из вышеприведенного кода, но с небольшими изменениями. С другой стороны, если бы вы хотели создать хранимую процедуру, которая отображает корзину при помощи реляционной базы данных, вам потребуется конкатенация содержимого HTML с данными, полученными из базы. Эта работа может потребовать достаточно труда, чтобы сделать вывод о том, что лучше хранить код представления за пределами хранимой процедуры, но в приложении.

<?php
foreach($cart as $pid => $quantity) { $stmt = db2_prepare($conn, "SELECT Name, Price FROM sqlproduct WHERE Pid = ?"); db2_execute($stmt, array($pid)); if($stmt) { list($prodName, $prodPrice) = db2_fetch_array($stmt); ?> <tr> <td class="itemDetails"> <a href="product.php?pid=<?php echo $pid ?>"><?php echo $prodName ?></a> </td> <td class="itemQuantity"> <?php echo $quantity ?> <br/> <a href="cart.php?action=del&pid=<?php echo $pid ?>">Remove</a> </td> <td class="itemPrice"> $<?php echo $prodPrice ?> </td> </tr> <?php}}?>

Бланк заказа

После того, как пользователь выбрал ссылку «подтвердить», информация корзины передается в приложение, и из тех товаров, которые были куплены, генерируется XML-документ бланка заказа.

Код XML и реляционный код для создания бланка заказа почти идентичны, единственное различие – это запрос на поиск текущей цены данного изделия.

$stmt = db2_prepare($conn, "VALUES (NEXT VALUE FOR POid)");
db2_execute($stmt);
list($POid) = db2_fetch_array($stmt);
foreach($cart as $pid => $quantity) {
$xquery = $t/product/description/price/text()';
$stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY($xquery' PASSING BY REF
T.DESCRIPTION AS \"t\" RETURNING SEQUENCE) AS VARCHAR(8)) FROM xmlproduct
AS t WHERE Pid = ?");
db2_execute($stmt, array($pid));
list($price) = db2_fetch_array($stmt);

Хотя мы могли бы использовать DOM для создания бланка заказа, в этом случае проще воспользоваться конкатенацией фрагментов XML.

$PO .= " <item pid=\"$pid\" quantity=\"$quantity\" price=\"$price\"/>\n";}
$stmt = db2_prepare($conn, "INSERT INTO xmlporder (POid, POrder) VALUES (?, ?)");
db2_execute($stmt, array($POid, $PO));

Бланк заказа (PO) сохраняется в реляционной базе данных как объект GLOB (а не распределяется). Преимущество целостного хранения заключается в том, что любое развитие схемы, обусловленное изменениями в бланке заказа (дополнительная информация, например, о доставке), является безболезненным. Хранение бланка заказа как объекта GLOB дает возможность использовать модель DOM в коде приложения для извлечения значимой информации. Но выигрыш в простоте реляционного хранения и развитии схемы имеет обратную сторону в виде снижения производительности запроса, в чем мы имели случай убедиться, когда пытались создать отчет об истории покупки.

Накладная

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

Рисунок 9. Накладная
Накладная

DB2 Viper

  1. Мы снова воспользуемся одним запросом XQuery для создания окончательной накладной:
    $xquery =
    for $po in $t/purchaseOrder
    let $sum := for $item in $po/items/item 
    return $item/@quantity * $item/@price
    let $items := for $item in $po/items/item
  2. Для получения подробной информации об изделии создаем соединение между бланком заказа и таблицей изделий:
    let $name := for $i in db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")/product 
    where $i/@pid = $item/@pid return $i/description/name/text()
    return
    <tr><td class="itemDetails">
    {$name}
    </td><td class="itemQuantity">
    {xs:string($item/@quantity)}
    </td><td class="itemPrice">
    ${xs:string($item/@price)}
    </td></tr>
    
    return
    <x>
    {$items}
    {$po/text()}
    <tr><td class="itemDetails"> </td>
    <td class="itemQuantity"><strong>Total</strong></td>
    <td class="itemPrice"><strong>${sum($sum)}</strong></td>
    </tr></x>;

Интересно отметить, что показанный выше запрос XQuery похож на тот, что мы использовали ранее для отображения содержимого корзины:

$stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY($xquery' PASSING BY REF
T.PORDER AS \"t\" RETURNING SEQUENCE) AS CLOB(32K)) FROM
xmlporder AS t WHERE POid = ?");
db2_execute($stmt, array($id));
list($po) = db2_fetch_array($stmt);
echo $po;

Обратите также внимание на то, что объем кода PHP для приложения минимален, поскольку большая часть компонентов бизнес-логики и преобразования содержатся в запросе.

Реляционная СУБД без поддержки XML

  1. $stmt = db2_prepare($conn, "SELECT POrder FROM sqlporder WHERE POid = ?");
    db2_execute($stmt, array($id));
    $sum = 0.0;
    while(list($po) = db2_fetch_array($stmt)) {
  2. Поскольку бланк заказа хранится как объект CLOB, нам нужно воспользоваться моделью DOM, чтобы получить доступ к каждому изделию, его количеству и цене. Для извлечения данных из бланка заказа используйте простую модель DOM:
    $dom = simplexml_load_string($po);
    foreach($dom->items->item as $item) {
    $cpid = (string) $item[pid'];
    $price = (float) $item[price'];
  3. Прослеживаем итоговую цену товара в каждой строке таблицы HTML:
    $sum += $price * (integer) $item[quantity'];
  4. Для поиска названия каждого товара необходим отдельный запрос к базе данных:
    $stmt2 = db2_prepare($conn, "SELECT Name FROM sqlproduct WHERE Pid = ?");
    db2_execute($stmt2, array($cpid));
    if($stmt2) {
    list($prodName) = db2_fetch_array($stmt2); ?>
    <tr> <td class="itemDetails"> <?php echo $prodName ?> </td> <td class="itemQuantity"> <?php echo $item[quantity'] ?> </td> <td class="itemPrice"> $<?php echo $price ?> </td> </tr> <?php}}}

Реляционная версия кода вводит в приложение больше логических компонентов.

Генерация отчета об истории заказов покупателя

Покупатель может просмотреть список своих покупок, нажав ссылку Order history в указателе:

Рисунок 10. Order history (История заказов)
Order history (История заказов)

DB2 Viper

  1. Для возвращения списка покупок данного клиента с сортировкой по дате мы используем SQL/XML. Для каждого бланка заказа выполняется запрос XQuery, который возвращает форматированный результат промежуточной суммы каждого изделия:
    $xquery =
    for $po in $t/purchaseOrderlet $items := for $item in $po/items/item
  2. Чтобы отобразить название каждого изделия, внутри запроса XQuery мы выполняем соединение, поскольку бланк заказа сохраняет только идентификатор изделия, цену и количество:
    let $name := for $i in db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")/product
    where $i/@pid = $item/@pid return $i/description/name/text()
    return
    <p><pre>{xs:string($item/@quantity)} x @ ${xs:string($item/@price)} 	 
    {$name}</pre></p>
    return
    <x>
    <h3>Order #{xs:string($po/@id)} placed on {xs:string($po/@orderDate)}</h3>
    {$items}
    </x> ;
    
    $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY
    ($xquery' PASSING BY REF
    T.PORDER AS \"t\" RETURNING SEQUENCE) AS CLOB(32K)) 
    FROM xmlporder AS t
    ORDER BY POid DESC");
    db2_execute($stmt);
    while(list($po) = db2_fetch_array($stmt)) {echo $po; }

Реляционная СУБД без поддержки XML

  1. В реляционном варианте мы должны выполнить один запрос, чтобы получить список изделий в каждом бланке заказа:
    $stmt = db2_prepare($conn, "SELECT POid, POrder FROM sqlporder 
    ORDER BY POid DESC");
    db2_execute($stmt);
    while(list($POid, $po) = db2_fetch_array($stmt)) {
  2. Из-за того, что бланк заказа хранится в реляционной базе данных в виде объекта CLOB, нам придется использовать модель DOM, чтобы получить доступ к дате заказа и отдельным изделиям. Здесь снова на помощь приходит функция SimpleXML PHP 5:
    $dom = simplexml_load_string($po);
    ?>
    <h3>Order #<?php echo $POid ?> 
    placed on <?php echo $dom[orderDate'] ?></h3>
    <?php
    foreach($dom->items->item as $item) {
  3. Мы должны запросить свойства для каждого изделия, в данном случае, название изделия:
    $stmt2 = db2_prepare($conn, "SELECT Name FROM sqlproduct WHERE Pid = ?");
    db2_execute($stmt2, array( (string) $item[pid'] ));
    while(list($prodName) = db2_fetch_array($stmt2)) {
    ?>
    <pre><?php echo $item[quantity'] ?> x @ $<?php echo $item[price'] ?> 
         	 <?php echo $prodName ?></pre>
    <?php}}}

Индексы XML

Хотя мы не создали ни одного реляционного индекса, давайте создадим некоторые индексы XML, чтобы понять, как встроенная поддержка XML DB2 позволяет создать индекс из любого элемента или атрибута в документе. Каждый документ изделия имеет уникальный идентификатор изделия, а также другую важную информацию, которая обычно используется браузером в процессе просмотра каталога; это категория, торговая марка и название. Для столбца XML изделия мы создадим четыре следующих индекса:

CREATE UNIQUE INDEX prod_pid ON xmlproduct(description) GENERATE KEY USING
	XMLPATTERN /product/@pid' AS SQL VARCHAR(10)

CREATE INDEX prod_name ON xmlproduct(description) GENERATE KEY USING
	XMLPATTERN /product/description/name' AS SQL VARCHAR(128)

CREATE INDEX prod_category ON xmlproduct(description) GENERATE KEY USING
	XMLPATTERN /product/description/category' AS SQL VARCHAR(128)

CREATE INDEX prod_brand ON xmlproduct(description) GENERATE KEY USING
	XMLPATTERN /product/description/brand' AS SQL VARCHAR(128)

Как видите, можно создать индекс как из атрибута, так и из элемента.


Настройка среды для запуска приложения

Настройка сервера Apache и PHP

Сначала нам нужно настроить среду разработки PHP и Web-сервер, чтобы выполнять сценарии PHP на стороне сервера. Данные инструкции ориентированы на операционную систему Windows, но код выполняется в неизмененном виде в среде Linux или на других UNIX-платформах. О том, как настроить модуль PHP для работы с сервером Apache, смотрите в документации на PHP.

  1. Убедитесь, что у вас установлены клиентские библиотеки DB2 версии 8.2 или более поздние;
  2. Загрузите и установите последнюю версию сервера Apache c сайта http://httpd.apache.org/. Для целей разработки лучше не устанавливать Apache как сервис, иначе вы обнаружите, что его приходится слишком часто перезапускать. Запустите Apache и перейдите на адрес http://localhost/ , чтобы убедиться, что программа работает;
  3. Загрузите zip-архив с последней стабильной версией PHP 5 и распакуйте его в папку c:\php;
  4. Загрузите коллекцию модулей PECL (PHP Extension CommunityLibrary) с той же страницы. Распакуйте zip-архив в папку c:\php\ext;
  5. Скопируйте файл c:\php\php.ini-dist в c:\php\php.ini и откройте в любом текстовом редакторе.
    1. Найдите строку параметра extension_dir и измените ее на:
      extension_dir = "c:/php/ext/"
    2. Найдите раздел Dynamic Extensions и добавьте следующие строки:
      extension=php_ibm_db2.dll
      extension=php_soap.dll
  6. Откройте конфигурационный файл Apache httpd.conf в текстовом редакторе;
    1. Найдите раздел Dynamic Shared Object (DSO) Support и в конце списка директив LoadModule добавьте следующие строки:
      LoadModule php5_module "c:/php/php5apache2.dll"
      AddType application/x-httpd-php .php
      AddType application/x-httpd-php-source .phps
      PHPIniDir "c:/php"
    2. Найдите директиву DirectoryIndex и добавьте в список index.php:
      DirectoryIndex index.php index.html index.html.var;
  7. Возможно, вам захочется удалить файлы, включенные в каталог установки Apache htdocs (значение директивы DocumentRoot). Создайте в каталоге htdocs новый файл info.php следующего содержания:
    <?php phpInfo(); ?>;
  8. Запустите Apache и перейдите на адрес http://localhost/info.php. Если, просматривая страницу, вы видите параметры конфигурации ibm_db2, значит, вы успешно настроили Apache, PHP и драйвер ibm_db2.

Настройка кода приложения

Перед тем как запускать присоединенное приложение, убедитесь, что вы имеете рабочее Web-окружение с поддержкой PHP. Клиентская часть приложения была разработана для правильного отображения в браузере Mozilla Firefox; поэтому, возможно, вы будете испытывать неудобства при использовании другого браузера. Выполните следующие действия для настройки и запуска приложения:

  1. Начните с загрузки zip-файла, указанного в конце данной статьи, и распакуйте его в каталог htdocs (обычно C:\Program Files\Apache Group\Apache\htdocs) Создайте каталог silvercastles;
  2. На сервере базы данных, который вы используете, создайте базу данных с именем silver. Чтобы функции XML в DB2 работали, вам следует явно задать для базы данных формат Unicode:
    CREATE DATABASE silver USING CODESET utf-8 TERRITORY us;
  3. Если вы хотите создать каталогизированное подключение к базе данных, следует выполнить на локальном компьютере в Command Window DB2 следующие команды:
    CATALOG TCPIP NODE myNode REMOTE serverAddr SERVER serverPort
    CATALOG DB silver AT NODE myNode
    Аргументы serverAddr и serverPort следует заменить, соответственно, на название или IP-адрес вашего сервера базы данных и его порт TCP/IP (переменная конфигурации администратора базы данных SVCENAME). Если переменная SVCENAME не установлена на сервере, вам нужно, перезапустив DB2, установить ее на незанятом порту:
    $ db2 UPDATE DBM CFG USING SVCENAME 12345
    $ db2stop ; db2start
  4. Отредактируйте файл config.php и измените соответствующие значения. Убедитесь, что при необходимости вы экранировали символы, когда изменяли код PHP;
    1. $basedir: путь к каталогу silvercastles (чтобы избежать необходимости экранировать путь, используйте косую черту, а не обратную косую черту, например: C:/Program Files/Apache Group/Apache/htdocs/silvercastles)
    2. $dbname: имя базы данных;
    3. $dbuser: имя пользователя, которому разрешено подключаться к базе данных;
    4. $dbpass: пароль пользователя.

Если вы используете некаталогизированное подключение к базе данных, вам необходимо также изменить следующие значения:

    1. $dbhost: имя или IP-адрес сервера вашей базы данных;
    2. $dbport: номер порта сервера;
  1. Сохраните настройки и введите в адресную строку браузера http://localhost/setup.php, чтобы приступить к созданию XML и реляционных таблиц и вставке данных. Для продолжения работы с интернет-магазином перейдите по ссылке Continue.

Загрузка

ОписаниеИмяРазмер
Source code and data for the scenariosilvercastles.zip  ( HTTP | FTP )7000 KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management, XML, SOA и web-сервисы
ArticleID=151619
ArticleTitle=Совместное использование встроенной поддержки XML в DB2 и PHP
publish-date=10272005