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

Base58 Laravel Package

tuupola/base58

tuupola/base58 is a lightweight PHP library for Base58 encoding and decoding, supporting Bitcoin, Flickr, Ripple, and custom alphabets plus Base58Check. It offers a simple API for compact, human-resistant identifiers in PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer — there is no Laravel auto-discovery, but nothing needs publishing:

composer require tuupola/base58

Confirm the runtime has one of the math extensions, since that determines your default adapter:

php -m | grep -E 'gmp|bcmath'

Minimal first use — encode a string, decode it back:

use Tuupola\Base58;

$base58  = new Base58();                    // Bitcoin alphabet, GMP by default
$encoded = $base58->encode('Hello World!'); // 2NEpo7TZRRrLZSi2U
$decoded = $base58->decode($encoded);       // Hello World!

Where to look first:

  1. The constructor options — characters and mode are the only knobs you will touch 95% of the time.
  2. The three alphabet constants: Base58::BITCOIN, Base58::FLICKR, Base58::RIPPLE.
  3. The three mode constants: Base58::GMP, Base58::BCMATH, Base58::PHP.

First realistic use case: shortening opaque identifiers (UUIDs, random tokens, SHA-256 digests) into a URL-safe, character-safe representation, or producing Bitcoin-style addresses. Base58 is encoding, not encryption — do not use it to hide secrets.

Implementation Patterns

Bind as a singleton service provider

The class is stateless after construction, so one instance per request is enough. Configure the adapter once at the container level instead of in every call site:

// app/Providers/Base58ServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Tuupola\Base58;

class Base58ServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Base58::class, fn () => new Base58([
            'characters' => Base58::BITCOIN,
            'mode'       => extension_loaded('gmp') ? Base58::GMP : Base58::PHP,
        ]));
    }
}

Optional Laravel facade

There is no shipped facade, but you can wrap it in seconds:

namespace App\Support\Facades;

use Illuminate\Support\Facades\Facade;

class Base58 extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return \Tuupola\Base58::class;
    }
}

Prefer constructor injection in application code; keep the facade for Blade and quick scripts.

Wrap it in a domain service

Resist sprinkling encode()/decode() across controllers. A thin service keeps alphabet and checksum logic in one place:

namespace App\Services;

use Tuupola\Base58;

class ShortId
{
    public function __construct(private Base58 $base58) {}

    public function encode(string $binary): string
    {
        return $this->base58->encode($binary);
    }

    public function decode(string $encoded): string
    {
        return $this->base58->decode($encoded);
    }
}

Encoding UUIDs / random tokens

encode() and decode() are binary-safe, which is the whole point for arbitrary data:

$uuid   = (string) \Illuminate\Support\Str::uuid();
$binary = hex2bin(str_replace('-', '', $uuid));
$short  = $base58->encode($binary);          // ~22 chars instead of 36

For opaque tokens, start from random bytes, not from a string:

$token = base64_encode(random_bytes(16));    // source
$short = $base58->encode(random_bytes(16));  // 22-ish chars, URL safe

Bitcoin-style addresses (checksum is your job)

The package only handles the alphabet math. Checksum, version byte, and payload are on you:

$payload  = "\x00" . $pubKeyHash;                       // version + hash160
$checksum = substr(hash('sha256', hash('sha256', $payload, true), true), 0, 4);
$address  = $base58->encode($payload . $checksum);

Choosing an alphabet per feature

Alphabets are not interchangeable — you must decode with the same one you encoded with. Keep the constant next to the caller:

$flickr = new Base58(['characters' => Base58::FLICKR]);  // 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
$ripple = new Base58(['characters' => Base58::RIPPLE]);  // rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz

Bitcoin is the default and the right choice for anything user-facing. Choose Flickr/Ripple only for interoperability with those ecosystems.

Testing

Behavior is deterministic for a given (input, alphabet) pair, so golden-vector tests are trivial:

test('base58 roundtrip', function () {
    $codec = new Base58(['mode' => Base58::PHP]); // force pure PHP so CI needs no extensions
    expect($codec->decode($codec->encode('Hello World!')))->toBe('Hello World!');
});

Gotchas and Tips

  • Missing math extension. Default adapter is GMP; if ext-gmp is absent on a deploy target, construction fails (or silently falls back, depending on version). Pin mode explicitly via extension_loaded('gmp') and prefer BCMath over PHP when possible.
  • Base58::PHP is slow. It's a per-byte long-division implementation — fine for a 32-byte digest, painful for kilobytes of data. Never use it for bulk payloads.
  • Not encryption, not hashing, not compression. It's a base conversion. A Base58 string is freely reversible by anyone. Don't present it as obfuscation.
  • No built-in checksum. A single typo on decode yields garbage silently — validate the checksum yourself (double SHA-256 for Bitcoin-style) before trusting the output.
  • Alphabet must match. Encoding with Bitcoin and decoding with Flickr returns bytes without error; you'll only notice later. Encode the alphabet choice in configuration or your service, not in ad-hoc call sites.
  • Case sensitivity in the database. Bitcoin Base58 is case-sensitive but MySQL's default utf8mb4_general_ci collation is not — WHERE short_id = ? can match the wrong row. Use a binary collation, VARBINARY, or a BINARY cast, and store the raw bytes column as BLOB/VARBINARY, never VARCHAR.
  • Leading zero bytes are significant. Each leading \x00 encodes to a leading 1 (Bitcoin alphabet). Don't ltrim() anything before encoding, and don't strip leading 1s before decoding — the round trip will silently lose data.
  • Binary safety cuts both ways. encode() returns printable ASCII, but decode() returns raw bytes. Be explicit about which side of the boundary you're on — a UTF-8 assumption on the decoded value will corrupt data.
  • Base58Proxy is not a Laravel facade. The package ships a static proxy (Tuupola\Base58Proxy::encode()); don't confuse it with a service-container-bound facade. It's handy in one-off scripts, but it bypasses container config, so avoid it in application code.
  • URL/copy safety. Base58 strips 0 O I l from the Bitcoin alphabet, which makes it good for human-transcribed IDs, but it is not base62 — don't assume it's shorter than base64; it's usually ~5% longer than base64 for the same bytes.
  • Extension points. Both characters (any 58-char string) and mode are constructor options, so you can inject alternative alphabets without subclassing. Subclass Base58 only if you need to add checksum/versioning behavior as part of the object.
  • Version pinning. This is a small, low-activity package (last release cadence is slow). Pin a version in composer.json and cover your own encode/decode round trip with a golden-vector test so a future upgrade that changes defaults shows up as a failing test, not a production incident.
  • Debugging mismatched output. If encode looks wrong, verify: (1) you're feeding the bytes you think you are (bin2hex() and inspect), (2) the alphabet is the default Bitcoin one, (3) the mode matches what the reference implementation used. The mode should not change output, but a wrong alphabet absolutely will.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
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