【PHP8.x】is_uploaded_file関数の使い方

作成日: 更新日:

is_uploaded_file関数は、指定されたファイルがHTTP POSTによるアップロードを通じてアップロードされたかどうかを調べる関数です。この関数は、セキュリティ上の重要な役割を果たします。なぜなら、悪意のあるユーザーがファイルを偽装してシステムに侵入しようとするのを防ぐことができるからです。具体的には、ユーザーがアップロードしたファイルを処理する前に、この関数を使ってファイルが正規のアップロードプロセスを経たものであることを確認します。

is_uploaded_file関数は、引数としてファイルのパスを受け取ります。このパスは、アップロードされたファイルが一時的に保存されている場所を指します。関数は、指定されたファイルが存在し、かつアップロードされたファイルである場合にtrueを返します。それ以外の場合、つまり、ファイルが存在しないか、アップロードされたファイルでない場合はfalseを返します。

この関数を使用する際には、ファイルパスが信頼できる情報源から提供されていることを確認することが重要です。例えば、ユーザーが直接入力したファイルパスをそのままis_uploaded_file関数に渡すことは避けるべきです。なぜなら、悪意のあるユーザーが偽のファイルパスを入力することで、セキュリティ上の脆弱性を悪用する可能性があるからです。通常は、$_FILESスーパーグローバル変数を通じて得られる一時ファイル名をこの関数に渡すのが安全です。

is_uploaded_file関数は、アップロードされたファイルを安全に処理するための基本的なツールの一つです。しかし、これだけで完全に安全が確保できるわけではありません。ファイルのコンテンツの検証や、適切なファイルサイズの制限、ファイル名のサニタイズなど、他のセキュリティ対策と組み合わせて使用することで、より安全なWebアプリケーションを構築できます。

基本的な使い方

構文(syntax)

is_uploaded_file(string $filename): bool

引数(parameters)

string $filename

  • string $filename: アップロードされたファイルへのパスを指定する文字列

戻り値(return)

bool

指定されたファイルがHTTP POSTリクエストでアップロードされたファイルである場合に true を返します。それ以外の場合は false を返します。

サンプルコード

PHPでis_uploaded_fileを使ったファイルアップロードエラー処理

<?php

/**
 * is_uploaded_file() を使用してファイルのアップロードとエラー処理を行う
 *
 * この関数は、HTTP POSTリクエストで送信されたファイルを安全に処理します。
 * ファイルアップロード時に発生する可能性のある様々なエラーをチェックし、
 * is_uploaded_file() を使って不正なファイル操作でないことを検証します。
 */
function processFileUpload(): void
{
    // 1. フォームが送信され、ファイルが選択されているかを確認
    if (!isset($_FILES['userfile']) || !is_array($_FILES['userfile'])) {
        // フォームが送信されていない、または壊れている場合は何もしない
        return;
    }

    // 2. アップロード時のエラーコードを確認
    $errorCode = $_FILES['userfile']['error'];
    if ($errorCode !== UPLOAD_ERR_OK) {
        handleUploadError($errorCode);
        return;
    }

    $tmpFilePath = $_FILES['userfile']['tmp_name'];

    // 3. is_uploaded_file() でファイルが正当なアップロードか検証【最重要】
    // このチェックがないと、サーバー上の任意のファイルを指定される攻撃を受ける可能性がある。
    // is_uploaded_file() が false を返す場合は、不正なアクセス試行としてエラー処理する。
    if (!is_uploaded_file($tmpFilePath)) {
        echo '<p style="color: red;">エラー: 不正なファイルアップロードの試みです。</p>';
        return;
    }

    // 4. ファイルを永続的な場所に移動する
    $uploadDir = __DIR__ . '/uploads/';
    // セキュリティのため、ユーザーが指定したファイル名をそのまま使わないことが望ましい
    $safeFilename = uniqid('', true) . '_' . basename($_FILES['userfile']['name']);
    $destination = $uploadDir . $safeFilename;

    // アップロードディレクトリが存在しない場合は作成する
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true);
    }

    if (move_uploaded_file($tmpFilePath, $destination)) {
        echo '<p style="color: green;">ファイルは正常にアップロードされました。</p>';
    } else {
        echo '<p style="color: red;">エラー: ファイルの移動中に問題が発生しました。</p>';
    }
}

/**
 * ファイルアップロードのエラーコードに対応するメッセージを表示する
 *
 * @param int $errorCode $_FILES['userfile']['error'] の値
 */
function handleUploadError(int $errorCode): void
{
    $message = 'エラー: ';
    switch ($errorCode) {
        case UPLOAD_ERR_INI_SIZE:
            $message .= 'アップロードされたファイルは、php.ini の upload_max_filesize ディレクティブの値を超えています。';
            break;
        case UPLOAD_ERR_FORM_SIZE:
            $message .= 'アップロードされたファイルは、HTML フォームで指定された MAX_FILE_SIZE を超えています。';
            break;
        case UPLOAD_ERR_PARTIAL:
            $message .= 'ファイルは一部しかアップロードされませんでした。';
            break;
        case UPLOAD_ERR_NO_FILE:
            $message .= 'ファイルが選択されませんでした。';
            break;
        case UPLOAD_ERR_NO_TMP_DIR:
            $message .= 'サーバーに一時保存フォルダがありません。';
            break;
        case UPLOAD_ERR_CANT_WRITE:
            $message .= 'サーバーにファイルを書き込めませんでした。';
            break;
        case UPLOAD_ERR_EXTENSION:
            $message .= 'PHPの拡張機能がファイルのアップロードを中止しました。';
            break;
        default:
            $message .= '不明なアップロードエラーが発生しました。';
            break;
    }
    echo '<p style="color: red;">' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . '</p>';
}

// HTTPメソッドがPOSTの場合のみ、ファイル処理を実行する
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    processFileUpload();
}

?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>PHP is_uploaded_file エラー処理サンプル</title>
</head>
<body>
    <h1>ファイルアップロードフォーム</h1>
    <p>
        is_uploaded_file() は、ファイルがHTTP POSTによってアップロードされたものであることを確認するセキュリティ上重要な関数です。<br>
        この関数が false を返した場合、それは不正なアクセスや設定ミスの可能性があることを示します。
    </p>

    <!-- ファイルアップロードフォームには enctype="multipart/form-data" が必須 -->
    <form action="" method="post" enctype="multipart/form-data">
        <p>
            ファイルを選択してください:
            <input type="file" name="userfile">
        </p>
        <p>
            <input type="submit" value="ファイルを送信">
        </p>
    </form>
</body>
</html>

PHP 8のis_uploaded_file関数は、指定されたファイルがHTTP POSTアップロードによってアップロードされたものであるかを安全に確認するためのものです。この関数は、引数として検証したいファイルのパスを文字列(string $filename)で受け取ります。通常、これは$_FILESスーパーグローバル変数から取得できる一時的なファイルパスです。検証が成功し、ファイルが正規のアップロードファイルであればtrueを、そうでなければfalseを真偽値(bool)として返します。

この関数は、ファイルアップロード処理におけるセキュリティの要となります。もしこのチェックを怠ると、悪意のあるユーザーがサーバー上の任意のファイルを指定し、それを操作する「ディレクトリトラバーサル」のようなセキュリティ上の脆弱性を引き起こす可能性があります。

サンプルコードでは、まず$_FILES配列の存在やアップロード時のエラーコード(UPLOAD_ERR_OKなど)を確認し、その後にis_uploaded_file()を使って、一時ファイルが実際にHTTP POSTで送られた正当なファイルであるかを厳重に検証しています。この検証がfalseを返した場合、それは不正なアップロードの試みとして扱われ、エラーメッセージが表示されます。これにより、PHPにおける安全なファイルアップロードとエラー処理の基盤を築くことができます。

is_uploaded_file関数は、アップロードされたファイルがHTTP POSTリクエストによる正規の一時ファイルであるかを検証する、セキュリティ上非常に重要な機能です。このチェックを怠ると、サーバー上の既存ファイルが不正に扱われる危険性がありますので、必ず使用してください。また、is_uploaded_file()の実行前に、$_FILES配列の存在確認や、様々なアップロードエラーコード(UPLOAD_ERR_INI_SIZEなど)の確認も必須となります。ファイルを永続的に保存する際は、ユーザーが指定したファイル名をそのまま使わず、basename関数で安全な名前に加工し、必要に応じてユニークなIDを付与するなどのセキュリティ対策を講じることが重要です。HTMLフォームにはenctype="multipart/form-data"の指定を忘れないでください。

PHP is_uploaded_file が false を返す例

<?php

/**
 * is_uploaded_file() が false を返す典型的なケースを示すサンプルコード。
 * この関数は、指定されたファイルが HTTP POST アップロード経由でアップロードされた
 * 有効なファイルであるかどうかを確認します。
 *
 * @param string $filePath 確認するファイルパス。
 * @return void
 */
