URL 包含 “&” 符号会导致 DirectoryIterator 不工作。

huangapple go评论72阅读模式
英文:

URL contains "&" don't work with DirectoryIterator

问题

I understand that you want a translation of the code part. Here it is:

$selectedDir = isset($_GET["dir"]) ? $_GET["dir"] : "";
echo '<h1> '.$selectedDir.' </h1>';
$dirs = "\\\\server\images\\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="'.'.\Intraimages\VD_images/'.$selectedDir.'/'.$fileinfo.'">'; ?>
       <?php echo '<img src="'.'.\Intraimages\VD_images/'.$selectedDir.'/'.$fileinfo.'" /> </a>'; ?>
         
         <?php 
    }
}

Please note that I've left the code as-is, including any potential issues with "&" in folder names, as your problem was already solved in the subsequent code comments.

英文:

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:

&lt;?php 

$selectedDir = isset($_GET[&quot;dir&quot;]) ? $_GET[&quot;dir&quot;] : &quot;&quot;;
//echo $selectedDir;
echo &#39;&lt;h1&gt; &#39;.$selectedDir.&#39; &lt;/h1&gt;&#39;;
$dirs = &quot;\\\\server\images\\moreimages/$selectedDir&quot;;


$dir = new DirectoryIterator($dirs);
foreach ($dir as $fileinfo) {
    if ($fileinfo-&gt;isDir() &amp;&amp; !$fileinfo-&gt;isDot()) {
        $directorypath = $selectedDir.&quot;/&quot;.$fileinfo-&gt;getFilename();
        echo &quot;&lt;a href=&#39;?dir=&quot;.$directorypath.&quot;&#39;&gt;&quot;.$fileinfo-&gt;getFilename().&quot;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&quot;;
        
    }
        elseif (stripos($fileinfo, &#39;.jpg&#39;) !== false || stripos($fileinfo, &#39;.png&#39;) !== false) {

        
        ?&gt;
        &lt;?php  echo &#39;&lt;a target=&quot;_blank&quot; href=&quot;&#39;.&quot;\Intraimages\VD_images/$selectedDir/&quot;.$fileinfo.&#39;&quot;/&gt;&#39;; ?&gt;
       &lt;?php echo &#39;&lt;img src=&quot;&#39;.&quot;\Intraimages\VD_images/$selectedDir/&quot;.$fileinfo.&#39;&quot;/&gt; &lt;/a&gt;&#39;; ?&gt;
         
         &lt;?php 
    
    }

}

?&gt;

(For clarification the different paths if it's any help:
"\\server\images\moreimages/" is the UNC path.
"\Intraimages\VD_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(\server\images\moreimages//35000-35999/35144 MAN T): The system cannot find the file specifi (code: 2) in C:\inetpub\wwwroot\Intraimages\index.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 = "&amp;"

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(&quot;&amp;&quot;,&quot;%26&quot;,$selectedDir); but the URL and $selectedDir don't contain "&" since it stops right before "&" so I guess there's nothing to replace...?

SOLVED, this is my new code thanks to the all the help:

if ($fileinfo-&gt;isDir() &amp;&amp; !$fileinfo-&gt;isDot()) {
        $directorypath = http_build_query(array($selectedDir.&quot;/&quot;.$fileinfo-&gt;getFilename()));
        $url = parse_url($directorypath);
        $newurl = str_replace(&#39;0=&#39;,&#39;&#39;,$url[&#39;path&#39;]);
        echo &quot;&lt;a href=&#39;?dir=&quot;.$newurl.&quot;&#39;&gt;&quot;.$fileinfo-&gt;getFilename().&quot;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&quot;;        
    }

NOTE: that this my not be the best solution since i'm using str_replace() but it just proves that it works with http_build_query

For those who are interested, the new URL is now:
.../?dir=%2F35000-35999%2F35144+MAN+T%26B+T2-L62

答案1

得分: 1

需要您首先理解这里发生了什么,否则很容易错过。

它从这里开始:

$_GET["dir"]

该数组成员的内容不是您想象的那样。您会发现从字符串中删除的任何内容都是从第一个和包括第一个“&”开始的。

如果您查看$_GET的所有数组键,您会注意到在“dir”条目之后,下一个键是您想要使用的路径名的继续部分。

这是因为PHP解析传入的请求URL的方式,具体来说是查询信息部分。这是URL末尾以第一个问号开头的部分。

?dir=why&amp;why-not?

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

因此,这基本上是缺少URL编码,正如您可以想象的那样,PHP具有这个功能。

因此,当您构建要点击的URL时,比如为_dir_参数的目录路径,要正确编码路径名的值。

您的脚本需要使用相同的语言,否则事情可能会出现意外。这也是为什么很容易被忽视的原因。

构建URL的查询(使用http_build_query)以获得适当的href属性值。

并且出于调试目的,

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

将显示$selectedDir的HTML,然后使用htmlspecialchars

这两个建议应该很好地说明了数据是如何在您的PHP脚本和浏览器之间以及再次在您的PHP脚本中处理的。

示例脚本

<?php
/*
 * index.php - http_build_query()和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&amp;why-not?">A</a>
  </li>

  <li>
      <a href="<?= http_build_query(array('dir' => 'why&amp;why-not?')) ?>">B</a>
  </li>

</ul>

<hr>

<pre><?=

    htmlspecialchars(var_export($_GET, true))

?></pre>

如果您的计算机上有PHP,可以将此文件保存到其中一个目录中(创建一个新目录),然后打开cmd.exe并切换到该目录,运行PHP开发服务器:

php -S 127.0.0.1:8080

它会显示一个HTTP URL,您可以使用它来运行示例。然后,您将看到浏览器如何与您的PHP脚本在终端中交互:

[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&amp;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

您可以通过按ctrl + c来停止PHP开发web服务器。

英文:

It requires you to first understand what is happening here, as otherwise it is easy to miss.

It starts here:

$_GET[&quot;dir&quot;]

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&amp;why-not?

array (
  &#39;dir&#39; =&gt; &#39;why&#39;,
  &#39;why-not?&#39; =&gt; &#39;&#39;,
)

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 &#39;&lt;h1&gt; &#39;.$selectedDir.&#39; &lt;/h1&gt;&#39;;

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

&lt;?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
 */
?&gt;

&lt;ul&gt;

  &lt;li&gt;
      &lt;a href=&quot;?dir=why&amp;why-not?&quot;&gt;A&lt;/a&gt;

  &lt;li&gt;
      &lt;a href=&quot;?&lt;?= http_build_query(array(&#39;dir&#39; =&gt; &#39;why&amp;why-not?&#39;)) ?&gt;&quot;&gt;B&lt;/a&gt;

&lt;/ul&gt;

&lt;hr&gt;

&lt;pre&gt;&lt;?=

    htmlspecialchars(var_export($_GET, true))

?&gt;&lt;/pre&gt;

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&amp;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 <kbd>ctrl</kbd> + <kbd>c</kbd>.

答案2

得分: 0

以下是翻译好的部分:

与上面的单个DirectoryIterator不同,以下示例使用递归迭代器来说明如果正确转义反斜杠字符,则&不需要成为UNC路径的问题。

在本地网络共享上有一些测试文件夹,其中包含带有&字符的文件和子文件夹...


$depth=5;
$path='\\\\buffalo-1\\share\\temp\\test folder';
$selectedDir='files & folders';

function isDot( $dir=true ){
    return basename( $dir )=='.' or basename( $dir )=='..';
}

# 其中$selectedDir模拟您的GET请求变量。
$dir=sprintf( '%s\\%s', $path, $selectedDir );
printf(
    '
    <h1>
    搜索的根目录:%s<br />
    选择的目录:%s<br />
    工作路径:%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('目录:%s<br />', $info->getPathName() );
    elseif( $info->isFile() ) printf('文件:%s<br />', $info->getFileName() );    
}
?>

上述示例的示例输出:

<h1>
    搜索的根目录:\\buffalo-1\share\temp\test folder<br />
    选择的目录:files & folders<br />
    工作路径:\\buffalo-1\share\temp\test folder\files & folders<br /><br />
</h1>
目录:\\buffalo-1\share\temp\test folder\files & folders\hot & cold<br />
目录:\\buffalo-1\share\temp\test folder\files & folders\sweet & sour<br />
目录:\\buffalo-1\share\temp\test folder\files & folders\up & down<br />
文件:left & right.txt<br />

`&`字符不会妨碍文件和文件夹的扫描或遍历。是否建议在路径中使用这些字符是另一回事。

<details>
<summary>英文:</summary>

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...

    &lt;?php

    	$depth=5;
    	$path=&#39;\\\\buffalo-1\\share\\temp\\test folder&#39;;
    	$selectedDir=&#39;files &amp; folders&#39;;
    	
    	function isDot( $dir=true ){
    		return basename( $dir )==&#39;.&#39; or basename( $dir )==&#39;..&#39;;
    	}

    	# where $selectedDir emulates your GET request variable.
    	$dir=sprintf( &#39;%s\\%s&#39;, $path, $selectedDir );
    	printf(
    		&#39;
    		&lt;h1&gt;
    		Root directory for searches: %s&lt;br /&gt;
    		Selected Directory: %s&lt;br /&gt;
    		Working path: %s&lt;br /&gt;&lt;br /&gt;
    		&lt;/h1&gt;&#39;,
    		$path,
    		$selectedDir,
    		$dir
    	);
    	
    	$dirItr=new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::KEY_AS_PATHNAME );
    	$recItr=new RecursiveIteratorIterator( $dirItr, RecursiveIteratorIterator::CHILD_FIRST );
    	$recItr-&gt;setMaxDepth( $depth );
    	
    	foreach( $recItr as $obj =&gt; $info ) {
    		if( $info-&gt;isDir() &amp;&amp; !isDot( $info-&gt;getPathname() ) ) printf(&#39;directory:%s&lt;br /&gt;&#39;, $info-&gt;getPathName() );
    		elseif( $info-&gt;isFile() ) printf(&#39;File:%s&lt;br /&gt;&#39;, $info-&gt;getFileName() );	
    	}
    ?&gt;

Example output from the above:

	&lt;h1&gt;
		Root directory for searches: \\buffalo-1\share\temp\test folder&lt;br /&gt;
		Selected Directory: files &amp; folders&lt;br /&gt;
		Working path: \\buffalo-1\share\temp\test folder\files &amp; folders&lt;br /&gt;&lt;br /&gt;
	&lt;/h1&gt;
	directory:\\buffalo-1\share\temp\test folder\files &amp; folders\hot &amp; cold&lt;br /&gt;
	directory:\\buffalo-1\share\temp\test folder\files &amp; folders\sweet &amp; sour&lt;br /&gt;
	directory:\\buffalo-1\share\temp\test folder\files &amp; folders\up &amp; down&lt;br /&gt;
	File:left &amp; right.txt&lt;br /&gt;

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.

</details>



huangapple
  • 本文由 发表于 2023年6月29日 15:23:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76578861.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定