PHP can't unlink file after fclose
Asked Answered
D

1

11

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.

Dermatosis answered 20/12, 2016 at 21:37 Comment(9)
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.Malignity
Remove the @ before the unlink so you can let php tell you why it failed. Also, check the return value of fclose.Jesus
@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 partsDermatosis
@Jesus I've already done that, I get my xdebug output that gives the same errorDermatosis
@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 itDermatosis
What is the underlying filesystem on which invincible-file.csv resides?Squarely
@Squarely 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)Dermatosis
Did you try chiliNUT's suggestion of checking the return value of fclose? It should be true.Malignity
@KodosJohnson no I didn't get that far, I tried the answer out and it fixed the problem I was havingDermatosis
F
8

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.

Fletcher answered 20/12, 2016 at 21:51 Comment(4)
Wow that worked, no where else could I find this function to run after fclose() but that worked without a hiccup, thank you for thatDermatosis
do you think that additionally that clearing the cache (clearstatcache) would assist with this sort of overrun issue?Brain
@BrianLeishman Would you please try fflush before the fclose, without the gc_collect_cycles hack?Squarely
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.Hippogriff

© 2022 - 2024 — McMap. All rights reserved.