PHP HTTP Proxy: Vollständiger Leitfaden für cURL, Guzzle und Laravel

Lernen Sie, wie Sie HTTP-Proxies in PHP mit cURL, Guzzle, Symfony HTTP Client und Laravel einrichten. Mit produktionsreifen Codebeispielen für Scraping und API-Integration.

PHP HTTP Proxy: Vollständiger Leitfaden für cURL, Guzzle und Laravel

Wenn Sie als PHP-Entwickler Daten von Drittanbieter-APIs abrufen oder Web-Scraping betreiben, werden Sie früher oder später auf IP-basierte Blockaden stoßen. Rate Limits, Geo-Restriktionen und Bot-Erkennung sind alltägliche Hürden. Die Lösung: PHP Proxy-Integration auf verschiedenen Abstraktionsebenen – von rohem cURL bis hin zu eleganten Laravel-Service-Klassen.

In diesem Leitfaden zeige ich Ihnen, wie Sie HTTP-Proxies in PHP korrekt konfigurieren. Wir behandeln native cURL-Funktionen, Guzzle HTTP-Client, Symfony HTTP Client mit asynchroner Verarbeitung, und eine produktionsreife Laravel-Integration. Alle Codebeispiele verwenden ProxyHat als Proxy-Provider.

Grundlagen: Proxy-Verbindung mit nativem cURL

PHPs eingebautes cURL-Modul bietet die niedrigste Abstraktionsebene für HTTP-Anfragen mit Proxy-Unterstützung. Die wichtigsten Optionen sind CURLOPT_PROXY für den Proxy-Host und CURLOPT_PROXYUSERPWD für die Authentifizierung.

<?php

/**
 * Einfache HTTP-Anfrage durch einen Proxy mit cURL
 */
function fetchWithProxy(string $url, string $proxyUrl): string
{
    $ch = curl_init();
    
    // Basis-Optionen
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_TIMEOUT => 30,
        
        // Proxy-Konfiguration
        CURLOPT_PROXY => 'gate.proxyhat.com',
        CURLOPT_PROXYPORT => 8080,
        CURLOPT_PROXYUSERPWD => 'username:password',
        CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
        
        // TLS/SSL-Konfiguration
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt', // Pfad anpassen
    ]);
    
    $response = curl_exec($ch);
    
    if ($response === false) {
        $errorCode = curl_errno($ch);
        $errorMessage = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException(
            "cURL Fehler ($errorCode): $errorMessage"
        );
    }
    
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode >= 400) {
        throw new RuntimeException("HTTP Fehler: $httpCode");
    }
    
    return $response;
}

// Verwendung mit ProxyHat Residential Proxy
$proxyAuth = 'user-country-DE:your_password@gate.proxyhat.com:8080';
$url = 'https://httpbin.org/ip';

try {
    $result = fetchWithProxy($url, $proxyAuth);
    echo $result;
} catch (RuntimeException $e) {
    echo "Fehler: " . $e->getMessage();
}

Für ProxyHat verwenden Sie das Format http://USERNAME:PASSWORD@gate.proxyhat.com:8080. Die Geo-Targeting-Optionen werden direkt im Benutzernamen übergeben, zum Beispiel user-country-US für US-IPs oder user-country-DE-city-berlin für Berliner IPs.

Proxy-Authentifizierung mit CURLOPT_PROXYUSERPWD

Die Option CURLOPT_PROXYUSERPWD erwartet Benutzername und Passwort im Format username:password. Bei ProxyHat können Sie Geo-Targeting-Flags direkt im Benutzernamen integrieren:

<?php

// ProxyHat mit Geo-Targeting
$username = 'user-country-DE-session-abc123'; // Deutschland, sticky Session
$password = 'your_api_key';

$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_PROXY, 'gate.proxyhat.com');
curl_setopt($ch, CURLOPT_PROXYPORT, 8080);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

