承接 zenphp/obsidian 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

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

zenphp/obsidian

Composer 安装命令:

composer require zenphp/obsidian

包简介

Obsidian provides expressive, fluent subscription billing for Laravel applications using CCBill and SegPay payment processors.

README 文档

README

Obsidian

Coverage Build Status Total Downloads Latest Stable Version License

About Obsidian

Obsidian provides expressive, fluent subscription billing for Laravel applications using CCBill and SegPay payment processors. Built specifically for adult content platforms and high-risk merchants who need reliable, compliant payment processing.

Gateway Support Status

Gateway Status Subscriptions One-Time Charges Webhooks Cancellation
CCBill ✅ Implemented ✅ (via DataLink)
SegPay 🚧 Planned
Fake ✅ Implemented

Note: SegPay integration is planned for a future release. Currently, all SegPay gateway methods will throw a GatewayException.

Features

  • Multiple Payment Gateways - Support for CCBill with SegPay planned
  • Subscription Management - Create, cancel, and manage recurring subscriptions
  • Trial Periods - Built-in support for trial subscriptions
  • Webhook Handling - Automatic webhook processing with signature validation
  • One-Time Charges - Process single payments alongside subscriptions
  • Fake Gateway - Test your billing logic without hitting real APIs
  • 100% Test Coverage - Fully tested with comprehensive mocked responses
  • Type Safe - Full PHP 8.4 type coverage with PHPStan level max

Requirements

  • PHP 8.4 or higher
  • Laravel 12.0 or higher
  • A CCBill merchant account (SegPay support coming soon)

Installation

Install the package via Composer:

composer require zenphp/obsidian

Publish Configuration

Publish the configuration file and migrations:

php artisan vendor:publish --tag=obsidian-config
php artisan vendor:publish --tag=obsidian-migrations

Run the migrations:

php artisan migrate

Environment Configuration

Add your payment gateway credentials to your .env file:

# Default Gateway
OBSIDIAN_GATEWAY=ccbill

# CCBill Configuration
CCBILL_MERCHANT_ID=your_merchant_id
CCBILL_SUBACCOUNT_ID=your_subaccount_id
CCBILL_MERCHANT_APP_ID=your_merchant_application_id
CCBILL_SECRET_KEY=your_secret_key
CCBILL_DATALINK_USERNAME=your_datalink_username
CCBILL_DATALINK_PASSWORD=your_datalink_password
CCBILL_WEBHOOK_SECRET=your_webhook_secret

# Currency Settings
OBSIDIAN_CURRENCY=usd
OBSIDIAN_CURRENCY_LOCALE=en

CCBill Requirements

To use the CCBill gateway, you'll need:

  1. Merchant Application ID & Secret Key - For OAuth 2.0 authentication with the CCBill REST API
  2. DataLink Credentials - Username and password for subscription cancellation via the legacy DataLink system
  3. Webhook Secret - For validating incoming webhook signatures (HMAC SHA256)
  4. FlexForms - A configured FlexForm for payment page generation

Important: CCBill uses OAuth 2.0 for API authentication. The access token is automatically cached and refreshed as needed.

Setup

Add the Billable Trait

Add the Billable trait to your User model (or any model that should have subscriptions):

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Zen\Obsidian\Billable;

class User extends Authenticatable
{
    use Billable;

    // ... rest of your model
}

Database Columns

The migrations will add the following columns to your users table:

  • trial_ends_at - For generic trial periods (optional)

And create the following tables:

  • subscriptions - Stores subscription records
  • subscription_items - Stores subscription line items (for future use)

Usage

Creating Subscriptions

Create a new subscription for a user:

use Illuminate\Http\Request;

Route::post('/subscribe', function (Request $request) {
    $user = $request->user();

    $subscription = $user->newSubscription('default', 'plan_monthly')
        ->create($request->payment_token);

    return redirect('/dashboard');
});

With Trial Period

Add a trial period to a subscription:

$subscription = $user->newSubscription('default', 'plan_monthly')
    ->trialDays(14)
    ->create($request->payment_token);

