diff --git a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php index dae227f5520..c7fa19acd0c 100644 --- a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php @@ -3,13 +3,13 @@ namespace Psalm\Internal\Provider; use Psalm\Config; +use Psalm\Internal\Provider\Providers; use Psalm\Storage\ClassLikeStorage; use UnexpectedValueException; use function array_merge; use function dirname; use function file_exists; -use function file_get_contents; use function file_put_contents; use function filemtime; use function get_class; @@ -25,6 +25,7 @@ use function unserialize; use const DIRECTORY_SEPARATOR; +use const LOCK_EX; use const PHP_VERSION_ID; /** @@ -86,9 +87,9 @@ public function writeToCache(ClassLikeStorage $storage, string $file_path, strin $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true); if ($this->config->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($storage)); + file_put_contents($cache_location, igbinary_serialize($storage), LOCK_EX); } else { - file_put_contents($cache_location, serialize($storage)); + file_put_contents($cache_location, serialize($storage), LOCK_EX); } } @@ -132,7 +133,7 @@ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path) if (file_exists($cache_location)) { if ($this->config->use_igbinary) { - $storage = igbinary_unserialize((string)file_get_contents($cache_location)); + $storage = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); if ($storage instanceof ClassLikeStorage) { return $storage; @@ -141,7 +142,7 @@ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path) return null; } - $storage = unserialize((string)file_get_contents($cache_location)); + $storage = unserialize(Providers::safeFileGetContents($cache_location)); if ($storage instanceof ClassLikeStorage) { return $storage; diff --git a/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php b/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php index 616a1c2c4e0..e512aacf29b 100644 --- a/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php +++ b/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php @@ -4,10 +4,10 @@ use Psalm\Config; use Psalm\Internal\Codebase\Analyzer; +use Psalm\Internal\Provider\Providers; use UnexpectedValueException; use function file_exists; -use function file_get_contents; use function file_put_contents; use function igbinary_serialize; use function igbinary_unserialize; @@ -18,6 +18,7 @@ use function unserialize; use const DIRECTORY_SEPARATOR; +use const LOCK_EX; /** * @psalm-import-type FileMapType from Analyzer @@ -84,9 +85,9 @@ public function getCachedFileReferences(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -114,9 +115,9 @@ public function getCachedClassLikeFiles(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -144,9 +145,9 @@ public function getCachedNonMethodClassReferences(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -174,9 +175,9 @@ public function getCachedMethodClassReferences(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -203,7 +204,7 @@ public function getCachedMethodMemberReferences(): ?array return null; } - $class_member_reference_cache = (string) file_get_contents($class_member_cache_location); + $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); if ($this->config->use_igbinary) { $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); } else { @@ -235,7 +236,7 @@ public function getCachedMethodDependencies(): ?array return null; } - $method_dependencies_cache = (string) file_get_contents($method_dependencies_cache_location); + $method_dependencies_cache = Providers::safeFileGetContents($method_dependencies_cache_location); if ($this->config->use_igbinary) { $method_dependencies_cache = igbinary_unserialize($method_dependencies_cache); } else { @@ -266,7 +267,7 @@ public function getCachedMethodPropertyReferences(): ?array return null; } - $class_member_reference_cache = (string) file_get_contents($class_member_cache_location); + $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); if ($this->config->use_igbinary) { $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); } else { @@ -297,7 +298,7 @@ public function getCachedMethodMethodReturnReferences(): ?array return null; } - $class_member_reference_cache = (string) file_get_contents($class_member_cache_location); + $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); if ($this->config->use_igbinary) { $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); } else { @@ -328,7 +329,7 @@ public function getCachedMethodMissingMemberReferences(): ?array return null; } - $class_member_reference_cache = (string) file_get_contents($class_member_cache_location); + $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); if ($this->config->use_igbinary) { $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); } else { @@ -359,7 +360,7 @@ public function getCachedFileMemberReferences(): ?array return null; } - $file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location); + $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); if ($this->config->use_igbinary) { $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); } else { @@ -392,7 +393,7 @@ public function getCachedFilePropertyReferences(): ?array return null; } - $file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location); + $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); if ($this->config->use_igbinary) { $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); } else { @@ -425,7 +426,7 @@ public function getCachedFileMethodReturnReferences(): ?array return null; } - $file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location); + $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); if ($this->config->use_igbinary) { $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); } else { @@ -457,7 +458,7 @@ public function getCachedFileMissingMemberReferences(): ?array return null; } - $file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location); + $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); if ($this->config->use_igbinary) { $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); } else { @@ -489,9 +490,9 @@ public function getCachedMixedMemberNameReferences(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -519,9 +520,9 @@ public function getCachedMethodParamUses(): ?array } if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); } else { - $reference_cache = unserialize((string) file_get_contents($reference_cache_location)); + $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); } if (!is_array($reference_cache)) { @@ -549,9 +550,9 @@ public function getCachedIssues(): ?array } if ($this->config->use_igbinary) { - $issues_cache = igbinary_unserialize((string) file_get_contents($issues_cache_location)); + $issues_cache = igbinary_unserialize(Providers::safeFileGetContents($issues_cache_location)); } else { - $issues_cache = unserialize((string) file_get_contents($issues_cache_location)); + $issues_cache = unserialize(Providers::safeFileGetContents($issues_cache_location)); } if (!is_array($issues_cache)) { @@ -572,9 +573,9 @@ public function setCachedFileReferences(array $file_references): void $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_references)); + file_put_contents($reference_cache_location, igbinary_serialize($file_references), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($file_references)); + file_put_contents($reference_cache_location, serialize($file_references), LOCK_EX); } } @@ -589,9 +590,9 @@ public function setCachedClassLikeFiles(array $file_references): void $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_references)); + file_put_contents($reference_cache_location, igbinary_serialize($file_references), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($file_references)); + file_put_contents($reference_cache_location, serialize($file_references), LOCK_EX); } } @@ -606,9 +607,9 @@ public function setCachedNonMethodClassReferences(array $file_class_references): $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_class_references)); + file_put_contents($reference_cache_location, igbinary_serialize($file_class_references), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($file_class_references)); + file_put_contents($reference_cache_location, serialize($file_class_references), LOCK_EX); } } @@ -623,9 +624,9 @@ public function setCachedMethodClassReferences(array $method_class_references): $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($method_class_references)); + file_put_contents($reference_cache_location, igbinary_serialize($method_class_references), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($method_class_references)); + file_put_contents($reference_cache_location, serialize($method_class_references), LOCK_EX); } } @@ -640,9 +641,9 @@ public function setCachedMethodMemberReferences(array $member_references): void $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references)); + file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($member_references)); + file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); } } @@ -657,9 +658,9 @@ public function setCachedMethodDependencies(array $member_references): void $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_DEPENDENCIES_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references)); + file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($member_references)); + file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); } } @@ -674,9 +675,9 @@ public function setCachedMethodPropertyReferences(array $property_references): v $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_PROPERTY_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($property_references)); + file_put_contents($member_cache_location, igbinary_serialize($property_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($property_references)); + file_put_contents($member_cache_location, serialize($property_references), LOCK_EX); } } @@ -691,9 +692,9 @@ public function setCachedMethodMethodReturnReferences(array $method_return_refer $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_RETURN_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($method_return_references)); + file_put_contents($member_cache_location, igbinary_serialize($method_return_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($method_return_references)); + file_put_contents($member_cache_location, serialize($method_return_references), LOCK_EX); } } @@ -708,9 +709,9 @@ public function setCachedMethodMissingMemberReferences(array $member_references) $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references)); + file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($member_references)); + file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); } } @@ -725,9 +726,9 @@ public function setCachedFileMemberReferences(array $member_references): void $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references)); + file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($member_references)); + file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); } } @@ -742,9 +743,9 @@ public function setCachedFilePropertyReferences(array $property_references): voi $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_PROPERTY_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($property_references)); + file_put_contents($member_cache_location, igbinary_serialize($property_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($property_references)); + file_put_contents($member_cache_location, serialize($property_references), LOCK_EX); } } @@ -759,9 +760,9 @@ public function setCachedFileMethodReturnReferences(array $method_return_referen $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_METHOD_RETURN_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($method_return_references)); + file_put_contents($member_cache_location, igbinary_serialize($method_return_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($method_return_references)); + file_put_contents($member_cache_location, serialize($method_return_references), LOCK_EX); } } @@ -776,9 +777,9 @@ public function setCachedFileMissingMemberReferences(array $member_references): $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references)); + file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); } else { - file_put_contents($member_cache_location, serialize($member_references)); + file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); } } @@ -793,9 +794,9 @@ public function setCachedMixedMemberNameReferences(array $references): void $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($references)); + file_put_contents($reference_cache_location, igbinary_serialize($references), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($references)); + file_put_contents($reference_cache_location, serialize($references), LOCK_EX); } } @@ -810,9 +811,9 @@ public function setCachedMethodParamUses(array $uses): void $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($uses)); + file_put_contents($reference_cache_location, igbinary_serialize($uses), LOCK_EX); } else { - file_put_contents($reference_cache_location, serialize($uses)); + file_put_contents($reference_cache_location, serialize($uses), LOCK_EX); } } @@ -827,9 +828,9 @@ public function setCachedIssues(array $issues): void $issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($issues_cache_location, igbinary_serialize($issues)); + file_put_contents($issues_cache_location, igbinary_serialize($issues), LOCK_EX); } else { - file_put_contents($issues_cache_location, serialize($issues)); + file_put_contents($issues_cache_location, serialize($issues), LOCK_EX); } } @@ -847,10 +848,10 @@ public function getAnalyzedMethodCache() ) { if ($this->config->use_igbinary) { /** @var array> */ - return igbinary_unserialize(file_get_contents($analyzed_methods_cache_location)); + return igbinary_unserialize(Providers::safeFileGetContents($analyzed_methods_cache_location)); } else { /** @var array> */ - return unserialize(file_get_contents($analyzed_methods_cache_location)); + return unserialize(Providers::safeFileGetContents($analyzed_methods_cache_location)); } } @@ -870,9 +871,9 @@ public function setAnalyzedMethodCache(array $analyzed_methods): void . self::ANALYZED_METHODS_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($analyzed_methods_cache_location, igbinary_serialize($analyzed_methods)); + file_put_contents($analyzed_methods_cache_location, igbinary_serialize($analyzed_methods), LOCK_EX); } else { - file_put_contents($analyzed_methods_cache_location, serialize($analyzed_methods)); + file_put_contents($analyzed_methods_cache_location, serialize($analyzed_methods), LOCK_EX); } } } @@ -893,12 +894,12 @@ public function getFileMapCache() /** * @var array */ - $file_maps_cache = igbinary_unserialize(file_get_contents($file_maps_cache_location)); + $file_maps_cache = igbinary_unserialize(Providers::safeFileGetContents($file_maps_cache_location)); } else { /** * @var array */ - $file_maps_cache = unserialize(file_get_contents($file_maps_cache_location)); + $file_maps_cache = unserialize(Providers::safeFileGetContents($file_maps_cache_location)); } return $file_maps_cache; @@ -918,9 +919,9 @@ public function setFileMapCache(array $file_maps): void $file_maps_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MAPS_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($file_maps_cache_location, igbinary_serialize($file_maps)); + file_put_contents($file_maps_cache_location, igbinary_serialize($file_maps), LOCK_EX); } else { - file_put_contents($file_maps_cache_location, serialize($file_maps)); + file_put_contents($file_maps_cache_location, serialize($file_maps), LOCK_EX); } } } @@ -939,10 +940,10 @@ public function getTypeCoverage() ) { if ($this->config->use_igbinary) { /** @var array */ - $type_coverage_cache = igbinary_unserialize(file_get_contents($type_coverage_cache_location)); + $type_coverage_cache = igbinary_unserialize(Providers::safeFileGetContents($type_coverage_cache_location)); } else { /** @var array */ - $type_coverage_cache = unserialize(file_get_contents($type_coverage_cache_location)); + $type_coverage_cache = unserialize(Providers::safeFileGetContents($type_coverage_cache_location)); } return $type_coverage_cache; @@ -962,9 +963,9 @@ public function setTypeCoverage(array $mixed_counts): void $type_coverage_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::TYPE_COVERAGE_CACHE_NAME; if ($this->config->use_igbinary) { - file_put_contents($type_coverage_cache_location, igbinary_serialize($mixed_counts)); + file_put_contents($type_coverage_cache_location, igbinary_serialize($mixed_counts), LOCK_EX); } else { - file_put_contents($type_coverage_cache_location, serialize($mixed_counts)); + file_put_contents($type_coverage_cache_location, serialize($mixed_counts), LOCK_EX); } } } @@ -981,7 +982,7 @@ public function getConfigHashCache() if ($cache_directory && file_exists($config_hash_cache_location) ) { - return file_get_contents($config_hash_cache_location); + return Providers::safeFileGetContents($config_hash_cache_location); } return false; @@ -1000,7 +1001,8 @@ public function setConfigHashCache(string $hash): void file_put_contents( $config_hash_cache_location, - $hash + $hash, + LOCK_EX ); } } diff --git a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php index d52b4165acf..2f9279f12ae 100644 --- a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php @@ -3,13 +3,13 @@ namespace Psalm\Internal\Provider; use Psalm\Config; +use Psalm\Internal\Provider\Providers; use Psalm\Storage\FileStorage; use UnexpectedValueException; use function array_merge; use function dirname; use function file_exists; -use function file_get_contents; use function file_put_contents; use function filemtime; use function get_class; @@ -24,6 +24,7 @@ use function unserialize; use const DIRECTORY_SEPARATOR; +use const LOCK_EX; use const PHP_VERSION_ID; /** @@ -79,9 +80,9 @@ public function writeToCache(FileStorage $storage, string $file_contents): void $storage->hash = $this->getCacheHash($file_path, $file_contents); if ($this->config->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($storage)); + file_put_contents($cache_location, igbinary_serialize($storage), LOCK_EX); } else { - file_put_contents($cache_location, serialize($storage)); + file_put_contents($cache_location, serialize($storage), LOCK_EX); } } @@ -135,7 +136,7 @@ private function loadFromCache(string $file_path): ?FileStorage if (file_exists($cache_location)) { if ($this->config->use_igbinary) { - $storage = igbinary_unserialize((string)file_get_contents($cache_location)); + $storage = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); if ($storage instanceof FileStorage) { return $storage; @@ -144,7 +145,7 @@ private function loadFromCache(string $file_path): ?FileStorage return null; } - $storage = unserialize((string)file_get_contents($cache_location)); + $storage = unserialize(Providers::safeFileGetContents($cache_location)); if ($storage instanceof FileStorage) { return $storage; diff --git a/src/Psalm/Internal/Provider/ParserCacheProvider.php b/src/Psalm/Internal/Provider/ParserCacheProvider.php index a8f053f09b8..c1c30c27b76 100644 --- a/src/Psalm/Internal/Provider/ParserCacheProvider.php +++ b/src/Psalm/Internal/Provider/ParserCacheProvider.php @@ -5,18 +5,13 @@ use PhpParser; use PhpParser\Node\Stmt; use Psalm\Config; +use Psalm\Internal\Provider\Providers; use RuntimeException; use function clearstatcache; use function error_log; -use function fclose; -use function file_get_contents; use function file_put_contents; use function filemtime; -use function filesize; -use function flock; -use function fopen; -use function fread; use function gettype; use function igbinary_serialize; use function igbinary_unserialize; @@ -33,11 +28,9 @@ use function touch; use function unlink; use function unserialize; -use function usleep; use const DIRECTORY_SEPARATOR; use const LOCK_EX; -use const LOCK_SH; use const SCANDIR_SORT_NONE; /** @@ -108,10 +101,10 @@ public function loadStatementsFromCache( ) { if ($this->use_igbinary) { /** @var list */ - $stmts = igbinary_unserialize((string)file_get_contents($cache_location)); + $stmts = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); } else { /** @var list */ - $stmts = unserialize((string)file_get_contents($cache_location)); + $stmts = unserialize(Providers::safeFileGetContents($cache_location)); } return $stmts; @@ -142,11 +135,11 @@ public function loadExistingStatementsFromCache(string $file_path): ?array if (is_readable($cache_location)) { if ($this->use_igbinary) { /** @var list */ - return igbinary_unserialize((string)file_get_contents($cache_location)) ?: null; + return igbinary_unserialize(Providers::safeFileGetContents($cache_location)) ?: null; } /** @var list */ - return unserialize((string)file_get_contents($cache_location)) ?: null; + return unserialize(Providers::safeFileGetContents($cache_location)) ?: null; } return null; @@ -173,7 +166,7 @@ public function loadExistingFileContentsFromCache(string $file_path): ?string $cache_location = $parser_cache_directory . DIRECTORY_SEPARATOR . $file_cache_key; if (is_readable($cache_location)) { - return file_get_contents($cache_location); + return Providers::safeFileGetContents($cache_location); } return null; @@ -191,29 +184,7 @@ private function getExistingFileContentHashes(): array $file_hashes_path = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_HASHES; if ($root_cache_directory && is_readable($file_hashes_path)) { - $fp = fopen($file_hashes_path, 'r'); - $max_wait_cycles = 5; - $has_lock = false; - while ($max_wait_cycles > 0) { - if (flock($fp, LOCK_SH)) { - $has_lock = true; - break; - } - $max_wait_cycles--; - usleep(50000); - } - - if (!$has_lock) { - fclose($fp); - error_log('Could not acquire lock for content hashes file'); - $this->existing_file_content_hashes = []; - - return []; - } - - $hashes_encoded = fread($fp, filesize($file_hashes_path)); - fclose($fp); - + $hashes_encoded = Providers::safeFileGetContents($file_hashes_path); if (!$hashes_encoded) { error_log('Unexpected value when loading from file content hashes'); $this->existing_file_content_hashes = []; @@ -269,9 +240,9 @@ public function saveStatementsToCache( $this->createCacheDirectory($parser_cache_directory); if ($this->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($stmts)); + file_put_contents($cache_location, igbinary_serialize($stmts), LOCK_EX); } else { - file_put_contents($cache_location, serialize($stmts)); + file_put_contents($cache_location, serialize($stmts), LOCK_EX); } $this->new_file_content_hashes[$file_cache_key] = $file_content_hash; @@ -343,7 +314,7 @@ public function cacheFileContents(string $file_path, string $file_contents): voi $this->createCacheDirectory($parser_cache_directory); - file_put_contents($cache_location, $file_contents); + file_put_contents($cache_location, $file_contents, LOCK_EX); } public function deleteOldParserCaches(float $time_before): int diff --git a/src/Psalm/Internal/Provider/Providers.php b/src/Psalm/Internal/Provider/Providers.php index d42e1004342..8d246b2d1f9 100644 --- a/src/Psalm/Internal/Provider/Providers.php +++ b/src/Psalm/Internal/Provider/Providers.php @@ -2,6 +2,17 @@ namespace Psalm\Internal\Provider; +use RuntimeException; + +use function fclose; +use function filesize; +use function flock; +use function fopen; +use function fread; +use function usleep; + +use const LOCK_SH; + /** * @internal */ @@ -63,4 +74,38 @@ public function __construct( ); $this->file_reference_provider = new FileReferenceProvider($file_reference_cache_provider); } + + public static function safeFileGetContents(string $path): string + { + // no readable validation as that must be done in the caller + $fp = fopen($path, 'r'); + if ($fp === false) { + return ''; + } + $max_wait_cycles = 5; + $has_lock = false; + while ($max_wait_cycles > 0) { + if (flock($fp, LOCK_SH)) { + $has_lock = true; + break; + } + $max_wait_cycles--; + usleep(50000); + } + + if (!$has_lock) { + fclose($fp); + throw new RuntimeException('Could not acquire lock for ' . $path); + } + + $file_size = filesize($path); + $content = ''; + if ( $file_size > 0 ) { + $content = (string) fread($fp, $file_size); + } + + fclose($fp); + + return $content; + } }