PHPでWebアプリケーションを開発していると、画像のバックアップを取ったり、設定ファイルのひな形を複製したりと、「ファイルをコピーする」処理が必要になる場面は多々あります。
copy() という便利な関数が用意されており、これを使えばたった1行でファイルの複製が可能です。しかし、実務では「コピー先に同名のファイルがあったらどうする?」「ディレクトリごと丸ごとコピーしたい場合は?」といった、一歩進んだ要件への対応が求められます。
この記事では、PHPにおけるファイルコピーの基本から、エラーを防ぐための安全な実装方法、さらに標準関数ではサポートされていないディレクトリの再帰的なコピー方法まで、徹底的にわかりやすく解説します。
![]() 執筆者:マヒロ |
|
PHPでファイルをコピーする基本:copy関数
PHPでファイルをコピーする際に最も基本となるのが copy 関数です。
まずはこの関数の構文と、シンプルな使用例を見ていきましょう。
copy関数の基本的な書き方と構文
copy 関数は、第一引数に「コピー元のファイルパス」、第二引数に「コピー先のファイルパス」を指定して使用します。
// 基本構文
bool copy ( string $from , string $to [, resource $context ] )
- $from:コピー元のファイルパス
- $to:コピー先のファイルパス
- 戻り値:コピーに成功した場合は
true、失敗した場合はfalseを返します。
以下は、source.txt というファイルを backup.txt という名前でコピーする簡単なサンプルコードです。
<?php
// コピー元のファイル
$source_file = 'source.txt';
// コピー先のファイル名
$dest_file = 'backup.txt';
// ファイルをコピー実行
if (copy($source_file, $dest_file)) {
echo "ファイルのコピーに成功しました。";
} else {
echo "ファイルのコピーに失敗しました。";
}
?>
実行結果と動作のポイント
上記のコードを実行すると、同じディレクトリ内に backup.txt が生成されます。
もし backup.txt が既に存在していた場合、copy 関数はデフォルトで警告なしに上書き保存を行います。
これは便利な反面、重要なデータを消してしまうリスクもあるため、後述するエラー対策が重要になります。
また、ファイルパスは相対パスだけでなく、サーバー上の絶対パス(例: /var/www/html/data/file.txt)や、URL(PHPの設定で allow_url_fopen が有効な場合)を指定することも可能です。
ファイルコピー時のよくあるトラブルとエラー対策
copy 関数はシンプルですが、何も考えずに使うと予期せぬエラーでプログラムが停止してしまうことがあります。
堅牢なシステムを作るために必須となる、事前チェックとエラーハンドリングの方法を解説します。
コピー元ファイルが存在するか確認する
そもそもコピー元のファイルが存在しなければ、コピー処理は失敗します。
処理を実行する前に file_exists 関数を使ってファイルの有無を確認するのが定石です。
<?php
$source = 'data/user_list.csv';
$dest = 'backup/user_list_2025.csv';
// コピー元が存在するかチェック
if (file_exists($source)) {
if (copy($source, $dest)) {
echo "コピー完了";
} else {
echo "コピー処理に失敗しました";
}
} else {
echo "エラー:コピー元のファイルが見つかりません";
}
?>
上書きコピーを防ぐ方法
前述の通り、copy 関数は同名ファイルが存在すると上書きしてしまいます。
上書きを防ぎたい場合は、コピー先のファイルが存在しないことを file_exists で確認してから実行するようにしましょう。
<?php
$source = 'image.jpg';
$dest = 'images/image_copy.jpg';
// コピー先が既に存在するかチェック
if (file_exists($dest)) {
echo "エラー:コピー先に同名のファイルが存在します。上書きは行いません。";
} else {
if (copy($source, $dest)) {
echo "コピー成功";
} else {
echo "コピー失敗";
}
}
?>
コピー先のディレクトリが存在しない場合
初心者がよく陥るミスとして、「存在しないディレクトリの中にファイルをコピーしようとする」ケースがあります。
例えば backup というフォルダがない状態で copy('file.txt', 'backup/file.txt') を実行するとエラーになります。
この場合は、is_dir 関数でディレクトリの存在を確認し、なければ mkdir 関数で作成するという手順を踏みます。
<?php
$source = 'log.txt';
$dir_path = 'logs/2025/01'; // 深い階層のディレクトリ
$dest = $dir_path . '/log_backup.txt';
// ディレクトリが存在しない場合、再帰的に作成する
if (!is_dir($dir_path)) {
// 第3引数の true は再帰的作成(logsも2025も01も作る)を許可する設定
mkdir($dir_path, 0777, true);
}
if (copy($source, $dest)) {
echo "ディレクトリを作成してコピーしました";
}
?>
ディレクトリごとコピーしたい場合(再帰的コピー)
実は、PHPの copy 関数はディレクトリ(フォルダ)のコピーには対応していません。
ディレクトリパスを copy 関数に渡してもエラーになってしまいます。
ディレクトリの中身(サブディレクトリ含む)を丸ごと複製したい場合は、自作の関数を定義して「再帰処理」を行う必要があります。
再帰的にディレクトリをコピーする自作関数
ディレクトリ内を走査し、ファイルなら copy、ディレクトリなら mkdir を実行するという処理を繰り返す関数を作成します。
<?php
/**
* ディレクトリを再帰的にコピーする関数
*
* @param string $source_dir コピー元ディレクトリ
* @param string $dest_dir コピー先ディレクトリ
* @return bool 成功時true
*/
function copy_directory($source_dir, $dest_dir) {
// コピー元がディレクトリでなければ終了
if (!is_dir($source_dir)) {
return false;
}
// コピー先ディレクトリがなければ作成
if (!is_dir($dest_dir)) {
mkdir($dest_dir, 0777, true);
}
// ディレクトリハンドルを開く
$handle = opendir($source_dir);
if (!$handle) {
return false;
}
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
$src_path = $source_dir . '/' . $file;
$dst_path = $dest_dir . '/' . $file;
if (is_dir($src_path)) {
// ディレクトリなら再帰呼び出し
copy_directory($src_path, $dst_path);
} else {
// ファイルならコピー実行
copy($src_path, $dst_path);
}
}
closedir($handle);
return true;
}
// 使用例
copy_directory('original_data', 'backup_data');
echo "ディレクトリのコピーが完了しました";
?>
ソースコードの解説
この関数では、opendir と readdir を使ってディレクトリの中身を一つずつ取り出しています。
.(自分自身)と ..(親ディレクトリ)は処理から除外し、それ以外のアイテムについてファイルかディレクトリかを判定しています。
ディレクトリであれば自分自身の関数 copy_directory を再度呼び出す(再帰)ことで、階層がどれだけ深くてもすべてコピーすることが可能になります。
その他のファイル操作関数との違い
ファイルを複製・移動する関数は copy 以外にも存在します。
目的によって使い分けることが重要です。
ファイルの移動(rename)との違い
ファイルを「コピー(複製)」するのではなく、「移動(カット&ペースト)」したい場合は rename 関数を使います。
copy は元のファイルを残しますが、rename は元のファイルを新しい場所に移動するため、元の場所からはなくなります。
また、ファイル名の変更(リネーム)もこの関数で行います。
// ファイルを移動(リネーム)する場合
rename('old_name.txt', 'new_name.txt');
ファイルの中身を読み込んで書き込む(file_get_contents / file_put_contents)
テキストファイルの内容を一部加工してから別ファイルとして保存したい場合などは、copy ではなく file_get_contents で中身を読み込み、処理後に file_put_contents で保存するという方法もあります。
単純なコピーであれば copy の方が高速ですが、中身に手を加えたい場合にはこちらが便利です。
PHPのスキルを活かして年収を上げる方法
以上、PHPでファイルをコピーする方法について解説してきました。
なお、PHPのスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。
PHPエンジニアの需要は非常に高く求人数・案件数も多いため、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。
なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。
併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなPHPの案件を探しやすくなります。
転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。



