# How OpenMage Image Cleaner Uses fnmatch for Blacklist Pattern Matching

> Discover how OpenMage Image Cleaner employs fnmatch for secure blacklist pattern matching. Learn how it protects your files from unwanted cleanup scans by matching glob patterns.

- Repository: [Fabrizio Balliano/openmage-image-cleaner](https://github.com/fballiano/openmage-image-cleaner)
- Tags: how-to-guide
- Published: 2026-03-01

---

**The OpenMage Image Cleaner module uses PHP's native `fnmatch()` function with a `*/` prefix to match admin-defined glob patterns against filesystem paths, excluding protected files and folders from cleanup scans.**

The `fballiano/openmage-image-cleaner` extension provides administrators with a flexible mechanism to safeguard specific assets from automated cleanup routines. By leveraging standard shell-style glob patterns processed through PHP's `fnmatch()` function, the module enables precise control over which files remain untouched during media directory scans. This implementation resides primarily within the helper class and integrates seamlessly with the recursive filesystem scanner.

## Configuration and Pattern Storage

Administrators define exclusion rules through the Magento Admin interface, where patterns are stored and subsequently processed by the module's helper methods.

### Admin Interface Configuration

The configuration interface is defined in [`app/code/community/Fballiano/ImageCleaner/etc/system.xml`](https://github.com/fballiano/openmage-image-cleaner/blob/main/app/code/community/Fballiano/ImageCleaner/etc/system.xml). The textarea field stores user input under the configuration path **`admin/fb_image_cleaner/blacklist`** as a newline-separated string. Each line represents an independent glob pattern that will be evaluated against filesystem paths during scan operations.

### Retrieving Patterns in Code

The helper class converts the stored configuration into an array of patterns. In [`app/code/community/Fballiano/ImageCleaner/Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/app/code/community/Fballiano/ImageCleaner/Helper/Data.php), the `getBlacklistedPatterns()` method retrieves and splits the configuration value:

```php
$blacklist = Mage::getStoreConfig('admin/fb_image_cleaner/blacklist');
return preg_split('/\r\n|\r|\n/', $blacklist);

```

This method handles various newline formats (CRLF, CR, or LF) to ensure cross-platform compatibility when administrators paste patterns from different operating systems.

## The fnmatch Implementation

The core matching logic resides in the `isBlacklisted()` method, which determines whether a given filesystem path matches any user-defined exclusion pattern.

### The isBlacklisted Method

Located in [`Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/Helper/Data.php) at lines 86-92, the method iterates through all blacklist patterns and applies `fnmatch()` to each candidate path:

```php
public function isBlacklisted($path, $blacklisted_patterns): bool
{
    foreach ($blacklisted_patterns as $blacklisted_pattern) {
        if (fnmatch('*/' . $blacklisted_pattern, $path)) return true;
    }
    return false;
}

```

The function prepends `*/` to every admin-defined pattern before passing it to `fnmatch()`. This transformation ensures that patterns match regardless of the absolute path prefix preceding the media directory.

### The Critical */ Prefix

The prepended `*/` wildcard serves a specific architectural purpose. The scanner operates on full filesystem paths (e.g., `/var/www/html/media/wysiwyg/banner.jpg`), while administrators define patterns relative to the media root (e.g., `wysiwyg/banner.jpg`).

By prefixing patterns with `*/`, the code forces the match to occur at any directory depth:

- **Without prefix**: `fnmatch('wysiwyg/*.jpg', '/var/www/media/wysiwyg/banner.jpg')` returns `false`
- **With prefix**: `fnmatch('*/wysiwyg/*.jpg', '/var/www/media/wysiwyg/banner.jpg')` returns `true`

The leading asterisk consumes the server-specific path components up to the media directory, allowing portable patterns that work across different server configurations.

## Integration with the File Scanner

The blacklist integrates directly into the recursive directory traversal, filtering protected assets before they reach the cleanup logic.

### Recursive Directory Scanning

The `scandirRecursive()` method in [`Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/Helper/Data.php) (lines 15-32) invokes `isBlacklisted()` for every file and folder encountered:

```php
public function scandirRecursive($dir)
{
    $result = [];
    $blacklist_patterns = $this->getBlacklistedPatterns();
    $root = scandir($dir);
    foreach ($root as $value) {
        if ($value === '.' || $value === '..') continue;
        $fullPath = "$dir/$value";

        // Skip anything matching the blacklist
        if ($this->isBlacklisted($fullPath, $blacklist_patterns)) {
            continue;
        }

        if (is_file($fullPath)) {
            $result[] = $fullPath;
        } else {
            $result = array_merge($result, $this->scandirRecursive($fullPath));
        }
    }
    return $result;
}

```

When `isBlacklisted()` returns `true`, the scanner immediately skips that entry via `continue`, preventing blacklisted items from appearing in the cleanup candidates list.

### Protected Asset Categories

This mechanism effectively protects:

- **Individual files**: Specific design assets like `logo.png` or `favicon.ico`
- **Directory trees**: Entire folders such as `wysiwyg/legacy/` or `catalog/custom/`
- **Pattern-based groups**: File collections matching `*.pdf` or `landing202*/*`

The controller layer ([`FbimagecleanerController.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/FbimagecleanerController.php)) relies entirely on this helper implementation and does not perform additional blacklist validation, ensuring consistent behavior across all cleanup operations.

## Supported Pattern Syntax

Because the module delegates to PHP's native `fnmatch()` without the `FNM_PATHNAME` flag, administrators can utilize standard shell glob syntax:

- **`*`**: Matches zero or more characters (including directory separators when used with the `*/` prefix)
- **`?`**: Matches exactly one character
- **`[abc]`**: Matches any single character from the specified set
- **`[a-z]`**: Matches any single character within the range
- **`{a,b}`**: Brace expansion (when supported by the underlying system)

Patterns operate on the full relative path from the media root. For example, `catalog/product/cache/*` excludes all cached product images while preserving original uploads.

## Summary

- **Pattern Storage**: Administrators enter newline-separated glob patterns in *Stores → Configuration → Advanced → Image Cleaner*, stored under `admin/fb_image_cleaner/blacklist`.
- **Pattern Retrieval**: The `getBlacklistedPatterns()` method in [`Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/Helper/Data.php) splits the configuration into an array using `preg_split()` to handle multiple newline formats.
- **Matching Logic**: The `isBlacklisted()` method prepends `*/` to each pattern and applies `fnmatch()` to test against full filesystem paths.
- **Scanner Integration**: The recursive scanner calls `isBlacklisted()` for every entry, skipping matches to prevent protected files from being processed for deletion.
- **Syntax Support**: Standard shell glob patterns (`*`, `?`, `[...]`) are fully supported, enabling flexible exclusion rules without regex complexity.

## Frequently Asked Questions

### How do I add multiple blacklist patterns in the OpenMage Image Cleaner?

Enter each pattern on a separate line in the blacklist textarea located at *Stores → Configuration → Advanced → Image Cleaner*. The `getBlacklistedPatterns()` method automatically splits the input using `preg_split('/\r\n|\r|\n/', ...)` to handle Windows, Mac, and Unix line endings, returning an array of individual patterns for processing.

### Why does the module prepend */ to my blacklist patterns?

The `*/` prefix ensures that patterns match regardless of the server's absolute filesystem path preceding the media directory. Since `fnmatch()` performs literal string matching, without this prefix, a pattern like `wysiwyg/*.jpg` would fail to match `/var/www/html/media/wysiwyg/photo.jpg`. The leading wildcard consumes the variable server path components, allowing portable patterns that work across different hosting environments.

### Can I use regular expressions instead of glob patterns for blacklisting?

No, the module exclusively uses `fnmatch()` for pattern matching, which supports shell-style glob syntax only. Regular expressions are not supported in the blacklist configuration. To exclude specific files, use glob patterns such as `catalog/product/banner.jpg` or `wysiwyg/important*/*.png` instead of regex syntax.

### Does the blacklist apply to all cleanup operations in the module?

Yes, the blacklist applies universally to all file scans performed through the `scandirRecursive()` method in [`Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/Helper/Data.php). Since the admin controller relies entirely on this helper method for filesystem enumeration, any path matching a blacklist pattern is excluded from the candidate list before deletion options are presented, ensuring consistent protection across the entire cleanup workflow.