如何根据 RFC 2231 在 PHP 中对文件名进行编码?

Posted

技术标签:

【中文标题】如何根据 RFC 2231 在 PHP 中对文件名进行编码?【英文标题】:How can I encode a filename in PHP according to RFC 2231? 【发布时间】:2011-06-25 11:49:55 【问题描述】:

如何根据MIME Parameter Value and Encoded Word Extensions: Character Sets, Languages, and Continuations (RFC 2231)的编码对文件名的值进行编码?

【问题讨论】:

你可能想澄清这个问题。 【参考方案1】:

我认为应该这样做:

function rfc2231_encode($name, $value, $charset='', $lang='', $ll=78) 
    if (strlen($name) === 0 || preg_match('/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/', $name)) 
        // invalid parameter name;
        return false;
    
    if (strlen($charset) !== 0 && !preg_match('/^[A-Za-z]1,8(?:-[A-Za-z]1,8)*$/', $charset)) 
        // invalid charset;
        return false;
    
    if (strlen($lang) !== 0 && !preg_match('/^[A-Za-z]1,8(?:-[A-Za-z]1,8)*$/', $lang)) 
        // invalid language;
        return false;
    
    $value = "$charset'$lang'".preg_replace_callback('/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/', function($match)  return rawurlencode($match[0]); , $value);
    $nlen = strlen($name);
    $vlen = strlen($value);
    if (strlen($name) + $vlen > $ll-3) 
        $sections = array();
        $section = 0;
        for ($i=0, $j=0; $i<$vlen; $i+=$j) 
            $j = $ll - $nlen - strlen($section) - 4;
            $sections[$section++] = substr($value, $i, $j);
        
        for ($i=0, $n=$section; $i<$n; $i++) 
            $sections[$i] = " $name*$i*=".$sections[$i];
        
        return implode(";\r\n", $sections);
     else 
        return " $name*=$value";
    

请注意,此函数期望输出在单独的行中使用,前面有适当的换行(即 CRLF),例如:

"Content-Type: application/x-stuff;\r\n".rfc2231_encode('title', 'This is even more ***fun*** isn\'t it!', 'us-ascii', 'en', 48)

输出是:

Content-Type: application/x-stuff;
 title*0*=us-ascii'en'This%20is%20even%20more%20;
 title*1=%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it!

另见Test Cases for HTTP Content-Disposition header field and the Encodings defined in RFC 2047 and RFC 2231/5987

【讨论】:

能否提供一个使用示例? 我只想要接收 1 个参数的东西:rfc_2231_encode($filename),但似乎需要属性名称长度(在这种情况下为 count('filename')。是否有最大字符数$name + $value??我要求 $ll=78。$ll 是什么? @Juanjo Conti:最小参数是namevalue,所以:rfc2231_encode('filename', $filename)$ll 只是最大行长。 注意:HTTP 不需要限制行长。问题:字符集似乎并未用于实际从字符映射到八位字节;我错过了什么吗(我不是 php 程序员)。 不错的帖子,但您的输出无效!标题*1= 内容被编码,因此它必须是标题*1*=。注意额外的 * 告诉解码器它已被编码。在 RFC 示例中,title*1 未编码,因此没有额外的 *。此外,您的输出在 title*0*=... 之后缺少分号。它不在 RFC 示例中,但如果您检查 errata,您会发现它已修复。请修复您的错误,因为您的输出无效,并且期望正确编码电子邮件的解码器可能无法正确解码。

以上是关于如何根据 RFC 2231 在 PHP 中对文件名进行编码?的主要内容,如果未能解决你的问题,请参考以下文章

PHP:RFC-2231 如何将 UTF-8 字符串编码为 Content-Disposition 文件名

如何在 Excel VBA 中对字符串进行 URL 编码?

如何在 PHP 中对文件进行数字签名

如何对 RFC 3986 字符串进行转义

libsodium PHP将私钥存储在文件中

如何在 PHP 中对多维数组进行排序 [重复]