Jak vytvořit XML zboží v ZenCart

Nastane čas kdy se struktura zboží (počet položek) vezme za své a zjístíte že máte hodně zboží a velké popisky a info u zboží. Zjísíte že máte omezen server ohledně paměti a časově prostě nestíháte generovat v běhu jednoho scriptu celé xml. Tento případ nastal u několika obchodů. Proto jsem se rozhodl že se na to podívám jestli by nešlo udělat změnu ve vytváření xml výpisu zboží.

V ZenCart se jedná o soubor rss.php . Tento soubor obsahuje kod pro vytvoření xml souboru pro vyhledávače a služby které nabízí zveřejnění vašeho zboží. Takové služby poskytují jyxo.cz, bezvaceny.cz, seznam.cz, centrum.cz, atlas.cz, naakup.cz, bezvaceny.cz atd. Pro tyto služby byl vytvořen tento soubor který obsahuje několik šablon pro vytvoření výpisu do xml souboru.

Celý proces vypadá následovně. Na dotaz sql se provede výběr zboží a příslušné doplňkové hodnoty jako ID zobží, popis, cena, kategorie, várobce atd. . Vše se načte v jednom balíku do paměti a pak se vytváří soubor xml. některé služby požadovali tento xml v archívu ZIP. A zde začíná problém s omezením alokace paměti na straně serveru a časový limit pro vykonání jednoho scriptu. Většina serveru má standartní nastavení 16MB nebo 32MB a časový limit 30 sec. . Pokud máte málo zboží a textu, může být vše v pořádku. Jestli máte hodně zboží v řádu 10-tisíců už to může být problém.

Podařilo se zjistit že obsah nad 10-tisíc položek a textu o velikost 1024 znaku bude dělat problém s alokaci paměti. Bohužel i ti co mají menší počty zboží mohou mít problém. Vše záleží i na nastavení serveru a jak se chová. Protože ten problém je dosti vážný, začalo se přemýšlet nad úpravou tohoto kodu php.

Změny kódu provádí následující. Načtení určitého počtu zboží,vytvoření (zápis do) soboru. Vynulování a načtení dalšího balíku položek (ale jako nový script). Tento kolotoč se provádí s kontrolou celkového počtu položek zboží. Jakmile se rozná počet položek počtu průchodu, script se zastaví.

Pro názornost uvedu příklad tvorby XML souboru pro portál centrum.cz

počet položek v obchodu: 20500
vysledný soubor: centrum.xml
počet položek v jednom načtení: 2000
velikost popisu zboží: 2048 znaků
alokace paměti na straně serveru: 16MB
čas pro vykonání scriptu: 30sec.

výsledek:

čas pro vytvoření XML souboru: cca 1min. 30sec. (test proveden 20x)
velikost souboru XML: cca 17,5 MB

upravené rss.php. (nachází se v adresáří ADMIN) Uvádím jen tu část která byla upravena. Button odkaz.

<tr>
<td class="main" width="15%" align="left" valign="top">
Centrum RSS
</td>
<td class="main" align="left" valign="middle">
<?php echo '<a href="' . zen_href_link(FILENAME_RSS,
'action=centrum&a=0') . '">' .
zen_image_button('button_update.gif', IMAGE_UPDATE) .

'</a>'; ?>
</tr>

upravená část vytváření XML.

