PHPでファイルとディレクトリを区別する必要がある場面は多々あります。そんなときに重要な役割を果たすのがis_file
関数です。この記事では、is_file
関数の基本的な使い方から実践的な活用例まで、詳しく解説していきます。
is_file関数とは?
is_file
関数は、指定されたパスが通常のファイル(ディレクトリ、シンボリックリンク、デバイスファイルなどではない)かどうかを判定するPHPの組み込み関数です。ファイルである場合はtrue
、そうでない場合はfalse
を返します。
基本構文
bool is_file(string $filename)
- パラメータ:
$filename
– チェックしたいファイルまたはディレクトリのパス - 戻り値: 通常のファイルの場合は
true
、それ以外はfalse
基本的な使い方
シンプルな例
<?php
// ファイルの場合
if (is_file('config.txt')) {
echo "config.txtは通常のファイルです";
} else {
echo "config.txtは通常のファイルではありません";
}
// ディレクトリの場合
if (is_file('/tmp')) {
echo "/tmpはファイルです";
} else {
echo "/tmpはファイルではありません(ディレクトリです)";
}
?>
複数のパスをチェック
<?php
$paths = [
'index.php', // ファイル
'images/', // ディレクトリ
'config.json', // ファイル
'logs/', // ディレクトリ
'script.sh' // ファイル
];
foreach ($paths as $path) {
if (is_file($path)) {
echo "✓ {$path} はファイルです\n";
} else {
echo "✗ {$path} はファイルではありません\n";
}
}
?>
実践的な活用例
1. ファイル処理システム
<?php
class FileProcessor {
private $processedCount = 0;
private $skippedCount = 0;
public function processDirectory($directory) {
if (!is_dir($directory)) {
throw new Exception("指定されたパスはディレクトリではありません: {$directory}");
}
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$fullPath = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($fullPath)) {
$this->processFile($fullPath);
$this->processedCount++;
} else {
echo "スキップ(ファイルではない): {$fullPath}\n";
$this->skippedCount++;
}
}
return [
'processed' => $this->processedCount,
'skipped' => $this->skippedCount
];
}
private function processFile($filePath) {
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
$size = filesize($filePath);
echo "処理中: {$filePath} ({$extension}, {$size} bytes)\n";
// ここで実際のファイル処理を行う
// 例:画像リサイズ、テキスト変換など
}
}
// 使用例
$processor = new FileProcessor();
$result = $processor->processDirectory('./uploads/');
echo "処理完了 - 処理済み: {$result['processed']}, スキップ: {$result['skipped']}\n";
?>
2. 設定ファイル管理システム
<?php
class ConfigManager {
private $configDir;
private $defaultConfig = [
'app_name' => 'My Application',
'debug' => false,
'database' => [
'host' => 'localhost',
'port' => 3306
]
];
public function __construct($configDir = './config/') {
$this->configDir = rtrim($configDir, '/') . '/';
}
public function loadConfig($configName) {
$configFile = $this->configDir . $configName . '.json';
// ファイルの存在とタイプをチェック
if (!file_exists($configFile)) {
echo "設定ファイルが見つかりません: {$configFile}\n";
return $this->defaultConfig;
}
if (!is_file($configFile)) {
throw new Exception("指定されたパスはファイルではありません: {$configFile}");
}
$content = file_get_contents($configFile);
$config = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("設定ファイルのJSONが不正です: " . json_last_error_msg());
}
return array_merge($this->defaultConfig, $config);
}
public function saveConfig($configName, $config) {
$configFile = $this->configDir . $configName . '.json';
// ディレクトリが存在しない場合は作成
if (!is_dir($this->configDir)) {
mkdir($this->configDir, 0755, true);
}
$jsonContent = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
if (file_put_contents($configFile, $jsonContent) === false) {
throw new Exception("設定ファイルの保存に失敗しました: {$configFile}");
}
return true;
}
public function listConfigs() {
$configs = [];
if (!is_dir($this->configDir)) {
return $configs;
}
$files = scandir($this->configDir);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$fullPath = $this->configDir . $file;
// ファイルかつ.json拡張子のもののみ
if (is_file($fullPath) && pathinfo($file, PATHINFO_EXTENSION) === 'json') {
$configName = pathinfo($file, PATHINFO_FILENAME);
$configs[] = [
'name' => $configName,
'file' => $file,
'size' => filesize($fullPath),
'modified' => filemtime($fullPath)
];
}
}
return $configs;
}
}
// 使用例
$configManager = new ConfigManager('./config/');
// 設定の保存
$appConfig = [
'app_name' => 'サンプルアプリ',
'debug' => true,
'database' => [
'host' => 'db.example.com',
'port' => 5432
]
];
$configManager->saveConfig('app', $appConfig);
// 設定の読み込み
$loadedConfig = $configManager->loadConfig('app');
print_r($loadedConfig);
// 設定ファイル一覧の表示
$configs = $configManager->listConfigs();
echo "利用可能な設定ファイル:\n";
foreach ($configs as $config) {
echo "- {$config['name']} ({$config['size']} bytes)\n";
}
?>
3. ファイルアップロード処理
<?php
class FileUploadHandler {
private $uploadDir;
private $allowedExtensions;
private $maxFileSize;
public function __construct($uploadDir = './uploads/', $allowedExtensions = null, $maxFileSize = 5242880) {
$this->uploadDir = rtrim($uploadDir, '/') . '/';
$this->allowedExtensions = $allowedExtensions ?: ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt'];
$this->maxFileSize = $maxFileSize; // 5MB
// アップロードディレクトリの作成
if (!is_dir($this->uploadDir)) {
mkdir($this->uploadDir, 0755, true);
}
}
public function handleUpload($fileInputName) {
if (!isset($_FILES[$fileInputName])) {
throw new Exception("ファイルが選択されていません");
}
$file = $_FILES[$fileInputName];
// エラーチェック
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new Exception("ファイルアップロードエラー: " . $this->getUploadErrorMessage($file['error']));
}
// ファイルサイズチェック
if ($file['size'] > $this->maxFileSize) {
throw new Exception("ファイルサイズが大きすぎます(最大: " . $this->formatBytes($this->maxFileSize) . ")");
}
// 拡張子チェック
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($extension, $this->allowedExtensions)) {
throw new Exception("許可されていないファイル形式です: {$extension}");
}
// 一意なファイル名の生成
$filename = $this->generateUniqueFilename($file['name']);
$targetPath = $this->uploadDir . $filename;
// ファイルの移動
if (!move_uploaded_file($file['tmp_name'], $targetPath)) {
throw new Exception("ファイルの保存に失敗しました");
}
// アップロード後の検証
if (!is_file($targetPath)) {
throw new Exception("ファイルの保存後検証に失敗しました");
}
return [
'filename' => $filename,
'original_name' => $file['name'],
'size' => $file['size'],
'type' => $file['type'],
'path' => $targetPath
];
}
public function getUploadedFiles() {
$files = [];
if (!is_dir($this->uploadDir)) {
return $files;
}
$items = scandir($this->uploadDir);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$fullPath = $this->uploadDir . $item;
// ファイルのみを対象とする
if (is_file($fullPath)) {
$files[] = [
'name' => $item,
'size' => filesize($fullPath),
'modified' => filemtime($fullPath),
'extension' => pathinfo($item, PATHINFO_EXTENSION)
];
}
}
// 更新日時でソート
usort($files, function($a, $b) {
return $b['modified'] - $a['modified'];
});
return $files;
}
private function generateUniqueFilename($originalName) {
$extension = pathinfo($originalName, PATHINFO_EXTENSION);
$basename = pathinfo($originalName, PATHINFO_FILENAME);
$timestamp = time();
$random = mt_rand(1000, 9999);
return "{$basename}_{$timestamp}_{$random}.{$extension}";
}
private function getUploadErrorMessage($errorCode) {
$errors = [
UPLOAD_ERR_INI_SIZE => 'ファイルサイズがphp.iniの設定を超えています',
UPLOAD_ERR_FORM_SIZE => 'ファイルサイズがフォームの設定を超えています',
UPLOAD_ERR_PARTIAL => 'ファイルが部分的にしかアップロードされませんでした',
UPLOAD_ERR_NO_FILE => 'ファイルがアップロードされませんでした',
UPLOAD_ERR_NO_TMP_DIR => '一時ディレクトリがありません',
UPLOAD_ERR_CANT_WRITE => 'ディスクへの書き込みに失敗しました',
UPLOAD_ERR_EXTENSION => '拡張モジュールによりアップロードが中断されました'
];
return $errors[$errorCode] ?? '不明なエラー';
}
private function formatBytes($size) {
$units = ['B', 'KB', 'MB', 'GB'];
$factor = floor((strlen($size) - 1) / 3);
return sprintf("%.2f %s", $size / pow(1024, $factor), $units[$factor]);
}
}
// 使用例(HTMLフォームと組み合わせて使用)
/*
HTML:
<form method="post" enctype="multipart/form-data">
<input type="file" name="upload_file" required>
<button type="submit">アップロード</button>
</form>
*/
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$uploader = new FileUploadHandler('./uploads/', ['jpg', 'png', 'pdf'], 10485760); // 10MB
$result = $uploader->handleUpload('upload_file');
echo "アップロード成功:\n";
echo "ファイル名: {$result['filename']}\n";
echo "サイズ: " . number_format($result['size']) . " bytes\n";
} catch (Exception $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
}
// アップロード済みファイル一覧の表示
$uploader = new FileUploadHandler('./uploads/');
$uploadedFiles = $uploader->getUploadedFiles();
echo "アップロード済みファイル:\n";
foreach ($uploadedFiles as $file) {
echo "- {$file['name']} ({$file['size']} bytes, {$file['extension']})\n";
}
?>
他の関数との比較
is_file vs file_exists
<?php
// 比較例
$testPaths = [
'existing_file.txt', // 存在するファイル
'nonexistent_file.txt', // 存在しないファイル
'/tmp', // 存在するディレクトリ
'/nonexistent_dir' // 存在しないディレクトリ
];
foreach ($testPaths as $path) {
echo "パス: {$path}\n";
echo " file_exists(): " . (file_exists($path) ? 'true' : 'false') . "\n";
echo " is_file(): " . (is_file($path) ? 'true' : 'false') . "\n";
echo " is_dir(): " . (is_dir($path) ? 'true' : 'false') . "\n";
echo "\n";
}
?>
ファイルタイプ判定の包括的な関数
<?php
function getFileType($path) {
if (!file_exists($path)) {
return '存在しない';
}
if (is_file($path)) {
return 'ファイル';
}
if (is_dir($path)) {
return 'ディレクトリ';
}
if (is_link($path)) {
return 'シンボリックリンク';
}
return 'その他';
}
// 使用例
$paths = ['.', '..', 'index.php', '/tmp', '/dev/null'];
foreach ($paths as $path) {
echo "{$path}: " . getFileType($path) . "\n";
}
?>
注意すべきポイント
1. パフォーマンスの考慮
大量のファイルをチェックする場合は、パフォーマンスに注意が必要です。
<?php
class FileChecker {
private $cache = [];
public function isFileWithCache($path) {
if (isset($this->cache[$path])) {
return $this->cache[$path];
}
$result = is_file($path);
$this->cache[$path] = $result;
return $result;
}
public function clearCache() {
$this->cache = [];
}
}
?>
2. セキュリティ上の考慮事項
ユーザー入力を直接使用する場合は、パストラバーサル攻撃を防ぐ必要があります。
<?php
function safeFileCheck($filename, $allowedDir = './safe/') {
// ディレクトリトラバーサル攻撃を防ぐ
$filename = basename($filename);
$fullPath = rtrim($allowedDir, '/') . '/' . $filename;
// 実際のパスが許可されたディレクトリ内にあるかチェック
$realPath = realpath($fullPath);
$allowedRealPath = realpath($allowedDir);
if ($realPath === false || strpos($realPath, $allowedRealPath) !== 0) {
return false;
}
return is_file($realPath);
}
// 使用例
$userFile = $_GET['file'] ?? '';
if (safeFileCheck($userFile, './uploads/')) {
echo "ファイルは安全に検証されました";
} else {
echo "ファイルの検証に失敗しました";
}
?>
3. 権限の問題
ファイルの存在確認において、読み取り権限がない場合の対処法:
<?php
function checkFileWithPermissions($path) {
$result = [
'exists' => file_exists($path),
'is_file' => false,
'readable' => false,
'writable' => false,
'executable' => false
];
if ($result['exists']) {
$result['is_file'] = is_file($path);
if ($result['is_file']) {
$result['readable'] = is_readable($path);
$result['writable'] = is_writable($path);
$result['executable'] = is_executable($path);
}
}
return $result;
}
// 使用例
$fileInfo = checkFileWithPermissions('./config.json');
print_r($fileInfo);
?>
まとめ
is_file
関数は、PHPでファイルとディレクトリを区別する際の基本的で重要な関数です。この記事で紹介した内容をまとめると:
- 基本的な使い方 – ファイルかどうかの判定
- 実践的な活用 – ファイル処理、設定管理、アップロード処理
- 他の関数との組み合わせ – より堅牢な判定システム
- セキュリティとパフォーマンス – 実用的な考慮事項
これらのポイントを理解することで、より安全で効率的なファイル処理システムを構築できるようになります。is_file
関数を適切に活用して、堅牢なPHPアプリケーションを開発しましょう。