str_ends_with
Checks whether a string ends with a given substring, case-sensitively.
str_ends_with(string $haystack, string $needle): bool- Added in PHP 8.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$haystack | string | The string to search in. |
$needle | string | The substring to look for at the end of haystack. |
Return value
booltrue if haystack ends with needle, false otherwise.
Errors
Throws a TypeError if a non-string is passed under strict_types; otherwise no errors are raised.
str_ends_with replaces the old substr($s, -strlen($n)) === $n dance with a single readable call. It compares bytes from the end of the string and returns a boolean.
When to reach for it
The obvious use is suffix checks: does this filename end in .php, does this URL end in a trailing slash, does this hostname end in your domain. It is also handy for cheap format sniffing before a heavier parse — skip anything not ending in .json rather than decoding every file.
What trips people up
It is case-sensitive, so Report.CSV does not end with .csv. Filenames arriving from a filesystem or an upload routinely carry uppercase extensions; lowercase the haystack first, or use pathinfo($f, PATHINFO_EXTENSION) when you specifically want the extension. An empty needle always returns true.
For security checks, a suffix test is weaker than it looks. str_ends_with($host, 'example.com') also matches notexample.com; compare against '.example.com' or parse the host properly. The same applies to path checks, where .. segments make suffix matching unreliable.
Example
When to use it
- Filter a directory listing down to files ending in .csv
- Check whether a URL already has a trailing slash before appending one
- Detect a specific file extension before choosing a parser
- Verify a hostname belongs to a given domain suffix
Frequently asked questions
What is the difference between str_ends_with and substr?
str_ends_with returns a boolean and handles the length arithmetic for you; the substr equivalent, substr($s, -strlen($n)) === $n, is longer and breaks when the needle is empty. Prefer str_ends_with on PHP 8.0 and later.
Is str_ends_with case-insensitive?
No, it compares bytes exactly. Lowercase both values first, or use substr_compare with its case-insensitive flag, if case should not matter.
Does str_ends_with return true for an empty needle?
Yes. Every string ends with the empty string, so the result is always true. Guard against empty input if the needle comes from a user.
More examples
Normalising a trailing slash
Each path is given exactly one trailing slash. The middle input already ends in a slash so it is left alone, which is the point: a blind concatenation would have produced a double slash there.
<?php
$paths = ['https://example.com/api', 'https://example.com/api/', '/tmp'];
foreach ($paths as $p) {
$normalised = str_ends_with($p, '/') ? $p : $p . '/';
echo $normalised, "\n";
}Why a bare suffix check is not a domain check
The naive check accepts evilexample.com because that string genuinely ends with "example.com". The safe check requires either an exact match or a leading dot, which rejects the lookalike host. This is the difference between a string test and an ownership test.
<?php
$hosts = ['app.example.com', 'example.com', 'evilexample.com'];
foreach ($hosts as $h) {
$naive = str_ends_with($h, 'example.com');
$safe = $h === 'example.com' || str_ends_with($h, '.example.com');
printf("%-18s naive:%-5s safe:%s\n", $h, var_export($naive, true), var_export($safe, true));
}
Discussion