XF 2.3 Integration of the Amazon Advertising API (PA-API)

I am currently integrating the Amazon Advertising API (PA-API), which is functioning as expected so far. I am using the Siropu ad manager to manage ads and load the script via a callback. However, I want to dynamically generate the keywords for the ads.

What would be the best way to achieve this? My server handles a high volume of requests, so I would prefer to query the keywords via the API or directly through an SQL query. Each thread has a TAG that I would like to use for this purpose
PHP:
<?php

namespace Callback;

class AdCallback
{
    private static $memcached;

    private static function getMemcachedClient()
    {
        if (self::$memcached === null) {
            self::$memcached = new \Memcached();
            self::$memcached->addServer('127.0.0.1', 11211); // Verbindung nur einmal herstellen
        }
        return self::$memcached;
    }

    public static function getAmazonAd($content, $params, $reply)
    {
        try {
            // Statisches Keyword
            $keyword = 'amazon keyword';

            // Amazon API-Aufruf mit Memcached-Option
            return self::callAmazonApi($keyword);
        } catch (\Exception $e) {
            return "<p>Ein Fehler ist aufgetreten. Bitte überprüfen Sie das Fehlerprotokoll.</p>";
        }
    }

    private static function callAmazonApi($keyword)
    {
        $cacheKey = 'amazon_api_' . $keyword;
        $cachedResponse = self::getCachedResponse($cacheKey);

        if ($cachedResponse) {
            return $cachedResponse; // Cache verwenden
        }

        // API-Konfiguration
        $payload = json_encode([
            "Keywords" => $keyword,
            "Resources" => ["ItemInfo.Title"],
            "ItemCount" => 1,
            "PartnerTag" => "*******",
            "PartnerType" => "Associates",
            "Marketplace" => "www.amazon.de"
        ]);

        $host = "webservices.amazon.de";
        $uriPath = "/paapi5/searchitems";

        $awsv4 = new AwsV4(
            ""*******",",
            ""*******","
        );
        $awsv4->setRegionName("eu-west-1");
        $awsv4->setServiceName("ProductAdvertisingAPI");
        $awsv4->setPath($uriPath);
        $awsv4->setPayload($payload);
        $awsv4->setRequestMethod("POST");
        $awsv4->addHeader('content-encoding', 'amz-1.0');
        $awsv4->addHeader('content-type', 'application/json; charset=utf-8');
        $awsv4->addHeader('host', $host);
        $awsv4->addHeader('x-amz-target', 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.SearchItems');

        $headers = $awsv4->getHeaders();
        $headerString = implode("\r\n", array_map(fn($k, $v) => "$k: $v", array_keys($headers), $headers));

        $params = [
            'http' => [
                'header' => $headerString,
                'method' => 'POST',
                'content' => $payload,
                'timeout' => 10
            ]
        ];

        $stream = stream_context_create($params);
        $response = @file_get_contents('https://' . $host . $uriPath, false, $stream);

        if ($response === false) {
            return '<p>Keine Antwort von der Amazon API erhalten.</p>';
        }

        $data = json_decode($response, true);
        if (isset($data['SearchResult']['Items'][0]['DetailPageURL'])) {
            $result = '<a href="' . htmlspecialchars($data['SearchResult']['Items'][0]['DetailPageURL']) . '" target="_blank">Klicke hier</a>';
            self::saveToCache($cacheKey, $result); // Cache speichern
            return $result;
        }

        return '<p>Keine Produkte gefunden.</p>';
    }

    private static function getCachedResponse($cacheKey)
    {
        $memcached = self::getMemcachedClient();
        $cachedData = $memcached->get($cacheKey);
        return $cachedData ?: null; // Gibt null zurück, wenn kein Cache vorhanden ist
    }

    private static function saveToCache($cacheKey, $data, $ttl = 3600)
    {
        $memcached = self::getMemcachedClient();
        $memcached->set($cacheKey, $data, $ttl); // Cache-Daten speichern
    }
}

class AwsV4
{
    private $accessKey;
    private $secretKey;
    private $path;
    private $regionName;
    private $serviceName;
    private $httpMethodName;
    private $queryParametes = [];
    private $awsHeaders = [];
    private $payload;

