keepcalculator

06 Numbers and Powers

Let PHP Delete Nginx FastCGI Cache Files Safely

Card No. 06·4791 · Updated · Standard formula, shown below

This guide shows you how to let a PHP script delete specific Nginx FastCGI cache files without compromising security or breaking your site. You’ll learn the exact configuration steps for Nginx, the PHP script logic, and the safety checks that prevent accidental deletion of unrelated files.

What You’ll Need

  • Root or sudo access to your server (to edit Nginx and PHP-FPM configuration files).
  • Nginx with FastCGI caching already configured and working.
  • PHP-FPM running on the same server (or a socket that PHP can access).
  • Basic familiarity with the command line and editing files via SSH.

Step-by-Step

  1. Identify your cache directory and key format. In your Nginx configuration, find the line that sets fastcgi_cache_path. For example: fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=MYCACHE:100m inactive=60m;. Note the path (/var/run/nginx-cache) and the levels (1:2). Also note the fastcgi_cache_key directive; it defines how the cache key is built (e.g., $scheme$request_method$host$request_uri).
  2. Understand how Nginx maps keys to file paths. Nginx hashes the cache key with MD5, then splits the hash into directories according to the levels setting. For levels=1:2, the first character of the MD5 hash becomes a subdirectory, and the next two characters become a second-level subdirectory. The remaining characters are the filename. Example: hash abc123... becomes /var/run/nginx-cache/a/bc/abc123....
  3. Create a PHP script to delete a cache entry. The script must compute the MD5 hash of the exact cache key string that Nginx uses, then construct the file path and delete it only if it exists and is within the cache directory. Here’s a robust example:
    <?php
    function delete_nginx_cache($cache_key, $cache_path, $levels) {
        $hash = md5($cache_key);
        $dir = $cache_path;
        $offset = 0;
        // Build directory structure based on levels, e.g., 1:2
        foreach (explode(':', $levels) as $level) {
            $dir .= '/' . substr($hash, $offset, (int)$level);
            $offset += (int)$level;
        }
        $file = $dir . '/' . $hash;
        // Safety: ensure the resolved path is still inside the cache directory
        $real_base = realpath($cache_path);
        $real_file = realpath($file);
        if ($real_file === false || strpos($real_file, $real_base) !== 0) {
            return false;
        }
        if (is_file($real_file)) {
            return unlink($real_file);
        }
        return false;
    }
    
    // Example usage:
    $cache_key = 'GET' . 'https' . 'example.com' . '/page';
    // Note: adjust the key to exactly match your fastcgi_cache_key directive.
    delete_nginx_cache($cache_key, '/var/run/nginx-cache', '1:2');
    ?>
  4. Match the cache key exactly. The most common mistake is mismatching the key. Look at your fastcgi_cache_key directive. If it is $scheme$request_method$host$request_uri, then for a request to https://example.com/page with GET method, the key is GEThttpsexample.com/page (no separators). Use the same concatenation in PHP. If your key includes variables like $http_accept_encoding, you must replicate that as well.
  5. Set proper permissions for PHP-FPM. PHP-FPM runs as a specific user (e.g., www-data). That user must have read and write (delete) permissions on the cache directory. You can either change the owner of the cache directory to that user, or add the user to a group that owns the directory. For example: chown -R www-data:www-data /var/run/nginx-cache. But be careful: if Nginx also runs as www-data, this is fine. If not, adjust accordingly.
  6. Test with a known cache file. Create a test cache entry by visiting a page on your site, then find its corresponding file using the hash. You can compute the MD5 hash of the key in PHP or with command-line tools. Then run your PHP script and verify the file is gone.
  7. Integrate into your application. Call the PHP function whenever you update content that should invalidate its cached version (e.g., after saving a post). Make sure to construct the correct cache key for the URL that was updated.
  8. Consider using the fastcgi_cache_purge directive (if available). Nginx Plus and some open-source builds support the fastcgi_cache_purge directive, which allows you to purge cache entries via a special request (e.g., PURGE method). This is often simpler and safer, but it requires that your Nginx build includes the purge module. Check with nginx -V 2>&1 | grep purge. If available, you can configure a location block that handles PURGE requests and calls fastcgi_cache_purge.

