instasent/sms-counter-php
A PHP library for accurately counting SMS messages and calculating message parts, with support for GSM 7-bit and Unicode characters, concatenation, and encoding detection. Useful for estimating SMS costs and validating message length in PHP applications.
What the package is: A single-purpose, framework-agnostic PHP utility that classifies a message body as GSM 03.38 (7-bit) or UCS-2, counts characters/remaining capacity, and computes single vs. multipart segment counts against the standard thresholds (160/153 GSM-7, 70/67 UCS-2). It is not a Laravel package — no service provider, facade, config, or publishable assets. It is a library we call from our own code.
Architecture fit: Good fit as an internal domain utility, not as an infrastructure dependency. It slots naturally into the pre-send boundary of any SMS path (notification, job, form validation, cost preview) and is stateless, so it is safe in queued workers and long-running Octane processes. Because it has no framework coupling and (presumably) no runtime dependencies, it does not distort our architecture — it becomes a leaf node behind an interface we own.
Integration feasibility: High, and low-effort. composer require plus a thin adapter class is measured in hours, not days. The work is not "integrate the library," it is "decide where segment counting is authoritative and enforce it consistently."
Technical risk: Low code risk, medium supply-chain risk.
{ } [ ] € ^ \ ~ |) consume two septets and change segment math; emoji and ZWJ sequences are multiple UTF-16 code units under UCS-2; national language shift tables and non-GSM characters can flip an entire message to UCS-2 and roughly halve capacity. The cost of a wrong answer is a silent 2x message bill or an unexpected split — which is exactly the failure the library exists to prevent.Key questions to resolve before adoption:
app/Support?Stack fit: Laravel-idiomatic but not Laravel-native. Treat it as a third-party algorithm behind a first-party contract. Do not let Instasent\... namespaces leak into controllers, jobs, or notifications; that is the difference between a one-day swap and a one-week migration if the library dies.
Recommended shape:
App\Contracts\SmsSegmentCounter with a single method returning a value object (encoding, segments, length, remaining, perSegmentLimit).InstasentSmsSegmentCounter as the adapter; bind it in AppServiceProvider.SmsSegments validation rule for FormRequests and a SmsCostEstimator service built on top of the counter for admin/preview surfaces.sms.segments and sms.encoding as metrics on every send so drift vs. carrier billing is observable — this is the only reliable way to catch an edge-case miscount in production.Migration path: There is nothing to migrate from unless we currently hardcode strlen()/mb_strlen() checks or rely on the gateway's own segmentation. If we do, catalogue those call sites first; they are the real scope. Adoption is additive: no schema change, no data migration, no breaking API change.
Compatibility: Pure-PHP, no extensions or services required, so it runs anywhere our app runs. The genuine compatibility question is PHP version and Laravel version — the package predates Laravel 8+, but since it has no framework integration, Laravel compatibility is effectively a non-issue; only the PHP runtime matters. Verify under our exact PHP minor with E_ALL before committing.
Sequencing:
€, emoji, mixed, empty, 160/161/306/307-char boundaries) and diff against carrier-reported segment counts from historical sends.packages/ or reimplement — the algorithm is fully specified and the effort is small and known.Maintenance: Very low ongoing effort, but no upstream momentum to lean on. Plan for a soft fork posture: pin the exact version, keep the adapter thin, and budget ~1 day/quarter (or on PHP upgrades) to verify behaviour. If the maintainer goes quiet — the likely scenario given the 2019 release — we own it. That is acceptable only because the codebase is small enough to own.
Support: Community-only, no SLA, no vendor to escalate to. Internal ownership must be explicit: name a code owner for the adapter and the golden dataset. The dataset is the real asset here, not the library.
Scaling: Effectively free. Counting is O(n) on message length (tens to hundreds of bytes), no I/O, no allocations of note, no caching layer needed. It will not be a bottleneck at any plausible volume; calling it per message in a bulk-send loop of 100k is still negligible. Safe under Octane provided it is stateless (verify).
Failure modes and blast radius:
Ramp-up: Hours for any Laravel developer. The concept (GSM-7 vs UCS-2, 160/153 and 70/67) is the only learning curve, and it is well documented publicly. The adapter pattern means a new engineer never needs to read the library source unless debugging an edge case.
TPM recommendation: Adopt as a wrapped, pinned utility with a golden-dataset test and segment-level metrics — provided the spike passes for PHP 8.x and emoji/extension-character handling matches carrier behaviour. Do not adopt it as a trusted dependency without that validation, and do not adopt it at all if we only need a rough estimate in one place; the rules are simple enough to implement inline. The value here is consistency across every send path, not the algorithm itself.
How can I help you explore Laravel packages today?