jrk/paymentsips-bundle
Symfony bundle for PaymentsIPS integration, providing configuration and services to add payment processing to Symfony applications. It helps wire payment flows with less boilerplate and quicker setup, making PaymentsIPS gateway adoption straightforward.
jrk/paymentsips-bundle is a Symfony2 bundle, not a Laravel package. It ships a *Bundle class, a DependencyInjection/*Extension, a Resources/config/services.yml, and expects registration in app/AppKernel.php. composer require jrk/paymentsips-bundle will not give you a service provider, config publishing, or facades. Treat it as a reference implementation / PHP source drop, not a drop-in dependency. There is no Laravel path to "just install it."DependencyInjection/Configuration.php and ...Extension.php — this is the real API surface. It tells you the required parameters: merchant ID, country, currency, the pathfile path, and the path/certificate files used to sign requests.Resources/config/routing.yml — the bundle exposes a route for the return/callback URL. That route name and path shape are what you must replicate in routes/web.php.Caisse/PaymentRequest toolkit) and the one that parses the response.app/Services/Sips/ (or app/Support/Payments/), replace the Symfony container wiring with constructor injection via a PaymentServiceProvider, and replace the bundle's config.yml block with a config/payments.php file. Keep the ATOS toolkit files (bin/, lib/) exactly as vendored — they are the bank's signed binaries and must not be rewritten.pathfile + request fields, bank returns a parm blob / reference). SIPS/2 and Paybox/OSB use different field sets and a JSON or key-versioned seal. If your contract is OSB or SIPS/2, most of this bundle's request-building code is wrong for you..env:// config/payments.php
return [
'sips' => [
'merchant_id' => env('SIPS_MERCHANT_ID'),
'country' => 'FR',
'currency' => 'EUR',
'pathfile' => storage_path('sips/pathfile'),
'key' => storage_path('sips/'.env('SIPS_MERCHANT_ID').'.key'),
'cert' => storage_path('sips/'.env('SIPS_MERCHANT_ID').'.crt'),
'normal_return' => route('sips.return'),
'cancel_return' => route('sips.cancel'),
'auto_return' => route('sips.server'),
],
];
public function checkout(Order $order, SipsGateway $sips)
{
$request = $sips->buildRequest([
'amount' => $this->toMinorUnits($order->total, 'EUR'),
'currency' => '978', // ISO 4217 numeric for EUR
'order_id' => $order->reference,
'customer' => ['email' => $order->email],
]);
return view('checkout.redirect', [
'action' => $sips->gatewayUrl(),
'fields' => $request, // signed fields
]);
}
interface PaymentGateway {
public function buildRequest(array $payload): array;
public function verifyResponse(array $response): bool;
public function gatewayUrl(): string;
}
Then SipsGateway implements PaymentGateway and bind in AppServiceProvider. This is the difference between "stuck with SIPS forever" and "can drop in Stripe/Adyen for another market later."
ProcessSipsCallback, and inside the job: (1) verify seal, (2) DB::transaction + lockForUpdate(), (3) check transition is legal (pending → paid only, never paid → paid), (4) log. Key idempotency on the SIPS reference field.payment_attempts table with order_id, reference, amount, currency, status, raw_response (json) saves hours of "why did this one fail?" debugging.123.45 EUR → 12345. Use integer math throughout; don't do intval($order->total * 100) — use bcmul or a money library. Currency is the ISO 4217 numeric code (978 for EUR), not the alpha code.~5.3–5.6 and symfony/* ~2.x, all EOL. Even if it resolves on a modern PHP runtime you gain nothing without porting. Expect composer require to either fail or drag in a wall of deprecated transitive dependencies. Don't fight it — clone the repo and copy the classes you need.array(), no scalar type hints, no return types, possibly long-removed functions (each(), create_function()), and $HTTP_RAW_POST_DATA-era code. Budget mechanical modernization before the code will even pass a linter on PHP 8.2/8.3. Run it through PHPStan level 5+ before you trust it in a payment path.$ prefix on empty fields, then cert signing). If your acquirer's contract uses SHA-256 seal (key_version present) rather than legacy SHA-1, this code is wrong, not just outdated. Silent declines are the symptom — you won't see an exception, just a rejected transaction. Log the bank's response code separately from the seal verification result so you can tell the two failure modes apart.error_log) in debug mode. If it's there, strip those calls before the fork goes to production. Do the same for anything that serializes the request object — payment credentials should never end up in a stack trace.LICENSE or explicit grant in composer.json. If not, you have no legal right to copy the code, and the whole reference-implementation plan collapses. Check first.Extension/CompilerPass pattern has no analog. Don't try to port it — you'd be building a container adapter for a container you're not using. Replace it with a ServiceProvider + config file and move on.web middleware with CSRF verification, every callback will 419. Put it in routes/web.php but exclude CSRF for that path, or place it in routes/api.php with session handling configured. Verify the seal, not the CSRF token.(reference, amount, currency), retries will double-credit or corrupt state. Test by firing the same callback twice in the sandbox and verifying no state change the second time.pending orders) and repairs state. Anything pending > X hours should alert someone.How can I help you explore Laravel packages today?