العودة إلى المدونة

إعداد البروكسي في PHP باستخدام cURL و Guzzle HTTP Client: دليل كامل مع أمثلة على الكود

دليل كامل لإعداد البروكسي في PHP عبر cURL و Guzzle HTTP Client - مع أمثلة على الشيفرة، وتدوير IP، ونصائح لاختيار نوع البروكسي للتجريف والأتمتة.

📅٢٩ صفر ١٤٤٨ هـ
```html

إذا كنت تكتب زاحفًا، أو تقوم بأتمتة جمع البيانات، أو تتجاوز قيود IP — فلا يمكنك الاستغناء عن البروكسي في PHP. في هذا الدليل، سنستعرض أداتين رئيسيتين: cURL و Guzzle HTTP Client — مع أمثلة جاهزة من التعليمات البرمجية التي يمكنك استخدامها مباشرة في مشروعك.

لماذا البروكسي في مشاريع PHP

تظل PHP واحدة من أكثر اللغات شيوعًا لأتمتة الخادم، وتظهر المهام التي تتطلب بروكسي بشكل مستمر. إليك السيناريوهات الرئيسية التي لا يمكنك الاستغناء فيها عن البروكسي:

  • زحف المواقع والأسواق — تقوم Wildberries و Ozon و Avito و AliExpress بحظر IP بعد عدة عشرات من الطلبات. تسمح البروكسي بتوزيع الحمل بين عناوين مختلفة وعدم الحصول على 403/429.
  • جمع البيانات من الموارد المعتمدة على الموقع الجغرافي — قد تختلف الأسعار ونتائج محركات البحث والمحتوى حسب البلد. تحل البروكسي ذات الموقع الجغرافي المطلوب هذه المشكلة.
  • تجاوز قيود المعدل — العديد من واجهات برمجة التطبيقات تحد من عدد الطلبات من IP واحد. يسمح تدوير البروكسي بتجاوز هذه الحدود.
  • اختبار المحتوى المعتمد على الموقع الجغرافي — تحقق من كيفية ظهور الموقع للمستخدمين من دول مختلفة دون مغادرة المكتب.
  • الخصوصية أثناء الأتمتة — إخفاء IP الحقيقي للخادم عند إجراء طلبات جماعية إلى موارد خارجية.
  • مراقبة المنافسين — جمع منتظم للأسعار والتشكيلات والعروض من مواقع المنافسين دون خطر الحظر.

في PHP، يتم استخدام أداتين رئيسيتين لطلبات HTTP: الامتداد المدمج cURL ومكتبة Guzzle HTTP Client. كلاهما يدعم بروكسي HTTP و HTTPS و SOCKS4 و SOCKS5 — سنستعرض كل منهما بالتفصيل.

ما هو نوع البروكسي الذي يجب اختياره لـ PHP

قبل كتابة الكود، من المهم فهم نوع البروكسي المناسب لمهمتك. الأنواع المختلفة لها خصائص مختلفة من حيث السرعة والموثوقية ودرجة الخصوصية.

نوع البروكسي السرعة الخصوصية أفضل ما يناسب
بروكسي مراكز البيانات عالية جدًا متوسطة الزحف بدون أنظمة مكافحة الروبوتات الصارمة، طلبات API
بروكسي سكنية متوسطة عالية الزحف على المواقع المحمية، الأسواق، البيانات الجغرافية
بروكسي موبايل متوسطة قصوى المواقع ذات الحماية الصارمة ضد الروبوتات، الشبكات الاجتماعية

بالنسبة لمعظم مهام الزحف من الأسواق مثل Wildberries أو Ozon، سيكون الخيار الأمثل هو البروكسي السكنية — حيث أن IP الخاص بها ينتمي لمستخدمين حقيقيين، مما يجعل الطلبات شبه غير قابلة للاكتشاف من حركة مرور المتصفح العادية. بينما تناسب بروكسي مراكز البيانات حيث تكون السرعة أكثر أهمية من عدم الكشف، والحماية ضعيفة.

تدعم جميع الأنواع الثلاثة من البروكسي بروتوكولات HTTP/HTTPS و SOCKS5، لذا من حيث الكود — الإعداد هو نفسه. الفرق الوحيد هو في سلسلة الاتصال.

البروكسي في cURL: الإعداد الأساسي

يتوفر امتداد cURL في PHP بشكل افتراضي وهو الطريقة القياسية لتنفيذ طلبات HTTP على الخادم. يتم استخدام خيارين رئيسيين لتوصيل البروكسي: CURLOPT_PROXY و CURLOPT_PROXYTYPE.

بروكسي HTTP بدون مصادقة

<?php

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL            => 'https://httpbin.org/ip',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT        => 30,

    // تحديد عنوان البروكسي
    CURLOPT_PROXY          => '185.199.100.1:8080',

    // نوع البروكسي: HTTP (افتراضي)
    CURLOPT_PROXYTYPE      => CURLPROXY_HTTP,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "HTTP Code: $httpCode\n";
echo $response;

هنا CURLOPT_PROXY تأخذ سلسلة بالتنسيق host:port. بالنسبة لحركة مرور HTTPS عبر بروكسي HTTP، يستخدم cURL تلقائيًا طريقة CONNECT — النفق، لذا يبقى محتوى الطلب مشفرًا.

خيارات cURL المفيدة للعمل مع البروكسي

الخيار الوصف
CURLOPT_PROXY عنوان خادم البروكسي (host:port)
CURLOPT_PROXYTYPE النوع: CURLPROXY_HTTP، CURLPROXY_SOCKS4، CURLPROXY_SOCKS5
CURLOPT_PROXYUSERPWD اسم المستخدم وكلمة المرور بالتنسيق user:password
CURLOPT_HTTPPROXYTUNNEL تفعيل النفق عبر HTTP CONNECT
CURLOPT_SSL_VERIFYPEER التحقق من شهادة SSL (false — إيقاف التشغيل)
CURLOPT_TIMEOUT مهلة الطلب بالثواني
CURLOPT_CONNECTTIMEOUT مهلة الاتصال بالبروكسي

المصادقة و SOCKS5 في cURL

تتطلب معظم البروكسي التجارية المصادقة باستخدام اسم المستخدم وكلمة المرور. أيضًا، يعد SOCKS5 بروتوكولًا مفضلًا عندما تحتاج إلى خصوصية كاملة، لأنه لا يضيف رؤوسًا مثل X-Forwarded-For، التي قد تكشف عن استخدام البروكسي.

بروكسي HTTP مع اسم المستخدم وكلمة المرور

<?php

$proxyHost = '185.199.100.1';
$proxyPort = '8080';
$proxyUser = 'your_login';
$proxyPass = 'your_password';

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL            => 'https://httpbin.org/ip',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_CONNECTTIMEOUT => 10,

    // بروكسي مع المصادقة
    CURLOPT_PROXY          => "$proxyHost:$proxyPort",
    CURLOPT_PROXYTYPE      => CURLPROXY_HTTP,
    CURLOPT_PROXYUSERPWD   => "$proxyUser:$proxyPass",

    // النفق لـ HTTPS
    CURLOPT_HTTPPROXYTUNNEL => true,

    // رؤوس المتصفح للتخفي
    CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    CURLOPT_HTTPHEADER     => [
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language: ru-RU,ru;q=0.9,en;q=0.8',
    ],
]);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'خطأ في cURL: ' . curl_error($ch);
} else {
    echo $response;
}

curl_close($ch);

بروكسي SOCKS5 في cURL

<?php

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL            => 'https://httpbin.org/ip',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,

    CURLOPT_PROXY          => '185.199.100.1:1080',

    // SOCKS5 مع حل DNS عبر البروكسي (موصى به!)
    CURLOPT_PROXYTYPE      => CURLPROXY_SOCKS5_HOSTNAME,

    // المصادقة (إذا لزم الأمر)
    CURLOPT_PROXYUSERPWD   => 'login:password',
]);

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

echo $response;

💡 مهم: SOCKS5 مقابل SOCKS5_HOSTNAME

استخدم CURLPROXY_SOCKS5_HOSTNAME بدلاً من CURLPROXY_SOCKS5. الفرق هو أنه عند استخدام SOCKS5_HOSTNAME، تمر طلبات DNS أيضًا عبر البروكسي، مما يمنع تسرب DNS ويزيد من الخصوصية. بينما يتم حل DNS محليًا عند استخدام SOCKS5 العادي — مما قد يكشف عن IP الحقيقي الخاص بك.

تدوير البروكسي في cURL

سيتعرض بروكسي واحد للحظر بسرعة عند إجراء طلبات جماعية. الاستراتيجية الصحيحة هي أن يكون لديك مجموعة من البروكسي وتدويرها. إليك تنفيذ بسيط ولكنه فعال:

<?php

class ProxyRotator
{
    private array $proxies;
    private int $currentIndex = 0;

    public function __construct(array $proxies)
    {
        $this->proxies = $proxies;
        shuffle($this->proxies); // خلط لتحديد ترتيب عشوائي
    }

    /**
     * الحصول على البروكسي التالي من المجموعة
     */
    public function getNext(): string
    {
        $proxy = $this->proxies[$this->currentIndex];
        $this->currentIndex = ($this->currentIndex + 1) % count($this->proxies);
        return $proxy;
    }

    /**
     * الحصول على بروكسي عشوائي
     */
    public function getRandom(): string
    {
        return $this->proxies[array_rand($this->proxies)];
    }
}

// قائمة البروكسي بالتنسيق login:password@host:port
$proxyList = [
    'user1:[email protected]:8080',
    'user2:[email protected]:8080',
    'user3:[email protected]:8080',
    'user4:[email protected]:8080',
];

$rotator = new ProxyRotator($proxyList);

/**
 * وظيفة الطلب مع اختيار البروكسي تلقائيًا
 */
function fetchWithProxy(string $url, ProxyRotator $rotator): ?string
{
    $proxyStr = $rotator->getNext();

    // تحليل سلسلة البروكسي
    preg_match('/^(.+):(.+)@(.+):(\d+)$/', $proxyStr, $m);
    [, $user, $pass, $host, $port] = $m;

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_CONNECTTIMEOUT => 8,
        CURLOPT_PROXY          => "$host:$port",
        CURLOPT_PROXYTYPE      => CURLPROXY_HTTP,
        CURLOPT_PROXYUSERPWD   => "$user:$pass",
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
        CURLOPT_SSL_VERIFYPEER => false,
    ]);

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

    if ($error) {
        error_log("البروكسي $host:$port غير متاح: $error");
        return null;
    }

    return $response;
}

// مثال: زحف 10 صفحات مع تدوير البروكسي
$urls = [
    'https://example.com/page/1',
    'https://example.com/page/2',
    'https://example.com/page/3',
    // ...
];

foreach ($urls as $url) {
    $html = fetchWithProxy($url, $rotator);
    if ($html) {
        echo "تم الحصول على: " . strlen($html) . " بايت\n";
    }
    usleep(500000); // توقف 0.5 ثانية بين الطلبات
}

لاحظ usleep(500000) — التوقف بين الطلبات مهم للغاية. حتى مع تدوير البروكسي، قد تؤدي الطلبات المتكررة إلى حظر بسبب أنماط السلوك. الفترة الموصى بها هي من 500 مللي ثانية إلى 2 ثانية حسب الموقع.

البروكسي في Guzzle HTTP Client: الإعداد الأساسي

Guzzle هي مكتبة PHP قوية لطلبات HTTP، تُستخدم في معظم أطر PHP الحديثة (Laravel، Symfony). توفر واجهة برمجة تطبيقات أكثر سهولة ووضوحًا مقارنةً بـ cURL العاري، وتدعم الطلبات غير المتزامنة، والبرمجيات الوسيطة، ومعالجة الأخطاء بشكل مريح.

التثبيت عبر Composer

composer require guzzlehttp/guzzle

بروكسي HTTP بدون مصادقة

<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new Client([
    // عنوان URL الأساسي (اختياري)
    'base_uri' => 'https://httpbin.org',

    // إعدادات افتراضية لجميع الطلبات
    'timeout'  => 30,
    'connect_timeout' => 10,

    // البروكسي لجميع طلبات العميل
    'proxy' => 'http://185.199.100.1:8080',
]);

$response = $client->get('/ip');

echo $response->getStatusCode() . "\n";  // 200
echo $response->getBody() . "\n";        // {"origin": "185.199.100.1"}

في Guzzle، يتم تحديد البروكسي من خلال خيار proxy بالتنسيق URL. هذا أكثر بديهية من cURL. يمكن تحديد البروكسي على مستوى العميل (لكل الطلبات) أو لكل طلب على حدة.

بروكسي HTTP مع مصادقة

<?php

use GuzzleHttp\Client;

$login    = 'your_login';
$password = 'your_password';
$host     = '185.199.100.1';
$port     = '8080';

$client = new Client([
    'timeout' => 30,
]);

// البروكسي مع المصادقة يتم تمريره بتنسيق URL
$response = $client->get('https://httpbin.org/ip', [
    'proxy' => "http://$login:$password@$host:$port",
    'headers' => [
        'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept'     => 'text/html,application/xhtml+xml,application/xml;q=0.9',
    ],
]);

echo $response->getBody();

تنسيق URL للبروكسي في Guzzle: scheme://user:password@host:port. بالنسبة لبروكسي HTTP، نستخدم http://، ولـ SOCKS5 — socks5://.

العمل المتقدم مع Guzzle: المهلات، الرؤوس، SOCKS5

دعونا نستعرض سيناريوهات أكثر تعقيدًا: بروكسي مختلفة لـ HTTP و HTTPS، SOCKS5، تعطيل التحقق من SSL، وضبط الرؤوس لمحاكاة المتصفح.

بروكسي مختلفة لـ HTTP و HTTPS

<?php

use GuzzleHttp\Client;

$client = new Client([
    'timeout' => 30,
    'proxy'   => [
        // بروكسي لطلبات HTTP
        'http'  => 'http://login:[email protected]:8080',
        // بروكسي لطلبات HTTPS
        'https' => 'http://login:[email protected]:8080',
        // استثناءات — هذه المضيفات تذهب بدون بروكسي
        'no'    => ['localhost', '127.0.0.1', '.internal.corp'],
    ],
]);

SOCKS5 في Guzzle

<?php

use GuzzleHttp\Client;

// لـ SOCKS5 في Guzzle، تحتاج إلى حزمة إضافية
// composer require clue/socks-react (أو استخدم معالج curl)

$client = new Client([
    'timeout' => 30,
    'proxy'   => 'socks5://login:[email protected]:1080',
    'curl'    => [
        CURLOPT_PROXYTYPE => CURLPROXY_SOCKS5_HOSTNAME,
    ],
]);

$response = $client->get('https://httpbin.org/ip');
echo $response->getBody();

تكوين كامل مع رؤوس المتصفح

<?php

use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

$client = new Client([
    'timeout'         => 30,
    'connect_timeout' => 10,
    'verify'          => false, // تعطيل التحقق من SSL (لأغراض التصحيح)
    'allow_redirects' => [
        'max'       => 5,
        'strict'    => false,
        'referer'   => true,
        'protocols' => ['http', 'https'],
    ],
    'headers' => [
        'User-Agent'      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Accept'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language' => 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
        'Accept-Encoding' => 'gzip, deflate, br',
        'Cache-Control'   => 'no-cache',
        'Connection'      => 'keep-alive',
    ],
]);

$response = $client->get('https://example.com/catalog', [
    'proxy' => 'http://login:[email protected]:8080',
]);

$statusCode = $response->getStatusCode();
$body       = (string) $response->getBody();

echo "الحالة: $statusCode، الحجم: " . strlen($body) . " بايت\n";

⚠️ حول verify => false

تعطيل التحقق من SSL ('verify' => false) مقبول فقط لأغراض التصحيح أو عند العمل مع خدمات داخلية. في كود الإنتاج، يجب دائمًا ترك التحقق من SSL مفعلًا، وإلا ستكون عرضة لهجمات مثل man-in-the-middle.

تدوير البروكسي في Guzzle

في Guzzle، من السهل تنفيذ التدوير عبر البرمجيات الوسيطة — طبقة وسيطة تعترض كل طلب وتضيف إليه البروكسي. هذا أكثر أناقة من تمرير البروكسي يدويًا في كل استدعاء.

<?php

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;

/**
 * برمجية وسيطة لتدوير البروكسي تلقائيًا
 */
function proxyRotationMiddleware(array $proxies): callable
{
    $index = 0;
    $total = count($proxies);

    return Middleware::mapRequest(
        function (RequestInterface $request) use ($proxies, &$index, $total) {
            $proxy = $proxies[$index % $total];
            $index++;

            // إضافة البروكسي إلى سمات الطلب
            // (تمرير عبر الخيارات في المعالج)
            return $request->withHeader('X-Selected-Proxy', $proxy);
        }
    );
}

// قائمة البروكسي
$proxies = [
    'http://user1:[email protected]:8080',
    'http://user2:[email protected]:8080',
    'http://user3:[email protected]:8080',
];

// خيار بسيط: فئة تغليف حول Guzzle مع التدوير
class GuzzleWithRotation
{
    private Client $client;
    private array $proxies;
    private int $index = 0;

    public function __construct(array $proxies, array $clientConfig = [])
    {
        $this->proxies = $proxies;
        $this->client  = new Client($clientConfig);
    }

    public function get(string $url, array $options = []): \GuzzleHttp\Psr7\Response
    {
        $options['proxy'] = $this->proxies[$this->index % count($this->proxies)];
        $this->index++;

        return $this->client->get($url, $options);
    }

    public function post(string $url, array $options = []): \GuzzleHttp\Psr7\Response
    {
        $options['proxy'] = $this->proxies[$this->index % count($this->proxies)];
        $this->index++;

        return $this->client->post($url, $options);
    }
}

// الاستخدام
$guzzle = new GuzzleWithRotation($proxies, [
    'timeout' => 30,
    'headers' => [
        'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
    ],
]);

$urls = [
    'https://example.com/product/1',
    'https://example.com/product/2',
    'https://example.com/product/3',
];

foreach ($urls as $url) {
    try {
        $response = $guzzle->get($url);
        echo "OK [{$response->getStatusCode()}]: $url\n";
        sleep(1);
    } catch (\Exception $e) {
        echo "خطأ: " . $e->getMessage() . "\n";
    }
}

معالجة الأخطاء وتصحيح الأخطاء

عند العمل مع البروكسي، تكون الأخطاء حتمية: قد يكون البروكسي غير متاح، أو يستجيب ببطء، أو قد يعيد الموقع المستهدف خطأ. من المهم معالجة كل هذه الحالات بشكل صحيح.

معالجة الأخطاء في cURL

<?php

function fetchWithErrorHandling(string $url, string $proxy): array
{
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_CONNECTTIMEOUT => 8,
        CURLOPT_PROXY          => $proxy,
        CURLOPT_PROXYTYPE      => CURLPROXY_HTTP,
    ]);

    $body     = curl_exec($ch);
    $errno    = curl_errno($ch);
    $error    = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $totalTime = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
    curl_close($ch);

    // أكواد أخطاء cURL للبروكسي
    $proxyErrors = [
        CURLE_COULDNT_CONNECT    => 'لم يتمكن من الاتصال بالبروكسي',
        CURLE_OPERATION_TIMEDOUT => 'مهلة الاتصال بالبروكسي',
        CURLE_RECV_ERROR         => 'خطأ في استلام البيانات',
        CURLE_SSL_CONNECT_ERROR  => 'خطأ SSL عبر البروكسي',
    ];

    if ($errno) {
        $message = $proxyErrors[$errno] ?? "خطأ cURL #$errno: $error";
        return ['success' => false, 'error' => $message, 'code' => $errno];
    }

    if ($httpCode >= 400) {
        return ['success' => false, 'error' => "HTTP $httpCode", 'code' => $httpCode];
    }

    return [
        'success' => true,
        'body'    => $body,
        'code'    => $httpCode,
        'time'    => round($totalTime, 3),
    ];
}

// الاستخدام مع محاولات متكررة
function fetchWithRetry(string $url, array $proxies, int $maxRetries = 3): ?string
{
    foreach ($proxies as $proxy) {
        for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
            $result = fetchWithErrorHandling($url, $proxy);

            if ($result['success']) {
                echo "نجاح عبر $proxy (محاولة $attempt، {$result['time']}ث)\n";
                return $result['body'];
            }

            echo "خطأ عبر $proxy: {$result['error']}\n";

            if ($attempt < $maxRetries) {
                sleep(2); // توقف قبل المحاولة مرة أخرى
            }
        }
    }

    return null; // جميع البروكسي لم تنجح
}

معالجة الأخطاء في Guzzle

<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\ClientException;

$client = new Client(['timeout' => 30]);

$proxies = [
    'http://user1:[email protected]:8080',
    'http://user2:[email protected]:8080',
];

function fetchGuzzleWithFallback(Client $client, string $url, array $proxies): ?string
{
    foreach ($proxies as $proxy) {
        try {
            $response = $client->get($url, [
                'proxy'   => $proxy,
                'timeout' => 20,
            ]);

            return (string) $response->getBody();

        } catch (ConnectException $e) {
            // البروكسي غير متاح أو مهلة الاتصال
            echo "البروكسي غير متاح ($proxy): " . $e->getMessage() . "\n";

        } catch (ClientException $e) {
            // HTTP 4xx — خطأ في العميل (403، 404، 429)
            $code = $e->getResponse()->getStatusCode();
            echo "HTTP $code لـ $url عبر $proxy\n";

            if ($code === 429) {
                echo "حد المعدل — توقف 5 ثوان\n";
                sleep(5);
            }

        } catch (ServerException $e) {
            // HTTP 5xx — خطأ في الخادم
            echo "خطأ في الخادم: " . $e->getResponse()->getStatusCode() . "\n";

        } catch (RequestException $e) {
            // أخطاء طلب أخرى
            echo "خطأ في الطلب: " . $e->getMessage() . "\n";
        }
    }

    return null;
}

cURL مقابل Guzzle: ماذا تختار

تعمل الأداتان بشكل ممتاز مع البروكسي، لكن لكل منهما نقاط قوة مختلفة. إليك مقارنة وفقًا لمعايير رئيسية:

المعيار cURL Guzzle
التثبيت ✅ مدمج في PHP ⚠️ يحتاج إلى Composer
قابلية قراءة الكود ⚠️ الكثير من الخيارات، مطول ✅ واجهة برمجة تطبيقات نظيفة وسهلة الاستخدام
الأداء ✅ أسرع قليلاً (بدون تغليف) ✅ أداء مشابه، يوجد دعم غير متزامن
الطلبات غير المتزامنة ⚠️ curl_multi (صعب) ✅ دعم مدمج
البرمجيات الوسيطة / الخطافات ❌ لا يوجد ✅ HandlerStack، البرمجيات الوسيطة
دعم SOCKS5 ✅ أصلي ✅ عبر معالج curl
معالجة الأخطاء ⚠️ أكواد الأخطاء يدويًا ✅ استثناءات مع أنواع
التكامل في Laravel/Symfony ⚠️ يدويًا ✅ دعم أصلي
تناسب لـ سكريبتات بسيطة، بدون تبعيات مشاريع على الأطر، منطق معقد

التوصية: إذا كنت تكتب سكريبتًا بسيطًا أو تعمل على استضافة بدون Composer — استخدم cURL. لمشاريع على Laravel أو Symfony أو أي تطبيقات PHP حديثة — سيكون Guzzle أكثر ملاءمة ويوفر المزيد من الفرص للتوسع.

🚀 قائمة مراجعة سريعة قبل التشغيل

  • ✅ تحقق من أن البروكسي يعمل: curl -x http://login:pass@host:port https://httpbin.org/ip
  • ✅ قم بتعيين المهلات: timeout و connect_timeout
  • ✅ أضف User-Agent واقعي
  • ✅ نفذ فترات توقف بين الطلبات (حد أدنى 500 مللي ثانية)
  • ✅ ضع في اعتبارك معالجة الأخطاء والعودة إلى بروكسي آخر
  • ✅ لا تستخدم verify SSL في الإنتاج

الخاتمة

إعداد البروكسي في PHP ليس مهمة صعبة إذا كنت تعرف الخيارات الصحيحة والتنسيقات. للمهام الأساسية، يكفي استخدام cURL مع CURLOPT_PROXY و CURLOPT_PROXYUSERPWD. لمشاريع الأطر، يوفر Guzzle واجهة برمجة تطبيقات أكثر ملاءمة، واستثناءات نوعية، ودعمًا للبرمجيات الوسيطة لتدوير البروكسي.

المبادئ الأساسية للعمل بشكل موثوق: استخدم SOCKS5 مع حل DNS عبر البروكسي (CURLPROXY_SOCKS5_HOSTNAME)، دائمًا قم بتعيين المهلات، أضف فترات توقف بين الطلبات، ونفذ تدوير البروكسي للمهام الكبيرة. معالجة الأخطاء مع العودة إلى بروكسي آخر هي عنصر أساسي في أي كود إنتاج.

تذكر: العمل مع البروكسي يتطلب الحذر والتخطيط الجيد لضمان الأداء السلس والموثوق.

```