Specify Gateway

Choose a specific payment gateway:

$subscription = $user->newSubscription('default', 'plan_monthly')
    ->gateway('segpay')
    ->create($request->payment_token);

With Metadata

Attach custom metadata to a subscription:

$subscription = $user->newSubscription('default', 'plan_monthly')
    ->withMetadata([
        'user_ip' => $request->ip(),
        'referral_code' => 'SUMMER2024',
    ])
    ->create($request->payment_token);

Checking Subscription Status

Check if a user has an active subscription:

if ($user->subscribed('default')) {
    // User has an active subscription
}

// Check for a specific subscription name
if ($user->subscribed('premium')) {
    // User has an active premium subscription
}

Check Trial Status

if ($user->onTrial('default')) {
    // User is on trial
}

Get Subscription

Retrieve a user's subscription:

$subscription = $user->subscription('default');

if ($subscription && $subscription->active()) {
    // Subscription is active
}

Cancelling Subscriptions

Cancel a subscription at the end of the billing period:

$subscription = $user->subscription('default');
$subscription->cancel();

Cancel immediately:

$subscription->cancelNow();

One-Time Charges

Process a one-time payment:

$result = $user->charge(2999, $paymentToken, [
    'description' => 'Premium content purchase',
]);

// Result contains:
// - transaction_id
// - amount
// - status

Webhooks

Obsidian automatically handles webhooks from CCBill and SegPay to keep your subscription status in sync.

Webhook URLs

Configure these webhook URLs in your payment processor dashboards:

  • CCBill: https://yourdomain.com/webhooks/ccbill
  • SegPay: https://yourdomain.com/webhooks/segpay

Webhook Events

Obsidian dispatches the following events that you can listen to:

  • Zen\Obsidian\Events\SubscriptionCreated - New subscription activated
  • Zen\Obsidian\Events\PaymentSucceeded - Successful payment processed
  • Zen\Obsidian\Events\PaymentFailed - Payment failed
  • Zen\Obsidian\Events\SubscriptionCancelled - Subscription cancelled

Listening to Events

Create an event listener:

<?php

namespace App\Listeners;

use Zen\Obsidian\Events\PaymentSucceeded;

class SendPaymentReceipt
{
    public function handle(PaymentSucceeded $event): void
    {
        $subscription = $event->subscription;
        $amount = $event->amount;

        // Send receipt email to user
        $subscription->user->notify(new PaymentReceiptNotification($amount));
    }
}

Register in EventServiceProvider:

protected $listen = [
    \Zen\Obsidian\Events\PaymentSucceeded::class => [
        \App\Listeners\SendPaymentReceipt::class,
    ],
];

Testing

Obsidian includes a FakeGateway for testing your billing logic without hitting real payment APIs.

Using the Fake Gateway

In your tests or local environment:

// In your .env or test configuration
OBSIDIAN_GATEWAY=fake

// In your test
$subscription = $user->newSubscription('default', 'plan_monthly')
    ->gateway('fake')
    ->create('fake_token_123');

expect($subscription->active())->toBeTrue();

Mocking HTTP Responses

For testing with real gateways, use Laravel's HTTP fake:

use Illuminate\Support\Facades\Http;

Http::fake([
    'api.ccbill.com/*' => Http::response([
        'subscriptionId' => 'sub_123',
        'status' => 'active',
    ], 200),
]);

$subscription = $user->newSubscription('default', 'plan_monthly')
    ->gateway('ccbill')
    ->create('test_token');

Running Tests

# Run all tests
composer test

# Run tests with coverage
composer test:coverage

# Run type coverage
composer test:types

# Run static analysis
composer test:static

API Reference

Billable Trait Methods

The Billable trait provides the following methods:

subscriptions()

Get all subscriptions for the user.

$subscriptions = $user->subscriptions;

subscription(string $name = 'default')

Get a specific subscription by name.

$subscription = $user->subscription('premium');

subscribed(string $name = 'default')

Check if the user has an active subscription.

if ($user->subscribed()) {
    // User is subscribed
}