    private $HMACAlgorithm = "AWS4-HMAC-SHA256";
    private $aws4Request = "aws4_request";
    private $strSignedHeader;
    private $xAmzDate;
    private $currentDate;

    public function __construct($accessKey, $secretKey)
    {
        $this->accessKey = $accessKey;
        $this->secretKey = $secretKey;
        $this->xAmzDate = gmdate("Ymd\THis\Z");
        $this->currentDate = gmdate("Ymd");
    }

    function setPath($path)
    {
        $this->path = $path;
    }

    function setServiceName($serviceName)
    {
        $this->serviceName = $serviceName;
    }

    function setRegionName($regionName)
    {
        $this->regionName = $regionName;
    }

    function setPayload($payload)
    {
        $this->payload = $payload;
    }

    function setRequestMethod($method)
    {
        $this->httpMethodName = $method;
    }

    function addHeader($headerName, $headerValue)
    {
        $this->awsHeaders[$headerName] = $headerValue;
    }

    public function getHeaders()
    {
        $this->awsHeaders['x-amz-date'] = $this->xAmzDate;
        ksort($this->awsHeaders);

        $canonicalURL = $this->prepareCanonicalRequest();
        $stringToSign = $this->prepareStringToSign($canonicalURL);
        $signature = $this->calculateSignature($stringToSign);

        if ($signature) {
            $this->awsHeaders['Authorization'] = $this->buildAuthorizationString($signature);
            return $this->awsHeaders;
        }
    }

    private function prepareCanonicalRequest()
    {
        $canonicalURL = $this->httpMethodName . "\n";
        $canonicalURL .= $this->path . "\n" . "\n";
        $signedHeaders = '';
        foreach ($this->awsHeaders as $key => $value) {
            $signedHeaders .= $key . ";";
            $canonicalURL .= $key . ":" . $value . "\n";
        }
        $canonicalURL .= "\n";
        $this->strSignedHeader = substr($signedHeaders, 0, -1);
        $canonicalURL .= $this->strSignedHeader . "\n";
        $canonicalURL .= $this->generateHex($this->payload);
        return $canonicalURL;
    }

    private function prepareStringToSign($canonicalURL)
    {
        return $this->HMACAlgorithm . "\n" .
               $this->xAmzDate . "\n" .
               $this->currentDate . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "\n" .
               $this->generateHex($canonicalURL);
    }

    private function calculateSignature($stringToSign)
    {
        $signatureKey = $this->getSignatureKey($this->secretKey, $this->currentDate, $this->regionName, $this->serviceName);
        return strtolower(bin2hex(hash_hmac("sha256", $stringToSign, $signatureKey, true)));
    }

    private function buildAuthorizationString($strSignature)
    {
        return $this->HMACAlgorithm . " Credential=" . $this->accessKey . "/" . $this->currentDate . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . ",SignedHeaders=" . $this->strSignedHeader . ",Signature=" . $strSignature;
    }

    private function generateHex($data)
    {
        return strtolower(bin2hex(hash("sha256", $data, true)));
    }

    private function getSignatureKey($key, $date, $regionName, $serviceName)
    {
        $kSecret = "AWS4" . $key;
        $kDate = hash_hmac("sha256", $date, $kSecret, true);
        $kRegion = hash_hmac("sha256", $regionName, $kDate, true);
        $kService = hash_hmac("sha256", $serviceName, $kRegion, true);
        return hash_hmac("sha256", $this->aws4Request, $kService, true);
    }
}

ADS Code
PHP:
<xf:callback class="Callback\AdCallback" method="getAmazonAd"></xf:callback>
 
Back
Top Bottom