is_valid_rs_path()

Description

Check if a given file path is from a valid RS accessible location

Parameters

ColumnTypeDefaultDescription
$path string
$override_paths array []: bool { debug_function_call__FUNCTION__ Override checking of the default RS paths to check a specific location only.
func_get_args;

Location

include/file_functions.php lines 345 to 429

Definition

 
function is_valid_rs_path(string $path, array $override_paths = []): bool
{
    
debug_function_call(__FUNCTION__func_get_args());
    if (
$GLOBALS["config_windows"]) {
        
$path str_replace("\\""/"$path);
    }

    
$sourcerealpath realpath($path);
    
$source_path_not_real = !$sourcerealpath || !file_exists($sourcerealpath);
    
debug('source_path_not_real = ' json_encode($source_path_not_real));

    
$checkname  $path;
    
$pathinfo pathinfo($path);
    if ((
$pathinfo["extension"] ?? "") === "icc") {
        
// ResourceSpace generated .icc files have a double extension, need to strip extension again before checking
        
$checkname $pathinfo["filename"] ?? "";
    }
    
debug("checkname = {$checkname}");

    if (
        
$source_path_not_real
        
&& !(preg_match('/^(?!\.)(?!.*\.$)(?!.*\.\.)[a-zA-Z0-9_\-[:space:]\/:.]+$/', ($pathinfo['dirname'] ?? ""))
            && 
is_safe_basename($checkname))
    ) {
        
debug('Invalid non-existing path');
        return 
false;
    }

    
// Check if path contains symlinks, if so don't use the value returned by realpath() as it is unlikely to match the expected paths
    
$symlink false;
    
$path_parts array_filter(explode("/"$path));

    if (
$GLOBALS["config_windows"]) {
        
$checkpath "";
    } else {
        
$checkpath "/";
    }

    foreach (
$path_parts as $path_part) {
        
$checkpath .=  $path_part "/";
        if (
is_link($checkpath) || ($GLOBALS["config_windows"] && stat($checkpath) != lstat($checkpath))) {
            
// is_link() returns false for junction links on Windows so check if stat and lstat return identical info
            
debug("{$checkpath} is a symlink");
            
$symlink true;
            break;
        }
    }
    
$path_to_validate = ($source_path_not_real || $symlink) ? $path $sourcerealpath;
    
debug("path_to_validate = {$path_to_validate}");

    if (
count($override_paths) > 0) {
        
$default_paths $override_paths;
    } else {
        
$default_paths = [
            
dirname(__DIR__) . '/gfx',
            
$GLOBALS['storagedir'],
            
$GLOBALS['syncdir'],
            
$GLOBALS['fstemplate_alt_storagedir'],
        ];
        if (isset(
$GLOBALS['tempdir'])) {
            
$default_paths[] = $GLOBALS['tempdir'];
        }
    }
    
$allowed_paths array_filter(array_map('trim'array_unique($default_paths)));
    
debug('allowed_paths = ' implode(', '$allowed_paths));

    foreach (
$allowed_paths as $allowed_path) {
        
debug("Iter allowed path - {$allowed_path}");
        
$validpath = ($source_path_not_real || $symlink) ? $allowed_path realpath($allowed_path);
        if (
$GLOBALS["config_windows"]) {
            
$allowed_path str_replace("\\""/"$allowed_path);
            
$validpath str_replace("\\""/"$validpath);
            
$path_to_validate str_replace("\\""/"$path_to_validate);
        }
        
debug("validpath = {$validpath}");
        
debug("path_to_validate = {$path_to_validate}");
        if (
$validpath !== false && mb_strpos($path_to_validate$validpath) === 0) {
            
debug('Path allowed');
            return 
true;
        }
    }

    
debug('Default as an invalid path');
    return 
false;
}

This article was last updated 23rd June 2025 18:35 Europe/London time based on the source file dated 23rd May 2025 17:15 Europe/London time.