ecourty / tor-php
A Symfony-based HTTP client and ControlPort client for interacting with the Tor network in PHP.
Installs: 5
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/ecourty/tor-php
Requires
- php: >= 8.4
- selective/base32: ^2.0
- symfony/http-client: ^7.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.71
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.0
- symfony/var-dumper: ^7.2
Suggests
- ext-sodium: Required for generating ED25519-V3 keypairs for Tor onion services
This package is auto-updated.
Last update: 2026-01-25 22:06:32 UTC
README
TOR-PHP is a PHP library for Tor network integration. It provides two main components:
- TorHttpClient - A Symfony HttpClient implementation that routes HTTP requests through the Tor SOCKS5 proxy for anonymous communication.
- TorControlClient - A socket-based client implementing the Tor Control Protocol for managing circuits, configuration, and onion services.
Table of Contents
- Quick Start
- Installation
- Requirements
- Authentication
- Features
- Security Baseline
- Usage Examples
- Changelog
- Contributing
- License
Quick Start
-
Install and start Tor:
# Debian/Ubuntu sudo apt install tor sudo systemctl start tor # macOS brew install tor brew services start tor
-
Install TOR-PHP:
composer require ecourty/tor-php
-
Make your first request:
<?php require 'vendor/autoload.php'; use TorPHP\TorHttpClient; $client = new TorHttpClient(); $response = $client->request('GET', 'https://api.ipify.org?format=json'); echo $response->getContent(); // Your Tor exit IP
Installation
1. Install Tor
On Debian/Ubuntu
sudo apt install tor
On macOS (Homebrew)
brew install tor
2. Configure Tor ControlPort
Edit your Tor configuration file (/etc/tor/torrc or /usr/local/etc/tor/torrc):
ControlPort 9051
See the Authentication section for configuring authentication.
3. Install TOR-PHP via Composer
composer require ecourty/tor-php
Requirements
- PHP 8.4 or higher
- Tor daemon running locally
- ControlPort enabled in Tor configuration (required for
TorControlClientfeatures)
Authentication
The Tor ControlPort should always be protected with authentication. TOR-PHP supports three authentication methods.
Password Authentication
Recommended for production environments.
-
Generate a hashed password:
tor --hash-password "your_secure_password" -
Add to
/etc/tor/torrc:ControlPort 9051 HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
-
Use in PHP:
use TorPHP\TorControlClient; $control = new TorControlClient( password: 'your_secure_password' );
Cookie Authentication
Recommended when the PHP process runs as the same user as Tor.
-
Configure
/etc/tor/torrc:ControlPort 9051 CookieAuthentication 1
-
Use in PHP:
use TorPHP\TorControlClient; $control = new TorControlClient( authenticationCookie: '/var/run/tor/control.authcookie' );
The cookie file path varies by system:
- Linux:
/var/run/tor/control.authcookie - macOS (Homebrew):
/usr/local/var/run/tor/control.authcookie
- Linux:
No Authentication (Not Recommended)
Only use for local development on isolated systems.
Configure /etc/tor/torrc:
ControlPort 9051 CookieAuthentication 0
Use in PHP:
use TorPHP\TorControlClient; $control = new TorControlClient(); // No credentials
Warning: Running Tor ControlPort without authentication is a security risk. Any process on the system can control your Tor instance.
Features
HTTP Client Features
- HTTP/HTTPS requests through Tor SOCKS5 proxy (port 9050)
- Request new identity (change Tor circuit)
- Retrieve current Tor exit nodes
- Compatible with Symfony HttpClient interface
Control Client Features
- Circuit management and inspection
- Signal new identity (
NEWNYM) - Configuration management (
GETCONF,SETCONF) - Onion service creation and deletion
- ED25519-V3 keypair generation for onion services
- Tor event subscription
- Wait for circuit build completion
Security Baseline
Mandatory Authentication
Running Tor ControlPort without authentication is dangerous. An attacker with local access could:
- Reconfigure your Tor instance
- Create onion services
- Monitor your traffic
- Manipulate circuits
Always use password or cookie authentication in production.
Best Practices
- Protect credentials: Never commit passwords or cookie files to version control
- File permissions: Set restrictive permissions on sensitive files:
chmod 600 /path/to/onion/private.key chmod 600 /path/to/.env
- Environment variables: Store credentials in environment variables:
$control = new TorControlClient( password: $_ENV['TOR_CONTROL_PASSWORD'] );
- Sensitive parameter protection: TOR-PHP uses
#[\SensitiveParameter]to prevent credential leakage in stack traces
Usage Examples
Example 1: Get current IP via Tor
<?php use TorPHP\TorHttpClient; use Symfony\Component\HttpClient\HttpClient; $torClient = new TorHttpClient(); $response = $torClient->request('GET', 'https://api.ipify.org?format=json'); $torIp = $response->toArray()['ip']; $normalClient = HttpClient::create(); $normalIp = $normalClient->request('GET', 'https://api.ipify.org?format=json')->toArray()['ip']; echo "Tor IP: $torIp" . PHP_EOL; echo "Non-Tor IP: $normalIp" . PHP_EOL;
Example 2: Request a New Identity
<?php use TorPHP\TorHttpClient; $torClient = new TorHttpClient(); $torClient->request('GET', 'https://example.com'); // Change circuit when you need $torClient->newIdentity(); $response = $torClient->request('GET', 'https://example.com/another-page');
Example 3: Manage Your Tor Node
<?php use TorPHP\TorControlClient; use TorPHP\Model\PortMapping; $control = new TorControlClient(); // Get circuits $circuits = $control->getCircuits(); // Change config $control->setConfigValue('SocksPort', '9080'); // Add onion service $onion = $control->addOnionService([ new PortMapping(host: 'localhost', localPort: 3000, remotePort: 80), ]); // List onion services $services = $control->listOnionServices(); // Delete onion service $control->deleteOnionService($onion->id);
Example 4: Generate Onion Service Keys
<?php use TorPHP\Helper\KeyPairGenerator; use TorPHP\TorControlClient; use TorPHP\Model\PortMapping; // Generate a new ED25519-V3 keypair $keyPair = KeyPairGenerator::generate(); echo "Service ID: {$keyPair->serviceId}.onion\n"; echo "Private Key: {$keyPair->getPrivateKeyFormatted()}\n"; // Use the generated key to create an onion service $control = new TorControlClient(); $onion = $control->addOnionService( portMappings: [new PortMapping('127.0.0.1', 8080, 80)], privateKey: $keyPair->getPrivateKeyBase64() ); // The onion service ID will match the derived serviceId from the keypair assert($onion->id === $keyPair->serviceId);
Other code examples can be found here.
Changelog
See CHANGELOG.md for details.
Contributing
See CONTRIBUTING.md for contribution guidelines.
License
Author: Edouard Courty
License: MIT - See LICENSE
Copyright © 2025
Need Help?
Feel free to open an issue or contribute via pull requests.