Str::random

Generates a cryptographically secure random alphanumeric string of the requested length.

Signature
Str::random(int $length = 16): string

Parameters

ParameterTypeDescription
$$lengthoptionalint= 16Number of characters to generate. Zero or a negative value returns an empty string.

Return value

stringA string of the requested length drawn from A-Z, a-z and 0-9.

Errors

random_bytes throws Random\RandomException when the platform cannot supply cryptographically secure randomness.

Str::random draws bytes from random_bytes, base64-encodes them and strips +, / and =, leaving a purely alphanumeric string. That makes the output safe to drop into a URL, a filename, a header or a database column without escaping, and secure enough for tokens — it is not rand() with a character list.

Length is characters, not entropy

The alphabet has 62 symbols, so each character carries roughly 5.95 bits. The default 16 characters is about 95 bits, fine for a filename suffix or a cache-busting key. For anything a stranger could brute-force — password reset links, invitation tokens, signed URLs — use 32 or more, and remember that Laravel's own token features already generate their own values.

Making it deterministic in tests

Because the value changes on every call, an assertion against a literal will fail. Str::createRandomStringsUsing() installs a factory that receives the requested length and returns whatever you want; Str::createRandomStringsNormally() restores the real generator. The override is static and global, so restore it in tearDown or the next test inherits your fake.

Uniqueness is overwhelmingly likely but never guaranteed. If a column must be unique, put a unique index on it and retry on violation rather than trusting the odds.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Generate a unique suffix for an uploaded filename so two uploads cannot collide.
  • Create an invitation or share token stored alongside a record.
  • Produce a throwaway identifier for a job, batch, or cache key in a seeder.

Frequently asked questions

Is Str::random safe for security tokens?

Yes — it is built on random_bytes, PHP's cryptographically secure source, not on rand() or uniqid(). Use 32 or more characters for anything an attacker could try to guess, such as a password reset or invitation token.

How do I make Str::random return a fixed value in a test?

Call Str::createRandomStringsUsing(fn ($length) => 'fixed-value') before the code under test, and Str::createRandomStringsNormally() in tearDown. The override is a static property, so failing to restore it affects every later test in the process.

What characters can Str::random produce?

Only A-Z, a-z and 0-9 — the base64 alphabet with +, / and = removed. That makes the output safe in URLs, filenames and headers with no escaping, but it also means it is not valid base64 and cannot be decoded.

More examples

A unique filename for an upload

The alphanumeric output needs no escaping in a path or a URL, and dropping the original name removes directory traversal and encoding problems in one step. Requires a booted application for the Storage facade and the request.

Example · php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class AvatarController extends Controller
{
    public function store(Request $request)
    {
        $file = $request->file('avatar');

        // Never trust the client-supplied name.
        $name = Str::random(40).'.'.$file->extension();

        Storage::disk('public')->putFileAs('avatars', $file, $name);

        return back();
    }
}

Pinning the value in a test

The factory replaces every Str::random call for the duration of the test, so the token written to the database is predictable. The tearDown is not optional — the override is a static property and would otherwise leak into every test that runs after this one.

Example · php
<?php

namespace Tests\Feature;

use Illuminate\Support\Str;
use Tests\TestCase;

class InvitationTest extends TestCase
{
    protected function tearDown(): void
    {
        Str::createRandomStringsNormally();

        parent::tearDown();
    }

    public function test_the_invitation_token_is_stored(): void
    {
        Str::createRandomStringsUsing(fn () => 'fixed-token');

        $this->post('/invitations', ['email' => '[email protected]']);

        $this->assertDatabaseHas('invitations', [
            'token' => 'fixed-token',
        ]);
    }
}

Choosing a length

Eight characters is guessable by an attacker with a botnet and is only appropriate for a non-secret identifier. Laravel itself uses 40 for API and password-reset tokens, which is the length to copy for anything security-bearing.

Example · php
<?php

use Illuminate\Support\Str;

// 62 possible characters per position.
foreach ([8, 16, 32, 40] as $length) {
    $bits = $length * log(62, 2);

    printf("%2d chars ≈ %5.1f bits of entropy\n", $length, $bits);
}

//  8 chars ≈  47.6 bits of entropy
// 16 chars ≈  95.3 bits of entropy
// 32 chars ≈ 190.6 bits of entropy
// 40 chars ≈ 238.2 bits of entropy

Discussion

  • Be the first to comment on this lesson.