Search code examples
phppathcanonicalizationrealpath

How to get canonicalized path (realpath) of nonexistent file in PHP?


script.php

$filename = realpath(sprintf("%s/%s", getcwd(), $argv[1]));
var_dump($filename);

Let's try some things

[/foo/bar/bof] $ php script.php ../foo.txt
string(16) "/foo/bar/foo.txt"

[/foo/bar/bof] $ php script.php ../nonexistent.txt
bool(false)

Dammit! realpath is returning false because the file doesn't exist.

What I'd like to see for the ../nonexistent.txt is

string(24) "/foo/bar/nonexistent.txt"

How can I get the canonicalized path for any relative path in PHP?

Note: I saw some questions regarding resolving symlink paths. Answers to these questions are not applicable to my question.


Solution

  • This is the best I could come up with

    function canonicalize_path($path, $cwd=null) {
    
      // don't prefix absolute paths
      if (substr($path, 0, 1) === "/") {
        $filename = $path;
      }
    
      // prefix relative path with $root
      else {
        $root      = is_null($cwd) ? getcwd() : $cwd;
        $filename  = sprintf("%s/%s", $root, $path);
      }
    
      // get realpath of dirname
      $dirname   = dirname($filename);
      $canonical = realpath($dirname);
    
      // trigger error if $dirname is nonexistent
      if ($canonical === false) {
        trigger_error(sprintf("Directory `%s' does not exist", $dirname), E_USER_ERROR);
      }
    
      // prevent double slash "//" below
      if ($canonical === "/") $canonical = null;
    
      // return canonicalized path
      return sprintf("%s/%s", $canonical, basename($filename));
    }
    

    It requires that all directories in the path exist. The basename of the path is the only part that can be nonexistent.

    An error will be thrown in the event that the dirname doesn't exist.