Str::remove

Deletes every occurrence of a value, or of each value in a list, from a string.

Signature
Str::remove(string|iterable $search, string|iterable $subject, bool $caseSensitive = true): string

Parameters

ParameterTypeDescription
$$searchstring|iterable<string>The value to delete, or a list of values applied one after another in order.
$$subjectstring|iterable<string>The string to remove from. An array subject returns an array with the removal applied to each element.
$$caseSensitiveoptionalbool= trueWhen false, matching ignores case (str_ireplace instead of str_replace).

Return value

stringThe subject with every occurrence of each search value deleted.

Str::remove is str_replace with an empty replacement and a case flag bolted on. The value it adds over calling str_replace($search, '', $subject) yourself is the $caseSensitive argument and the fact that it reads as an intent rather than a mechanism.

Argument order

Needle first, haystack second — Str::remove($search, $subject). That matches str_replace but is the reverse of what people write from memory, and because both arguments are strings there is no type error to catch the mistake: you just get the wrong string back.

An array of needles is applied sequentially

Each search value is removed from the result of the previous one, not all at once against the original. That ordering matters when one removal can create or destroy a match for a later one, and it is why the common trick of "removing" script tags with a list of strings is not a sanitiser.

One pass, no rescanning

Within a single search value the scan does not restart after a match, so a removal can leave a fresh occurrence behind: deleting foo from ffoooo yields foo. If you need removal repeated until the string stops changing, loop until the result is stable.

Example

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

When to use it

  • Strip formatting characters out of a phone number or card number before storing it.
  • Delete a fixed prefix such as a currency symbol or unit from scraped input.
  • Remove known noise words or zero-width characters from a pasted value.

Frequently asked questions

What is the argument order for Str::remove?

The search value comes first and the subject second: Str::remove($search, $subject). This matches str_replace, but since both arguments accept strings, reversing them fails silently rather than throwing.

How do I remove a substring ignoring case in Laravel?

Pass false as the third argument, as in Str::remove('E', 'Peter', false), which switches the implementation from str_replace to str_ireplace. Matching is case-insensitive for ASCII; multibyte case handling is not guaranteed.

Why is a substring still present after Str::remove?

The scan makes a single pass and does not restart after a match, so a removal can join surrounding text into a new occurrence — removing 'foo' from 'ffoooo' returns 'foo'. Loop until the result stops changing if you need exhaustive removal.

More examples

Normalising a card or phone number before storage

Two differently formatted cards collapse to the same stored value, which is what makes a uniqueness check or a lookup work. For arbitrary input a preg_replace('/\D/', '', $input) is stricter, since it removes any separator rather than only the ones you listed.

Example · php
<?php

use Illuminate\Support\Str;

$inputs = [
    '4242 4242 4242 4242',
    '4242-4242-4242-4242',
    '+1 (555) 867-5309',
];

foreach ($inputs as $input) {
    $digits = Str::remove([' ', '-', '(', ')', '+'], $input);

    echo str_pad($input, 22), '=> ', $digits, "\n";
}

// 4242 4242 4242 4242   => 4242424242424242
// 4242-4242-4242-4242   => 4242424242424242
// +1 (555) 867-5309     => 15558675309

Why a list of needles is not a sanitiser

The removal of the inner <script> joins the surrounding fragments into a working tag that the pass has already moved past. Blocklist removal is the wrong shape for security work; escape at the point of output instead.

Example · php
<?php

use Illuminate\Support\Str;

$payload = '<scr<script>ipt>alert(1)</script>';

// Looks like it strips the tags...
echo Str::remove(['<script>', '</script>'], $payload), "\n";
// <script>alert(1)

// ...because removing the inner tag re-forms an outer one.
// Use a real sanitiser, or escape on output:
echo htmlspecialchars($payload, ENT_QUOTES, 'UTF-8'), "\n";
// &lt;scr&lt;script&gt;ipt&gt;alert(1)&lt;/script&gt;

Discussion

  • Be the first to comment on this lesson.