baseUrl, '/') . '/store-api/search'; $sanitizedCriteria = $this->sanitizeValue($criteria); $body = json_encode( $sanitizedCriteria, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE ); if (!is_string($body)) { throw new RuntimeException('Failed to encode Store API criteria.'); } $response = $this->httpClient->request('POST', $url, [ 'headers' => [ 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'sw-access-key' => $this->salesChannelAccessKey, ], 'body' => $body, 'timeout' => $this->timeoutSeconds, ]); $statusCode = $response->getStatusCode(); $content = $response->getContent(false); $content = $this->sanitizeString($content); if ($statusCode < 200 || $statusCode >= 300) { throw new RuntimeException(sprintf( 'Shopware Store API request failed with status %d. Response: %s', $statusCode, mb_substr(trim($content), 0, 1000) )); } $data = json_decode($content, true); if (!is_array($data)) { throw new RuntimeException('Shopware Store API returned invalid JSON.'); } return $data; } private function sanitizeValue(mixed $value): mixed { if (is_array($value)) { $out = []; foreach ($value as $key => $item) { $out[$key] = $this->sanitizeValue($item); } return $out; } if (!is_string($value)) { return $value; } return $this->sanitizeString($value); } private function sanitizeString(string $value): string { if (preg_match('//u', $value) === 1) { return $value; } if (function_exists('mb_convert_encoding')) { $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); } if (preg_match('//u', $value) === 1) { return $value; } if (function_exists('iconv')) { $converted = @iconv('UTF-8', 'UTF-8//IGNORE', $value); if (is_string($converted) && $converted !== '') { return $converted; } } return ''; } }