Table Of Contents
The Implementation
You can solve file and directory copying needs by using PHP's built-in functions with recursive handling:
<?php
// Basic file copying
if (!copy('source.txt', 'destination.txt')) {
throw new RuntimeException('Failed to copy file');
}
// Safe file copy with validation
function copyFileSafely(string $source, string $destination): bool {
// Validate source file
if (!file_exists($source)) {
throw new InvalidArgumentException("Source file does not exist: $source");
}
if (!is_readable($source)) {
throw new RuntimeException("Source file is not readable: $source");
}
// Ensure destination directory exists
$destDir = dirname($destination);
if (!is_dir($destDir)) {
if (!mkdir($destDir, 0755, true)) {
throw new RuntimeException("Cannot create destination directory: $destDir");
}
}
// Check if destination is writable
if (file_exists($destination) && !is_writable($destination)) {
throw new RuntimeException("Destination file is not writable: $destination");
}
// Perform the copy
if (!copy($source, $destination)) {
throw new RuntimeException("Failed to copy file from $source to $destination");
}
return true;
}
// Copy with backup of existing file
function copyWithBackup(string $source, string $destination): bool {
if (file_exists($destination)) {
$backupName = $destination . '.backup.' . date('Y-m-d_H-i-s');
if (!copy($destination, $backupName)) {
throw new RuntimeException("Failed to create backup of existing file");
}
}
return copyFileSafely($source, $destination);
}
// Recursive directory copying
function copyDirectory(string $source, string $destination): bool {
if (!is_dir($source)) {
throw new InvalidArgumentException("Source is not a directory: $source");
}
// Create destination directory
if (!is_dir($destination)) {
if (!mkdir($destination, 0755, true)) {
throw new RuntimeException("Cannot create destination directory: $destination");
}
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $file) {
$destPath = $destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName();
if ($file->isDir()) {
if (!mkdir($destPath, 0755, true)) {
throw new RuntimeException("Cannot create directory: $destPath");
}
} else {
if (!copy($file->getRealPath(), $destPath)) {
throw new RuntimeException("Cannot copy file: {$file->getRealPath()} to $destPath");
}
}
}
return true;
}
// Copy files matching pattern
function copyFilesByPattern(string $sourceDir, string $pattern, string $destinationDir): array {
$copiedFiles = [];
if (!is_dir($destinationDir)) {
mkdir($destinationDir, 0755, true);
}
$files = glob($sourceDir . DIRECTORY_SEPARATOR . $pattern);
foreach ($files as $file) {
if (is_file($file)) {
$filename = basename($file);
$destination = $destinationDir . DIRECTORY_SEPARATOR . $filename;
if (copyFileSafely($file, $destination)) {
$copiedFiles[] = $filename;
}
}
}
return $copiedFiles;
}
// Copy files newer than specified date
function copyNewerFiles(string $sourceDir, string $destinationDir, string $sinceDate): array {
$copiedFiles = [];
$sinceTimestamp = strtotime($sinceDate);
if (!is_dir($destinationDir)) {
mkdir($destinationDir, 0755, true);
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
if ($file->isFile() && $file->getMTime() > $sinceTimestamp) {
$relativePath = substr($file->getPathname(), strlen($sourceDir) + 1);
$destPath = $destinationDir . DIRECTORY_SEPARATOR . $relativePath;
// Create destination directory structure
$destDir = dirname($destPath);
if (!is_dir($destDir)) {
mkdir($destDir, 0755, true);
}
if (copyFileSafely($file->getPathname(), $destPath)) {
$copiedFiles[] = $relativePath;
}
}
}
return $copiedFiles;
}
// Create backup of directory
function createDirectoryBackup(string $sourceDir, string $backupRoot = 'backups'): string {
$timestamp = date('Y-m-d_H-i-s');
$dirName = basename($sourceDir);
$backupPath = $backupRoot . DIRECTORY_SEPARATOR . $dirName . '_' . $timestamp;
copyDirectory($sourceDir, $backupPath);
return $backupPath;
}
// Copy with progress tracking
function copyWithProgress(string $source, string $destination, callable $progressCallback = null): bool {
$sourceSize = filesize($source);
$sourceHandle = fopen($source, 'rb');
$destHandle = fopen($destination, 'wb');
if (!$sourceHandle || !$destHandle) {
throw new RuntimeException('Cannot open files for copying');
}
$copiedBytes = 0;
$chunkSize = 1024 * 1024; // 1MB chunks
while (!feof($sourceHandle)) {
$chunk = fread($sourceHandle, $chunkSize);
fwrite($destHandle, $chunk);
$copiedBytes += strlen($chunk);
if ($progressCallback) {
$progressCallback($copiedBytes, $sourceSize);
}
}
fclose($sourceHandle);
fclose($destHandle);
return true;
}
// Usage examples
try {
// Simple file copy
copyFileSafely('important.txt', 'backup/important.txt');
// Copy with backup
copyWithBackup('config.php', 'config.php.new');
// Copy entire directory
copyDirectory('project', 'project_backup');
// Copy specific file types
$copiedImages = copyFilesByPattern('uploads', '*.{jpg,png,gif}', 'backup/images');
echo "Copied images: " . implode(', ', $copiedImages) . "\n";
// Copy files modified in last 7 days
$recentFiles = copyNewerFiles('documents', 'recent_backup', '-7 days');
echo "Copied " . count($recentFiles) . " recent files\n";
// Create timestamped backup
$backupPath = createDirectoryBackup('important_data');
echo "Backup created at: $backupPath\n";
// Copy large file with progress
copyWithProgress('large_file.zip', 'backup/large_file.zip', function($copied, $total) {
$percent = round(($copied / $total) * 100, 2);
echo "Progress: $percent%\r";
});
} catch (Exception $e) {
echo "Copy error: " . $e->getMessage() . "\n";
}
Key Points
PHP file copying provides several approaches for different needs:
- File Copying: Use
copy()
for simple file-to-file operations - Directory Copying: Requires recursive iteration through all files
- Validation: Always check source exists and destination is writable
- Error Handling: Proper exception handling for robust operations
Essential Functions:
copy($source, $dest)
- Basic file copyingRecursiveDirectoryIterator
- Directory traversalfilesize()
,filemtime()
- File informationmkdir()
- Create destination directories
Best Practices:
- Validate source and destination paths
- Create destination directories as needed
- Handle large files with chunked copying
- Provide progress feedback for long operations
Perfect for backups, file organization, and data migration tasks.
Share this article
Add Comment
No comments yet. Be the first to comment!