Guzzle HTTP Client: Proxy-Konfiguration und Rotation

Guzzle Proxy-Konfiguration ist deutlich eleganter als rohes cURL. Guzzle abstrahiert die cURL-Optionen und bietet eine saubere API für Middleware, Handler und Request-Optionen.

Basis-Konfiguration mit statischem Proxy

<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

// Guzzle Client mit Proxy-Konfiguration
$client = new Client([
    'base_uri' => 'https://httpbin.org',
    'timeout' => 30,
    'proxy' => 'http://user-country-DE:password@gate.proxyhat.com:8080',
    'verify' => true, // TLS-Verifizierung aktivieren
    'headers' => [
        'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    ],
]);

try {
    $response = $client->get('/ip');
    echo $response->getBody()->getContents();
} catch (RequestException $e) {
    echo "Anfrage fehlgeschlagen: " . $e->getMessage();
}

Per-Request Proxy-Rotation

Für Laravel Proxy Scraping Szenarien müssen Sie oft für jede Anfrage einen anderen Proxy verwenden. Guzzle ermöglicht dies durch Request-Optionen:

<?php

use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Promise;

class ProxyRotatingClient
{
    private Client $client;
    private array $proxyCredentials;
    private int $currentIndex = 0;
    
    public function __construct(array $proxyCredentials)
    {
        $this->proxyCredentials = $proxyCredentials;
        $this->client = new Client([
            'timeout' => 30,
            'verify' => true,
        ]);
    }
    
    /**
     * Rotiert durch verfügbare Proxy-Credentials
     */
    private function getNextProxyUrl(): string
    {
        $cred = $this->proxyCredentials[$this->currentIndex];
        $this->currentIndex = ($this->currentIndex + 1) % count($this->proxyCredentials);
        
        return "http://{$cred['username']}:{$cred['password']}@gate.proxyhat.com:8080";
    }
    
    /**
     * Führt eine einzelne Anfrage mit rotierendem Proxy aus
     */
    public function fetch(string $url): string
    {
        $proxyUrl = $this->getNextProxyUrl();
        
        $response = $this->client->get($url, [
            'proxy' => $proxyUrl,
        ]);
        
        return (string) $response->getBody();
    }
    
    /**
     * Concurrent Requests mit verschiedenen Proxies
     */
    public function fetchMultiple(array $urls): array
    {
        $promises = [];
        
        foreach ($urls as $key => $url) {
            $promises[$key] = $this->client->getAsync($url, [
                'proxy' => $this->getNextProxyUrl(),
            ]);
        }
        
        $results = Promise\Utils::settle($promises)->wait();
        
        $responses = [];
        foreach ($results as $key => $result) {
            if ($result['state'] === 'fulfilled') {
                $responses[$key] = (string) $result['value']->getBody();
            } else {
                $responses[$key] = null; // Fehlerbehandlung
            }
        }
        
        return $responses;
    }
}

// Verwendung für SERP Scraping
$proxyPool = [
    ['username' => 'user-country-US', 'password' => 'key1'],
    ['username' => 'user-country-DE', 'password' => 'key2'],
    ['username' => 'user-country-GB', 'password' => 'key3'],
];

$client = new ProxyRotatingClient($proxyPool);

$urls = [
    'google' => 'https://www.google.com/search?q=php+proxy',
    'bing' => 'https://www.bing.com/search?q=php+proxy',
];

$results = $client->fetchMultiple(array_values($urls));
print_r($results);

Symfony HTTP Client: AsyncResponse und Streaming

Der Symfony HTTP Client bietet eine moderne, asynchrone API mit ausgezeichneter Proxy-Unterstützung. Besonders nützlich für große Scraping-Projekte mit vielen gleichzeitigen Anfragen.

<?php

require 'vendor/autoload.php';

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Response\AsyncResponse;
use Symfony\Contracts\HttpClient\ResponseInterface;

class SymfonyProxyClient
{
    private $client;
    private string $proxyAuth;
    
    public function __construct(string $username, string $password)
    {
        $this->proxyAuth = "{$username}:{$password}";
        
        $this->client = HttpClient::create([
            'timeout' => 30,
            'verify_peer' => true,
            'verify_host' => true,
            'max_redirects' => 5,
        ]);
    }
    
    /**
     * Asynchrone Anfrage mit Proxy
     */
    public function fetchAsync(string $url, array $options = []): ResponseInterface
    {
        $options = array_merge($options, [
            'proxy' => "http://{$this->proxyAuth}@gate.proxyhat.com:8080",
        ]);
        
        return $this->client->request('GET', $url, $options);
    }
    
    /**
     * Mehrere URLs gleichzeitig abrufen (Streaming)
     */
    public function fetchConcurrent(array $urls, callable $onProgress = null): array
    {
        $responses = [];
        
        foreach ($urls as $key => $url) {
            $responses[$key] = $this->fetchAsync($url, [
                'on_progress' => $onProgress,
            ]);
        }
        
        // Streaming: Verarbeitet Responses sobald sie eintreffen
        $results = [];
        foreach ($responses as $key => $response) {
            try {
                $statusCode = $response->getStatusCode();
                
                if ($statusCode === 200) {
                    $results[$key] = $response->getContent();
                } else {
                    $results[$key] = [
                        'error' => "HTTP $statusCode",
                        'content' => null,
                    ];
                }
            } catch (\Exception $e) {
                $results[$key] = [
                    'error' => $e->getMessage(),
                    'content' => null,
                ];
            }
        }
        
        return $results;
    }
    
    /**
     * Chunk-basiertes Streaming für große Responses
     */
    public function streamLargeResponse(string $url, string $outputFile): int
    {
        $response = $this->fetchAsync($url);
        
        $handle = fopen($outputFile, 'w');
        $bytesWritten = 0;
        
        foreach ($this->client->stream($response) as $chunk) {
            $bytesWritten += fwrite($handle, $chunk->getContent());
        }
        
        fclose($handle);
        return $bytesWritten;
    }
}

// Praktisches Beispiel: SERP-Daten abrufen
$client = new SymfonyProxyClient('user-country-DE', 'your_api_key');

$searchUrls = [
    'results' => 'https://serpapi.com/search?q=php+proxy+guide',
];

$results = $client->fetchConcurrent($searchUrls);

foreach ($results as $name => $content) {
    if (is_string($content)) {
        echo "$name: " . strlen($content) . " Bytes empfangen\n";
    } else {
        echo "$name: Fehler - " . $content['error'] . "\n";
    }
}

Laravel Integration: Service-Klasse für Residential Proxy Pool

In Laravel-Anwendungen sollten Sie Proxy-Logik in eine dedizierte Service-Klasse auslagern. Diese kann von Jobs, Controllern und anderen Services verwendet werden.

<?php

namespace App\Services;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class ResidentialProxyService
{
    private Client $client;
    private string $gateway = 'gate.proxyhat.com';
    private int $port = 8080;
    private string $username;
    private string $password;
    
    // Retry-Konfiguration
    private int $maxRetries = 3;
    private int $retryDelay = 1000; // Millisekunden
    
    public function __construct()
    {
        $this->username = config('proxyhat.username');
        $this->password = config('proxyhat.password');
        
        $this->client = new Client([
            'timeout' => 30,
            'connect_timeout' => 10,
            'verify' => config('proxyhat.verify_ssl', true),
            'headers' => [
                'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language' => 'de-DE,de;q=0.9,en;q=0.8',
            ],
        ]);
    }
    
    /**
     * Generiert Proxy-URL mit Geo-Targeting
     */
    private function buildProxyUrl(?string $country = null, ?string $city = null, ?string $session = null): string
    {
        $username = $this->username;
        
        // Geo-Targeting-Flags hinzufügen
        if ($country) {
            $username .= "-country-$country";
        }
        
        if ($city) {
            $username .= "-city-" . strtolower($city);
        }
        
        // Sticky Session für konsistente IP
        if ($session) {
            $username .= "-session-$session";
        }
        
        return "http://{$username}:{$this->password}@{$this->gateway}:{$this->port}";
    }
    
    /**
     * Führt HTTP-Anfrage mit automatischen Retries durch
     */
    public function fetch(
        string $url,
        ?string $country = null,
        ?string $city = null,
        array $options = []
    ): ?string {
        $lastException = null;
        
        for ($attempt = 1; $attempt <= $this->maxRetries; $attempt++) {
            try {
                $proxyUrl = $this->buildProxyUrl(
                    $country,
                    $city,
                    $options['session'] ?? null
                );
                
                $response = $this->client->get($url, [
                    'proxy' => $proxyUrl,
                    'headers' => $options['headers'] ?? [],
                ]);
                
                Log::info('Proxy request successful', [
                    'url' => $url,
                    'country' => $country,
                    'attempt' => $attempt,
                ]);
                
                return (string) $response->getBody();
                
            } catch (RequestException $e) {
                $lastException = $e;
                
                Log::warning('Proxy request failed, retrying', [
                    'url' => $url,
                    'attempt' => $attempt,
                    'error' => $e->getMessage(),
                ]);
                
                if ($attempt < $this->maxRetries) {
                    usleep($this->retryDelay * 1000 * $attempt);
                }
            }
        }
        
        Log::error('Proxy request failed after all retries', [
            'url' => $url,
            'error' => $lastException?->getMessage(),
        ]);
        
        return null;
    }
    
    /**
     * Prüft Proxy-Verfügbarkeit
     */
    public function checkConnection(): bool
    {
        try {
            $response = $this->client->get('https://httpbin.org/ip', [
                'proxy' => $this->buildProxyUrl(),
                'timeout' => 10,
            ]);
            
            return $response->getStatusCode() === 200;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * Ermittelt die aktuelle Proxy-IP
     */
    public function getCurrentIp(?string $country = null): ?string
    {
        $response = $this->fetch('https://httpbin.org/ip', $country);
        
        if ($response) {
            $data = json_decode($response, true);
            return $data['origin'] ?? null;
        }
        
        return null;
    }
}

Laravel Job Integration

Die Service-Klasse lässt sich perfekt in Queue Jobs verwenden:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Services\ResidentialProxyService;

class ScrapeProductData implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
    public string $url;
    public string $country;
    public int $tries = 3;
    public int $backoff = 5;
    
    public function __construct(string $url, string $country = 'DE')
    {
        $this->url = $url;
        $this->country = $country;
    }
    
    public function handle(ResidentialProxyService $proxyService): void
    {
        $html = $proxyService->fetch(
            $this->url,
            country: $this->country,
            options: [
                'headers' => [
                    'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                ],
            ]
        );
        
        if ($html === null) {
            $this->fail('Proxy request failed');
            return;
        }
        
        // HTML parsern und Daten extrahieren
        $data = $this->parseHtml($html);
        
        // Daten speichern
        $this->saveData($data);
    }
    
    private function parseHtml(string $html): array
    {
        // Ihre Parsing-Logik hier
        return [];
    }
    
    private function saveData(array $data): void
    {
        // Datenbank-Operation
    }
}

// Verwendung
ScrapeProductData::dispatch('https://example.com/product/123', 'DE')
    ->onQueue('scraping');

Multi-cURL für Concurrent Fetching

Für High-Performance-Scraping ohne externe Dependencies bietet PHPs curl_multi_*-Funktionen echte Parallelität. Alle Anfragen laufen gleichzeitig, nicht sequenziell.

<?php

class ConcurrentProxyFetcher
{
    private array $proxyCredentials;
    private string $gateway = 'gate.proxyhat.com';
    private int $port = 8080;
    private int $maxConnections = 10;
    
    public function __construct(array $proxyCredentials)
    {
        $this->proxyCredentials = $proxyCredentials;
    }
    
    /**
     * Führt mehrere Anfragen parallel durch
     */
    public function fetchAll(array $urls): array
    {
        $mh = curl_multi_init();
        $handles = [];
        $results = [];
        
        // cURL-Handles erstellen
        foreach ($urls as $key => $url) {
            $ch = $this->createCurlHandle($url, $key);
            curl_multi_add_handle($mh, $ch);
            $handles[$key] = $ch;
        }
        
        // Alle Anfragen ausführen
        $active = null;
        do {
            $status = curl_multi_exec($mh, $active);
            
            if ($status === CURLM_OK) {
                // Warten auf Aktivität
                curl_multi_select($mh, 1.0);
            }
        } while ($status === CURLM_OK && $active);
        
        // Ergebnisse sammeln
        foreach ($handles as $key => $ch) {
            $response = curl_multi_getcontent($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            
            $results[$key] = [
                'status' => $httpCode,
                'body' => $response ?: null,
                'error' => $error ?: null,
            ];
            
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
        }
        
        curl_multi_close($mh);
        
        return $results;
    }
    
    /**
     * Erstellt einen cURL-Handle mit Proxy-Konfiguration
     */
    private function createCurlHandle(string $url, $key): \CurlHandle
    {
        $ch = curl_init($url);
        
        // Rotierende Proxy-Credentials
        $credIndex = array_search($key, array_keys($this->proxyCredentials)) % count($this->proxyCredentials);
        $cred = $this->proxyCredentials[$credIndex];
        
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 5,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CONNECTTIMEOUT => 10,
            
            // Proxy-Konfiguration
            CURLOPT_PROXY => $this->gateway,
            CURLOPT_PROXYPORT => $this->port,
            CURLOPT_PROXYUSERPWD => "{$cred['username']}:{$cred['password']}",
            CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
            
            // TLS
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
        ]);
        
        return $ch;
    }
}

// Praktisches Beispiel: Preisvergleich mehrerer Shops
$proxyPool = [
    ['username' => 'user-country-DE-session-shop1', 'password' => 'key1'],
    ['username' => 'user-country-DE-session-shop2', 'password' => 'key2'],
    ['username' => 'user-country-DE-session-shop3', 'password' => 'key3'],
];

$fetcher = new ConcurrentProxyFetcher($proxyPool);

$productUrls = [
    'amazon' => 'https://www.amazon.de/dp/B08N5WRWNW',
    'otto' => 'https://www.otto.de/p/product-123',
    'ebay' => 'https://www.ebay.de/itm/123456',
];

$results = $fetcher->fetchAll($productUrls);

foreach ($results as $shop => $result) {
    if ($result['status'] === 200) {
        echo "$shop: " . strlen($result['body']) . " Bytes\n";
    } else {
        echo "$shop: Fehler - {$result['error']}\n";
    }
}

TLS/SSL-Konfiguration und CA Bundle Handling

Bei HTTPS-Anfragen durch Proxies ist die TLS-Verifizierung kritisch. Falsch konfigurierte CA-Bundles führen zu schwer debuggbaren Fehlern.

CA-Bundle-Pfade auf verschiedenen Systemen

System Typischer CA-Bundle-Pfad
Ubuntu/Debian /etc/ssl/certs/ca-certificates.crt
CentOS/RHEL /etc/pki/tls/certs/ca-bundle.crt
macOS (Homebrew) /usr/local/etc/openssl/cert.pem
Windows (XAMPP) C:\xampp\php\extras\openssl\cacert.pem
Docker (Alpine) /etc/ssl/certs/ca-certificates.crt
<?php

class TlsAwareProxyClient
{
    private ?string $caBundlePath;
    private bool $verifyPeer;
    
    public function __construct(?string $customCaPath = null)
    {
        $this->caBundlePath = $customCaPath ?? $this->detectCaBundle();
        $this->verifyPeer = true;
        
        // CA-Bundle validieren
        if ($this->caBundlePath && !file_exists($this->caBundlePath)) {
            throw new RuntimeException("CA bundle not found: {$this->caBundlePath}");
        }
    }
    
    /**
     * Erkennt das System-CA-Bundle automatisch
     */
    private function detectCaBundle(): ?string
    {
        $candidates = [
            '/etc/ssl/certs/ca-certificates.crt', // Debian/Ubuntu
            '/etc/pki/tls/certs/ca-bundle.crt',   // RHEL/CentOS
            '/usr/local/etc/openssl/cert.pem',    // macOS
            '/etc/ssl/cert.pem',                   // Alpine
        ];
        
        foreach ($candidates as $path) {
            if (file_exists($path)) {
                return $path;
            }
        }
        
        // Fallback: cURL's eingebauter Bundle
        return null;
    }
    
    /**
     * cURL-Handle mit korrekter TLS-Konfiguration
     */
    public function createSecureHandle(string $url, string $proxyAuth): \CurlHandle
    {
        $ch = curl_init($url);
        
        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 5,
            CURLOPT_TIMEOUT => 30,
            
            // Proxy
            CURLOPT_PROXY => 'gate.proxyhat.com',
            CURLOPT_PROXYPORT => 8080,
            CURLOPT_PROXYUSERPWD => $proxyAuth,
            
            // TLS/SSL - strikte Verifizierung
            CURLOPT_SSL_VERIFYPEER => $this->verifyPeer,
            CURLOPT_SSL_VERIFYHOST => 2, // Strikt: Hostname muss passen
            CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2, // Minimum TLS 1.2
        ];
        
        // CA-Bundle nur setzen wenn verfügbar
        if ($this->caBundlePath) {
            $options[CURLOPT_CAINFO] = $this->caBundlePath;
        }
        
        curl_setopt_array($ch, $options);
        
        return $ch;
    }
    
    /**
     * Testet TLS-Konnektivität
     */
    public function testTlsConnection(): array
    {
        $testUrls = [
            'google' => 'https://www.google.com',
            'cloudflare' => 'https://1.1.1.1',
            'letsencrypt' => 'https://letsencrypt.org',
        ];
        
        $results = [];
        
        foreach ($testUrls as $name => $url) {
            $ch = $this->createSecureHandle($url, 'user:pass');
            
            $response = curl_exec($ch);
            $error = curl_error($ch);
            $info = curl_getinfo($ch);
            
            $results[$name] = [
                'ssl_verify_result' => $info['ssl_verify_result'],
                'certinfo' => $info['certinfo'] ?? [],
                'success' => $response !== false,
                'error' => $error,
            ];
            
            curl_close($ch);
        }
        
        return $results;
    }
}

// Laravel-Konfiguration (config/proxyhat.php)
/*
return [
    'username' => env('PROXYHAT_USERNAME'),
    'password' => env('PROXYHAT_PASSWORD'),
    'gateway' => 'gate.proxyhat.com',
    'http_port' => 8080,
    'socks5_port' => 1080,
    'verify_ssl' => env('PROXYHAT_VERIFY_SSL', true),
    'ca_bundle' => env('PROXYHAT_CA_BUNDLE'),
    'timeout' => env('PROXYHAT_TIMEOUT', 30),
    'retry_attempts' => env('PROXYHAT_RETRY_ATTEMPTS', 3),
];
*/

Produktionstipps für TLS

  • CA-Bundle aktuell halten: Führen Sie regelmäßig update-ca-certificates (Debian/Ubuntu) aus.
  • Testen Sie TLS 1.3: Moderne APIs erfordern oft TLS 1.2+.
  • Certificate Pinning vermeiden: Bei Proxies können Intermediate-Zertifikate variieren.
  • Debugging aktivieren: CURLOPT_VERBOSE zeigt TLS-Handshake-Details.

Vergleich: Proxy-Ansatz nach Anwendungsfall

Anwendungsfall Empfohlener Ansatz Begründung
Einfache API-Anfragen Natives cURL Minimale Dependencies, volle Kontrolle
REST-API-Integration Guzzle Saubere API, Middleware-Unterstützung
High-Volume Scraping multi_curl Echte Parallelität ohne externe Libraries
Laravel Queue Jobs Service-Klasse + Guzzle Testbarkeit, Dependency Injection
Streaming/Large Responses Symfony HTTP Client Native Streaming-Unterstützung
SOCKS5 erforderlich cURL mit CURLPROXY_SOCKS5 Vollständige SOCKS5-Implementierung

Key Takeaways

  • cURL-Optionen: CURLOPT_PROXY setzt den Host, CURLOPT_PROXYUSERPWD enthält Benutzername und Passwort im Format user:pass.
  • Guzzle Proxy: Konfigurieren Sie Proxies entweder im Client-Konstruktor (global) oder per Request-Option (Rotation).
  • Symfony HTTP Client: Nutzen Sie proxy in den Request-Optionen und stream() für große Responses.
  • Laravel Integration: Lagern Sie Proxy-Logik in eine Service-Klasse aus und injizieren Sie diese in Jobs.
  • Concurrent Fetching: curl_multi_* bietet echte Parallelität ohne externe Dependencies.
  • TLS-Verifizierung: Stellen Sie sicher, dass Ihr CA-Bundle aktuell ist und CURLOPT_SSL_VERIFYHOST auf 2 gesetzt ist.
  • ProxyHat-Format: Geo-Targeting und Sessions werden im Benutzernamen übergeben: user-country-DE-city-berlin-session-abc123.

FAQ

Wie verwende ich SOCKS5 statt HTTP-Proxy in PHP?

Setzen Sie CURLOPT_PROXYTYPE auf CURLPROXY_SOCKS5 und verwenden Sie Port 1080 für ProxyHat: curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); und CURLOPT_PROXYPORT, 1080.

