How the Mass Delete Action in OpenMage Image Cleaner Handles Missing Files Safely
The mass delete action in OpenMage Image Cleaner safely skips files that no longer exist on disk by checking file_exists() before attempting unlink(), automatically cleaning up stale database records without throwing PHP warnings.
The fballiano/openmage-image-cleaner extension provides a robust mechanism for purging unused images from your OpenMage (Magento 1) installation. When administrators select multiple entries in the Unused Images grid and execute a bulk deletion, the controller implements defensive checks to handle scenarios where physical files may have been removed externally or corrupted, ensuring the database remains synchronized with the filesystem state.
How the Mass Delete Action Processes Files
The deletion logic resides in FbimagecleanerController::massDeleteAction() within app/code/community/Fballiano/ImageCleaner/controllers/Adminhtml/FbimagecleanerController.php. The controller receives an array of image IDs via the ids parameter and processes each entry through a four-step safety workflow.
Loading Database Records and Resolving Paths
For each image ID submitted by the admin grid, the controller first retrieves the corresponding database record and constructs the absolute filesystem path:
$image = $db->fetchRow("SELECT * FROM {$cleaner_table} WHERE image_id=?", $image_id);
$image_path = $helper->getMediaDirByEntityTypeId($image['entity_type_id']) . $image["path"];
The helper method getMediaDirByEntityTypeId() (defined in Helper/Data.php) maps entity types to their correct media directories, ensuring the system targets the right physical location regardless of whether the image belongs to products, categories, or other entities.
The Critical File Existence Check
Before attempting any filesystem operation, the code explicitly verifies the file's presence:
if (!file_exists($image_path)) {
$db->query("DELETE FROM {$cleaner_table} WHERE image_id=?", $image_id);
continue;
}
This check prevents PHP from generating warnings or fatal errors when calling unlink() on non-existent paths. If the file is missing, the controller bypasses the deletion attempt and immediately removes the stale database row, maintaining referential integrity between the cleaner table and the actual filesystem state.
Safe Deletion and Error Handling
When a file exists, the controller attempts deletion and implements single-error reporting to avoid UI flooding:
if (unlink($image_path)) {
$db->query("DELETE FROM {$cleaner_table} WHERE image_id=?", $image_id);
} elseif (!$error_message_thrown) {
$error_message_thrown = true;
Mage::getSingleton('adminhtml/session')
->addError($this->__('It was not possible to delete one or more files from the filesystem.'));
}
The $error_message_thrown boolean flag ensures administrators see only one error message per batch operation, even if multiple files fail to delete due to permissions or other filesystem constraints.
Code Implementation Deep Dive
The complete mass delete action implementation demonstrates enterprise-grade error handling for legacy OpenMage environments:
// File: app/code/community/Fballiano/ImageCleaner/controllers/Adminhtml/FbimagecleanerController.php
public function massDeleteAction()
{
$ids = $this->getRequest()->getParam('ids');
$db = Mage::getSingleton('core/resource')->getConnection('core_write');
$cleaner_table = Mage::getSingleton('core/resource')->getTableName('fballiano_imagecleaner/cleaner');
$helper = Mage::helper('fballiano_imagecleaner');
$error_message_thrown = false;
foreach ($ids as $image_id) {
$image = $db->fetchRow("SELECT * FROM {$cleaner_table} WHERE image_id=?", $image_id);
$image_path = $helper->getMediaDirByEntityTypeId($image['entity_type_id']) . $image["path"];
// Safety check: Skip missing files and clean DB record
if (!file_exists($image_path)) {
$db->query("DELETE FROM {$cleaner_table} WHERE image_id=?", $image_id);
continue;
}
// Attempt filesystem deletion
if (unlink($image_path)) {
$db->query("DELETE FROM {$cleaner_table} WHERE image_id=?", $image_id);
} elseif (!$error_message_thrown) {
$error_message_thrown = true;
Mage::getSingleton('adminhtml/session')
->addError($this->__('It was not possible to delete one or more files from the filesystem.'));
}
}
$this->_redirect('*/*');
}
Practical Usage Examples
Admin Panel Workflow
To trigger the mass delete action with missing file protection through the OpenMage backend:
- Navigate to System → Image Cleaner → Unused Images
- Select the checkbox for each image entry you wish to purge
- Choose Delete from the Actions dropdown and click Submit
The POST request sends ids array parameters to /admin/fballiano_imagecleaner/fbimagecleaner/massDelete. The controller processes each ID sequentially, silently removing database entries for files that have already been deleted externally, and only attempts unlink() on files that actually exist.
Programmatic Execution
You can invoke the same safety logic from custom scripts or cron jobs:
<?php
require 'app/Mage.php';
Mage::app('admin');
// Simulate admin selection of image IDs
$ids = [12, 45, 78];
$controller = new Fballiano_ImageCleaner_Adminhtml_FbimagecleanerController();
$controller->getRequest()->setParam('ids', $ids);
// Execute mass delete with built-in missing file handling
$controller->massDeleteAction();
This programmatic approach benefits from identical protections: missing files are pruned from the database without throwing exceptions, while present files are physically removed and then expunged from the tracking table.
Summary
- The mass delete action validates file existence using
file_exists()before callingunlink(), preventing PHP warnings on missing files. - Stale database records are automatically purged even when the physical file is already gone, ensuring the unused images list remains accurate.
- Error reporting is throttled to a single message per batch operation to maintain a clean admin user experience.
- The helper method
getMediaDirByEntityTypeId()ensures correct path resolution across different entity types (products, categories, etc.).
Frequently Asked Questions
What happens if a file was deleted outside of OpenMage before running the mass delete action?
The controller detects the missing file via file_exists(), skips the unlink() attempt entirely, and immediately executes a SQL DELETE statement to remove the corresponding row from the cleaner table. This prevents PHP errors and keeps the database synchronized with the actual filesystem state.
Does the mass delete action report all file deletion failures?
No. According to the source code in FbimagecleanerController.php, the system uses a $error_message_thrown boolean flag to display only the first deletion failure to the admin session. This design prevents the user interface from being flooded with multiple error messages when batch processing large numbers of images with permission issues or locked files.
How does the controller determine the correct media directory for each image?
The controller utilizes Mage::helper('fballiano_imagecleaner')->getMediaDirByEntityTypeId(), defined in Helper/Data.php, to map the entity_type_id stored in the database record to the proper media folder path. This abstraction handles variations between product images, category images, and other entity types without hardcoding directory paths in the controller logic.
Can I run the mass delete action from the command line or a cron job?
Yes. You can instantiate Fballiano_ImageCleaner_Adminhtml_FbimagecleanerController programmatically, set the ids parameter on the request object, and call massDeleteAction(). The same safety checks apply in CLI contexts, making it safe to automate image cleanup without risking fatal errors from missing files.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →