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

作成日: 更新日:

move_uploaded_file関数は、HTTP POSTによるファイルアップロードでアップロードされたファイルを、指定された新しい場所に移動する関数です。これは、アップロードされたファイルを安全に処理し、ウェブサーバー上の適切な場所に保存するために不可欠な関数です。第一引数には、アップロードされたファイルの一時的なファイル名(通常は$_FILES配列の'tmp_name'キーで指定されます)を指定します。第二引数には、ファイルを移動させたい新しいパスとファイル名を指定します。

この関数は、アップロードされたファイルが実際にHTTP POSTによってアップロードされたものであることを確認し、セキュリティ上のリスクを軽減します。move_uploaded_file関数を使用する前に、ファイルサイズやファイルの種類などのバリデーションを行うことが推奨されます。

移動が成功した場合、この関数はtrueを返します。失敗した場合、falseを返します。失敗の原因としては、指定された移動先のディレクトリが存在しない、書き込み権限がない、ファイルサイズが大きすぎるなどが考えられます。関数の実行結果を適切に確認し、エラーが発生した場合は適切なエラー処理を行うことが重要です。

move_uploaded_file関数は、アップロードされたファイルを確実に移動させることを保証するものではありません。移動が成功したかどうかを確認するために、返り値を必ず確認してください。また、ファイル名にユーザーが入力した値を使用する場合は、セキュリティ上の問題を防ぐために、ファイル名を適切にサニタイズする必要があります。これにより、悪意のあるスクリプトの実行を防ぐことができます。

基本的な使い方

構文(syntax)

move_uploaded_file ( string $filename , string $destination ) : bool

引数(parameters)

string $from, string $to

  • string $from: アップロードされたファイルの元のファイルパス
  • string $to: ファイルを移動する先の新しいファイルパス

戻り値(return)

bool

指定されたファイルからアップロードされたファイルを、指定された宛先に移動できたかどうかを真偽値(trueまたはfalse)で返します。移動に成功した場合はtrue、失敗した場合はfalseを返します。

サンプルコード

PHP move_uploaded_file でファイルを安全に移動・上書きする

<?php

/**
 * アップロードされたファイルを指定されたディレクトリへ安全に移動するサンプル関数。
 *
 * この関数は、ファイルのアップロード処理の一部をシミュレートします。
 * 実際には、Webサーバー経由でアップロードされたファイルの一時パスを使用します。
 *
 * @param array $fileInfo 通常は `$_FILES['input_name']` の形式で提供されるファイル情報。
 *                        ['tmp_name' => 一時ファイルパス, 'name' => 元のファイル名] を含むことを想定。
 * @param string $destinationDirectory ファイルを移動する最終的なディレクトリのパス。
 * @return string 処理結果のメッセージ。
 */
function handleFileUploadAndMove(array $fileInfo, string $destinationDirectory): string
{
    // アップロードされたファイルの一時的なパス。
    // 実際には `$_FILES['input_name']['tmp_name']` から取得されます。
    $temporaryFilePath = $fileInfo['tmp_name'];

    // 元のファイル名。basename() を使用して、パス情報を除去し、
    // ディレクトリトラバーサル攻撃(例: ../../../evil.php)を防ぎます。
    // 実際には `$_FILES['input_name']['name']` から取得されます。
    $originalFileName = basename($fileInfo['name']);

    // 移動先の完全なファイルパスを構築します。
    $destinationFilePath = rtrim($destinationDirectory, '/') . '/' . $originalFileName;

    // 移動先ディレクトリが存在しない場合は作成を試みます。
    if (!is_dir($destinationDirectory)) {
        // 0755 は一般的なディレクトリ権限です。true は再帰的にディレクトリを作成します。
        if (!mkdir($destinationDirectory, 0755, true)) {
            return "エラー: 移動先ディレクトリ '$destinationDirectory' の作成に失敗しました。パーミッションを確認してください。";
        }
    }

    // move_uploaded_file() を使用してファイルを一時パスから最終的な保存場所へ移動します。
    //
    // キーワード「上書き」について:
    // もし指定された $destinationFilePath に同名のファイルが既に存在する場合、
    // move_uploaded_file() は既存のファイルを新しいファイルで上書きします。
    //
    // セキュリティ上の注意点:
    // move_uploaded_file() は、渡されたファイルがHTTP POSTアップロードによって
    // アップロードされた正規の一時ファイルであるかを内部で厳格にチェックします(`is_uploaded_file()`と同様)。
    // このチェックにより、悪意のあるユーザーがシステム上の任意のファイルを移動することを防ぎます。
    //
    // このサンプルコードはPHPスクリプト単体で実行されるため、HTTP POSTアップロード環境ではありません。
    // したがって、`$temporaryFilePath` に指定されたパスは有効なアップロード済み一時ファイルではないため、
    // move_uploaded_file() は通常、ここで失敗します。
    // 実際のWebアプリケーションでは、`$_FILES`経由で提供される有効な一時ファイルパスでこの関数は成功します。
    if (move_uploaded_file($temporaryFilePath, $destinationFilePath)) {
        return "ファイル '$originalFileName' が '$destinationFilePath' に正常に移動されました。";
    } else {
        return "エラー: ファイル '$originalFileName' の移動に失敗しました。詳細: この環境では一時ファイルがHTTPアップロードによって提供されていない可能性があります。";
    }
}

// --- 使用例 ---
// 実際のWebアプリケーションでは、HTMLフォームからファイルをアップロードした際に、
// PHPが自動で生成する一時ファイルパスとファイル名が `$_FILES['フォームのname属性']` に格納されます。
// この例では、`move_uploaded_file` 関数の引数構造を示すためにダミーのファイル情報を使用しています。
$dummyUploadedFileInfo = [
    'tmp_name' => '/tmp/php_dummy_temp_file_'.uniqid(), // 実際にはPHPが自動生成する一時ファイルパス
    'name' => 'report_2023.pdf', // 元のファイル名
    'type' => 'application/pdf',
    'size' => 512000,
    'error' => UPLOAD_ERR_OK, // アップロードエラーがないことを示す(実際のエラーは UPLOAD_ERR_XXX 定数)
];

// ファイルを保存する最終的なディレクトリのパス。
// __DIR__ は現在のスクリプトが置かれているディレクトリを指します。
$uploadDirectory = __DIR__ . '/uploaded_files';

// アップロード処理を実行し、結果を表示
echo handleFileUploadAndMove($dummyUploadedFileInfo, $uploadDirectory);

?>

PHPのmove_uploaded_file関数は、WebサーバーにHTTP POSTリクエストでアップロードされたファイルを、一時的な場所から指定した最終保存先へ安全に移動するために使用されます。

この関数は二つの文字列型引数を取ります。一つ目の$from引数にはアップロードされたファイルの一時的なパスを、二つ目の$to引数にはファイルを移動させたい最終的な保存先のパスを指定します。処理が成功するとtrueを、失敗するとfalseを返します。

move_uploaded_file関数は、ファイルが本当にHTTP POSTアップロードによってアップロードされたものであるかを厳しくチェックします。これにより、悪意のあるユーザーがシステム上の他のファイルを移動させるのを防ぐ、重要なセキュリティ機能が組み込まれています。また、もし移動先のパスに同名のファイルが既に存在する場合、その既存のファイルは新しいファイルで上書きされます。

提示されたサンプルコードでは、$_FILESスーパーグローバル変数で通常提供されるファイル情報(一時パスや元のファイル名)を模倣し、アップロードされたファイルを安全に移動する一連の流れを示しています。特にbasename()関数を使って元のファイル名からパス情報を除去し、セキュリティを考慮しています。また、移動先ディレクトリが存在しない場合には自動的に作成する処理も含まれています。ただし、このサンプルコードはHTTPアップロード環境ではないため、move_uploaded_file関数は通常、指定された一時ファイルパスが有効なアップロード済み一時ファイルではないと判断し、失敗する点にご注意ください。実際のWebアプリケーションでは、HTMLフォームからのファイルアップロード時にPHPが生成する一時ファイルパスを$fromに指定することで、この関数が正常に機能します。

move_uploaded_file関数は、HTTP POSTでアップロードされた正規の一時ファイルのみを安全に移動するための関数です。サンプルコードはダミー情報を使っていますが、実際のWebアプリケーションでは$_FILESから得られる一時ファイルパスを指定する必要があります。この関数は、移動先に同名のファイルが既に存在する場合、既存のファイルを新しいファイルで上書きしますので、意図しないデータ消失を防ぐために事前のファイル名チェックやリネーム処理を検討してください。また、アップロードされたファイルの元のファイル名を安全に扱うため、basename()関数を使用してパス情報を除去し、ディレクトリトラバーサル攻撃などのセキュリティリスクを防ぐことが非常に重要です。移動先のディレクトリが存在しない場合はmkdir()で作成し、適切なパーミッション(例: 0755)を設定することも忘れないでください。関数が失敗した場合はfalseを返すため、必ず戻り値をチェックし、エラーに応じた適切な処理を行うことが安全なコードにつながります。

PHP move_uploaded_file 失敗時の処理

<?php

/**
 * ファイルアップロードを処理し、move_uploaded_file の失敗ケースをハンドリングする関数
 *
 * このスクリプトは単体で動作します。
 * 1. HTMLフォームでファイルを選択し「アップロード」ボタンを押してください。
 * 2. サーバーサイドでファイルを受け取り、指定ディレクトリに保存します。
 * 3. move_uploaded_file が成功したか失敗したかに応じてメッセージを表示します。
 */
function handleFileUpload(): void
{
    // アップロードされたファイルを保存するディレクトリ
    $uploadDirectory = 'uploads/';
    $message = '';

    // 保存先ディレクトリが存在しない場合は作成を試みる
    if (!is_dir($uploadDirectory)) {
        // mkdirの第三引数を true にすることで、再帰的にディレクトリを作成
        if (!mkdir($uploadDirectory, 0755, true)) {
            // ディレクトリ作成に失敗した場合、処理を中断
            $message = 'エラー: アップロードディレクトリの作成に失敗しました。';
        }
    }

    // フォームがPOSTメソッドで送信された場合のみ処理を実行
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // ファイルが選択され、アップロードエラーがないことを確認
        if (isset($_FILES['user_file']) && $_FILES['user_file']['error'] === UPLOAD_ERR_OK) {
            $tmpFilePath = $_FILES['user_file']['tmp_name'];

            // 安全のため、ファイル名からディレクトリ情報を除去
            $fileName = basename($_FILES['user_file']['name']);
            $destinationPath = $uploadDirectory . $fileName;

            // move_uploaded_file() でファイルを一時ディレクトリから指定の場所へ移動
            // この関数は、成功時に true、失敗時に false を返す
            if (move_uploaded_file($tmpFilePath, $destinationPath)) {
                $message = "ファイル '{$fileName}' のアップロードに成功しました。";
            } else {
                // ここが move_uploaded_file() が失敗した場合の処理
                $message = "エラー: ファイルの移動に失敗しました。";
                $message .= "考えられる原因として、サーバー上の '{$uploadDirectory}' ディレクトリに対する書き込み権限がない可能性があります。";
            }
        } else {
            // ファイルが選択されていない、またはアップロード中にエラーが発生した場合
            $message = 'エラー: ファイルが選択されていないか、アップロード中にエラーが発生しました。';
            if (isset($_FILES['user_file']['error'])) {
                 $message .= ' (エラーコード: ' . $_FILES['user_file']['error'] . ')';
            }
        }
    }
    // HTML部分と処理結果のメッセージを表示
    displayForm($message);
}

/**
 * HTMLフォームとメッセージを表示する関数
 * @param string $message 表示するメッセージ
 */
function displayForm(string $message): void
{
    echo '<!DOCTYPE html>';
    echo '<html lang="ja">';
    echo '<head>';
    echo '    <meta charset="UTF-8">';
    echo '    <title>move_uploaded_file 失敗サンプル</title>';
    echo '</head>';
    echo '<body>';
    echo '    <h1>ファイルアップロード</h1>';

    if ($message) {
        // XSS対策として、メッセージをエスケープして表示
        echo '    <p><strong>' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . '</strong></p>';
    }

    // ファイルアップロード用のフォーム
    // enctype="multipart/form-data" はファイル送信に必須
    echo '    <form action="" method="post" enctype="multipart/form-data">';
    echo '        <p>';
    echo '            <label for="file_input">ファイルを選択:</label>';
    echo '            <input type="file" name="user_file" id="file_input">';
    echo '        </p>';
    echo '        <p>';
    echo '            <input type="submit" value="アップロード">';
    echo '        </p>';
    echo '    </form>';
    echo '</body>';
    echo '</html>';
}

// メイン処理の実行
handleFileUpload();

PHPのmove_uploaded_file関数は、ユーザーがウェブフォームを通じてアップロードしたファイルを、一時的な保存場所からサーバー上の指定したディレクトリへ安全に移動させるための重要な関数です。この関数は、アップロードされたファイルが本当にアップロード処理を経てサーバーに到着したものであることを保証し、セキュリティ上のリスクを軽減します。

引数$fromには、アップロードされた一時ファイルが現在置かれているパス(通常は$_FILES['入力フィールド名']['tmp_name']で取得)を指定します。一方、引数$toには、ファイルを最終的に保存したいサーバー上のディレクトリとファイル名を指定します。

関数が正常にファイルの移動を完了した場合、戻り値としてtrueが返されます。しかし、ファイルの移動に失敗した場合はfalseが返されます。サンプルコードでは、このfalseが返されたケースを「失敗」としてハンドリングし、ユーザーにエラーメッセージを表示しています。失敗の一般的な原因としては、指定された保存先ディレクトリが存在しない、またはそのディレクトリに対するウェブサーバーの書き込み権限がないことなどが挙げられます。ファイルをアップロードする際は、保存先ディレクトリの作成と適切な権限設定が不可欠です。

move_uploaded_file関数が失敗する最も一般的な原因は、移動先のディレクトリに対する書き込み権限がないことです。Webサーバーを実行しているユーザー(例: www-data)に、指定したディレクトリへの書き込みを許可する必要があります。この関数は、PHPによってアップロードされた正規のファイルであることも検証するため、rename関数などを使うより安全です。また、サンプルコードのようにbasename関数でファイル名からパス情報を除去するのは、意図しない場所にファイルを保存される攻撃を防ぐための重要なセキュリティ対策です。アップロード自体が失敗している可能性もあるため、$_FILES['error']の値を確認することも問題解決の助けになります。

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