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 Work Server Bundle Laravel Package

tourze/wechat-work-server-bundle

Symfony bundle integrating WeChat Work (企业微信) server-side APIs. Provides callback verification, event and message handling, and a ready-to-use API client wired through Symfony DI, so you can receive events, send messages, and manage contacts without boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin. composer require tourze/wechat-work-server-bundle:^0.1.0. The jump from 0.0.2 to 0.1.0 is a pre-1.0 minor, which under Composer semantics is treated as breaking: the caret constraint ^0.1.0 will not pick up 0.0.x, and 0.2.0 will not be picked up either. Pin what you test against and read the compare link (0.0.2...0.1.0) yourself before upgrading — the release notes carry no description of what actually changed.

Check the foundation first. This is a bundle — it is built against Symfony's kernel, DI container, and config-tree conventions, not Laravel's. Before writing any application code, confirm which underlying transport/crypto package it depends on (a WeChat Work kernel or SDK of some kind) and whether you can use those classes standalone. In a Laravel app the realistic path is: pull in the bundle for its server-side callback handling (signature verification, AES decryption, XML parsing, message/event dispatch), and either run it through a Symfony-kernel bridge or instantiate the handler services manually in a Laravel service provider. Do not assume php artisan vendor:publish will produce anything useful — Symfony bundles ship config trees, not Laravel publishable config.

Where to look first, in order:

  1. The bundle class (*Bundle.php) — its loadExtension/prependExtension tells you the config keys and which services are auto-registered.
  2. The HTTP entry point that receives the WeCom callback POST/GET — that is the surface you have to expose as a route.
  3. The message/event dispatch layer — that's where your business logic attaches.

First use case: stand up the callback URL verification. WeCom sends a GET with msg_signature, timestamp, nonce, echostr; you must verify the signature, AES-decrypt echostr, and return the plaintext. Get that green in the WeCom admin console before touching message handling — it validates token, EncodingAESKey, and CorpID config in one shot.

Implementation Patterns

Route wiring. Register the callback as a POST (and GET for verification) route inside your WeCom-facing middleware group. Explicitly exclude it from VerifyCsrfToken, from Authenticate/session middleware, and from any middleware that rewrites the request body. The handler needs the raw request body and the raw query string.

Config, not .env magic. Whatever the bundle calls its config (token, encoding AES key, corp ID, agent ID), funnel it through config/services.php + .env and construct the handler explicitly. Symfony bundles generally won't read env() the way a Laravel package would, so treat config as an adapter you write, not something the package handles for you.

Dispatch on MsgType / Event, then get out of the request cycle. The standard shape:

$message = $handler->parse($rawBody, $query);   // verifies signature + decrypts
if ($messages->seen($message->msgId)) {         // idempotency guard
    return response('', 200);
}
ProcessWecomMessage::dispatch($message);        // queue it
return response('', 200);                       // respond fast, always

Keep the controller handler thin. WeCom's event vocabulary (text/image/event: enter_agent, change_contact, approval, task_card, …) grows, and you want one match on the type mapping to jobs, not business logic inline.

Passive vs. active replies. If the bundle supports returning an encrypted reply body synchronously, use that only for trivial cases (echo, canned help text). Everything else should go async and be delivered through the WeCom push/客服 message API using a cached access token — do not fetch a fresh access_token per message, WeCom rate-limits and invalidates aggressively. Put the token behind a cache key with TTL slightly under the returned expires_in.

Persistence/logging. Persist raw inbound payloads (encrypted or decrypted, your call) alongside your parsed record. When WeCom support asks "did you receive event X at 14:32", you want the answer to be a SELECT, not a log grep.

Gotchas and Tips

  • Empty changelog on a 0.x minor bump is a red flag. 0.0.2 → 0.1.0 is the release where the author felt free to break things. Until you've read the diff, treat this as an API you don't control: wrap the bundle's handler behind your own small interface so a future 0.2.0 doesn't ripple through your controllers.
  • Signature verification is order-sensitive. It's a SHA-1 over the sorted concatenation of token, timestamp, nonce, and (for encrypted mode) the encrypted payload. If verification fails, check sort order and the exact string you're hashing before you suspect the AES key.
  • EncodingAESKey is 43 characters, base64-decoded with a trailing =. The most common integration failure is a key pasted with/without padding or with whitespace. Also confirm the CorpID used in decrypt matches the one configured — a mismatch fails silently-ish.
  • WeCom retries. If you don't return HTTP 200 within ~5 seconds, the platform retries the same message up to three times. Without a MsgId-keyed idempotency guard you will process duplicates and double-send replies. This is the single most common production bug in WeCom integrations.
  • Byte-exact body. $request->all() and JSON-parsing middleware destroy the payload the signature covers. Use $request->getContent().
  • Clock skew. Timestamp-based signature checks reject requests if your server's clock drifts; make sure NTP is healthy on the box.
  • Doctrine assumptions. Tourze bundles frequently assume Doctrine entities and a configured entity manager. In Laravel you're on Eloquent — check whether the bundle hard-requires an ORM/DB layer at boot, or only for optional features like message logging. If it does, you may need to register a minimal Doctrine setup or bypass those services entirely.
  • Extension points to prefer: the event/message handler registration (add your own handlers rather than editing vendor dispatch), and the HTTP handler service (decorate it if you need custom verification or logging). Avoid subclassing bundle internals — at 0.1.0 with an unreadable changelog, there is no stability contract protecting you.
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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment