atm-code/ar-php-laravel
Laravel integration for the Ar-PHP library, bringing Arabic text processing to your apps: Arabic string manipulation, numbers, dates and Hijri conversion, Quran utilities, transliteration, and more through a convenient service provider and facade.
still-code/ar-php-laravel is a thin Laravel service-provider/facade wrapper around the ar-php library (Khaled Al-Shamaa's ArPHP). It does not ship any domain logic of its own — everything useful lives in the underlying ArPHP class, so your mental model should be "Laravel-native DI and config for a legacy Arabic text utility."
Minimal setup:
composer require still-code/ar-php-laravel
php artisan vendor:publish --provider="StillCode\ArPHP\Laravel\ArPHPServiceProvider"
The provider is auto-discovered; there is nothing to register by hand. Publishing gives you the package config (charset, default Hijri adjustment, Arabic-numeral vs. Latin-numeral output) — read this file first, because most surprising behaviour traces back to those defaults. Check the README's facade alias; resolve the class via the container (app(ArPHP::class)) rather than a hardcoded use if you want to keep it mockable.
First use case to try: number-to-Arabic-words, since it is the highest-value, lowest-risk call and needs no text state.
ArPHP::setText('1250');
echo ArPHP::int2str(); // "ألف ومئتان وخمسون"
If that renders correctly in your terminal or Blade view, your charset and font path are fine and everything else will behave.
Upgrading from 2.x: 3.0.0 is a maintenance-boundary release. The only functional change is Laravel 13 support with a PHP ^8.2 floor (PR #56), plus CI/dependabot bumps. Consequently the major version bump is almost certainly Laravel-version constraint noise, not an API break — but confirm your illuminate/support resolution with composer why illuminate/support and re-run your test suite before shipping, because the PHP floor change can silently shift transitive dependencies.
Wrap it, don't sprinkle it. The facade is stateful (see Gotchas), so day-to-day usage should go through one or two small application services that own the state lifecycle:
final class ArabicText
{
public function __construct(private ArPHP $ar) {}
public function toWords(int|float $n): string
{
$this->ar->setText((string) $n);
return $this->ar->int2str();
}
public function formatMoney(float $amount, string $currency = 'SAR'): string
{
$this->ar->setText((string) $amount, $currency);
return $this->ar->money();
}
}
This gives you a mockable seam, a single place to reset text between calls, and a place to add Number::currency() fallbacks.
Validation/messages and invoices are the two natural homes: money() for invoice totals and int2str() for cheque amounts ("only one thousand two hundred fifty riyals"), arDate() for Hijri/Gregorian dual dates on printed documents, and utf8Glyphs() only when you are rendering to a PDF generator (mPDF/TCPDF) whose font lacks proper Arabic shaping.
Queues and jobs: because the binding is a shared singleton, never rely on setText() state surviving across calls in a long-running worker without re-setting it in the same method. Prefer passing the input explicitly into your wrapper method every time.
Blade: use a view composer or a @arabicNumber directive rather than calling the facade inside templates; the glyph-shaping calls are not free and templates get cached poorly around them.
Testing: bind a fake in your test case ($this->instance(ArPHP::class, $fake)) — otherwise your feature tests will start depending on PHP extensions and the underlying library's quirks.
setText() mutates the shared instance. In Octane, queue workers, and Pest/PHPUnit suites that share the container, a forgotten setText() from a previous call will produce plausible-but-wrong output rather than an error. Always set text immediately before the consuming call, or clone the injected instance.utf8Glyphs() outputs Arabic Presentation Forms-B. The string looks fine in a PDF but breaks search, copy-paste, strlen-based limits, and comparison against your database values. Store the logical (unshaped) text and shape only at the render boundary.int2str/money emit Eastern Arabic-Indic digits (١٢٣) or Latin (123). If your Blade views or PDFs assume one form, pin it in config and assert on it in a test — this is a classic "looks right on my machine" bug.mbstring (and often intl). Missing extensions surface as mangled output, not exceptions. Add ext-mbstring to composer.json and to your CI image.ä or ????, you are almost always double-encoding — a UTF-8 config value being passed through utf8_encode/iconv a second time, or a controller returning the string inside a json_encode with JSON_UNESCAPED_UNICODE missing.AppServiceProvider::register() and keep the facade contract stable.Carbon::translatedFormat() covers most Arabic month-name formatting, and Number::currency() covers display. Reserve this package for what it uniquely does: number-to-words, Hijri arithmetic, and glyph shaping..github/ affects your runtime. Review the diff for composer.json and src/ specifically; that is where the real signal is.How can I help you explore Laravel packages today?