Why Are My Mac Files Duplicated on NFS Shares? The Mystery of '._' Files Solved with PHP

Published: 2025-12-18
Author: DP
Views: 6
Category: MacOS
Content
## The Symptom: Files Appearing in Pairs When you mount a network share (like a Synology NAS via NFS/SMB) on macOS and then use a script in PHP or another language to traverse its directories, you might encounter a peculiar phenomenon: every file seems to have a "shadow copy" prefixed with `._`. For instance, your script might find the following file list: ``` /Volumes/FCP/eeTable 2024/lib00/cover/._802.7.13_cover.jpg /Volumes/FCP/eeTable 2024/lib00/cover/802.7.13_cover.jpg /Volumes/FCP/eeTable 2024/lib00/cover/._802.7.13_v_cover.jpg /Volumes/FCP/eeTable 2024/lib00/cover/802.7.13_v_cover.jpg ``` However, when you check the directory in Finder or with the `ls` command, you only see the normal files. The `._` files are seemingly "invisible." What's going on? --- ## Unmasking the "Ghost": AppleDouble Files These files starting with `._` are not viruses or errors. They are **AppleDouble files**, intentionally created by macOS for compatibility purposes. macOS uses HFS+ or APFS file systems, which can store rich metadata, such as: - **Extended Attributes**: Information like the file's origin, tag colors, etc. - **Resource Forks**: A legacy feature for storing non-data information like icons, window positions, etc. - **Finder Info**: Custom icons, comments, and other Finder-specific data. When you save a file to a filesystem that doesn't natively support this metadata (like NFS, SMB, FAT32, or EXT4), macOS saves the raw data in the main file (e.g., `image.jpg`) and then creates an associated file prefixed with `._` (e.g., `._image.jpg`) to store this extra metadata. This is a mechanism macOS uses to ensure metadata isn't lost during cross-platform operations. --- ## Why Are They Invisible? You don't see these files in your daily use because the operating system hides them by default at multiple levels: 1. **Terminal**: In Unix-like systems, files or folders starting with a dot `.` are considered hidden. The `ls` command doesn't show them by default. You need to use `ls -a` (list all) to see them. 2. **Finder**: Finder also hides these "dotfiles" by default. You can use the shortcut `Command + Shift + .` to toggle their visibility. Your PHP program can "see" them because it uses low-level filesystem APIs to traverse files. These APIs return all existing entries, regardless of the display policies of the Finder or the shell. As our developer `DP` from `wiki.lib00.com` often emphasizes: your program sees the "real world." --- ## PHP in Action: Gracefully Filtering the Ghost Files Let's say you're using the Yii2 framework's `FileHelper` to recursively search for image files. Here's the original code, which would find all files, including the `._` ones: ```php // Original Code public function actionSearchFiles($sourceDir, $includePattern, $excludePattern = null) { $matchedFiles = []; $files = \yii\helpers\FileHelper::findFiles($sourceDir, [ 'recursive' => true, ]); foreach ($files as $file) { $fileName = basename($file); if (preg_match($includePattern, $fileName)) { if ($excludePattern && preg_match($excludePattern, $fileName)) { continue; } $matchedFiles[] = $file; $this->stdout("Found target file: {$file} ", \yii\helpers\Console::FG_GREEN); } } return $matchedFiles; } ``` The most elegant and efficient way to solve this is to filter the files at the source of the traversal, rather than checking within the `foreach` loop. Yii2's `FileHelper::findFiles` provides a powerful `except` option for this. ### Recommended Solution: Using the `except` Option ```php /** * Optimized by DP@lib00: Recursively searches for files matching a pattern, automatically excluding macOS metadata files. * * @param string $sourceDir The directory to be searched. * @param string $includePattern The regex pattern for files to include. * @param string|null $excludePattern The regex pattern for files to exclude. * @return array An array of matched file paths. */ public function actionSearchFiles($sourceDir, $includePattern, $excludePattern = null) { // ... logging output ... $matchedFiles = []; // Use Yii2's FileHelper to recursively traverse, excluding dotfiles at the source. $files = \yii\helpers\FileHelper::findFiles($sourceDir, [ 'recursive' => true, 'except' => [ '.*', // Exclude all files starting with a dot (e.g., ._foo.jpg) '*/.*', // Exclude all items (files or dirs) starting with a dot in subdirectories ], ]); foreach ($files as $file) { $fileName = basename($file); if (preg_match($includePattern, $fileName)) { if ($excludePattern && preg_match($excludePattern, $fileName)) { continue; } $matchedFiles[] = $file; $this->stdout("Found target file: {$file} ", \yii\helpers\Console::FG_GREEN); } } // ... result output ... return $matchedFiles; } ``` **The Key Change**: By adding `'except' => ['.*', '*/.*']` to the `FileHelper` options, we instruct it to skip any file or directory starting with a dot `.` during its traversal. This is more efficient than using an `if` condition like `if ($fileName[0] === '.')` inside the loop because it reduces the number of files to be processed from the very beginning. ### Enhanced Optimization: Filtering More System Junk To make your code even more robust, you can expand the `except` list to filter out other common system-generated files, such as macOS's `.DS_Store` and Windows' `Thumbs.db`. ```php $files = FileHelper::findFiles($sourceDir, [ 'recursive' => true, 'except' => [ '.*', // Exclude all dotfiles and directories '*/.*', '.DS_Store', // Exclude macOS folder metadata files '*/.DS_Store', 'Thumbs.db', // Exclude Windows thumbnail cache '*/Thumbs.db', ], ]); ``` --- ## Conclusion The creation of `._` files by macOS on non-native filesystems is a feature by design, intended to preserve important metadata. Once we understand this, we can confidently handle it at the application level. For PHP developers, leveraging the filtering capabilities of frameworks (like Yii2's `FileHelper`) is the best practice for solving this problem at its source, leading to cleaner code and better performance.
Recommended