← All writing

Why strpos misses a match at the beginning of a string

PHP 8.3+Sources checked 2026-09-13

A support-ticket parser should recognize a line beginning with ERROR:. The parser works when the marker appears halfway through a line, but skips the most obvious case: a marker at character zero. The problem is a truthiness check on a function that returns either an integer position or false.

Keep the return types separate

<?php
$line = 'ERROR: supplier unavailable';
$position = strpos($line, 'ERROR:');
assert($position === 0);
assert((bool) $position === false);
assert($position !== false);
assert(strpos('all clear', 'ERROR:') === false);

Zero is a valid position. if ($position) discards it. !== false asks the actual question: did the search find anything? If you only need presence, str_contains($line, 'ERROR:') communicates that more directly. If the requirement is specifically a prefix, use str_starts_with instead of searching anywhere.

Decide what counts as a match

These functions perform case-sensitive matching. A lowercase error: will not match the uppercase marker. Decide whether the incoming format guarantees casing before normalizing it. Do not uppercase the complete message merely to find a prefix if that message also contains case-sensitive identifiers.

Test a marker at the start, in the middle, absent, and with different casing. Include an empty needle if it can reach the parser: an empty search string matches, which is usually not what a configurable alert rule intended. Validate the rule when saving it, rather than discovering an empty marker during an incident.

Reference

Official documentation. The examples here illustrate the stated boundary; adapt them to your application and test its failure paths.