skip to Main Content

I’m trying to view images in different network folders. Everything works but as soon there’s a folder have "&" in its name, I can’t view the content. The URL stops after "&" so it can’t find the folder in question.

I’ve looked at other questions similar to this problem but none of them worked (where also many could use strreplace() for a single URL which in my case don’t work when I have hundreds of folders)

Running on Windows Server 2022 with IIS.

My code:

<?php 

$selectedDir = isset($_GET["dir"]) ? $_GET["dir"] : "";
//echo $selectedDir;
echo '<h1> '.$selectedDir.' </h1>';
$dirs = "\\serverimages\moreimages/$selectedDir";


$dir = new DirectoryIterator($dirs);
foreach ($dir as $fileinfo) {
    if ($fileinfo->isDir() && !$fileinfo->isDot()) {
        $directorypath = $selectedDir."/".$fileinfo->getFilename();
        echo "<a href='?dir=".$directorypath."'>".$fileinfo->getFilename()."</a><br><br>";
        
    }
        elseif (stripos($fileinfo, '.jpg') !== false || stripos($fileinfo, '.png') !== false) {

        
        ?>
        <?php  echo '<a target="_blank" href="'."IntraimagesVD_images/$selectedDir/".$fileinfo.'"/>'; ?>
       <?php echo '<img src="'."IntraimagesVD_images/$selectedDir/".$fileinfo.'"/> </a>'; ?>
         
         <?php 
    
    }

}

?>

(For clarification the different paths if it’s any help:
"\serverimagesmoreimages/" is the UNC path.
"IntraimagesVD_images/" is the Virtual Directory path in IIS.)

I will try to provide as much info as I can in advance.

The folder name is: 35144 MAN T&B T2-L62

PHP_errors log:

PHP Fatal error: Uncaught UnexpectedValueException: DirectoryIterator::__construct(serverimagesmoreimages//35000-35999/35144 MAN T): The system cannot find the file specifi (code: 2) in C:inetpubwwwrootIntraimagesindex.php:38

Tried var_dump $selectedDir which says:
string(28) "%2F35000-35999%2F35144+MAN+T"

URL in my web browser says: …/?dir=/35000-35999/35144 MAN T&B T2-L62

HTTP Error

What I’ve tried

urlencode the $selectedDir

Change some settings in php.ini to %26:

arg_separator.output = "&"

arg_separator.input = ";&"

Do I need to insert "%26" in the URL instead of "&"? If so, I have no idea how.

EDIT

I tried with:
str_replace("&","%26",$selectedDir); but the URL and $selectedDir don’t contain "&" since it stops right before "&" so I guess there’s nothing to replace…?

2

Answers


  1. Rather than the single DirectoryIterator as above the following uses recursive iterators to illustrate that ampersands need not be an issue in UNC paths if proper escaping of backslash characters is observed.

    Given some test folders on a local network share that have files and sub-folders where the names contain the ampersand…

    <?php
    
        $depth=5;
        $path='\\buffalo-1\share\temp\test folder';
        $selectedDir='files & folders';
        
        function isDot( $dir=true ){
            return basename( $dir )=='.' or basename( $dir )=='..';
        }
    
        # where $selectedDir emulates your GET request variable.
        $dir=sprintf( '%s\%s', $path, $selectedDir );
        printf(
            '
            <h1>
            Root directory for searches: %s<br />
            Selected Directory: %s<br />
            Working path: %s<br /><br />
            </h1>',
            $path,
            $selectedDir,
            $dir
        );
        
        $dirItr=new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::KEY_AS_PATHNAME );
        $recItr=new RecursiveIteratorIterator( $dirItr, RecursiveIteratorIterator::CHILD_FIRST );
        $recItr->setMaxDepth( $depth );
        
        foreach( $recItr as $obj => $info ) {
            if( $info->isDir() && !isDot( $info->getPathname() ) ) printf('directory:%s<br />', $info->getPathName() );
            elseif( $info->isFile() ) printf('File:%s<br />', $info->getFileName() );   
        }
    ?>
    

    Example output from the above:

    <h1>
        Root directory for searches: \buffalo-1sharetemptest folder<br />
        Selected Directory: files & folders<br />
        Working path: \buffalo-1sharetemptest folderfiles & folders<br /><br />
    </h1>
    directory:\buffalo-1sharetemptest folderfiles & foldershot & cold<br />
    directory:\buffalo-1sharetemptest folderfiles & folderssweet & sour<br />
    directory:\buffalo-1sharetemptest folderfiles & foldersup & down<br />
    File:left & right.txt<br />
    

    The ampsersand characters do not hinder the scanning of nor traversal of files and folders. Whether the practise of using said characters in paths is advisable or not is another matter.

    Login or Signup to reply.
  2. It requires you to first understand what is happening here, as otherwise it is easy to miss.

    It starts here:

    $_GET["dir"]
    

    The contents of that array member is not what you think. You will find anything removed from the string starting with (and including) the first ampersand (&).

    If you then look into all the array keys of $_GET, you will notice that after the "dir" entry the next key is the continuation of the pathname you’d like to use.

    This is because of how PHP parses the incoming request URL, specifically the query-info part. That is the part at the end of a URL starting with the first question mark.

    ?dir=why&why-not?
    
    array (
      'dir' => 'why',
      'why-not?' => '',
    )
    

    So this is basically missing URL encoding, and as you can imagine, PHP has that.

    So when you build the URL to be clicked, like having the pathname of the directory for the dir parameter, encode the pathname value properly.

    Your script needs to speak the same language, otherwise things may end up unexpected. This is also why it is easy to miss.

    Build the query of the URL (http_build_query) to have a proper href attribute value.

    And for debugging purposes

    echo '<h1> '.$selectedDir.' </h1>';
    

    will display you the HTML of $selectedDir, use htmlspecialchars then.

    Both suggestions should be a good example how the data is processed between your PHP scripts and the Browser and back in your PHP scripts.

    Example Script

    <?php
    /*
     * index.php - example of http_build_query() and htmlspecialchars()
     *
     * @link https://www.php.net/manual/en/function.http-build-query.php
     * @link https://www.php.net/manual/en/function.htmlspecialchars.php
     * @link https://stackoverflow.com/a/76579728/367456
     */
    ?>
    
    <ul>
    
      <li>
          <a href="?dir=why&why-not?">A</a>
    
      <li>
          <a href="?<?= http_build_query(array('dir' => 'why&why-not?')) ?>">B</a>
    
    </ul>
    
    <hr>
    
    <pre><?=
    
        htmlspecialchars(var_export($_GET, true))
    
    ?></pre>
    
    

    If you have PHP on your own computer, you can save this file into one of your directories (create a new one), then open cmd.exe and change into that directory and run the PHP development server:

    php -S 127.0.0.1:8080
    

    It will display you a http URL you can use to run the example. You will then see how the browser interacts with your PHP script in the terminal:

    [Thu Jun 29 11:44:50 2023] PHP 8.2.7 Development Server (http://127.0.0.1:8080) started
    [Thu Jun 29 11:44:55 2023] 127.0.0.1:42426 Accepted
    [Thu Jun 29 11:44:55 2023] 127.0.0.1:42426 [200]: GET /
    [Thu Jun 29 11:44:55 2023] 127.0.0.1:42426 Closing
    [Thu Jun 29 11:44:58 2023] 127.0.0.1:42440 Accepted
    [Thu Jun 29 11:44:58 2023] 127.0.0.1:42440 [200]: GET /?dir=why&why-not?
    [Thu Jun 29 11:44:58 2023] 127.0.0.1:42440 Closing
    [Thu Jun 29 11:45:00 2023] 127.0.0.1:49138 Accepted
    [Thu Jun 29 11:45:00 2023] 127.0.0.1:49138 [200]: GET /?dir=dir%3Dwhy%26why-not%3F
    [Thu Jun 29 11:45:00 2023] 127.0.0.1:49138 Closing
    

    You stop the PHP development webserver by pressing ctrl + c.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search