こんにちは!今回は、PHPの標準関数であるstrtolower()について詳しく解説していきます。文字列をすべて小文字に変換する、シンプルだけど非常によく使われる関数です!
strtolower関数とは?
strtolower()関数は、文字列内のすべての英字を小文字に変換する関数です。
“string to lower”の略で、大文字小文字を統一したい場面や、比較処理、データの正規化など、様々な用途で使用されます!
基本的な構文
strtolower(string $string): string
- $string: 小文字に変換する文字列
- 戻り値: 小文字に変換された文字列
基本的な使用例
シンプルな変換
// 大文字を小文字に
$text = "HELLO WORLD";
echo strtolower($text) . "\n";
// 出力: hello world
// 混在した文字列
$text = "Hello World";
echo strtolower($text) . "\n";
// 出力: hello world
// すでに小文字の場合
$text = "hello";
echo strtolower($text) . "\n";
// 出力: hello(変化なし)
数字と記号
// 数字と記号は変化しない
$text = "ABC123!@#";
echo strtolower($text) . "\n";
// 出力: abc123!@#
$text = "Test-Case_2024";
echo strtolower($text) . "\n";
// 出力: test-case_2024
マルチバイト文字の扱い
// ASCII文字のみ処理される
$text = "Hello こんにちは WORLD";
echo strtolower($text) . "\n";
// 出力: hello こんにちは world
// 日本語は変化しない
$text = "テスト TEST テスト";
echo strtolower($text) . "\n";
// 出力: テスト test テスト
// マルチバイト対応が必要な場合
$text = "HELLO";
echo mb_strtolower($text, 'UTF-8') . "\n";
// 出力: hello
実践的な使用例
例1: 大文字小文字を区別しない比較
class CaseInsensitiveComparator {
/**
* 大文字小文字を区別しない比較
*/
public static function equals($str1, $str2) {
return strtolower($str1) === strtolower($str2);
}
/**
* 配列内に含まれるかチェック
*/
public static function inArray($needle, $haystack) {
$needle = strtolower($needle);
foreach ($haystack as $item) {
if (strtolower($item) === $needle) {
return true;
}
}
return false;
}
/**
* 配列から検索
*/
public static function search($needle, $haystack) {
$needle = strtolower($needle);
foreach ($haystack as $key => $value) {
if (strtolower($value) === $needle) {
return $key;
}
}
return false;
}
/**
* ソート(大文字小文字無視)
*/
public static function sort($array) {
usort($array, function($a, $b) {
return strcmp(strtolower($a), strtolower($b));
});
return $array;
}
/**
* 重複を除去(大文字小文字無視)
*/
public static function unique($array) {
$lowercaseMap = [];
$result = [];
foreach ($array as $item) {
$lower = strtolower($item);
if (!isset($lowercaseMap[$lower])) {
$lowercaseMap[$lower] = true;
$result[] = $item;
}
}
return $result;
}
}
// 使用例
echo "=== 大文字小文字無視比較 ===\n";
var_dump(CaseInsensitiveComparator::equals("Hello", "HELLO")); // true
var_dump(CaseInsensitiveComparator::equals("Hello", "World")); // false
$array = ['Apple', 'Banana', 'CHERRY'];
echo "\n=== 配列内検索 ===\n";
var_dump(CaseInsensitiveComparator::inArray('apple', $array)); // true
var_dump(CaseInsensitiveComparator::inArray('BANANA', $array)); // true
echo "\n=== ソート ===\n";
$items = ['Zebra', 'apple', 'BANANA', 'cherry'];
$sorted = CaseInsensitiveComparator::sort($items);
print_r($sorted);
echo "\n=== 重複除去 ===\n";
$items = ['Apple', 'APPLE', 'apple', 'Banana', 'BANANA'];
$unique = CaseInsensitiveComparator::unique($items);
print_r($unique);
例2: URLとスラッグの生成
class SlugGenerator {
/**
* URLフレンドリーなスラッグを生成
*/
public static function generate($text) {
// 小文字に変換
$slug = strtolower($text);
// スペースをハイフンに
$slug = str_replace(' ', '-', $slug);
// 英数字とハイフン以外を除去
$slug = preg_replace('/[^a-z0-9-]/', '', $slug);
// 連続するハイフンを1つに
$slug = preg_replace('/-+/', '-', $slug);
// 前後のハイフンを除去
$slug = trim($slug, '-');
return $slug;
}
/**
* タイトルからスラッグを生成
*/
public static function fromTitle($title) {
return self::generate($title);
}
/**
* ファイル名を正規化
*/
public static function normalizeFilename($filename) {
$info = pathinfo($filename);
$basename = $info['filename'];
$extension = isset($info['extension']) ? $info['extension'] : '';
$slug = self::generate($basename);
if (!empty($extension)) {
$slug .= '.' . strtolower($extension);
}
return $slug;
}
/**
* ユニークなスラッグを生成
*/
public static function generateUnique($text, $existingSlugs) {
$baseSlug = self::generate($text);
$slug = $baseSlug;
$counter = 1;
while (in_array($slug, $existingSlugs)) {
$slug = $baseSlug . '-' . $counter;
$counter++;
}
return $slug;
}
}
// 使用例
$titles = [
'Hello World!',
'PHP Programming Guide',
'Best Practices 2024',
'Test@#$%File'
];
echo "=== スラッグ生成 ===\n";
foreach ($titles as $title) {
echo "{$title} → " . SlugGenerator::generate($title) . "\n";
}
echo "\n=== ファイル名正規化 ===\n";
$files = ['My Document.PDF', 'Photo_2024.JPG', 'test FILE.txt'];
foreach ($files as $file) {
echo "{$file} → " . SlugGenerator::normalizeFilename($file) . "\n";
}
echo "\n=== ユニークスラッグ ===\n";
$existing = ['hello-world', 'hello-world-1'];
$newSlug = SlugGenerator::generateUnique('Hello World', $existing);
echo $newSlug . "\n"; // hello-world-2
例3: データの正規化
class DataNormalizer {
/**
* メールアドレスを正規化
*/
public static function normalizeEmail($email) {
return strtolower(trim($email));
}
/**
* ユーザー名を正規化
*/
public static function normalizeUsername($username) {
return strtolower(trim($username));
}
/**
* タグを正規化
*/
public static function normalizeTags($tags) {
$normalized = [];
foreach ($tags as $tag) {
$tag = strtolower(trim($tag));
if (!empty($tag) && !in_array($tag, $normalized)) {
$normalized[] = $tag;
}
}
return $normalized;
}
/**
* ドメイン名を正規化
*/
public static function normalizeDomain($domain) {
$domain = strtolower(trim($domain));
// プロトコルを除去
$domain = preg_replace('#^https?://#', '', $domain);
// www. を除去
$domain = preg_replace('#^www\.#', '', $domain);
// 末尾のスラッシュを除去
$domain = rtrim($domain, '/');
return $domain;
}
/**
* ファイル拡張子を正規化
*/
public static function normalizeExtension($extension) {
return strtolower(trim($extension, '.'));
}
}
// 使用例
echo "=== メールアドレス正規化 ===\n";
$emails = ['User@Example.COM', ' ADMIN@TEST.ORG ', 'Info@Company.Co.JP'];
foreach ($emails as $email) {
echo "{$email} → " . DataNormalizer::normalizeEmail($email) . "\n";
}
echo "\n=== タグ正規化 ===\n";
$tags = ['PHP', 'php', 'Programming', 'PROGRAMMING', 'Web'];
$normalized = DataNormalizer::normalizeTags($tags);
print_r($normalized);
echo "\n=== ドメイン正規化 ===\n";
$domains = ['HTTPS://WWW.Example.COM/', 'www.test.org', 'Company.CO.JP'];
foreach ($domains as $domain) {
echo "{$domain} → " . DataNormalizer::normalizeDomain($domain) . "\n";
}
例4: 検索機能
class SearchEngine {
/**
* キーワード検索
*/
public static function search($text, $keyword) {
return stripos($text, $keyword) !== false;
// または: strpos(strtolower($text), strtolower($keyword)) !== false
}
/**
* 複数キーワードで検索(AND)
*/
public static function searchAll($text, $keywords) {
$lowerText = strtolower($text);
foreach ($keywords as $keyword) {
if (strpos($lowerText, strtolower($keyword)) === false) {
return false;
}
}
return true;
}
/**
* 複数キーワードで検索(OR)
*/
public static function searchAny($text, $keywords) {
$lowerText = strtolower($text);
foreach ($keywords as $keyword) {
if (strpos($lowerText, strtolower($keyword)) !== false) {
return true;
}
}
return false;
}
/**
* 配列をフィルタリング
*/
public static function filter($items, $keyword) {
$keyword = strtolower($keyword);
return array_filter($items, function($item) use ($keyword) {
return strpos(strtolower($item), $keyword) !== false;
});
}
/**
* キーワードをハイライト
*/
public static function highlight($text, $keyword, $tag = 'mark') {
$lowerText = strtolower($text);
$lowerKeyword = strtolower($keyword);
$keywordLength = strlen($keyword);
$result = '';
$offset = 0;
while (($pos = strpos($lowerText, $lowerKeyword, $offset)) !== false) {
// マッチ前の部分
$result .= substr($text, $offset, $pos - $offset);
// ハイライトされたキーワード(元の大文字小文字を保持)
$result .= "<{$tag}>" . substr($text, $pos, $keywordLength) . "</{$tag}>";
$offset = $pos + $keywordLength;
}
// 残りの部分
$result .= substr($text, $offset);
return $result;
}
}
// 使用例
$text = "PHP is a popular programming language. Many developers love PHP.";
echo "=== 検索 ===\n";
var_dump(SearchEngine::search($text, 'php')); // true
var_dump(SearchEngine::search($text, 'PHP')); // true
var_dump(SearchEngine::search($text, 'python')); // false
echo "\n=== AND検索 ===\n";
var_dump(SearchEngine::searchAll($text, ['PHP', 'programming'])); // true
var_dump(SearchEngine::searchAll($text, ['PHP', 'python'])); // false
echo "\n=== OR検索 ===\n";
var_dump(SearchEngine::searchAny($text, ['python', 'ruby', 'php'])); // true
$items = ['Apple', 'Banana', 'CHERRY', 'date', 'Elderberry'];
echo "\n=== フィルタリング ===\n";
$filtered = SearchEngine::filter($items, 'a');
print_r($filtered); // Apple, Banana, date
echo "\n=== ハイライト ===\n";
echo SearchEngine::highlight($text, 'php') . "\n";
例5: ファイル処理
class FileProcessor {
/**
* 拡張子で分類
*/
public static function groupByExtension($files) {
$grouped = [];
foreach ($files as $file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!isset($grouped[$ext])) {
$grouped[$ext] = [];
}
$grouped[$ext][] = $file;
}
return $grouped;
}
/**
* 特定の拡張子か判定
*/
public static function hasExtension($filename, $extensions) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$extensions = array_map('strtolower', $extensions);
return in_array($ext, $extensions);
}
/**
* 画像ファイルか判定
*/
public static function isImage($filename) {
return self::hasExtension($filename, ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']);
}
/**
* ドキュメントファイルか判定
*/
public static function isDocument($filename) {
return self::hasExtension($filename, ['pdf', 'doc', 'docx', 'txt', 'rtf']);
}
/**
* ファイル名を安全に
*/
public static function sanitizeFilename($filename) {
$info = pathinfo($filename);
$basename = $info['filename'];
$extension = isset($info['extension']) ? $info['extension'] : '';
// 小文字に変換
$basename = strtolower($basename);
// 安全な文字のみに
$basename = preg_replace('/[^a-z0-9-_]/', '-', $basename);
if (!empty($extension)) {
$basename .= '.' . strtolower($extension);
}
return $basename;
}
}
// 使用例
$files = [
'photo.JPG',
'document.PDF',
'image.PNG',
'report.DOCX',
'video.MP4'
];
echo "=== 拡張子で分類 ===\n";
$grouped = FileProcessor::groupByExtension($files);
print_r($grouped);
echo "\n=== ファイルタイプ判定 ===\n";
foreach ($files as $file) {
echo "{$file}: ";
if (FileProcessor::isImage($file)) {
echo "画像";
} elseif (FileProcessor::isDocument($file)) {
echo "ドキュメント";
} else {
echo "その他";
}
echo "\n";
}
echo "\n=== ファイル名サニタイズ ===\n";
$unsafeFiles = ['My Photo.JPG', 'Test@File!.PDF', 'Document (1).DOCX'];
foreach ($unsafeFiles as $file) {
echo "{$file} → " . FileProcessor::sanitizeFilename($file) . "\n";
}
例6: バリデーション
class Validator {
/**
* メールアドレスのドメインをチェック
*/
public static function isEmailDomain($email, $allowedDomains) {
$email = strtolower($email);
$allowedDomains = array_map('strtolower', $allowedDomains);
foreach ($allowedDomains as $domain) {
if (strpos($email, '@' . $domain) !== false) {
return true;
}
}
return false;
}
/**
* 禁止ワードチェック
*/
public static function containsBannedWords($text, $bannedWords) {
$lowerText = strtolower($text);
$bannedWords = array_map('strtolower', $bannedWords);
foreach ($bannedWords as $word) {
if (strpos($lowerText, $word) !== false) {
return true;
}
}
return false;
}
/**
* ユーザー名が許可されているかチェック
*/
public static function isValidUsername($username, $reservedNames) {
$username = strtolower($username);
$reservedNames = array_map('strtolower', $reservedNames);
return !in_array($username, $reservedNames);
}
/**
* ファイル拡張子が許可されているかチェック
*/
public static function isAllowedFileType($filename, $allowedExtensions) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$allowedExtensions = array_map('strtolower', $allowedExtensions);
return in_array($ext, $allowedExtensions);
}
}
// 使用例
echo "=== メールドメインチェック ===\n";
$allowedDomains = ['example.com', 'company.co.jp'];
var_dump(Validator::isEmailDomain('user@EXAMPLE.COM', $allowedDomains)); // true
var_dump(Validator::isEmailDomain('user@test.org', $allowedDomains)); // false
echo "\n=== 禁止ワードチェック ===\n";
$bannedWords = ['spam', 'viagra', 'casino'];
var_dump(Validator::containsBannedWords('This is SPAM message', $bannedWords)); // true
var_dump(Validator::containsBannedWords('Hello world', $bannedWords)); // false
echo "\n=== 予約ユーザー名チェック ===\n";
$reserved = ['admin', 'root', 'system'];
var_dump(Validator::isValidUsername('ADMIN', $reserved)); // false
var_dump(Validator::isValidUsername('john', $reserved)); // true
echo "\n=== ファイルタイプチェック ===\n";
$allowed = ['jpg', 'png', 'pdf'];
var_dump(Validator::isAllowedFileType('photo.JPG', $allowed)); // true
var_dump(Validator::isAllowedFileType('script.PHP', $allowed)); // false
例7: キャッシュキーの生成
class CacheKeyGenerator {
/**
* キャッシュキーを生成
*/
public static function generate($prefix, $params) {
// パラメータを正規化
$normalized = [];
foreach ($params as $key => $value) {
$key = strtolower($key);
if (is_string($value)) {
$value = strtolower($value);
}
$normalized[$key] = $value;
}
// ソート
ksort($normalized);
// キー生成
$key = $prefix . ':' . md5(serialize($normalized));
return strtolower($key);
}
/**
* URLからキャッシュキーを生成
*/
public static function fromUrl($url) {
$url = strtolower($url);
$url = preg_replace('#^https?://#', '', $url);
return 'url:' . md5($url);
}
/**
* クエリパラメータからキーを生成
*/
public static function fromQuery($params) {
$normalized = [];
foreach ($params as $key => $value) {
$normalized[strtolower($key)] = strtolower($value);
}
ksort($normalized);
return 'query:' . md5(http_build_query($normalized));
}
}
// 使用例
echo "=== キャッシュキー生成 ===\n";
$params = ['UserId' => '123', 'Category' => 'ELECTRONICS', 'Sort' => 'PRICE'];
$key = CacheKeyGenerator::generate('product', $params);
echo "パラメータキー: {$key}\n";
$url = 'HTTPS://EXAMPLE.COM/Products?id=123';
$urlKey = CacheKeyGenerator::fromUrl($url);
echo "URLキー: {$urlKey}\n";
$query = ['Page' => '1', 'Limit' => '20', 'Order' => 'ASC'];
$queryKey = CacheKeyGenerator::fromQuery($query);
echo "クエリキー: {$queryKey}\n";
strtoupper()との関係
$text = "Hello World";
// strtolower(): 小文字に変換
echo strtolower($text) . "\n"; // hello world
// strtoupper(): 大文字に変換
echo strtoupper($text) . "\n"; // HELLO WORLD
// 往復変換
$lower = strtolower($text);
$upper = strtoupper($lower);
echo $upper . "\n"; // HELLO WORLD
パフォーマンスの考慮
// 大量のデータで小文字変換
$text = str_repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10000);
// strtolower()
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
strtolower($text);
}
$time1 = microtime(true) - $start;
// 手動変換
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
$result = '';
for ($j = 0; $j < strlen($text); $j++) {
$char = $text[$j];
if ($char >= 'A' && $char <= 'Z') {
$result .= chr(ord($char) + 32);
} else {
$result .= $char;
}
}
}
$time2 = microtime(true) - $start;
echo "strtolower(): {$time1}秒\n";
echo "手動変換: {$time2}秒\n";
// strtolower()は高度に最適化されており非常に高速
まとめ
strtolower()関数の特徴をまとめると:
できること:
- 文字列を小文字に変換
- 大文字小文字を統一
- 正規化処理
推奨される使用場面:
- 大文字小文字を区別しない比較
- データの正規化
- URL・スラッグの生成
- 検索機能
- ファイル処理
- キャッシュキー生成
注意点:
- ASCII文字のみ処理(A-Z → a-z)
- マルチバイト文字には
mb_strtolower()を使用 - 元の文字列は変更されない
関連関数:
strtoupper(): 大文字に変換ucfirst(): 最初の文字を大文字にucwords(): 各単語の最初を大文字にmb_strtolower(): マルチバイト対応版lcfirst(): 最初の文字を小文字に
大文字小文字を区別しない比較:
// 方法1: strtolower()を使用
if (strtolower($str1) === strtolower($str2)) {
// 一致
}
// 方法2: strcasecmp()を使用
if (strcasecmp($str1, $str2) === 0) {
// 一致
}
パフォーマンス:
- 非常に高速(C言語レベルで最適化)
- 大量のデータでも効率的
strtolower()は、文字列処理の基本中の基本です。データの正規化や比較処理など、様々な場面で活躍する関数なので、マルチバイト文字の扱いに注意しながら、適切に使いこなしましょう!