<?php
switch($action) {
case ('centrum'):
?>
<?php
$a=($_GET["a"]);
if ($a==0){
$text= '<?xml version="1.0" encoding="' . CHARSET . '"?>';
$filename = "../rss/centrum.xml";
$fd = fopen ($filename, "wb");
$out = fwrite ($fd, $text);
fclose ($fd);
$text.= "";
}
if (!isset($_GET["start"])){
$filename = "../rss/centrum.xml";
$fd = fopen ($filename, "wb");
$out = fwrite ($fd, $text);
fclose ($fd);
$text= "";
$start = 0;
echo "start :".$start;
}
else {
$start=$_GET["start"];
}
$counts = $db->Execute("SELECT count(*) as number_active FROM " .
TABLE_PRODUCTS . " WHERE products_status='1'");
$sql_products .= "select p.products_id, pd.products_name, pd.products_description,
p.products_price, p.products_tax_class_id, p.products_image, m.manufacturers_name ";
$sql_products .= "from " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS .
" m on (p.manufacturers_id = m.manufacturers_id), ";
$sql_products .= TABLE_PRODUCTS_DESCRIPTION . " pd ";
$sql_products .= "where p.products_id = pd.products_id ";
$sql_products .= "and p.products_status = 1 and pd.language_id = '" .
$_SESSION['languages_id']. "' LIMIT $start,$limit";
$products = $db->Execute($sql_products);
if (($a)==0){
$text.= "\n<SHOP>\n";
}
while(!$products->EOF)
{
$product_id = $products->fields['products_id'];
$products_description = strip_tags($products->fields['products_description']);
if (strlen($products_description) > 2048){
$products_description = substr($products_description, 0, 2048) . '..';
}
$specials = $db->Execute("select specials_new_products_price from " .
TABLE_SPECIALS . " where products_id = '" . (int)$product_id . "' and status='1'");
if ($specials->RecordCount() > 0) {
$price = $specials->fields['specials_new_products_price'];
} else {
$price = $products->fields['products_price'];
}
$categories = $db->Execute("select c.categories_name from " .
TABLE_CATEGORIES_DESCRIPTION . " c, " . TABLE_PRODUCTS_TO_CATEGORIES .
" f where f.products_id = '" . (int)$product_id . "' and f.categories_id = c.categories_id AND
c.language_id = '" . $_SESSION['languages_id']. "'");

$tax_rate=zen_get_tax_rate_value($products->fields['products_tax_class_id']);
//$link = HTTP_SERVER.DIR_WS_CATALOG."index.php?main_page=".
zen_get_info_page($products->fields['products_id']). '&amp;products_id=' .
$products->fields['products_id'];

//$link = HTTP_SERVER.DIR_WS_CATALOG. zen_catalog_href_link;
$link = zen_seo_href_link(zen_get_info_page($products->fields['products_id']),
'products_id=' . $products->fields['products_id'], 'NONSSL', false);

$text.= " <SHOPITEM>\n";
$text.= " <MANUFACTURER>" . clean($products->fields['manufacturers_name']) .
"</MANUFACTURER>\n";

$text.= " <PRODUCT>" . clean($products->fields['products_name']) . "</PRODUCT>\n";
$text.= " <DESCRIPTION>" . clean($products_description) . "</DESCRIPTION>\n";
$text.= " <URL>" . $link . "</URL>\n";
$text.= " <PRICE>". $price . "</PRICE>\n";
$text.= " <PRICE_VAT>" . ((($price)*($tax_rate+100))/100) . "</PRICE_VAT>\n";
$text.= " <VAT>" . ($tax_rate/100) . "</VAT>\n";
$text.= " <CATEGORYTEXT>" . clean($categories->fields['categories_name']) .
"</CATEGORYTEXT>\n";

$text.= " <IMGURL>".HTTP_SERVER.DIR_WS_CATALOG.DIR_WS_IMAGES.
$products->fields['products_image'] . "</IMGURL>\n";

$text.= " </SHOPITEM>\n";
$a = $a+1;
//echo ":- ".$a;
$products->MoveNext();
}
$pocet=$counts->fields['number_active'];
echo "celkem zaznamu: ".$pocet."";
if (($start+$limit)>= $pocet || ($start+$limit) == $pocet){
$filename = "../rss/centrum.xml";
$fd = fopen ($filename, "ab");
$out = fwrite ($fd, $text);
fclose ($fd);
$text.= "";
}
else {
$c=$start+$limit;

echo "C-- ".$c;
echo "<script type='text/javascript'>window.location.
replace('rss.php?action=centrum&start=$c&a=$a')</script>";

}
if (($a == $pocet)){
$text.= "</SHOP>";
$filename = "../rss/centrum.xml";
$fd = fopen ($filename, "ab");
$out = fwrite ($fd, $text);
fclose ($fd);
$text.= "";
}else{
$filename = "../rss/centrum.xml";
$fd = fopen ($filename, "ab");
$out = fwrite ($fd, $text);
fclose ($fd);
$text.= "";
}
// $zipfile = new zipfile();
// $filedata = $text;
// $zipfile -> add_file($filedata, "centrum.xml");
// $filename = "../rss/centrum.zip";
// $fd = fopen ($filename, "wb");
// $out = fwrite ($fd, $zipfile -> file());
// fclose ($fd);
echo '<br><b>XML CENTRUM vytvořeno!</b><br>Celkem: ' .
$counts->fields['number_active'] . ' produktů.<br>';

break;

Zakomentované řádky můžete i klidně smazat. Jedná se o původní kód.

Informační technologie: 
Rok: 
Zlaté ručičky: