File Management Beyond Uploads
Uploading files is just the beginning. Once files are on your server, you need to manage them.
Trongate's File module provides methods for all common file operations:
- Checking if files exist
- Deleting files
- Copying files
- Moving/renaming files
- Reading file contents
- Writing to files
- Getting file information
The Pattern: Check Before You Act
All file management methods follow a simple calling pattern:
$this->file->method_name($path, $parameters...);
The methods introduced on this page throw exceptions for genuine errors (permission denied, disk full, file locked) - not for expected conditions that you should handle in advance.
It's highly recommended to make sure appropriate conditions are met before trying to invoke file management methods.
Make sure files exist before calling file management methods:
// ✅ GOOD: Check first, then act
if ($this->file->exists($file_path)) {
$this->file->delete($file_path);
set_flashdata('File deleted successfully');
redirect('files/manage');
} else {
redirect('files/not_found');
}
// ❌ BAD: Don't rely on exceptions for validation
try {
$this->file->delete($file_path);
set_flashdata('File deleted successfully'); // Wrong use of flashdata
} catch (Exception $e) {
set_flashdata('Failed: ' . $e->getMessage()); // Wrong use of flashdata
}
1. Checking File Existence
Use included-file-exists() to make sure a file exists before operating on it:
/**
* @param string $path File or directory path
* @return bool True if exists, false otherwise
*/
public function exists(string $path): bool
Example: Verify Before Deletion
public function remove_user_file($file_id): void {
// Get the database record
$file_record = $this->db->get_where($file_id, 'user_files');
if ($file_record === false) {
redirect('files/not_found');
}
// Reconstruct the relative file path
$file_path = '../modules/users/uploads/' . $file_record->filename;
// Check if file exists before attempting deletion
if ($this->file->exists($file_path)) {
$this->file->delete($file_path);
$this->db->delete($file_id, 'user_files');
set_flashdata('File removed successfully');
redirect('files/manage');
} else {
redirect('files/not_found');
}
}
2. Deleting Files
The included-file-delete() method removes files from the file system:
/**
* @param string $file_path Path to the file
* @return bool True if deleted successfully
* @throws Exception If file doesn't exist or can't be deleted
*/
public function delete(string $file_path): bool
Example: Clean Up Old Uploads
public function cleanup_old_files(): void {
// Find files older than 30 days
$cutoff_date = date('Y-m-d H:i:s', strtotime('-30 days'));
$sql = 'SELECT id, filename FROM temp_uploads WHERE created_at < ?';
$old_files = $this->db->query($sql, [$cutoff_date], 'object');
$deleted_count = 0;
foreach ($old_files as $file) {
$file_path = 'public/temp/' . $file->filename;
if ($this->file->exists($file_path)) {
$this->file->delete($file_path);
$this->db->delete($file->id, 'temp_uploads');
$deleted_count++;
}
}
set_flashdata("Cleaned up $deleted_count old files");
redirect('admin/maintenance');
}
3. Copying Files
The included-file-copy() method copies a file from one location to another.
/**
* @param string $source_path Original file location
* @param string $destination_path Copy target location
* @return bool True if copied successfully
* @throws Exception If source doesn't exist or copy fails
*/
public function copy(string $source_path, string $destination_path): bool
Example: Create Document Backup
public function backup_document($document_id): void {
$document = $this->db->get_where($document_id, 'documents');
if ($document === false) {
redirect('documents/not_found');
}
// Original file location
$source_path = '../modules/documents/storage/' . $document->filename;
// Check source exists
if (!$this->file->exists($source_path)) {
redirect('documents/not_found');
}
// Create dated backup directory if needed
$backup_dir = '../modules/documents/backups/' . date('Y-m-d');
if (!$this->file->exists($backup_dir)) {
$this->file->create_directory($backup_dir, 0755, true);
}
// Create backup
$backup_path = $backup_dir . '/' . $document->filename;
$this->file->copy($source_path, $backup_path);
set_flashdata('Backup created successfully');
redirect('documents/view/' . $document_id);
}
4. Moving Files
With included-file-move() you can relocate or rename files in a single operation:
/**
* @param string $source_path Current file location
* @param string $destination_path New file location
* @return bool True if moved successfully
* @throws Exception If source doesn't exist or move fails
*/
public function move(string $source_path, string $destination_path): bool
Example: Organize Files by Date
public function organize_by_date($file_id): void {
$file = $this->db->get_where($file_id, 'uploads');
if ($file === false) {
redirect('uploads/not_found');
}
// Current location
$current_path = '../modules/uploads/incoming/' . $file->filename;
if (!$this->file->exists($current_path)) {
redirect('uploads/not_found');
}
// Organize into year/month structure
$year_month = date('Y/m', strtotime($file->created_at));
$organized_dir = '../modules/uploads/organized/' . $year_month;
// Create directory structure if needed
if (!$this->file->exists($organized_dir)) {
$this->file->create_directory($organized_dir, 0755, true);
}
// Move the file
$new_path = $organized_dir . '/' . $file->filename;
$this->file->move($current_path, $new_path);
// Update database with new path
$data['file_path'] = $new_path;
$this->db->update($file_id, $data, 'uploads');
set_flashdata('File organized successfully');
redirect('uploads/manage');
}
5. Reading Files
The included-file-read() method returns complete file contents as a string:
/**
* @param string $file_path Path to the file
* @return string Complete file contents
* @throws Exception If file doesn't exist or can't be read
*/
public function read(string $file_path): string
Example: Process CSV Data
public function import_contacts($file_id): void {
$import = $this->db->get_where($file_id, 'imports');
if ($import === false) {
redirect('imports/not_found');
}
$file_path = '../modules/imports/uploads/' . $import->filename;
if (!$this->file->exists($file_path)) {
redirect('imports/not_found');
}
// Read the CSV file
$csv_content = $this->file->read($file_path);
$rows = array_map('str_getcsv', explode("\n", $csv_content));
// Skip header row and process
$imported = 0;
for ($i = 1; $i < count($rows); $i++) {
if (count($rows[$i]) >= 3) {
$data = [
'name' => $rows[$i][0],
'email' => $rows[$i][1],
'phone' => $rows[$i][2]
];
$this->db->insert($data, 'contacts');
$imported++;
}
}
set_flashdata("Imported $imported contacts");
redirect('contacts/manage');
}
6. Writing Files
With the included-file-write() method, you can create new files or update existing ones:
/**
* @param string $file_path Path where file should be written
* @param mixed $data Content to write
* @param bool $append If true, append instead of overwrite (default: false)
* @return bool True if written successfully
* @throws Exception If write operation fails
*/
public function write(string $file_path, $data, bool $append = false): bool
Example: Generate Export File
public function export_users(): void {
// Get all users
$users = $this->db->get('users', 'object');
// Create CSV content
$csv = "Name,Email,Joined\n";
foreach ($users as $user) {
$csv .= "{$user->name},{$user->email},{$user->created_at}\n";
}
// Write to exports directory
$filename = 'users_export_' . date('Y-m-d_His') . '.csv';
$file_path = '../modules/users/exports/' . $filename;
$this->file->write($file_path, $csv);
set_flashdata('Export file created');
redirect('users/manage');
}
Example: Append to Log File
public function log_activity($message): void {
$log_entry = date('[Y-m-d H:i:s] ') . $message . "\n";
$log_path = '../modules/admin/logs/activity.log';
// Append to existing log file
$this->file->write($log_path, $log_entry, true);
}
7. Getting File Information
The included-file-info() method can be used to retrieve comprehensive metadata about a file:
/**
* @param string $file_path Path to the file
* @return array Associative array with file metadata
* @throws Exception If file doesn't exist
*/
public function info(string $file_path): array
Returns an array containing:
file_name - The filename
size - Size in bytes
human_readable_size - Size formatted (e.g., "2.4 MB")
modified_time - Unix timestamp of last modification
permissions - File permissions
readable_permissions - Formatted permissions (e.g., "0644")
mime_type - MIME type of the file
Example: Display File Details
public function view_file_info($file_id): void {
$file = $this->db->get_where($file_id, 'documents');
if ($file === false) {
redirect('documents/not_found');
}
$file_path = '../modules/documents/storage/' . $file->filename;
if ($this->file->exists($file_path)) {
$info = $this->file->info($file_path);
$data['file_record'] = $file;
$data['file_info'] = $info;
$data['view_file'] = 'file_details';
$this->view('file_details', $data);
} else {
redirect('documents/not_found');
}
}
Quick Reference Table
| Method |
Purpose |
Example |
| included-file-exists() |
Check if file exists |
if ($this->file->exists($path)) |
| included-file-delete() |
Remove a file |
$this->file->delete($file_path) |
| included-file-copy() |
Duplicate a file |
$this->file->copy($source, $destination) |
| included-file-move() |
Relocate/rename a file |
$this->file->move($old_path, $new_path) |
| included-file-read() |
Get file contents |
$content = $this->file->read($file_path) |
| included-file-write() |
Create or update file |
$this->file->write($path, $data) |
| included-file-info() |
Get file metadata |
$info = $this->file->info($file_path) |
Common Patterns and Best Practices
Pattern 1: Store Relative Paths in Database
// During upload, store the relative path
$file_info = $this->file->upload($config);
$data['filename'] = $file_info['file_name'];
$data['file_path'] = $file_info['file_path']; // Store the relative path
$this->db->insert($data, 'documents');
// Later, use the stored path directly
$doc = $this->db->get_where($id, 'documents');
if ($doc === false) {
redirect('documents/not_found');
}
if ($this->file->exists($doc->file_path)) {
$this->file->delete($doc->file_path);
$this->db->delete($id, 'documents');
set_flashdata('Document deleted');
redirect('documents/manage');
} else {
redirect('documents/not_found');
}
Pattern 2: Store Filename, Reconstruct Path
// During upload, store just the filename
$file_info = $this->file->upload($config);
$data['filename'] = $file_info['file_name'];
$this->db->insert($data, 'documents');
// Later, reconstruct the relative path
$doc = $this->db->get_where($id, 'documents');
if ($doc === false) {
redirect('documents/not_found');
}
$file_path = '../modules/documents/storage/' . $doc->filename;
if ($this->file->exists($file_path)) {
$this->file->delete($file_path);
$this->db->delete($id, 'documents');
set_flashdata('Document deleted');
redirect('documents/manage');
} else {
redirect('documents/not_found');
}
Pattern 3: Complete Validation Flow
public function process_file($file_id): void {
// 1. Validate database record
$file = $this->db->get_where($file_id, 'uploads');
if ($file === false) {
redirect('uploads/not_found');
}
// 2. Build relative file path
$file_path = '../modules/uploads/storage/' . $file->filename;
// 3. Validate file exists
if (!$this->file->exists($file_path)) {
redirect('uploads/not_found');
}
// 4. Now safe to perform operations
$content = $this->file->read($file_path);
// Process content...
$processed = strtoupper($content);
// Write back to file
$this->file->write($file_path, $processed);
set_flashdata('File processed successfully');
redirect('uploads/manage');
}