Skip to content

MkdirRaceCondition ​

error on by default quick-fix

Group: Probable bugs · PhpStorm name: MkdirRaceConditionInspection

mkdir() fails when the directory already exists — including when another process created it a moment after our own is_dir() check. A failed mkdir() must therefore be followed by an is_dir() re-check before being treated as an error, and its result must not be ignored.

Example ​

php
<?php
function prepare($root, $cfg) {
    @mkdir($root, 0750);
    $made = mkdir("$root/cache");
    mkdir($root . '/tmp') or exit(1);

    if ((false === mkdir($root))) {}
    if ((mkdir("$root/log", 0700, true))) {}
    if ((mkdir(dirname($root)))) {}
    if (file_exists($root) || mkdir($root, permissions: 0700)) {}
    if ($cfg->ok && !mkdir(strtolower($root))) {}

    if (!is_dir($root) && !mkdir($root) && !is_dir($root)) {}
    return mkdir($root);
}
php
<?php
function prepare($root, $cfg) {
    if (!mkdir($root, 0750) && !is_dir($root)) { throw new \RuntimeException(sprintf('Directory "%s" was not created', $root)); }
    $made = mkdir("$root/cache");
    mkdir($root . '/tmp') or exit(1);

    if (!mkdir($root) && !is_dir($root)) {}
    if (mkdir("$root/log", 0700, true) || is_dir("$root/log")) {}
    if (mkdir($concurrentDirectory = dirname($root)) || is_dir($concurrentDirectory)) {}
    if (file_exists($root) || mkdir($root, permissions: 0700) || is_dir($root)) {}
    if ($cfg->ok && !mkdir($concurrentDirectory = strtolower($root)) && !is_dir($concurrentDirectory)) {}

    if (!is_dir($root) && !mkdir($root) && !is_dir($root)) {}
    return mkdir($root);
}

Reported:

  • line 3: mkdir() outcome is ignored; use 'if (!mkdir($root, 0750) && !is_dir(...)) { ... }'.
  • line 7: Re-check with is_dir() after a failed mkdir: '!mkdir($root) && !is_dir(...)'.
  • line 8: Re-check with is_dir() after a failed mkdir: 'mkdir("$root/log", 0700, true) || is_dir(...)'.
  • line 9: Re-check with is_dir() after a failed mkdir: 'mkdir(dirname($root)) || is_dir(...)'.
  • line 10: Re-check with is_dir() after a failed mkdir: 'mkdir($root, permissions: 0700) || is_dir(...)'.
  • line 11: Re-check with is_dir() after a failed mkdir: '!mkdir(strtolower($root)) && !is_dir(...)'.

Configure ​

In custos.json:

json
{
  "rules": {
    "MkdirRaceCondition": {
      "enabled": false
    }
  }
}

Suppress ​

Before the statement or declaration (or the first statement of the file), either of:

php
// @custos-ignore MkdirRaceCondition

/**
 * @noinspection MkdirRaceConditionInspection
 */

Released under the MIT License. Rule catalogue modelled on Php Inspections (EA Extended); independent clean-room implementation.