Avatar billede mmalling Nybegynder
12. januar 2012 - 00:02 Der er 14 kommentarer

Optimering af script

Iforbindelse med en webshop har jeg et script der eksportere data til diverse prissøgninger på nettet, men problemet er at det indtil nu har virket fint.
Men efter at have tilføjet flere produkter så den nu skal hente +6000 produkter ligger den serveren ned eller får timeout.
Timeout kan ikke sætte længere op..
Er det muligt at optimere scriptet...

Her er scriptet
<?php

include(dirname(__FILE__).'/config/config.inc.php');
require_once(dirname(__FILE__).'/init.php');
$max_execution_time = 60 ;



$confPasswd = '';

$tags = array(
  'name' => 'produktnavn',
  'ean13' => 'ean13', 
  'ISBN' => 'ISBN',
  'url' => 'link',
'lager' => 'LagerNiveau',
  'imageUrl' => 'billedeUrl',
  'price_inc' => 'pris',
  'description_short' => 'produktbeskrivelse',
// 'description' => 'langbeskrivelse',
  'id_product' => 'databaseid',
  'reference' => 'interntvarenummer',
  'categoryName' => 'category',
  'subCategoryName' => 'subCategory',
  'shipping_cost' => 'fragt',
  'leveringstid' => 'leveringstid',
  'manufacturerName' => 'producent',
  'supplier_reference' => 'produktID ',
'lagerstatus' => 'PaaLager ',



);


function my_strip_tags($t)
{
  $t = preg_replace('/</',' <',$t);
  $t = preg_replace('/>/','> ',$t);
  $t = preg_replace('/[\n\r\t]/',' ',$t);
  $t = preg_replace('/  /',' ',$t);
  return strip_tags($t);
}

function my_number_format($t)
{
  return number_format($t, 2, ',', '.');
}

function print_field($k, $v)
{
  global $tags;
  if (isset($tags[$k])) {
    $k = $tags[$k];
    $v = htmlspecialchars($v, ENT_NOQUOTES, "UTF-8");
    print "    <$k>$v</$k>\n";
  }
}


header("Content-Type:text/xml; charset=utf-8");
print '<?xml version="1.0" encoding="UTF-8"?>'."\n";
print "<products>\n";
$configuration = Configuration::getMultiple(array(
  'PS_LANG_DEFAULT',
  'PS_SHIPPING_FREE_PRICE',
  'PS_SHIPPING_HANDLING',
  'PS_SHIPPING_METHOD',
  'PS_SHIPPING_FREE_WEIGHT',
  'PS_CARRIER_DEFAULT'));