function demonstrateIsUploadedFileReturnsFalse(string $filePath): void
{
    echo "Checking file: '{$filePath}'\n";

    // is_uploaded_file は、指定されたファイルが HTTP POST アップロードによって
    // 生成された一時ファイルである場合にのみ true を返します。
    // それ以外のファイル(存在しないファイル、通常のファイルなど)では false を返します。
    if (is_uploaded_file($filePath)) {
        echo "  結果: '{$filePath}' はアップロードされた一時ファイルです。\n";
    } else {
        echo "  結果: '{$filePath}' はアップロードされた一時ファイルではありません (または存在しません)。\n";
    }
    echo "\n";
}

// ----------------------------------------------------
// is_uploaded_file が false を返すケース
// ----------------------------------------------------

// ケース1: 存在しないファイルパスを指定した場合
// このファイルはシステム上に存在しないため、is_uploaded_file は false を返します。
demonstrateIsUploadedFileReturnsFalse('/path/to/non_existent_upload_file.tmp');

// ケース2: 存在するが、HTTP POST アップロード経由ではない通常のファイルを指定した場合
// まずテスト用のファイルを作成します。
$testFilePath = 'non_uploaded_regular_file.txt';
// ファイルが存在しなくても、file_put_contents はファイルを作成します。
file_put_contents($testFilePath, 'This is a test content for a regular file.');

// 作成したファイルは通常のファイルであり、HTTP POST アップロードされた一時ファイルではないため、
// is_uploaded_file は false を返します。
demonstrateIsUploadedFileReturnsFalse($testFilePath);

// テストファイルをクリーンアップします。
if (file_exists($testFilePath)) {
    unlink($testFilePath);
    echo "Cleaned up: '{$testFilePath}'\n";
}

// ----------------------------------------------------
// (参考) is_uploaded_file が true を返す可能性のあるケース (実際のアップロード処理が必要なためコメントアウト)
// ----------------------------------------------------
// 実際のファイルアップロードでは、例えば $_FILES['userfile']['tmp_name'] のような
// 一時ファイルパスに対して is_uploaded_file が true を返します。
//
// <form action="upload.php" method="post" enctype="multipart/form-data">
//     <input type="file" name="userfile">
//     <input type="submit" value="Upload">
// </form>
//
// // upload.php の内部で
// if (isset($_FILES['userfile']) && is_uploaded_file($_FILES['userfile']['tmp_name'])) {
//     // ここでは true が返され、ファイル処理に進むことができます。
//     echo "アップロードされた有効なファイルです!";
// } else {
//     echo "アップロードされたファイルではありません。";
// }

?>

PHPのis_uploaded_file関数は、指定されたファイルパスがHTTP POSTアップロードによって生成された一時ファイルであるかどうかを厳密にチェックします。この関数は引数として確認したいファイルパス(文字列型)を受け取り、結果を真偽値(ブール型)で返します。指定されたファイルがHTTP POSTアップロードによる有効な一時ファイルであればtrueを、そうでなければfalseを返します。

このサンプルコードは、is_uploaded_file関数がfalseを返す典型的な状況を初心者にもわかりやすく示しています。具体的には、システム上に存在しないファイルパスを指定した場合、ファイルが存在しないため当然ながらfalseが返されます。また、ファイルがシステム上に存在していても、それがHTTP POSTアップロードによって作成された一時ファイルではない通常のファイルである場合(例えば、プログラムがfile_put_contents関数などで作成したファイル)もfalseが返されます。

通常、この関数はウェブアプリケーションでユーザーがファイルをアップロードした際に、$_FILESスーパーグローバル変数を通じて提供される一時ファイルパスに対して使われます。その場合、有効なアップロードであればtrueが返され、ファイルの移動や処理に進むことができます。このチェックは、セキュリティ上、不正なファイル操作を防ぐために非常に重要な工程となります。

is_uploaded_file関数は、ファイルがサーバーに存在するかを確認するものではなく、正規のフォーム送信によってアップロードされた一時ファイルであるかを厳密に検証するためのものです。そのため、自分で作成したファイルや任意のファイルパスを指定しても必ずfalseを返します。この関数には、$_FILESグローバル変数に格納される一時ファイルのパス (tmp_name) を渡すのが唯一の正しい使い方です。このチェックはセキュリティ対策として非常に重要であり、悪意のあるリクエストによってサーバー上の意図しないファイルが操作されるのを防ぎます。ファイルアップロード処理を実装する際は、必ずこの関数で検証した後にmove_uploaded_file関数でファイルを移動させるようにしてください。

【PHP8.x】is_uploaded_file関数の使い方 | いっしー@Webエンジニア