10

After my script finishes I can delete the file, but while it's running I can't touch it, even after an fclose(). Here is the code I'm trying to use:

    $Files = glob("$_SERVER[DOCUMENT_ROOT]/files/*.csv");

    $File = fopen($Files[0], "r");        

    //while (($Data = fgetcsv($File)) !== false) {...

    $i = 0;
    while (is_resource($File)) {
        $i && sleep(1);
        echo "Closing handle.\n";
        fclose($File);
        if (++$i > 5)
            die("Could not close handle.");
    }

foreach ($Files as $File) {
    $i = 0;
    while (file_exists($File)) {
        $i && sleep(1);
        echo "Deleting file.\n";
        @unlink($File);
        echo 'www-data@debian:~$ ', $Command = "rm -f '$File' 2>&1", "\n", shell_exec($Command);
        if (++$i > 5)
            die("Could not delete the file.");
    }
}

As you can see I'm trying to delete it through unlink() and using shell commands and neither are working, both give me this error:

rm: cannot remove 'invincible-file.csv': Text file busy

I also realize the script might be a bit overkill, but that's purely because I couldn't get it to work in any way, and some of the extra code is just for output purposes to try and debug what is happening.

Brian Leishman
  • 6,574
  • 7
  • 47
  • 82
  • 4
    What is the content of `$Files`? Also, you use `fopen` with the "r" mode for reading and you are trying to delete the file later. Are you sure that the user has permission to delete? Maybe it's a permission issue. Try doing the `unlink` without any of the other code. – Cave Johnson Dec 20 '16 at 21:45
  • 2
    Remove the `@` before the `unlink` so you can let php tell you why it failed. Also, check the return value of `fclose`. – chiliNUT Dec 20 '16 at 21:48
  • @KodosJohnson Thanks for helping me so far, I'm going to try your `unlink` without the `fopen` at all, and I've added even more code to the example, hopefully I'm not missing any more important parts – Brian Leishman Dec 20 '16 at 21:49
  • @chiliNUT I've already done that, I get my xdebug output that gives the same error – Brian Leishman Dec 20 '16 at 21:49
  • @KodosJohnson If I remove the `fopen`, etc. it deletes all of the files without any issues. It's only once I open and close the file withing the PHP script that I can no longer delete it – Brian Leishman Dec 20 '16 at 21:52
  • What is the underlying filesystem on which `invincible-file.csv` resides? – bishop Dec 20 '16 at 21:54
  • @bishop underlying is NTFS, it's on the host machine that this web server is running from (a Debian Virtual Box, folder shared through the Virtual Box shared folders) – Brian Leishman Dec 20 '16 at 21:55
  • Did you try chiliNUT's suggestion of checking the return value of `fclose`? It should be true. – Cave Johnson Dec 20 '16 at 21:55
  • @KodosJohnson no I didn't get that far, I tried the answer out and it fixed the problem I was having – Brian Leishman Dec 20 '16 at 21:57

1 Answers1

7

I've run into this issue before and been able to remedy by forcing garbage collection after closing the file and before unlinking it:

gc_collect_cycles();

By far not the best solution, but it did resolve an issue I had deleting files that had been previously opened and closed lines before.

Bryant Jackson
  • 1,175
  • 1
  • 10
  • 31
  • Wow that worked, no where else could I find this function to run after `fclose()` but that worked without a hiccup, thank you for that – Brian Leishman Dec 20 '16 at 21:56
  • do you think that additionally that clearing the cache (`clearstatcache`) would assist with this sort of overrun issue? – Martin Dec 20 '16 at 22:00
  • @BrianLeishman Would you please try `fflush` before the `fclose`, without the `gc_collect_cycles` hack? – bishop Dec 20 '16 at 22:21
  • 1
    The problem also happens with files created with touch, the same solution worked for it too. I used to touch a file as a mutex to prevent same script from overlapping if run more than once at the same time. I wasn't able to unlink at the end of the script. – Mohyaddin Alaoddin Dec 07 '17 at 11:49