Replace PHP's Realpath()

Replace PHP's realpath()

Thanks to Sven Arduwie's code (pointed out by Pekka) and some modification, I've built a (hopefully) better implementation:

/**
* This function is to replace PHP's extremely buggy realpath().
* @param string The original path, can be relative etc.
* @return string The resolved path, it might not exist.
*/
function truepath($path){
// whether $path is unix or not
$unipath=strlen($path)==0 || $path{0}!='/';
// attempts to detect if path is relative in which case, add cwd
if(strpos($path,':')===false && $unipath)
$path=getcwd().DIRECTORY_SEPARATOR.$path;
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part) continue;
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
$path=implode(DIRECTORY_SEPARATOR, $absolutes);
// resolve any symlinks
if(file_exists($path) && linkinfo($path)>0)$path=readlink($path);
// put initial separator that could have been lost
$path=!$unipath ? '/'.$path : $path;
return $path;
}

NB: Unlike PHP's realpath, this function does not return false on error; it returns a path which is as far as it could to resolving these quirks.

Note 2: Apparently some people can't read properly. Truepath() does not work on network resources including UNC and URLs. It works for the local file system only.

Laravel | Change realPath value of file()

This should do the trick, it assumes your <input with file is named file:

public function store(UploadRequest $request)
{
if ($request->hasFile('file')) { // depends on your FormRequest validation if `file` field is required or not
$path = $request->file->storePublicly(public_path('/uploads'));
}

Project::create(array_merge($request->except('file'), ['file' => $path])); // do some array manipulation

return $request->all();
}

And this for uploading multiple files:

public function store(UploadRequest $request)
{
foreach ($request->file() as $key => $file) {
if ($request->hasFile($key)) {
$path = $request->$key->storePublicly('/uploads');
}
$keys[] = $key;
$paths[] = $path;
}
$data = $request->except($keys);
$data = array_merge($data, array_combine($keys, $paths));

Project::create($data);

return back()->with('success', 'Project has been created successfully.');
}

Sanitize file path in PHP without realpath()

Not sure why you wouldn't want to use realpath but path name sanitisation is a very simple concept, along the following lines:

  • If the path is relative (does not start with /), prefix it with the current working directory and /, making it an absolute path.
  • Replace all sequences of more than one / with a single one (a).
  • Replace all occurrences of /./ with /.
  • Remove /. if at the end.
  • Replace /anything/../ with /.
  • Remove /anything/.. if at the end.

The text anything in this case means the longest sequence of characters that aren't /.

Note that those rules should be applied continuously until such time as none of them result in a change. In other words, do all six (one pass). If the string changed, then go back and do all six again (another pass). Keep doing that until the string is the same as before the pass just executed.

Once those steps are done, you have a canonical path name that can be checked for a valid pattern. Most likely that will be anything that doesn't start with ../ (in other words, it doesn't try to move above the starting point. There may be other rules you want to apply but that's outside the scope of this question.


(a) If you're working on a system that treats // at the start of a path as special, make sure you replace multiple / characters at the start with two of them. This is the only place where POSIX allows (but does not mandate) special handling for multiples, in all other cases, multiple / characters are equivalent to a single one.

Replacing php realpth when outputing to users

I would use configuration variables $privatePath and $publicPath.

So you can concat whichever you want to the relative paths to your directories or files.

For your example:

$privatePath = '/mnt/wef66/d2/81/557642661/htdocs/';
$publicPath = 'www.example.com/';

$pic1RelativePath = 'useruploads/myfiles/imagefolder/mosaic_1.jpg';

$pic1privatePath = $privatePath . $pic1RelativePath;
// /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg

$pic1publicPath = $publicPath . $pic1RelativePath;
// www.example.com/useruploads/myfiles/imagefolder/mosaic_1.jpg

I think this is easier and more efficient than replacing the paths with regex.

EDIT:

If you have all the real paths in an array, you can loop through it and replace easily all the private paths with the public paths this way:

$paths = [
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg',
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/room_home_1.jpg',
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder'
];

foreach ($paths as &$path) {
$path = str_replace($privatePath, $publicPath, $path);
}

print_r($paths);

Changing Base Path In PHP

The function chdir() does this.
For example:

echo ('BEFORE = '.realpath('.')); // BEFORE = C:\ABC\XYZ\123\ZZZ
chdir('C:/Some/Other/Folder');
echo ('AFTER = '.realpath('.')); // AFTER = C:\Some\Other\Folder

PHP realpath on Windows Case Issue

Turns out

do {
$to = realpath($to);
} while (realpath($to) !== false && $to !== realpath($to));

is the only way.

https://bugs.php.net/bug.php?id=61933



Related Topics



Leave a reply



Submit