id_product = (int)$productId; $image->position = Image::getHighestPosition($productId) + 1; $image->cover = ($image->position == 1); // Pierwsze zdjęcie jako okładka if (!$image->add()) return false; $imagePath = $image->getPathForCreation(); $url = str_replace(' ', '%20', trim($imageUrl)); // Próba pobrania if (!@copy($url, $imagePath . '.jpg')) { $image->delete(); return false; } // Generowanie miniatur $imageTypes = ImageType::getImagesTypes('products'); foreach ($imageTypes as $imageType) { if (!ImageManager::resize( $imagePath . '.jpg', $imagePath . '-' . stripslashes($imageType['name']) . '.jpg', (int)$imageType['width'], (int)$imageType['height'] )) { // W razie błędu resize można obsłużyć wyjątek, tutaj cicho pomijamy } } return true; } // Znajdź produkt po SKU (reference) function findProductByReference($reference) { if (empty($reference)) return false; $sql = 'SELECT `id_product` FROM `'._DB_PREFIX_.'product` WHERE `reference` = \''.pSQL($reference).'\''; $result = Db::getInstance()->getRow($sql); return $result ? new Product((int)$result['id_product']) : false; } // Parsowanie ceny (zamiana przecinków na kropki, usuwanie spacji) function parsePrice($rawPrice) { $clean = str_replace([' ', ','], ['', '.'], (string)$rawPrice); return (float)$clean; } // Budowanie tabeli HTML z atrybutów XML function buildAttributesHtml($xmlAttributesNode) { if (!$xmlAttributesNode || !isset($xmlAttributesNode->attribute)) { return ''; } $html = '
'; $html .= '

Specyfikacja produktu:

'; $html .= ''; $html .= ''; foreach ($xmlAttributesNode->attribute as $attr) { $name = (string)$attr->attribute_name; $value = (string)$attr->attribute_value; if (!empty($name) && !empty($value) && $value !== 'Nie dotyczy') { $html .= ''; $html .= ''; $html .= ''; $html .= ''; } } $html .= ''; $html .= '
' . htmlspecialchars($name) . '' . htmlspecialchars($value) . '
'; $html .= '
'; return $html; } // Czyści log aktualizacji - zostawia X dni function cleanLogFile($logFile, $days = 7) { if (!file_exists($logFile)) return; $content = file($logFile); $newContent = []; $cutoff = strtotime("-$days days"); foreach ($content as $line) { $parts = explode(';', $line); if (isset($parts[0]) && strtotime($parts[0]) >= $cutoff) { $newContent[] = $line; } } file_put_contents($logFile, implode("", $newContent)); } // ============================================ // ================ LOGIKA ==================== // ============================================ // 1. TRYB SYNCHRONIZACJI (Włączanie/Wyłączanie produktów) if ($modeSynch) { echo '

Synchronizacja stanów (Active/Inactive)...

'; $db = Db::getInstance(); // Tabela tymczasowa na SKU z XML $db->execute('CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'sollux_temp` (`sku` VARCHAR(64), PRIMARY KEY (`sku`)) ENGINE='._MYSQL_ENGINE_); $db->execute('TRUNCATE TABLE `'._DB_PREFIX_.'sollux_temp`'); // Zbieranie SKU z XML $sqlValues = []; foreach ($xml->product as $productNode) { $sku = trim((string)$productNode->sku); if ($sku) { $sqlValues[] = '(\''.pSQL($sku).'\')'; } // Wstawiamy paczkami po 100, żeby nie zapchać SQL if (count($sqlValues) >= 100) { $db->execute('INSERT IGNORE INTO `'._DB_PREFIX_.'sollux_temp` (`sku`) VALUES '.implode(',', $sqlValues)); $sqlValues = []; } } if (!empty($sqlValues)) { $db->execute('INSERT IGNORE INTO `'._DB_PREFIX_.'sollux_temp` (`sku`) VALUES '.implode(',', $sqlValues)); } // Wyłącz produkty, których nie ma w XML a są w bazie $sqlDisable = 'UPDATE `'._DB_PREFIX_.'product` p LEFT JOIN `'._DB_PREFIX_.'sollux_temp` t ON p.reference = t.sku SET p.active = 0 WHERE t.sku IS NULL AND p.id_manufacturer = '.(int)$configManufacturerId; $db->execute($sqlDisable); echo "

Wyłączono produkty niedostępne w feedzie.

"; // Włącz produkty, które są w XML $sqlEnable = 'UPDATE `'._DB_PREFIX_.'product` p JOIN `'._DB_PREFIX_.'sollux_temp` t ON p.reference = t.sku SET p.active = 1 WHERE p.active = 0'; $db->execute($sqlEnable); echo "

Włączono produkty dostępne w feedzie.

"; // Posprzątaj $db->execute('DROP TABLE `'._DB_PREFIX_.'sollux_temp`'); $totalTime = microtime(true) - $scriptStartTime; echo '

Zakończono synchronizację. Całkowity czas: '.formatTime($totalTime).'

'; exit; } // 2. TRYB AKTUALIZACJI (Ceny, Stany) if ($modeUpdate) { cleanLogFile($logFile); $today = date('Y-m-d'); $updatedCount = 0; // Wczytaj log $processedSkus = []; if (file_exists($logFile)) { $lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($lines as $line) { $data = explode(';', $line); if (isset($data[0]) && $data[0] == $today && isset($data[1])) { $processedSkus[trim($data[1])] = true; } } } echo "

