An enterprise-ready JSON-RPC 2.0 library for PHP applications with simplified APIs, structured logging, middleware system, schema validation, batch processing, and full BigInt/Date serialization support.
- Features
- Installation
- Quick Start
- Advanced Usage
- JavaScript Client
- API Reference
- Examples
- Contributing
- License
- JSON-RPC 2.0 Compliance: Fully adheres to JSON-RPC 2.0 specification
- Server & Client Support: Provides server endpoints and PHP & JavaScript client classes
- Async Support: Handles asynchronous operations with Promises
- BigInt & Date Serialization: Robust serialization/deserialization with timezone support
- Cross-Platform: Works in both browser and PHP server environments
- Error Handling: Comprehensive error responses with sanitization options
- 🔧 Structured Logging: Configurable logging with multiple transports and levels
- ⚡ Middleware System: Extensible middleware with built-in rate limiting, CORS, auth
- ✅ Schema Validation: JSON Schema validation with schema builder utilities
- 📦 Batch Processing: Efficient batch request handling with concurrent processing
- 📊 Health & Metrics: Built-in health check endpoints and metrics
- 🔒 Security: Method whitelisting, authentication, and error sanitization
- 🎯 Performance: Request timing, caching support, and optimized serialization
composer require rpc-php-toolkit/rpc-php-toolkit<?php
require_once 'vendor/autoload.php';
use RpcPhpToolkit\RpcEndpoint;
// Context object to pass to method handlers
$context = ['database' => $db, 'config' => $config];
// Create the RPC endpoint
$rpc = new RpcEndpoint('/api/rpc', $context);
// Add methods
$rpc->addMethod('getTime', function($params, $context) {
return [
'timestamp' => time(),
'datetime' => date('c')
];
});
$rpc->addMethod('echo', function($params, $context) {
return ['message' => $params['message'] ?? 'Hello World!'];
});
// Handle requests
$input = file_get_contents('php://input');
echo $rpc->handleRequest($input);use RpcPhpToolkit\Client\RpcClient;
// Create client
$client = new RpcClient('http://localhost:8000/api/rpc', [], [
'timeout' => 30,
'verifySSL' => true,
'safeEnabled' => false // Enable safe serialization if needed
]);
// Single call
$result = $client->call('getTime');
// Call with parameters
$result = $client->call('echo', ['message' => 'Hello!']);
// With authentication
$client->setAuthToken('your-token-here');
$result = $client->call('protected.method');
// Batch request
$results = $client->batch([
['method' => 'getTime', 'id' => 1],
['method' => 'echo', 'params' => ['message' => 'Test'], 'id' => 2]
]);
// Notification (no response)
$client->notify('log.event', ['data' => 'something']);// Import ES Module
import RpcClient from './rpc-client.mjs';
// Or classic script loading
// <script src="rpc-client.js"></script>
const client = new RpcClient('http://localhost:8000/api/rpc');
// Single call
const result = await client.call('getTime');
// Call with parameters
const echo = await client.call('echo', {message: 'Hello!'});
// Batch request
const results = await client.batch([
{method: 'getTime', id: 1},
{method: 'echo', params: {message: 'Test'}, id: 2}
]);use RpcPhpToolkit\Middleware\RateLimitMiddleware;
use RpcPhpToolkit\Middleware\AuthMiddleware;
use RpcPhpToolkit\Middleware\CorsMiddleware;
// CORS support
$rpc->getMiddleware()->add(
new CorsMiddleware([
'origin' => '*', // or specific origin(s)
'methods' => ['GET', 'POST', 'OPTIONS'],
'headers' => ['Content-Type', 'Authorization', 'X-RPC-Safe'],
'credentials' => false,
'maxAge' => 86400
]),
'before'
);
// Rate limiting
$rpc->getMiddleware()->add(
new RateLimitMiddleware(100, 60, 'ip'),
'before'
);
// Authentication
$rpc->getMiddleware()->add(
new AuthMiddleware(function($token) {
return $this->authenticateUser($token);
}),
'before'
);$rpc->addMethod('createUser', function($params, $context) {
// User creation logic
return ['id' => 123, 'name' => $params['name']];
}, [
'type' => 'object',
'properties' => [
'name' => [
'type' => 'string',
'minLength' => 2,
'maxLength' => 50
],
'email' => [
'type' => 'string',
'format' => 'email'
]
],
'required' => ['name', 'email']
]);Enable introspection to expose metadata about registered methods via reserved __rpc.* methods:
// Create endpoint with introspection enabled
$rpc = new RpcEndpoint('/api/rpc', $context, [
'enableIntrospection' => true, // Enable __rpc.* methods (default: false)
'introspectionPrefix' => '__rpc' // Prefix for introspection methods (configurable)
]);
// Register methods with public schemas
$rpc->addMethod('add', function($params, $context) {
return $params['a'] + $params['b'];
}, [
'schema' => [
'type' => 'object',
'properties' => [
'a' => ['type' => 'number'],
'b' => ['type' => 'number']
],
'required' => ['a', 'b']
],
'exposeSchema' => true, // Make schema publicly queryable
'description' => 'Add two numbers' // Method description
]);
// Available introspection methods:
// __rpc.listMethods() → ["add", "multiply", ...]
$methods = $client->call('__rpc.listMethods');
// __rpc.describe(['method' => 'add']) → {name, schema, description}
$info = $client->call('__rpc.describe', ['method' => 'add']);
// __rpc.describeAll() → [{name, schema, description}, ...]
$allPublic = $client->call('__rpc.describeAll');
// __rpc.version() → {toolkit, version, phpVersion}
$version = $client->call('__rpc.version');
// __rpc.capabilities() → {batch, introspection, validation, ...}
$capabilities = $client->call('__rpc.capabilities');Security Notes:
- Methods with
exposeSchema: falseare hidden from__rpc.describe - Introspection methods cannot describe themselves
- Users cannot register methods starting with the introspection prefix
- The prefix is configurable to avoid conflicts with existing methods
See examples/introspection/ for complete examples.
use RpcPhpToolkit\Logger\Logger;
use RpcPhpToolkit\Logger\FileTransport;
$logger = new Logger([
'level' => Logger::INFO,
'transports' => [
new FileTransport([
'filename' => 'logs/rpc.log',
'format' => 'json'
])
]
]);
$rpc = new RpcEndpoint('/api/rpc', $context, [
'logger' => $logger
]);<!DOCTYPE html>
<html>
<head>
<script src="rpc-client.js"></script>
</head>
<body>
<script>
const client = new RpcClient('http://localhost:8000/api/rpc');
client.call('getTime').then(result => {
console.log('Server time:', result);
});
</script>
</body>
</html>const RpcClient = require('./rpc-client.js');
const client = new RpcClient('http://localhost:8000/api/rpc');
async function test() {
try {
const result = await client.call('getTime');
console.log(result);
} catch (error) {
console.error('RPC Error:', error.message);
}
}import RpcClient from './rpc-client.mjs';
const client = new RpcClient('http://localhost:8000/api/rpc');
const result = await client.call('getTime');The examples/ folder contains:
basic-server.php- Complete RPC server with all middlewareclient.php- Example PHP client with all testsbrowser-test.html- Interactive browser testing
cd examples
php -S localhost:8000 basic-server.phpThen open browser-test.html in your browser to test the interface.
new RpcEndpoint(string $endpoint = '/rpc', mixed $context = null, array $options = [])addMethod(string $name, callable $handler, array $schema = null, array $middleware = []): selfremoveMethod(string $name): selfhandleRequest(string $input): stringgetLogger(): ?LoggergetMiddleware(): ?MiddlewareManager
$options = [
'sanitizeErrors' => true, // Sanitize errors in production
'enableBatch' => true, // Enable batch requests
'enableLogging' => true, // Enable logging
'enableValidation' => true, // Enable schema validation
'enableMiddleware' => true, // Enable middleware system
'maxBatchSize' => 100, // Maximum batch size
'timeout' => 30, // Timeout in seconds
'safeEnabled' => false, // Enable safe type serialization (S:, D: prefixes)
'warnOnUnsafe' => true, // Warn when BigInt/Date serialized without safe mode
'errorProperties' => [...] // Error properties to include
];Like the Express version, PHP toolkit supports Safe Mode for type-safe serialization:
// Enable safe mode
$rpc = new RpcEndpoint('/api/rpc', $context, [
'safeEnabled' => true
]);
// Client with safe mode
$client = new RpcClient('http://localhost:8000/api/rpc', [], [
'safeEnabled' => true
]);How it works:
- Strings: Prefixed with
S:→"hello"becomes"S:hello" - Dates: Prefixed with
D:→ ISO string becomes"D:2025-11-26T10:30:00Z" - Large integers: Suffixed with
n→9007199254740992becomes"9007199254740992n"
This prevents ambiguity when deserializing JSON, especially useful when:
- You control both client and server
- Type safety is critical
- Working with BigInt or Date values
Default behavior (safeEnabled: false):
- Maximum JSON-RPC 2.0 compatibility
- Standard serialization without prefixes
- Warnings logged when BigInt/Date detected (disable with
warnOnUnsafe: false)
### JSON-RPC Error Codes
- `-32600` - Invalid Request
- `-32601` - Method not found
- `-32602` - Invalid params
- `-32603` - Internal error
- `-32000` to `-32099` - Implementation specific errors
## Security
- **Error Sanitization**: In production, set `sanitizeErrors: true`
- **Rate Limiting**: Use `RateLimitMiddleware` to limit requests
- **Authentication**: Implement `AuthMiddleware` for protected methods
- **Input Validation**: Use schema validation for all parameters
- **CORS**: Configure CORS appropriately for browser clients
## Performance
- **Batch Processing**: Use batch requests for multiple operations
- **Efficient Middleware**: Middleware is executed in optimized order
- **Async Logging**: Configurable logger for different levels
- **Caching**: Implement caching at middleware level if needed
#### ⚠️ SSL and self-signed certificates in development (PHP)
If you need to connect to a server with a self-signed certificate during development in PHP, you can disable SSL verification for testing purposes (not recommended in production). For example, with cURL:
```php
$ch = curl_init('https://localhost:8000/api/rpc');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable certificate verification (development only)
$response = curl_exec($ch);
curl_close($ch);
Or with Guzzle:
$client = new \GuzzleHttp\Client([
'verify' => false // Disable certificate verification (development only)
]);
$response = $client->get('https://localhost:8000/api/rpc');Warning: Disabling SSL verification exposes you to security risks. Use only in local development environments.
- Fork the project
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is distributed under the MIT License. See the LICENSE file for details.
- rpc-express-toolkit - Node.js/Express implementation
- rpc-dotnet-toolkit - .NET implementation
- rpc-arduino-toolkit - Arduino/ESP32 implementation
- rpc-java-toolkit - Java & Android implementation
- node-red-contrib-rpc-toolkit - Node-RED visual programming
RPC PHP Toolkit - A professional JSON-RPC 2.0 implementation for PHP with enterprise features.