无法提供名称中带有“&”符号的静态文件

无法提供名称中带有“&”符号的静态文件

我有一个镜像网站wget,我想通过 Apache 来提供服务。问题是我无法访问带有特殊字符的文件。例如,我有带有名称像这样:

$ ls -N components/com_flexicontent/librairies/phpthumb/ | head -4
phpThumb.php?src=%2Fimages%2Fpiekny-wschod%2Ffestiwal-globtroterski-lublin2020-karuzela.jpg&w=290&h=177&aoe=1&q=95
phpThumb.php?src=%2Fimages%2Fdrezyny-rowerowe.jpg&w=90&h=90&aoe=1&q=95
phpThumb.php?src=%2Fimages%2FEko-Karpaty.jpg&w=90&h=90&aoe=1&q=95
phpThumb.php?src=%2Fimages%2FHotel_Anders_SPA.jpg&w=90&h=90&aoe=1&q=95

所以phpThumb.php?src=%2Fimages%2Fpiekny-wschod%2Ffestiwal-globtroterski-lublin2020-karuzela.jpg&w=290&h=177&aoe=1&q=95指的是文件夹中的单个文件。

当我尝试在网络浏览器中读取此文件时,出现“未找到文件”的信息:

https://xxxx/components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/images/piekny-wschod/festiwal-globtroterski-lublin2020-karuzela.jpg&w=290&h=177&aoe=1&q=95

这是我的.htaccess

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]

RewriteCond %{QUERY_STRING} ^src=/images/piekny-wschod/(.*)$
RewriteRule ^components/com_flexicontent/librairies/phpthumb/phpThumb.php?$ components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=%2Fimages%2Fpiekny-wschod%2F%1 [NE,L]
</IfModule>

我已经测试过制定许多不同的规则,它们适用于不带“&”符号的文件名。例如,这个有效:

RewriteRule ^components/com_flexicontent/librairies/phpthumb/phpThumb.php?$ components/com_flexicontent/librairies/select2/select2.css [NC,L]

我已尝试过带有标志的规则NEB但没有效果。

答案1

我猜测网络服务器误解了该&字符作为参数分隔符,或者其他什么东西。

可能需要使用 重新下载网站wget --restrict-file-names=windows,以便让 wget 在文件名中转换&@。或者只是批量重命名文件?

find -name '*&*' | while read name ; do
  newname=$(echo $name | sed -e 's:&:@:g')
  mv "$name" "$newname"
done

答案2

当我尝试在网络浏览器中读取此文件时,出现“未找到文件”的信息:

https://xxxx/components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/images/piekny-wschod/festiwal-globtroterski-lublin2020-karuzela.jpg&w=290&h=177&aoe=1&q=95

如果磁盘上的实际文件名是phpThumb.php?src=%2Fimages%2Fpiekny-wschod%2Ffestiwal-globtroterski-lublin2020-karuzela.jpg&w=290&h=177&aoe=1&q=95,那么不仅是&(&) 导致了问题,而且?还有编码的斜杠%2F- 整个查询字符串。%2F正在被 URL 解码为/... 但文件名包含文字字符%2F(因此需要在请求中进行双重编码)。

如果你请求该 URL,那么 Apache 正在寻找文件 phpThump.php- 大概不存在。

理想情况下,URL 应在初始请求中正确进行 URL(百分比)编码,否则我们将不得不手动对这些字符进行 URL 编码。例如,正确的 URL 应为:

.../phpThumb.php%3Fsrc=%252Fimages%252Fpiekny-wschod%252Ffestiwal-globtroterski-lublin2020-karuzela.jpg%26w=290%26h=177%26aoe=1%26q=95

请注意,由于实际文件包含%2F(编码的/),这些字符需要在请求的 URL 中进行双重 URL 编码,以便它们只能解码为%2F而不是/。虽然这里的复杂之处在于属性中似乎可能有任意数量的编码斜杠src

URL 参数的数量似乎是固定的(即&),因此用一个条件替换这些参数相对简单。

还有一个额外的复杂性,因为这些不是.jpg文件(即没有.jpg文件扩展名),所以 Apache 将不会发送正确的Content-Type标头(由文件扩展名决定)。这需要手动设置。

请尝试以下操作:

# Manually encode all "%2F" in the query string as "%252F", ie. recursively search and replace
#  - This is not confined just to the "src" URL parameter value
#  - Backslash escape literal "%" in RewriteRule substitution string
RewriteCond %{QUERY_STRING} (.*)%2F(.*)
RewriteRule ^(.+/phpThumb\.php)$ $1?%1\%252F%2 [N]

# Manually encode "?" and "&" in the query string (occur at fixed points)
#  - Backslash escape literal "%" in RewriteRule substitution string
RewriteCond %{QUERY_STRING} ^(src=[^&]+)&(w=[^&]+)&(h=[^&]+)&(aoe=[^&]+)&(q=[^&]+)$
RewriteRule ^(.+/phpThumb\.php)$ $1\%3F%1\%26%2\%26%3\%26%4\%26%5 [T=image/jpg,L]

%正如代码注释中所述,RewriteRule 代换字符串需要使用反斜杠转义,以避免被解释为以下形式的反向引用%n(对最后一个匹配的条件模式)。

请注意,这假设所有图像都是 类型image/jpg


另一种方法是“美化”源应用程序中的 URL(在源应用程序中进行 URL 重写)。

例如,如果图像源 URL 的格式如下:

.../phpthumb/290/177/1/95/images/piekny-wschod/festiwal-globtroterski-lublin2020-karuzela.jpg

然后,您可以在源应用程序中使用一些 URL 重写:

RewriteRule ^(.+/phpthumb)/(\d+)/(\d+)/(\d+)/(\d+)/(.+\.jpg)$ $1/phpThumb.php?src=$6&w=$2&h=$3&aoe=$4&q=$5 [L]

然后,您不需要在“镜像”网站中做任何特殊的事情来提供这些图像,并且您将拥有合理的文件名。

相关内容