Warum schlägt die Proxy-Verbindung mit SSL-Fehler fehl?

Meistens ist das CA-Bundle veraltet oder der Pfad falsch. Prüfen Sie mit curl_setopt($ch, CURLOPT_VERBOSE, true); und stellen Sie sicher, dass CURLOPT_CAINFO auf eine gültige Datei zeigt.

Wie rotiere ich IPs automatisch?

Bei ProxyHat verwenden Sie Sticky Sessions für kontrollierte Rotation: user-session-abc123 hält die IP. Für automatische Rotation pro Request lassen Sie das Session-Flag weg oder ändern es bei jeder Anfrage.

Was ist der Unterschied zwischen Residential und Datacenter Proxies?

Residential Proxies verwenden echte ISP-IPs und sind schwerer zu erkennen. Datacenter Proxies sind schneller, aber einfacher zu blockieren. Für Scraping mit Anti-Bot-Schutz sind Residential Proxies empfehlenswert.

Wie debugge ich Proxy-Verbindungsprobleme?

Aktivieren Sie cURL-Verbose-Modus mit CURLOPT_VERBOSE und prüfen Sie curl_getinfo($ch) nach der Anfrage. Achten Sie auf HTTP-Statuscodes, Redirect-Ketten und SSL-Verify-Results.

Weitere Details zu Proxy-Konfiguration und Geo-Targeting finden Sie in unserer Web-Scraping-Dokumentation oder auf der Preisseite für verschiedene Proxy-Typen.

Bereit loszulegen?

Zugang zu über 50 Mio. Residential-IPs in über 148 Ländern mit KI-gesteuerter Filterung.

Preise ansehenResidential Proxies
← Zurück zum Blog