- カテゴリ: 文字列操作(PHP標準関数)
- 対象バージョン: PHP 7.4 〜 8.4(offsetの負数指定はPHP 7.1以降、needleへのint渡しはPHP 8.0で廃止)
- シグネチャ:
strpos(string $haystack, string $needle, int $offset = 0): int|false - 関連: stripos / strrpos / str_contains / str_starts_with / mb_strpos
- 変更履歴: PHP 7.1でoffsetの負数指定に対応/PHP 8.0でneedleへのint渡しが廃止され空文字列は許可に/PHP 8.0でoffsetがhaystackの文字数を超えるとValueError
要点(TL;DR)
strpos()は文字列$haystackの中で$needleが最初に見つかる位置(0始まりの整数)を返す。見つからなければfalse- 最重要の罠: 先頭(0文字目)で見つかった場合も戻り値は
0。if ($pos)ではなく必ず!== false/=== falseで判定する - 「含むかどうか」だけ知りたいならPHP 8.0+の
str_contains()、日本語などマルチバイト文字はmb_strpos()を使う
概要
strposは、文字列$haystackの中に別の文字列$needleが含まれているか、含まれているならどの位置にあるかを調べるPHPの標準関数です。バリデーションでのキーワード判定、ログやURLからの部分文字列抽出、テンプレート処理など幅広い場面で使われる基本関数ですが、戻り値の0とfalseを見分けられずにバグを作り込みやすい関数としても知られています。strposはバイト単位で位置を数えるため、日本語のようなマルチバイト文字列を扱う場合はmb_strposを使う必要がある点にも注意してください。
構文 / シグネチャ
int|false strpos(string $haystack, string $needle, int $offset = 0)
引数
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
$haystack | string | 必須 | — | 検索対象の文字列 |
$needle | string | 必須 | — | 探したい部分文字列(PHP 8.0以降は空文字列も指定可能) |
$offset | int | 任意 | 0 | 検索開始位置。正の値は先頭からの文字数、負の値は末尾から数えた位置(PHP 7.1以降) |
- 戻り値:見つかった位置(0始まりの整数)、見つからなければ
boolのfalse - 例外/副作用:
$offsetが$haystackの文字数を超えるとValueErrorが発生する(PHP 8.0以降)/$haystack自体は変更されない
使用例
基本の使い方(含むかどうかを判定する)
<?php
$text = 'Hello, PHP World!';
if (strpos($text, 'PHP') !== false) {
echo '「PHP」が含まれています';
} else {
echo '「PHP」は含まれていません';
}
// 出力: 「PHP」が含まれています
見つかった位置を取得する
<?php
$text = 'Welcome to PHP!';
$pos = strpos($text, 'PHP');
if ($pos !== false) {
echo '「PHP」は ' . $pos . ' 文字目にあります'; // 11文字目
}
0とfalseを区別する(最重要)
<?php
$str = 'PHP is great';
$pos = strpos($str, 'PHP'); // 先頭にあるので 0 が返る
// NG: 0 は false と等価に評価されるため誤動作する
if ($pos) {
echo '見つかった'; // ← 実行されない(バグ!)
}
// OK: 厳密比較(!==)を使う
if ($pos !== false) {
echo '見つかった: ' . $pos . ' 文字目'; // 正しく動作
}
PHPは0 == falseをtrueと評価するため、if ($pos)では先頭にあるケースを「見つからなかった」と誤判定します。判定には必ず=== falseまたは!== falseを使ってください。
offsetを指定してすべての出現位置を検索する
strposは最初の1件しか返さないため、同じ文字列が複数回出現する位置をすべて取得したい場合は$offsetを1つずつずらしながらループします。
<?php
$text = 'PHPはシンプル。PHPは人気。PHPは学びやすい。';
$needle = 'PHP';
$offset = 0;
$positions = [];
while (($pos = strpos($text, $needle, $offset)) !== false) {
$positions[] = $pos;
$offset = $pos + strlen($needle);
}
print_r($positions);
大文字小文字を区別しない場合(stripos)
<?php
$text = 'Hello World';
var_dump(strpos($text, 'hello')); // bool(false)(大文字小文字が異なる)
var_dump(stripos($text, 'hello')); // int(0)(区別しない)
末尾から検索する(strrpos)
最後に出現する位置を知りたい場合はstrrposを使います。
<?php
$path = '/var/www/html/index.php';
$firstSlash = strpos($path, '/'); // 0(最初の / の位置)
$lastSlash = strrpos($path, '/'); // 13(最後の / の位置)
echo substr($path, $lastSlash + 1); // index.php
PHP 8.0+のstr_containsとの比較
<?php
$text = 'Hello, PHP!';
// PHP 7以前の書き方(strpos)
if (strpos($text, 'PHP') !== false) {
echo '含む';
}
// PHP 8.0以降の書き方(str_contains)
if (str_contains($text, 'PHP')) {
echo '含む';
}
位置を知る必要がなく「含むかどうか」だけを判定する場合は、PHP 8.0以上ならstr_contains()のほうがシンプルで0 / falseの混同も起きません。
日本語などマルチバイト文字列を検索する(mb_strpos)
<?php
$text = 'こんにちは PHP!';
// strpos: バイト単位(UTF-8では日本語1文字=3バイト)
$bytePos = strpos($text, 'PHP'); // 15(バイト位置)
// mb_strpos: 文字単位
$charPos = mb_strpos($text, 'PHP'); // 5(文字位置)
echo 'strpos: ' . $bytePos . PHP_EOL; // 15
echo 'mb_strpos: ' . $charPos . PHP_EOL; // 5
日本語・中国語・韓国語など2バイト以上の文字を含む文字列を扱う場合は、位置を文字単位で正しく取得できるmb_strpos()を選んでください。
よくある落とし穴・注意
- 0とfalseの混同:見つかった位置が
0(先頭)の場合、if ($pos)のような緩い判定ではfalse(見つからない)と区別できません。必ず!== false/=== falseの厳密比較を使ってください。 - 大文字小文字を区別する:
strposは大文字小文字を区別して検索します。区別せずに検索したい場合はstriposを使います。 - マルチバイト文字で位置がずれる:
strposはバイト単位で数えるため、日本語などを含む文字列では返ってくる位置が文字数と一致しません。文字単位で正確な位置が必要な場合はmb_strposを使います。 - offsetが文字数を超えるとエラーになる:PHP 8.0以降、
$offsetが$haystackの文字数を超えるとValueErrorが発生します。ループで$offsetをずらす処理では、範囲外にならないか事前にチェックするかtry/catchで受け止めてください。 - 複数の候補文字列を一度に検索できない:
$needleに配列を渡すことはできません(PHP 8.0でintの自動キャストも廃止済み)。複数のキーワードのいずれかが含まれるか調べたい場合は、候補をループして1つずつstrposを呼ぶか、preg_matchで正規表現のOR条件を使います。
代替・関連APIとの比較
| 関数 | PHPバージョン | 戻り値 | 主な用途 |
|---|---|---|---|
strpos | 全バージョン | int|false | 大文字小文字を区別して位置を取得・含む判定を行う(最も基本) |
stripos | 全バージョン | int|false | 大文字小文字を区別せずに検索したいとき |
strrpos | 全バージョン | int|false | 最後に出現する位置を知りたいとき |
str_contains | PHP 8.0+ | bool | 位置は不要で「含むかどうか」だけ調べたいとき |
str_starts_with | PHP 8.0+ | bool | 先頭一致かどうかだけ調べたいとき |
mb_strpos | 全バージョン(mbstring) | int|false | 日本語などマルチバイト文字列を文字単位で検索したいとき |
トラブルシュート(症状別)
| 症状 | 原因 | 対処 |
|---|---|---|
| 先頭にあるはずなのに「見つからない」と判定される | if ($pos)で判定しており0とfalseが区別できていない | if ($pos !== false)のように厳密比較にする |
| 日本語を含む文字列で位置がずれる/文字化けした位置が返る | strposはバイト単位で計算しており、マルチバイト文字1文字が複数バイトになっている | mb_strposに置き換える |
| 大文字小文字が違うだけで見つからない | strposは大文字小文字を区別する | striposを使う |
| 「ValueError: strpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)」が発生する | $offsetが$haystackの文字数を超えている(PHP 8.0以降はエラーになる) | ループ処理では$offsetが範囲内か事前にチェックする、またはstrlen($haystack)と比較してからループを止める |
よくある質問(FAQ)
Q. strposとは?
A. strpos()はPHPの組み込み文字列関数で、指定した文字列($haystack)の中から別の文字列($needle)が最初に現れる位置を返します。見つかった場合は0以上の整数、見つからない場合はfalseを返します。PHPのすべてのバージョンで利用可能です。
Q. strposが0を返すのはどういう意味ですか?
A. 検索したい文字列が対象文字列の先頭(0文字目)で見つかったことを意味し、false(見つからない)ではありません。if ($pos)のように評価すると0とfalseが区別できずバグになるため、必ずif ($pos !== false)と書いてください。
Q. 文字列を含むかだけ判定するにはどうすればいいですか?
A. PHP 8.0以上ならstr_contains($text, 'keyword')が最もシンプルで安全です。PHP 7系ではstrpos($text, 'keyword') !== falseで代替できます。どちらも0 / falseの問題を意識せずに使えます(str_containsはboolを返すため)。
Q. 複数の文字列のどれかが含まれているか調べるにはどうすればいいですか?
A. $needleに配列を直接渡すことはできません。候補の文字列を配列で用意し、foreachでループしながらstrpos(またはstr_contains)を呼び出すか、正規表現のOR条件(preg_match('/word1|word2/', $text))を使います。
Q. strposとmb_strposはどちらを使うべきですか?
A. 英数字のみを扱うならどちらでも結果は同じです。日本語・中国語・韓国語などのマルチバイト文字を含む文字列を扱う場合は、文字単位で正確な位置を返すmb_strposを使ってください。strposはバイト単位で計算するため、位置がずれることがあります。
関連記事
- PHP substr関数の使い方と実例:文字列操作をマスターしよう
- PHPのexplode関数を使った文字列分割の基本と応用テクニック
- PHP in_array関数の使い方完全ガイド: 配列内の要素検索を極めよう!
参考リンク
- PHP公式マニュアル「strpos」:https://www.php.net/manual/ja/function.strpos.php
- PHP公式マニュアル「str_contains」:https://www.php.net/manual/ja/function.str-contains.php
- PHP公式マニュアル「mb_strpos」:https://www.php.net/manual/ja/function.mb-strpos.php

コメント