如何preg_matchcontent-disposition中的所有三种情况header?

How to preg_match all three cases in the content-disposition header?

我正在尝试解码 content-disposition header(来自 curl)以使用以下正则表达式获取文件名:

<?php
$str = 'attachment;filename="unnamed.jpg";filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])([^"\']+)/m', $str, $matches);

print_r($matches);

因此,如果文件名在单引号或双引号中它会匹配,但如果文件名周围没有引号(这可能会发生),它就会失败

$str = 'attachment;filename=unnamed.jpg;filename*=unnamed.jpg';

现在我正在使用两个正则表达式(if-else),但我只是想了解是否可以在一个正则表达式中执行?仅供自己学习掌握正则表达式。

一种方法是在单个正则表达式中使用交替来匹配 single/double 带引号的文件名或完全不带引号的文件名。请注意,这种方法的一个副作用是我们在正则表达式中引入了更多的捕获组。所以我们需要一些额外的逻辑来处理这个。

<?php
    $str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
    $result = preg_match('/^.*?filename=(?:(?:(["\'])([^"\']+))|([^"\';]+))/m',
        $str, $matches);
    print_r($matches);
    $index = count($matches) == 3 ? 2 : 3;
    if ($result) {
        echo $matches[$index];
    }
    else {
        echo "filename not found";
    }
?>

Demo

您可以将捕获组设置为可选 (["\'])??,例如: 并在非捕获组中的正则表达式末尾添加一个分号或字符串结尾,该组检查是否存在 ; 或行尾 (?:;|$)

^.*?filename=(["\'])?([^"\']+)?(?:;|$)

$str = 'attachment;filename=unnamed.jpg;filename*=UTF-8\'\'unnamed.jpg\'';
preg_match('/^.*?filename=(["\'])?([^"\']+)?(?:;|$)/m', $str, $matches);
print_r($matches);

Output php

也可以使用\K重新设置上报匹配的起始点,然后匹配直到遇到双引号或分号[^";]+。这只会 return 文件名。

^.*?filename="?\K[^";]+

foreach ($strings as $string) {
    preg_match('/^.*?filename="?\K[^";]+/m', $string, $matches);
    print_r($matches);
}

Output php

我将使用 branch reset 功能 (?|...|...|...) 提供更易读的模式并避免为引号创建捕获组。在分支重置组中,每个捕获组的每个备选方案都具有相同的编号:

if ( preg_match('~filename=(?|"([^"]*)"|\'([^\']*)\'|([^;]*))~', $str, $match) )
    echo $match[1], PHP_EOL;

无论哪种选择成功,捕获总是在组 1 中。

只是把我的两分钱放进去 - 你可以使用 条件正则表达式:

filename=(['"])?(?(1)(.+?)|([^;]+))


分解后,这表示:

filename=   # match filename=
(['"])?     # capture " or ' into group 1, optional
(?(1)       # if group 1 was set ...
    (.+?) # ... then match up to 
    |       # else
    ([^;]+) # not a semicolon
)

之后,您需要检查第 2 组或第 3 组是否存在。
或者,使用(经常被忽视的)分支重置来寻找@Casimir 的答案。

a demo on regex101.com