onTrial(string $name = 'default')

Check if the user is on a trial period.

if ($user->onTrial()) {
    // User is on trial
}

onGenericTrial()

Check if the user is on a generic trial (not tied to a subscription).

if ($user->onGenericTrial()) {
    // User has a generic trial
}

newSubscription(string $name, string $plan)

Start building a new subscription.

$builder = $user->newSubscription('default', 'plan_monthly');

charge(int $amount, string $token, array $options = [])

Process a one-time charge.

$result = $user->charge(2999, 'payment_token');

Subscription Methods

active()

Check if the subscription is active.

if ($subscription->active()) {
    // Subscription is active
}

cancelled()

Check if the subscription has been cancelled.

if ($subscription->cancelled()) {
    // Subscription is cancelled
}

expired()

Check if the subscription has expired.

if ($subscription->expired()) {
    // Subscription has expired
}

onTrial()

Check if the subscription is on a trial period.

if ($subscription->onTrial()) {
    // Subscription is on trial
}

cancel()

Cancel the subscription at the end of the billing period.

$subscription->cancel();

cancelNow()

Cancel the subscription immediately.

$subscription->cancelNow();

Gateway Configuration

CCBill

CCBill uses OAuth 2.0 for API authentication and supports:

  • Payment token charging for subscriptions and one-time payments
  • Subscription cancellation via DataLink (legacy CGI system)
  • Webhook events with HMAC SHA256 signature validation
  • ISO 4217 numeric currency codes (USD=840, EUR=978, GBP=826, etc.)

Webhook Events Supported:

CCBill Event Normalized Type
NewSaleSuccess subscription.created
NewSaleFailure subscription.failed
RenewalSuccess payment.succeeded
RenewalFailure payment.failed
Cancellation subscription.cancelled
Chargeback subscription.chargeback
Refund payment.refunded
Expiration subscription.expired

SegPay

🚧 Coming Soon: SegPay integration is planned for a future release. All SegPay gateway methods currently throw a GatewayException with the message "SegPay gateway is not yet implemented".

Fake Gateway

The FakeGateway is perfect for testing and development:

  • No external API calls
  • Instant responses
  • Predictable behavior
  • Static state storage for test assertions
  • shouldFail() method for simulating failures
  • reset() method for test isolation
use Zen\Obsidian\Gateways\FakeGateway;

// Reset state between tests
FakeGateway::reset();

// Simulate a failure
FakeGateway::shouldFail('Payment declined', 402);

// Access internal state
$subscriptions = FakeGateway::getSubscriptions();
$charges = FakeGateway::getCharges();

Security

Webhook Signature Validation

All webhooks are validated using HMAC SHA256 signatures to ensure they come from your payment processor.

Configure your webhook secrets in .env:

CCBILL_WEBHOOK_SECRET=your_secret_here
SEGPAY_WEBHOOK_SECRET=your_secret_here

Redirect URL Validation

The VerifyRedirectUrl middleware prevents open redirect vulnerabilities by ensuring redirect URLs match your application's host.

Troubleshooting

Webhooks Not Working

  1. Verify webhook URLs are configured correctly in your payment processor dashboard
  2. Check webhook secrets match between your .env and processor settings
  3. Review logs for signature validation errors
  4. Ensure your application is accessible from the internet (use ngrok for local testing)

Subscription Not Activating

  1. Check that the subscription exists in your database
  2. Verify the gateway_subscription_id matches the processor's ID
  3. Review webhook logs to ensure events are being received
  4. Check that the subscription status is being updated correctly

Payment Failures

  1. Verify API credentials are correct in .env
  2. Check that payment tokens are valid and not expired
  3. Review gateway-specific error messages in logs
  4. Ensure your merchant account is active and in good standing

Contributing

Please see CONTRIBUTING.md for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

License

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

Credits

  • Built by Jetstream Labs
  • Inspired by Laravel Cashier
  • Designed for adult content platforms and high-risk merchants

Support

zenphp/obsidian 适用场景与选型建议

zenphp/obsidian 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 11 月 21 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

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

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-11-21