PHP cURL and Guzzle with AeonProxy proxies

A few cURL options, or one Guzzle setting, send PHP requests through residential or mobile IPs, rotating or sticky, over HTTP or SOCKS5.

Protocols
HTTP proxy for HTTP and HTTPS sites; SOCKS5 with CURLPROXY_SOCKS5_HOSTNAME or socks5h://
Authentication
CURLOPT_PROXYUSERPWD, or the login in Guzzle's proxy URL
Rotation
A new IP per connection (a cURL handle or Guzzle client reuses its own); a -sid- key keeps one IP for up to 60 minutes
Works with
Residential and mobile proxies

Before you start

  • PHP 8 with the curl extension (php -m lists curl). For Guzzle: composer require guzzlehttp/guzzle.
  • Your proxy login and password from the Residential or Mobile page of the dashboard, and traffic on that product; a login without traffic gets 402.
Connection details
Host
gate.aeonproxy.com
Port (HTTP / HTTPS)
7000
Port (SOCKS5)
7001
Login
your proxy login, with targeting keys if you need them: LOGIN-cc-us-sid-abc123
Password
your proxy password

Copy the login and password from the Residential or Mobile page of the dashboard; the generator there also writes ready lines. Key syntax: targeting and sessions.

cURL

CURLOPT_PROXY takes the host and port, CURLOPT_PROXYUSERPWD the login and password. Leave CURLOPT_PROXYTYPE at CURLPROXY_HTTP for port 7000: cURL tunnels HTTPS sites through it with CONNECT. CURLPROXY_HTTPS or an https:// proxy URL would start TLS with the proxy itself, which fails.

<?php
$ch = curl_init("https://api.ipify.org");
curl_setopt_array($ch, [
    CURLOPT_PROXY => "gate.aeonproxy.com:7000",
    CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
    CURLOPT_PROXYUSERPWD => "LOGIN-cc-us:PASSWORD",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);

$body = curl_exec($ch);
if ($body === false) {
    echo "cURL error: ", curl_error($ch), "\n";
} else {
    echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), " ", $body, "\n";
}

When a request fails, curl_getinfo($ch, CURLINFO_HTTP_CONNECTCODE) returns the gateway's answer to the tunnel request (407, 402 and so on), while CURLINFO_RESPONSE_CODE stays 0.

Rotating or sticky

A rotating login gets a new IP for every connection. Each new cURL handle opens a new connection; reusing one handle keeps its connection, and its IP. A -sid- key keeps one IP across handles and scripts until its -ttl- runs out (1 to 60 minutes).

<?php
function ip(string $login): string
{
    $ch = curl_init("https://api.ipify.org"); // a new handle opens a new connection
    curl_setopt_array($ch, [
        CURLOPT_PROXY => "gate.aeonproxy.com:7000",
        CURLOPT_PROXYUSERPWD => "{$login}:PASSWORD",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
    ]);
    return curl_exec($ch) ?: curl_error($ch);
}

echo ip("LOGIN-cc-us"), " ", ip("LOGIN-cc-us"), "\n"; // two IPs

$sid = bin2hex(random_bytes(4)); // one key per session you want to keep
$login = "LOGIN-cc-us-sid-{$sid}-ttl-30";
echo ip($login), " ", ip($login), "\n"; // one IP for up to 30 minutes

SOCKS5

Use port 7001 with CURLPROXY_SOCKS5_HOSTNAME, so the proxy resolves the site's name. Plain CURLPROXY_SOCKS5 resolves it on your server first, and that DNS lookup leaves from your own network.

<?php
$ch = curl_init("https://api.ipify.org");
curl_setopt_array($ch, [
    CURLOPT_PROXY => "gate.aeonproxy.com:7001",
    CURLOPT_PROXYTYPE => CURLPROXY_SOCKS5_HOSTNAME,
    CURLOPT_PROXYUSERPWD => "LOGIN-cc-de:PASSWORD",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
echo curl_exec($ch) ?: curl_error($ch), "\n";

Guzzle

Guzzle takes the whole proxy URL, login included, in its proxy option. A socks5h:// URL on port 7001 works the same way.

<?php
require "vendor/autoload.php";

use GuzzleHttp\Client;

$client = new Client([
    "proxy" => "http://LOGIN-cc-us:[email protected]:7000",
    // SOCKS5: "socks5h://LOGIN-cc-us:[email protected]:7001"
    "timeout" => 30,
]);

echo $client->get("https://api.ipify.org")->getBody(), "\n";

A Guzzle client keeps its connection between requests, so a rotating login keeps one IP. For a new IP on every request, add 'curl' => [CURLOPT_FORBID_REUSE => true] to the client options.

If it does not work

What you seeWhat to check
CONNECT tunnel failed, response 407 (cURL error 56, also in Guzzle)The login, the password, or a key in the login that is not in the lists (a misspelled city, for example).
The same with response 402No traffic left on the product, or the sub-user reached its limit.
The same with response 502The exit failed. Retry: the gateway closes the connection after an error, so a rotating login gets a new IP on the next one.
The same with response 403The site is blocked by default for every account: mail ports, .gov and .mil sites, some banking and ticketing sites. See gateway errors.
SSL routines::wrong version number, or a hangThe proxy type is HTTPS. Use CURLPROXY_HTTP and an http:// proxy URL for port 7000.
User was rejected by the SOCKS5 server (cURL error 97)The gateway refused the SOCKS5 login. SOCKS5 has one failure code for every cause: check the login, the password, the keys and the traffic left.

Questions

Yes, with curl_multi_* or Guzzle's concurrent requests. Bought traffic has no thread or connection limit on the gateway. Give each parallel job its own -sid- key if it needs its own sticky IP.

No. The country, region, city and session are keys in the login (LOGIN-cc-us-sid-abc123), so one login and password cover every location.

Proxy questions? Ask support in the live chat.