strpos($haystack, $needle) devuelve la posición del primer $needle dentro de $haystack, contando desde 0, o false si no está. Comprueba siempre el resultado con !== false, porque una coincidencia al principio devuelve 0.
Si en PHP 8 solo necesitas un sí o un no, str_contains() es más claro. Usa strpos() cuando importe la posición.
Sintaxis
strpos(string $haystack, string $needle, int $offset = 0): int|false
La búsqueda distingue mayúsculas y minúsculas. $offset le dice dónde empezar a buscar; un desplazamiento negativo cuenta desde el final de la cadena.
La trampa de !== false
0 y false son iguales con la comparación flexible (==). Por eso cualquier comprobación que no sea estricta trata una coincidencia en la posición 0 como "no encontrado".
La misma regla se aplica a stripos(), strrpos() y array_search(), que pueden devolver 0 para una coincidencia real.
Búsqueda sin distinguir mayúsculas con stripos
stripos() acepta los mismos argumentos e ignora las mayúsculas y minúsculas de las letras ASCII.
Encontrar la última aparición con strrpos
strrpos() devuelve la posición de la última coincidencia. Es la forma estándar de obtener la extensión de un archivo o el último segmento de una ruta.
Para nombres de archivo en concreto, pathinfo($file, PATHINFO_EXTENSION) lo hace por ti. Cortar la cadena en esa posición se explica en la página de substr().
Empezar la búsqueda en un desplazamiento
El tercer argumento se salta el principio de la cadena. Un desplazamiento negativo empieza esa cantidad de caracteres antes del final.
Encontrar todas las apariciones
strpos() encuentra una coincidencia. Recorre en un bucle y mueve el desplazamiento más allá de cada coincidencia para encontrarlas todas:
¿Solo el número? substr_count($text, 'the') es más corto. Para patrones, preg_match_all() con PREG_OFFSET_CAPTURE devuelve cada coincidencia con su posición.
Texto japonés: posición en bytes vs posición en caracteres
strpos() encuentra correctamente el texto multibyte, pero el número que devuelve está en bytes. Los kana y los kanji comunes ocupan 3 bytes cada uno en UTF-8, así que en un texto todo en japonés la posición en bytes es el triple de la posición en caracteres, y en un texto mixto las dos se separan de formas menos evidentes. mb_strpos() devuelve caracteres, que es lo que espera mb_substr().
Mezclar las dos es un bug clásico: pasar un resultado de strpos() a mb_substr() empieza demasiado adentro de la cadena. Usa strpos con substr, y mb_strpos con mb_substr.
Preguntas frecuentes
¿Qué devuelve strpos() en PHP?
La posición de la primera coincidencia como entero, contando desde 0, o false si no encuentra la aguja. strpos('hello', 'l') devuelve 2.
¿Por qué necesito !== false con strpos()?
Porque una coincidencia justo al principio devuelve 0, y 0 == false es verdadero. if (strpos($s, 'a')) trata una coincidencia en la posición 0 como "no encontrado". Compara siempre con strpos($s, 'a') !== false.
¿Cuál es la diferencia entre strpos, stripos y strrpos?
strpos() encuentra la primera coincidencia y distingue mayúsculas y minúsculas. stripos() encuentra la primera coincidencia ignorando las mayúsculas. strrpos() encuentra la última coincidencia. strripos() encuentra la última coincidencia ignorando las mayúsculas.
¿Uso strpos o str_contains para comprobar si una cadena contiene un texto?
En PHP 8 usa str_contains($haystack, $needle), que devuelve un true o false limpio y no tiene la trampa de la posición 0. Usa strpos() cuando necesites la propia posición.
¿Cómo uso strpos con texto japonés?
strpos() encuentra correctamente el texto japonés pero devuelve una posición en bytes. Si pasas la posición a mb_substr() o se la muestras a un usuario, usa mb_strpos(), que devuelve la posición en caracteres.