Are rename() and unlink() asynchronous fun

2019-07-18 15:39发布

问题:

I have strong reason to believe that both functions rename() and unlink() are asynchronous, which, from my understanding, means that when the functions are called, the code below them are continued before it finishes its procedures on the filesystem. This is a problem for the internet app I'll explain below, because later code depends on these changes to already be set in stone. So, is there a way to make both synchronous, so that the code reader freezes when it hits these functions, until all of its tasks are fully carried out on the filesystem?

Here is the code in delete-image.php, which is called by ajax from another admin-images.php(the latter will not be shown):

`

    foreach ($dirScan as $key => $value) {
        $fileParts = explode('.', $dirScan[$key]);
        if (isset($fileParts[1])) {
            if ((!($fileParts[1] == "gif") && !($fileParts[1] == "jpg")) && (!($fileParts[1] == "png") && !($fileParts[1] == "jpg"))) {
                unset($dirScan[$key]);
            }
        } else {
            unset($dirScan[$key]);
        }
    }
    $dirScan = array_values($dirScan);

    // for thumbnail
    $file = 'galleries/' . $currentGal . '/' . $currentDir . "/" . $dirScan[$imageNum - 1];
    unlink($file);      
    for ($i = ($imageNum - 1) + 1; $i < count($dirScan); $i++) {
        $thisFile = 'galleries/' . $currentGal . '/' . $currentDir . '/' . $dirScan[$i];
        $thisSplitFileName = explode('.', $dirScan[$i]);
        $newName = 'galleries/' . $currentGal . '/' . $currentDir . "/" . ($thisSplitFileName[0] - 1)  . "." . $thisSplitFileName[1];
        rename($thisFile, $newName);
    }

    // for large image
    $fileParts = explode('.', $dirScan[$imageNum - 1]);
    $file = 'galleries/' . $currentGal . '/' . $currentDir . "/large/" . $fileParts[0] . "Large." . $fileParts[1];
    unlink($file);
    for ($i = ($imageNum - 1) + 1; $i < count($dirScan); $i++) {
        $thisSplitFileName = explode('.', $dirScan[$i]);
        $thisFile = 'galleries/' . $currentGal . '/' . $currentDir . '/large/' . $thisSplitFileName[0] . "Large." . $thisSplitFileName[1];
        $newName = 'galleries/' . $currentGal . '/' . $currentDir . "/large/" . ($thisSplitFileName[0] - 1)  . "Large." . $thisSplitFileName[1];
        rename($thisFile, $newName);
    }

    sleep(1);
    echo 'deleted ' . $dirScan[$imageNum - 1] . " successfully!";

} else {
    echo "please set the post data";
} ?>`

After this script returns its completed text, admin-images.php triggers a new function which populates an image table from these renamed and trimmed files. Sometimes it displays old names and files that were suppose to be deleted, and a simple page refresh gets rid of them. This seems to suggest that the above php script is running through all the code and spitting out echoed text to the mainfile before it completes its file-system manipulation (All of this other code is long and complicated, and hopefully unnecessary for the discussion at hand).

You'll notice, I've tried a sleep() function to halt the php script to hopefully give it time to finish. This is an ineligent, and problematic way of doing things, because I have to put a large amount of time to insure it works every-time, but I don't want the user to wait longer than she / he has to.

回答1:

I suppose they are not asynchronous, because they return a result telling if the operation was successful or not.

I believe the problem happens because when you run scandir after making the modifications, it may be using "cached" data, from memory, instead of re-scanning the file system.



回答2:

Mind that file-systems often use caches to reduce the load. Normally you won't notice, but sometimes you need to clear the cache if you need to have the real information. Check the configuration of your file-system if your issue is file-system related.

PHP itself uses a cache as well for some file-operations, so clear that, too.

See clearstatcache to clear the PHP stat cache.

Take note that this is a "view" issue, the file is actually deleted on disk, but PHP might still return it's there (until you clear the cache).



回答3:

rename() is not, but unlink() is asynchronous on Windows.

Because there seems to be no way of waiting for a pending delete to finish, this answer suggests to rename a file before deleting it. PHP does not seem to do that, so you can assume it's asynchronous.



回答4:

To use any file operation you are required to use the $_SERVER["DOCUMENT_ROOT"] to make that work. In case you wont do it.. the real operation wont work properly. Also in case you are using the Linux Server then you will be required to set the permissions for the folders in which you want to perform the file operation.

And mind it both the operations are synchronous they are not asynchronous. It also depends on the type of the server or the OS that you are using.