[PHP]glob関数でファイル検索をマスターする!パターンマッチングの実践テクニック

PHP

こんにちは、PHPユーザーの皆さん!今回は、ファイルシステム操作の中でも特に便利な「glob」関数について詳しく解説していきます。この関数を使いこなせば、特定のパターンに一致するファイルを簡単に検索できるようになり、ファイル処理の効率が大幅に向上します。実例を交えながら、基本から応用まで見ていきましょう。

glob関数とは

glob()は、指定したパターンに一致するファイルパスを配列で返す関数です。Unixシェルで使われるワイルドカード記法と同様のパターンマッチングを使用するため、柔軟なファイル検索が可能です。

基本的な構文は以下の通りです:

array|false glob(string $pattern, int $flags = 0)
  • $pattern: 検索パターン
  • $flags: オプションフラグ(後述)

基本的な使用例

まずは、基本的な使い方を見ていきましょう:

<?php
// カレントディレクトリ内のすべてのPHPファイルを取得
$php_files = glob("*.php");

// 結果を表示
foreach ($php_files as $file) {
    echo $file . "\n";
}
?>

この例では、カレントディレクトリ内の拡張子が.phpのすべてのファイルを取得しています。

パターンマッチングの基本

glob関数で使用できる主なワイルドカードは以下の通りです:

  • *: 0文字以上の任意の文字列
  • ?: 任意の1文字
  • [abc]: 指定した文字のいずれか(この場合はab、またはc
  • [a-z]: 指定した範囲の文字のいずれか(この場合は小文字のアルファベット)
  • [!abc]: 指定した文字以外(この場合はabc以外)

これらを組み合わせることで、様々なパターンでファイルを検索できます:

<?php
// すべてのJPGとPNGファイルを取得
$images = glob("*.{jpg,png}", GLOB_BRACE);

// fileで始まる数字1桁のファイル(例:file1.txt, file2.php)
$numbered_files = glob("file[0-9].*");

// reportで始まる、任意の1文字、続いて.txtで終わるファイル
// 例:reportA.txt, report1.txt, reportX.txt
$reports = glob("report?.txt");

foreach ($images as $image) {
    echo "画像: " . $image . "\n";
}

foreach ($numbered_files as $file) {
    echo "番号付きファイル: " . $file . "\n";
}

foreach ($reports as $report) {
    echo "レポート: " . $report . "\n";
}
?>

フラグオプション

glob関数の2番目のパラメータには、検索動作を制御するためのフラグを指定できます:

  • GLOB_MARK: 各項目の末尾にスラッシュを追加(ディレクトリの場合)
  • GLOB_NOSORT: 結果を並べ替えない
  • GLOB_NOCHECK: パターンに一致するものがない場合、パターン自体を返す
  • GLOB_NOESCAPE: バックスラッシュをエスケープ文字として扱わない
  • GLOB_BRACE: 中括弧展開を有効にする(例:{a,b,c}
  • GLOB_ONLYDIR: ディレクトリのみを返す
  • GLOB_ERR: 読み取りエラー時に false を返す(デフォルトでは無視)

これらのフラグはビット演算子を使用して組み合わせることができます:

<?php
// ディレクトリのみを取得し、末尾にスラッシュを追加
$directories = glob("*", GLOB_ONLYDIR | GLOB_MARK);

foreach ($directories as $dir) {
    echo "ディレクトリ: " . $dir . "\n";
}

// 中括弧展開を使用して複数のパターンを指定
$code_files = glob("*.{php,js,html}", GLOB_BRACE);

foreach ($code_files as $file) {
    echo "コードファイル: " . $file . "\n";
}
?>

実践的な活用例

1. ファイルの一括処理

特定のディレクトリ内の画像ファイルをすべてリサイズする例:

<?php
// 画像ディレクトリ内のすべてのJPGファイルを取得
$images = glob("images/*.jpg");

foreach ($images as $image) {
    // 元のファイル名を取得
    $filename = basename($image);
    
    // 画像のリサイズ処理(GDライブラリを使用)
    $source = imagecreatefromjpeg($image);
    $width = imagesx($source);
    $height = imagesy($source);
    
    // 幅200pxに縮小
    $new_width = 200;
    $new_height = floor($height * ($new_width / $width));
    
    $destination = imagecreatetruecolor($new_width, $new_height);
    imagecopyresampled($destination, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    
    // リサイズした画像を保存
    imagejpeg($destination, "images/thumbnails/{$filename}", 90);
    
    // メモリ解放
    imagedestroy($source);
    imagedestroy($destination);
    
    echo "{$filename} をリサイズしました。\n";
}
?>

2. 再帰的なファイル検索

PHPのglob()関数は直接再帰的に検索する機能を持っていませんが、関数を組み合わせることで再帰的な検索を実現できます:

<?php
/**
 * 再帰的にファイルを検索する関数
 * @param string $pattern 検索パターン
 * @param int $flags globフラグ
 * @return array 見つかったファイルのパスの配列
 */
function recursive_glob($pattern, $flags = 0) {
    $files = glob($pattern, $flags);
    
    // パターンに一致するディレクトリを取得
    $directories = glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT);
    
    foreach ($directories as $dir) {
        // 各ディレクトリについて同じパターンで再帰的に検索
        $dir_pattern = $dir . '/' . basename($pattern);
        $files = array_merge($files, recursive_glob($dir_pattern, $flags));
    }
    
    return $files;
}

// 使用例:すべてのサブディレクトリを含むPHPファイルを検索
$all_php_files = recursive_glob("*.php");

echo "見つかったPHPファイル: " . count($all_php_files) . "個\n";
foreach ($all_php_files as $file) {
    echo $file . "\n";
}
?>

3. ファイルの一括削除

特定のパターンに一致する古いログファイルを削除する例:

<?php
// 30日以上前のログファイルを削除
$old_logs = glob("logs/app_*.log");
$now = time();
$days_to_keep = 30;

foreach ($old_logs as $log) {
    $file_time = filemtime($log);
    // ファイルの更新時間が30日以上前なら削除
    if ($now - $file_time > $days_to_keep * 24 * 60 * 60) {
        if (unlink($log)) {
            echo "削除しました: {$log}\n";
        } else {
            echo "削除に失敗しました: {$log}\n";
        }
    }
}
?>

4. プラグインシステムの実装

簡易的なプラグインシステムの実装例:

<?php
// プラグインディレクトリから全てのプラグインファイルを読み込む
$plugins = glob("plugins/*.plugin.php");
$loaded_plugins = [];

foreach ($plugins as $plugin_file) {
    // プラグインファイルを読み込む
    require_once $plugin_file;
    
    // プラグイン名を取得(ファイル名から)
    $plugin_name = basename($plugin_file, '.plugin.php');
    
    // プラグインクラス名を想定
    $plugin_class = ucfirst($plugin_name) . 'Plugin';
    
    // プラグインクラスのインスタンスを生成
    if (class_exists($plugin_class)) {
        $loaded_plugins[$plugin_name] = new $plugin_class();
        echo "プラグイン '{$plugin_name}' を読み込みました。\n";
    } else {
        echo "警告: プラグイン '{$plugin_name}' に対応するクラスが見つかりません。\n";
    }
}

// 全てのプラグインに対して初期化メソッドを呼び出す
foreach ($loaded_plugins as $name => $plugin) {
    if (method_exists($plugin, 'initialize')) {
        $plugin->initialize();
        echo "プラグイン '{$name}' を初期化しました。\n";
    }
}
?>

注意点と制限

1. パフォーマンスの考慮

大量のファイルを含むディレクトリでは、glob()関数は遅くなる可能性があります。そのような場合は、キャッシュを利用するか、DirectoryIteratorRecursiveDirectoryIteratorクラスを検討することをお勧めします。

2. 結果の並べ替え

glob()関数はデフォルトでは結果をアルファベット順に並べ替えますが、GLOB_NOSORTフラグを使用するとこの動作を無効にできます。これにより、大量のファイルを処理する場合にパフォーマンスを向上させることができます。

3. セキュリティ上の考慮

ユーザー入力をそのままglob()のパターンとして使用すると、意図しないファイルにアクセスされる可能性があります。必ず適切にサニタイズしてください:

<?php
// 悪い例(セキュリティリスク)
$user_input = $_GET['pattern'];
$files = glob($user_input);

// 良い例(許可されたパターンのみ)
$allowed_patterns = [
    'images/*.jpg',
    'documents/*.pdf',
    'logs/*.log'
];

$user_input = $_GET['pattern'];
if (in_array($user_input, $allowed_patterns)) {
    $files = glob($user_input);
} else {
    die("許可されていないパターンです");
}
?>

4. 結果が空の場合の処理

パターンに一致するファイルが見つからない場合、glob()関数は空の配列を返します。これをチェックすることで、ファイルが存在しない場合の処理を追加できます:

<?php
$files = glob("non_existent_pattern.*");

if (empty($files)) {
    echo "一致するファイルが見つかりませんでした。\n";
} else {
    echo count($files) . "個のファイルが見つかりました。\n";
}
?>

まとめ

PHPのglob()関数は、ファイルシステム内のファイルを柔軟に検索するための強力なツールです。単純なワイルドカードから複雑なパターンマッチングまで、様々なニーズに対応できます。

この関数を活用することで、バックアップ処理、画像処理、ログ管理、プラグインシステムなど、多くのタスクを効率的に実装できます。ただし、大量のファイルを処理する場合のパフォーマンスやセキュリティについては十分に考慮する必要があります。

これらの知識を活かして、より効率的なファイル処理を実現してください。glob()関数は、PHPプログラマーにとって必須の武器となるでしょう!

タイトルとURLをコピーしました