定制 hotmeteor/receiver 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

hotmeteor/receiver

Composer 安装命令:

composer require hotmeteor/receiver

包简介

A drop-in webhook handling library for Laravel

README 文档

README

Receiver

Receiver

Receiver is a drop-in webhook handling library for Laravel.

Receiver gives you a consistent, expressive way to receive, verify, and handle incoming webhooks in your Laravel app. Point a route at a controller, call three methods, and you're done.

Out of the box, Receiver supports:

Provider Driver
GitHub github
HubSpot hubspot
Mailchimp Marketing mailchimp
Paddle Billing paddle
Postmark postmark
SendGrid Events sendgrid
Shopify shopify
Slack Events API slack
Stripe stripe
Twilio twilio

Any other webhook source can be added with a custom provider.

Tests Latest Version on Packagist PHP from Packagist

Table of Contents

Installation

Requires PHP ^8.2 and Laravel 10+.

composer require hotmeteor/receiver

Note: The Stripe provider requires stripe/stripe-php:

composer require stripe/stripe-php

Configuration

Each provider reads its secret from config/services.php. Add an entry for each source you intend to receive from.

Most providers use the same shape:

'github'   => ['webhook_secret' => env('GITHUB_WEBHOOK_SECRET')],
'hubspot'  => ['webhook_secret' => env('HUBSPOT_WEBHOOK_SECRET')],
'paddle'   => ['webhook_secret' => env('PADDLE_WEBHOOK_SECRET')],
'shopify'  => ['webhook_secret' => env('SHOPIFY_WEBHOOK_SECRET')],
'slack'    => ['webhook_secret' => env('SLACK_WEBHOOK_SECRET')],
'stripe'   => ['webhook_secret' => env('STRIPE_WEBHOOK_SECRET')],
'twilio'   => ['webhook_secret' => env('TWILIO_AUTH_TOKEN')],

Mailchimp — Mailchimp Marketing webhooks are verified via a secret you embed in your webhook URL (?secret=...). Configure the same value here so Receiver can compare it:

'mailchimp' => ['webhook_secret' => env('MAILCHIMP_WEBHOOK_SECRET')],

SendGrid — Signature verification is opt-in. Set webhook_secret to the PEM-format public key found in the SendGrid dashboard under Settings → Mail Settings → Event Webhook. Leave it empty to accept all requests without verification.

'sendgrid' => ['webhook_secret' => env('SENDGRID_WEBHOOK_PUBLIC_KEY', '')],

Postmark — Postmark supports several verification strategies. Configure which ones to use under the webhook key:

'postmark' => [
    'token' => env('POSTMARK_TOKEN'),
    'webhook' => [
        // One or more of: 'auth', 'headers', 'ips'
        'verification_types' => ['headers', 'ips'],

        // Header name => expected value pairs (used with 'headers')
        'headers' => [
            'X-Custom-Header' => env('POSTMARK_WEBHOOK_HEADER'),
        ],

        // Allowed source IPs (used with 'ips')
        // https://postmarkapp.com/support/article/800-ips-for-firewalls#webhooks
        'ips' => [
            '3.134.147.250',
            '50.31.156.6',
            '50.31.156.77',
            '18.217.206.57',
        ],
    ],
],
Postmark verification_type Description
auth HTTP Basic Auth via Auth::onceBasic()
headers Validates that specific request headers match expected values
ips Validates that the request originates from an allowed IP

If verification_types is empty or not set, all Postmark requests are accepted without verification.

Receiving Webhooks

Single provider

Create a controller and route for each webhook source, then call driver(), receive(), and ok():

<?php

namespace App\Http\Controllers\Webhooks;

use Illuminate\Http\Request;
use Receiver\Facades\Receiver;

class StripeWebhookController extends Controller
{
    public function store(Request $request)
    {
        return Receiver::driver('stripe')
            ->receive($request)
            ->ok();
    }
}
  • driver() — selects the provider and reads its config
  • receive() — verifies the signature and maps the event
  • ok() — dispatches matched handlers and returns a 200 response

Multiple providers

If you'd rather handle all webhooks through a single controller, use a {provider} route parameter:

// routes/web.php
Route::post('/webhooks/{provider}', [WebhookController::class, 'store'])
    ->withoutMiddleware(\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class);
<?php

namespace App\Http\Controllers\Webhooks;

use Illuminate\Http\Request;
use Receiver\Facades\Receiver;

class WebhookController extends Controller
{
    public function store(Request $request, string $provider)
    {
        return Receiver::driver($provider)
            ->receive($request)
            ->ok();
    }
}

Or use the included ReceivesWebhooks trait, which provides this exact store() method for you:

<?php

namespace App\Http\Controllers\Webhooks;

use Receiver\ReceivesWebhooks;

class WebhookController extends Controller
{
    use ReceivesWebhooks;
}

Fallbacks

Receiver silently ignores events it has no handler for. If you'd like to do something with unhandled events, add a fallback() callback before ok():

use Receiver\Providers\Webhook;

return Receiver::driver($provider)
    ->receive($request)
    ->fallback(function (Webhook $webhook) {
        Log::info('Unhandled webhook', ['event' => $webhook->getEvent()]);
    })
    ->ok();

Handling Webhooks

Once a webhook is received, Receiver looks for a handler class that matches the event and dispatches it. Handlers live in App\Http\Handlers\{Driver}\ by default. If no matching handler is found the webhook is silently ignored and a 200 is returned.

Handler naming

The handler class name is derived from the event name — all non-alphanumeric characters are treated as word separators, then converted to StudlyCase:

Event name Handler class
customer.created CustomerCreated
subscription_activated SubscriptionActivated
orders_created OrdersCreated
invoice.payment_failed InvoicePaymentFailed

For example, Stripe's customer.created event dispatches App\Http\Handlers\Stripe\CustomerCreated.

Each handler receives the $event name and the $data array, and must use the Dispatchable trait:

<?php

namespace App\Http\Handlers\Stripe;

use Illuminate\Foundation\Bus\Dispatchable;

class CustomerCreated
{
    use Dispatchable;

    public function __construct(
        public string $event,
        public array $data,
    ) {}

    public function handle(): void
    {
        // Your code here
    }
}

Queueing handlers

Because Receiver calls dispatch() on each handler, making a handler queued is as simple as implementing ShouldQueue:

<?php

namespace App\Http\Handlers\Stripe;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class CustomerCreated implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        public string $event,
        public array $data,
    ) {}

    public function handle(): void
    {
        // Your code here
    }
}

See the Laravel queue documentation for full details.

Extending Receiver

A provider is a PHP class that tells Receiver how to extract the event name, the payload data, and optionally how to verify the request's authenticity.

Generating a provider

The quickest way to scaffold a new provider is with the receiver:make Artisan command:

# Basic provider
php artisan receiver:make Mailgun

# With signature verification scaffolded
php artisan receiver:make Mailgun --verified

The generated class is placed in App\Http\Receivers. Once created, register the driver in your AppServiceProvider:

public function boot(): void
{
    app('receiver')->extend('mailgun', function () {
        return new \App\Http\Receivers\MailgunProvider(
            config('services.mailgun.webhook_secret')
        );
    });
}

Defining getEvent() and getData()

Implement getEvent() to return the event name. Optionally implement getData() to return the event payload — by default it returns $request->all().

<?php

namespace App\Http\Receivers;

use Illuminate\Http\Request;
use Receiver\Providers\AbstractProvider;

class MailgunProvider extends AbstractProvider
{
    public function getEvent(Request $request): string|array
    {
        return $request->input('event-data.event');
    }

    public function getData(Request $request): array
    {
        return $request->input('event-data', []);
    }
}

Securing webhooks

Implement a verify() method that returns true if the request is authentic, or false to reject it with a 401 response:

public function verify(Request $request): bool
{
    $signature = $request->header('X-Mailgun-Signature');
    $expected = hash_hmac('sha256', $request->getContent(), $this->secret);

    return hash_equals($expected, (string) $signature);
}

The signing secret from config/services.{driver}.webhook_secret is available as $this->secret.

Handshakes

Some services send a verification request when a webhook URL is first registered. Implement handshake() to respond to it:

public function handshake(Request $request): array
{
    return ['challenge' => $request->input('challenge')];
}

When handshake() returns a non-empty array, Receiver responds immediately with that payload and skips normal event handling. When it returns an empty array, Receiver processes the request normally.

Multiple events per request

Some services batch multiple events into a single request. Return an ['event_name' => $eventData] array from getEvent() and Receiver will dispatch a separate handler for each entry:

public function getEvent(Request $request): string|array
{
    $events = [];

    foreach (json_decode($request->getContent(), true) as $event) {
        $type = $event['type'] ?? null;
        if ($type && ! isset($events[$type])) {
            $events[$type] = $event;
        }
    }

    return $events;
}

Creating a community provider

If you're building a reusable provider package to share, add the --provider flag to also generate a companion ServiceProvider that registers the driver automatically:

php artisan receiver:make Mailgun --provider
php artisan receiver:make Mailgun --verified --provider

This generates:

  • app/Http/Receivers/MailgunProvider.php — your provider class
  • app/Providers/MailgunReceiverServiceProvider.php — auto-registers the driver via Receiver::extend()

To support Laravel package auto-discovery, add the service provider to your package's composer.json:

{
    "extra": {
        "laravel": {
            "providers": [
                "YourVendor\\YourPackage\\MailgunReceiverServiceProvider"
            ]
        }
    }
}

Users who install your package will have the driver available immediately, with no manual registration required.

Share Your Receivers!

Built a provider for a service not listed above? Share it with the community in the Receivers Discussion topic!

Credits

Made with contributors-img.

License

The MIT License (MIT). Please see License File for more information.

hotmeteor/receiver 适用场景与选型建议

hotmeteor/receiver 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 154.04k 次下载、GitHub Stars 达 393, 最近一次更新时间为 2022 年 08 月 22 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「webhooks」 「receiver」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 hotmeteor/receiver 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 hotmeteor/receiver 我们能提供哪些服务?
定制开发 / 二次开发

基于 hotmeteor/receiver 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 154.04k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 394
  • 点击次数: 24
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 393
  • Watchers: 2
  • Forks: 23
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-08-22