touch() creates a file or sets its times, copy() duplicates, rename() moves and overwrites the target, and unlink() deletes. Within one file system rename() is atomic, so readers see the old file or the new one, never half. Replace a cache or config file by writing a tempnam() file (unique, mode 0600) beside it and renaming it over.
<?php
declare(strict_types=1);
touch($csv = __DIR__ . '/prices.csv');
copy($csv, "$csv.bak");
$tmp = tempnam(__DIR__, 'prices-'); // same directory, so same file system
file_put_contents($tmp, "sku,price\nBK-101,9.99\n");
printf("%s %o\n", basename($tmp), fileperms($tmp) & 0777);
rename($tmp, $csv); // atomic swap over the old file
echo file_get_contents($csv);
var_dump(unlink("$csv.bak"), unlink("$csv.old"));Output
prices-rdvphp9nupeo8T4oJJO 600 sku,price BK-101,9.99 PHP Warning: unlink(/home/dev/shop/prices.csv.old): No such file or directory in /home/dev/shop/main.php on line 10 bool(true) bool(false)
Across file systems, rename() falls back to copy-and-delete, which is not atomic. Test return values rather than silencing warnings with @. tmpfile() opens a file deleted on close, and deleting needs write permission on the directory (Permission Bits).