$id_lang = intval($configuration['PS_LANG_DEFAULT']);
$id_zone = intval($defaultCountry->id_zone);
$link = new Link();
$id_carrier = $configuration['PS_CARRIER_DEFAULT'];
$carrier = new Carrier(intval($id_carrier));
$carrierTax = 0;
if ($carrier->id_tax) {
  $tax = new Tax(intval($carrier->id_tax));
  if (Validate::isLoadedObject($tax) AND Tax::zoneHasTax(intval($tax->id), intval($id_zone)) AND !Tax::excludeTaxeOption())
    $carrierTax = $tax->rate;
}
$passwd = Tools::getValue('passwd');
$categories = Category::getCategories($id_lang, true, false);
$manufacturers = Manufacturer::getManufacturers(false, $id_lang);
if ($passwd == $confPasswd) {
  $products = Product::getProducts($id_lang, 0, 0, 'price', 'ASC', false, true);
}
else {
  $products = array();
}
$manMap =array();
foreach ($manufacturers as $manufacturer) {
  $manMap[$manufacturer['id_manufacturer']] = $manufacturer;
}
$catMap =array();
foreach ($categories as $category) {
  $catMap[$category['id_category']] = $category;
}
foreach ($products as $product) {
  $prodObj = new Product($product['id_product'], false, $id_lang);
  $product['url'] = $link->getProductLink($prodObj);
  $cover = Product::getCover($product['id_product']);
  $product['imageUrl'] = _PS_BASE_URL_.$link->getImageLink($prodObj->link_rewrite, $product['id_product'].'-'.$cover['id_image'], 'large');
  if (intval($configuration['PS_SHIPPING_METHOD']))
    $shipping_cost = $carrier->getDeliveryPriceByWeight($product['weight'], $id_zone);
  else
    $shipping_cost = $carrier->getDeliveryPriceByPrice($product['price'], $id_zone);
  $shipping_cost *= 1 + ($carrierTax / 100);
  $shipping_cost += floatval($configuration['PS_SHIPPING_HANDLING']);
  $product['shipping_cost'] = $shipping_cost;
  $product['price_exc'] = my_number_format($prodObj->getPrice(false));
  $product['price_inc'] = my_number_format($prodObj->getPrice(true));
//  $price = $product['price'] * (1 + $product ['tax_rate'] / 100  );
//  $product['price_inc'] = number_format($price, 2, ',', '.');
  $product['manufacturerName'] = $manMap[$product['id_manufacturer']]['name'];
  $product['description_short'] = my_strip_tags($product['description_short']);
  if ($product ['quantity']==0)
  $product['lagerstatus'] = 'Nej';
  else
  $product['lagerstatus'] = 'Ja';
  $product['lager'] = $product['quantity'];
  if ($product ['quantity']==0)
  $product['leveringstid'] = ($product['available_later']);
  else
  $product['leveringstid'] = '1 - 3 dage';




  //print "  <product>\n";
  $product_num++;
  echo '<product place="'.$product_num.'">'."\n";
  foreach ($product as $k => $v) {
    print_field($k, $v);
  }
  $catList = Product::getIndexedCategories($product['id_product']);
  foreach ($catList as $cat) {
    $catNames = array();
    $catId = $cat['id_category'];
    while ($catId && $catId != 1) {
      array_unshift($catNames, trim($catMap[$catId]['name']));
      $catId = $catMap[$catId]['id_parent'];
    }
    print_field('categoryName', implode(' | ', $catNames));
  }
  print "  </product>\n";
}
print "</products>\n";

?>
Avatar billede JensPeterSvensson Nybegynder
12. januar 2012 - 12:07 #1
Ja. Du kan minimere antallet af funktion kald til at begynde med:

function my_number_format($t)
{
  return number_format($t, 2, ',', '.');
}

du kunne så bare skrive:
  number_format($t, 2, ',', '.');
hvor du har:
  my_number_format($t);

du har to if sætninger:
  if ($product ['quantity']==0)
  $product['lagerstatus'] = 'Nej';
  else
  $product['lagerstatus'] = 'Ja';
  $product['lager'] = $product['quantity'];
  if ($product ['quantity']==0)
  $product['leveringstid'] = ($product['available_later']);
  else
  $product['leveringstid'] = '1 - 3 dage';
Såvidt jeg kan se tester de præcis det samme, så de kan slås sammen til:
  if ($product ['quantity']==0){
    $product['lagerstatus'] = 'Nej';
    $product['leveringstid'] = ($product['available_later']);
  }else{
    $product['lagerstatus'] = 'Ja';
    $product['leveringstid'] = '1 - 3 dage';
  }
  $product['lager'] = $product['quantity'];

du har:
  1 + ($carrierTax / 100);

Det er såvidt jeg kan se konstant i forløkken så kan udregnes før løkken. (Fortolkeren laver muligvis selv denne forbedring.)


Du stripper tags. Jeg ville foreslå at du gjorde når du indsatte beskrivelsen, bare have 2 kolonner i databasen et med og et uden tags. (Antager at beskrivelserne er storset konstante efter de er blevet skrevet.)


De her kan skrives som en ting:
  $shipping_cost *= 1 + ($carrierTax / 100);
  $shipping_cost += floatval($configuration['PS_SHIPPING_HANDLING']);
  $product['shipping_cost'] = $shipping_cost;

Det her er det samme:
  $product['shipping_cost'] =  $shipping_cost * (1 + ($carrierTax / 100)) + floatval($configuration['PS_SHIPPING_HANDLING']);


Din nederste med printning af kategorier ser en anelse mystisk ud, medmindre $catlist faktisk er en liste af lister af kategorier, så er den inderste while løkke vel næppe relevant, er bare en if sætning.


I stedet for at opbygge dit associative product array, kunne du bare bruge direkte variabler og have flere print_field linier. (Ved ikke om det er en forbedring, men kunne forestille mig at det ikke er helt gratis at opbygge og slå op i sådan et.)
Avatar billede olebole Juniormester
12. januar 2012 - 16:24 #2
<ole>

Tværtimod bruger du arrays for lidt!  =)

At skrive til dokumentet er noget, der tager tid. Derfor bør du tilstræbe at udskrive én gang - f.eks. ved at implodere et array. Og du bør ikke være bange for at bruge arrays - de er generelt lynhurtige at arbejde med.

Hvis du ændrede din funktion print_field, så den ikke skriver ud, men nøjes med at formatere de enkelte tags og fylde dem i et array. Derefter kan du så skrive hele array'et ud i ét hug:

$formatted_tags = array();
function print_field($k, $v, $tags)
{
  if (isset($tags[$k])) {
    $k = $tags[$k];
    $v = htmlspecialchars($v, ENT_NOQUOTES, "UTF-8");
    $formatted_tags = "    <$k>$v</$k>";
  }
}

// - og længere nede

foreach ($product as $k => $v) {
    print_field($k, $v, $tags);
}
print implode("\n", $formatted_tags);

Det vil forbedre scriptets performance en hel del - og du vil sikkert selv kunne ændre til samme fremgangsmåde flere steder.

I funktionen my_strip_tags bruger du preg_replace, som fungerer forholdsvis langsomt. Kik i stedet på strtr her. Den er beregnet til at oversætte ord/tegn i en streng. Brug den med to arrays.

Jeg har ikke kikket koden efter i enkeltheder, men disse to ting sprang i hvertfald i øjnene  =)

/mvh
</bole>
Avatar billede olebole Juniormester
12. januar 2012 - 16:28 #3
- og det fik jeg skrevet lidt for hurtigt!

function print_field($k, $v, $tags)
{
  $formatted_tags = array();
  if (isset($tags[$k])) {
    $k = $tags[$k];
    $v = htmlspecialchars($v, ENT_NOQUOTES, "UTF-8");
    $formatted_tags[] = "    <$k>$v</$k>";
  }
  return $formatted_tags;
}

// - og længere nede

foreach ($product as $k => $v) {
    $formatted_tags = print_field($k, $v, $tags);
}
print implode("\n", $formatted_tags);

Læg i øvrigt mærke til, at jeg bevidst begrænser brugen af globale variabler mest muligt. I stedet sender jeg dem med til funktionen som argumenter - og returnerer dem igen.
Avatar billede mmalling Nybegynder
12. januar 2012 - 17:19 #4
Tak for svarene indtil videre prøver at kigge lidt på det.

Det som script laver er en prisfil der bla hentes af pricerunner,og udtrækket ser/skal altid se således ud.:

<product place="4418">
<databaseid>7371</databaseid>
<ean13>7611990190607</ean13>
<interntvarenummer>344117320</interntvarenummer>
<produktID>21.18.1753</produktID>
<produktbeskrivelse>      IEEE 802.11n, IEEE 802.11g, IEEE 802.11b    Frekvens: 2,4 - 2,4835 GHz     Plug & Play     Support WPS (Wifi beskyttet setup)    Support QoS-WMM,WMM-PS       </produktbeskrivelse>
<produktnavn>Trådløst netværk - USB2.0 antenne - 150 Mbit/s  -</produktnavn>
<link>http://www.mbmdata.dk/netvarksprodukter-netkort/7371-trdlst-netvrk---usb20-antenne---150-mbits----7611990190607.html</link>
<billedeUrl>http://www.mbmdata.dk/7371-7369-large/trdlst-netvrk---usb20-antenne---150-mbits---.jpg</billedeUrl>
<fragt>39</fragt>
<pris>230,16</pris>
<producent>ROLINE</producent>
<PaaLager>Ja</PaaLager>
<leveringstid>1 - 3 dage</leveringstid>
<LagerNiveau>6</LagerNiveau>
<category>Netværksprodukter | Netkort</category>
</product>
Der hentes lige p.t omkring 6100 produkter så det tager lidt tid, der ville jeg gerne optimere scriptet for at forkorte tiden og forbedre performance.
Avatar billede mmalling Nybegynder
12. januar 2012 - 17:21 #5
function my_number_format($t)
{
  return number_format($t, 2, ',', '.');
}

du kunne så bare skrive:
  number_format($t, 2, ',', '.');
hvor du har:
  my_number_format($t);

Den forstod jeg ikke helt...
Skal jeg fjerne

function my_number_format($t)
{
  return number_format($t, 2, ',', '.');
}

eller hvordan skal det forstået
Avatar billede olebole Juniormester
12. januar 2012 - 18:11 #6
Så lyder det som en komplet håbløs tilgang. Hentes der 6.100 poster, skal der formateres små 100.000 XML-tags - og deres data formateres endvidere på alle mulige måder on-the-fly. Det er ikke en hensigtsmæssig fremgangsmåde.

Lav en tabel med data, som PriceRunner umiddelbart kan bruge uden yderligere manipulation. Den tabel opdaterer du så, hvergang du opretter, redigerer og/eller sletter en vare.

Kik derefter på PHP's indbyggede XML-API'er og brug et af dem til at formatere XML-filen med - f.eks. SimpleXML eller XML-DOM
Avatar billede mmalling Nybegynder
12. januar 2012 - 18:28 #7
Jeg har nu prøvet lidt med de rettelser i har skrevet og filen kører uden at få timeout på serveren...
tager dog lidt tid at hente den ca 2 min, men pricerunner har indtil videre ikke problemer med at hente den....

de henter den her

http://www.mbmdata.dk/xmlexport.php?passwd=mbm
Avatar billede olebole Juniormester
12. januar 2012 - 18:43 #8
Det ændrer ikke ved mine kommentarer i #6  =)
Avatar billede olebole Juniormester
12. januar 2012 - 18:45 #9
- og så er det faktisk ikke en XML-fil, du leverer. Du skal som det allerførste i dokumentet sætte en passende HTTP-header:

header('Content-Type: text/xml');
Avatar billede mmalling Nybegynder
12. januar 2012 - 18:55 #10
Ok, filen er bygget op efter krav anvisninger fra pricerunner for at de kunne kører den i deres system
Avatar billede olebole Juniormester
12. januar 2012 - 19:02 #11
*LoL* Jeg giver op!  :D
Avatar billede mmalling Nybegynder
12. januar 2012 - 21:02 #12
Iorden. Tak for hjælpen alligevel
Avatar billede JensPeterSvensson Nybegynder
14. januar 2012 - 10:18 #13
#5

Et eller andet sted i din kode har du et kald til funktionen
my_number_format, dette sted kan du i stedet for skrive number_format (med samme parameter som du kalder den med i my_number_format). Dette ville såvidt jeg kan se spare dig for 5000 funktionskald (medmindre fortolkeren optimerer disse ud).
Avatar billede mmalling Nybegynder
14. januar 2012 - 14:18 #14
Jeg har øverste i koden.

function my_number_format($t)
{
  return number_format($t, 2, ',', '.');
}

og længere nede har jeg
$product['price_exc'] = my_number_format($prodObj->getPrice(false));
  $product['price_inc'] = my_number_format($prodObj->getPrice(true));
Hvilket af disse steder skal jeg skrive number_format istedet?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester