@pilaniaanand/node-php-bridge
v0.0.1
Published
Bidirectional bridge between Node.js and PHP — call PHP handlers from Node.js and vice versa, framework agnostic.
Maintainers
Readme
node-php-bridge
Bidirectional bridge between Node.js and PHP — call PHP handlers from Node.js and Node.js handlers from PHP. Framework agnostic.
Works with: Express, Next.js, Nuxt.js, Fastify, NestJS ↔ Laravel, Symfony, Zend/Laminas, Slim, vanilla PHP.
How It Works
Your Node App Your PHP App
(Express / Next / Nuxt) (Laravel / Symfony / Slim)
NodeBridge ◄──── HTTP ────► PhpBridge
:5555 :5556
register() ← PHP can call register() ← Node can call
call() → calls PHP call() → calls NodeBoth sides register named handlers and call each other over local HTTP. JSON payloads. Shared secret auth. Timeout handling. Middleware support.
Installation
npm install node-php-bridgeQuick Start
Node.js side
const NodeBridge = require('node-php-bridge');
const bridge = new NodeBridge({
port: 5555, // This Node bridge listens here
phpPort: 5556, // PHP bridge listens here
phpHost: '127.0.0.1',
secret: 'my-secret', // Must match PHP config
timeout: 10000,
});
// Register handlers PHP can call
bridge
.register('pdf.generate', async ({ template, data }) => {
// use puppeteer, pdfkit, etc.
return { url: '/storage/output.pdf' };
})
.register('email.send', async ({ to, subject, body }) => {
// use nodemailer, etc.
return { sent: true };
});
// Call PHP
const invoice = await bridge.call('invoice.create', {
customerId: 42,
items: [{ sku: 'A1', qty: 2 }],
});
// Start bridge server
await bridge.listen();API
new NodeBridge(config)
| Option | Type | Default | Description |
| ---------- | ------ | ----------- | ---------------------------------------------- |
| port | number | 5555 | Port this Node bridge listens on |
| phpPort | number | 5556 | Port the PHP bridge listens on |
| phpHost | string | 127.0.0.1 | PHP bridge host |
| secret | string | null | Shared secret for auth (recommended) |
| timeout | number | 10000 | Default call timeout in ms |
| logLevel | string | 'info' | silent / error / warn / info / debug |
bridge.register(name, fn)
Register a handler PHP can call. fn is async (payload) => result.
bridge.registerAll(handlersMap)
Register multiple handlers at once: bridge.registerAll({ 'a': fn1, 'b': fn2 }).
bridge.unregister(name)
Remove a handler.
bridge.call(handler, payload?, timeout?)
Call a handler on the PHP side. Returns a Promise.
bridge.fire(handler, payload?)
Call PHP without waiting for a response (fire-and-forget).
bridge.use(middleware)
Add middleware: async (handlerName, payload) => void. Throw to reject.
bridge.listen()
Start listening. Returns Promise<NodeBridge>.
bridge.close()
Gracefully stop the server. Returns Promise<void>.
bridge.listHandlers()
Returns string[] of registered handler names.
Events
bridge.on('ready', ({ port }) => { ... });
bridge.on('call', ({ handler, payload, result }) => { ... });
bridge.on('handlerError', (err) => { ... });
bridge.on('error', (err) => { ... });Framework Examples
Express.js
const express = require('express');
const NodeBridge = require('node-php-bridge');
const app = express();
const bridge = new NodeBridge({ port: 5555, phpPort: 5556 });
bridge.register('pdf.generate', async ({ template, data }) => {
return { url: `/pdfs/${Date.now()}.pdf` };
});
app.post('/api/invoice', async (req, res) => {
const invoice = await bridge.call('invoice.create', req.body);
res.json(invoice);
});
await bridge.listen();
app.listen(3000);Next.js (pages/api)
// lib/bridge.js — singleton
const NodeBridge = require('node-php-bridge');
let bridge;
export function getBridge() {
if (!bridge) {
bridge = new NodeBridge({ port: 5555, phpPort: 5556, secret: process.env.BRIDGE_SECRET });
bridge.register('pdf.generate', async (p) => { /* ... */ return {}; });
bridge.listen();
}
return bridge;
}
// pages/api/checkout.js
import { getBridge } from '../../lib/bridge';
export default async function handler(req, res) {
const order = await getBridge().call('order.create', req.body);
res.json(order);
}Nuxt 3 (server plugin)
// server/plugins/bridge.js
import NodeBridge from 'node-php-bridge';
export default defineNitroPlugin((nitroApp) => {
const bridge = new NodeBridge({ port: 5555, phpPort: 5556 });
bridge.register('render.og', async ({ title }) => { return { url: '...' }; });
bridge.listen();
nitroApp.hooks.hook('request', (event) => {
event.context.bridge = bridge;
});
});Security
- Always set
secretin production - Bind bridge ports to
127.0.0.1(localhost only) — never expose to public internet - Use Docker internal networks when running in containers
Docker Compose Setup
services:
node:
build: ./node-app
environment:
PHP_BRIDGE_HOST: php
BRIDGE_SECRET: ${BRIDGE_SECRET}
ports:
- "3000:3000"
- "5555:5555"
php:
build: ./php-app
environment:
NODE_BRIDGE_HOST: node
BRIDGE_SECRET: ${BRIDGE_SECRET}
ports:
- "8000:8000"
- "5556:5556"Testing
npm testLicense
MIT