Rozpoczynam aktualizację...

"; foreach ($xml->product as $productNode) { $sku = trim((string)$productNode->sku); if (empty($sku)) continue; if (isset($processedSkus[$sku])) continue; // MIERZENIE: Szukanie produktu $tStartCheck = microtime(true); $product = findProductByReference($sku); $tCheckDuration = microtime(true) - $tStartCheck; if (!$product) { continue; } // MIERZENIE: Update produktu $tStartUpdate = microtime(true); $priceGross = parsePrice($productNode->cena_detaliczna_brutto_pln); $priceNet = Tools::ps_round($priceGross / 1.23, 6); $product->price = $priceNet; $product->active = 1; StockAvailable::setQuantity($product->id, 0, 100); $product->update(); $tUpdateDuration = microtime(true) - $tStartUpdate; // Logowanie file_put_contents($logFile, $today.';'.$sku.PHP_EOL, FILE_APPEND); echo "

Zaktualizowano: $sku (Cena netto: $priceNet)

"; // RAPORT UPDATE echo '
'; echo 'Raport czasu (Update):
'; echo 'Szukanie w bazie: ' . formatTime($tCheckDuration) . '
'; echo 'Zapis update (SQL): ' . formatTime($tUpdateDuration) . '
'; echo '
'; $updatedCount++; break; } if ($updatedCount > 0) { echo ''; echo '

Trwa przeładowanie strony...

'; } else { echo '

Wszystkie produkty z XML zostały już dzisiaj zaktualizowane.

'; } exit; } // 3. TRYB DODAWANIA (ADD) if ($modeAdd) { $addedCount = 0; foreach ($xml->product as $productNode) { $sku = trim((string)$productNode->sku); if (empty($sku)) continue; // MIERZENIE: Sprawdzenie istnienia $tStartCheck = microtime(true); $exists = findProductByReference($sku); $tCheckDuration = microtime(true) - $tStartCheck; if ($exists) { continue; } // MIERZENIE: Przygotowanie obiektu (Pamięć) $tStartPrep = microtime(true); $product = new Product(); $product->reference = $sku; $product->ean13 = trim((string)$productNode->ean); $product->name = createMultiLangField(trim((string)$productNode->nazwa_produktu)); $product->id_category_default = (int)$configDefaultCategoryId; $product->id_manufacturer = (int)$configManufacturerId; $product->id_tax_rules_group = (int)$configTaxRulesGroupId; $priceGross = parsePrice($productNode->cena_detaliczna_brutto_pln); $product->price = Tools::ps_round($priceGross / 1.23, 6); $product->width = (float)$productNode->szerokosc; $product->height = (float)$productNode->wysokosc; $product->depth = (float)$productNode->dlugosc; $product->weight = (float)$productNode->waga_produktu; $shortDesc = trim((string)$productNode->opis_krotki_html); $longDescRaw = trim((string)$productNode->opis_dlugi_korzysci_html); $attributesHtml = buildAttributesHtml($productNode->attributes); $finalLongDesc = $longDescRaw . '

' . $attributesHtml; $product->description_short = createMultiLangField($shortDesc); $product->description = createMultiLangField($finalLongDesc); $product->link_rewrite = createLinkRewrite((string)$productNode->nazwa_produktu); $product->active = (int)$configActive; $tPrepDuration = microtime(true) - $tStartPrep; // MIERZENIE: Dodanie do bazy (INSERT) $tStartSave = microtime(true); $saveResult = $product->add(); $tSaveDuration = microtime(true) - $tStartSave; if ($saveResult) { // Przypisanie do kategorii i stanu $product->addToCategories([(int)$configDefaultCategoryId]); StockAvailable::setQuantity($product->id, 0, 100); // Dodanie Cechy if (!empty($configFeatureId) && !empty($configFeatureValueId)) { Product::addFeatureProductImport( (int)$product->id, (int)$configFeatureId, (int)$configFeatureValueId ); } // MIERZENIE: Zdjęcia (Pobieranie + Resize) $tStartImages = microtime(true); $imgCount = 0; for ($i = 1; $i <= 25; $i++) { $imgTag = 'image_' . $i; $imgUrl = (string)$productNode->$imgTag; if (!empty($imgUrl)) { if (addProductImage($product->id, $imgUrl)) { $imgCount++; } } } $tImagesDuration = microtime(true) - $tStartImages; echo "

Dodano produkt: " . $product->name[Context::getContext()->language->id] . " ($sku)

"; // --- RAPORT WYDAJNOŚCI --- $totalProductTime = microtime(true) - $tStartCheck; // Czas od sprawdzenia do końca zdjęć echo '
'; echo '

⏱️ Raport czasu dla: '.$sku.'

'; echo ''; echo '
'; // -------------------------- $addedCount++; // Break po dodaniu jednego break; } else { echo "

Błąd podczas dodawania produktu: $sku

"; } } if ($addedCount > 0) { echo ''; echo '

Dodano produkt. Odświeżanie...

'; } else { echo '

Brak nowych produktów do dodania (lub wszystkie już istnieją).

'; } } ?>