Skip to content

Commit 9e1fc4a

Browse files
authored
Merge pull request #14 from proxymesh/feature/php-examples
Add comprehensive PHP proxy examples
2 parents 397d2e5 + 4652b27 commit 9e1fc4a

11 files changed

Lines changed: 3562 additions & 1 deletion

README.md

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Example code for using proxy servers in different programming languages. Current
55
* Python
66
* JavaScript / Node.js
77
* Ruby
8+
* PHP
89

910
## Python Proxy Examples
1011

@@ -119,8 +120,87 @@ node javascript/run_tests.js axios got
119120
120121
## Ruby Proxy Examples
121122

123+
These examples use [Bundler](https://bundler.io/). Install Ruby development headers and libcurl first so native extensions can compile (Debian/Ubuntu: `ruby-dev` and `libcurl4-openssl-dev`; Fedora: `ruby-devel` and `libcurl-devel`).
124+
125+
```bash
126+
cd ruby
127+
bundle install
128+
```
129+
130+
**Running examples:**
131+
132+
```bash
133+
# Required: set your proxy URL
134+
export PROXY_URL='http://user:pass@proxy.example.com:8080'
135+
136+
# Optional: target URL (default: https://api.ipify.org?format=json)
137+
export TEST_URL='https://httpbin.org/ip'
138+
139+
# Optional: print one response header
140+
export RESPONSE_HEADER='X-ProxyMesh-IP'
141+
142+
# Single example (from ruby/)
143+
bundle exec ruby faraday-proxy.rb
144+
145+
# All examples as tests
146+
bundle exec ruby run_tests.rb
147+
148+
# Specific examples
149+
bundle exec ruby run_tests.rb faraday typhoeus
150+
```
151+
152+
**Examples:**
153+
154+
| Library | Example | Description |
155+
|---------|---------|-------------|
156+
| [Net::HTTP](https://docs.ruby-lang.org/en/master/Net/HTTP.html) (stdlib) | [net-http-proxy.rb](ruby/net-http-proxy.rb) | Low-level HTTP with proxy (`Net::HTTP.new` + proxy host/port/user/pass) |
157+
| [Faraday](https://lostisland.github.io/faraday/) | [faraday-proxy.rb](ruby/faraday-proxy.rb) | Middleware-style client; `Faraday.new(proxy: url)` |
158+
| [HTTParty](https://github.com/jnunemaker/httparty) | [httparty-proxy.rb](ruby/httparty-proxy.rb) | Simple API; `http_proxyaddr` / `http_proxyport` / credentials |
159+
| [HTTP.rb](https://github.com/httprb/http) | [http-rb-proxy.rb](ruby/http-rb-proxy.rb) | Lightweight DSL; proxy via `HTTP.via(host, port, user, pass)` |
160+
| [RestClient](https://github.com/rest-client/rest-client) | [rest-client-proxy.rb](ruby/rest-client-proxy.rb) | Simple REST API; proxy via `RestClient.proxy = url` |
161+
| [Typhoeus](https://github.com/typhoeus/typhoeus) | [typhoeus-proxy.rb](ruby/typhoeus-proxy.rb) | libcurl via Ethon; `proxy:` URL on the request |
162+
| [Excon](https://github.com/excon/excon) | [excon-proxy.rb](ruby/excon-proxy.rb) | Fast client; `Excon.get(url, proxy: url)` |
163+
| [HTTPClient](https://github.com/nahi/httpclient) | [httpclient-proxy.rb](ruby/httpclient-proxy.rb) | LWP-like client; pass full proxy URL to `HTTPClient.new` |
164+
| [Mechanize](https://github.com/sparklemotion/mechanize) | [mechanize-proxy.rb](ruby/mechanize-proxy.rb) | Crawling / forms; `set_proxy(host, port, user, password)` |
165+
| [Nokogiri](https://nokogiri.org/) | [nokogiri-proxy.rb](ruby/nokogiri-proxy.rb) | Parse HTML after a proxied `Net::HTTP` fetch |
166+
167+
Libraries above are actively maintained on RubyGems (releases within the last year as of early 2026). Like most high-level Ruby HTTP clients, they do not expose custom headers on the HTTPS `CONNECT` tunnel to the proxy or proxy response headers; for ProxyMesh-style custom proxy headers, lower-level clients or a dedicated helper library may be required.
168+
169+
## PHP Proxy Examples
170+
122171
**Installation:**
123172

173+
```bash
174+
cd php
175+
composer install
176+
```
177+
178+
**Running Examples:**
179+
180+
```bash
181+
# Required: Set your proxy URL
182+
export PROXY_URL='http://user:pass@proxy.example.com:8080'
183+
184+
# Run a single example
185+
php php/guzzle_proxy.php
186+
187+
# Run all examples as tests
188+
php php/run_tests.php
189+
```
190+
191+
**Examples:**
192+
193+
| Library | Example | Description |
194+
|---------|---------|-------------|
195+
| [cURL](https://www.php.net/manual/en/book.curl.php) | [curl_proxy.php](php/curl_proxy.php) | PHP's built-in HTTP client (libcurl) |
196+
| [Guzzle](https://docs.guzzlephp.org/) | [guzzle_proxy.php](php/guzzle_proxy.php) | Most popular PHP HTTP client |
197+
| [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) | [symfony_http_client_proxy.php](php/symfony_http_client_proxy.php) | Modern PSR-18 HTTP client |
198+
| [Buzz](https://github.com/kriswallsmith/Buzz) | [buzz_proxy.php](php/buzz_proxy.php) | Simple PSR-18 HTTP client |
199+
| [PHP Streams](https://www.php.net/manual/en/book.stream.php) | [streams_proxy.php](php/streams_proxy.php) | Built-in PHP streams (file_get_contents) |
200+
| [Amp HTTP](https://amphp.org/http-client) | [amphp_proxy.php](php/amphp_proxy.php) | Async HTTP client |
201+
202+
> **Note:** See [php-proxy-headers](https://github.com/proxymeshai/php-proxy-headers) for extensions that add custom proxy header support.
203+
124204
These examples use [Bundler](https://bundler.io/). Install Ruby development headers and libcurl first so native extensions can compile (Debian/Ubuntu: `ruby-dev` and `libcurl4-openssl-dev`; Fedora: `ruby-devel` and `libcurl-devel`).
125205

126206
```bash
@@ -189,7 +269,7 @@ More examples and language-specific proxy-header tooling:
189269

190270
## Contributing
191271

192-
Contributions are welcome for all supported languages in this repository (Python, JavaScript, and Ruby), as well as new language examples.
272+
Contributions are welcome for all supported languages in this repository (Python, JavaScript, Ruby, and PHP), as well as new language examples.
193273

194274
When opening a Pull Request:
195275

php/amphp_proxy.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env php
2+
<?php
3+
/**
4+
* Amp HTTP Client with proxy example.
5+
*
6+
* Configuration via environment variables:
7+
* PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080
8+
* TEST_URL - URL to request (default: https://api.ipify.org?format=json)
9+
*
10+
* Amp HTTP Client is an async HTTP client for PHP. It supports proxies
11+
* but does NOT support custom CONNECT headers or reading proxy response headers.
12+
*/
13+
14+
require_once __DIR__ . '/vendor/autoload.php';
15+
require_once __DIR__ . '/common.php';
16+
17+
use Amp\Http\Client\HttpClientBuilder;
18+
use Amp\Http\Client\Request;
19+
use Amp\Http\Client\Connection\DefaultConnectionFactory;
20+
use Amp\Http\Client\Connection\UnlimitedConnectionPool;
21+
use Amp\Http\Tunnel\Http1TunnelConnector;
22+
23+
$proxyUrl = get_proxy_url();
24+
25+
$testUrl = getenv('TEST_URL') ?: 'https://api.ipify.org?format=json';
26+
27+
$parsedProxy = parse_url($proxyUrl);
28+
$proxyHost = $parsedProxy['host'];
29+
$proxyPort = $parsedProxy['port'] ?? 8080;
30+
31+
try {
32+
$tunnelHeaders = [];
33+
if (isset($parsedProxy['user'])) {
34+
$credentials = $parsedProxy['user'] . ':' . ($parsedProxy['pass'] ?? '');
35+
$tunnelHeaders['Proxy-Authorization'] = 'Basic ' . base64_encode($credentials);
36+
}
37+
$connector = new Http1TunnelConnector("{$proxyHost}:{$proxyPort}", $tunnelHeaders);
38+
$pool = new UnlimitedConnectionPool(new DefaultConnectionFactory($connector));
39+
40+
$client = (new HttpClientBuilder())
41+
->usingPool($pool)
42+
->build();
43+
44+
$request = new Request($testUrl);
45+
$response = $client->request($request);
46+
47+
echo "Status: " . $response->getStatus() . "\n";
48+
echo "Body: " . $response->getBody()->buffer() . "\n";
49+
} catch (Exception $e) {
50+
fwrite(STDERR, "Error: " . $e->getMessage() . "\n");
51+
exit(1);
52+
}

php/buzz_proxy.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env php
2+
<?php
3+
/**
4+
* Buzz with proxy example.
5+
*
6+
* Configuration via environment variables:
7+
* PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080
8+
* TEST_URL - URL to request (default: https://api.ipify.org?format=json)
9+
*
10+
* Buzz is a simple PSR-18 HTTP client. It supports proxies but does NOT
11+
* support custom CONNECT headers or reading proxy response headers.
12+
*/
13+
14+
require_once __DIR__ . '/vendor/autoload.php';
15+
require_once __DIR__ . '/common.php';
16+
17+
use Buzz\Browser;
18+
use Buzz\Client\Curl;
19+
use Nyholm\Psr7\Factory\Psr17Factory;
20+
21+
$proxyUrl = get_proxy_url();
22+
23+
$testUrl = getenv('TEST_URL') ?: 'https://api.ipify.org?format=json';
24+
25+
try {
26+
$psr17Factory = new Psr17Factory();
27+
28+
$client = new Curl($psr17Factory, [
29+
'proxy' => $proxyUrl,
30+
'timeout' => 30,
31+
]);
32+
33+
$browser = new Browser($client, $psr17Factory);
34+
$response = $browser->get($testUrl);
35+
36+
echo "Status: " . $response->getStatusCode() . "\n";
37+
echo "Body: " . $response->getBody() . "\n";
38+
} catch (Exception $e) {
39+
fwrite(STDERR, "Error: " . $e->getMessage() . "\n");
40+
exit(1);
41+
}

php/common.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/**
4+
* Shared helpers for PHP proxy examples.
5+
*/
6+
7+
function normalize_proxy_url(string $value): string
8+
{
9+
$trimmed = trim($value);
10+
if ($trimmed === '') {
11+
return '';
12+
}
13+
14+
if (!preg_match('/^[a-z][a-z0-9+\-.]*:\/\//i', $trimmed)) {
15+
$trimmed = "http://{$trimmed}";
16+
}
17+
18+
$parts = parse_url($trimmed);
19+
if (!is_array($parts) || empty($parts['host'])) {
20+
return '';
21+
}
22+
23+
$scheme = $parts['scheme'] ?? 'http';
24+
$host = $parts['host'];
25+
$port = $parts['port'] ?? 31280;
26+
$user = $parts['user'] ?? null;
27+
$pass = $parts['pass'] ?? null;
28+
29+
$auth = '';
30+
if ($user !== null) {
31+
$auth = rawurlencode($user);
32+
if ($pass !== null) {
33+
$auth .= ':' . rawurlencode($pass);
34+
}
35+
$auth .= '@';
36+
}
37+
38+
return sprintf('%s://%s%s:%d', $scheme, $auth, $host, $port);
39+
}
40+
41+
function get_proxy_url(): string
42+
{
43+
$raw = getenv('PROXY_URL') ?: getenv('HTTPS_PROXY');
44+
if (!$raw) {
45+
fwrite(STDERR, "Error: Set PROXY_URL environment variable\n");
46+
exit(1);
47+
}
48+
49+
$normalized = normalize_proxy_url($raw);
50+
if ($normalized === '') {
51+
fwrite(STDERR, "Error: Invalid PROXY_URL value\n");
52+
exit(1);
53+
}
54+
55+
return $normalized;
56+
}

php/composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "proxymesh/proxy-examples-php",
3+
"description": "PHP proxy usage examples",
4+
"type": "project",
5+
"license": "MIT",
6+
"require": {
7+
"php": ">=8.1",
8+
"guzzlehttp/guzzle": "^7.8",
9+
"symfony/http-client": "^7.0",
10+
"php-http/guzzle7-adapter": "^1.0",
11+
"nyholm/psr7": "^1.8",
12+
"kriswallsmith/buzz": "^1.2",
13+
"amphp/http-client": "^5.0",
14+
"amphp/http-tunnel": "^2.0"
15+
},
16+
"autoload": {
17+
"psr-4": {
18+
"ProxyExamples\\": "src/"
19+
}
20+
},
21+
"scripts": {
22+
"test": "php run_tests.php"
23+
}
24+
}

0 commit comments

Comments
 (0)