Common Mistakes

  • Incorrect cache key construction. The most common error. If the key doesn’t match exactly, the hash will be different, and the script will try to delete a non-existent file.
  • Forgetting the levels structure. If your cache path uses levels=1:2, you must replicate that in the PHP path builder. Using a flat path will fail.
  • Not checking realpath. Without the realpath check, a malicious or accidental input could cause the script to delete files outside the cache directory (e.g., if the cache key contains path traversal sequences).
  • Permission errors. PHP-FPM may not have permission to delete files in the cache directory, especially if Nginx created them with a different user.
  • Deleting while Nginx is writing. If you delete a file while Nginx is writing to it, you might leave a partial file. However, Nginx handles this gracefully by ignoring incomplete files, so it’s usually safe.

Tips

  • Use a helper function. Centralize the cache deletion logic in a single PHP function or class so you can reuse it across your codebase.
  • Log deletions. For debugging, log when you delete a cache file to a file or syslog. Include the cache key and the resulting file path.
  • Cache key normalization. Ensure your cache key is normalized (e.g., lowercase host, remove trailing slashes) to avoid duplicate cache entries and mismatched deletions.
  • Batch deletion. If you need to purge multiple URLs, loop through them, but be mindful of performance. Each deletion is a filesystem operation.
  • Consider a cache tag system. For complex sites, implementing cache tags (e.g., using a header like X-Cache-Tags) and a background script to purge by tag can be more efficient than purging individual URLs.

Troubleshooting

  • File not deleted. Check the cache key by logging the computed hash and comparing it to the actual file in the cache directory. Also verify the file permissions and that the path is correct.
  • Permission denied. Run ls -l on the cache directory to see the owner and permissions. Adjust the PHP-FPM user or group accordingly. You may need to set chmod -R 775 and add the PHP user to the group that owns the directory.
  • Cache still served after deletion. If you delete the file but the page still shows old content, it might be cached by the browser or by an upstream proxy. Also, Nginx might have a separate cache zone (e.g., for microcache) that you didn’t clear.
  • PHP script works manually but not in web context. The web server user might have different permissions than your CLI user. Test with the same user that PHP-FPM uses.
  • Nginx configuration changes not taking effect. After changing the cache key or path, remember to reload Nginx: sudo nginx -s reload.

Frequently Asked Questions

Can I delete the entire cache directory with PHP?

Yes, but it’s not recommended. You can use exec('rm -rf /path/to/cache/*') but that’s risky and slow. Instead, use a loop with unlink and rmdir to clear it safely. Or better, use Nginx’s inactive parameter to let old entries expire naturally.

How do I find the cache key for a specific URL?

You can replicate the Nginx key construction in PHP. For example, if your key is $scheme$request_method$host$request_uri, then for a GET request to https://example.com/page, the key is GEThttpsexample.com/page. You can also add a temporary header to your Nginx config to log the key: add_header X-Cache-Key $fastcgi_cache_key; and then view the response headers.

Is it safe to delete a cache file while Nginx is reading it?

Yes, on Linux/Unix, deleting a file that is being read is safe. Nginx will continue to serve the content from the open file descriptor until it finishes, and subsequent requests will miss the cache and regenerate it.

What if I have multiple cache zones?

You need to handle each zone separately. The PHP script must know which zone (and its path and levels) to target. You can pass the zone name as a parameter to your function.

Can I use the PURGE method with open-source Nginx?

Only if your Nginx build includes the ngx_cache_purge module. Many distribution packages do not include it. You can check by running nginx -V 2>&1 | grep purge. If it’s not there, you’ll need to compile Nginx with the module or use the PHP method described above.

How do I prevent PHP from deleting files outside the cache directory?

Always use realpath() on both the base cache path and the constructed file path, and ensure the file path starts with the base path. Also, sanitize the cache key to avoid any path traversal characters like ../.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →