Add Write File Check to detect plugin directory writes#1137
Conversation
…-use-uploads-folder
…-use-uploads-folder
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Co-authored-by: Nilambar Sharma <ernilambar@users.noreply.github.com>
Co-authored-by: Nilambar Sharma <ernilambar@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a new “Write File” check to Plugin Check, implemented as a PHPCS sniff + a corresponding check wrapper, to flag plugins that write generated/user data into the plugin directory (which gets wiped on upgrades).
Changes:
- Introduces a new PHPCS sniff (
WriteFileSniff) to detect common file write/copy/move operations targeting plugin-directory related paths, with allowlisting for uploads/temp paths. - Registers a new
Write_File_Checkin the default check repository and wires the sniff into the PluginCheck PHPCS ruleset. - Adds PHPUnit + sniff unit tests and test plugin fixtures (with and without violations).
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/phpunit/tests/Checker/Checks/Write_File_Check_Tests.php | Adds PHPUnit coverage for the new check wrapper behavior. |
| tests/phpunit/testdata/plugins/test-plugin-write-file-without-errors/load.php | Fixture plugin demonstrating allowed/safe write locations. |
| tests/phpunit/testdata/plugins/test-plugin-write-file-with-errors/load.php | Fixture plugin demonstrating disallowed write locations. |
| tests/phpunit/testdata/plugins/test-plugin-write-file-with-errors/file-operations.php | Additional fixture file to validate multi-file scanning + indirect path cases. |
| phpcs-sniffs/PluginCheck/Tests/CodeAnalysis/WriteFileUnitTest.php | Adds PHPCS sniff unit test harness for WriteFileSniff. |
| phpcs-sniffs/PluginCheck/Tests/CodeAnalysis/WriteFileUnitTest.inc | Provides the test cases (expected errors/ok cases) for the sniff unit test. |
| phpcs-sniffs/PluginCheck/Sniffs/CodeAnalysis/WriteFileSniff.php | Implements the new static-analysis detection logic for plugin-directory write operations. |
| phpcs-sniffs/PluginCheck/ruleset.xml | Enables the new sniff in the PluginCheck PHPCS standard. |
| includes/Checker/Default_Check_Repository.php | Registers the new check in the default check set. |
| includes/Checker/Checks/Plugin_Repo/Write_File_Check.php | Adds the new check wrapper that runs the sniff within Plugin Check. |
| composer.lock | Updates the locked sniffs package version reference to include this new rule. |
Comments suppressed due to low confidence (2)
includes/Checker/Checks/Plugin_Repo/Write_File_Check.php:19
- The class docblock description says this check detects loading files from external sites, but this check actually runs the WriteFile PHPCS sniff to detect writes into the plugin folder. Please update the docblock summary to reflect what the check does.
/**
* Check to detect loading files from external sites.
*
* @since 2.0.0
includes/Checker/Checks/Plugin_Repo/Write_File_Check.php:41
- Several new docblocks use the placeholder "@SInCE n.e.x.t." which is inconsistent with the rest of the codebase where released version numbers are used (e.g., other checks in this directory). Please replace these placeholders with the correct version for when this check will ship, and keep the
@sincetags consistent within the file.
/**
* Bitwise flags to control check behavior.
*
* @since n.e.x.t.
* @var int
*/
protected $flags = 0;
/**
* Gets the categories for the check.
*
* Every check must have at least one category.
*
* @since n.e.x.t.
*
* @return array The categories for the check.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nilambar Sharma <ernilambar@users.noreply.github.com>
…-use-uploads-folder
Fixes #665
Implements a new check to detect when plugins save data in the plugin folder.
Plugin folders are deleted when upgraded, so using them to store any data is problematic. This check helps developers identify these issues and directs them to use the uploads directory or database instead.
Changes Made
1. WriteFileSniff (PHPCS Sniff)
Created
phpcs-sniffs/PluginCheck/Sniffs/CodeAnalysis/WriteFileSniff.php:AbstractFunctionParameterSniffto detect file write functionsfwrite,fputs,file_put_contents,touch,copy,rename,copy_dir,move_dir,unzip_fileWP_PLUGIN_DIR,WP_PLUGIN_URL,PLUGINDIR,WPINC,WP_CONTENT_DIR,WP_CONTENT_URLplugins_url(),plugin_dir_path(),plugin_dir_url()__FILE__,__DIR__wp_upload_dir(),wp_tempnam(),get_temp_dir()2. Write_File_Check Class
Updated
includes/Checker/Checks/Plugin_Repo/Write_File_Check.php:3. Test Coverage
Test Plugins:
test-plugin-write-file-with-errors/: Contains 7 examples of incorrect usagetest-plugin-write-file-without-errors/: Contains examples of correct usagePHPUnit Tests:
Write_File_Check_Tests.php: Tests the check classWriteFileUnitTest.phpandWriteFileUnitTest.inc: Tests the sniff directly4. Configuration
PluginCheck.CodeAnalysis.WriteFilerule tophpcs-sniffs/PluginCheck/ruleset.xmlLimitations
The sniff uses static analysis and can only detect file write operations where the path is directly specified in the function call. It cannot detect:
This limitation is acceptable as it catches the most common cases.
Related Resources
Acknowledgments
This check is based on the
calls_write_file_warningdetection logic from the internal plugin review scanner developed by @frantorres, which has been successfully identifying these issues during manual reviews. This implementation makes that same detection available to plugin developers as an automated check.