Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wechat Mini Program Share Bundle Laravel Package

tourze/wechat-mini-program-share-bundle

A PHP bundle for adding WeChat Mini Program sharing to your application. It packages configuration and services for share-related workflows, helping developers generate and manage mini program share links with less boilerplate and integrate sharing features more quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

This package covers a narrow but awkward slice of the WeChat Mini Program API: turning a shareTicket + encryptedData/iv pair from wx.getShareInfo into a decrypted group identifier (openGId), which is what you need to build anything group-aware — group leaderboards, "invite 3 friends" campaigns, team challenges, group-scoped coupons.

1. Require it (pin the new minor):

composer require tourze/wechat-mini-program-share-bundle:^1.1

2. Check the framework wiring before anything else. The Tourze family is predominantly Symfony bundles. Look in vendor/tourze/wechat-mini-program-share-bundle/ for:

  • composer.json → extra.laravel.providers (means Laravel auto-discovery works, you're done)
  • *Bundle.php at the root (means it's a Symfony bundle — you'll need a Laravel bridge package such as a tourze/laravel-* counterpart, or a ~20-line adapter ServiceProvider that binds the decryption service)

Do this first; it determines whether step 3 looks like php artisan vendor:publish or like hand-wiring a container definition.

3. Publish and configure:

php artisan vendor:publish --tag=wechat-mini-program-share-config
WECHAT_MINI_APP_ID=wx...
WECHAT_MINI_APP_SECRET=...

The mini program's AppID/Secret are needed because the share flow depends on the session_key obtained at code2Session login — the bundle either wraps that call or expects you to feed it a session_key.

4. First use case — resolve a group after a share: the mini program client calls wx.getShareInfo({ shareTicket }) inside onShow, POSTs encryptedData + iv + shareTicket to your API, and you decrypt:

// app/Http/Controllers/WechatShareController.php
public function store(Request $request)
{
    $data = $request->validate([
        'encryptedData' => ['required', 'string'],
        'iv'            => ['required', 'string'],
        'shareTicket'   => ['required', 'string'],
    ]);

    $group = $this->shares->decrypt(
        encryptedData: $data['encryptedData'],
        iv:            $data['iv'],
        sessionKey:    $request->user()->wechat_session_key, // cached at login
    );

    // { "openGId": "...", "watermark": { "appid": "wx...", ... } }
    return response()->json(['openGId' => $group->openGId]);
}

Verify the exact method name and return type against src/ — the returned value is a DTO or array containing openGId and a watermark.appid you should assert against your own AppID.

Where to look first: the config file (session-key source, cache adapter, HTTP client), then the single decryption service class — that class is the package. Everything else is glue.

Implementation Patterns

Login-then-share (the canonical flow). The session_key is minted at code2Session and is invalidated whenever the user re-opens the mini program. Persist it on your users row (or a dedicated wechat_sessions table) at login time and read it at share time:

// at login
$session = $this->miniProgram->code2Session($code);
$user->forceFill([
    'wechat_open_id'    => $session['openid'],
    'wechat_session_key'=> $session['session_key'], // encrypt at rest
    'wechat_session_at' => now(),
])->save();

Decouple decryption from the request. Share decryption happens in a burst right after a group share goes viral; put it behind a job so a slow WeChat/HTTP call never blocks the mini program's onShow handling:

ResolveShareGroup::dispatch($userId, $encryptedData, $iv, $shareTicket);

Model group membership explicitly. Treat openGId as a first-class entity rather than a loose string, because every downstream feature (scoped leaderboard, group-only promo, invite counting) joins on it:

Schema::create('wechat_groups', function (Blueprint $t) {
    $t->id();
    $t->string('open_gid')->unique();   // from the decrypted payload
    $t->foreignId('owner_id')->nullable();
    $t->timestamps();
});

Idempotency on the share ticket. shareTicket is short-lived and single-purpose; store a hash of it with a TTL and short-circuit repeats. This keeps re-renders of onShow from double-counting invites.

Events over inheritance. If the bundle dispatches a post-decrypt event, listen rather than subclass:

Event::listen(ShareGroupResolved::class, function ($event) {
    Cache::put("group:{$event->openGId}", $event->payload, now()->addHour());
});

Test with a fixed fixture. Capture one real encryptedData/iv/session_key triple from a staging mini program once, freeze it in tests/fixtures/, and assert the decryptor returns the expected openGId. This is the only reliable way to test without hitting WeChat.

Adapter boundary. Wrap the bundle behind your own interface (ShareGroupResolver) and bind it in AppServiceProvider. If the bundle's API shifts or you outgrow it, only the binding changes.

$this->app->bind(ShareGroupResolver::class, TourzeShareGroupResolver::class);

Gotchas and Tips

session_key goes stale faster than you think. WeChat rotates it on every wx.login, and it also expires. A stale key surfaces as -41001 / -41003 from the decrypt path, not as an obvious "session expired" — the error looks like a crypto failure. Always re-run code2Session before decrypting if wechat_session_at is older than a few hours, and treat decrypt failure as "refresh session and retry once," not as a 500.

iv is base64 but often URL-safe or padded oddly. If you get openssl_decrypt(): IV passed is only N bytes long, base64-decode with strict mode off and pad to 16 bytes. The bundle may already normalise this; if not, do it before handing the value in.

withShareTicket: true is mandatory client-side. Without it in onShareAppMessage's return value, wx.getShareInfo returns nothing usable and no amount of server-side work helps. When the payload arrives with an empty shareTicket, look at the front-end first.

Group share is not available in every context. Sharing to a single contact never yields a group openGId; only group shares do. Your UI must degrade gracefully — users sharing 1:1 should get a normal referral flow, not an error.

Verify watermark.appid. The decrypted payload carries the AppID it was encrypted for. Assert it matches your configured AppID; a mismatch means a cross-environment mixup (staging key, production front end) and is the fastest way to diagnose "it works locally" bugs.

Laravel config cache bites hard here. Because credentials come from env through a bundle config file, php artisan config:cache during deploy will freeze a stale AppID/Secret if the env isn't set at that moment. Run config:clear after any credential change and confirm the values via php artisan tinker before debugging the crypto.

Config keys may not follow Laravel conventions. Symfony bundles typically use snake_case flat keys or nested parameters: blocks, so config('wechat-mini-program-share.app_id') might actually be config('wechat_mini_program_share.app_id'). Dump config('wechat-mini-program-share') once to confirm rather than guessing.

Never log session_key or raw encryptedData. Both are user-scoped secrets. Log the ticket hash, the resolved openGId, and error codes only — the bundle's own exception messages may include payload fragments, so review what you're piping into your log handler.

Extension points worth knowing: the HTTP client (swap for a Guzzle instance with your own retry/middleware), the cache store used for session keys (point it at Redis, not the database), and the event dispatcher. These three cover ~90% of production customisation; avoid forking the decryptor itself.

On the 1.1.0 upgrade: the release is a 1.0.1 → 1.1.0 minor bump with no documented breaking changes in the available notes, so a standard composer update tourze/wechat-mini-program-share-bundle is reasonable. Because the changelog link carries no detail, read the diff (compare/1.0.1...1.1.0) for signature changes on the decryption entry point before deploying — that's the one method your controllers and jobs touch directly, and it's the only place a minor-version rename would break you. Pin ^1.1 and let your ShareGroupResolver adapter absorb any churn.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource